JSFunction.cpp (65542B)
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 /* 8 * JS function support. 9 */ 10 11 #include "vm/JSFunction-inl.h" 12 13 #include "mozilla/Maybe.h" 14 15 #include <string.h> 16 17 #include "jsapi.h" 18 #include "jstypes.h" 19 20 #include "builtin/Array.h" 21 #include "builtin/BigInt.h" 22 #include "builtin/Object.h" 23 #include "builtin/Symbol.h" 24 #include "frontend/BytecodeCompiler.h" // frontend::{CompileStandaloneFunction, CompileStandaloneGenerator, CompileStandaloneAsyncFunction, CompileStandaloneAsyncGenerator, DelazifyCanonicalScriptedFunction} 25 #include "frontend/FrontendContext.h" // AutoReportFrontendContext, ManualReportFrontendContext 26 #include "frontend/Stencil.h" // js::DumpFunctionFlagsItems 27 #include "jit/InlinableNatives.h" 28 #include "jit/Ion.h" 29 #include "js/CallNonGenericMethod.h" 30 #include "js/CompilationAndEvaluation.h" 31 #include "js/CompileOptions.h" 32 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* 33 #include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit 34 #include "js/Printer.h" // js::GenericPrinter 35 #include "js/PropertySpec.h" 36 #include "js/SourceText.h" 37 #include "js/StableStringChars.h" 38 #include "js/Wrapper.h" 39 #include "util/DifferentialTesting.h" 40 #include "util/StringBuilder.h" 41 #include "util/Text.h" 42 #include "vm/BooleanObject.h" 43 #include "vm/BoundFunctionObject.h" 44 #include "vm/Compartment.h" 45 #include "vm/FunctionFlags.h" // js::FunctionFlags 46 #include "vm/GeneratorAndAsyncKind.h" // js::GeneratorKind, js::FunctionAsyncKind 47 #include "vm/GlobalObject.h" 48 #include "vm/Interpreter.h" 49 #include "vm/JSAtomUtils.h" // ToAtom 50 #include "vm/JSContext.h" 51 #include "vm/JSObject.h" 52 #include "vm/JSONPrinter.h" // js::JSONPrinter 53 #include "vm/JSScript.h" 54 #include "vm/NumberObject.h" 55 #include "vm/PlainObject.h" // js::PlainObject 56 #include "vm/SelfHosting.h" 57 #include "vm/Shape.h" 58 #include "vm/StringObject.h" 59 #include "wasm/AsmJS.h" 60 #include "wasm/WasmCode.h" 61 #include "wasm/WasmInstance.h" 62 #include "vm/Interpreter-inl.h" 63 #include "vm/JSScript-inl.h" 64 65 using namespace js; 66 67 using mozilla::Maybe; 68 using mozilla::Some; 69 70 using JS::AutoStableStringChars; 71 using JS::CompileOptions; 72 using JS::SourceText; 73 74 static bool fun_enumerate(JSContext* cx, HandleObject obj) { 75 MOZ_ASSERT(obj->is<JSFunction>()); 76 77 RootedId id(cx); 78 bool found; 79 80 if (obj->as<JSFunction>().needsPrototypeProperty()) { 81 id = NameToId(cx->names().prototype); 82 if (!HasOwnProperty(cx, obj, id, &found)) { 83 return false; 84 } 85 } 86 87 if (!obj->as<JSFunction>().hasResolvedLength()) { 88 id = NameToId(cx->names().length); 89 if (!HasOwnProperty(cx, obj, id, &found)) { 90 return false; 91 } 92 } 93 94 if (!obj->as<JSFunction>().hasResolvedName()) { 95 id = NameToId(cx->names().name); 96 if (!HasOwnProperty(cx, obj, id, &found)) { 97 return false; 98 } 99 } 100 101 return true; 102 } 103 104 static bool IsFunction(HandleValue v) { 105 return v.isObject() && v.toObject().is<JSFunction>(); 106 } 107 108 static bool AdvanceToActiveCallLinear(JSContext* cx, 109 NonBuiltinScriptFrameIter& iter, 110 HandleFunction fun) { 111 MOZ_ASSERT(!fun->isBuiltin()); 112 113 for (; !iter.done(); ++iter) { 114 if (!iter.isFunctionFrame()) { 115 continue; 116 } 117 if (iter.matchCallee(cx, fun)) { 118 return true; 119 } 120 } 121 return false; 122 } 123 124 void js::ThrowTypeErrorBehavior(JSContext* cx) { 125 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 126 JSMSG_THROW_TYPE_ERROR); 127 } 128 129 static bool IsSloppyNormalFunction(JSFunction* fun) { 130 // FunctionDeclaration or FunctionExpression in sloppy mode. 131 if (fun->kind() == FunctionFlags::NormalFunction) { 132 if (fun->isBuiltin()) { 133 return false; 134 } 135 136 if (fun->isGenerator() || fun->isAsync()) { 137 return false; 138 } 139 140 MOZ_ASSERT(fun->isInterpreted()); 141 return !fun->strict(); 142 } 143 144 // Or asm.js function in sloppy mode. 145 if (fun->kind() == FunctionFlags::AsmJS) { 146 return !IsAsmJSStrictModeModuleOrFunction(fun); 147 } 148 149 return false; 150 } 151 152 // Beware: this function can be invoked on *any* function! That includes 153 // natives, strict mode functions, bound functions, arrow functions, 154 // self-hosted functions and constructors, asm.js functions, functions with 155 // destructuring arguments and/or a rest argument, and probably a few more I 156 // forgot. Turn back and save yourself while you still can. It's too late for 157 // me. 158 static bool ArgumentsRestrictions(JSContext* cx, HandleFunction fun) { 159 // Throw unless the function is a sloppy, normal function. 160 // TODO (bug 1057208): ensure semantics are correct for all possible 161 // pairings of callee/caller. 162 if (!IsSloppyNormalFunction(fun)) { 163 ThrowTypeErrorBehavior(cx); 164 return false; 165 } 166 167 return true; 168 } 169 170 static bool ArgumentsGetterImpl(JSContext* cx, const CallArgs& args) { 171 MOZ_ASSERT(IsFunction(args.thisv())); 172 173 RootedFunction fun(cx, &args.thisv().toObject().as<JSFunction>()); 174 if (!ArgumentsRestrictions(cx, fun)) { 175 return false; 176 } 177 178 // Function.arguments isn't standard (not even Annex B), so it isn't 179 // worth the effort to guarantee that we can always recover it from 180 // an Ion frame. Always return null for differential fuzzing. 181 if (js::SupportDifferentialTesting()) { 182 args.rval().setNull(); 183 return true; 184 } 185 186 // Return null if this function wasn't found on the stack. 187 NonBuiltinScriptFrameIter iter(cx); 188 if (!AdvanceToActiveCallLinear(cx, iter, fun)) { 189 args.rval().setNull(); 190 return true; 191 } 192 193 Rooted<ArgumentsObject*> argsobj(cx, 194 ArgumentsObject::createUnexpected(cx, iter)); 195 if (!argsobj) { 196 return false; 197 } 198 199 #ifndef JS_CODEGEN_NONE 200 // Disabling compiling of this script in IonMonkey. IonMonkey doesn't 201 // guarantee |f.arguments| can be fully recovered, so we try to mitigate 202 // observing this behavior by detecting its use early. 203 JSScript* script = iter.script(); 204 jit::ForbidCompilation(cx, script); 205 #endif 206 207 args.rval().setObject(*argsobj); 208 return true; 209 } 210 211 static bool ArgumentsGetter(JSContext* cx, unsigned argc, Value* vp) { 212 CallArgs args = CallArgsFromVp(argc, vp); 213 return CallNonGenericMethod<IsFunction, ArgumentsGetterImpl>(cx, args); 214 } 215 216 static bool ArgumentsSetterImpl(JSContext* cx, const CallArgs& args) { 217 MOZ_ASSERT(IsFunction(args.thisv())); 218 219 RootedFunction fun(cx, &args.thisv().toObject().as<JSFunction>()); 220 if (!ArgumentsRestrictions(cx, fun)) { 221 return false; 222 } 223 224 // If the function passes the gauntlet, return |undefined|. 225 args.rval().setUndefined(); 226 return true; 227 } 228 229 static bool ArgumentsSetter(JSContext* cx, unsigned argc, Value* vp) { 230 CallArgs args = CallArgsFromVp(argc, vp); 231 return CallNonGenericMethod<IsFunction, ArgumentsSetterImpl>(cx, args); 232 } 233 234 // Beware: this function can be invoked on *any* function! That includes 235 // natives, strict mode functions, bound functions, arrow functions, 236 // self-hosted functions and constructors, asm.js functions, functions with 237 // destructuring arguments and/or a rest argument, and probably a few more I 238 // forgot. Turn back and save yourself while you still can. It's too late for 239 // me. 240 static bool CallerRestrictions(JSContext* cx, HandleFunction fun) { 241 // Throw unless the function is a sloppy, normal function. 242 // TODO (bug 1057208): ensure semantics are correct for all possible 243 // pairings of callee/caller. 244 if (!IsSloppyNormalFunction(fun)) { 245 ThrowTypeErrorBehavior(cx); 246 return false; 247 } 248 249 return true; 250 } 251 252 static bool CallerGetterImpl(JSContext* cx, const CallArgs& args) { 253 MOZ_ASSERT(IsFunction(args.thisv())); 254 255 // Beware! This function can be invoked on *any* function! It can't 256 // assume it'll never be invoked on natives, strict mode functions, bound 257 // functions, or anything else that ordinarily has immutable .caller 258 // defined with [[ThrowTypeError]]. 259 RootedFunction fun(cx, &args.thisv().toObject().as<JSFunction>()); 260 if (!CallerRestrictions(cx, fun)) { 261 return false; 262 } 263 264 // Also return null if this function wasn't found on the stack. 265 NonBuiltinScriptFrameIter iter(cx); 266 if (!AdvanceToActiveCallLinear(cx, iter, fun)) { 267 args.rval().setNull(); 268 return true; 269 } 270 271 ++iter; 272 while (!iter.done() && iter.isEvalFrame()) { 273 ++iter; 274 } 275 276 if (iter.done() || !iter.isFunctionFrame()) { 277 args.rval().setNull(); 278 return true; 279 } 280 281 RootedObject caller(cx, iter.callee(cx)); 282 if (!cx->compartment()->wrap(cx, &caller)) { 283 return false; 284 } 285 286 // Censor the caller if we don't have full access to it. If we do, but the 287 // caller is a function with strict mode code, throw a TypeError per ES5. 288 // If we pass these checks, we can return the computed caller. 289 { 290 JSObject* callerObj = CheckedUnwrapStatic(caller); 291 if (!callerObj) { 292 args.rval().setNull(); 293 return true; 294 } 295 296 if (JS_IsDeadWrapper(callerObj)) { 297 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 298 JSMSG_DEAD_OBJECT); 299 return false; 300 } 301 302 JSFunction* callerFun = &callerObj->as<JSFunction>(); 303 MOZ_ASSERT(!callerFun->isBuiltin(), 304 "non-builtin iterator returned a builtin?"); 305 306 if (callerFun->strict() || callerFun->isAsync() || 307 callerFun->isGenerator()) { 308 args.rval().setNull(); 309 return true; 310 } 311 } 312 313 args.rval().setObject(*caller); 314 return true; 315 } 316 317 static bool CallerGetter(JSContext* cx, unsigned argc, Value* vp) { 318 CallArgs args = CallArgsFromVp(argc, vp); 319 return CallNonGenericMethod<IsFunction, CallerGetterImpl>(cx, args); 320 } 321 322 static bool CallerSetterImpl(JSContext* cx, const CallArgs& args) { 323 MOZ_ASSERT(IsFunction(args.thisv())); 324 325 // We just have to return |undefined|, but first we call CallerGetterImpl 326 // because we need the same strict-mode and security checks. 327 328 if (!CallerGetterImpl(cx, args)) { 329 return false; 330 } 331 332 args.rval().setUndefined(); 333 return true; 334 } 335 336 static bool CallerSetter(JSContext* cx, unsigned argc, Value* vp) { 337 CallArgs args = CallArgsFromVp(argc, vp); 338 return CallNonGenericMethod<IsFunction, CallerSetterImpl>(cx, args); 339 } 340 341 static const JSPropertySpec function_properties[] = { 342 JS_PSGS("arguments", ArgumentsGetter, ArgumentsSetter, 0), 343 JS_PSGS("caller", CallerGetter, CallerSetter, 0), 344 JS_PS_END, 345 }; 346 347 static bool ResolveInterpretedFunctionPrototype(JSContext* cx, 348 HandleFunction fun, 349 HandleId id) { 350 MOZ_ASSERT(fun->isInterpreted() || fun->isAsmJSNative()); 351 MOZ_ASSERT(id == NameToId(cx->names().prototype)); 352 353 // Assert that fun is not a compiler-created function object, which 354 // must never leak to script or embedding code and then be mutated. 355 // Also assert that fun is not bound, per the ES5 15.3.4.5 ref above. 356 MOZ_ASSERT(!IsInternalFunctionObject(*fun)); 357 358 // Make the prototype object an instance of Object with the same parent as 359 // the function object itself, unless the function is an ES6 generator. In 360 // that case, per the 15 July 2013 ES6 draft, section 15.19.3, its parent is 361 // the GeneratorObjectPrototype singleton. 362 bool isGenerator = fun->isGenerator(); 363 Rooted<GlobalObject*> global(cx, &fun->global()); 364 RootedObject objProto(cx); 365 if (isGenerator && fun->isAsync()) { 366 objProto = GlobalObject::getOrCreateAsyncGeneratorPrototype(cx, global); 367 } else if (isGenerator) { 368 objProto = GlobalObject::getOrCreateGeneratorObjectPrototype(cx, global); 369 } else { 370 objProto = &global->getObjectPrototype(); 371 } 372 if (!objProto) { 373 return false; 374 } 375 376 Rooted<PlainObject*> proto( 377 cx, NewPlainObjectWithProto(cx, objProto, TenuredObject)); 378 if (!proto) { 379 return false; 380 } 381 382 // Per ES5 13.2 the prototype's .constructor property is configurable, 383 // non-enumerable, and writable. However, per the 15 July 2013 ES6 draft, 384 // section 15.19.3, the .prototype of a generator function does not link 385 // back with a .constructor. 386 if (!isGenerator) { 387 RootedValue objVal(cx, ObjectValue(*fun)); 388 if (!DefineDataProperty(cx, proto, cx->names().constructor, objVal, 0)) { 389 return false; 390 } 391 } 392 393 // Per ES5 15.3.5.2 a user-defined function's .prototype property is 394 // initially non-configurable, non-enumerable, and writable. 395 RootedValue protoVal(cx, ObjectValue(*proto)); 396 return DefineDataProperty(cx, fun, id, protoVal, 397 JSPROP_PERMANENT | JSPROP_RESOLVING); 398 } 399 400 bool JSFunction::needsPrototypeProperty() { 401 /* 402 * Built-in functions do not have a .prototype property per ECMA-262, 403 * or (Object.prototype, Function.prototype, etc.) have that property 404 * created eagerly. 405 * 406 * ES6 9.2.8 MakeConstructor defines the .prototype property on constructors. 407 * Generators are not constructors, but they have a .prototype property 408 * anyway, according to errata to ES6. See bug 1191486. 409 * 410 * Thus all of the following don't get a .prototype property: 411 * - Methods (that are not class-constructors or generators) 412 * - Arrow functions 413 * - Function.prototype 414 * - Async functions 415 */ 416 return !isBuiltin() && (isConstructor() || isGenerator()); 417 } 418 419 bool JSFunction::hasNonConfigurablePrototypeDataProperty() { 420 if (!isBuiltin()) { 421 return needsPrototypeProperty(); 422 } 423 424 if (isSelfHostedBuiltin()) { 425 // Self-hosted constructors have a non-configurable .prototype data 426 // property. 427 if (!isConstructor()) { 428 return false; 429 } 430 #ifdef DEBUG 431 PropertyName* prototypeName = 432 runtimeFromMainThread()->commonNames->prototype; 433 Maybe<PropertyInfo> prop = lookupPure(prototypeName); 434 MOZ_ASSERT(prop.isSome()); 435 MOZ_ASSERT(prop->isDataProperty()); 436 MOZ_ASSERT(!prop->configurable()); 437 #endif 438 return true; 439 } 440 441 if (!isConstructor()) { 442 // We probably don't have a .prototype property. Avoid the lookup below. 443 return false; 444 } 445 446 PropertyName* prototypeName = runtimeFromMainThread()->commonNames->prototype; 447 Maybe<PropertyInfo> prop = lookupPure(prototypeName); 448 return prop.isSome() && prop->isDataProperty() && !prop->configurable(); 449 } 450 451 uint32_t JSFunction::wasmFuncIndex() const { 452 MOZ_ASSERT(isWasm() || isAsmJSNative()); 453 if (!isNativeWithJitEntry()) { 454 uintptr_t tagged = uintptr_t(nativeJitInfoOrInterpretedScript()); 455 MOZ_ASSERT(tagged & 1); 456 return tagged >> 1; 457 } 458 return wasmInstance().code().funcIndexFromJitEntry(wasmJitEntry()); 459 } 460 461 void JSFunction::initWasm(uint32_t funcIndex, wasm::Instance* instance, 462 const wasm::SuperTypeVector* superTypeVector, 463 void* uncheckedCallEntry) { 464 MOZ_ASSERT(isWasm() || isAsmJSNative()); 465 MOZ_ASSERT(!isWasmWithJitEntry()); 466 MOZ_ASSERT(!nativeJitInfoOrInterpretedScript()); 467 468 // Set the func index, see comment on the field for why we set the low bit. 469 uintptr_t tagged = (uintptr_t(funcIndex) << 1) | 1; 470 setNativeJitInfoOrInterpretedScript(reinterpret_cast<void*>(tagged)); 471 // Set the instance 472 setExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT, 473 JS::PrivateValue(instance)); 474 // Set the super type vector 475 setExtendedSlot(FunctionExtended::WASM_STV_SLOT, 476 JS::PrivateValue((void*)superTypeVector)); 477 // Set the unchecked entry slot 478 setExtendedSlot(FunctionExtended::WASM_FUNC_UNCHECKED_ENTRY_SLOT, 479 JS::PrivateValue(uncheckedCallEntry)); 480 } 481 482 void JSFunction::initWasmWithJitEntry( 483 void** entry, wasm::Instance* instance, 484 const wasm::SuperTypeVector* superTypeVector, void* uncheckedCallEntry) { 485 MOZ_ASSERT(*entry); 486 MOZ_ASSERT(isWasm()); 487 MOZ_ASSERT(!isWasmWithJitEntry()); 488 489 // Mark that we have a JIT entry, and initialize it 490 setFlags(flags().setNativeJitEntry()); 491 setNativeJitInfoOrInterpretedScript(entry); 492 493 // Set the instance 494 setExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT, 495 JS::PrivateValue(instance)); 496 // Set the super type vector 497 setExtendedSlot(FunctionExtended::WASM_STV_SLOT, 498 JS::PrivateValue((void*)superTypeVector)); 499 // Set the unchecked entry slot 500 setExtendedSlot(FunctionExtended::WASM_FUNC_UNCHECKED_ENTRY_SLOT, 501 JS::PrivateValue(uncheckedCallEntry)); 502 503 MOZ_ASSERT(isWasmWithJitEntry()); 504 } 505 506 void* JSFunction::wasmUncheckedCallEntry() const { 507 MOZ_ASSERT(isWasm()); 508 return getExtendedSlot(FunctionExtended::WASM_FUNC_UNCHECKED_ENTRY_SLOT) 509 .toPrivate(); 510 } 511 512 void* JSFunction::wasmCheckedCallEntry() const { 513 uint8_t* codeRangeBase; 514 const wasm::CodeRange* codeRange; 515 wasmInstance().code().funcCodeRange(wasmFuncIndex(), &codeRange, 516 &codeRangeBase); 517 return codeRangeBase + codeRange->funcCheckedCallEntry(); 518 } 519 520 static bool fun_mayResolve(const JSAtomState& names, jsid id, JSObject*) { 521 if (!id.isAtom()) { 522 return false; 523 } 524 525 JSAtom* atom = id.toAtom(); 526 return atom == names.prototype || atom == names.length || atom == names.name; 527 } 528 529 bool JSFunction::getExplicitName(JSContext* cx, 530 JS::MutableHandle<JSAtom*> name) { 531 if (isAccessorWithLazyName()) { 532 JSAtom* accessorName = getAccessorNameForLazy(cx); 533 if (!accessorName) { 534 return false; 535 } 536 537 name.set(accessorName); 538 return true; 539 } 540 541 name.set(maybePartialExplicitName()); 542 return true; 543 } 544 545 bool JSFunction::getDisplayAtom(JSContext* cx, 546 JS::MutableHandle<JSAtom*> name) { 547 if (isAccessorWithLazyName()) { 548 JSAtom* accessorName = getAccessorNameForLazy(cx); 549 if (!accessorName) { 550 return false; 551 } 552 553 name.set(accessorName); 554 return true; 555 } 556 557 name.set(maybePartialDisplayAtom()); 558 return true; 559 } 560 561 static JSAtom* NameToPrefixedFunctionName(JSContext* cx, JSString* nameStr, 562 FunctionPrefixKind prefixKind) { 563 MOZ_ASSERT(prefixKind != FunctionPrefixKind::None); 564 565 StringBuilder sb(cx); 566 if (prefixKind == FunctionPrefixKind::Get) { 567 if (!sb.append("get ")) { 568 return nullptr; 569 } 570 } else { 571 if (!sb.append("set ")) { 572 return nullptr; 573 } 574 } 575 if (!sb.append(nameStr)) { 576 return nullptr; 577 } 578 return sb.finishAtom(); 579 } 580 581 static JSAtom* NameToFunctionName(JSContext* cx, HandleValue name, 582 FunctionPrefixKind prefixKind) { 583 MOZ_ASSERT(name.isString() || name.isNumeric()); 584 585 if (prefixKind == FunctionPrefixKind::None) { 586 return ToAtom<CanGC>(cx, name); 587 } 588 589 JSString* nameStr = ToString(cx, name); 590 if (!nameStr) { 591 return nullptr; 592 } 593 594 return NameToPrefixedFunctionName(cx, nameStr, prefixKind); 595 } 596 597 JSAtom* JSFunction::getAccessorNameForLazy(JSContext* cx) { 598 MOZ_ASSERT(isAccessorWithLazyName()); 599 600 JSAtom* name = NameToPrefixedFunctionName( 601 cx, rawAtom(), 602 isGetter() ? FunctionPrefixKind::Get : FunctionPrefixKind::Set); 603 if (!name) { 604 return nullptr; 605 } 606 607 setAtom(name); 608 setFlags(flags().clearLazyAccessorName()); 609 return name; 610 } 611 612 static bool fun_resolve(JSContext* cx, HandleObject obj, HandleId id, 613 bool* resolvedp) { 614 if (!id.isAtom()) { 615 return true; 616 } 617 618 RootedFunction fun(cx, &obj->as<JSFunction>()); 619 620 if (id.isAtom(cx->names().prototype)) { 621 if (!fun->needsPrototypeProperty()) { 622 return true; 623 } 624 625 if (!ResolveInterpretedFunctionPrototype(cx, fun, id)) { 626 return false; 627 } 628 629 *resolvedp = true; 630 return true; 631 } 632 633 bool isLength = id.isAtom(cx->names().length); 634 if (isLength || id.isAtom(cx->names().name)) { 635 MOZ_ASSERT(!IsInternalFunctionObject(*obj)); 636 637 RootedValue v(cx); 638 639 // Since f.length and f.name are configurable, they could be resolved 640 // and then deleted: 641 // function f(x) {} 642 // assertEq(f.length, 1); 643 // delete f.length; 644 // assertEq(f.name, "f"); 645 // delete f.name; 646 // Afterwards, asking for f.length or f.name again will cause this 647 // resolve hook to run again. Defining the property again the second 648 // time through would be a bug. 649 // assertEq(f.length, 0); // gets Function.prototype.length! 650 // assertEq(f.name, ""); // gets Function.prototype.name! 651 // We use the RESOLVED_LENGTH and RESOLVED_NAME flags as a hack to prevent 652 // this bug. 653 if (isLength) { 654 if (fun->hasResolvedLength()) { 655 return true; 656 } 657 658 uint16_t len = 0; 659 if (!JSFunction::getUnresolvedLength(cx, fun, &len)) { 660 return false; 661 } 662 v.setInt32(len); 663 } else { 664 if (fun->hasResolvedName()) { 665 return true; 666 } 667 668 JSAtom* name = fun->getUnresolvedName(cx); 669 if (!name) { 670 return false; 671 } 672 v.setString(name); 673 } 674 675 if (!NativeDefineDataProperty(cx, fun, id, v, 676 JSPROP_READONLY | JSPROP_RESOLVING)) { 677 return false; 678 } 679 680 if (isLength) { 681 fun->setResolvedLength(); 682 } else { 683 fun->setResolvedName(); 684 } 685 686 *resolvedp = true; 687 return true; 688 } 689 690 return true; 691 } 692 693 /* ES6 (04-25-16) 19.2.3.6 Function.prototype [ @@hasInstance ] */ 694 static bool fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp) { 695 CallArgs args = CallArgsFromVp(argc, vp); 696 697 if (args.length() < 1) { 698 args.rval().setBoolean(false); 699 return true; 700 } 701 702 /* Step 1. */ 703 HandleValue func = args.thisv(); 704 705 // Primitives are non-callable and will always return false from 706 // OrdinaryHasInstance. 707 if (!func.isObject()) { 708 args.rval().setBoolean(false); 709 return true; 710 } 711 712 RootedObject obj(cx, &func.toObject()); 713 714 /* Step 2. */ 715 bool result; 716 if (!OrdinaryHasInstance(cx, obj, args[0], &result)) { 717 return false; 718 } 719 720 args.rval().setBoolean(result); 721 return true; 722 } 723 724 /* 725 * ES6 (4-25-16) 7.3.19 OrdinaryHasInstance 726 */ 727 bool JS::OrdinaryHasInstance(JSContext* cx, HandleObject objArg, HandleValue v, 728 bool* bp) { 729 AssertHeapIsIdle(); 730 cx->check(objArg, v); 731 732 RootedObject obj(cx, objArg); 733 734 /* Step 1. */ 735 if (!obj->isCallable()) { 736 *bp = false; 737 return true; 738 } 739 740 /* Step 2. */ 741 if (obj->is<BoundFunctionObject>()) { 742 /* Steps 2a-b. */ 743 AutoCheckRecursionLimit recursion(cx); 744 if (!recursion.check(cx)) { 745 return false; 746 } 747 obj = obj->as<BoundFunctionObject>().getTarget(); 748 return InstanceofOperator(cx, obj, v, bp); 749 } 750 751 /* Step 3. */ 752 if (!v.isObject()) { 753 *bp = false; 754 return true; 755 } 756 757 /* Step 4. */ 758 RootedValue pval(cx); 759 if (!GetProperty(cx, obj, obj, cx->names().prototype, &pval)) { 760 return false; 761 } 762 763 /* Step 5. */ 764 if (pval.isPrimitive()) { 765 /* 766 * Throw a runtime error if instanceof is called on a function that 767 * has a non-object as its .prototype value. 768 */ 769 RootedValue val(cx, ObjectValue(*obj)); 770 ReportValueError(cx, JSMSG_BAD_PROTOTYPE, -1, val, nullptr); 771 return false; 772 } 773 774 /* Step 6. */ 775 RootedObject pobj(cx, &pval.toObject()); 776 bool isPrototype; 777 if (!IsPrototypeOf(cx, pobj, &v.toObject(), &isPrototype)) { 778 return false; 779 } 780 *bp = isPrototype; 781 return true; 782 } 783 784 inline void JSFunction::trace(JSTracer* trc) { 785 // Functions can be be marked as interpreted despite having no script yet at 786 // some points when parsing, and can be lazy with no lazy script for 787 // self-hosted code. 788 MOZ_ASSERT(!getFixedSlot(NativeJitInfoOrInterpretedScriptSlot).isGCThing()); 789 if (isInterpreted() && hasBaseScript()) { 790 if (BaseScript* script = baseScript()) { 791 TraceManuallyBarrieredEdge(trc, &script, "JSFunction script"); 792 // Self-hosted scripts are shared with workers but are never relocated. 793 // Skip unnecessary writes to prevent the possible data race. 794 if (baseScript() != script) { 795 HeapSlot& slot = getFixedSlotRef(NativeJitInfoOrInterpretedScriptSlot); 796 slot.unbarrieredSet(JS::PrivateValue(script)); 797 } 798 } 799 } 800 // wasm/asm.js exported functions need to keep WasmInstantObject alive, 801 // access it via WASM_INSTANCE_SLOT extended slot. 802 if (isAsmJSNative() || isWasm()) { 803 const Value& v = getExtendedSlot(FunctionExtended::WASM_INSTANCE_SLOT); 804 if (!v.isUndefined()) { 805 auto* instance = static_cast<wasm::Instance*>(v.toPrivate()); 806 wasm::TraceInstanceEdge(trc, instance, "JSFunction instance"); 807 } 808 } 809 } 810 811 static void fun_trace(JSTracer* trc, JSObject* obj) { 812 obj->as<JSFunction>().trace(trc); 813 } 814 815 static JSObject* CreateFunctionConstructor(JSContext* cx, JSProtoKey key) { 816 RootedObject functionProto(cx, &cx->global()->getPrototype(JSProto_Function)); 817 818 return NewFunctionWithProto( 819 cx, Function, 1, FunctionFlags::NATIVE_CTOR, nullptr, 820 Handle<PropertyName*>(cx->names().Function), functionProto, 821 gc::AllocKind::FUNCTION, TenuredObject); 822 } 823 824 static bool FunctionPrototype(JSContext* cx, unsigned argc, Value* vp) { 825 CallArgs args = CallArgsFromVp(argc, vp); 826 args.rval().setUndefined(); 827 return true; 828 } 829 830 static JSObject* CreateFunctionPrototype(JSContext* cx, JSProtoKey key) { 831 RootedObject objectProto(cx, &cx->global()->getPrototype(JSProto_Object)); 832 833 return NewFunctionWithProto( 834 cx, FunctionPrototype, 0, FunctionFlags::NATIVE_FUN, nullptr, 835 Handle<PropertyName*>(cx->names().empty_), objectProto, 836 gc::AllocKind::FUNCTION, TenuredObject); 837 } 838 839 JSString* js::FunctionToStringCache::lookup(BaseScript* script) const { 840 for (size_t i = 0; i < NumEntries; i++) { 841 if (entries_[i].script == script) { 842 return entries_[i].string; 843 } 844 } 845 return nullptr; 846 } 847 848 void js::FunctionToStringCache::put(BaseScript* script, JSString* string) { 849 for (size_t i = NumEntries - 1; i > 0; i--) { 850 entries_[i] = entries_[i - 1]; 851 } 852 853 entries_[0].set(script, string); 854 } 855 856 JSString* js::FunctionToString(JSContext* cx, HandleFunction fun, 857 bool isToSource) { 858 if (IsAsmJSModule(fun)) { 859 return AsmJSModuleToString(cx, fun, isToSource); 860 } 861 if (IsAsmJSFunction(fun)) { 862 return AsmJSFunctionToString(cx, fun); 863 } 864 865 // Self-hosted built-ins should not expose their source code. 866 bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin(); 867 868 // If we're in toSource mode, put parentheses around lambda functions so 869 // that eval returns lambda, not function statement. 870 bool addParentheses = 871 haveSource && isToSource && (fun->isLambda() && !fun->isArrow()); 872 873 if (haveSource) { 874 if (!ScriptSource::loadSource(cx, fun->baseScript()->scriptSource(), 875 &haveSource)) { 876 return nullptr; 877 } 878 } 879 880 // Fast path for the common case, to avoid StringBuilder overhead. 881 if (!addParentheses && haveSource) { 882 FunctionToStringCache& cache = cx->zone()->functionToStringCache(); 883 if (JSString* str = cache.lookup(fun->baseScript())) { 884 return str; 885 } 886 887 BaseScript* script = fun->baseScript(); 888 size_t start = script->toStringStart(); 889 size_t end = script->toStringEnd(); 890 JSString* str = 891 (end - start <= ScriptSource::SourceDeflateLimit) 892 ? script->scriptSource()->substring(cx, start, end) 893 : script->scriptSource()->substringDontDeflate(cx, start, end); 894 if (!str) { 895 return nullptr; 896 } 897 898 cache.put(fun->baseScript(), str); 899 return str; 900 } 901 902 JSStringBuilder out(cx); 903 if (addParentheses) { 904 if (!out.append('(')) { 905 return nullptr; 906 } 907 } 908 909 if (haveSource) { 910 if (!fun->baseScript()->appendSourceDataForToString(cx, out)) { 911 return nullptr; 912 } 913 } else if (!isToSource) { 914 // For the toString() output the source representation must match 915 // NativeFunction when no source text is available. 916 // 917 // NativeFunction: 918 // function PropertyName[~Yield,~Await]opt ( 919 // FormalParameters[~Yield,~Await] ) { [native code] } 920 // 921 // Additionally, if |fun| is a well-known intrinsic object and is not 922 // identified as an anonymous function, the portion of the returned 923 // string that would be matched by IdentifierName must be the initial 924 // value of the name property of |fun|. 925 926 auto hasGetterOrSetterPrefix = [](JSAtom* name) { 927 auto hasGetterOrSetterPrefix = [](const auto* chars) { 928 return (chars[0] == 'g' || chars[0] == 's') && chars[1] == 'e' && 929 chars[2] == 't' && chars[3] == ' '; 930 }; 931 932 JS::AutoCheckCannotGC nogc; 933 return name->length() >= 4 && 934 (name->hasLatin1Chars() 935 ? hasGetterOrSetterPrefix(name->latin1Chars(nogc)) 936 : hasGetterOrSetterPrefix(name->twoByteChars(nogc))); 937 }; 938 939 if (!out.append("function")) { 940 return nullptr; 941 } 942 943 // We don't want to fully parse the function's name here because of 944 // performance reasons, so only append the name if we're confident it 945 // can be matched as the 'PropertyName' grammar production. 946 if (fun->maybePartialExplicitName() && 947 (fun->kind() == FunctionFlags::NormalFunction || 948 (fun->isBuiltinNative() && (fun->kind() == FunctionFlags::Getter || 949 fun->kind() == FunctionFlags::Setter)) || 950 fun->kind() == FunctionFlags::Wasm || 951 fun->kind() == FunctionFlags::ClassConstructor)) { 952 if (!out.append(' ')) { 953 return nullptr; 954 } 955 956 // Built-in getters or setters are classified as one of 957 // NormalFunction, Getter, or Setter. Strip any leading "get " or "set " 958 // if present. 959 JSAtom* name = fun->maybePartialExplicitName(); 960 size_t offset = hasGetterOrSetterPrefix(name) ? 4 : 0; 961 if (!out.appendSubstring(name, offset, name->length() - offset)) { 962 return nullptr; 963 } 964 } 965 966 if (!out.append("() {\n [native code]\n}")) { 967 return nullptr; 968 } 969 } else { 970 if (fun->isAsync()) { 971 if (!out.append("async ")) { 972 return nullptr; 973 } 974 } 975 976 if (!fun->isArrow()) { 977 if (!out.append("function")) { 978 return nullptr; 979 } 980 981 if (fun->isGenerator()) { 982 if (!out.append('*')) { 983 return nullptr; 984 } 985 } 986 } 987 988 JS::Rooted<JSAtom*> name(cx); 989 if (!fun->getExplicitName(cx, &name)) { 990 return nullptr; 991 } 992 993 if (name) { 994 if (!out.append(' ')) { 995 return nullptr; 996 } 997 if (!out.append(name)) { 998 return nullptr; 999 } 1000 } 1001 1002 if (!out.append("() {\n [native code]\n}")) { 1003 return nullptr; 1004 } 1005 } 1006 1007 if (addParentheses) { 1008 if (!out.append(')')) { 1009 return nullptr; 1010 } 1011 } 1012 1013 return out.finishString(); 1014 } 1015 1016 JSString* js::fun_toStringHelper(JSContext* cx, HandleObject obj, 1017 bool isToSource) { 1018 if (!obj->is<JSFunction>()) { 1019 if (JSFunToStringOp op = obj->getOpsFunToString()) { 1020 return op(cx, obj, isToSource); 1021 } 1022 1023 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 1024 JSMSG_INCOMPATIBLE_PROTO, "Function", "toString", 1025 "object"); 1026 return nullptr; 1027 } 1028 1029 return FunctionToString(cx, obj.as<JSFunction>(), isToSource); 1030 } 1031 1032 bool js::fun_toString(JSContext* cx, unsigned argc, Value* vp) { 1033 CallArgs args = CallArgsFromVp(argc, vp); 1034 MOZ_ASSERT(IsFunctionObject(args.calleev())); 1035 1036 RootedObject obj(cx, ToObject(cx, args.thisv())); 1037 if (!obj) { 1038 return false; 1039 } 1040 1041 JSString* str = fun_toStringHelper(cx, obj, /* isToSource = */ false); 1042 if (!str) { 1043 return false; 1044 } 1045 1046 args.rval().setString(str); 1047 return true; 1048 } 1049 1050 static bool fun_toSource(JSContext* cx, unsigned argc, Value* vp) { 1051 CallArgs args = CallArgsFromVp(argc, vp); 1052 MOZ_ASSERT(IsFunctionObject(args.calleev())); 1053 1054 RootedObject obj(cx, ToObject(cx, args.thisv())); 1055 if (!obj) { 1056 return false; 1057 } 1058 1059 RootedString str(cx); 1060 if (obj->isCallable()) { 1061 str = fun_toStringHelper(cx, obj, /* isToSource = */ true); 1062 } else { 1063 str = ObjectToSource(cx, obj); 1064 } 1065 if (!str) { 1066 return false; 1067 } 1068 1069 args.rval().setString(str); 1070 return true; 1071 } 1072 1073 bool js::fun_call(JSContext* cx, unsigned argc, Value* vp) { 1074 CallArgs args = CallArgsFromVp(argc, vp); 1075 1076 HandleValue func = args.thisv(); 1077 1078 // We don't need to do this -- Call would do it for us -- but the error 1079 // message is *much* better if we do this here. (Without this, 1080 // JSDVG_SEARCH_STACK tries to decompile |func| as if it were |this| in 1081 // the scripted caller's frame -- so for example 1082 // 1083 // Function.prototype.call.call({}); 1084 // 1085 // would identify |{}| as |this| as being the result of evaluating 1086 // |Function.prototype.call| and would conclude, "Function.prototype.call 1087 // is not a function". Grotesque.) 1088 if (!IsCallable(func)) { 1089 ReportIncompatibleMethod(cx, args, &FunctionClass); 1090 return false; 1091 } 1092 1093 size_t argCount = args.length(); 1094 if (argCount > 0) { 1095 argCount--; // strip off provided |this| 1096 } 1097 1098 InvokeArgs iargs(cx); 1099 if (!iargs.init(cx, argCount)) { 1100 return false; 1101 } 1102 1103 for (size_t i = 0; i < argCount; i++) { 1104 iargs[i].set(args[i + 1]); 1105 } 1106 1107 return Call(cx, func, args.get(0), iargs, args.rval(), CallReason::FunCall); 1108 } 1109 1110 // ES5 15.3.4.3 1111 bool js::fun_apply(JSContext* cx, unsigned argc, Value* vp) { 1112 CallArgs args = CallArgsFromVp(argc, vp); 1113 1114 // Step 1. 1115 // 1116 // Note that we must check callability here, not at actual call time, 1117 // because extracting argument values from the provided arraylike might 1118 // have side effects or throw an exception. 1119 HandleValue fval = args.thisv(); 1120 if (!IsCallable(fval)) { 1121 ReportIncompatibleMethod(cx, args, &FunctionClass); 1122 return false; 1123 } 1124 1125 // Step 2. 1126 if (args.length() < 2 || args[1].isNullOrUndefined()) { 1127 return fun_call(cx, (args.length() > 0) ? 1 : 0, vp); 1128 } 1129 1130 // Step 3. 1131 if (!args[1].isObject()) { 1132 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 1133 JSMSG_BAD_APPLY_ARGS, "apply"); 1134 return false; 1135 } 1136 1137 // Steps 4-5 (note erratum removing steps originally numbered 5 and 7 in 1138 // original version of ES5). 1139 RootedObject aobj(cx, &args[1].toObject()); 1140 uint64_t length; 1141 if (!GetLengthProperty(cx, aobj, &length)) { 1142 return false; 1143 } 1144 1145 // Step 6. 1146 InvokeArgs args2(cx); 1147 if (!args2.init(cx, length)) { 1148 return false; 1149 } 1150 1151 MOZ_ASSERT(length <= ARGS_LENGTH_MAX); 1152 1153 // Steps 7-8. 1154 if (!GetElements(cx, aobj, length, args2.array())) { 1155 return false; 1156 } 1157 1158 // Step 9. 1159 return Call(cx, fval, args[0], args2, args.rval(), CallReason::FunCall); 1160 } 1161 1162 static const JSFunctionSpec function_methods[] = { 1163 JS_FN("toSource", fun_toSource, 0, 0), 1164 JS_FN("toString", fun_toString, 0, 0), 1165 JS_FN("apply", fun_apply, 2, 0), 1166 JS_FN("call", fun_call, 1, 0), 1167 JS_INLINABLE_FN("bind", BoundFunctionObject::functionBind, 1, 0, 1168 FunctionBind), 1169 JS_SYM_FN(hasInstance, fun_symbolHasInstance, 1, 1170 JSPROP_READONLY | JSPROP_PERMANENT), 1171 JS_FS_END, 1172 }; 1173 1174 static const JSClassOps JSFunctionClassOps = { 1175 nullptr, // addProperty 1176 nullptr, // delProperty 1177 fun_enumerate, // enumerate 1178 nullptr, // newEnumerate 1179 fun_resolve, // resolve 1180 fun_mayResolve, // mayResolve 1181 nullptr, // finalize 1182 nullptr, // call 1183 nullptr, // construct 1184 fun_trace, // trace 1185 }; 1186 1187 static const ClassSpec JSFunctionClassSpec = { 1188 CreateFunctionConstructor, CreateFunctionPrototype, nullptr, nullptr, 1189 function_methods, function_properties, 1190 }; 1191 1192 const JSClass js::FunctionClass = { 1193 "Function", 1194 JSCLASS_HAS_CACHED_PROTO(JSProto_Function) | 1195 JSCLASS_HAS_RESERVED_SLOTS(JSFunction::SlotCount), 1196 &JSFunctionClassOps, 1197 &JSFunctionClassSpec, 1198 }; 1199 1200 const JSClass js::ExtendedFunctionClass = { 1201 "Function", 1202 JSCLASS_HAS_CACHED_PROTO(JSProto_Function) | 1203 JSCLASS_HAS_RESERVED_SLOTS(FunctionExtended::SlotCount), 1204 &JSFunctionClassOps, 1205 &JSFunctionClassSpec, 1206 }; 1207 1208 const JSClass* const js::FunctionClassPtr = &FunctionClass; 1209 const JSClass* const js::FunctionExtendedClassPtr = &ExtendedFunctionClass; 1210 1211 bool JSFunction::isDerivedClassConstructor() const { 1212 bool derived = hasBaseScript() && baseScript()->isDerivedClassConstructor(); 1213 MOZ_ASSERT_IF(derived, isClassConstructor()); 1214 return derived; 1215 } 1216 1217 bool JSFunction::isSyntheticFunction() const { 1218 bool synthetic = hasBaseScript() && baseScript()->isSyntheticFunction(); 1219 MOZ_ASSERT_IF(synthetic, isMethod()); 1220 return synthetic; 1221 } 1222 1223 /* static */ 1224 bool JSFunction::delazifyLazilyInterpretedFunction(JSContext* cx, 1225 HandleFunction fun) { 1226 MOZ_ASSERT(fun->hasBaseScript()); 1227 MOZ_ASSERT(cx->compartment() == fun->compartment()); 1228 1229 // The function must be same-compartment but might be cross-realm. Make sure 1230 // the script is created in the function's realm. 1231 AutoRealm ar(cx, fun); 1232 1233 Rooted<BaseScript*> lazy(cx, fun->baseScript()); 1234 RootedFunction canonicalFun(cx, lazy->function()); 1235 1236 // If this function is non-canonical, then use the canonical function first 1237 // to get the delazified script. This may result in calling this method 1238 // again on the canonical function. This ensures the canonical function is 1239 // always non-lazy if any of the clones are non-lazy. 1240 if (fun != canonicalFun) { 1241 JSScript* script = JSFunction::getOrCreateScript(cx, canonicalFun); 1242 if (!script) { 1243 return false; 1244 } 1245 1246 // Delazifying the canonical function should naturally make us non-lazy 1247 // because we share a BaseScript with the canonical function. 1248 MOZ_ASSERT(fun->hasBytecode()); 1249 return true; 1250 } 1251 1252 // Finally, compile the script if it really doesn't exist. 1253 AutoReportFrontendContext fc(cx); 1254 if (!frontend::DelazifyCanonicalScriptedFunction(cx, &fc, fun)) { 1255 // The frontend shouldn't fail after linking the function and the 1256 // non-lazy script together. 1257 MOZ_ASSERT(fun->baseScript() == lazy); 1258 MOZ_ASSERT(lazy->isReadyForDelazification()); 1259 return false; 1260 } 1261 1262 return true; 1263 } 1264 1265 /* static */ 1266 bool JSFunction::delazifySelfHostedLazyFunction(JSContext* cx, 1267 js::HandleFunction fun) { 1268 MOZ_ASSERT(cx->compartment() == fun->compartment()); 1269 1270 // The function must be same-compartment but might be cross-realm. Make sure 1271 // the script is created in the function's realm. 1272 AutoRealm ar(cx, fun); 1273 1274 /* Lazily cloned self-hosted script. */ 1275 MOZ_ASSERT(fun->isSelfHostedBuiltin()); 1276 Rooted<PropertyName*> funName(cx, GetClonedSelfHostedFunctionName(fun)); 1277 if (!funName) { 1278 return false; 1279 } 1280 return cx->runtime()->delazifySelfHostedFunction(cx, funName, fun); 1281 } 1282 1283 void JSFunction::maybeRelazify(JSRuntime* rt) { 1284 MOZ_ASSERT(!isIncomplete(), "Cannot relazify incomplete functions"); 1285 1286 // Don't relazify functions in compartments that are active. 1287 Realm* realm = this->realm(); 1288 if (!rt->allowRelazificationForTesting) { 1289 if (realm->compartment()->gcState.hasEnteredRealm) { 1290 return; 1291 } 1292 1293 MOZ_ASSERT(!realm->hasBeenEnteredIgnoringJit()); 1294 } 1295 1296 // Don't relazify if the realm is being debugged. The debugger side-tables 1297 // such as the set of active breakpoints require bytecode to exist. 1298 if (realm->isDebuggee()) { 1299 return; 1300 } 1301 1302 // Don't relazify if we are collecting coverage so that we do not lose count 1303 // information. 1304 if (coverage::IsLCovEnabled()) { 1305 return; 1306 } 1307 1308 // Check the script's eligibility. 1309 JSScript* script = nonLazyScript(); 1310 if (!script->allowRelazify()) { 1311 return; 1312 } 1313 MOZ_ASSERT(script->isRelazifiable()); 1314 1315 // There must not be any JIT code attached since the relazification process 1316 // does not know how to discard it. In general, the GC should discard most JIT 1317 // code before attempting relazification. 1318 if (script->hasJitScript()) { 1319 return; 1320 } 1321 1322 if (isSelfHostedBuiltin()) { 1323 gc::PreWriteBarrier(script); 1324 initSelfHostedLazyScript(&rt->selfHostedLazyScript.ref()); 1325 } else { 1326 script->relazify(rt); 1327 } 1328 } 1329 1330 js::GeneratorKind JSFunction::clonedSelfHostedGeneratorKind() const { 1331 MOZ_ASSERT(hasSelfHostedLazyScript()); 1332 1333 // This is a lazy clone of a self-hosted builtin. It has no BaseScript, and 1334 // `this->flags_` does not contain the generator kind. Consult the 1335 // implementation in the self-hosting realm, which has a BaseScript. 1336 MOZ_RELEASE_ASSERT(isExtended()); 1337 PropertyName* name = GetClonedSelfHostedFunctionName(this); 1338 return runtimeFromMainThread()->getSelfHostedFunctionGeneratorKind(name); 1339 } 1340 1341 // ES2018 draft rev 2aea8f3e617b49df06414eb062ab44fad87661d3 1342 // 19.2.1.1.1 CreateDynamicFunction( constructor, newTarget, kind, args ) 1343 static bool CreateDynamicFunction(JSContext* cx, const CallArgs& args, 1344 GeneratorKind generatorKind, 1345 FunctionAsyncKind asyncKind) { 1346 using namespace frontend; 1347 1348 // Steps 1-5. 1349 bool isGenerator = generatorKind == GeneratorKind::Generator; 1350 bool isAsync = asyncKind == FunctionAsyncKind::AsyncFunction; 1351 1352 RootedScript maybeScript(cx); 1353 const char* filename; 1354 uint32_t lineno; 1355 bool mutedErrors; 1356 uint32_t pcOffset; 1357 DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, 1358 &pcOffset, &mutedErrors); 1359 1360 const char* introductionType = "Function"; 1361 if (isAsync) { 1362 if (isGenerator) { 1363 introductionType = "AsyncGenerator"; 1364 } else { 1365 introductionType = "AsyncFunction"; 1366 } 1367 } else if (isGenerator) { 1368 introductionType = "GeneratorFunction"; 1369 } 1370 1371 const char* introducerFilename = filename; 1372 if (maybeScript && maybeScript->scriptSource()->introducerFilename()) { 1373 introducerFilename = maybeScript->scriptSource()->introducerFilename(); 1374 } 1375 1376 CompileOptions options(cx); 1377 options.setMutedErrors(mutedErrors) 1378 .setFileAndLine(filename, 1) 1379 .setNoScriptRval(false) 1380 .setIntroductionInfo(introducerFilename, introductionType, lineno, 1381 pcOffset) 1382 .setDeferDebugMetadata(); 1383 1384 JSStringBuilder sb(cx); 1385 1386 if (isAsync) { 1387 if (!sb.append("async ")) { 1388 return false; 1389 } 1390 } 1391 if (!sb.append("function")) { 1392 return false; 1393 } 1394 if (isGenerator) { 1395 if (!sb.append('*')) { 1396 return false; 1397 } 1398 } 1399 1400 if (!sb.append(" anonymous(")) { 1401 return false; 1402 } 1403 1404 JS::RootedVector<JSString*> parameterStrings(cx); 1405 JS::RootedVector<Value> parameterArgs(cx); 1406 if (args.length() > 1) { 1407 RootedString str(cx); 1408 1409 // Steps 10, 14.d. 1410 unsigned n = args.length() - 1; 1411 if (!parameterStrings.reserve(n) || !parameterArgs.reserve(n)) { 1412 return false; 1413 } 1414 1415 for (unsigned i = 0; i < n; i++) { 1416 if (!parameterArgs.append(args[i])) { 1417 return false; 1418 } 1419 1420 // Steps 14.a-b, 14.d.i-ii. 1421 str = ToString<CanGC>(cx, args[i]); 1422 if (!str) { 1423 return false; 1424 } 1425 1426 if (!parameterStrings.append(str)) { 1427 return false; 1428 } 1429 1430 // Steps 14.b, 14.d.iii. 1431 if (!sb.append(str)) { 1432 return false; 1433 } 1434 1435 if (i < args.length() - 2) { 1436 // Step 14.d.iii. 1437 if (!sb.append(',')) { 1438 return false; 1439 } 1440 } 1441 } 1442 } 1443 1444 if (!sb.append('\n')) { 1445 return false; 1446 } 1447 1448 // Remember the position of ")". 1449 Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length())); 1450 static_assert(FunctionConstructorMedialSigils[0] == ')'); 1451 1452 if (!sb.append(FunctionConstructorMedialSigils.data(), 1453 FunctionConstructorMedialSigils.length())) { 1454 return false; 1455 } 1456 1457 JS::RootedValue bodyArg(cx); 1458 RootedString bodyString(cx); 1459 if (args.length() > 0) { 1460 // Steps 13, 14.e, 15. 1461 bodyArg = args[args.length() - 1]; 1462 bodyString = ToString<CanGC>(cx, bodyArg); 1463 if (!bodyString || !sb.append(bodyString)) { 1464 return false; 1465 } 1466 } 1467 1468 if (!sb.append(FunctionConstructorFinalBrace.data(), 1469 FunctionConstructorFinalBrace.length())) { 1470 return false; 1471 } 1472 1473 // The parser only accepts two byte strings. 1474 if (!sb.ensureTwoByteChars()) { 1475 return false; 1476 } 1477 1478 RootedString functionText(cx, sb.finishString()); 1479 if (!functionText) { 1480 return false; 1481 } 1482 1483 // Block this call if security callbacks forbid it. 1484 bool canCompileStrings = cx->bypassCSPForDebugger; 1485 1486 if (!canCompileStrings && 1487 !cx->isRuntimeCodeGenEnabled(JS::RuntimeCode::JS, functionText, 1488 JS::CompilationType::Function, 1489 parameterStrings, bodyString, parameterArgs, 1490 bodyArg, &canCompileStrings)) { 1491 return false; 1492 } 1493 if (!canCompileStrings) { 1494 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 1495 JSMSG_CSP_BLOCKED_FUNCTION); 1496 return false; 1497 } 1498 1499 // Steps 7.a-b, 8.a-b, 9.a-b, 16-28. 1500 AutoStableStringChars linearChars(cx); 1501 if (!linearChars.initTwoByte(cx, functionText)) { 1502 return false; 1503 } 1504 1505 SourceText<char16_t> srcBuf; 1506 if (!srcBuf.initMaybeBorrowed(cx, linearChars)) { 1507 return false; 1508 } 1509 1510 FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Expression; 1511 1512 RootedFunction fun(cx); 1513 JSProtoKey protoKey; 1514 if (isAsync) { 1515 if (isGenerator) { 1516 fun = CompileStandaloneAsyncGenerator(cx, options, srcBuf, 1517 parameterListEnd, syntaxKind); 1518 protoKey = JSProto_AsyncGeneratorFunction; 1519 } else { 1520 fun = CompileStandaloneAsyncFunction(cx, options, srcBuf, 1521 parameterListEnd, syntaxKind); 1522 protoKey = JSProto_AsyncFunction; 1523 } 1524 } else { 1525 if (isGenerator) { 1526 fun = CompileStandaloneGenerator(cx, options, srcBuf, parameterListEnd, 1527 syntaxKind); 1528 protoKey = JSProto_GeneratorFunction; 1529 } else { 1530 fun = CompileStandaloneFunction(cx, options, srcBuf, parameterListEnd, 1531 syntaxKind); 1532 protoKey = JSProto_Function; 1533 } 1534 } 1535 if (!fun) { 1536 return false; 1537 } 1538 1539 RootedValue undefValue(cx); 1540 RootedScript funScript(cx, JS_GetFunctionScript(cx, fun)); 1541 JS::InstantiateOptions instantiateOptions(options); 1542 if (funScript && 1543 !UpdateDebugMetadata(cx, funScript, instantiateOptions, undefValue, 1544 nullptr, maybeScript, maybeScript)) { 1545 return false; 1546 } 1547 1548 if (fun->isInterpreted()) { 1549 fun->initEnvironment(&cx->global()->lexicalEnvironment()); 1550 } 1551 1552 // Steps 6, 29. 1553 RootedObject proto(cx); 1554 if (!GetPrototypeFromBuiltinConstructor(cx, args, protoKey, &proto)) { 1555 return false; 1556 } 1557 1558 // Steps 7.d, 8.d (implicit). 1559 // Call SetPrototype if an explicit prototype was given. 1560 if (proto && !SetPrototype(cx, fun, proto)) { 1561 return false; 1562 } 1563 1564 // Step 38. 1565 args.rval().setObject(*fun); 1566 return true; 1567 } 1568 1569 bool js::Function(JSContext* cx, unsigned argc, Value* vp) { 1570 CallArgs args = CallArgsFromVp(argc, vp); 1571 return CreateDynamicFunction(cx, args, GeneratorKind::NotGenerator, 1572 FunctionAsyncKind::SyncFunction); 1573 } 1574 1575 bool js::Generator(JSContext* cx, unsigned argc, Value* vp) { 1576 CallArgs args = CallArgsFromVp(argc, vp); 1577 return CreateDynamicFunction(cx, args, GeneratorKind::Generator, 1578 FunctionAsyncKind::SyncFunction); 1579 } 1580 1581 bool js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp) { 1582 CallArgs args = CallArgsFromVp(argc, vp); 1583 return CreateDynamicFunction(cx, args, GeneratorKind::NotGenerator, 1584 FunctionAsyncKind::AsyncFunction); 1585 } 1586 1587 bool js::AsyncGeneratorConstructor(JSContext* cx, unsigned argc, Value* vp) { 1588 CallArgs args = CallArgsFromVp(argc, vp); 1589 return CreateDynamicFunction(cx, args, GeneratorKind::Generator, 1590 FunctionAsyncKind::AsyncFunction); 1591 } 1592 1593 bool JSFunction::isBuiltinFunctionConstructor() { 1594 return maybeNative() == Function || maybeNative() == Generator; 1595 } 1596 1597 bool JSFunction::needsExtraBodyVarEnvironment() const { 1598 if (isNativeFun()) { 1599 return false; 1600 } 1601 1602 if (!nonLazyScript()->functionHasExtraBodyVarScope()) { 1603 return false; 1604 } 1605 1606 return nonLazyScript()->functionExtraBodyVarScope()->hasEnvironment(); 1607 } 1608 1609 bool JSFunction::needsNamedLambdaEnvironment() const { 1610 if (!isNamedLambda()) { 1611 return false; 1612 } 1613 1614 LexicalScope* scope = nonLazyScript()->maybeNamedLambdaScope(); 1615 if (!scope) { 1616 return false; 1617 } 1618 1619 return scope->hasEnvironment(); 1620 } 1621 1622 bool JSFunction::needsCallObject() const { 1623 if (isNativeFun()) { 1624 return false; 1625 } 1626 1627 MOZ_ASSERT(hasBytecode()); 1628 1629 // Note: this should be kept in sync with 1630 // FunctionBox::needsCallObjectRegardlessOfBindings(). 1631 MOZ_ASSERT_IF( 1632 baseScript()->funHasExtensibleScope() || isGenerator() || isAsync(), 1633 nonLazyScript()->bodyScope()->hasEnvironment()); 1634 1635 return nonLazyScript()->bodyScope()->hasEnvironment(); 1636 } 1637 1638 #if defined(DEBUG) || defined(JS_JITSPEW) 1639 void JSFunction::dumpOwnFields(js::JSONPrinter& json) const { 1640 if (maybePartialDisplayAtom()) { 1641 js::GenericPrinter& out = 1642 json.beginStringProperty("maybePartialDisplayAtom"); 1643 maybePartialDisplayAtom()->dumpPropertyName(out); 1644 json.endStringProperty(); 1645 } 1646 1647 if (hasBaseScript()) { 1648 js::GenericPrinter& out = json.beginStringProperty("baseScript"); 1649 baseScript()->dumpStringContent(out); 1650 json.endStringProperty(); 1651 } 1652 1653 json.property("nargs", nargs()); 1654 1655 json.beginInlineListProperty("flags"); 1656 DumpFunctionFlagsItems(json, flags()); 1657 json.endInlineList(); 1658 1659 if (isNativeFun()) { 1660 json.formatProperty("native", "0x%p", native()); 1661 if (hasJitInfo()) { 1662 json.formatProperty("jitInfo", "0x%p", jitInfo()); 1663 } 1664 } 1665 } 1666 1667 void JSFunction::dumpOwnStringContent(js::GenericPrinter& out) const { 1668 if (maybePartialDisplayAtom() && maybePartialDisplayAtom()->length() > 0) { 1669 maybePartialDisplayAtom()->dumpPropertyName(out); 1670 } else { 1671 out.put("(anonymous)"); 1672 } 1673 1674 if (hasBaseScript()) { 1675 out.put(" ("); 1676 baseScript()->dumpStringContent(out); 1677 out.put(")"); 1678 } 1679 } 1680 #endif 1681 1682 #ifdef DEBUG 1683 static JSObject* SkipEnvironmentObjects(JSObject* env) { 1684 if (!env) { 1685 return nullptr; 1686 } 1687 while (env->is<EnvironmentObject>()) { 1688 env = &env->as<EnvironmentObject>().enclosingEnvironment(); 1689 } 1690 return env; 1691 } 1692 1693 static bool NewFunctionEnvironmentIsWellFormed(JSContext* cx, 1694 HandleObject env) { 1695 // Assert that the terminating environment is null, global, or a debug 1696 // scope proxy. All other cases of polluting global scope behavior are 1697 // handled by EnvironmentObjects (viz. non-syntactic DynamicWithObject and 1698 // NonSyntacticVariablesObject). 1699 JSObject* terminatingEnv = SkipEnvironmentObjects(env); 1700 return !terminatingEnv || terminatingEnv == cx->global() || 1701 terminatingEnv->is<DebugEnvironmentProxy>(); 1702 } 1703 #endif 1704 1705 static inline const JSClass* FunctionClassForAllocKind( 1706 gc::AllocKind allocKind) { 1707 return (allocKind == gc::AllocKind::FUNCTION) ? FunctionClassPtr 1708 : FunctionExtendedClassPtr; 1709 } 1710 1711 static void AssertClassMatchesAllocKind(const JSClass* clasp, 1712 gc::AllocKind kind) { 1713 #ifdef DEBUG 1714 if (kind == gc::AllocKind::FUNCTION_EXTENDED) { 1715 MOZ_ASSERT(clasp == FunctionExtendedClassPtr); 1716 } else { 1717 MOZ_ASSERT(kind == gc::AllocKind::FUNCTION); 1718 MOZ_ASSERT(clasp == FunctionClassPtr); 1719 } 1720 #endif 1721 } 1722 1723 static SharedShape* GetFunctionShape(JSContext* cx, const JSClass* clasp, 1724 JSObject* proto, gc::AllocKind allocKind) { 1725 AssertClassMatchesAllocKind(clasp, allocKind); 1726 1727 size_t nfixed = GetGCKindSlots(allocKind); 1728 return SharedShape::getInitialShape( 1729 cx, clasp, cx->realm(), TaggedProto(proto), nfixed, ObjectFlags()); 1730 } 1731 1732 SharedShape* GlobalObject::createFunctionShapeWithDefaultProto(JSContext* cx, 1733 bool extended) { 1734 GlobalObjectData& data = cx->global()->data(); 1735 GCPtr<SharedShape*>& shapeRef = 1736 extended ? data.extendedFunctionShapeWithDefaultProto 1737 : data.functionShapeWithDefaultProto; 1738 MOZ_ASSERT(!shapeRef); 1739 1740 RootedObject proto(cx, 1741 GlobalObject::getOrCreatePrototype(cx, JSProto_Function)); 1742 if (!proto) { 1743 return nullptr; 1744 } 1745 1746 // Creating %Function.prototype% can end up initializing the shape. 1747 if (shapeRef) { 1748 return shapeRef; 1749 } 1750 1751 gc::AllocKind allocKind = 1752 extended ? gc::AllocKind::FUNCTION_EXTENDED : gc::AllocKind::FUNCTION; 1753 const JSClass* clasp = FunctionClassForAllocKind(allocKind); 1754 1755 SharedShape* shape = GetFunctionShape(cx, clasp, proto, allocKind); 1756 if (!shape) { 1757 return nullptr; 1758 } 1759 1760 shapeRef.init(shape); 1761 return shape; 1762 } 1763 1764 JSFunction* js::NewFunctionWithProto( 1765 JSContext* cx, Native native, unsigned nargs, FunctionFlags flags, 1766 HandleObject enclosingEnv, Handle<JSAtom*> atom, HandleObject proto, 1767 gc::AllocKind allocKind /* = AllocKind::FUNCTION */, 1768 NewObjectKind newKind /* = GenericObject */) { 1769 MOZ_ASSERT(allocKind == gc::AllocKind::FUNCTION || 1770 allocKind == gc::AllocKind::FUNCTION_EXTENDED); 1771 MOZ_ASSERT_IF(native, !enclosingEnv); 1772 MOZ_ASSERT(NewFunctionEnvironmentIsWellFormed(cx, enclosingEnv)); 1773 1774 // NOTE: Keep this in sync with `CreateFunctionFast` in Stencil.cpp 1775 1776 const JSClass* clasp = FunctionClassForAllocKind(allocKind); 1777 1778 Rooted<SharedShape*> shape(cx); 1779 if (!proto) { 1780 bool extended = (allocKind == gc::AllocKind::FUNCTION_EXTENDED); 1781 shape = GlobalObject::getFunctionShapeWithDefaultProto(cx, extended); 1782 } else { 1783 shape = GetFunctionShape(cx, clasp, proto, allocKind); 1784 } 1785 if (!shape) { 1786 return nullptr; 1787 } 1788 1789 gc::Heap heap = GetInitialHeap(newKind, clasp); 1790 JSFunction* fun = JSFunction::create(cx, allocKind, heap, shape); 1791 if (!fun) { 1792 return nullptr; 1793 } 1794 1795 if (allocKind == gc::AllocKind::FUNCTION_EXTENDED) { 1796 flags.setIsExtended(); 1797 } 1798 1799 // Disallow flags that require special union arms to be initialized. 1800 MOZ_ASSERT(!flags.hasSelfHostedLazyScript()); 1801 MOZ_ASSERT(!flags.isWasmWithJitEntry()); 1802 1803 /* Initialize all function members. */ 1804 fun->setArgCount(uint16_t(nargs)); 1805 fun->setFlags(flags); 1806 if (fun->isInterpreted()) { 1807 fun->initScript(nullptr); 1808 fun->initEnvironment(enclosingEnv); 1809 } else { 1810 MOZ_ASSERT(fun->isNativeFun()); 1811 fun->initNative(native, nullptr); 1812 } 1813 fun->initAtom(atom); 1814 1815 #ifdef DEBUG 1816 fun->assertFunctionKindIntegrity(); 1817 #endif 1818 1819 return fun; 1820 } 1821 1822 bool js::GetFunctionPrototype(JSContext* cx, js::GeneratorKind generatorKind, 1823 js::FunctionAsyncKind asyncKind, 1824 js::MutableHandleObject proto) { 1825 if (generatorKind == js::GeneratorKind::NotGenerator) { 1826 if (asyncKind == js::FunctionAsyncKind::SyncFunction) { 1827 proto.set(nullptr); 1828 return true; 1829 } 1830 1831 proto.set( 1832 GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global())); 1833 } else { 1834 if (asyncKind == js::FunctionAsyncKind::SyncFunction) { 1835 proto.set(GlobalObject::getOrCreateGeneratorFunctionPrototype( 1836 cx, cx->global())); 1837 } else { 1838 proto.set(GlobalObject::getOrCreateAsyncGenerator(cx, cx->global())); 1839 } 1840 } 1841 return !!proto; 1842 } 1843 1844 #ifdef DEBUG 1845 static bool CanReuseScriptForClone(JS::Realm* realm, HandleFunction fun, 1846 HandleObject newEnclosingEnv) { 1847 MOZ_ASSERT(fun->isInterpreted()); 1848 1849 if (realm != fun->realm()) { 1850 return false; 1851 } 1852 1853 if (newEnclosingEnv->is<GlobalObject>()) { 1854 return true; 1855 } 1856 1857 // Don't need to clone the script if newEnclosingEnv is a syntactic scope, 1858 // since in that case we have some actual scope objects on our scope chain and 1859 // whatnot; whoever put them there should be responsible for setting our 1860 // script's flags appropriately. We hit this case for JSOp::Lambda, for 1861 // example. 1862 if (IsSyntacticEnvironment(newEnclosingEnv)) { 1863 return true; 1864 } 1865 1866 // We need to clone the script if we're not already marked as having a 1867 // non-syntactic scope. The HasNonSyntacticScope flag is not computed for lazy 1868 // scripts so fallback to checking the scope chain. 1869 BaseScript* script = fun->baseScript(); 1870 return script->hasNonSyntacticScope() || 1871 script->enclosingScope()->hasOnChain(ScopeKind::NonSyntactic); 1872 } 1873 #endif 1874 1875 static inline JSFunction* NewFunctionClone(JSContext* cx, HandleFunction fun, 1876 HandleObject proto, 1877 gc::Heap heap = gc::Heap::Default, 1878 gc::AllocSite* site = nullptr) { 1879 MOZ_ASSERT(cx->realm() == fun->realm()); 1880 MOZ_ASSERT(proto); 1881 1882 const JSClass* clasp = fun->getClass(); 1883 gc::AllocKind allocKind = fun->getAllocKind(); 1884 AssertClassMatchesAllocKind(clasp, allocKind); 1885 1886 // If |fun| also has |proto| as prototype (the common case) we can reuse its 1887 // shape for the clone. This works because |fun| isn't exposed to script. 1888 Rooted<SharedShape*> shape(cx); 1889 if (fun->staticPrototype() == proto) { 1890 shape = fun->sharedShape(); 1891 MOZ_ASSERT(shape->propMapLength() == 0); 1892 MOZ_ASSERT(shape->objectFlags().isEmpty()); 1893 MOZ_ASSERT(shape->realm() == cx->realm()); 1894 } else { 1895 shape = GetFunctionShape(cx, clasp, proto, allocKind); 1896 if (!shape) { 1897 return nullptr; 1898 } 1899 } 1900 1901 JSFunction* clone = JSFunction::create(cx, allocKind, heap, shape, site); 1902 if (!clone) { 1903 return nullptr; 1904 } 1905 1906 // The following flags shouldn't be set or cloned. 1907 MOZ_ASSERT(!fun->flags().hasResolvedLength()); 1908 MOZ_ASSERT(!fun->flags().hasResolvedName()); 1909 1910 clone->setArgCount(fun->nargs()); 1911 clone->setFlags(fun->flags()); 1912 1913 // Note: |clone| and |fun| are same-zone so we don't need to call markAtom. 1914 clone->initAtom(fun->maybePartialDisplayAtom()); 1915 1916 #ifdef DEBUG 1917 clone->assertFunctionKindIntegrity(); 1918 #endif 1919 1920 return clone; 1921 } 1922 1923 JSFunction* js::CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, 1924 HandleObject enclosingEnv, 1925 HandleObject proto, gc::Heap heap, 1926 gc::AllocSite* site) { 1927 MOZ_ASSERT(cx->realm() == fun->realm()); 1928 MOZ_ASSERT(NewFunctionEnvironmentIsWellFormed(cx, enclosingEnv)); 1929 MOZ_ASSERT(fun->isInterpreted()); 1930 MOZ_ASSERT(fun->hasBaseScript()); 1931 MOZ_ASSERT(CanReuseScriptForClone(cx->realm(), fun, enclosingEnv)); 1932 1933 JSFunction* clone = NewFunctionClone(cx, fun, proto, heap, site); 1934 if (!clone) { 1935 return nullptr; 1936 } 1937 1938 BaseScript* base = fun->baseScript(); 1939 clone->initScript(base); 1940 clone->initEnvironment(enclosingEnv); 1941 1942 #ifdef DEBUG 1943 // Assert extended slots don't need to be copied. 1944 if (fun->isExtended()) { 1945 for (unsigned i = 0; i < FunctionExtended::NUM_EXTENDED_SLOTS; i++) { 1946 MOZ_ASSERT(fun->getExtendedSlot(i).isUndefined()); 1947 MOZ_ASSERT(clone->getExtendedSlot(i).isUndefined()); 1948 } 1949 } 1950 #endif 1951 1952 return clone; 1953 } 1954 1955 JSFunction* js::CloneAsmJSModuleFunction(JSContext* cx, HandleFunction fun) { 1956 MOZ_ASSERT(fun->isNativeFun()); 1957 MOZ_ASSERT(IsAsmJSModule(fun)); 1958 MOZ_ASSERT(fun->isExtended()); 1959 MOZ_ASSERT(cx->compartment() == fun->compartment()); 1960 1961 RootedObject proto(cx, fun->staticPrototype()); 1962 JSFunction* clone = NewFunctionClone(cx, fun, proto); 1963 if (!clone) { 1964 return nullptr; 1965 } 1966 1967 MOZ_ASSERT(fun->native() == InstantiateAsmJS); 1968 MOZ_ASSERT(!fun->hasJitInfo()); 1969 clone->initNative(InstantiateAsmJS, nullptr); 1970 1971 JSObject* moduleObj = 1972 &fun->getExtendedSlot(FunctionExtended::ASMJS_MODULE_SLOT).toObject(); 1973 clone->initExtendedSlot(FunctionExtended::ASMJS_MODULE_SLOT, 1974 ObjectValue(*moduleObj)); 1975 1976 return clone; 1977 } 1978 1979 static JSAtom* SymbolToFunctionName(JSContext* cx, JS::Symbol* symbol, 1980 FunctionPrefixKind prefixKind) { 1981 // Step 4.a. 1982 JSAtom* desc = symbol->description(); 1983 1984 // Step 4.b, no prefix fastpath. 1985 if (!desc && prefixKind == FunctionPrefixKind::None) { 1986 return cx->names().empty_; 1987 } 1988 1989 // Step 5 (reordered). 1990 StringBuilder sb(cx); 1991 if (prefixKind == FunctionPrefixKind::Get) { 1992 if (!sb.append("get ")) { 1993 return nullptr; 1994 } 1995 } else if (prefixKind == FunctionPrefixKind::Set) { 1996 if (!sb.append("set ")) { 1997 return nullptr; 1998 } 1999 } 2000 2001 // Step 4.b. 2002 if (desc) { 2003 // Note: Private symbols are wedged in, as implementation wise they're 2004 // PrivateNameSymbols with a the source level name as a description 2005 // i.e. obj.#f desugars to obj.[PrivateNameSymbol("#f")], however 2006 // they don't use the symbol naming, but rather property naming. 2007 if (symbol->isPrivateName()) { 2008 if (!sb.append(desc)) { 2009 return nullptr; 2010 } 2011 } else { 2012 // Step 4.c. 2013 if (!sb.append('[') || !sb.append(desc) || !sb.append(']')) { 2014 return nullptr; 2015 } 2016 } 2017 } 2018 return sb.finishAtom(); 2019 } 2020 2021 /* 2022 * Return an atom for use as the name of a builtin method with the given 2023 * property id. 2024 * 2025 * Function names are always strings. If id is the well-known @@iterator 2026 * symbol, this returns "[Symbol.iterator]". If a prefix is supplied the final 2027 * name is |prefix + " " + name|. 2028 * 2029 * Implements steps 3-5 of 9.2.11 SetFunctionName in ES2016. 2030 */ 2031 JSAtom* js::IdToFunctionName( 2032 JSContext* cx, HandleId id, 2033 FunctionPrefixKind prefixKind /* = FunctionPrefixKind::None */) { 2034 MOZ_ASSERT(id.isString() || id.isSymbol() || id.isInt()); 2035 2036 // No prefix fastpath. 2037 if (id.isAtom() && prefixKind == FunctionPrefixKind::None) { 2038 return id.toAtom(); 2039 } 2040 2041 // Step 3 (implicit). 2042 2043 // Step 4. 2044 if (id.isSymbol()) { 2045 return SymbolToFunctionName(cx, id.toSymbol(), prefixKind); 2046 } 2047 2048 // Step 5. 2049 RootedValue idv(cx, IdToValue(id)); 2050 return NameToFunctionName(cx, idv, prefixKind); 2051 } 2052 2053 bool js::SetFunctionName(JSContext* cx, HandleFunction fun, HandleValue name, 2054 FunctionPrefixKind prefixKind) { 2055 MOZ_ASSERT(name.isString() || name.isSymbol() || name.isNumeric()); 2056 2057 // `fun` is a newly created function, so it can't already have an inferred 2058 // name. 2059 MOZ_ASSERT(!fun->hasInferredName()); 2060 2061 // Anonymous functions should neither have an own 'name' property nor a 2062 // resolved name at this point. 2063 MOZ_ASSERT(!fun->containsPure(cx->names().name)); 2064 MOZ_ASSERT(!fun->hasResolvedName()); 2065 2066 JSAtom* funName = name.isSymbol() 2067 ? SymbolToFunctionName(cx, name.toSymbol(), prefixKind) 2068 : NameToFunctionName(cx, name, prefixKind); 2069 if (!funName) { 2070 return false; 2071 } 2072 2073 fun->setInferredName(funName); 2074 2075 return true; 2076 } 2077 2078 JSFunction* js::DefineFunction( 2079 JSContext* cx, HandleObject obj, HandleId id, Native native, unsigned nargs, 2080 unsigned flags, gc::AllocKind allocKind /* = AllocKind::FUNCTION */) { 2081 Rooted<JSAtom*> atom(cx, IdToFunctionName(cx, id)); 2082 if (!atom) { 2083 return nullptr; 2084 } 2085 2086 MOZ_ASSERT(native); 2087 2088 RootedFunction fun(cx); 2089 if (flags & JSFUN_CONSTRUCTOR) { 2090 fun = NewNativeConstructor(cx, native, nargs, atom, allocKind); 2091 } else { 2092 fun = NewNativeFunction(cx, native, nargs, atom, allocKind); 2093 } 2094 2095 if (!fun) { 2096 return nullptr; 2097 } 2098 2099 RootedValue funVal(cx, ObjectValue(*fun)); 2100 if (!DefineDataProperty(cx, obj, id, funVal, flags & ~JSFUN_FLAGS_MASK)) { 2101 return nullptr; 2102 } 2103 2104 return fun; 2105 } 2106 2107 void js::ReportIncompatibleMethod(JSContext* cx, const CallArgs& args, 2108 const JSClass* clasp) { 2109 HandleValue thisv = args.thisv(); 2110 2111 #ifdef DEBUG 2112 switch (thisv.type()) { 2113 case ValueType::Object: 2114 MOZ_ASSERT(thisv.toObject().getClass() != clasp || 2115 !thisv.toObject().is<NativeObject>() || 2116 !thisv.toObject().staticPrototype() || 2117 thisv.toObject().staticPrototype()->getClass() != clasp); 2118 break; 2119 case ValueType::String: 2120 MOZ_ASSERT(clasp != &StringObject::class_); 2121 break; 2122 case ValueType::Double: 2123 case ValueType::Int32: 2124 MOZ_ASSERT(clasp != &NumberObject::class_); 2125 break; 2126 case ValueType::Boolean: 2127 MOZ_ASSERT(clasp != &BooleanObject::class_); 2128 break; 2129 case ValueType::Symbol: 2130 MOZ_ASSERT(clasp != &SymbolObject::class_); 2131 break; 2132 case ValueType::BigInt: 2133 MOZ_ASSERT(clasp != &BigIntObject::class_); 2134 break; 2135 case ValueType::Undefined: 2136 case ValueType::Null: 2137 break; 2138 case ValueType::Magic: 2139 case ValueType::PrivateGCThing: 2140 MOZ_CRASH("unexpected type"); 2141 } 2142 #endif 2143 2144 if (JSFunction* fun = ReportIfNotFunction(cx, args.calleev())) { 2145 UniqueChars funNameBytes; 2146 if (const char* funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) { 2147 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 2148 JSMSG_INCOMPATIBLE_PROTO, clasp->name, funName, 2149 InformalValueTypeName(thisv)); 2150 } 2151 } 2152 } 2153 2154 void js::ReportIncompatible(JSContext* cx, const CallArgs& args) { 2155 if (JSFunction* fun = ReportIfNotFunction(cx, args.calleev())) { 2156 UniqueChars funNameBytes; 2157 if (const char* funName = GetFunctionNameBytes(cx, fun, &funNameBytes)) { 2158 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 2159 JSMSG_INCOMPATIBLE_METHOD, funName, "method", 2160 InformalValueTypeName(args.thisv())); 2161 } 2162 } 2163 } 2164 2165 namespace JS { 2166 namespace detail { 2167 2168 JS_PUBLIC_API void CheckIsValidConstructible(const Value& calleev) { 2169 MOZ_ASSERT(calleev.toObject().isConstructor()); 2170 } 2171 2172 } // namespace detail 2173 } // namespace JS