/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef jscompartmentinlines_h #define jscompartmentinlines_h #include "jscompartment.h" #include "gc/Barrier.h" #include "jscntxtinlines.h" inline void JSCompartment::initGlobal(js::GlobalObject& global) { MOZ_ASSERT(global.compartment() == this); MOZ_ASSERT(!global_); global_.set(&global); } js::GlobalObject* JSCompartment::maybeGlobal() const { MOZ_ASSERT_IF(global_, global_->compartment() == this); return global_; } js::GlobalObject* JSCompartment::unsafeUnbarrieredMaybeGlobal() const { return *global_.unsafeGet(); } js::AutoCompartment::AutoCompartment(ExclusiveContext* cx, JSObject* target, js::AutoLockForExclusiveAccess* maybeLock /* = nullptr */) : cx_(cx), origin_(cx->compartment_), maybeLock_(maybeLock) { cx_->enterCompartment(target->compartment(), maybeLock); } js::AutoCompartment::AutoCompartment(ExclusiveContext* cx, JSCompartment* target, js::AutoLockForExclusiveAccess* maybeLock /* = nullptr */) : cx_(cx), origin_(cx_->compartment_), maybeLock_(maybeLock) { cx_->enterCompartment(target, maybeLock); } js::AutoCompartment::~AutoCompartment() { cx_->leaveCompartment(origin_, maybeLock_); } inline bool JSCompartment::wrap(JSContext* cx, JS::MutableHandleValue vp) { /* Only GC things have to be wrapped or copied. */ if (!vp.isGCThing()) return true; /* * Symbols are GC things, but never need to be wrapped or copied because * they are always allocated in the atoms compartment. */ if (vp.isSymbol()) return true; /* Handle strings. */ if (vp.isString()) { JS::RootedString str(cx, vp.toString()); if (!wrap(cx, &str)) return false; vp.setString(str); return true; } if (vp.isBigInt()) { JS::RootedBigInt bi(cx, vp.toBigInt()); if (!wrap(cx, &bi)) return false; vp.setBigInt(bi); return true; } MOZ_ASSERT(vp.isObject()); /* * All that's left are objects. * * Object wrapping isn't the fastest thing in the world, in part because * we have to unwrap and invoke the prewrap hook to find the identity * object before we even start checking the cache. Neither of these * operations are needed in the common case, where we're just wrapping * a plain JS object from the wrappee's side of the membrane to the * wrapper's side. * * To optimize this, we note that the cache should only ever contain * identity objects - that is to say, objects that serve as the * canonical representation for a unique object identity observable by * script. Unwrap and prewrap are both steps that we take to get to the * identity of an incoming objects, and as such, they shuld never map * one identity object to another object. This means that we can safely * check the cache immediately, and only risk false negatives. Do this * in opt builds, and do both in debug builds so that we can assert * that we get the same answer. */ #ifdef DEBUG JS::RootedObject cacheResult(cx); #endif JS::RootedValue v(cx, vp); if (js::WrapperMap::Ptr p = crossCompartmentWrappers.lookup(js::CrossCompartmentKey(v))) { #ifdef DEBUG cacheResult = &p->value().get().toObject(); #else vp.set(p->value().get()); return true; #endif } JS::RootedObject obj(cx, &vp.toObject()); if (!wrap(cx, &obj)) return false; vp.setObject(*obj); MOZ_ASSERT_IF(cacheResult, obj == cacheResult); return true; } #endif /* jscompartmentinlines_h */