Author: [email protected]
Date: Wed Feb 25 06:57:46 2009
New Revision: 1364
Modified:
branches/bleeding_edge/src/api.cc
branches/bleeding_edge/src/assembler-ia32.cc
branches/bleeding_edge/src/assembler-ia32.h
branches/bleeding_edge/src/codegen-ia32.cc
branches/bleeding_edge/src/cpu-ia32.cc
branches/bleeding_edge/src/mksnapshot.cc
branches/bleeding_edge/src/serialize.cc
branches/bleeding_edge/src/serialize.h
branches/bleeding_edge/src/v8.cc
branches/bleeding_edge/test/cctest/test-assembler-ia32.cc
branches/bleeding_edge/test/cctest/test-disasm-ia32.cc
branches/bleeding_edge/test/cctest/test-serialize.cc
Log:
Use SSE3 instructions - if available - for faster To(U)Int32
conversion in bit operation stubs. Disable serialization
support by default to allow us to use SSE3 instructions and
faster write barrier code when running without snapshot.
Review URL: http://codereview.chromium.org/27046
Modified: branches/bleeding_edge/src/api.cc
==============================================================================
--- branches/bleeding_edge/src/api.cc (original)
+++ branches/bleeding_edge/src/api.cc Wed Feb 25 06:57:46 2009
@@ -2175,7 +2175,6 @@
if (i::V8::HasBeenSetup()) return true;
HandleScope scope;
if (i::Snapshot::Initialize()) {
- i::Serializer::disable();
return true;
} else {
return i::V8::Initialize(NULL);
Modified: branches/bleeding_edge/src/assembler-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/assembler-ia32.cc (original)
+++ branches/bleeding_edge/src/assembler-ia32.cc Wed Feb 25 06:57:46 2009
@@ -69,27 +69,27 @@
// Implementation of CpuFeatures
// Safe default is no features.
-uint32_t CpuFeatures::supported_ = 0;
-uint32_t CpuFeatures::enabled_ = 0;
+uint64_t CpuFeatures::supported_ = 0;
+uint64_t CpuFeatures::enabled_ = 0;
-typedef int (*F0)();
-
// The Probe method needs executable memory, so it uses Heap::CreateCode.
// Allocation failure is silent and leads to safe default.
void CpuFeatures::Probe() {
- supported_ = 0;
+ ASSERT(Heap::HasBeenSetup());
+ ASSERT(supported_ == 0);
if (Serializer::enabled()) return; // No features if we might serialize.
+
Assembler assm(NULL, 0);
- Label done;
+ Label cpuid, done;
#define __ assm.
// Save old esp, since we are going to modify the stack.
__ push(ebp);
__ pushfd();
__ push(ecx);
- __ push(edx);
__ push(ebx);
__ mov(ebp, Operand(esp));
+
// If we can modify bit 21 of the EFLAGS register, then CPUID is
supported.
__ pushfd();
__ pop(eax);
@@ -100,34 +100,48 @@
__ pushfd();
__ pop(eax);
__ xor_(eax, Operand(edx)); // Different if CPUID is supported.
- __ j(zero, &done);
- // Invoke CPUID with 1 in eax to get feature information in edx.
+ __ j(not_zero, &cpuid);
+
+ // CPUID not supported. Clear the supported features in edx:eax.
+ __ xor_(eax, Operand(eax));
+ __ xor_(edx, Operand(edx));
+ __ 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);
__ mov(eax, 1);
- // Temporarily force CPUID support, since we know it is safe here.
supported_ = (1 << CPUID);
{ Scope fscope(CPUID);
__ cpuid();
}
supported_ = 0;
- // Return result in eax.
+
+ // Move the result from ecx:edx to edx:eax and make sure to mark the
+ // CPUID feature as supported.
__ mov(eax, Operand(edx));
+ __ or_(eax, 1 << CPUID);
+ __ mov(edx, Operand(ecx));
+
+ // Done.
__ bind(&done);
__ mov(esp, Operand(ebp));
__ pop(ebx);
- __ pop(edx);
__ pop(ecx);
__ popfd();
__ pop(ebp);
__ ret(0);
#undef __
+
CodeDesc desc;
assm.GetCode(&desc);
Object* code =
Heap::CreateCode(desc, NULL, Code::ComputeFlags(Code::STUB), NULL);
if (!code->IsCode()) return;
- F0 f = FUNCTION_CAST<F0>(Code::cast(code)->entry());
- uint32_t res = f();
- supported_ = (res | (1 << CPUID));
+ typedef uint64_t (*F0)();
+ F0 probe = FUNCTION_CAST<F0>(Code::cast(code)->entry());
+ supported_ = probe();
}
@@ -1614,6 +1628,15 @@
}
+void Assembler::fisttp_s(const Operand& adr) {
+ ASSERT(CpuFeatures::IsEnabled(CpuFeatures::SSE3));
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ EMIT(0xDB);
+ emit_operand(ecx, adr);
+}
+
+
void Assembler::fist_s(const Operand& adr) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
@@ -1806,6 +1829,14 @@
last_pc_ = pc_;
EMIT(0xD9);
EMIT(0xFC);
+}
+
+
+void Assembler::fnclex() {
+ EnsureSpace ensure_space(this);
+ last_pc_ = pc_;
+ EMIT(0xDB);
+ EMIT(0xE2);
}
Modified: branches/bleeding_edge/src/assembler-ia32.h
==============================================================================
--- branches/bleeding_edge/src/assembler-ia32.h (original)
+++ branches/bleeding_edge/src/assembler-ia32.h Wed Feb 25 06:57:46 2009
@@ -347,14 +347,18 @@
// Feature flags bit positions. They are mostly based on the CPUID spec.
// (We assign CPUID itself to one of the currently reserved bits --
// feel free to change this if needed.)
- enum Feature { SSE2 = 26, CMOV = 15, RDTSC = 4, CPUID = 10 };
+ enum Feature { SSE3 = 32, SSE2 = 26, CMOV = 15, RDTSC = 4, CPUID = 10 };
// Detect features of the target CPU. Set safe defaults if the serializer
// is enabled (snapshots must be portable).
static void Probe();
// Check whether a feature is supported by the target CPU.
- static bool IsSupported(Feature f) { return supported_ & (1 << f); }
+ static bool IsSupported(Feature f) {
+ return (supported_ & (static_cast<uint64_t>(1) << f)) != 0;
+ }
// Check whether a feature is currently enabled.
- static bool IsEnabled(Feature f) { return enabled_ & (1 << f); }
+ static bool IsEnabled(Feature f) {
+ return (enabled_ & (static_cast<uint64_t>(1) << f)) != 0;
+ }
// Enable a specified feature within a scope.
class Scope BASE_EMBEDDED {
#ifdef DEBUG
@@ -362,19 +366,19 @@
explicit Scope(Feature f) {
ASSERT(CpuFeatures::IsSupported(f));
old_enabled_ = CpuFeatures::enabled_;
- CpuFeatures::enabled_ |= (1 << f);
+ CpuFeatures::enabled_ |= (static_cast<uint64_t>(1) << f);
}
~Scope() { CpuFeatures::enabled_ = old_enabled_; }
private:
- uint32_t old_enabled_;
+ uint64_t old_enabled_;
#else
public:
explicit Scope(Feature f) {}
#endif
};
private:
- static uint32_t supported_;
- static uint32_t enabled_;
+ static uint64_t supported_;
+ static uint64_t enabled_;
};
@@ -635,6 +639,8 @@
void fistp_s(const Operand& adr);
void fistp_d(const Operand& adr);
+ void fisttp_s(const Operand& adr);
+
void fabs();
void fchs();
@@ -663,6 +669,7 @@
void fcompp();
void fnstsw_ax();
void fwait();
+ void fnclex();
void frndint();
Modified: branches/bleeding_edge/src/codegen-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/codegen-ia32.cc (original)
+++ branches/bleeding_edge/src/codegen-ia32.cc Wed Feb 25 06:57:46 2009
@@ -4507,31 +4507,44 @@
FloatingPointHelper::CheckFloatOperands(masm, &call_runtime, ebx);
FloatingPointHelper::LoadFloatOperands(masm, ecx);
- Label non_int32_operands, non_smi_result, skip_allocation;
+ Label skip_allocation, non_smi_result, operand_conversion_failure;
+
// Reserve space for converted numbers.
__ sub(Operand(esp), Immediate(2 * kPointerSize));
- // Check if right operand is int32.
- __ fist_s(Operand(esp, 1 * kPointerSize));
- __ fild_s(Operand(esp, 1 * kPointerSize));
- __ fucompp();
- __ fnstsw_ax();
- __ sahf();
- __ j(not_zero, &non_int32_operands);
- __ j(parity_even, &non_int32_operands);
-
- // Check if left operand is int32.
- __ fist_s(Operand(esp, 0 * kPointerSize));
- __ fild_s(Operand(esp, 0 * kPointerSize));
- __ fucompp();
- __ fnstsw_ax();
- __ sahf();
- __ j(not_zero, &non_int32_operands);
- __ j(parity_even, &non_int32_operands);
+ bool use_sse3 = CpuFeatures::IsSupported(CpuFeatures::SSE3);
+ if (use_sse3) {
+ // Truncate the operands to 32-bit integers and check for
+ // exceptions in doing so.
+ CpuFeatures::Scope scope(CpuFeatures::SSE3);
+ __ fisttp_s(Operand(esp, 0 * kPointerSize));
+ __ fisttp_s(Operand(esp, 1 * kPointerSize));
+ __ fnstsw_ax();
+ __ test(eax, Immediate(1));
+ __ j(not_zero, &operand_conversion_failure);
+ } else {
+ // Check if right operand is int32.
+ __ fist_s(Operand(esp, 0 * kPointerSize));
+ __ fild_s(Operand(esp, 0 * kPointerSize));
+ __ fucompp();
+ __ fnstsw_ax();
+ __ sahf();
+ __ j(not_zero, &operand_conversion_failure);
+ __ j(parity_even, &operand_conversion_failure);
+
+ // Check if left operand is int32.
+ __ fist_s(Operand(esp, 1 * kPointerSize));
+ __ fild_s(Operand(esp, 1 * kPointerSize));
+ __ fucompp();
+ __ fnstsw_ax();
+ __ sahf();
+ __ j(not_zero, &operand_conversion_failure);
+ __ j(parity_even, &operand_conversion_failure);
+ }
// Get int32 operands and perform bitop.
- __ pop(eax);
__ pop(ecx);
+ __ pop(eax);
switch (op_) {
case Token::BIT_OR: __ or_(eax, Operand(ecx)); break;
case Token::BIT_AND: __ and_(eax, Operand(ecx)); break;
@@ -4579,10 +4592,22 @@
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
__ ret(2 * kPointerSize);
}
- __ bind(&non_int32_operands);
- // Restore stacks and operands before calling runtime.
- __ ffree(0);
+
+ // Clear the FPU exception flag and reset the stack before calling
+ // the runtime system.
+ __ bind(&operand_conversion_failure);
__ add(Operand(esp), Immediate(2 * kPointerSize));
+ if (use_sse3) {
+ // If we've used the SSE3 instructions for truncating the
+ // floating point values to integers and it failed, we have a
+ // pending #IA exception. Clear it.
+ __ fnclex();
+ } else {
+ // The non-SSE3 variant does early bailout if the right
+ // operand isn't a 32-bit integer, so we may have a single
+ // value on the FPU stack we need to get rid of.
+ __ ffree(0);
+ }
// SHR should return uint32 - go to runtime for non-smi/negative
result.
if (op_ == Token::SHR) __ bind(&non_smi_result);
Modified: branches/bleeding_edge/src/cpu-ia32.cc
==============================================================================
--- branches/bleeding_edge/src/cpu-ia32.cc (original)
+++ branches/bleeding_edge/src/cpu-ia32.cc Wed Feb 25 06:57:46 2009
@@ -30,11 +30,12 @@
#include "v8.h"
#include "cpu.h"
+#include "macro-assembler.h"
namespace v8 { namespace internal {
void CPU::Setup() {
- // Nothing to do.
+ CpuFeatures::Probe();
}
Modified: branches/bleeding_edge/src/mksnapshot.cc
==============================================================================
--- branches/bleeding_edge/src/mksnapshot.cc (original)
+++ branches/bleeding_edge/src/mksnapshot.cc Wed Feb 25 06:57:46 2009
@@ -162,6 +162,8 @@
const int kExtensionCount = 1;
const char* extension_list[kExtensionCount] = { "v8/gc" };
v8::ExtensionConfiguration extensions(kExtensionCount, extension_list);
+
+ i::Serializer::Enable();
v8::Context::New(&extensions);
// Make sure all builtin scripts are cached.
Modified: branches/bleeding_edge/src/serialize.cc
==============================================================================
--- branches/bleeding_edge/src/serialize.cc (original)
+++ branches/bleeding_edge/src/serialize.cc Wed Feb 25 06:57:46 2009
@@ -930,7 +930,7 @@
}
-bool Serializer::serialization_enabled_ = true;
+bool Serializer::serialization_enabled_ = false;
#ifdef DEBUG
@@ -993,7 +993,7 @@
Heap::IterateRoots(this);
PutLog();
PutContextStack();
- disable();
+ Disable();
}
Modified: branches/bleeding_edge/src/serialize.h
==============================================================================
--- branches/bleeding_edge/src/serialize.h (original)
+++ branches/bleeding_edge/src/serialize.h Wed Feb 25 06:57:46 2009
@@ -147,7 +147,8 @@
static bool enabled() { return serialization_enabled_; }
- static void disable() { serialization_enabled_ = false; }
+ static void Enable() { serialization_enabled_ = true; }
+ static void Disable() { serialization_enabled_ = false; }
private:
friend class ReferenceUpdater;
Modified: branches/bleeding_edge/src/v8.cc
==============================================================================
--- branches/bleeding_edge/src/v8.cc (original)
+++ branches/bleeding_edge/src/v8.cc Wed Feb 25 06:57:46 2009
@@ -51,9 +51,6 @@
Logger::Setup();
if (des) des->GetLog();
- // Setup the CPU support.
- CPU::Setup();
-
// Setup the platform OS support.
OS::Setup();
@@ -82,6 +79,11 @@
des->Deserialize();
StubCache::Clear();
}
+
+ // Setup the CPU support. Must be done after heap setup and after
+ // any deserialization because we have to have the initial heap
+ // objects in place for creating the code object used for probing.
+ CPU::Setup();
return true;
}
Modified: branches/bleeding_edge/test/cctest/test-assembler-ia32.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-assembler-ia32.cc (original)
+++ branches/bleeding_edge/test/cctest/test-assembler-ia32.cc Wed Feb 25
06:57:46 2009
@@ -164,8 +164,6 @@
v8::internal::byte buffer[256];
Assembler assm(buffer, sizeof buffer);
- Serializer::disable(); // Needed for Probe when running without
snapshot.
- CpuFeatures::Probe();
CHECK(CpuFeatures::IsSupported(CpuFeatures::SSE2));
{ CpuFeatures::Scope fscope(CpuFeatures::SSE2);
__ cvttss2si(eax, Operand(esp, 4));
@@ -197,8 +195,6 @@
v8::internal::byte buffer[256];
Assembler assm(buffer, sizeof buffer);
- Serializer::disable(); // Needed for Probe when running without
snapshot.
- CpuFeatures::Probe();
CHECK(CpuFeatures::IsSupported(CpuFeatures::SSE2));
CpuFeatures::Scope fscope(CpuFeatures::SSE2);
__ cvttsd2si(eax, Operand(esp, 4));
@@ -246,8 +242,6 @@
TEST(AssemblerIa326) {
InitializeVM();
v8::HandleScope scope;
- Serializer::disable(); // Needed for Probe when running without
snapshot.
- CpuFeatures::Probe();
CHECK(CpuFeatures::IsSupported(CpuFeatures::SSE2));
CpuFeatures::Scope fscope(CpuFeatures::SSE2);
v8::internal::byte buffer[256];
@@ -290,8 +284,6 @@
TEST(AssemblerIa328) {
InitializeVM();
v8::HandleScope scope;
- Serializer::disable(); // Needed for Probe when running without
snapshot.
- CpuFeatures::Probe();
CHECK(CpuFeatures::IsSupported(CpuFeatures::SSE2));
CpuFeatures::Scope fscope(CpuFeatures::SSE2);
v8::internal::byte buffer[256];
Modified: branches/bleeding_edge/test/cctest/test-disasm-ia32.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-disasm-ia32.cc (original)
+++ branches/bleeding_edge/test/cctest/test-disasm-ia32.cc Wed Feb 25
06:57:46 2009
@@ -56,8 +56,6 @@
TEST(DisasmIa320) {
InitializeVM();
- Serializer::disable(); // Needed for Probe when running without
snapshot.
- CpuFeatures::Probe();
v8::HandleScope scope;
v8::internal::byte buffer[1024];
Assembler assm(buffer, sizeof buffer);
Modified: branches/bleeding_edge/test/cctest/test-serialize.cc
==============================================================================
--- branches/bleeding_edge/test/cctest/test-serialize.cc (original)
+++ branches/bleeding_edge/test/cctest/test-serialize.cc Wed Feb 25
06:57:46 2009
@@ -157,6 +157,7 @@
const int kExtensionCount = 1;
const char* extension_list[kExtensionCount] = { "v8/gc" };
v8::ExtensionConfiguration extensions(kExtensionCount, extension_list);
+ Serializer::Enable();
v8::Persistent<v8::Context> env = v8::Context::New(&extensions);
env->Enter();
@@ -187,6 +188,7 @@
if (Snapshot::IsEnabled()) return;
StatsTable::SetCounterFunction(counter_function);
v8::HandleScope scope;
+ Serializer::Enable();
v8::Persistent<v8::Context> env = v8::Context::New();
v8::Context::Scope context_scope(env);
Serializer().Serialize();
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---