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:
parent
32ce7956ac
commit
b918e64dc3
@ -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; }
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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_;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user