mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 966518 - Part 0: Make proxy callability into a trap, rather than a class check. (r=bholley, r=djvj, r=peterv)
This commit is contained in:
parent
9d54d5a7be
commit
9b8255f0c4
@ -642,6 +642,12 @@ public:
|
||||
JS::Handle<jsid> id, JS::Handle<JSObject*> callable) const MOZ_OVERRIDE;
|
||||
virtual bool unwatch(JSContext *cx, JS::Handle<JSObject*> proxy,
|
||||
JS::Handle<jsid> id) const MOZ_OVERRIDE;
|
||||
virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE {
|
||||
return false;
|
||||
}
|
||||
virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Derived traps
|
||||
virtual bool has(JSContext *cx, JS::Handle<JSObject*> proxy,
|
||||
@ -694,8 +700,6 @@ const js::Class OuterWindowProxyClass =
|
||||
"Proxy",
|
||||
0, /* additional slots */
|
||||
0, /* additional class flags */
|
||||
nullptr, /* call */
|
||||
nullptr, /* construct */
|
||||
PROXY_MAKE_EXT(
|
||||
nullptr, /* outerObject */
|
||||
js::proxy_innerObject,
|
||||
@ -1055,7 +1059,7 @@ NewOuterWindowProxy(JSContext *cx, JS::Handle<JSObject*> parent, bool isChrome)
|
||||
JSObject *obj = js::Wrapper::New(cx, parent, parent,
|
||||
isChrome ? &nsChromeOuterWindowProxy::singleton
|
||||
: &nsOuterWindowProxy::singleton,
|
||||
&options);
|
||||
options);
|
||||
|
||||
NS_ASSERTION(js::GetObjectClass(obj)->ext.innerObject, "bad class");
|
||||
return obj;
|
||||
|
@ -481,21 +481,17 @@ class CGDOMProxyJSClass(CGThing):
|
||||
# HTMLAllCollection. So just hardcode it here.
|
||||
if self.descriptor.interface.identifier.name == "HTMLAllCollection":
|
||||
flags.append("JSCLASS_EMULATES_UNDEFINED")
|
||||
callHook = LEGACYCALLER_HOOK_NAME if self.descriptor.operations["LegacyCaller"] else 'nullptr'
|
||||
return fill(
|
||||
"""
|
||||
static const DOMJSClass Class = {
|
||||
PROXY_CLASS_DEF("${name}",
|
||||
0, /* extra slots */
|
||||
${flags},
|
||||
${call}, /* call */
|
||||
nullptr /* construct */),
|
||||
${flags}),
|
||||
$*{descriptor}
|
||||
};
|
||||
""",
|
||||
name=self.descriptor.interface.identifier.name,
|
||||
flags=" | ".join(flags),
|
||||
call=callHook,
|
||||
descriptor=DOMClass(self.descriptor))
|
||||
|
||||
|
||||
@ -10641,6 +10637,33 @@ class CGDOMJSProxyHandler_getInstance(ClassMethod):
|
||||
""")
|
||||
|
||||
|
||||
class CGDOMJSProxyHandler_call(ClassMethod):
|
||||
def __init__(self):
|
||||
args = [Argument('JSContext*', 'cx'),
|
||||
Argument('JS::Handle<JSObject*>', 'proxy'),
|
||||
Argument('const JS::CallArgs&', 'args')]
|
||||
|
||||
ClassMethod.__init__(self, "call", "bool", args, virtual=True, override=True, const=True)
|
||||
|
||||
def getBody(self):
|
||||
return fill(
|
||||
"""
|
||||
return js::ForwardToNative(cx, ${legacyCaller}, args);
|
||||
""",
|
||||
legacyCaller=LEGACYCALLER_HOOK_NAME)
|
||||
|
||||
|
||||
class CGDOMJSProxyHandler_isCallable(ClassMethod):
|
||||
def __init__(self):
|
||||
ClassMethod.__init__(self, "isCallable", "bool", [Argument('JSObject*', 'obj')],
|
||||
virtual=True, override=True, const=True)
|
||||
|
||||
def getBody(self):
|
||||
return dedent("""
|
||||
return true;
|
||||
""")
|
||||
|
||||
|
||||
class CGDOMJSProxyHandler(CGClass):
|
||||
def __init__(self, descriptor):
|
||||
assert (descriptor.supportsIndexedProperties() or
|
||||
@ -10672,6 +10695,9 @@ class CGDOMJSProxyHandler(CGClass):
|
||||
(descriptor.operations['NamedSetter'] is not None and
|
||||
descriptor.interface.getExtendedAttribute('OverrideBuiltins'))):
|
||||
methods.append(CGDOMJSProxyHandler_setCustom(descriptor))
|
||||
if descriptor.operations['LegacyCaller']:
|
||||
methods.append(CGDOMJSProxyHandler_call())
|
||||
methods.append(CGDOMJSProxyHandler_isCallable())
|
||||
|
||||
CGClass.__init__(self, 'DOMProxyHandler',
|
||||
bases=[ClassBase('mozilla::dom::DOMProxyHandler')],
|
||||
|
@ -82,6 +82,8 @@ class CPOWProxyHandler : public BaseProxyHandler
|
||||
JSContext *cx) const MOZ_OVERRIDE;
|
||||
virtual const char* className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
|
||||
virtual void finalize(JSFreeOp *fop, JSObject *proxy) const MOZ_OVERRIDE;
|
||||
virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE;
|
||||
virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE;
|
||||
|
||||
static const char family;
|
||||
static const CPOWProxyHandler singleton;
|
||||
@ -620,6 +622,25 @@ CPOWProxyHandler::finalize(JSFreeOp *fop, JSObject *proxy) const
|
||||
OwnerOf(proxy)->drop(proxy);
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::isCallable(JSObject *obj) const
|
||||
{
|
||||
return OwnerOf(obj)->isCallable(obj);
|
||||
}
|
||||
|
||||
bool
|
||||
CPOWProxyHandler::isConstructor(JSObject *obj) const
|
||||
{
|
||||
return isCallable(obj);
|
||||
}
|
||||
|
||||
bool
|
||||
WrapperOwner::isCallable(JSObject *obj)
|
||||
{
|
||||
ObjectId objId = idOf(obj);
|
||||
return !!(objId & OBJECT_IS_CALLABLE);
|
||||
}
|
||||
|
||||
void
|
||||
WrapperOwner::drop(JSObject *obj)
|
||||
{
|
||||
@ -837,19 +858,14 @@ WrapperOwner::fromRemoteObjectVariant(JSContext *cx, RemoteObject objVar)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool callable = !!(objId & OBJECT_IS_CALLABLE);
|
||||
|
||||
RootedObject global(cx, JS::CurrentGlobalOrNull(cx));
|
||||
|
||||
RootedValue v(cx, UndefinedValue());
|
||||
ProxyOptions options;
|
||||
options.selectDefaultClass(callable);
|
||||
obj = NewProxyObject(cx,
|
||||
&CPOWProxyHandler::singleton,
|
||||
v,
|
||||
nullptr,
|
||||
global,
|
||||
options);
|
||||
global);
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
|
@ -59,6 +59,8 @@ class WrapperOwner : public virtual JavaScriptShared
|
||||
bool construct);
|
||||
bool objectClassIs(JSContext *cx, JS::HandleObject obj, js::ESClassValue classValue);
|
||||
const char* className(JSContext *cx, JS::HandleObject proxy);
|
||||
bool isCallable(JSObject *obj);
|
||||
// isConstructable is implemented here as isCallable.
|
||||
|
||||
nsresult instanceOf(JSObject *obj, const nsID *id, bool *bp);
|
||||
|
||||
|
@ -482,7 +482,8 @@ struct Class
|
||||
return flags & JSCLASS_EMULATES_UNDEFINED;
|
||||
}
|
||||
|
||||
bool isCallable() const {
|
||||
bool nonProxyCallable() const {
|
||||
MOZ_ASSERT(!isProxy());
|
||||
return this == js::FunctionClassPtr || call;
|
||||
}
|
||||
|
||||
|
@ -8764,16 +8764,40 @@ CodeGenerator::visitProfilerStackOp(LProfilerStackOp *lir)
|
||||
}
|
||||
}
|
||||
|
||||
class OutOfLineIsCallable : public OutOfLineCodeBase<CodeGenerator>
|
||||
{
|
||||
LIsCallable *ins_;
|
||||
|
||||
public:
|
||||
OutOfLineIsCallable(LIsCallable *ins)
|
||||
: ins_(ins)
|
||||
{ }
|
||||
|
||||
bool accept(CodeGenerator *codegen) {
|
||||
return codegen->visitOutOfLineIsCallable(this);
|
||||
}
|
||||
LIsCallable *ins() const {
|
||||
return ins_;
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
CodeGenerator::visitIsCallable(LIsCallable *ins)
|
||||
{
|
||||
Register object = ToRegister(ins->object());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
OutOfLineIsCallable *ool = new(alloc()) OutOfLineIsCallable(ins);
|
||||
if (!addOutOfLineCode(ool, ins->mir()))
|
||||
return false;
|
||||
|
||||
Label notFunction, done;
|
||||
masm.loadObjClass(object, output);
|
||||
|
||||
// An object is callable iff (is<JSFunction>() || getClass()->call).
|
||||
Label notFunction, done, notCall;
|
||||
// Just skim proxies off. Their notion of isCallable() is more complicated.
|
||||
masm.branchTestClassIsProxy(true, output, ool->entry());
|
||||
|
||||
// An object is callable iff (is<JSFunction>() || getClass()->call.
|
||||
masm.branchPtr(Assembler::NotEqual, output, ImmPtr(&JSFunction::class_), ¬Function);
|
||||
masm.move32(Imm32(1), output);
|
||||
masm.jump(&done);
|
||||
@ -8781,6 +8805,28 @@ CodeGenerator::visitIsCallable(LIsCallable *ins)
|
||||
masm.bind(¬Function);
|
||||
masm.cmpPtrSet(Assembler::NonZero, Address(output, offsetof(js::Class, call)), ImmPtr(nullptr), output);
|
||||
masm.bind(&done);
|
||||
masm.bind(ool->rejoin());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitOutOfLineIsCallable(OutOfLineIsCallable *ool)
|
||||
{
|
||||
LIsCallable *ins = ool->ins();
|
||||
Register object = ToRegister(ins->object());
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
saveVolatile(output);
|
||||
masm.setupUnalignedABICall(1, output);
|
||||
masm.passABIArg(object);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ObjectIsCallable));
|
||||
masm.storeCallResult(output);
|
||||
// C++ compilers like to only use the bottom byte for bools, but we need to maintain the entire
|
||||
// register.
|
||||
masm.and32(Imm32(0xFF), output);
|
||||
restoreVolatile(output);
|
||||
masm.jump(ool->rejoin());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ class OutOfLineLoadTypedArray;
|
||||
class OutOfLineNewGCThingPar;
|
||||
class OutOfLineUpdateCache;
|
||||
class OutOfLineCallPostWriteBarrier;
|
||||
class OutOfLineIsCallable;
|
||||
|
||||
class CodeGenerator : public CodeGeneratorSpecific
|
||||
{
|
||||
@ -296,6 +297,7 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||
bool visitCallDOMNative(LCallDOMNative *lir);
|
||||
bool visitCallGetIntrinsicValue(LCallGetIntrinsicValue *lir);
|
||||
bool visitIsCallable(LIsCallable *lir);
|
||||
bool visitOutOfLineIsCallable(OutOfLineIsCallable *ool);
|
||||
bool visitIsObject(LIsObject *lir);
|
||||
bool visitHaveSameClass(LHaveSameClass *lir);
|
||||
bool visitHasClass(LHasClass *lir);
|
||||
|
@ -1567,16 +1567,6 @@ GetPropertyIC::tryAttachProxy(JSContext *cx, HandleScript outerScript, IonScript
|
||||
return tryAttachGenericProxy(cx, outerScript, ion, obj, name, returnAddr, emitted);
|
||||
}
|
||||
|
||||
static void
|
||||
GenerateProxyClassGuards(MacroAssembler &masm, Register object, Register scratchReg,
|
||||
Label *failures)
|
||||
{
|
||||
masm.loadObjClass(object, scratchReg);
|
||||
masm.branchTest32(Assembler::Zero,
|
||||
Address(scratchReg, Class::offsetOfFlags()),
|
||||
Imm32(JSCLASS_IS_PROXY), failures);
|
||||
}
|
||||
|
||||
bool
|
||||
GetPropertyIC::tryAttachGenericProxy(JSContext *cx, HandleScript outerScript, IonScript *ion,
|
||||
HandleObject obj, HandlePropertyName name, void *returnAddr,
|
||||
@ -1602,7 +1592,7 @@ GetPropertyIC::tryAttachGenericProxy(JSContext *cx, HandleScript outerScript, Io
|
||||
|
||||
Register scratchReg = output().valueReg().scratchReg();
|
||||
|
||||
GenerateProxyClassGuards(masm, object(), scratchReg, &failures);
|
||||
masm.branchTestObjectIsProxy(false, object(), scratchReg, &failures);
|
||||
|
||||
// Ensure that the incoming object is not a DOM proxy, so that we can get to
|
||||
// the specialized stubs
|
||||
@ -2181,7 +2171,7 @@ SetPropertyIC::attachGenericProxy(JSContext *cx, HandleScript outerScript, IonSc
|
||||
Register scratch = regSet.takeGeneral();
|
||||
masm.push(scratch);
|
||||
|
||||
GenerateProxyClassGuards(masm, object(), scratch, &proxyFailures);
|
||||
masm.branchTestObjectIsProxy(false, object(), scratch, &proxyFailures);
|
||||
|
||||
// Remove the DOM proxies. They'll take care of themselves so this stub doesn't
|
||||
// catch too much. The failure case is actually Equal. Fall through to the failure code.
|
||||
|
@ -982,12 +982,25 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
loadObjClass(objReg, scratch);
|
||||
Address flags(scratch, Class::offsetOfFlags());
|
||||
|
||||
branchTest32(Assembler::NonZero, flags, Imm32(JSCLASS_IS_PROXY), slowCheck);
|
||||
branchTestClassIsProxy(true, scratch, slowCheck);
|
||||
|
||||
Condition cond = truthy ? Assembler::Zero : Assembler::NonZero;
|
||||
branchTest32(cond, flags, Imm32(JSCLASS_EMULATES_UNDEFINED), checked);
|
||||
}
|
||||
|
||||
void branchTestClassIsProxy(bool proxy, Register clasp, Label *label)
|
||||
{
|
||||
branchTest32(proxy ? Assembler::NonZero : Assembler::Zero,
|
||||
Address(clasp, Class::offsetOfFlags()),
|
||||
Imm32(JSCLASS_IS_PROXY), label);
|
||||
}
|
||||
|
||||
void branchTestObjectIsProxy(bool proxy, Register object, Register scratch, Label *label)
|
||||
{
|
||||
loadObjClass(object, scratch);
|
||||
branchTestClassIsProxy(proxy, scratch, label);
|
||||
}
|
||||
|
||||
private:
|
||||
// These two functions are helpers used around call sites throughout the
|
||||
// assembler. They are called from the above call wrappers to emit the
|
||||
|
@ -1982,9 +1982,9 @@ IonBuilder::inlineIsCallable(CallInfo &callInfo)
|
||||
} else {
|
||||
types::TemporaryTypeSet *types = callInfo.getArg(0)->resultTypeSet();
|
||||
const Class *clasp = types ? types->getKnownClass() : nullptr;
|
||||
if (clasp) {
|
||||
if (clasp && !clasp->isProxy()) {
|
||||
isCallableKnown = true;
|
||||
isCallableConstant = clasp->isCallable();
|
||||
isCallableConstant = clasp->nonProxyCallable();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1239,6 +1239,12 @@ TypedObjectProto(JSObject *obj)
|
||||
return &typedObj.typedProto();
|
||||
}
|
||||
|
||||
bool
|
||||
ObjectIsCallable(JSObject *obj)
|
||||
{
|
||||
return obj->isCallable();
|
||||
}
|
||||
|
||||
void
|
||||
MarkValueFromIon(JSRuntime *rt, Value *vp)
|
||||
{
|
||||
|
@ -747,6 +747,8 @@ IonMarkFunction(MIRType type)
|
||||
}
|
||||
}
|
||||
|
||||
bool ObjectIsCallable(JSObject *obj);
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
||||
|
@ -19,8 +19,6 @@ const js::Class OuterWrapperClass =
|
||||
"Proxy",
|
||||
0, /* additional slots */
|
||||
0, /* additional class flags */
|
||||
nullptr, /* call */
|
||||
nullptr, /* construct */
|
||||
PROXY_MAKE_EXT(
|
||||
nullptr, /* outerObject */
|
||||
js::proxy_innerObject,
|
||||
@ -63,7 +61,7 @@ BEGIN_TEST(testBug604087)
|
||||
js::WrapperOptions options;
|
||||
options.setClass(&OuterWrapperClass);
|
||||
options.setSingleton(true);
|
||||
JS::RootedObject outerObj(cx, js::Wrapper::New(cx, global, global, &js::Wrapper::singleton, &options));
|
||||
JS::RootedObject outerObj(cx, js::Wrapper::New(cx, global, global, &js::Wrapper::singleton, options));
|
||||
JS::RootedObject compartment2(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook));
|
||||
JS::RootedObject compartment3(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook));
|
||||
JS::RootedObject compartment4(cx, JS_NewGlobalObject(cx, getGlobalClass(), nullptr, JS::FireOnNewGlobalHook));
|
||||
@ -84,7 +82,7 @@ BEGIN_TEST(testBug604087)
|
||||
JS::RootedObject next(cx);
|
||||
{
|
||||
JSAutoCompartment ac(cx, compartment2);
|
||||
next = js::Wrapper::New(cx, compartment2, compartment2, &js::Wrapper::singleton, &options);
|
||||
next = js::Wrapper::New(cx, compartment2, compartment2, &js::Wrapper::singleton, options);
|
||||
CHECK(next);
|
||||
}
|
||||
|
||||
|
@ -284,7 +284,7 @@ CallJSNativeConstructor(JSContext *cx, Native native, const CallArgs &args)
|
||||
*
|
||||
* - (new Object(Object)) returns the callee.
|
||||
*/
|
||||
JS_ASSERT_IF(native != ProxyObject::callableClass_.construct &&
|
||||
JS_ASSERT_IF(native != js::proxy_Construct &&
|
||||
native != js::CallOrConstructBoundFunction &&
|
||||
native != js::IteratorConstructor &&
|
||||
(!callee->is<JSFunction>() || callee->as<JSFunction>().native() != obj_construct),
|
||||
|
@ -435,8 +435,8 @@ JSCompartment::wrap(JSContext *cx, MutableHandleObject obj, HandleObject existin
|
||||
if (existing) {
|
||||
// Is it possible to reuse |existing|?
|
||||
if (!existing->getTaggedProto().isLazy() ||
|
||||
// Note: don't use is<ObjectProxyObject>() here -- it also matches subclasses!
|
||||
existing->getClass() != &ProxyObject::uncallableClass_ ||
|
||||
// Note: Class asserted above, so all that's left to check is callability
|
||||
existing->isCallable() ||
|
||||
existing->getParent() != global ||
|
||||
obj->isCallable())
|
||||
{
|
||||
|
@ -1218,3 +1218,9 @@ JS_StoreStringPostBarrierCallback(JSContext* cx,
|
||||
rt->gc.storeBuffer.putCallback(callback, key, data);
|
||||
}
|
||||
#endif /* JSGC_GENERATIONAL */
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
js::ForwardToNative(JSContext *cx, JSNative native, const CallArgs &args)
|
||||
{
|
||||
return native(cx, args.length(), args.base());
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ namespace js {
|
||||
js::proxy_ObjectMoved \
|
||||
}
|
||||
|
||||
#define PROXY_CLASS_WITH_EXT(name, extraSlots, flags, callOp, constructOp, ext) \
|
||||
#define PROXY_CLASS_WITH_EXT(name, extraSlots, flags, ext) \
|
||||
{ \
|
||||
name, \
|
||||
js::Class::NON_NATIVE | \
|
||||
@ -282,9 +282,9 @@ namespace js {
|
||||
JS_ResolveStub, \
|
||||
js::proxy_Convert, \
|
||||
js::proxy_Finalize, /* finalize */ \
|
||||
callOp, /* call */ \
|
||||
nullptr, /* call */ \
|
||||
js::proxy_HasInstance, /* hasInstance */ \
|
||||
constructOp, /* construct */ \
|
||||
nullptr, /* construct */ \
|
||||
js::proxy_Trace, /* trace */ \
|
||||
JS_NULL_CLASS_SPEC, \
|
||||
ext, \
|
||||
@ -311,8 +311,8 @@ namespace js {
|
||||
} \
|
||||
}
|
||||
|
||||
#define PROXY_CLASS_DEF(name, extraSlots, flags, callOp, constructOp) \
|
||||
PROXY_CLASS_WITH_EXT(name, extraSlots, flags, callOp, constructOp, \
|
||||
#define PROXY_CLASS_DEF(name, extraSlots, flags) \
|
||||
PROXY_CLASS_WITH_EXT(name, extraSlots, flags, \
|
||||
PROXY_MAKE_EXT( \
|
||||
nullptr, /* outerObject */ \
|
||||
nullptr, /* innerObject */ \
|
||||
@ -2476,6 +2476,9 @@ JS_FRIEND_API(bool)
|
||||
SliceSlowly(JSContext* cx, JS::HandleObject obj, JS::HandleObject receiver,
|
||||
uint32_t begin, uint32_t end, JS::HandleObject result);
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
ForwardToNative(JSContext *cx, JSNative native, const JS::CallArgs &args);
|
||||
|
||||
/* ES5 8.12.8. */
|
||||
extern JS_FRIEND_API(bool)
|
||||
DefaultValue(JSContext *cx, JS::HandleObject obj, JSType hint, JS::MutableHandleValue vp);
|
||||
|
@ -2183,7 +2183,7 @@ CheckIsValidConstructible(Value calleev)
|
||||
if (callee->is<JSFunction>())
|
||||
JS_ASSERT(callee->as<JSFunction>().isNativeConstructor());
|
||||
else
|
||||
JS_ASSERT(callee->getClass()->construct != nullptr);
|
||||
JS_ASSERT(callee->constructHook() != nullptr);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
@ -2063,7 +2063,7 @@ TemporaryTypeSet::maybeCallable()
|
||||
unsigned count = getObjectCount();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
const Class *clasp = getObjectClass(i);
|
||||
if (clasp && clasp->isCallable())
|
||||
if (clasp && (clasp->isProxy() || clasp->nonProxyCallable()))
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -3794,6 +3794,14 @@ js::FindClassObject(ExclusiveContext *cx, MutableHandleObject protop, const Clas
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSObject::isCallable() const
|
||||
{
|
||||
if (is<JSFunction>())
|
||||
return true;
|
||||
return callHook() != nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
JSObject::isConstructor() const
|
||||
{
|
||||
@ -3801,7 +3809,39 @@ JSObject::isConstructor() const
|
||||
const JSFunction &fun = as<JSFunction>();
|
||||
return fun.isNativeConstructor() || fun.isInterpretedConstructor();
|
||||
}
|
||||
return getClass()->construct != nullptr;
|
||||
return constructHook() != nullptr;
|
||||
}
|
||||
|
||||
JSNative
|
||||
JSObject::callHook() const
|
||||
{
|
||||
const js::Class *clasp = getClass();
|
||||
|
||||
if (clasp->call)
|
||||
return clasp->call;
|
||||
|
||||
if (is<js::ProxyObject>()) {
|
||||
const js::ProxyObject &p = as<js::ProxyObject>();
|
||||
if (p.handler()->isCallable(const_cast<JSObject*>(this)))
|
||||
return js::proxy_Call;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSNative
|
||||
JSObject::constructHook() const
|
||||
{
|
||||
const js::Class *clasp = getClass();
|
||||
|
||||
if (clasp->construct)
|
||||
return clasp->construct;
|
||||
|
||||
if (is<js::ProxyObject>()) {
|
||||
const js::ProxyObject &p = as<js::ProxyObject>();
|
||||
if (p.handler()->isConstructor(const_cast<JSObject*>(this)))
|
||||
return js::proxy_Construct;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
|
@ -851,10 +851,10 @@ class JSObject : public js::ObjectImpl
|
||||
/*
|
||||
* Back to generic stuff.
|
||||
*/
|
||||
bool isCallable() {
|
||||
return getClass()->isCallable();
|
||||
}
|
||||
bool isCallable() const;
|
||||
bool isConstructor() const;
|
||||
JSNative callHook() const;
|
||||
JSNative constructHook() const;
|
||||
|
||||
inline void finish(js::FreeOp *fop);
|
||||
MOZ_ALWAYS_INLINE void finalize(js::FreeOp *fop);
|
||||
|
@ -98,7 +98,7 @@
|
||||
real(Float32Array, 28, js_InitViaClassSpec, TYPED_ARRAY_CLASP(Float32)) \
|
||||
real(Float64Array, 29, js_InitViaClassSpec, TYPED_ARRAY_CLASP(Float64)) \
|
||||
real(Uint8ClampedArray, 30, js_InitViaClassSpec, TYPED_ARRAY_CLASP(Uint8Clamped)) \
|
||||
real(Proxy, 31, js_InitProxyClass, &ProxyObject::uncallableClass_) \
|
||||
real(Proxy, 31, js_InitProxyClass, OCLASP(Proxy)) \
|
||||
real(WeakMap, 32, js_InitWeakMapClass, OCLASP(WeakMap)) \
|
||||
real(Map, 33, js_InitMapClass, OCLASP(Map)) \
|
||||
real(Set, 34, js_InitSetClass, OCLASP(Set)) \
|
||||
|
@ -224,6 +224,13 @@ class JS_FRIEND_API(BaseProxyHandler)
|
||||
virtual bool getPrototypeOf(JSContext *cx, HandleObject proxy, MutableHandleObject protop) const;
|
||||
virtual bool setPrototypeOf(JSContext *cx, HandleObject proxy, HandleObject proto, bool *bp) const;
|
||||
|
||||
// Allow proxies, wrappers in particular, to specify callability at runtime.
|
||||
// Note: These do not take const JSObject *, but they do in spirit.
|
||||
// We are not prepared to do this, as there's little const correctness
|
||||
// in the external APIs that handle proxies.
|
||||
virtual bool isCallable(JSObject *obj) const;
|
||||
virtual bool isConstructor(JSObject *obj) const;
|
||||
|
||||
// These two hooks must be overridden, or not overridden, in tandem -- no
|
||||
// overriding just one!
|
||||
virtual bool watch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
|
||||
@ -306,11 +313,10 @@ class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler
|
||||
RegExpGuard *g) const MOZ_OVERRIDE;
|
||||
virtual bool boxedValue_unbox(JSContext *cx, HandleObject proxy, MutableHandleValue vp) const;
|
||||
virtual JSObject *weakmapKeyDelegate(JSObject *proxy) const MOZ_OVERRIDE;
|
||||
virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
// Use these in places where you don't want to #include vm/ProxyObject.h.
|
||||
extern JS_FRIEND_DATA(const js::Class* const) CallableProxyClassPtr;
|
||||
extern JS_FRIEND_DATA(const js::Class* const) UncallableProxyClassPtr;
|
||||
extern JS_FRIEND_DATA(const js::Class* const) ProxyClassPtr;
|
||||
|
||||
inline bool IsProxy(JSObject *obj)
|
||||
{
|
||||
@ -382,14 +388,14 @@ IsScriptedProxy(JSObject *obj)
|
||||
class MOZ_STACK_CLASS ProxyOptions {
|
||||
protected:
|
||||
/* protected constructor for subclass */
|
||||
ProxyOptions(bool singletonArg, const Class *claspArg)
|
||||
ProxyOptions(bool singletonArg)
|
||||
: singleton_(singletonArg),
|
||||
clasp_(claspArg)
|
||||
clasp_(ProxyClassPtr)
|
||||
{}
|
||||
|
||||
public:
|
||||
ProxyOptions() : singleton_(false),
|
||||
clasp_(UncallableProxyClassPtr)
|
||||
clasp_(ProxyClassPtr)
|
||||
{}
|
||||
|
||||
bool singleton() const { return singleton_; }
|
||||
@ -405,11 +411,6 @@ class MOZ_STACK_CLASS ProxyOptions {
|
||||
clasp_ = claspArg;
|
||||
return *this;
|
||||
}
|
||||
ProxyOptions &selectDefaultClass(bool callable) {
|
||||
const Class *classp = callable? CallableProxyClassPtr :
|
||||
UncallableProxyClassPtr;
|
||||
return setClass(classp);
|
||||
}
|
||||
|
||||
private:
|
||||
bool singleton_;
|
||||
|
@ -23,11 +23,11 @@ class DummyFrameGuard;
|
||||
*/
|
||||
class MOZ_STACK_CLASS WrapperOptions : public ProxyOptions {
|
||||
public:
|
||||
WrapperOptions() : ProxyOptions(false, nullptr),
|
||||
WrapperOptions() : ProxyOptions(false),
|
||||
proto_()
|
||||
{}
|
||||
|
||||
explicit WrapperOptions(JSContext *cx) : ProxyOptions(false, nullptr),
|
||||
explicit WrapperOptions(JSContext *cx) : ProxyOptions(false),
|
||||
proto_()
|
||||
{
|
||||
proto_.emplace(cx);
|
||||
@ -69,7 +69,7 @@ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
|
||||
MutableHandleValue vp) const MOZ_OVERRIDE;
|
||||
|
||||
static JSObject *New(JSContext *cx, JSObject *obj, JSObject *parent, const Wrapper *handler,
|
||||
const WrapperOptions *options = nullptr);
|
||||
const WrapperOptions &options = WrapperOptions());
|
||||
|
||||
static JSObject *Renew(JSContext *cx, JSObject *existing, JSObject *obj, const Wrapper *handler);
|
||||
|
||||
@ -88,6 +88,7 @@ class JS_FRIEND_API(Wrapper) : public DirectProxyHandler
|
||||
{ }
|
||||
|
||||
virtual bool finalizeInBackground(Value priv) const MOZ_OVERRIDE;
|
||||
virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE;
|
||||
|
||||
static const char family;
|
||||
static const Wrapper singleton;
|
||||
@ -198,6 +199,9 @@ class JS_FRIEND_API(SecurityWrapper) : public Base
|
||||
JS::HandleObject callable) const MOZ_OVERRIDE;
|
||||
virtual bool unwatch(JSContext *cx, JS::HandleObject proxy, JS::HandleId id) const MOZ_OVERRIDE;
|
||||
|
||||
// Allow isCallable and isConstructor. They used to be class-level, and so could not be guarded
|
||||
// against.
|
||||
|
||||
/*
|
||||
* Allow our subclasses to select the superclass behavior they want without
|
||||
* needing to specify an exact superclass.
|
||||
|
@ -341,3 +341,15 @@ BaseProxyHandler::slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint3
|
||||
|
||||
return js::SliceSlowly(cx, proxy, proxy, begin, end, result);
|
||||
}
|
||||
|
||||
bool
|
||||
BaseProxyHandler::isCallable(JSObject *obj) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
BaseProxyHandler::isConstructor(JSObject *obj) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -248,3 +248,10 @@ DirectProxyHandler::preventExtensions(JSContext *cx, HandleObject proxy) const
|
||||
RootedObject target(cx, proxy->as<ProxyObject>().target());
|
||||
return JSObject::preventExtensions(cx, target);
|
||||
}
|
||||
|
||||
bool
|
||||
DirectProxyHandler::isCallable(JSObject *obj) const
|
||||
{
|
||||
JSObject * target = obj->as<ProxyObject>().target();
|
||||
return target->isCallable();
|
||||
}
|
||||
|
@ -839,18 +839,12 @@ js::proxy_Slice(JSContext *cx, HandleObject proxy, uint32_t begin, uint32_t end,
|
||||
return Proxy::slice(cx, proxy, begin, end, result);
|
||||
}
|
||||
|
||||
#define PROXY_CLASS(callOp, constructOp) \
|
||||
PROXY_CLASS_DEF("Proxy", \
|
||||
0, /* additional slots */ \
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy), \
|
||||
callOp, \
|
||||
constructOp)
|
||||
const Class js::ProxyObject::class_ =
|
||||
PROXY_CLASS_DEF("Proxy",
|
||||
0,
|
||||
JSCLASS_HAS_CACHED_PROTO(JSProto_Proxy));
|
||||
|
||||
const Class js::ProxyObject::uncallableClass_ = PROXY_CLASS(nullptr, nullptr);
|
||||
const Class js::ProxyObject::callableClass_ = PROXY_CLASS(proxy_Call, proxy_Construct);
|
||||
|
||||
const Class* const js::CallableProxyClassPtr = &ProxyObject::callableClass_;
|
||||
const Class* const js::UncallableProxyClassPtr = &ProxyObject::uncallableClass_;
|
||||
const Class* const js::ProxyClassPtr = &js::ProxyObject::class_;
|
||||
|
||||
JS_FRIEND_API(JSObject *)
|
||||
js::NewProxyObject(JSContext *cx, const BaseProxyHandler *handler, HandleValue priv, JSObject *proto_,
|
||||
@ -865,7 +859,8 @@ ProxyObject::renew(JSContext *cx, const BaseProxyHandler *handler, Value priv)
|
||||
{
|
||||
JS_ASSERT_IF(IsCrossCompartmentWrapper(this), IsDeadProxyObject(this));
|
||||
JS_ASSERT(getParent() == cx->global());
|
||||
JS_ASSERT(getClass() == &uncallableClass_);
|
||||
JS_ASSERT(getClass() == &ProxyObject::class_);
|
||||
JS_ASSERT(!isCallable());
|
||||
JS_ASSERT(!getClass()->ext.innerObject);
|
||||
JS_ASSERT(getTaggedProto().isLazy());
|
||||
|
||||
|
@ -1083,6 +1083,13 @@ ScriptedDirectProxyHandler::construct(JSContext *cx, HandleObject proxy, const C
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedDirectProxyHandler::isCallable(JSObject *obj) const
|
||||
{
|
||||
MOZ_ASSERT(obj->as<ProxyObject>().handler() == &ScriptedDirectProxyHandler::singleton);
|
||||
return obj->as<ProxyObject>().extra(IS_CALLABLE_EXTRA).toBoolean();
|
||||
}
|
||||
|
||||
const char ScriptedDirectProxyHandler::family = 0;
|
||||
const ScriptedDirectProxyHandler ScriptedDirectProxyHandler::singleton;
|
||||
|
||||
@ -1102,15 +1109,14 @@ js::proxy(JSContext *cx, unsigned argc, jsval *vp)
|
||||
if (!handler)
|
||||
return false;
|
||||
RootedValue priv(cx, ObjectValue(*target));
|
||||
ProxyOptions options;
|
||||
options.selectDefaultClass(target->isCallable());
|
||||
ProxyObject *proxy =
|
||||
ProxyObject::New(cx, &ScriptedDirectProxyHandler::singleton,
|
||||
priv, TaggedProto(TaggedProto::LazyProto), cx->global(),
|
||||
options);
|
||||
JSObject *proxy =
|
||||
NewProxyObject(cx, &ScriptedDirectProxyHandler::singleton,
|
||||
priv, TaggedProto::LazyProto, cx->global());
|
||||
if (!proxy)
|
||||
return false;
|
||||
proxy->setExtra(ScriptedDirectProxyHandler::HANDLER_EXTRA, ObjectValue(*handler));
|
||||
proxy->as<ProxyObject>().setExtra(ScriptedDirectProxyHandler::HANDLER_EXTRA, ObjectValue(*handler));
|
||||
proxy->as<ProxyObject>().setExtra(ScriptedDirectProxyHandler::IS_CALLABLE_EXTRA,
|
||||
BooleanValue(target->isCallable()));
|
||||
args.rval().setObject(*proxy);
|
||||
return true;
|
||||
}
|
||||
|
@ -54,6 +54,12 @@ class ScriptedDirectProxyHandler : public DirectProxyHandler {
|
||||
/* Spidermonkey extensions. */
|
||||
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
|
||||
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
|
||||
virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE;
|
||||
virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE {
|
||||
// For now we maintain the broken behavior that a scripted proxy is constructable if it's
|
||||
// callable. See bug 929467.
|
||||
return isCallable(obj);
|
||||
}
|
||||
virtual bool isScripted() const MOZ_OVERRIDE { return true; }
|
||||
|
||||
static const char family;
|
||||
@ -62,6 +68,7 @@ class ScriptedDirectProxyHandler : public DirectProxyHandler {
|
||||
// The "proxy extra" slot index in which the handler is stored. Revocable proxies need to set
|
||||
// this at revocation time.
|
||||
static const int HANDLER_EXTRA = 0;
|
||||
static const int IS_CALLABLE_EXTRA = 1;
|
||||
// The "function extended" slot index in which the revocation object is stored. Per spec, this
|
||||
// is to be cleared during the first revocation.
|
||||
static const int REVOKE_SLOT = 0;
|
||||
|
@ -328,29 +328,6 @@ ScriptedIndirectProxyHandler::iterate(JSContext *cx, HandleObject proxy, unsigne
|
||||
ReturnedValueMustNotBePrimitive(cx, proxy, cx->names().iterate, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) const
|
||||
{
|
||||
assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
|
||||
RootedObject ccHolder(cx, &proxy->as<ProxyObject>().extra(0).toObject());
|
||||
JS_ASSERT(ccHolder->getClass() == &CallConstructHolder);
|
||||
RootedValue call(cx, ccHolder->getReservedSlot(0));
|
||||
JS_ASSERT(call.isObject() && call.toObject().isCallable());
|
||||
return Invoke(cx, args.thisv(), call, args.length(), args.array(), args.rval());
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const
|
||||
{
|
||||
assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
|
||||
RootedObject ccHolder(cx, &proxy->as<ProxyObject>().extra(0).toObject());
|
||||
JS_ASSERT(ccHolder->getClass() == &CallConstructHolder);
|
||||
RootedValue construct(cx, ccHolder->getReservedSlot(1));
|
||||
JS_ASSERT(construct.isObject() && construct.toObject().isCallable());
|
||||
return InvokeConstructor(cx, construct, args.length(), args.array(),
|
||||
args.rval().address());
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptedIndirectProxyHandler::nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
|
||||
CallArgs args) const
|
||||
@ -375,6 +352,31 @@ ScriptedIndirectProxyHandler::fun_toString(JSContext *cx, HandleObject proxy, un
|
||||
|
||||
const ScriptedIndirectProxyHandler ScriptedIndirectProxyHandler::singleton;
|
||||
|
||||
bool
|
||||
CallableScriptedIndirectProxyHandler::call(JSContext *cx, HandleObject proxy, const CallArgs &args) const
|
||||
{
|
||||
assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
|
||||
RootedObject ccHolder(cx, &proxy->as<ProxyObject>().extra(0).toObject());
|
||||
JS_ASSERT(ccHolder->getClass() == &CallConstructHolder);
|
||||
RootedValue call(cx, ccHolder->getReservedSlot(0));
|
||||
JS_ASSERT(call.isObject() && call.toObject().isCallable());
|
||||
return Invoke(cx, args.thisv(), call, args.length(), args.array(), args.rval());
|
||||
}
|
||||
|
||||
bool
|
||||
CallableScriptedIndirectProxyHandler::construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const
|
||||
{
|
||||
assertEnteredPolicy(cx, proxy, JSID_VOID, CALL);
|
||||
RootedObject ccHolder(cx, &proxy->as<ProxyObject>().extra(0).toObject());
|
||||
JS_ASSERT(ccHolder->getClass() == &CallConstructHolder);
|
||||
RootedValue construct(cx, ccHolder->getReservedSlot(1));
|
||||
JS_ASSERT(construct.isObject() && construct.toObject().isCallable());
|
||||
return InvokeConstructor(cx, construct, args.length(), args.array(),
|
||||
args.rval().address());
|
||||
}
|
||||
|
||||
const CallableScriptedIndirectProxyHandler CallableScriptedIndirectProxyHandler::singleton;
|
||||
|
||||
bool
|
||||
js::proxy_create(JSContext *cx, unsigned argc, Value *vp)
|
||||
{
|
||||
@ -448,11 +450,9 @@ js::proxy_createFunction(JSContext *cx, unsigned argc, Value *vp)
|
||||
ccHolder->setReservedSlot(1, ObjectValue(*construct));
|
||||
|
||||
RootedValue priv(cx, ObjectValue(*handler));
|
||||
ProxyOptions options;
|
||||
options.selectDefaultClass(true);
|
||||
JSObject *proxy =
|
||||
ProxyObject::New(cx, &ScriptedIndirectProxyHandler::singleton,
|
||||
priv, TaggedProto(proto), parent, options);
|
||||
NewProxyObject(cx, &CallableScriptedIndirectProxyHandler::singleton,
|
||||
priv, proto, parent);
|
||||
if (!proxy)
|
||||
return false;
|
||||
proxy->as<ProxyObject>().setExtra(0, ObjectValue(*ccHolder));
|
||||
|
@ -45,8 +45,6 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler
|
||||
|
||||
/* Spidermonkey extensions. */
|
||||
virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) const MOZ_OVERRIDE;
|
||||
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
|
||||
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
|
||||
virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
|
||||
CallArgs args) const MOZ_OVERRIDE;
|
||||
virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE;
|
||||
@ -56,6 +54,24 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler
|
||||
static const ScriptedIndirectProxyHandler singleton;
|
||||
};
|
||||
|
||||
/* Derived class to handle Proxy.createFunction() */
|
||||
class CallableScriptedIndirectProxyHandler : public ScriptedIndirectProxyHandler
|
||||
{
|
||||
public:
|
||||
CallableScriptedIndirectProxyHandler() : ScriptedIndirectProxyHandler() { }
|
||||
virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
|
||||
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
|
||||
|
||||
virtual bool isCallable(JSObject *obj) const MOZ_OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
virtual bool isConstructor(JSObject *obj) const MOZ_OVERRIDE {
|
||||
return true;
|
||||
}
|
||||
|
||||
static const CallableScriptedIndirectProxyHandler singleton;
|
||||
};
|
||||
|
||||
bool
|
||||
proxy_create(JSContext *cx, unsigned argc, Value *vp);
|
||||
|
||||
|
@ -34,18 +34,12 @@ Wrapper::defaultValue(JSContext *cx, HandleObject proxy, JSType hint, MutableHan
|
||||
|
||||
JSObject *
|
||||
Wrapper::New(JSContext *cx, JSObject *obj, JSObject *parent, const Wrapper *handler,
|
||||
const WrapperOptions *options)
|
||||
const WrapperOptions &options)
|
||||
{
|
||||
JS_ASSERT(parent);
|
||||
|
||||
RootedValue priv(cx, ObjectValue(*obj));
|
||||
mozilla::Maybe<WrapperOptions> opts;
|
||||
if (!options) {
|
||||
opts.emplace();
|
||||
opts->selectDefaultClass(obj->isCallable());
|
||||
options = opts.ptr();
|
||||
}
|
||||
return NewProxyObject(cx, handler, priv, options->proto(), parent, *options);
|
||||
return NewProxyObject(cx, handler, priv, options.proto(), parent, options);
|
||||
}
|
||||
|
||||
JSObject *
|
||||
@ -70,6 +64,15 @@ Wrapper::wrappedObject(JSObject *wrapper)
|
||||
return wrapper->as<ProxyObject>().target();
|
||||
}
|
||||
|
||||
bool
|
||||
Wrapper::isConstructor(JSObject *obj) const
|
||||
{
|
||||
// For now, all wrappers are constructable if they are callable. We will want to eventually
|
||||
// decouple this behavior, but none of the Wrapper infrastructure is currently prepared for
|
||||
// that.
|
||||
return isCallable(obj);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject *)
|
||||
js::UncheckedUnwrap(JSObject *wrapped, bool stopAtOuter, unsigned *flagsp)
|
||||
{
|
||||
|
@ -4032,9 +4032,8 @@ WrapWithProto(JSContext *cx, unsigned argc, jsval *vp)
|
||||
|
||||
WrapperOptions options(cx);
|
||||
options.setProto(proto.toObjectOrNull());
|
||||
options.selectDefaultClass(obj.toObject().isCallable());
|
||||
JSObject *wrapped = Wrapper::New(cx, &obj.toObject(), &obj.toObject().global(),
|
||||
&Wrapper::singletonWithPrototype, &options);
|
||||
&Wrapper::singletonWithPrototype, options);
|
||||
if (!wrapped)
|
||||
return false;
|
||||
|
||||
|
@ -468,10 +468,11 @@ js::Invoke(JSContext *cx, CallArgs args, MaybeConstruct construct)
|
||||
if (MOZ_UNLIKELY(clasp == &js_NoSuchMethodClass))
|
||||
return NoSuchMethod(cx, args.length(), args.base());
|
||||
#endif
|
||||
JS_ASSERT_IF(construct, !clasp->construct);
|
||||
if (!clasp->call)
|
||||
JS_ASSERT_IF(construct, !callee.constructHook());
|
||||
JSNative call = callee.callHook();
|
||||
if (!call)
|
||||
return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, construct);
|
||||
return CallJSNative(cx, clasp->call, args);
|
||||
return CallJSNative(cx, call, args);
|
||||
}
|
||||
|
||||
/* Invoke native functions. */
|
||||
@ -571,11 +572,11 @@ js::InvokeConstructor(JSContext *cx, CallArgs args)
|
||||
return true;
|
||||
}
|
||||
|
||||
const Class *clasp = callee.getClass();
|
||||
if (!clasp->construct)
|
||||
JSNative construct = callee.constructHook();
|
||||
if (!construct)
|
||||
return ReportIsNotFunction(cx, args.calleev(), args.length() + 1, CONSTRUCT);
|
||||
|
||||
return CallJSNativeConstructor(cx, clasp->construct, args);
|
||||
return CallJSNativeConstructor(cx, construct, args);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -42,8 +42,9 @@ class ProxyObject : public JSObject
|
||||
return const_cast<ProxyObject*>(this)->private_().toObjectOrNull();
|
||||
}
|
||||
|
||||
const BaseProxyHandler *handler() {
|
||||
return static_cast<const BaseProxyHandler*>(GetReservedSlot(this, HANDLER_SLOT).toPrivate());
|
||||
const BaseProxyHandler *handler() const {
|
||||
return static_cast<const BaseProxyHandler*>(
|
||||
GetReservedSlot(const_cast<ProxyObject*>(this), HANDLER_SLOT).toPrivate());
|
||||
}
|
||||
|
||||
void initHandler(const BaseProxyHandler *handler);
|
||||
@ -85,9 +86,13 @@ class ProxyObject : public JSObject
|
||||
|
||||
// proxy_Trace is just a trivial wrapper around ProxyObject::trace for
|
||||
// friend api exposure.
|
||||
|
||||
// Proxy classes are not allowed to have call or construct hooks directly. Their
|
||||
// callability is instead decided by a trap call
|
||||
return clasp->isProxy() &&
|
||||
(clasp->flags & JSCLASS_IMPLEMENTS_BARRIERS) &&
|
||||
clasp->trace == proxy_Trace &&
|
||||
!clasp->call && !clasp->construct &&
|
||||
JSCLASS_RESERVED_SLOTS(clasp) >= PROXY_MINIMUM_SLOTS;
|
||||
}
|
||||
|
||||
@ -100,8 +105,7 @@ class ProxyObject : public JSObject
|
||||
|
||||
void nuke(const BaseProxyHandler *handler);
|
||||
|
||||
static const Class callableClass_;
|
||||
static const Class uncallableClass_;
|
||||
static const Class class_;
|
||||
};
|
||||
|
||||
} // namespace js
|
||||
|
@ -1657,7 +1657,7 @@ DebugScopeObject::getMaybeSentinelValue(JSContext *cx, HandleId id, MutableHandl
|
||||
bool
|
||||
js_IsDebugScopeSlow(ProxyObject *proxy)
|
||||
{
|
||||
JS_ASSERT(proxy->hasClass(&ProxyObject::uncallableClass_));
|
||||
JS_ASSERT(proxy->hasClass(&ProxyObject::class_));
|
||||
return proxy->handler() == &DebugScopeProxy::singleton;
|
||||
}
|
||||
|
||||
|
@ -914,7 +914,7 @@ JSObject::is<js::DebugScopeObject>() const
|
||||
extern bool js_IsDebugScopeSlow(js::ProxyObject *proxy);
|
||||
|
||||
// Note: don't use is<ProxyObject>() here -- it also matches subclasses!
|
||||
return hasClass(&js::ProxyObject::uncallableClass_) &&
|
||||
return hasClass(&js::ProxyObject::class_) &&
|
||||
js_IsDebugScopeSlow(&const_cast<JSObject*>(this)->as<js::ProxyObject>());
|
||||
}
|
||||
|
||||
|
@ -562,11 +562,9 @@ WrapCallable(JSContext *cx, JSObject *callable, JSObject *sandboxProtoProxy)
|
||||
&xpc::sandboxProxyHandler);
|
||||
|
||||
RootedValue priv(cx, ObjectValue(*callable));
|
||||
js::ProxyOptions options;
|
||||
options.selectDefaultClass(true);
|
||||
return js::NewProxyObject(cx, &xpc::sandboxCallableProxyHandler,
|
||||
priv, nullptr,
|
||||
sandboxProtoProxy, options);
|
||||
sandboxProtoProxy);
|
||||
}
|
||||
|
||||
template<typename Op>
|
||||
|
Loading…
Reference in New Issue
Block a user