summaryrefslogtreecommitdiff
path: root/js/src/jscompartmentinlines.h
blob: c092889e28362b3f42c183ba38c62f34edc99ef0 (plain)
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
127
128
129
130
131
132
133
/* -*- 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 */