DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (d38398e5144e)

VCS Links

Macros

Line Code
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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
/* -*- 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 "jsiter.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();
}

template <typename T>
js::AutoCompartment::AutoCompartment(JSContext* cx, const T& target)
  : cx_(cx),
    origin_(cx->compartment()),
    maybeLock_(nullptr)
{
    cx_->enterCompartmentOf(target);
}

// Protected constructor that bypasses assertions in enterCompartmentOf.
js::AutoCompartment::AutoCompartment(JSContext* 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_);
}

js::AutoAtomsCompartment::AutoAtomsCompartment(JSContext* cx,
                                               js::AutoLockForExclusiveAccess& lock)
  : AutoCompartment(cx, cx->atomsCompartment(lock), &lock)
{}

js::AutoCompartmentUnchecked::AutoCompartmentUnchecked(JSContext* cx, JSCompartment* target)
  : AutoCompartment(cx, target)
{}

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. They still need to
     * be marked in the new compartment's zone, however.
     */
    if (vp.isSymbol()) {
        cx->markAtomValue(vp);
        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
    MOZ_ASSERT(JS::ValueIsNotGray(vp));
    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;
}

MOZ_ALWAYS_INLINE bool
JSCompartment::objectMaybeInIteration(JSObject* obj)
{
    MOZ_ASSERT(obj->compartment() == this);

    // If the list is empty we're not iterating any objects.
    js::NativeIterator* next = enumerators->next();
    if (enumerators == next)
        return false;

    // If the list contains a single object, check if it's |obj|.
    if (next->next() == enumerators)
        return next->obj == obj;

    return true;
}

#endif /* jscompartmentinlines_h */