1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
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/. */
10 #include "js/shadow/Realm.h" // JS::shadow::Realm
12 #include "js/GCPolicyAPI.h"
13 #include "js/TypeDecls.h" // forward-declaration of JS::Realm
15 /************************************************************************/
19 // Data associated with a global object. In the browser each frame has its
24 JS_PUBLIC_API
void TraceRealm(JSTracer
* trc
, JS::Realm
* realm
,
30 class JS_PUBLIC_API AutoRequireNoGC
;
32 // Each Realm holds a weak reference to its GlobalObject.
34 struct GCPolicy
<Realm
*> : public NonGCPointerPolicy
<Realm
*> {
35 static void trace(JSTracer
* trc
, Realm
** vp
, const char* name
) {
37 ::js::gc::TraceRealm(trc
, *vp
, name
);
42 // Get the current realm, if any. The ECMAScript spec calls this "the current
44 extern JS_PUBLIC_API Realm
* GetCurrentRealmOrNull(JSContext
* cx
);
46 // Return the compartment that contains a given realm.
47 inline JS::Compartment
* GetCompartmentForRealm(Realm
* realm
) {
48 return shadow::Realm::get(realm
)->compartment();
51 // Return an object's realm. All objects except cross-compartment wrappers are
52 // created in a particular realm, which never changes. Returns null if obj is
53 // a cross-compartment wrapper.
54 extern JS_PUBLIC_API Realm
* GetObjectRealmOrNull(JSObject
* obj
);
56 // Get the value of the "private data" internal field of the given Realm.
57 // This field is initially null and is set using SetRealmPrivate.
58 // It's a pointer to embeddding-specific data that SpiderMonkey never uses.
59 extern JS_PUBLIC_API
void* GetRealmPrivate(Realm
* realm
);
61 // Set the "private data" internal field of the given Realm.
62 extern JS_PUBLIC_API
void SetRealmPrivate(Realm
* realm
, void* data
);
64 typedef void (*DestroyRealmCallback
)(JS::GCContext
* gcx
, Realm
* realm
);
66 // Set the callback SpiderMonkey calls just before garbage-collecting a realm.
67 // Embeddings can use this callback to free private data associated with the
68 // realm via SetRealmPrivate.
70 // By the time this is called, the global object for the realm has already been
72 extern JS_PUBLIC_API
void SetDestroyRealmCallback(
73 JSContext
* cx
, DestroyRealmCallback callback
);
75 using RealmNameCallback
= void (*)(JSContext
* cx
, Realm
* realm
, char* buf
,
77 const JS::AutoRequireNoGC
& nogc
);
79 // Set the callback SpiderMonkey calls to get the name of a realm, for
81 extern JS_PUBLIC_API
void SetRealmNameCallback(JSContext
* cx
,
82 RealmNameCallback callback
);
84 // Get the global object for the given realm. This only returns nullptr during
85 // GC, between collecting the global object and destroying the Realm.
86 extern JS_PUBLIC_API JSObject
* GetRealmGlobalOrNull(Realm
* realm
);
88 // Initialize standard JS class constructors, prototypes, and any top-level
89 // functions and constants associated with the standard classes (e.g. isNaN
91 extern JS_PUBLIC_API
bool InitRealmStandardClasses(JSContext
* cx
);
93 // If the current realm has the non-standard freezeBuiltins option set to true,
94 // freeze the constructor object and seal the prototype.
95 extern JS_PUBLIC_API
bool MaybeFreezeCtorAndPrototype(JSContext
* cx
,
97 HandleObject maybeProto
);
100 * Ways to get various per-Realm objects. All the getters declared below operate
101 * on the JSContext's current Realm.
104 extern JS_PUBLIC_API JSObject
* GetRealmObjectPrototype(JSContext
* cx
);
105 extern JS_PUBLIC_API
JS::Handle
<JSObject
*> GetRealmObjectPrototypeHandle(
108 extern JS_PUBLIC_API JSObject
* GetRealmFunctionPrototype(JSContext
* cx
);
110 extern JS_PUBLIC_API JSObject
* GetRealmArrayPrototype(JSContext
* cx
);
112 extern JS_PUBLIC_API JSObject
* GetRealmErrorPrototype(JSContext
* cx
);
114 extern JS_PUBLIC_API JSObject
* GetRealmIteratorPrototype(JSContext
* cx
);
116 extern JS_PUBLIC_API JSObject
* GetRealmAsyncIteratorPrototype(JSContext
* cx
);
118 // Returns an object that represents the realm, that can be referred from
119 // other realm/compartment.
120 // See the consumer in `MaybeCrossOriginObjectMixins::EnsureHolder` for details.
121 extern JS_PUBLIC_API JSObject
* GetRealmKeyObject(JSContext
* cx
);
123 // Implements https://tc39.github.io/ecma262/#sec-getfunctionrealm
124 // 7.3.22 GetFunctionRealm ( obj )
126 // WARNING: may return a realm in a different compartment!
128 // Will throw an exception and return nullptr when a security wrapper or revoked
129 // proxy is encountered.
130 extern JS_PUBLIC_API Realm
* GetFunctionRealm(JSContext
* cx
,
131 HandleObject objArg
);
133 /** NB: This API is infallible; a nullptr return value does not indicate error.
135 * |target| must not be a cross-compartment wrapper because CCWs are not
136 * associated with a single realm.
138 * Entering a realm roots the realm and its global object until the matching
139 * JS::LeaveRealm() call.
141 extern JS_PUBLIC_API
JS::Realm
* EnterRealm(JSContext
* cx
, JSObject
* target
);
143 extern JS_PUBLIC_API
void LeaveRealm(JSContext
* cx
, JS::Realm
* oldRealm
);
148 * At any time, a JSContext has a current (possibly-nullptr) realm. The
149 * preferred way to change the current realm is with JSAutoRealm:
151 * void foo(JSContext* cx, JSObject* obj) {
152 * // in some realm 'r'
154 * JSAutoRealm ar(cx, obj); // constructor enters
155 * // in the realm of 'obj'
156 * } // destructor leaves
157 * // back in realm 'r'
160 * The object passed to JSAutoRealm must *not* be a cross-compartment wrapper,
161 * because CCWs are not associated with a single realm.
163 * For more complicated uses that don't neatly fit in a C++ stack frame, the
164 * realm can be entered and left using separate function calls:
166 * void foo(JSContext* cx, JSObject* obj) {
168 * JS::Realm* oldRealm = JS::EnterRealm(cx, obj);
169 * // in the realm of 'obj'
170 * JS::LeaveRealm(cx, oldRealm);
171 * // back in 'oldRealm'
174 * Note: these calls must still execute in a LIFO manner w.r.t all other
175 * enter/leave calls on the context. Furthermore, only the return value of a
176 * JS::EnterRealm call may be passed as the 'oldRealm' argument of
177 * the corresponding JS::LeaveRealm call.
179 * Entering a realm roots the realm and its global object for the lifetime of
183 class MOZ_RAII JS_PUBLIC_API JSAutoRealm
{
185 JS::Realm
* oldRealm_
;
188 JSAutoRealm(JSContext
* cx
, JSObject
* target
);
189 JSAutoRealm(JSContext
* cx
, JSScript
* target
);
193 class MOZ_RAII JS_PUBLIC_API JSAutoNullableRealm
{
195 JS::Realm
* oldRealm_
;
198 explicit JSAutoNullableRealm(JSContext
* cx
, JSObject
* targetOrNull
);
199 ~JSAutoNullableRealm();