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