1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2  * vim: set ts=8 sts=2 et sw=2 tw=80:
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #ifndef vm_JSFunction_h
8 #define vm_JSFunction_h
9 
10 /*
11  * JS function definitions.
12  */
13 
14 #include <iterator>
15 
16 #include "jstypes.h"
17 
18 #include "js/shadow/Function.h"        // JS::shadow::Function
19 #include "vm/FunctionFlags.h"          // FunctionFlags
20 #include "vm/FunctionPrefixKind.h"     // FunctionPrefixKind
21 #include "vm/GeneratorAndAsyncKind.h"  // GeneratorKind, FunctionAsyncKind
22 #include "vm/JSObject.h"
23 #include "vm/JSScript.h"
24 
25 class JSJitInfo;
26 
27 namespace js {
28 
29 class FunctionExtended;
30 struct SelfHostedLazyScript;
31 
32 using Native = JSNative;
33 
34 static constexpr uint32_t BoundFunctionEnvTargetSlot = 2;
35 static constexpr uint32_t BoundFunctionEnvThisSlot = 3;
36 static constexpr uint32_t BoundFunctionEnvArgsSlot = 4;
37 
38 static const char FunctionConstructorMedialSigils[] = ") {\n";
39 static const char FunctionConstructorFinalBrace[] = "\n}";
40 
41 }  // namespace js
42 
43 class JSFunction : public js::NativeObject {
44  public:
45   static const JSClass class_;
46 
47  private:
48   /*
49    * number of formal arguments
50    * (including defaults and the rest parameter unlike f.length)
51    */
52   uint16_t nargs_;
53 
54   /*
55    * Bitfield composed of the above Flags enum, as well as the kind.
56    *
57    * If any of these flags needs to be accessed in off-thread JIT
58    * compilation, copy it to js::jit::WrappedFunction.
59    */
60   using FunctionFlags = js::FunctionFlags;
61   FunctionFlags flags_;
62 
63   union U {
64     class {
65       friend class JSFunction;
66       js::Native func_; /* native method pointer or null */
67       // Warning: this |extra| union MUST NOT store a value that could be a
68       // valid BaseScript* pointer! JIT guards depend on this.
69       union {
70         // Information about this function to be used by the JIT, only
71         // used if isBuiltinNative(); use the accessor!
72         const JSJitInfo* jitInfo_;
73         // For wasm/asm.js without a jit entry. Always has the low bit set to
74         // ensure it's never identical to a BaseScript* pointer. See warning
75         // above.
76         uintptr_t taggedWasmFuncIndex_;
77         // for wasm that has been given a jit entry
78         void** wasmJitEntry_;
79       } extra;
80     } native;
81     struct {
82       JSObject* env_; /* environment for new activations */
83       union {
84         js::BaseScript* script_;
85         js::SelfHostedLazyScript* selfHostedLazy_;
86       } s;
87     } scripted;
88   } u;
89 
90   // The `atom_` field can have different meanings depending on the function
91   // type and flags. It is used for diagnostics, decompiling, and
92   //
93   // 1. If the function is not a bound function:
94   //   a. If HAS_GUESSED_ATOM is not set, to store the initial value of the
95   //      "name" property of functions. But also see RESOLVED_NAME.
96   //   b. If HAS_GUESSED_ATOM is set, `atom_` is only used for diagnostics,
97   //      but must not be used for the "name" property.
98   //   c. If HAS_INFERRED_NAME is set, the function wasn't given an explicit
99   //      name in the source text, e.g. `function fn(){}`, but instead it
100   //      was inferred based on how the function was defined in the source
101   //      text. The exact name inference rules are defined in the ECMAScript
102   //      specification.
103   //      Name inference can happen at compile-time, for example in
104   //      `var fn = function(){}`, or it can happen at runtime, for example
105   //      in `var o = {[Symbol.iterator]: function(){}}`. When it happens at
106   //      compile-time, the HAS_INFERRED_NAME is set directly in the
107   //      bytecode emitter, when it happens at runtime, the flag is set when
108   //      evaluating the JSOp::SetFunName bytecode.
109   //   d. HAS_GUESSED_ATOM and HAS_INFERRED_NAME cannot both be set.
110   //   e. `atom_` can be null if neither an explicit, nor inferred, nor a
111   //      guessed name was set.
112   //
113   // 2. If the function is a bound function:
114   //   a. To store the initial value of the "name" property.
115   //   b. If HAS_BOUND_FUNCTION_NAME_PREFIX is not set, `atom_` doesn't
116   //      contain the "bound " prefix which is prepended to the "name"
117   //      property of bound functions per ECMAScript.
118   //   c. Bound functions can never have an inferred or guessed name.
119   //   d. `atom_` is never null for bound functions.
120   //
121   // Self-hosted functions have two names. For example, Array.prototype.sort
122   // has the standard name "sort", but the implementation in Array.js is named
123   // "ArraySort".
124   //
125   // -   In the self-hosting realm, these functions have `_atom` set to the
126   //     implementation name.
127   //
128   // -   When we clone these functions into normal realms, we set `_atom` to
129   //     the standard name. (The self-hosted name is also stored on the clone,
130   //     in another slot; see GetClonedSelfHostedFunctionName().)
131   js::GCPtrAtom atom_;
132 
133  public:
134   static inline JS::Result<JSFunction*, JS::OOM> create(
135       JSContext* cx, js::gc::AllocKind kind, js::gc::InitialHeap heap,
136       js::HandleShape shape);
137 
138   /* Call objects must be created for each invocation of this function. */
139   bool needsCallObject() const;
140 
141   bool needsExtraBodyVarEnvironment() const;
142   bool needsNamedLambdaEnvironment() const;
143 
needsFunctionEnvironmentObjects()144   bool needsFunctionEnvironmentObjects() const {
145     bool res = nonLazyScript()->needsFunctionEnvironmentObjects();
146     MOZ_ASSERT(res == (needsCallObject() || needsNamedLambdaEnvironment()));
147     return res;
148   }
149 
needsSomeEnvironmentObject()150   bool needsSomeEnvironmentObject() const {
151     return needsFunctionEnvironmentObjects() || needsExtraBodyVarEnvironment();
152   }
153 
154   static constexpr size_t NArgsBits = sizeof(nargs_) * CHAR_BIT;
nargs()155   size_t nargs() const { return nargs_; }
156 
flags()157   FunctionFlags flags() { return flags_; }
158 
kind()159   FunctionFlags::FunctionKind kind() const { return flags_.kind(); }
160 
161   /* A function can be classified as either native (C++) or interpreted (JS): */
isInterpreted()162   bool isInterpreted() const { return flags_.isInterpreted(); }
isNativeFun()163   bool isNativeFun() const { return flags_.isNativeFun(); }
164 
isConstructor()165   bool isConstructor() const { return flags_.isConstructor(); }
166 
isNonBuiltinConstructor()167   bool isNonBuiltinConstructor() const {
168     return flags_.isNonBuiltinConstructor();
169   }
170 
171   /* Possible attributes of a native function: */
isAsmJSNative()172   bool isAsmJSNative() const { return flags_.isAsmJSNative(); }
173 
isWasm()174   bool isWasm() const { return flags_.isWasm(); }
isWasmWithJitEntry()175   bool isWasmWithJitEntry() const { return flags_.isWasmWithJitEntry(); }
isNativeWithoutJitEntry()176   bool isNativeWithoutJitEntry() const {
177     return flags_.isNativeWithoutJitEntry();
178   }
isBuiltinNative()179   bool isBuiltinNative() const { return flags_.isBuiltinNative(); }
180 
hasJitEntry()181   bool hasJitEntry() const { return flags_.hasJitEntry(); }
182 
183   /* Possible attributes of an interpreted function: */
isBoundFunction()184   bool isBoundFunction() const { return flags_.isBoundFunction(); }
hasInferredName()185   bool hasInferredName() const { return flags_.hasInferredName(); }
hasGuessedAtom()186   bool hasGuessedAtom() const { return flags_.hasGuessedAtom(); }
hasBoundFunctionNamePrefix()187   bool hasBoundFunctionNamePrefix() const {
188     return flags_.hasBoundFunctionNamePrefix();
189   }
190 
isLambda()191   bool isLambda() const { return flags_.isLambda(); }
192 
193   // These methods determine which of the u.scripted.s union arms are active.
194   // For live JSFunctions the pointer values will always be non-null, but due
195   // to partial initialization the GC (and other features that scan the heap
196   // directly) may still return a null pointer.
hasSelfHostedLazyScript()197   bool hasSelfHostedLazyScript() const {
198     return flags_.hasSelfHostedLazyScript();
199   }
hasBaseScript()200   bool hasBaseScript() const { return flags_.hasBaseScript(); }
201 
hasBytecode()202   bool hasBytecode() const {
203     MOZ_ASSERT(!isIncomplete());
204     return hasBaseScript() && baseScript()->hasBytecode();
205   }
206 
isGhost()207   bool isGhost() const { return flags_.isGhost(); }
208 
209   // Arrow functions store their lexical new.target in the first extended slot.
isArrow()210   bool isArrow() const { return flags_.isArrow(); }
211   // Every class-constructor is also a method.
isMethod()212   bool isMethod() const { return flags_.isMethod(); }
isClassConstructor()213   bool isClassConstructor() const { return flags_.isClassConstructor(); }
214 
isGetter()215   bool isGetter() const { return flags_.isGetter(); }
isSetter()216   bool isSetter() const { return flags_.isSetter(); }
217 
allowSuperProperty()218   bool allowSuperProperty() const { return flags_.allowSuperProperty(); }
219 
hasResolvedLength()220   bool hasResolvedLength() const { return flags_.hasResolvedLength(); }
hasResolvedName()221   bool hasResolvedName() const { return flags_.hasResolvedName(); }
222 
isSelfHostedOrIntrinsic()223   bool isSelfHostedOrIntrinsic() const {
224     return flags_.isSelfHostedOrIntrinsic();
225   }
isSelfHostedBuiltin()226   bool isSelfHostedBuiltin() const { return flags_.isSelfHostedBuiltin(); }
227 
isIntrinsic()228   bool isIntrinsic() const { return flags_.isIntrinsic(); }
229 
hasJitScript()230   bool hasJitScript() const {
231     if (!hasBaseScript()) {
232       return false;
233     }
234 
235     return baseScript()->hasJitScript();
236   }
237 
238   /* Compound attributes: */
isBuiltin()239   bool isBuiltin() const { return isBuiltinNative() || isSelfHostedBuiltin(); }
240 
isNamedLambda()241   bool isNamedLambda() const {
242     return flags_.isNamedLambda(displayAtom() != nullptr);
243   }
244 
hasLexicalThis()245   bool hasLexicalThis() const { return isArrow(); }
246 
247   bool isBuiltinFunctionConstructor();
248   bool needsPrototypeProperty();
249 
250   // Returns true if this function must have a non-configurable .prototype data
251   // property. This is used to ensure looking up .prototype elsewhere will have
252   // no side-effects.
253   bool hasNonConfigurablePrototypeDataProperty();
254 
255   // Returns true if |new Fun()| should not allocate a new object caller-side
256   // but pass the uninitialized-lexical MagicValue and rely on the callee to
257   // construct its own |this| object.
constructorNeedsUninitializedThis()258   bool constructorNeedsUninitializedThis() const {
259     MOZ_ASSERT(isConstructor());
260     MOZ_ASSERT(isInterpreted());
261     return isBoundFunction() || isDerivedClassConstructor();
262   }
263 
264   /* Returns the strictness of this function, which must be interpreted. */
strict()265   bool strict() const { return baseScript()->strict(); }
266 
setFlags(uint16_t flags)267   void setFlags(uint16_t flags) { flags_ = FunctionFlags(flags); }
setFlags(FunctionFlags flags)268   void setFlags(FunctionFlags flags) { flags_ = flags; }
269 
270   // Make the function constructible.
setIsConstructor()271   void setIsConstructor() { flags_.setIsConstructor(); }
272 
273   // Can be called multiple times by the parser.
setArgCount(uint16_t nargs)274   void setArgCount(uint16_t nargs) { this->nargs_ = nargs; }
275 
setIsBoundFunction()276   void setIsBoundFunction() { flags_.setIsBoundFunction(); }
setIsSelfHostedBuiltin()277   void setIsSelfHostedBuiltin() { flags_.setIsSelfHostedBuiltin(); }
setIsIntrinsic()278   void setIsIntrinsic() { flags_.setIsIntrinsic(); }
279 
setResolvedLength()280   void setResolvedLength() { flags_.setResolvedLength(); }
setResolvedName()281   void setResolvedName() { flags_.setResolvedName(); }
282 
283   static bool getUnresolvedLength(JSContext* cx, js::HandleFunction fun,
284                                   js::MutableHandleValue v);
285 
286   JSAtom* infallibleGetUnresolvedName(JSContext* cx);
287 
288   static bool getUnresolvedName(JSContext* cx, js::HandleFunction fun,
289                                 js::MutableHandleValue v);
290 
291   static JSLinearString* getBoundFunctionName(JSContext* cx,
292                                               js::HandleFunction fun);
293 
explicitName()294   JSAtom* explicitName() const {
295     return (hasInferredName() || hasGuessedAtom()) ? nullptr : atom_.get();
296   }
297 
explicitOrInferredName()298   JSAtom* explicitOrInferredName() const {
299     return hasGuessedAtom() ? nullptr : atom_.get();
300   }
301 
initAtom(JSAtom * atom)302   void initAtom(JSAtom* atom) {
303     MOZ_ASSERT_IF(atom, js::AtomIsMarked(zone(), atom));
304     atom_.init(atom);
305   }
306 
setAtom(JSAtom * atom)307   void setAtom(JSAtom* atom) {
308     MOZ_ASSERT_IF(atom, js::AtomIsMarked(zone(), atom));
309     atom_ = atom;
310   }
311 
displayAtom()312   JSAtom* displayAtom() const { return atom_; }
313 
setInferredName(JSAtom * atom)314   void setInferredName(JSAtom* atom) {
315     MOZ_ASSERT(!atom_);
316     MOZ_ASSERT(atom);
317     MOZ_ASSERT(!hasGuessedAtom());
318     setAtom(atom);
319     flags_.setInferredName();
320   }
inferredName()321   JSAtom* inferredName() const {
322     MOZ_ASSERT(hasInferredName());
323     MOZ_ASSERT(atom_);
324     return atom_;
325   }
326 
setGuessedAtom(JSAtom * atom)327   void setGuessedAtom(JSAtom* atom) {
328     MOZ_ASSERT(!atom_);
329     MOZ_ASSERT(atom);
330     MOZ_ASSERT(!hasInferredName());
331     MOZ_ASSERT(!hasGuessedAtom());
332     MOZ_ASSERT(!isBoundFunction());
333     setAtom(atom);
334     flags_.setGuessedAtom();
335   }
336 
setPrefixedBoundFunctionName(JSAtom * atom)337   void setPrefixedBoundFunctionName(JSAtom* atom) {
338     MOZ_ASSERT(!hasBoundFunctionNamePrefix());
339     MOZ_ASSERT(atom);
340     flags_.setPrefixedBoundFunctionName();
341     setAtom(atom);
342   }
343 
344   /* uint16_t representation bounds number of call object dynamic slots. */
345   enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) };
346 
347   /*
348    * For an interpreted function, accessors for the initial scope object of
349    * activations (stack frames) of the function.
350    */
environment()351   JSObject* environment() const {
352     MOZ_ASSERT(isInterpreted());
353     return u.scripted.env_;
354   }
355 
initEnvironment(JSObject * obj)356   void initEnvironment(JSObject* obj) {
357     MOZ_ASSERT(isInterpreted());
358     reinterpret_cast<js::GCPtrObject*>(&u.scripted.env_)->init(obj);
359   }
360 
361  public:
offsetOfNargs()362   static constexpr size_t offsetOfNargs() {
363     return offsetof(JSFunction, nargs_);
364   }
offsetOfFlags()365   static constexpr size_t offsetOfFlags() {
366     return offsetof(JSFunction, flags_);
367   }
offsetOfEnvironment()368   static size_t offsetOfEnvironment() {
369     return offsetof(JSFunction, u.scripted.env_);
370   }
offsetOfAtom()371   static size_t offsetOfAtom() { return offsetof(JSFunction, atom_); }
372 
373   static bool delazifyLazilyInterpretedFunction(JSContext* cx,
374                                                 js::HandleFunction fun);
375   static bool delazifySelfHostedLazyFunction(JSContext* cx,
376                                              js::HandleFunction fun);
377   void maybeRelazify(JSRuntime* rt);
378 
379   // Function Scripts
380   //
381   // Interpreted functions have either a BaseScript or a SelfHostedLazyScript. A
382   // BaseScript may either be lazy or non-lazy (hasBytecode()). Methods may
383   // return a JSScript* if underlying BaseScript is known to have bytecode.
384   //
385   // There are several methods to get the script of an interpreted function:
386   //
387   // - For all interpreted functions, getOrCreateScript() will get the
388   //   JSScript, delazifying the function if necessary. This is the safest to
389   //   use, but has extra checks, requires a cx and may trigger a GC.
390   //
391   // - For functions known to have a JSScript, nonLazyScript() will get it.
392 
getOrCreateScript(JSContext * cx,js::HandleFunction fun)393   static JSScript* getOrCreateScript(JSContext* cx, js::HandleFunction fun) {
394     MOZ_ASSERT(fun->isInterpreted());
395     MOZ_ASSERT(cx);
396 
397     if (fun->hasSelfHostedLazyScript()) {
398       if (!delazifySelfHostedLazyFunction(cx, fun)) {
399         return nullptr;
400       }
401       return fun->nonLazyScript();
402     }
403 
404     MOZ_ASSERT(fun->hasBaseScript());
405     JS::Rooted<js::BaseScript*> script(cx, fun->baseScript());
406 
407     if (!script->hasBytecode()) {
408       if (!delazifyLazilyInterpretedFunction(cx, fun)) {
409         return nullptr;
410       }
411     }
412     return fun->nonLazyScript();
413   }
414 
415   // If this is a scripted function, returns its canonical function (the
416   // original function allocated by the frontend). Note that lazy self-hosted
417   // builtins don't have a lazy script so in that case we also return nullptr.
maybeCanonicalFunction()418   JSFunction* maybeCanonicalFunction() const {
419     if (hasBaseScript()) {
420       return baseScript()->function();
421     }
422     return nullptr;
423   }
424 
425   // The default state of a JSFunction that is not ready for execution. If
426   // observed outside initialization, this is the result of failure during
427   // bytecode compilation.
428   //
429   // A BaseScript is fully initialized before u.script.s.script_ is initialized
430   // with a reference to it.
isIncomplete()431   bool isIncomplete() const { return isInterpreted() && !u.scripted.s.script_; }
432 
nonLazyScript()433   JSScript* nonLazyScript() const {
434     MOZ_ASSERT(hasBytecode());
435     MOZ_ASSERT(u.scripted.s.script_);
436     return static_cast<JSScript*>(u.scripted.s.script_);
437   }
438 
selfHostedLazyScript()439   js::SelfHostedLazyScript* selfHostedLazyScript() const {
440     MOZ_ASSERT(hasSelfHostedLazyScript());
441     MOZ_ASSERT(u.scripted.s.selfHostedLazy_);
442     return u.scripted.s.selfHostedLazy_;
443   }
444 
445   // Access fields defined on both lazy and non-lazy scripts.
baseScript()446   js::BaseScript* baseScript() const {
447     MOZ_ASSERT(hasBaseScript());
448     MOZ_ASSERT(u.scripted.s.script_);
449     return u.scripted.s.script_;
450   }
451 
452   static bool getLength(JSContext* cx, js::HandleFunction fun,
453                         uint16_t* length);
454 
enclosingScope()455   js::Scope* enclosingScope() const { return baseScript()->enclosingScope(); }
456 
setEnclosingLazyScript(js::BaseScript * enclosingScript)457   void setEnclosingLazyScript(js::BaseScript* enclosingScript) {
458     baseScript()->setEnclosingScript(enclosingScript);
459   }
460 
generatorKind()461   js::GeneratorKind generatorKind() const {
462     if (hasBaseScript()) {
463       return baseScript()->generatorKind();
464     }
465     if (hasSelfHostedLazyScript()) {
466       return clonedSelfHostedGeneratorKind();
467     }
468     return js::GeneratorKind::NotGenerator;
469   }
470 
471   js::GeneratorKind clonedSelfHostedGeneratorKind() const;
472 
isGenerator()473   bool isGenerator() const {
474     return generatorKind() == js::GeneratorKind::Generator;
475   }
476 
asyncKind()477   js::FunctionAsyncKind asyncKind() const {
478     if (hasBaseScript()) {
479       return baseScript()->asyncKind();
480     }
481     return js::FunctionAsyncKind::SyncFunction;
482   }
483 
isAsync()484   bool isAsync() const {
485     return asyncKind() == js::FunctionAsyncKind::AsyncFunction;
486   }
487 
isGeneratorOrAsync()488   bool isGeneratorOrAsync() const { return isGenerator() || isAsync(); }
489 
initScript(js::BaseScript * script)490   void initScript(js::BaseScript* script) {
491     MOZ_ASSERT_IF(script, realm() == script->realm());
492     MOZ_ASSERT(isInterpreted());
493     u.scripted.s.script_ = script;
494   }
495 
initSelfHostedLazyScript(js::SelfHostedLazyScript * lazy)496   void initSelfHostedLazyScript(js::SelfHostedLazyScript* lazy) {
497     MOZ_ASSERT(isSelfHostedBuiltin());
498     MOZ_ASSERT(isInterpreted());
499     flags_.clearBaseScript();
500     flags_.setSelfHostedLazy();
501     u.scripted.s.selfHostedLazy_ = lazy;
502     MOZ_ASSERT(hasSelfHostedLazyScript());
503   }
504 
clearSelfHostedLazyScript()505   void clearSelfHostedLazyScript() {
506     // Note: The selfHostedLazy_ field is not a GC-thing pointer so we don't
507     // need to trigger barriers.
508     flags_.clearSelfHostedLazy();
509     flags_.setBaseScript();
510     u.scripted.s.script_ = nullptr;
511     MOZ_ASSERT(isIncomplete());
512   }
513 
native()514   JSNative native() const {
515     MOZ_ASSERT(isNativeFun());
516     return u.native.func_;
517   }
nativeUnchecked()518   JSNative nativeUnchecked() const {
519     // Called by Ion off-main thread.
520     return u.native.func_;
521   }
522 
maybeNative()523   JSNative maybeNative() const { return isInterpreted() ? nullptr : native(); }
524 
initNative(js::Native native,const JSJitInfo * jitInfo)525   void initNative(js::Native native, const JSJitInfo* jitInfo) {
526     MOZ_ASSERT(isNativeFun());
527     MOZ_ASSERT_IF(jitInfo, isBuiltinNative());
528     MOZ_ASSERT(native);
529     u.native.func_ = native;
530     u.native.extra.jitInfo_ = jitInfo;
531   }
hasJitInfo()532   bool hasJitInfo() const {
533     return isBuiltinNative() && u.native.extra.jitInfo_;
534   }
jitInfo()535   const JSJitInfo* jitInfo() const {
536     MOZ_ASSERT(hasJitInfo());
537     return u.native.extra.jitInfo_;
538   }
jitInfoUnchecked()539   const JSJitInfo* jitInfoUnchecked() const {
540     // Called by Ion off-main thread.
541     return u.native.extra.jitInfo_;
542   }
setJitInfo(const JSJitInfo * data)543   void setJitInfo(const JSJitInfo* data) {
544     MOZ_ASSERT(isBuiltinNative());
545     u.native.extra.jitInfo_ = data;
546   }
547 
548   // wasm functions are always natives and either:
549   //  - store a function-index in u.n.extra and can only be called through the
550   //    fun->native() entry point from C++.
551   //  - store a jit-entry code pointer in u.n.extra and can be called by jit
552   //    code directly. C++ callers can still use the fun->native() entry point
553   //    (computing the function index from the jit-entry point).
setWasmFuncIndex(uint32_t funcIndex)554   void setWasmFuncIndex(uint32_t funcIndex) {
555     MOZ_ASSERT(isWasm() || isAsmJSNative());
556     MOZ_ASSERT(!isWasmWithJitEntry());
557     MOZ_ASSERT(!u.native.extra.taggedWasmFuncIndex_);
558     // See wasmFuncIndex_ comment for why we set the low bit.
559     u.native.extra.taggedWasmFuncIndex_ = (uintptr_t(funcIndex) << 1) | 1;
560   }
wasmFuncIndex()561   uint32_t wasmFuncIndex() const {
562     MOZ_ASSERT(isWasm() || isAsmJSNative());
563     MOZ_ASSERT(!isWasmWithJitEntry());
564     MOZ_ASSERT(u.native.extra.taggedWasmFuncIndex_ & 1);
565     return u.native.extra.taggedWasmFuncIndex_ >> 1;
566   }
setWasmJitEntry(void ** entry)567   void setWasmJitEntry(void** entry) {
568     MOZ_ASSERT(*entry);
569     MOZ_ASSERT(isWasm());
570     MOZ_ASSERT(!isWasmWithJitEntry());
571     flags_.setWasmJitEntry();
572     u.native.extra.wasmJitEntry_ = entry;
573     MOZ_ASSERT(isWasmWithJitEntry());
574   }
wasmJitEntry()575   void** wasmJitEntry() const {
576     MOZ_ASSERT(isWasmWithJitEntry());
577     MOZ_ASSERT(u.native.extra.wasmJitEntry_);
578     return u.native.extra.wasmJitEntry_;
579   }
580 
581   bool isDerivedClassConstructor() const;
582   bool isSyntheticFunction() const;
583 
offsetOfNative()584   static unsigned offsetOfNative() {
585     return offsetof(JSFunction, u.native.func_);
586   }
offsetOfScript()587   static unsigned offsetOfScript() {
588     static_assert(offsetof(U, scripted.s.script_) ==
589                       offsetof(U, native.extra.wasmJitEntry_),
590                   "scripted.s.script_ must be at the same offset as "
591                   "native.extra.wasmJitEntry_");
592     return offsetof(JSFunction, u.scripted.s.script_);
593   }
offsetOfNativeOrEnv()594   static unsigned offsetOfNativeOrEnv() {
595     static_assert(
596         offsetof(U, native.func_) == offsetof(U, scripted.env_),
597         "U.native.func_ must be at the same offset as U.scripted.env_");
598     return offsetOfNative();
599   }
offsetOfBaseScript()600   static unsigned offsetOfBaseScript() {
601     return offsetof(JSFunction, u.scripted.s.script_);
602   }
603 
offsetOfJitInfo()604   static unsigned offsetOfJitInfo() {
605     return offsetof(JSFunction, u.native.extra.jitInfo_);
606   }
607 
608   inline void trace(JSTracer* trc);
609 
610   /* Bound function accessors. */
611 
612   JSObject* getBoundFunctionTarget() const;
613   const js::Value& getBoundFunctionThis() const;
614   const js::Value& getBoundFunctionArgument(unsigned which) const;
615   size_t getBoundFunctionArgumentCount() const;
616 
617   /*
618    * Used to mark bound functions as such and make them constructible if the
619    * target is. Also assigns the prototype and sets the name and correct length.
620    */
621   static bool finishBoundFunctionInit(JSContext* cx, js::HandleFunction bound,
622                                       js::HandleObject targetObj,
623                                       int32_t argCount);
624 
625  private:
626   inline js::FunctionExtended* toExtended();
627   inline const js::FunctionExtended* toExtended() const;
628 
629  public:
isExtended()630   inline bool isExtended() const {
631     bool extended = flags_.isExtended();
632     MOZ_ASSERT_IF(isTenured(),
633                   extended == (asTenured().getAllocKind() ==
634                                js::gc::AllocKind::FUNCTION_EXTENDED));
635     return extended;
636   }
637 
638   /*
639    * Accessors for data stored in extended functions. Use setExtendedSlot if
640    * the function has already been initialized. Otherwise use
641    * initExtendedSlot.
642    */
643   inline void initializeExtended();
644   inline void initExtendedSlot(size_t which, const js::Value& val);
645   inline void setExtendedSlot(size_t which, const js::Value& val);
646   inline const js::Value& getExtendedSlot(size_t which) const;
647 
648   /*
649    * Same as `toExtended` and `getExtendedSlot`, but `this` is guaranteed to be
650    * an extended function.
651    *
652    * This function is supposed to be used off-thread, especially the JIT
653    * compilation thread, that cannot access JSFunction.flags_, because of
654    * a race condition.
655    *
656    * See Also: WrappedFunction.isExtended_
657    */
658   inline js::FunctionExtended* toExtendedOffMainThread();
659   inline const js::FunctionExtended* toExtendedOffMainThread() const;
660   inline const js::Value& getExtendedSlotOffMainThread(size_t which) const;
661 
662   /* GC support. */
getAllocKind()663   js::gc::AllocKind getAllocKind() const {
664     static_assert(
665         js::gc::AllocKind::FUNCTION != js::gc::AllocKind::FUNCTION_EXTENDED,
666         "extended/non-extended AllocKinds have to be different "
667         "for getAllocKind() to have a reason to exist");
668 
669     js::gc::AllocKind kind = js::gc::AllocKind::FUNCTION;
670     if (isExtended()) {
671       kind = js::gc::AllocKind::FUNCTION_EXTENDED;
672     }
673     MOZ_ASSERT_IF(isTenured(), kind == asTenured().getAllocKind());
674     return kind;
675   }
676 };
677 
678 static_assert(sizeof(JSFunction) == sizeof(JS::shadow::Function),
679               "shadow interface must match actual interface");
680 
681 extern JSString* fun_toStringHelper(JSContext* cx, js::HandleObject obj,
682                                     bool isToSource);
683 
684 namespace js {
685 
686 extern bool Function(JSContext* cx, unsigned argc, Value* vp);
687 
688 extern bool Generator(JSContext* cx, unsigned argc, Value* vp);
689 
690 extern bool AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp);
691 
692 extern bool AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp);
693 
694 // If enclosingEnv is null, the function will have a null environment()
695 // (yes, null, not the global lexical environment).  In all cases, the global
696 // will be used as the terminating environment.
697 
698 extern JSFunction* NewFunctionWithProto(
699     JSContext* cx, JSNative native, unsigned nargs, FunctionFlags flags,
700     HandleObject enclosingEnv, HandleAtom atom, HandleObject proto,
701     gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
702     NewObjectKind newKind = GenericObject);
703 
704 // Allocate a new function backed by a JSNative.  Note that by default this
705 // creates a tenured object.
706 inline JSFunction* NewNativeFunction(
707     JSContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
708     gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
709     NewObjectKind newKind = TenuredObject,
710     FunctionFlags flags = FunctionFlags::NATIVE_FUN) {
711   MOZ_ASSERT(native);
712   return NewFunctionWithProto(cx, native, nargs, flags, nullptr, atom, nullptr,
713                               allocKind, newKind);
714 }
715 
716 // Allocate a new constructor backed by a JSNative.  Note that by default this
717 // creates a tenured object.
718 inline JSFunction* NewNativeConstructor(
719     JSContext* cx, JSNative native, unsigned nargs, HandleAtom atom,
720     gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
721     NewObjectKind newKind = TenuredObject,
722     FunctionFlags flags = FunctionFlags::NATIVE_CTOR) {
723   MOZ_ASSERT(native);
724   MOZ_ASSERT(flags.isNativeConstructor());
725   return NewFunctionWithProto(cx, native, nargs, flags, nullptr, atom, nullptr,
726                               allocKind, newKind);
727 }
728 
729 // Allocate a new scripted function.  If enclosingEnv is null, the
730 // global lexical environment will be used.  In all cases the terminating
731 // environment of the resulting object will be the global.
732 extern JSFunction* NewScriptedFunction(
733     JSContext* cx, unsigned nargs, FunctionFlags flags, HandleAtom atom,
734     HandleObject proto = nullptr,
735     gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
736     NewObjectKind newKind = GenericObject, HandleObject enclosingEnv = nullptr);
737 
738 // Determine which [[Prototype]] to use when creating a new function using the
739 // requested generator and async kind.
740 //
741 // This sets `proto` to `nullptr` for non-generator, synchronous functions to
742 // mean "the builtin %FunctionPrototype% in the current realm", the common case.
743 //
744 // We could set it to `cx->global()->getOrCreateFunctionPrototype()`, but
745 // nullptr gets a fast path in e.g. js::NewObjectWithClassProtoCommon.
746 extern bool GetFunctionPrototype(JSContext* cx, js::GeneratorKind generatorKind,
747                                  js::FunctionAsyncKind asyncKind,
748                                  js::MutableHandleObject proto);
749 
750 extern JSAtom* IdToFunctionName(
751     JSContext* cx, HandleId id,
752     FunctionPrefixKind prefixKind = FunctionPrefixKind::None);
753 
754 extern bool SetFunctionName(JSContext* cx, HandleFunction fun, HandleValue name,
755                             FunctionPrefixKind prefixKind);
756 
757 extern JSFunction* DefineFunction(
758     JSContext* cx, HandleObject obj, HandleId id, JSNative native,
759     unsigned nargs, unsigned flags,
760     gc::AllocKind allocKind = gc::AllocKind::FUNCTION);
761 
762 extern bool fun_toString(JSContext* cx, unsigned argc, Value* vp);
763 
764 extern void ThrowTypeErrorBehavior(JSContext* cx);
765 
766 /*
767  * Function extended with reserved slots for use by various kinds of functions.
768  * Most functions do not have these extensions, but enough do that efficient
769  * storage is required (no malloc'ed reserved slots).
770  */
771 class FunctionExtended : public JSFunction {
772  public:
773   static const unsigned NUM_EXTENDED_SLOTS = 2;
774 
775   // Arrow functions store their lexical new.target in the first extended
776   // slot.
777   static const unsigned ARROW_NEWTARGET_SLOT = 0;
778 
779   static const unsigned METHOD_HOMEOBJECT_SLOT = 0;
780 
781   // Stores the length for bound functions, so the .length property doesn't need
782   // to be resolved eagerly.
783   static const unsigned BOUND_FUNCTION_LENGTH_SLOT = 1;
784 
785   // Exported asm.js/wasm functions store their WasmInstanceObject in the
786   // first slot.
787   static const unsigned WASM_INSTANCE_SLOT = 0;
788 
789   // wasm/asm.js exported functions store the wasm::TlsData pointer of their
790   // instance.
791   static const unsigned WASM_TLSDATA_SLOT = 1;
792 
793   // asm.js module functions store their WasmModuleObject in the first slot.
794   static const unsigned ASMJS_MODULE_SLOT = 0;
795 
796   // Async module callback handlers store their ModuleObject in the first slot.
797   static const unsigned MODULE_SLOT = 0;
798 
offsetOfExtendedSlot(unsigned which)799   static inline size_t offsetOfExtendedSlot(unsigned which) {
800     MOZ_ASSERT(which < NUM_EXTENDED_SLOTS);
801     return offsetof(FunctionExtended, extendedSlots) +
802            which * sizeof(GCPtrValue);
803   }
offsetOfArrowNewTargetSlot()804   static inline size_t offsetOfArrowNewTargetSlot() {
805     return offsetOfExtendedSlot(ARROW_NEWTARGET_SLOT);
806   }
offsetOfMethodHomeObjectSlot()807   static inline size_t offsetOfMethodHomeObjectSlot() {
808     return offsetOfExtendedSlot(METHOD_HOMEOBJECT_SLOT);
809   }
offsetOfBoundFunctionLengthSlot()810   static inline size_t offsetOfBoundFunctionLengthSlot() {
811     return offsetOfExtendedSlot(BOUND_FUNCTION_LENGTH_SLOT);
812   }
813 
814  private:
815   friend class JSFunction;
816 
817   /* Reserved slots available for storage by particular native functions. */
818   GCPtrValue extendedSlots[NUM_EXTENDED_SLOTS];
819 };
820 
821 extern bool CanReuseScriptForClone(JS::Realm* realm, HandleFunction fun,
822                                    HandleObject newEnclosingEnv);
823 
824 extern JSFunction* CloneFunctionReuseScript(JSContext* cx, HandleFunction fun,
825                                             HandleObject enclosingEnv,
826                                             gc::AllocKind kind,
827                                             HandleObject proto);
828 
829 extern JSFunction* CloneFunctionAndScript(
830     JSContext* cx, HandleFunction fun, HandleObject enclosingEnv,
831     HandleScope newScope, Handle<ScriptSourceObject*> sourceObject,
832     gc::AllocKind kind, HandleObject proto = nullptr);
833 
834 extern JSFunction* CloneAsmJSModuleFunction(JSContext* cx, HandleFunction fun);
835 
836 extern JSFunction* CloneSelfHostingIntrinsic(JSContext* cx, HandleFunction fun);
837 
838 }  // namespace js
839 
toExtended()840 inline js::FunctionExtended* JSFunction::toExtended() {
841   MOZ_ASSERT(isExtended());
842   return static_cast<js::FunctionExtended*>(this);
843 }
844 
toExtended()845 inline const js::FunctionExtended* JSFunction::toExtended() const {
846   MOZ_ASSERT(isExtended());
847   return static_cast<const js::FunctionExtended*>(this);
848 }
849 
toExtendedOffMainThread()850 inline js::FunctionExtended* JSFunction::toExtendedOffMainThread() {
851   return static_cast<js::FunctionExtended*>(this);
852 }
853 
toExtendedOffMainThread()854 inline const js::FunctionExtended* JSFunction::toExtendedOffMainThread() const {
855   return static_cast<const js::FunctionExtended*>(this);
856 }
857 
initializeExtended()858 inline void JSFunction::initializeExtended() {
859   MOZ_ASSERT(isExtended());
860 
861   MOZ_ASSERT(std::size(toExtended()->extendedSlots) == 2);
862   toExtended()->extendedSlots[0].init(js::UndefinedValue());
863   toExtended()->extendedSlots[1].init(js::UndefinedValue());
864 }
865 
initExtendedSlot(size_t which,const js::Value & val)866 inline void JSFunction::initExtendedSlot(size_t which, const js::Value& val) {
867   MOZ_ASSERT(which < std::size(toExtended()->extendedSlots));
868   MOZ_ASSERT(js::IsObjectValueInCompartment(val, compartment()));
869   toExtended()->extendedSlots[which].init(val);
870 }
871 
setExtendedSlot(size_t which,const js::Value & val)872 inline void JSFunction::setExtendedSlot(size_t which, const js::Value& val) {
873   MOZ_ASSERT(which < std::size(toExtended()->extendedSlots));
874   MOZ_ASSERT(js::IsObjectValueInCompartment(val, compartment()));
875   toExtended()->extendedSlots[which] = val;
876 }
877 
getExtendedSlot(size_t which)878 inline const js::Value& JSFunction::getExtendedSlot(size_t which) const {
879   MOZ_ASSERT(which < std::size(toExtended()->extendedSlots));
880   return toExtended()->extendedSlots[which];
881 }
882 
getExtendedSlotOffMainThread(size_t which)883 inline const js::Value& JSFunction::getExtendedSlotOffMainThread(
884     size_t which) const {
885   MOZ_ASSERT(which < std::size(toExtendedOffMainThread()->extendedSlots));
886   return toExtendedOffMainThread()->extendedSlots[which];
887 }
888 
889 namespace js {
890 
891 JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool isToSource);
892 
893 template <XDRMode mode>
894 XDRResult XDRInterpretedFunction(XDRState<mode>* xdr,
895                                  HandleScope enclosingScope,
896                                  HandleScriptSourceObject sourceObject,
897                                  MutableHandleFunction objp);
898 
899 /*
900  * Report an error that call.thisv is not compatible with the specified class,
901  * assuming that the method (clasp->name).prototype.<name of callee function>
902  * is what was called.
903  */
904 extern void ReportIncompatibleMethod(JSContext* cx, const CallArgs& args,
905                                      const JSClass* clasp);
906 
907 /*
908  * Report an error that call.thisv is not an acceptable this for the callee
909  * function.
910  */
911 extern void ReportIncompatible(JSContext* cx, const CallArgs& args);
912 
913 extern bool fun_apply(JSContext* cx, unsigned argc, Value* vp);
914 
915 extern bool fun_call(JSContext* cx, unsigned argc, Value* vp);
916 
917 } /* namespace js */
918 
919 #ifdef DEBUG
920 namespace JS {
921 namespace detail {
922 
923 JS_PUBLIC_API void CheckIsValidConstructible(const Value& calleev);
924 
925 }  // namespace detail
926 }  // namespace JS
927 #endif
928 
929 #endif /* vm_JSFunction_h */
930