[runtime] Kill %Arguments and %ArgumentsLength.
This removes support for the %Arguments and %ArgumentsLength runtime entries and their intrinsic counterparts. If you need variable arguments in any builtin, either use (strict) arguments object or rest parameters, which are both compositional across inlining (in TurboFan), and not that much slower compared to the %_Arguments hackery. R=jarin@chromium.org Review URL: https://codereview.chromium.org/1688163004 Cr-Commit-Position: refs/heads/master@{#33943}
This commit is contained in:
parent
1b33ffa49a
commit
98aec4a719
@ -1489,59 +1489,6 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
// The displacement is the offset of the last parameter (if any)
|
||||
// relative to the frame pointer.
|
||||
const int kDisplacement =
|
||||
StandardFrameConstants::kCallerSPOffset - kPointerSize;
|
||||
DCHECK(r1.is(ArgumentsAccessReadDescriptor::index()));
|
||||
DCHECK(r0.is(ArgumentsAccessReadDescriptor::parameter_count()));
|
||||
|
||||
// Check that the key is a smi.
|
||||
Label slow;
|
||||
__ JumpIfNotSmi(r1, &slow);
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label adaptor;
|
||||
__ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
|
||||
__ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||
__ b(eq, &adaptor);
|
||||
|
||||
// Check index against formal parameters count limit passed in
|
||||
// through register r0. Use unsigned comparison to get negative
|
||||
// check for free.
|
||||
__ cmp(r1, r0);
|
||||
__ b(hs, &slow);
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
__ sub(r3, r0, r1);
|
||||
__ add(r3, fp, Operand::PointerOffsetFromSmiKey(r3));
|
||||
__ ldr(r0, MemOperand(r3, kDisplacement));
|
||||
__ Jump(lr);
|
||||
|
||||
// Arguments adaptor case: Check index against actual arguments
|
||||
// limit found in the arguments adaptor frame. Use unsigned
|
||||
// comparison to get negative check for free.
|
||||
__ bind(&adaptor);
|
||||
__ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ cmp(r1, r0);
|
||||
__ b(cs, &slow);
|
||||
|
||||
// Read the argument from the adaptor frame and return it.
|
||||
__ sub(r3, r0, r1);
|
||||
__ add(r3, r2, Operand::PointerOffsetFromSmiKey(r3));
|
||||
__ ldr(r0, MemOperand(r3, kDisplacement));
|
||||
__ Jump(lr);
|
||||
|
||||
// Slow-case: Handle non-smi or out-of-bounds access to arguments
|
||||
// by calling the runtime system.
|
||||
__ bind(&slow);
|
||||
__ push(r1);
|
||||
__ TailCallRuntime(Runtime::kArguments);
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
|
||||
// r1 : function
|
||||
// r2 : number of parameters (tagged)
|
||||
|
@ -56,10 +56,6 @@ const Register StringCompareDescriptor::LeftRegister() { return r1; }
|
||||
const Register StringCompareDescriptor::RightRegister() { return r0; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessReadDescriptor::index() { return r1; }
|
||||
const Register ArgumentsAccessReadDescriptor::parameter_count() { return r0; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessNewDescriptor::function() { return r1; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_count() { return r2; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_pointer() { return r3; }
|
||||
|
@ -1626,57 +1626,6 @@ void InstanceOfStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
Register arg_count = ArgumentsAccessReadDescriptor::parameter_count();
|
||||
Register key = ArgumentsAccessReadDescriptor::index();
|
||||
DCHECK(arg_count.is(x0));
|
||||
DCHECK(key.is(x1));
|
||||
|
||||
// The displacement is the offset of the last parameter (if any) relative
|
||||
// to the frame pointer.
|
||||
static const int kDisplacement =
|
||||
StandardFrameConstants::kCallerSPOffset - kPointerSize;
|
||||
|
||||
// Check that the key is a smi.
|
||||
Label slow;
|
||||
__ JumpIfNotSmi(key, &slow);
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Register local_fp = x11;
|
||||
Register caller_fp = x11;
|
||||
Register caller_ctx = x12;
|
||||
Label skip_adaptor;
|
||||
__ Ldr(caller_fp, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ Ldr(caller_ctx, MemOperand(caller_fp,
|
||||
StandardFrameConstants::kContextOffset));
|
||||
__ Cmp(caller_ctx, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
||||
__ Csel(local_fp, fp, caller_fp, ne);
|
||||
__ B(ne, &skip_adaptor);
|
||||
|
||||
// Load the actual arguments limit found in the arguments adaptor frame.
|
||||
__ Ldr(arg_count, MemOperand(caller_fp,
|
||||
ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ Bind(&skip_adaptor);
|
||||
|
||||
// Check index against formal parameters count limit. Use unsigned comparison
|
||||
// to get negative check for free: branch if key < 0 or key >= arg_count.
|
||||
__ Cmp(key, arg_count);
|
||||
__ B(hs, &slow);
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
__ Sub(x10, arg_count, key);
|
||||
__ Add(x10, local_fp, Operand::UntagSmiAndScale(x10, kPointerSizeLog2));
|
||||
__ Ldr(x0, MemOperand(x10, kDisplacement));
|
||||
__ Ret();
|
||||
|
||||
// Slow case: handle non-smi or out-of-bounds access to arguments by calling
|
||||
// the runtime system.
|
||||
__ Bind(&slow);
|
||||
__ Push(key);
|
||||
__ TailCallRuntime(Runtime::kArguments);
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
|
||||
// x1 : function
|
||||
// x2 : number of parameters (tagged)
|
||||
|
@ -56,10 +56,6 @@ const Register StringCompareDescriptor::LeftRegister() { return x1; }
|
||||
const Register StringCompareDescriptor::RightRegister() { return x0; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessReadDescriptor::index() { return x1; }
|
||||
const Register ArgumentsAccessReadDescriptor::parameter_count() { return x0; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessNewDescriptor::function() { return x1; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_count() { return x2; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_pointer() { return x3; }
|
||||
|
@ -822,9 +822,6 @@ void StoreFastElementStub::GenerateAheadOfTime(Isolate* isolate) {
|
||||
|
||||
void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
|
||||
switch (type()) {
|
||||
case READ_ELEMENT:
|
||||
GenerateReadElement(masm);
|
||||
break;
|
||||
case NEW_SLOPPY_FAST:
|
||||
GenerateNewSloppyFast(masm);
|
||||
break;
|
||||
@ -838,9 +835,6 @@ void ArgumentsAccessStub::Generate(MacroAssembler* masm) {
|
||||
void ArgumentsAccessStub::PrintName(std::ostream& os) const { // NOLINT
|
||||
os << "ArgumentsAccessStub_";
|
||||
switch (type()) {
|
||||
case READ_ELEMENT:
|
||||
os << "ReadElement";
|
||||
break;
|
||||
case NEW_SLOPPY_FAST:
|
||||
os << "NewSloppyFast";
|
||||
break;
|
||||
|
@ -1843,7 +1843,6 @@ class JSEntryStub : public PlatformCodeStub {
|
||||
class ArgumentsAccessStub: public PlatformCodeStub {
|
||||
public:
|
||||
enum Type {
|
||||
READ_ELEMENT,
|
||||
NEW_SLOPPY_FAST,
|
||||
NEW_SLOPPY_SLOW,
|
||||
};
|
||||
@ -1853,11 +1852,7 @@ class ArgumentsAccessStub: public PlatformCodeStub {
|
||||
}
|
||||
|
||||
CallInterfaceDescriptor GetCallInterfaceDescriptor() const override {
|
||||
if (type() == READ_ELEMENT) {
|
||||
return ArgumentsAccessReadDescriptor(isolate());
|
||||
} else {
|
||||
return ArgumentsAccessNewDescriptor(isolate());
|
||||
}
|
||||
return ArgumentsAccessNewDescriptor(isolate());
|
||||
}
|
||||
|
||||
static Type ComputeType(bool has_duplicate_parameters) {
|
||||
@ -1871,13 +1866,12 @@ class ArgumentsAccessStub: public PlatformCodeStub {
|
||||
private:
|
||||
Type type() const { return TypeBits::decode(minor_key_); }
|
||||
|
||||
void GenerateReadElement(MacroAssembler* masm);
|
||||
void GenerateNewSloppyFast(MacroAssembler* masm);
|
||||
void GenerateNewSloppySlow(MacroAssembler* masm);
|
||||
|
||||
void PrintName(std::ostream& os) const override; // NOLINT
|
||||
|
||||
class TypeBits : public BitField<Type, 0, 2> {};
|
||||
class TypeBits : public BitField<Type, 0, 1> {};
|
||||
|
||||
DEFINE_PLATFORM_CODE_STUB(ArgumentsAccess, PlatformCodeStub);
|
||||
};
|
||||
|
@ -168,8 +168,6 @@ int Linkage::FrameStateInputCount(Runtime::FunctionId function) {
|
||||
case Runtime::kTraceEnter:
|
||||
case Runtime::kTraceExit:
|
||||
return 0;
|
||||
case Runtime::kInlineArguments:
|
||||
case Runtime::kInlineArgumentsLength:
|
||||
case Runtime::kInlineGetPrototype:
|
||||
case Runtime::kInlineRegExpConstructResult:
|
||||
case Runtime::kInlineRegExpExec:
|
||||
|
@ -12422,48 +12422,6 @@ void HOptimizedGraphBuilder::GenerateHasFastPackedElements(CallRuntime* call) {
|
||||
}
|
||||
|
||||
|
||||
// Support for arguments.length and arguments[?].
|
||||
void HOptimizedGraphBuilder::GenerateArgumentsLength(CallRuntime* call) {
|
||||
DCHECK(call->arguments()->length() == 0);
|
||||
HInstruction* result = NULL;
|
||||
if (function_state()->outer() == NULL) {
|
||||
HInstruction* elements = Add<HArgumentsElements>(false);
|
||||
result = New<HArgumentsLength>(elements);
|
||||
} else {
|
||||
// Number of arguments without receiver.
|
||||
int argument_count = environment()->
|
||||
arguments_environment()->parameter_count() - 1;
|
||||
result = New<HConstant>(argument_count);
|
||||
}
|
||||
return ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateArguments(CallRuntime* call) {
|
||||
DCHECK(call->arguments()->length() == 1);
|
||||
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
||||
HValue* index = Pop();
|
||||
HInstruction* result = NULL;
|
||||
if (function_state()->outer() == NULL) {
|
||||
HInstruction* elements = Add<HArgumentsElements>(false);
|
||||
HInstruction* length = Add<HArgumentsLength>(elements);
|
||||
HInstruction* checked_index = Add<HBoundsCheck>(index, length);
|
||||
result = New<HAccessArgumentsAt>(elements, length, checked_index);
|
||||
} else {
|
||||
EnsureArgumentsArePushedForAccess();
|
||||
|
||||
// Number of arguments without receiver.
|
||||
HInstruction* elements = function_state()->arguments_elements();
|
||||
int argument_count = environment()->
|
||||
arguments_environment()->parameter_count() - 1;
|
||||
HInstruction* length = Add<HConstant>(argument_count);
|
||||
HInstruction* checked_key = Add<HBoundsCheck>(index, length);
|
||||
result = New<HAccessArgumentsAt>(elements, length, checked_key);
|
||||
}
|
||||
return ast_context()->ReturnInstruction(result, call->id());
|
||||
}
|
||||
|
||||
|
||||
void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) {
|
||||
DCHECK(call->arguments()->length() == 1);
|
||||
CHECK_ALIVE(VisitForValue(call->arguments()->at(0)));
|
||||
|
@ -2207,8 +2207,6 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
|
||||
F(IsRegExp) \
|
||||
F(IsJSProxy) \
|
||||
F(Call) \
|
||||
F(ArgumentsLength) \
|
||||
F(Arguments) \
|
||||
F(ValueOf) \
|
||||
F(SetValueOf) \
|
||||
F(IsDate) \
|
||||
|
@ -3152,40 +3152,6 @@ void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
// ArgumentsAccessStub expects the key in edx and the formal
|
||||
// parameter count in r0.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
__ mov(r1, r0);
|
||||
__ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
|
||||
ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(r0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
|
||||
DCHECK(expr->arguments()->length() == 0);
|
||||
|
||||
// Get the number of formal parameters.
|
||||
__ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
__ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
|
||||
__ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||
|
||||
// Arguments adaptor case: Read the arguments length from the
|
||||
// adaptor frame.
|
||||
__ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset), eq);
|
||||
|
||||
context()->Plug(r0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -2958,41 +2958,6 @@ void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
// ArgumentsAccessStub expects the key in x1.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
__ Mov(x1, x0);
|
||||
__ Mov(x0, Smi::FromInt(info_->scope()->num_parameters()));
|
||||
ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(x0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
|
||||
DCHECK(expr->arguments()->length() == 0);
|
||||
Label exit;
|
||||
// Get the number of formal parameters.
|
||||
__ Mov(x0, Smi::FromInt(info_->scope()->num_parameters()));
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
__ Ldr(x12, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ Ldr(x13, MemOperand(x12, StandardFrameConstants::kContextOffset));
|
||||
__ Cmp(x13, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
||||
__ B(ne, &exit);
|
||||
|
||||
// Arguments adaptor case: Read the arguments length from the
|
||||
// adaptor frame.
|
||||
__ Ldr(x0, MemOperand(x12, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
|
||||
__ Bind(&exit);
|
||||
context()->Plug(x0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
ASM_LOCATION("FullCodeGenerator::EmitClassOf");
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
|
@ -525,8 +525,6 @@ class FullCodeGenerator: public AstVisitor {
|
||||
F(IsRegExp) \
|
||||
F(IsJSProxy) \
|
||||
F(Call) \
|
||||
F(ArgumentsLength) \
|
||||
F(Arguments) \
|
||||
F(ValueOf) \
|
||||
F(SetValueOf) \
|
||||
F(IsDate) \
|
||||
|
@ -3033,44 +3033,6 @@ void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
// ArgumentsAccessStub expects the key in edx and the formal
|
||||
// parameter count in eax.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
__ mov(edx, eax);
|
||||
__ Move(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
|
||||
ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(eax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
|
||||
DCHECK(expr->arguments()->length() == 0);
|
||||
|
||||
Label exit;
|
||||
// Get the number of formal parameters.
|
||||
__ Move(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
|
||||
Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||
__ j(not_equal, &exit);
|
||||
|
||||
// Arguments adaptor case: Read the arguments length from the
|
||||
// adaptor frame.
|
||||
__ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
|
||||
__ bind(&exit);
|
||||
__ AssertSmi(eax);
|
||||
context()->Plug(eax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -3139,42 +3139,6 @@ void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
// ArgumentsAccessStub expects the key in a1 and the formal
|
||||
// parameter count in a0.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
__ mov(a1, v0);
|
||||
__ li(a0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
|
||||
ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(v0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
|
||||
DCHECK(expr->arguments()->length() == 0);
|
||||
Label exit;
|
||||
// Get the number of formal parameters.
|
||||
__ li(v0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
__ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset));
|
||||
__ Branch(&exit, ne, a3,
|
||||
Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||
|
||||
// Arguments adaptor case: Read the arguments length from the
|
||||
// adaptor frame.
|
||||
__ lw(v0, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
|
||||
__ bind(&exit);
|
||||
context()->Plug(v0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -3144,42 +3144,6 @@ void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
// ArgumentsAccessStub expects the key in a1 and the formal
|
||||
// parameter count in a0.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
__ mov(a1, v0);
|
||||
__ li(a0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
|
||||
ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(v0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
|
||||
DCHECK(expr->arguments()->length() == 0);
|
||||
Label exit;
|
||||
// Get the number of formal parameters.
|
||||
__ li(v0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
__ ld(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ ld(a3, MemOperand(a2, StandardFrameConstants::kContextOffset));
|
||||
__ Branch(&exit, ne, a3,
|
||||
Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||
|
||||
// Arguments adaptor case: Read the arguments length from the
|
||||
// adaptor frame.
|
||||
__ ld(v0, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
|
||||
__ bind(&exit);
|
||||
context()->Plug(v0);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -3120,42 +3120,6 @@ void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
// ArgumentsAccessStub expects the key in r4 and the formal
|
||||
// parameter count in r3.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
__ mr(r4, r3);
|
||||
__ LoadSmiLiteral(r3, Smi::FromInt(info_->scope()->num_parameters()));
|
||||
ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(r3);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
|
||||
DCHECK(expr->arguments()->length() == 0);
|
||||
Label exit;
|
||||
// Get the number of formal parameters.
|
||||
__ LoadSmiLiteral(r3, Smi::FromInt(info_->scope()->num_parameters()));
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
__ LoadP(r5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ LoadP(r6, MemOperand(r5, StandardFrameConstants::kContextOffset));
|
||||
__ CmpSmiLiteral(r6, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
|
||||
__ bne(&exit);
|
||||
|
||||
// Arguments adaptor case: Read the arguments length from the
|
||||
// adaptor frame.
|
||||
__ LoadP(r3, MemOperand(r5, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
|
||||
__ bind(&exit);
|
||||
context()->Plug(r3);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -3019,44 +3019,6 @@ void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
// ArgumentsAccessStub expects the key in rdx and the formal
|
||||
// parameter count in rax.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
__ movp(rdx, rax);
|
||||
__ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
|
||||
ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(rax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
|
||||
DCHECK(expr->arguments()->length() == 0);
|
||||
|
||||
Label exit;
|
||||
// Get the number of formal parameters.
|
||||
__ Move(rax, Smi::FromInt(info_->scope()->num_parameters()));
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
__ movp(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
|
||||
Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
||||
__ j(not_equal, &exit, Label::kNear);
|
||||
|
||||
// Arguments adaptor case: Read the arguments length from the
|
||||
// adaptor frame.
|
||||
__ movp(rax, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
|
||||
__ bind(&exit);
|
||||
__ AssertSmi(rax);
|
||||
context()->Plug(rax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -3012,44 +3012,6 @@ void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
||||
// ArgumentsAccessStub expects the key in edx and the formal
|
||||
// parameter count in eax.
|
||||
VisitForAccumulatorValue(args->at(0));
|
||||
__ mov(edx, eax);
|
||||
__ Move(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
|
||||
ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
|
||||
__ CallStub(&stub);
|
||||
context()->Plug(eax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
|
||||
DCHECK(expr->arguments()->length() == 0);
|
||||
|
||||
Label exit;
|
||||
// Get the number of formal parameters.
|
||||
__ Move(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
|
||||
Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||
__ j(not_equal, &exit);
|
||||
|
||||
// Arguments adaptor case: Read the arguments length from the
|
||||
// adaptor frame.
|
||||
__ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
|
||||
__ bind(&exit);
|
||||
__ AssertSmi(eax);
|
||||
context()->Plug(eax);
|
||||
}
|
||||
|
||||
|
||||
void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
|
||||
ZoneList<Expression*>* args = expr->arguments();
|
||||
DCHECK(args->length() == 1);
|
||||
|
@ -727,67 +727,6 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
// The key is in edx and the parameter count is in eax.
|
||||
DCHECK(edx.is(ArgumentsAccessReadDescriptor::index()));
|
||||
DCHECK(eax.is(ArgumentsAccessReadDescriptor::parameter_count()));
|
||||
|
||||
// The displacement is used for skipping the frame pointer on the
|
||||
// stack. It is the offset of the last parameter (if any) relative
|
||||
// to the frame pointer.
|
||||
static const int kDisplacement = 1 * kPointerSize;
|
||||
|
||||
// Check that the key is a smi.
|
||||
Label slow;
|
||||
__ JumpIfNotSmi(edx, &slow, Label::kNear);
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label adaptor;
|
||||
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset));
|
||||
__ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||
__ j(equal, &adaptor, Label::kNear);
|
||||
|
||||
// Check index against formal parameters count limit passed in
|
||||
// through register eax. Use unsigned comparison to get negative
|
||||
// check for free.
|
||||
__ cmp(edx, eax);
|
||||
__ j(above_equal, &slow, Label::kNear);
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
STATIC_ASSERT(kSmiTagSize == 1);
|
||||
STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these.
|
||||
__ lea(ebx, Operand(ebp, eax, times_2, 0));
|
||||
__ neg(edx);
|
||||
__ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
|
||||
__ ret(0);
|
||||
|
||||
// Arguments adaptor case: Check index against actual arguments
|
||||
// limit found in the arguments adaptor frame. Use unsigned
|
||||
// comparison to get negative check for free.
|
||||
__ bind(&adaptor);
|
||||
__ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ cmp(edx, ecx);
|
||||
__ j(above_equal, &slow, Label::kNear);
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
STATIC_ASSERT(kSmiTagSize == 1);
|
||||
STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these.
|
||||
__ lea(ebx, Operand(ebx, ecx, times_2, 0));
|
||||
__ neg(edx);
|
||||
__ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
|
||||
__ ret(0);
|
||||
|
||||
// Slow-case: Handle non-smi or out-of-bounds access to arguments
|
||||
// by calling the runtime system.
|
||||
__ bind(&slow);
|
||||
__ pop(ebx); // Return address.
|
||||
__ push(edx);
|
||||
__ push(ebx);
|
||||
__ TailCallRuntime(Runtime::kArguments);
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
|
||||
// ecx : number of parameters (tagged)
|
||||
// edx : parameters pointer
|
||||
|
@ -59,10 +59,6 @@ const Register StringCompareDescriptor::LeftRegister() { return edx; }
|
||||
const Register StringCompareDescriptor::RightRegister() { return eax; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessReadDescriptor::index() { return edx; }
|
||||
const Register ArgumentsAccessReadDescriptor::parameter_count() { return eax; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessNewDescriptor::function() { return edi; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_count() { return ecx; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_pointer() { return edx; }
|
||||
|
@ -339,13 +339,6 @@ void ApiGetterDescriptor::InitializePlatformSpecific(
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessReadDescriptor::InitializePlatformSpecific(
|
||||
CallInterfaceDescriptorData* data) {
|
||||
Register registers[] = {index(), parameter_count()};
|
||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||
}
|
||||
|
||||
FunctionType*
|
||||
ArgumentsAccessNewDescriptor::BuildCallInterfaceDescriptorFunctionType(
|
||||
Isolate* isolate, int paramater_count) {
|
||||
|
@ -69,7 +69,6 @@ class PlatformInterfaceDescriptor;
|
||||
V(ApiFunction) \
|
||||
V(ApiAccessor) \
|
||||
V(ApiGetter) \
|
||||
V(ArgumentsAccessRead) \
|
||||
V(ArgumentsAccessNew) \
|
||||
V(LoadGlobalViaContext) \
|
||||
V(StoreGlobalViaContext) \
|
||||
@ -709,15 +708,6 @@ class ApiGetterDescriptor : public CallInterfaceDescriptor {
|
||||
};
|
||||
|
||||
|
||||
class ArgumentsAccessReadDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DECLARE_DESCRIPTOR(ArgumentsAccessReadDescriptor, CallInterfaceDescriptor)
|
||||
|
||||
static const Register index();
|
||||
static const Register parameter_count();
|
||||
};
|
||||
|
||||
|
||||
class ArgumentsAccessNewDescriptor : public CallInterfaceDescriptor {
|
||||
public:
|
||||
DECLARE_DESCRIPTOR_WITH_CUSTOM_FUNCTION_TYPE(ArgumentsAccessNewDescriptor,
|
||||
|
@ -1591,59 +1591,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
// The displacement is the offset of the last parameter (if any)
|
||||
// relative to the frame pointer.
|
||||
const int kDisplacement =
|
||||
StandardFrameConstants::kCallerSPOffset - kPointerSize;
|
||||
DCHECK(a1.is(ArgumentsAccessReadDescriptor::index()));
|
||||
DCHECK(a0.is(ArgumentsAccessReadDescriptor::parameter_count()));
|
||||
|
||||
// Check that the key is a smiGenerateReadElement.
|
||||
Label slow;
|
||||
__ JumpIfNotSmi(a1, &slow);
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label adaptor;
|
||||
__ lw(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ lw(a3, MemOperand(a2, StandardFrameConstants::kContextOffset));
|
||||
__ Branch(&adaptor,
|
||||
eq,
|
||||
a3,
|
||||
Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||
|
||||
// Check index (a1) against formal parameters count limit passed in
|
||||
// through register a0. Use unsigned comparison to get negative
|
||||
// check for free.
|
||||
__ Branch(&slow, hs, a1, Operand(a0));
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
__ subu(a3, a0, a1);
|
||||
__ Lsa(a3, fp, a3, kPointerSizeLog2 - kSmiTagSize);
|
||||
__ Ret(USE_DELAY_SLOT);
|
||||
__ lw(v0, MemOperand(a3, kDisplacement));
|
||||
|
||||
// Arguments adaptor case: Check index (a1) against actual arguments
|
||||
// limit found in the arguments adaptor frame. Use unsigned
|
||||
// comparison to get negative check for free.
|
||||
__ bind(&adaptor);
|
||||
__ lw(a0, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ Branch(&slow, Ugreater_equal, a1, Operand(a0));
|
||||
|
||||
// Read the argument from the adaptor frame and return it.
|
||||
__ subu(a3, a0, a1);
|
||||
__ Lsa(a3, a2, a3, kPointerSizeLog2 - kSmiTagSize);
|
||||
__ Ret(USE_DELAY_SLOT);
|
||||
__ lw(v0, MemOperand(a3, kDisplacement));
|
||||
|
||||
// Slow-case: Handle non-smi or out-of-bounds access to arguments
|
||||
// by calling the runtime system.
|
||||
__ bind(&slow);
|
||||
__ push(a1);
|
||||
__ TailCallRuntime(Runtime::kArguments);
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
|
||||
// a1 : function
|
||||
// a2 : number of parameters (tagged)
|
||||
|
@ -54,10 +54,6 @@ const Register StringCompareDescriptor::LeftRegister() { return a1; }
|
||||
const Register StringCompareDescriptor::RightRegister() { return a0; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessReadDescriptor::index() { return a1; }
|
||||
const Register ArgumentsAccessReadDescriptor::parameter_count() { return a0; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessNewDescriptor::function() { return a1; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_count() { return a2; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_pointer() { return a3; }
|
||||
|
@ -1587,61 +1587,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
// The displacement is the offset of the last parameter (if any)
|
||||
// relative to the frame pointer.
|
||||
const int kDisplacement =
|
||||
StandardFrameConstants::kCallerSPOffset - kPointerSize;
|
||||
DCHECK(a1.is(ArgumentsAccessReadDescriptor::index()));
|
||||
DCHECK(a0.is(ArgumentsAccessReadDescriptor::parameter_count()));
|
||||
|
||||
// Check that the key is a smiGenerateReadElement.
|
||||
Label slow;
|
||||
__ JumpIfNotSmi(a1, &slow);
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label adaptor;
|
||||
__ ld(a2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ ld(a3, MemOperand(a2, StandardFrameConstants::kContextOffset));
|
||||
__ Branch(&adaptor,
|
||||
eq,
|
||||
a3,
|
||||
Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||
|
||||
// Check index (a1) against formal parameters count limit passed in
|
||||
// through register a0. Use unsigned comparison to get negative
|
||||
// check for free.
|
||||
__ Branch(&slow, hs, a1, Operand(a0));
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
__ dsubu(a3, a0, a1);
|
||||
__ SmiScale(a7, a3, kPointerSizeLog2);
|
||||
__ Daddu(a3, fp, Operand(a7));
|
||||
__ Ret(USE_DELAY_SLOT);
|
||||
__ ld(v0, MemOperand(a3, kDisplacement));
|
||||
|
||||
// Arguments adaptor case: Check index (a1) against actual arguments
|
||||
// limit found in the arguments adaptor frame. Use unsigned
|
||||
// comparison to get negative check for free.
|
||||
__ bind(&adaptor);
|
||||
__ ld(a0, MemOperand(a2, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ Branch(&slow, Ugreater_equal, a1, Operand(a0));
|
||||
|
||||
// Read the argument from the adaptor frame and return it.
|
||||
__ dsubu(a3, a0, a1);
|
||||
__ SmiScale(a7, a3, kPointerSizeLog2);
|
||||
__ Daddu(a3, a2, Operand(a7));
|
||||
__ Ret(USE_DELAY_SLOT);
|
||||
__ ld(v0, MemOperand(a3, kDisplacement));
|
||||
|
||||
// Slow-case: Handle non-smi or out-of-bounds access to arguments
|
||||
// by calling the runtime system.
|
||||
__ bind(&slow);
|
||||
__ push(a1);
|
||||
__ TailCallRuntime(Runtime::kArguments);
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
|
||||
// a1 : function
|
||||
// a2 : number of parameters (tagged)
|
||||
|
@ -54,10 +54,6 @@ const Register StringCompareDescriptor::LeftRegister() { return a1; }
|
||||
const Register StringCompareDescriptor::RightRegister() { return a0; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessReadDescriptor::index() { return a1; }
|
||||
const Register ArgumentsAccessReadDescriptor::parameter_count() { return a0; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessNewDescriptor::function() { return a1; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_count() { return a2; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_pointer() { return a3; }
|
||||
|
@ -1540,62 +1540,6 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
// The displacement is the offset of the last parameter (if any)
|
||||
// relative to the frame pointer.
|
||||
const int kDisplacement =
|
||||
StandardFrameConstants::kCallerSPOffset - kPointerSize;
|
||||
DCHECK(r4.is(ArgumentsAccessReadDescriptor::index()));
|
||||
DCHECK(r3.is(ArgumentsAccessReadDescriptor::parameter_count()));
|
||||
|
||||
// Check that the key is a smi.
|
||||
Label slow;
|
||||
__ JumpIfNotSmi(r4, &slow);
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label adaptor;
|
||||
__ LoadP(r5, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ LoadP(r6, MemOperand(r5, StandardFrameConstants::kContextOffset));
|
||||
STATIC_ASSERT(StackFrame::ARGUMENTS_ADAPTOR < 0x3fffu);
|
||||
__ CmpSmiLiteral(r6, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
|
||||
__ beq(&adaptor);
|
||||
|
||||
// Check index against formal parameters count limit passed in
|
||||
// through register r3. Use unsigned comparison to get negative
|
||||
// check for free.
|
||||
__ cmpl(r4, r3);
|
||||
__ bge(&slow);
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
__ sub(r6, r3, r4);
|
||||
__ SmiToPtrArrayOffset(r6, r6);
|
||||
__ add(r6, fp, r6);
|
||||
__ LoadP(r3, MemOperand(r6, kDisplacement));
|
||||
__ blr();
|
||||
|
||||
// Arguments adaptor case: Check index against actual arguments
|
||||
// limit found in the arguments adaptor frame. Use unsigned
|
||||
// comparison to get negative check for free.
|
||||
__ bind(&adaptor);
|
||||
__ LoadP(r3, MemOperand(r5, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ cmpl(r4, r3);
|
||||
__ bge(&slow);
|
||||
|
||||
// Read the argument from the adaptor frame and return it.
|
||||
__ sub(r6, r3, r4);
|
||||
__ SmiToPtrArrayOffset(r6, r6);
|
||||
__ add(r6, r5, r6);
|
||||
__ LoadP(r3, MemOperand(r6, kDisplacement));
|
||||
__ blr();
|
||||
|
||||
// Slow-case: Handle non-smi or out-of-bounds access to arguments
|
||||
// by calling the runtime system.
|
||||
__ bind(&slow);
|
||||
__ push(r4);
|
||||
__ TailCallRuntime(Runtime::kArguments);
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
|
||||
// r4 : function
|
||||
// r5 : number of parameters (tagged)
|
||||
|
@ -54,10 +54,6 @@ const Register StringCompareDescriptor::LeftRegister() { return r4; }
|
||||
const Register StringCompareDescriptor::RightRegister() { return r3; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessReadDescriptor::index() { return r4; }
|
||||
const Register ArgumentsAccessReadDescriptor::parameter_count() { return r3; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessNewDescriptor::function() { return r4; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_count() { return r5; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_pointer() { return r6; }
|
||||
|
@ -1137,88 +1137,5 @@ RUNTIME_FUNCTION(Runtime_StoreLookupSlot_Strict) {
|
||||
return *value;
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_ArgumentsLength) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 0);
|
||||
int argument_count = 0;
|
||||
GetCallerArguments(isolate, &argument_count);
|
||||
return Smi::FromInt(argument_count);
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_Arguments) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
CONVERT_ARG_HANDLE_CHECKED(Object, raw_key, 0);
|
||||
|
||||
// Determine the actual arguments passed to the function.
|
||||
int argument_count_signed = 0;
|
||||
base::SmartArrayPointer<Handle<Object>> arguments =
|
||||
GetCallerArguments(isolate, &argument_count_signed);
|
||||
const uint32_t argument_count = argument_count_signed;
|
||||
|
||||
// Try to convert the key to an index. If successful and within
|
||||
// index return the the argument from the frame.
|
||||
uint32_t index = 0;
|
||||
if (raw_key->ToArrayIndex(&index) && index < argument_count) {
|
||||
return *arguments[index];
|
||||
}
|
||||
|
||||
if (raw_key->IsSymbol()) {
|
||||
Handle<Symbol> symbol = Handle<Symbol>::cast(raw_key);
|
||||
if (Name::Equals(symbol, isolate->factory()->iterator_symbol())) {
|
||||
return isolate->native_context()->array_values_iterator();
|
||||
}
|
||||
// Lookup in the initial Object.prototype object.
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result,
|
||||
Object::GetProperty(isolate->initial_object_prototype(),
|
||||
Handle<Symbol>::cast(raw_key)));
|
||||
return *result;
|
||||
}
|
||||
|
||||
// Convert the key to a string.
|
||||
Handle<Object> converted;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, converted,
|
||||
Object::ToString(isolate, raw_key));
|
||||
Handle<String> key = Handle<String>::cast(converted);
|
||||
|
||||
// Try to convert the string key into an array index.
|
||||
if (key->AsArrayIndex(&index)) {
|
||||
if (index < argument_count) {
|
||||
return *arguments[index];
|
||||
} else {
|
||||
Handle<Object> initial_prototype(isolate->initial_object_prototype());
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result,
|
||||
Object::GetElement(isolate, initial_prototype, index));
|
||||
return *result;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle special arguments properties.
|
||||
if (String::Equals(isolate->factory()->length_string(), key)) {
|
||||
return Smi::FromInt(argument_count);
|
||||
}
|
||||
if (String::Equals(isolate->factory()->callee_string(), key)) {
|
||||
JavaScriptFrameIterator it(isolate);
|
||||
JSFunction* function = it.frame()->function();
|
||||
if (is_strict(function->shared()->language_mode())) {
|
||||
THROW_NEW_ERROR_RETURN_FAILURE(
|
||||
isolate, NewTypeError(MessageTemplate::kStrictPoisonPill));
|
||||
}
|
||||
return function;
|
||||
}
|
||||
|
||||
// Lookup in the initial Object.prototype object.
|
||||
Handle<Object> result;
|
||||
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
|
||||
isolate, result,
|
||||
Object::GetProperty(isolate->initial_object_prototype(), key));
|
||||
return *result;
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -562,9 +562,7 @@ namespace internal {
|
||||
F(LoadLookupSlot, 1, 1) \
|
||||
F(LoadLookupSlotInsideTypeof, 1, 1) \
|
||||
F(StoreLookupSlot_Sloppy, 2, 1) \
|
||||
F(StoreLookupSlot_Strict, 2, 1) \
|
||||
F(ArgumentsLength, 0, 1) \
|
||||
F(Arguments, 1, 1)
|
||||
F(StoreLookupSlot_Strict, 2, 1)
|
||||
|
||||
#define FOR_EACH_INTRINSIC_SIMD(F) \
|
||||
F(IsSimdValue, 1, 1) \
|
||||
|
@ -534,64 +534,6 @@ void FunctionPrototypeStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
// The key is in rdx and the parameter count is in rax.
|
||||
DCHECK(rdx.is(ArgumentsAccessReadDescriptor::index()));
|
||||
DCHECK(rax.is(ArgumentsAccessReadDescriptor::parameter_count()));
|
||||
|
||||
// Check that the key is a smi.
|
||||
Label slow;
|
||||
__ JumpIfNotSmi(rdx, &slow);
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame. We look at the
|
||||
// context offset, and if the frame is not a regular one, then we find a
|
||||
// Smi instead of the context. We can't use SmiCompare here, because that
|
||||
// only works for comparing two smis.
|
||||
Label adaptor;
|
||||
__ movp(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset),
|
||||
Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
|
||||
__ j(equal, &adaptor);
|
||||
|
||||
// Check index against formal parameters count limit passed in
|
||||
// through register rax. Use unsigned comparison to get negative
|
||||
// check for free.
|
||||
__ cmpp(rdx, rax);
|
||||
__ j(above_equal, &slow);
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
__ SmiSub(rax, rax, rdx);
|
||||
__ SmiToInteger32(rax, rax);
|
||||
StackArgumentsAccessor args(rbp, rax, ARGUMENTS_DONT_CONTAIN_RECEIVER);
|
||||
__ movp(rax, args.GetArgumentOperand(0));
|
||||
__ Ret();
|
||||
|
||||
// Arguments adaptor case: Check index against actual arguments
|
||||
// limit found in the arguments adaptor frame. Use unsigned
|
||||
// comparison to get negative check for free.
|
||||
__ bind(&adaptor);
|
||||
__ movp(rcx, Operand(rbx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ cmpp(rdx, rcx);
|
||||
__ j(above_equal, &slow);
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
__ SmiSub(rcx, rcx, rdx);
|
||||
__ SmiToInteger32(rcx, rcx);
|
||||
StackArgumentsAccessor adaptor_args(rbx, rcx,
|
||||
ARGUMENTS_DONT_CONTAIN_RECEIVER);
|
||||
__ movp(rax, adaptor_args.GetArgumentOperand(0));
|
||||
__ Ret();
|
||||
|
||||
// Slow-case: Handle non-smi or out-of-bounds access to arguments
|
||||
// by calling the runtime system.
|
||||
__ bind(&slow);
|
||||
__ PopReturnAddressTo(rbx);
|
||||
__ Push(rdx);
|
||||
__ PushReturnAddressFrom(rbx);
|
||||
__ TailCallRuntime(Runtime::kArguments);
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateNewSloppyFast(MacroAssembler* masm) {
|
||||
// rcx : number of parameters (tagged)
|
||||
// rdx : parameters pointer
|
||||
|
@ -54,10 +54,6 @@ const Register StringCompareDescriptor::LeftRegister() { return rdx; }
|
||||
const Register StringCompareDescriptor::RightRegister() { return rax; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessReadDescriptor::index() { return rdx; }
|
||||
const Register ArgumentsAccessReadDescriptor::parameter_count() { return rax; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessNewDescriptor::function() { return rdi; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_count() { return rcx; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_pointer() { return rdx; }
|
||||
|
@ -429,67 +429,6 @@ void LoadIndexedStringStub::Generate(MacroAssembler* masm) {
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
|
||||
// The key is in edx and the parameter count is in eax.
|
||||
DCHECK(edx.is(ArgumentsAccessReadDescriptor::index()));
|
||||
DCHECK(eax.is(ArgumentsAccessReadDescriptor::parameter_count()));
|
||||
|
||||
// The displacement is used for skipping the frame pointer on the
|
||||
// stack. It is the offset of the last parameter (if any) relative
|
||||
// to the frame pointer.
|
||||
static const int kDisplacement = 1 * kPointerSize;
|
||||
|
||||
// Check that the key is a smi.
|
||||
Label slow;
|
||||
__ JumpIfNotSmi(edx, &slow, Label::kNear);
|
||||
|
||||
// Check if the calling frame is an arguments adaptor frame.
|
||||
Label adaptor;
|
||||
__ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
|
||||
__ mov(ecx, Operand(ebx, StandardFrameConstants::kContextOffset));
|
||||
__ cmp(ecx, Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
|
||||
__ j(equal, &adaptor, Label::kNear);
|
||||
|
||||
// Check index against formal parameters count limit passed in
|
||||
// through register eax. Use unsigned comparison to get negative
|
||||
// check for free.
|
||||
__ cmp(edx, eax);
|
||||
__ j(above_equal, &slow, Label::kNear);
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
STATIC_ASSERT(kSmiTagSize == 1);
|
||||
STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these.
|
||||
__ lea(ebx, Operand(ebp, eax, times_2, 0));
|
||||
__ neg(edx);
|
||||
__ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
|
||||
__ ret(0);
|
||||
|
||||
// Arguments adaptor case: Check index against actual arguments
|
||||
// limit found in the arguments adaptor frame. Use unsigned
|
||||
// comparison to get negative check for free.
|
||||
__ bind(&adaptor);
|
||||
__ mov(ecx, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||
__ cmp(edx, ecx);
|
||||
__ j(above_equal, &slow, Label::kNear);
|
||||
|
||||
// Read the argument from the stack and return it.
|
||||
STATIC_ASSERT(kSmiTagSize == 1);
|
||||
STATIC_ASSERT(kSmiTag == 0); // Shifting code depends on these.
|
||||
__ lea(ebx, Operand(ebx, ecx, times_2, 0));
|
||||
__ neg(edx);
|
||||
__ mov(eax, Operand(ebx, edx, times_2, kDisplacement));
|
||||
__ ret(0);
|
||||
|
||||
// Slow-case: Handle non-smi or out-of-bounds access to arguments
|
||||
// by calling the runtime system.
|
||||
__ bind(&slow);
|
||||
__ pop(ebx); // Return address.
|
||||
__ push(edx);
|
||||
__ push(ebx);
|
||||
__ TailCallRuntime(Runtime::kArguments);
|
||||
}
|
||||
|
||||
|
||||
void ArgumentsAccessStub::GenerateNewSloppySlow(MacroAssembler* masm) {
|
||||
// ecx : number of parameters (tagged)
|
||||
// edx : parameters pointer
|
||||
|
@ -59,10 +59,6 @@ const Register StringCompareDescriptor::LeftRegister() { return edx; }
|
||||
const Register StringCompareDescriptor::RightRegister() { return eax; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessReadDescriptor::index() { return edx; }
|
||||
const Register ArgumentsAccessReadDescriptor::parameter_count() { return eax; }
|
||||
|
||||
|
||||
const Register ArgumentsAccessNewDescriptor::function() { return edi; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_count() { return ecx; }
|
||||
const Register ArgumentsAccessNewDescriptor::parameter_pointer() { return edx; }
|
||||
|
@ -1,132 +0,0 @@
|
||||
// Copyright 2008 the V8 project authors. All rights reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Flags: --allow-natives-syntax
|
||||
|
||||
function L0() {
|
||||
return %_ArgumentsLength();
|
||||
}
|
||||
|
||||
function L1(a) {
|
||||
return %_ArgumentsLength();
|
||||
}
|
||||
|
||||
function L5(a,b,c,d,e) {
|
||||
return %_ArgumentsLength();
|
||||
}
|
||||
|
||||
|
||||
assertEquals(0, L0());
|
||||
assertEquals(1, L0(1));
|
||||
assertEquals(2, L0(1,2));
|
||||
assertEquals(5, L0(1,2,3,4,5));
|
||||
|
||||
assertEquals(0, L1());
|
||||
assertEquals(1, L1(1));
|
||||
assertEquals(2, L1(1,2));
|
||||
assertEquals(5, L1(1,2,3,4,5));
|
||||
|
||||
assertEquals(0, L5());
|
||||
assertEquals(1, L5(1));
|
||||
assertEquals(2, L5(1,2));
|
||||
assertEquals(5, L5(1,2,3,4,5));
|
||||
|
||||
|
||||
function A(key) {
|
||||
return %_Arguments(key);
|
||||
}
|
||||
|
||||
// Integer access.
|
||||
assertEquals(0, A(0));
|
||||
assertEquals(0, A(0,1));
|
||||
assertEquals(2, A(1,2));
|
||||
assertEquals(2, A(1,2,3,4,5));
|
||||
assertEquals(5, A(4,2,3,4,5));
|
||||
assertTrue(typeof A(1) == 'undefined');
|
||||
assertTrue(typeof A(3,2,1) == 'undefined');
|
||||
|
||||
// Out-of-bounds integer access with and without argument
|
||||
// adaptor frames.
|
||||
assertTrue(typeof(A(-10000)) == 'undefined');
|
||||
assertTrue(typeof(A(-10000, 0)) == 'undefined');
|
||||
assertTrue(typeof(A(-1)) == 'undefined');
|
||||
assertTrue(typeof(A(-1, 0)) == 'undefined');
|
||||
assertTrue(typeof(A(10000)) == 'undefined');
|
||||
assertTrue(typeof(A(10000, 0)) == 'undefined');
|
||||
|
||||
// String access.
|
||||
assertEquals('0', A('0'));
|
||||
assertEquals('0', A('0',1));
|
||||
assertEquals(2, A('1',2));
|
||||
assertEquals(2, A('1',2,3,4,5));
|
||||
assertEquals(5, A('4',2,3,4,5));
|
||||
assertEquals('undefined', typeof A('1'));
|
||||
assertEquals('undefined', typeof A('3',2,1));
|
||||
assertEquals(A, A('callee'));
|
||||
assertEquals(1, A('length'));
|
||||
assertEquals(2, A('length',2));
|
||||
assertEquals(5, A('length',2,3,4,5));
|
||||
assertEquals({}.toString, A('toString'));
|
||||
assertEquals({}.isPrototypeOf, A('isPrototypeOf'));
|
||||
assertEquals('undefined', typeof A('xxx'));
|
||||
|
||||
// Object access.
|
||||
function O(key) {
|
||||
return { toString: function() { return key; } };
|
||||
}
|
||||
|
||||
var O0 = O(0);
|
||||
assertSame(O0, A(O0));
|
||||
assertSame(O0, A(O0,1));
|
||||
assertEquals(2, A(O(1),2));
|
||||
assertEquals(2, A(O(1),2,3,4,5));
|
||||
assertEquals(5, A(O(4),2,3,4,5));
|
||||
assertTrue(typeof A(O(1)) == 'undefined');
|
||||
assertTrue(typeof A(O(3),2,1) == 'undefined');
|
||||
|
||||
O0 = O('0');
|
||||
assertSame(O0, A(O0));
|
||||
assertSame(O0, A(O0,1));
|
||||
assertEquals(2, A(O('1'),2));
|
||||
assertEquals(2, A(O('1'),2,3,4,5));
|
||||
assertEquals(5, A(O('4'),2,3,4,5));
|
||||
assertTrue(typeof A(O('1')) == 'undefined');
|
||||
assertTrue(typeof A(O('3'),2,1) == 'undefined');
|
||||
assertEquals(A, A(O('callee')));
|
||||
assertEquals(1, A(O('length')));
|
||||
assertEquals(2, A(O('length'),2));
|
||||
assertEquals(5, A(O('length'),2,3,4,5));
|
||||
assertEquals({}.toString, A(O('toString')));
|
||||
assertEquals({}.isPrototypeOf, A(O('isPrototypeOf')));
|
||||
assertTrue(typeof A(O('xxx')) == 'undefined');
|
||||
|
||||
// Make sure that out-of-bounds access do lookups in the
|
||||
// prototype chain.
|
||||
Object.prototype[5] = 42;
|
||||
assertEquals(42, A(5));
|
||||
Object.prototype[-5] = 87;
|
||||
assertEquals(87, A(-5));
|
@ -309,29 +309,3 @@ test_toarr(toarr2);
|
||||
delete forceDeopt.deopt;
|
||||
outer();
|
||||
})();
|
||||
|
||||
|
||||
// Test inlining of functions with %_Arguments and %_ArgumentsLength intrinsic.
|
||||
(function () {
|
||||
function inner(len,a,b,c) {
|
||||
assertSame(len, %_ArgumentsLength());
|
||||
for (var i = 1; i < len; ++i) {
|
||||
var c = String.fromCharCode(96 + i);
|
||||
assertSame(c, %_Arguments(i));
|
||||
}
|
||||
}
|
||||
|
||||
function outer() {
|
||||
inner(1);
|
||||
inner(2, 'a');
|
||||
inner(3, 'a', 'b');
|
||||
inner(4, 'a', 'b', 'c');
|
||||
inner(5, 'a', 'b', 'c', 'd');
|
||||
inner(6, 'a', 'b', 'c', 'd', 'e');
|
||||
}
|
||||
|
||||
outer();
|
||||
outer();
|
||||
%OptimizeFunctionOnNextCall(outer);
|
||||
outer();
|
||||
})();
|
||||
|
@ -35,18 +35,18 @@ function ToNumber(x) {
|
||||
// Reduced version of String.fromCharCode;
|
||||
// does not actually do the same calculation but exhibits untagging bug.
|
||||
function StringFromCharCode(code) {
|
||||
var n = %_ArgumentsLength();
|
||||
var n = arguments.length;
|
||||
var one_byte = %NewString(n, true);
|
||||
var i;
|
||||
for (i = 0; i < n; i++) {
|
||||
var code = %_Arguments(i);
|
||||
var code = arguments[i];
|
||||
if (!%_IsSmi(code)) code = ToNumber(code) & 0xffff;
|
||||
if (code > 0xff) break;
|
||||
}
|
||||
|
||||
var two_byte = %NewString(n - i, false);
|
||||
for (var j = 0; i < n; i++, j++) {
|
||||
var code = %_Arguments(i);
|
||||
var code = arguments[i];
|
||||
%_TwoByteSeqStringSetChar(j, code, two_byte);
|
||||
}
|
||||
return one_byte + two_byte;
|
||||
|
Loading…
Reference in New Issue
Block a user