X64 implementation: Add function literals and function calls.
Review URL: http://codereview.chromium.org/131029 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2217 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
a1a962f65e
commit
da49c0f8a2
@ -1417,7 +1417,7 @@ void Assembler::call(const Operand& adr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Assembler::call(Handle<Code> code, RelocInfo::Mode rmode) {
|
void Assembler::call(Handle<Code> code, RelocInfo::Mode rmode) {
|
||||||
WriteRecordedPositions();
|
WriteRecordedPositions();
|
||||||
EnsureSpace ensure_space(this);
|
EnsureSpace ensure_space(this);
|
||||||
last_pc_ = pc_;
|
last_pc_ = pc_;
|
||||||
|
@ -7163,7 +7163,6 @@ void CallFunctionStub::Generate(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
|
void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
|
||||||
// eax holds the exception.
|
// eax holds the exception.
|
||||||
|
|
||||||
|
@ -103,7 +103,15 @@ void CodeGenerator::DeclareGlobals(Handle<FixedArray> a) {
|
|||||||
void CodeGenerator::TestCodeGenerator() {
|
void CodeGenerator::TestCodeGenerator() {
|
||||||
// Compile a function from a string, and run it.
|
// Compile a function from a string, and run it.
|
||||||
Handle<JSFunction> test_function = Compiler::Compile(
|
Handle<JSFunction> test_function = Compiler::Compile(
|
||||||
Factory::NewStringFromAscii(CStrVector("39; 42;")),
|
Factory::NewStringFromAscii(CStrVector(
|
||||||
|
"39;"
|
||||||
|
"(function(){return 43})();"
|
||||||
|
"42;"
|
||||||
|
// "function foo(x, y){return x;};"
|
||||||
|
"43;"
|
||||||
|
// "foo(2,3);"
|
||||||
|
"44;"
|
||||||
|
"(function(){return (function(){return 47})()})();")),
|
||||||
Factory::NewStringFromAscii(CStrVector("CodeGeneratorTestScript")),
|
Factory::NewStringFromAscii(CStrVector("CodeGeneratorTestScript")),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@ -132,7 +140,7 @@ void CodeGenerator::TestCodeGenerator() {
|
|||||||
&pending_exceptions);
|
&pending_exceptions);
|
||||||
// Function compiles and runs, but returns a JSFunction object.
|
// Function compiles and runs, but returns a JSFunction object.
|
||||||
CHECK(result->IsSmi());
|
CHECK(result->IsSmi());
|
||||||
CHECK_EQ(42, Smi::cast(*result)->value());
|
CHECK_EQ(47, Smi::cast(*result)->value());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -370,15 +378,44 @@ void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* a) {
|
|||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* a) {
|
|
||||||
UNIMPLEMENTED();
|
void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
|
||||||
|
// Call the runtime to instantiate the function boilerplate object.
|
||||||
|
// The inevitable call will sync frame elements to memory anyway, so
|
||||||
|
// we do it eagerly to allow us to push the arguments directly into
|
||||||
|
// place.
|
||||||
|
ASSERT(boilerplate->IsBoilerplate());
|
||||||
|
frame_->SyncRange(0, frame_->element_count() - 1);
|
||||||
|
|
||||||
|
// Push the boilerplate on the stack.
|
||||||
|
__ movq(kScratchRegister, boilerplate, RelocInfo::EMBEDDED_OBJECT);
|
||||||
|
frame_->EmitPush(kScratchRegister);
|
||||||
|
|
||||||
|
// Create a new closure.
|
||||||
|
frame_->EmitPush(rsi);
|
||||||
|
Result result = frame_->CallRuntime(Runtime::kNewClosure, 2);
|
||||||
|
frame_->Push(&result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenerator::VisitFunctionBoilerplateLiteral(
|
|
||||||
FunctionBoilerplateLiteral* a) {
|
void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
|
||||||
UNIMPLEMENTED();
|
Comment cmnt(masm_, "[ FunctionLiteral");
|
||||||
|
|
||||||
|
// Build the function boilerplate and instantiate it.
|
||||||
|
Handle<JSFunction> boilerplate = BuildBoilerplate(node);
|
||||||
|
// Check for stack-overflow exception.
|
||||||
|
if (HasStackOverflow()) return;
|
||||||
|
InstantiateBoilerplate(boilerplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CodeGenerator::VisitFunctionBoilerplateLiteral(
|
||||||
|
FunctionBoilerplateLiteral* node) {
|
||||||
|
Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
|
||||||
|
InstantiateBoilerplate(node->boilerplate());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenerator::VisitConditional(Conditional* a) {
|
void CodeGenerator::VisitConditional(Conditional* a) {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
@ -521,10 +558,153 @@ void CodeGenerator::VisitProperty(Property* a) {
|
|||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeGenerator::VisitCall(Call* a) {
|
|
||||||
UNIMPLEMENTED();
|
void CodeGenerator::VisitCall(Call* node) {
|
||||||
|
Comment cmnt(masm_, "[ Call");
|
||||||
|
|
||||||
|
ZoneList<Expression*>* args = node->arguments();
|
||||||
|
|
||||||
|
CodeForStatementPosition(node);
|
||||||
|
|
||||||
|
// Check if the function is a variable or a property.
|
||||||
|
Expression* function = node->expression();
|
||||||
|
Variable* var = function->AsVariableProxy()->AsVariable();
|
||||||
|
Property* property = function->AsProperty();
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Fast-case: Use inline caching.
|
||||||
|
// ---
|
||||||
|
// According to ECMA-262, section 11.2.3, page 44, the function to call
|
||||||
|
// must be resolved after the arguments have been evaluated. The IC code
|
||||||
|
// automatically handles this by loading the arguments before the function
|
||||||
|
// is resolved in cache misses (this also holds for megamorphic calls).
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if (var != NULL && !var->is_this() && var->is_global()) {
|
||||||
|
// ----------------------------------
|
||||||
|
// 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.
|
||||||
|
LoadGlobal();
|
||||||
|
|
||||||
|
// Load the arguments.
|
||||||
|
int arg_count = args->length();
|
||||||
|
for (int i = 0; i < arg_count; i++) {
|
||||||
|
Load(args->at(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the IC initialization code.
|
||||||
|
CodeForSourcePosition(node->position());
|
||||||
|
Result result = frame_->CallCallIC(RelocInfo::CODE_TARGET_CONTEXT,
|
||||||
|
arg_count,
|
||||||
|
loop_nesting());
|
||||||
|
frame_->RestoreContextRegister();
|
||||||
|
// Replace the function on the stack with the result.
|
||||||
|
frame_->SetElementAt(0, &result);
|
||||||
|
} else if (var != NULL && var->slot() != NULL &&
|
||||||
|
var->slot()->type() == Slot::LOOKUP) {
|
||||||
|
// TODO(X64): Enable calls of non-global functions.
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
/*
|
||||||
|
// ----------------------------------
|
||||||
|
// JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
|
// Load the function from the context. Sync the frame so we can
|
||||||
|
// push the arguments directly into place.
|
||||||
|
frame_->SyncRange(0, frame_->element_count() - 1);
|
||||||
|
frame_->EmitPush(esi);
|
||||||
|
frame_->EmitPush(Immediate(var->name()));
|
||||||
|
frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
|
||||||
|
// The runtime call returns a pair of values in eax and edx. The
|
||||||
|
// looked-up function is in eax and the receiver is in edx. These
|
||||||
|
// register references are not ref counted here. We spill them
|
||||||
|
// eagerly since they are arguments to an inevitable call (and are
|
||||||
|
// not sharable by the arguments).
|
||||||
|
ASSERT(!allocator()->is_used(eax));
|
||||||
|
frame_->EmitPush(eax);
|
||||||
|
|
||||||
|
// Load the receiver.
|
||||||
|
ASSERT(!allocator()->is_used(edx));
|
||||||
|
frame_->EmitPush(edx);
|
||||||
|
|
||||||
|
// Call the function.
|
||||||
|
CallWithArguments(args, node->position());
|
||||||
|
*/
|
||||||
|
} else if (property != NULL) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
/*
|
||||||
|
// Check if the key is a literal string.
|
||||||
|
Literal* literal = property->key()->AsLiteral();
|
||||||
|
|
||||||
|
if (literal != NULL && literal->handle()->IsSymbol()) {
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// 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.
|
||||||
|
frame_->Push(literal->handle());
|
||||||
|
Load(property->obj());
|
||||||
|
|
||||||
|
// Load the arguments.
|
||||||
|
int arg_count = args->length();
|
||||||
|
for (int i = 0; i < arg_count; i++) {
|
||||||
|
Load(args->at(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// -------------------------------------------
|
||||||
|
// JavaScript example: 'array[index](1, 2, 3)'
|
||||||
|
// -------------------------------------------
|
||||||
|
|
||||||
|
// Load the function to call from the property through a reference.
|
||||||
|
Reference ref(this, property);
|
||||||
|
ref.GetValue(NOT_INSIDE_TYPEOF);
|
||||||
|
|
||||||
|
// Pass receiver to called function.
|
||||||
|
if (property->is_synthetic()) {
|
||||||
|
// Use global object as receiver.
|
||||||
|
LoadGlobalReceiver();
|
||||||
|
} else {
|
||||||
|
// The reference's size is non-negative.
|
||||||
|
frame_->PushElementAt(ref.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call the function.
|
||||||
|
CallWithArguments(args, node->position());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
// ----------------------------------
|
||||||
|
// JavaScript example: 'foo(1, 2, 3)' // foo is not global
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
|
// Load the function.
|
||||||
|
Load(function);
|
||||||
|
|
||||||
|
// Pass the global proxy as the receiver.
|
||||||
|
LoadGlobalReceiver();
|
||||||
|
|
||||||
|
// Call the function.
|
||||||
|
CallWithArguments(args, node->position());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenerator::VisitCallEval(CallEval* a) {
|
void CodeGenerator::VisitCallEval(CallEval* a) {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
@ -537,6 +717,7 @@ void CodeGenerator::VisitCallRuntime(CallRuntime* a) {
|
|||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CodeGenerator::VisitUnaryOperation(UnaryOperation* a) {
|
void CodeGenerator::VisitUnaryOperation(UnaryOperation* a) {
|
||||||
UNIMPLEMENTED();
|
UNIMPLEMENTED();
|
||||||
}
|
}
|
||||||
@ -1216,6 +1397,16 @@ void CodeGenerator::LoadGlobal() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CodeGenerator::LoadGlobalReceiver() {
|
||||||
|
Result temp = allocator_->Allocate();
|
||||||
|
Register reg = temp.reg();
|
||||||
|
__ movq(reg, GlobalObject());
|
||||||
|
__ movq(reg, FieldOperand(reg, GlobalObject::kGlobalReceiverOffset));
|
||||||
|
frame_->Push(&temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#undef __
|
#undef __
|
||||||
|
|
||||||
// End of CodeGenerator implementation.
|
// End of CodeGenerator implementation.
|
||||||
@ -1588,6 +1779,54 @@ class CallFunctionStub: public CodeStub {
|
|||||||
|
|
||||||
|
|
||||||
void CallFunctionStub::Generate(MacroAssembler* masm) {
|
void CallFunctionStub::Generate(MacroAssembler* masm) {
|
||||||
|
Label slow;
|
||||||
|
|
||||||
|
// Get the function to call from the stack.
|
||||||
|
// +2 ~ receiver, return address
|
||||||
|
__ movq(rdi, Operand(rsp, (argc_ + 2) * kPointerSize));
|
||||||
|
|
||||||
|
// Check that the function really is a JavaScript function.
|
||||||
|
__ testq(rdi, Immediate(kSmiTagMask));
|
||||||
|
__ j(zero, &slow);
|
||||||
|
// Goto slow case if we do not have a function.
|
||||||
|
__ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
|
||||||
|
__ j(not_equal, &slow);
|
||||||
|
|
||||||
|
// Fast-case: Just invoke the function.
|
||||||
|
ParameterCount actual(argc_);
|
||||||
|
__ InvokeFunction(rdi, actual, JUMP_FUNCTION);
|
||||||
|
|
||||||
|
// Slow-case: Non-function called.
|
||||||
|
__ bind(&slow);
|
||||||
|
__ Set(rax, argc_);
|
||||||
|
__ Set(rbx, 0);
|
||||||
|
__ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
|
||||||
|
Handle<Code> adaptor(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline));
|
||||||
|
__ Jump(adaptor, RelocInfo::CODE_TARGET);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Call the function just below TOS on the stack with the given
|
||||||
|
// arguments. The receiver is the TOS.
|
||||||
|
void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
|
||||||
|
int position) {
|
||||||
|
// Push the arguments ("left-to-right") on the stack.
|
||||||
|
int arg_count = args->length();
|
||||||
|
for (int i = 0; i < arg_count; i++) {
|
||||||
|
Load(args->at(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record the position for debugging purposes.
|
||||||
|
CodeForSourcePosition(position);
|
||||||
|
|
||||||
|
// Use the shared code stub to call the function.
|
||||||
|
InLoopFlag in_loop = loop_nesting() > 0 ? IN_LOOP : NOT_IN_LOOP;
|
||||||
|
CallFunctionStub call_function(arg_count, in_loop);
|
||||||
|
Result answer = frame_->CallStub(&call_function, arg_count + 1);
|
||||||
|
// Restore context and replace function on the stack with the
|
||||||
|
// result of the stub invocation.
|
||||||
|
frame_->RestoreContextRegister();
|
||||||
|
frame_->SetElementAt(0, &answer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1595,7 +1834,6 @@ void InstanceofStub::Generate(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
|
void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
|
||||||
// The displacement is used for skipping the return address and the
|
// The displacement is used for skipping the return address and the
|
||||||
// frame pointer on the stack. It is the offset of the last
|
// frame pointer on the stack. It is the offset of the last
|
||||||
|
@ -206,6 +206,44 @@ void MacroAssembler::JumpToBuiltin(const ExternalReference& ext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MacroAssembler::GetBuiltinEntry(Register target, Builtins::JavaScript id) {
|
||||||
|
bool resolved;
|
||||||
|
Handle<Code> code = ResolveBuiltin(id, &resolved);
|
||||||
|
|
||||||
|
const char* name = Builtins::GetName(id);
|
||||||
|
int argc = Builtins::GetArgumentsCount(id);
|
||||||
|
|
||||||
|
movq(target, code, RelocInfo::EXTERNAL_REFERENCE); // Is external reference?
|
||||||
|
if (!resolved) {
|
||||||
|
uint32_t flags =
|
||||||
|
Bootstrapper::FixupFlagsArgumentsCount::encode(argc) |
|
||||||
|
Bootstrapper::FixupFlagsIsPCRelative::encode(false) |
|
||||||
|
Bootstrapper::FixupFlagsUseCodeObject::encode(true);
|
||||||
|
Unresolved entry = { pc_offset() - sizeof(intptr_t), flags, name };
|
||||||
|
unresolved_.Add(entry);
|
||||||
|
}
|
||||||
|
addq(target, Immediate(Code::kHeaderSize - kHeapObjectTag));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Handle<Code> MacroAssembler::ResolveBuiltin(Builtins::JavaScript id,
|
||||||
|
bool* resolved) {
|
||||||
|
// Move the builtin function into the temporary function slot by
|
||||||
|
// reading it from the builtins object. NOTE: We should be able to
|
||||||
|
// reduce this to two instructions by putting the function table in
|
||||||
|
// the global object instead of the "builtins" object and by using a
|
||||||
|
// real register for the function.
|
||||||
|
movq(rdx, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
|
||||||
|
movq(rdx, FieldOperand(rdx, GlobalObject::kBuiltinsOffset));
|
||||||
|
int builtins_offset =
|
||||||
|
JSBuiltinsObject::kJSBuiltinsOffset + (id * kPointerSize);
|
||||||
|
movq(rdi, FieldOperand(rdx, builtins_offset));
|
||||||
|
|
||||||
|
|
||||||
|
return Builtins::GetCode(id, resolved);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MacroAssembler::Set(Register dst, int64_t x) {
|
void MacroAssembler::Set(Register dst, int64_t x) {
|
||||||
if (is_int32(x)) {
|
if (is_int32(x)) {
|
||||||
movq(dst, Immediate(x));
|
movq(dst, Immediate(x));
|
||||||
@ -241,6 +279,14 @@ void MacroAssembler::Jump(Address destination, RelocInfo::Mode rmode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MacroAssembler::Jump(Handle<Code> code_object, RelocInfo::Mode rmode) {
|
||||||
|
WriteRecordedPositions();
|
||||||
|
ASSERT(RelocInfo::IsCodeTarget(rmode));
|
||||||
|
movq(kScratchRegister, code_object, rmode);
|
||||||
|
jmp(kScratchRegister);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MacroAssembler::Call(ExternalReference ext) {
|
void MacroAssembler::Call(ExternalReference ext) {
|
||||||
movq(kScratchRegister, ext);
|
movq(kScratchRegister, ext);
|
||||||
call(kScratchRegister);
|
call(kScratchRegister);
|
||||||
@ -253,6 +299,14 @@ void MacroAssembler::Call(Address destination, RelocInfo::Mode rmode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MacroAssembler::Call(Handle<Code> code_object, RelocInfo::Mode rmode) {
|
||||||
|
WriteRecordedPositions();
|
||||||
|
ASSERT(RelocInfo::IsCodeTarget(rmode));
|
||||||
|
movq(kScratchRegister, code_object, rmode);
|
||||||
|
call(kScratchRegister);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MacroAssembler::PushTryHandler(CodeLocation try_location,
|
void MacroAssembler::PushTryHandler(CodeLocation try_location,
|
||||||
HandlerType type) {
|
HandlerType type) {
|
||||||
// Adjust this code if not the case.
|
// Adjust this code if not the case.
|
||||||
|
@ -161,8 +161,11 @@ class MacroAssembler: public Assembler {
|
|||||||
// Control Flow
|
// Control Flow
|
||||||
void Jump(Address destination, RelocInfo::Mode rmode);
|
void Jump(Address destination, RelocInfo::Mode rmode);
|
||||||
void Jump(ExternalReference ext);
|
void Jump(ExternalReference ext);
|
||||||
|
void Jump(Handle<Code> code_object, RelocInfo::Mode rmode);
|
||||||
|
|
||||||
void Call(Address destination, RelocInfo::Mode rmode);
|
void Call(Address destination, RelocInfo::Mode rmode);
|
||||||
void Call(ExternalReference ext);
|
void Call(ExternalReference ext);
|
||||||
|
void Call(Handle<Code> code_object, RelocInfo::Mode rmode);
|
||||||
|
|
||||||
// Compare object type for heap object.
|
// Compare object type for heap object.
|
||||||
// Incoming register is heap_object and outgoing register is map.
|
// Incoming register is heap_object and outgoing register is map.
|
||||||
|
@ -137,6 +137,26 @@ void VirtualFrame::AllocateStackSlots() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VirtualFrame::SaveContextRegister() {
|
||||||
|
ASSERT(elements_[context_index()].is_memory());
|
||||||
|
__ movq(Operand(rbp, fp_relative(context_index())), rsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VirtualFrame::RestoreContextRegister() {
|
||||||
|
ASSERT(elements_[context_index()].is_memory());
|
||||||
|
__ movq(rsi, Operand(rbp, fp_relative(context_index())));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VirtualFrame::PushReceiverSlotAddress() {
|
||||||
|
Result temp = cgen()->allocator()->Allocate();
|
||||||
|
ASSERT(temp.is_valid());
|
||||||
|
__ lea(temp.reg(), ParameterAt(-1));
|
||||||
|
Push(&temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void VirtualFrame::EmitPop(Register reg) {
|
void VirtualFrame::EmitPop(Register reg) {
|
||||||
ASSERT(stack_pointer_ == element_count() - 1);
|
ASSERT(stack_pointer_ == element_count() - 1);
|
||||||
stack_pointer_--;
|
stack_pointer_--;
|
||||||
@ -433,13 +453,65 @@ Result VirtualFrame::Pop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Result VirtualFrame::RawCallStub(CodeStub* a) {
|
Result VirtualFrame::RawCallStub(CodeStub* stub) {
|
||||||
UNIMPLEMENTED();
|
ASSERT(cgen()->HasValidEntryRegisters());
|
||||||
return Result(NULL);
|
__ CallStub(stub);
|
||||||
|
Result result = cgen()->allocator()->Allocate(rax);
|
||||||
|
ASSERT(result.is_valid());
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualFrame::SyncElementBelowStackPointer(int a) {
|
|
||||||
UNIMPLEMENTED();
|
void VirtualFrame::SyncElementBelowStackPointer(int index) {
|
||||||
|
// Emit code to write elements below the stack pointer to their
|
||||||
|
// (already allocated) stack address.
|
||||||
|
ASSERT(index <= stack_pointer_);
|
||||||
|
FrameElement element = elements_[index];
|
||||||
|
ASSERT(!element.is_synced());
|
||||||
|
switch (element.type()) {
|
||||||
|
case FrameElement::INVALID:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FrameElement::MEMORY:
|
||||||
|
// This function should not be called with synced elements.
|
||||||
|
// (memory elements are always synced).
|
||||||
|
UNREACHABLE();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FrameElement::REGISTER:
|
||||||
|
__ movq(Operand(rbp, fp_relative(index)), element.reg());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FrameElement::CONSTANT:
|
||||||
|
if (element.handle()->IsSmi()) {
|
||||||
|
if (CodeGeneratorScope::Current()->IsUnsafeSmi(element.handle())) {
|
||||||
|
CodeGeneratorScope::Current()->LoadUnsafeSmi(kScratchRegister,
|
||||||
|
element.handle());
|
||||||
|
} else {
|
||||||
|
__ movq(kScratchRegister, element.handle(), RelocInfo::NONE);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
__ movq(kScratchRegister,
|
||||||
|
element.handle(),
|
||||||
|
RelocInfo::EMBEDDED_OBJECT);
|
||||||
|
}
|
||||||
|
__ movq(Operand(rbp, fp_relative(index)), kScratchRegister);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case FrameElement::COPY: {
|
||||||
|
int backing_index = element.index();
|
||||||
|
FrameElement backing_element = elements_[backing_index];
|
||||||
|
if (backing_element.is_memory()) {
|
||||||
|
__ movq(kScratchRegister, Operand(rbp, fp_relative(backing_index)));
|
||||||
|
__ movq(Operand(rbp, fp_relative(index)), kScratchRegister);
|
||||||
|
} else {
|
||||||
|
ASSERT(backing_element.is_register());
|
||||||
|
__ movq(Operand(rbp, fp_relative(index)), backing_element.reg());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elements_[index].set_sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -519,6 +591,55 @@ void VirtualFrame::SyncRange(int begin, int end) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// Virtual frame stub and IC calling functions.
|
||||||
|
|
||||||
|
Result VirtualFrame::RawCallCodeObject(Handle<Code> code,
|
||||||
|
RelocInfo::Mode rmode) {
|
||||||
|
ASSERT(cgen()->HasValidEntryRegisters());
|
||||||
|
__ Call(code, rmode);
|
||||||
|
Result result = cgen()->allocator()->Allocate(rax);
|
||||||
|
ASSERT(result.is_valid());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Result VirtualFrame::CallRuntime(Runtime::Function* f, int arg_count) {
|
||||||
|
PrepareForCall(arg_count, arg_count);
|
||||||
|
ASSERT(cgen()->HasValidEntryRegisters());
|
||||||
|
__ CallRuntime(f, arg_count);
|
||||||
|
Result result = cgen()->allocator()->Allocate(rax);
|
||||||
|
ASSERT(result.is_valid());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Result VirtualFrame::CallRuntime(Runtime::FunctionId id, int arg_count) {
|
||||||
|
PrepareForCall(arg_count, arg_count);
|
||||||
|
ASSERT(cgen()->HasValidEntryRegisters());
|
||||||
|
__ CallRuntime(id, arg_count);
|
||||||
|
Result result = cgen()->allocator()->Allocate(rax);
|
||||||
|
ASSERT(result.is_valid());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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).
|
||||||
|
InLoopFlag in_loop = loop_nesting > 0 ? IN_LOOP : NOT_IN_LOOP;
|
||||||
|
Handle<Code> ic = cgen()->ComputeCallInitialize(arg_count, in_loop);
|
||||||
|
// Spill args, receiver, and function. The call will drop args and
|
||||||
|
// receiver.
|
||||||
|
PrepareForCall(arg_count + 2, arg_count + 1);
|
||||||
|
return RawCallCodeObject(ic, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#undef __
|
#undef __
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user