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