Change CallIC interface on ARM. Remove name from the stack, and pass it in register r2.
Review URL: http://codereview.chromium.org/598065 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3856 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
976ab7d7b5
commit
58b04396bf
@ -915,7 +915,7 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2. Get the function to call from the stack.
|
// 2. Get the function to call from the stack.
|
||||||
// r0: actual number of argument
|
// r0: actual number of arguments
|
||||||
{ Label done, non_function, function;
|
{ Label done, non_function, function;
|
||||||
__ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
|
__ ldr(r1, MemOperand(sp, r0, LSL, kPointerSizeLog2));
|
||||||
__ tst(r1, Operand(kSmiTagMask));
|
__ tst(r1, Operand(kSmiTagMask));
|
||||||
@ -997,13 +997,27 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
|||||||
__ bind(&done);
|
__ bind(&done);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. Shift stuff one slot down the stack
|
// 4. Handle non-functions.
|
||||||
// r0: actual number of arguments (including call() receiver)
|
// r0: actual number of arguments (including call() receiver)
|
||||||
// r1: function
|
// r1: function
|
||||||
|
{ Label done;
|
||||||
|
__ tst(r1, r1);
|
||||||
|
__ b(ne, &done);
|
||||||
|
__ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION
|
||||||
|
// Transfer the receiver from the first argument to the top of the
|
||||||
|
// caller's expression stack simply by decrementing argc.
|
||||||
|
__ sub(r0, r0, Operand(1));
|
||||||
|
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
|
||||||
|
__ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
|
||||||
|
RelocInfo::CODE_TARGET);
|
||||||
|
__ bind(&done);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Shift arguments one slot toward the bottom of the
|
||||||
|
// stack, overwriting the receiver.
|
||||||
{ Label loop;
|
{ Label loop;
|
||||||
// Calculate the copy start address (destination). Copy end address is sp.
|
// Calculate the copy start address (destination). Copy end address is sp.
|
||||||
__ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
|
__ add(r2, sp, Operand(r0, LSL, kPointerSizeLog2));
|
||||||
__ add(r2, r2, Operand(kPointerSize)); // copy receiver too
|
|
||||||
|
|
||||||
__ bind(&loop);
|
__ bind(&loop);
|
||||||
__ ldr(ip, MemOperand(r2, -kPointerSize));
|
__ ldr(ip, MemOperand(r2, -kPointerSize));
|
||||||
@ -1011,43 +1025,28 @@ void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
|
|||||||
__ sub(r2, r2, Operand(kPointerSize));
|
__ sub(r2, r2, Operand(kPointerSize));
|
||||||
__ cmp(r2, sp);
|
__ cmp(r2, sp);
|
||||||
__ b(ne, &loop);
|
__ b(ne, &loop);
|
||||||
|
// Adjust the actual number of arguments and remove the top element.
|
||||||
|
__ sub(r0, r0, Operand(1));
|
||||||
|
__ pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. Adjust the actual number of arguments and remove the top element.
|
|
||||||
// r0: actual number of arguments (including call() receiver)
|
|
||||||
// r1: function
|
|
||||||
__ sub(r0, r0, Operand(1));
|
|
||||||
__ add(sp, sp, Operand(kPointerSize));
|
|
||||||
|
|
||||||
// 6. Get the code for the function or the non-function builtin.
|
// 6. Get the code for the function or the non-function builtin.
|
||||||
// If number of expected arguments matches, then call. Otherwise restart
|
// If number of expected arguments matches, then call. Otherwise restart
|
||||||
// the arguments adaptor stub.
|
// the arguments adaptor stub.
|
||||||
// r0: actual number of arguments
|
// r0: actual number of arguments
|
||||||
// r1: function
|
// r1: function
|
||||||
{ Label invoke;
|
__ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
|
||||||
__ tst(r1, r1);
|
__ ldr(r2,
|
||||||
__ b(ne, &invoke);
|
FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset));
|
||||||
__ mov(r2, Operand(0)); // expected arguments is 0 for CALL_NON_FUNCTION
|
__ ldr(r3, FieldMemOperand(r3, SharedFunctionInfo::kCodeOffset));
|
||||||
__ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
|
__ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
|
||||||
__ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
|
__ cmp(r2, r0); // Check formal and actual parameter counts.
|
||||||
RelocInfo::CODE_TARGET);
|
__ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
|
||||||
|
RelocInfo::CODE_TARGET, ne);
|
||||||
|
|
||||||
__ bind(&invoke);
|
// 7. Jump (tail-call) to the code in r3 without checking arguments.
|
||||||
__ ldr(r3, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
|
ParameterCount expected(0);
|
||||||
__ ldr(r2,
|
__ InvokeCode(r3, expected, expected, JUMP_FUNCTION);
|
||||||
FieldMemOperand(r3,
|
|
||||||
SharedFunctionInfo::kFormalParameterCountOffset));
|
|
||||||
__ ldr(r3,
|
|
||||||
MemOperand(r3, SharedFunctionInfo::kCodeOffset - kHeapObjectTag));
|
|
||||||
__ add(r3, r3, Operand(Code::kHeaderSize - kHeapObjectTag));
|
|
||||||
__ cmp(r2, r0); // Check formal and actual parameter counts.
|
|
||||||
__ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
|
|
||||||
RelocInfo::CODE_TARGET, ne);
|
|
||||||
|
|
||||||
// 7. Jump to the code in r3 without checking arguments.
|
|
||||||
ParameterCount expected(0);
|
|
||||||
__ InvokeCode(r3, expected, expected, JUMP_FUNCTION);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3023,11 +3023,6 @@ void CodeGenerator::VisitCall(Call* node) {
|
|||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
// JavaScript example: 'foo(1, 2, 3)' // foo is global
|
// JavaScript example: 'foo(1, 2, 3)' // foo is global
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
|
|
||||||
// Push the name of the function and the receiver onto the stack.
|
|
||||||
__ mov(r0, Operand(var->name()));
|
|
||||||
frame_->EmitPush(r0);
|
|
||||||
|
|
||||||
// Pass the global object as the receiver and let the IC stub
|
// Pass the global object as the receiver and let the IC stub
|
||||||
// patch the stack to use the global proxy as 'this' in the
|
// patch the stack to use the global proxy as 'this' in the
|
||||||
// invoked function.
|
// invoked function.
|
||||||
@ -3039,15 +3034,14 @@ void CodeGenerator::VisitCall(Call* node) {
|
|||||||
LoadAndSpill(args->at(i));
|
LoadAndSpill(args->at(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup the receiver register and call the IC initialization code.
|
// Setup the name register and call the IC initialization code.
|
||||||
|
__ mov(r2, Operand(var->name()));
|
||||||
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
|
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
|
||||||
Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
|
Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
|
||||||
CodeForSourcePosition(node->position());
|
CodeForSourcePosition(node->position());
|
||||||
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT,
|
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT,
|
||||||
arg_count + 1);
|
arg_count + 1);
|
||||||
__ ldr(cp, frame_->Context());
|
__ ldr(cp, frame_->Context());
|
||||||
// Remove the function from the stack.
|
|
||||||
frame_->Drop();
|
|
||||||
frame_->EmitPush(r0);
|
frame_->EmitPush(r0);
|
||||||
|
|
||||||
} else if (var != NULL && var->slot() != NULL &&
|
} else if (var != NULL && var->slot() != NULL &&
|
||||||
@ -3080,28 +3074,21 @@ void CodeGenerator::VisitCall(Call* node) {
|
|||||||
// JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
|
// JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
|
|
||||||
// Push the name of the function and the receiver onto the stack.
|
LoadAndSpill(property->obj()); // Receiver.
|
||||||
__ mov(r0, Operand(literal->handle()));
|
|
||||||
frame_->EmitPush(r0);
|
|
||||||
LoadAndSpill(property->obj());
|
|
||||||
|
|
||||||
// Load the arguments.
|
// Load the arguments.
|
||||||
int arg_count = args->length();
|
int arg_count = args->length();
|
||||||
for (int i = 0; i < arg_count; i++) {
|
for (int i = 0; i < arg_count; i++) {
|
||||||
LoadAndSpill(args->at(i));
|
LoadAndSpill(args->at(i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the receiver register and call the IC initialization code.
|
// Set the name register and call the IC initialization code.
|
||||||
|
__ mov(r2, Operand(literal->handle()));
|
||||||
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
|
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
|
||||||
Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
|
Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
|
||||||
CodeForSourcePosition(node->position());
|
CodeForSourcePosition(node->position());
|
||||||
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
|
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
|
||||||
__ ldr(cp, frame_->Context());
|
__ ldr(cp, frame_->Context());
|
||||||
|
frame_->EmitPush(r0);
|
||||||
// Remove the function from the stack.
|
|
||||||
frame_->Drop();
|
|
||||||
|
|
||||||
frame_->EmitPush(r0); // push after get rid of function from the stack
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
@ -3636,8 +3623,6 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
|
|||||||
|
|
||||||
if (function == NULL) {
|
if (function == NULL) {
|
||||||
// Prepare stack for calling JS runtime function.
|
// Prepare stack for calling JS runtime function.
|
||||||
__ mov(r0, Operand(node->name()));
|
|
||||||
frame_->EmitPush(r0);
|
|
||||||
// Push the builtins object found in the current global object.
|
// Push the builtins object found in the current global object.
|
||||||
__ ldr(r1, GlobalObject());
|
__ ldr(r1, GlobalObject());
|
||||||
__ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
|
__ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
|
||||||
@ -3652,11 +3637,11 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
|
|||||||
|
|
||||||
if (function == NULL) {
|
if (function == NULL) {
|
||||||
// Call the JS runtime function.
|
// Call the JS runtime function.
|
||||||
|
__ mov(r2, Operand(node->name()));
|
||||||
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
|
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
|
||||||
Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
|
Handle<Code> stub = ComputeCallInitialize(arg_count, in_loop);
|
||||||
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
|
frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
|
||||||
__ ldr(cp, frame_->Context());
|
__ ldr(cp, frame_->Context());
|
||||||
frame_->Drop();
|
|
||||||
frame_->EmitPush(r0);
|
frame_->EmitPush(r0);
|
||||||
} else {
|
} else {
|
||||||
// Call the C runtime function.
|
// Call the C runtime function.
|
||||||
|
@ -1090,7 +1090,7 @@ void FullCodeGenerator::VisitProperty(Property* expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FullCodeGenerator::EmitCallWithIC(Call* expr,
|
void FullCodeGenerator::EmitCallWithIC(Call* expr,
|
||||||
Handle<Object> ignored,
|
Handle<Object> name,
|
||||||
RelocInfo::Mode mode) {
|
RelocInfo::Mode mode) {
|
||||||
// Code common for calls using the IC.
|
// Code common for calls using the IC.
|
||||||
ZoneList<Expression*>* args = expr->arguments();
|
ZoneList<Expression*>* args = expr->arguments();
|
||||||
@ -1098,16 +1098,16 @@ void FullCodeGenerator::EmitCallWithIC(Call* expr,
|
|||||||
for (int i = 0; i < arg_count; i++) {
|
for (int i = 0; i < arg_count; i++) {
|
||||||
VisitForValue(args->at(i), kStack);
|
VisitForValue(args->at(i), kStack);
|
||||||
}
|
}
|
||||||
|
__ mov(r2, Operand(name));
|
||||||
// Record source position for debugger.
|
// Record source position for debugger.
|
||||||
SetSourcePosition(expr->position());
|
SetSourcePosition(expr->position());
|
||||||
// Call the IC initialization code.
|
// Call the IC initialization code.
|
||||||
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
|
InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
|
||||||
NOT_IN_LOOP);
|
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
|
||||||
__ Call(ic, mode);
|
__ Call(ic, mode);
|
||||||
// Restore context register.
|
// Restore context register.
|
||||||
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
// Discard the function left on TOS.
|
Apply(context_, r0);
|
||||||
DropAndApply(1, context_, r0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1124,7 +1124,6 @@ void FullCodeGenerator::EmitCallWithStub(Call* expr) {
|
|||||||
__ CallStub(&stub);
|
__ CallStub(&stub);
|
||||||
// Restore context register.
|
// Restore context register.
|
||||||
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
// Discard the function left on TOS.
|
|
||||||
DropAndApply(1, context_, r0);
|
DropAndApply(1, context_, r0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1138,11 +1137,9 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|||||||
// Call to the identifier 'eval'.
|
// Call to the identifier 'eval'.
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
} else if (var != NULL && !var->is_this() && var->is_global()) {
|
} else if (var != NULL && !var->is_this() && var->is_global()) {
|
||||||
// Call to a global variable.
|
// Push global object as receiver for the call IC.
|
||||||
__ mov(r1, Operand(var->name()));
|
|
||||||
// Push global object as receiver for the call IC lookup.
|
|
||||||
__ ldr(r0, CodeGenerator::GlobalObject());
|
__ ldr(r0, CodeGenerator::GlobalObject());
|
||||||
__ stm(db_w, sp, r1.bit() | r0.bit());
|
__ push(r0);
|
||||||
EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
|
EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
|
||||||
} else if (var != NULL && var->slot() != NULL &&
|
} else if (var != NULL && var->slot() != NULL &&
|
||||||
var->slot()->type() == Slot::LOOKUP) {
|
var->slot()->type() == Slot::LOOKUP) {
|
||||||
@ -1154,8 +1151,6 @@ void FullCodeGenerator::VisitCall(Call* expr) {
|
|||||||
Literal* key = prop->key()->AsLiteral();
|
Literal* key = prop->key()->AsLiteral();
|
||||||
if (key != NULL && key->handle()->IsSymbol()) {
|
if (key != NULL && key->handle()->IsSymbol()) {
|
||||||
// Call to a named property, use call IC.
|
// Call to a named property, use call IC.
|
||||||
__ mov(r0, Operand(key->handle()));
|
|
||||||
__ push(r0);
|
|
||||||
VisitForValue(prop->obj(), kStack);
|
VisitForValue(prop->obj(), kStack);
|
||||||
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
|
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
|
||||||
} else {
|
} else {
|
||||||
@ -1241,10 +1236,9 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
|||||||
|
|
||||||
if (expr->is_jsruntime()) {
|
if (expr->is_jsruntime()) {
|
||||||
// Prepare for calling JS runtime function.
|
// Prepare for calling JS runtime function.
|
||||||
__ mov(r1, Operand(expr->name()));
|
|
||||||
__ ldr(r0, CodeGenerator::GlobalObject());
|
__ ldr(r0, CodeGenerator::GlobalObject());
|
||||||
__ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset));
|
__ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset));
|
||||||
__ stm(db_w, sp, r1.bit() | r0.bit());
|
__ push(r0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push the arguments ("left-to-right").
|
// Push the arguments ("left-to-right").
|
||||||
@ -1255,18 +1249,17 @@ void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
|
|||||||
|
|
||||||
if (expr->is_jsruntime()) {
|
if (expr->is_jsruntime()) {
|
||||||
// Call the JS runtime function.
|
// Call the JS runtime function.
|
||||||
|
__ mov(r2, Operand(expr->name()));
|
||||||
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
|
Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
|
||||||
NOT_IN_LOOP);
|
NOT_IN_LOOP);
|
||||||
__ Call(ic, RelocInfo::CODE_TARGET);
|
__ Call(ic, RelocInfo::CODE_TARGET);
|
||||||
// Restore context register.
|
// Restore context register.
|
||||||
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
__ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
|
||||||
// Discard the function left on TOS.
|
|
||||||
DropAndApply(1, context_, r0);
|
|
||||||
} else {
|
} else {
|
||||||
// Call the C runtime function.
|
// Call the C runtime function.
|
||||||
__ CallRuntime(expr->function(), arg_count);
|
__ CallRuntime(expr->function(), arg_count);
|
||||||
Apply(context_, r0);
|
|
||||||
}
|
}
|
||||||
|
Apply(context_, r0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ static void GenerateDictionaryLoad(MacroAssembler* masm,
|
|||||||
// r3 - used as temporary and to hold the capacity of the property
|
// r3 - used as temporary and to hold the capacity of the property
|
||||||
// dictionary.
|
// dictionary.
|
||||||
//
|
//
|
||||||
// r2 - holds the name of the property and is unchanges.
|
// r2 - holds the name of the property and is unchanged.
|
||||||
|
|
||||||
Label done;
|
Label done;
|
||||||
|
|
||||||
@ -219,14 +219,13 @@ Object* CallIC_Miss(Arguments args);
|
|||||||
|
|
||||||
void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- lr: return address
|
// -- r2 : name
|
||||||
|
// -- lr : return address
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label number, non_number, non_string, boolean, probe, miss;
|
Label number, non_number, non_string, boolean, probe, miss;
|
||||||
|
|
||||||
// Get the receiver of the function from the stack into r1.
|
// Get the receiver of the function from the stack into r1.
|
||||||
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
|
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
|
||||||
// Get the name of the function from the stack; 1 ~ receiver.
|
|
||||||
__ ldr(r2, MemOperand(sp, (argc + 1) * kPointerSize));
|
|
||||||
|
|
||||||
// Probe the stub cache.
|
// Probe the stub cache.
|
||||||
Code::Flags flags =
|
Code::Flags flags =
|
||||||
@ -301,9 +300,9 @@ static void GenerateNormalHelper(MacroAssembler* masm,
|
|||||||
|
|
||||||
// Patch the receiver with the global proxy if necessary.
|
// Patch the receiver with the global proxy if necessary.
|
||||||
if (is_global_object) {
|
if (is_global_object) {
|
||||||
__ ldr(r2, MemOperand(sp, argc * kPointerSize));
|
__ ldr(r0, MemOperand(sp, argc * kPointerSize));
|
||||||
__ ldr(r2, FieldMemOperand(r2, GlobalObject::kGlobalReceiverOffset));
|
__ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalReceiverOffset));
|
||||||
__ str(r2, MemOperand(sp, argc * kPointerSize));
|
__ str(r0, MemOperand(sp, argc * kPointerSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invoke the function.
|
// Invoke the function.
|
||||||
@ -314,14 +313,13 @@ static void GenerateNormalHelper(MacroAssembler* masm,
|
|||||||
|
|
||||||
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
|
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- lr: return address
|
// -- r2 : name
|
||||||
|
// -- lr : return address
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label miss, global_object, non_global_object;
|
Label miss, global_object, non_global_object;
|
||||||
|
|
||||||
// Get the receiver of the function from the stack into r1.
|
// Get the receiver of the function from the stack into r1.
|
||||||
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
|
__ ldr(r1, MemOperand(sp, argc * kPointerSize));
|
||||||
// Get the name of the function from the stack; 1 ~ receiver.
|
|
||||||
__ ldr(r2, MemOperand(sp, (argc + 1) * kPointerSize));
|
|
||||||
|
|
||||||
// Check that the receiver isn't a smi.
|
// Check that the receiver isn't a smi.
|
||||||
__ tst(r1, Operand(kSmiTagMask));
|
__ tst(r1, Operand(kSmiTagMask));
|
||||||
@ -374,18 +372,17 @@ void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
|
|||||||
|
|
||||||
void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
|
void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- lr: return address
|
// -- r2 : name
|
||||||
|
// -- lr : return address
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
|
|
||||||
// Get the receiver of the function from the stack.
|
// Get the receiver of the function from the stack.
|
||||||
__ ldr(r2, MemOperand(sp, argc * kPointerSize));
|
__ ldr(r3, MemOperand(sp, argc * kPointerSize));
|
||||||
// Get the name of the function to call from the stack.
|
|
||||||
__ ldr(r1, MemOperand(sp, (argc + 1) * kPointerSize));
|
|
||||||
|
|
||||||
__ EnterInternalFrame();
|
__ EnterInternalFrame();
|
||||||
|
|
||||||
// Push the receiver and the name of the function.
|
// Push the receiver and the name of the function.
|
||||||
__ stm(db_w, sp, r1.bit() | r2.bit());
|
__ stm(db_w, sp, r2.bit() | r3.bit());
|
||||||
|
|
||||||
// Call the entry.
|
// Call the entry.
|
||||||
__ mov(r0, Operand(2));
|
__ mov(r0, Operand(2));
|
||||||
|
@ -376,7 +376,7 @@ static void GenerateCallFunction(MacroAssembler* masm,
|
|||||||
|
|
||||||
// Check that the function really is a function.
|
// Check that the function really is a function.
|
||||||
__ BranchOnSmi(r1, miss);
|
__ BranchOnSmi(r1, miss);
|
||||||
__ CompareObjectType(r1, r2, r2, JS_FUNCTION_TYPE);
|
__ CompareObjectType(r1, r3, r3, JS_FUNCTION_TYPE);
|
||||||
__ b(ne, miss);
|
__ b(ne, miss);
|
||||||
|
|
||||||
// Patch the receiver on the stack with the global proxy if
|
// Patch the receiver on the stack with the global proxy if
|
||||||
@ -803,7 +803,8 @@ Object* CallStubCompiler::CompileCallField(Object* object,
|
|||||||
int index,
|
int index,
|
||||||
String* name) {
|
String* name) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- lr: return address
|
// -- r2 : name
|
||||||
|
// -- lr : return address
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
@ -817,7 +818,7 @@ Object* CallStubCompiler::CompileCallField(Object* object,
|
|||||||
|
|
||||||
// Do the right check and compute the holder register.
|
// Do the right check and compute the holder register.
|
||||||
Register reg =
|
Register reg =
|
||||||
CheckPrototypes(JSObject::cast(object), r0, holder, r3, r2, name, &miss);
|
CheckPrototypes(JSObject::cast(object), r0, holder, r1, r3, name, &miss);
|
||||||
GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
|
GenerateFastPropertyLoad(masm(), r1, reg, holder, index);
|
||||||
|
|
||||||
GenerateCallFunction(masm(), object, arguments(), &miss);
|
GenerateCallFunction(masm(), object, arguments(), &miss);
|
||||||
@ -838,7 +839,8 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
|
|||||||
String* name,
|
String* name,
|
||||||
CheckType check) {
|
CheckType check) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- lr: return address
|
// -- r2 : name
|
||||||
|
// -- lr : return address
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
@ -859,7 +861,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
|
|||||||
switch (check) {
|
switch (check) {
|
||||||
case RECEIVER_MAP_CHECK:
|
case RECEIVER_MAP_CHECK:
|
||||||
// Check that the maps haven't changed.
|
// Check that the maps haven't changed.
|
||||||
CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss);
|
CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
|
||||||
|
|
||||||
// Patch the receiver on the stack with the global proxy if
|
// Patch the receiver on the stack with the global proxy if
|
||||||
// necessary.
|
// necessary.
|
||||||
@ -875,13 +877,13 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
|
|||||||
__ jmp(&miss);
|
__ jmp(&miss);
|
||||||
} else {
|
} else {
|
||||||
// Check that the object is a two-byte string or a symbol.
|
// Check that the object is a two-byte string or a symbol.
|
||||||
__ CompareObjectType(r1, r2, r2, FIRST_NONSTRING_TYPE);
|
__ CompareObjectType(r1, r3, r3, FIRST_NONSTRING_TYPE);
|
||||||
__ b(hs, &miss);
|
__ b(hs, &miss);
|
||||||
// Check that the maps starting from the prototype haven't changed.
|
// Check that the maps starting from the prototype haven't changed.
|
||||||
GenerateLoadGlobalFunctionPrototype(masm(),
|
GenerateLoadGlobalFunctionPrototype(masm(),
|
||||||
Context::STRING_FUNCTION_INDEX,
|
Context::STRING_FUNCTION_INDEX,
|
||||||
r2);
|
r0);
|
||||||
CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
|
CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
|
||||||
r1, name, &miss);
|
r1, name, &miss);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -895,14 +897,14 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
|
|||||||
// Check that the object is a smi or a heap number.
|
// Check that the object is a smi or a heap number.
|
||||||
__ tst(r1, Operand(kSmiTagMask));
|
__ tst(r1, Operand(kSmiTagMask));
|
||||||
__ b(eq, &fast);
|
__ b(eq, &fast);
|
||||||
__ CompareObjectType(r1, r2, r2, HEAP_NUMBER_TYPE);
|
__ CompareObjectType(r1, r0, r0, HEAP_NUMBER_TYPE);
|
||||||
__ b(ne, &miss);
|
__ b(ne, &miss);
|
||||||
__ bind(&fast);
|
__ bind(&fast);
|
||||||
// Check that the maps starting from the prototype haven't changed.
|
// Check that the maps starting from the prototype haven't changed.
|
||||||
GenerateLoadGlobalFunctionPrototype(masm(),
|
GenerateLoadGlobalFunctionPrototype(masm(),
|
||||||
Context::NUMBER_FUNCTION_INDEX,
|
Context::NUMBER_FUNCTION_INDEX,
|
||||||
r2);
|
r0);
|
||||||
CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
|
CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
|
||||||
r1, name, &miss);
|
r1, name, &miss);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -925,22 +927,22 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
|
|||||||
// Check that the maps starting from the prototype haven't changed.
|
// Check that the maps starting from the prototype haven't changed.
|
||||||
GenerateLoadGlobalFunctionPrototype(masm(),
|
GenerateLoadGlobalFunctionPrototype(masm(),
|
||||||
Context::BOOLEAN_FUNCTION_INDEX,
|
Context::BOOLEAN_FUNCTION_INDEX,
|
||||||
r2);
|
r0);
|
||||||
CheckPrototypes(JSObject::cast(object->GetPrototype()), r2, holder, r3,
|
CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
|
||||||
r1, name, &miss);
|
r1, name, &miss);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
|
case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
|
||||||
CheckPrototypes(JSObject::cast(object), r1, holder, r3, r2, name, &miss);
|
CheckPrototypes(JSObject::cast(object), r1, holder, r3, r0, name, &miss);
|
||||||
// Make sure object->HasFastElements().
|
// Make sure object->HasFastElements().
|
||||||
// Get the elements array of the object.
|
// Get the elements array of the object.
|
||||||
__ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
|
__ ldr(r3, FieldMemOperand(r1, JSObject::kElementsOffset));
|
||||||
// Check that the object is in fast mode (not dictionary).
|
// Check that the object is in fast mode (not dictionary).
|
||||||
__ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
|
__ ldr(r0, FieldMemOperand(r3, HeapObject::kMapOffset));
|
||||||
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
|
__ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
|
||||||
__ cmp(r2, ip);
|
__ cmp(r0, ip);
|
||||||
__ b(ne, &miss);
|
__ b(ne, &miss);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -968,15 +970,16 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object,
|
|||||||
JSObject* holder,
|
JSObject* holder,
|
||||||
String* name) {
|
String* name) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- lr: return address
|
// -- r2 : name
|
||||||
|
// -- lr : return address
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
ASSERT(holder->HasNamedInterceptor());
|
ASSERT(holder->HasNamedInterceptor());
|
||||||
ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
|
ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined());
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
const Register receiver = r0;
|
const Register receiver = r0;
|
||||||
const Register name_reg = r1;
|
const Register holder_reg = r1;
|
||||||
const Register holder_reg = r2;
|
const Register name_reg = r2;
|
||||||
const Register scratch = r3;
|
const Register scratch = r3;
|
||||||
|
|
||||||
// Get the number of arguments.
|
// Get the number of arguments.
|
||||||
@ -985,10 +988,8 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object,
|
|||||||
LookupResult lookup;
|
LookupResult lookup;
|
||||||
LookupPostInterceptor(holder, name, &lookup);
|
LookupPostInterceptor(holder, name, &lookup);
|
||||||
|
|
||||||
// Load the receiver from the stack.
|
// Get the receiver from the stack into r0.
|
||||||
__ ldr(receiver, MemOperand(sp, argc * kPointerSize));
|
__ ldr(r0, MemOperand(sp, argc * kPointerSize));
|
||||||
// Load the name from the stack.
|
|
||||||
__ ldr(name_reg, MemOperand(sp, (argc + 1) * kPointerSize));
|
|
||||||
|
|
||||||
// Check that the receiver isn't a smi.
|
// Check that the receiver isn't a smi.
|
||||||
__ BranchOnSmi(receiver, &miss);
|
__ BranchOnSmi(receiver, &miss);
|
||||||
@ -1061,9 +1062,7 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object,
|
|||||||
__ LeaveInternalFrame();
|
__ LeaveInternalFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Move returned value, the function to call, to r1.
|
// Move returned value, the function to call, to r1.
|
||||||
// Neither receiver nor name contain their original value at this point.
|
|
||||||
__ mov(r1, r0);
|
__ mov(r1, r0);
|
||||||
// Restore receiver.
|
// Restore receiver.
|
||||||
__ ldr(receiver, MemOperand(sp, argc * kPointerSize));
|
__ ldr(receiver, MemOperand(sp, argc * kPointerSize));
|
||||||
@ -1086,7 +1085,8 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
|
|||||||
JSFunction* function,
|
JSFunction* function,
|
||||||
String* name) {
|
String* name) {
|
||||||
// ----------- S t a t e -------------
|
// ----------- S t a t e -------------
|
||||||
// -- lr: return address
|
// -- r2 : name
|
||||||
|
// -- lr : return address
|
||||||
// -----------------------------------
|
// -----------------------------------
|
||||||
Label miss;
|
Label miss;
|
||||||
|
|
||||||
@ -1105,7 +1105,7 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check that the maps haven't changed.
|
// Check that the maps haven't changed.
|
||||||
CheckPrototypes(object, r0, holder, r3, r2, name, &miss);
|
CheckPrototypes(object, r0, holder, r3, r1, name, &miss);
|
||||||
|
|
||||||
// Get the value from the cell.
|
// Get the value from the cell.
|
||||||
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
|
__ mov(r3, Operand(Handle<JSGlobalPropertyCell>(cell)));
|
||||||
@ -1125,8 +1125,8 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
|
|||||||
|
|
||||||
// Check the shared function info. Make sure it hasn't changed.
|
// Check the shared function info. Make sure it hasn't changed.
|
||||||
__ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
|
__ mov(r3, Operand(Handle<SharedFunctionInfo>(function->shared())));
|
||||||
__ ldr(r2, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
|
__ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
|
||||||
__ cmp(r2, r3);
|
__ cmp(r4, r3);
|
||||||
__ b(ne, &miss);
|
__ b(ne, &miss);
|
||||||
} else {
|
} else {
|
||||||
__ cmp(r1, Operand(Handle<JSFunction>(function)));
|
__ cmp(r1, Operand(Handle<JSFunction>(function)));
|
||||||
@ -1144,7 +1144,7 @@ Object* CallStubCompiler::CompileCallGlobal(JSObject* object,
|
|||||||
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
|
__ ldr(cp, FieldMemOperand(r1, JSFunction::kContextOffset));
|
||||||
|
|
||||||
// Jump to the cached code (tail call).
|
// Jump to the cached code (tail call).
|
||||||
__ IncrementCounter(&Counters::call_global_inline, 1, r2, r3);
|
__ IncrementCounter(&Counters::call_global_inline, 1, r1, r3);
|
||||||
ASSERT(function->is_compiled());
|
ASSERT(function->is_compiled());
|
||||||
Handle<Code> code(function->code());
|
Handle<Code> code(function->code());
|
||||||
ParameterCount expected(function->shared()->formal_parameter_count());
|
ParameterCount expected(function->shared()->formal_parameter_count());
|
||||||
|
Loading…
Reference in New Issue
Block a user