mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-02 15:15:23 +00:00
Handle arguments[i] (Bug 735406 part 3, r=dvander)
This commit is contained in:
parent
b051eca1e0
commit
7dbe13857b
@ -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()
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -160,6 +160,10 @@ class CompileInfo
|
||||
return firstStackSlot() + i;
|
||||
}
|
||||
|
||||
bool hasArguments() {
|
||||
return script()->argumentsHasLocalBinding();
|
||||
}
|
||||
|
||||
private:
|
||||
JSScript *script_;
|
||||
JSFunction *fun_;
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
{
|
||||
|
@ -173,6 +173,7 @@
|
||||
_(TypedArrayElements) \
|
||||
_(StringLength) \
|
||||
_(ArgumentsLength) \
|
||||
_(GetArgument) \
|
||||
_(TypeOfV) \
|
||||
_(ToIdV) \
|
||||
_(Floor) \
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
@ -147,6 +147,7 @@ namespace ion {
|
||||
_(IteratorEnd) \
|
||||
_(StringLength) \
|
||||
_(ArgumentsLength) \
|
||||
_(GetArgument) \
|
||||
_(Floor) \
|
||||
_(Round) \
|
||||
_(InstanceOf) \
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user