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