diff --git a/src/memory.h b/src/memory.h index 1e36bf54ce..c64699ee3b 100644 --- a/src/memory.h +++ b/src/memory.h @@ -36,6 +36,10 @@ namespace internal { class Memory { public: + static uint16_t& uint16_at(Address addr) { + return *reinterpret_cast(addr); + } + static uint32_t& uint32_at(Address addr) { return *reinterpret_cast(addr); } diff --git a/src/x64/assembler-x64-inl.h b/src/x64/assembler-x64-inl.h index ad349345a4..8d82a53ff1 100644 --- a/src/x64/assembler-x64-inl.h +++ b/src/x64/assembler-x64-inl.h @@ -55,6 +55,12 @@ void Assembler::emitq(uint64_t x, RelocInfo::Mode rmode) { } +void Assembler::emitw(uint16_t x) { + Memory::uint16_at(pc_) = x; + pc_ += sizeof(uint16_t); +} + + // High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B. // REX.W is set. REX.X is cleared. void Assembler::emit_rex_64(Register reg, Register rm_reg) { @@ -118,14 +124,14 @@ void Assembler::emit_optional_rex_32(Register reg, const Operand& op) { } -void Assembler::set_target_address_at(byte* location, byte* value) { - UNIMPLEMENTED(); +Address Assembler::target_address_at(Address pc) { + return Memory::Address_at(pc); } -byte* Assembler::target_address_at(byte* location) { - UNIMPLEMENTED(); - return NULL; +void Assembler::set_target_address_at(Address pc, Address target) { + Memory::Address_at(pc) = target; + CPU::FlushICache(pc, sizeof(intptr_t)); } @@ -166,6 +172,8 @@ void RelocInfo::set_target_address(Address target) { ASSERT(IsCodeTarget(rmode_) || rmode_ == RUNTIME_ENTRY); Assembler::set_target_address_at(pc_, target); } + + Object* RelocInfo::target_object() { ASSERT(IsCodeTarget(rmode_) || rmode_ == EMBEDDED_OBJECT); return *reinterpret_cast(pc_); diff --git a/src/x64/assembler-x64.cc b/src/x64/assembler-x64.cc index 589db08898..ed9f2ad62e 100644 --- a/src/x64/assembler-x64.cc +++ b/src/x64/assembler-x64.cc @@ -77,7 +77,73 @@ uint64_t CpuFeatures::supported_ = 0; uint64_t CpuFeatures::enabled_ = 0; void CpuFeatures::Probe() { - // TODO(X64): UNIMPLEMENTED + ASSERT(Heap::HasBeenSetup()); + ASSERT(supported_ == 0); + if (Serializer::enabled()) return; // No features if we might serialize. + + Assembler assm(NULL, 0); + Label cpuid, done; +#define __ assm. + // Save old esp, since we are going to modify the stack. + __ push(rbp); + __ pushfq(); + __ push(rcx); + __ push(rbx); + __ movq(rbp, rsp); + + // If we can modify bit 21 of the EFLAGS register, then CPUID is supported. + __ pushfq(); + __ pop(rax); + __ movq(rdx, rax); + __ xor_(rax, Immediate(0x200000)); // Flip bit 21. + __ push(rax); + __ popfq(); + __ pushfq(); + __ pop(rax); + __ xor_(rax, rdx); // Different if CPUID is supported. + __ j(not_zero, &cpuid); + + // CPUID not supported. Clear the supported features in edx:eax. + __ xor_(rax, rax); + __ jmp(&done); + + // Invoke CPUID with 1 in eax to get feature information in + // ecx:edx. Temporarily enable CPUID support because we know it's + // safe here. + __ bind(&cpuid); + __ movq(rax, Immediate(1)); + supported_ = (1 << CPUID); + { Scope fscope(CPUID); + __ cpuid(); + } + supported_ = 0; + + // Move the result from ecx:edx to rax and make sure to mark the + // CPUID feature as supported. + __ movl(rax, rdx); // Zero-extended to 64 bits. + __ shl(rcx, Immediate(32)); + __ or_(rax, rcx); + __ or_(rax, Immediate(1 << CPUID)); + + // Done. + __ bind(&done); + __ movq(rsp, rbp); + __ pop(rbx); + __ pop(rcx); + __ popfq(); + __ pop(rbp); + __ ret(0); +#undef __ + + CodeDesc desc; + assm.GetCode(&desc); + Object* code = + Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB), NULL); + if (!code->IsCode()) return; + LOG(CodeCreateEvent("Builtin", Code::cast(code), "CpuFeatures::Probe")); + typedef uint64_t (*F0)(); + F0 probe = FUNCTION_CAST(Code::cast(code)->entry()); + supported_ = probe(); } // ----------------------------------------------------------------------------- @@ -368,6 +434,26 @@ void Assembler::shift(Register dst, int subcode) { } +void Assembler::bt(const Operand& dst, Register src) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit_rex_64(src, dst); + emit(0x0F); + emit(0xA3); + emit_operand(src, dst); +} + + +void Assembler::bts(const Operand& dst, Register src) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit_rex_64(src, dst); + emit(0x0F); + emit(0xAB); + emit_operand(src, dst); +} + + void Assembler::call(Label* L) { EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -401,6 +487,23 @@ void Assembler::call(Register adr) { } +void Assembler::cpuid() { + ASSERT(CpuFeatures::IsEnabled(CpuFeatures::CPUID)); + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit(0x0F); + emit(0xA2); +} + + +void Assembler::cqo() { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit_rex_64(); + emit(0x99); +} + + void Assembler::dec(Register dst) { EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -419,6 +522,15 @@ void Assembler::dec(const Operand& dst) { } +void Assembler::enter(Immediate size) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit(0xC8); + emitw(size.value_); // 16 bit operand, always. + emit(0); +} + + void Assembler::hlt() { EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -530,6 +642,49 @@ void Assembler::jmp(Register target) { } +void Assembler::lea(Register dst, const Operand& src) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit_rex_64(dst, src); + emit(0x8D); + emit_operand(dst, src); +} + + +void Assembler::leave() { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit(0xC9); +} + + +void Assembler::movl(Register dst, const Operand& src) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit_optional_rex_32(dst, src); + emit(0x8B); + emit_operand(dst, src); +} + + +void Assembler::movl(Register dst, Register src) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit_optional_rex_32(dst, src); + emit(0x8B); + emit(0xC0 | (dst.code() & 0x7) << 3 | (src.code() & 0x7)); +} + + +void Assembler::movl(const Operand& dst, Register src) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit_optional_rex_32(src, dst); + emit(0x89); + emit_operand(src, dst); +} + + void Assembler::movq(Register dst, const Operand& src) { EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -548,6 +703,15 @@ void Assembler::movq(Register dst, Register src) { } +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, Immediate value) { EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -716,6 +880,13 @@ void Assembler::pop(const Operand& dst) { } +void Assembler::popfq() { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit(0x9D); +} + + void Assembler::push(Register src) { EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -735,6 +906,43 @@ void Assembler::push(const Operand& src) { } +void Assembler::push(Immediate value) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + if (is_int8(value.value_)) { + emit(0x6A); + emit(value.value_); // Emit low byte of value. + } else { + emit(0x68); + emitl(value.value_); + } +} + + +void Assembler::pushfq() { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + emit(0x9C); +} + + +void Assembler::rcl(Register dst, uint8_t imm8) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + ASSERT(is_uint6(imm8)); // illegal shift count + if (imm8 == 1) { + emit_rex_64(dst); + emit(0xD1); + emit(0xD0 | (dst.code() & 0x7)); + } else { + emit_rex_64(dst); + emit(0xC1); + emit(0xD0 | (dst.code() & 0x7)); + emit(imm8); + } +} + + void Assembler::ret(int imm16) { EnsureSpace ensure_space(this); last_pc_ = pc_; @@ -749,6 +957,21 @@ void Assembler::ret(int imm16) { } +void Assembler::xchg(Register dst, Register src) { + EnsureSpace ensure_space(this); + last_pc_ = pc_; + if (src.is(rax) || dst.is(rax)) { // Single-byte encoding + Register other = src.is(rax) ? dst : src; + emit_rex_64(other); + emit(0x90 | (other.code() & 0x7)); + } else { + emit_rex_64(src, dst); + emit(0x87); + emit(0xC0 | (src.code() & 0x7) << 3 | (dst.code() & 0x7)); + } +} + + 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 b9973ef953..be88162000 100644 --- a/src/x64/assembler-x64.h +++ b/src/x64/assembler-x64.h @@ -294,11 +294,11 @@ class CpuFeatures : public AllStatic { static void Probe(); // Check whether a feature is supported by the target CPU. static bool IsSupported(Feature f) { - return (supported_ & (static_cast(1) << f)) != 0; + return (supported_ & (V8_UINT64_C(1) << f)) != 0; } // Check whether a feature is currently enabled. static bool IsEnabled(Feature f) { - return (enabled_ & (static_cast(1) << f)) != 0; + return (enabled_ & (V8_UINT64_C(1) << f)) != 0; } // Enable a specified feature within a scope. class Scope BASE_EMBEDDED { @@ -307,7 +307,7 @@ class CpuFeatures : public AllStatic { explicit Scope(Feature f) { ASSERT(CpuFeatures::IsSupported(f)); old_enabled_ = CpuFeatures::enabled_; - CpuFeatures::enabled_ |= (static_cast(1) << f); + CpuFeatures::enabled_ |= (V8_UINT64_C(1) << f); } ~Scope() { CpuFeatures::enabled_ = old_enabled_; } private: @@ -355,8 +355,9 @@ class Assembler : public Malloced { void GetCode(CodeDesc* desc); // Read/Modify the code target in the branch/call instruction at pc. - inline static Address target_address_at(Address pc); - inline static void set_target_address_at(Address pc, Address target); + // On the x64 architecture, the address is absolute, not relative. + static inline Address target_address_at(Address pc); + static inline void set_target_address_at(Address pc, Address target); // Distance between the address of the code target in the call instruction // and the return address @@ -387,13 +388,10 @@ class Assembler : public Malloced { void Align(int m); // Stack - void pushad(); - void popad(); + void pushfq(); + void popfq(); - void pushfd(); - void popfd(); - - void push(const Immediate& x); + void push(Immediate value); void push(Register src); void push(const Operand& src); void push(Label* label, RelocInfo::Mode relocation_mode); @@ -401,7 +399,7 @@ class Assembler : public Malloced { void pop(Register dst); void pop(const Operand& dst); - void enter(const Immediate& size); + void enter(Immediate size); void leave(); // Moves @@ -409,6 +407,10 @@ class Assembler : public Malloced { void movb(const Operand& dst, int8_t imm8); void movb(const Operand& dst, Register src); + void movl(Register dst, Register src); + void movl(Register dst, const Operand& src); + void movl(const Operand& dst, Register src); + void movq(Register dst, int32_t imm32); void movq(Register dst, Immediate x); void movq(Register dst, const Operand& src); @@ -515,7 +517,8 @@ class Assembler : public Malloced { void dec(Register dst); void dec(const Operand& dst); - void cdq(); + // Sign-extends rax into rdx:rax. + void cqo(); void idiv(Register src); @@ -830,6 +833,7 @@ class Assembler : public Malloced { inline void emitl(uint32_t x); inline void emit(Handle handle); inline void emitq(uint64_t x, RelocInfo::Mode rmode); + inline void emitw(uint16_t x); void emit(Immediate x) { emitl(x.value_); } // Emits a REX prefix that encodes a 64-bit operand size and @@ -858,6 +862,9 @@ class Assembler : public Malloced { // REX.W is set and REX.R clear. inline void emit_rex_64(const Operand& op); + // Emit a REX prefix that only sets REX.W to choose a 64-bit operand size. + void emit_rex_64() { emit(0x48); } + // High bit of reg goes to REX.R, high bit of rm_reg goes to REX.B. // REX.W is clear. inline void emit_rex_32(Register reg, Register rm_reg);