Fix Centurion name.
[0ad.git] / libraries / source / spidermonkey / include-win32-debug / js / Wrapper.h
blob02513a16333e687cc2c2a366ce62d61d4534424c
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* NewSingleton(
155 JSContext* cx, JSObject* obj, const Wrapper* handler,
156 const WrapperOptions& options = WrapperOptions());
158 static JSObject* Renew(JSObject* existing, JSObject* obj,
159 const Wrapper* handler);
161 static inline const Wrapper* wrapperHandler(const JSObject* wrapper);
163 static JSObject* wrappedObject(JSObject* wrapper);
165 unsigned flags() const { return mFlags; }
167 bool isCrossCompartmentWrapper() const {
168 return !!(mFlags & CROSS_COMPARTMENT);
171 static const char family;
172 static const Wrapper singleton;
173 static const Wrapper singletonWithPrototype;
175 static JSObject* const defaultProto;
178 inline JSObject* WrapperOptions::proto() const {
179 return proto_ ? *proto_ : Wrapper::defaultProto;
182 /* Base class for all cross compartment wrapper handlers. */
183 class JS_FRIEND_API CrossCompartmentWrapper : public Wrapper {
184 public:
185 explicit constexpr CrossCompartmentWrapper(unsigned aFlags,
186 bool aHasPrototype = false,
187 bool aHasSecurityPolicy = false)
188 : Wrapper(CROSS_COMPARTMENT | aFlags, aHasPrototype, aHasSecurityPolicy) {
191 /* Standard internal methods. */
192 virtual bool getOwnPropertyDescriptor(
193 JSContext* cx, HandleObject wrapper, HandleId id,
194 MutableHandle<PropertyDescriptor> desc) const override;
195 virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
196 Handle<PropertyDescriptor> desc,
197 ObjectOpResult& result) const override;
198 virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
199 MutableHandleIdVector props) const override;
200 virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
201 ObjectOpResult& result) const override;
202 virtual bool enumerate(JSContext* cx, HandleObject proxy,
203 MutableHandleIdVector props) const override;
204 virtual bool getPrototype(JSContext* cx, HandleObject proxy,
205 MutableHandleObject protop) const override;
206 virtual bool setPrototype(JSContext* cx, HandleObject proxy,
207 HandleObject proto,
208 ObjectOpResult& result) const override;
210 virtual bool getPrototypeIfOrdinary(
211 JSContext* cx, HandleObject proxy, bool* isOrdinary,
212 MutableHandleObject protop) const override;
213 virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
214 bool* succeeded) const override;
215 virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
216 ObjectOpResult& result) const override;
217 virtual bool isExtensible(JSContext* cx, HandleObject wrapper,
218 bool* extensible) const override;
219 virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id,
220 bool* bp) const override;
221 virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
222 HandleId id, MutableHandleValue vp) const override;
223 virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id,
224 HandleValue v, HandleValue receiver,
225 ObjectOpResult& result) const override;
226 virtual bool call(JSContext* cx, HandleObject wrapper,
227 const CallArgs& args) const override;
228 virtual bool construct(JSContext* cx, HandleObject wrapper,
229 const CallArgs& args) const override;
231 /* SpiderMonkey extensions. */
232 virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id,
233 bool* bp) const override;
234 virtual bool getOwnEnumerablePropertyKeys(
235 JSContext* cx, HandleObject wrapper,
236 MutableHandleIdVector props) const override;
237 virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
238 const CallArgs& args) const override;
239 virtual bool hasInstance(JSContext* cx, HandleObject wrapper,
240 MutableHandleValue v, bool* bp) const override;
241 virtual const char* className(JSContext* cx,
242 HandleObject proxy) const override;
243 virtual JSString* fun_toString(JSContext* cx, HandleObject wrapper,
244 bool isToSource) const override;
245 virtual RegExpShared* regexp_toShared(JSContext* cx,
246 HandleObject proxy) const override;
247 virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
248 MutableHandleValue vp) const override;
250 // Allocate CrossCompartmentWrappers in the nursery.
251 virtual bool canNurseryAllocate() const override { return true; }
253 static const CrossCompartmentWrapper singleton;
254 static const CrossCompartmentWrapper singletonWithPrototype;
257 class JS_FRIEND_API OpaqueCrossCompartmentWrapper
258 : public CrossCompartmentWrapper {
259 public:
260 explicit constexpr OpaqueCrossCompartmentWrapper()
261 : CrossCompartmentWrapper(0) {}
263 /* Standard internal methods. */
264 virtual bool getOwnPropertyDescriptor(
265 JSContext* cx, HandleObject wrapper, HandleId id,
266 MutableHandle<PropertyDescriptor> desc) const override;
267 virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
268 Handle<PropertyDescriptor> desc,
269 ObjectOpResult& result) const override;
270 virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper,
271 MutableHandleIdVector props) const override;
272 virtual bool delete_(JSContext* cx, HandleObject wrapper, HandleId id,
273 ObjectOpResult& result) const override;
274 virtual bool enumerate(JSContext* cx, HandleObject proxy,
275 MutableHandleIdVector props) const override;
276 virtual bool getPrototype(JSContext* cx, HandleObject wrapper,
277 MutableHandleObject protop) const override;
278 virtual bool setPrototype(JSContext* cx, HandleObject wrapper,
279 HandleObject proto,
280 ObjectOpResult& result) const override;
281 virtual bool getPrototypeIfOrdinary(
282 JSContext* cx, HandleObject wrapper, bool* isOrdinary,
283 MutableHandleObject protop) const override;
284 virtual bool setImmutablePrototype(JSContext* cx, HandleObject wrapper,
285 bool* succeeded) const override;
286 virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
287 ObjectOpResult& result) const override;
288 virtual bool isExtensible(JSContext* cx, HandleObject wrapper,
289 bool* extensible) const override;
290 virtual bool has(JSContext* cx, HandleObject wrapper, HandleId id,
291 bool* bp) const override;
292 virtual bool get(JSContext* cx, HandleObject wrapper, HandleValue receiver,
293 HandleId id, MutableHandleValue vp) const override;
294 virtual bool set(JSContext* cx, HandleObject wrapper, HandleId id,
295 HandleValue v, HandleValue receiver,
296 ObjectOpResult& result) const override;
297 virtual bool call(JSContext* cx, HandleObject wrapper,
298 const CallArgs& args) const override;
299 virtual bool construct(JSContext* cx, HandleObject wrapper,
300 const CallArgs& args) const override;
302 /* SpiderMonkey extensions. */
303 virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id,
304 bool* bp) const override;
305 virtual bool getOwnEnumerablePropertyKeys(
306 JSContext* cx, HandleObject wrapper,
307 MutableHandleIdVector props) const override;
308 virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper,
309 ESClass* cls) const override;
310 virtual bool isArray(JSContext* cx, HandleObject obj,
311 JS::IsArrayAnswer* answer) const override;
312 virtual bool hasInstance(JSContext* cx, HandleObject wrapper,
313 MutableHandleValue v, bool* bp) const override;
314 virtual const char* className(JSContext* cx,
315 HandleObject wrapper) const override;
316 virtual JSString* fun_toString(JSContext* cx, HandleObject proxy,
317 bool isToSource) const override;
319 static const OpaqueCrossCompartmentWrapper singleton;
323 * Base class for security wrappers. A security wrapper is potentially hiding
324 * all or part of some wrapped object thus SecurityWrapper defaults to denying
325 * access to the wrappee. This is the opposite of Wrapper which tries to be
326 * completely transparent.
328 * NB: Currently, only a few ProxyHandler operations are overridden to deny
329 * access, relying on derived SecurityWrapper to block access when necessary.
331 template <class Base>
332 class JS_FRIEND_API SecurityWrapper : public Base {
333 public:
334 explicit constexpr SecurityWrapper(unsigned flags, bool hasPrototype = false)
335 : Base(flags, hasPrototype, /* hasSecurityPolicy = */ true) {}
337 virtual bool enter(JSContext* cx, HandleObject wrapper, HandleId id,
338 Wrapper::Action act, bool mayThrow,
339 bool* bp) const override;
341 virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id,
342 Handle<PropertyDescriptor> desc,
343 ObjectOpResult& result) const override;
344 virtual bool isExtensible(JSContext* cx, HandleObject wrapper,
345 bool* extensible) const override;
346 virtual bool preventExtensions(JSContext* cx, HandleObject wrapper,
347 ObjectOpResult& result) const override;
348 virtual bool setPrototype(JSContext* cx, HandleObject proxy,
349 HandleObject proto,
350 ObjectOpResult& result) const override;
351 virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy,
352 bool* succeeded) const override;
354 virtual bool nativeCall(JSContext* cx, IsAcceptableThis test, NativeImpl impl,
355 const CallArgs& args) const override;
356 virtual bool getBuiltinClass(JSContext* cx, HandleObject wrapper,
357 ESClass* cls) const override;
358 virtual bool isArray(JSContext* cx, HandleObject wrapper,
359 JS::IsArrayAnswer* answer) const override;
360 virtual RegExpShared* regexp_toShared(JSContext* cx,
361 HandleObject proxy) const override;
362 virtual bool boxedValue_unbox(JSContext* cx, HandleObject proxy,
363 MutableHandleValue vp) const override;
365 // Allow isCallable and isConstructor. They used to be class-level, and so
366 // could not be guarded against.
369 * Allow our subclasses to select the superclass behavior they want without
370 * needing to specify an exact superclass.
372 typedef Base Permissive;
373 typedef SecurityWrapper<Base> Restrictive;
376 typedef SecurityWrapper<CrossCompartmentWrapper>
377 CrossCompartmentSecurityWrapper;
379 extern JSObject* TransparentObjectWrapper(JSContext* cx, HandleObject existing,
380 HandleObject obj);
382 inline bool IsWrapper(const JSObject* obj) {
383 return IsProxy(obj) && GetProxyHandler(obj)->family() == &Wrapper::family;
386 inline bool IsCrossCompartmentWrapper(const JSObject* obj) {
387 return IsWrapper(obj) &&
388 (Wrapper::wrapperHandler(obj)->flags() & Wrapper::CROSS_COMPARTMENT);
391 /* static */ inline const Wrapper* Wrapper::wrapperHandler(
392 const JSObject* wrapper) {
393 MOZ_ASSERT(IsWrapper(wrapper));
394 return static_cast<const Wrapper*>(GetProxyHandler(wrapper));
397 // Given a JSObject, returns that object stripped of wrappers. If
398 // stopAtWindowProxy is true, then this returns the WindowProxy if it was
399 // previously wrapped. Otherwise, this returns the first object for which
400 // JSObject::isWrapper returns false.
402 // ExposeToActiveJS is called on wrapper targets to allow gray marking
403 // assertions to work while an incremental GC is in progress, but this means
404 // that this cannot be called from the GC or off the main thread.
405 JS_FRIEND_API JSObject* UncheckedUnwrap(JSObject* obj,
406 bool stopAtWindowProxy = true,
407 unsigned* flagsp = nullptr);
409 // Given a JSObject, returns that object stripped of wrappers, except
410 // WindowProxy wrappers. At each stage, the wrapper has the opportunity to veto
411 // the unwrap. Null is returned if there are security wrappers that can't be
412 // unwrapped.
414 // This does a static-only unwrap check: it basically checks whether _all_
415 // globals in the wrapper's source compartment should be able to access the
416 // wrapper target. This won't necessarily return the right thing for the HTML
417 // spec's cross-origin objects (WindowProxy and Location), but is fine to use
418 // when failure to unwrap one of those objects wouldn't be a problem. For
419 // example, if you want to test whether your target object is a specific class
420 // that's not WindowProxy or Location, you can use this.
422 // ExposeToActiveJS is called on wrapper targets to allow gray marking
423 // assertions to work while an incremental GC is in progress, but this means
424 // that this cannot be called from the GC or off the main thread.
425 JS_FRIEND_API JSObject* CheckedUnwrapStatic(JSObject* obj);
427 // Unwrap only the outermost security wrapper, with the same semantics as
428 // above. This is the checked version of Wrapper::wrappedObject.
429 JS_FRIEND_API JSObject* UnwrapOneCheckedStatic(JSObject* obj);
431 // Given a JSObject, returns that object stripped of wrappers. At each stage,
432 // the security wrapper has the opportunity to veto the unwrap. If
433 // stopAtWindowProxy is true, then this returns the WindowProxy if it was
434 // previously wrapped. Null is returned if there are security wrappers that
435 // can't be unwrapped.
437 // ExposeToActiveJS is called on wrapper targets to allow gray marking
438 // assertions to work while an incremental GC is in progress, but this means
439 // that this cannot be called from the GC or off the main thread.
441 // The JSContext argument will be used for dynamic checks (needed by WindowProxy
442 // and Location) and should represent the Realm doing the unwrapping. It is not
443 // used to throw exceptions; this function never throws.
445 // This function may be able to GC (and the static analysis definitely thinks it
446 // can), but it still takes a JSObject* argument, because some of its callers
447 // would actually have a bit of a hard time producing a Rooted. And it ends up
448 // having to root internally anyway, because it wants to use the value in a loop
449 // and you can't assign to a HandleObject. What this means is that callers who
450 // plan to use the argument object after they have called this function will
451 // need to root it to avoid hazard failures, even though this function doesn't
452 // require a Handle.
453 JS_FRIEND_API JSObject* CheckedUnwrapDynamic(JSObject* obj, JSContext* cx,
454 bool stopAtWindowProxy = true);
456 // Unwrap only the outermost security wrapper, with the same semantics as
457 // above. This is the checked version of Wrapper::wrappedObject.
458 JS_FRIEND_API JSObject* UnwrapOneCheckedDynamic(HandleObject obj, JSContext* cx,
459 bool stopAtWindowProxy = true);
461 // Given a JSObject, returns that object stripped of wrappers. This returns the
462 // WindowProxy if it was previously wrapped.
464 // ExposeToActiveJS is not called on wrapper targets so this can be called from
465 // the GC or off the main thread.
466 JS_FRIEND_API JSObject* UncheckedUnwrapWithoutExpose(JSObject* obj);
468 void ReportAccessDenied(JSContext* cx);
470 JS_FRIEND_API void NukeCrossCompartmentWrapper(JSContext* cx,
471 JSObject* wrapper);
473 // If a cross-compartment wrapper source => target exists, nuke it.
474 JS_FRIEND_API void NukeCrossCompartmentWrapperIfExists(JSContext* cx,
475 JS::Compartment* source,
476 JSObject* target);
478 void RemapWrapper(JSContext* cx, JSObject* wobj, JSObject* newTarget);
479 void RemapDeadWrapper(JSContext* cx, HandleObject wobj, HandleObject newTarget);
481 JS_FRIEND_API bool RemapAllWrappersForObject(JSContext* cx,
482 HandleObject oldTarget,
483 HandleObject newTarget);
485 // API to recompute all cross-compartment wrappers whose source and target
486 // match the given filters.
487 JS_FRIEND_API bool RecomputeWrappers(JSContext* cx,
488 const CompartmentFilter& sourceFilter,
489 const CompartmentFilter& targetFilter);
491 } /* namespace js */
493 #endif /* js_Wrapper_h */