Chromium Code Reviews| 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); |
| } |