jsapi.cpp (165700B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* 8 * JavaScript API. 9 */ 10 11 #include "jsapi.h" 12 13 #include "mozilla/FloatingPoint.h" 14 #include "mozilla/Maybe.h" 15 #include "mozilla/PodOperations.h" 16 #include "mozilla/Sprintf.h" 17 18 #include <algorithm> 19 #include <cstdarg> 20 #ifdef __linux__ 21 # include <dlfcn.h> 22 #endif 23 #include <stdarg.h> 24 #include <string.h> 25 26 #include "jsexn.h" 27 #include "jsfriendapi.h" 28 #include "jsmath.h" 29 #include "jstypes.h" 30 31 #include "builtin/AtomicsObject.h" 32 #include "builtin/Eval.h" 33 #include "builtin/JSON.h" 34 #include "builtin/Promise.h" 35 #include "builtin/Symbol.h" 36 #include "frontend/FrontendContext.h" // AutoReportFrontendContext 37 #include "gc/GC.h" 38 #include "gc/GCContext.h" 39 #include "gc/Marking.h" 40 #include "gc/PublicIterators.h" 41 #include "jit/JitSpewer.h" 42 #include "jit/TrampolineNatives.h" 43 #include "js/CallAndConstruct.h" // JS::IsCallable 44 #include "js/CharacterEncoding.h" 45 #include "js/ColumnNumber.h" // JS::TaggedColumnNumberOneOrigin, JS::ColumnNumberOneOrigin 46 #include "js/CompileOptions.h" 47 #include "js/ContextOptions.h" // JS::ContextOptions{,Ref} 48 #include "js/Conversions.h" 49 #include "js/Date.h" // JS::GetReduceMicrosecondTimePrecisionCallback 50 #include "js/ErrorInterceptor.h" 51 #include "js/ErrorReport.h" // JSErrorBase 52 #include "js/experimental/JitInfo.h" // JSJitInfo 53 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* 54 #include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit 55 #include "js/GlobalObject.h" 56 #include "js/Initialization.h" 57 #include "js/Interrupt.h" 58 #include "js/JSON.h" 59 #include "js/LocaleSensitive.h" 60 #include "js/MemoryCallbacks.h" 61 #include "js/MemoryFunctions.h" 62 #include "js/Prefs.h" 63 #include "js/PropertySpec.h" 64 #include "js/Proxy.h" 65 #include "js/ScriptPrivate.h" 66 #include "js/StableStringChars.h" 67 #include "js/Stack.h" // JS::NativeStackSize, JS::NativeStackLimitMax, JS::GetNativeStackLimit 68 #include "js/StreamConsumer.h" 69 #include "js/String.h" // JS::MaxStringLength 70 #include "js/Symbol.h" 71 #include "js/TelemetryTimers.h" 72 #include "js/Utility.h" 73 #include "js/WaitCallbacks.h" 74 #include "js/WasmModule.h" 75 #include "js/Wrapper.h" 76 #include "js/WrapperCallbacks.h" 77 #include "proxy/DOMProxy.h" 78 #include "util/Identifier.h" // IsIdentifier 79 #include "util/StringBuilder.h" 80 #include "util/Text.h" 81 #include "vm/BoundFunctionObject.h" 82 #include "vm/EnvironmentObject.h" 83 #include "vm/ErrorObject.h" 84 #include "vm/ErrorReporting.h" 85 #include "vm/FunctionPrefixKind.h" 86 #include "vm/Interpreter.h" 87 #include "vm/JSAtomState.h" 88 #include "vm/JSAtomUtils.h" // Atomize, AtomizeWithoutActiveZone, AtomizeChars, PinAtom, ClassName 89 #include "vm/JSContext.h" 90 #include "vm/JSFunction.h" 91 #include "vm/JSObject.h" 92 #include "vm/JSScript.h" 93 #include "vm/Logging.h" 94 #include "vm/PlainObject.h" // js::PlainObject 95 #include "vm/PromiseObject.h" // js::PromiseObject 96 #include "vm/Runtime.h" 97 #include "vm/SavedStacks.h" 98 #include "vm/StringType.h" 99 #include "vm/Time.h" 100 #include "vm/ToSource.h" 101 #include "vm/Watchtower.h" 102 #include "vm/WrapperObject.h" 103 #include "wasm/WasmModule.h" 104 #include "wasm/WasmProcess.h" 105 106 #include "builtin/Promise-inl.h" 107 #include "debugger/DebugAPI-inl.h" 108 #include "vm/Compartment-inl.h" 109 #include "vm/Interpreter-inl.h" 110 #include "vm/IsGivenTypeObject-inl.h" // js::IsGivenTypeObject 111 #include "vm/JSAtomUtils-inl.h" // AtomToId, PrimitiveValueToId, IndexToId, ClassName 112 #include "vm/JSFunction-inl.h" 113 #include "vm/JSScript-inl.h" 114 #include "vm/NativeObject-inl.h" 115 #include "vm/SavedStacks-inl.h" 116 #include "vm/StringType-inl.h" 117 118 using namespace js; 119 120 using mozilla::Maybe; 121 122 using JS::AutoStableStringChars; 123 using JS::CompileOptions; 124 using JS::ReadOnlyCompileOptions; 125 126 // See preprocessor definition of JS_BITS_PER_WORD in jstypes.h; make sure 127 // JS_64BIT (used internally) agrees with it 128 #ifdef JS_64BIT 129 static_assert(JS_BITS_PER_WORD == 64, "values must be in sync"); 130 #else 131 static_assert(JS_BITS_PER_WORD == 32, "values must be in sync"); 132 #endif 133 134 JS_PUBLIC_API void JS::CallArgs::reportMoreArgsNeeded(JSContext* cx, 135 const char* fnname, 136 unsigned required, 137 unsigned actual) { 138 char requiredArgsStr[40]; 139 SprintfLiteral(requiredArgsStr, "%u", required); 140 char actualArgsStr[40]; 141 SprintfLiteral(actualArgsStr, "%u", actual); 142 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 143 JSMSG_MORE_ARGS_NEEDED, fnname, requiredArgsStr, 144 required == 1 ? "" : "s", actualArgsStr); 145 } 146 147 static bool ErrorTakesArguments(unsigned msg) { 148 MOZ_ASSERT(msg < JSErr_Limit); 149 unsigned argCount = js_ErrorFormatString[msg].argCount; 150 MOZ_ASSERT(argCount <= 2); 151 return argCount == 1 || argCount == 2; 152 } 153 154 static bool ErrorTakesObjectArgument(unsigned msg) { 155 MOZ_ASSERT(msg < JSErr_Limit); 156 unsigned argCount = js_ErrorFormatString[msg].argCount; 157 MOZ_ASSERT(argCount <= 2); 158 return argCount == 2; 159 } 160 161 bool JS::ObjectOpResult::reportError(JSContext* cx, HandleObject obj, 162 HandleId id) { 163 static_assert(unsigned(OkCode) == unsigned(JSMSG_NOT_AN_ERROR), 164 "unsigned value of OkCode must not be an error code"); 165 MOZ_ASSERT(code_ != Uninitialized); 166 MOZ_ASSERT(!ok()); 167 cx->check(obj); 168 169 if (code_ == JSMSG_OBJECT_NOT_EXTENSIBLE) { 170 RootedValue val(cx, ObjectValue(*obj)); 171 return ReportValueError(cx, code_, JSDVG_IGNORE_STACK, val, nullptr); 172 } 173 174 if (ErrorTakesArguments(code_)) { 175 UniqueChars propName = 176 IdToPrintableUTF8(cx, id, IdToPrintableBehavior::IdIsPropertyKey); 177 if (!propName) { 178 return false; 179 } 180 181 if (code_ == JSMSG_SET_NON_OBJECT_RECEIVER) { 182 // We know that the original receiver was a primitive, so unbox it. 183 RootedValue val(cx, ObjectValue(*obj)); 184 if (!obj->is<ProxyObject>()) { 185 if (!Unbox(cx, obj, &val)) { 186 return false; 187 } 188 } 189 return ReportValueError(cx, code_, JSDVG_IGNORE_STACK, val, nullptr, 190 propName.get()); 191 } 192 193 if (ErrorTakesObjectArgument(code_)) { 194 JSObject* unwrapped = js::CheckedUnwrapStatic(obj); 195 const char* name = unwrapped ? unwrapped->getClass()->name : "Object"; 196 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, code_, name, 197 propName.get()); 198 return false; 199 } 200 201 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, code_, 202 propName.get()); 203 return false; 204 } 205 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, code_); 206 return false; 207 } 208 209 bool JS::ObjectOpResult::reportError(JSContext* cx, HandleObject obj) { 210 MOZ_ASSERT(code_ != Uninitialized); 211 MOZ_ASSERT(!ok()); 212 MOZ_ASSERT(!ErrorTakesArguments(code_)); 213 cx->check(obj); 214 215 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, code_); 216 return false; 217 } 218 219 JS_PUBLIC_API bool JS::ObjectOpResult::failCantRedefineProp() { 220 return fail(JSMSG_CANT_REDEFINE_PROP); 221 } 222 223 JS_PUBLIC_API bool JS::ObjectOpResult::failReadOnly() { 224 return fail(JSMSG_READ_ONLY); 225 } 226 227 JS_PUBLIC_API bool JS::ObjectOpResult::failGetterOnly() { 228 return fail(JSMSG_GETTER_ONLY); 229 } 230 231 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDelete() { 232 return fail(JSMSG_CANT_DELETE); 233 } 234 235 JS_PUBLIC_API bool JS::ObjectOpResult::failCantSetInterposed() { 236 return fail(JSMSG_CANT_SET_INTERPOSED); 237 } 238 239 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDefineWindowElement() { 240 return fail(JSMSG_CANT_DEFINE_WINDOW_ELEMENT); 241 } 242 243 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDeleteWindowElement() { 244 return fail(JSMSG_CANT_DELETE_WINDOW_ELEMENT); 245 } 246 247 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDefineWindowNamedProperty() { 248 return fail(JSMSG_CANT_DEFINE_WINDOW_NAMED_PROPERTY); 249 } 250 251 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDeleteWindowNamedProperty() { 252 return fail(JSMSG_CANT_DELETE_WINDOW_NAMED_PROPERTY); 253 } 254 255 JS_PUBLIC_API bool JS::ObjectOpResult::failCantDefineWindowNonConfigurable() { 256 return fail(JSMSG_CANT_DEFINE_WINDOW_NC); 257 } 258 259 JS_PUBLIC_API bool JS::ObjectOpResult::failCantPreventExtensions() { 260 return fail(JSMSG_CANT_PREVENT_EXTENSIONS); 261 } 262 263 JS_PUBLIC_API bool JS::ObjectOpResult::failCantSetProto() { 264 return fail(JSMSG_CANT_SET_PROTO); 265 } 266 267 JS_PUBLIC_API bool JS::ObjectOpResult::failNoNamedSetter() { 268 return fail(JSMSG_NO_NAMED_SETTER); 269 } 270 271 JS_PUBLIC_API bool JS::ObjectOpResult::failNoIndexedSetter() { 272 return fail(JSMSG_NO_INDEXED_SETTER); 273 } 274 275 JS_PUBLIC_API bool JS::ObjectOpResult::failNotDataDescriptor() { 276 return fail(JSMSG_NOT_DATA_DESCRIPTOR); 277 } 278 279 JS_PUBLIC_API bool JS::ObjectOpResult::failInvalidDescriptor() { 280 return fail(JSMSG_INVALID_DESCRIPTOR); 281 } 282 283 JS_PUBLIC_API bool JS::ObjectOpResult::failBadArrayLength() { 284 return fail(JSMSG_BAD_ARRAY_LENGTH); 285 } 286 287 JS_PUBLIC_API bool JS::ObjectOpResult::failBadIndex() { 288 return fail(JSMSG_BAD_INDEX); 289 } 290 291 JS_PUBLIC_API int64_t JS_Now() { return PRMJ_Now(); } 292 293 JS_PUBLIC_API Value JS_GetEmptyStringValue(JSContext* cx) { 294 return StringValue(cx->runtime()->emptyString); 295 } 296 297 JS_PUBLIC_API JSString* JS_GetEmptyString(JSContext* cx) { 298 MOZ_ASSERT(cx->emptyString()); 299 return cx->emptyString(); 300 } 301 302 namespace js { 303 304 void AssertHeapIsIdle() { MOZ_ASSERT(!JS::RuntimeHeapIsBusy()); } 305 306 } // namespace js 307 308 static void AssertHeapIsIdleOrIterating() { 309 MOZ_ASSERT(!JS::RuntimeHeapIsCollecting()); 310 } 311 312 JS_PUBLIC_API bool JS_ValueToObject(JSContext* cx, HandleValue value, 313 MutableHandleObject objp) { 314 AssertHeapIsIdle(); 315 CHECK_THREAD(cx); 316 cx->check(value); 317 if (value.isNullOrUndefined()) { 318 objp.set(nullptr); 319 return true; 320 } 321 JSObject* obj = ToObject(cx, value); 322 if (!obj) { 323 return false; 324 } 325 objp.set(obj); 326 return true; 327 } 328 329 JS_PUBLIC_API JSFunction* JS_ValueToFunction(JSContext* cx, HandleValue value) { 330 AssertHeapIsIdle(); 331 CHECK_THREAD(cx); 332 cx->check(value); 333 return ReportIfNotFunction(cx, value); 334 } 335 336 JS_PUBLIC_API JSFunction* JS_ValueToConstructor(JSContext* cx, 337 HandleValue value) { 338 AssertHeapIsIdle(); 339 CHECK_THREAD(cx); 340 cx->check(value); 341 return ReportIfNotFunction(cx, value); 342 } 343 344 JS_PUBLIC_API JSString* JS_ValueToSource(JSContext* cx, HandleValue value) { 345 AssertHeapIsIdle(); 346 CHECK_THREAD(cx); 347 cx->check(value); 348 return ValueToSource(cx, value); 349 } 350 351 JS_PUBLIC_API bool JS_DoubleIsInt32(double d, int32_t* ip) { 352 return mozilla::NumberIsInt32(d, ip); 353 } 354 355 JS_PUBLIC_API JSType JS_TypeOfValue(JSContext* cx, HandleValue value) { 356 AssertHeapIsIdle(); 357 CHECK_THREAD(cx); 358 cx->check(value); 359 return TypeOfValue(value); 360 } 361 362 JS_PUBLIC_API bool JS_IsBuiltinEvalFunction(JSFunction* fun) { 363 return IsAnyBuiltinEval(fun); 364 } 365 366 JS_PUBLIC_API bool JS_IsBuiltinFunctionConstructor(JSFunction* fun) { 367 return fun->isBuiltinFunctionConstructor(); 368 } 369 370 JS_PUBLIC_API bool JS_ObjectIsBoundFunction(JSObject* obj) { 371 return obj->is<BoundFunctionObject>(); 372 } 373 374 JS_PUBLIC_API JSObject* JS_GetBoundFunctionTarget(JSObject* obj) { 375 return obj->is<BoundFunctionObject>() 376 ? obj->as<BoundFunctionObject>().getTarget() 377 : nullptr; 378 } 379 380 /************************************************************************/ 381 382 // Prevent functions from being discarded by linker, so that they are callable 383 // when debugging. 384 static void PreventDiscardingFunctions() { 385 if (reinterpret_cast<uintptr_t>(&PreventDiscardingFunctions) == 1) { 386 // Never executed. 387 memset((void*)&js::debug::GetMarkInfo, 0, 1); 388 memset((void*)&js::debug::GetMarkWordAddress, 0, 1); 389 memset((void*)&js::debug::GetMarkMask, 0, 1); 390 } 391 } 392 393 JS_PUBLIC_API JSContext* JS_NewContext(uint32_t maxbytes, 394 JSRuntime* parentRuntime) { 395 MOZ_ASSERT(JS::detail::libraryInitState == JS::detail::InitState::Running, 396 "must call JS_Init prior to creating any JSContexts"); 397 398 // Prevent linker from discarding unused debug functions. 399 PreventDiscardingFunctions(); 400 401 // Make sure that all parent runtimes are the topmost parent. 402 while (parentRuntime && parentRuntime->parentRuntime) { 403 parentRuntime = parentRuntime->parentRuntime; 404 } 405 406 return NewContext(maxbytes, parentRuntime); 407 } 408 409 JS_PUBLIC_API void JS_DestroyContext(JSContext* cx) { DestroyContext(cx); } 410 411 JS_PUBLIC_API void* JS_GetContextPrivate(JSContext* cx) { return cx->data; } 412 413 JS_PUBLIC_API void JS_SetContextPrivate(JSContext* cx, void* data) { 414 cx->data = data; 415 } 416 417 JS_PUBLIC_API void JS_SetFutexCanWait(JSContext* cx) { 418 cx->fx.setCanWait(true); 419 } 420 421 JS_PUBLIC_API JSRuntime* JS_GetParentRuntime(JSContext* cx) { 422 return cx->runtime()->parentRuntime ? cx->runtime()->parentRuntime 423 : cx->runtime(); 424 } 425 426 JS_PUBLIC_API JSRuntime* JS_GetRuntime(JSContext* cx) { return cx->runtime(); } 427 428 JS_PUBLIC_API JS::ContextOptions& JS::ContextOptionsRef(JSContext* cx) { 429 return cx->options(); 430 } 431 432 JS::ContextOptions& JS::ContextOptions::setFuzzing(bool flag) { 433 #ifdef FUZZING 434 fuzzing_ = flag; 435 #endif 436 return *this; 437 } 438 439 JS_PUBLIC_API const char* JS_GetImplementationVersion(void) { 440 return "JavaScript-C" MOZILLA_VERSION; 441 } 442 443 JS_PUBLIC_API void JS_SetDestroyZoneCallback(JSContext* cx, 444 JSDestroyZoneCallback callback) { 445 cx->runtime()->destroyZoneCallback = callback; 446 } 447 448 JS_PUBLIC_API void JS_SetDestroyCompartmentCallback( 449 JSContext* cx, JSDestroyCompartmentCallback callback) { 450 cx->runtime()->destroyCompartmentCallback = callback; 451 } 452 453 JS_PUBLIC_API void JS_SetSizeOfIncludingThisCompartmentCallback( 454 JSContext* cx, JSSizeOfIncludingThisCompartmentCallback callback) { 455 cx->runtime()->sizeOfIncludingThisCompartmentCallback = callback; 456 } 457 458 JS_PUBLIC_API void JS_SetErrorInterceptorCallback( 459 JSRuntime* rt, JSErrorInterceptor* callback) { 460 #if defined(NIGHTLY_BUILD) 461 rt->errorInterception.interceptor = callback; 462 #endif // defined(NIGHTLY_BUILD) 463 } 464 465 JS_PUBLIC_API JSErrorInterceptor* JS_GetErrorInterceptorCallback( 466 JSRuntime* rt) { 467 #if defined(NIGHTLY_BUILD) 468 return rt->errorInterception.interceptor; 469 #else // !NIGHTLY_BUILD 470 return nullptr; 471 #endif // defined(NIGHTLY_BUILD) 472 } 473 474 JS_PUBLIC_API Maybe<JSExnType> JS_GetErrorType(const JS::Value& val) { 475 // All errors are objects. 476 if (!val.isObject()) { 477 return mozilla::Nothing(); 478 } 479 480 const JSObject& obj = val.toObject(); 481 482 // All errors are `ErrorObject`. 483 if (!obj.is<js::ErrorObject>()) { 484 // Not one of the primitive errors. 485 return mozilla::Nothing(); 486 } 487 488 const js::ErrorObject& err = obj.as<js::ErrorObject>(); 489 return mozilla::Some(err.type()); 490 } 491 492 JS_PUBLIC_API void JS_SetWrapObjectCallbacks( 493 JSContext* cx, const JSWrapObjectCallbacks* callbacks) { 494 cx->runtime()->wrapObjectCallbacks = callbacks; 495 } 496 497 JS_PUBLIC_API Realm* JS::EnterRealm(JSContext* cx, JSObject* target) { 498 AssertHeapIsIdle(); 499 CHECK_THREAD(cx); 500 501 MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(target)); 502 503 Realm* oldRealm = cx->realm(); 504 cx->enterRealmOf(target); 505 return oldRealm; 506 } 507 508 JS_PUBLIC_API void JS::LeaveRealm(JSContext* cx, JS::Realm* oldRealm) { 509 AssertHeapIsIdle(); 510 CHECK_THREAD(cx); 511 cx->leaveRealm(oldRealm); 512 } 513 514 JSAutoRealm::JSAutoRealm(JSContext* cx, JSObject* target) 515 : cx_(cx), oldRealm_(cx->realm()) { 516 MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(target)); 517 AssertHeapIsIdleOrIterating(); 518 cx_->enterRealmOf(target); 519 } 520 521 JSAutoRealm::JSAutoRealm(JSContext* cx, JSScript* target) 522 : cx_(cx), oldRealm_(cx->realm()) { 523 AssertHeapIsIdleOrIterating(); 524 cx_->enterRealmOf(target); 525 } 526 527 JSAutoRealm::~JSAutoRealm() { cx_->leaveRealm(oldRealm_); } 528 529 JSAutoNullableRealm::JSAutoNullableRealm(JSContext* cx, JSObject* targetOrNull) 530 : cx_(cx), oldRealm_(cx->realm()) { 531 AssertHeapIsIdleOrIterating(); 532 if (targetOrNull) { 533 MOZ_DIAGNOSTIC_ASSERT(!js::IsCrossCompartmentWrapper(targetOrNull)); 534 cx_->enterRealmOf(targetOrNull); 535 } else { 536 cx_->enterNullRealm(); 537 } 538 } 539 540 JSAutoNullableRealm::~JSAutoNullableRealm() { cx_->leaveRealm(oldRealm_); } 541 542 JS_PUBLIC_API void JS_SetCompartmentPrivate(JS::Compartment* compartment, 543 void* data) { 544 compartment->data = data; 545 } 546 547 JS_PUBLIC_API void* JS_GetCompartmentPrivate(JS::Compartment* compartment) { 548 return compartment->data; 549 } 550 551 JS_PUBLIC_API void JS_MarkCrossZoneId(JSContext* cx, jsid id) { 552 cx->markId(id); 553 } 554 555 JS_PUBLIC_API void JS_MarkCrossZoneIdValue(JSContext* cx, const Value& value) { 556 cx->markAtomValue(value); 557 } 558 559 JS_PUBLIC_API void JS_SetZoneUserData(JS::Zone* zone, void* data) { 560 zone->data = data; 561 } 562 563 JS_PUBLIC_API void* JS_GetZoneUserData(JS::Zone* zone) { return zone->data; } 564 565 JS_PUBLIC_API bool JS_WrapObject(JSContext* cx, MutableHandleObject objp) { 566 AssertHeapIsIdle(); 567 CHECK_THREAD(cx); 568 if (objp) { 569 JS::ExposeObjectToActiveJS(objp); 570 } 571 return cx->compartment()->wrap(cx, objp); 572 } 573 574 JS_PUBLIC_API bool JS_WrapValue(JSContext* cx, MutableHandleValue vp) { 575 AssertHeapIsIdle(); 576 CHECK_THREAD(cx); 577 JS::ExposeValueToActiveJS(vp); 578 return cx->compartment()->wrap(cx, vp); 579 } 580 581 static void ReleaseAssertObjectHasNoWrappers(JSContext* cx, 582 HandleObject target) { 583 for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) { 584 if (c->lookupWrapper(target)) { 585 MOZ_CRASH("wrapper found for target object"); 586 } 587 } 588 } 589 590 /* 591 * [SMDOC] Brain transplants. 592 * 593 * Not for beginners or the squeamish. 594 * 595 * Sometimes a web spec requires us to transplant an object from one 596 * compartment to another, like when a DOM node is inserted into a document in 597 * another window and thus gets "adopted". We cannot literally change the 598 * `.compartment()` of a `JSObject`; that would break the compartment 599 * invariants. However, as usual, we have a workaround using wrappers. 600 * 601 * Of all the wrapper-based workarounds we do, it's safe to say this is the 602 * most spectacular and questionable. 603 * 604 * `JS_TransplantObject(cx, origobj, target)` changes `origobj` into a 605 * simulacrum of `target`, using highly esoteric means. To JS code, the effect 606 * is as if `origobj` magically "became" `target`, but most often what actually 607 * happens is that `origobj` gets turned into a cross-compartment wrapper for 608 * `target`. The old behavior and contents of `origobj` are overwritten or 609 * discarded. 610 * 611 * Thus, to "transplant" an object from one compartment to another: 612 * 613 * 1. Let `origobj` be the object that you want to move. First, create a 614 * clone of it, `target`, in the destination compartment. 615 * 616 * In our DOM adoption example, `target` will be a Node of the same type as 617 * `origobj`, same content, but in the adopting document. We're not done 618 * yet: the spec for DOM adoption requires that `origobj.ownerDocument` 619 * actually change. All we've done so far is make a copy. 620 * 621 * 2. Call `JS_TransplantObject(cx, origobj, target)`. This typically turns 622 * `origobj` into a wrapper for `target`, so that any JS code that has a 623 * reference to `origobj` will observe it to have the behavior of `target` 624 * going forward. In addition, all existing wrappers for `origobj` are 625 * changed into wrappers for `target`, extending the illusion to those 626 * compartments as well. 627 * 628 * During navigation, we use the above technique to transplant the WindowProxy 629 * into the new Window's compartment. 630 * 631 * A few rules: 632 * 633 * - `origobj` and `target` must be two distinct objects of the same 634 * `JSClass`. Some classes may not support transplantation; WindowProxy 635 * objects and DOM nodes are OK. 636 * 637 * - `target` should be created specifically to be passed to this function. 638 * There must be no existing cross-compartment wrappers for it; ideally 639 * there shouldn't be any pointers to it at all, except the one passed in. 640 * 641 * - `target` shouldn't be used afterwards. Instead, `JS_TransplantObject` 642 * returns a pointer to the transplanted object, which might be `target` 643 * but might be some other object in the same compartment. Use that. 644 * 645 * The reason for this last rule is that JS_TransplantObject does very strange 646 * things in some cases, like swapping `target`'s brain with that of another 647 * object. Leaving `target` behaving like its former self is not a goal. 648 * 649 * We don't have a good way to recover from failure in this function, so 650 * we intentionally crash instead. 651 */ 652 653 static void CheckTransplantObject(JSObject* obj) { 654 #ifdef DEBUG 655 MOZ_ASSERT(!obj->is<CrossCompartmentWrapperObject>()); 656 JS::AssertCellIsNotGray(obj); 657 #endif 658 } 659 660 JS_PUBLIC_API JSObject* JS_TransplantObject(JSContext* cx, HandleObject origobj, 661 HandleObject target) { 662 AssertHeapIsIdle(); 663 MOZ_ASSERT(origobj != target); 664 CheckTransplantObject(origobj); 665 CheckTransplantObject(target); 666 ReleaseAssertObjectHasNoWrappers(cx, target); 667 668 RootedObject newIdentity(cx); 669 670 // Don't allow a compacting GC to observe any intermediate state. 671 AutoDisableCompactingGC nocgc(cx); 672 673 AutoDisableProxyCheck adpc; 674 675 AutoEnterOOMUnsafeRegion oomUnsafe; 676 677 JS::Compartment* destination = target->compartment(); 678 679 if (origobj->compartment() == destination) { 680 // If the original object is in the same compartment as the 681 // destination, then we know that we won't find a wrapper in the 682 // destination's cross compartment map and that the same 683 // object will continue to work. 684 AutoRealm ar(cx, origobj); 685 JSObject::swap(cx, origobj, target, oomUnsafe); 686 newIdentity = origobj; 687 } else if (ObjectWrapperMap::Ptr p = destination->lookupWrapper(origobj)) { 688 // There might already be a wrapper for the original object in 689 // the new compartment. If there is, we use its identity and swap 690 // in the contents of |target|. 691 newIdentity = p->value().get(); 692 693 // When we remove origv from the wrapper map, its wrapper, newIdentity, 694 // must immediately cease to be a cross-compartment wrapper. Nuke it. 695 destination->removeWrapper(p); 696 NukeCrossCompartmentWrapper(cx, newIdentity); 697 698 AutoRealm ar(cx, newIdentity); 699 JSObject::swap(cx, newIdentity, target, oomUnsafe); 700 } else { 701 // Otherwise, we use |target| for the new identity object. 702 newIdentity = target; 703 } 704 705 // Now, iterate through other scopes looking for references to the old 706 // object, and update the relevant cross-compartment wrappers. We do this 707 // even if origobj is in the same compartment as target and thus 708 // `newIdentity == origobj`, because this process also clears out any 709 // cached wrapper state. 710 if (!RemapAllWrappersForObject(cx, origobj, newIdentity)) { 711 oomUnsafe.crash("JS_TransplantObject"); 712 } 713 714 // Lastly, update the original object to point to the new one. 715 if (origobj->compartment() != destination) { 716 RootedObject newIdentityWrapper(cx, newIdentity); 717 AutoRealm ar(cx, origobj); 718 if (!JS_WrapObject(cx, &newIdentityWrapper)) { 719 MOZ_RELEASE_ASSERT(cx->isThrowingOutOfMemory() || 720 cx->isThrowingOverRecursed()); 721 oomUnsafe.crash("JS_TransplantObject"); 722 } 723 MOZ_ASSERT(Wrapper::wrappedObject(newIdentityWrapper) == newIdentity); 724 JSObject::swap(cx, origobj, newIdentityWrapper, oomUnsafe); 725 if (origobj->compartment()->lookupWrapper(newIdentity)) { 726 MOZ_ASSERT(origobj->is<CrossCompartmentWrapperObject>()); 727 if (!origobj->compartment()->putWrapper(cx, newIdentity, origobj)) { 728 oomUnsafe.crash("JS_TransplantObject"); 729 } 730 } 731 } 732 733 // The new identity object might be one of several things. Return it to avoid 734 // ambiguity. 735 JS::AssertCellIsNotGray(newIdentity); 736 return newIdentity; 737 } 738 739 JS_PUBLIC_API void js::RemapRemoteWindowProxies( 740 JSContext* cx, CompartmentTransplantCallback* callback, 741 MutableHandleObject target) { 742 AssertHeapIsIdle(); 743 CheckTransplantObject(target); 744 ReleaseAssertObjectHasNoWrappers(cx, target); 745 746 // |target| can't be a remote proxy, because we expect it to get a CCW when 747 // wrapped across compartments. 748 MOZ_ASSERT(!js::IsDOMRemoteProxyObject(target)); 749 750 // Don't allow a compacting GC to observe any intermediate state. 751 AutoDisableCompactingGC nocgc(cx); 752 753 AutoDisableProxyCheck adpc; 754 755 AutoEnterOOMUnsafeRegion oomUnsafe; 756 757 AutoCheckRecursionLimit recursion(cx); 758 if (!recursion.checkSystem(cx)) { 759 oomUnsafe.crash("js::RemapRemoteWindowProxies"); 760 } 761 762 RootedObject targetCompartmentProxy(cx); 763 JS::RootedVector<JSObject*> otherProxies(cx); 764 765 // Use the callback to find remote proxies in all compartments that match 766 // whatever criteria callback uses. 767 for (CompartmentsIter c(cx->runtime()); !c.done(); c.next()) { 768 RootedObject remoteProxy(cx, callback->getObjectToTransplant(c)); 769 if (!remoteProxy) { 770 continue; 771 } 772 // The object the callback returns should be a DOM remote proxy object in 773 // the compartment c. We rely on it being a DOM remote proxy because that 774 // means that it won't have any cross-compartment wrappers. 775 MOZ_ASSERT(js::IsDOMRemoteProxyObject(remoteProxy)); 776 MOZ_ASSERT(remoteProxy->compartment() == c); 777 CheckTransplantObject(remoteProxy); 778 779 // Immediately turn the DOM remote proxy object into a dead proxy object 780 // so we don't have to worry about anything weird going on with it. 781 js::NukeNonCCWProxy(cx, remoteProxy); 782 783 if (remoteProxy->compartment() == target->compartment()) { 784 targetCompartmentProxy = remoteProxy; 785 } else if (!otherProxies.append(remoteProxy)) { 786 oomUnsafe.crash("js::RemapRemoteWindowProxies"); 787 } 788 } 789 790 // If there was a remote proxy in |target|'s compartment, we need to use it 791 // instead of |target|, in case it had any references, so swap it. Do this 792 // before any other compartment so that the target object will be set up 793 // correctly before we start wrapping it into other compartments. 794 if (targetCompartmentProxy) { 795 AutoRealm ar(cx, targetCompartmentProxy); 796 JSObject::swap(cx, targetCompartmentProxy, target, oomUnsafe); 797 target.set(targetCompartmentProxy); 798 } 799 800 for (JSObject*& obj : otherProxies) { 801 RootedObject deadWrapper(cx, obj); 802 js::RemapDeadWrapper(cx, deadWrapper, target); 803 } 804 } 805 806 /* 807 * Recompute all cross-compartment wrappers for an object, resetting state. 808 * Gecko uses this to clear Xray wrappers when doing a navigation that reuses 809 * the inner window and global object. 810 */ 811 JS_PUBLIC_API bool JS_RefreshCrossCompartmentWrappers(JSContext* cx, 812 HandleObject obj) { 813 return RemapAllWrappersForObject(cx, obj, obj); 814 } 815 816 struct JSStdName { 817 size_t atomOffset; /* offset of atom pointer in JSAtomState */ 818 JSProtoKey key; 819 bool isDummy() const { return key == JSProto_Null; } 820 bool isSentinel() const { return key == JSProto_LIMIT; } 821 }; 822 823 static const JSStdName* LookupStdName(const JSAtomState& names, JSAtom* name, 824 const JSStdName* table) { 825 for (unsigned i = 0; !table[i].isSentinel(); i++) { 826 if (table[i].isDummy()) { 827 continue; 828 } 829 JSAtom* atom = AtomStateOffsetToName(names, table[i].atomOffset); 830 MOZ_ASSERT(atom); 831 if (name == atom) { 832 return &table[i]; 833 } 834 } 835 836 return nullptr; 837 } 838 839 /* 840 * Table of standard classes, indexed by JSProtoKey. For entries where the 841 * JSProtoKey does not correspond to a class with a meaningful constructor, we 842 * insert a null entry into the table. 843 */ 844 #define STD_NAME_ENTRY(name, clasp) {NAME_OFFSET(name), JSProto_##name}, 845 #define STD_DUMMY_ENTRY(name, dummy) {0, JSProto_Null}, 846 static const JSStdName standard_class_names[] = { 847 JS_FOR_PROTOTYPES(STD_NAME_ENTRY, STD_DUMMY_ENTRY){0, JSProto_LIMIT}}; 848 849 /* 850 * Table of top-level function and constant names and the JSProtoKey of the 851 * standard class that initializes them. 852 */ 853 static const JSStdName builtin_property_names[] = { 854 {NAME_OFFSET(eval), JSProto_Object}, 855 856 /* Global properties and functions defined by the Number class. */ 857 {NAME_OFFSET(NaN), JSProto_Number}, 858 {NAME_OFFSET(Infinity), JSProto_Number}, 859 {NAME_OFFSET(isNaN), JSProto_Number}, 860 {NAME_OFFSET(isFinite), JSProto_Number}, 861 {NAME_OFFSET(parseFloat), JSProto_Number}, 862 {NAME_OFFSET(parseInt), JSProto_Number}, 863 864 /* String global functions. */ 865 {NAME_OFFSET(escape), JSProto_String}, 866 {NAME_OFFSET(unescape), JSProto_String}, 867 {NAME_OFFSET(decodeURI), JSProto_String}, 868 {NAME_OFFSET(encodeURI), JSProto_String}, 869 {NAME_OFFSET(decodeURIComponent), JSProto_String}, 870 {NAME_OFFSET(encodeURIComponent), JSProto_String}, 871 {NAME_OFFSET(uneval), JSProto_String}, 872 873 {0, JSProto_LIMIT}}; 874 875 static bool SkipUneval(jsid id, JSContext* cx) { 876 return !cx->realm()->creationOptions().getToSourceEnabled() && 877 id == NameToId(cx->names().uneval); 878 } 879 880 static bool SkipSharedArrayBufferConstructor(JSProtoKey key, 881 GlobalObject* global) { 882 if (key != JSProto_SharedArrayBuffer) { 883 return false; 884 } 885 886 const JS::RealmCreationOptions& options = global->realm()->creationOptions(); 887 MOZ_ASSERT(options.getSharedMemoryAndAtomicsEnabled(), 888 "shouldn't contemplate defining SharedArrayBuffer if shared " 889 "memory is disabled"); 890 891 // On the web, it isn't presently possible to expose the global 892 // "SharedArrayBuffer" property unless the page is cross-site-isolated. Only 893 // define this constructor if an option on the realm indicates that it should 894 // be defined. 895 return !options.defineSharedArrayBufferConstructor(); 896 } 897 898 JS_PUBLIC_API bool JS_ResolveStandardClass(JSContext* cx, HandleObject obj, 899 HandleId id, bool* resolved) { 900 AssertHeapIsIdle(); 901 CHECK_THREAD(cx); 902 cx->check(obj, id); 903 904 Handle<GlobalObject*> global = obj.as<GlobalObject>(); 905 *resolved = false; 906 907 if (!id.isAtom()) { 908 return true; 909 } 910 911 /* Check whether we're resolving 'undefined', and define it if so. */ 912 JSAtom* idAtom = id.toAtom(); 913 if (idAtom == cx->names().undefined) { 914 *resolved = true; 915 return js::DefineDataProperty( 916 cx, global, id, UndefinedHandleValue, 917 JSPROP_PERMANENT | JSPROP_READONLY | JSPROP_RESOLVING); 918 } 919 920 // Resolve a "globalThis" self-referential property if necessary. 921 if (idAtom == cx->names().globalThis) { 922 return GlobalObject::maybeResolveGlobalThis(cx, global, resolved); 923 } 924 925 // Try for class constructors/prototypes named by well-known atoms. 926 const JSStdName* stdnm = 927 LookupStdName(cx->names(), idAtom, standard_class_names); 928 if (!stdnm) { 929 // Try less frequently used top-level functions and constants. 930 stdnm = LookupStdName(cx->names(), idAtom, builtin_property_names); 931 if (!stdnm) { 932 return true; 933 } 934 } 935 936 JSProtoKey key = stdnm->key; 937 if (key == JSProto_Null || GlobalObject::skipDeselectedConstructor(cx, key) || 938 SkipUneval(id, cx)) { 939 return true; 940 } 941 942 // If this class is anonymous (or it's "SharedArrayBuffer" but that global 943 // constructor isn't supposed to be defined), then it doesn't exist as a 944 // global property, so we won't resolve anything. 945 const JSClass* clasp = ProtoKeyToClass(key); 946 if (clasp && !clasp->specShouldDefineConstructor()) { 947 return true; 948 } 949 if (SkipSharedArrayBufferConstructor(key, global)) { 950 return true; 951 } 952 953 if (!GlobalObject::ensureConstructor(cx, global, key)) { 954 return false; 955 } 956 *resolved = true; 957 return true; 958 } 959 960 JS_PUBLIC_API bool JS_MayResolveStandardClass(const JSAtomState& names, jsid id, 961 JSObject* maybeObj) { 962 MOZ_ASSERT_IF(maybeObj, maybeObj->is<GlobalObject>()); 963 964 // The global object's resolve hook is special: JS_ResolveStandardClass 965 // initializes the prototype chain lazily. Only attempt to optimize here 966 // if we know the prototype chain has been initialized. 967 if (!maybeObj || !maybeObj->staticPrototype()) { 968 return true; 969 } 970 971 if (!id.isAtom()) { 972 return false; 973 } 974 975 JSAtom* atom = id.toAtom(); 976 977 // This will return true even for deselected constructors. (To do 978 // better, we need a JSContext here; it's fine as it is.) 979 980 return atom == names.undefined || atom == names.globalThis || 981 LookupStdName(names, atom, standard_class_names) || 982 LookupStdName(names, atom, builtin_property_names); 983 } 984 985 JS_PUBLIC_API bool JS_EnumerateStandardClasses(JSContext* cx, 986 HandleObject obj) { 987 AssertHeapIsIdle(); 988 CHECK_THREAD(cx); 989 cx->check(obj); 990 Handle<GlobalObject*> global = obj.as<GlobalObject>(); 991 return GlobalObject::initStandardClasses(cx, global); 992 } 993 994 static bool EnumerateStandardClassesInTable(JSContext* cx, 995 Handle<GlobalObject*> global, 996 MutableHandleIdVector properties, 997 const JSStdName* table, 998 bool includeResolved) { 999 for (unsigned i = 0; !table[i].isSentinel(); i++) { 1000 if (table[i].isDummy()) { 1001 continue; 1002 } 1003 1004 JSProtoKey key = table[i].key; 1005 1006 // If the standard class has been resolved, the properties have been 1007 // defined on the global so we don't need to add them here. 1008 if (!includeResolved && global->isStandardClassResolved(key)) { 1009 continue; 1010 } 1011 1012 if (GlobalObject::skipDeselectedConstructor(cx, key)) { 1013 continue; 1014 } 1015 1016 if (const JSClass* clasp = ProtoKeyToClass(key)) { 1017 if (!clasp->specShouldDefineConstructor() || 1018 SkipSharedArrayBufferConstructor(key, global)) { 1019 continue; 1020 } 1021 } 1022 1023 jsid id = NameToId(AtomStateOffsetToName(cx->names(), table[i].atomOffset)); 1024 1025 if (SkipUneval(id, cx)) { 1026 continue; 1027 } 1028 1029 if (!properties.append(id)) { 1030 return false; 1031 } 1032 } 1033 1034 return true; 1035 } 1036 1037 static bool EnumerateStandardClasses(JSContext* cx, JS::HandleObject obj, 1038 JS::MutableHandleIdVector properties, 1039 bool enumerableOnly, 1040 bool includeResolved) { 1041 if (enumerableOnly) { 1042 // There are no enumerable standard classes and "undefined" is 1043 // not enumerable. 1044 return true; 1045 } 1046 1047 Handle<GlobalObject*> global = obj.as<GlobalObject>(); 1048 1049 // It's fine to always append |undefined| here, it's non-configurable and 1050 // the enumeration code filters duplicates. 1051 if (!properties.append(NameToId(cx->names().undefined))) { 1052 return false; 1053 } 1054 1055 bool resolved = false; 1056 if (!GlobalObject::maybeResolveGlobalThis(cx, global, &resolved)) { 1057 return false; 1058 } 1059 if (resolved || includeResolved) { 1060 if (!properties.append(NameToId(cx->names().globalThis))) { 1061 return false; 1062 } 1063 } 1064 1065 if (!EnumerateStandardClassesInTable(cx, global, properties, 1066 standard_class_names, includeResolved)) { 1067 return false; 1068 } 1069 if (!EnumerateStandardClassesInTable( 1070 cx, global, properties, builtin_property_names, includeResolved)) { 1071 return false; 1072 } 1073 1074 return true; 1075 } 1076 1077 JS_PUBLIC_API bool JS_NewEnumerateStandardClasses( 1078 JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties, 1079 bool enumerableOnly) { 1080 return EnumerateStandardClasses(cx, obj, properties, enumerableOnly, false); 1081 } 1082 1083 JS_PUBLIC_API bool JS_NewEnumerateStandardClassesIncludingResolved( 1084 JSContext* cx, JS::HandleObject obj, JS::MutableHandleIdVector properties, 1085 bool enumerableOnly) { 1086 return EnumerateStandardClasses(cx, obj, properties, enumerableOnly, true); 1087 } 1088 1089 JS_PUBLIC_API bool JS_GetClassObject(JSContext* cx, JSProtoKey key, 1090 MutableHandleObject objp) { 1091 AssertHeapIsIdle(); 1092 CHECK_THREAD(cx); 1093 JSObject* obj = GlobalObject::getOrCreateConstructor(cx, key); 1094 if (!obj) { 1095 return false; 1096 } 1097 objp.set(obj); 1098 return true; 1099 } 1100 1101 JS_PUBLIC_API bool JS_GetClassPrototype(JSContext* cx, JSProtoKey key, 1102 MutableHandleObject objp) { 1103 AssertHeapIsIdle(); 1104 CHECK_THREAD(cx); 1105 1106 // Bound functions don't have their own prototype object: they reuse the 1107 // prototype of the target object. This is typically Function.prototype so we 1108 // use that here. 1109 if (key == JSProto_BoundFunction) { 1110 key = JSProto_Function; 1111 } 1112 1113 JSObject* proto = GlobalObject::getOrCreatePrototype(cx, key); 1114 if (!proto) { 1115 return false; 1116 } 1117 objp.set(proto); 1118 return true; 1119 } 1120 1121 namespace JS { 1122 1123 JS_PUBLIC_API void ProtoKeyToId(JSContext* cx, JSProtoKey key, 1124 MutableHandleId idp) { 1125 idp.set(NameToId(ClassName(key, cx))); 1126 } 1127 1128 } /* namespace JS */ 1129 1130 JS_PUBLIC_API JSProtoKey JS_IdToProtoKey(JSContext* cx, HandleId id) { 1131 AssertHeapIsIdle(); 1132 CHECK_THREAD(cx); 1133 cx->check(id); 1134 1135 if (!id.isAtom()) { 1136 return JSProto_Null; 1137 } 1138 1139 JSAtom* atom = id.toAtom(); 1140 const JSStdName* stdnm = 1141 LookupStdName(cx->names(), atom, standard_class_names); 1142 if (!stdnm) { 1143 return JSProto_Null; 1144 } 1145 1146 if (GlobalObject::skipDeselectedConstructor(cx, stdnm->key)) { 1147 return JSProto_Null; 1148 } 1149 1150 if (SkipSharedArrayBufferConstructor(stdnm->key, cx->global())) { 1151 MOZ_ASSERT(id == NameToId(cx->names().SharedArrayBuffer)); 1152 return JSProto_Null; 1153 } 1154 1155 if (SkipUneval(id, cx)) { 1156 return JSProto_Null; 1157 } 1158 1159 static_assert(std::size(standard_class_names) == JSProto_LIMIT + 1); 1160 return static_cast<JSProtoKey>(stdnm - standard_class_names); 1161 } 1162 1163 extern JS_PUBLIC_API bool JS_IsGlobalObject(JSObject* obj) { 1164 return obj->is<GlobalObject>(); 1165 } 1166 1167 extern JS_PUBLIC_API JSObject* JS_GlobalLexicalEnvironment(JSObject* obj) { 1168 return &obj->as<GlobalObject>().lexicalEnvironment(); 1169 } 1170 1171 extern JS_PUBLIC_API bool JS_HasExtensibleLexicalEnvironment(JSObject* obj) { 1172 return obj->is<GlobalObject>() || 1173 ObjectRealm::get(obj).getNonSyntacticLexicalEnvironment(obj); 1174 } 1175 1176 extern JS_PUBLIC_API JSObject* JS_ExtensibleLexicalEnvironment(JSObject* obj) { 1177 return ExtensibleLexicalEnvironmentObject::forVarEnvironment(obj); 1178 } 1179 1180 JS_PUBLIC_API JSObject* JS::CurrentGlobalOrNull(JSContext* cx) { 1181 AssertHeapIsIdleOrIterating(); 1182 CHECK_THREAD(cx); 1183 if (!cx->realm()) { 1184 return nullptr; 1185 } 1186 return cx->global(); 1187 } 1188 1189 JS_PUBLIC_API JSObject* JS::GetNonCCWObjectGlobal(JSObject* obj) { 1190 AssertHeapIsIdleOrIterating(); 1191 MOZ_DIAGNOSTIC_ASSERT(!IsCrossCompartmentWrapper(obj)); 1192 return &obj->nonCCWGlobal(); 1193 } 1194 1195 JS_PUBLIC_API bool JS::detail::ComputeThis(JSContext* cx, Value* vp, 1196 MutableHandleObject thisObject) { 1197 AssertHeapIsIdle(); 1198 cx->check(vp[0], vp[1]); 1199 1200 MutableHandleValue thisv = MutableHandleValue::fromMarkedLocation(&vp[1]); 1201 JSObject* obj = BoxNonStrictThis(cx, thisv); 1202 if (!obj) { 1203 return false; 1204 } 1205 1206 thisObject.set(obj); 1207 return true; 1208 } 1209 1210 static bool gProfileTimelineRecordingEnabled = false; 1211 1212 JS_PUBLIC_API void JS::SetProfileTimelineRecordingEnabled(bool enabled) { 1213 gProfileTimelineRecordingEnabled = enabled; 1214 } 1215 1216 JS_PUBLIC_API bool JS::IsProfileTimelineRecordingEnabled() { 1217 return gProfileTimelineRecordingEnabled; 1218 } 1219 1220 JS_PUBLIC_API void* JS_malloc(JSContext* cx, size_t nbytes) { 1221 AssertHeapIsIdle(); 1222 CHECK_THREAD(cx); 1223 return static_cast<void*>(cx->maybe_pod_malloc<uint8_t>(nbytes)); 1224 } 1225 1226 JS_PUBLIC_API void* JS_realloc(JSContext* cx, void* p, size_t oldBytes, 1227 size_t newBytes) { 1228 AssertHeapIsIdle(); 1229 CHECK_THREAD(cx); 1230 return static_cast<void*>(cx->maybe_pod_realloc<uint8_t>( 1231 static_cast<uint8_t*>(p), oldBytes, newBytes)); 1232 } 1233 1234 JS_PUBLIC_API void JS_free(JSContext* cx, void* p) { return js_free(p); } 1235 1236 JS_PUBLIC_API void* JS_string_malloc(JSContext* cx, size_t nbytes) { 1237 AssertHeapIsIdle(); 1238 CHECK_THREAD(cx); 1239 return static_cast<void*>( 1240 cx->maybe_pod_arena_malloc<uint8_t>(js::StringBufferArena, nbytes)); 1241 } 1242 1243 JS_PUBLIC_API void* JS_string_realloc(JSContext* cx, void* p, size_t oldBytes, 1244 size_t newBytes) { 1245 AssertHeapIsIdle(); 1246 CHECK_THREAD(cx); 1247 return static_cast<void*>(cx->maybe_pod_arena_realloc<uint8_t>( 1248 js::StringBufferArena, static_cast<uint8_t*>(p), oldBytes, newBytes)); 1249 } 1250 1251 JS_PUBLIC_API void JS_string_free(JSContext* cx, void* p) { return js_free(p); } 1252 1253 JS_PUBLIC_API void JS::AddAssociatedMemory(JSObject* obj, size_t nbytes, 1254 JS::MemoryUse use) { 1255 MOZ_ASSERT(obj); 1256 if (!nbytes) { 1257 return; 1258 } 1259 1260 Zone* zone = obj->zone(); 1261 MOZ_ASSERT(!IsInsideNursery(obj)); 1262 zone->addCellMemory(obj, nbytes, js::MemoryUse(use)); 1263 zone->maybeTriggerGCOnMalloc(); 1264 } 1265 1266 JS_PUBLIC_API void JS::RemoveAssociatedMemory(JSObject* obj, size_t nbytes, 1267 JS::MemoryUse use) { 1268 MOZ_ASSERT(obj); 1269 if (!nbytes) { 1270 return; 1271 } 1272 1273 GCContext* gcx = obj->runtimeFromMainThread()->gcContext(); 1274 gcx->removeCellMemory(obj, nbytes, js::MemoryUse(use)); 1275 } 1276 1277 #undef JS_AddRoot 1278 1279 JS_PUBLIC_API bool JS_AddExtraGCRootsTracer(JSContext* cx, 1280 JSTraceDataOp traceOp, void* data) { 1281 return cx->runtime()->gc.addBlackRootsTracer(traceOp, data); 1282 } 1283 1284 JS_PUBLIC_API void JS_RemoveExtraGCRootsTracer(JSContext* cx, 1285 JSTraceDataOp traceOp, 1286 void* data) { 1287 return cx->runtime()->gc.removeBlackRootsTracer(traceOp, data); 1288 } 1289 1290 JS_PUBLIC_API JS::GCReason JS::WantEagerMinorGC(JSRuntime* rt) { 1291 if (rt->gc.nursery().wantEagerCollection()) { 1292 return JS::GCReason::EAGER_NURSERY_COLLECTION; 1293 } 1294 return JS::GCReason::NO_REASON; 1295 } 1296 1297 JS_PUBLIC_API JS::GCReason JS::WantEagerMajorGC(JSRuntime* rt) { 1298 return rt->gc.wantMajorGC(true); 1299 } 1300 1301 JS_PUBLIC_API void JS::MaybeRunNurseryCollection(JSRuntime* rt, 1302 JS::GCReason reason) { 1303 gc::GCRuntime& gc = rt->gc; 1304 if (gc.nursery().wantEagerCollection()) { 1305 gc.minorGC(reason); 1306 } 1307 } 1308 1309 JS_PUBLIC_API void JS::RunNurseryCollection( 1310 JSRuntime* rt, JS::GCReason reason, 1311 mozilla::TimeDuration aSinceLastMinorGC) { 1312 gc::GCRuntime& gc = rt->gc; 1313 if (!gc.nursery().lastCollectionEndTime() || 1314 (mozilla::TimeStamp::Now() - gc.nursery().lastCollectionEndTime() > 1315 aSinceLastMinorGC)) { 1316 gc.minorGC(reason); 1317 } 1318 } 1319 1320 JS_PUBLIC_API void JS_GC(JSContext* cx, JS::GCReason reason) { 1321 AssertHeapIsIdle(); 1322 JS::PrepareForFullGC(cx); 1323 cx->runtime()->gc.gc(JS::GCOptions::Normal, reason); 1324 } 1325 1326 JS_PUBLIC_API void JS_MaybeGC(JSContext* cx) { 1327 AssertHeapIsIdle(); 1328 cx->runtime()->gc.maybeGC(); 1329 } 1330 1331 JS_PUBLIC_API void JS_SetGCCallback(JSContext* cx, JSGCCallback cb, 1332 void* data) { 1333 AssertHeapIsIdle(); 1334 cx->runtime()->gc.setGCCallback(cb, data); 1335 } 1336 1337 JS_PUBLIC_API void JS_SetObjectsTenuredCallback(JSContext* cx, 1338 JSObjectsTenuredCallback cb, 1339 void* data) { 1340 AssertHeapIsIdle(); 1341 cx->runtime()->gc.setObjectsTenuredCallback(cb, data); 1342 } 1343 1344 JS_PUBLIC_API bool JS_AddFinalizeCallback(JSContext* cx, JSFinalizeCallback cb, 1345 void* data) { 1346 AssertHeapIsIdle(); 1347 return cx->runtime()->gc.addFinalizeCallback(cb, data); 1348 } 1349 1350 JS_PUBLIC_API void JS_RemoveFinalizeCallback(JSContext* cx, 1351 JSFinalizeCallback cb) { 1352 cx->runtime()->gc.removeFinalizeCallback(cb); 1353 } 1354 1355 JS_PUBLIC_API void JS::SetHostCleanupFinalizationRegistryCallback( 1356 JSContext* cx, JSHostCleanupFinalizationRegistryCallback cb, void* data) { 1357 AssertHeapIsIdle(); 1358 cx->runtime()->gc.setHostCleanupFinalizationRegistryCallback(cb, data); 1359 } 1360 1361 JS_PUBLIC_API void JS::ClearKeptObjects(JSContext* cx) { 1362 gc::GCRuntime* gc = &cx->runtime()->gc; 1363 1364 for (ZonesIter zone(gc, ZoneSelector::WithAtoms); !zone.done(); zone.next()) { 1365 zone->clearKeptObjects(); 1366 } 1367 } 1368 1369 JS_PUBLIC_API bool JS::AtomsZoneIsCollecting(JSRuntime* runtime) { 1370 return runtime->activeGCInAtomsZone(); 1371 } 1372 1373 JS_PUBLIC_API bool JS::IsAtomsZone(JS::Zone* zone) { 1374 return zone->isAtomsZone(); 1375 } 1376 1377 JS_PUBLIC_API bool JS_AddWeakPointerZonesCallback(JSContext* cx, 1378 JSWeakPointerZonesCallback cb, 1379 void* data) { 1380 AssertHeapIsIdle(); 1381 return cx->runtime()->gc.addWeakPointerZonesCallback(cb, data); 1382 } 1383 1384 JS_PUBLIC_API void JS_RemoveWeakPointerZonesCallback( 1385 JSContext* cx, JSWeakPointerZonesCallback cb) { 1386 cx->runtime()->gc.removeWeakPointerZonesCallback(cb); 1387 } 1388 1389 JS_PUBLIC_API bool JS_AddWeakPointerCompartmentCallback( 1390 JSContext* cx, JSWeakPointerCompartmentCallback cb, void* data) { 1391 AssertHeapIsIdle(); 1392 return cx->runtime()->gc.addWeakPointerCompartmentCallback(cb, data); 1393 } 1394 1395 JS_PUBLIC_API void JS_RemoveWeakPointerCompartmentCallback( 1396 JSContext* cx, JSWeakPointerCompartmentCallback cb) { 1397 cx->runtime()->gc.removeWeakPointerCompartmentCallback(cb); 1398 } 1399 1400 JS_PUBLIC_API bool JS_UpdateWeakPointerAfterGC(JSTracer* trc, 1401 JS::Heap<JSObject*>* objp) { 1402 return TraceWeakEdge(trc, objp); 1403 } 1404 1405 JS_PUBLIC_API bool JS_UpdateWeakPointerAfterGCUnbarriered(JSTracer* trc, 1406 JSObject** objp) { 1407 return TraceManuallyBarrieredWeakEdge(trc, objp, "External weak pointer"); 1408 } 1409 1410 JS_PUBLIC_API void JS_SetGCParameter(JSContext* cx, JSGCParamKey key, 1411 uint32_t value) { 1412 // Bug 1742118: JS_SetGCParameter has no way to return an error 1413 // The GC ignores invalid values internally but this is not reported to the 1414 // caller. 1415 (void)cx->runtime()->gc.setParameter(cx, key, value); 1416 } 1417 1418 JS_PUBLIC_API void JS_ResetGCParameter(JSContext* cx, JSGCParamKey key) { 1419 cx->runtime()->gc.resetParameter(cx, key); 1420 } 1421 1422 JS_PUBLIC_API uint32_t JS_GetGCParameter(JSContext* cx, JSGCParamKey key) { 1423 return cx->runtime()->gc.getParameter(key); 1424 } 1425 1426 JS_PUBLIC_API void JS_SetGCParametersBasedOnAvailableMemory( 1427 JSContext* cx, uint32_t availMemMB) { 1428 struct JSGCConfig { 1429 JSGCParamKey key; 1430 uint32_t value; 1431 }; 1432 1433 static const JSGCConfig minimal[] = { 1434 {JSGC_SLICE_TIME_BUDGET_MS, 5}, 1435 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1500}, 1436 {JSGC_LARGE_HEAP_SIZE_MIN, 250}, 1437 {JSGC_SMALL_HEAP_SIZE_MAX, 50}, 1438 {JSGC_HIGH_FREQUENCY_SMALL_HEAP_GROWTH, 300}, 1439 {JSGC_HIGH_FREQUENCY_LARGE_HEAP_GROWTH, 120}, 1440 {JSGC_LOW_FREQUENCY_HEAP_GROWTH, 120}, 1441 {JSGC_ALLOCATION_THRESHOLD, 15}, 1442 {JSGC_MALLOC_THRESHOLD_BASE, 20}, 1443 {JSGC_SMALL_HEAP_INCREMENTAL_LIMIT, 200}, 1444 {JSGC_LARGE_HEAP_INCREMENTAL_LIMIT, 110}, 1445 {JSGC_URGENT_THRESHOLD_MB, 8}}; 1446 1447 static const JSGCConfig nominal[] = { 1448 {JSGC_SLICE_TIME_BUDGET_MS, 5}, 1449 {JSGC_HIGH_FREQUENCY_TIME_LIMIT, 1000}, 1450 {JSGC_LARGE_HEAP_SIZE_MIN, 500}, 1451 {JSGC_SMALL_HEAP_SIZE_MAX, 100}, 1452 {JSGC_HIGH_FREQUENCY_SMALL_HEAP_GROWTH, 300}, 1453 {JSGC_HIGH_FREQUENCY_LARGE_HEAP_GROWTH, 150}, 1454 {JSGC_LOW_FREQUENCY_HEAP_GROWTH, 150}, 1455 {JSGC_ALLOCATION_THRESHOLD, 27}, 1456 {JSGC_MALLOC_THRESHOLD_BASE, 38}, 1457 {JSGC_SMALL_HEAP_INCREMENTAL_LIMIT, 150}, 1458 {JSGC_LARGE_HEAP_INCREMENTAL_LIMIT, 110}, 1459 {JSGC_URGENT_THRESHOLD_MB, 16}}; 1460 1461 const auto& configSet = availMemMB > 512 ? nominal : minimal; 1462 for (const auto& config : configSet) { 1463 JS_SetGCParameter(cx, config.key, config.value); 1464 } 1465 } 1466 1467 JS_PUBLIC_API JSString* JS_NewExternalStringLatin1( 1468 JSContext* cx, const Latin1Char* chars, size_t length, 1469 const JSExternalStringCallbacks* callbacks) { 1470 AssertHeapIsIdle(); 1471 CHECK_THREAD(cx); 1472 return JSExternalString::new_(cx, chars, length, callbacks); 1473 } 1474 1475 JS_PUBLIC_API JSString* JS_NewExternalUCString( 1476 JSContext* cx, const char16_t* chars, size_t length, 1477 const JSExternalStringCallbacks* callbacks) { 1478 AssertHeapIsIdle(); 1479 CHECK_THREAD(cx); 1480 return JSExternalString::new_(cx, chars, length, callbacks); 1481 } 1482 1483 JS_PUBLIC_API JSString* JS_NewMaybeExternalStringLatin1( 1484 JSContext* cx, const JS::Latin1Char* chars, size_t length, 1485 const JSExternalStringCallbacks* callbacks, bool* allocatedExternal) { 1486 AssertHeapIsIdle(); 1487 CHECK_THREAD(cx); 1488 return NewMaybeExternalString(cx, chars, length, callbacks, 1489 allocatedExternal); 1490 } 1491 1492 JS_PUBLIC_API JSString* JS_NewMaybeExternalStringUTF8( 1493 JSContext* cx, const JS::UTF8Chars& utf8, 1494 const JSExternalStringCallbacks* callbacks, bool* allocatedExternal) { 1495 AssertHeapIsIdle(); 1496 CHECK_THREAD(cx); 1497 1498 JS::SmallestEncoding encoding = JS::FindSmallestEncoding(utf8); 1499 if (encoding == JS::SmallestEncoding::ASCII) { 1500 // ASCII case can use the external buffer as Latin1 buffer. 1501 return NewMaybeExternalString( 1502 cx, reinterpret_cast<JS::Latin1Char*>(utf8.begin().get()), 1503 utf8.length(), callbacks, allocatedExternal); 1504 } 1505 1506 // Non-ASCII case cannot use the external buffer. 1507 *allocatedExternal = false; 1508 return NewStringCopyUTF8N(cx, utf8, encoding); 1509 } 1510 1511 JS_PUBLIC_API JSString* JS_NewMaybeExternalUCString( 1512 JSContext* cx, const char16_t* chars, size_t length, 1513 const JSExternalStringCallbacks* callbacks, bool* allocatedExternal) { 1514 AssertHeapIsIdle(); 1515 CHECK_THREAD(cx); 1516 return NewMaybeExternalString(cx, chars, length, callbacks, 1517 allocatedExternal); 1518 } 1519 1520 extern JS_PUBLIC_API const JSExternalStringCallbacks* 1521 JS_GetExternalStringCallbacks(JSString* str) { 1522 return str->asExternal().callbacks(); 1523 } 1524 1525 static void SetNativeStackSize(JSContext* cx, JS::StackKind kind, 1526 JS::NativeStackSize stackSize) { 1527 #ifdef __wasi__ 1528 cx->nativeStackLimit[kind] = JS::WASINativeStackLimit; 1529 #else // __wasi__ 1530 if (stackSize == 0) { 1531 cx->nativeStackLimit[kind] = JS::NativeStackLimitMax; 1532 } else { 1533 cx->nativeStackLimit[kind] = 1534 JS::GetNativeStackLimit(cx->nativeStackBase(), stackSize - 1); 1535 } 1536 #endif // !__wasi__ 1537 } 1538 1539 JS_PUBLIC_API void JS_SetNativeStackQuota( 1540 JSContext* cx, JS::NativeStackSize systemCodeStackSize, 1541 JS::NativeStackSize trustedScriptStackSize, 1542 JS::NativeStackSize untrustedScriptStackSize) { 1543 MOZ_ASSERT(!cx->activation()); 1544 1545 if (!trustedScriptStackSize) { 1546 trustedScriptStackSize = systemCodeStackSize; 1547 } else { 1548 MOZ_ASSERT(trustedScriptStackSize < systemCodeStackSize); 1549 } 1550 1551 if (!untrustedScriptStackSize) { 1552 untrustedScriptStackSize = trustedScriptStackSize; 1553 } else { 1554 MOZ_ASSERT(untrustedScriptStackSize < trustedScriptStackSize); 1555 } 1556 1557 SetNativeStackSize(cx, JS::StackForSystemCode, systemCodeStackSize); 1558 SetNativeStackSize(cx, JS::StackForTrustedScript, trustedScriptStackSize); 1559 SetNativeStackSize(cx, JS::StackForUntrustedScript, untrustedScriptStackSize); 1560 1561 if (cx->runtime()->isMainRuntime()) { 1562 js::gc::MapStack(systemCodeStackSize); 1563 } 1564 1565 cx->initJitStackLimit(); 1566 } 1567 1568 /************************************************************************/ 1569 1570 JS_PUBLIC_API bool JS_ValueToId(JSContext* cx, HandleValue value, 1571 MutableHandleId idp) { 1572 AssertHeapIsIdle(); 1573 CHECK_THREAD(cx); 1574 cx->check(value); 1575 return ToPropertyKey(cx, value, idp); 1576 } 1577 1578 JS_PUBLIC_API bool JS_StringToId(JSContext* cx, HandleString string, 1579 MutableHandleId idp) { 1580 AssertHeapIsIdle(); 1581 CHECK_THREAD(cx); 1582 cx->check(string); 1583 RootedValue value(cx, StringValue(string)); 1584 return PrimitiveValueToId<CanGC>(cx, value, idp); 1585 } 1586 1587 JS_PUBLIC_API bool JS_IdToValue(JSContext* cx, jsid id, MutableHandleValue vp) { 1588 AssertHeapIsIdle(); 1589 CHECK_THREAD(cx); 1590 cx->check(id); 1591 vp.set(IdToValue(id)); 1592 cx->check(vp); 1593 return true; 1594 } 1595 1596 JS_PUBLIC_API bool JS::ToPrimitive(JSContext* cx, HandleObject obj, JSType hint, 1597 MutableHandleValue vp) { 1598 AssertHeapIsIdle(); 1599 CHECK_THREAD(cx); 1600 cx->check(obj); 1601 MOZ_ASSERT(obj != nullptr); 1602 MOZ_ASSERT(hint == JSTYPE_UNDEFINED || hint == JSTYPE_STRING || 1603 hint == JSTYPE_NUMBER); 1604 vp.setObject(*obj); 1605 return ToPrimitiveSlow(cx, hint, vp); 1606 } 1607 1608 JS_PUBLIC_API bool JS::GetFirstArgumentAsTypeHint(JSContext* cx, 1609 const CallArgs& args, 1610 JSType* result) { 1611 if (!args.get(0).isString()) { 1612 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 1613 JSMSG_NOT_EXPECTED_TYPE, "Symbol.toPrimitive", 1614 "\"string\", \"number\", or \"default\"", 1615 InformalValueTypeName(args.get(0))); 1616 return false; 1617 } 1618 1619 RootedString str(cx, args.get(0).toString()); 1620 bool match; 1621 1622 if (!EqualStrings(cx, str, cx->names().default_, &match)) { 1623 return false; 1624 } 1625 if (match) { 1626 *result = JSTYPE_UNDEFINED; 1627 return true; 1628 } 1629 1630 if (!EqualStrings(cx, str, cx->names().string, &match)) { 1631 return false; 1632 } 1633 if (match) { 1634 *result = JSTYPE_STRING; 1635 return true; 1636 } 1637 1638 if (!EqualStrings(cx, str, cx->names().number, &match)) { 1639 return false; 1640 } 1641 if (match) { 1642 *result = JSTYPE_NUMBER; 1643 return true; 1644 } 1645 1646 UniqueChars bytes; 1647 const char* source = ValueToSourceForError(cx, args.get(0), bytes); 1648 MOZ_ASSERT(source); 1649 1650 JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, 1651 JSMSG_NOT_EXPECTED_TYPE, "Symbol.toPrimitive", 1652 "\"string\", \"number\", or \"default\"", source); 1653 return false; 1654 } 1655 1656 JS_PUBLIC_API JSObject* JS_InitClass( 1657 JSContext* cx, HandleObject obj, const JSClass* protoClass, 1658 HandleObject protoProto, const char* name, JSNative constructor, 1659 unsigned nargs, const JSPropertySpec* ps, const JSFunctionSpec* fs, 1660 const JSPropertySpec* static_ps, const JSFunctionSpec* static_fs) { 1661 AssertHeapIsIdle(); 1662 CHECK_THREAD(cx); 1663 cx->check(obj, protoProto); 1664 return InitClass(cx, obj, protoClass, protoProto, name, constructor, nargs, 1665 ps, fs, static_ps, static_fs); 1666 } 1667 1668 JS_PUBLIC_API bool JS_LinkConstructorAndPrototype(JSContext* cx, 1669 HandleObject ctor, 1670 HandleObject proto) { 1671 return LinkConstructorAndPrototype(cx, ctor, proto); 1672 } 1673 1674 JS_PUBLIC_API bool JS_InstanceOf(JSContext* cx, HandleObject obj, 1675 const JSClass* clasp, CallArgs* args) { 1676 AssertHeapIsIdle(); 1677 CHECK_THREAD(cx); 1678 #ifdef DEBUG 1679 if (args) { 1680 cx->check(obj, args->thisv(), args->calleev()); 1681 } 1682 #endif 1683 if (!obj || obj->getClass() != clasp) { 1684 if (args) { 1685 ReportIncompatibleMethod(cx, *args, clasp); 1686 } 1687 return false; 1688 } 1689 return true; 1690 } 1691 1692 JS_PUBLIC_API bool JS_HasInstance(JSContext* cx, HandleObject obj, 1693 HandleValue value, bool* bp) { 1694 AssertHeapIsIdle(); 1695 cx->check(obj, value); 1696 return InstanceofOperator(cx, obj, value, bp); 1697 } 1698 1699 JS_PUBLIC_API JSObject* JS_GetConstructor(JSContext* cx, HandleObject proto) { 1700 AssertHeapIsIdle(); 1701 CHECK_THREAD(cx); 1702 cx->check(proto); 1703 1704 RootedValue cval(cx); 1705 if (!GetProperty(cx, proto, proto, cx->names().constructor, &cval)) { 1706 return nullptr; 1707 } 1708 if (!IsFunctionObject(cval)) { 1709 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 1710 JSMSG_NO_CONSTRUCTOR, proto->getClass()->name); 1711 return nullptr; 1712 } 1713 return &cval.toObject(); 1714 } 1715 1716 JS::RealmCreationOptions& 1717 JS::RealmCreationOptions::setNewCompartmentInSystemZone() { 1718 compSpec_ = CompartmentSpecifier::NewCompartmentInSystemZone; 1719 comp_ = nullptr; 1720 return *this; 1721 } 1722 1723 JS::RealmCreationOptions& 1724 JS::RealmCreationOptions::setNewCompartmentInExistingZone(JSObject* obj) { 1725 compSpec_ = CompartmentSpecifier::NewCompartmentInExistingZone; 1726 zone_ = obj->zone(); 1727 return *this; 1728 } 1729 1730 JS::RealmCreationOptions& JS::RealmCreationOptions::setExistingCompartment( 1731 JSObject* obj) { 1732 compSpec_ = CompartmentSpecifier::ExistingCompartment; 1733 comp_ = obj->compartment(); 1734 return *this; 1735 } 1736 1737 JS::RealmCreationOptions& JS::RealmCreationOptions::setExistingCompartment( 1738 JS::Compartment* compartment) { 1739 compSpec_ = CompartmentSpecifier::ExistingCompartment; 1740 comp_ = compartment; 1741 return *this; 1742 } 1743 1744 JS::RealmCreationOptions& JS::RealmCreationOptions::setNewCompartmentAndZone() { 1745 compSpec_ = CompartmentSpecifier::NewCompartmentAndZone; 1746 comp_ = nullptr; 1747 return *this; 1748 } 1749 1750 const JS::RealmCreationOptions& JS::RealmCreationOptionsRef(Realm* realm) { 1751 return realm->creationOptions(); 1752 } 1753 1754 const JS::RealmCreationOptions& JS::RealmCreationOptionsRef(JSContext* cx) { 1755 return cx->realm()->creationOptions(); 1756 } 1757 1758 bool JS::RealmCreationOptions::getSharedMemoryAndAtomicsEnabled() const { 1759 return sharedMemoryAndAtomics_; 1760 } 1761 1762 JS::RealmCreationOptions& 1763 JS::RealmCreationOptions::setSharedMemoryAndAtomicsEnabled(bool flag) { 1764 sharedMemoryAndAtomics_ = flag; 1765 return *this; 1766 } 1767 1768 bool JS::RealmCreationOptions::getCoopAndCoepEnabled() const { 1769 return coopAndCoep_; 1770 } 1771 1772 JS::RealmCreationOptions& JS::RealmCreationOptions::setCoopAndCoepEnabled( 1773 bool flag) { 1774 coopAndCoep_ = flag; 1775 return *this; 1776 } 1777 1778 template <class RefCountedString> 1779 static RefCountedString* CopyStringZ(const char* str) { 1780 MOZ_ASSERT(str); 1781 1782 const size_t size = strlen(str) + 1; 1783 1784 AutoEnterOOMUnsafeRegion oomUnsafe; 1785 char* memoryPtr = js_pod_malloc<char>(sizeof(RefCountedString) + size); 1786 if (!memoryPtr) { 1787 oomUnsafe.crash("CopyStringZ"); 1788 } 1789 1790 char* strPtr = memoryPtr + sizeof(RefCountedString); 1791 memcpy(strPtr, str, size); 1792 1793 return new (memoryPtr) RefCountedString(strPtr); 1794 } 1795 1796 JS::RealmBehaviors& JS::RealmBehaviors::setLocaleOverride(const char* locale) { 1797 if (locale) { 1798 localeOverride_ = CopyStringZ<JS::LocaleString>(locale); 1799 } else { 1800 localeOverride_ = nullptr; 1801 } 1802 return *this; 1803 } 1804 1805 JS::RealmBehaviors& JS::RealmBehaviors::setTimeZoneOverride( 1806 const char* timeZone) { 1807 if (timeZone) { 1808 timeZoneOverride_ = CopyStringZ<JS::TimeZoneString>(timeZone); 1809 } else { 1810 timeZoneOverride_ = nullptr; 1811 } 1812 return *this; 1813 } 1814 1815 const JS::RealmBehaviors& JS::RealmBehaviorsRef(JS::Realm* realm) { 1816 return realm->behaviors(); 1817 } 1818 1819 const JS::RealmBehaviors& JS::RealmBehaviorsRef(JSContext* cx) { 1820 return cx->realm()->behaviors(); 1821 } 1822 1823 void JS::SetRealmLocaleOverride(Realm* realm, const char* locale) { 1824 realm->setLocaleOverride(locale); 1825 } 1826 1827 void JS::SetRealmTimezoneOverride(Realm* realm, const char* timezone) { 1828 realm->setTimeZoneOverride(timezone); 1829 } 1830 1831 void JS::SetRealmNonLive(Realm* realm) { realm->setNonLive(); } 1832 1833 void JS::SetRealmReduceTimerPrecisionCallerType(Realm* realm, 1834 JS::RTPCallerTypeToken type) { 1835 realm->setReduceTimerPrecisionCallerType(type); 1836 } 1837 1838 JS_PUBLIC_API JSObject* JS_NewGlobalObject(JSContext* cx, const JSClass* clasp, 1839 JSPrincipals* principals, 1840 JS::OnNewGlobalHookOption hookOption, 1841 const JS::RealmOptions& options) { 1842 MOZ_RELEASE_ASSERT( 1843 cx->runtime()->hasInitializedSelfHosting(), 1844 "Must call JS::InitSelfHostedCode() before creating a global"); 1845 1846 AssertHeapIsIdle(); 1847 CHECK_THREAD(cx); 1848 1849 return GlobalObject::new_(cx, clasp, principals, hookOption, options); 1850 } 1851 1852 JS_PUBLIC_API void JS_GlobalObjectTraceHook(JSTracer* trc, JSObject* global) { 1853 GlobalObject* globalObj = &global->as<GlobalObject>(); 1854 Realm* globalRealm = globalObj->realm(); 1855 1856 // If we GC when creating the global, we may not have set that global's 1857 // realm's global pointer yet. In this case, the realm will not yet contain 1858 // anything that needs to be traced. 1859 if (globalRealm->unsafeUnbarrieredMaybeGlobal() != globalObj) { 1860 return; 1861 } 1862 1863 // Trace the realm for any GC things that should only stick around if we 1864 // know the global is live. 1865 globalRealm->traceGlobalData(trc); 1866 1867 globalObj->traceData(trc, globalObj); 1868 1869 if (JSTraceOp trace = globalRealm->creationOptions().getTrace()) { 1870 trace(trc, global); 1871 } 1872 } 1873 1874 const JSClassOps JS::DefaultGlobalClassOps = { 1875 nullptr, // addProperty 1876 nullptr, // delProperty 1877 nullptr, // enumerate 1878 JS_NewEnumerateStandardClasses, // newEnumerate 1879 JS_ResolveStandardClass, // resolve 1880 JS_MayResolveStandardClass, // mayResolve 1881 nullptr, // finalize 1882 nullptr, // call 1883 nullptr, // construct 1884 JS_GlobalObjectTraceHook, // trace 1885 }; 1886 1887 JS_PUBLIC_API void JS_FireOnNewGlobalObject(JSContext* cx, 1888 JS::HandleObject global) { 1889 // This hook is infallible, because we don't really want arbitrary script 1890 // to be able to throw errors during delicate global creation routines. 1891 // This infallibility will eat OOM and slow script, but if that happens 1892 // we'll likely run up into them again soon in a fallible context. 1893 cx->check(global); 1894 1895 Rooted<js::GlobalObject*> globalObject(cx, &global->as<GlobalObject>()); 1896 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 1897 if (JS::GetReduceMicrosecondTimePrecisionCallback()) { 1898 MOZ_DIAGNOSTIC_ASSERT(globalObject->realm() 1899 ->behaviors() 1900 .reduceTimerPrecisionCallerType() 1901 .isSome(), 1902 "Trying to create a global without setting an " 1903 "explicit RTPCallerType!"); 1904 } 1905 #endif 1906 DebugAPI::onNewGlobalObject(cx, globalObject); 1907 cx->runtime()->ensureRealmIsRecordingAllocations(globalObject); 1908 } 1909 1910 JS_PUBLIC_API JSObject* JS_NewObject(JSContext* cx, const JSClass* clasp) { 1911 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 1912 AssertHeapIsIdle(); 1913 CHECK_THREAD(cx); 1914 1915 if (!clasp) { 1916 // Default class is Object. 1917 return NewPlainObject(cx); 1918 } 1919 1920 MOZ_ASSERT(!clasp->isJSFunction()); 1921 MOZ_ASSERT(clasp != &PlainObject::class_); 1922 MOZ_ASSERT(clasp != &ArrayObject::class_); 1923 MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL)); 1924 1925 return NewBuiltinClassInstance(cx, clasp); 1926 } 1927 1928 JS_PUBLIC_API JSObject* JS_NewObjectWithGivenProto(JSContext* cx, 1929 const JSClass* clasp, 1930 HandleObject proto) { 1931 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 1932 AssertHeapIsIdle(); 1933 CHECK_THREAD(cx); 1934 cx->check(proto); 1935 1936 if (!clasp) { 1937 // Default class is Object. 1938 return NewPlainObjectWithProto(cx, proto); 1939 } 1940 1941 MOZ_ASSERT(!clasp->isJSFunction()); 1942 MOZ_ASSERT(clasp != &PlainObject::class_); 1943 MOZ_ASSERT(clasp != &ArrayObject::class_); 1944 MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL)); 1945 1946 return NewObjectWithGivenProto(cx, clasp, proto); 1947 } 1948 1949 JS_PUBLIC_API JSObject* JS_NewObjectWithGivenProtoAndUseAllocSite( 1950 JSContext* cx, const JSClass* clasp, HandleObject proto) { 1951 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 1952 AssertHeapIsIdle(); 1953 CHECK_THREAD(cx); 1954 cx->check(proto); 1955 1956 MOZ_ASSERT(clasp); 1957 MOZ_ASSERT(!clasp->isJSFunction()); 1958 MOZ_ASSERT(clasp != &PlainObject::class_); 1959 MOZ_ASSERT(clasp != &ArrayObject::class_); 1960 MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL)); 1961 1962 return NewObjectWithGivenProtoAndAllocSite(cx, clasp, proto, 1963 cx->realm()->localAllocSite); 1964 } 1965 1966 JS_PUBLIC_API JSObject* JS_NewPlainObject(JSContext* cx) { 1967 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 1968 AssertHeapIsIdle(); 1969 CHECK_THREAD(cx); 1970 1971 return NewPlainObject(cx); 1972 } 1973 1974 JS_PUBLIC_API JSObject* JS_NewObjectForConstructor(JSContext* cx, 1975 const JSClass* clasp, 1976 const CallArgs& args) { 1977 AssertHeapIsIdle(); 1978 CHECK_THREAD(cx); 1979 1980 MOZ_ASSERT(!clasp->isJSFunction()); 1981 MOZ_ASSERT(clasp != &PlainObject::class_); 1982 MOZ_ASSERT(clasp != &ArrayObject::class_); 1983 MOZ_ASSERT(!(clasp->flags & JSCLASS_IS_GLOBAL)); 1984 1985 if (!ThrowIfNotConstructing(cx, args, clasp->name)) { 1986 return nullptr; 1987 } 1988 1989 RootedObject newTarget(cx, &args.newTarget().toObject()); 1990 cx->check(newTarget); 1991 1992 RootedObject proto(cx); 1993 if (!GetPrototypeFromConstructor(cx, newTarget, 1994 JSCLASS_CACHED_PROTO_KEY(clasp), &proto)) { 1995 return nullptr; 1996 } 1997 1998 return NewObjectWithClassProto(cx, clasp, proto); 1999 } 2000 2001 JS_PUBLIC_API bool JS_IsNative(JSObject* obj) { 2002 return obj->is<NativeObject>(); 2003 } 2004 2005 JS_PUBLIC_API void JS::AssertObjectBelongsToCurrentThread(JSObject* obj) { 2006 JSRuntime* rt = obj->compartment()->runtimeFromAnyThread(); 2007 MOZ_RELEASE_ASSERT(CurrentThreadCanAccessRuntime(rt)); 2008 } 2009 2010 JS_PUBLIC_API void JS::SetFilenameValidationCallback( 2011 JS::FilenameValidationCallback cb) { 2012 js::gFilenameValidationCallback = cb; 2013 } 2014 2015 JS_PUBLIC_API void JS::SetHostEnsureCanAddPrivateElementHook( 2016 JSContext* cx, JS::EnsureCanAddPrivateElementOp op) { 2017 cx->runtime()->canAddPrivateElement = op; 2018 } 2019 2020 JS_PUBLIC_API bool JS::SetBrittleMode(JSContext* cx, bool setting) { 2021 bool wasBrittle = cx->brittleMode; 2022 cx->brittleMode = setting; 2023 return wasBrittle; 2024 } 2025 2026 /*** Standard internal methods **********************************************/ 2027 2028 JS_PUBLIC_API bool JS_GetPrototype(JSContext* cx, HandleObject obj, 2029 MutableHandleObject result) { 2030 cx->check(obj); 2031 return GetPrototype(cx, obj, result); 2032 } 2033 2034 JS_PUBLIC_API bool JS_SetPrototype(JSContext* cx, HandleObject obj, 2035 HandleObject proto) { 2036 AssertHeapIsIdle(); 2037 CHECK_THREAD(cx); 2038 cx->check(obj, proto); 2039 2040 return SetPrototype(cx, obj, proto); 2041 } 2042 2043 JS_PUBLIC_API bool JS_GetPrototypeIfOrdinary(JSContext* cx, HandleObject obj, 2044 bool* isOrdinary, 2045 MutableHandleObject result) { 2046 cx->check(obj); 2047 return GetPrototypeIfOrdinary(cx, obj, isOrdinary, result); 2048 } 2049 2050 JS_PUBLIC_API bool JS_IsExtensible(JSContext* cx, HandleObject obj, 2051 bool* extensible) { 2052 cx->check(obj); 2053 return IsExtensible(cx, obj, extensible); 2054 } 2055 2056 JS_PUBLIC_API bool JS_PreventExtensions(JSContext* cx, JS::HandleObject obj, 2057 ObjectOpResult& result) { 2058 cx->check(obj); 2059 return PreventExtensions(cx, obj, result); 2060 } 2061 2062 JS_PUBLIC_API bool JS_SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, 2063 bool* succeeded) { 2064 cx->check(obj); 2065 return SetImmutablePrototype(cx, obj, succeeded); 2066 } 2067 2068 /* * */ 2069 2070 JS_PUBLIC_API bool JS_FreezeObject(JSContext* cx, HandleObject obj) { 2071 AssertHeapIsIdle(); 2072 CHECK_THREAD(cx); 2073 cx->check(obj); 2074 return FreezeObject(cx, obj); 2075 } 2076 2077 static bool DeepFreezeSlot(JSContext* cx, const Value& v) { 2078 if (v.isPrimitive()) { 2079 return true; 2080 } 2081 RootedObject obj(cx, &v.toObject()); 2082 return JS_DeepFreezeObject(cx, obj); 2083 } 2084 2085 JS_PUBLIC_API bool JS_DeepFreezeObject(JSContext* cx, HandleObject obj) { 2086 AssertHeapIsIdle(); 2087 CHECK_THREAD(cx); 2088 cx->check(obj); 2089 2090 // Assume that non-extensible objects are already deep-frozen, to avoid 2091 // divergence. 2092 bool extensible; 2093 if (!IsExtensible(cx, obj, &extensible)) { 2094 return false; 2095 } 2096 if (!extensible) { 2097 return true; 2098 } 2099 2100 if (!FreezeObject(cx, obj)) { 2101 return false; 2102 } 2103 2104 // Walk slots in obj and if any value is a non-null object, seal it. 2105 if (obj->is<NativeObject>()) { 2106 Rooted<NativeObject*> nobj(cx, &obj->as<NativeObject>()); 2107 for (uint32_t i = 0, n = nobj->slotSpan(); i < n; ++i) { 2108 if (!DeepFreezeSlot(cx, nobj->getSlot(i))) { 2109 return false; 2110 } 2111 } 2112 for (uint32_t i = 0, n = nobj->getDenseInitializedLength(); i < n; ++i) { 2113 if (!DeepFreezeSlot(cx, nobj->getDenseElement(i))) { 2114 return false; 2115 } 2116 } 2117 } 2118 2119 return true; 2120 } 2121 2122 JS_PUBLIC_API bool JSPropertySpec::getValue(JSContext* cx, 2123 MutableHandleValue vp) const { 2124 MOZ_ASSERT(!isAccessor()); 2125 2126 switch (u.value.type) { 2127 case ValueWrapper::Type::String: { 2128 JSAtom* atom = Atomize(cx, u.value.string, strlen(u.value.string)); 2129 if (!atom) { 2130 return false; 2131 } 2132 vp.setString(atom); 2133 return true; 2134 } 2135 2136 case ValueWrapper::Type::Int32: 2137 vp.setInt32(u.value.int32); 2138 return true; 2139 2140 case ValueWrapper::Type::Double: 2141 vp.setDouble(u.value.double_); 2142 return true; 2143 } 2144 2145 MOZ_CRASH("Unexpected type"); 2146 } 2147 2148 bool PropertySpecNameToId(JSContext* cx, JSPropertySpec::Name name, 2149 MutableHandleId id) { 2150 if (name.isSymbol()) { 2151 id.set(PropertyKey::Symbol(cx->wellKnownSymbols().get(name.symbol()))); 2152 } else { 2153 JSAtom* atom = Atomize(cx, name.string(), strlen(name.string())); 2154 if (!atom) { 2155 return false; 2156 } 2157 id.set(AtomToId(atom)); 2158 } 2159 return true; 2160 } 2161 2162 JS_PUBLIC_API bool JS::PropertySpecNameToPermanentId(JSContext* cx, 2163 JSPropertySpec::Name name, 2164 jsid* idp) { 2165 // We are calling fromMarkedLocation(idp) even though idp points to a 2166 // location that will never be marked. This is OK because the whole point 2167 // of this API is to populate *idp with a jsid that does not need to be 2168 // marked. 2169 MutableHandleId id = MutableHandleId::fromMarkedLocation(idp); 2170 if (!PropertySpecNameToId(cx, name, id)) { 2171 return false; 2172 } 2173 2174 if (id.isString() && !PinAtom(cx, &id.toString()->asAtom())) { 2175 return false; 2176 } 2177 2178 return true; 2179 } 2180 2181 JS_PUBLIC_API bool JS::ToCompletePropertyDescriptor( 2182 JSContext* cx, HandleValue descriptor, 2183 MutableHandle<PropertyDescriptor> desc) { 2184 AssertHeapIsIdle(); 2185 CHECK_THREAD(cx); 2186 cx->check(descriptor); 2187 if (!ToPropertyDescriptor(cx, descriptor, /* checkAccessors */ true, desc)) { 2188 return false; 2189 } 2190 CompletePropertyDescriptor(desc); 2191 return true; 2192 } 2193 2194 JS_PUBLIC_API void JS_SetAllNonReservedSlotsToUndefined(JS::HandleObject obj) { 2195 if (!obj->is<NativeObject>()) { 2196 return; 2197 } 2198 2199 NativeObject& nobj = obj->as<NativeObject>(); 2200 2201 // XPConnect calls this for global objects and global lexical environments 2202 // that won't be used anymore. These objects can have an associated ObjectFuse 2203 // but we can ignore them here because the objects are effectively dead (after 2204 // clearing all slots below it'd be hard to execute JS code without breaking 2205 // JS semantics). 2206 MOZ_RELEASE_ASSERT(nobj.is<GlobalObject>() || 2207 nobj.is<GlobalLexicalEnvironmentObject>() || 2208 !Watchtower::watchesPropertyValueChange(&nobj)); 2209 2210 const JSClass* clasp = obj->getClass(); 2211 unsigned numReserved = JSCLASS_RESERVED_SLOTS(clasp); 2212 unsigned numSlots = nobj.slotSpan(); 2213 for (unsigned i = numReserved; i < numSlots; i++) { 2214 obj->as<NativeObject>().setSlot(i, UndefinedValue()); 2215 } 2216 } 2217 2218 JS_PUBLIC_API void JS_SetReservedSlot(JSObject* obj, uint32_t index, 2219 const Value& value) { 2220 // Note: we don't use setReservedSlot so that this also works on swappable DOM 2221 // objects. See NativeObject::getReservedSlotRef comment. 2222 NativeObject& nobj = obj->as<NativeObject>(); 2223 MOZ_ASSERT(index < JSCLASS_RESERVED_SLOTS(obj->getClass())); 2224 nobj.setSlot(index, value); 2225 } 2226 2227 JS_PUBLIC_API void JS_InitReservedSlot(JSObject* obj, uint32_t index, void* ptr, 2228 size_t nbytes, JS::MemoryUse use) { 2229 // Note: we don't use InitReservedSlot so that this also works on swappable 2230 // DOM objects. See NativeObject::getReservedSlotRef comment. 2231 MOZ_ASSERT(index < JSCLASS_RESERVED_SLOTS(obj->getClass())); 2232 AddCellMemory(obj, nbytes, js::MemoryUse(use)); 2233 obj->as<NativeObject>().initSlot(index, PrivateValue(ptr)); 2234 } 2235 2236 JS_PUBLIC_API bool JS::IsMapObject(JSContext* cx, JS::HandleObject obj, 2237 bool* isMap) { 2238 return IsGivenTypeObject(cx, obj, ESClass::Map, isMap); 2239 } 2240 2241 JS_PUBLIC_API bool JS::IsSetObject(JSContext* cx, JS::HandleObject obj, 2242 bool* isSet) { 2243 return IsGivenTypeObject(cx, obj, ESClass::Set, isSet); 2244 } 2245 2246 JS_PUBLIC_API void JS_HoldPrincipals(JSPrincipals* principals) { 2247 ++principals->refcount; 2248 } 2249 2250 JS_PUBLIC_API void JS_DropPrincipals(JSContext* cx, JSPrincipals* principals) { 2251 int rc = --principals->refcount; 2252 if (rc == 0) { 2253 JS::AutoSuppressGCAnalysis nogc; 2254 cx->runtime()->destroyPrincipals(principals); 2255 } 2256 } 2257 2258 JS_PUBLIC_API void JS_SetSecurityCallbacks(JSContext* cx, 2259 const JSSecurityCallbacks* scb) { 2260 MOZ_ASSERT(scb != &NullSecurityCallbacks); 2261 cx->runtime()->securityCallbacks = scb ? scb : &NullSecurityCallbacks; 2262 } 2263 2264 JS_PUBLIC_API const JSSecurityCallbacks* JS_GetSecurityCallbacks( 2265 JSContext* cx) { 2266 return (cx->runtime()->securityCallbacks != &NullSecurityCallbacks) 2267 ? cx->runtime()->securityCallbacks.ref() 2268 : nullptr; 2269 } 2270 2271 JS_PUBLIC_API void JS_SetTrustedPrincipals(JSContext* cx, JSPrincipals* prin) { 2272 cx->runtime()->setTrustedPrincipals(prin); 2273 } 2274 2275 extern JS_PUBLIC_API void JS_InitDestroyPrincipalsCallback( 2276 JSContext* cx, JSDestroyPrincipalsOp destroyPrincipals) { 2277 MOZ_ASSERT(destroyPrincipals); 2278 MOZ_ASSERT(!cx->runtime()->destroyPrincipals); 2279 cx->runtime()->destroyPrincipals = destroyPrincipals; 2280 } 2281 2282 extern JS_PUBLIC_API void JS_InitReadPrincipalsCallback( 2283 JSContext* cx, JSReadPrincipalsOp read) { 2284 MOZ_ASSERT(read); 2285 MOZ_ASSERT(!cx->runtime()->readPrincipals); 2286 cx->runtime()->readPrincipals = read; 2287 } 2288 2289 JS_PUBLIC_API JSFunction* JS_NewFunction(JSContext* cx, JSNative native, 2290 unsigned nargs, unsigned flags, 2291 const char* name) { 2292 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 2293 2294 AssertHeapIsIdle(); 2295 CHECK_THREAD(cx); 2296 2297 Rooted<JSAtom*> atom(cx); 2298 if (name) { 2299 atom = Atomize(cx, name, strlen(name)); 2300 if (!atom) { 2301 return nullptr; 2302 } 2303 } 2304 2305 return (flags & JSFUN_CONSTRUCTOR) 2306 ? NewNativeConstructor(cx, native, nargs, atom) 2307 : NewNativeFunction(cx, native, nargs, atom); 2308 } 2309 2310 JS_PUBLIC_API JSFunction* JS::GetSelfHostedFunction(JSContext* cx, 2311 const char* selfHostedName, 2312 HandleId id, 2313 unsigned nargs) { 2314 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 2315 AssertHeapIsIdle(); 2316 CHECK_THREAD(cx); 2317 cx->check(id); 2318 2319 Rooted<JSAtom*> name(cx, IdToFunctionName(cx, id)); 2320 if (!name) { 2321 return nullptr; 2322 } 2323 2324 JSAtom* shAtom = Atomize(cx, selfHostedName, strlen(selfHostedName)); 2325 if (!shAtom) { 2326 return nullptr; 2327 } 2328 Rooted<PropertyName*> shName(cx, shAtom->asPropertyName()); 2329 RootedValue funVal(cx); 2330 if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name, 2331 nargs, &funVal)) { 2332 return nullptr; 2333 } 2334 return &funVal.toObject().as<JSFunction>(); 2335 } 2336 2337 JS_PUBLIC_API JSFunction* JS::NewFunctionFromSpec(JSContext* cx, 2338 const JSFunctionSpec* fs, 2339 HandleId id) { 2340 cx->check(id); 2341 2342 #ifdef DEBUG 2343 if (fs->name.isSymbol()) { 2344 JS::Symbol* sym = cx->wellKnownSymbols().get(fs->name.symbol()); 2345 MOZ_ASSERT(PropertyKey::Symbol(sym) == id); 2346 } else { 2347 MOZ_ASSERT(id.isString() && 2348 StringEqualsAscii(id.toLinearString(), fs->name.string())); 2349 } 2350 #endif 2351 2352 // Delay cloning self-hosted functions until they are called. This is 2353 // achieved by passing DefineFunction a nullptr JSNative which produces an 2354 // interpreted JSFunction where !hasScript. Interpreted call paths then 2355 // call InitializeLazyFunctionScript if !hasScript. 2356 if (fs->selfHostedName) { 2357 MOZ_ASSERT(!fs->call.op); 2358 MOZ_ASSERT(!fs->call.info); 2359 2360 JSAtom* shAtom = 2361 Atomize(cx, fs->selfHostedName, strlen(fs->selfHostedName)); 2362 if (!shAtom) { 2363 return nullptr; 2364 } 2365 Rooted<PropertyName*> shName(cx, shAtom->asPropertyName()); 2366 Rooted<JSAtom*> name(cx, IdToFunctionName(cx, id)); 2367 if (!name) { 2368 return nullptr; 2369 } 2370 RootedValue funVal(cx); 2371 if (!GlobalObject::getSelfHostedFunction(cx, cx->global(), shName, name, 2372 fs->nargs, &funVal)) { 2373 return nullptr; 2374 } 2375 return &funVal.toObject().as<JSFunction>(); 2376 } 2377 2378 Rooted<JSAtom*> atom(cx, IdToFunctionName(cx, id)); 2379 if (!atom) { 2380 return nullptr; 2381 } 2382 2383 MOZ_ASSERT(fs->call.op); 2384 2385 JSFunction* fun; 2386 if (fs->flags & JSFUN_CONSTRUCTOR) { 2387 fun = NewNativeConstructor(cx, fs->call.op, fs->nargs, atom); 2388 } else { 2389 fun = NewNativeFunction(cx, fs->call.op, fs->nargs, atom); 2390 } 2391 if (!fun) { 2392 return nullptr; 2393 } 2394 2395 if (auto* jitInfo = fs->call.info) { 2396 if (jitInfo->type() == JSJitInfo::OpType::TrampolineNative) { 2397 jit::SetTrampolineNativeJitEntry(cx, fun, jitInfo->trampolineNative); 2398 } else { 2399 fun->setJitInfo(jitInfo); 2400 } 2401 } 2402 return fun; 2403 } 2404 2405 JS_PUBLIC_API JSFunction* JS::NewFunctionFromSpec(JSContext* cx, 2406 const JSFunctionSpec* fs) { 2407 RootedId id(cx); 2408 if (!PropertySpecNameToId(cx, fs->name, &id)) { 2409 return nullptr; 2410 } 2411 2412 return NewFunctionFromSpec(cx, fs, id); 2413 } 2414 2415 JS_PUBLIC_API JSObject* JS_GetFunctionObject(JSFunction* fun) { return fun; } 2416 2417 JS_PUBLIC_API bool JS_GetFunctionId(JSContext* cx, JS::Handle<JSFunction*> fun, 2418 JS::MutableHandle<JSString*> name) { 2419 JS::Rooted<JSAtom*> atom(cx); 2420 if (!fun->getExplicitName(cx, &atom)) { 2421 return false; 2422 } 2423 name.set(atom); 2424 return true; 2425 } 2426 2427 JS_PUBLIC_API JSString* JS_GetMaybePartialFunctionId(JSFunction* fun) { 2428 return fun->maybePartialExplicitName(); 2429 } 2430 2431 JS_PUBLIC_API bool JS_GetFunctionDisplayId(JSContext* cx, 2432 JS::Handle<JSFunction*> fun, 2433 JS::MutableHandle<JSString*> name) { 2434 JS::Rooted<JSAtom*> atom(cx); 2435 if (!fun->getDisplayAtom(cx, &atom)) { 2436 return false; 2437 } 2438 name.set(atom); 2439 return true; 2440 } 2441 2442 JS_PUBLIC_API JSString* JS_GetMaybePartialFunctionDisplayId(JSFunction* fun) { 2443 return fun->maybePartialDisplayAtom(); 2444 } 2445 2446 JS_PUBLIC_API uint16_t JS_GetFunctionArity(JSFunction* fun) { 2447 return fun->nargs(); 2448 } 2449 2450 JS_PUBLIC_API bool JS_GetFunctionLength(JSContext* cx, HandleFunction fun, 2451 uint16_t* length) { 2452 cx->check(fun); 2453 return JSFunction::getLength(cx, fun, length); 2454 } 2455 2456 JS_PUBLIC_API bool JS_ObjectIsFunction(JSObject* obj) { 2457 return obj->is<JSFunction>(); 2458 } 2459 2460 JS_PUBLIC_API bool JS_IsNativeFunction(JSObject* funobj, JSNative call) { 2461 if (!funobj->is<JSFunction>()) { 2462 return false; 2463 } 2464 JSFunction* fun = &funobj->as<JSFunction>(); 2465 return fun->isNativeFun() && fun->native() == call; 2466 } 2467 2468 extern JS_PUBLIC_API bool JS_IsConstructor(JSFunction* fun) { 2469 return fun->isConstructor(); 2470 } 2471 2472 void JS::CompileOptions::warnAboutConflictingDelazification() const { 2473 Fprinter out(stderr); 2474 out.printf( 2475 "WARNING: Parsing Everything Eagerly is already set " 2476 "and it cannot be disabled by other parsing strategy.\n" 2477 "The provided strategy is going to be ignored.\n\n" 2478 "Parse Everything Eagerly might be used by Code Coverage " 2479 "to ensure that all functions are known when the report is " 2480 "generated.\n"); 2481 } 2482 2483 void JS::TransitiveCompileOptions::copyPODTransitiveOptions( 2484 const TransitiveCompileOptions& rhs) { 2485 // filename_, introducerFilename_, sourceMapURL_ should be handled in caller. 2486 2487 mutedErrors_ = rhs.mutedErrors_; 2488 forceStrictMode_ = rhs.forceStrictMode_; 2489 alwaysUseFdlibm_ = rhs.alwaysUseFdlibm_; 2490 skipFilenameValidation_ = rhs.skipFilenameValidation_; 2491 hideScriptFromDebugger_ = rhs.hideScriptFromDebugger_; 2492 deferDebugMetadata_ = rhs.deferDebugMetadata_; 2493 eagerDelazificationStrategy_ = rhs.eagerDelazificationStrategy_; 2494 2495 selfHostingMode = rhs.selfHostingMode; 2496 discardSource = rhs.discardSource; 2497 sourceIsLazy = rhs.sourceIsLazy; 2498 allowHTMLComments = rhs.allowHTMLComments; 2499 nonSyntacticScope = rhs.nonSyntacticScope; 2500 2501 topLevelAwait = rhs.topLevelAwait; 2502 2503 borrowBuffer = rhs.borrowBuffer; 2504 usePinnedBytecode = rhs.usePinnedBytecode; 2505 2506 prefableOptions_ = rhs.prefableOptions_; 2507 2508 introductionType = rhs.introductionType; 2509 introductionLineno = rhs.introductionLineno; 2510 introductionOffset = rhs.introductionOffset; 2511 hasIntroductionInfo = rhs.hasIntroductionInfo; 2512 }; 2513 2514 void JS::ReadOnlyCompileOptions::copyPODNonTransitiveOptions( 2515 const ReadOnlyCompileOptions& rhs) { 2516 lineno = rhs.lineno; 2517 column = rhs.column; 2518 scriptSourceOffset = rhs.scriptSourceOffset; 2519 isRunOnce = rhs.isRunOnce; 2520 noScriptRval = rhs.noScriptRval; 2521 } 2522 2523 JS::OwningCompileOptions::OwningCompileOptions(JSContext* cx) {} 2524 2525 void JS::OwningCompileOptions::release() { 2526 // OwningCompileOptions always owns these, so these casts are okay. 2527 js_free(const_cast<char*>(filename_.c_str())); 2528 js_free(const_cast<char16_t*>(sourceMapURL_)); 2529 js_free(const_cast<char*>(introducerFilename_.c_str())); 2530 2531 filename_ = JS::ConstUTF8CharsZ(); 2532 sourceMapURL_ = nullptr; 2533 introducerFilename_ = JS::ConstUTF8CharsZ(); 2534 } 2535 2536 JS::OwningCompileOptions::~OwningCompileOptions() { release(); } 2537 2538 size_t JS::OwningCompileOptions::sizeOfExcludingThis( 2539 mozilla::MallocSizeOf mallocSizeOf) const { 2540 return mallocSizeOf(filename_.c_str()) + mallocSizeOf(sourceMapURL_) + 2541 mallocSizeOf(introducerFilename_.c_str()); 2542 } 2543 2544 void JS::OwningCompileOptions::steal(JS::OwningCompileOptions&& rhs) { 2545 // Release existing string allocations. 2546 release(); 2547 2548 copyPODNonTransitiveOptions(rhs); 2549 copyPODTransitiveOptions(rhs); 2550 2551 filename_ = rhs.filename_; 2552 rhs.filename_ = JS::ConstUTF8CharsZ(); 2553 introducerFilename_ = rhs.introducerFilename_; 2554 rhs.introducerFilename_ = JS::ConstUTF8CharsZ(); 2555 sourceMapURL_ = rhs.sourceMapURL_; 2556 rhs.sourceMapURL_ = nullptr; 2557 } 2558 2559 void JS::OwningCompileOptions::steal(JS::OwningDecodeOptions&& rhs) { 2560 // Release existing string allocations. 2561 release(); 2562 2563 rhs.copyPODOptionsTo(*this); 2564 2565 introducerFilename_ = rhs.introducerFilename_; 2566 rhs.introducerFilename_ = JS::ConstUTF8CharsZ(); 2567 } 2568 2569 template <typename ContextT> 2570 bool JS::OwningCompileOptions::copyImpl(ContextT* cx, 2571 const ReadOnlyCompileOptions& rhs) { 2572 // Release existing string allocations. 2573 release(); 2574 2575 copyPODNonTransitiveOptions(rhs); 2576 copyPODTransitiveOptions(rhs); 2577 2578 if (rhs.filename()) { 2579 const char* str = DuplicateString(cx, rhs.filename().c_str()).release(); 2580 if (!str) { 2581 return false; 2582 } 2583 filename_ = JS::ConstUTF8CharsZ(str); 2584 } 2585 2586 if (rhs.sourceMapURL()) { 2587 sourceMapURL_ = DuplicateString(cx, rhs.sourceMapURL()).release(); 2588 if (!sourceMapURL_) { 2589 return false; 2590 } 2591 } 2592 2593 if (rhs.introducerFilename()) { 2594 const char* str = 2595 DuplicateString(cx, rhs.introducerFilename().c_str()).release(); 2596 if (!str) { 2597 return false; 2598 } 2599 introducerFilename_ = JS::ConstUTF8CharsZ(str); 2600 } 2601 2602 return true; 2603 } 2604 2605 bool JS::OwningCompileOptions::copy(JSContext* cx, 2606 const ReadOnlyCompileOptions& rhs) { 2607 return copyImpl(cx, rhs); 2608 } 2609 2610 bool JS::OwningCompileOptions::copy(JS::FrontendContext* fc, 2611 const ReadOnlyCompileOptions& rhs) { 2612 return copyImpl(fc, rhs); 2613 } 2614 2615 JS::CompileOptions::CompileOptions(JSContext* cx) { 2616 prefableOptions_ = cx->options().compileOptions(); 2617 2618 if (cx->options().asmJSOption() == AsmJSOption::Enabled) { 2619 if (!js::IsAsmJSCompilationAvailable(cx)) { 2620 prefableOptions_.setAsmJSOption(AsmJSOption::DisabledByNoWasmCompiler); 2621 } else if (cx->realm() && (cx->realm()->debuggerObservesWasm() || 2622 cx->realm()->debuggerObservesAsmJS())) { 2623 prefableOptions_.setAsmJSOption(AsmJSOption::DisabledByDebugger); 2624 } 2625 } 2626 2627 // Certain modes of operation disallow syntax parsing in general. 2628 if (coverage::IsLCovEnabled()) { 2629 eagerDelazificationStrategy_ = DelazificationOption::ParseEverythingEagerly; 2630 } 2631 2632 // Note: If we parse outside of a specific realm, we do not inherit any realm 2633 // behaviours. These can still be set manually on the options though. 2634 if (Realm* realm = cx->realm()) { 2635 alwaysUseFdlibm_ = realm->creationOptions().alwaysUseFdlibm(); 2636 discardSource = realm->behaviors().discardSource(); 2637 } 2638 2639 if (cx->options().disableFilenameSecurityChecks()) { 2640 skipFilenameValidation_ = true; 2641 } 2642 } 2643 2644 JS::InstantiateOptions::InstantiateOptions() { 2645 if (coverage::IsLCovEnabled()) { 2646 eagerDelazificationStrategy_ = DelazificationOption::ParseEverythingEagerly; 2647 } 2648 } 2649 2650 CompileOptions& CompileOptions::setIntroductionInfoToCaller( 2651 JSContext* cx, const char* introductionType, 2652 MutableHandle<JSScript*> introductionScript) { 2653 RootedScript maybeScript(cx); 2654 const char* filename; 2655 uint32_t lineno; 2656 uint32_t pcOffset; 2657 bool mutedErrors; 2658 DescribeScriptedCallerForCompilation(cx, &maybeScript, &filename, &lineno, 2659 &pcOffset, &mutedErrors); 2660 if (filename) { 2661 introductionScript.set(maybeScript); 2662 return setIntroductionInfo(filename, introductionType, lineno, pcOffset); 2663 } 2664 return setIntroductionType(introductionType); 2665 } 2666 2667 JS::OwningDecodeOptions::~OwningDecodeOptions() { release(); } 2668 2669 void JS::OwningDecodeOptions::release() { 2670 js_free(const_cast<char*>(introducerFilename_.c_str())); 2671 2672 introducerFilename_ = JS::ConstUTF8CharsZ(); 2673 } 2674 2675 bool JS::OwningDecodeOptions::copy(JS::FrontendContext* maybeFc, 2676 const JS::ReadOnlyDecodeOptions& rhs) { 2677 copyPODOptionsFrom(rhs); 2678 2679 if (rhs.introducerFilename()) { 2680 MOZ_ASSERT(maybeFc); 2681 const char* str = 2682 DuplicateString(maybeFc, rhs.introducerFilename().c_str()).release(); 2683 if (!str) { 2684 return false; 2685 } 2686 introducerFilename_ = JS::ConstUTF8CharsZ(str); 2687 } 2688 2689 return true; 2690 } 2691 2692 void JS::OwningDecodeOptions::infallibleCopy( 2693 const JS::ReadOnlyDecodeOptions& rhs) { 2694 copyPODOptionsFrom(rhs); 2695 2696 MOZ_ASSERT(!rhs.introducerFilename()); 2697 } 2698 2699 size_t JS::OwningDecodeOptions::sizeOfExcludingThis( 2700 mozilla::MallocSizeOf mallocSizeOf) const { 2701 return mallocSizeOf(introducerFilename_.c_str()); 2702 } 2703 2704 JS_PUBLIC_API JSObject* JS_GetGlobalFromScript(JSScript* script) { 2705 return &script->global(); 2706 } 2707 2708 JS_PUBLIC_API const char* JS_GetScriptFilename(JSScript* script) { 2709 // This is called from ThreadStackHelper which can be called from another 2710 // thread or inside a signal hander, so we need to be careful in case a 2711 // copmacting GC is currently moving things around. 2712 return script->maybeForwardedFilename(); 2713 } 2714 2715 JS_PUBLIC_API unsigned JS_GetScriptBaseLineNumber(JSContext* cx, 2716 JSScript* script) { 2717 return script->lineno(); 2718 } 2719 2720 JS_PUBLIC_API JSScript* JS_GetFunctionScript(JSContext* cx, 2721 HandleFunction fun) { 2722 if (fun->isNativeFun()) { 2723 return nullptr; 2724 } 2725 2726 if (fun->hasBytecode()) { 2727 return fun->nonLazyScript(); 2728 } 2729 2730 AutoRealm ar(cx, fun); 2731 JSScript* script = JSFunction::getOrCreateScript(cx, fun); 2732 if (!script) { 2733 MOZ_CRASH(); 2734 } 2735 return script; 2736 } 2737 2738 JS_PUBLIC_API JSString* JS_DecompileScript(JSContext* cx, HandleScript script) { 2739 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 2740 2741 AssertHeapIsIdle(); 2742 CHECK_THREAD(cx); 2743 RootedFunction fun(cx, script->function()); 2744 if (fun) { 2745 return JS_DecompileFunction(cx, fun); 2746 } 2747 bool haveSource; 2748 if (!ScriptSource::loadSource(cx, script->scriptSource(), &haveSource)) { 2749 return nullptr; 2750 } 2751 return haveSource ? JSScript::sourceData(cx, script) 2752 : NewStringCopyZ<CanGC>(cx, "[no source]"); 2753 } 2754 2755 JS_PUBLIC_API JSString* JS_DecompileFunction(JSContext* cx, 2756 HandleFunction fun) { 2757 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 2758 AssertHeapIsIdle(); 2759 CHECK_THREAD(cx); 2760 cx->check(fun); 2761 return FunctionToString(cx, fun, /* isToSource = */ false); 2762 } 2763 2764 JS_PUBLIC_API void JS::SetScriptPrivate(JSScript* script, 2765 const JS::Value& value) { 2766 JSRuntime* rt = script->zone()->runtimeFromMainThread(); 2767 script->sourceObject()->setPrivate(rt, value); 2768 } 2769 2770 JS_PUBLIC_API JS::Value JS::GetScriptPrivate(JSScript* script) { 2771 return script->sourceObject()->getPrivate(); 2772 } 2773 2774 JS_PUBLIC_API JS::Value JS::GetScriptedCallerPrivate(JSContext* cx) { 2775 AssertHeapIsIdle(); 2776 CHECK_THREAD(cx); 2777 2778 NonBuiltinFrameIter iter(cx, cx->realm()->principals()); 2779 if (iter.done() || !iter.hasScript()) { 2780 return UndefinedValue(); 2781 } 2782 2783 return iter.script()->sourceObject()->getPrivate(); 2784 } 2785 2786 JS_PUBLIC_API void JS::SetScriptPrivateReferenceHooks( 2787 JSRuntime* rt, JS::ScriptPrivateReferenceHook addRefHook, 2788 JS::ScriptPrivateReferenceHook releaseHook) { 2789 AssertHeapIsIdle(); 2790 rt->scriptPrivateAddRefHook = addRefHook; 2791 rt->scriptPrivateReleaseHook = releaseHook; 2792 } 2793 2794 JS_PUBLIC_API void JS::SetWaitCallback(JSRuntime* rt, 2795 BeforeWaitCallback beforeWait, 2796 AfterWaitCallback afterWait, 2797 size_t requiredMemory) { 2798 MOZ_RELEASE_ASSERT(requiredMemory <= WAIT_CALLBACK_CLIENT_MAXMEM); 2799 MOZ_RELEASE_ASSERT((beforeWait == nullptr) == (afterWait == nullptr)); 2800 rt->beforeWaitCallback = beforeWait; 2801 rt->afterWaitCallback = afterWait; 2802 } 2803 2804 JS_PUBLIC_API bool JS_CheckForInterrupt(JSContext* cx) { 2805 return js::CheckForInterrupt(cx); 2806 } 2807 2808 JS_PUBLIC_API bool JS_AddInterruptCallback(JSContext* cx, 2809 JSInterruptCallback callback) { 2810 return cx->interruptCallbacks().append(callback); 2811 } 2812 2813 JS_PUBLIC_API bool JS_DisableInterruptCallback(JSContext* cx) { 2814 bool result = cx->interruptCallbackDisabled; 2815 cx->interruptCallbackDisabled = true; 2816 return result; 2817 } 2818 2819 JS_PUBLIC_API void JS_ResetInterruptCallback(JSContext* cx, bool enable) { 2820 cx->interruptCallbackDisabled = enable; 2821 } 2822 2823 /************************************************************************/ 2824 2825 /* 2826 * Promises. 2827 */ 2828 JS_PUBLIC_API void JS::SetJobQueue(JSContext* cx, JobQueue* queue) { 2829 cx->jobQueue = queue; 2830 } 2831 2832 extern JS_PUBLIC_API void JS::SetPromiseRejectionTrackerCallback( 2833 JSContext* cx, PromiseRejectionTrackerCallback callback, 2834 void* data /* = nullptr */) { 2835 cx->promiseRejectionTrackerCallback = callback; 2836 cx->promiseRejectionTrackerCallbackData = data; 2837 } 2838 2839 extern JS_PUBLIC_API void JS::JobQueueIsEmpty(JSContext* cx) { 2840 cx->canSkipEnqueuingJobs = true; 2841 } 2842 2843 extern JS_PUBLIC_API void JS::JobQueueMayNotBeEmpty(JSContext* cx) { 2844 cx->canSkipEnqueuingJobs = false; 2845 } 2846 2847 JS_PUBLIC_API JSObject* JS::NewPromiseObject(JSContext* cx, 2848 HandleObject executor) { 2849 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 2850 AssertHeapIsIdle(); 2851 CHECK_THREAD(cx); 2852 cx->check(executor); 2853 2854 if (!executor) { 2855 return PromiseObject::createSkippingExecutor(cx); 2856 } 2857 2858 MOZ_ASSERT(IsCallable(executor)); 2859 return PromiseObject::create(cx, executor); 2860 } 2861 2862 JS_PUBLIC_API bool JS::IsPromiseObject(JS::HandleObject obj) { 2863 return obj->is<PromiseObject>(); 2864 } 2865 2866 JS_PUBLIC_API JSObject* JS::GetPromiseConstructor(JSContext* cx) { 2867 CHECK_THREAD(cx); 2868 Rooted<GlobalObject*> global(cx, cx->global()); 2869 return GlobalObject::getOrCreatePromiseConstructor(cx, global); 2870 } 2871 2872 JS_PUBLIC_API JSObject* JS::GetPromisePrototype(JSContext* cx) { 2873 CHECK_THREAD(cx); 2874 Rooted<GlobalObject*> global(cx, cx->global()); 2875 return GlobalObject::getOrCreatePromisePrototype(cx, global); 2876 } 2877 2878 JS_PUBLIC_API JS::PromiseState JS::GetPromiseState(JS::HandleObject promise) { 2879 PromiseObject* promiseObj = promise->maybeUnwrapIf<PromiseObject>(); 2880 if (!promiseObj) { 2881 return JS::PromiseState::Pending; 2882 } 2883 2884 return promiseObj->state(); 2885 } 2886 2887 JS_PUBLIC_API uint64_t JS::GetPromiseID(JS::HandleObject promise) { 2888 return promise->as<PromiseObject>().getID(); 2889 } 2890 2891 JS_PUBLIC_API JS::Value JS::GetPromiseResult(JS::HandleObject promiseObj) { 2892 PromiseObject* promise = &promiseObj->as<PromiseObject>(); 2893 MOZ_ASSERT(promise->state() != JS::PromiseState::Pending); 2894 return promise->state() == JS::PromiseState::Fulfilled ? promise->value() 2895 : promise->reason(); 2896 } 2897 2898 JS_PUBLIC_API bool JS::GetPromiseIsHandled(JS::HandleObject promise) { 2899 PromiseObject* promiseObj = &promise->as<PromiseObject>(); 2900 return !promiseObj->isUnhandled(); 2901 } 2902 2903 static PromiseObject* UnwrapPromise(JSContext* cx, JS::HandleObject promise, 2904 mozilla::Maybe<AutoRealm>& ar) { 2905 AssertHeapIsIdle(); 2906 CHECK_THREAD(cx); 2907 cx->check(promise); 2908 2909 PromiseObject* promiseObj; 2910 if (IsWrapper(promise)) { 2911 promiseObj = promise->maybeUnwrapAs<PromiseObject>(); 2912 if (!promiseObj) { 2913 ReportAccessDenied(cx); 2914 return nullptr; 2915 } 2916 ar.emplace(cx, promiseObj); 2917 } else { 2918 promiseObj = promise.as<PromiseObject>(); 2919 } 2920 return promiseObj; 2921 } 2922 2923 JS_PUBLIC_API bool JS::SetSettledPromiseIsHandled(JSContext* cx, 2924 JS::HandleObject promise) { 2925 mozilla::Maybe<AutoRealm> ar; 2926 Rooted<PromiseObject*> promiseObj(cx, UnwrapPromise(cx, promise, ar)); 2927 if (!promiseObj) { 2928 return false; 2929 } 2930 js::SetSettledPromiseIsHandled(cx, promiseObj); 2931 return true; 2932 } 2933 2934 JS_PUBLIC_API bool JS::SetAnyPromiseIsHandled(JSContext* cx, 2935 JS::HandleObject promise) { 2936 mozilla::Maybe<AutoRealm> ar; 2937 Rooted<PromiseObject*> promiseObj(cx, UnwrapPromise(cx, promise, ar)); 2938 if (!promiseObj) { 2939 return false; 2940 } 2941 js::SetAnyPromiseIsHandled(cx, promiseObj); 2942 return true; 2943 } 2944 2945 JS_PUBLIC_API JSObject* JS::GetPromiseAllocationSite(JS::HandleObject promise) { 2946 return promise->as<PromiseObject>().allocationSite(); 2947 } 2948 2949 JS_PUBLIC_API JSObject* JS::GetPromiseResolutionSite(JS::HandleObject promise) { 2950 return promise->as<PromiseObject>().resolutionSite(); 2951 } 2952 2953 #ifdef DEBUG 2954 JS_PUBLIC_API void JS::DumpPromiseAllocationSite(JSContext* cx, 2955 JS::HandleObject promise) { 2956 RootedObject stack(cx, promise->as<PromiseObject>().allocationSite()); 2957 JSPrincipals* principals = cx->realm()->principals(); 2958 UniqueChars stackStr = BuildUTF8StackString(cx, principals, stack); 2959 if (stackStr) { 2960 fputs(stackStr.get(), stderr); 2961 } 2962 } 2963 2964 JS_PUBLIC_API void JS::DumpPromiseResolutionSite(JSContext* cx, 2965 JS::HandleObject promise) { 2966 RootedObject stack(cx, promise->as<PromiseObject>().resolutionSite()); 2967 JSPrincipals* principals = cx->realm()->principals(); 2968 UniqueChars stackStr = BuildUTF8StackString(cx, principals, stack); 2969 if (stackStr) { 2970 fputs(stackStr.get(), stderr); 2971 } 2972 } 2973 #endif 2974 2975 JS_PUBLIC_API JSObject* JS::CallOriginalPromiseResolve( 2976 JSContext* cx, JS::HandleValue resolutionValue) { 2977 AssertHeapIsIdle(); 2978 CHECK_THREAD(cx); 2979 cx->check(resolutionValue); 2980 2981 RootedObject promise(cx, 2982 PromiseObject::unforgeableResolve(cx, resolutionValue)); 2983 MOZ_ASSERT_IF(promise, promise->canUnwrapAs<PromiseObject>()); 2984 return promise; 2985 } 2986 2987 JS_PUBLIC_API JSObject* JS::CallOriginalPromiseReject( 2988 JSContext* cx, JS::HandleValue rejectionValue) { 2989 AssertHeapIsIdle(); 2990 CHECK_THREAD(cx); 2991 cx->check(rejectionValue); 2992 2993 RootedObject promise(cx, 2994 PromiseObject::unforgeableReject(cx, rejectionValue)); 2995 MOZ_ASSERT_IF(promise, promise->canUnwrapAs<PromiseObject>()); 2996 return promise; 2997 } 2998 2999 static bool ResolveOrRejectPromise(JSContext* cx, JS::HandleObject promiseObj, 3000 JS::HandleValue resultOrReason_, 3001 bool reject) { 3002 AssertHeapIsIdle(); 3003 CHECK_THREAD(cx); 3004 cx->check(promiseObj, resultOrReason_); 3005 3006 mozilla::Maybe<AutoRealm> ar; 3007 Rooted<PromiseObject*> promise(cx); 3008 RootedValue resultOrReason(cx, resultOrReason_); 3009 if (IsWrapper(promiseObj)) { 3010 promise = promiseObj->maybeUnwrapAs<PromiseObject>(); 3011 if (!promise) { 3012 ReportAccessDenied(cx); 3013 return false; 3014 } 3015 ar.emplace(cx, promise); 3016 if (!cx->compartment()->wrap(cx, &resultOrReason)) { 3017 return false; 3018 } 3019 } else { 3020 promise = promiseObj.as<PromiseObject>(); 3021 } 3022 3023 return reject ? PromiseObject::reject(cx, promise, resultOrReason) 3024 : PromiseObject::resolve(cx, promise, resultOrReason); 3025 } 3026 3027 JS_PUBLIC_API bool JS::ResolvePromise(JSContext* cx, 3028 JS::HandleObject promiseObj, 3029 JS::HandleValue resolutionValue) { 3030 return ResolveOrRejectPromise(cx, promiseObj, resolutionValue, false); 3031 } 3032 3033 JS_PUBLIC_API bool JS::RejectPromise(JSContext* cx, JS::HandleObject promiseObj, 3034 JS::HandleValue rejectionValue) { 3035 return ResolveOrRejectPromise(cx, promiseObj, rejectionValue, true); 3036 } 3037 3038 JS_PUBLIC_API JSObject* JS::CallOriginalPromiseThen( 3039 JSContext* cx, JS::HandleObject promiseObj, JS::HandleObject onFulfilled, 3040 JS::HandleObject onRejected) { 3041 AssertHeapIsIdle(); 3042 CHECK_THREAD(cx); 3043 cx->check(promiseObj, onFulfilled, onRejected); 3044 3045 MOZ_ASSERT_IF(onFulfilled, IsCallable(onFulfilled)); 3046 MOZ_ASSERT_IF(onRejected, IsCallable(onRejected)); 3047 3048 return OriginalPromiseThen(cx, promiseObj, onFulfilled, onRejected); 3049 } 3050 3051 [[nodiscard]] static bool ReactToPromise(JSContext* cx, 3052 JS::Handle<JSObject*> promiseObj, 3053 JS::Handle<JSObject*> onFulfilled, 3054 JS::Handle<JSObject*> onRejected, 3055 UnhandledRejectionBehavior behavior) { 3056 AssertHeapIsIdle(); 3057 CHECK_THREAD(cx); 3058 cx->check(promiseObj, onFulfilled, onRejected); 3059 3060 MOZ_ASSERT_IF(onFulfilled, IsCallable(onFulfilled)); 3061 MOZ_ASSERT_IF(onRejected, IsCallable(onRejected)); 3062 3063 Rooted<PromiseObject*> unwrappedPromise(cx); 3064 { 3065 RootedValue promiseVal(cx, ObjectValue(*promiseObj)); 3066 unwrappedPromise = UnwrapAndTypeCheckValue<PromiseObject>( 3067 cx, promiseVal, [cx, promiseObj] { 3068 JS_ReportErrorNumberLatin1(cx, GetErrorMessage, nullptr, 3069 JSMSG_INCOMPATIBLE_PROTO, "Promise", 3070 "then", promiseObj->getClass()->name); 3071 }); 3072 if (!unwrappedPromise) { 3073 return false; 3074 } 3075 } 3076 3077 return ReactToUnwrappedPromise(cx, unwrappedPromise, onFulfilled, onRejected, 3078 behavior); 3079 } 3080 3081 JS_PUBLIC_API bool JS::AddPromiseReactions(JSContext* cx, 3082 JS::HandleObject promiseObj, 3083 JS::HandleObject onFulfilled, 3084 JS::HandleObject onRejected) { 3085 return ReactToPromise(cx, promiseObj, onFulfilled, onRejected, 3086 UnhandledRejectionBehavior::Report); 3087 } 3088 3089 JS_PUBLIC_API bool JS::AddPromiseReactionsIgnoringUnhandledRejection( 3090 JSContext* cx, JS::HandleObject promiseObj, JS::HandleObject onFulfilled, 3091 JS::HandleObject onRejected) { 3092 return ReactToPromise(cx, promiseObj, onFulfilled, onRejected, 3093 UnhandledRejectionBehavior::Ignore); 3094 } 3095 3096 JS_PUBLIC_API JS::PromiseUserInputEventHandlingState 3097 JS::GetPromiseUserInputEventHandlingState(JS::HandleObject promiseObj_) { 3098 PromiseObject* promise = promiseObj_->maybeUnwrapIf<PromiseObject>(); 3099 if (!promise) { 3100 return JS::PromiseUserInputEventHandlingState::DontCare; 3101 } 3102 3103 if (!promise->requiresUserInteractionHandling()) { 3104 return JS::PromiseUserInputEventHandlingState::DontCare; 3105 } 3106 if (promise->hadUserInteractionUponCreation()) { 3107 return JS::PromiseUserInputEventHandlingState::HadUserInteractionAtCreation; 3108 } 3109 return JS::PromiseUserInputEventHandlingState:: 3110 DidntHaveUserInteractionAtCreation; 3111 } 3112 3113 JS_PUBLIC_API bool JS::SetPromiseUserInputEventHandlingState( 3114 JS::HandleObject promiseObj_, 3115 JS::PromiseUserInputEventHandlingState state) { 3116 PromiseObject* promise = promiseObj_->maybeUnwrapIf<PromiseObject>(); 3117 if (!promise) { 3118 return false; 3119 } 3120 3121 switch (state) { 3122 case JS::PromiseUserInputEventHandlingState::DontCare: 3123 promise->setRequiresUserInteractionHandling(false); 3124 break; 3125 case JS::PromiseUserInputEventHandlingState::HadUserInteractionAtCreation: 3126 promise->setRequiresUserInteractionHandling(true); 3127 promise->setHadUserInteractionUponCreation(true); 3128 break; 3129 case JS::PromiseUserInputEventHandlingState:: 3130 DidntHaveUserInteractionAtCreation: 3131 promise->setRequiresUserInteractionHandling(true); 3132 promise->setHadUserInteractionUponCreation(false); 3133 break; 3134 default: 3135 MOZ_ASSERT_UNREACHABLE( 3136 "Invalid PromiseUserInputEventHandlingState enum value"); 3137 return false; 3138 } 3139 return true; 3140 } 3141 3142 /* static */ 3143 void JS::Dispatchable::Run(JSContext* cx, 3144 js::UniquePtr<JS::Dispatchable>&& task, 3145 MaybeShuttingDown maybeShuttingDown) { 3146 // Release the uniquePtr so that we don't have a double delete. 3147 JS::Dispatchable* rawTaskPtr = task.release(); 3148 // Execute run. This will result in the task being deleted. 3149 rawTaskPtr->run(cx, maybeShuttingDown); 3150 } 3151 3152 /* static */ 3153 void JS::Dispatchable::ReleaseFailedTask( 3154 js::UniquePtr<JS::Dispatchable>&& task) { 3155 // release the task from the uniquePtr so that it does not delete. 3156 JS::Dispatchable* rawTaskPtr = task.release(); 3157 // We've attempted to transfer to the embedding, but this has failed. 3158 // Transfer the task back to the runtime, as defined by the subclass of 3159 // JS::Dispatchable. The Runtime will delete the task once we are sure 3160 // we are once more executing on the main thread. 3161 rawTaskPtr->transferToRuntime(); 3162 } 3163 3164 /** 3165 * Unforgeable version of Promise.all for internal use. 3166 * 3167 * Takes a dense array of Promise objects and returns a promise that's 3168 * resolved with an array of resolution values when all those promises ahve 3169 * been resolved, or rejected with the rejection value of the first rejected 3170 * promise. 3171 * 3172 * Asserts that the array is dense and all entries are Promise objects. 3173 */ 3174 JS_PUBLIC_API JSObject* JS::GetWaitForAllPromise( 3175 JSContext* cx, JS::HandleObjectVector promises) { 3176 AssertHeapIsIdle(); 3177 CHECK_THREAD(cx); 3178 3179 return js::GetWaitForAllPromise(cx, promises); 3180 } 3181 3182 JS_PUBLIC_API void JS::InitAsyncTaskCallbacks( 3183 JSContext* cx, JS::DispatchToEventLoopCallback dispatchCallback, 3184 JS::DelayedDispatchToEventLoopCallback delayedDispatchCallback, 3185 JS::AsyncTaskStartedCallback asyncTaskStartedCallback, 3186 JS::AsyncTaskFinishedCallback asyncTaskFinishedCallback, void* closure) { 3187 cx->runtime()->offThreadPromiseState.ref().init( 3188 dispatchCallback, delayedDispatchCallback, asyncTaskStartedCallback, 3189 asyncTaskFinishedCallback, closure); 3190 } 3191 3192 JS_PUBLIC_API void JS::CancelAsyncTasks(JSContext* cx) { 3193 cx->runtime()->offThreadPromiseState.ref().cancelTasks(cx); 3194 } 3195 3196 JS_PUBLIC_API void JS::ShutdownAsyncTasks(JSContext* cx) { 3197 cx->runtime()->offThreadPromiseState.ref().shutdown(cx); 3198 } 3199 3200 JS_PUBLIC_API void JS::InitConsumeStreamCallback( 3201 JSContext* cx, ConsumeStreamCallback consume, 3202 ReportStreamErrorCallback report) { 3203 cx->runtime()->consumeStreamCallback = consume; 3204 cx->runtime()->reportStreamErrorCallback = report; 3205 } 3206 3207 JS_PUBLIC_API void JS_RequestInterruptCallback(JSContext* cx) { 3208 cx->requestInterrupt(InterruptReason::CallbackUrgent); 3209 } 3210 3211 JS_PUBLIC_API void JS_RequestInterruptCallbackCanWait(JSContext* cx) { 3212 cx->requestInterrupt(InterruptReason::CallbackCanWait); 3213 } 3214 3215 JS::AutoSetAsyncStackForNewCalls::AutoSetAsyncStackForNewCalls( 3216 JSContext* cx, JSObject* stack, const char* asyncCause, 3217 JS::AutoSetAsyncStackForNewCalls::AsyncCallKind kind) 3218 : cx(cx), 3219 oldAsyncStack(cx, cx->asyncStackForNewActivations()), 3220 oldAsyncCause(cx->asyncCauseForNewActivations), 3221 oldAsyncCallIsExplicit(cx->asyncCallIsExplicit) { 3222 CHECK_THREAD(cx); 3223 3224 // The option determines whether we actually use the new values at this 3225 // point. It will not affect restoring the previous values when the object 3226 // is destroyed, so if the option changes it won't cause consistency issues. 3227 if (!cx->options().asyncStack()) { 3228 return; 3229 } 3230 3231 SavedFrame* asyncStack = &stack->as<SavedFrame>(); 3232 3233 cx->asyncStackForNewActivations() = asyncStack; 3234 cx->asyncCauseForNewActivations = asyncCause; 3235 cx->asyncCallIsExplicit = kind == AsyncCallKind::EXPLICIT; 3236 } 3237 3238 JS::AutoSetAsyncStackForNewCalls::~AutoSetAsyncStackForNewCalls() { 3239 cx->asyncCauseForNewActivations = oldAsyncCause; 3240 cx->asyncStackForNewActivations() = 3241 oldAsyncStack ? &oldAsyncStack->as<SavedFrame>() : nullptr; 3242 cx->asyncCallIsExplicit = oldAsyncCallIsExplicit; 3243 } 3244 3245 /************************************************************************/ 3246 JS_PUBLIC_API JSString* JS_NewStringCopyN(JSContext* cx, const char* s, 3247 size_t n) { 3248 AssertHeapIsIdle(); 3249 CHECK_THREAD(cx); 3250 return NewStringCopyN<CanGC>(cx, s, n); 3251 } 3252 3253 JS_PUBLIC_API JSString* JS_NewStringCopyZ(JSContext* cx, const char* s) { 3254 AssertHeapIsIdle(); 3255 CHECK_THREAD(cx); 3256 if (!s) { 3257 return cx->runtime()->emptyString; 3258 } 3259 return NewStringCopyZ<CanGC>(cx, s); 3260 } 3261 3262 JS_PUBLIC_API JSString* JS_NewStringCopyUTF8Z(JSContext* cx, 3263 const JS::ConstUTF8CharsZ s) { 3264 AssertHeapIsIdle(); 3265 CHECK_THREAD(cx); 3266 return NewStringCopyUTF8Z(cx, s); 3267 } 3268 3269 JS_PUBLIC_API JSString* JS_NewStringCopyUTF8N(JSContext* cx, 3270 const JS::UTF8Chars& s) { 3271 AssertHeapIsIdle(); 3272 CHECK_THREAD(cx); 3273 return NewStringCopyUTF8N(cx, s); 3274 } 3275 3276 JS_PUBLIC_API bool JS_StringHasBeenPinned(JSContext* cx, JSString* str) { 3277 AssertHeapIsIdle(); 3278 CHECK_THREAD(cx); 3279 3280 if (!str->isAtom()) { 3281 return false; 3282 } 3283 3284 return AtomIsPinned(cx, &str->asAtom()); 3285 } 3286 3287 JS_PUBLIC_API JSString* JS_AtomizeString(JSContext* cx, const char* s) { 3288 return JS_AtomizeStringN(cx, s, strlen(s)); 3289 } 3290 3291 JS_PUBLIC_API JSString* JS_AtomizeStringN(JSContext* cx, const char* s, 3292 size_t length) { 3293 AssertHeapIsIdle(); 3294 CHECK_THREAD(cx); 3295 return Atomize(cx, s, length); 3296 } 3297 3298 JS_PUBLIC_API JSString* JS_AtomizeAndPinString(JSContext* cx, const char* s) { 3299 return JS_AtomizeAndPinStringN(cx, s, strlen(s)); 3300 } 3301 3302 JS_PUBLIC_API JSString* JS_AtomizeAndPinStringN(JSContext* cx, const char* s, 3303 size_t length) { 3304 AssertHeapIsIdle(); 3305 CHECK_THREAD(cx); 3306 3307 JSAtom* atom = cx->zone() ? Atomize(cx, s, length) 3308 : AtomizeWithoutActiveZone(cx, s, length); 3309 if (!atom || !PinAtom(cx, atom)) { 3310 return nullptr; 3311 } 3312 3313 MOZ_ASSERT(JS_StringHasBeenPinned(cx, atom)); 3314 return atom; 3315 } 3316 3317 JS_PUBLIC_API JSString* JS_NewLatin1String( 3318 JSContext* cx, js::UniquePtr<JS::Latin1Char[], JS::FreePolicy> chars, 3319 size_t length) { 3320 AssertHeapIsIdle(); 3321 CHECK_THREAD(cx); 3322 return NewString<CanGC>(cx, std::move(chars), length); 3323 } 3324 3325 JS_PUBLIC_API JSString* JS_NewUCString(JSContext* cx, 3326 JS::UniqueTwoByteChars chars, 3327 size_t length) { 3328 AssertHeapIsIdle(); 3329 CHECK_THREAD(cx); 3330 return NewString<CanGC>(cx, std::move(chars), length); 3331 } 3332 3333 JS_PUBLIC_API JSString* JS_NewUCStringDontDeflate(JSContext* cx, 3334 JS::UniqueTwoByteChars chars, 3335 size_t length) { 3336 AssertHeapIsIdle(); 3337 CHECK_THREAD(cx); 3338 return NewStringDontDeflate<CanGC>(cx, std::move(chars), length); 3339 } 3340 3341 JS_PUBLIC_API JSString* JS_NewUCStringCopyN(JSContext* cx, const char16_t* s, 3342 size_t n) { 3343 AssertHeapIsIdle(); 3344 CHECK_THREAD(cx); 3345 if (!n) { 3346 return cx->names().empty_; 3347 } 3348 return NewStringCopyN<CanGC>(cx, s, n); 3349 } 3350 3351 JS_PUBLIC_API JSString* JS_NewUCStringCopyZ(JSContext* cx, const char16_t* s) { 3352 AssertHeapIsIdle(); 3353 CHECK_THREAD(cx); 3354 if (!s) { 3355 return cx->runtime()->emptyString; 3356 } 3357 return NewStringCopyZ<CanGC>(cx, s); 3358 } 3359 3360 JS_PUBLIC_API JSString* JS_AtomizeUCString(JSContext* cx, const char16_t* s) { 3361 return JS_AtomizeUCStringN(cx, s, js_strlen(s)); 3362 } 3363 3364 JS_PUBLIC_API JSString* JS_AtomizeUCStringN(JSContext* cx, const char16_t* s, 3365 size_t length) { 3366 AssertHeapIsIdle(); 3367 CHECK_THREAD(cx); 3368 return AtomizeChars(cx, s, length); 3369 } 3370 3371 JS_PUBLIC_API size_t JS_GetStringLength(JSString* str) { return str->length(); } 3372 3373 JS_PUBLIC_API bool JS_StringIsLinear(JSString* str) { return str->isLinear(); } 3374 3375 JS_PUBLIC_API bool JS_DeprecatedStringHasLatin1Chars(JSString* str) { 3376 return str->hasLatin1Chars(); 3377 } 3378 3379 JS_PUBLIC_API const JS::Latin1Char* JS_GetLatin1StringCharsAndLength( 3380 JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str, 3381 size_t* plength) { 3382 MOZ_ASSERT(plength); 3383 AssertHeapIsIdle(); 3384 CHECK_THREAD(cx); 3385 cx->check(str); 3386 JSLinearString* linear = str->ensureLinear(cx); 3387 if (!linear) { 3388 return nullptr; 3389 } 3390 *plength = linear->length(); 3391 return linear->latin1Chars(nogc); 3392 } 3393 3394 JS_PUBLIC_API const char16_t* JS_GetTwoByteStringCharsAndLength( 3395 JSContext* cx, const JS::AutoRequireNoGC& nogc, JSString* str, 3396 size_t* plength) { 3397 MOZ_ASSERT(plength); 3398 AssertHeapIsIdle(); 3399 CHECK_THREAD(cx); 3400 cx->check(str); 3401 JSLinearString* linear = str->ensureLinear(cx); 3402 if (!linear) { 3403 return nullptr; 3404 } 3405 *plength = linear->length(); 3406 return linear->twoByteChars(nogc); 3407 } 3408 3409 JS_PUBLIC_API const char16_t* JS_GetTwoByteExternalStringChars(JSString* str) { 3410 return str->asExternal().twoByteChars(); 3411 } 3412 3413 JS_PUBLIC_API bool JS_GetStringCharAt(JSContext* cx, JSString* str, 3414 size_t index, char16_t* res) { 3415 AssertHeapIsIdle(); 3416 CHECK_THREAD(cx); 3417 cx->check(str); 3418 3419 JSLinearString* linear = str->ensureLinear(cx); 3420 if (!linear) { 3421 return false; 3422 } 3423 3424 *res = linear->latin1OrTwoByteChar(index); 3425 return true; 3426 } 3427 3428 JS_PUBLIC_API bool JS_CopyStringChars(JSContext* cx, 3429 const mozilla::Range<char16_t>& dest, 3430 JSString* str) { 3431 AssertHeapIsIdle(); 3432 CHECK_THREAD(cx); 3433 cx->check(str); 3434 3435 JSLinearString* linear = str->ensureLinear(cx); 3436 if (!linear) { 3437 return false; 3438 } 3439 3440 MOZ_ASSERT(linear->length() <= dest.length()); 3441 CopyChars(dest.begin().get(), *linear); 3442 return true; 3443 } 3444 3445 extern JS_PUBLIC_API JS::UniqueTwoByteChars JS_CopyStringCharsZ(JSContext* cx, 3446 JSString* str) { 3447 AssertHeapIsIdle(); 3448 CHECK_THREAD(cx); 3449 3450 JSLinearString* linear = str->ensureLinear(cx); 3451 if (!linear) { 3452 return nullptr; 3453 } 3454 3455 size_t len = linear->length(); 3456 3457 static_assert(JS::MaxStringLength < UINT32_MAX, 3458 "len + 1 must not overflow on 32-bit platforms"); 3459 3460 UniqueTwoByteChars chars(cx->pod_malloc<char16_t>(len + 1)); 3461 if (!chars) { 3462 return nullptr; 3463 } 3464 3465 CopyChars(chars.get(), *linear); 3466 chars[len] = '\0'; 3467 3468 return chars; 3469 } 3470 3471 extern JS_PUBLIC_API JSLinearString* JS_EnsureLinearString(JSContext* cx, 3472 JSString* str) { 3473 AssertHeapIsIdle(); 3474 CHECK_THREAD(cx); 3475 cx->check(str); 3476 return str->ensureLinear(cx); 3477 } 3478 3479 JS_PUBLIC_API bool JS_CompareStrings(JSContext* cx, JSString* str1, 3480 JSString* str2, int32_t* result) { 3481 AssertHeapIsIdle(); 3482 CHECK_THREAD(cx); 3483 3484 return CompareStrings(cx, str1, str2, result); 3485 } 3486 3487 JS_PUBLIC_API bool JS_StringEqualsAscii(JSContext* cx, JSString* str, 3488 const char* asciiBytes, bool* match) { 3489 AssertHeapIsIdle(); 3490 CHECK_THREAD(cx); 3491 3492 JSLinearString* linearStr = str->ensureLinear(cx); 3493 if (!linearStr) { 3494 return false; 3495 } 3496 *match = StringEqualsAscii(linearStr, asciiBytes); 3497 return true; 3498 } 3499 3500 JS_PUBLIC_API bool JS_StringEqualsAscii(JSContext* cx, JSString* str, 3501 const char* asciiBytes, size_t length, 3502 bool* match) { 3503 AssertHeapIsIdle(); 3504 CHECK_THREAD(cx); 3505 3506 JSLinearString* linearStr = str->ensureLinear(cx); 3507 if (!linearStr) { 3508 return false; 3509 } 3510 *match = StringEqualsAscii(linearStr, asciiBytes, length); 3511 return true; 3512 } 3513 3514 JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str, 3515 const char* asciiBytes) { 3516 return StringEqualsAscii(str, asciiBytes); 3517 } 3518 3519 JS_PUBLIC_API bool JS_LinearStringEqualsAscii(JSLinearString* str, 3520 const char* asciiBytes, 3521 size_t length) { 3522 return StringEqualsAscii(str, asciiBytes, length); 3523 } 3524 3525 JS_PUBLIC_API size_t JS_PutEscapedLinearString(char* buffer, size_t size, 3526 JSLinearString* str, 3527 char quote) { 3528 return PutEscapedString(buffer, size, str, quote); 3529 } 3530 3531 JS_PUBLIC_API size_t JS_PutEscapedString(JSContext* cx, char* buffer, 3532 size_t size, JSString* str, 3533 char quote) { 3534 AssertHeapIsIdle(); 3535 JSLinearString* linearStr = str->ensureLinear(cx); 3536 if (!linearStr) { 3537 return size_t(-1); 3538 } 3539 return PutEscapedString(buffer, size, linearStr, quote); 3540 } 3541 3542 JS_PUBLIC_API JSString* JS_NewDependentString(JSContext* cx, HandleString str, 3543 size_t start, size_t length) { 3544 AssertHeapIsIdle(); 3545 CHECK_THREAD(cx); 3546 return NewDependentString(cx, str, start, length); 3547 } 3548 3549 JS_PUBLIC_API JSString* JS_ConcatStrings(JSContext* cx, HandleString left, 3550 HandleString right) { 3551 AssertHeapIsIdle(); 3552 CHECK_THREAD(cx); 3553 return ConcatStrings<CanGC>(cx, left, right); 3554 } 3555 3556 JS_PUBLIC_API bool JS_DecodeBytes(JSContext* cx, const char* src, size_t srclen, 3557 char16_t* dst, size_t* dstlenp) { 3558 AssertHeapIsIdle(); 3559 CHECK_THREAD(cx); 3560 3561 if (!dst) { 3562 *dstlenp = srclen; 3563 return true; 3564 } 3565 3566 size_t dstlen = *dstlenp; 3567 3568 if (srclen > dstlen) { 3569 CopyAndInflateChars(dst, src, dstlen); 3570 3571 gc::AutoSuppressGC suppress(cx); 3572 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 3573 JSMSG_BUFFER_TOO_SMALL); 3574 return false; 3575 } 3576 3577 CopyAndInflateChars(dst, src, srclen); 3578 *dstlenp = srclen; 3579 return true; 3580 } 3581 3582 JS_PUBLIC_API JS::UniqueChars JS_EncodeStringToASCII(JSContext* cx, 3583 JSString* str) { 3584 AssertHeapIsIdle(); 3585 CHECK_THREAD(cx); 3586 3587 return js::EncodeAscii(cx, str); 3588 } 3589 3590 JS_PUBLIC_API JS::UniqueChars JS_EncodeStringToLatin1(JSContext* cx, 3591 JSString* str) { 3592 AssertHeapIsIdle(); 3593 CHECK_THREAD(cx); 3594 3595 return js::EncodeLatin1(cx, str); 3596 } 3597 3598 JS_PUBLIC_API JS::UniqueChars JS_EncodeStringToUTF8(JSContext* cx, 3599 HandleString str) { 3600 AssertHeapIsIdle(); 3601 CHECK_THREAD(cx); 3602 3603 return StringToNewUTF8CharsZ(cx, *str); 3604 } 3605 3606 JS_PUBLIC_API size_t JS_GetStringEncodingLength(JSContext* cx, JSString* str) { 3607 AssertHeapIsIdle(); 3608 CHECK_THREAD(cx); 3609 3610 if (!str->ensureLinear(cx)) { 3611 return size_t(-1); 3612 } 3613 return str->length(); 3614 } 3615 3616 JS_PUBLIC_API bool JS_EncodeStringToBuffer(JSContext* cx, JSString* str, 3617 char* buffer, size_t length) { 3618 AssertHeapIsIdle(); 3619 CHECK_THREAD(cx); 3620 3621 JSLinearString* linear = str->ensureLinear(cx); 3622 if (!linear) { 3623 return false; 3624 } 3625 3626 JS::AutoCheckCannotGC nogc; 3627 size_t writeLength = std::min(linear->length(), length); 3628 if (linear->hasLatin1Chars()) { 3629 mozilla::PodCopy(reinterpret_cast<Latin1Char*>(buffer), 3630 linear->latin1Chars(nogc), writeLength); 3631 } else { 3632 const char16_t* src = linear->twoByteChars(nogc); 3633 for (size_t i = 0; i < writeLength; i++) { 3634 buffer[i] = char(src[i]); 3635 } 3636 } 3637 return true; 3638 } 3639 3640 JS_PUBLIC_API mozilla::Maybe<std::tuple<size_t, size_t>> 3641 JS_EncodeStringToUTF8BufferPartial(JSContext* cx, JSString* str, 3642 mozilla::Span<char> buffer) { 3643 AssertHeapIsIdle(); 3644 CHECK_THREAD(cx); 3645 JS::AutoCheckCannotGC nogc; 3646 return str->encodeUTF8Partial(nogc, buffer); 3647 } 3648 3649 JS_PUBLIC_API JS::Symbol* JS::NewSymbol(JSContext* cx, 3650 HandleString description) { 3651 AssertHeapIsIdle(); 3652 CHECK_THREAD(cx); 3653 if (description) { 3654 cx->check(description); 3655 } 3656 3657 return Symbol::new_(cx, SymbolCode::UniqueSymbol, description); 3658 } 3659 3660 JS_PUBLIC_API JS::Symbol* JS::GetSymbolFor(JSContext* cx, HandleString key) { 3661 AssertHeapIsIdle(); 3662 CHECK_THREAD(cx); 3663 cx->check(key); 3664 3665 return Symbol::for_(cx, key); 3666 } 3667 3668 JS_PUBLIC_API JSString* JS::GetSymbolDescription(HandleSymbol symbol) { 3669 return symbol->description(); 3670 } 3671 3672 JS_PUBLIC_API JS::SymbolCode JS::GetSymbolCode(Handle<Symbol*> symbol) { 3673 return symbol->code(); 3674 } 3675 3676 JS_PUBLIC_API JS::Symbol* JS::GetWellKnownSymbol(JSContext* cx, 3677 JS::SymbolCode which) { 3678 return cx->wellKnownSymbols().get(which); 3679 } 3680 3681 JS_PUBLIC_API JS::PropertyKey JS::GetWellKnownSymbolKey(JSContext* cx, 3682 JS::SymbolCode which) { 3683 return PropertyKey::Symbol(cx->wellKnownSymbols().get(which)); 3684 } 3685 3686 static bool AddPrefix(JSContext* cx, JS::Handle<JS::PropertyKey> id, 3687 FunctionPrefixKind prefixKind, 3688 JS::MutableHandle<JS::PropertyKey> out) { 3689 JSAtom* atom = js::IdToFunctionName(cx, id, prefixKind); 3690 if (!atom) { 3691 return false; 3692 } 3693 3694 out.set(JS::PropertyKey::NonIntAtom(atom)); 3695 return true; 3696 } 3697 3698 JS_PUBLIC_API bool JS::ToGetterId(JSContext* cx, JS::Handle<JS::PropertyKey> id, 3699 JS::MutableHandle<JS::PropertyKey> getterId) { 3700 return AddPrefix(cx, id, FunctionPrefixKind::Get, getterId); 3701 } 3702 3703 JS_PUBLIC_API bool JS::ToSetterId(JSContext* cx, JS::Handle<JS::PropertyKey> id, 3704 JS::MutableHandle<JS::PropertyKey> setterId) { 3705 return AddPrefix(cx, id, FunctionPrefixKind::Set, setterId); 3706 } 3707 3708 #ifdef DEBUG 3709 static bool PropertySpecNameIsDigits(JSPropertySpec::Name name) { 3710 if (name.isSymbol()) { 3711 return false; 3712 } 3713 const char* s = name.string(); 3714 if (!*s) { 3715 return false; 3716 } 3717 for (; *s; s++) { 3718 if (*s < '0' || *s > '9') { 3719 return false; 3720 } 3721 } 3722 return true; 3723 } 3724 #endif // DEBUG 3725 3726 JS_PUBLIC_API bool JS::PropertySpecNameEqualsId(JSPropertySpec::Name name, 3727 HandleId id) { 3728 if (name.isSymbol()) { 3729 return id.isWellKnownSymbol(name.symbol()); 3730 } 3731 3732 MOZ_ASSERT(!PropertySpecNameIsDigits(name)); 3733 return id.isAtom() && JS_LinearStringEqualsAscii(id.toAtom(), name.string()); 3734 } 3735 3736 JS_PUBLIC_API bool JS_Stringify(JSContext* cx, MutableHandleValue vp, 3737 HandleObject replacer, HandleValue space, 3738 JSONWriteCallback callback, void* data) { 3739 return JS_StringifyWithLengthHint(cx, vp, replacer, space, callback, data, 0); 3740 } 3741 3742 JS_PUBLIC_API bool JS_StringifyWithLengthHint(JSContext* cx, 3743 MutableHandleValue vp, 3744 HandleObject replacer, 3745 HandleValue space, 3746 JSONWriteCallback callback, 3747 void* data, size_t lengthHint) { 3748 AssertHeapIsIdle(); 3749 CHECK_THREAD(cx); 3750 cx->check(replacer, space); 3751 StringBuilder sb(cx); 3752 if (!sb.ensureTwoByteChars()) { 3753 return false; 3754 } 3755 if (lengthHint && !sb.reserve(lengthHint)) { 3756 return false; 3757 } 3758 if (!Stringify(cx, vp, replacer, space, sb, StringifyBehavior::Normal)) { 3759 return false; 3760 } 3761 if (sb.empty() && !sb.append(cx->names().null)) { 3762 return false; 3763 } 3764 return callback(sb.rawTwoByteBegin(), sb.length(), data); 3765 } 3766 3767 JS_PUBLIC_API bool JS::ToJSON(JSContext* cx, HandleValue value, 3768 HandleObject replacer, HandleValue space, 3769 JSONWriteCallback callback, void* data) { 3770 AssertHeapIsIdle(); 3771 CHECK_THREAD(cx); 3772 cx->check(replacer, space); 3773 StringBuilder sb(cx); 3774 if (!sb.ensureTwoByteChars()) { 3775 return false; 3776 } 3777 RootedValue v(cx, value); 3778 if (!Stringify(cx, &v, replacer, space, sb, StringifyBehavior::Normal)) { 3779 return false; 3780 } 3781 if (sb.empty()) { 3782 return true; 3783 } 3784 return callback(sb.rawTwoByteBegin(), sb.length(), data); 3785 } 3786 3787 JS_PUBLIC_API bool JS::ToJSONMaybeSafely(JSContext* cx, JS::HandleObject input, 3788 JSONWriteCallback callback, 3789 void* data) { 3790 AssertHeapIsIdle(); 3791 CHECK_THREAD(cx); 3792 cx->check(input); 3793 3794 StringBuilder sb(cx); 3795 if (!sb.ensureTwoByteChars()) { 3796 return false; 3797 } 3798 3799 RootedValue inputValue(cx, ObjectValue(*input)); 3800 if (!Stringify(cx, &inputValue, nullptr, NullHandleValue, sb, 3801 StringifyBehavior::RestrictedSafe)) 3802 return false; 3803 3804 if (sb.empty() && !sb.append(cx->names().null)) { 3805 return false; 3806 } 3807 3808 return callback(sb.rawTwoByteBegin(), sb.length(), data); 3809 } 3810 3811 JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, const char16_t* chars, 3812 uint32_t len, MutableHandleValue vp) { 3813 AssertHeapIsIdle(); 3814 CHECK_THREAD(cx); 3815 return ParseJSONWithReviver(cx, mozilla::Range<const char16_t>(chars, len), 3816 NullHandleValue, vp); 3817 } 3818 3819 JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, HandleString str, 3820 MutableHandleValue vp) { 3821 return JS_ParseJSONWithReviver(cx, str, NullHandleValue, vp); 3822 } 3823 3824 JS_PUBLIC_API bool JS_ParseJSON(JSContext* cx, const Latin1Char* chars, 3825 uint32_t len, MutableHandleValue vp) { 3826 AssertHeapIsIdle(); 3827 CHECK_THREAD(cx); 3828 return ParseJSONWithReviver(cx, mozilla::Range<const Latin1Char>(chars, len), 3829 NullHandleValue, vp); 3830 } 3831 3832 JS_PUBLIC_API bool JS_ParseJSONWithReviver(JSContext* cx, const char16_t* chars, 3833 uint32_t len, HandleValue reviver, 3834 MutableHandleValue vp) { 3835 AssertHeapIsIdle(); 3836 CHECK_THREAD(cx); 3837 return ParseJSONWithReviver(cx, mozilla::Range<const char16_t>(chars, len), 3838 reviver, vp); 3839 } 3840 3841 JS_PUBLIC_API bool JS_ParseJSONWithReviver(JSContext* cx, HandleString str, 3842 HandleValue reviver, 3843 MutableHandleValue vp) { 3844 AssertHeapIsIdle(); 3845 CHECK_THREAD(cx); 3846 cx->check(str); 3847 3848 AutoStableStringChars stableChars(cx); 3849 if (!stableChars.init(cx, str)) { 3850 return false; 3851 } 3852 3853 return stableChars.isLatin1() 3854 ? ParseJSONWithReviver(cx, stableChars.latin1Range(), reviver, vp) 3855 : ParseJSONWithReviver(cx, stableChars.twoByteRange(), reviver, 3856 vp); 3857 } 3858 3859 /************************************************************************/ 3860 3861 JS_PUBLIC_API void JS_ReportErrorASCII(JSContext* cx, const char* format, ...) { 3862 va_list ap; 3863 3864 AssertHeapIsIdle(); 3865 va_start(ap, format); 3866 ReportErrorVA(cx, IsWarning::No, format, ArgumentsAreASCII, ap); 3867 va_end(ap); 3868 } 3869 3870 JS_PUBLIC_API void JS_ReportErrorLatin1(JSContext* cx, const char* format, 3871 ...) { 3872 va_list ap; 3873 3874 AssertHeapIsIdle(); 3875 va_start(ap, format); 3876 ReportErrorVA(cx, IsWarning::No, format, ArgumentsAreLatin1, ap); 3877 va_end(ap); 3878 } 3879 3880 JS_PUBLIC_API void JS_ReportErrorUTF8(JSContext* cx, const char* format, ...) { 3881 va_list ap; 3882 3883 AssertHeapIsIdle(); 3884 va_start(ap, format); 3885 ReportErrorVA(cx, IsWarning::No, format, ArgumentsAreUTF8, ap); 3886 va_end(ap); 3887 } 3888 3889 JS_PUBLIC_API void JS_ReportErrorNumberASCII(JSContext* cx, 3890 JSErrorCallback errorCallback, 3891 void* userRef, 3892 const unsigned errorNumber, ...) { 3893 va_list ap; 3894 va_start(ap, errorNumber); 3895 JS_ReportErrorNumberASCIIVA(cx, errorCallback, userRef, errorNumber, ap); 3896 va_end(ap); 3897 } 3898 3899 JS_PUBLIC_API void JS_ReportErrorNumberASCIIVA(JSContext* cx, 3900 JSErrorCallback errorCallback, 3901 void* userRef, 3902 const unsigned errorNumber, 3903 va_list ap) { 3904 AssertHeapIsIdle(); 3905 ReportErrorNumberVA(cx, IsWarning::No, errorCallback, userRef, errorNumber, 3906 ArgumentsAreASCII, ap); 3907 } 3908 3909 JS_PUBLIC_API void JS_ReportErrorNumberLatin1(JSContext* cx, 3910 JSErrorCallback errorCallback, 3911 void* userRef, 3912 const unsigned errorNumber, ...) { 3913 va_list ap; 3914 va_start(ap, errorNumber); 3915 JS_ReportErrorNumberLatin1VA(cx, errorCallback, userRef, errorNumber, ap); 3916 va_end(ap); 3917 } 3918 3919 JS_PUBLIC_API void JS_ReportErrorNumberLatin1VA(JSContext* cx, 3920 JSErrorCallback errorCallback, 3921 void* userRef, 3922 const unsigned errorNumber, 3923 va_list ap) { 3924 AssertHeapIsIdle(); 3925 ReportErrorNumberVA(cx, IsWarning::No, errorCallback, userRef, errorNumber, 3926 ArgumentsAreLatin1, ap); 3927 } 3928 3929 JS_PUBLIC_API void JS_ReportErrorNumberUTF8(JSContext* cx, 3930 JSErrorCallback errorCallback, 3931 void* userRef, 3932 const unsigned errorNumber, ...) { 3933 va_list ap; 3934 va_start(ap, errorNumber); 3935 JS_ReportErrorNumberUTF8VA(cx, errorCallback, userRef, errorNumber, ap); 3936 va_end(ap); 3937 } 3938 3939 JS_PUBLIC_API void JS_ReportErrorNumberUTF8VA(JSContext* cx, 3940 JSErrorCallback errorCallback, 3941 void* userRef, 3942 const unsigned errorNumber, 3943 va_list ap) { 3944 AssertHeapIsIdle(); 3945 ReportErrorNumberVA(cx, IsWarning::No, errorCallback, userRef, errorNumber, 3946 ArgumentsAreUTF8, ap); 3947 } 3948 3949 JS_PUBLIC_API void JS_ReportErrorNumberUTF8Array(JSContext* cx, 3950 JSErrorCallback errorCallback, 3951 void* userRef, 3952 const unsigned errorNumber, 3953 const char** args) { 3954 AssertHeapIsIdle(); 3955 ReportErrorNumberUTF8Array(cx, IsWarning::No, errorCallback, userRef, 3956 errorNumber, args); 3957 } 3958 3959 JS_PUBLIC_API void JS_ReportErrorNumberUC(JSContext* cx, 3960 JSErrorCallback errorCallback, 3961 void* userRef, 3962 const unsigned errorNumber, ...) { 3963 va_list ap; 3964 3965 AssertHeapIsIdle(); 3966 va_start(ap, errorNumber); 3967 ReportErrorNumberVA(cx, IsWarning::No, errorCallback, userRef, errorNumber, 3968 ArgumentsAreUnicode, ap); 3969 va_end(ap); 3970 } 3971 3972 JS_PUBLIC_API void JS_ReportErrorNumberUCArray(JSContext* cx, 3973 JSErrorCallback errorCallback, 3974 void* userRef, 3975 const unsigned errorNumber, 3976 const char16_t** args) { 3977 AssertHeapIsIdle(); 3978 ReportErrorNumberUCArray(cx, IsWarning::No, errorCallback, userRef, 3979 errorNumber, args); 3980 } 3981 3982 JS_PUBLIC_API void JS_ReportOutOfMemory(JSContext* cx) { 3983 ReportOutOfMemory(cx); 3984 } 3985 3986 JS_PUBLIC_API void JS_ReportAllocationOverflow(JSContext* cx) { 3987 ReportAllocationOverflow(cx); 3988 } 3989 3990 JS_PUBLIC_API void JS::ReportUncatchableException(JSContext* cx) { 3991 cx->reportUncatchableException(); 3992 } 3993 3994 JS_PUBLIC_API bool JS_ExpandErrorArgumentsASCII(JSContext* cx, 3995 JSErrorCallback errorCallback, 3996 const unsigned errorNumber, 3997 JSErrorReport* reportp, ...) { 3998 va_list ap; 3999 bool ok; 4000 4001 AssertHeapIsIdle(); 4002 va_start(ap, reportp); 4003 AutoReportFrontendContext fc(cx); 4004 ok = ExpandErrorArgumentsVA(&fc, errorCallback, nullptr, errorNumber, 4005 ArgumentsAreASCII, reportp, ap); 4006 va_end(ap); 4007 return ok; 4008 } 4009 /************************************************************************/ 4010 4011 JS_PUBLIC_API bool JS_SetDefaultLocale(JSRuntime* rt, const char* locale) { 4012 AssertHeapIsIdle(); 4013 return rt->setDefaultLocale(locale); 4014 } 4015 4016 JS_PUBLIC_API UniqueChars JS_GetDefaultLocale(JSContext* cx) { 4017 AssertHeapIsIdle(); 4018 if (const char* locale = cx->runtime()->getDefaultLocale()) { 4019 return DuplicateString(cx, locale); 4020 } 4021 4022 return nullptr; 4023 } 4024 4025 JS_PUBLIC_API void JS_ResetDefaultLocale(JSRuntime* rt) { 4026 AssertHeapIsIdle(); 4027 rt->resetDefaultLocale(); 4028 } 4029 4030 JS_PUBLIC_API void JS_SetLocaleCallbacks(JSRuntime* rt, 4031 const JSLocaleCallbacks* callbacks) { 4032 AssertHeapIsIdle(); 4033 rt->localeCallbacks = callbacks; 4034 } 4035 4036 JS_PUBLIC_API const JSLocaleCallbacks* JS_GetLocaleCallbacks(JSRuntime* rt) { 4037 /* This function can be called by a finalizer. */ 4038 return rt->localeCallbacks; 4039 } 4040 4041 /************************************************************************/ 4042 4043 JS_PUBLIC_API bool JS_IsExceptionPending(JSContext* cx) { 4044 /* This function can be called by a finalizer. */ 4045 return (bool)cx->isExceptionPending(); 4046 } 4047 4048 JS_PUBLIC_API bool JS_IsThrowingOutOfMemory(JSContext* cx) { 4049 return cx->isThrowingOutOfMemory(); 4050 } 4051 4052 JS_PUBLIC_API bool JS_GetPendingException(JSContext* cx, 4053 MutableHandleValue vp) { 4054 AssertHeapIsIdle(); 4055 CHECK_THREAD(cx); 4056 if (!cx->isExceptionPending()) { 4057 return false; 4058 } 4059 return cx->getPendingException(vp); 4060 } 4061 4062 JS_PUBLIC_API void JS_SetPendingException(JSContext* cx, HandleValue value, 4063 JS::ExceptionStackBehavior behavior) { 4064 AssertHeapIsIdle(); 4065 CHECK_THREAD(cx); 4066 // We don't check the compartment of `value` here, because we're not 4067 // doing anything with it other than storing it, and stored 4068 // exception values can be in an abitrary compartment. 4069 4070 if (behavior == JS::ExceptionStackBehavior::Capture) { 4071 cx->setPendingException(value, ShouldCaptureStack::Always); 4072 } else { 4073 cx->setPendingException(value, nullptr); 4074 } 4075 } 4076 4077 JS_PUBLIC_API void JS_ClearPendingException(JSContext* cx) { 4078 AssertHeapIsIdle(); 4079 cx->clearPendingException(); 4080 } 4081 4082 JS::AutoSaveExceptionState::AutoSaveExceptionState(JSContext* cx) 4083 : context(cx), status(cx->status), exceptionValue(cx), exceptionStack(cx) { 4084 AssertHeapIsIdle(); 4085 CHECK_THREAD(cx); 4086 if (IsCatchableExceptionStatus(status)) { 4087 exceptionValue = cx->unwrappedException(); 4088 exceptionStack = cx->unwrappedExceptionStack(); 4089 } 4090 cx->clearPendingException(); 4091 } 4092 4093 void JS::AutoSaveExceptionState::drop() { 4094 status = JS::ExceptionStatus::None; 4095 exceptionValue.setUndefined(); 4096 exceptionStack = nullptr; 4097 } 4098 4099 void JS::AutoSaveExceptionState::restore() { 4100 context->status = status; 4101 context->unwrappedException() = exceptionValue; 4102 if (exceptionStack) { 4103 context->unwrappedExceptionStack() = &exceptionStack->as<SavedFrame>(); 4104 } 4105 drop(); 4106 } 4107 4108 JS::AutoSaveExceptionState::~AutoSaveExceptionState() { 4109 // NOTE: An interrupt/uncatchable exception or a debugger-forced-return may be 4110 // clobbered here by the saved exception. If that is not desired, this 4111 // state should be dropped before the destructor fires. 4112 if (!context->isExceptionPending()) { 4113 if (status != JS::ExceptionStatus::None) { 4114 context->status = status; 4115 } 4116 if (IsCatchableExceptionStatus(status)) { 4117 context->unwrappedException() = exceptionValue; 4118 if (exceptionStack) { 4119 context->unwrappedExceptionStack() = &exceptionStack->as<SavedFrame>(); 4120 } 4121 } 4122 } 4123 } 4124 4125 JS_PUBLIC_API JSErrorReport* JS_ErrorFromException(JSContext* cx, 4126 HandleObject obj) { 4127 AssertHeapIsIdle(); 4128 CHECK_THREAD(cx); 4129 cx->check(obj); 4130 return ErrorFromException(cx, obj); 4131 } 4132 4133 void JSErrorReport::initBorrowedLinebuf(const char16_t* linebufArg, 4134 size_t linebufLengthArg, 4135 size_t tokenOffsetArg) { 4136 MOZ_ASSERT(linebufArg); 4137 MOZ_ASSERT(tokenOffsetArg <= linebufLengthArg); 4138 MOZ_ASSERT(linebufArg[linebufLengthArg] == '\0'); 4139 4140 linebuf_ = linebufArg; 4141 linebufLength_ = linebufLengthArg; 4142 tokenOffset_ = tokenOffsetArg; 4143 } 4144 4145 void JSErrorReport::freeLinebuf() { 4146 if (ownsLinebuf_ && linebuf_) { 4147 js_free((void*)linebuf_); 4148 ownsLinebuf_ = false; 4149 } 4150 linebuf_ = nullptr; 4151 } 4152 4153 JSString* JSErrorBase::newMessageString(JSContext* cx) { 4154 if (!message_) { 4155 return cx->runtime()->emptyString; 4156 } 4157 4158 return JS_NewStringCopyUTF8Z(cx, message_); 4159 } 4160 4161 void JSErrorBase::freeMessage() { 4162 if (ownsMessage_) { 4163 js_free((void*)message_.get()); 4164 ownsMessage_ = false; 4165 } 4166 message_ = JS::ConstUTF8CharsZ(); 4167 } 4168 4169 JSErrorNotes::JSErrorNotes() = default; 4170 4171 JSErrorNotes::~JSErrorNotes() = default; 4172 4173 static UniquePtr<JSErrorNotes::Note> CreateErrorNoteVA( 4174 FrontendContext* fc, const char* filename, unsigned sourceId, 4175 uint32_t lineno, JS::ColumnNumberOneOrigin column, 4176 JSErrorCallback errorCallback, void* userRef, const unsigned errorNumber, 4177 ErrorArgumentsType argumentsType, va_list ap) { 4178 auto note = MakeUnique<JSErrorNotes::Note>(); 4179 if (!note) { 4180 ReportOutOfMemory(fc); 4181 return nullptr; 4182 } 4183 4184 note->errorNumber = errorNumber; 4185 note->filename = JS::ConstUTF8CharsZ(filename); 4186 note->sourceId = sourceId; 4187 note->lineno = lineno; 4188 note->column = column; 4189 4190 if (!ExpandErrorArgumentsVA(fc, errorCallback, userRef, errorNumber, nullptr, 4191 argumentsType, note.get(), ap)) { 4192 return nullptr; 4193 } 4194 4195 return note; 4196 } 4197 4198 bool JSErrorNotes::addNoteVA(FrontendContext* fc, const char* filename, 4199 unsigned sourceId, uint32_t lineno, 4200 JS::ColumnNumberOneOrigin column, 4201 JSErrorCallback errorCallback, void* userRef, 4202 const unsigned errorNumber, 4203 ErrorArgumentsType argumentsType, va_list ap) { 4204 auto note = 4205 CreateErrorNoteVA(fc, filename, sourceId, lineno, column, errorCallback, 4206 userRef, errorNumber, argumentsType, ap); 4207 4208 if (!note) { 4209 return false; 4210 } 4211 if (!notes_.append(std::move(note))) { 4212 ReportOutOfMemory(fc); 4213 return false; 4214 } 4215 return true; 4216 } 4217 4218 bool JSErrorNotes::addNoteASCII(JSContext* cx, const char* filename, 4219 unsigned sourceId, uint32_t lineno, 4220 JS::ColumnNumberOneOrigin column, 4221 JSErrorCallback errorCallback, void* userRef, 4222 const unsigned errorNumber, ...) { 4223 AutoReportFrontendContext fc(cx); 4224 va_list ap; 4225 va_start(ap, errorNumber); 4226 bool ok = addNoteVA(&fc, filename, sourceId, lineno, column, errorCallback, 4227 userRef, errorNumber, ArgumentsAreASCII, ap); 4228 va_end(ap); 4229 return ok; 4230 } 4231 4232 bool JSErrorNotes::addNoteASCII(FrontendContext* fc, const char* filename, 4233 unsigned sourceId, uint32_t lineno, 4234 JS::ColumnNumberOneOrigin column, 4235 JSErrorCallback errorCallback, void* userRef, 4236 const unsigned errorNumber, ...) { 4237 va_list ap; 4238 va_start(ap, errorNumber); 4239 bool ok = addNoteVA(fc, filename, sourceId, lineno, column, errorCallback, 4240 userRef, errorNumber, ArgumentsAreASCII, ap); 4241 va_end(ap); 4242 return ok; 4243 } 4244 4245 bool JSErrorNotes::addNoteLatin1(JSContext* cx, const char* filename, 4246 unsigned sourceId, uint32_t lineno, 4247 JS::ColumnNumberOneOrigin column, 4248 JSErrorCallback errorCallback, void* userRef, 4249 const unsigned errorNumber, ...) { 4250 AutoReportFrontendContext fc(cx); 4251 va_list ap; 4252 va_start(ap, errorNumber); 4253 bool ok = addNoteVA(&fc, filename, sourceId, lineno, column, errorCallback, 4254 userRef, errorNumber, ArgumentsAreLatin1, ap); 4255 va_end(ap); 4256 return ok; 4257 } 4258 4259 bool JSErrorNotes::addNoteLatin1(FrontendContext* fc, const char* filename, 4260 unsigned sourceId, uint32_t lineno, 4261 JS::ColumnNumberOneOrigin column, 4262 JSErrorCallback errorCallback, void* userRef, 4263 const unsigned errorNumber, ...) { 4264 va_list ap; 4265 va_start(ap, errorNumber); 4266 bool ok = addNoteVA(fc, filename, sourceId, lineno, column, errorCallback, 4267 userRef, errorNumber, ArgumentsAreLatin1, ap); 4268 va_end(ap); 4269 return ok; 4270 } 4271 4272 bool JSErrorNotes::addNoteUTF8(JSContext* cx, const char* filename, 4273 unsigned sourceId, uint32_t lineno, 4274 JS::ColumnNumberOneOrigin column, 4275 JSErrorCallback errorCallback, void* userRef, 4276 const unsigned errorNumber, ...) { 4277 AutoReportFrontendContext fc(cx); 4278 va_list ap; 4279 va_start(ap, errorNumber); 4280 bool ok = addNoteVA(&fc, filename, sourceId, lineno, column, errorCallback, 4281 userRef, errorNumber, ArgumentsAreUTF8, ap); 4282 va_end(ap); 4283 return ok; 4284 } 4285 4286 bool JSErrorNotes::addNoteUTF8(FrontendContext* fc, const char* filename, 4287 unsigned sourceId, uint32_t lineno, 4288 JS::ColumnNumberOneOrigin column, 4289 JSErrorCallback errorCallback, void* userRef, 4290 const unsigned errorNumber, ...) { 4291 va_list ap; 4292 va_start(ap, errorNumber); 4293 bool ok = addNoteVA(fc, filename, sourceId, lineno, column, errorCallback, 4294 userRef, errorNumber, ArgumentsAreUTF8, ap); 4295 va_end(ap); 4296 return ok; 4297 } 4298 4299 JS_PUBLIC_API size_t JSErrorNotes::length() { return notes_.length(); } 4300 4301 UniquePtr<JSErrorNotes> JSErrorNotes::copy(JSContext* cx) { 4302 auto copiedNotes = MakeUnique<JSErrorNotes>(); 4303 if (!copiedNotes) { 4304 ReportOutOfMemory(cx); 4305 return nullptr; 4306 } 4307 4308 for (auto&& note : *this) { 4309 UniquePtr<JSErrorNotes::Note> copied = CopyErrorNote(cx, note.get()); 4310 if (!copied) { 4311 return nullptr; 4312 } 4313 4314 if (!copiedNotes->notes_.append(std::move(copied))) { 4315 return nullptr; 4316 } 4317 } 4318 4319 return copiedNotes; 4320 } 4321 4322 JS_PUBLIC_API JSErrorNotes::iterator JSErrorNotes::begin() { 4323 return iterator(notes_.begin()); 4324 } 4325 4326 JS_PUBLIC_API JSErrorNotes::iterator JSErrorNotes::end() { 4327 return iterator(notes_.end()); 4328 } 4329 4330 extern MOZ_NEVER_INLINE JS_PUBLIC_API void JS_AbortIfWrongThread( 4331 JSContext* cx) { 4332 if (!CurrentThreadCanAccessRuntime(cx->runtime())) { 4333 MOZ_CRASH(); 4334 } 4335 if (TlsContext.get() != cx) { 4336 MOZ_CRASH(); 4337 } 4338 } 4339 4340 JS_PUBLIC_API void JS_SetOffthreadBaselineCompilationEnabled(JSContext* cx, 4341 bool enabled) { 4342 cx->runtime()->setOffthreadBaselineCompilationEnabled(enabled); 4343 } 4344 4345 JS_PUBLIC_API void JS_SetOffthreadIonCompilationEnabled(JSContext* cx, 4346 bool enabled) { 4347 cx->runtime()->setOffthreadIonCompilationEnabled(enabled); 4348 } 4349 4350 JS_PUBLIC_API void JS_SetGlobalJitCompilerOption(JSContext* cx, 4351 JSJitCompilerOption opt, 4352 uint32_t value) { 4353 JSRuntime* rt = cx->runtime(); 4354 switch (opt) { 4355 #ifdef ENABLE_PORTABLE_BASELINE_INTERP 4356 case JSJITCOMPILER_PORTABLE_BASELINE_ENABLE: 4357 if (value == 1) { 4358 jit::JitOptions.portableBaselineInterpreter = true; 4359 } else if (value == 0) { 4360 jit::JitOptions.portableBaselineInterpreter = false; 4361 } 4362 break; 4363 case JSJITCOMPILER_PORTABLE_BASELINE_WARMUP_THRESHOLD: 4364 if (value == uint32_t(-1)) { 4365 jit::DefaultJitOptions defaultValues; 4366 value = defaultValues.portableBaselineInterpreterWarmUpThreshold; 4367 } 4368 jit::JitOptions.portableBaselineInterpreterWarmUpThreshold = value; 4369 break; 4370 #endif 4371 case JSJITCOMPILER_BASELINE_INTERPRETER_WARMUP_TRIGGER: 4372 if (value == uint32_t(-1)) { 4373 jit::DefaultJitOptions defaultValues; 4374 value = defaultValues.baselineInterpreterWarmUpThreshold; 4375 } 4376 jit::JitOptions.baselineInterpreterWarmUpThreshold = value; 4377 break; 4378 case JSJITCOMPILER_BASELINE_WARMUP_TRIGGER: 4379 if (value == uint32_t(-1)) { 4380 jit::DefaultJitOptions defaultValues; 4381 value = defaultValues.baselineJitWarmUpThreshold; 4382 } 4383 jit::JitOptions.baselineJitWarmUpThreshold = value; 4384 break; 4385 case JSJITCOMPILER_IC_FORCE_MEGAMORPHIC: 4386 jit::JitOptions.forceMegamorphicICs = !!value; 4387 break; 4388 case JSJITCOMPILER_ION_NORMAL_WARMUP_TRIGGER: 4389 if (value == uint32_t(-1)) { 4390 jit::JitOptions.resetNormalIonWarmUpThreshold(); 4391 break; 4392 } 4393 jit::JitOptions.setNormalIonWarmUpThreshold(value); 4394 break; 4395 case JSJITCOMPILER_ION_GVN_ENABLE: 4396 if (value == 0) { 4397 jit::JitOptions.enableGvn(false); 4398 JitSpew(js::jit::JitSpew_IonScripts, "Disable ion's GVN"); 4399 } else { 4400 jit::JitOptions.enableGvn(true); 4401 JitSpew(js::jit::JitSpew_IonScripts, "Enable ion's GVN"); 4402 } 4403 break; 4404 case JSJITCOMPILER_ION_FORCE_IC: 4405 if (value == 0) { 4406 jit::JitOptions.forceInlineCaches = false; 4407 JitSpew(js::jit::JitSpew_IonScripts, 4408 "Ion: Enable non-IC optimizations."); 4409 } else { 4410 jit::JitOptions.forceInlineCaches = true; 4411 JitSpew(js::jit::JitSpew_IonScripts, 4412 "Ion: Disable non-IC optimizations."); 4413 } 4414 break; 4415 case JSJITCOMPILER_ION_CHECK_RANGE_ANALYSIS: 4416 if (value == 0) { 4417 jit::JitOptions.checkRangeAnalysis = false; 4418 JitSpew(js::jit::JitSpew_IonScripts, 4419 "Ion: Enable range analysis checks."); 4420 } else { 4421 jit::JitOptions.checkRangeAnalysis = true; 4422 JitSpew(js::jit::JitSpew_IonScripts, 4423 "Ion: Disable range analysis checks."); 4424 } 4425 break; 4426 case JSJITCOMPILER_ION_ENABLE: 4427 if (value == 1) { 4428 jit::JitOptions.ion = true; 4429 JitSpew(js::jit::JitSpew_IonScripts, "Enable ion"); 4430 } else if (value == 0) { 4431 jit::JitOptions.ion = false; 4432 JitSpew(js::jit::JitSpew_IonScripts, "Disable ion"); 4433 } 4434 break; 4435 case JSJITCOMPILER_JIT_TRUSTEDPRINCIPALS_ENABLE: 4436 if (value == 1) { 4437 jit::JitOptions.jitForTrustedPrincipals = true; 4438 JitSpew(js::jit::JitSpew_IonScripts, 4439 "Enable ion and baselinejit for trusted principals"); 4440 } else if (value == 0) { 4441 jit::JitOptions.jitForTrustedPrincipals = false; 4442 JitSpew(js::jit::JitSpew_IonScripts, 4443 "Disable ion and baselinejit for trusted principals"); 4444 } 4445 break; 4446 case JSJITCOMPILER_ION_FREQUENT_BAILOUT_THRESHOLD: 4447 if (value == uint32_t(-1)) { 4448 jit::DefaultJitOptions defaultValues; 4449 value = defaultValues.frequentBailoutThreshold; 4450 } 4451 jit::JitOptions.frequentBailoutThreshold = value; 4452 break; 4453 case JSJITCOMPILER_BASE_REG_FOR_LOCALS: { 4454 #ifdef JS_CODEGEN_ARM64 4455 bool canUseBaseRegForLocals = !fuzzingSafe; 4456 #else 4457 bool canUseBaseRegForLocals = true; 4458 #endif 4459 if (canUseBaseRegForLocals) { 4460 if (value == 0) { 4461 jit::JitOptions.baseRegForLocals = jit::BaseRegForAddress::SP; 4462 } else if (value == 1) { 4463 jit::JitOptions.baseRegForLocals = jit::BaseRegForAddress::FP; 4464 } else { 4465 jit::DefaultJitOptions defaultValues; 4466 jit::JitOptions.baseRegForLocals = defaultValues.baseRegForLocals; 4467 } 4468 } else { 4469 JitSpew(js::jit::JitSpew_BaselineScripts, 4470 "base-reg-for-locals is always SP."); 4471 } 4472 break; 4473 } 4474 case JSJITCOMPILER_BASELINE_INTERPRETER_ENABLE: 4475 if (value == 1) { 4476 jit::JitOptions.baselineInterpreter = true; 4477 } else if (value == 0) { 4478 ReleaseAllJITCode(rt->gcContext()); 4479 jit::JitOptions.baselineInterpreter = false; 4480 } 4481 break; 4482 case JSJITCOMPILER_BASELINE_ENABLE: 4483 if (value == 1) { 4484 jit::JitOptions.baselineJit = true; 4485 ReleaseAllJITCode(rt->gcContext()); 4486 JitSpew(js::jit::JitSpew_BaselineScripts, "Enable baseline"); 4487 } else if (value == 0) { 4488 jit::JitOptions.baselineJit = false; 4489 ReleaseAllJITCode(rt->gcContext()); 4490 JitSpew(js::jit::JitSpew_BaselineScripts, "Disable baseline"); 4491 } 4492 break; 4493 case JSJITCOMPILER_NATIVE_REGEXP_ENABLE: 4494 jit::JitOptions.nativeRegExp = !!value; 4495 break; 4496 case JSJITCOMPILER_JIT_HINTS_ENABLE: 4497 jit::JitOptions.disableJitHints = !value; 4498 break; 4499 case JSJITCOMPILER_OFFTHREAD_COMPILATION_ENABLE: 4500 if (value == 1) { 4501 rt->setOffthreadCompilationEnabled(true); 4502 JitSpew(js::jit::JitSpew_IonScripts, "Enable offthread compilation"); 4503 } else if (value == 0) { 4504 rt->setOffthreadCompilationEnabled(false); 4505 JitSpew(js::jit::JitSpew_IonScripts, "Disable offthread compilation"); 4506 } 4507 break; 4508 case JSJITCOMPILER_INLINING_BYTECODE_MAX_LENGTH: 4509 if (value == uint32_t(-1)) { 4510 jit::DefaultJitOptions defaultValues; 4511 value = defaultValues.smallFunctionMaxBytecodeLength; 4512 } 4513 jit::JitOptions.smallFunctionMaxBytecodeLength = value; 4514 break; 4515 case JSJITCOMPILER_JUMP_THRESHOLD: 4516 if (value == uint32_t(-1)) { 4517 jit::DefaultJitOptions defaultValues; 4518 value = defaultValues.jumpThreshold; 4519 } 4520 jit::JitOptions.jumpThreshold = value; 4521 break; 4522 case JSJITCOMPILER_SPECTRE_INDEX_MASKING: 4523 jit::JitOptions.spectreIndexMasking = !!value; 4524 break; 4525 case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS: 4526 jit::JitOptions.spectreObjectMitigations = !!value; 4527 break; 4528 case JSJITCOMPILER_SPECTRE_STRING_MITIGATIONS: 4529 jit::JitOptions.spectreStringMitigations = !!value; 4530 break; 4531 case JSJITCOMPILER_SPECTRE_VALUE_MASKING: 4532 jit::JitOptions.spectreValueMasking = !!value; 4533 break; 4534 case JSJITCOMPILER_SPECTRE_JIT_TO_CXX_CALLS: 4535 jit::JitOptions.spectreJitToCxxCalls = !!value; 4536 break; 4537 case JSJITCOMPILER_WRITE_PROTECT_CODE: 4538 jit::JitOptions.maybeSetWriteProtectCode(!!value); 4539 break; 4540 case JSJITCOMPILER_WASM_FOLD_OFFSETS: 4541 jit::JitOptions.wasmFoldOffsets = !!value; 4542 break; 4543 case JSJITCOMPILER_WASM_DELAY_TIER2: 4544 jit::JitOptions.wasmDelayTier2 = !!value; 4545 break; 4546 case JSJITCOMPILER_WASM_JIT_BASELINE: 4547 JS::ContextOptionsRef(cx).setWasmBaseline(!!value); 4548 break; 4549 case JSJITCOMPILER_WASM_JIT_OPTIMIZING: 4550 JS::ContextOptionsRef(cx).setWasmIon(!!value); 4551 break; 4552 #ifdef DEBUG 4553 case JSJITCOMPILER_FULL_DEBUG_CHECKS: 4554 jit::JitOptions.fullDebugChecks = !!value; 4555 break; 4556 #endif 4557 default: 4558 break; 4559 } 4560 } 4561 4562 JS_PUBLIC_API bool JS_GetGlobalJitCompilerOption(JSContext* cx, 4563 JSJitCompilerOption opt, 4564 uint32_t* valueOut) { 4565 MOZ_ASSERT(valueOut); 4566 #ifndef JS_CODEGEN_NONE 4567 JSRuntime* rt = cx->runtime(); 4568 switch (opt) { 4569 case JSJITCOMPILER_BASELINE_INTERPRETER_WARMUP_TRIGGER: 4570 *valueOut = jit::JitOptions.baselineInterpreterWarmUpThreshold; 4571 break; 4572 case JSJITCOMPILER_BASELINE_WARMUP_TRIGGER: 4573 *valueOut = jit::JitOptions.baselineJitWarmUpThreshold; 4574 break; 4575 case JSJITCOMPILER_IC_FORCE_MEGAMORPHIC: 4576 *valueOut = jit::JitOptions.forceMegamorphicICs; 4577 break; 4578 case JSJITCOMPILER_ION_NORMAL_WARMUP_TRIGGER: 4579 *valueOut = jit::JitOptions.normalIonWarmUpThreshold; 4580 break; 4581 case JSJITCOMPILER_ION_FORCE_IC: 4582 *valueOut = jit::JitOptions.forceInlineCaches; 4583 break; 4584 case JSJITCOMPILER_ION_CHECK_RANGE_ANALYSIS: 4585 *valueOut = jit::JitOptions.checkRangeAnalysis; 4586 break; 4587 case JSJITCOMPILER_ION_ENABLE: 4588 *valueOut = jit::JitOptions.ion; 4589 break; 4590 case JSJITCOMPILER_ION_FREQUENT_BAILOUT_THRESHOLD: 4591 *valueOut = jit::JitOptions.frequentBailoutThreshold; 4592 break; 4593 case JSJITCOMPILER_BASE_REG_FOR_LOCALS: 4594 *valueOut = uint32_t(jit::JitOptions.baseRegForLocals); 4595 break; 4596 case JSJITCOMPILER_INLINING_BYTECODE_MAX_LENGTH: 4597 *valueOut = jit::JitOptions.smallFunctionMaxBytecodeLength; 4598 break; 4599 case JSJITCOMPILER_BASELINE_INTERPRETER_ENABLE: 4600 *valueOut = jit::JitOptions.baselineInterpreter; 4601 break; 4602 case JSJITCOMPILER_BASELINE_ENABLE: 4603 *valueOut = jit::JitOptions.baselineJit; 4604 break; 4605 case JSJITCOMPILER_NATIVE_REGEXP_ENABLE: 4606 *valueOut = jit::JitOptions.nativeRegExp; 4607 break; 4608 case JSJITCOMPILER_OFFTHREAD_COMPILATION_ENABLE: 4609 *valueOut = rt->canUseOffthreadIonCompilation(); 4610 break; 4611 case JSJITCOMPILER_SPECTRE_INDEX_MASKING: 4612 *valueOut = jit::JitOptions.spectreIndexMasking ? 1 : 0; 4613 break; 4614 case JSJITCOMPILER_SPECTRE_OBJECT_MITIGATIONS: 4615 *valueOut = jit::JitOptions.spectreObjectMitigations ? 1 : 0; 4616 break; 4617 case JSJITCOMPILER_SPECTRE_STRING_MITIGATIONS: 4618 *valueOut = jit::JitOptions.spectreStringMitigations ? 1 : 0; 4619 break; 4620 case JSJITCOMPILER_SPECTRE_VALUE_MASKING: 4621 *valueOut = jit::JitOptions.spectreValueMasking ? 1 : 0; 4622 break; 4623 case JSJITCOMPILER_SPECTRE_JIT_TO_CXX_CALLS: 4624 *valueOut = jit::JitOptions.spectreJitToCxxCalls ? 1 : 0; 4625 break; 4626 case JSJITCOMPILER_WRITE_PROTECT_CODE: 4627 *valueOut = jit::JitOptions.writeProtectCode ? 1 : 0; 4628 break; 4629 case JSJITCOMPILER_WASM_FOLD_OFFSETS: 4630 *valueOut = jit::JitOptions.wasmFoldOffsets ? 1 : 0; 4631 break; 4632 case JSJITCOMPILER_WASM_JIT_BASELINE: 4633 *valueOut = JS::ContextOptionsRef(cx).wasmBaseline() ? 1 : 0; 4634 break; 4635 case JSJITCOMPILER_WASM_JIT_OPTIMIZING: 4636 *valueOut = JS::ContextOptionsRef(cx).wasmIon() ? 1 : 0; 4637 break; 4638 # ifdef DEBUG 4639 case JSJITCOMPILER_FULL_DEBUG_CHECKS: 4640 *valueOut = jit::JitOptions.fullDebugChecks ? 1 : 0; 4641 break; 4642 # endif 4643 default: 4644 return false; 4645 } 4646 #else 4647 switch (opt) { 4648 # ifdef ENABLE_PORTABLE_BASELINE_INTERP 4649 case JSJITCOMPILER_PORTABLE_BASELINE_ENABLE: 4650 *valueOut = jit::JitOptions.portableBaselineInterpreter; 4651 break; 4652 case JSJITCOMPILER_PORTABLE_BASELINE_WARMUP_THRESHOLD: 4653 *valueOut = jit::JitOptions.portableBaselineInterpreterWarmUpThreshold; 4654 break; 4655 # endif 4656 default: 4657 *valueOut = 0; 4658 } 4659 #endif 4660 return true; 4661 } 4662 4663 JS_PUBLIC_API void JS::DisableSpectreMitigationsAfterInit() { 4664 // This is used to turn off Spectre mitigations in pre-allocated child 4665 // processes used for isolated web content. Assert there's a single runtime 4666 // and cancel off-thread compilations, to ensure we're not racing with any 4667 // compilations. 4668 JSContext* cx = TlsContext.get(); 4669 MOZ_RELEASE_ASSERT(cx); 4670 MOZ_RELEASE_ASSERT(JSRuntime::hasSingleLiveRuntime()); 4671 MOZ_RELEASE_ASSERT(cx->runtime()->wasmInstances.lock()->empty()); 4672 4673 CancelOffThreadIonCompile(cx->runtime()); 4674 4675 jit::JitOptions.spectreIndexMasking = false; 4676 jit::JitOptions.spectreObjectMitigations = false; 4677 jit::JitOptions.spectreStringMitigations = false; 4678 jit::JitOptions.spectreValueMasking = false; 4679 jit::JitOptions.spectreJitToCxxCalls = false; 4680 } 4681 4682 /************************************************************************/ 4683 4684 #if !defined(STATIC_EXPORTABLE_JS_API) && !defined(STATIC_JS_API) && \ 4685 defined(XP_WIN) && (defined(MOZ_MEMORY) || !defined(JS_STANDALONE)) 4686 4687 # include "util/WindowsWrapper.h" 4688 4689 /* 4690 * Initialization routine for the JS DLL. 4691 */ 4692 BOOL WINAPI DllMain(HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved) { 4693 return TRUE; 4694 } 4695 4696 #endif 4697 4698 JS_PUBLIC_API bool JS_IndexToId(JSContext* cx, uint32_t index, 4699 MutableHandleId id) { 4700 return IndexToId(cx, index, id); 4701 } 4702 4703 JS_PUBLIC_API bool JS_CharsToId(JSContext* cx, JS::TwoByteChars chars, 4704 MutableHandleId idp) { 4705 JSAtom* atom = AtomizeChars(cx, chars.begin().get(), chars.length()); 4706 if (!atom) { 4707 return false; 4708 } 4709 #ifdef DEBUG 4710 MOZ_ASSERT(!atom->isIndex(), "API misuse: |chars| must not encode an index"); 4711 #endif 4712 idp.set(AtomToId(atom)); 4713 return true; 4714 } 4715 4716 JS_PUBLIC_API bool JS_IsIdentifier(JSContext* cx, HandleString str, 4717 bool* isIdentifier) { 4718 cx->check(str); 4719 4720 JSLinearString* linearStr = str->ensureLinear(cx); 4721 if (!linearStr) { 4722 return false; 4723 } 4724 4725 *isIdentifier = IsIdentifier(linearStr); 4726 return true; 4727 } 4728 4729 JS_PUBLIC_API bool JS_IsIdentifier(const char16_t* chars, size_t length) { 4730 return IsIdentifier(chars, length); 4731 } 4732 4733 namespace JS { 4734 4735 void AutoFilename::reset() { 4736 if (ss_) { 4737 ss_->Release(); 4738 ss_ = nullptr; 4739 } 4740 if (filename_.is<const char*>()) { 4741 filename_.as<const char*>() = nullptr; 4742 } else { 4743 filename_.as<UniqueChars>().reset(); 4744 } 4745 } 4746 4747 void AutoFilename::setScriptSource(js::ScriptSource* p) { 4748 MOZ_ASSERT(!ss_); 4749 MOZ_ASSERT(!get()); 4750 ss_ = p; 4751 if (p) { 4752 p->AddRef(); 4753 setUnowned(p->filename()); 4754 } 4755 } 4756 4757 void AutoFilename::setUnowned(const char* filename) { 4758 MOZ_ASSERT(!get()); 4759 filename_.as<const char*>() = filename ? filename : ""; 4760 } 4761 4762 void AutoFilename::setOwned(UniqueChars&& filename) { 4763 MOZ_ASSERT(!get()); 4764 filename_ = mozilla::AsVariant(std::move(filename)); 4765 } 4766 4767 const char* AutoFilename::get() const { 4768 if (filename_.is<const char*>()) { 4769 return filename_.as<const char*>(); 4770 } 4771 return filename_.as<UniqueChars>().get(); 4772 } 4773 4774 JS_PUBLIC_API bool DescribeScriptedCaller(AutoFilename* filename, JSContext* cx, 4775 uint32_t* lineno, 4776 JS::ColumnNumberOneOrigin* column) { 4777 #ifdef DEBUG 4778 auto noThrow = mozilla::MakeScopeExit([=]() { 4779 MOZ_ASSERT(!cx->isThrowingOutOfMemory() && !cx->isThrowingOverRecursed() && 4780 !cx->isExceptionPending()); 4781 }); 4782 #endif 4783 if (filename) { 4784 filename->reset(); 4785 } 4786 if (lineno) { 4787 *lineno = 0; 4788 } 4789 if (column) { 4790 *column = JS::ColumnNumberOneOrigin(); 4791 } 4792 4793 if (!cx->compartment()) { 4794 return false; 4795 } 4796 4797 NonBuiltinFrameIter i(cx, cx->realm()->principals()); 4798 if (i.done()) { 4799 return false; 4800 } 4801 4802 // If the caller is hidden, the embedding wants us to return false here so 4803 // that it can check its own stack (see HideScriptedCaller). 4804 if (i.activation()->scriptedCallerIsHidden()) { 4805 return false; 4806 } 4807 4808 if (filename) { 4809 if (i.isWasm()) { 4810 // For Wasm, copy out the filename, there is no script source. 4811 UniqueChars copy = DuplicateString(i.filename() ? i.filename() : ""); 4812 if (!copy) { 4813 filename->setUnowned("out of memory"); 4814 } else { 4815 filename->setOwned(std::move(copy)); 4816 } 4817 } else { 4818 // All other frames have a script source to read the filename from. 4819 filename->setScriptSource(i.scriptSource()); 4820 } 4821 } 4822 4823 if (lineno) { 4824 JS::TaggedColumnNumberOneOrigin columnNumber; 4825 *lineno = i.computeLine(&columnNumber); 4826 if (column) { 4827 *column = JS::ColumnNumberOneOrigin(columnNumber.oneOriginValue()); 4828 } 4829 } else if (column) { 4830 JS::TaggedColumnNumberOneOrigin columnNumber; 4831 i.computeLine(&columnNumber); 4832 *column = JS::ColumnNumberOneOrigin(columnNumber.oneOriginValue()); 4833 } 4834 4835 return true; 4836 } 4837 4838 // Fast path to get the activation and realm to use for GetScriptedCallerGlobal. 4839 // If this returns false, the fast path didn't work out and the caller has to 4840 // use the (much slower) NonBuiltinFrameIter path. 4841 // 4842 // The optimization here is that we skip Ion-inlined frames and only look at 4843 // 'outer' frames. That's fine because Ion doesn't inline cross-realm calls. 4844 // However, GetScriptedCallerGlobal has to skip self-hosted frames and Ion 4845 // can inline self-hosted scripts, so we have to be careful: 4846 // 4847 // * When we see a non-self-hosted outer script, it's possible we inlined 4848 // self-hosted scripts into it but that doesn't matter because these scripts 4849 // all have the same realm/global anyway. 4850 // 4851 // * When we see a self-hosted outer script, it's possible we inlined 4852 // non-self-hosted scripts into it, so we have to give up because in this 4853 // case, whether or not to skip the self-hosted frame (to the possibly 4854 // different-realm caller) requires the slow path to handle inlining. Baseline 4855 // and the interpreter don't inline so this only affects Ion. 4856 static bool GetScriptedCallerActivationRealmFast(JSContext* cx, 4857 Activation** activation, 4858 Realm** realm) { 4859 ActivationIterator activationIter(cx); 4860 4861 if (activationIter.done()) { 4862 *activation = nullptr; 4863 *realm = nullptr; 4864 return true; 4865 } 4866 4867 if (activationIter->isJit()) { 4868 jit::JitActivation* act = activationIter->asJit(); 4869 JitFrameIter iter(act); 4870 while (true) { 4871 iter.skipNonScriptedJSFrames(); 4872 if (iter.done()) { 4873 break; 4874 } 4875 4876 if (!iter.isSelfHostedIgnoringInlining()) { 4877 *activation = act; 4878 *realm = iter.realm(); 4879 return true; 4880 } 4881 4882 if (iter.isJSJit() && iter.asJSJit().isIonScripted()) { 4883 // Ion might have inlined non-self-hosted scripts in this 4884 // self-hosted script. 4885 return false; 4886 } 4887 4888 ++iter; 4889 } 4890 } else if (activationIter->isInterpreter()) { 4891 InterpreterActivation* act = activationIter->asInterpreter(); 4892 for (InterpreterFrameIterator iter(act); !iter.done(); ++iter) { 4893 if (!iter.frame()->script()->selfHosted()) { 4894 *activation = act; 4895 *realm = iter.frame()->script()->realm(); 4896 return true; 4897 } 4898 } 4899 } 4900 4901 return false; 4902 } 4903 4904 JS_PUBLIC_API JSObject* GetScriptedCallerGlobal(JSContext* cx) { 4905 Activation* activation; 4906 Realm* realm; 4907 if (GetScriptedCallerActivationRealmFast(cx, &activation, &realm)) { 4908 if (!activation) { 4909 return nullptr; 4910 } 4911 } else { 4912 NonBuiltinFrameIter i(cx); 4913 if (i.done()) { 4914 return nullptr; 4915 } 4916 activation = i.activation(); 4917 realm = i.realm(); 4918 } 4919 4920 MOZ_ASSERT(realm->compartment() == activation->compartment()); 4921 4922 // If the caller is hidden, the embedding wants us to return null here so 4923 // that it can check its own stack (see HideScriptedCaller). 4924 if (activation->scriptedCallerIsHidden()) { 4925 return nullptr; 4926 } 4927 4928 GlobalObject* global = realm->maybeGlobal(); 4929 4930 // No one should be running code in a realm without any live objects, so 4931 // there should definitely be a live global. 4932 MOZ_ASSERT(global); 4933 4934 return global; 4935 } 4936 4937 JS_PUBLIC_API void HideScriptedCaller(JSContext* cx) { 4938 MOZ_ASSERT(cx); 4939 4940 // If there's no accessible activation on the stack, we'll return null from 4941 // DescribeScriptedCaller anyway, so there's no need to annotate anything. 4942 Activation* act = cx->activation(); 4943 if (!act) { 4944 return; 4945 } 4946 act->hideScriptedCaller(); 4947 } 4948 4949 JS_PUBLIC_API void UnhideScriptedCaller(JSContext* cx) { 4950 Activation* act = cx->activation(); 4951 if (!act) { 4952 return; 4953 } 4954 act->unhideScriptedCaller(); 4955 } 4956 4957 } /* namespace JS */ 4958 4959 #ifdef JS_DEBUG 4960 JS_PUBLIC_API void JS::detail::AssertArgumentsAreSane(JSContext* cx, 4961 HandleValue value) { 4962 AssertHeapIsIdle(); 4963 CHECK_THREAD(cx); 4964 cx->check(value); 4965 } 4966 #endif /* JS_DEBUG */ 4967 4968 bool JS::IsWasmModuleObject(HandleObject obj) { 4969 return obj->canUnwrapAs<WasmModuleObject>(); 4970 } 4971 4972 JS_PUBLIC_API RefPtr<JS::WasmModule> JS::GetWasmModule(HandleObject obj) { 4973 MOZ_ASSERT(JS::IsWasmModuleObject(obj)); 4974 WasmModuleObject& mobj = obj->unwrapAs<WasmModuleObject>(); 4975 return const_cast<wasm::Module*>(&mobj.module()); 4976 } 4977 4978 JS_PUBLIC_API void JS::SetProcessLargeAllocationFailureCallback( 4979 JS::LargeAllocationFailureCallback lafc) { 4980 MOZ_ASSERT(!OnLargeAllocationFailure); 4981 OnLargeAllocationFailure = lafc; 4982 } 4983 4984 JS_PUBLIC_API void JS::SetOutOfMemoryCallback(JSContext* cx, 4985 OutOfMemoryCallback cb, 4986 void* data) { 4987 cx->runtime()->oomCallback = cb; 4988 cx->runtime()->oomCallbackData = data; 4989 } 4990 4991 JS_PUBLIC_API void JS::SetShadowRealmInitializeGlobalCallback( 4992 JSContext* cx, JS::GlobalInitializeCallback callback) { 4993 cx->runtime()->shadowRealmInitializeGlobalCallback = callback; 4994 } 4995 4996 JS_PUBLIC_API void JS::SetShadowRealmGlobalCreationCallback( 4997 JSContext* cx, JS::GlobalCreationCallback callback) { 4998 cx->runtime()->shadowRealmGlobalCreationCallback = callback; 4999 } 5000 5001 JS_PUBLIC_API bool JS::SetLoggingInterface(LoggingInterface& iface) { 5002 return js::LogModule::initializeAll(iface); 5003 } 5004 5005 JS::FirstSubsumedFrame::FirstSubsumedFrame( 5006 JSContext* cx, bool ignoreSelfHostedFrames /* = true */) 5007 : JS::FirstSubsumedFrame(cx, cx->realm()->principals(), 5008 ignoreSelfHostedFrames) {} 5009 5010 JS_PUBLIC_API bool JS::CaptureCurrentStack( 5011 JSContext* cx, JS::MutableHandleObject stackp, 5012 JS::StackCapture&& capture /* = JS::StackCapture(JS::AllFrames()) */, 5013 JS::HandleObject startAt /* = nullptr*/) { 5014 AssertHeapIsIdle(); 5015 CHECK_THREAD(cx); 5016 MOZ_RELEASE_ASSERT(cx->realm()); 5017 5018 Realm* realm = cx->realm(); 5019 Rooted<SavedFrame*> frame(cx); 5020 if (!realm->savedStacks().saveCurrentStack(cx, &frame, std::move(capture), 5021 startAt)) { 5022 return false; 5023 } 5024 stackp.set(frame.get()); 5025 return true; 5026 } 5027 5028 JS_PUBLIC_API bool JS::IsAsyncStackCaptureEnabledForRealm(JSContext* cx) { 5029 if (!cx->options().asyncStack()) { 5030 return false; 5031 } 5032 5033 if (!cx->options().asyncStackCaptureDebuggeeOnly() || 5034 cx->realm()->isDebuggee()) { 5035 return true; 5036 } 5037 5038 return cx->realm()->isAsyncStackCapturingEnabled; 5039 } 5040 5041 JS_PUBLIC_API bool JS::CopyAsyncStack(JSContext* cx, 5042 JS::HandleObject asyncStack, 5043 JS::HandleString asyncCause, 5044 JS::MutableHandleObject stackp, 5045 const Maybe<size_t>& maxFrameCount) { 5046 AssertHeapIsIdle(); 5047 CHECK_THREAD(cx); 5048 MOZ_RELEASE_ASSERT(cx->realm()); 5049 5050 js::AssertObjectIsSavedFrameOrWrapper(cx, asyncStack); 5051 Realm* realm = cx->realm(); 5052 Rooted<SavedFrame*> frame(cx); 5053 if (!realm->savedStacks().copyAsyncStack(cx, asyncStack, asyncCause, &frame, 5054 maxFrameCount)) { 5055 return false; 5056 } 5057 stackp.set(frame.get()); 5058 return true; 5059 } 5060 5061 JS_PUBLIC_API Zone* JS::GetObjectZone(JSObject* obj) { 5062 Zone* zone = obj->zone(); 5063 5064 // Check zone pointer is valid and not a poison value. See bug 1878421. 5065 MOZ_RELEASE_ASSERT(zone->runtimeFromMainThread()); 5066 5067 return zone; 5068 } 5069 5070 JS_PUBLIC_API Zone* JS::GetTenuredGCThingZone(GCCellPtr thing) { 5071 js::gc::Cell* cell = thing.asCell(); 5072 MOZ_ASSERT(!js::gc::IsInsideNursery(cell)); 5073 Zone* zone = js::gc::detail::GetTenuredGCThingZone(cell); 5074 5075 // Check zone pointer is valid and not a poison value. See bug 1878421. 5076 MOZ_RELEASE_ASSERT(zone->runtimeFromMainThread()); 5077 5078 return zone; 5079 } 5080 5081 JS_PUBLIC_API Zone* JS::GetNurseryCellZone(gc::Cell* cell) { 5082 return cell->nurseryZone(); 5083 } 5084 5085 JS_PUBLIC_API JS::TraceKind JS::GCThingTraceKind(void* thing) { 5086 MOZ_ASSERT(thing); 5087 return static_cast<js::gc::Cell*>(thing)->getTraceKind(); 5088 } 5089 5090 JS_PUBLIC_API void js::SetStackFormat(JSContext* cx, js::StackFormat format) { 5091 cx->runtime()->setStackFormat(format); 5092 } 5093 5094 JS_PUBLIC_API js::StackFormat js::GetStackFormat(JSContext* cx) { 5095 return cx->runtime()->stackFormat(); 5096 } 5097 5098 JS_PUBLIC_API void JS::SetMeasuringExecutionTimeEnabled(JSContext* cx, 5099 bool value) { 5100 cx->setMeasuringExecutionTimeEnabled(value); 5101 } 5102 5103 JS_PUBLIC_API JS::JSTimers JS::GetJSTimers(JSContext* cx) { 5104 return cx->realm()->timers; 5105 } 5106 5107 namespace js { 5108 5109 JS_PUBLIC_API void NoteIntentionalCrash() { 5110 #ifdef __linux__ 5111 static bool* addr = 5112 reinterpret_cast<bool*>(dlsym(RTLD_DEFAULT, "gBreakpadInjectorEnabled")); 5113 if (addr) { 5114 *addr = false; 5115 } 5116 #endif 5117 } 5118 5119 #ifdef DEBUG 5120 bool gSupportDifferentialTesting = false; 5121 #endif // DEBUG 5122 5123 } // namespace js 5124 5125 #ifdef DEBUG 5126 5127 JS_PUBLIC_API void JS::SetSupportDifferentialTesting(bool value) { 5128 js::gSupportDifferentialTesting = value; 5129 } 5130 5131 #endif // DEBUG