1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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;
}
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 */
|