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