JSFunction.h (35913B)
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 <string_view> 15 16 #include "jstypes.h" 17 18 #include "gc/Policy.h" 19 #include "js/shadow/Function.h" // JS::shadow::Function 20 #include "vm/FunctionFlags.h" // FunctionFlags 21 #include "vm/FunctionPrefixKind.h" // FunctionPrefixKind 22 #include "vm/GeneratorAndAsyncKind.h" // GeneratorKind, FunctionAsyncKind 23 #include "vm/JSAtomUtils.h" // AtomIsMarked 24 #include "vm/JSObject.h" 25 #include "vm/JSScript.h" 26 #include "wasm/WasmTypeDef.h" 27 28 class JSJitInfo; 29 30 namespace js { 31 32 class FunctionExtended; 33 class JS_PUBLIC_API GenericPrinter; 34 class JSONPrinter; 35 struct SelfHostedLazyScript; 36 37 using Native = JSNative; 38 39 static constexpr std::string_view FunctionConstructorMedialSigils = ") {\n"; 40 static constexpr std::string_view FunctionConstructorFinalBrace = "\n}"; 41 42 // JSFunctions can have one of two classes: 43 extern const JSClass FunctionClass; 44 extern const JSClass ExtendedFunctionClass; 45 46 namespace wasm { 47 48 class Instance; 49 50 } // namespace wasm 51 } // namespace js 52 53 class JSFunction : public js::NativeObject { 54 public: 55 static_assert(sizeof(js::FunctionFlags) == sizeof(uint16_t)); 56 static constexpr size_t ArgCountShift = 16; 57 static constexpr size_t FlagsMask = js::BitMask(ArgCountShift); 58 static constexpr size_t ArgCountMask = js::BitMask(16) << ArgCountShift; 59 60 enum { 61 /* 62 * Bitfield composed of FunctionFlags and argument count, stored as a 63 * PrivateUint32Value. 64 * 65 * If any of these flags needs to be accessed in off-thread JIT compilation, 66 * copy it to js::jit::WrappedFunction. 67 */ 68 FlagsAndArgCountSlot, 69 70 /* 71 * For native functions, the native method pointer stored as a private 72 * value, or undefined. 73 * 74 * For interpreted functions, the environment object for new activations or 75 * null. 76 */ 77 NativeFuncOrInterpretedEnvSlot, 78 79 /* 80 * For native functions this is one of: 81 * 82 * - JSJitInfo* to be used by the JIT, only used if isBuiltinNative() for 83 * builtin natives 84 * 85 * - wasm function index for wasm/asm.js without a jit entry. Always has 86 * the low bit set to ensure it's never identical to a BaseScript* 87 * pointer 88 * 89 * - a native JIT entry (used for Wasm and TrampolineNative functions) 90 * 91 * The JIT depends on none of the above being a valid BaseScript pointer. 92 * 93 * For interpreted functions this is either a BaseScript or the 94 * SelfHostedLazyScript pointer. 95 * 96 * These are all stored as private values, because the JIT assumes that it 97 * can access the SelfHostedLazyScript and BaseScript pointer in the same 98 * way. 99 */ 100 NativeJitInfoOrInterpretedScriptSlot, 101 102 // The `atom_` field can have different meanings depending on the function 103 // type and flags. It is used for diagnostics, decompiling, and 104 // 105 // a. If LAZY_ACCESSOR_NAME is set, to store the initial value of the 106 // unprefixed part of "name" property of a accessor function. 107 // But also see RESOLVED_NAME. 108 // b. If HAS_GUESSED_ATOM is not set, to store the initial value of the 109 // "name" property of functions. But also see RESOLVED_NAME. 110 // c. If HAS_GUESSED_ATOM is set, `atom_` is only used for diagnostics, 111 // but must not be used for the "name" property. 112 // d. If HAS_INFERRED_NAME is set, the function wasn't given an explicit 113 // name in the source text, e.g. `function fn(){}`, but instead it 114 // was inferred based on how the function was defined in the source 115 // text. The exact name inference rules are defined in the ECMAScript 116 // specification. 117 // Name inference can happen at compile-time, for example in 118 // `var fn = function(){}`, or it can happen at runtime, for example 119 // in `var o = {[Symbol.iterator]: function(){}}`. When it happens at 120 // compile-time, the HAS_INFERRED_NAME is set directly in the 121 // bytecode emitter, when it happens at runtime, the flag is set when 122 // evaluating the JSOp::SetFunName bytecode. 123 // e. HAS_GUESSED_ATOM, HAS_INFERRED_NAME, and LAZY_ACCESSOR_NAME are 124 // mutually exclusive and cannot be set at the same time. 125 // f. `atom_` can be null if neither an explicit, nor inferred, nor a 126 // guessed name was set. 127 // 128 // Self-hosted functions have two names. For example, Array.prototype.sort 129 // has the standard name "sort", but the implementation in Array.js is named 130 // "ArraySort". 131 // 132 // - In the self-hosting realm, these functions have `_atom` set to the 133 // implementation name. 134 // 135 // - When we clone these functions into normal realms, we set `_atom` to 136 // the standard name. (The self-hosted name is also stored on the clone, 137 // in another slot; see GetClonedSelfHostedFunctionName().) 138 AtomSlot, 139 140 SlotCount 141 }; 142 143 private: 144 using FunctionFlags = js::FunctionFlags; 145 146 public: 147 static inline JSFunction* create(JSContext* cx, js::gc::AllocKind kind, 148 js::gc::Heap heap, 149 js::Handle<js::SharedShape*> shape, 150 js::gc::AllocSite* site = nullptr); 151 152 /* Call objects must be created for each invocation of this function. */ 153 bool needsCallObject() const; 154 155 bool needsExtraBodyVarEnvironment() const; 156 bool needsNamedLambdaEnvironment() const; 157 158 bool needsFunctionEnvironmentObjects() const { 159 bool res = nonLazyScript()->needsFunctionEnvironmentObjects(); 160 MOZ_ASSERT(res == (needsCallObject() || needsNamedLambdaEnvironment())); 161 return res; 162 } 163 164 bool needsSomeEnvironmentObject() const { 165 return needsFunctionEnvironmentObjects() || needsExtraBodyVarEnvironment(); 166 } 167 168 uint32_t flagsAndArgCountRaw() const { 169 return getFixedSlot(FlagsAndArgCountSlot).toPrivateUint32(); 170 } 171 172 void initFlagsAndArgCount() { 173 initFixedSlot(FlagsAndArgCountSlot, JS::PrivateUint32Value(0)); 174 } 175 176 size_t nargs() const { return flagsAndArgCountRaw() >> ArgCountShift; } 177 178 FunctionFlags flags() const { 179 return FunctionFlags(uint16_t(flagsAndArgCountRaw() & FlagsMask)); 180 } 181 182 FunctionFlags::FunctionKind kind() const { return flags().kind(); } 183 184 #ifdef DEBUG 185 void assertFunctionKindIntegrity() { flags().assertFunctionKindIntegrity(); } 186 #endif 187 188 /* A function can be classified as either native (C++) or interpreted (JS): */ 189 bool isInterpreted() const { return flags().isInterpreted(); } 190 bool isNativeFun() const { return flags().isNativeFun(); } 191 192 bool isConstructor() const { return flags().isConstructor(); } 193 194 bool isNonBuiltinConstructor() const { 195 return flags().isNonBuiltinConstructor(); 196 } 197 198 /* Possible attributes of a native function: */ 199 bool isAsmJSNative() const { return flags().isAsmJSNative(); } 200 201 // A WebAssembly "Exported Function" is the spec name for the JS function 202 // objects created to wrap wasm functions. This predicate returns false 203 // for asm.js functions which are semantically just normal JS functions 204 // (even if they are implemented via wasm under the hood). The accessor 205 // functions for extracting the instance and func-index of a wasm function 206 // can be used for both wasm and asm.js, however. 207 bool isWasm() const { return flags().isWasm(); } 208 bool isWasmWithJitEntry() const { return flags().isWasmWithJitEntry(); } 209 210 bool isNativeWithJitEntry() const { return flags().isNativeWithJitEntry(); } 211 bool isNativeWithoutJitEntry() const { 212 return flags().isNativeWithoutJitEntry(); 213 } 214 bool isBuiltinNative() const { return flags().isBuiltinNative(); } 215 216 bool hasJitEntry() const { return flags().hasJitEntry(); } 217 218 /* Possible attributes of an interpreted function: */ 219 bool hasInferredName() const { return flags().hasInferredName(); } 220 bool hasGuessedAtom() const { return flags().hasGuessedAtom(); } 221 222 bool isLambda() const { return flags().isLambda(); } 223 224 // These methods determine which kind of script we hold. 225 // 226 // For live JSFunctions the pointer values will always be non-null, but due to 227 // partial initialization the GC (and other features that scan the heap 228 // directly) may still return a null pointer. 229 bool hasSelfHostedLazyScript() const { 230 return flags().hasSelfHostedLazyScript(); 231 } 232 bool hasBaseScript() const { return flags().hasBaseScript(); } 233 234 bool hasBytecode() const { 235 MOZ_ASSERT(!isIncomplete()); 236 return hasBaseScript() && baseScript()->hasBytecode(); 237 } 238 239 bool isGhost() const { return flags().isGhost(); } 240 241 // Arrow functions store their lexical new.target in the first extended slot. 242 bool isArrow() const { return flags().isArrow(); } 243 // Every class-constructor is also a method. 244 bool isMethod() const { return flags().isMethod(); } 245 bool isClassConstructor() const { return flags().isClassConstructor(); } 246 247 bool isGetter() const { return flags().isGetter(); } 248 bool isSetter() const { return flags().isSetter(); } 249 250 bool isAccessorWithLazyName() const { 251 return flags().isAccessorWithLazyName(); 252 } 253 254 bool allowSuperProperty() const { return flags().allowSuperProperty(); } 255 256 bool hasResolvedLength() const { return flags().hasResolvedLength(); } 257 bool hasResolvedName() const { return flags().hasResolvedName(); } 258 259 bool isSelfHostedOrIntrinsic() const { 260 return flags().isSelfHostedOrIntrinsic(); 261 } 262 bool isSelfHostedBuiltin() const { return flags().isSelfHostedBuiltin(); } 263 264 bool isIntrinsic() const { return flags().isIntrinsic(); } 265 266 bool hasJitScript() const { 267 if (!hasBaseScript()) { 268 return false; 269 } 270 271 return baseScript()->hasJitScript(); 272 } 273 274 /* Compound attributes: */ 275 bool isBuiltin() const { return isBuiltinNative() || isSelfHostedBuiltin(); } 276 277 bool isNamedLambda() const { 278 return flags().isNamedLambda(maybePartialDisplayAtom() != nullptr); 279 } 280 281 bool hasLexicalThis() const { return isArrow(); } 282 283 bool isBuiltinFunctionConstructor(); 284 bool needsPrototypeProperty(); 285 286 // Returns true if this function must have a non-configurable .prototype data 287 // property. This is used to ensure looking up .prototype elsewhere will have 288 // no side-effects. 289 bool hasNonConfigurablePrototypeDataProperty(); 290 291 // Returns true if |new Fun()| should not allocate a new object caller-side 292 // but pass the uninitialized-lexical MagicValue and rely on the callee to 293 // construct its own |this| object. 294 bool constructorNeedsUninitializedThis() const { 295 MOZ_ASSERT(isConstructor()); 296 MOZ_ASSERT(isInterpreted()); 297 return isDerivedClassConstructor(); 298 } 299 300 /* Returns the strictness of this function, which must be interpreted. */ 301 bool strict() const { return baseScript()->strict(); } 302 303 void setFlags(FunctionFlags flags) { setFlags(flags.toRaw()); } 304 void setFlags(uint16_t flags) { 305 uint32_t flagsAndArgCount = flagsAndArgCountRaw(); 306 flagsAndArgCount &= ~FlagsMask; 307 flagsAndArgCount |= flags; 308 setReservedSlotPrivateUint32Unbarriered(FlagsAndArgCountSlot, 309 flagsAndArgCount); 310 } 311 312 // Make the function constructible. 313 void setIsConstructor() { setFlags(flags().setIsConstructor()); } 314 315 // Can be called multiple times by the parser. 316 void setArgCount(uint16_t nargs) { 317 uint32_t flagsAndArgCount = flagsAndArgCountRaw(); 318 flagsAndArgCount &= ~ArgCountMask; 319 flagsAndArgCount |= nargs << ArgCountShift; 320 setReservedSlotPrivateUint32Unbarriered(FlagsAndArgCountSlot, 321 flagsAndArgCount); 322 } 323 324 void setIsSelfHostedBuiltin() { setFlags(flags().setIsSelfHostedBuiltin()); } 325 void setIsIntrinsic() { setFlags(flags().setIsIntrinsic()); } 326 327 void setResolvedLength() { setFlags(flags().setResolvedLength()); } 328 void setResolvedName() { setFlags(flags().setResolvedName()); } 329 330 static inline bool getUnresolvedLength(JSContext* cx, js::HandleFunction fun, 331 uint16_t* length); 332 333 // Returns the function's unresolved name. 334 // Returns an empty string if the function doesn't have name. 335 // Returns nullptr when OOM happens. 336 inline JSAtom* getUnresolvedName(JSContext* cx); 337 338 // Returns the function's unresolved name. 339 // Returns an empty string if the function doesn't have name. 340 inline JSAtom* infallibleGetUnresolvedName(JSContext* cx); 341 342 // Returns the name of an accessor function with lazy name. 343 JSAtom* getAccessorNameForLazy(JSContext* cx); 344 345 // Returns the function's name expclitly specified as syntax, or 346 // passed when creating a native function. 347 // 348 // Returns true and *name!=nullptr if the function has an explicit name. 349 // Returns true and *name==nullptr if the function doesn't have an explicit 350 // name. 351 // Returns false if OOM happens. 352 bool getExplicitName(JSContext* cx, JS::MutableHandle<JSAtom*> name); 353 354 // Almost same as getExplicitName. 355 // 356 // Returns non-nullptr if the function has an explicit name. 357 // Returns nullptr if the function doesn't have an explicit name. 358 // 359 // If this function has lazy name, this returns partial name, such as the 360 // function name without "get " or "set " prefix. 361 JSAtom* maybePartialExplicitName() const { 362 return (hasInferredName() || hasGuessedAtom()) ? nullptr : rawAtom(); 363 } 364 365 // Same as maybePartialExplicitName, except for asserting this function 366 // doesn't have lazy name. 367 // 368 // This can be used e.g. when this function is known to be scripted. 369 JSAtom* fullExplicitName() const { 370 MOZ_ASSERT(!isAccessorWithLazyName()); 371 return (hasInferredName() || hasGuessedAtom()) ? nullptr : rawAtom(); 372 } 373 374 JSAtom* fullExplicitOrInferredName() const { 375 MOZ_ASSERT(!isAccessorWithLazyName()); 376 return hasGuessedAtom() ? nullptr : rawAtom(); 377 } 378 379 void initAtom(JSAtom* atom) { 380 MOZ_ASSERT_IF(atom, js::AtomIsMarked(zone(), atom)); 381 MOZ_ASSERT(getFixedSlot(AtomSlot).isUndefined()); 382 if (atom) { 383 initFixedSlot(AtomSlot, JS::StringValue(atom)); 384 } 385 } 386 387 void setAtom(JSAtom* atom) { 388 MOZ_ASSERT_IF(atom, js::AtomIsMarked(zone(), atom)); 389 setFixedSlot(AtomSlot, atom ? JS::StringValue(atom) : JS::UndefinedValue()); 390 } 391 392 // Returns the function's name which can be used for informative purpose. 393 // 394 // Returns true and *name!=nullptr if the function has a name. 395 // Returns true and *name==nullptr if the function doesn't have a name. 396 // Returns false if OOM happens. 397 bool getDisplayAtom(JSContext* cx, JS::MutableHandle<JSAtom*> name); 398 399 // Almost same as getDisplayAtom. 400 // 401 // Returns non-nullptr if the function has a name. 402 // Returns nullptr if the function doesn't have a name. 403 // 404 // If this function has lazy name, this returns partial name, such as the 405 // function name without "get " or "set " prefix. 406 JSAtom* maybePartialDisplayAtom() const { return rawAtom(); } 407 408 // Same as maybePartialDisplayAtom, except for asserting this function 409 // doesn't have lazy name. 410 // 411 // This can be used e.g. when this function is known to be scripted. 412 JSAtom* fullDisplayAtom() const { 413 MOZ_ASSERT(!isAccessorWithLazyName()); 414 return rawAtom(); 415 } 416 417 JSAtom* rawAtom() const { 418 JS::Value value = getFixedSlot(AtomSlot); 419 return value.isUndefined() ? nullptr : &value.toString()->asAtom(); 420 } 421 422 void setInferredName(JSAtom* atom) { 423 MOZ_ASSERT(!rawAtom()); 424 MOZ_ASSERT(atom); 425 MOZ_ASSERT(!hasGuessedAtom()); 426 setAtom(atom); 427 setFlags(flags().setInferredName()); 428 } 429 JSAtom* inferredName() const { 430 MOZ_ASSERT(hasInferredName()); 431 MOZ_ASSERT(rawAtom()); 432 return rawAtom(); 433 } 434 435 void setGuessedAtom(JSAtom* atom) { 436 MOZ_ASSERT(!rawAtom()); 437 MOZ_ASSERT(atom); 438 MOZ_ASSERT(!hasInferredName()); 439 MOZ_ASSERT(!hasGuessedAtom()); 440 setAtom(atom); 441 setFlags(flags().setGuessedAtom()); 442 } 443 444 /* uint16_t representation bounds number of call object dynamic slots. */ 445 enum { MAX_ARGS_AND_VARS = 2 * ((1U << 16) - 1) }; 446 447 /* 448 * For an interpreted function, accessors for the initial scope object of 449 * activations (stack frames) of the function. 450 */ 451 JSObject* environment() const { 452 MOZ_ASSERT(isInterpreted()); 453 return getFixedSlot(NativeFuncOrInterpretedEnvSlot).toObjectOrNull(); 454 } 455 456 void initEnvironment(JSObject* obj) { 457 MOZ_ASSERT(isInterpreted()); 458 initFixedSlot(NativeFuncOrInterpretedEnvSlot, JS::ObjectOrNullValue(obj)); 459 } 460 461 public: 462 static constexpr size_t offsetOfFlagsAndArgCount() { 463 return getFixedSlotOffset(FlagsAndArgCountSlot); 464 } 465 static size_t offsetOfEnvironment() { return offsetOfNativeOrEnv(); } 466 static size_t offsetOfAtom() { return getFixedSlotOffset(AtomSlot); } 467 468 static bool delazifyLazilyInterpretedFunction(JSContext* cx, 469 js::HandleFunction fun); 470 static bool delazifySelfHostedLazyFunction(JSContext* cx, 471 js::HandleFunction fun); 472 void maybeRelazify(JSRuntime* rt); 473 474 // Function Scripts 475 // 476 // Interpreted functions have either a BaseScript or a SelfHostedLazyScript. A 477 // BaseScript may either be lazy or non-lazy (hasBytecode()). Methods may 478 // return a JSScript* if underlying BaseScript is known to have bytecode. 479 // 480 // There are several methods to get the script of an interpreted function: 481 // 482 // - For all interpreted functions, getOrCreateScript() will get the 483 // JSScript, delazifying the function if necessary. This is the safest to 484 // use, but has extra checks, requires a cx and may trigger a GC. 485 // 486 // - For functions known to have a JSScript, nonLazyScript() will get it. 487 488 static JSScript* getOrCreateScript(JSContext* cx, js::HandleFunction fun) { 489 MOZ_ASSERT(fun->isInterpreted()); 490 MOZ_ASSERT(cx); 491 492 if (fun->hasSelfHostedLazyScript()) { 493 if (!delazifySelfHostedLazyFunction(cx, fun)) { 494 return nullptr; 495 } 496 return fun->nonLazyScript(); 497 } 498 499 MOZ_ASSERT(fun->hasBaseScript()); 500 501 if (!fun->baseScript()->hasBytecode()) { 502 if (!delazifyLazilyInterpretedFunction(cx, fun)) { 503 return nullptr; 504 } 505 } 506 return fun->nonLazyScript(); 507 } 508 509 // If this is a scripted function, returns its canonical function (the 510 // original function allocated by the frontend). Note that lazy self-hosted 511 // builtins don't have a lazy script so in that case we also return nullptr. 512 JSFunction* maybeCanonicalFunction() const { 513 if (hasBaseScript()) { 514 return baseScript()->function(); 515 } 516 return nullptr; 517 } 518 519 private: 520 void* nativeJitInfoOrInterpretedScript() const { 521 return getFixedSlot(NativeJitInfoOrInterpretedScriptSlot).toPrivate(); 522 } 523 void setNativeJitInfoOrInterpretedScript(void* ptr) { 524 // This always stores a PrivateValue and so doesn't require a barrier. 525 setReservedSlotPrivateUnbarriered(NativeJitInfoOrInterpretedScriptSlot, 526 ptr); 527 } 528 529 public: 530 // The default state of a JSFunction that is not ready for execution. If 531 // observed outside initialization, this is the result of failure during 532 // bytecode compilation. 533 // 534 // A BaseScript is fully initialized before u.script.s.script_ is initialized 535 // with a reference to it. 536 bool isIncomplete() const { 537 return isInterpreted() && !nativeJitInfoOrInterpretedScript(); 538 } 539 540 JSScript* nonLazyScript() const { 541 MOZ_ASSERT(hasBytecode()); 542 return static_cast<JSScript*>(baseScript()); 543 } 544 545 js::SelfHostedLazyScript* selfHostedLazyScript() const { 546 MOZ_ASSERT(hasSelfHostedLazyScript()); 547 return static_cast<js::SelfHostedLazyScript*>( 548 nativeJitInfoOrInterpretedScript()); 549 } 550 551 // Access fields defined on both lazy and non-lazy scripts. 552 js::BaseScript* baseScript() const { 553 MOZ_ASSERT(hasBaseScript()); 554 return static_cast<JSScript*>(nativeJitInfoOrInterpretedScript()); 555 } 556 557 static inline bool getLength(JSContext* cx, js::HandleFunction fun, 558 uint16_t* length); 559 560 js::Scope* enclosingScope() const { return baseScript()->enclosingScope(); } 561 562 void setEnclosingLazyScript(js::BaseScript* enclosingScript) { 563 baseScript()->setEnclosingScript(enclosingScript); 564 } 565 566 js::GeneratorKind generatorKind() const { 567 if (hasBaseScript()) { 568 return baseScript()->generatorKind(); 569 } 570 if (hasSelfHostedLazyScript()) { 571 return clonedSelfHostedGeneratorKind(); 572 } 573 return js::GeneratorKind::NotGenerator; 574 } 575 576 js::GeneratorKind clonedSelfHostedGeneratorKind() const; 577 578 bool isGenerator() const { 579 return generatorKind() == js::GeneratorKind::Generator; 580 } 581 582 js::FunctionAsyncKind asyncKind() const { 583 if (hasBaseScript()) { 584 return baseScript()->asyncKind(); 585 } 586 return js::FunctionAsyncKind::SyncFunction; 587 } 588 589 bool isAsync() const { 590 return asyncKind() == js::FunctionAsyncKind::AsyncFunction; 591 } 592 593 bool isGeneratorOrAsync() const { return isGenerator() || isAsync(); } 594 595 void initScript(js::BaseScript* script) { 596 MOZ_ASSERT_IF(script, realm() == script->realm()); 597 MOZ_ASSERT(isInterpreted()); 598 MOZ_ASSERT_IF(hasBaseScript(), 599 !baseScript()); // No write barrier required. 600 setNativeJitInfoOrInterpretedScript(script); 601 } 602 603 void initSelfHostedLazyScript(js::SelfHostedLazyScript* lazy) { 604 MOZ_ASSERT(isSelfHostedBuiltin()); 605 MOZ_ASSERT(isInterpreted()); 606 if (hasBaseScript()) { 607 js::gc::PreWriteBarrier(baseScript()); 608 } 609 FunctionFlags f = flags(); 610 f.clearBaseScript(); 611 f.setSelfHostedLazy(); 612 setFlags(f); 613 setNativeJitInfoOrInterpretedScript(lazy); 614 MOZ_ASSERT(hasSelfHostedLazyScript()); 615 } 616 617 void clearSelfHostedLazyScript() { 618 MOZ_ASSERT(isSelfHostedBuiltin()); 619 MOZ_ASSERT(isInterpreted()); 620 MOZ_ASSERT(!hasBaseScript()); // No write barrier required. 621 FunctionFlags f = flags(); 622 f.clearSelfHostedLazy(); 623 f.setBaseScript(); 624 setFlags(f); 625 setNativeJitInfoOrInterpretedScript(nullptr); 626 MOZ_ASSERT(isIncomplete()); 627 } 628 629 JSNative native() const { 630 MOZ_ASSERT(isNativeFun()); 631 return nativeUnchecked(); 632 } 633 JSNative nativeUnchecked() const { 634 // Can be called by Ion off-main thread. 635 JS::Value value = getFixedSlot(NativeFuncOrInterpretedEnvSlot); 636 return reinterpret_cast<JSNative>(value.toPrivate()); 637 } 638 639 JSNative maybeNative() const { return isInterpreted() ? nullptr : native(); } 640 641 void initNative(js::Native native, const JSJitInfo* jitInfo) { 642 MOZ_ASSERT(isNativeFun()); 643 MOZ_ASSERT_IF(jitInfo, isBuiltinNative()); 644 MOZ_ASSERT(native); 645 initFixedSlot(NativeFuncOrInterpretedEnvSlot, 646 JS::PrivateValue(reinterpret_cast<void*>(native))); 647 setNativeJitInfoOrInterpretedScript(const_cast<JSJitInfo*>(jitInfo)); 648 } 649 bool hasJitInfo() const { 650 return flags().canHaveJitInfo() && jitInfoUnchecked(); 651 } 652 const JSJitInfo* jitInfo() const { 653 MOZ_ASSERT(hasJitInfo()); 654 return jitInfoUnchecked(); 655 } 656 const JSJitInfo* jitInfoUnchecked() const { 657 // Can be called by Ion off-main thread. 658 return static_cast<const JSJitInfo*>(nativeJitInfoOrInterpretedScript()); 659 } 660 void setJitInfo(const JSJitInfo* data) { 661 MOZ_ASSERT(isBuiltinNative()); 662 MOZ_ASSERT(data); 663 setNativeJitInfoOrInterpretedScript(const_cast<JSJitInfo*>(data)); 664 } 665 666 void setTrampolineNativeJitEntry(void** entry) { 667 MOZ_ASSERT(*entry); 668 MOZ_ASSERT(isBuiltinNative()); 669 MOZ_ASSERT(!hasJitEntry()); 670 MOZ_ASSERT(!hasJitInfo(), "shouldn't clobber JSJitInfo"); 671 setFlags(flags().setNativeJitEntry()); 672 setNativeJitInfoOrInterpretedScript(entry); 673 MOZ_ASSERT(isNativeWithJitEntry()); 674 } 675 void** nativeJitEntry() const { 676 MOZ_ASSERT(isNativeWithJitEntry()); 677 return static_cast<void**>(nativeJitInfoOrInterpretedScript()); 678 } 679 680 // wasm functions are always natives and either: 681 // - store a function-index in u.n.extra and can only be called through the 682 // fun->native() entry point from C++. 683 // - store a jit-entry code pointer in u.n.extra and can be called by jit 684 // code directly. C++ callers can still use the fun->native() entry point 685 // (computing the function index from the jit-entry point). 686 void initWasm(uint32_t funcIndex, js::wasm::Instance* instance, 687 const js::wasm::SuperTypeVector* superTypeVector, 688 void* uncheckedCallEntry); 689 void initWasmWithJitEntry(void** entry, js::wasm::Instance* instance, 690 const js::wasm::SuperTypeVector* superTypeVector, 691 void* uncheckedCallEntry); 692 693 void** wasmJitEntry() const { 694 MOZ_ASSERT(isWasmWithJitEntry()); 695 return nativeJitEntry(); 696 } 697 inline js::wasm::Instance& wasmInstance() const; 698 uint32_t wasmFuncIndex() const; 699 void* wasmUncheckedCallEntry() const; 700 void* wasmCheckedCallEntry() const; 701 inline js::wasm::SuperTypeVector& wasmSuperTypeVector() const; 702 inline const js::wasm::TypeDef* wasmTypeDef() const; 703 704 bool isDerivedClassConstructor() const; 705 bool isSyntheticFunction() const; 706 707 static unsigned offsetOfNativeOrEnv() { 708 return getFixedSlotOffset(NativeFuncOrInterpretedEnvSlot); 709 } 710 static unsigned offsetOfJitInfoOrScript() { 711 return getFixedSlotOffset(NativeJitInfoOrInterpretedScriptSlot); 712 } 713 714 inline void trace(JSTracer* trc); 715 716 public: 717 inline bool isExtended() const { 718 bool extended = flags().isExtended(); 719 MOZ_ASSERT_IF(isTenured(), 720 extended == (asTenured().getAllocKind() == 721 js::gc::AllocKind::FUNCTION_EXTENDED)); 722 return extended; 723 } 724 725 /* 726 * Accessors for data stored in extended functions. Use setExtendedSlot if the 727 * function has already been initialized. Otherwise use initExtendedSlot. 728 */ 729 inline void initExtendedSlot(uint32_t slot, const js::Value& val); 730 inline void setExtendedSlot(uint32_t slot, const js::Value& val); 731 inline const js::Value& getExtendedSlot(uint32_t slot) const; 732 733 /* GC support. */ 734 js::gc::AllocKind getAllocKind() const { 735 static_assert( 736 js::gc::AllocKind::FUNCTION != js::gc::AllocKind::FUNCTION_EXTENDED, 737 "extended/non-extended AllocKinds have to be different " 738 "for getAllocKind() to have a reason to exist"); 739 740 js::gc::AllocKind kind = js::gc::AllocKind::FUNCTION; 741 if (isExtended()) { 742 kind = js::gc::AllocKind::FUNCTION_EXTENDED; 743 } 744 MOZ_ASSERT_IF(isTenured(), kind == asTenured().getAllocKind()); 745 return kind; 746 } 747 748 // If we're constructing with this function, choose an appropriate 749 // allocKind. 750 static bool getAllocKindForThis(JSContext* cx, js::HandleFunction func, 751 js::gc::AllocKind& allocKind); 752 753 #if defined(DEBUG) || defined(JS_JITSPEW) 754 void dumpOwnFields(js::JSONPrinter& json) const; 755 void dumpOwnStringContent(js::GenericPrinter& out) const; 756 #endif 757 }; 758 759 static_assert(sizeof(JSFunction) == sizeof(JS::shadow::Function), 760 "shadow interface must match actual interface"); 761 762 static_assert(unsigned(JSFunction::FlagsAndArgCountSlot) == 763 unsigned(JS::shadow::Function::FlagsAndArgCountSlot)); 764 static_assert(unsigned(JSFunction::NativeFuncOrInterpretedEnvSlot) == 765 unsigned(JS::shadow::Function::NativeFuncOrInterpretedEnvSlot)); 766 static_assert( 767 unsigned(JSFunction::NativeJitInfoOrInterpretedScriptSlot) == 768 unsigned(JS::shadow::Function::NativeJitInfoOrInterpretedScriptSlot)); 769 static_assert(unsigned(JSFunction::AtomSlot) == 770 unsigned(JS::shadow::Function::AtomSlot)); 771 772 namespace js { 773 774 extern JSString* fun_toStringHelper(JSContext* cx, HandleObject obj, 775 bool isToSource); 776 777 extern bool Function(JSContext* cx, unsigned argc, Value* vp); 778 779 extern bool Generator(JSContext* cx, unsigned argc, Value* vp); 780 781 extern bool AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp); 782 783 extern bool AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp); 784 785 // If enclosingEnv is null, the function will have a null environment() 786 // (yes, null, not the global lexical environment). In all cases, the global 787 // will be used as the terminating environment. 788 789 extern JSFunction* NewFunctionWithProto( 790 JSContext* cx, JSNative native, unsigned nargs, FunctionFlags flags, 791 HandleObject enclosingEnv, Handle<JSAtom*> atom, HandleObject proto, 792 gc::AllocKind allocKind = gc::AllocKind::FUNCTION, 793 NewObjectKind newKind = GenericObject); 794 795 // Allocate a new function backed by a JSNative. Note that by default this 796 // creates a tenured object. 797 inline JSFunction* NewNativeFunction( 798 JSContext* cx, JSNative native, unsigned nargs, Handle<JSAtom*> atom, 799 gc::AllocKind allocKind = gc::AllocKind::FUNCTION, 800 NewObjectKind newKind = TenuredObject, 801 FunctionFlags flags = FunctionFlags::NATIVE_FUN) { 802 MOZ_ASSERT(native); 803 return NewFunctionWithProto(cx, native, nargs, flags, nullptr, atom, nullptr, 804 allocKind, newKind); 805 } 806 807 // Allocate a new constructor backed by a JSNative. Note that by default this 808 // creates a tenured object. 809 inline JSFunction* NewNativeConstructor( 810 JSContext* cx, JSNative native, unsigned nargs, Handle<JSAtom*> atom, 811 gc::AllocKind allocKind = gc::AllocKind::FUNCTION, 812 NewObjectKind newKind = TenuredObject, 813 FunctionFlags flags = FunctionFlags::NATIVE_CTOR) { 814 MOZ_ASSERT(native); 815 MOZ_ASSERT(flags.isNativeConstructor()); 816 return NewFunctionWithProto(cx, native, nargs, flags, nullptr, atom, nullptr, 817 allocKind, newKind); 818 } 819 820 // Determine which [[Prototype]] to use when creating a new function using the 821 // requested generator and async kind. 822 // 823 // This sets `proto` to `nullptr` for non-generator, synchronous functions to 824 // mean "the builtin %FunctionPrototype% in the current realm", the common case. 825 // 826 // We could set it to `cx->global()->getOrCreateFunctionPrototype()`, but 827 // nullptr gets a fast path in e.g. js::NewObjectWithClassProtoCommon. 828 extern bool GetFunctionPrototype(JSContext* cx, js::GeneratorKind generatorKind, 829 js::FunctionAsyncKind asyncKind, 830 js::MutableHandleObject proto); 831 832 extern JSAtom* IdToFunctionName( 833 JSContext* cx, HandleId id, 834 FunctionPrefixKind prefixKind = FunctionPrefixKind::None); 835 836 extern bool SetFunctionName(JSContext* cx, HandleFunction fun, HandleValue name, 837 FunctionPrefixKind prefixKind); 838 839 extern JSFunction* DefineFunction( 840 JSContext* cx, HandleObject obj, HandleId id, JSNative native, 841 unsigned nargs, unsigned flags, 842 gc::AllocKind allocKind = gc::AllocKind::FUNCTION); 843 844 extern bool fun_toString(JSContext* cx, unsigned argc, Value* vp); 845 846 extern void ThrowTypeErrorBehavior(JSContext* cx); 847 848 /* 849 * Function extended with reserved slots for use by various kinds of functions. 850 * Most functions do not have these extensions, but enough do that efficient 851 * storage is required (no malloc'ed reserved slots). 852 */ 853 class FunctionExtended : public JSFunction { 854 public: 855 enum { 856 FirstExtendedSlot = JSFunction::SlotCount, 857 SecondExtendedSlot, 858 ThirdExtendedSlot, 859 860 SlotCount 861 }; 862 863 static const uint32_t NUM_EXTENDED_SLOTS = 3; 864 865 static const uint32_t METHOD_HOMEOBJECT_SLOT = 0; 866 867 // wasm/asm.js exported functions store a code pointer to their direct entry 868 // point (see CodeRange::funcUncheckedCallEntry()) to support the call_ref 869 // instruction. 870 static const uint32_t WASM_FUNC_UNCHECKED_ENTRY_SLOT = 0; 871 872 // wasm/asm.js exported functions store the wasm::Instance pointer of their 873 // instance. 874 static const uint32_t WASM_INSTANCE_SLOT = 1; 875 876 // wasm/asm.js exported functions store a pointer to their 877 // wasm::SuperTypeVector for downcasting. 878 static const uint32_t WASM_STV_SLOT = 2; 879 880 // asm.js module functions store their WasmModuleObject in the first slot. 881 static const uint32_t ASMJS_MODULE_SLOT = 0; 882 883 // Async module callback handlers store their ModuleObject in the first slot. 884 static const uint32_t MODULE_SLOT = 0; 885 886 static inline size_t offsetOfExtendedSlot(uint32_t which) { 887 MOZ_ASSERT(which < NUM_EXTENDED_SLOTS); 888 return getFixedSlotOffset(FirstExtendedSlot + which); 889 } 890 static inline size_t offsetOfMethodHomeObjectSlot() { 891 return offsetOfExtendedSlot(METHOD_HOMEOBJECT_SLOT); 892 } 893 static inline size_t offsetOfWasmSTV() { 894 return offsetOfExtendedSlot(WASM_STV_SLOT); 895 } 896 897 private: 898 friend class JSFunction; 899 }; 900 901 extern JSFunction* CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, 902 HandleObject enclosingEnv, 903 HandleObject proto, 904 gc::Heap heap = gc::Heap::Default, 905 gc::AllocSite* site = nullptr); 906 907 extern JSFunction* CloneAsmJSModuleFunction(JSContext* cx, HandleFunction fun); 908 909 } // namespace js 910 911 template <> 912 inline bool JSObject::is<JSFunction>() const { 913 return getClass()->isJSFunction(); 914 } 915 916 inline void JSFunction::initExtendedSlot(uint32_t which, const js::Value& val) { 917 MOZ_ASSERT(isExtended()); 918 MOZ_ASSERT(which < js::FunctionExtended::NUM_EXTENDED_SLOTS); 919 MOZ_ASSERT(js::IsObjectValueInCompartment(val, compartment())); 920 initFixedSlot(js::FunctionExtended::FirstExtendedSlot + which, val); 921 } 922 923 inline void JSFunction::setExtendedSlot(uint32_t which, const js::Value& val) { 924 MOZ_ASSERT(isExtended()); 925 MOZ_ASSERT(which < js::FunctionExtended::NUM_EXTENDED_SLOTS); 926 MOZ_ASSERT(js::IsObjectValueInCompartment(val, compartment())); 927 setFixedSlot(js::FunctionExtended::FirstExtendedSlot + which, val); 928 } 929 930 inline const js::Value& JSFunction::getExtendedSlot(uint32_t which) const { 931 MOZ_ASSERT(isExtended()); 932 MOZ_ASSERT(which < js::FunctionExtended::NUM_EXTENDED_SLOTS); 933 return getFixedSlot(js::FunctionExtended::FirstExtendedSlot + which); 934 } 935 936 inline js::wasm::Instance& JSFunction::wasmInstance() const { 937 MOZ_ASSERT(isWasm() || isAsmJSNative()); 938 MOZ_ASSERT( 939 !getExtendedSlot(js::FunctionExtended::WASM_INSTANCE_SLOT).isUndefined()); 940 return *static_cast<js::wasm::Instance*>( 941 getExtendedSlot(js::FunctionExtended::WASM_INSTANCE_SLOT).toPrivate()); 942 } 943 944 inline js::wasm::SuperTypeVector& JSFunction::wasmSuperTypeVector() const { 945 MOZ_ASSERT(isWasm()); 946 MOZ_ASSERT( 947 !getExtendedSlot(js::FunctionExtended::WASM_STV_SLOT).isUndefined()); 948 return *static_cast<js::wasm::SuperTypeVector*>( 949 getExtendedSlot(js::FunctionExtended::WASM_STV_SLOT).toPrivate()); 950 } 951 952 inline const js::wasm::TypeDef* JSFunction::wasmTypeDef() const { 953 MOZ_ASSERT(isWasm()); 954 return wasmSuperTypeVector().typeDef(); 955 } 956 957 namespace js { 958 959 JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool isToSource); 960 961 /* 962 * Report an error that call.thisv is not compatible with the specified class, 963 * assuming that the method (clasp->name).prototype.<name of callee function> 964 * is what was called. 965 */ 966 extern void ReportIncompatibleMethod(JSContext* cx, const CallArgs& args, 967 const JSClass* clasp); 968 969 /* 970 * Report an error that call.thisv is not an acceptable this for the callee 971 * function. 972 */ 973 extern void ReportIncompatible(JSContext* cx, const CallArgs& args); 974 975 extern bool fun_apply(JSContext* cx, unsigned argc, Value* vp); 976 977 extern bool fun_call(JSContext* cx, unsigned argc, Value* vp); 978 979 } /* namespace js */ 980 981 #ifdef DEBUG 982 namespace JS { 983 namespace detail { 984 985 JS_PUBLIC_API void CheckIsValidConstructible(const Value& calleev); 986 987 } // namespace detail 988 } // namespace JS 989 #endif 990 991 #endif /* vm_JSFunction_h */