Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set ts=8 sts=4 et sw=4 tw=99:
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 jsproxy_h
8 #define jsproxy_h
10 #include "mozilla/Maybe.h"
12 #include "jsfriendapi.h"
14 #include "js/CallNonGenericMethod.h"
15 #include "js/Class.h"
17 namespace js {
19 using JS::AutoIdVector;
20 using JS::CallArgs;
21 using JS::HandleId;
22 using JS::HandleObject;
23 using JS::HandleValue;
24 using JS::IsAcceptableThis;
25 using JS::MutableHandle;
26 using JS::MutableHandleObject;
27 using JS::MutableHandleValue;
28 using JS::NativeImpl;
29 using JS::PrivateValue;
30 using JS::Value;
32 class RegExpGuard;
33 class JS_FRIEND_API(Wrapper);
35 /*
36 * A proxy is a JSObject that implements generic behavior by providing custom
37 * implementations for each object trap. The implementation for each trap is
38 * provided by a C++ object stored on the proxy, known as its handler.
39 *
40 * A major use case for proxies is to forward each trap to another object,
41 * known as its target. The target can be an arbitrary C++ object. Not every
42 * proxy has the notion of a target, however.
43 *
44 * Proxy traps are grouped into fundamental and derived traps. Every proxy has
45 * to at least provide implementations for the fundamental traps, but the
46 * derived traps can be implemented in terms of the fundamental ones
47 * BaseProxyHandler provides implementations of the derived traps in terms of
48 * the (pure virtual) fundamental traps.
49 *
50 * In addition to the normal traps, there are two models for proxy prototype
51 * chains. First, proxies may opt to use the standard prototype mechanism used
52 * throughout the engine. To do so, simply pass a prototype to NewProxyObject()
53 * at creation time. All prototype accesses will then "just work" to treat the
54 * proxy as a "normal" object. Alternatively, if instead the proxy wishes to
55 * implement more complicated prototype semantics (if, for example, it wants to
56 * delegate the prototype lookup to a wrapped object), it may pass Proxy::LazyProto
57 * as the prototype at create time and opt in to the trapped prototype system,
58 * which guarantees that their trap will be called on any and every prototype
59 * chain access of the object.
60 *
61 * This system is implemented with two traps: {get,set}PrototypeOf. The default
62 * implementation of setPrototypeOf throws a TypeError. Since it is not possible
63 * to create an object without a sense of prototype chain, handler implementors
64 * must provide a getPrototypeOf trap if opting in to the dynamic prototype system.
65 *
66 * To minimize code duplication, a set of abstract proxy handler classes is
67 * provided, from which other handlers may inherit. These abstract classes
68 * are organized in the following hierarchy:
69 *
70 * BaseProxyHandler
71 * |
72 * DirectProxyHandler
73 * |
74 * Wrapper
75 */
77 /*
78 * BaseProxyHandler is the most generic kind of proxy handler. It does not make
79 * any assumptions about the target. Consequently, it does not provide any
80 * default implementation for the fundamental traps. It does, however, implement
81 * the derived traps in terms of the fundamental ones. This allows consumers of
82 * this class to define any custom behavior they want.
83 *
84 * Important: If you add a trap here, you should probably also add a Proxy::foo
85 * entry point with an AutoEnterPolicy. If you don't, you need an explicit
86 * override for the trap in SecurityWrapper. See bug 945826 comment 0.
87 */
88 class JS_FRIEND_API(BaseProxyHandler)
89 {
90 const void *mFamily;
92 /*
93 * Proxy handlers can use mHasPrototype to request the following special
94 * treatment from the JS engine:
95 *
96 * - When mHasPrototype is true, the engine never calls these methods:
97 * getPropertyDescriptor, has, set, enumerate, iterate. Instead, for
98 * these operations, it calls the "own" traps like
99 * getOwnPropertyDescriptor, hasOwn, defineProperty, keys, etc., and
100 * consults the prototype chain if needed.
101 *
102 * - When mHasPrototype is true, the engine calls handler->get() only if
103 * handler->hasOwn() says an own property exists on the proxy. If not,
104 * it consults the prototype chain.
105 *
106 * This is useful because it frees the ProxyHandler from having to implement
107 * any behavior having to do with the prototype chain.
108 */
109 bool mHasPrototype;
111 /*
112 * All proxies indicate whether they have any sort of interesting security
113 * policy that might prevent the caller from doing something it wants to
114 * the object. In the case of wrappers, this distinction is used to
115 * determine whether the caller may strip off the wrapper if it so desires.
116 */
117 bool mHasSecurityPolicy;
119 protected:
120 // Subclasses may set this in their constructor.
121 void setHasPrototype(bool aHasPrototype) { mHasPrototype = aHasPrototype; }
122 void setHasSecurityPolicy(bool aHasPolicy) { mHasSecurityPolicy = aHasPolicy; }
124 public:
125 explicit BaseProxyHandler(const void *family);
126 virtual ~BaseProxyHandler();
128 bool hasPrototype() {
129 return mHasPrototype;
130 }
132 bool hasSecurityPolicy() {
133 return mHasSecurityPolicy;
134 }
136 inline const void *family() {
137 return mFamily;
138 }
139 static size_t offsetOfFamily() {
140 return offsetof(BaseProxyHandler, mFamily);
141 }
143 virtual bool finalizeInBackground(Value priv) {
144 /*
145 * Called on creation of a proxy to determine whether its finalize
146 * method can be finalized on the background thread.
147 */
148 return true;
149 }
151 /* Policy enforcement traps.
152 *
153 * enter() allows the policy to specify whether the caller may perform |act|
154 * on the proxy's |id| property. In the case when |act| is CALL, |id| is
155 * generally JSID_VOID.
156 *
157 * The |act| parameter to enter() specifies the action being performed.
158 * If |bp| is false, the trap suggests that the caller throw (though it
159 * may still decide to squelch the error).
160 *
161 * We make these OR-able so that assertEnteredPolicy can pass a union of them.
162 * For example, get{,Own}PropertyDescriptor is invoked by both calls to ::get()
163 * and ::set() (since we need to look up the accessor), so its
164 * assertEnteredPolicy would pass GET | SET.
165 */
166 typedef uint32_t Action;
167 enum {
168 NONE = 0x00,
169 GET = 0x01,
170 SET = 0x02,
171 CALL = 0x04,
172 ENUMERATE = 0x08
173 };
175 virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Action act,
176 bool *bp);
178 /* ES5 Harmony fundamental proxy traps. */
179 virtual bool preventExtensions(JSContext *cx, HandleObject proxy) = 0;
180 virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
181 MutableHandle<JSPropertyDescriptor> desc) = 0;
182 virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
183 HandleId id, MutableHandle<JSPropertyDescriptor> desc) = 0;
184 virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
185 MutableHandle<JSPropertyDescriptor> desc) = 0;
186 virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
187 AutoIdVector &props) = 0;
188 virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) = 0;
189 virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) = 0;
191 /* ES5 Harmony derived proxy traps. */
192 virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
193 virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
194 virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
195 HandleId id, MutableHandleValue vp);
196 virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
197 HandleId id, bool strict, MutableHandleValue vp);
198 virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props);
199 virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
200 MutableHandleValue vp);
202 /* Spidermonkey extensions. */
203 virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) = 0;
204 virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args);
205 virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args);
206 virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args);
207 virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp);
208 virtual bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx);
209 virtual const char *className(JSContext *cx, HandleObject proxy);
210 virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent);
211 virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g);
212 virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp);
213 virtual void finalize(JSFreeOp *fop, JSObject *proxy);
214 virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
215 virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp);
217 // These two hooks must be overridden, or not overridden, in tandem -- no
218 // overriding just one!
219 virtual bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
220 JS::HandleObject callable);
221 virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id);
223 virtual bool slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
224 HandleObject result);
226 /* See comment for weakmapKeyDelegateOp in js/Class.h. */
227 virtual JSObject *weakmapKeyDelegate(JSObject *proxy);
228 virtual bool isScripted() { return false; }
229 };
231 /*
232 * DirectProxyHandler includes a notion of a target object. All traps are
233 * reimplemented such that they forward their behavior to the target. This
234 * allows consumers of this class to forward to another object as transparently
235 * and efficiently as possible.
236 *
237 * Important: If you add a trap implementation here, you probably also need to
238 * add an override in CrossCompartmentWrapper. If you don't, you risk
239 * compartment mismatches. See bug 945826 comment 0.
240 */
241 class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler
242 {
243 public:
244 explicit DirectProxyHandler(const void *family);
246 /* ES5 Harmony fundamental proxy traps. */
247 virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
248 virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
249 MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
250 virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
251 MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
252 virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
253 MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
254 virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
255 AutoIdVector &props) MOZ_OVERRIDE;
256 virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id,
257 bool *bp) MOZ_OVERRIDE;
258 virtual bool enumerate(JSContext *cx, HandleObject proxy,
259 AutoIdVector &props) MOZ_OVERRIDE;
261 /* ES5 Harmony derived proxy traps. */
262 virtual bool has(JSContext *cx, HandleObject proxy, HandleId id,
263 bool *bp) MOZ_OVERRIDE;
264 virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id,
265 bool *bp) MOZ_OVERRIDE;
266 virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
267 HandleId id, MutableHandleValue vp) MOZ_OVERRIDE;
268 virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver,
269 HandleId id, bool strict, MutableHandleValue vp) MOZ_OVERRIDE;
270 virtual bool keys(JSContext *cx, HandleObject proxy,
271 AutoIdVector &props) MOZ_OVERRIDE;
272 virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags,
273 MutableHandleValue vp) MOZ_OVERRIDE;
275 /* Spidermonkey extensions. */
276 virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) MOZ_OVERRIDE;
277 virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
278 virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
279 virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
280 CallArgs args) MOZ_OVERRIDE;
281 virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v,
282 bool *bp) MOZ_OVERRIDE;
283 virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
284 virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp);
285 virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
286 JSContext *cx) MOZ_OVERRIDE;
287 virtual const char *className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
288 virtual JSString *fun_toString(JSContext *cx, HandleObject proxy,
289 unsigned indent) MOZ_OVERRIDE;
290 virtual bool regexp_toShared(JSContext *cx, HandleObject proxy,
291 RegExpGuard *g) MOZ_OVERRIDE;
292 virtual JSObject *weakmapKeyDelegate(JSObject *proxy);
293 };
295 /*
296 * Dispatch point for handlers that executes the appropriate C++ or scripted traps.
297 *
298 * Important: All proxy traps need either (a) an AutoEnterPolicy in their
299 * Proxy::foo entry point below or (b) an override in SecurityWrapper. See bug
300 * 945826 comment 0.
301 */
302 class Proxy
303 {
304 public:
305 /* ES5 Harmony fundamental proxy traps. */
306 static bool preventExtensions(JSContext *cx, HandleObject proxy);
307 static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
308 MutableHandle<JSPropertyDescriptor> desc);
309 static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
310 MutableHandleValue vp);
311 static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
312 MutableHandle<JSPropertyDescriptor> desc);
313 static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
314 MutableHandleValue vp);
315 static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
316 MutableHandle<JSPropertyDescriptor> desc);
317 static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v);
318 static bool getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props);
319 static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
320 static bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props);
322 /* ES5 Harmony derived proxy traps. */
323 static bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
324 static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
325 static bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
326 MutableHandleValue vp);
327 static bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
328 bool strict, MutableHandleValue vp);
329 static bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props);
330 static bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp);
332 /* Spidermonkey extensions. */
333 static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible);
334 static bool call(JSContext *cx, HandleObject proxy, const CallArgs &args);
335 static bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args);
336 static bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args);
337 static bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp);
338 static bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx);
339 static const char *className(JSContext *cx, HandleObject proxy);
340 static JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent);
341 static bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g);
342 static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp);
343 static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop);
344 static bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp);
346 static bool watch(JSContext *cx, HandleObject proxy, HandleId id, HandleObject callable);
347 static bool unwatch(JSContext *cx, HandleObject proxy, HandleId id);
349 static bool slice(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end,
350 HandleObject result);
352 /* IC entry path for handling __noSuchMethod__ on access. */
353 static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id,
354 MutableHandleValue vp);
355 };
357 // Use these in places where you don't want to #include vm/ProxyObject.h.
358 extern JS_FRIEND_DATA(const js::Class* const) CallableProxyClassPtr;
359 extern JS_FRIEND_DATA(const js::Class* const) UncallableProxyClassPtr;
361 inline bool IsProxy(JSObject *obj)
362 {
363 return GetObjectClass(obj)->isProxy();
364 }
366 /*
367 * These are part of the API.
368 *
369 * NOTE: PROXY_PRIVATE_SLOT is 0 because that way slot 0 is usable by API
370 * clients for both proxy and non-proxy objects. So an API client that only
371 * needs to store one slot's worth of data doesn't need to branch on what sort
372 * of object it has.
373 */
374 const uint32_t PROXY_PRIVATE_SLOT = 0;
375 const uint32_t PROXY_HANDLER_SLOT = 1;
376 const uint32_t PROXY_EXTRA_SLOT = 2;
377 const uint32_t PROXY_MINIMUM_SLOTS = 4;
379 inline BaseProxyHandler *
380 GetProxyHandler(JSObject *obj)
381 {
382 JS_ASSERT(IsProxy(obj));
383 return (BaseProxyHandler *) GetReservedSlot(obj, PROXY_HANDLER_SLOT).toPrivate();
384 }
386 inline const Value &
387 GetProxyPrivate(JSObject *obj)
388 {
389 JS_ASSERT(IsProxy(obj));
390 return GetReservedSlot(obj, PROXY_PRIVATE_SLOT);
391 }
393 inline JSObject *
394 GetProxyTargetObject(JSObject *obj)
395 {
396 JS_ASSERT(IsProxy(obj));
397 return GetProxyPrivate(obj).toObjectOrNull();
398 }
400 inline const Value &
401 GetProxyExtra(JSObject *obj, size_t n)
402 {
403 JS_ASSERT(IsProxy(obj));
404 return GetReservedSlot(obj, PROXY_EXTRA_SLOT + n);
405 }
407 inline void
408 SetProxyHandler(JSObject *obj, BaseProxyHandler *handler)
409 {
410 JS_ASSERT(IsProxy(obj));
411 SetReservedSlot(obj, PROXY_HANDLER_SLOT, PrivateValue(handler));
412 }
414 inline void
415 SetProxyExtra(JSObject *obj, size_t n, const Value &extra)
416 {
417 JS_ASSERT(IsProxy(obj));
418 JS_ASSERT(n <= 1);
419 SetReservedSlot(obj, PROXY_EXTRA_SLOT + n, extra);
420 }
422 inline bool
423 IsScriptedProxy(JSObject *obj)
424 {
425 return IsProxy(obj) && GetProxyHandler(obj)->isScripted();
426 }
428 class MOZ_STACK_CLASS ProxyOptions {
429 protected:
430 /* protected constructor for subclass */
431 ProxyOptions(bool singletonArg, const Class *claspArg)
432 : singleton_(singletonArg),
433 clasp_(claspArg)
434 {}
436 public:
437 ProxyOptions() : singleton_(false),
438 clasp_(UncallableProxyClassPtr)
439 {}
441 bool singleton() const { return singleton_; }
442 ProxyOptions &setSingleton(bool flag) {
443 singleton_ = flag;
444 return *this;
445 }
447 const Class *clasp() const {
448 return clasp_;
449 }
450 ProxyOptions &setClass(const Class *claspArg) {
451 clasp_ = claspArg;
452 return *this;
453 }
454 ProxyOptions &selectDefaultClass(bool callable) {
455 const Class *classp = callable? CallableProxyClassPtr :
456 UncallableProxyClassPtr;
457 return setClass(classp);
458 }
460 private:
461 bool singleton_;
462 const Class *clasp_;
463 };
465 JS_FRIEND_API(JSObject *)
466 NewProxyObject(JSContext *cx, BaseProxyHandler *handler, HandleValue priv,
467 JSObject *proto, JSObject *parent, const ProxyOptions &options = ProxyOptions());
469 JSObject *
470 RenewProxyObject(JSContext *cx, JSObject *obj, BaseProxyHandler *handler, Value priv);
472 class JS_FRIEND_API(AutoEnterPolicy)
473 {
474 public:
475 typedef BaseProxyHandler::Action Action;
476 AutoEnterPolicy(JSContext *cx, BaseProxyHandler *handler,
477 HandleObject wrapper, HandleId id, Action act, bool mayThrow)
478 #ifdef JS_DEBUG
479 : context(nullptr)
480 #endif
481 {
482 allow = handler->hasSecurityPolicy() ? handler->enter(cx, wrapper, id, act, &rv)
483 : true;
484 recordEnter(cx, wrapper, id, act);
485 // We want to throw an exception if all of the following are true:
486 // * The policy disallowed access.
487 // * The policy set rv to false, indicating that we should throw.
488 // * The caller did not instruct us to ignore exceptions.
489 // * The policy did not throw itself.
490 if (!allow && !rv && mayThrow)
491 reportErrorIfExceptionIsNotPending(cx, id);
492 }
494 virtual ~AutoEnterPolicy() { recordLeave(); }
495 inline bool allowed() { return allow; }
496 inline bool returnValue() { JS_ASSERT(!allowed()); return rv; }
498 protected:
499 // no-op constructor for subclass
500 AutoEnterPolicy()
501 #ifdef JS_DEBUG
502 : context(nullptr)
503 , enteredAction(BaseProxyHandler::NONE)
504 #endif
505 {};
506 void reportErrorIfExceptionIsNotPending(JSContext *cx, jsid id);
507 bool allow;
508 bool rv;
510 #ifdef JS_DEBUG
511 JSContext *context;
512 mozilla::Maybe<HandleObject> enteredProxy;
513 mozilla::Maybe<HandleId> enteredId;
514 Action enteredAction;
516 // NB: We explicitly don't track the entered action here, because sometimes
517 // SET traps do an implicit GET during their implementation, leading to
518 // spurious assertions.
519 AutoEnterPolicy *prev;
520 void recordEnter(JSContext *cx, HandleObject proxy, HandleId id, Action act);
521 void recordLeave();
523 friend JS_FRIEND_API(void) assertEnteredPolicy(JSContext *cx, JSObject *proxy, jsid id, Action act);
524 #else
525 inline void recordEnter(JSContext *cx, JSObject *proxy, jsid id, Action act) {}
526 inline void recordLeave() {}
527 #endif
529 };
531 #ifdef JS_DEBUG
532 class JS_FRIEND_API(AutoWaivePolicy) : public AutoEnterPolicy {
533 public:
534 AutoWaivePolicy(JSContext *cx, HandleObject proxy, HandleId id,
535 BaseProxyHandler::Action act)
536 {
537 allow = true;
538 recordEnter(cx, proxy, id, act);
539 }
540 };
541 #else
542 class JS_FRIEND_API(AutoWaivePolicy) {
543 public:
544 AutoWaivePolicy(JSContext *cx, HandleObject proxy, HandleId id,
545 BaseProxyHandler::Action act)
546 {}
547 };
548 #endif
550 #ifdef JS_DEBUG
551 extern JS_FRIEND_API(void)
552 assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id,
553 BaseProxyHandler::Action act);
554 #else
555 inline void assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id,
556 BaseProxyHandler::Action act)
557 {};
558 #endif
560 } /* namespace js */
562 extern JS_FRIEND_API(JSObject *)
563 js_InitProxyClass(JSContext *cx, JS::HandleObject obj);
565 #endif /* jsproxy_h */