Bug 1568151 - Replace `target.getInspector()` by `target.getFront("inspector")`....
[gecko.git] / js / public / Wrapper.h
blobe8c214d7f1f1cfcf8d3143cc232890cd7209dc77
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/. */
7 #ifndef js_Wrapper_h
8 #define js_Wrapper_h
10 #include "mozilla/Attributes.h"
12 #include "js/Proxy.h"
14 namespace js {
17 * Helper for Wrapper::New default options.
19 * Callers of Wrapper::New() who wish to specify a prototype for the created
20 * Wrapper, *MUST* construct a WrapperOptions with a JSContext.
22 class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions {
23 public:
24 WrapperOptions() : ProxyOptions(false), proto_() {}
26 explicit WrapperOptions(JSContext* cx) : ProxyOptions(false), proto_() {
27 proto_.emplace(cx);
30 inline JSObject* proto() const;
31 WrapperOptions& setProto(JSObject* protoArg) {
32 MOZ_ASSERT(proto_);
33 *proto_ = protoArg;
34 return *this;
37 private:
38 mozilla::Maybe<JS::RootedObject> proto_;
41 // Base class for proxy handlers that want to forward all operations to an
42 // object stored in the proxy's private slot.
43 class JS_FRIEND_API ForwardingProxyHandler : public BaseProxyHandler {
44 public:
45 using BaseProxyHandler::BaseProxyHandler;
47 /* Standard internal methods. */
48 virtual bool getOwnPropertyDescriptor(
49 JSContext* cx, HandleObject proxy, HandleId id,
50 MutableHandle<PropertyDescriptor> desc) const override;
51 virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id,
52 Handle<PropertyDescriptor> desc,
53 ObjectOpResult& result) const override;
54 virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy,
55 MutableHandleIdVector props) const override;
56 virtual bool delete_(JSContext* cx, HandleObject proxy, HandleId id,
57 ObjectOpResult& result) const override;
58 virtual bool enumerate(JSContext* cx, HandleObject proxy,
59 MutableHandleIdVector props) const override;
60 virtual bool getPrototype(JSContext* cx, HandleObject proxy,
61 MutableHandleObject protop) const override;
62 virtual bool setPrototype(JSContext* cx, HandleObject proxy,
63 HandleObject proto,
64 ObjectOpResult& result) const override;
65 virtual bool getPrototypeIfOrdinary(
66 JSContext* cx, HandleObject proxy, bool* isOrdinary,
67 MutableHandleObject protop) const override;
68 virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
69 bool* succeeded) const override;
70 virtual bool preventExtensions(JSContext* cx, HandleObject proxy,
71 ObjectOpResult& result) const override;
72 virtual bool isExtensible(JSContext* cx, HandleObject proxy,
73 bool* extensible) const override;
74 virtual bool has(JSContext* cx, HandleObject proxy, HandleId id,
75 bool* bp) const override;
76 virtual bool get(JSContext* cx, HandleObject proxy, HandleValue receiver,
77 HandleId id, MutableHandleValue vp) const override;
78 virtual bool set(JSContext* cx, HandleObject proxy, HandleId id,
79 HandleValue v, HandleValue receiver,
80 ObjectOpResult& result) const override;
81 virtual bool call(JSContext* cx, HandleObject proxy,
82 const CallArgs& args) const override;
83 virtual bool construct(JSContext* cx, HandleObject proxy,
84 const CallArgs& args) const override;
86 /* SpiderMonkey extensions. */
87 virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id,
88 bool* bp) const override;
89 virtual bool getOwnEnumerablePropertyKeys(
90 JSContext* cx, HandleObject proxy,
91 MutableHandleIdVector props) const override;
92 virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
93 const CallArgs& args) const override;
94 virtual bool hasInstance(JSContext* cx, HandleObject proxy,
95 MutableHandleValue v, bool* bp) const override;
96 virtual bool getBuiltinClass(JSContext* cx, HandleObject proxy,
97 ESClass* cls) const override;
98 virtual bool isArray(JSContext* cx, HandleObject proxy,
99 JS::IsArrayAnswer* answer) const override;
100 virtual const char* className(JSContext* cx,
101 HandleObject proxy) const override;
102 virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
103 bool isToSource) const override;
104 virtual RegExpShared* regexp_toShared(JSContext* cx,
105 HandleObject proxy) const override;
106 virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
107 MutableHandleValue vp) const override;
108 virtual bool isCallable(JSObject* obj) const override;
109 virtual bool isConstructor(JSObject* obj) const override;
113 * A wrapper is a proxy with a target object to which it generally forwards
114 * operations, but may restrict access to certain operations or augment those
115 * operations in various ways.
117 * A wrapper can be "unwrapped" in C++, exposing the underlying object.
118 * Callers should be careful to avoid unwrapping security wrappers in the wrong
119 * context.
121 * Important: If you add a method implementation here, you probably also need
122 * to add an override in CrossCompartmentWrapper. If you don't, you risk
123 * compartment mismatches. See bug 945826 comment 0.
125 class JS_FRIEND_API Wrapper : public ForwardingProxyHandler {
126 unsigned mFlags;
128 public:
129 explicit constexpr Wrapper(unsigned aFlags, bool aHasPrototype = false,
130 bool aHasSecurityPolicy = false)
131 : ForwardingProxyHandler(&family, aHasPrototype, aHasSecurityPolicy),
132 mFlags(aFlags) {}
134 virtual bool finalizeInBackground(const Value& priv) const override;
137 * A hook subclasses can override to implement CheckedUnwrapDynamic
138 * behavior. The JSContext represents the "who is trying to unwrap?" Realm.
139 * The JSObject is the wrapper that the caller is trying to unwrap.
141 virtual bool dynamicCheckedUnwrapAllowed(HandleObject obj,
142 JSContext* cx) const {
143 MOZ_ASSERT(hasSecurityPolicy(), "Why are you asking?");
144 return false;
147 using BaseProxyHandler::Action;
149 enum Flags { CROSS_COMPARTMENT = 1 << 0, LAST_USED_FLAG = CROSS_COMPARTMENT };
151 static JSObject* New(JSContext* cx, JSObject* obj, const Wrapper* handler,
152 const WrapperOptions& options = WrapperOptions());
154 static JSObject* Renew(JSObject* existing, JSObject* obj,
155 const Wrapper* handler);
157 static inline const Wrapper* wrapperHandler(const JSObject* wrapper);
159 static JSObject* wrappedObject(JSObject* wrapper);
161 unsigned flags() const { return mFlags; }
163 bool isCrossCompartmentWrapper() const {
164 return !!(mFlags & CROSS_COMPARTMENT);
167 static const char family;
168 static const Wrapper singleton;
169 static const Wrapper singletonWithPrototype;
171 static JSObject* const defaultProto;
174 inline JSObject* WrapperOptions::proto() const {
175 return proto_ ? *proto_ : Wrapper::defaultProto;
178 /* Base class for all cross compartment wrapper handlers. */
179 class JS_FRIEND_API CrossCompartmentWrapper : public Wrapper {
180 public:
181 explicit constexpr CrossCompartmentWrapper(unsigned aFlags,
182 bool aHasPrototype = false,
183 bool aHasSecurityPolicy = false)
184 : Wrapper(CROSS_COMPARTMENT | aFlags, aHasPrototype, aHasSecurityPolicy) {
187 /* Standard internal methods. */
188 virtual bool getOwnPropertyDescriptor(
189 JSContext* cx, HandleObject wrapper, HandleId id,
190 MutableHandle<PropertyDescriptor> desc) const override;
191 virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
192 Handle<PropertyDescriptor> desc,
193 ObjectOpResult& result) const override;
194 virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
195 MutableHandleIdVector props) const override;
196 virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
197 ObjectOpResult& result) const override;
198 virtual bool enumerate(JSContext* cx, HandleObject proxy,
199 MutableHandleIdVector props) const override;
200 virtual bool getPrototype(JSContext* cx, HandleObject proxy,
201 MutableHandleObject protop) const override;
202 virtual bool setPrototype(JSContext* cx, HandleObject proxy,
203 HandleObject proto,
204 ObjectOpResult& result) const override;
206 virtual bool getPrototypeIfOrdinary(
207 JSContext* cx, HandleObject proxy, bool* isOrdinary,
208 MutableHandleObject protop) const override;
209 virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
210 bool* succeeded) const override;
211 virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
212 ObjectOpResult& result) const override;
213 virtual bool isExtensible(JSContext* cx, HandleObject wrapper,
214 bool* extensible) const override;
215 virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id,
216 bool* bp) const override;
217 virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
218 HandleId id, MutableHandleValue vp) const override;
219 virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id,
220 HandleValue v, HandleValue receiver,
221 ObjectOpResult& result) const override;
222 virtual bool call(JSContext* cx, HandleObject wrapper,
223 const CallArgs& args) const override;
224 virtual bool construct(JSContext* cx, HandleObject wrapper,
225 const CallArgs& args) const override;
227 /* SpiderMonkey extensions. */
228 virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id,
229 bool* bp) const override;
230 virtual bool getOwnEnumerablePropertyKeys(
231 JSContext* cx, HandleObject wrapper,
232 MutableHandleIdVector props) const override;
233 virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
234 const CallArgs& args) const override;
235 virtual bool hasInstance(JSContext* cx, HandleObject wrapper,
236 MutableHandleValue v, bool* bp) const override;
237 virtual const char* className(JSContext* cx,
238 HandleObject proxy) const override;
239 virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper,
240 bool isToSource) const override;
241 virtual RegExpShared* regexp_toShared(JSContext* cx,
242 HandleObject proxy) const override;
243 virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
244 MutableHandleValue vp) const override;
246 // Allocate CrossCompartmentWrappers in the nursery.
247 virtual bool canNurseryAllocate() const override { return true; }
249 static const CrossCompartmentWrapper singleton;
250 static const CrossCompartmentWrapper singletonWithPrototype;
253 class JS_FRIEND_API OpaqueCrossCompartmentWrapper
254 : public CrossCompartmentWrapper {
255 public:
256 explicit constexpr OpaqueCrossCompartmentWrapper()
257 : CrossCompartmentWrapper(0) {}
259 /* Standard internal methods. */
260 virtual bool getOwnPropertyDescriptor(
261 JSContext* cx, HandleObject wrapper, HandleId id,
262 MutableHandle<PropertyDescriptor> desc) const override;
263 virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
264 Handle<PropertyDescriptor> desc,
265 ObjectOpResult& result) const override;
266 virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
267 MutableHandleIdVector props) const override;
268 virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
269 ObjectOpResult& result) const override;
270 virtual bool enumerate(JSContext* cx, HandleObject proxy,
271 MutableHandleIdVector props) const override;
272 virtual bool getPrototype(JSContext* cx, HandleObject wrapper,
273 MutableHandleObject protop) const override;
274 virtual bool setPrototype(JSContext* cx, HandleObject wrapper,
275 HandleObject proto,
276 ObjectOpResult& result) const override;
277 virtual bool getPrototypeIfOrdinary(
278 JSContext* cx, HandleObject wrapper, bool* isOrdinary,
279 MutableHandleObject protop) const override;
280 virtual bool setImmutablePrototype(JSContext* cx, HandleObject wrapper,
281 bool* succeeded) const override;
282 virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
283 ObjectOpResult& result) const override;
284 virtual bool isExtensible(JSContext* cx, HandleObject wrapper,
285 bool* extensible) const override;
286 virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id,
287 bool* bp) const override;
288 virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
289 HandleId id, MutableHandleValue vp) const override;
290 virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id,
291 HandleValue v, HandleValue receiver,
292 ObjectOpResult& result) const override;
293 virtual bool call(JSContext* cx, HandleObject wrapper,
294 const CallArgs& args) const override;
295 virtual bool construct(JSContext* cx, HandleObject wrapper,
296 const CallArgs& args) const override;
298 /* SpiderMonkey extensions. */
299 virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id,
300 bool* bp) const override;
301 virtual bool getOwnEnumerablePropertyKeys(
302 JSContext* cx, HandleObject wrapper,
303 MutableHandleIdVector props) const override;
304 virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper,
305 ESClass* cls) const override;
306 virtual bool isArray(JSContext* cx, HandleObject obj,
307 JS::IsArrayAnswer* answer) const override;
308 virtual bool hasInstance(JSContext* cx, HandleObject wrapper,
309 MutableHandleValue v, bool* bp) const override;
310 virtual const char* className(JSContext* cx,
311 HandleObject wrapper) const override;
312 virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
313 bool isToSource) const override;
315 static const OpaqueCrossCompartmentWrapper singleton;
319 * Base class for security wrappers. A security wrapper is potentially hiding
320 * all or part of some wrapped object thus SecurityWrapper defaults to denying
321 * access to the wrappee. This is the opposite of Wrapper which tries to be
322 * completely transparent.
324 * NB: Currently, only a few ProxyHandler operations are overridden to deny
325 * access, relying on derived SecurityWrapper to block access when necessary.
327 template <class Base>
328 class JS_FRIEND_API SecurityWrapper : public Base {
329 public:
330 explicit constexpr SecurityWrapper(unsigned flags, bool hasPrototype = false)
331 : Base(flags, hasPrototype, /* hasSecurityPolicy = */ true) {}
333 virtual bool enter(JSContext* cx, HandleObject wrapper, HandleId id,
334 Wrapper::Action act, bool mayThrow,
335 bool* bp) const override;
337 virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
338 Handle<PropertyDescriptor> desc,
339 ObjectOpResult& result) const override;
340 virtual bool isExtensible(JSContext* cx, HandleObject wrapper,
341 bool* extensible) const override;
342 virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
343 ObjectOpResult& result) const override;
344 virtual bool setPrototype(JSContext* cx, HandleObject proxy,
345 HandleObject proto,
346 ObjectOpResult& result) const override;
347 virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
348 bool* succeeded) const override;
350 virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
351 const CallArgs& args) const override;
352 virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper,
353 ESClass* cls) const override;
354 virtual bool isArray(JSContext* cx, HandleObject wrapper,
355 JS::IsArrayAnswer* answer) const override;
356 virtual RegExpShared* regexp_toShared(JSContext* cx,
357 HandleObject proxy) const override;
358 virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
359 MutableHandleValue vp) const override;
361 // Allow isCallable and isConstructor. They used to be class-level, and so
362 // could not be guarded against.
365 * Allow our subclasses to select the superclass behavior they want without
366 * needing to specify an exact superclass.
368 typedef Base Permissive;
369 typedef SecurityWrapper<Base> Restrictive;
372 typedef SecurityWrapper<CrossCompartmentWrapper>
373 CrossCompartmentSecurityWrapper;
375 extern JSObject* TransparentObjectWrapper(JSContext* cx, HandleObject existing,
376 HandleObject obj);
378 inline bool IsWrapper(const JSObject* obj) {
379 return IsProxy(obj) && GetProxyHandler(obj)->family() == &Wrapper::family;
382 inline bool IsCrossCompartmentWrapper(const JSObject* obj) {
383 return IsWrapper(obj) &&
384 (Wrapper::wrapperHandler(obj)->flags() & Wrapper::CROSS_COMPARTMENT);
387 /* static */ inline const Wrapper* Wrapper::wrapperHandler(
388 const JSObject* wrapper) {
389 MOZ_ASSERT(IsWrapper(wrapper));
390 return static_cast<const Wrapper*>(GetProxyHandler(wrapper));
393 // Given a JSObject, returns that object stripped of wrappers. If
394 // stopAtWindowProxy is true, then this returns the WindowProxy if it was
395 // previously wrapped. Otherwise, this returns the first object for which
396 // JSObject::isWrapper returns false.
398 // ExposeToActiveJS is called on wrapper targets to allow gray marking
399 // assertions to work while an incremental GC is in progress, but this means
400 // that this cannot be called from the GC or off the main thread.
401 JS_FRIEND_API JSObject* UncheckedUnwrap(JSObject* obj,
402 bool stopAtWindowProxy = true,
403 unsigned* flagsp = nullptr);
405 // Given a JSObject, returns that object stripped of wrappers, except
406 // WindowProxy wrappers. At each stage, the wrapper has the opportunity to veto
407 // the unwrap. Null is returned if there are security wrappers that can't be
408 // unwrapped.
410 // This does a static-only unwrap check: it basically checks whether _all_
411 // globals in the wrapper's source compartment should be able to access the
412 // wrapper target. This won't necessarily return the right thing for the HTML
413 // spec's cross-origin objects (WindowProxy and Location), but is fine to use
414 // when failure to unwrap one of those objects wouldn't be a problem. For
415 // example, if you want to test whether your target object is a specific class
416 // that's not WindowProxy or Location, you can use this.
418 // ExposeToActiveJS is called on wrapper targets to allow gray marking
419 // assertions to work while an incremental GC is in progress, but this means
420 // that this cannot be called from the GC or off the main thread.
421 JS_FRIEND_API JSObject* CheckedUnwrapStatic(JSObject* obj);
423 // Unwrap only the outermost security wrapper, with the same semantics as
424 // above. This is the checked version of Wrapper::wrappedObject.
425 JS_FRIEND_API JSObject* UnwrapOneCheckedStatic(JSObject* obj);
427 // Given a JSObject, returns that object stripped of wrappers. At each stage,
428 // the security wrapper has the opportunity to veto the unwrap. If
429 // stopAtWindowProxy is true, then this returns the WindowProxy if it was
430 // previously wrapped. Null is returned if there are security wrappers that
431 // can't be unwrapped.
433 // ExposeToActiveJS is called on wrapper targets to allow gray marking
434 // assertions to work while an incremental GC is in progress, but this means
435 // that this cannot be called from the GC or off the main thread.
437 // The JSContext argument will be used for dynamic checks (needed by WindowProxy
438 // and Location) and should represent the Realm doing the unwrapping. It is not
439 // used to throw exceptions; this function never throws.
441 // This function may be able to GC (and the static analysis definitely thinks it
442 // can), but it still takes a JSObject* argument, because some of its callers
443 // would actually have a bit of a hard time producing a Rooted. And it ends up
444 // having to root internally anyway, because it wants to use the value in a loop
445 // and you can't assign to a HandleObject. What this means is that callers who
446 // plan to use the argument object after they have called this function will
447 // need to root it to avoid hazard failures, even though this function doesn't
448 // require a Handle.
449 JS_FRIEND_API JSObject* CheckedUnwrapDynamic(JSObject* obj, JSContext* cx,
450 bool stopAtWindowProxy = true);
452 // Unwrap only the outermost security wrapper, with the same semantics as
453 // above. This is the checked version of Wrapper::wrappedObject.
454 JS_FRIEND_API JSObject* UnwrapOneCheckedDynamic(HandleObject obj, JSContext* cx,
455 bool stopAtWindowProxy = true);
457 // Given a JSObject, returns that object stripped of wrappers. This returns the
458 // WindowProxy if it was previously wrapped.
460 // ExposeToActiveJS is not called on wrapper targets so this can be called from
461 // the GC or off the main thread.
462 JS_FRIEND_API JSObject* UncheckedUnwrapWithoutExpose(JSObject* obj);
464 void ReportAccessDenied(JSContext* cx);
466 JS_FRIEND_API void NukeCrossCompartmentWrapper(JSContext* cx,
467 JSObject* wrapper);
469 // If a cross-compartment wrapper source => target exists, nuke it.
470 JS_FRIEND_API void NukeCrossCompartmentWrapperIfExists(JSContext* cx,
471 JS::Compartment* source,
472 JSObject* target);
474 void RemapWrapper(JSContext* cx, JSObject* wobj, JSObject* newTarget);
476 JS_FRIEND_API bool RemapAllWrappersForObject(JSContext* cx,
477 HandleObject oldTarget,
478 HandleObject newTarget);
480 // API to recompute all cross-compartment wrappers whose source and target
481 // match the given filters.
482 JS_FRIEND_API bool RecomputeWrappers(JSContext* cx,
483 const CompartmentFilter& sourceFilter,
484 const CompartmentFilter& targetFilter);
486 } /* namespace js */
488 #endif /* js_Wrapper_h */