Author: l...@chromium.org
Date: Wed Jun 10 02:48:15 2009
New Revision: 2130

Modified:
    branches/bleeding_edge/src/ia32/macro-assembler-ia32.h
    branches/bleeding_edge/src/x64/assembler-x64-inl.h
    branches/bleeding_edge/src/x64/assembler-x64.cc
    branches/bleeding_edge/src/x64/assembler-x64.h
    branches/bleeding_edge/src/x64/builtins-x64.cc
    branches/bleeding_edge/src/x64/codegen-x64.cc
    branches/bleeding_edge/src/x64/frames-x64.h
    branches/bleeding_edge/src/x64/macro-assembler-x64.cc
    branches/bleeding_edge/src/x64/simulator-x64.h
    branches/bleeding_edge/test/cctest/test-assembler-x64.cc

Log:
X64: Implement CEntryStub and JSEntryTrampoline.
Still some supporting functions missing.

Review URL: http://codereview.chromium.org/114085


Modified: branches/bleeding_edge/src/ia32/macro-assembler-ia32.h
==============================================================================
--- branches/bleeding_edge/src/ia32/macro-assembler-ia32.h      (original)
+++ branches/bleeding_edge/src/ia32/macro-assembler-ia32.h      Wed Jun 10  
02:48:15 2009
@@ -285,7 +285,7 @@
    List<Unresolved> unresolved_;
    bool generating_stub_;
    bool allow_stub_calls_;
-  Handle<Object> code_object_;  // This handle will be patched with the  
code
+  Handle<Object> code_object_;  // This handle will be patched with the
                                  // code object on installation.

    // Helper functions for generating invokes.

Modified: branches/bleeding_edge/src/x64/assembler-x64-inl.h
==============================================================================
--- branches/bleeding_edge/src/x64/assembler-x64-inl.h  (original)
+++ branches/bleeding_edge/src/x64/assembler-x64-inl.h  Wed Jun 10 02:48:15  
2009
@@ -249,24 +249,6 @@
  //  
-----------------------------------------------------------------------------
  // Implementation of Operand

-Operand::Operand(Register base, int32_t disp) {
-  len_ = 1;
-  if (base.is(rsp) || base.is(r12)) {
-    // SIB byte is needed to encode (rsp + offset) or (r12 + offset).
-    set_sib(kTimes1, rsp, base);
-  }
-
-  if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
-    set_modrm(0, rsp);
-  } else if (is_int8(disp)) {
-    set_modrm(1, base);
-    set_disp8(disp);
-  } else {
-    set_modrm(2, base);
-    set_disp32(disp);
-  }
-}
-
  void Operand::set_modrm(int mod, Register rm) {
    ASSERT((mod & -4) == 0);
    buf_[0] = mod << 6 | (rm.code() & 0x7);

Modified: branches/bleeding_edge/src/x64/assembler-x64.cc
==============================================================================
--- branches/bleeding_edge/src/x64/assembler-x64.cc     (original)
+++ branches/bleeding_edge/src/x64/assembler-x64.cc     Wed Jun 10 02:48:15 2009
@@ -72,7 +72,49 @@
  XMMRegister xmm14 = { 14 };
  XMMRegister xmm15 = { 15 };

+
+Operand::Operand(Register base, int32_t disp) {
+  len_ = 1;
+  if (base.is(rsp) || base.is(r12)) {
+    // SIB byte is needed to encode (rsp + offset) or (r12 + offset).
+    set_sib(kTimes1, rsp, base);
+  }
+
+  if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
+    set_modrm(0, rsp);
+  } else if (is_int8(disp)) {
+    set_modrm(1, base);
+    set_disp8(disp);
+  } else {
+    set_modrm(2, base);
+    set_disp32(disp);
+  }
+}
+
+
+Operand::Operand(Register base,
+                 Register index,
+                 ScaleFactor scale,
+                 int32_t disp) {
+  ASSERT(!index.is(rsp) && !index.is(r12));
+  len_ = 1;
+  set_sib(scale, index, base);
+  if (disp == 0 && !base.is(rbp) && !base.is(r13)) {
+    // The call to set_modrm doesn't overwrite the REX.B bit possibly set
+    // by set_sib.
+    set_modrm(0, rsp);
+  } else if (is_int8(disp)) {
+    set_modrm(1, rsp);
+    set_disp8(disp);
+  } else {
+    set_modrm(2, rsp);
+    set_disp32(disp);
+  }
+}
+
+
  // Safe default is no features.
+// TODO(X64): Safe defaults include SSE2 for X64.
  uint64_t CpuFeatures::supported_ = 0;
  uint64_t CpuFeatures::enabled_ = 0;

@@ -487,6 +529,7 @@
    emit_modrm(0x2, adr);
  }

+
  void Assembler::cpuid() {
    ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CPUID));
    EnsureSpace ensure_space(this);
@@ -844,6 +887,31 @@
  }


+void Assembler::movq(const Operand& dst, Immediate value) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit_rex_64(dst);
+  emit(0xC7);
+  emit_operand(0, dst);
+  emit(value);
+}
+
+
+void Assembler::movq(Register dst, Handle<Object> value, RelocInfo::Mode  
mode) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  ASSERT(!Heap::InNewSpace(*value));
+  emit_rex_64(dst);
+  emit(0xB8 | dst.code() & 0x7);
+  if (value->IsHeapObject()) {
+    emitq(reinterpret_cast<uintptr_t>(value.location()), mode);
+  } else {
+    ASSERT_EQ(RelocInfo::NONE, mode);
+    emitq(reinterpret_cast<uintptr_t>(*value), RelocInfo::NONE);
+  }
+}
+
+
  void Assembler::mul(Register src) {
    EnsureSpace ensure_space(this);
    last_pc_ = pc_;
@@ -1129,6 +1197,7 @@


  void Assembler::testb(Register reg, Immediate mask) {
+  ASSERT(is_int8(mask.value_));
    EnsureSpace ensure_space(this);
    last_pc_ = pc_;
    if (reg.is(rax)) {
@@ -1147,6 +1216,7 @@


  void Assembler::testb(const Operand& op, Immediate mask) {
+  ASSERT(is_int8(mask.value_));
    EnsureSpace ensure_space(this);
    last_pc_ = pc_;
    emit_optional_rex_32(rax, op);
@@ -1196,6 +1266,22 @@
    emit_rex_64(dst, src);
    emit(0x85);
    emit_modrm(dst, src);
+}
+
+
+void Assembler::testq(Register dst, Immediate mask) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  if (dst.is(rax)) {
+    emit_rex_64();
+    emit(0xA9);
+    emit(mask);
+  } else {
+    emit_rex_64(dst);
+    emit(0xF7);
+    emit_modrm(0, dst);
+    emit(mask);
+  }
  }



Modified: branches/bleeding_edge/src/x64/assembler-x64.h
==============================================================================
--- branches/bleeding_edge/src/x64/assembler-x64.h      (original)
+++ branches/bleeding_edge/src/x64/assembler-x64.h      Wed Jun 10 02:48:15 2009
@@ -77,7 +77,7 @@

  struct Register {
    static Register toRegister(int code) {
-    Register r = {code};
+    Register r = { code };
      return r;
    }
    bool is_valid() const  { return 0 <= code_ && code_ < 16; }
@@ -89,11 +89,11 @@
      return code_;
    }
    int bit() const  {
-    UNIMPLEMENTED();
-    return 0;
+    return 1 << code_;
    }

-  // (unfortunately we can't make this private in a struct)
+  // (unfortunately we can't make this private in a struct when  
initializing
+  // by assignment.)
    int code_;
  };

@@ -250,7 +250,7 @@
  class Operand BASE_EMBEDDED {
   public:
    // [base + disp/r]
-  INLINE(Operand(Register base, int32_t disp));
+  Operand(Register base, int32_t disp);

    // [base + index*scale + disp/r]
    Operand(Register base,
@@ -434,7 +434,8 @@

    // Move 64 bit register value to 64-bit memory location.
    void movq(const Operand& dst, Register src);
-
+  // Move sign extended immediate to memory location.
+  void movq(const Operand& dst, Immediate value);
    // New x64 instructions to load a 64-bit immediate into a register.
    // All 64-bit immediates must have a relocation mode.
    void movq(Register dst, void* ptr, RelocInfo::Mode rmode);
@@ -444,7 +445,6 @@
    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);
@@ -647,6 +647,7 @@
    void testl(const Operand& op, Immediate mask);
    void testq(const Operand& op, Register reg);
    void testq(Register dst, Register src);
+  void testq(Register dst, Immediate mask);

    void xor_(Register dst, Register src) {
      arithmetic_op(0x33, dst, src);

Modified: branches/bleeding_edge/src/x64/builtins-x64.cc
==============================================================================
--- branches/bleeding_edge/src/x64/builtins-x64.cc      (original)
+++ branches/bleeding_edge/src/x64/builtins-x64.cc      Wed Jun 10 02:48:15 2009
@@ -27,10 +27,13 @@

  #include "v8.h"
  #include "codegen-inl.h"
+#include "macro-assembler.h"

  namespace v8 {
  namespace internal {

+#define __ ACCESS_MASM(masm)
+
  void Builtins::Generate_Adaptor(MacroAssembler* masm,
                                  Builtins::CFunctionId id) {
    masm->int3();  // UNIMPLEMENTED.
@@ -52,12 +55,125 @@
    masm->int3();  // UNIMPLEMENTED.
  }

-void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED.
+static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm,
+                                             bool is_construct) {
+  // Expects five C++ function parameters.
+  // - Address entry (ignored)
+  // - JSFunction* function (
+  // - Object* receiver
+  // - int argc
+  // - Object*** argv
+  // (see Handle::Invoke in execution.cc).
+
+  // Platform specific argument handling. After this, the stack contains
+  // an internal frame and the pushed function and receiver, and
+  // register rax and rbx holds the argument count and argument array,
+  // while rdi holds the function pointer and rsi the context.
+#ifdef __MSVC__
+  // MSVC parameters in:
+  // rcx : entry (ignored)
+  // rdx : function
+  // r8 : receiver
+  // r9 : argc
+  // [rsp+0x20] : argv
+
+  // Clear the context before we push it when entering the JS frame.
+  __ xor_(rsi, rsi);
+  // Enter an internal frame.
+  __ EnterInternalFrame();
+
+
+  // Load the function context into rsi.
+  __ movq(rsi, FieldOperand(rdx, JSFunction::kContextOffset));
+
+  // Push the function and the receiver onto the stack.
+  __ push(rdx);
+  __ push(r8);
+
+  // Load the number of arguments and setup pointer to the arguments.
+  __ movq(rax, r9);
+  // Load the previous frame pointer to access C argument on stack
+  __ movq(kScratchRegister, Operand(rbp, 0));
+  __ movq(rbx, Operand(kScratchRegister,  
EntryFrameConstants::kArgvOffset));
+  // Load the function pointer into rdi.
+  __ movq(rdi, rdx);
+#else  // !defined(__MSVC__)
+  // GCC parameters in:
+  // rdi : entry (ignored)
+  // rsi : function
+  // rdx : receiver
+  // rcx : argc
+  // r8  : argv
+
+  __ movq(rdi, rsi);
+  // rdi : function
+
+  // Clear the context before we push it when entering the JS frame.
+  __ xor_(rsi, rsi);
+  // Enter an internal frame.
+  __ EnterInternalFrame();
+
+  // Push the function and receiver and setup the context.
+  __ push(rdi);
+  __ push(rdx);
+  __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
+
+  // Load the number of arguments and setup pointer to the arguments.
+  __ movq(rax, rcx);
+  __ movq(rbx, r8);
+#endif  // __MSVC__
+  // Current stack contents:
+  // [rsp + 2 * kPointerSize ... ]: Internal frame
+  // [rsp + kPointerSize]         : function
+  // [rsp]                        : receiver
+  // Current register contents:
+  // rax : argc
+  // rbx : argv
+  // rsi : context
+  // rdi : function
+
+  // Copy arguments to the stack in a loop.
+  // Register rbx points to array of pointers to handle locations.
+  // Push the values of these handles.
+  Label loop, entry;
+  __ xor_(rcx, rcx);  // Set loop variable to 0.
+  __ jmp(&entry);
+  __ bind(&loop);
+  __ movq(kScratchRegister, Operand(rbx, rcx, kTimesPointerSize, 0));
+  __ push(Operand(kScratchRegister, 0));  // dereference handle
+  __ add(rcx, Immediate(1));
+  __ bind(&entry);
+  __ cmp(rcx, rax);
+  __ j(not_equal, &loop);
+
+  // Invoke the code.
+  if (is_construct) {
+    // Expects rdi to hold function pointer.
+    __ movq(kScratchRegister,
+            Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)),
+            RelocInfo::CODE_TARGET);
+    __ call(kScratchRegister);
+  } else {
+    ParameterCount actual(rax);
+    __ InvokeFunction(rdi, actual, CALL_FUNCTION);
+  }
+
+  // Exit the JS frame. Notice that this also removes the empty
+  // context and the function left on the stack by the code
+  // invocation.
+  __ LeaveInternalFrame();
+  // TODO(X64): Is argument correct? Is there a receiver to remove?
+  __ ret(1 * kPointerSize);  // remove receiver
  }

+
  void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
-  masm->int3();  // UNIMPLEMENTED.
+  Generate_JSEntryTrampolineHelper(masm, false);
+}
+
+
+void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
+  Generate_JSEntryTrampolineHelper(masm, true);
  }

  } }  // namespace v8::internal

Modified: branches/bleeding_edge/src/x64/codegen-x64.cc
==============================================================================
--- branches/bleeding_edge/src/x64/codegen-x64.cc       (original)
+++ branches/bleeding_edge/src/x64/codegen-x64.cc       Wed Jun 10 02:48:15 2009
@@ -58,7 +58,7 @@
        in_spilled_code_(false) {
  }

-#define __ masm->
+#define __ ACCESS_MASM(masm)


  void CodeGenerator::DeclareGlobals(Handle<FixedArray> a) {
@@ -236,8 +236,250 @@
  }


+void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
+  // Check that stack should contain frame pointer, code pointer, state and
+  // return address in that order.
+  ASSERT_EQ(StackHandlerConstants::kFPOffset + kPointerSize,
+            StackHandlerConstants::kStateOffset);
+  ASSERT_EQ(StackHandlerConstants::kStateOffset + kPointerSize,
+            StackHandlerConstants::kPCOffset);
+
+  ExternalReference handler_address(Top::k_handler_address);
+  __ movq(kScratchRegister, handler_address);
+  __ movq(rdx, Operand(kScratchRegister, 0));
+  // get next in chain
+  __ movq(rcx, Operand(rdx, 0));
+  __ movq(Operand(kScratchRegister, 0), rcx);
+  __ movq(rsp, rdx);
+  __ pop(rbp);  // pop frame pointer
+  __ pop(rdx);  // remove code pointer
+  __ pop(rdx);  // remove state
+
+  // Before returning we restore the context from the frame pointer if not  
NULL.
+  // The frame pointer is NULL in the exception handler of a JS entry  
frame.
+  __ xor_(rsi, rsi);  // tentatively set context pointer to NULL
+  Label skip;
+  __ cmp(rbp, Immediate(0));
+  __ j(equal, &skip);
+  __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
+  __ bind(&skip);
+
+  __ ret(0);
+}
+
+
+
+void CEntryStub::GenerateCore(MacroAssembler* masm,
+                              Label* throw_normal_exception,
+                              Label* throw_out_of_memory_exception,
+                              StackFrame::Type frame_type,
+                              bool do_gc,
+                              bool always_allocate_scope) {
+  // rax: result parameter for PerformGC, if any
+  // rbx: pointer to C function  (C callee-saved)
+  // rbp: frame pointer  (restored after C call)
+  // rsp: stack pointer  (restored after C call)
+  // rdi: number of arguments including receiver  (C callee-saved)
+  // rsi: pointer to the first argument (C callee-saved)
+
+  if (do_gc) {
+    __ movq(Operand(rsp, 0), rax);  // Result.
+    __ movq(kScratchRegister,
+            FUNCTION_ADDR(Runtime::PerformGC),
+            RelocInfo::RUNTIME_ENTRY);
+    __ call(kScratchRegister);
+  }
+
+  ExternalReference scope_depth =
+      ExternalReference::heap_always_allocate_scope_depth();
+  if (always_allocate_scope) {
+    __ movq(kScratchRegister, scope_depth);
+    __ inc(Operand(kScratchRegister, 0));
+  }
+
+  // Call C function.
+#ifdef __MSVC__
+  // MSVC passes arguments in rcx, rdx, r8, r9
+  __ movq(rcx, rdi);  // argc.
+  __ movq(rdx, rsi);  // argv.
+#else  // ! defined(__MSVC__)
+  // GCC passes arguments in rdi, rsi, rdx, rcx, r8, r9.
+  // First two arguments are already in rdi, rsi.
+#endif
+  __ call(rbx);
+  // Result is in rax - do not destroy this register!
+
+  if (always_allocate_scope) {
+    __ movq(kScratchRegister, scope_depth);
+    __ dec(Operand(kScratchRegister, 0));
+  }
+
+  // Check for failure result.
+  Label failure_returned;
+  ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
+  __ lea(rcx, Operand(rax, 1));
+  // Lower 2 bits of rcx are 0 iff rax has failure tag.
+  __ testl(rcx, Immediate(kFailureTagMask));
+  __ j(zero, &failure_returned);
+
+  // Exit the JavaScript to C++ exit frame.
+  __ LeaveExitFrame(frame_type);
+  __ ret(0);
+
+  // Handling of failure.
+  __ bind(&failure_returned);
+
+  Label retry;
+  // If the returned exception is RETRY_AFTER_GC continue at retry label
+  ASSERT(Failure::RETRY_AFTER_GC == 0);
+  __ testq(rax, Immediate(((1 << kFailureTypeTagSize) - 1) <<  
kFailureTagSize));
+  __ j(zero, &retry);
+
+  Label continue_exception;
+  // If the returned failure is EXCEPTION then promote  
Top::pending_exception().
+  __ movq(kScratchRegister, Failure::Exception(), RelocInfo::NONE);
+  __ cmp(rax, kScratchRegister);
+  __ j(not_equal, &continue_exception);
+
+  // Retrieve the pending exception and clear the variable.
+  ExternalReference  
pending_exception_address(Top::k_pending_exception_address);
+  __ movq(kScratchRegister, pending_exception_address);
+  __ movq(rax, Operand(kScratchRegister, 0));
+  __ movq(rdx, ExternalReference::the_hole_value_location());
+  __ movq(rdx, Operand(rdx, 0));
+  __ movq(Operand(kScratchRegister, 0), rdx);
+
+  __ bind(&continue_exception);
+  // Special handling of out of memory exception.
+  __ movq(kScratchRegister, Failure::OutOfMemoryException(),  
RelocInfo::NONE);
+  __ cmp(rax, kScratchRegister);
+  __ j(equal, throw_out_of_memory_exception);
+
+  // Handle normal exception.
+  __ jmp(throw_normal_exception);
+
+  // Retry.
+  __ bind(&retry);
+}
+
+
+void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
+  // Fetch top stack handler.
+  ExternalReference handler_address(Top::k_handler_address);
+  __ movq(kScratchRegister, handler_address);
+  __ movq(rdx, Operand(kScratchRegister, 0));
+
+  // Unwind the handlers until the ENTRY handler is found.
+  Label loop, done;
+  __ bind(&loop);
+  // Load the type of the current stack handler.
+  __ cmp(Operand(rdx, StackHandlerConstants::kStateOffset),
+         Immediate(StackHandler::ENTRY));
+  __ j(equal, &done);
+  // Fetch the next handler in the list.
+  __ movq(rdx, Operand(rdx, StackHandlerConstants::kNextOffset));
+  __ jmp(&loop);
+  __ bind(&done);
+
+  // Set the top handler address to next handler past the current ENTRY  
handler.
+  __ movq(rax, Operand(rdx, StackHandlerConstants::kNextOffset));
+  __ store_rax(handler_address);
+
+  // Set external caught exception to false.
+  __ movq(rax, Immediate(false));
+  ExternalReference  
external_caught(Top::k_external_caught_exception_address);
+  __ store_rax(external_caught);
+
+  // Set pending exception and rax to out of memory exception.
+  __ movq(rax, Failure::OutOfMemoryException(), RelocInfo::NONE);
+  ExternalReference pending_exception(Top::k_pending_exception_address);
+  __ store_rax(pending_exception);
+
+  // Restore the stack to the address of the ENTRY handler
+  __ movq(rsp, rdx);
+
+  // Clear the context pointer;
+  __ xor_(rsi, rsi);
+
+  // Restore registers from handler.
+
+  __ pop(rbp);  // FP
+  ASSERT_EQ(StackHandlerConstants::kFPOffset + kPointerSize,
+            StackHandlerConstants::kStateOffset);
+  __ pop(rdx);  // State
+
+  ASSERT_EQ(StackHandlerConstants::kStateOffset + kPointerSize,
+            StackHandlerConstants::kPCOffset);
+  __ ret(0);
+}
+
+
  void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
-  masm->int3();  // TODO(X64): UNIMPLEMENTED.
+  // rax: number of arguments including receiver
+  // rbx: pointer to C function  (C callee-saved)
+  // rbp: frame pointer  (restored after C call)
+  // rsp: stack pointer  (restored after C call)
+  // rsi: current context (C callee-saved)
+  // rdi: caller's parameter pointer pp  (C callee-saved)
+
+  // NOTE: Invocations of builtins may return failure objects
+  // instead of a proper result. The builtin entry handles
+  // this by performing a garbage collection and retrying the
+  // builtin once.
+
+  StackFrame::Type frame_type = is_debug_break ?
+      StackFrame::EXIT_DEBUG :
+      StackFrame::EXIT;
+
+  // Enter the exit frame that transitions from JavaScript to C++.
+  __ EnterExitFrame(frame_type);
+
+  // rax: result parameter for PerformGC, if any (setup below)
+  // rbx: pointer to builtin function  (C callee-saved)
+  // rbp: frame pointer  (restored after C call)
+  // rsp: stack pointer  (restored after C call)
+  // rdi: number of arguments including receiver (C callee-saved)
+  // rsi: argv pointer (C callee-saved)
+
+  Label throw_out_of_memory_exception;
+  Label throw_normal_exception;
+
+  // Call into the runtime system. Collect garbage before the call if
+  // running with --gc-greedy set.
+  if (FLAG_gc_greedy) {
+    Failure* failure = Failure::RetryAfterGC(0);
+    __ movq(rax, failure, RelocInfo::NONE);
+  }
+  GenerateCore(masm, &throw_normal_exception,
+               &throw_out_of_memory_exception,
+               frame_type,
+               FLAG_gc_greedy,
+               false);
+
+  // Do space-specific GC and retry runtime call.
+  GenerateCore(masm,
+               &throw_normal_exception,
+               &throw_out_of_memory_exception,
+               frame_type,
+               true,
+               false);
+
+  // Do full GC and retry runtime call one final time.
+  Failure* failure = Failure::InternalError();
+  __ movq(rax, failure, RelocInfo::NONE);
+  GenerateCore(masm,
+               &throw_normal_exception,
+               &throw_out_of_memory_exception,
+               frame_type,
+               true,
+               true);
+
+  __ bind(&throw_out_of_memory_exception);
+  GenerateThrowOutOfMemory(masm);
+  // control flow for generated will not return.
+
+  __ bind(&throw_normal_exception);
+  GenerateThrowTOS(masm);
  }



Modified: branches/bleeding_edge/src/x64/frames-x64.h
==============================================================================
--- branches/bleeding_edge/src/x64/frames-x64.h (original)
+++ branches/bleeding_edge/src/x64/frames-x64.h Wed Jun 10 02:48:15 2009
@@ -32,11 +32,18 @@
  namespace internal {

  // TODO(x64): This is a stub, mostly just a copy of the ia32 bit version.
-// This will all need to change to be correct for x64.
+// This might all need to change to be correct for x64.

  static const int kNumRegs = 8;
-static const RegList kJSCallerSaved = 0;
+static const RegList kJSCallerSaved =
+    1 << 0 |  // rax
+    1 << 1 |  // rcx
+    1 << 2 |  // rdx
+    1 << 3 |  // rbx - used as a caller-saved register in JavaScript code
+    1 << 7;   // rdi - callee function
+
  static const int kNumJSCallerSaved = 5;
+
  typedef Object* JSCallerSavedBuffer[kNumJSCallerSaved];

  class StackHandlerConstants : public AllStatic {
@@ -52,24 +59,26 @@

  class EntryFrameConstants : public AllStatic {
   public:
-  static const int kCallerFPOffset      = -1 * kPointerSize;
+  static const int kCallerFPOffset      = 0 * kPointerSize;

-  static const int kFunctionArgOffset   = -1 * kPointerSize;
-  static const int kReceiverArgOffset   = -1 * kPointerSize;
-  static const int kArgcOffset          = -1 * kPointerSize;
-  static const int kArgvOffset          = -1 * kPointerSize;
+  static const int kFunctionArgOffset   = 1 * kPointerSize;
+  static const int kReceiverArgOffset   = 2 * kPointerSize;
+  static const int kArgcOffset          = 3 * kPointerSize;
+  static const int kArgvOffset          = 4 * kPointerSize;
  };


  class ExitFrameConstants : public AllStatic {
   public:
-  static const int kDebugMarkOffset = -1 * kPointerSize;
+  static const int kDebugMarkOffset = -2 * kPointerSize;
    static const int kSPOffset        = -1 * kPointerSize;

-  static const int kPPDisplacement = -1 * kPointerSize;
+  // TODO(X64): Remove usage of PP in exit frames?
+  // Still used though StackFrame::pp()
+  static const int kPPDisplacement  = +2 * kPointerSize;

-  static const int kCallerFPOffset = -1 * kPointerSize;
-  static const int kCallerPCOffset = -1 * kPointerSize;
+  static const int kCallerFPOffset  = +0 * kPointerSize;
+  static const int kCallerPCOffset  = +1 * kPointerSize;
  };



Modified: branches/bleeding_edge/src/x64/macro-assembler-x64.cc
==============================================================================
--- branches/bleeding_edge/src/x64/macro-assembler-x64.cc       (original)
+++ branches/bleeding_edge/src/x64/macro-assembler-x64.cc       Wed Jun 10  
02:48:15 2009
@@ -29,7 +29,9 @@

  #include "bootstrapper.h"
  #include "codegen-inl.h"
+#include "assembler-x64.h"
  #include "macro-assembler-x64.h"
+#include "debug.h"

  namespace v8 {
  namespace internal {
@@ -43,6 +45,53 @@
  }


+void MacroAssembler::Assert(Condition cc, const char* msg) {
+  if (FLAG_debug_code) Check(cc, msg);
+}
+
+
+void MacroAssembler::Check(Condition cc, const char* msg) {
+  Label L;
+  j(cc, &L);
+  Abort(msg);
+  // will not return here
+  bind(&L);
+}
+
+
+void MacroAssembler::Abort(const char* msg) {
+  // We want to pass the msg string like a smi to avoid GC
+  // problems, however msg is not guaranteed to be aligned
+  // properly. Instead, we pass an aligned pointer that is
+  // a proper v8 smi, but also pass the alignment difference
+  // from the real pointer as a smi.
+  intptr_t p1 = reinterpret_cast<intptr_t>(msg);
+  intptr_t p0 = (p1 & ~kSmiTagMask) + kSmiTag;
+  // Note: p0 might not be a valid Smi *value*, but it has a valid Smi tag.
+  ASSERT(reinterpret_cast<Object*>(p0)->IsSmi());
+#ifdef DEBUG
+  if (msg != NULL) {
+    RecordComment("Abort message: ");
+    RecordComment(msg);
+  }
+#endif
+  push(rax);
+  movq(kScratchRegister, p0, RelocInfo::NONE);
+  push(kScratchRegister);
+  movq(kScratchRegister,
+       reinterpret_cast<intptr_t>(Smi::FromInt(p1 - p0)),
+       RelocInfo::NONE);
+  push(kScratchRegister);
+  CallRuntime(Runtime::kAbort, 2);
+  // will not return here
+}
+
+
+void MacroAssembler::CallRuntime(Runtime::FunctionId id, int argc) {
+  UNIMPLEMENTED();
+}
+
+
  void MacroAssembler::TailCallRuntime(ExternalReference const& a, int b) {
    UNIMPLEMENTED();
  }
@@ -106,6 +155,230 @@
    push(Operand(kScratchRegister, 0));
    // Link this handler.
    movq(Operand(kScratchRegister, 0), rsp);
+}
+
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+
+void MacroAssembler::PushRegistersFromMemory(RegList regs) {
+  ASSERT((regs & ~kJSCallerSaved) == 0);
+  // Push the content of the memory location to the stack.
+  for (int i = 0; i < kNumJSCallerSaved; i++) {
+    int r = JSCallerSavedCode(i);
+    if ((regs & (1 << r)) != 0) {
+      ExternalReference reg_addr =
+          ExternalReference(Debug_Address::Register(i));
+      movq(kScratchRegister, reg_addr);
+      push(Operand(kScratchRegister, 0));
+    }
+  }
+}
+
+void MacroAssembler::SaveRegistersToMemory(RegList regs) {
+  ASSERT((regs & ~kJSCallerSaved) == 0);
+  // Copy the content of registers to memory location.
+  for (int i = 0; i < kNumJSCallerSaved; i++) {
+    int r = JSCallerSavedCode(i);
+    if ((regs & (1 << r)) != 0) {
+      Register reg = { r };
+      ExternalReference reg_addr =
+          ExternalReference(Debug_Address::Register(i));
+      movq(kScratchRegister, reg_addr);
+      movq(Operand(kScratchRegister, 0), reg);
+    }
+  }
+}
+
+
+void MacroAssembler::RestoreRegistersFromMemory(RegList regs) {
+  ASSERT((regs & ~kJSCallerSaved) == 0);
+  // Copy the content of memory location to registers.
+  for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
+    int r = JSCallerSavedCode(i);
+    if ((regs & (1 << r)) != 0) {
+      Register reg = { r };
+      ExternalReference reg_addr =
+          ExternalReference(Debug_Address::Register(i));
+      movq(kScratchRegister, reg_addr);
+      movq(reg, Operand(kScratchRegister, 0));
+    }
+  }
+}
+
+
+void MacroAssembler::PopRegistersToMemory(RegList regs) {
+  ASSERT((regs & ~kJSCallerSaved) == 0);
+  // Pop the content from the stack to the memory location.
+  for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
+    int r = JSCallerSavedCode(i);
+    if ((regs & (1 << r)) != 0) {
+      ExternalReference reg_addr =
+          ExternalReference(Debug_Address::Register(i));
+      movq(kScratchRegister, reg_addr);
+      pop(Operand(kScratchRegister, 0));
+    }
+  }
+}
+
+
+void MacroAssembler::CopyRegistersFromStackToMemory(Register base,
+                                                    Register scratch,
+                                                    RegList regs) {
+  ASSERT(!scratch.is(kScratchRegister));
+  ASSERT(!base.is(kScratchRegister));
+  ASSERT(!base.is(scratch));
+  ASSERT((regs & ~kJSCallerSaved) == 0);
+  // Copy the content of the stack to the memory location and adjust base.
+  for (int i = kNumJSCallerSaved - 1; i >= 0; i--) {
+    int r = JSCallerSavedCode(i);
+    if ((regs & (1 << r)) != 0) {
+      movq(scratch, Operand(base, 0));
+      ExternalReference reg_addr =
+          ExternalReference(Debug_Address::Register(i));
+      movq(kScratchRegister, reg_addr);
+      movq(Operand(kScratchRegister, 0), scratch);
+      lea(base, Operand(base, kPointerSize));
+    }
+  }
+}
+
+#endif  // ENABLE_DEBUGGER_SUPPORT
+
+
+
+
+void MacroAssembler::InvokeFunction(Register fun,
+                                    const ParameterCount& actual,
+                                    InvokeFlag flag) {
+  UNIMPLEMENTED();
+}
+
+
+void MacroAssembler::EnterFrame(StackFrame::Type type) {
+  push(rbp);
+  movq(rbp, rsp);
+  push(rsi);  // Context.
+  push(Immediate(Smi::FromInt(type)));
+  movq(kScratchRegister, CodeObject(), RelocInfo::EMBEDDED_OBJECT);
+  push(kScratchRegister);
+  if (FLAG_debug_code) {
+    movq(kScratchRegister,
+         Factory::undefined_value(),
+         RelocInfo::EMBEDDED_OBJECT);
+    cmp(Operand(rsp, 0), kScratchRegister);
+    Check(not_equal, "code object not properly patched");
+  }
+}
+
+
+void MacroAssembler::LeaveFrame(StackFrame::Type type) {
+  if (FLAG_debug_code) {
+    movq(kScratchRegister, Immediate(Smi::FromInt(type)));
+    cmp(Operand(rbp, StandardFrameConstants::kMarkerOffset),  
kScratchRegister);
+    Check(equal, "stack frame types must match");
+  }
+  movq(rsp, rbp);
+  pop(rbp);
+}
+
+
+
+void MacroAssembler::EnterExitFrame(StackFrame::Type type) {
+  ASSERT(type == StackFrame::EXIT || type == StackFrame::EXIT_DEBUG);
+
+  // Setup the frame structure on the stack.
+  ASSERT(ExitFrameConstants::kPPDisplacement == +2 * kPointerSize);
+  ASSERT(ExitFrameConstants::kCallerPCOffset == +1 * kPointerSize);
+  ASSERT(ExitFrameConstants::kCallerFPOffset ==  0 * kPointerSize);
+  push(rbp);
+  movq(rbp, rsp);
+
+  // Reserve room for entry stack pointer and push the debug marker.
+  ASSERT(ExitFrameConstants::kSPOffset  == -1 * kPointerSize);
+  push(Immediate(0));  // saved entry sp, patched before call
+  push(Immediate(type == StackFrame::EXIT_DEBUG ? 1 : 0));
+
+  // Save the frame pointer and the context in top.
+  ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
+  ExternalReference context_address(Top::k_context_address);
+  movq(kScratchRegister, rax);
+  movq(rax, rbp);
+  store_rax(c_entry_fp_address);
+  movq(rax, rsi);
+  store_rax(context_address);
+  movq(rax, kScratchRegister);
+
+  // Setup argc and argv in callee-saved registers.
+  int offset = StandardFrameConstants::kCallerSPOffset - kPointerSize;
+  movq(rdi, rax);
+  lea(rsi, Operand(rbp, rax, kTimesPointerSize, offset));
+
+#ifdef ENABLE_DEBUGGER_SUPPORT
+  // Save the state of all registers to the stack from the memory
+  // location. This is needed to allow nested break points.
+  if (type == StackFrame::EXIT_DEBUG) {
+    // TODO(1243899): This should be symmetric to
+    // CopyRegistersFromStackToMemory() but it isn't! esp is assumed
+    // correct here, but computed for the other call. Very error
+    // prone! FIX THIS.  Actually there are deeper problems with
+    // register saving than this asymmetry (see the bug report
+    // associated with this issue).
+    PushRegistersFromMemory(kJSCallerSaved);
+  }
+#endif
+
+  // Reserve space for two arguments: argc and argv.
+  sub(rsp, Immediate(2 * kPointerSize));
+
+  // Get the required frame alignment for the OS.
+  static const int kFrameAlignment = OS::ActivationFrameAlignment();
+  if (kFrameAlignment > 0) {
+    ASSERT(IsPowerOf2(kFrameAlignment));
+    movq(r10, Immediate(-kFrameAlignment));
+    and_(rsp, r10);
+  }
+
+  // Patch the saved entry sp.
+  movq(Operand(rbp, ExitFrameConstants::kSPOffset), rsp);
+}
+
+
+void MacroAssembler::LeaveExitFrame(StackFrame::Type type) {
+#ifdef ENABLE_DEBUGGER_SUPPORT
+  // Restore the memory copy of the registers by digging them out from
+  // the stack. This is needed to allow nested break points.
+  if (type == StackFrame::EXIT_DEBUG) {
+    // It's okay to clobber register ebx below because we don't need
+    // the function pointer after this.
+    const int kCallerSavedSize = kNumJSCallerSaved * kPointerSize;
+    int kOffset = ExitFrameConstants::kDebugMarkOffset - kCallerSavedSize;
+    lea(rbx, Operand(rbp, kOffset));
+    CopyRegistersFromStackToMemory(rbx, rcx, kJSCallerSaved);
+  }
+#endif
+
+  // Get the return address from the stack and restore the frame pointer.
+  movq(rcx, Operand(rbp, 1 * kPointerSize));
+  movq(rbp, Operand(rbp, 0 * kPointerSize));
+
+  // Pop the arguments and the receiver from the caller stack.
+  lea(rsp, Operand(rsi, 1 * kPointerSize));
+
+  // Restore current context from top and clear it in debug mode.
+  ExternalReference context_address(Top::k_context_address);
+  movq(kScratchRegister, context_address);
+  movq(rsi, Operand(kScratchRegister, 0));
+#ifdef DEBUG
+  movq(Operand(kScratchRegister, 0), Immediate(0));
+#endif
+
+  // Push the return address to get ready to return.
+  push(rcx);
+
+  // Clear the top frame.
+  ExternalReference c_entry_fp_address(Top::k_c_entry_fp_address);
+  movq(kScratchRegister, c_entry_fp_address);
+  movq(Operand(kScratchRegister, 0), Immediate(0));
  }



Modified: branches/bleeding_edge/src/x64/simulator-x64.h
==============================================================================
--- branches/bleeding_edge/src/x64/simulator-x64.h      (original)
+++ branches/bleeding_edge/src/x64/simulator-x64.h      Wed Jun 10 02:48:15 2009
@@ -31,6 +31,7 @@

  // Since there is no simulator for the ia32 architecture the only thing we  
can
  // do is to call the entry directly.
+// TODO(X64): Don't pass p0, since it isn't used?
  #define CALL_GENERATED_CODE(entry, p0, p1, p2, p3, p4) \
    entry(p0, p1, p2, p3, p4);


Modified: branches/bleeding_edge/test/cctest/test-assembler-x64.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-assembler-x64.cc    (original)
+++ branches/bleeding_edge/test/cctest/test-assembler-x64.cc    Wed Jun 10  
02:48:15 2009
@@ -248,4 +248,5 @@
    int result =  FUNCTION_CAST<F0>(buffer)();
    CHECK_EQ(1, result);
  }
+
  #undef __

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
v8-dev@googlegroups.com
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to