Index: src/x64/macro-assembler-x64.cc |
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc |
index 9e989d17b3a0dd69bf9202aa8fa07f4349750276..39d68ce03968a62f378e7098b68a51d2875d1be8 100644 |
--- a/src/x64/macro-assembler-x64.cc |
+++ b/src/x64/macro-assembler-x64.cc |
@@ -45,6 +45,32 @@ MacroAssembler::MacroAssembler(void* buffer, int size) |
} |
William Hesse
2009/06/11 09:32:29
These are already implemented (using incl and addl
|
+void MacroAssembler::IncrementCounter(StatsCounter* counter, int value) { |
+ ASSERT(value > 0); |
+ if (FLAG_native_code_counters && counter->Enabled()) { |
+ movq(kScratchRegister, ExternalReference(counter)); |
+ if (value == 1) { |
+ inc(Operand(kScratchRegister, 0)); |
+ } else { |
+ add(Operand(kScratchRegister, 0), Immediate(value)); |
+ } |
+ } |
+} |
+ |
+ |
+void MacroAssembler::DecrementCounter(StatsCounter* counter, int value) { |
+ ASSERT(value > 0); |
+ if (FLAG_native_code_counters && counter->Enabled()) { |
+ movq(kScratchRegister, ExternalReference(counter)); |
+ if (value == 1) { |
+ dec(Operand(kScratchRegister, 0)); |
+ } else { |
+ sub(Operand(kScratchRegister, 0), Immediate(value)); |
+ } |
+ } |
+} |
+ |
+ |
void MacroAssembler::Assert(Condition cc, const char* msg) { |
if (FLAG_debug_code) Check(cc, msg); |
} |
@@ -87,13 +113,65 @@ void MacroAssembler::Abort(const char* msg) { |
} |
-void MacroAssembler::CallRuntime(Runtime::FunctionId id, int argc) { |
- UNIMPLEMENTED(); |
+void MacroAssembler::CallStub(CodeStub* stub) { |
+ ASSERT(allow_stub_calls()); // calls are not allowed in some stubs |
+ movq(kScratchRegister, stub->GetCode(), RelocInfo::CODE_TARGET); |
+ call(kScratchRegister); |
+} |
+ |
+ |
+void MacroAssembler::StubReturn(int argc) { |
+ ASSERT(argc >= 1 && generating_stub()); |
+ ret((argc - 1) * kPointerSize); |
+} |
+ |
+ |
+void MacroAssembler::IllegalOperation(int num_arguments) { |
+ if (num_arguments > 0) { |
+ add(rsp, Immediate(num_arguments * kPointerSize)); |
+ } |
+ movq(rax, Factory::undefined_value(), RelocInfo::EMBEDDED_OBJECT); |
+} |
+ |
+ |
+void MacroAssembler::CallRuntime(Runtime::FunctionId id, int num_arguments) { |
+ CallRuntime(Runtime::FunctionForId(id), num_arguments); |
+} |
+ |
+ |
+void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) { |
+ // If the expected number of arguments of the runtime function is |
+ // constant, we check that the actual number of arguments match the |
+ // expectation. |
+ if (f->nargs >= 0 && f->nargs != num_arguments) { |
+ IllegalOperation(num_arguments); |
+ return; |
+ } |
+ |
+ Runtime::FunctionId function_id = |
+ static_cast<Runtime::FunctionId>(f->stub_id); |
+ RuntimeStub stub(function_id, num_arguments); |
+ CallStub(&stub); |
+} |
+ |
+ |
+void MacroAssembler::TailCallRuntime(ExternalReference const& ext, |
+ int num_arguments) { |
+ // TODO(1236192): Most runtime routines don't need the number of |
+ // arguments passed in because it is constant. At some point we |
+ // should remove this need and make the runtime routine entry code |
+ // smarter. |
+ movq(rax, Immediate(num_arguments)); |
+ JumpToBuiltin(ext); |
} |
-void MacroAssembler::TailCallRuntime(ExternalReference const& a, int b) { |
- UNIMPLEMENTED(); |
+void MacroAssembler::JumpToBuiltin(const ExternalReference& ext) { |
+ // Set the entry point and jump to the C entry runtime stub. |
+ movq(rbx, ext); |
+ CEntryStub ces; |
+ movq(kScratchRegister, ces.GetCode(), RelocInfo::CODE_TARGET); |
+ jmp(kScratchRegister); |
} |
@@ -245,12 +323,121 @@ void MacroAssembler::CopyRegistersFromStackToMemory(Register base, |
#endif // ENABLE_DEBUGGER_SUPPORT |
+void MacroAssembler::InvokePrologue(const ParameterCount& expected, |
+ const ParameterCount& actual, |
+ Handle<Code> code_constant, |
+ Register code_register, |
+ Label* done, |
+ InvokeFlag flag) { |
+ bool definitely_matches = false; |
+ Label invoke; |
+ if (expected.is_immediate()) { |
+ ASSERT(actual.is_immediate()); |
+ if (expected.immediate() == actual.immediate()) { |
+ definitely_matches = true; |
+ } else { |
+ movq(rax, Immediate(actual.immediate())); |
+ const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel; |
William Hesse
2009/06/11 09:32:29
This is only used once. It is no more constant th
|
+ if (expected.immediate() == sentinel) { |
+ // Don't worry about adapting arguments for built-ins that |
+ // don't want that done. Skip adaption code by making it look |
+ // like we have a match between expected and actual number of |
+ // arguments. |
+ definitely_matches = true; |
+ } else { |
+ movq(rbx, Immediate(expected.immediate())); |
+ } |
+ } |
+ } else { |
+ if (actual.is_immediate()) { |
+ // Expected is in register, actual is immediate. This is the |
+ // case when we invoke function values without going through the |
+ // IC mechanism. |
+ cmp(expected.reg(), Immediate(actual.immediate())); |
+ j(equal, &invoke); |
+ ASSERT(expected.reg().is(rbx)); |
+ movq(rax, Immediate(actual.immediate())); |
+ } else if (!expected.reg().is(actual.reg())) { |
+ // Both expected and actual are in (different) registers. This |
+ // is the case when we invoke functions using call and apply. |
+ cmp(expected.reg(), actual.reg()); |
+ j(equal, &invoke); |
+ ASSERT(actual.reg().is(rax)); |
+ ASSERT(expected.reg().is(rbx)); |
+ } |
+ } |
+ |
+ if (!definitely_matches) { |
+ Handle<Code> adaptor = |
+ Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)); |
+ if (!code_constant.is_null()) { |
+ movq(rdx, code_constant, RelocInfo::EMBEDDED_OBJECT); |
+ add(rdx, Immediate(Code::kHeaderSize - kHeapObjectTag)); |
+ } else if (!code_register.is(rdx)) { |
+ movq(rdx, code_register); |
+ } |
+ |
+ movq(kScratchRegister, adaptor, RelocInfo::CODE_TARGET); |
+ if (flag == CALL_FUNCTION) { |
+ call(kScratchRegister); |
+ jmp(done); |
+ } else { |
+ jmp(kScratchRegister); |
+ } |
+ bind(&invoke); |
+ } |
+} |
+ |
+ |
+ |
+ |
+void MacroAssembler::InvokeCode(Register code, |
+ const ParameterCount& expected, |
+ const ParameterCount& actual, |
+ InvokeFlag flag) { |
+ Label done; |
+ InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag); |
+ if (flag == CALL_FUNCTION) { |
+ call(code); |
+ } else { |
+ ASSERT(flag == JUMP_FUNCTION); |
+ jmp(code); |
+ } |
+ bind(&done); |
+} |
+ |
+ |
+void MacroAssembler::InvokeCode(Handle<Code> code, |
+ const ParameterCount& expected, |
+ const ParameterCount& actual, |
+ RelocInfo::Mode rmode, |
+ InvokeFlag flag) { |
+ Label done; |
+ Register dummy = rax; |
+ InvokePrologue(expected, actual, code, dummy, &done, flag); |
+ movq(kScratchRegister, code, rmode); |
+ if (flag == CALL_FUNCTION) { |
+ call(kScratchRegister); |
+ } else { |
+ ASSERT(flag == JUMP_FUNCTION); |
+ jmp(kScratchRegister); |
+ } |
+ bind(&done); |
+} |
void MacroAssembler::InvokeFunction(Register fun, |
const ParameterCount& actual, |
InvokeFlag flag) { |
- UNIMPLEMENTED(); |
+ ASSERT(fun.is(rdi)); |
William Hesse
2009/06/11 09:32:29
Can we use function instead of fun as the paramete
|
+ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); |
+ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); |
+ movq(rbx, FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset)); |
+ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset)); |
+ lea(rdx, FieldOperand(rdx, Code::kHeaderSize)); |
+ |
+ ParameterCount expected(rbx); |
+ InvokeCode(rdx, expected, actual, flag); |
} |