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
This commit is contained in:
lrn@chromium.org 2009-06-04 11:54:14 +00:00
parent 32ce7956ac
commit b918e64dc3
8 changed files with 226 additions and 17 deletions

View 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; }

View 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);
}

View 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_;

View 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

View 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.
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

View 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;
};

View 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

View 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);