1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/jsproxy.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,565 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#ifndef jsproxy_h 1.11 +#define jsproxy_h 1.12 + 1.13 +#include "mozilla/Maybe.h" 1.14 + 1.15 +#include "jsfriendapi.h" 1.16 + 1.17 +#include "js/CallNonGenericMethod.h" 1.18 +#include "js/Class.h" 1.19 + 1.20 +namespace js { 1.21 + 1.22 +using JS::AutoIdVector; 1.23 +using JS::CallArgs; 1.24 +using JS::HandleId; 1.25 +using JS::HandleObject; 1.26 +using JS::HandleValue; 1.27 +using JS::IsAcceptableThis; 1.28 +using JS::MutableHandle; 1.29 +using JS::MutableHandleObject; 1.30 +using JS::MutableHandleValue; 1.31 +using JS::NativeImpl; 1.32 +using JS::PrivateValue; 1.33 +using JS::Value; 1.34 + 1.35 +class RegExpGuard; 1.36 +class JS_FRIEND_API(Wrapper); 1.37 + 1.38 +/* 1.39 + * A proxy is a JSObject that implements generic behavior by providing custom 1.40 + * implementations for each object trap. The implementation for each trap is 1.41 + * provided by a C++ object stored on the proxy, known as its handler. 1.42 + * 1.43 + * A major use case for proxies is to forward each trap to another object, 1.44 + * known as its target. The target can be an arbitrary C++ object. Not every 1.45 + * proxy has the notion of a target, however. 1.46 + * 1.47 + * Proxy traps are grouped into fundamental and derived traps. Every proxy has 1.48 + * to at least provide implementations for the fundamental traps, but the 1.49 + * derived traps can be implemented in terms of the fundamental ones 1.50 + * BaseProxyHandler provides implementations of the derived traps in terms of 1.51 + * the (pure virtual) fundamental traps. 1.52 + * 1.53 + * In addition to the normal traps, there are two models for proxy prototype 1.54 + * chains. First, proxies may opt to use the standard prototype mechanism used 1.55 + * throughout the engine. To do so, simply pass a prototype to NewProxyObject() 1.56 + * at creation time. All prototype accesses will then "just work" to treat the 1.57 + * proxy as a "normal" object. Alternatively, if instead the proxy wishes to 1.58 + * implement more complicated prototype semantics (if, for example, it wants to 1.59 + * delegate the prototype lookup to a wrapped object), it may pass Proxy::LazyProto 1.60 + * as the prototype at create time and opt in to the trapped prototype system, 1.61 + * which guarantees that their trap will be called on any and every prototype 1.62 + * chain access of the object. 1.63 + * 1.64 + * This system is implemented with two traps: {get,set}PrototypeOf. The default 1.65 + * implementation of setPrototypeOf throws a TypeError. Since it is not possible 1.66 + * to create an object without a sense of prototype chain, handler implementors 1.67 + * must provide a getPrototypeOf trap if opting in to the dynamic prototype system. 1.68 + * 1.69 + * To minimize code duplication, a set of abstract proxy handler classes is 1.70 + * provided, from which other handlers may inherit. These abstract classes 1.71 + * are organized in the following hierarchy: 1.72 + * 1.73 + * BaseProxyHandler 1.74 + * | 1.75 + * DirectProxyHandler 1.76 + * | 1.77 + * Wrapper 1.78 + */ 1.79 + 1.80 +/* 1.81 + * BaseProxyHandler is the most generic kind of proxy handler. It does not make 1.82 + * any assumptions about the target. Consequently, it does not provide any 1.83 + * default implementation for the fundamental traps. It does, however, implement 1.84 + * the derived traps in terms of the fundamental ones. This allows consumers of 1.85 + * this class to define any custom behavior they want. 1.86 + * 1.87 + * Important: If you add a trap here, you should probably also add a Proxy::foo 1.88 + * entry point with an AutoEnterPolicy. If you don't, you need an explicit 1.89 + * override for the trap in SecurityWrapper. See bug 945826 comment 0. 1.90 + */ 1.91 +class JS_FRIEND_API(BaseProxyHandler) 1.92 +{ 1.93 + const void *mFamily; 1.94 + 1.95 + /* 1.96 + * Proxy handlers can use mHasPrototype to request the following special 1.97 + * treatment from the JS engine: 1.98 + * 1.99 + * - When mHasPrototype is true, the engine never calls these methods: 1.100 + * getPropertyDescriptor, has, set, enumerate, iterate. Instead, for 1.101 + * these operations, it calls the "own" traps like 1.102 + * getOwnPropertyDescriptor, hasOwn, defineProperty, keys, etc., and 1.103 + * consults the prototype chain if needed. 1.104 + * 1.105 + * - When mHasPrototype is true, the engine calls handler->get() only if 1.106 + * handler->hasOwn() says an own property exists on the proxy. If not, 1.107 + * it consults the prototype chain. 1.108 + * 1.109 + * This is useful because it frees the ProxyHandler from having to implement 1.110 + * any behavior having to do with the prototype chain. 1.111 + */ 1.112 + bool mHasPrototype; 1.113 + 1.114 + /* 1.115 + * All proxies indicate whether they have any sort of interesting security 1.116 + * policy that might prevent the caller from doing something it wants to 1.117 + * the object. In the case of wrappers, this distinction is used to 1.118 + * determine whether the caller may strip off the wrapper if it so desires. 1.119 + */ 1.120 + bool mHasSecurityPolicy; 1.121 + 1.122 + protected: 1.123 + // Subclasses may set this in their constructor. 1.124 + void setHasPrototype(bool aHasPrototype) { mHasPrototype = aHasPrototype; } 1.125 + void setHasSecurityPolicy(bool aHasPolicy) { mHasSecurityPolicy = aHasPolicy; } 1.126 + 1.127 + public: 1.128 + explicit BaseProxyHandler(const void *family); 1.129 + virtual ~BaseProxyHandler(); 1.130 + 1.131 + bool hasPrototype() { 1.132 + return mHasPrototype; 1.133 + } 1.134 + 1.135 + bool hasSecurityPolicy() { 1.136 + return mHasSecurityPolicy; 1.137 + } 1.138 + 1.139 + inline const void *family() { 1.140 + return mFamily; 1.141 + } 1.142 + static size_t offsetOfFamily() { 1.143 + return offsetof(BaseProxyHandler, mFamily); 1.144 + } 1.145 + 1.146 + virtual bool finalizeInBackground(Value priv) { 1.147 + /* 1.148 + * Called on creation of a proxy to determine whether its finalize 1.149 + * method can be finalized on the background thread. 1.150 + */ 1.151 + return true; 1.152 + } 1.153 + 1.154 + /* Policy enforcement traps. 1.155 + * 1.156 + * enter() allows the policy to specify whether the caller may perform |act| 1.157 + * on the proxy's |id| property. In the case when |act| is CALL, |id| is 1.158 + * generally JSID_VOID. 1.159 + * 1.160 + * The |act| parameter to enter() specifies the action being performed. 1.161 + * If |bp| is false, the trap suggests that the caller throw (though it 1.162 + * may still decide to squelch the error). 1.163 + * 1.164 + * We make these OR-able so that assertEnteredPolicy can pass a union of them. 1.165 + * For example, get{,Own}PropertyDescriptor is invoked by both calls to ::get() 1.166 + * and ::set() (since we need to look up the accessor), so its 1.167 + * assertEnteredPolicy would pass GET | SET. 1.168 + */ 1.169 + typedef uint32_t Action; 1.170 + enum { 1.171 + NONE = 0x00, 1.172 + GET = 0x01, 1.173 + SET = 0x02, 1.174 + CALL = 0x04, 1.175 + ENUMERATE = 0x08 1.176 + }; 1.177 + 1.178 + virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Action act, 1.179 + bool *bp); 1.180 + 1.181 + /* ES5 Harmony fundamental proxy traps. */ 1.182 + virtual bool preventExtensions(JSContext *cx, HandleObject proxy) = 0; 1.183 + virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, 1.184 + MutableHandle<JSPropertyDescriptor> desc) = 0; 1.185 + virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, 1.186 + HandleId id, MutableHandle<JSPropertyDescriptor> desc) = 0; 1.187 + virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, 1.188 + MutableHandle<JSPropertyDescriptor> desc) = 0; 1.189 + virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy, 1.190 + AutoIdVector &props) = 0; 1.191 + virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) = 0; 1.192 + virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) = 0; 1.193 + 1.194 + /* ES5 Harmony derived proxy traps. */ 1.195 + virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp); 1.196 + virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp); 1.197 + virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, 1.198 + HandleId id, MutableHandleValue vp); 1.199 + virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, 1.200 + HandleId id, bool strict, MutableHandleValue vp); 1.201 + virtual bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props); 1.202 + virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, 1.203 + MutableHandleValue vp); 1.204 + 1.205 + /* Spidermonkey extensions. */ 1.206 + virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) = 0; 1.207 + virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args); 1.208 + virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args); 1.209 + virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args); 1.210 + virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp); 1.211 + virtual bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx); 1.212 + virtual const char *className(JSContext *cx, HandleObject proxy); 1.213 + virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent); 1.214 + virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g); 1.215 + virtual bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp); 1.216 + virtual void finalize(JSFreeOp *fop, JSObject *proxy); 1.217 + virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop); 1.218 + virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp); 1.219 + 1.220 + // These two hooks must be overridden, or not overridden, in tandem -- no 1.221 + // overriding just one! 1.222 + virtual bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, 1.223 + JS::HandleObject callable); 1.224 + virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id); 1.225 + 1.226 + virtual bool slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end, 1.227 + HandleObject result); 1.228 + 1.229 + /* See comment for weakmapKeyDelegateOp in js/Class.h. */ 1.230 + virtual JSObject *weakmapKeyDelegate(JSObject *proxy); 1.231 + virtual bool isScripted() { return false; } 1.232 +}; 1.233 + 1.234 +/* 1.235 + * DirectProxyHandler includes a notion of a target object. All traps are 1.236 + * reimplemented such that they forward their behavior to the target. This 1.237 + * allows consumers of this class to forward to another object as transparently 1.238 + * and efficiently as possible. 1.239 + * 1.240 + * Important: If you add a trap implementation here, you probably also need to 1.241 + * add an override in CrossCompartmentWrapper. If you don't, you risk 1.242 + * compartment mismatches. See bug 945826 comment 0. 1.243 + */ 1.244 +class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler 1.245 +{ 1.246 + public: 1.247 + explicit DirectProxyHandler(const void *family); 1.248 + 1.249 + /* ES5 Harmony fundamental proxy traps. */ 1.250 + virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE; 1.251 + virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, 1.252 + MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE; 1.253 + virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, 1.254 + MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE; 1.255 + virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, 1.256 + MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE; 1.257 + virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy, 1.258 + AutoIdVector &props) MOZ_OVERRIDE; 1.259 + virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, 1.260 + bool *bp) MOZ_OVERRIDE; 1.261 + virtual bool enumerate(JSContext *cx, HandleObject proxy, 1.262 + AutoIdVector &props) MOZ_OVERRIDE; 1.263 + 1.264 + /* ES5 Harmony derived proxy traps. */ 1.265 + virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, 1.266 + bool *bp) MOZ_OVERRIDE; 1.267 + virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, 1.268 + bool *bp) MOZ_OVERRIDE; 1.269 + virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, 1.270 + HandleId id, MutableHandleValue vp) MOZ_OVERRIDE; 1.271 + virtual bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, 1.272 + HandleId id, bool strict, MutableHandleValue vp) MOZ_OVERRIDE; 1.273 + virtual bool keys(JSContext *cx, HandleObject proxy, 1.274 + AutoIdVector &props) MOZ_OVERRIDE; 1.275 + virtual bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, 1.276 + MutableHandleValue vp) MOZ_OVERRIDE; 1.277 + 1.278 + /* Spidermonkey extensions. */ 1.279 + virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) MOZ_OVERRIDE; 1.280 + virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE; 1.281 + virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE; 1.282 + virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, 1.283 + CallArgs args) MOZ_OVERRIDE; 1.284 + virtual bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, 1.285 + bool *bp) MOZ_OVERRIDE; 1.286 + virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop); 1.287 + virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp); 1.288 + virtual bool objectClassIs(HandleObject obj, ESClassValue classValue, 1.289 + JSContext *cx) MOZ_OVERRIDE; 1.290 + virtual const char *className(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE; 1.291 + virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, 1.292 + unsigned indent) MOZ_OVERRIDE; 1.293 + virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, 1.294 + RegExpGuard *g) MOZ_OVERRIDE; 1.295 + virtual JSObject *weakmapKeyDelegate(JSObject *proxy); 1.296 +}; 1.297 + 1.298 +/* 1.299 + * Dispatch point for handlers that executes the appropriate C++ or scripted traps. 1.300 + * 1.301 + * Important: All proxy traps need either (a) an AutoEnterPolicy in their 1.302 + * Proxy::foo entry point below or (b) an override in SecurityWrapper. See bug 1.303 + * 945826 comment 0. 1.304 + */ 1.305 +class Proxy 1.306 +{ 1.307 + public: 1.308 + /* ES5 Harmony fundamental proxy traps. */ 1.309 + static bool preventExtensions(JSContext *cx, HandleObject proxy); 1.310 + static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, 1.311 + MutableHandle<JSPropertyDescriptor> desc); 1.312 + static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, 1.313 + MutableHandleValue vp); 1.314 + static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, 1.315 + MutableHandle<JSPropertyDescriptor> desc); 1.316 + static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, 1.317 + MutableHandleValue vp); 1.318 + static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, 1.319 + MutableHandle<JSPropertyDescriptor> desc); 1.320 + static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v); 1.321 + static bool getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props); 1.322 + static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp); 1.323 + static bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props); 1.324 + 1.325 + /* ES5 Harmony derived proxy traps. */ 1.326 + static bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp); 1.327 + static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp); 1.328 + static bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, 1.329 + MutableHandleValue vp); 1.330 + static bool set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, 1.331 + bool strict, MutableHandleValue vp); 1.332 + static bool keys(JSContext *cx, HandleObject proxy, AutoIdVector &props); 1.333 + static bool iterate(JSContext *cx, HandleObject proxy, unsigned flags, MutableHandleValue vp); 1.334 + 1.335 + /* Spidermonkey extensions. */ 1.336 + static bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible); 1.337 + static bool call(JSContext *cx, HandleObject proxy, const CallArgs &args); 1.338 + static bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args); 1.339 + static bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl, CallArgs args); 1.340 + static bool hasInstance(JSContext *cx, HandleObject proxy, MutableHandleValue v, bool *bp); 1.341 + static bool objectClassIs(HandleObject obj, ESClassValue classValue, JSContext *cx); 1.342 + static const char *className(JSContext *cx, HandleObject proxy); 1.343 + static JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent); 1.344 + static bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g); 1.345 + static bool defaultValue(JSContext *cx, HandleObject obj, JSType hint, MutableHandleValue vp); 1.346 + static bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop); 1.347 + static bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp); 1.348 + 1.349 + static bool watch(JSContext *cx, HandleObject proxy, HandleId id, HandleObject callable); 1.350 + static bool unwatch(JSContext *cx, HandleObject proxy, HandleId id); 1.351 + 1.352 + static bool slice(JSContext *cx, HandleObject obj, uint32_t begin, uint32_t end, 1.353 + HandleObject result); 1.354 + 1.355 + /* IC entry path for handling __noSuchMethod__ on access. */ 1.356 + static bool callProp(JSContext *cx, HandleObject proxy, HandleObject reveiver, HandleId id, 1.357 + MutableHandleValue vp); 1.358 +}; 1.359 + 1.360 +// Use these in places where you don't want to #include vm/ProxyObject.h. 1.361 +extern JS_FRIEND_DATA(const js::Class* const) CallableProxyClassPtr; 1.362 +extern JS_FRIEND_DATA(const js::Class* const) UncallableProxyClassPtr; 1.363 + 1.364 +inline bool IsProxy(JSObject *obj) 1.365 +{ 1.366 + return GetObjectClass(obj)->isProxy(); 1.367 +} 1.368 + 1.369 +/* 1.370 + * These are part of the API. 1.371 + * 1.372 + * NOTE: PROXY_PRIVATE_SLOT is 0 because that way slot 0 is usable by API 1.373 + * clients for both proxy and non-proxy objects. So an API client that only 1.374 + * needs to store one slot's worth of data doesn't need to branch on what sort 1.375 + * of object it has. 1.376 + */ 1.377 +const uint32_t PROXY_PRIVATE_SLOT = 0; 1.378 +const uint32_t PROXY_HANDLER_SLOT = 1; 1.379 +const uint32_t PROXY_EXTRA_SLOT = 2; 1.380 +const uint32_t PROXY_MINIMUM_SLOTS = 4; 1.381 + 1.382 +inline BaseProxyHandler * 1.383 +GetProxyHandler(JSObject *obj) 1.384 +{ 1.385 + JS_ASSERT(IsProxy(obj)); 1.386 + return (BaseProxyHandler *) GetReservedSlot(obj, PROXY_HANDLER_SLOT).toPrivate(); 1.387 +} 1.388 + 1.389 +inline const Value & 1.390 +GetProxyPrivate(JSObject *obj) 1.391 +{ 1.392 + JS_ASSERT(IsProxy(obj)); 1.393 + return GetReservedSlot(obj, PROXY_PRIVATE_SLOT); 1.394 +} 1.395 + 1.396 +inline JSObject * 1.397 +GetProxyTargetObject(JSObject *obj) 1.398 +{ 1.399 + JS_ASSERT(IsProxy(obj)); 1.400 + return GetProxyPrivate(obj).toObjectOrNull(); 1.401 +} 1.402 + 1.403 +inline const Value & 1.404 +GetProxyExtra(JSObject *obj, size_t n) 1.405 +{ 1.406 + JS_ASSERT(IsProxy(obj)); 1.407 + return GetReservedSlot(obj, PROXY_EXTRA_SLOT + n); 1.408 +} 1.409 + 1.410 +inline void 1.411 +SetProxyHandler(JSObject *obj, BaseProxyHandler *handler) 1.412 +{ 1.413 + JS_ASSERT(IsProxy(obj)); 1.414 + SetReservedSlot(obj, PROXY_HANDLER_SLOT, PrivateValue(handler)); 1.415 +} 1.416 + 1.417 +inline void 1.418 +SetProxyExtra(JSObject *obj, size_t n, const Value &extra) 1.419 +{ 1.420 + JS_ASSERT(IsProxy(obj)); 1.421 + JS_ASSERT(n <= 1); 1.422 + SetReservedSlot(obj, PROXY_EXTRA_SLOT + n, extra); 1.423 +} 1.424 + 1.425 +inline bool 1.426 +IsScriptedProxy(JSObject *obj) 1.427 +{ 1.428 + return IsProxy(obj) && GetProxyHandler(obj)->isScripted(); 1.429 +} 1.430 + 1.431 +class MOZ_STACK_CLASS ProxyOptions { 1.432 + protected: 1.433 + /* protected constructor for subclass */ 1.434 + ProxyOptions(bool singletonArg, const Class *claspArg) 1.435 + : singleton_(singletonArg), 1.436 + clasp_(claspArg) 1.437 + {} 1.438 + 1.439 + public: 1.440 + ProxyOptions() : singleton_(false), 1.441 + clasp_(UncallableProxyClassPtr) 1.442 + {} 1.443 + 1.444 + bool singleton() const { return singleton_; } 1.445 + ProxyOptions &setSingleton(bool flag) { 1.446 + singleton_ = flag; 1.447 + return *this; 1.448 + } 1.449 + 1.450 + const Class *clasp() const { 1.451 + return clasp_; 1.452 + } 1.453 + ProxyOptions &setClass(const Class *claspArg) { 1.454 + clasp_ = claspArg; 1.455 + return *this; 1.456 + } 1.457 + ProxyOptions &selectDefaultClass(bool callable) { 1.458 + const Class *classp = callable? CallableProxyClassPtr : 1.459 + UncallableProxyClassPtr; 1.460 + return setClass(classp); 1.461 + } 1.462 + 1.463 + private: 1.464 + bool singleton_; 1.465 + const Class *clasp_; 1.466 +}; 1.467 + 1.468 +JS_FRIEND_API(JSObject *) 1.469 +NewProxyObject(JSContext *cx, BaseProxyHandler *handler, HandleValue priv, 1.470 + JSObject *proto, JSObject *parent, const ProxyOptions &options = ProxyOptions()); 1.471 + 1.472 +JSObject * 1.473 +RenewProxyObject(JSContext *cx, JSObject *obj, BaseProxyHandler *handler, Value priv); 1.474 + 1.475 +class JS_FRIEND_API(AutoEnterPolicy) 1.476 +{ 1.477 + public: 1.478 + typedef BaseProxyHandler::Action Action; 1.479 + AutoEnterPolicy(JSContext *cx, BaseProxyHandler *handler, 1.480 + HandleObject wrapper, HandleId id, Action act, bool mayThrow) 1.481 +#ifdef JS_DEBUG 1.482 + : context(nullptr) 1.483 +#endif 1.484 + { 1.485 + allow = handler->hasSecurityPolicy() ? handler->enter(cx, wrapper, id, act, &rv) 1.486 + : true; 1.487 + recordEnter(cx, wrapper, id, act); 1.488 + // We want to throw an exception if all of the following are true: 1.489 + // * The policy disallowed access. 1.490 + // * The policy set rv to false, indicating that we should throw. 1.491 + // * The caller did not instruct us to ignore exceptions. 1.492 + // * The policy did not throw itself. 1.493 + if (!allow && !rv && mayThrow) 1.494 + reportErrorIfExceptionIsNotPending(cx, id); 1.495 + } 1.496 + 1.497 + virtual ~AutoEnterPolicy() { recordLeave(); } 1.498 + inline bool allowed() { return allow; } 1.499 + inline bool returnValue() { JS_ASSERT(!allowed()); return rv; } 1.500 + 1.501 + protected: 1.502 + // no-op constructor for subclass 1.503 + AutoEnterPolicy() 1.504 +#ifdef JS_DEBUG 1.505 + : context(nullptr) 1.506 + , enteredAction(BaseProxyHandler::NONE) 1.507 +#endif 1.508 + {}; 1.509 + void reportErrorIfExceptionIsNotPending(JSContext *cx, jsid id); 1.510 + bool allow; 1.511 + bool rv; 1.512 + 1.513 +#ifdef JS_DEBUG 1.514 + JSContext *context; 1.515 + mozilla::Maybe<HandleObject> enteredProxy; 1.516 + mozilla::Maybe<HandleId> enteredId; 1.517 + Action enteredAction; 1.518 + 1.519 + // NB: We explicitly don't track the entered action here, because sometimes 1.520 + // SET traps do an implicit GET during their implementation, leading to 1.521 + // spurious assertions. 1.522 + AutoEnterPolicy *prev; 1.523 + void recordEnter(JSContext *cx, HandleObject proxy, HandleId id, Action act); 1.524 + void recordLeave(); 1.525 + 1.526 + friend JS_FRIEND_API(void) assertEnteredPolicy(JSContext *cx, JSObject *proxy, jsid id, Action act); 1.527 +#else 1.528 + inline void recordEnter(JSContext *cx, JSObject *proxy, jsid id, Action act) {} 1.529 + inline void recordLeave() {} 1.530 +#endif 1.531 + 1.532 +}; 1.533 + 1.534 +#ifdef JS_DEBUG 1.535 +class JS_FRIEND_API(AutoWaivePolicy) : public AutoEnterPolicy { 1.536 +public: 1.537 + AutoWaivePolicy(JSContext *cx, HandleObject proxy, HandleId id, 1.538 + BaseProxyHandler::Action act) 1.539 + { 1.540 + allow = true; 1.541 + recordEnter(cx, proxy, id, act); 1.542 + } 1.543 +}; 1.544 +#else 1.545 +class JS_FRIEND_API(AutoWaivePolicy) { 1.546 + public: 1.547 + AutoWaivePolicy(JSContext *cx, HandleObject proxy, HandleId id, 1.548 + BaseProxyHandler::Action act) 1.549 + {} 1.550 +}; 1.551 +#endif 1.552 + 1.553 +#ifdef JS_DEBUG 1.554 +extern JS_FRIEND_API(void) 1.555 +assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id, 1.556 + BaseProxyHandler::Action act); 1.557 +#else 1.558 +inline void assertEnteredPolicy(JSContext *cx, JSObject *obj, jsid id, 1.559 + BaseProxyHandler::Action act) 1.560 +{}; 1.561 +#endif 1.562 + 1.563 +} /* namespace js */ 1.564 + 1.565 +extern JS_FRIEND_API(JSObject *) 1.566 +js_InitProxyClass(JSContext *cx, JS::HandleObject obj); 1.567 + 1.568 +#endif /* jsproxy_h */