jsfriendapi.cpp (26766B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 * This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "jsfriendapi.h" 8 9 #include "mozilla/Maybe.h" 10 #include "mozilla/PodOperations.h" 11 #include "mozilla/TimeStamp.h" 12 13 #include <stdint.h> 14 15 #include "builtin/BigInt.h" 16 #include "builtin/MapObject.h" 17 #include "builtin/TestingFunctions.h" 18 #include "frontend/FrontendContext.h" // FrontendContext 19 #include "gc/PublicIterators.h" 20 #include "gc/WeakMap.h" 21 #include "js/ColumnNumber.h" // JS::LimitedColumnNumberOneOrigin 22 #include "js/experimental/CodeCoverage.h" 23 #include "js/experimental/CTypes.h" // JS::AutoCTypesActivityCallback, JS::SetCTypesActivityCallback 24 #include "js/experimental/Intl.h" // JS::AddMoz{DateTimeFormat,DisplayNames}Constructor 25 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_* 26 #include "js/friend/StackLimits.h" // JS_STACK_GROWTH_DIRECTION 27 #include "js/friend/WindowProxy.h" // js::ToWindowIfWindowProxy 28 #include "js/HashTable.h" 29 #include "js/Object.h" // JS::GetClass 30 #include "js/PropertyAndElement.h" // JS_DefineProperty 31 #include "js/Proxy.h" 32 #include "js/Stack.h" // JS::NativeStackLimitMax 33 #include "js/String.h" // JS::detail::StringToLinearStringSlow 34 #include "js/Wrapper.h" 35 #include "proxy/DeadObjectProxy.h" 36 #include "util/Poison.h" 37 #include "vm/ArgumentsObject.h" 38 #include "vm/BooleanObject.h" 39 #include "vm/DateObject.h" 40 #include "vm/ErrorObject.h" 41 #include "vm/Interpreter.h" 42 #include "vm/JSContext.h" 43 #include "vm/JSObject.h" 44 #include "vm/NumberObject.h" 45 #include "vm/PlainObject.h" // js::PlainObject 46 #include "vm/PromiseObject.h" // js::PromiseObject 47 #include "vm/Realm.h" 48 #include "vm/StringObject.h" 49 #include "vm/Watchtower.h" 50 #include "vm/WrapperObject.h" 51 #include "gc/Marking-inl.h" 52 #include "vm/Compartment-inl.h" // JS::Compartment::wrap 53 #include "vm/JSObject-inl.h" 54 #include "vm/JSScript-inl.h" 55 #include "vm/Realm-inl.h" 56 57 using namespace js; 58 59 using mozilla::PodArrayZero; 60 61 JS::RootingContext::RootingContext(js::Nursery* nursery) 62 : nursery_(nursery), zone_(nullptr), realm_(nullptr) { 63 for (auto& listHead : stackRoots_) { 64 listHead = nullptr; 65 } 66 for (auto& listHead : autoGCRooters_) { 67 listHead = nullptr; 68 } 69 70 #if JS_STACK_GROWTH_DIRECTION > 0 71 for (int i = 0; i < StackKindCount; i++) { 72 nativeStackLimit[i] = JS::NativeStackLimitMax; 73 } 74 #else 75 static_assert(JS::NativeStackLimitMax == 0); 76 PodArrayZero(nativeStackLimit); 77 #endif 78 } 79 80 JS_PUBLIC_API void JS_SetGrayGCRootsTracer(JSContext* cx, 81 JSGrayRootsTracer traceOp, 82 void* data) { 83 cx->runtime()->gc.setGrayRootsTracer(traceOp, data); 84 } 85 86 JS_PUBLIC_API JSObject* JS_FindCompilationScope(JSContext* cx, 87 HandleObject objArg) { 88 cx->check(objArg); 89 90 RootedObject obj(cx, objArg); 91 92 /* 93 * We unwrap wrappers here. This is a little weird, but it's what's being 94 * asked of us. 95 */ 96 if (obj->is<WrapperObject>()) { 97 obj = UncheckedUnwrap(obj); 98 } 99 100 /* 101 * Get the Window if `obj` is a WindowProxy so that we compile in the 102 * correct (global) scope. 103 */ 104 return ToWindowIfWindowProxy(obj); 105 } 106 107 JS_PUBLIC_API JSFunction* JS_GetObjectFunction(JSObject* obj) { 108 if (obj->is<JSFunction>()) { 109 return &obj->as<JSFunction>(); 110 } 111 return nullptr; 112 } 113 114 JS_PUBLIC_API JSObject* JS_NewObjectWithoutMetadata( 115 JSContext* cx, const JSClass* clasp, JS::Handle<JSObject*> proto) { 116 cx->check(proto); 117 AutoSuppressAllocationMetadataBuilder suppressMetadata(cx); 118 return JS_NewObjectWithGivenProto(cx, clasp, proto); 119 } 120 121 JS_PUBLIC_API bool JS::GetIsSecureContext(JS::Realm* realm) { 122 return realm->creationOptions().secureContext(); 123 } 124 125 JS_PUBLIC_API JSPrincipals* JS::GetRealmPrincipals(JS::Realm* realm) { 126 return realm->principals(); 127 } 128 129 JS_PUBLIC_API bool JS::GetDebuggerObservesWasm(JS::Realm* realm) { 130 return realm->debuggerObservesAsmJS(); 131 } 132 133 JS_PUBLIC_API void JS::SetRealmPrincipals(JS::Realm* realm, 134 JSPrincipals* principals) { 135 // Short circuit if there's no change. 136 if (principals == realm->principals()) { 137 return; 138 } 139 140 // We'd like to assert that our new principals is always same-origin 141 // with the old one, but JSPrincipals doesn't give us a way to do that. 142 // But we can at least assert that we're not switching between system 143 // and non-system. 144 const JSPrincipals* trusted = 145 realm->runtimeFromMainThread()->trustedPrincipals(); 146 bool isSystem = principals && principals == trusted; 147 MOZ_RELEASE_ASSERT(realm->isSystem() == isSystem); 148 149 // Clear out the old principals, if any. 150 if (realm->principals()) { 151 JS_DropPrincipals(TlsContext.get(), realm->principals()); 152 realm->setPrincipals(nullptr); 153 } 154 155 // Set up the new principals. 156 if (principals) { 157 JS_HoldPrincipals(principals); 158 realm->setPrincipals(principals); 159 } 160 } 161 162 JS_PUBLIC_API JSPrincipals* JS_GetScriptPrincipals(JSScript* script) { 163 return script->principals(); 164 } 165 166 JS_PUBLIC_API bool JS_ScriptHasMutedErrors(JSScript* script) { 167 return script->mutedErrors(); 168 } 169 170 JS_PUBLIC_API bool JS_WrapPropertyDescriptor( 171 JSContext* cx, JS::MutableHandle<JS::PropertyDescriptor> desc) { 172 return cx->compartment()->wrap(cx, desc); 173 } 174 175 JS_PUBLIC_API bool JS_WrapPropertyDescriptor( 176 JSContext* cx, 177 JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> desc) { 178 return cx->compartment()->wrap(cx, desc); 179 } 180 181 JS_PUBLIC_API void JS_TraceShapeCycleCollectorChildren(JS::CallbackTracer* trc, 182 JS::GCCellPtr shape) { 183 MOZ_ASSERT(shape.is<Shape>()); 184 TraceCycleCollectorChildren(trc, &shape.as<Shape>()); 185 } 186 187 static bool DefineHelpProperty(JSContext* cx, HandleObject obj, 188 const char* prop, const char* value) { 189 Rooted<JSAtom*> atom(cx, Atomize(cx, value, strlen(value))); 190 if (!atom) { 191 return false; 192 } 193 return JS_DefineProperty(cx, obj, prop, atom, 194 JSPROP_READONLY | JSPROP_PERMANENT); 195 } 196 197 JS_PUBLIC_API bool JS_DefineFunctionsWithHelp( 198 JSContext* cx, HandleObject obj, const JSFunctionSpecWithHelp* fs) { 199 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 200 201 CHECK_THREAD(cx); 202 cx->check(obj); 203 for (; fs->name; fs++) { 204 JSAtom* atom = Atomize(cx, fs->name, strlen(fs->name)); 205 if (!atom) { 206 return false; 207 } 208 209 Rooted<jsid> id(cx, AtomToId(atom)); 210 RootedFunction fun(cx, DefineFunction(cx, obj, id, fs->call, fs->nargs, 211 fs->flags | JSPROP_RESOLVING)); 212 if (!fun) { 213 return false; 214 } 215 216 if (fs->jitInfo) { 217 fun->setJitInfo(fs->jitInfo); 218 } 219 220 if (fs->usage) { 221 if (!DefineHelpProperty(cx, fun, "usage", fs->usage)) { 222 return false; 223 } 224 } 225 226 if (fs->help) { 227 if (!DefineHelpProperty(cx, fun, "help", fs->help)) { 228 return false; 229 } 230 } 231 } 232 233 return true; 234 } 235 236 JS_PUBLIC_API bool JS::GetBuiltinClass(JSContext* cx, HandleObject obj, 237 js::ESClass* cls) { 238 if (MOZ_UNLIKELY(obj->is<ProxyObject>())) { 239 return Proxy::getBuiltinClass(cx, obj, cls); 240 } 241 242 if (obj->is<PlainObject>()) { 243 *cls = ESClass::Object; 244 } else if (obj->is<ArrayObject>()) { 245 *cls = ESClass::Array; 246 } else if (obj->is<NumberObject>()) { 247 *cls = ESClass::Number; 248 } else if (obj->is<StringObject>()) { 249 *cls = ESClass::String; 250 } else if (obj->is<BooleanObject>()) { 251 *cls = ESClass::Boolean; 252 } else if (obj->is<RegExpObject>()) { 253 *cls = ESClass::RegExp; 254 } else if (obj->is<ArrayBufferObject>()) { 255 *cls = ESClass::ArrayBuffer; 256 } else if (obj->is<SharedArrayBufferObject>()) { 257 *cls = ESClass::SharedArrayBuffer; 258 } else if (obj->is<DateObject>()) { 259 *cls = ESClass::Date; 260 } else if (obj->is<SetObject>()) { 261 *cls = ESClass::Set; 262 } else if (obj->is<MapObject>()) { 263 *cls = ESClass::Map; 264 } else if (obj->is<PromiseObject>()) { 265 *cls = ESClass::Promise; 266 } else if (obj->is<MapIteratorObject>()) { 267 *cls = ESClass::MapIterator; 268 } else if (obj->is<SetIteratorObject>()) { 269 *cls = ESClass::SetIterator; 270 } else if (obj->is<ArgumentsObject>()) { 271 *cls = ESClass::Arguments; 272 } else if (obj->is<ErrorObject>()) { 273 *cls = ESClass::Error; 274 } else if (obj->is<BigIntObject>()) { 275 *cls = ESClass::BigInt; 276 } else if (obj->is<JSFunction>()) { 277 *cls = ESClass::Function; 278 } else { 279 *cls = ESClass::Other; 280 } 281 282 return true; 283 } 284 285 JS_PUBLIC_API bool js::IsArgumentsObject(HandleObject obj) { 286 return obj->is<ArgumentsObject>(); 287 } 288 289 JS_PUBLIC_API JS::Zone* js::GetRealmZone(JS::Realm* realm) { 290 return realm->zone(); 291 } 292 293 JS_PUBLIC_API bool js::IsSystemCompartment(JS::Compartment* comp) { 294 // Realms in the same compartment must either all be system realms or 295 // non-system realms. We assert this in NewRealm and SetRealmPrincipals, 296 // but do an extra sanity check here. 297 MOZ_ASSERT(comp->realms()[0]->isSystem() == 298 comp->realms().back()->isSystem()); 299 return comp->realms()[0]->isSystem(); 300 } 301 302 JS_PUBLIC_API bool js::IsSystemRealm(JS::Realm* realm) { 303 return realm->isSystem(); 304 } 305 306 JS_PUBLIC_API bool js::IsSystemZone(Zone* zone) { return zone->isSystemZone(); } 307 308 JS_PUBLIC_API bool js::IsFunctionObject(JSObject* obj) { 309 return obj->is<JSFunction>(); 310 } 311 312 JS_PUBLIC_API bool js::IsSavedFrame(JSObject* obj) { 313 return obj->is<SavedFrame>(); 314 } 315 316 JS_PUBLIC_API bool js::UninlinedIsCrossCompartmentWrapper(const JSObject* obj) { 317 return js::IsCrossCompartmentWrapper(obj); 318 } 319 320 JS_PUBLIC_API void js::AssertSameCompartment(JSContext* cx, JSObject* obj) { 321 cx->check(obj); 322 } 323 324 JS_PUBLIC_API void js::AssertSameCompartment(JSContext* cx, JS::HandleValue v) { 325 cx->check(v); 326 } 327 328 #ifdef DEBUG 329 JS_PUBLIC_API void js::AssertSameCompartment(JSObject* objA, JSObject* objB) { 330 MOZ_ASSERT(objA->compartment() == objB->compartment()); 331 } 332 #endif 333 334 JS_PUBLIC_API void js::NotifyAnimationActivity(JSObject* obj) { 335 MOZ_ASSERT(obj->is<GlobalObject>()); 336 337 auto timeNow = mozilla::TimeStamp::Now(); 338 obj->as<GlobalObject>().realm()->lastAnimationTime = timeNow; 339 obj->runtimeFromMainThread()->lastAnimationTime = timeNow; 340 } 341 342 JS_PUBLIC_API bool js::IsObjectInContextCompartment(JSObject* obj, 343 const JSContext* cx) { 344 return obj->compartment() == cx->compartment(); 345 } 346 347 JS_PUBLIC_API JS::StackKind 348 js::AutoCheckRecursionLimit::stackKindForCurrentPrincipal(JSContext* cx) const { 349 return cx->stackKindForCurrentPrincipal(); 350 } 351 352 JS::NativeStackLimit AutoCheckRecursionLimit::getStackLimit( 353 FrontendContext* fc) const { 354 return fc->stackLimit(); 355 } 356 357 JS_PUBLIC_API JSFunction* js::DefineFunctionWithReserved( 358 JSContext* cx, JSObject* objArg, const char* name, JSNative call, 359 unsigned nargs, unsigned attrs) { 360 RootedObject obj(cx, objArg); 361 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 362 CHECK_THREAD(cx); 363 cx->check(obj); 364 JSAtom* atom = Atomize(cx, name, strlen(name)); 365 if (!atom) { 366 return nullptr; 367 } 368 Rooted<jsid> id(cx, AtomToId(atom)); 369 return DefineFunction(cx, obj, id, call, nargs, attrs, 370 gc::AllocKind::FUNCTION_EXTENDED); 371 } 372 373 JS_PUBLIC_API JSFunction* js::NewFunctionWithReserved(JSContext* cx, 374 JSNative native, 375 unsigned nargs, 376 unsigned flags, 377 const char* name) { 378 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 379 380 CHECK_THREAD(cx); 381 382 Rooted<JSAtom*> atom(cx); 383 if (name) { 384 atom = Atomize(cx, name, strlen(name)); 385 if (!atom) { 386 return nullptr; 387 } 388 } 389 390 return (flags & JSFUN_CONSTRUCTOR) 391 ? NewNativeConstructor(cx, native, nargs, atom, 392 gc::AllocKind::FUNCTION_EXTENDED) 393 : NewNativeFunction(cx, native, nargs, atom, 394 gc::AllocKind::FUNCTION_EXTENDED); 395 } 396 397 JS_PUBLIC_API JSFunction* js::NewFunctionByIdWithReserved( 398 JSContext* cx, JSNative native, unsigned nargs, unsigned flags, jsid id) { 399 MOZ_ASSERT(id.isAtom()); 400 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 401 CHECK_THREAD(cx); 402 cx->check(id); 403 404 Rooted<JSAtom*> atom(cx, id.toAtom()); 405 return (flags & JSFUN_CONSTRUCTOR) 406 ? NewNativeConstructor(cx, native, nargs, atom, 407 gc::AllocKind::FUNCTION_EXTENDED) 408 : NewNativeFunction(cx, native, nargs, atom, 409 gc::AllocKind::FUNCTION_EXTENDED); 410 } 411 412 JS_PUBLIC_API JSFunction* js::NewFunctionByIdWithReservedAndProto( 413 JSContext* cx, JSNative native, HandleObject proto, unsigned nargs, 414 unsigned flags, jsid id) { 415 MOZ_ASSERT(id.isAtom()); 416 MOZ_ASSERT(!cx->zone()->isAtomsZone()); 417 MOZ_ASSERT(native); 418 CHECK_THREAD(cx); 419 cx->check(id); 420 421 Rooted<JSAtom*> atom(cx, id.toAtom()); 422 FunctionFlags funflags = (flags & JSFUN_CONSTRUCTOR) 423 ? FunctionFlags::NATIVE_CTOR 424 : FunctionFlags::NATIVE_FUN; 425 return NewFunctionWithProto(cx, native, nargs, funflags, nullptr, atom, proto, 426 gc::AllocKind::FUNCTION_EXTENDED, TenuredObject); 427 } 428 429 JS_PUBLIC_API const Value& js::GetFunctionNativeReserved(JSObject* fun, 430 size_t which) { 431 MOZ_ASSERT(fun->as<JSFunction>().isNativeFun()); 432 return fun->as<JSFunction>().getExtendedSlot(which); 433 } 434 435 JS_PUBLIC_API void js::SetFunctionNativeReserved(JSObject* fun, size_t which, 436 const Value& val) { 437 MOZ_ASSERT(fun->as<JSFunction>().isNativeFun()); 438 MOZ_ASSERT_IF(val.isObject(), 439 val.toObject().compartment() == fun->compartment()); 440 fun->as<JSFunction>().setExtendedSlot(which, val); 441 } 442 443 JS_PUBLIC_API bool js::FunctionHasNativeReserved(JSObject* fun) { 444 MOZ_ASSERT(fun->as<JSFunction>().isNativeFun()); 445 return fun->as<JSFunction>().isExtended(); 446 } 447 448 bool js::GetObjectProto(JSContext* cx, JS::Handle<JSObject*> obj, 449 JS::MutableHandle<JSObject*> proto) { 450 cx->check(obj); 451 452 if (obj->is<ProxyObject>()) { 453 return JS_GetPrototype(cx, obj, proto); 454 } 455 456 proto.set(obj->staticPrototype()); 457 return true; 458 } 459 460 JS_PUBLIC_API JSObject* js::GetStaticPrototype(JSObject* obj) { 461 MOZ_ASSERT(obj->hasStaticPrototype()); 462 return obj->staticPrototype(); 463 } 464 465 JS_PUBLIC_API bool js::GetRealmOriginalEval(JSContext* cx, 466 MutableHandleObject eval) { 467 eval.set(&cx->global()->getEvalFunction()); 468 return true; 469 } 470 471 void JS::detail::SetReservedSlotWithBarrier(JSObject* obj, size_t slot, 472 const Value& value) { 473 if (obj->is<ProxyObject>()) { 474 obj->as<ProxyObject>().setReservedSlot(slot, value); 475 } else { 476 // Note: We do not currently support watching reserved object slots for 477 // property modification. 478 obj->as<NativeObject>().setSlot(slot, value); 479 } 480 } 481 482 void js::SetPreserveWrapperCallbacks( 483 JSContext* cx, PreserveWrapperCallback preserveWrapper, 484 HasReleasedWrapperCallback hasReleasedWrapper) { 485 cx->runtime()->preserveWrapperCallback = preserveWrapper; 486 cx->runtime()->hasReleasedWrapperCallback = hasReleasedWrapper; 487 } 488 489 void js::CommitPendingWrapperPreservations(JSContext* cx) { 490 cx->runtime()->commitPendingWrapperPreservations(); 491 } 492 493 JS_PUBLIC_API unsigned JS_PCToLineNumber( 494 JSScript* script, jsbytecode* pc, 495 JS::LimitedColumnNumberOneOrigin* columnp) { 496 return PCToLineNumber(script, pc, columnp); 497 } 498 499 JS_PUBLIC_API bool JS_IsDeadWrapper(JSObject* obj) { 500 return IsDeadProxyObject(obj); 501 } 502 503 JS_PUBLIC_API JSObject* JS_NewDeadWrapper(JSContext* cx, JSObject* origObj) { 504 return NewDeadProxyObject(cx, origObj); 505 } 506 507 void js::TraceWeakMaps(WeakMapTracer* trc) { 508 WeakMapBase::traceAllMappings(trc); 509 } 510 511 extern JS_PUBLIC_API bool js::AreGCGrayBitsValid(JSRuntime* rt) { 512 return rt->gc.areGrayBitsValid(); 513 } 514 515 JS_PUBLIC_API bool js::ZoneGlobalsAreAllGray(JS::Zone* zone) { 516 for (RealmsInZoneIter realm(zone); !realm.done(); realm.next()) { 517 JSObject* obj = realm->unsafeUnbarrieredMaybeGlobal(); 518 if (!obj || !JS::ObjectIsMarkedGray(obj)) { 519 return false; 520 } 521 } 522 return true; 523 } 524 525 JS_PUBLIC_API bool js::IsCompartmentZoneSweepingOrCompacting( 526 JS::Compartment* comp) { 527 MOZ_ASSERT(comp); 528 return comp->zone()->isGCSweepingOrCompacting(); 529 } 530 531 JS_PUBLIC_API void js::TraceGrayWrapperTargets(JSTracer* trc, Zone* zone) { 532 JS::AutoSuppressGCAnalysis nogc; 533 534 for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) { 535 for (Compartment::ObjectWrapperEnum e(comp); !e.empty(); e.popFront()) { 536 JSObject* target = e.front().key(); 537 if (target->isMarkedGray()) { 538 TraceManuallyBarrieredEdge(trc, &target, "gray CCW target"); 539 MOZ_ASSERT(target == e.front().key()); 540 } 541 } 542 } 543 } 544 545 JSLinearString* JS::detail::StringToLinearStringSlow(JSContext* cx, 546 JSString* str) { 547 return str->ensureLinear(cx); 548 } 549 550 static bool CopyProxyObject(JSContext* cx, Handle<ProxyObject*> from, 551 Handle<ProxyObject*> to) { 552 MOZ_ASSERT(from->getClass() == to->getClass()); 553 554 if (from->is<WrapperObject>() && 555 (Wrapper::wrapperHandler(from)->flags() & Wrapper::CROSS_COMPARTMENT)) { 556 to->setCrossCompartmentPrivate(GetProxyPrivate(from)); 557 } else { 558 RootedValue v(cx, GetProxyPrivate(from)); 559 if (!cx->compartment()->wrap(cx, &v)) { 560 return false; 561 } 562 to->setSameCompartmentPrivate(v); 563 } 564 565 MOZ_ASSERT(from->numReservedSlots() == to->numReservedSlots()); 566 567 RootedValue v(cx); 568 for (size_t n = 0; n < from->numReservedSlots(); n++) { 569 v = GetProxyReservedSlot(from, n); 570 if (!cx->compartment()->wrap(cx, &v)) { 571 return false; 572 } 573 SetProxyReservedSlot(to, n, v); 574 } 575 576 return true; 577 } 578 579 JS_PUBLIC_API JSObject* JS_CloneObject(JSContext* cx, HandleObject obj, 580 HandleObject proto) { 581 // |obj| might be in a different compartment. 582 cx->check(proto); 583 584 if (!obj->is<NativeObject>() && !obj->is<ProxyObject>()) { 585 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 586 JSMSG_CANT_CLONE_OBJECT); 587 return nullptr; 588 } 589 590 RootedObject clone(cx); 591 if (obj->is<NativeObject>()) { 592 clone = NewObjectWithGivenProto(cx, obj->getClass(), proto); 593 if (!clone) { 594 return nullptr; 595 } 596 597 if (clone->is<JSFunction>() && obj->compartment() != clone->compartment()) { 598 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, 599 JSMSG_CANT_CLONE_OBJECT); 600 return nullptr; 601 } 602 } else { 603 auto* handler = GetProxyHandler(obj); 604 clone = ProxyObject::New(cx, handler, JS::NullHandleValue, 605 AsTaggedProto(proto), obj->getClass()); 606 if (!clone) { 607 return nullptr; 608 } 609 610 if (!CopyProxyObject(cx, obj.as<ProxyObject>(), clone.as<ProxyObject>())) { 611 return nullptr; 612 } 613 } 614 615 MOZ_ASSERT(gc::GetFinalizeKind(obj->allocKind()) == 616 gc::GetFinalizeKind(clone->allocKind())); 617 618 return clone; 619 } 620 621 extern JS_PUBLIC_API bool JS::ForceLexicalInitialization(JSContext* cx, 622 HandleObject obj) { 623 AssertHeapIsIdle(); 624 CHECK_THREAD(cx); 625 cx->check(obj); 626 627 bool initializedAny = false; 628 NativeObject* nobj = &obj->as<NativeObject>(); 629 630 for (ShapePropertyIter<NoGC> iter(nobj->shape()); !iter.done(); iter++) { 631 Value v = nobj->getSlot(iter->slot()); 632 if (iter->isDataProperty() && v.isMagic() && 633 v.whyMagic() == JS_UNINITIALIZED_LEXICAL) { 634 nobj->setSlot(iter->slot(), UndefinedValue()); 635 initializedAny = true; 636 } 637 } 638 return initializedAny; 639 } 640 641 extern JS_PUBLIC_API bool JS::IsGCPoisoning() { 642 #ifdef JS_GC_ALLOW_EXTRA_POISONING 643 return JS::Prefs::extra_gc_poisoning(); 644 #else 645 return false; 646 #endif 647 } 648 649 JS_PUBLIC_API void JS::NotifyGCRootsRemoved(JSContext* cx) { 650 cx->runtime()->gc.notifyRootsRemoved(); 651 } 652 653 JS_PUBLIC_API JS::Realm* js::GetAnyRealmInZone(JS::Zone* zone) { 654 if (zone->isAtomsZone()) { 655 return nullptr; 656 } 657 658 RealmsInZoneIter realm(zone); 659 MOZ_ASSERT(!realm.done()); 660 return realm.get(); 661 } 662 663 JS_PUBLIC_API bool js::IsSharableCompartment(JS::Compartment* comp) { 664 // If this compartment has nuked outgoing wrappers (because all its globals 665 // got nuked), we won't be able to create any useful CCWs out of it in the 666 // future, and so we shouldn't use it for any new globals. 667 if (comp->nukedOutgoingWrappers) { 668 return false; 669 } 670 671 // If this compartment has no live globals, it might be in the middle of being 672 // GCed. Don't create any new Realms inside. There's no point to doing that 673 // anyway, since the idea would be to avoid CCWs from existing Realms in the 674 // compartment to the new Realm, and there are no existing Realms. 675 if (!CompartmentHasLiveGlobal(comp)) { 676 return false; 677 } 678 679 // Good to go. 680 return true; 681 } 682 683 JS_PUBLIC_API JSObject* js::GetTestingFunctions(JSContext* cx) { 684 RootedObject obj(cx, JS_NewPlainObject(cx)); 685 if (!obj) { 686 return nullptr; 687 } 688 689 if (!DefineTestingFunctions(cx, obj, false, false)) { 690 return nullptr; 691 } 692 693 return obj; 694 } 695 696 JS_PUBLIC_API void js::SetDOMCallbacks(JSContext* cx, 697 const DOMCallbacks* callbacks) { 698 cx->runtime()->DOMcallbacks = callbacks; 699 } 700 701 JS_PUBLIC_API const DOMCallbacks* js::GetDOMCallbacks(JSContext* cx) { 702 return cx->runtime()->DOMcallbacks; 703 } 704 705 JS_PUBLIC_API void js::PrepareScriptEnvironmentAndInvoke( 706 JSContext* cx, HandleObject global, 707 ScriptEnvironmentPreparer::Closure& closure) { 708 MOZ_ASSERT(!cx->isExceptionPending()); 709 MOZ_ASSERT(global->is<GlobalObject>()); 710 711 MOZ_RELEASE_ASSERT( 712 cx->runtime()->scriptEnvironmentPreparer, 713 "Embedding needs to set a scriptEnvironmentPreparer callback"); 714 715 cx->runtime()->scriptEnvironmentPreparer->invoke(global, closure); 716 } 717 718 JS_PUBLIC_API void js::SetScriptEnvironmentPreparer( 719 JSContext* cx, ScriptEnvironmentPreparer* preparer) { 720 cx->runtime()->scriptEnvironmentPreparer = preparer; 721 } 722 723 JS_PUBLIC_API void JS::SetCTypesActivityCallback(JSContext* cx, 724 CTypesActivityCallback cb) { 725 cx->runtime()->ctypesActivityCallback = cb; 726 } 727 728 JS::AutoCTypesActivityCallback::AutoCTypesActivityCallback( 729 JSContext* cx, CTypesActivityType beginType, CTypesActivityType endType) 730 : cx(cx), 731 callback(cx->runtime()->ctypesActivityCallback), 732 endType(endType) { 733 if (callback) { 734 callback(cx, beginType); 735 } 736 } 737 738 JS_PUBLIC_API void js::SetAllocationMetadataBuilder( 739 JSContext* cx, const AllocationMetadataBuilder* callback) { 740 cx->realm()->setAllocationMetadataBuilder(callback); 741 } 742 743 JS_PUBLIC_API JSObject* js::GetAllocationMetadata(JSObject* obj) { 744 ObjectRealm::ObjectMetadataTable* map = 745 ObjectRealm::get(obj).objectMetadataTable.get(); 746 if (map) { 747 auto ptr = map->lookup(obj); 748 if (ptr) { 749 return ptr->value(); 750 } 751 } 752 return nullptr; 753 } 754 755 JS_PUBLIC_API bool js::ReportIsNotFunction(JSContext* cx, HandleValue v) { 756 cx->check(v); 757 return ReportIsNotFunction(cx, v, -1); 758 } 759 760 #ifdef DEBUG 761 bool js::HasObjectMovedOp(JSObject* obj) { 762 return !!JS::GetClass(obj)->extObjectMovedOp(); 763 } 764 #endif 765 766 JS_PUBLIC_API bool js::ForwardToNative(JSContext* cx, JSNative native, 767 const CallArgs& args) { 768 return native(cx, args.length(), args.base()); 769 } 770 771 AutoAssertNoContentJS::AutoAssertNoContentJS(JSContext* cx) 772 : context_(cx), prevAllowContentJS_(cx->runtime()->allowContentJS_) { 773 cx->runtime()->allowContentJS_ = false; 774 } 775 776 AutoAssertNoContentJS::~AutoAssertNoContentJS() { 777 context_->runtime()->allowContentJS_ = prevAllowContentJS_; 778 } 779 780 JS_PUBLIC_API void js::EnableCodeCoverage() { js::coverage::EnableLCov(); } 781 782 JS_PUBLIC_API uint64_t js::GetMemoryUsageForZone(Zone* zone) { 783 // We do not include zone->sharedMemoryUseCounts since that's already included 784 // in zone->mallocHeapSize. 785 return zone->gcHeapSize.bytes() + zone->mallocHeapSize.bytes() + 786 zone->jitHeapSize.bytes(); 787 } 788 789 JS_PUBLIC_API const gc::SharedMemoryMap& js::GetSharedMemoryUsageForZone( 790 Zone* zone) { 791 return zone->sharedMemoryUseCounts; 792 } 793 794 JS_PUBLIC_API uint64_t js::GetGCHeapUsage(JSContext* cx) { 795 mozilla::CheckedInt<uint64_t> sum = 0; 796 using SharedSet = js::HashSet<void*, PointerHasher<void*>, SystemAllocPolicy>; 797 SharedSet sharedVisited; 798 799 for (ZonesIter zone(cx->runtime(), WithAtoms); !zone.done(); zone.next()) { 800 sum += GetMemoryUsageForZone(zone); 801 802 const gc::SharedMemoryMap& shared = GetSharedMemoryUsageForZone(zone); 803 for (auto iter = shared.iter(); !iter.done(); iter.next()) { 804 void* sharedMem = iter.get().key(); 805 SharedSet::AddPtr addShared = sharedVisited.lookupForAdd(sharedMem); 806 if (addShared) { 807 // We *have* seen this shared memory before. 808 809 // Because shared memory is already included in 810 // GetMemoryUsageForZone() above, and we've seen it for a 811 // previous zone, we subtract it here so it's not counted more 812 // than once. 813 sum -= iter.get().value().nbytes; 814 } else if (!sharedVisited.add(addShared, sharedMem)) { 815 // OOM, abort counting (usually causing an over-estimate). 816 break; 817 } 818 } 819 } 820 821 MOZ_ASSERT(sum.isValid(), "Memory calculation under/over flowed"); 822 return sum.value(); 823 } 824 825 #ifdef DEBUG 826 JS_PUBLIC_API bool js::RuntimeIsBeingDestroyed() { 827 JSRuntime* runtime = TlsContext.get()->runtime(); 828 MOZ_ASSERT(js::CurrentThreadCanAccessRuntime(runtime)); 829 return runtime->isBeingDestroyed(); 830 } 831 #endif 832 833 // No-op implementations of public API that would depend on --with-intl-api 834 835 #ifndef JS_HAS_INTL_API 836 837 static bool IntlNotEnabled(JSContext* cx) { 838 JS_ReportErrorNumberASCII(cx, js::GetErrorMessage, nullptr, 839 JSMSG_SUPPORT_NOT_ENABLED, "Intl"); 840 return false; 841 } 842 843 bool JS::AddMozDateTimeFormatConstructor(JSContext* cx, JS::HandleObject intl) { 844 return IntlNotEnabled(cx); 845 } 846 847 bool JS::AddMozDisplayNamesConstructor(JSContext* cx, JS::HandleObject intl) { 848 return IntlNotEnabled(cx); 849 } 850 851 #endif // !JS_HAS_INTL_API 852 853 JS_PUBLIC_API JS::Zone* js::GetObjectZoneFromAnyThread(const JSObject* obj) { 854 return MaybeForwarded(obj)->zoneFromAnyThread(); 855 }