SelfHosting.cpp (94178B)
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 #include "vm/SelfHosting.h" 8 9 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 10 # include "builtin/AsyncDisposableStackObject.h" 11 # include "builtin/DisposableStackObject.h" 12 #endif 13 #include "mozilla/BinarySearch.h" 14 #include "mozilla/Maybe.h" 15 #include "mozilla/ScopeExit.h" // mozilla::MakeScopeExit 16 #include "mozilla/Utf8.h" // mozilla::Utf8Unit 17 18 #include <algorithm> 19 #include <iterator> 20 21 #include "jsfriendapi.h" 22 #include "jsmath.h" 23 #include "jsnum.h" 24 #include "selfhosted.out.h" 25 26 #include "builtin/Array.h" 27 #include "builtin/BigInt.h" 28 #ifdef JS_HAS_INTL_API 29 # include "builtin/intl/Collator.h" 30 # include "builtin/intl/DateTimeFormat.h" 31 # include "builtin/intl/DisplayNames.h" 32 # include "builtin/intl/DurationFormat.h" 33 # include "builtin/intl/IntlObject.h" 34 # include "builtin/intl/ListFormat.h" 35 # include "builtin/intl/Locale.h" 36 # include "builtin/intl/NumberFormat.h" 37 # include "builtin/intl/PluralRules.h" 38 # include "builtin/intl/RelativeTimeFormat.h" 39 # include "builtin/intl/Segmenter.h" 40 #endif 41 #include "builtin/MapObject.h" 42 #include "builtin/Object.h" 43 #include "builtin/Promise.h" 44 #include "builtin/Reflect.h" 45 #include "builtin/RegExp.h" 46 #include "builtin/SelfHostingDefines.h" 47 #include "builtin/String.h" 48 #ifdef JS_HAS_INTL_API 49 # include "builtin/temporal/Duration.h" 50 # include "builtin/temporal/TimeZone.h" 51 #endif 52 #include "builtin/WeakMapObject.h" 53 #include "frontend/BytecodeCompiler.h" // CompileGlobalScriptToStencil 54 #include "frontend/CompilationStencil.h" // js::frontend::CompilationStencil 55 #include "frontend/FrontendContext.h" // AutoReportFrontendContext 56 #include "frontend/StencilXdr.h" // js::EncodeStencil, js::DecodeStencil 57 #include "jit/AtomicOperations.h" 58 #include "jit/BaselineJIT.h" 59 #include "jit/InlinableNatives.h" 60 #include "jit/TrampolineNatives.h" 61 #include "js/CompilationAndEvaluation.h" 62 #include "js/Conversions.h" 63 #include "js/ErrorReport.h" // JS::PrintError 64 #include "js/experimental/JSStencil.h" 65 #include "js/experimental/TypedData.h" // JS_GetArrayBufferViewType 66 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* 67 #include "js/HashTable.h" 68 #include "js/Printer.h" 69 #include "js/PropertySpec.h" 70 #include "js/ScalarType.h" // js::Scalar::Type 71 #include "js/SourceText.h" // JS::SourceText 72 #include "js/TracingAPI.h" 73 #include "js/Transcoding.h" 74 #include "js/Warnings.h" // JS::{,Set}WarningReporter 75 #include "js/Wrapper.h" 76 #include "vm/ArgumentsObject.h" 77 #include "vm/AsyncFunction.h" 78 #include "vm/AsyncIteration.h" 79 #include "vm/BigIntType.h" 80 #include "vm/Compression.h" 81 #include "vm/DateObject.h" 82 #include "vm/ErrorReporting.h" // js::MaybePrintAndClearPendingException 83 #include "vm/Float16.h" 84 #include "vm/FrameIter.h" // js::ScriptFrameIter 85 #include "vm/GeneratorObject.h" 86 #include "vm/Interpreter.h" 87 #include "vm/Iteration.h" 88 #include "vm/JSAtomUtils.h" // Atomize 89 #include "vm/JSContext.h" 90 #include "vm/JSFunction.h" 91 #include "vm/JSObject.h" 92 #include "vm/Logging.h" 93 #include "vm/PlainObject.h" // js::PlainObject 94 #include "vm/Realm.h" 95 #include "vm/RegExpObject.h" 96 #include "vm/StringType.h" 97 #include "vm/ToSource.h" // js::ValueToSource 98 #include "vm/TypedArrayObject.h" 99 #include "vm/Uint8Clamped.h" 100 #include "vm/Warnings.h" 101 #include "vm/WrapperObject.h" 102 103 #include "gc/WeakMap-inl.h" 104 #include "vm/Compartment-inl.h" 105 #include "vm/JSAtomUtils-inl.h" // PrimitiveValueToId 106 #include "vm/JSFunction-inl.h" 107 #include "vm/JSObject-inl.h" 108 #include "vm/NativeObject-inl.h" 109 #include "vm/TypedArrayObject-inl.h" 110 111 using namespace js; 112 using namespace js::selfhosted; 113 114 using JS::CompileOptions; 115 116 static bool intrinsic_ToObject(JSContext* cx, unsigned argc, Value* vp) { 117 CallArgs args = CallArgsFromVp(argc, vp); 118 JSObject* obj = ToObject(cx, args[0]); 119 if (!obj) { 120 return false; 121 } 122 args.rval().setObject(*obj); 123 return true; 124 } 125 126 static bool intrinsic_IsObject(JSContext* cx, unsigned argc, Value* vp) { 127 CallArgs args = CallArgsFromVp(argc, vp); 128 Value val = args[0]; 129 bool isObject = val.isObject(); 130 args.rval().setBoolean(isObject); 131 return true; 132 } 133 134 static bool intrinsic_IsArray(JSContext* cx, unsigned argc, Value* vp) { 135 CallArgs args = CallArgsFromVp(argc, vp); 136 MOZ_ASSERT(args.length() == 1); 137 RootedValue val(cx, args[0]); 138 if (val.isObject()) { 139 RootedObject obj(cx, &val.toObject()); 140 bool isArray = false; 141 if (!IsArray(cx, obj, &isArray)) { 142 return false; 143 } 144 args.rval().setBoolean(isArray); 145 } else { 146 args.rval().setBoolean(false); 147 } 148 return true; 149 } 150 151 static bool intrinsic_IsCrossRealmArrayConstructor(JSContext* cx, unsigned argc, 152 Value* vp) { 153 CallArgs args = CallArgsFromVp(argc, vp); 154 MOZ_ASSERT(args.length() == 1); 155 MOZ_ASSERT(args[0].isObject()); 156 157 bool result = false; 158 if (!IsCrossRealmArrayConstructor(cx, &args[0].toObject(), &result)) { 159 return false; 160 } 161 args.rval().setBoolean(result); 162 return true; 163 } 164 165 static bool intrinsic_ToLength(JSContext* cx, unsigned argc, Value* vp) { 166 CallArgs args = CallArgsFromVp(argc, vp); 167 MOZ_ASSERT(args.length() == 1); 168 169 // Inline fast path for the common case. 170 if (args[0].isInt32()) { 171 int32_t i = args[0].toInt32(); 172 args.rval().setInt32(i < 0 ? 0 : i); 173 return true; 174 } 175 176 uint64_t length = 0; 177 if (!ToLength(cx, args[0], &length)) { 178 return false; 179 } 180 181 args.rval().setNumber(double(length)); 182 return true; 183 } 184 185 static bool intrinsic_ToInteger(JSContext* cx, unsigned argc, Value* vp) { 186 CallArgs args = CallArgsFromVp(argc, vp); 187 double result; 188 if (!ToInteger(cx, args[0], &result)) { 189 return false; 190 } 191 args.rval().setNumber(result); 192 return true; 193 } 194 195 static bool intrinsic_ToSource(JSContext* cx, unsigned argc, Value* vp) { 196 CallArgs args = CallArgsFromVp(argc, vp); 197 JSString* str = ValueToSource(cx, args[0]); 198 if (!str) { 199 return false; 200 } 201 args.rval().setString(str); 202 return true; 203 } 204 205 static bool intrinsic_ToPropertyKey(JSContext* cx, unsigned argc, Value* vp) { 206 CallArgs args = CallArgsFromVp(argc, vp); 207 RootedId id(cx); 208 if (!ToPropertyKey(cx, args[0], &id)) { 209 return false; 210 } 211 212 args.rval().set(IdToValue(id)); 213 return true; 214 } 215 216 static bool intrinsic_IsCallable(JSContext* cx, unsigned argc, Value* vp) { 217 CallArgs args = CallArgsFromVp(argc, vp); 218 args.rval().setBoolean(IsCallable(args[0])); 219 return true; 220 } 221 222 static bool intrinsic_IsConstructor(JSContext* cx, unsigned argc, Value* vp) { 223 CallArgs args = CallArgsFromVp(argc, vp); 224 MOZ_ASSERT(args.length() == 1); 225 args.rval().setBoolean(IsConstructor(args[0])); 226 return true; 227 } 228 229 template <typename T> 230 static bool intrinsic_IsInstanceOfBuiltin(JSContext* cx, unsigned argc, 231 Value* vp) { 232 CallArgs args = CallArgsFromVp(argc, vp); 233 MOZ_ASSERT(args.length() == 1); 234 MOZ_ASSERT(args[0].isObject()); 235 236 args.rval().setBoolean(args[0].toObject().is<T>()); 237 return true; 238 } 239 240 template <typename T> 241 static bool intrinsic_GuardToBuiltin(JSContext* cx, unsigned argc, Value* vp) { 242 CallArgs args = CallArgsFromVp(argc, vp); 243 MOZ_ASSERT(args.length() == 1); 244 MOZ_ASSERT(args[0].isObject()); 245 246 if (args[0].toObject().is<T>()) { 247 args.rval().setObject(args[0].toObject()); 248 return true; 249 } 250 args.rval().setNull(); 251 return true; 252 } 253 254 template <typename T> 255 static bool intrinsic_IsWrappedInstanceOfBuiltin(JSContext* cx, unsigned argc, 256 Value* vp) { 257 CallArgs args = CallArgsFromVp(argc, vp); 258 MOZ_ASSERT(args.length() == 1); 259 MOZ_ASSERT(args[0].isObject()); 260 261 JSObject* obj = &args[0].toObject(); 262 if (!obj->is<WrapperObject>()) { 263 args.rval().setBoolean(false); 264 return true; 265 } 266 267 JSObject* unwrapped = CheckedUnwrapDynamic(obj, cx); 268 if (!unwrapped) { 269 ReportAccessDenied(cx); 270 return false; 271 } 272 273 args.rval().setBoolean(unwrapped->is<T>()); 274 return true; 275 } 276 277 template <typename T> 278 static bool intrinsic_IsPossiblyWrappedInstanceOfBuiltin(JSContext* cx, 279 unsigned argc, 280 Value* vp) { 281 CallArgs args = CallArgsFromVp(argc, vp); 282 MOZ_ASSERT(args.length() == 1); 283 MOZ_ASSERT(args[0].isObject()); 284 285 JSObject* obj = CheckedUnwrapDynamic(&args[0].toObject(), cx); 286 if (!obj) { 287 ReportAccessDenied(cx); 288 return false; 289 } 290 291 args.rval().setBoolean(obj->is<T>()); 292 return true; 293 } 294 295 static bool intrinsic_SubstringKernel(JSContext* cx, unsigned argc, Value* vp) { 296 CallArgs args = CallArgsFromVp(argc, vp); 297 MOZ_ASSERT(args[0].isString()); 298 MOZ_RELEASE_ASSERT(args[1].isInt32()); 299 MOZ_RELEASE_ASSERT(args[2].isInt32()); 300 301 RootedString str(cx, args[0].toString()); 302 int32_t begin = args[1].toInt32(); 303 int32_t length = args[2].toInt32(); 304 305 JSString* substr = SubstringKernel(cx, str, begin, length); 306 if (!substr) { 307 return false; 308 } 309 310 args.rval().setString(substr); 311 return true; 312 } 313 314 static bool PrepareErrorArguments(JSContext* cx, JSExnType type, 315 const CallArgs& args, 316 UniqueChars (&errorArgs)[3]) { 317 #ifdef DEBUG 318 MOZ_ASSERT(args[0].isInt32()); 319 uint32_t errorNumber = args[0].toInt32(); 320 321 const JSErrorFormatString* efs = GetErrorMessage(nullptr, errorNumber); 322 MOZ_ASSERT(efs->argCount == args.length() - 1); 323 MOZ_ASSERT(efs->exnType == type, 324 "error-throwing intrinsic and error number are inconsistent"); 325 #endif 326 327 for (unsigned i = 1; i < 4 && i < args.length(); i++) { 328 HandleValue val = args[i]; 329 if (val.isInt32() || val.isString()) { 330 JSString* str = ToString<CanGC>(cx, val); 331 if (!str) { 332 return false; 333 } 334 errorArgs[i - 1] = QuoteString(cx, str); 335 } else { 336 errorArgs[i - 1] = 337 DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, nullptr); 338 } 339 if (!errorArgs[i - 1]) { 340 return false; 341 } 342 } 343 return true; 344 } 345 346 static void ThrowErrorWithType(JSContext* cx, JSExnType type, 347 const CallArgs& args) { 348 MOZ_RELEASE_ASSERT(args[0].isInt32()); 349 uint32_t errorNumber = args[0].toInt32(); 350 351 UniqueChars errorArgs[3]; 352 if (!PrepareErrorArguments(cx, type, args, errorArgs)) { 353 return; 354 } 355 356 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber, 357 errorArgs[0].get(), errorArgs[1].get(), 358 errorArgs[2].get()); 359 } 360 361 static bool intrinsic_ThrowRangeError(JSContext* cx, unsigned argc, Value* vp) { 362 CallArgs args = CallArgsFromVp(argc, vp); 363 MOZ_ASSERT(args.length() >= 1); 364 365 ThrowErrorWithType(cx, JSEXN_RANGEERR, args); 366 return false; 367 } 368 369 static bool intrinsic_ThrowTypeError(JSContext* cx, unsigned argc, Value* vp) { 370 CallArgs args = CallArgsFromVp(argc, vp); 371 MOZ_ASSERT(args.length() >= 1); 372 373 ThrowErrorWithType(cx, JSEXN_TYPEERR, args); 374 return false; 375 } 376 377 static bool intrinsic_ThrowAggregateError(JSContext* cx, unsigned argc, 378 Value* vp) { 379 CallArgs args = CallArgsFromVp(argc, vp); 380 MOZ_ASSERT(args.length() >= 1); 381 382 ThrowErrorWithType(cx, JSEXN_AGGREGATEERR, args); 383 return false; 384 } 385 386 static bool intrinsic_ThrowInternalError(JSContext* cx, unsigned argc, 387 Value* vp) { 388 CallArgs args = CallArgsFromVp(argc, vp); 389 MOZ_ASSERT(args.length() >= 1); 390 391 ThrowErrorWithType(cx, JSEXN_INTERNALERR, args); 392 return false; 393 } 394 395 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 396 static bool intrinsic_CreateSuppressedError(JSContext* cx, unsigned argc, 397 Value* vp) { 398 CallArgs args = CallArgsFromVp(argc, vp); 399 MOZ_ASSERT(args.length() == 2); 400 401 JS::Handle<JS::Value> error = args[0]; 402 JS::Handle<JS::Value> suppressed = args[1]; 403 404 ErrorObject* suppressedError = CreateSuppressedError(cx, error, suppressed); 405 if (!suppressedError) { 406 return false; 407 } 408 args.rval().setObject(*suppressedError); 409 return true; 410 } 411 #endif 412 413 static bool intrinsic_ReportWarning(JSContext* cx, unsigned argc, Value* vp) { 414 CallArgs args = CallArgsFromVp(argc, vp); 415 MOZ_ASSERT(args.length() >= 1); 416 417 MOZ_RELEASE_ASSERT(args[0].isInt32()); 418 uint32_t errorNumber = args[0].toInt32(); 419 420 UniqueChars errorArgs[3]; 421 if (!PrepareErrorArguments(cx, JSEXN_WARN, args, errorArgs)) { 422 return false; 423 } 424 425 if (!WarnNumberUTF8(cx, errorNumber, errorArgs[0].get(), errorArgs[1].get(), 426 errorArgs[2].get())) { 427 return false; 428 } 429 430 args.rval().setUndefined(); 431 return true; 432 } 433 434 /** 435 * Handles an assertion failure in self-hosted code just like an assertion 436 * failure in C++ code. Information about the failure can be provided in 437 * args[0]. 438 */ 439 static bool intrinsic_AssertionFailed(JSContext* cx, unsigned argc, Value* vp) { 440 #ifdef DEBUG 441 CallArgs args = CallArgsFromVp(argc, vp); 442 if (args.length() > 0) { 443 // try to dump the informative string 444 JSString* str = ToString<CanGC>(cx, args[0]); 445 if (str) { 446 js::Fprinter out(stderr); 447 out.put("Self-hosted JavaScript assertion info: "); 448 str->dumpCharsNoQuote(out); 449 out.putChar('\n'); 450 } 451 } 452 #endif 453 MOZ_ASSERT(false); 454 return false; 455 } 456 457 /** 458 * Dumps a message to stderr, after stringifying it. Doesn't append a newline. 459 */ 460 static bool intrinsic_DumpMessage(JSContext* cx, unsigned argc, Value* vp) { 461 CallArgs args = CallArgsFromVp(argc, vp); 462 #ifdef DEBUG 463 if (args.length() > 0) { 464 // try to dump the informative string 465 js::Fprinter out(stderr); 466 JSString* str = ToString<CanGC>(cx, args[0]); 467 if (str) { 468 str->dumpCharsNoQuote(out); 469 out.putChar('\n'); 470 } else { 471 cx->recoverFromOutOfMemory(); 472 } 473 } 474 #endif 475 args.rval().setUndefined(); 476 return true; 477 } 478 479 /* 480 * Used to decompile values in the nearest non-builtin stack frame, falling 481 * back to decompiling in the current frame. Helpful for printing higher-order 482 * function arguments. 483 * 484 * The user must supply the argument number of the value in question; it 485 * _cannot_ be automatically determined. 486 */ 487 static bool intrinsic_DecompileArg(JSContext* cx, unsigned argc, Value* vp) { 488 CallArgs args = CallArgsFromVp(argc, vp); 489 MOZ_ASSERT(args.length() == 2); 490 MOZ_RELEASE_ASSERT(args[0].isInt32()); 491 492 HandleValue value = args[1]; 493 JSString* str = DecompileArgument(cx, args[0].toInt32(), value); 494 if (!str) { 495 return false; 496 } 497 args.rval().setString(str); 498 return true; 499 } 500 501 static bool intrinsic_DefineDataProperty(JSContext* cx, unsigned argc, 502 Value* vp) { 503 CallArgs args = CallArgsFromVp(argc, vp); 504 505 // When DefineDataProperty is called with 3 arguments, it's compiled to 506 // JSOp::InitElem in the bytecode emitter so we shouldn't get here. 507 MOZ_ASSERT(args.length() == 4); 508 MOZ_ASSERT(args[0].isObject()); 509 MOZ_RELEASE_ASSERT(args[3].isInt32()); 510 511 RootedObject obj(cx, &args[0].toObject()); 512 RootedId id(cx); 513 if (!ToPropertyKey(cx, args[1], &id)) { 514 return false; 515 } 516 RootedValue value(cx, args[2]); 517 518 JS::PropertyAttributes attrs; 519 unsigned attributes = args[3].toInt32(); 520 521 MOZ_ASSERT(bool(attributes & ATTR_ENUMERABLE) != 522 bool(attributes & ATTR_NONENUMERABLE), 523 "DefineDataProperty must receive either ATTR_ENUMERABLE xor " 524 "ATTR_NONENUMERABLE"); 525 if (attributes & ATTR_ENUMERABLE) { 526 attrs += JS::PropertyAttribute::Enumerable; 527 } 528 529 MOZ_ASSERT(bool(attributes & ATTR_CONFIGURABLE) != 530 bool(attributes & ATTR_NONCONFIGURABLE), 531 "DefineDataProperty must receive either ATTR_CONFIGURABLE xor " 532 "ATTR_NONCONFIGURABLE"); 533 if (attributes & ATTR_CONFIGURABLE) { 534 attrs += JS::PropertyAttribute::Configurable; 535 } 536 537 MOZ_ASSERT( 538 bool(attributes & ATTR_WRITABLE) != bool(attributes & ATTR_NONWRITABLE), 539 "DefineDataProperty must receive either ATTR_WRITABLE xor " 540 "ATTR_NONWRITABLE"); 541 if (attributes & ATTR_WRITABLE) { 542 attrs += JS::PropertyAttribute::Writable; 543 } 544 545 Rooted<PropertyDescriptor> desc(cx, PropertyDescriptor::Data(value, attrs)); 546 if (!DefineProperty(cx, obj, id, desc)) { 547 return false; 548 } 549 550 args.rval().setUndefined(); 551 return true; 552 } 553 554 static bool intrinsic_DefineProperty(JSContext* cx, unsigned argc, Value* vp) { 555 // _DefineProperty(object, propertyKey, attributes, 556 // valueOrGetter, setter, strict) 557 CallArgs args = CallArgsFromVp(argc, vp); 558 MOZ_ASSERT(args.length() == 6); 559 MOZ_ASSERT(args[0].isObject()); 560 MOZ_ASSERT(args[1].isString() || args[1].isNumber() || args[1].isSymbol()); 561 MOZ_RELEASE_ASSERT(args[2].isInt32()); 562 MOZ_ASSERT(args[5].isBoolean()); 563 564 RootedObject obj(cx, &args[0].toObject()); 565 RootedId id(cx); 566 if (!PrimitiveValueToId<CanGC>(cx, args[1], &id)) { 567 return false; 568 } 569 570 Rooted<PropertyDescriptor> desc(cx, PropertyDescriptor::Empty()); 571 572 unsigned attributes = args[2].toInt32(); 573 if (attributes & (ATTR_ENUMERABLE | ATTR_NONENUMERABLE)) { 574 desc.setEnumerable(attributes & ATTR_ENUMERABLE); 575 } 576 577 if (attributes & (ATTR_CONFIGURABLE | ATTR_NONCONFIGURABLE)) { 578 desc.setConfigurable(attributes & ATTR_CONFIGURABLE); 579 } 580 581 if (attributes & (ATTR_WRITABLE | ATTR_NONWRITABLE)) { 582 desc.setWritable(attributes & ATTR_WRITABLE); 583 } 584 585 // When args[4] is |null|, the data descriptor has a value component. 586 if ((attributes & DATA_DESCRIPTOR_KIND) && args[4].isNull()) { 587 desc.setValue(args[3]); 588 } 589 590 if (attributes & ACCESSOR_DESCRIPTOR_KIND) { 591 Value getter = args[3]; 592 if (getter.isObject()) { 593 desc.setGetter(&getter.toObject()); 594 } else if (getter.isUndefined()) { 595 desc.setGetter(nullptr); 596 } else { 597 MOZ_ASSERT(getter.isNull()); 598 } 599 600 Value setter = args[4]; 601 if (setter.isObject()) { 602 desc.setSetter(&setter.toObject()); 603 } else if (setter.isUndefined()) { 604 desc.setSetter(nullptr); 605 } else { 606 MOZ_ASSERT(setter.isNull()); 607 } 608 } 609 610 desc.assertValid(); 611 612 ObjectOpResult result; 613 if (!DefineProperty(cx, obj, id, desc, result)) { 614 return false; 615 } 616 617 bool strict = args[5].toBoolean(); 618 if (strict && !result.ok()) { 619 // We need to tell our caller Object.defineProperty, 620 // that this operation failed, without actually throwing 621 // for web-compatibility reasons. 622 if (result.failureCode() == JSMSG_CANT_DEFINE_WINDOW_NC) { 623 args.rval().setBoolean(false); 624 return true; 625 } 626 627 return result.reportError(cx, obj, id); 628 } 629 630 args.rval().setBoolean(result.ok()); 631 return true; 632 } 633 634 static bool intrinsic_UnsafeSetReservedSlot(JSContext* cx, unsigned argc, 635 Value* vp) { 636 CallArgs args = CallArgsFromVp(argc, vp); 637 MOZ_ASSERT(args.length() == 3); 638 MOZ_ASSERT(args[0].isObject()); 639 MOZ_RELEASE_ASSERT(args[1].isInt32()); 640 MOZ_ASSERT(args[1].toInt32() >= 0); 641 642 uint32_t slot = uint32_t(args[1].toInt32()); 643 args[0].toObject().as<NativeObject>().setReservedSlot(slot, args[2]); 644 args.rval().setUndefined(); 645 return true; 646 } 647 648 static bool intrinsic_UnsafeGetReservedSlot(JSContext* cx, unsigned argc, 649 Value* vp) { 650 CallArgs args = CallArgsFromVp(argc, vp); 651 MOZ_ASSERT(args.length() == 2); 652 MOZ_ASSERT(args[0].isObject()); 653 MOZ_RELEASE_ASSERT(args[1].isInt32()); 654 MOZ_ASSERT(args[1].toInt32() >= 0); 655 656 uint32_t slot = uint32_t(args[1].toInt32()); 657 args.rval().set(args[0].toObject().as<NativeObject>().getReservedSlot(slot)); 658 return true; 659 } 660 661 static bool intrinsic_UnsafeGetObjectFromReservedSlot(JSContext* cx, 662 unsigned argc, 663 Value* vp) { 664 if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp)) { 665 return false; 666 } 667 MOZ_ASSERT(vp->isObject()); 668 return true; 669 } 670 671 static bool intrinsic_UnsafeGetInt32FromReservedSlot(JSContext* cx, 672 unsigned argc, Value* vp) { 673 if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp)) { 674 return false; 675 } 676 MOZ_ASSERT(vp->isInt32()); 677 return true; 678 } 679 680 static bool intrinsic_UnsafeGetStringFromReservedSlot(JSContext* cx, 681 unsigned argc, 682 Value* vp) { 683 if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp)) { 684 return false; 685 } 686 MOZ_ASSERT(vp->isString()); 687 return true; 688 } 689 690 static bool intrinsic_IsPackedArray(JSContext* cx, unsigned argc, Value* vp) { 691 CallArgs args = CallArgsFromVp(argc, vp); 692 MOZ_ASSERT(args.length() == 1); 693 MOZ_ASSERT(args[0].isObject()); 694 args.rval().setBoolean(IsPackedArray(&args[0].toObject())); 695 return true; 696 } 697 698 bool js::intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, Value* vp) { 699 CallArgs args = CallArgsFromVp(argc, vp); 700 MOZ_ASSERT(args.length() == 0); 701 702 JSObject* obj = NewArrayIterator(cx); 703 if (!obj) { 704 return false; 705 } 706 707 args.rval().setObject(*obj); 708 return true; 709 } 710 711 static bool intrinsic_ArrayIteratorPrototypeOptimizable(JSContext* cx, 712 unsigned argc, 713 Value* vp) { 714 CallArgs args = CallArgsFromVp(argc, vp); 715 MOZ_ASSERT(args.length() == 0); 716 717 bool optimized = HasOptimizableArrayIteratorPrototype(cx); 718 args.rval().setBoolean(optimized); 719 return true; 720 } 721 722 static bool intrinsic_GetNextMapEntryForIterator(JSContext* cx, unsigned argc, 723 Value* vp) { 724 CallArgs args = CallArgsFromVp(argc, vp); 725 MOZ_ASSERT(args.length() == 2); 726 MOZ_ASSERT(args[0].toObject().is<MapIteratorObject>()); 727 MOZ_ASSERT(args[1].isObject()); 728 729 MapIteratorObject* mapIterator = &args[0].toObject().as<MapIteratorObject>(); 730 ArrayObject* result = &args[1].toObject().as<ArrayObject>(); 731 732 args.rval().setBoolean(MapIteratorObject::next(mapIterator, result)); 733 return true; 734 } 735 736 static bool intrinsic_CreateMapIterationResultPair(JSContext* cx, unsigned argc, 737 Value* vp) { 738 CallArgs args = CallArgsFromVp(argc, vp); 739 MOZ_ASSERT(args.length() == 0); 740 741 JSObject* result = MapIteratorObject::createResultPair(cx); 742 if (!result) { 743 return false; 744 } 745 746 args.rval().setObject(*result); 747 return true; 748 } 749 750 static bool intrinsic_GetNextSetEntryForIterator(JSContext* cx, unsigned argc, 751 Value* vp) { 752 CallArgs args = CallArgsFromVp(argc, vp); 753 MOZ_ASSERT(args.length() == 2); 754 MOZ_ASSERT(args[0].toObject().is<SetIteratorObject>()); 755 MOZ_ASSERT(args[1].isObject()); 756 757 SetIteratorObject* setIterator = &args[0].toObject().as<SetIteratorObject>(); 758 ArrayObject* result = &args[1].toObject().as<ArrayObject>(); 759 760 args.rval().setBoolean(SetIteratorObject::next(setIterator, result)); 761 return true; 762 } 763 764 static bool intrinsic_CreateSetIterationResult(JSContext* cx, unsigned argc, 765 Value* vp) { 766 CallArgs args = CallArgsFromVp(argc, vp); 767 MOZ_ASSERT(args.length() == 0); 768 769 JSObject* result = SetIteratorObject::createResult(cx); 770 if (!result) { 771 return false; 772 } 773 774 args.rval().setObject(*result); 775 return true; 776 } 777 778 bool js::intrinsic_NewStringIterator(JSContext* cx, unsigned argc, Value* vp) { 779 CallArgs args = CallArgsFromVp(argc, vp); 780 MOZ_ASSERT(args.length() == 0); 781 782 JSObject* obj = NewStringIterator(cx); 783 if (!obj) { 784 return false; 785 } 786 787 args.rval().setObject(*obj); 788 return true; 789 } 790 791 bool js::intrinsic_NewRegExpStringIterator(JSContext* cx, unsigned argc, 792 Value* vp) { 793 CallArgs args = CallArgsFromVp(argc, vp); 794 MOZ_ASSERT(args.length() == 0); 795 796 JSObject* obj = NewRegExpStringIterator(cx); 797 if (!obj) { 798 return false; 799 } 800 801 args.rval().setObject(*obj); 802 return true; 803 } 804 805 js::PropertyName* js::GetClonedSelfHostedFunctionName(const JSFunction* fun) { 806 if (!fun->isExtended()) { 807 return nullptr; 808 } 809 Value name = fun->getExtendedSlot(LAZY_FUNCTION_NAME_SLOT); 810 if (!name.isString()) { 811 return nullptr; 812 } 813 return name.toString()->asAtom().asPropertyName(); 814 } 815 816 bool js::IsExtendedUnclonedSelfHostedFunctionName(JSAtom* name) { 817 if (name->length() < 2) { 818 return false; 819 } 820 return name->latin1OrTwoByteChar(0) == 821 ExtendedUnclonedSelfHostedFunctionNamePrefix; 822 } 823 824 void js::SetClonedSelfHostedFunctionName(JSFunction* fun, 825 js::PropertyName* name) { 826 fun->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(name)); 827 } 828 829 static bool intrinsic_GeneratorObjectIsClosed(JSContext* cx, unsigned argc, 830 Value* vp) { 831 CallArgs args = CallArgsFromVp(argc, vp); 832 MOZ_ASSERT(args.length() == 1); 833 MOZ_ASSERT(args[0].isObject()); 834 835 GeneratorObject* genObj = &args[0].toObject().as<GeneratorObject>(); 836 args.rval().setBoolean(genObj->isClosed()); 837 return true; 838 } 839 840 static bool intrinsic_IsSuspendedGenerator(JSContext* cx, unsigned argc, 841 Value* vp) { 842 CallArgs args = CallArgsFromVp(argc, vp); 843 MOZ_ASSERT(args.length() == 1); 844 845 if (!args[0].isObject() || !args[0].toObject().is<GeneratorObject>()) { 846 args.rval().setBoolean(false); 847 return true; 848 } 849 850 GeneratorObject& genObj = args[0].toObject().as<GeneratorObject>(); 851 MOZ_ASSERT_IF(genObj.isSuspended(), !genObj.isClosed()); 852 args.rval().setBoolean(genObj.isSuspended()); 853 return true; 854 } 855 856 static bool intrinsic_GeneratorIsRunning(JSContext* cx, unsigned argc, 857 Value* vp) { 858 CallArgs args = CallArgsFromVp(argc, vp); 859 MOZ_ASSERT(args.length() == 1); 860 MOZ_ASSERT(args[0].isObject()); 861 862 GeneratorObject* genObj = &args[0].toObject().as<GeneratorObject>(); 863 args.rval().setBoolean(genObj->isRunning()); 864 return true; 865 } 866 867 static bool intrinsic_GeneratorSetClosed(JSContext* cx, unsigned argc, 868 Value* vp) { 869 CallArgs args = CallArgsFromVp(argc, vp); 870 MOZ_ASSERT(args.length() == 1); 871 MOZ_ASSERT(args[0].isObject()); 872 873 GeneratorObject* genObj = &args[0].toObject().as<GeneratorObject>(); 874 genObj->setClosed(cx); 875 return true; 876 } 877 878 static bool intrinsic_IsTypedArrayConstructor(JSContext* cx, unsigned argc, 879 Value* vp) { 880 CallArgs args = CallArgsFromVp(argc, vp); 881 MOZ_ASSERT(args.length() == 1); 882 MOZ_ASSERT(args[0].isObject()); 883 884 args.rval().setBoolean(js::IsTypedArrayConstructor(&args[0].toObject())); 885 return true; 886 } 887 888 // Return the value of [[ArrayLength]] internal slot of the TypedArray 889 static bool intrinsic_TypedArrayLength(JSContext* cx, unsigned argc, 890 Value* vp) { 891 CallArgs args = CallArgsFromVp(argc, vp); 892 MOZ_ASSERT(args.length() == 1); 893 MOZ_ASSERT(args[0].toObject().is<TypedArrayObject>()); 894 895 auto* tarr = &args[0].toObject().as<TypedArrayObject>(); 896 897 mozilla::Maybe<size_t> length = tarr->length(); 898 if (!length) { 899 // Return zero for detached buffers to match JIT code. 900 if (tarr->hasDetachedBuffer()) { 901 args.rval().setInt32(0); 902 return true; 903 } 904 905 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 906 JSMSG_TYPED_ARRAY_RESIZED_BOUNDS); 907 return false; 908 } 909 910 args.rval().setNumber(*length); 911 return true; 912 } 913 914 static bool intrinsic_PossiblyWrappedTypedArrayLength(JSContext* cx, 915 unsigned argc, 916 Value* vp) { 917 CallArgs args = CallArgsFromVp(argc, vp); 918 MOZ_ASSERT(args.length() == 1); 919 MOZ_ASSERT(args[0].isObject()); 920 921 TypedArrayObject* obj = args[0].toObject().maybeUnwrapAs<TypedArrayObject>(); 922 if (!obj) { 923 ReportAccessDenied(cx); 924 return false; 925 } 926 927 mozilla::Maybe<size_t> length = obj->length(); 928 if (!length) { 929 // Return zero for detached buffers to match JIT code. 930 if (obj->hasDetachedBuffer()) { 931 args.rval().setInt32(0); 932 return true; 933 } 934 935 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 936 JSMSG_TYPED_ARRAY_RESIZED_BOUNDS); 937 return false; 938 } 939 940 args.rval().setNumber(*length); 941 return true; 942 } 943 944 static bool intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer(JSContext* cx, 945 unsigned argc, 946 Value* vp) { 947 CallArgs args = CallArgsFromVp(argc, vp); 948 MOZ_ASSERT(args.length() == 1); 949 MOZ_ASSERT(args[0].isObject()); 950 951 TypedArrayObject* obj = args[0].toObject().maybeUnwrapAs<TypedArrayObject>(); 952 if (!obj) { 953 ReportAccessDenied(cx); 954 return false; 955 } 956 957 bool detached = obj->hasDetachedBuffer(); 958 args.rval().setBoolean(detached); 959 return true; 960 } 961 962 static bool intrinsic_PossiblyWrappedTypedArrayHasImmutableBuffer(JSContext* cx, 963 unsigned argc, 964 Value* vp) { 965 CallArgs args = CallArgsFromVp(argc, vp); 966 MOZ_ASSERT(args.length() == 1); 967 MOZ_ASSERT(args[0].isObject()); 968 969 auto* obj = args[0].toObject().maybeUnwrapAs<TypedArrayObject>(); 970 if (!obj) { 971 ReportAccessDenied(cx); 972 return false; 973 } 974 975 bool immutable = obj->is<ImmutableTypedArrayObject>(); 976 args.rval().setBoolean(immutable); 977 return true; 978 } 979 980 static bool intrinsic_TypedArrayInitFromPackedArray(JSContext* cx, 981 unsigned argc, Value* vp) { 982 CallArgs args = CallArgsFromVp(argc, vp); 983 MOZ_ASSERT(args.length() == 2); 984 MOZ_ASSERT(args[0].isObject()); 985 MOZ_ASSERT(args[1].isObject()); 986 987 Rooted<FixedLengthTypedArrayObject*> target( 988 cx, &args[0].toObject().as<FixedLengthTypedArrayObject>()); 989 MOZ_ASSERT(!target->hasDetachedBuffer()); 990 MOZ_ASSERT(!target->isSharedMemory()); 991 992 Rooted<ArrayObject*> source(cx, &args[1].toObject().as<ArrayObject>()); 993 MOZ_ASSERT(IsPackedArray(source)); 994 MOZ_ASSERT(source->length() == target->length()); 995 996 switch (target->type()) { 997 #define INIT_TYPED_ARRAY(_, T, N) \ 998 case Scalar::N: { \ 999 if (!ElementSpecific<T, UnsharedOps>::initFromIterablePackedArray( \ 1000 cx, target, source)) { \ 1001 return false; \ 1002 } \ 1003 break; \ 1004 } 1005 JS_FOR_EACH_TYPED_ARRAY(INIT_TYPED_ARRAY) 1006 #undef INIT_TYPED_ARRAY 1007 1008 default: 1009 MOZ_CRASH( 1010 "TypedArrayInitFromPackedArray with a typed array with bogus type"); 1011 } 1012 1013 args.rval().setUndefined(); 1014 return true; 1015 } 1016 1017 template <bool ForTest> 1018 static bool intrinsic_RegExpBuiltinExec(JSContext* cx, unsigned argc, 1019 Value* vp) { 1020 CallArgs args = CallArgsFromVp(argc, vp); 1021 MOZ_ASSERT(args.length() == 2); 1022 MOZ_ASSERT(args[0].isObject()); 1023 MOZ_ASSERT(args[0].toObject().is<RegExpObject>()); 1024 MOZ_ASSERT(args[1].isString()); 1025 1026 Rooted<RegExpObject*> obj(cx, &args[0].toObject().as<RegExpObject>()); 1027 Rooted<JSString*> string(cx, args[1].toString()); 1028 return RegExpBuiltinExec(cx, obj, string, ForTest, args.rval()); 1029 } 1030 1031 template <bool ForTest> 1032 static bool intrinsic_RegExpExec(JSContext* cx, unsigned argc, Value* vp) { 1033 CallArgs args = CallArgsFromVp(argc, vp); 1034 MOZ_ASSERT(args.length() == 2); 1035 MOZ_ASSERT(args[0].isObject()); 1036 MOZ_ASSERT(args[1].isString()); 1037 1038 Rooted<JSObject*> obj(cx, &args[0].toObject()); 1039 Rooted<JSString*> string(cx, args[1].toString()); 1040 return RegExpExec(cx, obj, string, ForTest, args.rval()); 1041 } 1042 1043 static bool intrinsic_RegExpCreate(JSContext* cx, unsigned argc, Value* vp) { 1044 CallArgs args = CallArgsFromVp(argc, vp); 1045 1046 MOZ_ASSERT(args.length() == 1 || args.length() == 2); 1047 MOZ_ASSERT_IF(args.length() == 2, 1048 args[1].isString() || args[1].isUndefined()); 1049 MOZ_ASSERT(!args.isConstructing()); 1050 1051 return RegExpCreate(cx, args[0], args.get(1), args.rval(), nullptr); 1052 } 1053 1054 static bool intrinsic_RegExpGetSubstitution(JSContext* cx, unsigned argc, 1055 Value* vp) { 1056 CallArgs args = CallArgsFromVp(argc, vp); 1057 MOZ_ASSERT(args.length() == 6); 1058 1059 Rooted<ArrayObject*> matchResult(cx, &args[0].toObject().as<ArrayObject>()); 1060 1061 Rooted<JSLinearString*> string(cx, args[1].toString()->ensureLinear(cx)); 1062 if (!string) { 1063 return false; 1064 } 1065 1066 int32_t position = int32_t(args[2].toNumber()); 1067 MOZ_ASSERT(position >= 0); 1068 1069 Rooted<JSLinearString*> replacement(cx, args[3].toString()->ensureLinear(cx)); 1070 if (!replacement) { 1071 return false; 1072 } 1073 1074 int32_t firstDollarIndex = int32_t(args[4].toNumber()); 1075 MOZ_ASSERT(firstDollarIndex >= 0); 1076 1077 RootedValue namedCaptures(cx, args[5]); 1078 MOZ_ASSERT(namedCaptures.isUndefined() || namedCaptures.isObject()); 1079 1080 return RegExpGetSubstitution(cx, matchResult, string, size_t(position), 1081 replacement, size_t(firstDollarIndex), 1082 namedCaptures, args.rval()); 1083 } 1084 1085 static bool intrinsic_RegExpHasCaptureGroups(JSContext* cx, unsigned argc, 1086 Value* vp) { 1087 CallArgs args = CallArgsFromVp(argc, vp); 1088 MOZ_ASSERT(args.length() == 2); 1089 MOZ_ASSERT(args[0].isObject()); 1090 MOZ_ASSERT(args[1].isString()); 1091 1092 Rooted<RegExpObject*> obj(cx, &args[0].toObject().as<RegExpObject>()); 1093 Rooted<JSString*> string(cx, args[1].toString()); 1094 1095 bool result; 1096 if (!RegExpHasCaptureGroups(cx, obj, string, &result)) { 1097 return false; 1098 } 1099 1100 args.rval().setBoolean(result); 1101 return true; 1102 } 1103 1104 static bool intrinsic_StringReplaceString(JSContext* cx, unsigned argc, 1105 Value* vp) { 1106 CallArgs args = CallArgsFromVp(argc, vp); 1107 MOZ_ASSERT(args.length() == 3); 1108 1109 RootedString string(cx, args[0].toString()); 1110 RootedString pattern(cx, args[1].toString()); 1111 RootedString replacement(cx, args[2].toString()); 1112 JSString* result = str_replace_string_raw(cx, string, pattern, replacement); 1113 if (!result) { 1114 return false; 1115 } 1116 1117 args.rval().setString(result); 1118 return true; 1119 } 1120 1121 static bool intrinsic_StringReplaceAllString(JSContext* cx, unsigned argc, 1122 Value* vp) { 1123 CallArgs args = CallArgsFromVp(argc, vp); 1124 MOZ_ASSERT(args.length() == 3); 1125 1126 RootedString string(cx, args[0].toString()); 1127 RootedString pattern(cx, args[1].toString()); 1128 RootedString replacement(cx, args[2].toString()); 1129 JSString* result = 1130 str_replaceAll_string_raw(cx, string, pattern, replacement); 1131 if (!result) { 1132 return false; 1133 } 1134 1135 args.rval().setString(result); 1136 return true; 1137 } 1138 1139 static bool intrinsic_StringSplitString(JSContext* cx, unsigned argc, 1140 Value* vp) { 1141 CallArgs args = CallArgsFromVp(argc, vp); 1142 MOZ_ASSERT(args.length() == 2); 1143 1144 RootedString string(cx, args[0].toString()); 1145 RootedString sep(cx, args[1].toString()); 1146 1147 JSObject* aobj = StringSplitString(cx, string, sep, INT32_MAX); 1148 if (!aobj) { 1149 return false; 1150 } 1151 1152 args.rval().setObject(*aobj); 1153 return true; 1154 } 1155 1156 static bool intrinsic_StringSplitStringLimit(JSContext* cx, unsigned argc, 1157 Value* vp) { 1158 CallArgs args = CallArgsFromVp(argc, vp); 1159 MOZ_ASSERT(args.length() == 3); 1160 1161 RootedString string(cx, args[0].toString()); 1162 RootedString sep(cx, args[1].toString()); 1163 1164 // args[2] should be already in UInt32 range, but it could be double typed, 1165 // because of Ion optimization. 1166 uint32_t limit = uint32_t(args[2].toNumber()); 1167 MOZ_ASSERT(limit > 0, 1168 "Zero limit case is already handled in self-hosted code."); 1169 1170 JSObject* aobj = StringSplitString(cx, string, sep, limit); 1171 if (!aobj) { 1172 return false; 1173 } 1174 1175 args.rval().setObject(*aobj); 1176 return true; 1177 } 1178 1179 bool CallSelfHostedNonGenericMethod(JSContext* cx, const CallArgs& args) { 1180 // This function is called when a self-hosted method is invoked on a 1181 // wrapper object, like a CrossCompartmentWrapper. The last argument is 1182 // the name of the self-hosted function. The other arguments are the 1183 // arguments to pass to this function. 1184 1185 MOZ_ASSERT(args.length() > 0); 1186 Rooted<PropertyName*> name( 1187 cx, args[args.length() - 1].toString()->asAtom().asPropertyName()); 1188 1189 InvokeArgs args2(cx); 1190 if (!args2.init(cx, args.length() - 1)) { 1191 return false; 1192 } 1193 1194 for (size_t i = 0; i < args.length() - 1; i++) { 1195 args2[i].set(args[i]); 1196 } 1197 1198 return CallSelfHostedFunction(cx, name, args.thisv(), args2, args.rval()); 1199 } 1200 1201 #ifdef DEBUG 1202 bool js::CallSelfHostedFunction(JSContext* cx, const char* name, 1203 HandleValue thisv, const AnyInvokeArgs& args, 1204 MutableHandleValue rval) { 1205 JSAtom* funAtom = Atomize(cx, name, strlen(name)); 1206 if (!funAtom) { 1207 return false; 1208 } 1209 Rooted<PropertyName*> funName(cx, funAtom->asPropertyName()); 1210 return CallSelfHostedFunction(cx, funName, thisv, args, rval); 1211 } 1212 #endif 1213 1214 bool js::CallSelfHostedFunction(JSContext* cx, Handle<PropertyName*> name, 1215 HandleValue thisv, const AnyInvokeArgs& args, 1216 MutableHandleValue rval) { 1217 RootedValue fun(cx); 1218 if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &fun)) { 1219 return false; 1220 } 1221 MOZ_ASSERT(fun.toObject().is<JSFunction>()); 1222 1223 return Call(cx, fun, thisv, args, rval); 1224 } 1225 1226 template <typename T> 1227 bool Is(HandleValue v) { 1228 return v.isObject() && v.toObject().is<T>(); 1229 } 1230 1231 template <IsAcceptableThis Test> 1232 static bool CallNonGenericSelfhostedMethod(JSContext* cx, unsigned argc, 1233 Value* vp) { 1234 CallArgs args = CallArgsFromVp(argc, vp); 1235 return CallNonGenericMethod<Test, CallSelfHostedNonGenericMethod>(cx, args); 1236 } 1237 1238 bool js::IsCallSelfHostedNonGenericMethod(NativeImpl impl) { 1239 return impl == CallSelfHostedNonGenericMethod; 1240 } 1241 1242 bool js::ReportIncompatibleSelfHostedMethod( 1243 JSContext* cx, Handle<Value> thisValue, 1244 IncompatibleContext incompatibleContext) { 1245 // The contract for this function is the same as 1246 // CallSelfHostedNonGenericMethod. The normal ReportIncompatible function 1247 // doesn't work for selfhosted functions, because they always call the 1248 // different CallXXXMethodIfWrapped methods, which would be reported as the 1249 // called function instead. 1250 1251 // Lookup the selfhosted method that was invoked. But skip over 1252 // internal self-hosted function frames, because those are never the 1253 // actual self-hosted callee from external code. We can't just skip 1254 // self-hosted things until we find a non-self-hosted one because of cases 1255 // like array.sort(somethingSelfHosted), where we want to report the error 1256 // in the somethingSelfHosted, not in the sort() call. 1257 1258 static const char* const internalNames[] = { 1259 "EnsureTypedArrayWithArrayBuffer", 1260 "RegExpSearchSlowPath", 1261 "RegExpReplaceSlowPath", 1262 "RegExpMatchSlowPath", 1263 }; 1264 1265 ScriptFrameIter iter(cx); 1266 MOZ_ASSERT(iter.isFunctionFrame()); 1267 1268 while (!iter.done()) { 1269 MOZ_ASSERT(iter.callee(cx)->isSelfHostedOrIntrinsic()); 1270 UniqueChars funNameBytes; 1271 const char* funName = 1272 GetFunctionNameBytes(cx, iter.callee(cx), &funNameBytes); 1273 if (!funName) { 1274 return false; 1275 } 1276 if (std::all_of( 1277 std::begin(internalNames), std::end(internalNames), 1278 [funName](auto* name) { return strcmp(funName, name) != 0; })) { 1279 if (incompatibleContext == IncompatibleContext::RegExpExec) { 1280 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 1281 JSMSG_INCOMPATIBLE_REGEXP_METHOD, funName, 1282 InformalValueTypeName(thisValue)); 1283 } else { 1284 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 1285 JSMSG_INCOMPATIBLE_METHOD, funName, "method", 1286 InformalValueTypeName(thisValue)); 1287 } 1288 return false; 1289 } 1290 ++iter; 1291 } 1292 1293 MOZ_ASSERT_UNREACHABLE("How did we not find a useful self-hosted frame?"); 1294 return false; 1295 } 1296 1297 #ifdef JS_HAS_INTL_API 1298 static bool intrinsic_DefaultLocale(JSContext* cx, unsigned argc, Value* vp) { 1299 CallArgs args = CallArgsFromVp(argc, vp); 1300 MOZ_ASSERT(args.length() == 0); 1301 1302 auto* locale = cx->global()->globalIntlData().defaultLocale(cx); 1303 if (!locale) { 1304 return false; 1305 } 1306 1307 args.rval().setString(locale); 1308 return true; 1309 } 1310 1311 static bool intrinsic_DefaultTimeZone(JSContext* cx, unsigned argc, Value* vp) { 1312 CallArgs args = CallArgsFromVp(argc, vp); 1313 MOZ_ASSERT(args.length() == 0); 1314 1315 auto* timeZone = cx->global()->globalIntlData().defaultTimeZone(cx); 1316 if (!timeZone) { 1317 return false; 1318 } 1319 1320 args.rval().setString(timeZone); 1321 return true; 1322 } 1323 1324 static bool intl_ValidateAndCanonicalizeTimeZone(JSContext* cx, unsigned argc, 1325 Value* vp) { 1326 CallArgs args = CallArgsFromVp(argc, vp); 1327 MOZ_ASSERT(args.length() == 1); 1328 1329 Rooted<JSString*> timeZone(cx, args[0].toString()); 1330 auto* timeZoneId = temporal::ToValidCanonicalTimeZoneIdentifier(cx, timeZone); 1331 if (!timeZoneId) { 1332 return false; 1333 } 1334 1335 args.rval().setString(timeZoneId); 1336 return true; 1337 } 1338 #endif // JS_HAS_INTL_API 1339 1340 static bool intrinsic_ConstructFunction(JSContext* cx, unsigned argc, 1341 Value* vp) { 1342 CallArgs args = CallArgsFromVp(argc, vp); 1343 MOZ_ASSERT(args.length() == 3); 1344 MOZ_ASSERT(IsConstructor(args[0])); 1345 MOZ_ASSERT(IsConstructor(args[1])); 1346 MOZ_ASSERT(args[2].toObject().is<ArrayObject>()); 1347 1348 Rooted<ArrayObject*> argsList(cx, &args[2].toObject().as<ArrayObject>()); 1349 uint32_t len = argsList->length(); 1350 ConstructArgs constructArgs(cx); 1351 if (!constructArgs.init(cx, len)) { 1352 return false; 1353 } 1354 for (uint32_t index = 0; index < len; index++) { 1355 constructArgs[index].set(argsList->getDenseElement(index)); 1356 } 1357 1358 RootedObject res(cx); 1359 if (!Construct(cx, args[0], constructArgs, args[1], &res)) { 1360 return false; 1361 } 1362 1363 args.rval().setObject(*res); 1364 return true; 1365 } 1366 1367 static bool intrinsic_IsConstructing(JSContext* cx, unsigned argc, Value* vp) { 1368 CallArgs args = CallArgsFromVp(argc, vp); 1369 MOZ_ASSERT(args.length() == 0); 1370 1371 ScriptFrameIter iter(cx); 1372 bool isConstructing = iter.isConstructing(); 1373 args.rval().setBoolean(isConstructing); 1374 return true; 1375 } 1376 1377 static bool intrinsic_ConstructorForTypedArray(JSContext* cx, unsigned argc, 1378 Value* vp) { 1379 CallArgs args = CallArgsFromVp(argc, vp); 1380 MOZ_ASSERT(args.length() == 1); 1381 MOZ_ASSERT(args[0].isObject()); 1382 1383 auto* object = UnwrapAndDowncastValue<TypedArrayObject>(cx, args[0]); 1384 if (!object) { 1385 return false; 1386 } 1387 1388 JSProtoKey protoKey = StandardProtoKeyOrNull(object); 1389 MOZ_ASSERT(protoKey); 1390 1391 // While it may seem like an invariant that in any compartment, 1392 // seeing a typed array object implies that the TypedArray constructor 1393 // for that type is initialized on the compartment's global, this is not 1394 // the case. When we construct a typed array given a cross-compartment 1395 // ArrayBuffer, we put the constructed TypedArray in the same compartment 1396 // as the ArrayBuffer. Since we use the prototype from the initial 1397 // compartment, and never call the constructor in the ArrayBuffer's 1398 // compartment from script, we are not guaranteed to have initialized 1399 // the constructor. 1400 JSObject* ctor = GlobalObject::getOrCreateConstructor(cx, protoKey); 1401 if (!ctor) { 1402 return false; 1403 } 1404 1405 args.rval().setObject(*ctor); 1406 return true; 1407 } 1408 1409 static bool intrinsic_PromiseResolve(JSContext* cx, unsigned argc, Value* vp) { 1410 CallArgs args = CallArgsFromVp(argc, vp); 1411 MOZ_ASSERT(args.length() == 2); 1412 1413 RootedObject constructor(cx, &args[0].toObject()); 1414 JSObject* promise = js::PromiseResolve(cx, constructor, args[1]); 1415 if (!promise) { 1416 return false; 1417 } 1418 1419 args.rval().setObject(*promise); 1420 return true; 1421 } 1422 1423 static bool intrinsic_CopyDataPropertiesOrGetOwnKeys(JSContext* cx, 1424 unsigned argc, Value* vp) { 1425 CallArgs args = CallArgsFromVp(argc, vp); 1426 MOZ_ASSERT(args.length() == 3); 1427 MOZ_ASSERT(args[0].isObject()); 1428 MOZ_ASSERT(args[1].isObject()); 1429 MOZ_ASSERT(args[2].isObjectOrNull()); 1430 1431 RootedObject target(cx, &args[0].toObject()); 1432 RootedObject from(cx, &args[1].toObject()); 1433 RootedObject excludedItems(cx, args[2].toObjectOrNull()); 1434 1435 if (from->is<NativeObject>() && target->is<PlainObject>() && 1436 (!excludedItems || excludedItems->is<PlainObject>())) { 1437 bool optimized; 1438 if (!CopyDataPropertiesNative( 1439 cx, target.as<PlainObject>(), from.as<NativeObject>(), 1440 (excludedItems ? excludedItems.as<PlainObject>() : nullptr), 1441 &optimized)) { 1442 return false; 1443 } 1444 1445 if (optimized) { 1446 args.rval().setNull(); 1447 return true; 1448 } 1449 } 1450 1451 return GetOwnPropertyKeys( 1452 cx, from, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, args.rval()); 1453 } 1454 1455 static bool intrinsic_NewWrapForValidIterator(JSContext* cx, unsigned argc, 1456 Value* vp) { 1457 CallArgs args = CallArgsFromVp(argc, vp); 1458 MOZ_ASSERT(args.length() == 0); 1459 1460 JSObject* obj = NewWrapForValidIterator(cx); 1461 if (!obj) { 1462 return false; 1463 } 1464 1465 args.rval().setObject(*obj); 1466 return true; 1467 } 1468 1469 static bool intrinsic_NewIteratorHelper(JSContext* cx, unsigned argc, 1470 Value* vp) { 1471 CallArgs args = CallArgsFromVp(argc, vp); 1472 MOZ_ASSERT(args.length() == 0); 1473 1474 JSObject* obj = NewIteratorHelper(cx); 1475 if (!obj) { 1476 return false; 1477 } 1478 1479 args.rval().setObject(*obj); 1480 return true; 1481 } 1482 1483 static bool intrinsic_NewAsyncIteratorHelper(JSContext* cx, unsigned argc, 1484 Value* vp) { 1485 CallArgs args = CallArgsFromVp(argc, vp); 1486 MOZ_ASSERT(args.length() == 0); 1487 1488 JSObject* obj = NewAsyncIteratorHelper(cx); 1489 if (!obj) { 1490 return false; 1491 } 1492 1493 args.rval().setObject(*obj); 1494 return true; 1495 } 1496 1497 #ifdef NIGHTLY_BUILD 1498 static bool intrinsic_NewIteratorRange(JSContext* cx, unsigned argc, 1499 Value* vp) { 1500 CallArgs args = CallArgsFromVp(argc, vp); 1501 MOZ_ASSERT(args.length() == 0); 1502 1503 JSObject* obj = NewIteratorRange(cx); 1504 if (!obj) { 1505 return false; 1506 } 1507 1508 args.rval().setObject(*obj); 1509 return true; 1510 } 1511 #endif 1512 1513 static JSObject* NewIteratorRecord(JSContext* cx, HandleObject iterator, 1514 HandleValue nextMethod) { 1515 gc::AllocKind allocKind = gc::GetGCObjectKind(3); 1516 Rooted<PlainObject*> obj( 1517 cx, NewPlainObjectWithProtoAndAllocKind(cx, nullptr, allocKind)); 1518 if (!obj) { 1519 return nullptr; 1520 } 1521 1522 RootedId propid(cx, NameToId(cx->names().iterator)); 1523 RootedValue value(cx, ObjectValue(*iterator)); 1524 if (!NativeDefineDataProperty(cx, obj, propid, value, JSPROP_ENUMERATE)) { 1525 return nullptr; 1526 } 1527 1528 propid = NameToId(cx->names().nextMethod); 1529 value.set(nextMethod); 1530 if (!NativeDefineDataProperty(cx, obj, propid, value, JSPROP_ENUMERATE)) { 1531 return nullptr; 1532 } 1533 1534 propid = NameToId(cx->names().done); 1535 value.setBoolean(false); 1536 if (!NativeDefineDataProperty(cx, obj, propid, value, JSPROP_ENUMERATE)) { 1537 return nullptr; 1538 } 1539 1540 return obj; 1541 } 1542 1543 static bool intrinsic_CreateAsyncFromSyncIterator(JSContext* cx, unsigned argc, 1544 Value* vp) { 1545 CallArgs args = CallArgsFromVp(argc, vp); 1546 MOZ_ASSERT(args.length() == 2); 1547 1548 RootedObject iterator(cx, &args[0].toObject()); 1549 RootedObject asyncIterator( 1550 cx, CreateAsyncFromSyncIterator(cx, iterator, args[1])); 1551 if (!asyncIterator) { 1552 return false; 1553 } 1554 1555 RootedValue nextMethod(cx); 1556 if (!GetProperty(cx, asyncIterator, asyncIterator, cx->names().next, 1557 &nextMethod)) { 1558 return false; 1559 } 1560 1561 RootedObject iteratorRecord(cx, 1562 NewIteratorRecord(cx, asyncIterator, nextMethod)); 1563 if (!iteratorRecord) { 1564 return false; 1565 } 1566 1567 args.rval().setObject(*iteratorRecord); 1568 return true; 1569 } 1570 1571 static bool intrinsic_NoPrivateGetter(JSContext* cx, unsigned argc, Value* vp) { 1572 CallArgs args = CallArgsFromVp(argc, vp); 1573 MOZ_ASSERT(args.length() == 0); 1574 1575 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 1576 JSMSG_PRIVATE_SETTER_ONLY); 1577 1578 args.rval().setUndefined(); 1579 return false; 1580 } 1581 1582 static bool intrinsic_newList(JSContext* cx, unsigned argc, js::Value* vp) { 1583 CallArgs args = CallArgsFromVp(argc, vp); 1584 MOZ_ASSERT(args.length() == 0); 1585 1586 ArrayObject* list = NewArrayWithNullProto(cx); 1587 if (!list) { 1588 return false; 1589 } 1590 1591 args.rval().setObject(*list); 1592 return true; 1593 } 1594 1595 static bool intrinsic_CanBeHeldWeakly(JSContext* cx, unsigned argc, Value* vp) { 1596 CallArgs args = CallArgsFromVp(argc, vp); 1597 MOZ_ASSERT(args.length() == 1); 1598 1599 args.rval().setBoolean(CanBeHeldWeakly(args[0])); 1600 return true; 1601 } 1602 1603 static const JSFunctionSpec intrinsic_functions[] = { 1604 // Intrinsic helper functions 1605 JS_INLINABLE_FN("ArrayIteratorPrototypeOptimizable", 1606 intrinsic_ArrayIteratorPrototypeOptimizable, 0, 0, 1607 IntrinsicArrayIteratorPrototypeOptimizable), 1608 JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1, 0), 1609 JS_FN("CallArrayIteratorMethodIfWrapped", 1610 CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>, 2, 0), 1611 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 1612 JS_FN("CallAsyncDisposableStackMethodIfWrapped", 1613 CallNonGenericSelfhostedMethod<Is<AsyncDisposableStackObject>>, 2, 0), 1614 #endif 1615 JS_FN("CallAsyncIteratorHelperMethodIfWrapped", 1616 CallNonGenericSelfhostedMethod<Is<AsyncIteratorHelperObject>>, 2, 0), 1617 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 1618 JS_FN("CallDisposableStackMethodIfWrapped", 1619 CallNonGenericSelfhostedMethod<Is<DisposableStackObject>>, 2, 0), 1620 #endif 1621 JS_FN("CallGeneratorMethodIfWrapped", 1622 CallNonGenericSelfhostedMethod<Is<GeneratorObject>>, 2, 0), 1623 JS_FN("CallIteratorHelperMethodIfWrapped", 1624 CallNonGenericSelfhostedMethod<Is<IteratorHelperObject>>, 2, 0), 1625 #ifdef NIGHTLY_BUILD 1626 JS_FN("CallIteratorRangeMethodIfWrapped", 1627 CallNonGenericSelfhostedMethod<Is<IteratorRangeObject>>, 2, 0), 1628 #endif 1629 JS_FN("CallMapIteratorMethodIfWrapped", 1630 CallNonGenericSelfhostedMethod<Is<MapIteratorObject>>, 2, 0), 1631 JS_FN("CallMapMethodIfWrapped", 1632 CallNonGenericSelfhostedMethod<Is<MapObject>>, 2, 0), 1633 JS_FN("CallRegExpMethodIfWrapped", 1634 CallNonGenericSelfhostedMethod<Is<RegExpObject>>, 2, 0), 1635 JS_FN("CallRegExpStringIteratorMethodIfWrapped", 1636 CallNonGenericSelfhostedMethod<Is<RegExpStringIteratorObject>>, 2, 0), 1637 JS_FN("CallSetIteratorMethodIfWrapped", 1638 CallNonGenericSelfhostedMethod<Is<SetIteratorObject>>, 2, 0), 1639 JS_FN("CallSetMethodIfWrapped", 1640 CallNonGenericSelfhostedMethod<Is<SetObject>>, 2, 0), 1641 JS_FN("CallStringIteratorMethodIfWrapped", 1642 CallNonGenericSelfhostedMethod<Is<StringIteratorObject>>, 2, 0), 1643 JS_FN("CallTypedArrayMethodIfWrapped", 1644 CallNonGenericSelfhostedMethod<Is<TypedArrayObject>>, 2, 0), 1645 JS_FN("CallWeakMapMethodIfWrapped", 1646 CallNonGenericSelfhostedMethod<Is<WeakMapObject>>, 2, 0), 1647 JS_FN("CallWrapForValidIteratorMethodIfWrapped", 1648 CallNonGenericSelfhostedMethod<Is<WrapForValidIteratorObject>>, 2, 0), 1649 JS_FN("CanBeHeldWeakly", intrinsic_CanBeHeldWeakly, 1, 0), 1650 JS_INLINABLE_FN("CanOptimizeArraySpecies", 1651 intrinsic_CanOptimizeArraySpecies, 1, 0, 1652 IntrinsicCanOptimizeArraySpecies), 1653 JS_FN("ConstructFunction", intrinsic_ConstructFunction, 2, 0), 1654 JS_FN("ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1, 0), 1655 JS_FN("CopyDataPropertiesOrGetOwnKeys", 1656 intrinsic_CopyDataPropertiesOrGetOwnKeys, 3, 0), 1657 JS_FN("CreateAsyncFromSyncIterator", intrinsic_CreateAsyncFromSyncIterator, 1658 2, 0), 1659 JS_FN("CreateMapIterationResultPair", 1660 intrinsic_CreateMapIterationResultPair, 0, 0), 1661 JS_FN("CreateSetIterationResult", intrinsic_CreateSetIterationResult, 0, 0), 1662 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 1663 JS_FN("CreateSuppressedError", intrinsic_CreateSuppressedError, 2, 0), 1664 #endif 1665 JS_FN("DecompileArg", intrinsic_DecompileArg, 2, 0), 1666 JS_FN("DefineDataProperty", intrinsic_DefineDataProperty, 4, 0), 1667 JS_FN("DefineProperty", intrinsic_DefineProperty, 6, 0), 1668 JS_FN("DumpMessage", intrinsic_DumpMessage, 1, 0), 1669 JS_FN("FlatStringMatch", FlatStringMatch, 2, 0), 1670 JS_FN("FlatStringSearch", FlatStringSearch, 2, 0), 1671 JS_FN("GeneratorIsRunning", intrinsic_GeneratorIsRunning, 1, 0), 1672 JS_FN("GeneratorObjectIsClosed", intrinsic_GeneratorObjectIsClosed, 1, 0), 1673 JS_FN("GeneratorSetClosed", intrinsic_GeneratorSetClosed, 1, 0), 1674 JS_FN("GetElemBaseForLambda", intrinsic_GetElemBaseForLambda, 1, 0), 1675 JS_INLINABLE_FN("GetFirstDollarIndex", GetFirstDollarIndex, 1, 0, 1676 GetFirstDollarIndex), 1677 JS_INLINABLE_FN("GetNextMapEntryForIterator", 1678 intrinsic_GetNextMapEntryForIterator, 2, 0, 1679 IntrinsicGetNextMapEntryForIterator), 1680 JS_INLINABLE_FN("GetNextSetEntryForIterator", 1681 intrinsic_GetNextSetEntryForIterator, 2, 0, 1682 IntrinsicGetNextSetEntryForIterator), 1683 JS_FN("GetOwnPropertyDescriptorToArray", GetOwnPropertyDescriptorToArray, 2, 1684 0), 1685 JS_FN("GetStringDataProperty", intrinsic_GetStringDataProperty, 2, 0), 1686 JS_INLINABLE_FN("GuardToArrayBuffer", 1687 intrinsic_GuardToBuiltin<ArrayBufferObject>, 1, 0, 1688 IntrinsicGuardToArrayBuffer), 1689 JS_INLINABLE_FN("GuardToArrayIterator", 1690 intrinsic_GuardToBuiltin<ArrayIteratorObject>, 1, 0, 1691 IntrinsicGuardToArrayIterator), 1692 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 1693 JS_INLINABLE_FN("GuardToAsyncDisposableStackHelper", 1694 intrinsic_GuardToBuiltin<AsyncDisposableStackObject>, 1, 0, 1695 IntrinsicGuardToAsyncDisposableStack), 1696 #endif 1697 JS_INLINABLE_FN("GuardToAsyncIteratorHelper", 1698 intrinsic_GuardToBuiltin<AsyncIteratorHelperObject>, 1, 0, 1699 IntrinsicGuardToAsyncIteratorHelper), 1700 #ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT 1701 JS_INLINABLE_FN("GuardToDisposableStackHelper", 1702 intrinsic_GuardToBuiltin<DisposableStackObject>, 1, 0, 1703 IntrinsicGuardToDisposableStack), 1704 #endif 1705 JS_INLINABLE_FN("GuardToIteratorHelper", 1706 intrinsic_GuardToBuiltin<IteratorHelperObject>, 1, 0, 1707 IntrinsicGuardToIteratorHelper), 1708 #ifdef NIGHTLY_BUILD 1709 JS_INLINABLE_FN("GuardToIteratorRange", 1710 intrinsic_GuardToBuiltin<IteratorRangeObject>, 1, 0, 1711 IntrinsicGuardToIteratorRange), 1712 #endif 1713 JS_INLINABLE_FN("GuardToMapIterator", 1714 intrinsic_GuardToBuiltin<MapIteratorObject>, 1, 0, 1715 IntrinsicGuardToMapIterator), 1716 JS_INLINABLE_FN("GuardToMapObject", intrinsic_GuardToBuiltin<MapObject>, 1, 1717 0, IntrinsicGuardToMapObject), 1718 JS_INLINABLE_FN("GuardToRegExpStringIterator", 1719 intrinsic_GuardToBuiltin<RegExpStringIteratorObject>, 1, 0, 1720 IntrinsicGuardToRegExpStringIterator), 1721 JS_INLINABLE_FN("GuardToSetIterator", 1722 intrinsic_GuardToBuiltin<SetIteratorObject>, 1, 0, 1723 IntrinsicGuardToSetIterator), 1724 JS_INLINABLE_FN("GuardToSetObject", intrinsic_GuardToBuiltin<SetObject>, 1, 1725 0, IntrinsicGuardToSetObject), 1726 JS_INLINABLE_FN("GuardToSharedArrayBuffer", 1727 intrinsic_GuardToBuiltin<SharedArrayBufferObject>, 1, 0, 1728 IntrinsicGuardToSharedArrayBuffer), 1729 JS_INLINABLE_FN("GuardToStringIterator", 1730 intrinsic_GuardToBuiltin<StringIteratorObject>, 1, 0, 1731 IntrinsicGuardToStringIterator), 1732 JS_FN("GuardToWeakMapObject", intrinsic_GuardToBuiltin<WeakMapObject>, 1, 1733 0), 1734 JS_INLINABLE_FN("GuardToWrapForValidIterator", 1735 intrinsic_GuardToBuiltin<WrapForValidIteratorObject>, 1, 0, 1736 IntrinsicGuardToWrapForValidIterator), 1737 JS_FN("IntrinsicAsyncGeneratorNext", AsyncGeneratorNext, 1, 0), 1738 JS_FN("IntrinsicAsyncGeneratorReturn", AsyncGeneratorReturn, 1, 0), 1739 JS_FN("IntrinsicAsyncGeneratorThrow", AsyncGeneratorThrow, 1, 0), 1740 JS_INLINABLE_FN("IsArray", intrinsic_IsArray, 1, 0, ArrayIsArray), 1741 JS_FN("IsAsyncFunctionGeneratorObject", 1742 intrinsic_IsInstanceOfBuiltin<AsyncFunctionGeneratorObject>, 1, 0), 1743 JS_FN("IsAsyncGeneratorObject", 1744 intrinsic_IsInstanceOfBuiltin<AsyncGeneratorObject>, 1, 0), 1745 JS_INLINABLE_FN("IsCallable", intrinsic_IsCallable, 1, 0, 1746 IntrinsicIsCallable), 1747 JS_INLINABLE_FN("IsConstructing", intrinsic_IsConstructing, 0, 0, 1748 IntrinsicIsConstructing), 1749 JS_INLINABLE_FN("IsConstructor", intrinsic_IsConstructor, 1, 0, 1750 IntrinsicIsConstructor), 1751 JS_INLINABLE_FN("IsCrossRealmArrayConstructor", 1752 intrinsic_IsCrossRealmArrayConstructor, 1, 0, 1753 IntrinsicIsCrossRealmArrayConstructor), 1754 JS_FN("IsGeneratorObject", intrinsic_IsInstanceOfBuiltin<GeneratorObject>, 1755 1, 0), 1756 JS_INLINABLE_FN("IsObject", intrinsic_IsObject, 1, 0, IntrinsicIsObject), 1757 JS_INLINABLE_FN("IsOptimizableRegExpObject", IsOptimizableRegExpObject, 1, 1758 0, IsOptimizableRegExpObject), 1759 JS_INLINABLE_FN("IsPackedArray", intrinsic_IsPackedArray, 1, 0, 1760 IntrinsicIsPackedArray), 1761 JS_INLINABLE_FN("IsPossiblyWrappedRegExpObject", 1762 intrinsic_IsPossiblyWrappedInstanceOfBuiltin<RegExpObject>, 1763 1, 0, IsPossiblyWrappedRegExpObject), 1764 JS_INLINABLE_FN( 1765 "IsPossiblyWrappedTypedArray", 1766 intrinsic_IsPossiblyWrappedInstanceOfBuiltin<TypedArrayObject>, 1, 0, 1767 IntrinsicIsPossiblyWrappedTypedArray), 1768 JS_INLINABLE_FN("IsRegExpObject", 1769 intrinsic_IsInstanceOfBuiltin<RegExpObject>, 1, 0, 1770 IsRegExpObject), 1771 JS_INLINABLE_FN("IsRegExpPrototypeOptimizable", 1772 IsRegExpPrototypeOptimizable, 0, 0, 1773 IsRegExpPrototypeOptimizable), 1774 JS_INLINABLE_FN("IsSuspendedGenerator", intrinsic_IsSuspendedGenerator, 1, 1775 0, IntrinsicIsSuspendedGenerator), 1776 JS_INLINABLE_FN("IsTypedArray", 1777 intrinsic_IsInstanceOfBuiltin<TypedArrayObject>, 1, 0, 1778 IntrinsicIsTypedArray), 1779 JS_INLINABLE_FN("IsTypedArrayConstructor", 1780 intrinsic_IsTypedArrayConstructor, 1, 0, 1781 IntrinsicIsTypedArrayConstructor), 1782 JS_INLINABLE_FN("NewArrayIterator", intrinsic_NewArrayIterator, 0, 0, 1783 IntrinsicNewArrayIterator), 1784 JS_FN("NewAsyncIteratorHelper", intrinsic_NewAsyncIteratorHelper, 0, 0), 1785 JS_FN("NewIteratorHelper", intrinsic_NewIteratorHelper, 0, 0), 1786 #ifdef NIGHTLY_BUILD 1787 JS_FN("NewIteratorRange", intrinsic_NewIteratorRange, 0, 0), 1788 #endif 1789 JS_INLINABLE_FN("NewRegExpStringIterator", 1790 intrinsic_NewRegExpStringIterator, 0, 0, 1791 IntrinsicNewRegExpStringIterator), 1792 JS_INLINABLE_FN("NewStringIterator", intrinsic_NewStringIterator, 0, 0, 1793 IntrinsicNewStringIterator), 1794 JS_FN("NewWrapForValidIterator", intrinsic_NewWrapForValidIterator, 0, 0), 1795 JS_FN("NoPrivateGetter", intrinsic_NoPrivateGetter, 1, 0), 1796 JS_FN("PossiblyWrappedTypedArrayHasDetachedBuffer", 1797 intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer, 1, 0), 1798 JS_FN("PossiblyWrappedTypedArrayHasImmutableBuffer", 1799 intrinsic_PossiblyWrappedTypedArrayHasImmutableBuffer, 1, 0), 1800 JS_INLINABLE_FN("PossiblyWrappedTypedArrayLength", 1801 intrinsic_PossiblyWrappedTypedArrayLength, 1, 0, 1802 IntrinsicPossiblyWrappedTypedArrayLength), 1803 JS_FN("PromiseResolve", intrinsic_PromiseResolve, 2, 0), 1804 JS_INLINABLE_FN("RegExpBuiltinExec", intrinsic_RegExpBuiltinExec<false>, 2, 1805 0, IntrinsicRegExpBuiltinExec), 1806 JS_INLINABLE_FN("RegExpBuiltinExecForTest", 1807 intrinsic_RegExpBuiltinExec<true>, 2, 0, 1808 IntrinsicRegExpBuiltinExecForTest), 1809 JS_FN("RegExpConstructRaw", regexp_construct_raw_flags, 2, 0), 1810 JS_FN("RegExpCreate", intrinsic_RegExpCreate, 2, 0), 1811 JS_INLINABLE_FN("RegExpExec", intrinsic_RegExpExec<false>, 2, 0, 1812 IntrinsicRegExpExec), 1813 JS_INLINABLE_FN("RegExpExecForTest", intrinsic_RegExpExec<true>, 2, 0, 1814 IntrinsicRegExpExecForTest), 1815 JS_FN("RegExpGetSubstitution", intrinsic_RegExpGetSubstitution, 5, 0), 1816 JS_INLINABLE_FN("RegExpHasCaptureGroups", intrinsic_RegExpHasCaptureGroups, 1817 2, 0, RegExpHasCaptureGroups), 1818 JS_INLINABLE_FN("RegExpMatcher", RegExpMatcher, 3, 0, RegExpMatcher), 1819 JS_INLINABLE_FN("RegExpSearcher", RegExpSearcher, 3, 0, RegExpSearcher), 1820 JS_INLINABLE_FN("RegExpSearcherLastLimit", RegExpSearcherLastLimit, 0, 0, 1821 RegExpSearcherLastLimit), 1822 JS_FN("ReportWarning", intrinsic_ReportWarning, 4, 0), 1823 JS_INLINABLE_FN("SameValue", js::obj_is, 2, 0, ObjectIs), 1824 JS_FN("SetCopy", SetObject::copy, 1, 0), 1825 JS_FN("StringReplaceAllString", intrinsic_StringReplaceAllString, 3, 0), 1826 JS_INLINABLE_FN("StringReplaceString", intrinsic_StringReplaceString, 3, 0, 1827 IntrinsicStringReplaceString), 1828 JS_INLINABLE_FN("StringSplitString", intrinsic_StringSplitString, 2, 0, 1829 IntrinsicStringSplitString), 1830 JS_FN("StringSplitStringLimit", intrinsic_StringSplitStringLimit, 3, 0), 1831 JS_INLINABLE_FN("SubstringKernel", intrinsic_SubstringKernel, 3, 0, 1832 IntrinsicSubstringKernel), 1833 JS_FN("ThrowAggregateError", intrinsic_ThrowAggregateError, 4, 0), 1834 JS_FN("ThrowInternalError", intrinsic_ThrowInternalError, 4, 0), 1835 JS_FN("ThrowRangeError", intrinsic_ThrowRangeError, 4, 0), 1836 JS_FN("ThrowTypeError", intrinsic_ThrowTypeError, 4, 0), 1837 JS_INLINABLE_FN("ToInteger", intrinsic_ToInteger, 1, 0, IntrinsicToInteger), 1838 JS_INLINABLE_FN("ToLength", intrinsic_ToLength, 1, 0, IntrinsicToLength), 1839 JS_INLINABLE_FN("ToObject", intrinsic_ToObject, 1, 0, IntrinsicToObject), 1840 JS_FN("ToPropertyKey", intrinsic_ToPropertyKey, 1, 0), 1841 JS_FN("ToSource", intrinsic_ToSource, 1, 0), 1842 JS_FN("TypedArrayInitFromPackedArray", 1843 intrinsic_TypedArrayInitFromPackedArray, 2, 0), 1844 JS_INLINABLE_FN("TypedArrayLength", intrinsic_TypedArrayLength, 1, 0, 1845 IntrinsicTypedArrayLength), 1846 JS_INLINABLE_FN("UnsafeGetInt32FromReservedSlot", 1847 intrinsic_UnsafeGetInt32FromReservedSlot, 2, 0, 1848 IntrinsicUnsafeGetInt32FromReservedSlot), 1849 JS_INLINABLE_FN("UnsafeGetObjectFromReservedSlot", 1850 intrinsic_UnsafeGetObjectFromReservedSlot, 2, 0, 1851 IntrinsicUnsafeGetObjectFromReservedSlot), 1852 JS_INLINABLE_FN("UnsafeGetReservedSlot", intrinsic_UnsafeGetReservedSlot, 2, 1853 0, IntrinsicUnsafeGetReservedSlot), 1854 JS_INLINABLE_FN("UnsafeGetStringFromReservedSlot", 1855 intrinsic_UnsafeGetStringFromReservedSlot, 2, 0, 1856 IntrinsicUnsafeGetStringFromReservedSlot), 1857 JS_INLINABLE_FN("UnsafeSetReservedSlot", intrinsic_UnsafeSetReservedSlot, 3, 1858 0, IntrinsicUnsafeSetReservedSlot), 1859 1860 // Intrinsics and standard functions used by Intl API implementation. 1861 #ifdef JS_HAS_INTL_API 1862 JS_FN("intl_BestAvailableLocale", intl_BestAvailableLocale, 3, 0), 1863 JS_FN("intl_CallCollatorMethodIfWrapped", 1864 CallNonGenericSelfhostedMethod<Is<CollatorObject>>, 2, 0), 1865 JS_FN("intl_CallDateTimeFormatMethodIfWrapped", 1866 CallNonGenericSelfhostedMethod<Is<DateTimeFormatObject>>, 2, 0), 1867 JS_FN("intl_CallDisplayNamesMethodIfWrapped", 1868 CallNonGenericSelfhostedMethod<Is<DisplayNamesObject>>, 2, 0), 1869 JS_FN("intl_CallDurationFormatMethodIfWrapped", 1870 CallNonGenericSelfhostedMethod<Is<DurationFormatObject>>, 2, 0), 1871 JS_FN("intl_CallListFormatMethodIfWrapped", 1872 CallNonGenericSelfhostedMethod<Is<ListFormatObject>>, 2, 0), 1873 JS_FN("intl_CallNumberFormatMethodIfWrapped", 1874 CallNonGenericSelfhostedMethod<Is<NumberFormatObject>>, 2, 0), 1875 JS_FN("intl_CallPluralRulesMethodIfWrapped", 1876 CallNonGenericSelfhostedMethod<Is<PluralRulesObject>>, 2, 0), 1877 JS_FN("intl_CallRelativeTimeFormatMethodIfWrapped", 1878 CallNonGenericSelfhostedMethod<Is<RelativeTimeFormatObject>>, 2, 0), 1879 JS_FN("intl_CallSegmentIteratorMethodIfWrapped", 1880 CallNonGenericSelfhostedMethod<Is<SegmentIteratorObject>>, 2, 0), 1881 JS_FN("intl_CallSegmenterMethodIfWrapped", 1882 CallNonGenericSelfhostedMethod<Is<SegmenterObject>>, 2, 0), 1883 JS_FN("intl_CallSegmentsMethodIfWrapped", 1884 CallNonGenericSelfhostedMethod<Is<SegmentsObject>>, 2, 0), 1885 JS_FN("intl_CompareStrings", intl_CompareStrings, 3, 0), 1886 JS_FN("intl_ComputeDisplayName", intl_ComputeDisplayName, 6, 0), 1887 JS_FN("intl_CreateSegmentIterator", intl_CreateSegmentIterator, 1, 0), 1888 JS_FN("intl_CreateSegmentsObject", intl_CreateSegmentsObject, 2, 0), 1889 JS_FN("intl_DefaultLocale", intrinsic_DefaultLocale, 0, 0), 1890 JS_FN("intl_DefaultTimeZone", intrinsic_DefaultTimeZone, 0, 0), 1891 JS_FN("intl_FindNextSegmentBoundaries", intl_FindNextSegmentBoundaries, 1, 1892 0), 1893 JS_FN("intl_FindSegmentBoundaries", intl_FindSegmentBoundaries, 2, 0), 1894 JS_FN("intl_FormatDateTime", intl_FormatDateTime, 2, 0), 1895 JS_FN("intl_FormatDateTimeRange", intl_FormatDateTimeRange, 4, 0), 1896 JS_FN("intl_FormatList", intl_FormatList, 3, 0), 1897 JS_FN("intl_FormatNumber", intl_FormatNumber, 3, 0), 1898 JS_FN("intl_FormatNumberRange", intl_FormatNumberRange, 4, 0), 1899 JS_FN("intl_FormatRelativeTime", intl_FormatRelativeTime, 4, 0), 1900 JS_FN("intl_GetCalendarInfo", intl_GetCalendarInfo, 1, 0), 1901 JS_FN("intl_GetPluralCategories", intl_GetPluralCategories, 1, 0), 1902 JS_INLINABLE_FN("intl_GuardToCollator", 1903 intrinsic_GuardToBuiltin<CollatorObject>, 1, 0, 1904 IntlGuardToCollator), 1905 JS_INLINABLE_FN("intl_GuardToDateTimeFormat", 1906 intrinsic_GuardToBuiltin<DateTimeFormatObject>, 1, 0, 1907 IntlGuardToDateTimeFormat), 1908 JS_INLINABLE_FN("intl_GuardToDisplayNames", 1909 intrinsic_GuardToBuiltin<DisplayNamesObject>, 1, 0, 1910 IntlGuardToDisplayNames), 1911 JS_INLINABLE_FN("intl_GuardToDurationFormat", 1912 intrinsic_GuardToBuiltin<DurationFormatObject>, 1, 0, 1913 IntlGuardToDurationFormat), 1914 JS_INLINABLE_FN("intl_GuardToListFormat", 1915 intrinsic_GuardToBuiltin<ListFormatObject>, 1, 0, 1916 IntlGuardToListFormat), 1917 JS_INLINABLE_FN("intl_GuardToNumberFormat", 1918 intrinsic_GuardToBuiltin<NumberFormatObject>, 1, 0, 1919 IntlGuardToNumberFormat), 1920 JS_INLINABLE_FN("intl_GuardToPluralRules", 1921 intrinsic_GuardToBuiltin<PluralRulesObject>, 1, 0, 1922 IntlGuardToPluralRules), 1923 JS_INLINABLE_FN("intl_GuardToRelativeTimeFormat", 1924 intrinsic_GuardToBuiltin<RelativeTimeFormatObject>, 1, 0, 1925 IntlGuardToRelativeTimeFormat), 1926 JS_INLINABLE_FN("intl_GuardToSegmentIterator", 1927 intrinsic_GuardToBuiltin<SegmentIteratorObject>, 1, 0, 1928 IntlGuardToSegmentIterator), 1929 JS_INLINABLE_FN("intl_GuardToSegmenter", 1930 intrinsic_GuardToBuiltin<SegmenterObject>, 1, 0, 1931 IntlGuardToSegmenter), 1932 JS_INLINABLE_FN("intl_GuardToSegments", 1933 intrinsic_GuardToBuiltin<SegmentsObject>, 1, 0, 1934 IntlGuardToSegments), 1935 JS_FN("intl_IsWrappedDateTimeFormat", 1936 intrinsic_IsWrappedInstanceOfBuiltin<DateTimeFormatObject>, 1, 0), 1937 JS_FN("intl_IsWrappedNumberFormat", 1938 intrinsic_IsWrappedInstanceOfBuiltin<NumberFormatObject>, 1, 0), 1939 JS_FN("intl_NumberFormat", intl_NumberFormat, 2, 0), 1940 JS_FN("intl_SelectPluralRule", intl_SelectPluralRule, 2, 0), 1941 JS_FN("intl_SelectPluralRuleRange", intl_SelectPluralRuleRange, 3, 0), 1942 JS_FN("intl_TryValidateAndCanonicalizeLanguageTag", 1943 intl_TryValidateAndCanonicalizeLanguageTag, 1, 0), 1944 JS_FN("intl_ValidateAndCanonicalizeLanguageTag", 1945 intl_ValidateAndCanonicalizeLanguageTag, 2, 0), 1946 JS_FN("intl_ValidateAndCanonicalizeTimeZone", 1947 intl_ValidateAndCanonicalizeTimeZone, 1, 0), 1948 JS_FN("intl_ValidateAndCanonicalizeUnicodeExtensionType", 1949 intl_ValidateAndCanonicalizeUnicodeExtensionType, 3, 0), 1950 JS_FN("intl_availableCalendars", intl_availableCalendars, 1, 0), 1951 JS_FN("intl_availableCollations", intl_availableCollations, 1, 0), 1952 # if DEBUG || MOZ_SYSTEM_ICU 1953 JS_FN("intl_availableMeasurementUnits", intl_availableMeasurementUnits, 0, 1954 0), 1955 # endif 1956 JS_FN("intl_defaultCalendar", intl_defaultCalendar, 1, 0), 1957 JS_FN("intl_isIgnorePunctuation", intl_isIgnorePunctuation, 1, 0), 1958 JS_FN("intl_isUpperCaseFirst", intl_isUpperCaseFirst, 1, 0), 1959 JS_FN("intl_numberingSystem", intl_numberingSystem, 1, 0), 1960 JS_FN("intl_resolveDateTimeFormatComponents", 1961 intl_resolveDateTimeFormatComponents, 3, 0), 1962 #endif // JS_HAS_INTL_API 1963 1964 // Standard builtins used by self-hosting. 1965 JS_FN("new_List", intrinsic_newList, 0, 0), 1966 JS_INLINABLE_FN("std_Array", array_construct, 1, 0, Array), 1967 JS_FN("std_Array_includes", array_includes, 1, 0), 1968 JS_FN("std_Array_indexOf", array_indexOf, 1, 0), 1969 JS_FN("std_Array_lastIndexOf", array_lastIndexOf, 1, 0), 1970 JS_INLINABLE_FN("std_Array_pop", array_pop, 0, 0, ArrayPop), 1971 JS_TRAMPOLINE_FN("std_Array_sort", array_sort, 1, 0, ArraySort), 1972 JS_FN("std_Function_apply", fun_apply, 2, 0), 1973 JS_FN("std_Map_entries", MapObject::entries, 0, 0), 1974 JS_INLINABLE_FN("std_Map_get", MapObject::get, 1, 0, MapGet), 1975 JS_INLINABLE_FN("std_Map_has", MapObject::has, 1, 0, MapHas), 1976 JS_INLINABLE_FN("std_Map_set", MapObject::set, 2, 0, MapSet), 1977 JS_INLINABLE_FN("std_Math_abs", math_abs, 1, 0, MathAbs), 1978 JS_INLINABLE_FN("std_Math_floor", math_floor, 1, 0, MathFloor), 1979 JS_INLINABLE_FN("std_Math_max", math_max, 2, 0, MathMax), 1980 JS_INLINABLE_FN("std_Math_min", math_min, 2, 0, MathMin), 1981 JS_INLINABLE_FN("std_Math_trunc", math_trunc, 1, 0, MathTrunc), 1982 JS_INLINABLE_FN("std_Object_create", obj_create, 2, 0, ObjectCreate), 1983 JS_INLINABLE_FN("std_Object_isPrototypeOf", obj_isPrototypeOf, 1, 0, 1984 ObjectIsPrototypeOf), 1985 JS_FN("std_Object_propertyIsEnumerable", obj_propertyIsEnumerable, 1, 0), 1986 JS_FN("std_Object_setProto", obj_setProto, 1, 0), 1987 JS_INLINABLE_FN("std_Object_toString", obj_toString, 0, 0, ObjectToString), 1988 JS_INLINABLE_FN("std_Reflect_getPrototypeOf", Reflect_getPrototypeOf, 1, 0, 1989 ReflectGetPrototypeOf), 1990 JS_FN("std_Reflect_isExtensible", Reflect_isExtensible, 1, 0), 1991 JS_FN("std_Reflect_ownKeys", Reflect_ownKeys, 1, 0), 1992 JS_INLINABLE_FN("std_Set_add", SetObject::add, 1, 0, SetAdd), 1993 JS_INLINABLE_FN("std_Set_delete", SetObject::delete_, 1, 0, SetDelete), 1994 JS_INLINABLE_FN("std_Set_has", SetObject::has, 1, 0, SetHas), 1995 JS_INLINABLE_FN("std_Set_size", SetObject::size, 1, 0, SetSize), 1996 JS_FN("std_Set_values", SetObject::values, 0, 0), 1997 JS_INLINABLE_FN("std_String_charCodeAt", str_charCodeAt, 1, 0, 1998 StringCharCodeAt), 1999 JS_INLINABLE_FN("std_String_codePointAt", str_codePointAt, 1, 0, 2000 StringCodePointAt), 2001 JS_INLINABLE_FN("std_String_endsWith", str_endsWith, 1, 0, StringEndsWith), 2002 JS_INLINABLE_FN("std_String_fromCharCode", str_fromCharCode, 1, 0, 2003 StringFromCharCode), 2004 JS_INLINABLE_FN("std_String_fromCodePoint", str_fromCodePoint, 1, 0, 2005 StringFromCodePoint), 2006 JS_INLINABLE_FN("std_String_includes", str_includes, 1, 0, StringIncludes), 2007 JS_INLINABLE_FN("std_String_indexOf", str_indexOf, 1, 0, StringIndexOf), 2008 JS_INLINABLE_FN("std_String_startsWith", str_startsWith, 1, 0, 2009 StringStartsWith), 2010 JS_TRAMPOLINE_FN("std_TypedArray_sort", TypedArrayObject::sort, 1, 0, 2011 TypedArraySort), 2012 JS_INLINABLE_FN("std_WeakMap_get", WeakMapObject::get, 1, 0, WeakMapGet), 2013 JS_INLINABLE_FN("std_WeakMap_has", WeakMapObject::has, 1, 0, WeakMapHas), 2014 JS_FN("std_WeakMap_set", WeakMapObject::set, 2, 0), 2015 2016 JS_FS_END, 2017 }; 2018 2019 #ifdef DEBUG 2020 2021 static void CheckSelfHostedIntrinsics() { 2022 // The `intrinsic_functions` list must be sorted so that we can use 2023 // mozilla::BinarySearch to do lookups on demand. 2024 const char* prev = ""; 2025 for (JSFunctionSpec spec : intrinsic_functions) { 2026 if (spec.name.string()) { 2027 MOZ_ASSERT(strcmp(prev, spec.name.string()) < 0, 2028 "Self-hosted intrinsics must be sorted"); 2029 prev = spec.name.string(); 2030 } 2031 } 2032 } 2033 2034 class CheckTenuredTracer : public JS::CallbackTracer { 2035 HashSet<gc::Cell*, DefaultHasher<gc::Cell*>, SystemAllocPolicy> visited; 2036 Vector<JS::GCCellPtr, 0, SystemAllocPolicy> stack; 2037 2038 public: 2039 explicit CheckTenuredTracer(JSRuntime* rt) : JS::CallbackTracer(rt) {} 2040 void check() { 2041 while (!stack.empty()) { 2042 JS::TraceChildren(this, stack.popCopy()); 2043 } 2044 } 2045 void onChild(JS::GCCellPtr thing, const char* name) override { 2046 gc::Cell* cell = thing.asCell(); 2047 MOZ_RELEASE_ASSERT(cell->isTenured(), "Expected tenured cell"); 2048 if (!visited.has(cell)) { 2049 if (!visited.put(cell) || !stack.append(thing)) { 2050 // Ignore OOM. This can happen during fuzzing. 2051 return; 2052 } 2053 } 2054 } 2055 }; 2056 2057 static void CheckSelfHostingDataIsTenured(JSRuntime* rt) { 2058 // Check everything is tenured as we don't trace it when collecting the 2059 // nursery. 2060 CheckTenuredTracer trc(rt); 2061 rt->traceSelfHostingStencil(&trc); 2062 trc.check(); 2063 } 2064 2065 #endif 2066 2067 const JSFunctionSpec* js::FindIntrinsicSpec(js::PropertyName* name) { 2068 size_t limit = std::size(intrinsic_functions) - 1; 2069 MOZ_ASSERT(!intrinsic_functions[limit].name); 2070 2071 MOZ_ASSERT(name->hasLatin1Chars()); 2072 2073 JS::AutoCheckCannotGC nogc; 2074 const char* chars = reinterpret_cast<const char*>(name->latin1Chars(nogc)); 2075 size_t len = name->length(); 2076 2077 // NOTE: CheckSelfHostedIntrinsics checks that the intrinsic_functions list is 2078 // sorted appropriately so that we can use binary search here. 2079 2080 size_t loc = 0; 2081 bool match = mozilla::BinarySearchIf( 2082 intrinsic_functions, 0, limit, 2083 [chars, len](const JSFunctionSpec& spec) { 2084 // The spec string is null terminated but the `name` string is not, so 2085 // compare chars up until the length of `name`. Since the `name` string 2086 // does not contain any nulls, seeing the null terminator of the spec 2087 // string will terminate the loop appropriately. A final comparison 2088 // against null is needed to determine if the spec string has an extra 2089 // suffix. 2090 const char* spec_chars = spec.name.string(); 2091 for (size_t i = 0; i < len; ++i) { 2092 if (auto cmp_result = int(chars[i]) - int(spec_chars[i])) { 2093 return cmp_result; 2094 } 2095 } 2096 return int('\0') - int(spec_chars[len]); 2097 }, 2098 &loc); 2099 if (match) { 2100 return &intrinsic_functions[loc]; 2101 } 2102 return nullptr; 2103 } 2104 2105 void js::FillSelfHostingCompileOptions(CompileOptions& options) { 2106 /* 2107 * In self-hosting mode, scripts use JSOp::GetIntrinsic instead of 2108 * JSOp::GetName or JSOp::GetGName to access unbound variables. 2109 * JSOp::GetIntrinsic does a name lookup on a special object, whose 2110 * properties are filled in lazily upon first access for a given global. 2111 * 2112 * As that object is inaccessible to client code, the lookups are 2113 * guaranteed to return the original objects, ensuring safe implementation 2114 * of self-hosted builtins. 2115 * 2116 * Additionally, the special syntax callFunction(fun, receiver, ...args) 2117 * is supported, for which bytecode is emitted that invokes |fun| with 2118 * |receiver| as the this-object and ...args as the arguments. 2119 */ 2120 options.setIntroductionType("self-hosted"); 2121 options.setFileAndLine("self-hosted", 1); 2122 options.setSkipFilenameValidation(true); 2123 options.setSelfHostingMode(true); 2124 options.setForceFullParse(); 2125 options.setForceStrictMode(); 2126 options.setDiscardSource(); 2127 options.setIsRunOnce(true); 2128 options.setNoScriptRval(true); 2129 } 2130 2131 // Report all errors and warnings to stderr because it is too early in the 2132 // startup process for any other error reporting to be used, and we don't want 2133 // errors in self-hosted code to be silently swallowed. 2134 class MOZ_STACK_CLASS AutoPrintSelfHostingFrontendContext 2135 : public FrontendContext { 2136 JSContext* cx_; 2137 2138 public: 2139 explicit AutoPrintSelfHostingFrontendContext(JSContext* cx) : cx_(cx) { 2140 setCurrentJSContext(cx_); 2141 } 2142 ~AutoPrintSelfHostingFrontendContext() { 2143 // TODO: Remove this once JSContext is removed from frontend. 2144 MaybePrintAndClearPendingException(cx_); 2145 2146 if (hadOutOfMemory()) { 2147 fprintf(stderr, "Out of memory\n"); 2148 } 2149 2150 if (maybeError()) { 2151 JS::PrintError(stderr, &*maybeError(), true); 2152 } 2153 for (CompileError& error : warnings()) { 2154 JS::PrintError(stderr, &error, true); 2155 } 2156 if (hadOverRecursed()) { 2157 fprintf(stderr, "Over recursed\n"); 2158 } 2159 if (hadAllocationOverflow()) { 2160 fprintf(stderr, "Allocation overflow\n"); 2161 } 2162 } 2163 }; 2164 2165 [[nodiscard]] static bool InitSelfHostingFromStencil( 2166 JSContext* cx, frontend::CompilationAtomCache& atomCache, 2167 const frontend::CompilationStencil& stencil) { 2168 // Build the JSAtom -> ScriptIndexRange mapping and save on the runtime. 2169 { 2170 auto& scriptMap = cx->runtime()->selfHostScriptMap.ref(); 2171 2172 // We don't easily know the number of top-level functions, so use the total 2173 // number of stencil functions instead. There is very little nesting of 2174 // functions in self-hosted code so this is a good approximation. 2175 size_t numSelfHostedScripts = stencil.scriptData.size(); 2176 if (!scriptMap.reserve(numSelfHostedScripts)) { 2177 ReportOutOfMemory(cx); 2178 return false; 2179 } 2180 2181 auto topLevelThings = 2182 stencil.scriptData[frontend::CompilationStencil::TopLevelIndex] 2183 .gcthings(stencil); 2184 2185 // Iterate over the (named) top-level functions. We record the ScriptIndex 2186 // as well as the ScriptIndex of the next top-level function. Scripts 2187 // between these two indices are the inner functions of the first one. We 2188 // only record named scripts here since they are what might be looked up. 2189 Rooted<JSAtom*> prevAtom(cx); 2190 frontend::ScriptIndex prevIndex; 2191 for (frontend::TaggedScriptThingIndex thing : topLevelThings) { 2192 if (!thing.isFunction()) { 2193 continue; 2194 } 2195 2196 frontend::ScriptIndex index = thing.toFunction(); 2197 const auto& script = stencil.scriptData[index]; 2198 2199 if (prevAtom) { 2200 frontend::ScriptIndexRange range{prevIndex, index}; 2201 scriptMap.putNewInfallible(prevAtom, range); 2202 } 2203 2204 prevAtom = script.functionAtom 2205 ? atomCache.getExistingAtomAt(cx, script.functionAtom) 2206 : nullptr; 2207 prevIndex = index; 2208 } 2209 if (prevAtom) { 2210 frontend::ScriptIndexRange range{ 2211 prevIndex, frontend::ScriptIndex(stencil.scriptData.size())}; 2212 scriptMap.putNewInfallible(prevAtom, range); 2213 } 2214 2215 // We over-estimated the capacity of `scriptMap`, so check that the estimate 2216 // hasn't drifted too hasn't drifted too far since this was written. If this 2217 // assert fails, we may need a new way to size the `scriptMap`. 2218 MOZ_ASSERT(numSelfHostedScripts < (scriptMap.count() * 1.15)); 2219 } 2220 2221 #ifdef DEBUG 2222 // Check that the list of intrinsics is well-formed. 2223 CheckSelfHostedIntrinsics(); 2224 CheckSelfHostingDataIsTenured(cx->runtime()); 2225 #endif 2226 2227 return true; 2228 } 2229 2230 bool JSRuntime::initSelfHostingStencil(JSContext* cx, 2231 JS::SelfHostedCache xdrCache, 2232 JS::SelfHostedWriter xdrWriter) { 2233 if (parentRuntime) { 2234 MOZ_RELEASE_ASSERT( 2235 parentRuntime->hasInitializedSelfHosting(), 2236 "Parent runtime must initialize self-hosting before workers"); 2237 2238 selfHostStencilInput_ = parentRuntime->selfHostStencilInput_; 2239 selfHostStencil_ = parentRuntime->selfHostStencil_; 2240 return true; 2241 } 2242 auto start = mozilla::TimeStamp::Now(); 2243 2244 // Variables used to instantiate scripts. 2245 CompileOptions options(cx); 2246 FillSelfHostingCompileOptions(options); 2247 2248 // Try initializing from Stencil XDR. 2249 AutoPrintSelfHostingFrontendContext fc(cx); 2250 if (xdrCache.Length() > 0) { 2251 // Allow the VM to directly use bytecode from the XDR buffer without 2252 // copying it. The buffer must outlive all runtimes (including workers). 2253 options.borrowBuffer = true; 2254 options.usePinnedBytecode = true; 2255 2256 Rooted<UniquePtr<frontend::CompilationInput>> input( 2257 cx, cx->new_<frontend::CompilationInput>(options)); 2258 if (!input) { 2259 return false; 2260 } 2261 { 2262 AutoReportFrontendContext fc(cx); 2263 if (!input->initForSelfHostingGlobal(&fc)) { 2264 return false; 2265 } 2266 } 2267 2268 JS::DecodeOptions decodeOption(options); 2269 RefPtr<frontend::CompilationStencil> stencil; 2270 JS::TranscodeResult result = 2271 js::DecodeStencil(&fc, decodeOption, xdrCache, getter_AddRefs(stencil)); 2272 if (result == JS::TranscodeResult::Ok) { 2273 MOZ_ASSERT(input->atomCache.empty()); 2274 2275 MOZ_ASSERT(!hasSelfHostStencil()); 2276 2277 // Move it to the runtime. 2278 setSelfHostingStencil(&input, std::move(stencil)); 2279 2280 auto end = mozilla::TimeStamp::Now(); 2281 JS_LOG(startup, Info, 2282 "Used XDR for process self-hosted startup. Took %f us", 2283 (end - start).ToMicroseconds()); 2284 return true; 2285 } 2286 } 2287 2288 // If script wasn't generated, it means XDR was either not provided or that it 2289 // failed the decoding phase. Parse from text as before. 2290 uint32_t srcLen = GetRawScriptsSize(); 2291 const unsigned char* compressed = compressedSources; 2292 uint32_t compressedLen = GetCompressedSize(); 2293 auto src = cx->make_pod_array<char>(srcLen); 2294 if (!src) { 2295 return false; 2296 } 2297 if (!DecompressString(compressed, compressedLen, 2298 reinterpret_cast<unsigned char*>(src.get()), srcLen)) { 2299 return false; 2300 } 2301 2302 JS::SourceText<mozilla::Utf8Unit> srcBuf; 2303 if (!srcBuf.init(cx, std::move(src), srcLen)) { 2304 return false; 2305 } 2306 2307 Rooted<UniquePtr<frontend::CompilationInput>> input( 2308 cx, cx->new_<frontend::CompilationInput>(options)); 2309 if (!input) { 2310 return false; 2311 } 2312 frontend::NoScopeBindingCache scopeCache; 2313 RefPtr<frontend::CompilationStencil> stencil = 2314 frontend::CompileGlobalScriptToStencilWithInput( 2315 cx, &fc, cx->tempLifoAlloc(), *input, &scopeCache, srcBuf, 2316 ScopeKind::Global); 2317 if (!stencil) { 2318 return false; 2319 } 2320 2321 mozilla::TimeDuration xdrDuration; 2322 // Serialize the stencil to XDR. 2323 if (xdrWriter) { 2324 auto encodeStart = mozilla::TimeStamp::Now(); 2325 JS::TranscodeBuffer xdrBuffer; 2326 JS::TranscodeResult result = js::EncodeStencil(cx, stencil, xdrBuffer); 2327 if (result != JS::TranscodeResult::Ok) { 2328 JS_ReportErrorASCII(cx, "Encoding failure"); 2329 return false; 2330 } 2331 2332 if (!xdrWriter(cx, xdrBuffer)) { 2333 return false; 2334 } 2335 auto encodeEnd = mozilla::TimeStamp::Now(); 2336 xdrDuration = (encodeEnd - encodeStart); 2337 JS_LOG(startup, Info, "Saved XDR Buffer. Took %f us", 2338 xdrDuration.ToMicroseconds()); 2339 } 2340 2341 MOZ_ASSERT(input->atomCache.empty()); 2342 2343 MOZ_ASSERT(!hasSelfHostStencil()); 2344 2345 // Move it to the runtime. 2346 setSelfHostingStencil(&input, std::move(stencil)); 2347 2348 auto end = mozilla::TimeStamp::Now(); 2349 JS_LOG(startup, Info, 2350 "Used source text for process self-hosted startup. Took %f us (%f us " 2351 "XDR encode)", 2352 (end - start).ToMicroseconds(), xdrDuration.ToMicroseconds()); 2353 return true; 2354 } 2355 2356 void JSRuntime::setSelfHostingStencil( 2357 MutableHandle<UniquePtr<frontend::CompilationInput>> input, 2358 RefPtr<frontend::CompilationStencil>&& stencil) { 2359 MOZ_ASSERT(!selfHostStencilInput_); 2360 MOZ_ASSERT(!selfHostStencil_); 2361 2362 selfHostStencilInput_ = input.release(); 2363 selfHostStencil_ = stencil.forget().take(); 2364 2365 #ifdef DEBUG 2366 CheckSelfHostingDataIsTenured(this); 2367 #endif 2368 } 2369 2370 bool JSRuntime::initSelfHostingFromStencil(JSContext* cx) { 2371 return InitSelfHostingFromStencil( 2372 cx, cx->runtime()->selfHostStencilInput_->atomCache, 2373 *cx->runtime()->selfHostStencil_); 2374 } 2375 2376 void JSRuntime::finishSelfHosting() { 2377 if (!parentRuntime) { 2378 js_delete(selfHostStencilInput_.ref()); 2379 if (selfHostStencil_) { 2380 // delete selfHostStencil_ by decrementing the ref-count of the last 2381 // instance. 2382 RefPtr<frontend::CompilationStencil> stencil; 2383 *getter_AddRefs(stencil) = selfHostStencil_; 2384 MOZ_ASSERT(!stencil->hasMultipleReference()); 2385 } 2386 } 2387 2388 selfHostStencilInput_ = nullptr; 2389 selfHostStencil_ = nullptr; 2390 2391 selfHostScriptMap.ref().clear(); 2392 clearSelfHostedJitCache(); 2393 } 2394 2395 void JSRuntime::clearSelfHostedJitCache() { 2396 for (auto iter = selfHostJitCache.ref().iter(); !iter.done(); iter.next()) { 2397 jit::BaselineScript* baselineScript = iter.get().value(); 2398 jit::BaselineScript::Destroy(gcContext(), baselineScript); 2399 } 2400 selfHostJitCache.ref().clear(); 2401 } 2402 2403 void JSRuntime::traceSelfHostingStencil(JSTracer* trc) { 2404 if (selfHostStencilInput_.ref()) { 2405 selfHostStencilInput_->trace(trc); 2406 } 2407 selfHostScriptMap.ref().trace(trc); 2408 selfHostJitCache.ref().trace(trc); 2409 } 2410 2411 GeneratorKind JSRuntime::getSelfHostedFunctionGeneratorKind( 2412 js::PropertyName* name) { 2413 frontend::ScriptIndex index = getSelfHostedScriptIndexRange(name)->start; 2414 auto flags = selfHostStencil().scriptExtra[index].immutableFlags; 2415 return flags.hasFlag(js::ImmutableScriptFlagsEnum::IsGenerator) 2416 ? GeneratorKind::Generator 2417 : GeneratorKind::NotGenerator; 2418 } 2419 2420 // Returns the ScriptSourceObject to use for cloned self-hosted scripts in the 2421 // current realm. 2422 ScriptSourceObject* js::SelfHostingScriptSourceObject(JSContext* cx) { 2423 return GlobalObject::getOrCreateSelfHostingScriptSourceObject(cx, 2424 cx->global()); 2425 } 2426 2427 /* static */ 2428 ScriptSourceObject* GlobalObject::getOrCreateSelfHostingScriptSourceObject( 2429 JSContext* cx, Handle<GlobalObject*> global) { 2430 MOZ_ASSERT(cx->global() == global); 2431 2432 if (ScriptSourceObject* sso = global->data().selfHostingScriptSource) { 2433 return sso; 2434 } 2435 2436 CompileOptions options(cx); 2437 FillSelfHostingCompileOptions(options); 2438 2439 RefPtr<ScriptSource> source(cx->new_<ScriptSource>()); 2440 if (!source) { 2441 return nullptr; 2442 } 2443 2444 Rooted<ScriptSourceObject*> sourceObject(cx); 2445 { 2446 AutoReportFrontendContext fc(cx); 2447 if (!source->initFromOptions(&fc, options)) { 2448 return nullptr; 2449 } 2450 2451 sourceObject = ScriptSourceObject::create(cx, source.get()); 2452 if (!sourceObject) { 2453 return nullptr; 2454 } 2455 2456 JS::InstantiateOptions instantiateOptions(options); 2457 if (!ScriptSourceObject::initFromOptions(cx, sourceObject, 2458 instantiateOptions)) { 2459 return nullptr; 2460 } 2461 2462 global->data().selfHostingScriptSource.init(sourceObject); 2463 } 2464 2465 return sourceObject; 2466 } 2467 2468 bool JSRuntime::delazifySelfHostedFunction(JSContext* cx, 2469 Handle<PropertyName*> name, 2470 HandleFunction targetFun) { 2471 MOZ_ASSERT(targetFun->isExtended()); 2472 MOZ_ASSERT(targetFun->hasSelfHostedLazyScript()); 2473 2474 auto indexRange = *getSelfHostedScriptIndexRange(name); 2475 auto& stencil = cx->runtime()->selfHostStencil(); 2476 2477 if (!stencil.delazifySelfHostedFunction( 2478 cx, cx->runtime()->selfHostStencilInput().atomCache, indexRange, name, 2479 targetFun)) { 2480 return false; 2481 } 2482 2483 // Relazifiable self-hosted functions may be relazified later into a 2484 // SelfHostedLazyScript, dropping the BaseScript entirely. This only applies 2485 // to named function being delazified. Inner functions used by self-hosting 2486 // are never relazified. 2487 BaseScript* targetScript = targetFun->baseScript(); 2488 if (targetScript->isRelazifiable()) { 2489 targetScript->setAllowRelazify(); 2490 } 2491 2492 return true; 2493 } 2494 2495 mozilla::Maybe<frontend::ScriptIndexRange> 2496 JSRuntime::getSelfHostedScriptIndexRange(js::PropertyName* name) { 2497 if (parentRuntime) { 2498 return parentRuntime->getSelfHostedScriptIndexRange(name); 2499 } 2500 MOZ_ASSERT(name->isPermanentAndMayBeShared()); 2501 if (auto ptr = selfHostScriptMap.ref().readonlyThreadsafeLookup(name)) { 2502 return mozilla::Some(ptr->value()); 2503 } 2504 return mozilla::Nothing(); 2505 } 2506 2507 static bool GetComputedIntrinsic(JSContext* cx, Handle<PropertyName*> name, 2508 MutableHandleValue vp) { 2509 // If the intrinsic was not in hardcoded set, run the top-level of the 2510 // selfhosted script. This will generate values and call `SetIntrinsic` to 2511 // save them on a special "computed intrinsics holder". We then can check for 2512 // our required values and cache on the normal intrinsics holder. 2513 2514 Rooted<NativeObject*> computedIntrinsicsHolder( 2515 cx, cx->global()->getComputedIntrinsicsHolder()); 2516 if (!computedIntrinsicsHolder) { 2517 auto computedIntrinsicHolderGuard = mozilla::MakeScopeExit( 2518 [cx]() { cx->global()->setComputedIntrinsicsHolder(nullptr); }); 2519 2520 // Instantiate a script in current realm from the shared Stencil. 2521 JSRuntime* runtime = cx->runtime(); 2522 RootedScript script( 2523 cx, runtime->selfHostStencil().instantiateSelfHostedTopLevelForRealm( 2524 cx, runtime->selfHostStencilInput())); 2525 if (!script) { 2526 return false; 2527 } 2528 2529 // Attach the computed intrinsics holder to the global now to capture 2530 // generated values. 2531 computedIntrinsicsHolder = 2532 NewPlainObjectWithProto(cx, nullptr, TenuredObject); 2533 if (!computedIntrinsicsHolder) { 2534 return false; 2535 } 2536 cx->global()->setComputedIntrinsicsHolder(computedIntrinsicsHolder); 2537 2538 // Disable the interrupt callback while executing the top-level script. 2539 // This prevents recursive calls to GetComputedIntrinsic through the 2540 // interrupt callback. 2541 bool hadInterruptsDisabled = JS_DisableInterruptCallback(cx); 2542 auto resetInterrupts = mozilla::MakeScopeExit( 2543 [&]() { JS_ResetInterruptCallback(cx, hadInterruptsDisabled); }); 2544 2545 // Attempt to execute the top-level script. If they fails to run to 2546 // successful completion, throw away the holder to avoid a partial 2547 // initialization state. 2548 if (!JS_ExecuteScript(cx, script)) { 2549 return false; 2550 } 2551 2552 // Successfully ran the self-host top-level in current realm, so these 2553 // computed intrinsic values are now source of truth for the realm. 2554 computedIntrinsicHolderGuard.release(); 2555 } 2556 2557 // Cache the individual intrinsic on the standard holder object so that we 2558 // only have to look for it in one place when performing `GetIntrinsic`. 2559 mozilla::Maybe<PropertyInfo> prop = 2560 computedIntrinsicsHolder->lookup(cx, name); 2561 #ifdef DEBUG 2562 if (!prop) { 2563 Fprinter out(stderr); 2564 out.printf("SelfHosted intrinsic not found: "); 2565 name->dumpPropertyName(out); 2566 out.printf("\n"); 2567 } 2568 #endif 2569 MOZ_RELEASE_ASSERT(prop, "SelfHosted intrinsic not found"); 2570 RootedValue value(cx, computedIntrinsicsHolder->getSlot(prop->slot())); 2571 return GlobalObject::addIntrinsicValue(cx, cx->global(), name, value); 2572 } 2573 2574 bool JSRuntime::getSelfHostedValue(JSContext* cx, Handle<PropertyName*> name, 2575 MutableHandleValue vp) { 2576 // If the self-hosted value we want is a function in the stencil, instantiate 2577 // a lazy self-hosted function for it. This is typical when a self-hosted 2578 // function calls other self-hosted helper functions. 2579 if (auto index = getSelfHostedScriptIndexRange(name)) { 2580 JSFunction* fun = 2581 cx->runtime()->selfHostStencil().instantiateSelfHostedLazyFunction( 2582 cx, cx->runtime()->selfHostStencilInput().atomCache, index->start, 2583 name); 2584 if (!fun) { 2585 return false; 2586 } 2587 vp.setObject(*fun); 2588 return true; 2589 } 2590 2591 return GetComputedIntrinsic(cx, name, vp); 2592 } 2593 2594 void JSRuntime::assertSelfHostedFunctionHasCanonicalName( 2595 Handle<PropertyName*> name) { 2596 #ifdef DEBUG 2597 frontend::ScriptIndex index = getSelfHostedScriptIndexRange(name)->start; 2598 MOZ_ASSERT(selfHostStencil().scriptData[index].hasSelfHostedCanonicalName()); 2599 #endif 2600 } 2601 2602 bool js::IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name) { 2603 return fun->isSelfHostedBuiltin() && fun->isExtended() && 2604 GetClonedSelfHostedFunctionName(fun) == name; 2605 } 2606 2607 bool js::IsSelfHostedFunctionWithName(const Value& v, JSAtom* name) { 2608 if (!v.isObject() || !v.toObject().is<JSFunction>()) { 2609 return false; 2610 } 2611 JSFunction* fun = &v.toObject().as<JSFunction>(); 2612 return IsSelfHostedFunctionWithName(fun, name); 2613 } 2614 2615 static_assert( 2616 JSString::MAX_LENGTH <= INT32_MAX, 2617 "StringIteratorNext in builtin/String.js assumes the stored index " 2618 "into the string is an Int32Value"); 2619 2620 static_assert(JSString::MAX_LENGTH == MAX_STRING_LENGTH, 2621 "JSString::MAX_LENGTH matches self-hosted constant for maximum " 2622 "string length"); 2623 2624 static_assert(ARGS_LENGTH_MAX == MAX_ARGS_LENGTH, 2625 "ARGS_LENGTH_MAX matches self-hosted constant for maximum " 2626 "arguments length");