From b918e64dc3981d7f0fea661852fc34c15757bf14 Mon Sep 17 00:00:00 2001 From: "lrn@chromium.org" Date: Thu, 4 Jun 2009 11:54:14 +0000 Subject: [PATCH] X64: JSEntry Stub Review URL: http://codereview.chromium.org/118115 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2104 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/frames.h | 3 +- src/x64/assembler-x64-inl.h | 10 +++- src/x64/assembler-x64.cc | 66 +++++++++++++++++++++-- src/x64/assembler-x64.h | 10 +++- src/x64/codegen-x64.cc | 98 ++++++++++++++++++++++++++++++++-- src/x64/frames-x64.h | 14 ++--- src/x64/macro-assembler-x64.cc | 43 +++++++++++++++ src/x64/macro-assembler-x64.h | 5 +- 8 files changed, 229 insertions(+), 20 deletions(-) diff --git a/src/frames.h b/src/frames.h index a75befb1f..e250609fd 100644 --- a/src/frames.h +++ b/src/frames.h @@ -443,7 +443,8 @@ class ArgumentsAdaptorFrame: public JavaScriptFrame { // the sentinel as its context, it is an arguments adaptor frame. It // must be tagged as a small integer to avoid GC issues. Crud. enum { - SENTINEL = (1 << kSmiTagSize) | kSmiTag + SENTINEL = (1 << kSmiTagSize) | kSmiTag, + NON_SENTINEL = ~SENTINEL }; virtual Type type() const { return ARGUMENTS_ADAPTOR; } diff --git a/src/x64/assembler-x64-inl.h b/src/x64/assembler-x64-inl.h index 830523e86..18225681e 100644 --- a/src/x64/assembler-x64-inl.h +++ b/src/x64/assembler-x64-inl.h @@ -37,6 +37,11 @@ Condition NegateCondition(Condition cc) { return static_cast(cc ^ 1); } +// ----------------------------------------------------------------------------- + +Immediate::Immediate(Smi* value) { + value_ = static_cast(reinterpret_cast(value)); +} // ----------------------------------------------------------------------------- // Implementation of Assembler @@ -51,7 +56,10 @@ void Assembler::emitl(uint32_t x) { void Assembler::emitq(uint64_t x, RelocInfo::Mode rmode) { Memory::uint64_at(pc_) = x; - RecordRelocInfo(rmode, x); + if (rmode != RelocInfo::NONE) { + RecordRelocInfo(rmode, x); + } + pc_ += sizeof(uint64_t); } diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc index 794c286f9..77bbf5240 100644 --- a/src/x64/assembler-x64.cc +++ b/src/x64/assembler-x64.cc @@ -486,7 +486,6 @@ void Assembler::call(Register adr) { emit_modrm(0x2, adr); } - void Assembler::cpuid() { ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CPUID)); EnsureSpace ensure_space(this); @@ -496,6 +495,16 @@ void Assembler::cpuid() { } +void Assembler::call(const Operand& op) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + // Opcode: FF /2 m64 + emit_rex_64(op); + emit(0xFF); + emit_operand(2, op); +} + + void Assembler::cqo() { EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -686,6 +695,20 @@ void Assembler::lea(Register dst, const Operand& src) { } +void Assembler::load_rax(void* value, RelocInfo::Mode mode) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit(0x48); // REX.W + emit(0xA1); + emitq(reinterpret_cast(value), mode); +} + + +void Assembler::load_rax(ExternalReference ref) { + load_rax(ref.address(), RelocInfo::EXTERNAL_REFERENCE); +} + + void Assembler::leave() { EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -783,6 +806,24 @@ void Assembler::movq(Register dst, Immediate value) { } +void Assembler::movq(const Operand& dst, Register src) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit_rex_64(src, dst); + emit(0x89); + emit_operand(src, dst); +} + + +void Assembler::movq(Register dst, void* value, RelocInfo::Mode rmode) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit_rex_64(dst); + emit(0xB8 | (dst.code() & 0x7)); + emitq(reinterpret_cast(value), rmode); +} + + void Assembler::movq(Register dst, int64_t value, RelocInfo::Mode rmode) { EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -792,12 +833,13 @@ void Assembler::movq(Register dst, int64_t value, RelocInfo::Mode rmode) { } -void Assembler::movq(const Operand& dst, Register src) { +void Assembler::movq(Register dst, ExternalReference ref) { EnsureSpace ensure_space(this); last_pc_ = pc_; - emit_rex_64(src, dst); - emit(0x89); - emit_operand(src, dst); + emit_rex_64(dst); + emit(0xB8 | (dst.code() & 0x7)); + emitq(reinterpret_cast(ref.address()), + RelocInfo::EXTERNAL_REFERENCE); } @@ -1071,6 +1113,20 @@ void Assembler::xchg(Register dst, Register src) { } +void Assembler::store_rax(void* dst, RelocInfo::Mode mode) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit(0x48); // REX.W + emit(0xA3); + emitq(reinterpret_cast(dst), mode); +} + + +void Assembler::store_rax(ExternalReference ref) { + store_rax(ref.address(), RelocInfo::EXTERNAL_REFERENCE); +} + + void Assembler::testb(Register reg, Immediate mask) { EnsureSpace ensure_space(this); last_pc_ = pc_; diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h index 5dee67585..b4882571e 100644 --- a/src/x64/assembler-x64.h +++ b/src/x64/assembler-x64.h @@ -440,12 +440,14 @@ class Assembler : public Malloced { void movq(Register dst, void* ptr, RelocInfo::Mode rmode); void movq(Register dst, int64_t value, RelocInfo::Mode rmode); void movq(Register dst, const char* s, RelocInfo::Mode rmode); - void movq(Register dst, const ExternalReference& ext, RelocInfo::Mode rmode); + // Moves the address of the external reference into the register. + void movq(Register dst, ExternalReference ext); void movq(Register dst, Handle handle, RelocInfo::Mode rmode); // New x64 instruction to load from an immediate 64-bit pointer into RAX. void load_rax(void* ptr, RelocInfo::Mode rmode); + void load_rax(ExternalReference ext); void movsx_b(Register dst, const Operand& src); @@ -616,6 +618,9 @@ class Assembler : public Malloced { shift(dst, 0x5); } + void store_rax(void* dst, RelocInfo::Mode mode); + void store_rax(ExternalReference ref); + void sub(Register dst, Register src) { arithmetic_op(0x2B, dst, src); } @@ -700,6 +705,9 @@ class Assembler : public Malloced { // Call near absolute indirect, address in register void call(Register adr); + // Call near indirect + void call(const Operand& operand); + // Jumps // Jump short or near relative. void jmp(Label* L); // unconditional jump to L diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index 3df547098..7e2e6ed2b 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -50,6 +50,9 @@ CodeGenerator::CodeGenerator(int buffer_size, in_spilled_code_(false) { } +#define __ masm-> + + void CodeGenerator::DeclareGlobals(Handle a) { UNIMPLEMENTED(); } @@ -229,10 +232,97 @@ void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) { masm->int3(); // TODO(X64): UNIMPLEMENTED. } -void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { - masm->int3(); // TODO(X64): UNIMPLEMENTED. -} - +void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) { + Label invoke, exit; + + // Setup frame. + __ push(rbp); + __ movq(rbp, rsp); + + // Save callee-saved registers (X64 calling conventions). + int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY; + // Push something that is not an arguments adaptor. + __ push(Immediate(ArgumentsAdaptorFrame::NON_SENTINEL)); + __ push(Immediate(Smi::FromInt(marker))); // @ function offset + __ push(r12); + __ push(r13); + __ push(r14); + __ push(r15); + __ push(rdi); + __ push(rsi); + __ push(rbx); + // TODO(X64): Push XMM6-XMM15 (low 64 bits) as well, or make them + // callee-save in JS code as well. + + // Save copies of the top frame descriptor on the stack. + ExternalReference c_entry_fp(Top::k_c_entry_fp_address); + __ load_rax(c_entry_fp); + __ push(rax); + + // Call a faked try-block that does the invoke. + __ call(&invoke); + + // Caught exception: Store result (exception) in the pending + // exception field in the JSEnv and return a failure sentinel. + ExternalReference pending_exception(Top::k_pending_exception_address); + __ store_rax(pending_exception); + __ movq(rax, Failure::Exception(), RelocInfo::NONE); + __ jmp(&exit); + + // Invoke: Link this frame into the handler chain. + __ bind(&invoke); + __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER); + __ push(rax); // flush TOS + + // Clear any pending exceptions. + __ load_rax(ExternalReference::the_hole_value_location()); + __ store_rax(pending_exception); + + // Fake a receiver (NULL). + __ push(Immediate(0)); // receiver + + // Invoke the function by calling through JS entry trampoline + // builtin and pop the faked function when we return. We load the address + // from an external reference instead of inlining the call target address + // directly in the code, because the builtin stubs may not have been + // generated yet at the time this code is generated. + if (is_construct) { + ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline); + __ load_rax(construct_entry); + } else { + ExternalReference entry(Builtins::JSEntryTrampoline); + __ load_rax(entry); + } + __ call(FieldOperand(rax, Code::kHeaderSize)); + + // Unlink this frame from the handler chain. + __ movq(kScratchRegister, ExternalReference(Top::k_handler_address)); + __ pop(Operand(kScratchRegister, 0)); + // Pop next_sp. + __ add(rsp, Immediate(StackHandlerConstants::kSize - kPointerSize)); + + // Restore the top frame descriptor from the stack. + __ bind(&exit); + __ movq(kScratchRegister, ExternalReference(Top::k_c_entry_fp_address)); + __ pop(Operand(kScratchRegister, 0)); + + // Restore callee-saved registers (X64 conventions). + __ pop(rbx); + __ pop(rsi); + __ pop(rdi); + __ pop(r15); + __ pop(r14); + __ pop(r13); + __ pop(r12); + __ add(rsp, Immediate(2 * kPointerSize)); // remove markers + + // Restore frame pointer and return. + __ pop(rbp); + __ ret(0); +} + + +#undef __ } } // namespace v8::internal diff --git a/src/x64/frames-x64.h b/src/x64/frames-x64.h index 345e33a6b..3416f51de 100644 --- a/src/x64/frames-x64.h +++ b/src/x64/frames-x64.h @@ -41,17 +41,17 @@ typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved]; class StackHandlerConstants : public AllStatic { public: - static const int kNextOffset = -1 * kPointerSize; - static const int kPPOffset = -1 * kPointerSize; - static const int kFPOffset = -1 * kPointerSize; + static const int kNextOffset = 0 * kPointerSize; + static const int kPPOffset = 1 * kPointerSize; + static const int kFPOffset = 2 * kPointerSize; - static const int kCodeOffset = -1 * kPointerSize; + static const int kCodeOffset = 3 * kPointerSize; - static const int kStateOffset = -1 * kPointerSize; - static const int kPCOffset = -1 * kPointerSize; + static const int kStateOffset = 4 * kPointerSize; + static const int kPCOffset = 5 * kPointerSize; static const int kAddressDisplacement = -1 * kPointerSize; - static const int kSize = kPCOffset + kPointerSize; + static const int kSize = 6 * kPointerSize; }; diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc index 968b459b2..54c299dbf 100644 --- a/src/x64/macro-assembler-x64.cc +++ b/src/x64/macro-assembler-x64.cc @@ -42,6 +42,7 @@ MacroAssembler::MacroAssembler(void* buffer, int size) code_object_(Heap::undefined_value()) { } + void MacroAssembler::TailCallRuntime(ExternalReference const& a, int b) { UNIMPLEMENTED(); } @@ -70,4 +71,46 @@ void MacroAssembler::Set(const Operand& dst, int64_t x) { } +void MacroAssembler::PushTryHandler(CodeLocation try_location, + HandlerType type) { + // The pc (return address) is already on TOS. + // This code pushes state, code, frame pointer and parameter pointer. + // Check that they are expected next on the stack, int that order. + ASSERT_EQ(StackHandlerConstants::kStateOffset, + StackHandlerConstants::kPCOffset - kPointerSize); + ASSERT_EQ(StackHandlerConstants::kCodeOffset, + StackHandlerConstants::kStateOffset - kPointerSize); + ASSERT_EQ(StackHandlerConstants::kFPOffset, + StackHandlerConstants::kCodeOffset - kPointerSize); + ASSERT_EQ(StackHandlerConstants::kPPOffset, + StackHandlerConstants::kFPOffset - kPointerSize); + + if (try_location == IN_JAVASCRIPT) { + if (type == TRY_CATCH_HANDLER) { + push(Immediate(StackHandler::TRY_CATCH)); + } else { + push(Immediate(StackHandler::TRY_FINALLY)); + } + push(Immediate(Smi::FromInt(StackHandler::kCodeNotPresent))); + push(rbp); + push(rdi); + } else { + ASSERT(try_location == IN_JS_ENTRY); + // The parameter pointer is meaningless here and ebp does not + // point to a JS frame. So we save NULL for both pp and ebp. We + // expect the code throwing an exception to check ebp before + // dereferencing it to restore the context. + push(Immediate(StackHandler::ENTRY)); + push(Immediate(Smi::FromInt(StackHandler::kCodeNotPresent))); + push(Immediate(0)); // NULL frame pointer + push(Immediate(0)); // NULL parameter pointer + } + movq(kScratchRegister, ExternalReference(Top::k_handler_address)); + // Cached TOS. + movq(rax, Operand(kScratchRegister, 0)); + // Link this handler. + movq(Operand(kScratchRegister, 0), rsp); +} + + } } // namespace v8::internal diff --git a/src/x64/macro-assembler-x64.h b/src/x64/macro-assembler-x64.h index 61834e01a..4af372a81 100644 --- a/src/x64/macro-assembler-x64.h +++ b/src/x64/macro-assembler-x64.h @@ -33,6 +33,9 @@ namespace v8 { namespace internal { +// Default scratch register used by MacroAssembler (and other code that needs +// a spare register). The register isn't callee save, and not used by the +// function calling convention. static const Register kScratchRegister = r10; // Forward declaration. @@ -158,7 +161,7 @@ class MacroAssembler: public Assembler { // Push a new try handler and link into try handler chain. // The return address must be pushed before calling this helper. - // On exit, eax contains TOS (next_sp). + // On exit, rax contains TOS (next_sp). void PushTryHandler(CodeLocation try_location, HandlerType type); -- 2.34.1