From: jkummerow@chromium.org Date: Fri, 5 Jul 2013 08:34:17 +0000 (+0000) Subject: Fix stack alignment corruption for MinGW32 build X-Git-Tag: upstream/4.7.83~13520 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7456e290f38d901d3dd8fde4c28d20baf332f8e6;p=platform%2Fupstream%2Fv8.git Fix stack alignment corruption for MinGW32 build Contributed by Peter Varga BUG= TEST=cctest/test-assembler-ia32/StackAlignmentForSSE2,cctest/test-assembler-x64/StackAlignmentForSSE2,cctest/test-platform/StackAlignment R=jkummerow@chromium.org Review URL: https://codereview.chromium.org/18300003 Patch from Peter Varga . git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15502 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- diff --git a/src/platform-win32.cc b/src/platform-win32.cc index 1913760..f325cb4 100644 --- a/src/platform-win32.cc +++ b/src/platform-win32.cc @@ -1479,6 +1479,10 @@ double OS::nan_value() { int OS::ActivationFrameAlignment() { #ifdef _WIN64 return 16; // Windows 64-bit ABI requires the stack to be 16-byte aligned. +#elif defined(__MINGW32__) + // With gcc 4.4 the tree vectorization optimizer can generate code + // that requires 16 byte alignment such as movdqa on x86. + return 16; #else return 8; // Floating-point math runs faster with 8-byte alignment. #endif diff --git a/test/cctest/test-assembler-ia32.cc b/test/cctest/test-assembler-ia32.cc index 880370f..ddd8745 100644 --- a/test/cctest/test-assembler-ia32.cc +++ b/test/cctest/test-assembler-ia32.cc @@ -473,6 +473,94 @@ TEST(AssemblerMultiByteNop) { } +#ifdef __GNUC__ +#define ELEMENT_COUNT 4 + +void DoSSE2(const v8::FunctionCallbackInfo& args) { + Isolate* isolate = reinterpret_cast(CcTest::isolate()); + HandleScope scope(isolate); + + CHECK(args[0]->IsArray()); + v8::Local vec = v8::Local::Cast(args[0]); + CHECK_EQ(ELEMENT_COUNT, vec->Length()); + + v8::internal::byte buffer[256]; + Assembler assm(isolate, buffer, sizeof buffer); + + ASSERT(CpuFeatures::IsSupported(SSE2)); + CpuFeatureScope fscope(&assm, SSE2); + + // Remove return address from the stack for fix stack frame alignment. + __ pop(ecx); + + // Store input vector on the stack. + for (int i = 0; i < ELEMENT_COUNT; ++i) { + __ push(Immediate(vec->Get(i)->Int32Value())); + } + + // Read vector into a xmm register. + __ pxor(xmm0, xmm0); + __ movdqa(xmm0, Operand(esp, 0)); + // Create mask and store it in the return register. + __ movmskps(eax, xmm0); + + // Remove unused data from the stack. + __ add(esp, Immediate(ELEMENT_COUNT * sizeof(int32_t))); + // Restore return address. + __ push(ecx); + + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + + Object* code = isolate->heap()->CreateCode( + desc, + Code::ComputeFlags(Code::STUB), + Handle())->ToObjectChecked(); + CHECK(code->IsCode()); + + F0 f = FUNCTION_CAST(Code::cast(code)->entry()); + int res = f(); + args.GetReturnValue().Set(v8::Integer::New(res)); +} + +TEST(StackAlignmentForSSE2) { + CcTest::InitializeVM(); + if (!CpuFeatures::IsSupported(SSE2)) return; + + CHECK_EQ(0, OS::ActivationFrameAlignment() % 16); + + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + v8::Handle global_template = v8::ObjectTemplate::New(); + global_template->Set(v8_str("do_sse2"), v8::FunctionTemplate::New(DoSSE2)); + + LocalContext env(NULL, global_template); + CompileRun( + "function foo(vec) {" + " return do_sse2(vec);" + "}"); + + v8::Local global_object = env->Global(); + v8::Local foo = + v8::Local::Cast(global_object->Get(v8_str("foo"))); + + int32_t vec[ELEMENT_COUNT] = { -1, 1, 1, 1 }; + v8::Local v8_vec = v8::Array::New(ELEMENT_COUNT); + for (int i = 0; i < ELEMENT_COUNT; i++) { + v8_vec->Set(i, v8_num(vec[i])); + } + + v8::Local args[] = { v8_vec }; + v8::Local result = foo->Call(global_object, 1, args); + + // The mask should be 0b1000. + CHECK_EQ(8, result->Int32Value()); +} + +#undef ELEMENT_COUNT +#endif // __GNUC__ #undef __ diff --git a/test/cctest/test-assembler-x64.cc b/test/cctest/test-assembler-x64.cc index 669475a..5fc9311 100644 --- a/test/cctest/test-assembler-x64.cc +++ b/test/cctest/test-assembler-x64.cc @@ -62,6 +62,7 @@ using v8::internal::rdx; using v8::internal::rsi; using v8::internal::rsp; using v8::internal::times_1; +using v8::internal::xmm0; // Test the x64 assembler by compiling some simple functions into // a buffer and executing them. These tests do not initialize the @@ -429,6 +430,91 @@ TEST(AssemblerMultiByteNop) { } +#ifdef __GNUC__ +#define ELEMENT_COUNT 4 + +void DoSSE2(const v8::FunctionCallbackInfo& args) { + CcTest::InitializeVM(); + v8::HandleScope scope(CcTest::isolate()); + v8::internal::byte buffer[1024]; + + CHECK(args[0]->IsArray()); + v8::Local vec = v8::Local::Cast(args[0]); + CHECK_EQ(ELEMENT_COUNT, vec->Length()); + + Isolate* isolate = Isolate::Current(); + Assembler assm(isolate, buffer, sizeof(buffer)); + + // Remove return address from the stack for fix stack frame alignment. + __ pop(rcx); + + // Store input vector on the stack. + for (int i = 0; i < ELEMENT_COUNT; i++) { + __ movl(rax, Immediate(vec->Get(i)->Int32Value())); + __ shl(rax, Immediate(0x20)); + __ or_(rax, Immediate(vec->Get(++i)->Int32Value())); + __ push(rax); + } + + // Read vector into a xmm register. + __ xorps(xmm0, xmm0); + __ movdqa(xmm0, Operand(rsp, 0)); + // Create mask and store it in the return register. + __ movmskps(rax, xmm0); + + // Remove unused data from the stack. + __ addq(rsp, Immediate(ELEMENT_COUNT * sizeof(int32_t))); + // Restore return address. + __ push(rcx); + + __ ret(0); + + CodeDesc desc; + assm.GetCode(&desc); + Code* code = Code::cast(isolate->heap()->CreateCode( + desc, + Code::ComputeFlags(Code::STUB), + v8::internal::Handle())->ToObjectChecked()); + CHECK(code->IsCode()); + + F0 f = FUNCTION_CAST(code->entry()); + int res = f(); + args.GetReturnValue().Set(v8::Integer::New(res)); +} + +TEST(StackAlignmentForSSE2) { + CHECK_EQ(0, OS::ActivationFrameAlignment() % 16); + + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + v8::Handle global_template = v8::ObjectTemplate::New(); + global_template->Set(v8_str("do_sse2"), v8::FunctionTemplate::New(DoSSE2)); + + LocalContext env(NULL, global_template); + CompileRun( + "function foo(vec) {" + " return do_sse2(vec);" + "}"); + + v8::Local global_object = env->Global(); + v8::Local foo = + v8::Local::Cast(global_object->Get(v8_str("foo"))); + + int32_t vec[ELEMENT_COUNT] = { -1, 1, 1, 1 }; + v8::Local v8_vec = v8::Array::New(ELEMENT_COUNT); + for (int i = 0; i < ELEMENT_COUNT; i++) { + v8_vec->Set(i, v8_num(vec[i])); + } + + v8::Local args[] = { v8_vec }; + v8::Local result = foo->Call(global_object, 1, args); + + // The mask should be 0b1000. + CHECK_EQ(8, result->Int32Value()); +} + +#undef ELEMENT_COUNT +#endif // __GNUC__ #undef __ diff --git a/test/cctest/test-platform.cc b/test/cctest/test-platform.cc index 6c20b85..7c8d4a4 100644 --- a/test/cctest/test-platform.cc +++ b/test/cctest/test-platform.cc @@ -35,3 +35,65 @@ using namespace ::v8::internal; TEST(NumberOfCores) { CHECK_GT(OS::NumberOfCores(), 0); } + + +#ifdef __GNUC__ +#define ASM __asm__ __volatile__ + +#if defined(_M_X64) || defined(__x86_64__) +#define GET_STACK_POINTER() \ + static int sp_addr = 0; \ + do { \ + ASM("mov %%rsp, %0" : "=g" (sp_addr)); \ + } while (0) +#elif defined(_M_IX86) || defined(__i386__) +#define GET_STACK_POINTER() \ + static int sp_addr = 0; \ + do { \ + ASM("mov %%esp, %0" : "=g" (sp_addr)); \ + } while (0) +#elif defined(__ARMEL__) +#define GET_STACK_POINTER() \ + static int sp_addr = 0; \ + do { \ + ASM("str %%sp, %0" : "=g" (sp_addr)); \ + } while (0) +#elif defined(__MIPSEL__) +#define GET_STACK_POINTER() \ + static int sp_addr = 0; \ + do { \ + ASM("sw $sp, %0" : "=g" (sp_addr)); \ + } while (0) +#else +#error Host architecture was not detected as supported by v8 +#endif + +void GetStackPointer(const v8::FunctionCallbackInfo& args) { + GET_STACK_POINTER(); + args.GetReturnValue().Set(v8_num(sp_addr)); +} + +TEST(StackAlignment) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); + v8::Handle global_template = v8::ObjectTemplate::New(); + global_template->Set(v8_str("get_stack_pointer"), + v8::FunctionTemplate::New(GetStackPointer)); + + LocalContext env(NULL, global_template); + CompileRun( + "function foo() {" + " return get_stack_pointer();" + "}"); + + v8::Local global_object = env->Global(); + v8::Local foo = + v8::Local::Cast(global_object->Get(v8_str("foo"))); + + v8::Local result = foo->Call(global_object, 0, NULL); + CHECK_EQ(0, result->Int32Value() % OS::ActivationFrameAlignment()); +} + +#undef GET_STACK_POINTERS +#undef ASM +#endif // __GNUC__