summaryrefslogtreecommitdiffstats
path: root/js/xpconnect/wrappers/XrayWrapper.h
diff options
context:
space:
mode:
Diffstat (limited to 'js/xpconnect/wrappers/XrayWrapper.h')
-rw-r--r--js/xpconnect/wrappers/XrayWrapper.h620
1 files changed, 620 insertions, 0 deletions
diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h
new file mode 100644
index 000000000..5630982c2
--- /dev/null
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -0,0 +1,620 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* vim: set ts=8 sts=4 et sw=4 tw=99: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef XrayWrapper_h
+#define XrayWrapper_h
+
+#include "mozilla/Attributes.h"
+
+#include "WrapperFactory.h"
+
+#include "jswrapper.h"
+#include "js/Proxy.h"
+
+// Slot where Xray functions for Web IDL methods store a pointer to
+// the Xray wrapper they're associated with.
+#define XRAY_DOM_FUNCTION_PARENT_WRAPPER_SLOT 0
+// Slot where in debug builds Xray functions for Web IDL methods store
+// a pointer to their themselves, just so we can assert that they're the
+// sort of functions we expect.
+#define XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_SELF 1
+
+// Xray wrappers re-resolve the original native properties on the native
+// object and always directly access to those properties.
+// Because they work so differently from the rest of the wrapper hierarchy,
+// we pull them out of the Wrapper inheritance hierarchy and create a
+// little world around them.
+
+class nsIPrincipal;
+class XPCWrappedNative;
+
+namespace xpc {
+
+namespace XrayUtils {
+
+bool IsXPCWNHolderClass(const JSClass* clasp);
+
+bool CloneExpandoChain(JSContext* cx, JSObject* src, JSObject* dst);
+
+bool
+IsTransparent(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id);
+
+JSObject*
+GetNativePropertiesObject(JSContext* cx, JSObject* wrapper);
+
+bool
+HasNativeProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id,
+ bool* hasProp);
+} // namespace XrayUtils
+
+enum XrayType {
+ XrayForDOMObject,
+ XrayForWrappedNative,
+ XrayForJSObject,
+ XrayForOpaqueObject,
+ NotXray
+};
+
+class XrayTraits
+{
+public:
+ constexpr XrayTraits() {}
+
+ static JSObject* getTargetObject(JSObject* wrapper) {
+ return js::UncheckedUnwrap(wrapper, /* stopAtWindowProxy = */ false);
+ }
+
+ virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper,
+ JS::HandleObject holder, JS::HandleId id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc) = 0;
+ // NB: resolveOwnProperty may decide whether or not to cache what it finds
+ // on the holder. If the result is not cached, the lookup will happen afresh
+ // for each access, which is the right thing for things like dynamic NodeList
+ // properties.
+ virtual bool resolveOwnProperty(JSContext* cx, const js::Wrapper& jsWrapper,
+ JS::HandleObject wrapper, JS::HandleObject holder,
+ JS::HandleId id, JS::MutableHandle<JS::PropertyDescriptor> desc);
+
+ bool delete_(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id,
+ JS::ObjectOpResult& result) {
+ return result.succeed();
+ }
+
+ static bool getBuiltinClass(JSContext* cx, JS::HandleObject wrapper, const js::Wrapper& baseInstance,
+ js::ESClass* cls) {
+ return baseInstance.getBuiltinClass(cx, wrapper, cls);
+ }
+
+ static const char* className(JSContext* cx, JS::HandleObject wrapper, const js::Wrapper& baseInstance) {
+ return baseInstance.className(cx, wrapper);
+ }
+
+ virtual void preserveWrapper(JSObject* target) = 0;
+
+ bool getExpandoObject(JSContext* cx, JS::HandleObject target,
+ JS::HandleObject consumer, JS::MutableHandleObject expandObject);
+ JSObject* ensureExpandoObject(JSContext* cx, JS::HandleObject wrapper,
+ JS::HandleObject target);
+
+ JSObject* getHolder(JSObject* wrapper);
+ JSObject* ensureHolder(JSContext* cx, JS::HandleObject wrapper);
+ virtual JSObject* createHolder(JSContext* cx, JSObject* wrapper) = 0;
+
+ JSObject* getExpandoChain(JS::HandleObject obj);
+ bool setExpandoChain(JSContext* cx, JS::HandleObject obj, JS::HandleObject chain);
+ bool cloneExpandoChain(JSContext* cx, JS::HandleObject dst, JS::HandleObject src);
+
+protected:
+ // Get the JSClass we should use for our expando object.
+ virtual const JSClass* getExpandoClass(JSContext* cx,
+ JS::HandleObject target) const;
+
+private:
+ bool expandoObjectMatchesConsumer(JSContext* cx, JS::HandleObject expandoObject,
+ nsIPrincipal* consumerOrigin,
+ JS::HandleObject exclusiveGlobal);
+ bool getExpandoObjectInternal(JSContext* cx, JS::HandleObject target,
+ nsIPrincipal* origin, JSObject* exclusiveGlobal,
+ JS::MutableHandleObject expandoObject);
+ JSObject* attachExpandoObject(JSContext* cx, JS::HandleObject target,
+ nsIPrincipal* origin,
+ JS::HandleObject exclusiveGlobal);
+
+ XrayTraits(XrayTraits&) = delete;
+ const XrayTraits& operator=(XrayTraits&) = delete;
+};
+
+class XPCWrappedNativeXrayTraits : public XrayTraits
+{
+public:
+ enum {
+ HasPrototype = 0
+ };
+
+ static const XrayType Type = XrayForWrappedNative;
+
+ virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper,
+ JS::HandleObject holder, JS::HandleId id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc) override;
+ virtual bool resolveOwnProperty(JSContext* cx, const js::Wrapper& jsWrapper, JS::HandleObject wrapper,
+ JS::HandleObject holder, JS::HandleId id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc) override;
+ bool defineProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id,
+ JS::Handle<JS::PropertyDescriptor> desc,
+ JS::Handle<JS::PropertyDescriptor> existingDesc,
+ JS::ObjectOpResult& result, bool* defined)
+ {
+ *defined = false;
+ return true;
+ }
+ virtual bool enumerateNames(JSContext* cx, JS::HandleObject wrapper, unsigned flags,
+ JS::AutoIdVector& props);
+ static bool call(JSContext* cx, JS::HandleObject wrapper,
+ const JS::CallArgs& args, const js::Wrapper& baseInstance);
+ static bool construct(JSContext* cx, JS::HandleObject wrapper,
+ const JS::CallArgs& args, const js::Wrapper& baseInstance);
+
+ static XPCWrappedNative* getWN(JSObject* wrapper);
+
+ virtual void preserveWrapper(JSObject* target) override;
+
+ virtual JSObject* createHolder(JSContext* cx, JSObject* wrapper) override;
+
+ static const JSClass HolderClass;
+ static XPCWrappedNativeXrayTraits singleton;
+};
+
+class DOMXrayTraits : public XrayTraits
+{
+public:
+ constexpr DOMXrayTraits() = default;
+
+ enum {
+ HasPrototype = 1
+ };
+
+ static const XrayType Type = XrayForDOMObject;
+
+ virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper,
+ JS::HandleObject holder, JS::HandleId id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc) override
+ {
+ // Xrays for DOM binding objects have a prototype chain that consists of
+ // Xrays for the prototypes of the DOM binding object (ignoring changes
+ // in the prototype chain made by script, plugins or XBL). All properties for
+ // these Xrays are really own properties, either of the instance object or
+ // of the prototypes.
+ // FIXME https://bugzilla.mozilla.org/show_bug.cgi?id=1072482
+ // This should really be:
+ // MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1");
+ // but we can't do that yet because XrayUtils::HasNativeProperty calls this.
+ return true;
+ }
+ virtual bool resolveOwnProperty(JSContext* cx, const js::Wrapper& jsWrapper, JS::HandleObject wrapper,
+ JS::HandleObject holder, JS::HandleId id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc) override;
+
+ bool delete_(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, JS::ObjectOpResult& result);
+
+ bool defineProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id,
+ JS::Handle<JS::PropertyDescriptor> desc,
+ JS::Handle<JS::PropertyDescriptor> existingDesc,
+ JS::ObjectOpResult& result, bool* defined);
+ virtual bool enumerateNames(JSContext* cx, JS::HandleObject wrapper, unsigned flags,
+ JS::AutoIdVector& props);
+ static bool call(JSContext* cx, JS::HandleObject wrapper,
+ const JS::CallArgs& args, const js::Wrapper& baseInstance);
+ static bool construct(JSContext* cx, JS::HandleObject wrapper,
+ const JS::CallArgs& args, const js::Wrapper& baseInstance);
+
+ static bool getPrototype(JSContext* cx, JS::HandleObject wrapper,
+ JS::HandleObject target,
+ JS::MutableHandleObject protop);
+
+ virtual void preserveWrapper(JSObject* target) override;
+
+ virtual JSObject* createHolder(JSContext* cx, JSObject* wrapper) override;
+
+ static DOMXrayTraits singleton;
+
+protected:
+ virtual const JSClass* getExpandoClass(JSContext* cx,
+ JS::HandleObject target) const override;
+};
+
+class JSXrayTraits : public XrayTraits
+{
+public:
+ enum {
+ HasPrototype = 1
+ };
+ static const XrayType Type = XrayForJSObject;
+
+ virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper,
+ JS::HandleObject holder, JS::HandleId id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc) override
+ {
+ MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1");
+ }
+
+ virtual bool resolveOwnProperty(JSContext* cx, const js::Wrapper& jsWrapper, JS::HandleObject wrapper,
+ JS::HandleObject holder, JS::HandleId id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc) override;
+
+ bool delete_(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, JS::ObjectOpResult& result);
+
+ bool defineProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id,
+ JS::Handle<JS::PropertyDescriptor> desc,
+ JS::Handle<JS::PropertyDescriptor> existingDesc,
+ JS::ObjectOpResult& result, bool* defined);
+
+ virtual bool enumerateNames(JSContext* cx, JS::HandleObject wrapper, unsigned flags,
+ JS::AutoIdVector& props);
+
+ static bool call(JSContext* cx, JS::HandleObject wrapper,
+ const JS::CallArgs& args, const js::Wrapper& baseInstance)
+ {
+ JSXrayTraits& self = JSXrayTraits::singleton;
+ JS::RootedObject holder(cx, self.ensureHolder(cx, wrapper));
+ if (self.getProtoKey(holder) == JSProto_Function)
+ return baseInstance.call(cx, wrapper, args);
+
+ JS::RootedValue v(cx, JS::ObjectValue(*wrapper));
+ js::ReportIsNotFunction(cx, v);
+ return false;
+ }
+
+ static bool construct(JSContext* cx, JS::HandleObject wrapper,
+ const JS::CallArgs& args, const js::Wrapper& baseInstance);
+
+ bool getPrototype(JSContext* cx, JS::HandleObject wrapper,
+ JS::HandleObject target,
+ JS::MutableHandleObject protop)
+ {
+ JS::RootedObject holder(cx, ensureHolder(cx, wrapper));
+ JSProtoKey key = getProtoKey(holder);
+ if (isPrototype(holder)) {
+ JSProtoKey protoKey = js::InheritanceProtoKeyForStandardClass(key);
+ if (protoKey == JSProto_Null) {
+ protop.set(nullptr);
+ return true;
+ }
+ key = protoKey;
+ }
+
+ {
+ JSAutoCompartment ac(cx, target);
+ if (!JS_GetClassPrototype(cx, key, protop))
+ return false;
+ }
+ return JS_WrapObject(cx, protop);
+ }
+
+ virtual void preserveWrapper(JSObject* target) override {
+ // In the case of pure JS objects, there is no underlying object, and
+ // the target is the canonical representation of state. If it gets
+ // collected, then expandos and such should be collected too. So there's
+ // nothing to do here.
+ }
+
+ enum {
+ SLOT_PROTOKEY = 0,
+ SLOT_ISPROTOTYPE,
+ SLOT_CONSTRUCTOR_FOR,
+ SLOT_COUNT
+ };
+ virtual JSObject* createHolder(JSContext* cx, JSObject* wrapper) override;
+
+ static JSProtoKey getProtoKey(JSObject* holder) {
+ int32_t key = js::GetReservedSlot(holder, SLOT_PROTOKEY).toInt32();
+ return static_cast<JSProtoKey>(key);
+ }
+
+ static bool isPrototype(JSObject* holder) {
+ return js::GetReservedSlot(holder, SLOT_ISPROTOTYPE).toBoolean();
+ }
+
+ static JSProtoKey constructorFor(JSObject* holder) {
+ int32_t key = js::GetReservedSlot(holder, SLOT_CONSTRUCTOR_FOR).toInt32();
+ return static_cast<JSProtoKey>(key);
+ }
+
+ // Operates in the wrapper compartment.
+ static bool getOwnPropertyFromWrapperIfSafe(JSContext* cx,
+ JS::HandleObject wrapper,
+ JS::HandleId id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc);
+
+ // Like the above, but operates in the target compartment.
+ static bool getOwnPropertyFromTargetIfSafe(JSContext* cx,
+ JS::HandleObject target,
+ JS::HandleObject wrapper,
+ JS::HandleId id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc);
+
+ static const JSClass HolderClass;
+ static JSXrayTraits singleton;
+};
+
+// These traits are used when the target is not Xrayable and we therefore want
+// to make it opaque modulo the usual Xray machinery (like expandos and
+// .wrappedJSObject).
+class OpaqueXrayTraits : public XrayTraits
+{
+public:
+ enum {
+ HasPrototype = 1
+ };
+ static const XrayType Type = XrayForOpaqueObject;
+
+ virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper,
+ JS::HandleObject holder, JS::HandleId id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc) override
+ {
+ MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1");
+ }
+
+ virtual bool resolveOwnProperty(JSContext* cx, const js::Wrapper& jsWrapper, JS::HandleObject wrapper,
+ JS::HandleObject holder, JS::HandleId id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc) override;
+
+ bool defineProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id,
+ JS::Handle<JS::PropertyDescriptor> desc,
+ JS::Handle<JS::PropertyDescriptor> existingDesc,
+ JS::ObjectOpResult& result, bool* defined)
+ {
+ *defined = false;
+ return true;
+ }
+
+ virtual bool enumerateNames(JSContext* cx, JS::HandleObject wrapper, unsigned flags,
+ JS::AutoIdVector& props)
+ {
+ return true;
+ }
+
+ static bool call(JSContext* cx, JS::HandleObject wrapper,
+ const JS::CallArgs& args, const js::Wrapper& baseInstance)
+ {
+ JS::RootedValue v(cx, JS::ObjectValue(*wrapper));
+ js::ReportIsNotFunction(cx, v);
+ return false;
+ }
+
+ static bool construct(JSContext* cx, JS::HandleObject wrapper,
+ const JS::CallArgs& args, const js::Wrapper& baseInstance)
+ {
+ JS::RootedValue v(cx, JS::ObjectValue(*wrapper));
+ js::ReportIsNotFunction(cx, v);
+ return false;
+ }
+
+ bool getPrototype(JSContext* cx, JS::HandleObject wrapper,
+ JS::HandleObject target,
+ JS::MutableHandleObject protop)
+ {
+ // Opaque wrappers just get targetGlobal.Object.prototype as their
+ // prototype. This is preferable to using a null prototype because it
+ // lets things like |toString| and |__proto__| work.
+ {
+ JSAutoCompartment ac(cx, target);
+ if (!JS_GetClassPrototype(cx, JSProto_Object, protop))
+ return false;
+ }
+ return JS_WrapObject(cx, protop);
+ }
+
+ static bool getBuiltinClass(JSContext* cx, JS::HandleObject wrapper, const js::Wrapper& baseInstance,
+ js::ESClass* cls) {
+ *cls = js::ESClass::Other;
+ return true;
+ }
+
+ static const char* className(JSContext* cx, JS::HandleObject wrapper, const js::Wrapper& baseInstance) {
+ return "Opaque";
+ }
+
+ virtual void preserveWrapper(JSObject* target) override { }
+
+ virtual JSObject* createHolder(JSContext* cx, JSObject* wrapper) override
+ {
+ return JS_NewObjectWithGivenProto(cx, nullptr, nullptr);
+ }
+
+ static OpaqueXrayTraits singleton;
+};
+
+XrayType GetXrayType(JSObject* obj);
+XrayTraits* GetXrayTraits(JSObject* obj);
+
+// NB: Base *must* derive from JSProxyHandler
+template <typename Base, typename Traits = XPCWrappedNativeXrayTraits >
+class XrayWrapper : public Base {
+ public:
+ constexpr explicit XrayWrapper(unsigned flags)
+ : Base(flags | WrapperFactory::IS_XRAY_WRAPPER_FLAG, Traits::HasPrototype)
+ { };
+
+ /* Standard internal methods. */
+ virtual bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
+ virtual bool defineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
+ JS::Handle<JS::PropertyDescriptor> desc,
+ JS::ObjectOpResult& result) const override;
+ virtual bool ownPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
+ JS::AutoIdVector& props) const override;
+ virtual bool delete_(JSContext* cx, JS::Handle<JSObject*> wrapper,
+ JS::Handle<jsid> id, JS::ObjectOpResult& result) const override;
+ virtual bool enumerate(JSContext* cx, JS::Handle<JSObject*> wrapper,
+ JS::MutableHandle<JSObject*> objp) const override;
+ virtual bool getPrototype(JSContext* cx, JS::HandleObject wrapper,
+ JS::MutableHandleObject protop) const override;
+ virtual bool setPrototype(JSContext* cx, JS::HandleObject wrapper,
+ JS::HandleObject proto, JS::ObjectOpResult& result) const override;
+ virtual bool getPrototypeIfOrdinary(JSContext* cx, JS::HandleObject wrapper, bool* isOrdinary,
+ JS::MutableHandleObject protop) const override;
+ virtual bool setImmutablePrototype(JSContext* cx, JS::HandleObject wrapper,
+ bool* succeeded) const override;
+ virtual bool preventExtensions(JSContext* cx, JS::Handle<JSObject*> wrapper,
+ JS::ObjectOpResult& result) const override;
+ virtual bool isExtensible(JSContext* cx, JS::Handle<JSObject*> wrapper, bool* extensible) const override;
+ virtual bool has(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
+ bool* bp) const override;
+ virtual bool get(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::HandleValue receiver,
+ JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const override;
+ virtual bool set(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
+ JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver,
+ JS::ObjectOpResult& result) const override;
+ virtual bool call(JSContext* cx, JS::Handle<JSObject*> wrapper,
+ const JS::CallArgs& args) const override;
+ virtual bool construct(JSContext* cx, JS::Handle<JSObject*> wrapper,
+ const JS::CallArgs& args) const override;
+
+ /* SpiderMonkey extensions. */
+ virtual bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
+ virtual bool hasOwn(JSContext* cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
+ bool* bp) const override;
+ virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper,
+ JS::AutoIdVector& props) const override;
+
+ virtual bool getBuiltinClass(JSContext* cx, JS::HandleObject wapper, js::ESClass* cls) const override;
+ virtual const char* className(JSContext* cx, JS::HandleObject proxy) const override;
+
+ static const XrayWrapper singleton;
+
+ private:
+ template <bool HasPrototype>
+ typename mozilla::EnableIf<HasPrototype, bool>::Type
+ getPrototypeHelper(JSContext* cx, JS::HandleObject wrapper,
+ JS::HandleObject target, JS::MutableHandleObject protop) const
+ {
+ return Traits::singleton.getPrototype(cx, wrapper, target, protop);
+ }
+ template <bool HasPrototype>
+ typename mozilla::EnableIf<!HasPrototype, bool>::Type
+ getPrototypeHelper(JSContext* cx, JS::HandleObject wrapper,
+ JS::HandleObject target, JS::MutableHandleObject protop) const
+ {
+ return Base::getPrototype(cx, wrapper, protop);
+ }
+ bool getPrototypeHelper(JSContext* cx, JS::HandleObject wrapper,
+ JS::HandleObject target, JS::MutableHandleObject protop) const
+ {
+ return getPrototypeHelper<Traits::HasPrototype>(cx, wrapper, target,
+ protop);
+ }
+
+ protected:
+ bool getPropertyKeys(JSContext* cx, JS::Handle<JSObject*> wrapper, unsigned flags,
+ JS::AutoIdVector& props) const;
+};
+
+#define PermissiveXrayXPCWN xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::XPCWrappedNativeXrayTraits>
+#define SecurityXrayXPCWN xpc::XrayWrapper<js::CrossCompartmentSecurityWrapper, xpc::XPCWrappedNativeXrayTraits>
+#define PermissiveXrayDOM xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::DOMXrayTraits>
+#define SecurityXrayDOM xpc::XrayWrapper<js::CrossCompartmentSecurityWrapper, xpc::DOMXrayTraits>
+#define PermissiveXrayJS xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::JSXrayTraits>
+#define PermissiveXrayOpaque xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::OpaqueXrayTraits>
+
+extern template class PermissiveXrayXPCWN;
+extern template class SecurityXrayXPCWN;
+extern template class PermissiveXrayDOM;
+extern template class SecurityXrayDOM;
+extern template class PermissiveXrayJS;
+extern template class PermissiveXrayOpaque;
+extern template class PermissiveXrayXPCWN;
+
+class SandboxProxyHandler : public js::Wrapper {
+public:
+ constexpr SandboxProxyHandler() : js::Wrapper(0)
+ {
+ }
+
+ virtual bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
+ JS::Handle<jsid> id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
+
+ // We just forward the high-level methods to the BaseProxyHandler versions
+ // which implement them in terms of lower-level methods.
+ virtual bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
+ bool* bp) const override;
+ virtual bool get(JSContext* cx, JS::Handle<JSObject*> proxy, JS::HandleValue receiver,
+ JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) const override;
+ virtual bool set(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
+ JS::Handle<JS::Value> v, JS::Handle<JS::Value> receiver,
+ JS::ObjectOpResult& result) const override;
+
+ virtual bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy,
+ JS::Handle<jsid> id,
+ JS::MutableHandle<JS::PropertyDescriptor> desc) const override;
+ virtual bool hasOwn(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
+ bool* bp) const override;
+ virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle<JSObject*> proxy,
+ JS::AutoIdVector& props) const override;
+ virtual bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy,
+ JS::MutableHandle<JSObject*> objp) const override;
+};
+
+extern const SandboxProxyHandler sandboxProxyHandler;
+
+// A proxy handler that lets us wrap callables and invoke them with
+// the correct this object, while forwarding all other operations down
+// to them directly.
+class SandboxCallableProxyHandler : public js::Wrapper {
+public:
+ constexpr SandboxCallableProxyHandler() : js::Wrapper(0)
+ {
+ }
+
+ virtual bool call(JSContext* cx, JS::Handle<JSObject*> proxy,
+ const JS::CallArgs& args) const override;
+
+ static const size_t SandboxProxySlot = 0;
+
+ static inline JSObject* getSandboxProxy(JS::Handle<JSObject*> proxy)
+ {
+ return &js::GetProxyExtra(proxy, SandboxProxySlot).toObject();
+ }
+};
+
+extern const SandboxCallableProxyHandler sandboxCallableProxyHandler;
+
+class AutoSetWrapperNotShadowing;
+
+/*
+ * Slots for Xray expando objects. See comments in XrayWrapper.cpp for details
+ * of how these get used; we mostly want the value of JSSLOT_EXPANDO_COUNT here.
+ */
+enum ExpandoSlots {
+ JSSLOT_EXPANDO_NEXT = 0,
+ JSSLOT_EXPANDO_ORIGIN,
+ JSSLOT_EXPANDO_EXCLUSIVE_GLOBAL,
+ JSSLOT_EXPANDO_PROTOTYPE,
+ JSSLOT_EXPANDO_COUNT
+};
+
+extern const JSClassOps XrayExpandoObjectClassOps;
+
+/*
+ * Clear the given slot on all Xray expandos for the given object.
+ *
+ * No-op when called on non-main threads (where Xrays don't exist).
+ */
+void
+ClearXrayExpandoSlots(JSObject* target, size_t slotIndex);
+
+/*
+ * Ensure the given wrapper has an expando object and return it. This can
+ * return null on failure. Will only be called when "wrapper" is an Xray for a
+ * DOM object.
+ */
+JSObject*
+EnsureXrayExpandoObject(JSContext* cx, JS::HandleObject wrapper);
+
+} // namespace xpc
+
+#endif