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<F0>(Code::cast(code)->entry());
+ supported_ = probe();
}
// -----------------------------------------------------------------------------
}
+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_;
}
+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_;
}
+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_;
}
+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_;
}
+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_;
}
+void Assembler::popfq() {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ emit(0x9D);
+}
+
+
void Assembler::push(Register src) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
}
+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_;
}
+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_;
static void Probe();
// Check whether a feature is supported by the target CPU.
static bool IsSupported(Feature f) {
- return (supported_ & (static_cast<uint64_t>(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<uint64_t>(1) << f)) != 0;
+ return (enabled_ & (V8_UINT64_C(1) << f)) != 0;
}
// Enable a specified feature within a scope.
class Scope BASE_EMBEDDED {
explicit Scope(Feature f) {
ASSERT(CpuFeatures::IsSupported(f));
old_enabled_ = CpuFeatures::enabled_;
- CpuFeatures::enabled_ |= (static_cast<uint64_t>(1) << f);
+ CpuFeatures::enabled_ |= (V8_UINT64_C(1) << f);
}
~Scope() { CpuFeatures::enabled_ = old_enabled_; }
private:
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
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);
void pop(Register dst);
void pop(const Operand& dst);
- void enter(const Immediate& size);
+ void enter(Immediate size);
void leave();
// Moves
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);
void dec(Register dst);
void dec(const Operand& dst);
- void cdq();
+ // Sign-extends rax into rdx:rax.
+ void cqo();
void idiv(Register src);
inline void emitl(uint32_t x);
inline void emit(Handle<Object> 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
// 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);