зеркало из https://github.com/mozilla/gecko-dev.git
Bug 825705: Creating this on caller-side shouldn't query prototype for unknown objects, r=jandem
This commit is contained in:
Родитель
aa4c0c0f58
Коммит
c95d254368
|
@ -2010,6 +2010,46 @@ CodeGenerator::visitInitProp(LInitProp *lir)
|
|||
return callVM(InitPropInfo, lir);
|
||||
}
|
||||
|
||||
typedef bool (*CreateThisFn)(JSContext *cx, HandleObject callee, MutableHandleValue rval);
|
||||
static const VMFunction CreateThisInfo =
|
||||
FunctionInfo<CreateThisFn>(CreateThis);
|
||||
|
||||
bool
|
||||
CodeGenerator::visitCreateThis(LCreateThis *lir)
|
||||
{
|
||||
const LAllocation *callee = lir->getCallee();
|
||||
|
||||
if (callee->isConstant())
|
||||
pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
|
||||
else
|
||||
pushArg(ToRegister(callee));
|
||||
|
||||
return callVM(CreateThisInfo, lir);
|
||||
}
|
||||
|
||||
typedef JSObject *(*CreateThisWithProtoFn)(JSContext *cx, HandleObject callee, JSObject *proto);
|
||||
static const VMFunction CreateThisWithProtoInfo =
|
||||
FunctionInfo<CreateThisWithProtoFn>(js_CreateThisForFunctionWithProto);
|
||||
|
||||
bool
|
||||
CodeGenerator::visitCreateThisWithProto(LCreateThisWithProto *lir)
|
||||
{
|
||||
const LAllocation *callee = lir->getCallee();
|
||||
const LAllocation *proto = lir->getPrototype();
|
||||
|
||||
if (proto->isConstant())
|
||||
pushArg(ImmGCPtr(&proto->toConstant()->toObject()));
|
||||
else
|
||||
pushArg(ToRegister(proto));
|
||||
|
||||
if (callee->isConstant())
|
||||
pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
|
||||
else
|
||||
pushArg(ToRegister(callee));
|
||||
|
||||
return callVM(CreateThisWithProtoInfo, lir);
|
||||
}
|
||||
|
||||
typedef JSObject *(*NewGCThingFn)(JSContext *cx, gc::AllocKind allocKind, size_t thingSize);
|
||||
static const VMFunction NewGCThingInfo =
|
||||
FunctionInfo<NewGCThingFn>(js::ion::NewGCThing);
|
||||
|
@ -2038,59 +2078,6 @@ CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate *lir)
|
|||
return true;
|
||||
}
|
||||
|
||||
typedef JSObject *(*CreateThisFn)(JSContext *cx, HandleObject callee, JSObject *proto);
|
||||
static const VMFunction CreateThisInfo =
|
||||
FunctionInfo<CreateThisFn>(js_CreateThisForFunctionWithProto);
|
||||
|
||||
bool
|
||||
CodeGenerator::emitCreateThisVM(LInstruction *lir,
|
||||
const LAllocation *proto,
|
||||
const LAllocation *callee)
|
||||
{
|
||||
if (proto->isConstant())
|
||||
pushArg(ImmGCPtr(&proto->toConstant()->toObject()));
|
||||
else
|
||||
pushArg(ToRegister(proto));
|
||||
|
||||
if (callee->isConstant())
|
||||
pushArg(ImmGCPtr(&callee->toConstant()->toObject()));
|
||||
else
|
||||
pushArg(ToRegister(callee));
|
||||
|
||||
return callVM(CreateThisInfo, lir);
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitCreateThisV(LCreateThisV *lir)
|
||||
{
|
||||
Label done, vm;
|
||||
|
||||
const LAllocation *proto = lir->getPrototype();
|
||||
const LAllocation *callee = lir->getCallee();
|
||||
|
||||
// When callee could be a native, put MagicValue in return operand.
|
||||
// Use the VMCall when callee turns out to not be a native.
|
||||
masm.branchIfInterpreted(ToRegister(callee), &vm);
|
||||
masm.moveValue(MagicValue(JS_IS_CONSTRUCTING), GetValueOutput(lir));
|
||||
masm.jump(&done);
|
||||
|
||||
masm.bind(&vm);
|
||||
if (!emitCreateThisVM(lir, proto, callee))
|
||||
return false;
|
||||
|
||||
masm.tagValue(JSVAL_TYPE_OBJECT, ReturnReg, GetValueOutput(lir));
|
||||
|
||||
masm.bind(&done);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitCreateThisO(LCreateThisO *lir)
|
||||
{
|
||||
return emitCreateThisVM(lir, lir->getPrototype(), lir->getCallee());
|
||||
}
|
||||
|
||||
bool
|
||||
CodeGenerator::visitReturnFromCtor(LReturnFromCtor *lir)
|
||||
{
|
||||
|
|
|
@ -99,9 +99,8 @@ class CodeGenerator : public CodeGeneratorSpecific
|
|||
bool visitNewCallObject(LNewCallObject *lir);
|
||||
bool visitNewStringObject(LNewStringObject *lir);
|
||||
bool visitInitProp(LInitProp *lir);
|
||||
bool emitCreateThisVM(LInstruction *lir, const LAllocation *proto, const LAllocation *callee);
|
||||
bool visitCreateThisV(LCreateThisV *lir);
|
||||
bool visitCreateThisO(LCreateThisO *lir);
|
||||
bool visitCreateThis(LCreateThis *lir);
|
||||
bool visitCreateThisWithProto(LCreateThisWithProto *lir);
|
||||
bool visitCreateThisWithTemplate(LCreateThisWithTemplate *lir);
|
||||
bool visitReturnFromCtor(LReturnFromCtor *lir);
|
||||
bool visitArrayLength(LArrayLength *lir);
|
||||
|
|
|
@ -3574,15 +3574,6 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
|
|||
return callObj;
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
IonBuilder::createThisNative()
|
||||
{
|
||||
// Native constructors build the new Object themselves.
|
||||
MConstant *magic = MConstant::New(MagicValue(JS_IS_CONSTRUCTING));
|
||||
current->add(magic);
|
||||
return magic;
|
||||
}
|
||||
|
||||
MDefinition *
|
||||
IonBuilder::createThisScripted(MDefinition *callee)
|
||||
{
|
||||
|
@ -3610,7 +3601,7 @@ IonBuilder::createThisScripted(MDefinition *callee)
|
|||
current->add(getProto);
|
||||
|
||||
// Create this from prototype
|
||||
MCreateThis *createThis = MCreateThis::New(callee, getProto);
|
||||
MCreateThisWithProto *createThis = MCreateThisWithProto::New(callee, getProto);
|
||||
current->add(createThis);
|
||||
|
||||
return createThis;
|
||||
|
@ -3633,8 +3624,13 @@ IonBuilder::getSingletonPrototype(JSFunction *target)
|
|||
}
|
||||
|
||||
MDefinition *
|
||||
IonBuilder::createThisScriptedSingleton(HandleFunction target, HandleObject proto, MDefinition *callee)
|
||||
IonBuilder::createThisScriptedSingleton(HandleFunction target, MDefinition *callee)
|
||||
{
|
||||
// Get the singleton prototype (if exists)
|
||||
RootedObject proto(cx, getSingletonPrototype(target));
|
||||
if (!proto)
|
||||
return NULL;
|
||||
|
||||
// Generate an inline path to create a new |this| object with
|
||||
// the given singleton prototype.
|
||||
types::TypeObject *type = proto->getNewType(cx, target);
|
||||
|
@ -3661,36 +3657,26 @@ MDefinition *
|
|||
IonBuilder::createThis(HandleFunction target, MDefinition *callee)
|
||||
{
|
||||
// Create this for unknown target
|
||||
if (!target)
|
||||
return createThisScripted(callee);
|
||||
|
||||
// Create this for native function
|
||||
if (target->isNative()) {
|
||||
if (!target->isNativeConstructor())
|
||||
return NULL;
|
||||
return createThisNative();
|
||||
if (!target) {
|
||||
MCreateThis *createThis = MCreateThis::New(callee);
|
||||
current->add(createThis);
|
||||
return createThis;
|
||||
}
|
||||
|
||||
// Create this with known prototype.
|
||||
RootedObject proto(cx, getSingletonPrototype(target));
|
||||
// Native constructors build the new Object themselves.
|
||||
if (target->isNative()) {
|
||||
JS_ASSERT (target->isNativeConstructor());
|
||||
MConstant *magic = MConstant::New(MagicValue(JS_IS_CONSTRUCTING));
|
||||
current->add(magic);
|
||||
return magic;
|
||||
}
|
||||
|
||||
// Try baking in the prototype.
|
||||
if (proto) {
|
||||
MDefinition *createThis = createThisScriptedSingleton(target, proto, callee);
|
||||
if (createThis)
|
||||
return createThis;
|
||||
}
|
||||
MDefinition *createThis = createThisScriptedSingleton(target, callee);
|
||||
if (createThis)
|
||||
return createThis;
|
||||
|
||||
MDefinition *createThis = createThisScripted(callee);
|
||||
if (!createThis)
|
||||
return NULL;
|
||||
|
||||
// The native function case is already handled upfront.
|
||||
// Here we can safely remove the native check for MCreateThis.
|
||||
JS_ASSERT(createThis->isCreateThis());
|
||||
createThis->toCreateThis()->removeNativeCheck();
|
||||
|
||||
return createThis;
|
||||
return createThisScripted(callee);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -275,9 +275,8 @@ class IonBuilder : public MIRGenerator
|
|||
|
||||
JSObject *getSingletonPrototype(JSFunction *target);
|
||||
|
||||
MDefinition *createThisNative();
|
||||
MDefinition *createThisScripted(MDefinition *callee);
|
||||
MDefinition *createThisScriptedSingleton(HandleFunction target, HandleObject proto, MDefinition *callee);
|
||||
MDefinition *createThisScriptedSingleton(HandleFunction target, MDefinition *callee);
|
||||
MDefinition *createThis(HandleFunction target, MDefinition *callee);
|
||||
MInstruction *createDeclEnvObject(MDefinition *callee, MDefinition *scopeObj);
|
||||
MInstruction *createCallObject(MDefinition *callee, MDefinition *scopeObj);
|
||||
|
|
|
@ -432,6 +432,52 @@ class LToIdV : public LCallInstructionHelper<BOX_PIECES, 2 * BOX_PIECES, 0>
|
|||
}
|
||||
};
|
||||
|
||||
// Allocate an object for |new| on the caller-side,
|
||||
// when there is no templateObject or prototype known
|
||||
class LCreateThis : public LCallInstructionHelper<BOX_PIECES, 1, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(CreateThis)
|
||||
|
||||
LCreateThis(const LAllocation &callee)
|
||||
{
|
||||
setOperand(0, callee);
|
||||
}
|
||||
|
||||
const LAllocation *getCallee() {
|
||||
return getOperand(0);
|
||||
}
|
||||
|
||||
MCreateThis *mir() const {
|
||||
return mir_->toCreateThis();
|
||||
}
|
||||
};
|
||||
|
||||
// Allocate an object for |new| on the caller-side,
|
||||
// when the prototype is known.
|
||||
class LCreateThisWithProto : public LCallInstructionHelper<1, 2, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(CreateThisWithProto)
|
||||
|
||||
LCreateThisWithProto(const LAllocation &callee, const LAllocation &prototype)
|
||||
{
|
||||
setOperand(0, callee);
|
||||
setOperand(1, prototype);
|
||||
}
|
||||
|
||||
const LAllocation *getCallee() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation *getPrototype() {
|
||||
return getOperand(1);
|
||||
}
|
||||
|
||||
MCreateThis *mir() const {
|
||||
return mir_->toCreateThis();
|
||||
}
|
||||
};
|
||||
|
||||
// Allocate an object for |new| on the caller-side.
|
||||
// Always performs object initialization with a fast path.
|
||||
class LCreateThisWithTemplate : public LInstructionHelper<1, 0, 0>
|
||||
|
@ -447,54 +493,6 @@ class LCreateThisWithTemplate : public LInstructionHelper<1, 0, 0>
|
|||
}
|
||||
};
|
||||
|
||||
// Allocate an object for |new| on the caller-side, when there is no templateObject.
|
||||
class LCreateThisV : public LCallInstructionHelper<BOX_PIECES, 2, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(CreateThisV)
|
||||
|
||||
LCreateThisV(const LAllocation &callee, const LAllocation &prototype)
|
||||
{
|
||||
setOperand(0, callee);
|
||||
setOperand(1, prototype);
|
||||
}
|
||||
|
||||
const LAllocation *getCallee() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation *getPrototype() {
|
||||
return getOperand(1);
|
||||
}
|
||||
|
||||
MCreateThis *mir() const {
|
||||
return mir_->toCreateThis();
|
||||
}
|
||||
};
|
||||
|
||||
// Allocate an object for |new| on the caller-side, when there is no templateObject.
|
||||
class LCreateThisO : public LCallInstructionHelper<1, 2, 0>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(CreateThisO)
|
||||
|
||||
LCreateThisO(const LAllocation &callee, const LAllocation &prototype)
|
||||
{
|
||||
setOperand(0, callee);
|
||||
setOperand(1, prototype);
|
||||
}
|
||||
|
||||
const LAllocation *getCallee() {
|
||||
return getOperand(0);
|
||||
}
|
||||
const LAllocation *getPrototype() {
|
||||
return getOperand(1);
|
||||
}
|
||||
|
||||
MCreateThis *mir() const {
|
||||
return mir_->toCreateThis();
|
||||
}
|
||||
};
|
||||
|
||||
// If the Value is an Object, return unbox(Value).
|
||||
// Otherwise, return the other Object.
|
||||
class LReturnFromCtor : public LInstructionHelper<1, BOX_PIECES + 1, 0>
|
||||
|
|
|
@ -39,8 +39,8 @@
|
|||
_(ApplyArgsGeneric) \
|
||||
_(StackArgT) \
|
||||
_(StackArgV) \
|
||||
_(CreateThisV) \
|
||||
_(CreateThisO) \
|
||||
_(CreateThis) \
|
||||
_(CreateThisWithProto) \
|
||||
_(CreateThisWithTemplate) \
|
||||
_(ReturnFromCtor) \
|
||||
_(BitNotI) \
|
||||
|
|
|
@ -241,18 +241,19 @@ LIRGenerator::visitCreateThisWithTemplate(MCreateThisWithTemplate *ins)
|
|||
return define(lir, ins) && assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitCreateThisWithProto(MCreateThisWithProto *ins)
|
||||
{
|
||||
LCreateThisWithProto *lir =
|
||||
new LCreateThisWithProto(useRegisterOrConstantAtStart(ins->getCallee()),
|
||||
useRegisterOrConstantAtStart(ins->getPrototype()));
|
||||
return defineReturn(lir, ins) && assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
bool
|
||||
LIRGenerator::visitCreateThis(MCreateThis *ins)
|
||||
{
|
||||
if (ins->needNativeCheck()) {
|
||||
JS_ASSERT(ins->type() == MIRType_Value);
|
||||
LCreateThisV *lir = new LCreateThisV(useRegisterAtStart(ins->getCallee()),
|
||||
useRegisterOrConstantAtStart(ins->getPrototype()));
|
||||
return defineReturn(lir, ins) && assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
LCreateThisO *lir = new LCreateThisO(useRegisterOrConstantAtStart(ins->getCallee()),
|
||||
useRegisterOrConstantAtStart(ins->getPrototype()));
|
||||
LCreateThis *lir = new LCreateThis(useRegisterOrConstantAtStart(ins->getCallee()));
|
||||
return defineReturn(lir, ins) && assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
|
|
|
@ -91,6 +91,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
|||
bool visitPrepareCall(MPrepareCall *ins);
|
||||
bool visitPassArg(MPassArg *arg);
|
||||
bool visitCreateThisWithTemplate(MCreateThisWithTemplate *ins);
|
||||
bool visitCreateThisWithProto(MCreateThisWithProto *ins);
|
||||
bool visitCreateThis(MCreateThis *ins);
|
||||
bool visitReturnFromCtor(MReturnFromCtor *ins);
|
||||
bool visitCall(MCall *call);
|
||||
|
|
|
@ -1688,29 +1688,21 @@ class MCreateThisWithTemplate
|
|||
|
||||
// Caller-side allocation of |this| for |new|:
|
||||
// Given a prototype operand, construct |this| for JSOP_NEW.
|
||||
// For native constructors, returns MagicValue(JS_IS_CONSTRUCTING).
|
||||
class MCreateThis
|
||||
: public MAryInstruction<2>,
|
||||
class MCreateThisWithProto
|
||||
: public MBinaryInstruction,
|
||||
public MixPolicy<ObjectPolicy<0>, ObjectPolicy<1> >
|
||||
{
|
||||
bool needNativeCheck_;
|
||||
|
||||
MCreateThis(MDefinition *callee, MDefinition *prototype)
|
||||
: needNativeCheck_(true)
|
||||
MCreateThisWithProto(MDefinition *callee, MDefinition *prototype)
|
||||
: MBinaryInstruction(callee, prototype)
|
||||
{
|
||||
initOperand(0, callee);
|
||||
initOperand(1, prototype);
|
||||
|
||||
// Type is mostly object, except for native constructors
|
||||
// therefore the need of Value type.
|
||||
setResultType(MIRType_Value);
|
||||
setResultType(MIRType_Object);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(CreateThis)
|
||||
static MCreateThis *New(MDefinition *callee, MDefinition *prototype)
|
||||
INSTRUCTION_HEADER(CreateThisWithProto)
|
||||
static MCreateThisWithProto *New(MDefinition *callee, MDefinition *prototype)
|
||||
{
|
||||
return new MCreateThis(callee, prototype);
|
||||
return new MCreateThisWithProto(callee, prototype);
|
||||
}
|
||||
|
||||
MDefinition *getCallee() const {
|
||||
|
@ -1719,12 +1711,37 @@ class MCreateThis
|
|||
MDefinition *getPrototype() const {
|
||||
return getOperand(1);
|
||||
}
|
||||
void removeNativeCheck() {
|
||||
needNativeCheck_ = false;
|
||||
setResultType(MIRType_Object);
|
||||
|
||||
// Although creation of |this| modifies global state, it is safely repeatable.
|
||||
AliasSet getAliasSet() const {
|
||||
return AliasSet::None();
|
||||
}
|
||||
bool needNativeCheck() const {
|
||||
return needNativeCheck_;
|
||||
TypePolicy *typePolicy() {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
// Caller-side allocation of |this| for |new|:
|
||||
// Constructs |this| when possible, else MagicValue(JS_IS_CONSTRUCTING).
|
||||
class MCreateThis
|
||||
: public MUnaryInstruction,
|
||||
public ObjectPolicy<0>
|
||||
{
|
||||
MCreateThis(MDefinition *callee)
|
||||
: MUnaryInstruction(callee)
|
||||
{
|
||||
setResultType(MIRType_Value);
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(CreateThis)
|
||||
static MCreateThis *New(MDefinition *callee)
|
||||
{
|
||||
return new MCreateThis(callee);
|
||||
}
|
||||
|
||||
MDefinition *getCallee() const {
|
||||
return getOperand(0);
|
||||
}
|
||||
|
||||
// Although creation of |this| modifies global state, it is safely repeatable.
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace ion {
|
|||
_(DefVar) \
|
||||
_(DefFun) \
|
||||
_(CreateThis) \
|
||||
_(CreateThisWithProto) \
|
||||
_(CreateThisWithTemplate) \
|
||||
_(PrepareCall) \
|
||||
_(PassArg) \
|
||||
|
|
|
@ -437,18 +437,21 @@ NewStringObject(JSContext *cx, HandleString str)
|
|||
return StringObject::create(cx, str);
|
||||
}
|
||||
|
||||
bool SPSEnter(JSContext *cx, HandleScript script)
|
||||
bool
|
||||
SPSEnter(JSContext *cx, HandleScript script)
|
||||
{
|
||||
return cx->runtime->spsProfiler.enter(cx, script, script->function());
|
||||
}
|
||||
|
||||
bool SPSExit(JSContext *cx, HandleScript script)
|
||||
bool
|
||||
SPSExit(JSContext *cx, HandleScript script)
|
||||
{
|
||||
cx->runtime->spsProfiler.exit(cx, script, script->function());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, JSBool *out)
|
||||
bool
|
||||
OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, JSBool *out)
|
||||
{
|
||||
RootedValue dummy(cx); // Disregards atomization changes: no way to propagate.
|
||||
RootedId id(cx);
|
||||
|
@ -464,10 +467,25 @@ bool OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, JSBool *out)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GetIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue rval)
|
||||
bool
|
||||
GetIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue rval)
|
||||
{
|
||||
return cx->global()->getIntrinsicValue(cx, name, rval);
|
||||
}
|
||||
|
||||
bool
|
||||
CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval)
|
||||
{
|
||||
rval.set(MagicValue(JS_IS_CONSTRUCTING));
|
||||
|
||||
if (callee->isFunction()) {
|
||||
JSFunction *fun = callee->toFunction();
|
||||
if (fun->isInterpreted())
|
||||
rval.set(ObjectValue(*js_CreateThisForFunction(cx, callee, false)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace ion
|
||||
} // namespace js
|
||||
|
|
|
@ -464,6 +464,7 @@ bool OperatorIn(JSContext *cx, HandleValue key, HandleObject obj, JSBool *out);
|
|||
|
||||
bool GetIntrinsicValue(JSContext *cx, HandlePropertyName name, MutableHandleValue rval);
|
||||
|
||||
bool CreateThis(JSContext *cx, HandleObject callee, MutableHandleValue rval);
|
||||
} // namespace ion
|
||||
} // namespace js
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
// Test 1: When constructing x, we shouldn't take the prototype for this.
|
||||
// it will crash if that happens
|
||||
evalcx("\
|
||||
var x = newGlobal().Object;\
|
||||
function f() { return new x; }\
|
||||
f();\
|
||||
f();\
|
||||
", newGlobal());
|
||||
|
||||
// Test 2: Don't take the prototype of proxy's to create |this|,
|
||||
// as this will throw... Not expected behaviour.
|
||||
var O = new Proxy(function() {}, {
|
||||
get: function() {
|
||||
throw "get trap";
|
||||
}
|
||||
});
|
||||
|
||||
function f() {
|
||||
new O();
|
||||
}
|
||||
|
||||
f();
|
||||
f();
|
Загрузка…
Ссылка в новой задаче