1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2  * vim: set ts=8 sts=4 et sw=4 tw=99:
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 #ifndef jscompartmentinlines_h
8 #define jscompartmentinlines_h
9 
10 #include "jscompartment.h"
11 
12 #include "gc/Barrier.h"
13 
14 #include "jscntxtinlines.h"
15 
16 inline void
initGlobal(js::GlobalObject & global)17 JSCompartment::initGlobal(js::GlobalObject& global)
18 {
19     MOZ_ASSERT(global.compartment() == this);
20     MOZ_ASSERT(!global_);
21     global_.set(&global);
22 }
23 
24 js::GlobalObject*
maybeGlobal()25 JSCompartment::maybeGlobal() const
26 {
27     MOZ_ASSERT_IF(global_, global_->compartment() == this);
28     return global_;
29 }
30 
31 js::GlobalObject*
unsafeUnbarrieredMaybeGlobal()32 JSCompartment::unsafeUnbarrieredMaybeGlobal() const
33 {
34     return *global_.unsafeGet();
35 }
36 
AutoCompartment(ExclusiveContext * cx,JSObject * target)37 js::AutoCompartment::AutoCompartment(ExclusiveContext* cx, JSObject* target)
38   : cx_(cx),
39     origin_(cx->compartment_)
40 {
41     cx_->enterCompartment(target->compartment());
42 }
43 
AutoCompartment(ExclusiveContext * cx,JSCompartment * target)44 js::AutoCompartment::AutoCompartment(ExclusiveContext* cx, JSCompartment* target)
45   : cx_(cx),
46     origin_(cx_->compartment_)
47 {
48     cx_->enterCompartment(target);
49 }
50 
~AutoCompartment()51 js::AutoCompartment::~AutoCompartment()
52 {
53     cx_->leaveCompartment(origin_);
54 }
55 
56 inline bool
wrap(JSContext * cx,JS::MutableHandleValue vp,JS::HandleObject existing)57 JSCompartment::wrap(JSContext* cx, JS::MutableHandleValue vp, JS::HandleObject existing)
58 {
59     MOZ_ASSERT_IF(existing, vp.isObject());
60 
61     /* Only GC things have to be wrapped or copied. */
62     if (!vp.isMarkable())
63         return true;
64 
65     /*
66      * Symbols are GC things, but never need to be wrapped or copied because
67      * they are always allocated in the atoms compartment.
68      */
69     if (vp.isSymbol())
70         return true;
71 
72     /* Handle strings. */
73     if (vp.isString()) {
74         JS::RootedString str(cx, vp.toString());
75         if (!wrap(cx, &str))
76             return false;
77         vp.setString(str);
78         return true;
79     }
80 
81     MOZ_ASSERT(vp.isObject());
82 
83     /*
84      * All that's left are objects.
85      *
86      * Object wrapping isn't the fastest thing in the world, in part because
87      * we have to unwrap and invoke the prewrap hook to find the identity
88      * object before we even start checking the cache. Neither of these
89      * operations are needed in the common case, where we're just wrapping
90      * a plain JS object from the wrappee's side of the membrane to the
91      * wrapper's side.
92      *
93      * To optimize this, we note that the cache should only ever contain
94      * identity objects - that is to say, objects that serve as the
95      * canonical representation for a unique object identity observable by
96      * script. Unwrap and prewrap are both steps that we take to get to the
97      * identity of an incoming objects, and as such, they shuld never map
98      * one identity object to another object. This means that we can safely
99      * check the cache immediately, and only risk false negatives. Do this
100      * in opt builds, and do both in debug builds so that we can assert
101      * that we get the same answer.
102      */
103 #ifdef DEBUG
104     JS::RootedObject cacheResult(cx);
105 #endif
106     JS::RootedValue v(cx, vp);
107     if (js::WrapperMap::Ptr p = crossCompartmentWrappers.lookup(js::CrossCompartmentKey(v))) {
108 #ifdef DEBUG
109         cacheResult = &p->value().get().toObject();
110 #else
111         vp.set(p->value());
112         return true;
113 #endif
114     }
115 
116     JS::RootedObject obj(cx, &vp.toObject());
117     if (!wrap(cx, &obj, existing))
118         return false;
119     vp.setObject(*obj);
120     MOZ_ASSERT_IF(cacheResult, obj == cacheResult);
121     return true;
122 }
123 
124 #endif /* jscompartmentinlines_h */
125