tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }