mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-02 01:48:05 +00:00
Bug 1053271 - Remove XPCWN Xrays. r=bz.
--HG-- extra : rebase_source : 4da59c56ffc6eab4af0bf59d3d3861bbc18a33ba
This commit is contained in:
parent
a0cb50c811
commit
c02d68395d
@ -164,7 +164,6 @@ IdentifyCrossOriginObject(JSObject* obj)
|
||||
{
|
||||
obj = js::UncheckedUnwrap(obj, /* stopAtWindowProxy = */ false);
|
||||
const js::Class* clasp = js::GetObjectClass(obj);
|
||||
MOZ_ASSERT(!XrayUtils::IsXPCWNHolderClass(Jsvalify(clasp)), "shouldn't have a holder here");
|
||||
|
||||
if (clasp->name[0] == 'L' && !strcmp(clasp->name, "Location"))
|
||||
return CrossOriginLocation;
|
||||
|
@ -400,9 +400,7 @@ SelectWrapper(bool securityWrapper, XrayType xrayType, bool waiveXrays, JSObject
|
||||
// Ok, we're using Xray. If this isn't a security wrapper, use the permissive
|
||||
// version and skip the filter.
|
||||
if (!securityWrapper) {
|
||||
if (xrayType == XrayForWrappedNative)
|
||||
return &PermissiveXrayXPCWN::singleton;
|
||||
else if (xrayType == XrayForDOMObject)
|
||||
if (xrayType == XrayForDOMObject)
|
||||
return &PermissiveXrayDOM::singleton;
|
||||
else if (xrayType == XrayForJSObject)
|
||||
return &PermissiveXrayJS::singleton;
|
||||
@ -435,7 +433,6 @@ WrapperFactory::Rewrap(JSContext* cx, HandleObject existing, HandleObject obj)
|
||||
GetProxyHandler(obj) == &XrayWaiver ||
|
||||
js::IsWindowProxy(obj),
|
||||
"wrapped object passed to rewrap");
|
||||
MOZ_ASSERT(!XrayUtils::IsXPCWNHolderClass(JS_GetClass(obj)), "trying to wrap a holder");
|
||||
MOZ_ASSERT(!js::IsWindow(obj));
|
||||
MOZ_ASSERT(dom::IsJSAPIActive());
|
||||
|
||||
|
@ -104,9 +104,7 @@ GetXrayType(JSObject* obj)
|
||||
if (mozilla::dom::UseDOMXray(obj))
|
||||
return XrayForDOMObject;
|
||||
|
||||
const js::Class* clasp = js::GetObjectClass(obj);
|
||||
if (IS_WN_CLASS(clasp) || js::IsWindowProxy(obj))
|
||||
return XrayForWrappedNative;
|
||||
MOZ_ASSERT(!js::IsWindowProxy(obj));
|
||||
|
||||
JSProtoKey standardProto = IdentifyStandardInstanceOrPrototype(obj);
|
||||
if (IsJSXraySupported(standardProto))
|
||||
@ -198,17 +196,6 @@ XrayTraits::setExpandoChain(JSContext* cx, HandleObject obj, HandleObject chain)
|
||||
return ObjectScope(obj)->SetExpandoChain(cx, obj, chain);
|
||||
}
|
||||
|
||||
// static
|
||||
XPCWrappedNative*
|
||||
XPCWrappedNativeXrayTraits::getWN(JSObject* wrapper)
|
||||
{
|
||||
return XPCWrappedNative::Get(getTargetObject(wrapper));
|
||||
}
|
||||
|
||||
const JSClass XPCWrappedNativeXrayTraits::HolderClass = {
|
||||
"NativePropertyHolder", JSCLASS_HAS_RESERVED_SLOTS(HOLDER_SHARED_SLOT_COUNT)
|
||||
};
|
||||
|
||||
const JSClass XrayTraits::HolderClass = {
|
||||
"XrayHolder", JSCLASS_HAS_RESERVED_SLOTS(HOLDER_SHARED_SLOT_COUNT)
|
||||
};
|
||||
@ -1029,7 +1016,6 @@ JSXrayTraits::createHolder(JSContext* cx, JSObject* wrapper)
|
||||
return holder;
|
||||
}
|
||||
|
||||
XPCWrappedNativeXrayTraits XPCWrappedNativeXrayTraits::singleton;
|
||||
DOMXrayTraits DOMXrayTraits::singleton;
|
||||
JSXrayTraits JSXrayTraits::singleton;
|
||||
OpaqueXrayTraits OpaqueXrayTraits::singleton;
|
||||
@ -1040,8 +1026,6 @@ GetXrayTraits(JSObject* obj)
|
||||
switch (GetXrayType(obj)) {
|
||||
case XrayForDOMObject:
|
||||
return &DOMXrayTraits::singleton;
|
||||
case XrayForWrappedNative:
|
||||
return &XPCWrappedNativeXrayTraits::singleton;
|
||||
case XrayForJSObject:
|
||||
return &JSXrayTraits::singleton;
|
||||
case XrayForOpaqueObject:
|
||||
@ -1423,16 +1407,6 @@ SetCachedXrayExpando(JSObject* holder, JSObject* expandoWrapper)
|
||||
JS_SetReservedSlot(holder, XrayTraits::HOLDER_SLOT_EXPANDO, ObjectValue(*expandoWrapper));
|
||||
}
|
||||
|
||||
namespace XrayUtils {
|
||||
|
||||
bool
|
||||
IsXPCWNHolderClass(const JSClass* clasp)
|
||||
{
|
||||
return clasp == &XPCWrappedNativeXrayTraits::HolderClass;
|
||||
}
|
||||
|
||||
} // namespace XrayUtils
|
||||
|
||||
static nsGlobalWindowInner*
|
||||
AsWindow(JSContext* cx, JSObject* wrapper)
|
||||
{
|
||||
@ -1448,106 +1422,6 @@ IsWindow(JSContext* cx, JSObject* wrapper)
|
||||
return !!AsWindow(cx, wrapper);
|
||||
}
|
||||
|
||||
void
|
||||
XPCWrappedNativeXrayTraits::preserveWrapper(JSObject* target)
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
XrayToString(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
bool
|
||||
XPCWrappedNativeXrayTraits::resolveNativeProperty(JSContext* cx, HandleObject wrapper,
|
||||
HandleObject holder, HandleId id,
|
||||
MutableHandle<PropertyDescriptor> desc)
|
||||
{
|
||||
MOZ_ASSERT(js::GetObjectJSClass(holder) == &HolderClass);
|
||||
|
||||
desc.object().set(nullptr);
|
||||
|
||||
// This will do verification and the method lookup for us.
|
||||
RootedObject target(cx, getTargetObject(wrapper));
|
||||
XPCCallContext ccx(cx, target, nullptr, id);
|
||||
|
||||
// There are no native numeric (or symbol-keyed) properties, so we can
|
||||
// shortcut here. We will not find the property.
|
||||
if (!JSID_IS_STRING(id))
|
||||
return true;
|
||||
|
||||
XPCNativeInterface* iface;
|
||||
XPCNativeMember* member;
|
||||
XPCWrappedNative* wn = getWN(wrapper);
|
||||
|
||||
if (ccx.GetWrapper() != wn || !wn->IsValid()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(iface = ccx.GetInterface()) || !(member = ccx.GetMember())) {
|
||||
if (id != XPCJSRuntime::Get()->GetStringID(XPCJSContext::IDX_TO_STRING))
|
||||
return true;
|
||||
|
||||
JSFunction* toString = JS_NewFunction(cx, XrayToString, 0, 0, "toString");
|
||||
if (!toString)
|
||||
return false;
|
||||
|
||||
FillPropertyDescriptor(desc, wrapper, 0,
|
||||
ObjectValue(*JS_GetFunctionObject(toString)));
|
||||
|
||||
return JS_DefinePropertyById(cx, holder, id, desc) &&
|
||||
JS_GetOwnPropertyDescriptorById(cx, holder, id, desc);
|
||||
}
|
||||
|
||||
desc.object().set(holder);
|
||||
desc.setAttributes(JSPROP_ENUMERATE);
|
||||
desc.setGetter(nullptr);
|
||||
desc.setSetter(nullptr);
|
||||
desc.value().setUndefined();
|
||||
|
||||
RootedValue fval(cx, JS::UndefinedValue());
|
||||
if (member->IsConstant()) {
|
||||
if (!member->GetConstantValue(ccx, iface, desc.value().address())) {
|
||||
JS_ReportErrorASCII(cx, "Failed to convert constant native property to JS value");
|
||||
return false;
|
||||
}
|
||||
} else if (member->IsAttribute()) {
|
||||
// This is a getter/setter. Clone a function for it.
|
||||
if (!member->NewFunctionObject(ccx, iface, wrapper, fval.address())) {
|
||||
JS_ReportErrorASCII(cx, "Failed to clone function object for native getter/setter");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned attrs = desc.attributes();
|
||||
attrs |= JSPROP_GETTER;
|
||||
if (member->IsWritableAttribute())
|
||||
attrs |= JSPROP_SETTER;
|
||||
|
||||
desc.setAttributes(attrs);
|
||||
} else {
|
||||
// This is a method. Clone a function for it.
|
||||
if (!member->NewFunctionObject(ccx, iface, wrapper, desc.value().address())) {
|
||||
JS_ReportErrorASCII(cx, "Failed to clone function object for native function");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Without a wrapper the function would live on the prototype. Since we
|
||||
// don't have one, we have to avoid calling the scriptable helper's
|
||||
// GetProperty method for this property, so null out the getter and
|
||||
// setter here explicitly.
|
||||
desc.setGetter(nullptr);
|
||||
desc.setSetter(nullptr);
|
||||
}
|
||||
|
||||
if (!JS_WrapValue(cx, desc.value()) || !JS_WrapValue(cx, &fval))
|
||||
return false;
|
||||
|
||||
if (desc.hasGetterObject())
|
||||
desc.setGetterObject(&fval.toObject());
|
||||
if (desc.hasSetterObject())
|
||||
desc.setSetterObject(&fval.toObject());
|
||||
|
||||
return JS_DefinePropertyById(cx, holder, id, desc);
|
||||
}
|
||||
|
||||
static bool
|
||||
wrappedJSObject_getter(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
@ -1638,112 +1512,6 @@ XrayTraits::resolveOwnProperty(JSContext* cx, HandleObject wrapper, HandleObject
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext* cx, HandleObject wrapper,
|
||||
HandleObject target, HandleObject holder,
|
||||
HandleId id,
|
||||
MutableHandle<PropertyDescriptor> desc)
|
||||
{
|
||||
// Call the common code.
|
||||
bool ok = XrayTraits::resolveOwnProperty(cx, wrapper, target, holder,
|
||||
id, desc);
|
||||
if (!ok || desc.object())
|
||||
return ok;
|
||||
|
||||
// Xray wrappers don't use the regular wrapper hierarchy, so we should be
|
||||
// in the wrapper's compartment here, not the wrappee.
|
||||
MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
|
||||
|
||||
return JS_GetOwnPropertyDescriptorById(cx, holder, id, desc);
|
||||
}
|
||||
|
||||
bool
|
||||
XPCWrappedNativeXrayTraits::enumerateNames(JSContext* cx, HandleObject wrapper, unsigned flags,
|
||||
AutoIdVector& props)
|
||||
{
|
||||
// Force all native properties to be materialized onto the wrapped native.
|
||||
AutoIdVector wnProps(cx);
|
||||
{
|
||||
RootedObject target(cx, getTargetObject(wrapper));
|
||||
JSAutoRealm ar(cx, target);
|
||||
if (!js::GetPropertyKeys(cx, target, flags, &wnProps))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Go through the properties we found on the underlying object and see if
|
||||
// they appear on the XrayWrapper. If it throws (which may happen if the
|
||||
// wrapper is a SecurityWrapper), just clear the exception and move on.
|
||||
MOZ_ASSERT(!JS_IsExceptionPending(cx));
|
||||
if (!props.reserve(wnProps.length()))
|
||||
return false;
|
||||
for (size_t n = 0; n < wnProps.length(); ++n) {
|
||||
RootedId id(cx, wnProps[n]);
|
||||
JS_MarkCrossZoneId(cx, id);
|
||||
bool hasProp;
|
||||
if (JS_HasPropertyById(cx, wrapper, id, &hasProp) && hasProp)
|
||||
props.infallibleAppend(id);
|
||||
JS_ClearPendingException(cx);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
XPCWrappedNativeXrayTraits::createHolder(JSContext* cx, JSObject* wrapper)
|
||||
{
|
||||
return JS_NewObjectWithGivenProto(cx, &HolderClass, nullptr);
|
||||
}
|
||||
|
||||
bool
|
||||
XPCWrappedNativeXrayTraits::call(JSContext* cx, HandleObject wrapper,
|
||||
const JS::CallArgs& args,
|
||||
const js::Wrapper& baseInstance)
|
||||
{
|
||||
// Run the call hook of the wrapped native.
|
||||
XPCWrappedNative* wn = getWN(wrapper);
|
||||
if (wn->GetScriptable() && wn->GetScriptable()->WantCall()) {
|
||||
XPCCallContext ccx(cx, wrapper, nullptr, JSID_VOIDHANDLE, args.length(),
|
||||
args.array(), args.rval().address());
|
||||
if (!ccx.IsValid())
|
||||
return false;
|
||||
bool ok = true;
|
||||
nsresult rv = wn->GetScriptable()->Call(wn, cx, wrapper, args, &ok);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (ok)
|
||||
XPCThrower::Throw(rv, cx);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
XPCWrappedNativeXrayTraits::construct(JSContext* cx, HandleObject wrapper,
|
||||
const JS::CallArgs& args,
|
||||
const js::Wrapper& baseInstance)
|
||||
{
|
||||
// Run the construct hook of the wrapped native.
|
||||
XPCWrappedNative* wn = getWN(wrapper);
|
||||
if (wn->GetScriptable() && wn->GetScriptable()->WantConstruct()) {
|
||||
XPCCallContext ccx(cx, wrapper, nullptr, JSID_VOIDHANDLE, args.length(),
|
||||
args.array(), args.rval().address());
|
||||
if (!ccx.IsValid())
|
||||
return false;
|
||||
bool ok = true;
|
||||
nsresult rv =
|
||||
wn->GetScriptable()->Construct(wn, cx, wrapper, args, &ok);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (ok)
|
||||
XPCThrower::Throw(rv, cx);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
DOMXrayTraits::resolveOwnProperty(JSContext* cx, HandleObject wrapper, HandleObject target,
|
||||
HandleObject holder, HandleId id,
|
||||
@ -1988,58 +1756,6 @@ HasNativeProperty(JSContext* cx, HandleObject wrapper, HandleId id, bool* hasPro
|
||||
|
||||
} // namespace XrayUtils
|
||||
|
||||
static bool
|
||||
XrayToString(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (!args.thisv().isObject()) {
|
||||
JS_ReportErrorASCII(cx, "XrayToString called on an incompatible object");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject wrapper(cx, &args.thisv().toObject());
|
||||
if (!wrapper)
|
||||
return false;
|
||||
if (IsWrapper(wrapper) &&
|
||||
GetProxyHandler(wrapper) == &sandboxCallableProxyHandler) {
|
||||
wrapper = xpc::SandboxCallableProxyHandler::wrappedObject(wrapper);
|
||||
}
|
||||
if (!IsWrapper(wrapper) || !WrapperFactory::IsXrayWrapper(wrapper)) {
|
||||
JS_ReportErrorASCII(cx, "XrayToString called on an incompatible object");
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject obj(cx, XrayTraits::getTargetObject(wrapper));
|
||||
if (GetXrayType(obj) != XrayForWrappedNative) {
|
||||
JS_ReportErrorASCII(cx, "XrayToString called on an incompatible object");
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char start[] = "[object XrayWrapper ";
|
||||
static const char end[] = "]";
|
||||
nsAutoString result;
|
||||
result.AppendASCII(start);
|
||||
|
||||
XPCCallContext ccx(cx, obj);
|
||||
XPCWrappedNative* wn = XPCWrappedNativeXrayTraits::getWN(wrapper);
|
||||
char* wrapperStr = wn->ToString();
|
||||
if (!wrapperStr) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
result.AppendASCII(wrapperStr);
|
||||
js_free(wrapperStr);
|
||||
|
||||
result.AppendASCII(end);
|
||||
|
||||
JSString* str = JS_NewUCStringCopyN(cx, result.get(), result.Length());
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
args.rval().setString(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Base, typename Traits>
|
||||
bool
|
||||
@ -2091,12 +1807,9 @@ XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext* cx, HandleObject wra
|
||||
// which are |own| value props.
|
||||
//
|
||||
// resolveOwnProperty may or may not cache what it finds on the holder,
|
||||
// depending on how ephemeral it decides the property is. XPCWN |own|
|
||||
// properties generally end up on the holder via Resolve, whereas
|
||||
// NodeList |own| properties don't get defined on the holder, since they're
|
||||
// supposed to be dynamic. This means that we have to first check the result
|
||||
// of resolveOwnProperty, and _then_, if that comes up blank, check the
|
||||
// holder for any cached native properties.
|
||||
// depending on how ephemeral it decides the property is. This means that we have to
|
||||
// first check the result of resolveOwnProperty, and _then_, if that comes up blank,
|
||||
// check the holder for any cached native properties.
|
||||
//
|
||||
// Finally, we call resolveNativeProperty, which checks non-own properties,
|
||||
// and unconditionally caches what it finds on the holder.
|
||||
@ -2612,8 +2325,6 @@ template<typename Base, typename Traits>
|
||||
const xpc::XrayWrapper<Base, Traits>
|
||||
xpc::XrayWrapper<Base, Traits>::singleton(0);
|
||||
|
||||
template class PermissiveXrayXPCWN;
|
||||
template class SecurityXrayXPCWN;
|
||||
template class PermissiveXrayDOM;
|
||||
template class SecurityXrayDOM;
|
||||
template class PermissiveXrayJS;
|
||||
|
@ -29,15 +29,11 @@
|
||||
// little world around them.
|
||||
|
||||
class nsIPrincipal;
|
||||
class XPCWrappedNative;
|
||||
|
||||
namespace xpc {
|
||||
|
||||
namespace XrayUtils {
|
||||
|
||||
bool
|
||||
IsXPCWNHolderClass(const JSClass* clasp);
|
||||
|
||||
bool
|
||||
IsTransparent(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id);
|
||||
|
||||
@ -51,7 +47,6 @@ HasNativeProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id,
|
||||
|
||||
enum XrayType {
|
||||
XrayForDOMObject,
|
||||
XrayForWrappedNative,
|
||||
XrayForJSObject,
|
||||
XrayForOpaqueObject,
|
||||
NotXray
|
||||
@ -146,46 +141,6 @@ private:
|
||||
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, JS::HandleObject wrapper, JS::HandleObject target,
|
||||
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:
|
||||
@ -450,7 +405,7 @@ XrayType GetXrayType(JSObject* obj);
|
||||
XrayTraits* GetXrayTraits(JSObject* obj);
|
||||
|
||||
// NB: Base *must* derive from JSProxyHandler
|
||||
template <typename Base, typename Traits = XPCWrappedNativeXrayTraits >
|
||||
template <typename Base, typename Traits>
|
||||
class XrayWrapper : public Base {
|
||||
public:
|
||||
constexpr explicit XrayWrapper(unsigned flags)
|
||||
@ -531,20 +486,15 @@ class XrayWrapper : public Base {
|
||||
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:
|
||||
|
Loading…
Reference in New Issue
Block a user