Handle arguments[i] (Bug 735406 part 3, r=dvander)

This commit is contained in:
Nicolas Pierron 2012-06-15 07:37:06 -07:00
parent b051eca1e0
commit 7dbe13857b
12 changed files with 142 additions and 19 deletions

View File

@ -2160,13 +2160,31 @@ CodeGenerator::visitArgumentsLength(LArgumentsLength *lir)
{
// read number of actual arguments from the JS frame.
Register argc = ToRegister(lir->output());
Address ptr(StackPointer, masm.framePushed() + IonJSFrameLayout::offsetOfNumActualArgs());
Address ptr(StackPointer, frameSize() + IonJSFrameLayout::offsetOfNumActualArgs());
JS_ASSERT(masm.framePushed() == frameSize());
masm.movePtr(ptr, argc);
return true;
}
bool
CodeGenerator::visitGetArgument(LGetArgument *lir)
{
ValueOperand result = GetValueOutput(lir);
const LAllocation *index = lir->index();
size_t argvOffset = frameSize() + IonJSFrameLayout::offsetOfActualArgs();
if (index->isConstant()) {
int32 i = index->toConstant()->toInt32();
Address argPtr(StackPointer, sizeof(Value*) * i + argvOffset);
masm.loadValue(argPtr, result);
} else {
Register i = ToRegister(index);
BaseIndex argPtr(StackPointer, i, ScaleFromShift(sizeof(Value*)), argvOffset);
masm.loadValue(argPtr, result);
}
return true;
}
bool
CodeGenerator::generate()
{

View File

@ -176,6 +176,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitIteratorMore(LIteratorMore *lir);
bool visitIteratorEnd(LIteratorEnd *lir);
bool visitArgumentsLength(LArgumentsLength *lir);
bool visitGetArgument(LGetArgument *lir);
bool visitCallSetProperty(LCallSetProperty *ins);
bool visitCallDeleteProperty(LCallDeleteProperty *lir);
bool visitBitNotV(LBitNotV *lir);

View File

@ -160,6 +160,10 @@ class CompileInfo
return firstStackSlot() + i;
}
bool hasArguments() {
return script()->argumentsHasLocalBinding();
}
private:
JSScript *script_;
JSFunction *fun_;

View File

@ -823,6 +823,13 @@ IonBuilder::inspectOpcode(JSOp op)
return true;
case JSOP_SETARG:
// To handle this case, we should spill the arguments to the space where
// actual arguments are stored. The tricky part is that if we add a MIR
// to wrap the spilling action, we don't want the spilling to be
// captured by the GETARG and by the resume point, only by
// MGetArgument.
if (info().hasArguments())
return abort("NYI: arguments & setarg.");
current->setArg(GET_SLOTNO(pc));
return true;
@ -2707,6 +2714,10 @@ IonBuilder::jsop_notearg()
MDefinition *def = current->pop();
MPassArg *arg = MPassArg::New(def);
// We do not support giving the argument object as argument yet.
if (def->type() == MIRType_ArgObj)
return abort("NYI: escaping of the argument object.");
current->add(arg);
current->push(arg);
return true;
@ -3048,14 +3059,8 @@ IonBuilder::jsop_funcall(uint32 argc)
// If |Function.prototype.call| may be overridden, don't optimize callsite.
RootedFunction native(cx, getSingleCallTarget(argc, pc));
if (native && native->isNative()) {
if (native->native() == &js_fun_apply)
return abort("NYI: fun.apply with arguments.");
if (native->native() != &js_fun_call)
return makeCall(native, argc, false);
} else {
if (!native || !native->isNative() || native->native() != &js_fun_call)
return makeCall(native, argc, false);
}
// Extract call target.
types::TypeSet *funTypes = oracle->getCallArg(script, argc, 0, pc);
@ -4475,9 +4480,30 @@ IonBuilder::jsop_arguments_length()
bool
IonBuilder::jsop_arguments_getelem()
{
types::TypeSet *barrier = oracle->propertyReadBarrier(script, pc);
types::TypeSet *types = oracle->propertyRead(script, pc);
MDefinition *idx = current->pop();
MDefinition *obj = current->pop();
return abort("NYI arguments[]");
MDefinition *args = current->pop();
// To ensure that we are not looking above the number of actual arguments.
MArgumentsLength *length = MArgumentsLength::New(args);
current->add(length);
// Ensure idx is an integer.
MToInt32 *index = MToInt32::New(idx);
current->add(index);
// Bailouts if we read more than the number of actual arguments.
MBoundsCheck *check = MBoundsCheck::New(index, length);
current->add(check);
// Load the argument from the actual arguments.
MGetArgument *load = MGetArgument::New(index);
current->add(load);
current->push(load);
return pushTypeBarrier(load, types, barrier);
}
bool

View File

@ -2632,6 +2632,21 @@ class LArgumentsLength : public LInstructionHelper<1, 0, 0>
}
};
// Load a value from the actual arguments.
class LGetArgument : public LInstructionHelper<BOX_PIECES, 1, 0>
{
public:
LIR_HEADER(GetArgument);
BOX_OUTPUT_ACCESSORS();
LGetArgument(const LAllocation &index) {
setOperand(0, index);
}
const LAllocation *index() {
return getOperand(0);
}
};
// Guard that a value is in a TypeSet.
class LTypeBarrier : public LInstructionHelper<BOX_PIECES, BOX_PIECES, 1>
{

View File

@ -173,6 +173,7 @@
_(TypedArrayElements) \
_(StringLength) \
_(ArgumentsLength) \
_(GetArgument) \
_(TypeOfV) \
_(ToIdV) \
_(Floor) \

View File

@ -847,10 +847,18 @@ LIRGenerator::visitToInt32(MToInt32 *convert)
return assignSnapshot(lir) && define(lir, convert);
}
case MIRType_String:
// Strings are complicated - we don't handle them yet.
IonSpew(IonSpew_Abort, "String to Int32 not supported yet.");
break;
case MIRType_Object:
// Objects might be effectful.
IonSpew(IonSpew_Abort, "Object to Int32 not supported yet.");
break;
default:
// Undefined coerces to NaN, not int32.
// Objects might be effectful.
// Strings are complicated - we don't handle them yet.
JS_NOT_REACHED("unexpected type");
}
@ -1578,6 +1586,13 @@ LIRGenerator::visitArgumentsLength(MArgumentsLength *ins)
return define(new LArgumentsLength(), ins);
}
bool
LIRGenerator::visitGetArgument(MGetArgument *ins)
{
LGetArgument *lir = new LGetArgument(useRegisterOrConstant(ins->index()));
return defineBox(lir, ins);
}
bool
LIRGenerator::visitThrow(MThrow *ins)
{

View File

@ -200,6 +200,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitIteratorEnd(MIteratorEnd *ins);
bool visitStringLength(MStringLength *ins);
bool visitArgumentsLength(MArgumentsLength *ins);
bool visitGetArgument(MGetArgument *ins);
bool visitThrow(MThrow *ins);
bool visitInstanceOf(MInstanceOf *ins);
};

View File

@ -343,6 +343,9 @@ MConstant::printOpcode(FILE *fp)
case MIRType_String:
fprintf(fp, "string %p", (void *)value().toString());
break;
case MIRType_Magic:
fprintf(fp, "magic");
break;
case MIRType_ArgObj:
fprintf(fp, "lazy arguments");
break;

View File

@ -4404,19 +4404,52 @@ class MArgumentsLength
return new MArgumentsLength(arguments);
}
TypePolicy *typePolicy() {
return this;
}
MDefinition *arguments() const {
return getOperand(0);
}
TypePolicy *typePolicy() {
return this;
}
bool congruentTo(MDefinition *const &ins) const {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const {
// Arguments |length| cannot be mutated by Ion Code.
return AliasSet::None();
}
};
// This MIR instruction is used to get an argument from the actual arguments.
class MGetArgument
: public MUnaryInstruction,
public IntPolicy<0>
{
MGetArgument(MDefinition *idx)
: MUnaryInstruction(idx)
{
setResultType(MIRType_Value);
setMovable();
}
public:
INSTRUCTION_HEADER(GetArgument);
static MGetArgument *New(MDefinition *idx) {
return new MGetArgument(idx);
}
MDefinition *index() const {
return getOperand(0);
}
TypePolicy *typePolicy() {
return this;
}
bool congruentTo(MDefinition *const &ins) const {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const {
// Arguments |length| cannot be mutated by Ion Code or any the the
// called functions.
return AliasSet::None();
}
};

View File

@ -147,6 +147,7 @@ namespace ion {
_(IteratorEnd) \
_(StringLength) \
_(ArgumentsLength) \
_(GetArgument) \
_(Floor) \
_(Round) \
_(InstanceOf) \

View File

@ -96,6 +96,11 @@ class IonJSFrameLayout : public IonCommonFrameLayout
static size_t offsetOfNumActualArgs() {
return offsetof(IonJSFrameLayout, numActualArgs_);
}
static size_t offsetOfActualArgs() {
IonJSFrameLayout *base = NULL;
// +1 to skip |this|.
return reinterpret_cast<size_t>(&base->argv()[1]);
}
Value *argv() {
return (Value *)(this + 1);