зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changesets f2387d9f146c and d12788533ab7 (bug 860145) for causing topcrashers.
This commit is contained in:
Родитель
bdd647a54d
Коммит
9d2dac0e32
|
@ -95,32 +95,18 @@ StackFrame::initFromBailout(JSContext *cx, SnapshotIterator &iter)
|
||||||
if (iter.bailoutKind() == Bailout_ArgumentCheck) {
|
if (iter.bailoutKind() == Bailout_ArgumentCheck) {
|
||||||
// Temporary hack -- skip the (unused) scopeChain, because it could be
|
// Temporary hack -- skip the (unused) scopeChain, because it could be
|
||||||
// bogus (we can fail before the scope chain slot is set). Strip the
|
// bogus (we can fail before the scope chain slot is set). Strip the
|
||||||
// hasScopeChain flag. If a call object is needed, it will get handled later
|
// hasScopeChain flag and we'll check this later to run prologue().
|
||||||
// by |ThunkToInterpreter| which call |EnsureHasScopeObjects|.
|
|
||||||
iter.skip();
|
iter.skip();
|
||||||
flags_ &= ~StackFrame::HAS_SCOPECHAIN;
|
flags_ &= ~StackFrame::HAS_SCOPECHAIN;
|
||||||
|
|
||||||
// If the script binds arguments, then skip the snapshot slot reserved to hold
|
|
||||||
// its value.
|
|
||||||
if (script()->argumentsHasVarBinding())
|
|
||||||
iter.skip();
|
|
||||||
flags_ &= ~StackFrame::HAS_ARGS_OBJ;
|
|
||||||
} else {
|
} else {
|
||||||
Value scopeChain = iter.read();
|
Value v = iter.read();
|
||||||
JS_ASSERT(scopeChain.isObject() || scopeChain.isUndefined());
|
if (v.isObject()) {
|
||||||
if (scopeChain.isObject()) {
|
scopeChain_ = &v.toObject();
|
||||||
scopeChain_ = &scopeChain.toObject();
|
|
||||||
flags_ |= StackFrame::HAS_SCOPECHAIN;
|
flags_ |= StackFrame::HAS_SCOPECHAIN;
|
||||||
if (isFunctionFrame() && fun()->isHeavyweight())
|
if (isFunctionFrame() && fun()->isHeavyweight())
|
||||||
flags_ |= StackFrame::HAS_CALL_OBJ;
|
flags_ |= StackFrame::HAS_CALL_OBJ;
|
||||||
}
|
} else {
|
||||||
|
JS_ASSERT(v.isUndefined());
|
||||||
// The second slot will be an arguments object if the script needs one.
|
|
||||||
if (script()->argumentsHasVarBinding()) {
|
|
||||||
Value argsObj = iter.read();
|
|
||||||
JS_ASSERT(argsObj.isObject() || argsObj.isUndefined());
|
|
||||||
if (argsObj.isObject())
|
|
||||||
initArgsObj(argsObj.toObject().asArguments());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,7 +125,7 @@ StackFrame::initFromBailout(JSContext *cx, SnapshotIterator &iter)
|
||||||
if (isConstructing())
|
if (isConstructing())
|
||||||
JS_ASSERT(!thisv.isPrimitive());
|
JS_ASSERT(!thisv.isPrimitive());
|
||||||
|
|
||||||
JS_ASSERT(iter.slots() >= CountArgSlots(script(), fun()));
|
JS_ASSERT(iter.slots() >= CountArgSlots(fun()));
|
||||||
IonSpew(IonSpew_Bailouts, " frame slots %u, nargs %u, nfixed %u",
|
IonSpew(IonSpew_Bailouts, " frame slots %u, nargs %u, nfixed %u",
|
||||||
iter.slots(), fun()->nargs, script()->nfixed);
|
iter.slots(), fun()->nargs, script()->nfixed);
|
||||||
|
|
||||||
|
@ -148,7 +134,7 @@ StackFrame::initFromBailout(JSContext *cx, SnapshotIterator &iter)
|
||||||
formals()[i] = arg;
|
formals()[i] = arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
exprStackSlots -= CountArgSlots(script(), maybeFun());
|
exprStackSlots -= CountArgSlots(maybeFun());
|
||||||
|
|
||||||
for (uint32_t i = 0; i < script()->nfixed; i++) {
|
for (uint32_t i = 0; i < script()->nfixed; i++) {
|
||||||
Value slot = iter.read();
|
Value slot = iter.read();
|
||||||
|
@ -512,7 +498,7 @@ ion::ReflowTypeInfo(uint32_t bailoutResult)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the decl env Object, call object, and any arguments obj of the current frame.
|
// Initialize the decl env Object and the call object of the current frame.
|
||||||
bool
|
bool
|
||||||
ion::EnsureHasScopeObjects(JSContext *cx, AbstractFramePtr fp)
|
ion::EnsureHasScopeObjects(JSContext *cx, AbstractFramePtr fp)
|
||||||
{
|
{
|
||||||
|
@ -617,22 +603,20 @@ ion::ThunkToInterpreter(Value *vp)
|
||||||
fp = iter.interpFrame();
|
fp = iter.interpFrame();
|
||||||
script = iter.script();
|
script = iter.script();
|
||||||
if (script->needsArgsObj()) {
|
if (script->needsArgsObj()) {
|
||||||
ArgumentsObject *argsObj;
|
// Currently IonMonkey does not compile if the script needs an
|
||||||
if (fp->hasArgsObj()) {
|
// arguments object, so the frame should not have any argument
|
||||||
argsObj = &fp->argsObj();
|
// object yet.
|
||||||
} else {
|
JS_ASSERT(!fp->hasArgsObj());
|
||||||
argsObj = ArgumentsObject::createExpected(cx, fp);
|
ArgumentsObject *argsobj = ArgumentsObject::createExpected(cx, fp);
|
||||||
if (!argsObj) {
|
if (!argsobj) {
|
||||||
resumeMode = JSINTERP_RETHROW;
|
resumeMode = JSINTERP_RETHROW;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The arguments is a local binding and needsArgsObj does not
|
// The arguments is a local binding and needsArgsObj does not
|
||||||
// check if it is clobbered. Ensure that the local binding
|
// check if it is clobbered. Ensure that the local binding
|
||||||
// restored during bailout before storing the arguments object
|
// restored during bailout before storing the arguments object
|
||||||
// to the slot.
|
// to the slot.
|
||||||
SetFrameArgumentsObject(cx, fp, script, argsObj);
|
SetFrameArgumentsObject(cx, fp, script, argsobj);
|
||||||
}
|
}
|
||||||
++iter;
|
++iter;
|
||||||
} while (fp != br->entryfp());
|
} while (fp != br->entryfp());
|
||||||
|
|
|
@ -447,7 +447,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
||||||
bool invalidate, BaselineStackBuilder &builder,
|
bool invalidate, BaselineStackBuilder &builder,
|
||||||
MutableHandleFunction nextCallee, jsbytecode **callPC)
|
MutableHandleFunction nextCallee, jsbytecode **callPC)
|
||||||
{
|
{
|
||||||
uint32_t exprStackSlots = iter.slots() - (script->nfixed + CountArgSlots(script, fun));
|
uint32_t exprStackSlots = iter.slots() - (script->nfixed + CountArgSlots(fun));
|
||||||
|
|
||||||
builder.resetFramePushed();
|
builder.resetFramePushed();
|
||||||
|
|
||||||
|
@ -508,25 +508,15 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
||||||
flags |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
|
flags |= BaselineFrame::HAS_PUSHED_SPS_FRAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize BaselineFrame's scopeChain and argsObj
|
// Initialize BaselineFrame::scopeChain
|
||||||
JSObject *scopeChain = NULL;
|
JSObject *scopeChain = NULL;
|
||||||
ArgumentsObject *argsObj = NULL;
|
|
||||||
BailoutKind bailoutKind = iter.bailoutKind();
|
BailoutKind bailoutKind = iter.bailoutKind();
|
||||||
if (bailoutKind == Bailout_ArgumentCheck) {
|
if (bailoutKind == Bailout_ArgumentCheck) {
|
||||||
// Temporary hack -- skip the (unused) scopeChain, because it could be
|
// Temporary hack -- skip the (unused) scopeChain, because it could be
|
||||||
// bogus (we can fail before the scope chain slot is set). Strip the
|
// bogus (we can fail before the scope chain slot is set). Strip the
|
||||||
// hasScopeChain flag and this will be fixed up later in |FinishBailoutToBaseline|,
|
// hasScopeChain flag and we'll check this later to run prologue().
|
||||||
// which calls |EnsureHasScopeObjects|.
|
|
||||||
IonSpew(IonSpew_BaselineBailouts, " Bailout_ArgumentCheck! (no valid scopeChain)");
|
IonSpew(IonSpew_BaselineBailouts, " Bailout_ArgumentCheck! (no valid scopeChain)");
|
||||||
iter.skip();
|
iter.skip();
|
||||||
|
|
||||||
// Scripts with |argumentsHasVarBinding| have an extra slot.
|
|
||||||
if (script->argumentsHasVarBinding()) {
|
|
||||||
IonSpew(IonSpew_BaselineBailouts,
|
|
||||||
" Bailout_ArgumentCheck for script with argumentsHasVarBinding!"
|
|
||||||
"Using empty arguments object");
|
|
||||||
iter.skip();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
Value v = iter.read();
|
Value v = iter.read();
|
||||||
if (v.isObject()) {
|
if (v.isObject()) {
|
||||||
|
@ -554,19 +544,9 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
||||||
scopeChain = &(script->global());
|
scopeChain = &(script->global());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If script maybe has an arguments object, the second slot will hold it.
|
|
||||||
if (script->argumentsHasVarBinding()) {
|
|
||||||
v = iter.read();
|
|
||||||
JS_ASSERT(v.isObject() || v.isUndefined());
|
|
||||||
if (v.isObject())
|
|
||||||
argsObj = &v.toObject().asArguments();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
IonSpew(IonSpew_BaselineBailouts, " ScopeChain=%p", scopeChain);
|
IonSpew(IonSpew_BaselineBailouts, " ScopeChain=%p", scopeChain);
|
||||||
blFrame->setScopeChain(scopeChain);
|
blFrame->setScopeChain(scopeChain);
|
||||||
if (argsObj)
|
|
||||||
blFrame->initArgsObjUnchecked(*argsObj);
|
|
||||||
// Do not need to initialize scratchValue or returnValue fields in BaselineFrame.
|
// Do not need to initialize scratchValue or returnValue fields in BaselineFrame.
|
||||||
|
|
||||||
// No flags are set.
|
// No flags are set.
|
||||||
|
@ -586,7 +566,7 @@ InitFromBailout(JSContext *cx, HandleScript caller, jsbytecode *callerPC,
|
||||||
size_t thisvOffset = builder.framePushed() + IonJSFrameLayout::offsetOfThis();
|
size_t thisvOffset = builder.framePushed() + IonJSFrameLayout::offsetOfThis();
|
||||||
*builder.valuePointerAtStackOffset(thisvOffset) = thisv;
|
*builder.valuePointerAtStackOffset(thisvOffset) = thisv;
|
||||||
|
|
||||||
JS_ASSERT(iter.slots() >= CountArgSlots(script, fun));
|
JS_ASSERT(iter.slots() >= CountArgSlots(fun));
|
||||||
IonSpew(IonSpew_BaselineBailouts, " frame slots %u, nargs %u, nfixed %u",
|
IonSpew(IonSpew_BaselineBailouts, " frame slots %u, nargs %u, nfixed %u",
|
||||||
iter.slots(), fun->nargs, script->nfixed);
|
iter.slots(), fun->nargs, script->nfixed);
|
||||||
|
|
||||||
|
@ -1210,26 +1190,19 @@ ion::FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo)
|
||||||
|
|
||||||
if (iter.isBaselineJS()) {
|
if (iter.isBaselineJS()) {
|
||||||
BaselineFrame *frame = iter.baselineFrame();
|
BaselineFrame *frame = iter.baselineFrame();
|
||||||
|
JS_ASSERT(!frame->hasArgsObj());
|
||||||
|
|
||||||
// If the frame doesn't even have a scope chain set yet, then it's resuming
|
if (frame->script()->needsArgsObj()) {
|
||||||
// into the the prologue before the scope chain is initialized. Any
|
ArgumentsObject *argsobj = ArgumentsObject::createExpected(cx, frame);
|
||||||
// necessary args object will also be initialized there.
|
if (!argsobj)
|
||||||
if (frame->scopeChain() && frame->script()->needsArgsObj()) {
|
return false;
|
||||||
ArgumentsObject *argsObj;
|
|
||||||
if (frame->hasArgsObj()) {
|
|
||||||
argsObj = &frame->argsObj();
|
|
||||||
} else {
|
|
||||||
argsObj = ArgumentsObject::createExpected(cx, frame);
|
|
||||||
if (!argsObj)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The arguments is a local binding and needsArgsObj does not
|
// The arguments is a local binding and needsArgsObj does not
|
||||||
// check if it is clobbered. Ensure that the local binding
|
// check if it is clobbered. Ensure that the local binding
|
||||||
// restored during bailout before storing the arguments object
|
// restored during bailout before storing the arguments object
|
||||||
// to the slot.
|
// to the slot.
|
||||||
RootedScript script(cx, frame->script());
|
RootedScript script(cx, frame->script());
|
||||||
SetFrameArgumentsObject(cx, frame, script, argsObj);
|
SetFrameArgumentsObject(cx, frame, script, argsobj);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frameno == 0)
|
if (frameno == 0)
|
||||||
|
|
|
@ -411,7 +411,7 @@ BaselineCompiler::emitUseCountIncrement()
|
||||||
// Emit no use count increments or bailouts if Ion is not
|
// Emit no use count increments or bailouts if Ion is not
|
||||||
// enabled, or if the script will never be Ion-compileable
|
// enabled, or if the script will never be Ion-compileable
|
||||||
|
|
||||||
if (!ionCompileable_ && !ionOSRCompileable_)
|
if (!ionCompileable_)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
Register scriptReg = R2.scratchReg();
|
Register scriptReg = R2.scratchReg();
|
||||||
|
|
|
@ -251,13 +251,10 @@ class BaselineFrame
|
||||||
bool heavyweightFunPrologue(JSContext *cx);
|
bool heavyweightFunPrologue(JSContext *cx);
|
||||||
bool initFunctionScopeObjects(JSContext *cx);
|
bool initFunctionScopeObjects(JSContext *cx);
|
||||||
|
|
||||||
void initArgsObjUnchecked(ArgumentsObject &argsobj) {
|
|
||||||
flags_ |= HAS_ARGS_OBJ;
|
|
||||||
argsObj_ = &argsobj;
|
|
||||||
}
|
|
||||||
void initArgsObj(ArgumentsObject &argsobj) {
|
void initArgsObj(ArgumentsObject &argsobj) {
|
||||||
JS_ASSERT(script()->needsArgsObj());
|
JS_ASSERT(script()->needsArgsObj());
|
||||||
initArgsObjUnchecked(argsobj);
|
flags_ |= HAS_ARGS_OBJ;
|
||||||
|
argsObj_ = &argsobj;
|
||||||
}
|
}
|
||||||
bool hasArgsObj() const {
|
bool hasArgsObj() const {
|
||||||
return flags_ & HAS_ARGS_OBJ;
|
return flags_ & HAS_ARGS_OBJ;
|
||||||
|
|
|
@ -94,9 +94,8 @@ EnterBaseline(JSContext *cx, StackFrame *fp, void *jitcode, bool osr)
|
||||||
|
|
||||||
void *calleeToken;
|
void *calleeToken;
|
||||||
if (fp->isNonEvalFunctionFrame()) {
|
if (fp->isNonEvalFunctionFrame()) {
|
||||||
// CountArgSlot include |this| and the |scopeChain|, and maybe |argumentsObj|
|
// CountArgSlot include |this| and the |scopeChain|.
|
||||||
// Want to keep including this, but remove the scopeChain and any argumentsObj.
|
maxArgc = CountArgSlots(fp->fun()) - 1; // -1 = discard |scopeChain|
|
||||||
maxArgc = CountArgSlots(fp->script(), fp->fun()) - StartArgSlot(fp->script(), fp->fun());
|
|
||||||
maxArgv = fp->formals() - 1; // -1 = include |this|
|
maxArgv = fp->formals() - 1; // -1 = include |this|
|
||||||
|
|
||||||
// Formal arguments are the argument corresponding to the function
|
// Formal arguments are the argument corresponding to the function
|
||||||
|
|
|
@ -1807,19 +1807,21 @@ CodeGenerator::generateArgumentsChecks()
|
||||||
|
|
||||||
CompileInfo &info = gen->info();
|
CompileInfo &info = gen->info();
|
||||||
|
|
||||||
|
// Indexes need to be shifted by one, to skip the scope chain slot.
|
||||||
|
JS_ASSERT(info.scopeChainSlot() == 0);
|
||||||
|
static const uint32_t START_SLOT = 1;
|
||||||
|
|
||||||
Label miss;
|
Label miss;
|
||||||
for (uint32_t i = info.startArgSlot(); i < info.endArgSlot(); i++) {
|
for (uint32_t i = START_SLOT; i < CountArgSlots(info.fun()); i++) {
|
||||||
// All initial parameters are guaranteed to be MParameters.
|
// All initial parameters are guaranteed to be MParameters.
|
||||||
MParameter *param = rp->getOperand(i)->toParameter();
|
MParameter *param = rp->getOperand(i)->toParameter();
|
||||||
const types::TypeSet *types = param->typeSet();
|
const types::TypeSet *types = param->typeSet();
|
||||||
if (!types || types->unknown())
|
if (!types || types->unknown())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Calculate the offset on the stack of the argument.
|
// Use ReturnReg as a scratch register here, since not all platforms
|
||||||
// (i - info.startArgSlot()) - Compute index of arg within arg vector.
|
// have an actual ScratchReg.
|
||||||
// ... * sizeof(Value) - Scale by value size.
|
int32_t offset = ArgToStackOffset((i - START_SLOT) * sizeof(Value));
|
||||||
// ArgToStackOffset(...) - Compute displacement within arg vector.
|
|
||||||
int32_t offset = ArgToStackOffset((i - info.startArgSlot()) * sizeof(Value));
|
|
||||||
Label matched;
|
Label matched;
|
||||||
masm.guardTypeSet(Address(StackPointer, offset), types, temp, &matched, &miss);
|
masm.guardTypeSet(Address(StackPointer, offset), types, temp, &matched, &miss);
|
||||||
masm.jump(&miss);
|
masm.jump(&miss);
|
||||||
|
@ -2848,66 +2850,6 @@ CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate *lir)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef JSObject *(*NewIonArgumentsObjectFn)(JSContext *cx, IonJSFrameLayout *frame, HandleObject);
|
|
||||||
static const VMFunction NewIonArgumentsObjectInfo =
|
|
||||||
FunctionInfo<NewIonArgumentsObjectFn>((NewIonArgumentsObjectFn) ArgumentsObject::createForIon);
|
|
||||||
|
|
||||||
bool
|
|
||||||
CodeGenerator::visitCreateArgumentsObject(LCreateArgumentsObject *lir)
|
|
||||||
{
|
|
||||||
// This should be getting constructed in the first block only, and not any OSR entry blocks.
|
|
||||||
JS_ASSERT(lir->mir()->block()->id() == 0);
|
|
||||||
|
|
||||||
const LAllocation *callObj = lir->getCallObject();
|
|
||||||
Register temp = ToRegister(lir->getTemp(0));
|
|
||||||
|
|
||||||
masm.movePtr(StackPointer, temp);
|
|
||||||
masm.addPtr(Imm32(frameSize()), temp);
|
|
||||||
|
|
||||||
pushArg(ToRegister(callObj));
|
|
||||||
pushArg(temp);
|
|
||||||
return callVM(NewIonArgumentsObjectInfo, lir);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CodeGenerator::visitGetArgumentsObjectArg(LGetArgumentsObjectArg *lir)
|
|
||||||
{
|
|
||||||
Register temp = ToRegister(lir->getTemp(0));
|
|
||||||
Register argsObj = ToRegister(lir->getArgsObject());
|
|
||||||
ValueOperand out = ToOutValue(lir);
|
|
||||||
|
|
||||||
masm.loadPrivate(Address(argsObj, ArgumentsObject::getDataSlotOffset()), temp);
|
|
||||||
Address argAddr(temp, ArgumentsData::offsetOfArgs() + lir->mir()->argno() * sizeof(Value));
|
|
||||||
masm.loadValue(argAddr, out);
|
|
||||||
#ifdef DEBUG
|
|
||||||
Label success;
|
|
||||||
masm.branchTestMagic(Assembler::NotEqual, out, &success);
|
|
||||||
masm.breakpoint();
|
|
||||||
masm.bind(&success);
|
|
||||||
#endif
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
CodeGenerator::visitSetArgumentsObjectArg(LSetArgumentsObjectArg *lir)
|
|
||||||
{
|
|
||||||
Register temp = ToRegister(lir->getTemp(0));
|
|
||||||
Register argsObj = ToRegister(lir->getArgsObject());
|
|
||||||
ValueOperand value = ToValue(lir, LSetArgumentsObjectArg::ValueIndex);
|
|
||||||
|
|
||||||
masm.loadPrivate(Address(argsObj, ArgumentsObject::getDataSlotOffset()), temp);
|
|
||||||
Address argAddr(temp, ArgumentsData::offsetOfArgs() + lir->mir()->argno() * sizeof(Value));
|
|
||||||
emitPreBarrier(argAddr, MIRType_Value);
|
|
||||||
#ifdef DEBUG
|
|
||||||
Label success;
|
|
||||||
masm.branchTestMagic(Assembler::NotEqual, argAddr, &success);
|
|
||||||
masm.breakpoint();
|
|
||||||
masm.bind(&success);
|
|
||||||
#endif
|
|
||||||
masm.storeValue(value, argAddr);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CodeGenerator::visitReturnFromCtor(LReturnFromCtor *lir)
|
CodeGenerator::visitReturnFromCtor(LReturnFromCtor *lir)
|
||||||
{
|
{
|
||||||
|
|
|
@ -121,9 +121,6 @@ class CodeGenerator : public CodeGeneratorSpecific
|
||||||
bool visitCreateThis(LCreateThis *lir);
|
bool visitCreateThis(LCreateThis *lir);
|
||||||
bool visitCreateThisWithProto(LCreateThisWithProto *lir);
|
bool visitCreateThisWithProto(LCreateThisWithProto *lir);
|
||||||
bool visitCreateThisWithTemplate(LCreateThisWithTemplate *lir);
|
bool visitCreateThisWithTemplate(LCreateThisWithTemplate *lir);
|
||||||
bool visitCreateArgumentsObject(LCreateArgumentsObject *lir);
|
|
||||||
bool visitGetArgumentsObjectArg(LGetArgumentsObjectArg *lir);
|
|
||||||
bool visitSetArgumentsObjectArg(LSetArgumentsObjectArg *lir);
|
|
||||||
bool visitReturnFromCtor(LReturnFromCtor *lir);
|
bool visitReturnFromCtor(LReturnFromCtor *lir);
|
||||||
bool visitArrayLength(LArrayLength *lir);
|
bool visitArrayLength(LArrayLength *lir);
|
||||||
bool visitTypedArrayLength(LTypedArrayLength *lir);
|
bool visitTypedArrayLength(LTypedArrayLength *lir);
|
||||||
|
|
|
@ -13,17 +13,9 @@ namespace js {
|
||||||
namespace ion {
|
namespace ion {
|
||||||
|
|
||||||
inline unsigned
|
inline unsigned
|
||||||
StartArgSlot(RawScript script, JSFunction *fun)
|
CountArgSlots(JSFunction *fun)
|
||||||
{
|
{
|
||||||
// First slot is for scope chain.
|
return fun ? fun->nargs + 2 : 1; // +2 for |scopeChain| and |this|, or +1 for |scopeChain|
|
||||||
// Second one may be for arguments object.
|
|
||||||
return 1 + (script->argumentsHasVarBinding() ? 1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline unsigned
|
|
||||||
CountArgSlots(RawScript script, JSFunction *fun)
|
|
||||||
{
|
|
||||||
return StartArgSlot(script, fun) + (fun ? fun->nargs + 1 : 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ExecutionMode {
|
enum ExecutionMode {
|
||||||
|
@ -45,8 +37,7 @@ class CompileInfo
|
||||||
executionMode_(executionMode)
|
executionMode_(executionMode)
|
||||||
{
|
{
|
||||||
JS_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY);
|
JS_ASSERT_IF(osrPc, JSOp(*osrPc) == JSOP_LOOPENTRY);
|
||||||
nimplicit_ = StartArgSlot(script, fun) /* scope chain and argument obj */
|
nimplicit_ = 1 /* scope chain */ + (fun ? 1 /* this */: 0);
|
||||||
+ (fun ? 1 : 0); /* this */
|
|
||||||
nargs_ = fun ? fun->nargs : 0;
|
nargs_ = fun ? fun->nargs : 0;
|
||||||
nlocals_ = script->nfixed;
|
nlocals_ = script->nfixed;
|
||||||
nstack_ = script->nslots - script->nfixed;
|
nstack_ = script->nslots - script->nfixed;
|
||||||
|
@ -126,30 +117,17 @@ class CompileInfo
|
||||||
JS_ASSERT(script());
|
JS_ASSERT(script());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
uint32_t argsObjSlot() const {
|
|
||||||
JS_ASSERT(hasArguments());
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
uint32_t thisSlot() const {
|
uint32_t thisSlot() const {
|
||||||
JS_ASSERT(fun());
|
JS_ASSERT(fun());
|
||||||
return hasArguments() ? 2 : 1;
|
return 1;
|
||||||
}
|
}
|
||||||
uint32_t firstActualArgSlot() const {
|
uint32_t firstArgSlot() const {
|
||||||
return nimplicit_;
|
return nimplicit_;
|
||||||
}
|
}
|
||||||
uint32_t argSlotUnchecked(uint32_t i) const {
|
uint32_t argSlot(uint32_t i) const {
|
||||||
// During initialization, some routines need to get at arg
|
|
||||||
// slots regardless of how regular argument access is done.
|
|
||||||
JS_ASSERT(i < nargs_);
|
JS_ASSERT(i < nargs_);
|
||||||
return nimplicit_ + i;
|
return nimplicit_ + i;
|
||||||
}
|
}
|
||||||
uint32_t argSlot(uint32_t i) const {
|
|
||||||
// This should only be accessed when compiling functions for
|
|
||||||
// which argument accesses don't need to go through the
|
|
||||||
// argument object.
|
|
||||||
JS_ASSERT(!argsObjAliasesFormals());
|
|
||||||
return argSlotUnchecked(i);
|
|
||||||
}
|
|
||||||
uint32_t firstLocalSlot() const {
|
uint32_t firstLocalSlot() const {
|
||||||
return nimplicit_ + nargs_;
|
return nimplicit_ + nargs_;
|
||||||
}
|
}
|
||||||
|
@ -163,28 +141,9 @@ class CompileInfo
|
||||||
return firstStackSlot() + i;
|
return firstStackSlot() + i;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t startArgSlot() const {
|
bool hasArguments() {
|
||||||
JS_ASSERT(scopeChainSlot() == 0);
|
|
||||||
return StartArgSlot(script(), fun());
|
|
||||||
}
|
|
||||||
uint32_t endArgSlot() const {
|
|
||||||
JS_ASSERT(scopeChainSlot() == 0);
|
|
||||||
return CountArgSlots(script(), fun());
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t totalSlots() const {
|
|
||||||
return 2 + (hasArguments() ? 1 : 0) + nargs() + nlocals();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasArguments() const {
|
|
||||||
return script()->argumentsHasVarBinding();
|
return script()->argumentsHasVarBinding();
|
||||||
}
|
}
|
||||||
bool needsArgsObj() const {
|
|
||||||
return script()->needsArgsObj();
|
|
||||||
}
|
|
||||||
bool argsObjAliasesFormals() const {
|
|
||||||
return script()->argsObjAliasesFormals();
|
|
||||||
}
|
|
||||||
|
|
||||||
ExecutionMode executionMode() const {
|
ExecutionMode executionMode() const {
|
||||||
return executionMode_;
|
return executionMode_;
|
||||||
|
|
|
@ -1448,11 +1448,11 @@ CheckFrame(AbstractFramePtr fp)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
CheckScript(RawScript script, bool osr)
|
CheckScript(RawScript script)
|
||||||
{
|
{
|
||||||
if (osr && script->needsArgsObj()) {
|
if (script->needsArgsObj()) {
|
||||||
// OSR-ing into functions with arguments objects is not supported.
|
// Functions with arguments objects, are not supported yet.
|
||||||
IonSpew(IonSpew_Abort, "OSR script has argsobj");
|
IonSpew(IonSpew_Abort, "script has argsobj");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1508,9 +1508,9 @@ SequentialCompileContext::checkScriptSize(JSContext *cx, RawScript script)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CanIonCompileScript(JSContext *cx, HandleScript script, bool osr)
|
CanIonCompileScript(JSContext *cx, HandleScript script)
|
||||||
{
|
{
|
||||||
if (!script->canIonCompile() || !CheckScript(script, osr))
|
if (!script->canIonCompile() || !CheckScript(script))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SequentialCompileContext compileContext;
|
SequentialCompileContext compileContext;
|
||||||
|
@ -1519,8 +1519,8 @@ CanIonCompileScript(JSContext *cx, HandleScript script, bool osr)
|
||||||
|
|
||||||
template <typename CompileContext>
|
template <typename CompileContext>
|
||||||
static MethodStatus
|
static MethodStatus
|
||||||
Compile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *osrPc,
|
Compile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *osrPc, bool constructing,
|
||||||
bool constructing, CompileContext &compileContext)
|
CompileContext &compileContext)
|
||||||
{
|
{
|
||||||
JS_ASSERT(ion::IsEnabled(cx));
|
JS_ASSERT(ion::IsEnabled(cx));
|
||||||
JS_ASSERT_IF(osrPc != NULL, (JSOp)*osrPc == JSOP_LOOPENTRY);
|
JS_ASSERT_IF(osrPc != NULL, (JSOp)*osrPc == JSOP_LOOPENTRY);
|
||||||
|
@ -1540,7 +1540,7 @@ Compile(JSContext *cx, HandleScript script, HandleFunction fun, jsbytecode *osrP
|
||||||
return Method_CantCompile;
|
return Method_CantCompile;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CheckScript(script, bool(osrPc))) {
|
if (!CheckScript(script)) {
|
||||||
IonSpew(IonSpew_Abort, "Aborted compilation of %s:%d", script->filename(), script->lineno);
|
IonSpew(IonSpew_Abort, "Aborted compilation of %s:%d", script->filename(), script->lineno);
|
||||||
return Method_CantCompile;
|
return Method_CantCompile;
|
||||||
}
|
}
|
||||||
|
@ -1922,9 +1922,8 @@ EnterIon(JSContext *cx, StackFrame *fp, void *jitcode)
|
||||||
if (fp->isFunctionFrame()) {
|
if (fp->isFunctionFrame()) {
|
||||||
fp->cleanupTornValues();
|
fp->cleanupTornValues();
|
||||||
|
|
||||||
// CountArgSlot include |this| and the |scopeChain| and maybe |argumentsObj|.
|
// CountArgSlot include |this| and the |scopeChain|.
|
||||||
// Keep |this|, but discard the others.
|
maxArgc = CountArgSlots(fp->fun()) - 1; // -1 = discard |scopeChain|
|
||||||
maxArgc = CountArgSlots(fp->script(), fp->fun()) - StartArgSlot(fp->script(), fp->fun());
|
|
||||||
maxArgv = fp->formals() - 1; // -1 = include |this|
|
maxArgv = fp->formals() - 1; // -1 = include |this|
|
||||||
|
|
||||||
// Formal arguments are the argument corresponding to the function
|
// Formal arguments are the argument corresponding to the function
|
||||||
|
|
|
@ -282,7 +282,7 @@ IonContext *GetIonContext();
|
||||||
|
|
||||||
bool SetIonContext(IonContext *ctx);
|
bool SetIonContext(IonContext *ctx);
|
||||||
|
|
||||||
bool CanIonCompileScript(JSContext *cx, HandleScript script, bool osr);
|
bool CanIonCompileScript(JSContext *cx, HandleScript script);
|
||||||
|
|
||||||
MethodStatus CanEnterAtBranch(JSContext *cx, JSScript *script,
|
MethodStatus CanEnterAtBranch(JSContext *cx, JSScript *script,
|
||||||
AbstractFramePtr fp, jsbytecode *pc, bool isConstructing);
|
AbstractFramePtr fp, jsbytecode *pc, bool isConstructing);
|
||||||
|
|
|
@ -196,20 +196,17 @@ IsPhiObservable(MPhi *phi, Observability observe)
|
||||||
|
|
||||||
// If the Phi is of the |this| value, it must always be observable.
|
// If the Phi is of the |this| value, it must always be observable.
|
||||||
uint32_t slot = phi->slot();
|
uint32_t slot = phi->slot();
|
||||||
CompileInfo &info = phi->block()->info();
|
if (slot == 1)
|
||||||
if (info.fun() && slot == info.thisSlot())
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// If the Phi is one of the formal argument, and we are using an argument
|
// If the Phi is one of the formal argument, and we are using an argument
|
||||||
// object in the function. The phi might be observable after a bailout.
|
// object in the function. The phi might be observable after a bailout.
|
||||||
// For inlined frames this is not needed, as they are captured in the inlineResumePoint.
|
// For inlined frames this is not needed, as they are captured in the inlineResumePoint.
|
||||||
|
CompileInfo &info = phi->block()->info();
|
||||||
if (info.fun() && info.hasArguments()) {
|
if (info.fun() && info.hasArguments()) {
|
||||||
uint32_t first = info.firstActualArgSlot();
|
uint32_t first = info.firstArgSlot();
|
||||||
if (first <= slot && slot - first < info.nargs()) {
|
if (first <= slot && slot - first < info.nargs())
|
||||||
// If arguments obj aliases formals, then no arguments slots should ever be phis.
|
|
||||||
JS_ASSERT(!info.argsObjAliasesFormals());
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -335,13 +335,6 @@ IonBuilder::build()
|
||||||
current->initSlot(info().scopeChainSlot(), scope);
|
current->initSlot(info().scopeChainSlot(), scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the arguments object slot to undefined if necessary.
|
|
||||||
if (info().hasArguments()) {
|
|
||||||
MInstruction *argsObj = MConstant::New(UndefinedValue());
|
|
||||||
current->add(argsObj);
|
|
||||||
current->initSlot(info().argsObjSlot(), argsObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emit the start instruction, so we can begin real instructions.
|
// Emit the start instruction, so we can begin real instructions.
|
||||||
current->makeStart(MStart::New(MStart::StartType_Default));
|
current->makeStart(MStart::New(MStart::StartType_Default));
|
||||||
if (instrumentedProfiling())
|
if (instrumentedProfiling())
|
||||||
|
@ -355,9 +348,6 @@ IonBuilder::build()
|
||||||
if (!initScopeChain())
|
if (!initScopeChain())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (info().needsArgsObj() && !initArgumentsObject())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Guard against over-recursion.
|
// Guard against over-recursion.
|
||||||
MCheckOverRecursed *check = new MCheckOverRecursed;
|
MCheckOverRecursed *check = new MCheckOverRecursed;
|
||||||
current->add(check);
|
current->add(check);
|
||||||
|
@ -382,14 +372,13 @@ IonBuilder::build()
|
||||||
// So we attach the initial resume point to each parameter, which the type
|
// So we attach the initial resume point to each parameter, which the type
|
||||||
// analysis explicitly checks (this is the same mechanism used for
|
// analysis explicitly checks (this is the same mechanism used for
|
||||||
// effectful operations).
|
// effectful operations).
|
||||||
for (uint32_t i = 0; i < info().endArgSlot(); i++) {
|
for (uint32_t i = 0; i < CountArgSlots(info().fun()); i++) {
|
||||||
MInstruction *ins = current->getEntrySlot(i)->toInstruction();
|
MInstruction *ins = current->getEntrySlot(i)->toInstruction();
|
||||||
if (ins->type() == MIRType_Value)
|
if (ins->type() == MIRType_Value)
|
||||||
ins->setResumePoint(current->entryResumePoint());
|
ins->setResumePoint(current->entryResumePoint());
|
||||||
}
|
}
|
||||||
|
|
||||||
// lazyArguments should never be accessed in |argsObjAliasesFormals| scripts.
|
if (script()->argumentsHasVarBinding()) {
|
||||||
if (info().hasArguments() && !info().argsObjAliasesFormals()) {
|
|
||||||
lazyArguments_ = MConstant::New(MagicValue(JS_OPTIMIZED_ARGUMENTS));
|
lazyArguments_ = MConstant::New(MagicValue(JS_OPTIMIZED_ARGUMENTS));
|
||||||
current->add(lazyArguments_);
|
current->add(lazyArguments_);
|
||||||
}
|
}
|
||||||
|
@ -491,25 +480,15 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi
|
||||||
if (!inlinedArgumentTypes_.append(callInfo.argvType().begin(), callInfo.argvType().end()))
|
if (!inlinedArgumentTypes_.append(callInfo.argvType().begin(), callInfo.argvType().end()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// The Oracle ensures that the inlined script does not use the scope chain, or need
|
// The Oracle ensures that the inlined script does not use the scope chain.
|
||||||
// an arguments object.
|
|
||||||
JS_ASSERT(!script()->analysis()->usesScopeChain());
|
JS_ASSERT(!script()->analysis()->usesScopeChain());
|
||||||
MInstruction *scope = MConstant::New(UndefinedValue());
|
MInstruction *scope = MConstant::New(UndefinedValue());
|
||||||
current->add(scope);
|
current->add(scope);
|
||||||
current->initSlot(info().scopeChainSlot(), scope);
|
current->initSlot(info().scopeChainSlot(), scope);
|
||||||
if (info().hasArguments()) {
|
|
||||||
MInstruction *argsObj = MConstant::New(UndefinedValue());
|
|
||||||
current->add(argsObj);
|
|
||||||
current->initSlot(info().argsObjSlot(), argsObj);
|
|
||||||
}
|
|
||||||
current->initSlot(info().thisSlot(), callInfo.thisArg());
|
current->initSlot(info().thisSlot(), callInfo.thisArg());
|
||||||
|
|
||||||
IonSpew(IonSpew_Inlining, "Initializing %u arg slots", info().nargs());
|
IonSpew(IonSpew_Inlining, "Initializing %u arg slots", info().nargs());
|
||||||
|
|
||||||
// NB: Ion does not inline functions which |needsArgsObj|. So using argSlot()
|
|
||||||
// instead of argSlotUnchecked() below is OK
|
|
||||||
JS_ASSERT(!info().needsArgsObj());
|
|
||||||
|
|
||||||
// Initialize actually set arguments.
|
// Initialize actually set arguments.
|
||||||
uint32_t existing_args = Min<uint32_t>(callInfo.argc(), info().nargs());
|
uint32_t existing_args = Min<uint32_t>(callInfo.argc(), info().nargs());
|
||||||
for (size_t i = 0; i < existing_args; ++i) {
|
for (size_t i = 0; i < existing_args; ++i) {
|
||||||
|
@ -536,8 +515,8 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi
|
||||||
IonSpew(IonSpew_Inlining, "Inline entry block MResumePoint %p, %u operands",
|
IonSpew(IonSpew_Inlining, "Inline entry block MResumePoint %p, %u operands",
|
||||||
(void *) current->entryResumePoint(), current->entryResumePoint()->numOperands());
|
(void *) current->entryResumePoint(), current->entryResumePoint()->numOperands());
|
||||||
|
|
||||||
// +2 for the scope chain and |this|, maybe another +1 for arguments object slot.
|
// +2 for the scope chain and |this|.
|
||||||
JS_ASSERT(current->entryResumePoint()->numOperands() == info().totalSlots());
|
JS_ASSERT(current->entryResumePoint()->numOperands() == info().nargs() + info().nlocals() + 2);
|
||||||
|
|
||||||
if (script_->argumentsHasVarBinding()) {
|
if (script_->argumentsHasVarBinding()) {
|
||||||
lazyArguments_ = MConstant::New(MagicValue(JS_OPTIMIZED_ARGUMENTS));
|
lazyArguments_ = MConstant::New(MagicValue(JS_OPTIMIZED_ARGUMENTS));
|
||||||
|
@ -547,55 +526,6 @@ IonBuilder::buildInline(IonBuilder *callerBuilder, MResumePoint *callerResumePoi
|
||||||
return traverseBytecode();
|
return traverseBytecode();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
IonBuilder::rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex)
|
|
||||||
{
|
|
||||||
JS_ASSERT(param->isParameter() || param->isGetArgumentsObjectArg());
|
|
||||||
|
|
||||||
// Find the original (not cloned) type set for the MParameter, as we
|
|
||||||
// will be adding constraints to it.
|
|
||||||
types::StackTypeSet *types;
|
|
||||||
if (argIndex == MParameter::THIS_SLOT)
|
|
||||||
types = oracle->thisTypeSet(script());
|
|
||||||
else
|
|
||||||
types = oracle->parameterTypeSet(script(), argIndex);
|
|
||||||
if (!types)
|
|
||||||
return;
|
|
||||||
|
|
||||||
JSValueType definiteType = types->getKnownTypeTag();
|
|
||||||
if (definiteType == JSVAL_TYPE_UNKNOWN)
|
|
||||||
return;
|
|
||||||
|
|
||||||
MInstruction *actual = NULL;
|
|
||||||
switch (definiteType) {
|
|
||||||
case JSVAL_TYPE_UNDEFINED:
|
|
||||||
param->setFoldedUnchecked();
|
|
||||||
actual = MConstant::New(UndefinedValue());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JSVAL_TYPE_NULL:
|
|
||||||
param->setFoldedUnchecked();
|
|
||||||
actual = MConstant::New(NullValue());
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
actual = MUnbox::New(param, MIRTypeFromValueType(definiteType), MUnbox::Infallible);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Careful! We leave the original MParameter in the entry resume point. The
|
|
||||||
// arguments still need to be checked unless proven otherwise at the call
|
|
||||||
// site, and these checks can bailout. We can end up:
|
|
||||||
// v0 = Parameter(0)
|
|
||||||
// v1 = Unbox(v0, INT32)
|
|
||||||
// -- ResumePoint(v0)
|
|
||||||
//
|
|
||||||
// As usual, it would be invalid for v1 to be captured in the initial
|
|
||||||
// resume point, rather than v0.
|
|
||||||
current->add(actual);
|
|
||||||
current->rewriteSlot(slotIdx, actual);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply Type Inference information to parameters early on, unboxing them if
|
// Apply Type Inference information to parameters early on, unboxing them if
|
||||||
// they have a definitive type. The actual guards will be emitted by the code
|
// they have a definitive type. The actual guards will be emitted by the code
|
||||||
// generator, explicitly, as part of the function prologue.
|
// generator, explicitly, as part of the function prologue.
|
||||||
|
@ -603,13 +533,53 @@ void
|
||||||
IonBuilder::rewriteParameters()
|
IonBuilder::rewriteParameters()
|
||||||
{
|
{
|
||||||
JS_ASSERT(info().scopeChainSlot() == 0);
|
JS_ASSERT(info().scopeChainSlot() == 0);
|
||||||
|
static const uint32_t START_SLOT = 1;
|
||||||
|
|
||||||
if (!info().fun())
|
for (uint32_t i = START_SLOT; i < CountArgSlots(info().fun()); i++) {
|
||||||
return;
|
MParameter *param = current->getSlot(i)->toParameter();
|
||||||
|
|
||||||
for (uint32_t i = info().startArgSlot(); i < info().endArgSlot(); i++) {
|
// Find the original (not cloned) type set for the MParameter, as we
|
||||||
MDefinition *param = current->getSlot(i);
|
// will be adding constraints to it.
|
||||||
rewriteParameter(i, param, param->toParameter()->index());
|
types::StackTypeSet *types;
|
||||||
|
if (param->index() == MParameter::THIS_SLOT)
|
||||||
|
types = oracle->thisTypeSet(script());
|
||||||
|
else
|
||||||
|
types = oracle->parameterTypeSet(script(), param->index());
|
||||||
|
if (!types)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
JSValueType definiteType = types->getKnownTypeTag();
|
||||||
|
if (definiteType == JSVAL_TYPE_UNKNOWN)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
MInstruction *actual = NULL;
|
||||||
|
switch (definiteType) {
|
||||||
|
case JSVAL_TYPE_UNDEFINED:
|
||||||
|
param->setFoldedUnchecked();
|
||||||
|
actual = MConstant::New(UndefinedValue());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JSVAL_TYPE_NULL:
|
||||||
|
param->setFoldedUnchecked();
|
||||||
|
actual = MConstant::New(NullValue());
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
actual = MUnbox::New(param, MIRTypeFromValueType(definiteType), MUnbox::Infallible);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Careful! We leave the original MParameter in the entry resume point. The
|
||||||
|
// arguments still need to be checked unless proven otherwise at the call
|
||||||
|
// site, and these checks can bailout. We can end up:
|
||||||
|
// v0 = Parameter(0)
|
||||||
|
// v1 = Unbox(v0, INT32)
|
||||||
|
// -- ResumePoint(v0)
|
||||||
|
//
|
||||||
|
// As usual, it would be invalid for v1 to be captured in the initial
|
||||||
|
// resume point, rather than v0.
|
||||||
|
current->add(actual);
|
||||||
|
current->rewriteSlot(i, actual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,7 +597,7 @@ IonBuilder::initParameters()
|
||||||
for (uint32_t i = 0; i < info().nargs(); i++) {
|
for (uint32_t i = 0; i < info().nargs(); i++) {
|
||||||
param = MParameter::New(i, cloneTypeSet(oracle->parameterTypeSet(script(), i)));
|
param = MParameter::New(i, cloneTypeSet(oracle->parameterTypeSet(script(), i)));
|
||||||
current->add(param);
|
current->add(param);
|
||||||
current->initSlot(info().argSlotUnchecked(i), param);
|
current->initSlot(info().argSlot(i), param);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -639,10 +609,8 @@ IonBuilder::initScopeChain()
|
||||||
MInstruction *scope = NULL;
|
MInstruction *scope = NULL;
|
||||||
|
|
||||||
// If the script doesn't use the scopechain, then it's already initialized
|
// If the script doesn't use the scopechain, then it's already initialized
|
||||||
// from earlier. However, always make a scope chain when |needsArgsObj| is true
|
// from earlier.
|
||||||
// for the script, since arguments object construction requires the scope chain
|
if (!script()->analysis()->usesScopeChain())
|
||||||
// to be passed in.
|
|
||||||
if (!info().needsArgsObj() && !script()->analysis()->usesScopeChain())
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// The scope chain is only tracked in scripts that have NAME opcodes which
|
// The scope chain is only tracked in scripts that have NAME opcodes which
|
||||||
|
@ -680,18 +648,6 @@ IonBuilder::initScopeChain()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
IonBuilder::initArgumentsObject()
|
|
||||||
{
|
|
||||||
IonSpew(IonSpew_MIR, "%s:%d - Emitting code to initialize arguments object! block=%p",
|
|
||||||
script()->filename(), script()->lineno, current);
|
|
||||||
JS_ASSERT(info().needsArgsObj());
|
|
||||||
MCreateArgumentsObject *argsObj = MCreateArgumentsObject::New(current->scopeChain());
|
|
||||||
current->add(argsObj);
|
|
||||||
current->setArgumentsObject(argsObj);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We try to build a control-flow graph in the order that it would be built as
|
// We try to build a control-flow graph in the order that it would be built as
|
||||||
// if traversing the AST. This leads to a nice ordering and lets us build SSA
|
// if traversing the AST. This leads to a nice ordering and lets us build SSA
|
||||||
// in one pass, since the bytecode is structured.
|
// in one pass, since the bytecode is structured.
|
||||||
|
@ -945,14 +901,7 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||||
|
|
||||||
case JSOP_GETARG:
|
case JSOP_GETARG:
|
||||||
case JSOP_CALLARG:
|
case JSOP_CALLARG:
|
||||||
if (info().argsObjAliasesFormals()) {
|
current->pushArg(GET_SLOTNO(pc));
|
||||||
MGetArgumentsObjectArg *getArg = MGetArgumentsObjectArg::New(current->argumentsObject(),
|
|
||||||
GET_SLOTNO(pc));
|
|
||||||
current->add(getArg);
|
|
||||||
current->push(getArg);
|
|
||||||
} else {
|
|
||||||
current->pushArg(GET_SLOTNO(pc));
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case JSOP_SETARG:
|
case JSOP_SETARG:
|
||||||
|
@ -961,16 +910,9 @@ IonBuilder::inspectOpcode(JSOp op)
|
||||||
// to wrap the spilling action, we don't want the spilling to be
|
// to wrap the spilling action, we don't want the spilling to be
|
||||||
// captured by the GETARG and by the resume point, only by
|
// captured by the GETARG and by the resume point, only by
|
||||||
// MGetArgument.
|
// MGetArgument.
|
||||||
if (info().argsObjAliasesFormals()) {
|
if (info().hasArguments())
|
||||||
current->add(MSetArgumentsObjectArg::New(current->argumentsObject(), GET_SLOTNO(pc),
|
return abort("NYI: arguments & setarg.");
|
||||||
current->peek(-1)));
|
current->setArg(GET_SLOTNO(pc));
|
||||||
} else {
|
|
||||||
// TODO: if hasArguments() is true, and the script has a JSOP_SETARG, then
|
|
||||||
// convert all arg accesses to go through the arguments object.
|
|
||||||
if (info().hasArguments())
|
|
||||||
return abort("NYI: arguments & setarg.");
|
|
||||||
current->setArg(GET_SLOTNO(pc));
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case JSOP_GETLOCAL:
|
case JSOP_GETLOCAL:
|
||||||
|
@ -4013,7 +3955,7 @@ IonBuilder::createCallObject(MDefinition *callee, MDefinition *scope)
|
||||||
for (AliasedFormalIter i(script()); i; i++) {
|
for (AliasedFormalIter i(script()); i; i++) {
|
||||||
unsigned slot = i.scopeSlot();
|
unsigned slot = i.scopeSlot();
|
||||||
unsigned formal = i.frameIndex();
|
unsigned formal = i.frameIndex();
|
||||||
MDefinition *param = current->getSlot(info().argSlotUnchecked(formal));
|
MDefinition *param = current->getSlot(info().argSlot(formal));
|
||||||
if (slot >= templateObj->numFixedSlots())
|
if (slot >= templateObj->numFixedSlots())
|
||||||
current->add(MStoreSlot::New(slots, slot - templateObj->numFixedSlots(), param));
|
current->add(MStoreSlot::New(slots, slot - templateObj->numFixedSlots(), param));
|
||||||
else
|
else
|
||||||
|
@ -5045,15 +4987,6 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry)
|
||||||
osrBlock->initSlot(slot, scopev);
|
osrBlock->initSlot(slot, scopev);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize arguments object. Ion will not allow OSR-ing into scripts
|
|
||||||
// with |needsArgsObj| set, so this can be undefined.
|
|
||||||
JS_ASSERT(!info().needsArgsObj());
|
|
||||||
if (info().hasArguments()) {
|
|
||||||
MInstruction *argsObj = MConstant::New(UndefinedValue());
|
|
||||||
osrBlock->add(argsObj);
|
|
||||||
osrBlock->initSlot(info().argsObjSlot(), argsObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info().fun()) {
|
if (info().fun()) {
|
||||||
// Initialize |this| parameter.
|
// Initialize |this| parameter.
|
||||||
uint32_t slot = info().thisSlot();
|
uint32_t slot = info().thisSlot();
|
||||||
|
@ -5065,8 +4998,6 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry)
|
||||||
|
|
||||||
// Initialize arguments.
|
// Initialize arguments.
|
||||||
for (uint32_t i = 0; i < info().nargs(); i++) {
|
for (uint32_t i = 0; i < info().nargs(); i++) {
|
||||||
// NB: Ion does not OSR into any function which |needsArgsObj|, so
|
|
||||||
// using argSlot() here instead of argSlotUnchecked() is ok.
|
|
||||||
uint32_t slot = info().argSlot(i);
|
uint32_t slot = info().argSlot(i);
|
||||||
ptrdiff_t offset = StackFrame::offsetOfFormalArg(info().fun(), i);
|
ptrdiff_t offset = StackFrame::offsetOfFormalArg(info().fun(), i);
|
||||||
|
|
||||||
|
@ -5087,8 +5018,8 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize stack.
|
// Initialize stack.
|
||||||
uint32_t numStackSlots = preheader->stackDepth() - info().firstStackSlot();
|
uint32_t numSlots = preheader->stackDepth() - CountArgSlots(info().fun()) - info().nlocals();
|
||||||
for (uint32_t i = 0; i < numStackSlots; i++) {
|
for (uint32_t i = 0; i < numSlots; i++) {
|
||||||
uint32_t slot = info().stackSlot(i);
|
uint32_t slot = info().stackSlot(i);
|
||||||
ptrdiff_t offset = StackFrame::offsetOfFixed(info().nlocals() + i);
|
ptrdiff_t offset = StackFrame::offsetOfFixed(info().nlocals() + i);
|
||||||
|
|
||||||
|
@ -5119,26 +5050,19 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry)
|
||||||
JS_ASSERT(info().scopeChainSlot() == 0);
|
JS_ASSERT(info().scopeChainSlot() == 0);
|
||||||
JS_ASSERT(osrBlock->scopeChain()->type() == MIRType_Object);
|
JS_ASSERT(osrBlock->scopeChain()->type() == MIRType_Object);
|
||||||
|
|
||||||
// When compiling functions which |hasArguments|, an extra slot is used to hold the
|
|
||||||
// potential arguments object. In OSR-compiled functions this object is always undefined,
|
|
||||||
// but the slot still exists.
|
|
||||||
bool argsSlotAdj = info().hasArguments() ? 1 : 0;
|
|
||||||
Vector<MIRType> slotTypes(cx);
|
Vector<MIRType> slotTypes(cx);
|
||||||
if (!slotTypes.growByUninitialized(osrBlock->stackDepth() - argsSlotAdj))
|
if (!slotTypes.growByUninitialized(osrBlock->stackDepth()))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// Fill slotTypes with the types of the predecessor block.
|
// Fill slotTypes with the types of the predecessor block.
|
||||||
for (uint32_t i = 0; i < osrBlock->stackDepth() - argsSlotAdj; i++)
|
for (uint32_t i = 0; i < osrBlock->stackDepth(); i++)
|
||||||
slotTypes[i] = MIRType_Value;
|
slotTypes[i] = MIRType_Value;
|
||||||
|
|
||||||
// Update slotTypes for slots that may have a different type at this join point.
|
// Update slotTypes for slots that may have a different type at this join point.
|
||||||
if (!oracle->getOsrTypes(loopEntry, slotTypes))
|
if (!oracle->getOsrTypes(loopEntry, slotTypes))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// Skip 0 - no type checks on scopeChain slot.
|
for (uint32_t i = 1; i < osrBlock->stackDepth(); i++) {
|
||||||
for (uint32_t i = 1; i < slotTypes.length(); i++) {
|
|
||||||
uint32_t slotNo = i + argsSlotAdj;
|
|
||||||
|
|
||||||
// Unbox the MOsrValue if it is known to be unboxable.
|
// Unbox the MOsrValue if it is known to be unboxable.
|
||||||
switch (slotTypes[i]) {
|
switch (slotTypes[i]) {
|
||||||
case MIRType_Boolean:
|
case MIRType_Boolean:
|
||||||
|
@ -5147,12 +5071,12 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry)
|
||||||
case MIRType_String:
|
case MIRType_String:
|
||||||
case MIRType_Object:
|
case MIRType_Object:
|
||||||
{
|
{
|
||||||
MDefinition *def = osrBlock->getSlot(slotNo);
|
MDefinition *def = osrBlock->getSlot(i);
|
||||||
JS_ASSERT(def->type() == MIRType_Value);
|
JS_ASSERT(def->type() == MIRType_Value);
|
||||||
|
|
||||||
MInstruction *actual = MUnbox::New(def, slotTypes[i], MUnbox::Infallible);
|
MInstruction *actual = MUnbox::New(def, slotTypes[i], MUnbox::Infallible);
|
||||||
osrBlock->add(actual);
|
osrBlock->add(actual);
|
||||||
osrBlock->rewriteSlot(slotNo, actual);
|
osrBlock->rewriteSlot(i, actual);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5160,7 +5084,7 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry)
|
||||||
{
|
{
|
||||||
MConstant *c = MConstant::New(NullValue());
|
MConstant *c = MConstant::New(NullValue());
|
||||||
osrBlock->add(c);
|
osrBlock->add(c);
|
||||||
osrBlock->rewriteSlot(slotNo, c);
|
osrBlock->rewriteSlot(i, c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5168,13 +5092,13 @@ IonBuilder::newOsrPreheader(MBasicBlock *predecessor, jsbytecode *loopEntry)
|
||||||
{
|
{
|
||||||
MConstant *c = MConstant::New(UndefinedValue());
|
MConstant *c = MConstant::New(UndefinedValue());
|
||||||
osrBlock->add(c);
|
osrBlock->add(c);
|
||||||
osrBlock->rewriteSlot(slotNo, c);
|
osrBlock->rewriteSlot(i, c);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case MIRType_Magic:
|
case MIRType_Magic:
|
||||||
JS_ASSERT(lazyArguments_);
|
JS_ASSERT(lazyArguments_);
|
||||||
osrBlock->rewriteSlot(slotNo, lazyArguments_);
|
osrBlock->rewriteSlot(i, lazyArguments_);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -6286,10 +6210,6 @@ IonBuilder::jsop_length_fastPath()
|
||||||
bool
|
bool
|
||||||
IonBuilder::jsop_arguments()
|
IonBuilder::jsop_arguments()
|
||||||
{
|
{
|
||||||
if (info().needsArgsObj()) {
|
|
||||||
current->push(current->argumentsObject());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
JS_ASSERT(lazyArguments_);
|
JS_ASSERT(lazyArguments_);
|
||||||
current->push(lazyArguments_);
|
current->push(lazyArguments_);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -273,10 +273,8 @@ class IonBuilder : public MIRGenerator
|
||||||
bool maybeInsertResume();
|
bool maybeInsertResume();
|
||||||
|
|
||||||
bool initParameters();
|
bool initParameters();
|
||||||
void rewriteParameter(uint32_t slotIdx, MDefinition *param, int32_t argIndex);
|
|
||||||
void rewriteParameters();
|
void rewriteParameters();
|
||||||
bool initScopeChain();
|
bool initScopeChain();
|
||||||
bool initArgumentsObject();
|
|
||||||
bool pushConstant(const Value &v);
|
bool pushConstant(const Value &v);
|
||||||
|
|
||||||
// Add a guard which ensure that the set of type which goes through this
|
// Add a guard which ensure that the set of type which goes through this
|
||||||
|
|
|
@ -18,8 +18,7 @@ namespace ion {
|
||||||
template <class Op>
|
template <class Op>
|
||||||
inline void
|
inline void
|
||||||
SnapshotIterator::readFrameArgs(Op &op, const Value *argv, Value *scopeChain, Value *thisv,
|
SnapshotIterator::readFrameArgs(Op &op, const Value *argv, Value *scopeChain, Value *thisv,
|
||||||
unsigned start, unsigned formalEnd, unsigned iterEnd,
|
unsigned start, unsigned formalEnd, unsigned iterEnd)
|
||||||
RawScript script)
|
|
||||||
{
|
{
|
||||||
if (scopeChain)
|
if (scopeChain)
|
||||||
*scopeChain = read();
|
*scopeChain = read();
|
||||||
|
@ -31,10 +30,6 @@ SnapshotIterator::readFrameArgs(Op &op, const Value *argv, Value *scopeChain, Va
|
||||||
else
|
else
|
||||||
skip();
|
skip();
|
||||||
|
|
||||||
// Skip slot for arguments object.
|
|
||||||
if (script->argumentsHasVarBinding())
|
|
||||||
skip();
|
|
||||||
|
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
if (formalEnd < start)
|
if (formalEnd < start)
|
||||||
i = start;
|
i = start;
|
||||||
|
@ -108,28 +103,26 @@ InlineFrameIteratorMaybeGC<allowGC>::forEachCanonicalActualArg(
|
||||||
// Get the non overflown arguments
|
// Get the non overflown arguments
|
||||||
unsigned formal_end = (end < nformal) ? end : nformal;
|
unsigned formal_end = (end < nformal) ? end : nformal;
|
||||||
SnapshotIterator s(si_);
|
SnapshotIterator s(si_);
|
||||||
s.readFrameArgs(op, NULL, NULL, NULL, start, nformal, formal_end, script());
|
s.readFrameArgs(op, NULL, NULL, NULL, start, nformal, formal_end);
|
||||||
|
|
||||||
// The overflown arguments are not available in current frame.
|
// The overflown arguments are not available in current frame.
|
||||||
// They are the last pushed arguments in the parent frame of this inlined frame.
|
// They are the last pushed arguments in the parent frame of this inlined frame.
|
||||||
InlineFrameIteratorMaybeGC it(cx, this);
|
InlineFrameIteratorMaybeGC it(cx, this);
|
||||||
++it;
|
SnapshotIterator parent_s((++it).snapshotIterator());
|
||||||
unsigned argsObjAdj = it.script()->argumentsHasVarBinding() ? 1 : 0;
|
|
||||||
SnapshotIterator parent_s(it.snapshotIterator());
|
|
||||||
|
|
||||||
// Skip over all slots untill we get to the last slots (= arguments slots of callee)
|
// Skip over all slots untill we get to the last slots (= arguments slots of callee)
|
||||||
// the +2 is for [this] and [scopechain], and maybe +1 for [argsObj]
|
// the +2 is for [this] and [scopechain]
|
||||||
JS_ASSERT(parent_s.slots() >= nactual + 2 + argsObjAdj);
|
JS_ASSERT(parent_s.slots() >= nactual + 2);
|
||||||
unsigned skip = parent_s.slots() - nactual - 2 - argsObjAdj;
|
unsigned skip = parent_s.slots() - nactual - 2;
|
||||||
for (unsigned j = 0; j < skip; j++)
|
for (unsigned j = 0; j < skip; j++)
|
||||||
parent_s.skip();
|
parent_s.skip();
|
||||||
|
|
||||||
// Get the overflown arguments
|
// Get the overflown arguments
|
||||||
parent_s.readFrameArgs(op, NULL, NULL, NULL, nformal, nactual, end, it.script());
|
parent_s.readFrameArgs(op, NULL, NULL, NULL, nformal, nactual, end);
|
||||||
} else {
|
} else {
|
||||||
SnapshotIterator s(si_);
|
SnapshotIterator s(si_);
|
||||||
Value *argv = frame_->actualArgs();
|
Value *argv = frame_->actualArgs();
|
||||||
s.readFrameArgs(op, argv, NULL, NULL, start, nformal, end, script());
|
s.readFrameArgs(op, argv, NULL, NULL, start, nformal, end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -269,8 +269,7 @@ class SnapshotIterator : public SnapshotReader
|
||||||
|
|
||||||
template <class Op>
|
template <class Op>
|
||||||
inline void readFrameArgs(Op &op, const Value *argv, Value *scopeChain, Value *thisv,
|
inline void readFrameArgs(Op &op, const Value *argv, Value *scopeChain, Value *thisv,
|
||||||
unsigned start, unsigned formalEnd, unsigned iterEnd,
|
unsigned start, unsigned formalEnd, unsigned iterEnd);
|
||||||
RawScript script);
|
|
||||||
|
|
||||||
Value maybeReadSlotByIndex(size_t index) {
|
Value maybeReadSlotByIndex(size_t index) {
|
||||||
while (index--) {
|
while (index--) {
|
||||||
|
|
|
@ -287,7 +287,7 @@ CloseLiveIterator(JSContext *cx, const InlineFrameIterator &frame, uint32_t loca
|
||||||
SnapshotIterator si = frame.snapshotIterator();
|
SnapshotIterator si = frame.snapshotIterator();
|
||||||
|
|
||||||
// Skip stack slots until we reach the iterator object.
|
// Skip stack slots until we reach the iterator object.
|
||||||
uint32_t base = CountArgSlots(frame.script(), frame.maybeCallee()) + frame.script()->nfixed;
|
uint32_t base = CountArgSlots(frame.maybeCallee()) + frame.script()->nfixed;
|
||||||
uint32_t skipSlots = base + localSlot - 1;
|
uint32_t skipSlots = base + localSlot - 1;
|
||||||
|
|
||||||
for (unsigned i = 0; i < skipSlots; i++)
|
for (unsigned i = 0; i < skipSlots; i++)
|
||||||
|
|
|
@ -710,71 +710,6 @@ class LCreateThisWithTemplate : public LInstructionHelper<1, 0, 0>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Allocate a new arguments object for the frame.
|
|
||||||
class LCreateArgumentsObject : public LCallInstructionHelper<1, 1, 1>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LIR_HEADER(CreateArgumentsObject)
|
|
||||||
|
|
||||||
LCreateArgumentsObject(const LAllocation &callObj, const LDefinition &temp)
|
|
||||||
{
|
|
||||||
setOperand(0, callObj);
|
|
||||||
setTemp(0, temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
const LAllocation *getCallObject() {
|
|
||||||
return getOperand(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
MCreateArgumentsObject *mir() const {
|
|
||||||
return mir_->toCreateArgumentsObject();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get argument from arguments object.
|
|
||||||
class LGetArgumentsObjectArg : public LInstructionHelper<BOX_PIECES, 1, 1>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LIR_HEADER(GetArgumentsObjectArg)
|
|
||||||
|
|
||||||
LGetArgumentsObjectArg(const LAllocation &argsObj, const LDefinition &temp)
|
|
||||||
{
|
|
||||||
setOperand(0, argsObj);
|
|
||||||
setTemp(0, temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
const LAllocation *getArgsObject() {
|
|
||||||
return getOperand(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
MGetArgumentsObjectArg *mir() const {
|
|
||||||
return mir_->toGetArgumentsObjectArg();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Set argument on arguments object.
|
|
||||||
class LSetArgumentsObjectArg : public LInstructionHelper<0, 1 + BOX_PIECES, 1>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LIR_HEADER(SetArgumentsObjectArg)
|
|
||||||
|
|
||||||
LSetArgumentsObjectArg(const LAllocation &argsObj, const LDefinition &temp)
|
|
||||||
{
|
|
||||||
setOperand(0, argsObj);
|
|
||||||
setTemp(0, temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
const LAllocation *getArgsObject() {
|
|
||||||
return getOperand(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
MSetArgumentsObjectArg *mir() const {
|
|
||||||
return mir_->toSetArgumentsObjectArg();
|
|
||||||
}
|
|
||||||
|
|
||||||
static const size_t ValueIndex = 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
// If the Value is an Object, return unbox(Value).
|
// If the Value is an Object, return unbox(Value).
|
||||||
// Otherwise, return the other Object.
|
// Otherwise, return the other Object.
|
||||||
class LReturnFromCtor : public LInstructionHelper<1, BOX_PIECES + 1, 0>
|
class LReturnFromCtor : public LInstructionHelper<1, BOX_PIECES + 1, 0>
|
||||||
|
|
|
@ -50,9 +50,6 @@
|
||||||
_(CreateThis) \
|
_(CreateThis) \
|
||||||
_(CreateThisWithProto) \
|
_(CreateThisWithProto) \
|
||||||
_(CreateThisWithTemplate) \
|
_(CreateThisWithTemplate) \
|
||||||
_(CreateArgumentsObject) \
|
|
||||||
_(GetArgumentsObjectArg) \
|
|
||||||
_(SetArgumentsObjectArg) \
|
|
||||||
_(ReturnFromCtor) \
|
_(ReturnFromCtor) \
|
||||||
_(BitNotI) \
|
_(BitNotI) \
|
||||||
_(BitNotV) \
|
_(BitNotV) \
|
||||||
|
|
|
@ -320,34 +320,6 @@ LIRGenerator::visitCreateThis(MCreateThis *ins)
|
||||||
return defineReturn(lir, ins) && assignSafepoint(lir, ins);
|
return defineReturn(lir, ins) && assignSafepoint(lir, ins);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
|
||||||
LIRGenerator::visitCreateArgumentsObject(MCreateArgumentsObject *ins)
|
|
||||||
{
|
|
||||||
// LAllocation callObj = useRegisterAtStart(ins->getCallObject());
|
|
||||||
LAllocation callObj = useFixed(ins->getCallObject(), CallTempReg0);
|
|
||||||
LCreateArgumentsObject *lir = new LCreateArgumentsObject(callObj, tempFixed(CallTempReg1));
|
|
||||||
return defineReturn(lir, ins) && assignSafepoint(lir, ins);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
LIRGenerator::visitGetArgumentsObjectArg(MGetArgumentsObjectArg *ins)
|
|
||||||
{
|
|
||||||
LAllocation argsObj = useRegister(ins->getArgsObject());
|
|
||||||
LGetArgumentsObjectArg *lir = new LGetArgumentsObjectArg(argsObj, temp());
|
|
||||||
return defineBox(lir, ins);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
LIRGenerator::visitSetArgumentsObjectArg(MSetArgumentsObjectArg *ins)
|
|
||||||
{
|
|
||||||
LAllocation argsObj = useRegister(ins->getArgsObject());
|
|
||||||
LSetArgumentsObjectArg *lir = new LSetArgumentsObjectArg(argsObj, temp());
|
|
||||||
if (!useBox(lir, LSetArgumentsObjectArg::ValueIndex, ins->getValue()))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return add(lir, ins);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
LIRGenerator::visitReturnFromCtor(MReturnFromCtor *ins)
|
LIRGenerator::visitReturnFromCtor(MReturnFromCtor *ins)
|
||||||
{
|
{
|
||||||
|
|
|
@ -105,9 +105,6 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||||
bool visitCreateThisWithTemplate(MCreateThisWithTemplate *ins);
|
bool visitCreateThisWithTemplate(MCreateThisWithTemplate *ins);
|
||||||
bool visitCreateThisWithProto(MCreateThisWithProto *ins);
|
bool visitCreateThisWithProto(MCreateThisWithProto *ins);
|
||||||
bool visitCreateThis(MCreateThis *ins);
|
bool visitCreateThis(MCreateThis *ins);
|
||||||
bool visitCreateArgumentsObject(MCreateArgumentsObject *ins);
|
|
||||||
bool visitGetArgumentsObjectArg(MGetArgumentsObjectArg *ins);
|
|
||||||
bool visitSetArgumentsObjectArg(MSetArgumentsObjectArg *ins);
|
|
||||||
bool visitReturnFromCtor(MReturnFromCtor *ins);
|
bool visitReturnFromCtor(MReturnFromCtor *ins);
|
||||||
bool visitCall(MCall *call);
|
bool visitCall(MCall *call);
|
||||||
bool visitApplyArgs(MApplyArgs *apply);
|
bool visitApplyArgs(MApplyArgs *apply);
|
||||||
|
|
108
js/src/ion/MIR.h
108
js/src/ion/MIR.h
|
@ -2118,114 +2118,6 @@ class MCreateThis
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Eager initialization of arguments object.
|
|
||||||
class MCreateArgumentsObject
|
|
||||||
: public MUnaryInstruction,
|
|
||||||
public ObjectPolicy<0>
|
|
||||||
{
|
|
||||||
MCreateArgumentsObject(MDefinition *callObj)
|
|
||||||
: MUnaryInstruction(callObj)
|
|
||||||
{
|
|
||||||
setResultType(MIRType_Object);
|
|
||||||
setGuard();
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
INSTRUCTION_HEADER(CreateArgumentsObject)
|
|
||||||
static MCreateArgumentsObject *New(MDefinition *callObj) {
|
|
||||||
return new MCreateArgumentsObject(callObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
MDefinition *getCallObject() const {
|
|
||||||
return getOperand(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
AliasSet getAliasSet() const {
|
|
||||||
return AliasSet::None();
|
|
||||||
}
|
|
||||||
|
|
||||||
TypePolicy *typePolicy() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class MGetArgumentsObjectArg
|
|
||||||
: public MUnaryInstruction,
|
|
||||||
public ObjectPolicy<0>
|
|
||||||
{
|
|
||||||
size_t argno_;
|
|
||||||
|
|
||||||
MGetArgumentsObjectArg(MDefinition *argsObject, size_t argno)
|
|
||||||
: MUnaryInstruction(argsObject),
|
|
||||||
argno_(argno)
|
|
||||||
{
|
|
||||||
setResultType(MIRType_Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
INSTRUCTION_HEADER(GetArgumentsObjectArg)
|
|
||||||
static MGetArgumentsObjectArg *New(MDefinition *argsObj, size_t argno)
|
|
||||||
{
|
|
||||||
return new MGetArgumentsObjectArg(argsObj, argno);
|
|
||||||
}
|
|
||||||
|
|
||||||
MDefinition *getArgsObject() const {
|
|
||||||
return getOperand(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t argno() const {
|
|
||||||
return argno_;
|
|
||||||
}
|
|
||||||
|
|
||||||
AliasSet getAliasSet() const {
|
|
||||||
return AliasSet::Load(AliasSet::Any);
|
|
||||||
}
|
|
||||||
|
|
||||||
TypePolicy *typePolicy() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class MSetArgumentsObjectArg
|
|
||||||
: public MBinaryInstruction,
|
|
||||||
public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
|
|
||||||
{
|
|
||||||
size_t argno_;
|
|
||||||
|
|
||||||
MSetArgumentsObjectArg(MDefinition *argsObj, size_t argno, MDefinition *value)
|
|
||||||
: MBinaryInstruction(argsObj, value),
|
|
||||||
argno_(argno)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
INSTRUCTION_HEADER(SetArgumentsObjectArg)
|
|
||||||
static MSetArgumentsObjectArg *New(MDefinition *argsObj, size_t argno, MDefinition *value)
|
|
||||||
{
|
|
||||||
return new MSetArgumentsObjectArg(argsObj, argno, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
MDefinition *getArgsObject() const {
|
|
||||||
return getOperand(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t argno() const {
|
|
||||||
return argno_;
|
|
||||||
}
|
|
||||||
|
|
||||||
MDefinition *getValue() const {
|
|
||||||
return getOperand(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
AliasSet getAliasSet() const {
|
|
||||||
return AliasSet::Store(AliasSet::Any);
|
|
||||||
}
|
|
||||||
|
|
||||||
TypePolicy *typePolicy() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Given a MIRType_Value A and a MIRType_Object B:
|
// Given a MIRType_Value A and a MIRType_Object B:
|
||||||
// If the Value may be safely unboxed to an Object, return Object(A).
|
// If the Value may be safely unboxed to an Object, return Object(A).
|
||||||
// Otherwise, return B.
|
// Otherwise, return B.
|
||||||
|
|
|
@ -352,8 +352,6 @@ MBasicBlock::linkOsrValues(MStart *start)
|
||||||
MDefinition *def = slots_[i];
|
MDefinition *def = slots_[i];
|
||||||
if (i == info().scopeChainSlot())
|
if (i == info().scopeChainSlot())
|
||||||
def->toOsrScopeChain()->setResumePoint(res);
|
def->toOsrScopeChain()->setResumePoint(res);
|
||||||
else if (info().hasArguments() && i == info().argsObjSlot())
|
|
||||||
JS_ASSERT(def->isConstant() && def->toConstant()->value() == UndefinedValue());
|
|
||||||
else
|
else
|
||||||
def->toOsrValue()->setResumePoint(res);
|
def->toOsrValue()->setResumePoint(res);
|
||||||
}
|
}
|
||||||
|
@ -456,24 +454,12 @@ MBasicBlock::scopeChain()
|
||||||
return getSlot(info().scopeChainSlot());
|
return getSlot(info().scopeChainSlot());
|
||||||
}
|
}
|
||||||
|
|
||||||
MDefinition *
|
|
||||||
MBasicBlock::argumentsObject()
|
|
||||||
{
|
|
||||||
return getSlot(info().argsObjSlot());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MBasicBlock::setScopeChain(MDefinition *scopeObj)
|
MBasicBlock::setScopeChain(MDefinition *scopeObj)
|
||||||
{
|
{
|
||||||
setSlot(info().scopeChainSlot(), scopeObj);
|
setSlot(info().scopeChainSlot(), scopeObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
MBasicBlock::setArgumentsObject(MDefinition *argsObj)
|
|
||||||
{
|
|
||||||
setSlot(info().argsObjSlot(), argsObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MBasicBlock::pick(int32_t depth)
|
MBasicBlock::pick(int32_t depth)
|
||||||
{
|
{
|
||||||
|
|
|
@ -102,7 +102,6 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
|
||||||
MDefinition *peek(int32_t depth);
|
MDefinition *peek(int32_t depth);
|
||||||
|
|
||||||
MDefinition *scopeChain();
|
MDefinition *scopeChain();
|
||||||
MDefinition *argumentsObject();
|
|
||||||
|
|
||||||
// Increase the number of slots available
|
// Increase the number of slots available
|
||||||
bool increaseSlots(size_t num);
|
bool increaseSlots(size_t num);
|
||||||
|
@ -138,7 +137,6 @@ class MBasicBlock : public TempObject, public InlineListNode<MBasicBlock>
|
||||||
void pushLocal(uint32_t local);
|
void pushLocal(uint32_t local);
|
||||||
void pushSlot(uint32_t slot);
|
void pushSlot(uint32_t slot);
|
||||||
void setScopeChain(MDefinition *ins);
|
void setScopeChain(MDefinition *ins);
|
||||||
void setArgumentsObject(MDefinition *ins);
|
|
||||||
|
|
||||||
// Returns the top of the stack, then decrements the virtual stack pointer.
|
// Returns the top of the stack, then decrements the virtual stack pointer.
|
||||||
MDefinition *pop();
|
MDefinition *pop();
|
||||||
|
|
|
@ -33,9 +33,6 @@ namespace ion {
|
||||||
_(CreateThis) \
|
_(CreateThis) \
|
||||||
_(CreateThisWithProto) \
|
_(CreateThisWithProto) \
|
||||||
_(CreateThisWithTemplate) \
|
_(CreateThisWithTemplate) \
|
||||||
_(CreateArgumentsObject) \
|
|
||||||
_(GetArgumentsObjectArg) \
|
|
||||||
_(SetArgumentsObjectArg) \
|
|
||||||
_(PrepareCall) \
|
_(PrepareCall) \
|
||||||
_(PassArg) \
|
_(PassArg) \
|
||||||
_(Call) \
|
_(Call) \
|
||||||
|
|
|
@ -130,9 +130,6 @@ class ParallelArrayVisitor : public MInstructionVisitor
|
||||||
UNSAFE_OP(CreateThis)
|
UNSAFE_OP(CreateThis)
|
||||||
UNSAFE_OP(CreateThisWithTemplate)
|
UNSAFE_OP(CreateThisWithTemplate)
|
||||||
UNSAFE_OP(CreateThisWithProto)
|
UNSAFE_OP(CreateThisWithProto)
|
||||||
UNSAFE_OP(CreateArgumentsObject)
|
|
||||||
UNSAFE_OP(GetArgumentsObjectArg)
|
|
||||||
UNSAFE_OP(SetArgumentsObjectArg)
|
|
||||||
SAFE_OP(PrepareCall)
|
SAFE_OP(PrepareCall)
|
||||||
SAFE_OP(PassArg)
|
SAFE_OP(PassArg)
|
||||||
CUSTOM_OP(Call)
|
CUSTOM_OP(Call)
|
||||||
|
|
|
@ -298,16 +298,15 @@ SnapshotWriter::startSnapshot(uint32_t frameCount, BailoutKind kind, bool resume
|
||||||
void
|
void
|
||||||
SnapshotWriter::startFrame(JSFunction *fun, RawScript script, jsbytecode *pc, uint32_t exprStack)
|
SnapshotWriter::startFrame(JSFunction *fun, RawScript script, jsbytecode *pc, uint32_t exprStack)
|
||||||
{
|
{
|
||||||
JS_ASSERT(CountArgSlots(script, fun) < SNAPSHOT_MAX_NARGS);
|
JS_ASSERT(CountArgSlots(fun) < SNAPSHOT_MAX_NARGS);
|
||||||
|
|
||||||
uint32_t implicit = StartArgSlot(script, fun);
|
uint32_t formalArgs = CountArgSlots(fun);
|
||||||
uint32_t formalArgs = CountArgSlots(script, fun);
|
|
||||||
|
|
||||||
nslots_ = formalArgs + script->nfixed + exprStack;
|
nslots_ = formalArgs + script->nfixed + exprStack;
|
||||||
slotsWritten_ = 0;
|
slotsWritten_ = 0;
|
||||||
|
|
||||||
IonSpew(IonSpew_Snapshots, "Starting frame; implicit %u, formals %u, fixed %u, exprs %u",
|
IonSpew(IonSpew_Snapshots, "Starting frame; formals %u, fixed %u, exprs %u",
|
||||||
implicit, formalArgs - implicit, script->nfixed, exprStack);
|
formalArgs, script->nfixed, exprStack);
|
||||||
|
|
||||||
JS_ASSERT(script->code <= pc && pc <= script->code + script->length);
|
JS_ASSERT(script->code <= pc && pc <= script->code + script->length);
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,7 @@ BaselineCompilerShared::BaselineCompilerShared(JSContext *cx, HandleScript scrip
|
||||||
: cx(cx),
|
: cx(cx),
|
||||||
script(cx, script),
|
script(cx, script),
|
||||||
pc(script->code),
|
pc(script->code),
|
||||||
ionCompileable_(ion::IsEnabled(cx) && CanIonCompileScript(cx, script, false)),
|
ionCompileable_(ion::IsEnabled(cx) && CanIonCompileScript(cx, script)),
|
||||||
ionOSRCompileable_(ion::IsEnabled(cx) && CanIonCompileScript(cx, script, true)),
|
|
||||||
debugMode_(cx->compartment->debugMode()),
|
debugMode_(cx->compartment->debugMode()),
|
||||||
frame(cx, script, masm),
|
frame(cx, script, masm),
|
||||||
stubSpace_(),
|
stubSpace_(),
|
||||||
|
|
|
@ -25,7 +25,6 @@ class BaselineCompilerShared
|
||||||
jsbytecode *pc;
|
jsbytecode *pc;
|
||||||
MacroAssembler masm;
|
MacroAssembler masm;
|
||||||
bool ionCompileable_;
|
bool ionCompileable_;
|
||||||
bool ionOSRCompileable_;
|
|
||||||
bool debugMode_;
|
bool debugMode_;
|
||||||
|
|
||||||
FrameInfo frame;
|
FrameInfo frame;
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
// Make sure arguments object handlig deals well with aliasing of args.
|
|
||||||
var arr = [];
|
|
||||||
function f(x) {
|
|
||||||
var args = arguments;
|
|
||||||
arr.push(arguments);
|
|
||||||
arguments[0] = 0;
|
|
||||||
return {
|
|
||||||
f: function () { return x; },
|
|
||||||
g: function () { return args[0]; }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that aliased arguments are correctly set to the callObject
|
|
||||||
for (var i = 0; i < 2000; i++)
|
|
||||||
assertEq(f(1).f(), 0);
|
|
||||||
|
|
||||||
// Check that aliased arguments are correctly read from the callObject
|
|
||||||
for (var i = 0; i < 2000; i++)
|
|
||||||
assertEq(f(1).g(), 0);
|
|
|
@ -18,8 +18,6 @@
|
||||||
#include "vm/Stack-inl.h"
|
#include "vm/Stack-inl.h"
|
||||||
#include "vm/ArgumentsObject-inl.h"
|
#include "vm/ArgumentsObject-inl.h"
|
||||||
|
|
||||||
#include "ion/IonFrames.h"
|
|
||||||
|
|
||||||
using namespace js;
|
using namespace js;
|
||||||
using namespace js::gc;
|
using namespace js::gc;
|
||||||
|
|
||||||
|
@ -47,8 +45,7 @@ CopyStackFrameArguments(const AbstractFramePtr frame, HeapValue *dst)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void
|
/* static */ void
|
||||||
ArgumentsObject::MaybeForwardToCallObject(AbstractFramePtr frame, JSObject *obj,
|
ArgumentsObject::MaybeForwardToCallObject(AbstractFramePtr frame, JSObject *obj, ArgumentsData *data)
|
||||||
ArgumentsData *data)
|
|
||||||
{
|
{
|
||||||
RawScript script = frame.script();
|
RawScript script = frame.script();
|
||||||
if (frame.fun()->isHeavyweight() && script->argsObjAliasesFormals()) {
|
if (frame.fun()->isHeavyweight() && script->argsObjAliasesFormals()) {
|
||||||
|
@ -58,22 +55,6 @@ ArgumentsObject::MaybeForwardToCallObject(AbstractFramePtr frame, JSObject *obj,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(JS_ION)
|
|
||||||
/* static */ void
|
|
||||||
ArgumentsObject::MaybeForwardToCallObject(ion::IonJSFrameLayout *frame, HandleObject callObj,
|
|
||||||
JSObject *obj, ArgumentsData *data)
|
|
||||||
{
|
|
||||||
RawFunction callee = ion::CalleeTokenToFunction(frame->calleeToken());
|
|
||||||
RawScript script = callee->nonLazyScript();
|
|
||||||
if (callee->isHeavyweight() && script->argsObjAliasesFormals()) {
|
|
||||||
JS_ASSERT(callObj && callObj->isCall());
|
|
||||||
obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(*callObj.get()));
|
|
||||||
for (AliasedFormalIter fi(script); fi; fi++)
|
|
||||||
data->args[fi.frameIndex()] = MagicValue(JS_FORWARD_TO_CALL_OBJECT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct CopyFrameArgs
|
struct CopyFrameArgs
|
||||||
{
|
{
|
||||||
AbstractFramePtr frame_;
|
AbstractFramePtr frame_;
|
||||||
|
@ -95,36 +76,6 @@ struct CopyFrameArgs
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#if defined(JS_ION)
|
|
||||||
struct CopyIonJSFrameArgs
|
|
||||||
{
|
|
||||||
ion::IonJSFrameLayout *frame_;
|
|
||||||
HandleObject callObj_;
|
|
||||||
|
|
||||||
CopyIonJSFrameArgs(ion::IonJSFrameLayout *frame, HandleObject callObj)
|
|
||||||
: frame_(frame), callObj_(callObj)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
void copyArgs(JSContext *, HeapValue *dst) const {
|
|
||||||
unsigned numActuals = frame_->numActualArgs();
|
|
||||||
|
|
||||||
/* Copy all arguments. */
|
|
||||||
Value *src = frame_->argv() + 1; /* +1 to skip this. */
|
|
||||||
Value *end = src + numActuals;
|
|
||||||
while (src != end)
|
|
||||||
(dst++)->init(*src++);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If a call object exists and the arguments object aliases formals, the
|
|
||||||
* call object is the canonical location for formals.
|
|
||||||
*/
|
|
||||||
void maybeForwardToCallObject(JSObject *obj, ArgumentsData *data) {
|
|
||||||
ArgumentsObject::MaybeForwardToCallObject(frame_, callObj_, obj, data);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct CopyStackIterArgs
|
struct CopyStackIterArgs
|
||||||
{
|
{
|
||||||
StackIter &iter_;
|
StackIter &iter_;
|
||||||
|
@ -257,20 +208,6 @@ ArgumentsObject::createUnexpected(JSContext *cx, AbstractFramePtr frame)
|
||||||
return create(cx, script, callee, frame.numActualArgs(), copy);
|
return create(cx, script, callee, frame.numActualArgs(), copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(JS_ION)
|
|
||||||
ArgumentsObject *
|
|
||||||
ArgumentsObject::createForIon(JSContext *cx, ion::IonJSFrameLayout *frame, HandleObject scopeChain)
|
|
||||||
{
|
|
||||||
ion::CalleeToken token = frame->calleeToken();
|
|
||||||
JS_ASSERT(ion::CalleeTokenIsFunction(token));
|
|
||||||
RootedScript script(cx, ion::ScriptFromCalleeToken(token));
|
|
||||||
RootedFunction callee(cx, ion::CalleeTokenToFunction(token));
|
|
||||||
RootedObject callObj(cx, scopeChain->isCall() ? scopeChain.get() : NULL);
|
|
||||||
CopyIonJSFrameArgs copy(frame, callObj);
|
|
||||||
return create(cx, script, callee, frame->numActualArgs(), copy);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static JSBool
|
static JSBool
|
||||||
args_delProperty(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded)
|
args_delProperty(JSContext *cx, HandleObject obj, HandleId id, JSBool *succeeded)
|
||||||
{
|
{
|
||||||
|
|
|
@ -125,10 +125,6 @@ class ArgumentsObject : public JSObject
|
||||||
*/
|
*/
|
||||||
static ArgumentsObject *createUnexpected(JSContext *cx, StackIter &iter);
|
static ArgumentsObject *createUnexpected(JSContext *cx, StackIter &iter);
|
||||||
static ArgumentsObject *createUnexpected(JSContext *cx, AbstractFramePtr frame);
|
static ArgumentsObject *createUnexpected(JSContext *cx, AbstractFramePtr frame);
|
||||||
#if defined(JS_ION)
|
|
||||||
static ArgumentsObject *createForIon(JSContext *cx, ion::IonJSFrameLayout *frame,
|
|
||||||
HandleObject scopeChain);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the initial length of the arguments. This may differ from the
|
* Return the initial length of the arguments. This may differ from the
|
||||||
|
@ -211,10 +207,6 @@ class ArgumentsObject : public JSObject
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MaybeForwardToCallObject(AbstractFramePtr frame, JSObject *obj, ArgumentsData *data);
|
static void MaybeForwardToCallObject(AbstractFramePtr frame, JSObject *obj, ArgumentsData *data);
|
||||||
#if defined(JS_ION)
|
|
||||||
static void MaybeForwardToCallObject(ion::IonJSFrameLayout *frame, HandleObject callObj,
|
|
||||||
JSObject *obj, ArgumentsData *data);
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class NormalArgumentsObject : public ArgumentsObject
|
class NormalArgumentsObject : public ArgumentsObject
|
||||||
|
|
|
@ -1132,7 +1132,7 @@ ContextStack::pushBailoutArgs(JSContext *cx, const ion::IonBailoutIterator &it,
|
||||||
CopyTo dst(iag->array());
|
CopyTo dst(iag->array());
|
||||||
Value *src = it.actualArgs();
|
Value *src = it.actualArgs();
|
||||||
Value thisv = iag->thisv();
|
Value thisv = iag->thisv();
|
||||||
s.readFrameArgs(dst, src, NULL, &thisv, 0, fun->nargs, argc, it.script());
|
s.readFrameArgs(dst, src, NULL, &thisv, 0, fun->nargs, argc);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче