__ bind(&done);
}
- // 4. Shift stuff one slot down the stack.
- { Label loop;
- __ lea(rcx, Operand(rax, +1)); // +1 ~ copy receiver too
- __ bind(&loop);
- __ movq(rbx, Operand(rsp, rcx, times_pointer_size, 0));
- __ movq(Operand(rsp, rcx, times_pointer_size, 1 * kPointerSize), rbx);
- __ decq(rcx);
- __ j(not_zero, &loop);
- }
-
- // 5. Remove TOS (copy of last arguments), but keep return address.
- __ pop(rbx);
- __ pop(rcx);
- __ push(rbx);
- __ decq(rax);
-
- // 6. Check that function really was a function and get the code to
- // call from the function and check that the number of expected
- // arguments matches what we're providing.
- { Label invoke, trampoline;
+ // 4. Check that the function really is a function.
+ { Label real_function;
__ testq(rdi, rdi);
- __ j(not_zero, &invoke);
+ __ j(not_zero, &real_function);
__ xor_(rbx, rbx);
+ // CALL_NON_FUNCTION will expect to find the non-function callee on the
+ // expression stack of the caller. Transfer it from receiver to the
+ // caller's expression stack (and make the first argument the receiver
+ // for CALL_NON_FUNCTION) by decrementing the argument count.
+ __ decq(rax);
__ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
- __ bind(&trampoline);
__ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
RelocInfo::CODE_TARGET);
- __ bind(&invoke);
- __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
- __ movsxlq(rbx,
- FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset));
- __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset));
- __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize));
- __ cmpq(rax, rbx);
- __ j(not_equal, &trampoline);
+ __ bind(&real_function);
}
+ // 5. Shift arguments and return address one slot down on the stack
+ // (overwriting the receiver).
+ { Label loop;
+ __ movq(rcx, rax);
+ __ bind(&loop);
+ __ movq(rbx, Operand(rsp, rcx, times_pointer_size, 0));
+ __ movq(Operand(rsp, rcx, times_pointer_size, 1 * kPointerSize), rbx);
+ __ decq(rcx);
+ __ j(not_sign, &loop);
+ __ pop(rbx); // Discard copy of return address.
+ __ decq(rax); // One fewer argument (first argument is new receiver).
+ }
+
+ // 6. Get the code to call from the function and check that the number of
+ // expected arguments matches what we're providing.
+ __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
+ __ movsxlq(rbx,
+ FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset));
+ __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset));
+ __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize));
+ __ cmpq(rax, rbx);
+ __ j(not_equal,
+ Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
+ RelocInfo::CODE_TARGET);
+
// 7. Jump (tail-call) to the code in register edx without checking arguments.
ParameterCount expected(0);
__ InvokeCode(rdx, expected, expected, JUMP_FUNCTION);
// JavaScript example: 'foo(1, 2, 3)' // foo is global
// ----------------------------------
- // Push the name of the function and the receiver onto the stack.
- frame_->Push(var->name());
-
// Pass the global object as the receiver and let the IC stub
// patch the stack to use the global proxy as 'this' in the
// invoked function.
Load(args->at(i));
}
+ // Push the name of the function on the frame.
+ frame_->Push(var->name());
+
// Call the IC initialization code.
CodeForSourcePosition(node->position());
Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET_CONTEXT,
loop_nesting());
frame_->RestoreContextRegister();
// Replace the function on the stack with the result.
- frame_->SetElementAt(0, &result);
+ frame_->Push(&result);
} else if (var != NULL && var->slot() != NULL &&
var->slot()->type() == Slot::LOOKUP) {
node->position());
} else {
- // Push the name of the function and the receiver onto the stack.
- frame_->Push(name);
+ // Push the receiver onto the frame.
Load(property->obj());
// Load the arguments.
Load(args->at(i));
}
+ // Push the name of the function onto the frame.
+ frame_->Push(name);
+
// Call the IC initialization code.
CodeForSourcePosition(node->position());
Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET,
arg_count,
loop_nesting());
frame_->RestoreContextRegister();
- // Replace the function on the stack with the result.
- frame_->SetElementAt(0, &result);
+ frame_->Push(&result);
}
} else {
Runtime::Function* function = node->function();
if (function == NULL) {
- // Prepare stack for calling JS runtime function.
- frame_->Push(node->name());
// Push the builtins object found in the current global object.
Result temp = allocator()->Allocate();
ASSERT(temp.is_valid());
if (function == NULL) {
// Call the JS runtime function.
+ frame_->Push(node->name());
Result answer = frame_->CallCallIC(RelocInfo::CODE_TARGET,
arg_count,
loop_nesting_);
frame_->RestoreContextRegister();
- frame_->SetElementAt(0, &answer);
+ frame_->Push(&answer);
} else {
// Call the C runtime function.
Result answer = frame_->CallRuntime(function, arg_count);
void FullCodeGenerator::EmitCallWithIC(Call* expr,
- Handle<Object> ignored,
+ Handle<Object> name,
RelocInfo::Mode mode) {
// Code common for calls using the IC.
ZoneList<Expression*>* args = expr->arguments();
for (int i = 0; i < arg_count; i++) {
VisitForValue(args->at(i), kStack);
}
+ __ Move(rcx, name);
// Record source position for debugger.
SetSourcePosition(expr->position());
// Call the IC initialization code.
__ Call(ic, mode);
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
- // Discard the function left on TOS.
- DropAndApply(1, context_, rax);
+ Apply(context_, rax);
}
UNREACHABLE();
} else if (var != NULL && !var->is_this() && var->is_global()) {
// Call to a global variable.
- __ Push(var->name());
// Push global object as receiver for the call IC lookup.
__ push(CodeGenerator::GlobalObject());
EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
Literal* key = prop->key()->AsLiteral();
if (key != NULL && key->handle()->IsSymbol()) {
// Call to a named property, use call IC.
- __ Push(key->handle());
VisitForValue(prop->obj(), kStack);
EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
} else {
if (expr->is_jsruntime()) {
// Prepare for calling JS runtime function.
- __ Push(expr->name());
__ movq(rax, CodeGenerator::GlobalObject());
__ push(FieldOperand(rax, GlobalObject::kBuiltinsOffset));
}
}
if (expr->is_jsruntime()) {
- // Call the JS runtime function.
- Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
- NOT_IN_LOOP);
+ // Call the JS runtime function using a call IC.
+ __ Move(rcx, expr->name());
+ InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
+ Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
__ call(ic, RelocInfo::CODE_TARGET);
// Restore context register.
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
- // Discard the function left on TOS.
- DropAndApply(1, context_, rax);
} else {
__ CallRuntime(expr->function(), arg_count);
- Apply(context_, rax);
}
+ Apply(context_, rax);
}
void CallIC::GenerateMiss(MacroAssembler* masm, int argc) {
+ // ----------- S t a t e -------------
+ // rcx : function name
+ // rsp[0] : return address
+ // rsp[8] : argument argc
+ // rsp[16] : argument argc - 1
+ // ...
+ // rsp[argc * 8] : argument 1
+ // rsp[(argc + 1) * 8] : argument 0 = receiver
+ // -----------------------------------
// Get the receiver of the function from the stack; 1 ~ return address.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
- // Get the name of the function to call from the stack.
- // 2 ~ receiver, return address.
- __ movq(rbx, Operand(rsp, (argc + 2) * kPointerSize));
// Enter an internal frame.
__ EnterInternalFrame();
// Push the receiver and the name of the function.
__ push(rdx);
- __ push(rbx);
+ __ push(rcx);
// Call the entry.
CEntryStub stub(1);
void CallIC::GenerateMegamorphic(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
- // rsp[0] return address
- // rsp[8] argument argc
- // rsp[16] argument argc - 1
+ // rcx : function name
+ // rsp[0] : return address
+ // rsp[8] : argument argc
+ // rsp[16] : argument argc - 1
// ...
- // rsp[argc * 8] argument 1
- // rsp[(argc + 1) * 8] argument 0 = receiver
- // rsp[(argc + 2) * 8] function name
+ // rsp[argc * 8] : argument 1
+ // rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
Label number, non_number, non_string, boolean, probe, miss;
// Get the receiver of the function from the stack; 1 ~ return address.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
- // Get the name of the function from the stack; 2 ~ return address, receiver
- __ movq(rcx, Operand(rsp, (argc + 2) * kPointerSize));
// Probe the stub cache.
Code::Flags flags =
int argc,
bool is_global_object,
Label* miss) {
+ // ----------- S t a t e -------------
+ // rcx : function name
+ // rdx : receiver
+ // rsp[0] : return address
+ // rsp[8] : argument argc
+ // rsp[16] : argument argc - 1
+ // ...
+ // rsp[argc * 8] : argument 1
+ // rsp[(argc + 1) * 8] : argument 0 = receiver
+ // -----------------------------------
// Search dictionary - put result in register rdx.
GenerateDictionaryLoad(masm, miss, rax, rdx, rbx, rcx, CHECK_DICTIONARY);
void CallIC::GenerateNormal(MacroAssembler* masm, int argc) {
// ----------- S t a t e -------------
- // rsp[0] return address
- // rsp[8] argument argc
- // rsp[16] argument argc - 1
+ // rcx : function name
+ // rsp[0] : return address
+ // rsp[8] : argument argc
+ // rsp[16] : argument argc - 1
// ...
- // rsp[argc * 8] argument 1
- // rsp[(argc + 1) * 8] argument 0 = receiver
- // rsp[(argc + 2) * 8] function name
+ // rsp[argc * 8] : argument 1
+ // rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
Label miss, global_object, non_global_object;
// Get the receiver of the function from the stack.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
- // Get the name of the function from the stack.
- __ movq(rcx, Operand(rsp, (argc + 2) * kPointerSize));
// Check that the receiver isn't a smi.
__ JumpIfSmi(rdx, &miss);
}
-template <typename Pushable>
static void PushInterceptorArguments(MacroAssembler* masm,
Register receiver,
Register holder,
- Pushable name,
+ Register name,
JSObject* holder_obj) {
__ push(receiver);
__ push(holder);
}
-template <class Pushable>
static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm,
Register receiver,
Register holder,
- Pushable name,
+ Register name,
JSObject* holder_obj) {
PushInterceptorArguments(masm, receiver, holder, name, holder_obj);
class CallInterceptorCompiler BASE_EMBEDDED {
public:
- explicit CallInterceptorCompiler(const ParameterCount& arguments)
- : arguments_(arguments), argc_(arguments.immediate()) {}
+ CallInterceptorCompiler(const ParameterCount& arguments, Register name)
+ : arguments_(arguments), argc_(arguments.immediate()), name_(name) {}
void CompileCacheable(MacroAssembler* masm,
StubCompiler* stub_compiler,
}
__ EnterInternalFrame();
- __ push(holder); // save the holder
+ __ push(holder); // Save the holder.
+ __ push(name_); // Save the name.
- CompileCallLoadPropertyWithInterceptor(
- masm,
- receiver,
- holder,
- // Under EnterInternalFrame this refers to name.
- Operand(rbp, (argc_ + 3) * kPointerSize),
- holder_obj);
+ CompileCallLoadPropertyWithInterceptor(masm,
+ receiver,
+ holder,
+ name_,
+ holder_obj);
- __ pop(receiver); // restore holder
+ __ pop(name_); // Restore the name.
+ __ pop(receiver); // Restore the holder.
__ LeaveInternalFrame();
__ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
JSObject* holder_obj,
Label* miss_label) {
__ EnterInternalFrame();
+ // Save the name_ register across the call.
+ __ push(name_);
PushInterceptorArguments(masm,
receiver,
holder,
- Operand(rbp, (argc_ + 3) * kPointerSize),
+ name_,
holder_obj);
ExternalReference ref = ExternalReference(
CEntryStub stub(1);
__ CallStub(&stub);
+ __ pop(name_);
__ LeaveInternalFrame();
}
private:
const ParameterCount& arguments_;
int argc_;
+ Register name_;
};
String* name,
StubCompiler::CheckType check) {
// ----------- S t a t e -------------
- // -----------------------------------
- // rsp[0] return address
- // rsp[8] argument argc
- // rsp[16] argument argc - 1
+ // rcx : function name
+ // rsp[0] : return address
+ // rsp[8] : argument argc
+ // rsp[16] : argument argc - 1
// ...
- // rsp[argc * 8] argument 1
- // rsp[(argc + 1) * 8] argument 0 = receiver
- // rsp[(argc + 2) * 8] function name
+ // rsp[argc * 8] : argument 1
+ // rsp[(argc + 1) * 8] : argument 0 = receiver
+ // -----------------------------------
Label miss;
case RECEIVER_MAP_CHECK:
// Check that the maps haven't changed.
CheckPrototypes(JSObject::cast(object), rdx, holder,
- rbx, rcx, name, &miss);
+ rbx, rax, name, &miss);
// Patch the receiver on the stack with the global proxy if
// necessary.
__ jmp(&miss);
} else {
// Check that the object is a two-byte string or a symbol.
- __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rcx);
+ __ CmpObjectType(rdx, FIRST_NONSTRING_TYPE, rax);
__ j(above_equal, &miss);
// Check that the maps starting from the prototype haven't changed.
GenerateLoadGlobalFunctionPrototype(masm(),
Context::STRING_FUNCTION_INDEX,
- rcx);
- CheckPrototypes(JSObject::cast(object->GetPrototype()), rcx, holder,
+ rax);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
rbx, rdx, name, &miss);
}
break;
Label fast;
// Check that the object is a smi or a heap number.
__ JumpIfSmi(rdx, &fast);
- __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rcx);
+ __ CmpObjectType(rdx, HEAP_NUMBER_TYPE, rax);
__ j(not_equal, &miss);
__ bind(&fast);
// Check that the maps starting from the prototype haven't changed.
GenerateLoadGlobalFunctionPrototype(masm(),
Context::NUMBER_FUNCTION_INDEX,
- rcx);
- CheckPrototypes(JSObject::cast(object->GetPrototype()), rcx, holder,
+ rax);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
rbx, rdx, name, &miss);
}
break;
// Check that the maps starting from the prototype haven't changed.
GenerateLoadGlobalFunctionPrototype(masm(),
Context::BOOLEAN_FUNCTION_INDEX,
- rcx);
- CheckPrototypes(JSObject::cast(object->GetPrototype()), rcx, holder,
+ rax);
+ CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
rbx, rdx, name, &miss);
}
break;
case JSARRAY_HAS_FAST_ELEMENTS_CHECK:
CheckPrototypes(JSObject::cast(object), rdx, holder,
- rbx, rcx, name, &miss);
+ rbx, rax, name, &miss);
// Make sure object->HasFastElements().
// Get the elements array of the object.
__ movq(rbx, FieldOperand(rdx, JSObject::kElementsOffset));
int index,
String* name) {
// ----------- S t a t e -------------
- // -----------------------------------
- // rsp[0] return address
- // rsp[8] argument argc
- // rsp[16] argument argc - 1
+ // rcx : function name
+ // rsp[0] : return address
+ // rsp[8] : argument argc
+ // rsp[16] : argument argc - 1
// ...
- // rsp[argc * 8] argument 1
- // rsp[(argc + 1) * 8] argument 0 = receiver
- // rsp[(argc + 2) * 8] function name
+ // rsp[argc * 8] : argument 1
+ // rsp[(argc + 1) * 8] : argument 0 = receiver
+ // -----------------------------------
Label miss;
// Get the receiver from the stack.
// Do the right check and compute the holder register.
Register reg =
CheckPrototypes(JSObject::cast(object), rdx, holder,
- rbx, rcx, name, &miss);
+ rbx, rax, name, &miss);
GenerateFastPropertyLoad(masm(), rdi, reg, holder, index);
JSObject* holder,
String* name) {
// ----------- S t a t e -------------
+ // rcx : function name
+ // rsp[0] : return address
+ // rsp[8] : argument argc
+ // rsp[16] : argument argc - 1
+ // ...
+ // rsp[argc * 8] : argument 1
+ // rsp[(argc + 1) * 8] : argument 0 = receiver
// -----------------------------------
Label miss;
// Get the receiver from the stack.
__ movq(rdx, Operand(rsp, (argc + 1) * kPointerSize));
- CallInterceptorCompiler compiler(arguments());
+ CallInterceptorCompiler compiler(arguments(), rcx);
CompileLoadInterceptor(&compiler,
this,
masm(),
&lookup,
rdx,
rbx,
- rcx,
+ rdi,
&miss);
// Restore receiver.
String* name) {
// ----------- S t a t e -------------
// -----------------------------------
- // rsp[0] return address
- // rsp[8] argument argc
- // rsp[16] argument argc - 1
+ // rcx : function name
+ // rsp[0] : return address
+ // rsp[8] : argument argc
+ // rsp[16] : argument argc - 1
// ...
- // rsp[argc * 8] argument 1
- // rsp[(argc + 1) * 8] argument 0 = receiver
- // rsp[(argc + 2) * 8] function name
+ // rsp[argc * 8] : argument 1
+ // rsp[(argc + 1) * 8] : argument 0 = receiver
Label miss;
// Get the number of arguments.
}
// Check that the maps haven't changed.
- CheckPrototypes(object, rdx, holder, rbx, rcx, name, &miss);
+ CheckPrototypes(object, rdx, holder, rbx, rax, name, &miss);
// Get the value from the cell.
__ Move(rdi, Handle<JSGlobalPropertyCell>(cell));
// function can all use this call IC. Before we load through the
// function, we have to verify that it still is a function.
__ JumpIfSmi(rdi, &miss);
- __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
+ __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rax);
__ j(not_equal, &miss);
// Check the shared function info. Make sure it hasn't changed.
- __ Move(rcx, Handle<SharedFunctionInfo>(function->shared()));
- __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rcx);
+ __ Move(rax, Handle<SharedFunctionInfo>(function->shared()));
+ __ cmpq(FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset), rax);
__ j(not_equal, &miss);
} else {
__ Cmp(rdi, Handle<JSFunction>(function));
Result VirtualFrame::CallCallIC(RelocInfo::Mode mode,
int arg_count,
int loop_nesting) {
- // Arguments, receiver, and function name are on top of the frame.
- // The IC expects them on the stack. It does not drop the function
- // name slot (but it does drop the rest).
+ // Function name, arguments, and receiver are found on top of the frame
+ // and dropped by the call. The IC expects the name in rcx and the rest
+ // on the stack, and drops them all.
InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
Handle<Code> ic = cgen()->ComputeCallInitialize(arg_count, in_loop);
+ Result name = Pop();
// Spill args, receiver, and function. The call will drop args and
// receiver.
- PrepareForCall(arg_count + 2, arg_count + 1);
+ PrepareForCall(arg_count + 1, arg_count + 1);
+ name.ToRegister(rcx);
+ name.Unuse();
return RawCallCodeObject(ic, mode);
}
// of the frame. Key and receiver are not dropped.
Result CallKeyedStoreIC();
- // Call call IC. Arguments, receiver, and function name are found
- // on top of the frame. Function name slot is not dropped. The
- // argument count does not include the receiver.
+ // Call call IC. Function name, arguments, and receiver are found on top
+ // of the frame and dropped by the call.
+ // The argument count does not include the receiver.
Result CallCallIC(RelocInfo::Mode mode, int arg_count, int loop_nesting);
// Allocate and call JS function as constructor. Arguments,