X64: JSEntry Stub
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 4 Jun 2009 11:54:14 +0000 (11:54 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 4 Jun 2009 11:54:14 +0000 (11:54 +0000)
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
src/x64/assembler-x64-inl.h
src/x64/assembler-x64.cc
src/x64/assembler-x64.h
src/x64/codegen-x64.cc
src/x64/frames-x64.h
src/x64/macro-assembler-x64.cc
src/x64/macro-assembler-x64.h

index a75befb1fe1920b8eac4fed7c504179d7a396003..e250609fd9a8ec7b0305aac9f91c0566e1cbfb1d 100644 (file)
@@ -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; }
index 830523e8662cef72026c4555a901237f3e8475a6..18225681edb16b5ad76246cc1a88c5317127df8d 100644 (file)
@@ -37,6 +37,11 @@ Condition NegateCondition(Condition cc) {
   return static_cast<Condition>(cc ^ 1);
 }
 
+// -----------------------------------------------------------------------------
+
+Immediate::Immediate(Smi* value) {
+  value_ = static_cast<int32_t>(reinterpret_cast<intptr_t>(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);
 }
 
 
index 794c286f962c0aff08fff87f2552188c78757c8c..77bbf524053722d4450dc4a8ceb18448c4abcbd3 100644 (file)
@@ -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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(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_;
index 5dee67585aab92cb522d4385c1ab5a05caa2895c..b4882571e21af0782772b69b9aa4cce37979a945 100644 (file)
@@ -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<Object> 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
index 3df547098d6969b75f592130cc021988a205ecea..7e2e6ed2b1d097c86cdd5c7bc481264f4e8e2934 100644 (file)
@@ -50,6 +50,9 @@ CodeGenerator::CodeGenerator(int buffer_size,
       in_spilled_code_(false) {
 }
 
+#define __ masm->
+
+
 void CodeGenerator::DeclareGlobals(Handle<FixedArray> 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
index 345e33a6bbadc69f1ce2a060cdfc74338f34f67e..3416f51dea3584fc1550f15702c69e35444de8ff 100644 (file)
@@ -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;
 };
 
 
index 968b459b2b8f06fa05f9a9b0aa24734b8ba78b39..54c299dbfae9894ff96cec5b59fbf835d3a99c57 100644 (file)
@@ -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
index 61834e01ac2825dd2100bb7c1b74220d5beceb0c..4af372a81a3eae3ed4742337b15fab141467a42e 100644 (file)
@@ -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);