Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (144042 => 144043)
--- trunk/Source/_javascript_Core/ChangeLog 2013-02-26 13:01:59 UTC (rev 144042)
+++ trunk/Source/_javascript_Core/ChangeLog 2013-02-26 13:04:28 UTC (rev 144043)
@@ -1,3 +1,35 @@
+2013-02-26 Jocelyn Turcotte <[email protected]>
+
+ Implement JIT on Windows 64 bits
+ https://bugs.webkit.org/show_bug.cgi?id=107965
+
+ Reviewed by Simon Hausmann.
+
+ 1. MSVC doesn't support inline assembly for 64 bits, implements the trampoline in a separate ASM file.
+
+ 2. Windows 64 bits has a different calling convention than other OSes following the AMD64 ABI.
+ Differences that we have to handle here:
+ - Registers passed parameters are RCX, RDX, R8 and R9 instead of RDI, RSI, RDX, RCX, R8 and R9
+ - RDI and RSI must be preserved by callee
+ - Only return values <= 8 bytes can be returned by register (RDX can't be used to return a second word)
+ - There is no red-zone after RIP on the stack, but instead 4 reserved words before it
+
+ * Target.pri:
+ * jit/JITStubs.cpp:
+ * jit/JITStubs.h:
+ (JSC):
+ (JITStackFrame):
+ (JSC::JITStackFrame::returnAddressSlot):
+ * jit/JITStubsMSVC64.asm: Added.
+ * jit/JSInterfaceJIT.h:
+ (JSInterfaceJIT):
+ * jit/ThunkGenerators.cpp:
+ (JSC::nativeForGenerator):
+ * yarr/YarrJIT.cpp:
+ (YarrGenerator):
+ (JSC::Yarr::YarrGenerator::generateEnter):
+ (JSC::Yarr::YarrGenerator::generateReturn):
+
2013-02-26 Oliver Hunt <[email protected]>
Kill another analyzer warning in _javascript_core
Modified: trunk/Source/_javascript_Core/Target.pri (144042 => 144043)
--- trunk/Source/_javascript_Core/Target.pri 2013-02-26 13:01:59 UTC (rev 144042)
+++ trunk/Source/_javascript_Core/Target.pri 2013-02-26 13:04:28 UTC (rev 144043)
@@ -335,6 +335,19 @@
disassembler/udis86/udis86_syn.c \
}
+win32:!win32-g++*:isEqual(QT_ARCH, "x86_64"):{
+ asm_compiler.commands = ml64 /c
+ asm_compiler.commands += /Fo ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN}
+ asm_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)}
+ asm_compiler.input = ASM_SOURCES
+ asm_compiler.variable_out = OBJECTS
+ asm_compiler.name = compiling[asm] ${QMAKE_FILE_IN}
+ silent:asm_compiler.commands = @echo compiling[asm] ${QMAKE_FILE_IN} && $$asm_compiler.commands
+ QMAKE_EXTRA_COMPILERS += asm_compiler
+
+ ASM_SOURCES += jit/JITStubsMSVC64.asm
+}
+
HEADERS += $$files(*.h, true)
*sh4* {
Modified: trunk/Source/_javascript_Core/jit/JITStubs.cpp (144042 => 144043)
--- trunk/Source/_javascript_Core/jit/JITStubs.cpp 2013-02-26 13:01:59 UTC (rev 144042)
+++ trunk/Source/_javascript_Core/jit/JITStubs.cpp 2013-02-26 13:04:28 UTC (rev 144043)
@@ -437,6 +437,13 @@
"ret" "\n"
);
+#elif COMPILER(MSVC) && CPU(X86_64)
+
+// These ASSERTs remind you that, if you change the layout of JITStackFrame, you
+// need to change the assembly trampolines in JITStubsMSVC64.asm to match.
+COMPILE_ASSERT(offsetof(struct JITStackFrame, code) % 16 == 0x0, JITStackFrame_maintains_16byte_stack_alignment);
+COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x58, JITStackFrame_stub_argument_space_matches_ctiTrampoline);
+
#else
#error "JIT not supported on this platform."
#endif
Modified: trunk/Source/_javascript_Core/jit/JITStubs.h (144042 => 144043)
--- trunk/Source/_javascript_Core/jit/JITStubs.h 2013-02-26 13:01:59 UTC (rev 144042)
+++ trunk/Source/_javascript_Core/jit/JITStubs.h 2013-02-26 13:04:28 UTC (rev 144043)
@@ -87,7 +87,7 @@
ArrayAllocationProfile* arrayAllocationProfile() { return static_cast<ArrayAllocationProfile*>(asPointer); }
};
-#if CPU(X86_64)
+#if !OS(WINDOWS) && CPU(X86_64)
struct JITStackFrame {
void* reserved; // Unused
JITStubArg args[6];
@@ -111,6 +111,34 @@
// When JIT code makes a call, it pushes its return address just below the rest of the stack.
ReturnAddressPtr* returnAddressSlot() { return reinterpret_cast<ReturnAddressPtr*>(this) - 1; }
};
+#elif OS(WINDOWS) && CPU(X86_64)
+struct JITStackFrame {
+ void* shadow[4]; // Shadow space reserved for a callee's parameters home addresses
+ void* reserved; // Unused, also maintains the 16-bytes stack alignment
+ JITStubArg args[6];
+
+ void* savedRBX;
+ void* savedR15;
+ void* savedR14;
+ void* savedR13;
+ void* savedR12;
+ void* savedRBP;
+ void* savedRIP;
+
+ // Home addresses for our register passed parameters
+ // http://msdn.microsoft.com/en-us/library/ew5tede7.aspx
+ void* code;
+ JSStack* stack;
+ CallFrame* callFrame;
+ void* unused1;
+
+ // Passed on the stack
+ void* unused2;
+ JSGlobalData* globalData;
+
+ // When JIT code makes a call, it pushes its return address just below the rest of the stack.
+ ReturnAddressPtr* returnAddressSlot() { return reinterpret_cast<ReturnAddressPtr*>(this) - 1; }
+};
#elif CPU(X86)
#if COMPILER(MSVC) || (OS(WINDOWS) && COMPILER(GCC))
#pragma pack(push)
Added: trunk/Source/_javascript_Core/jit/JITStubsMSVC64.asm (0 => 144043)
--- trunk/Source/_javascript_Core/jit/JITStubsMSVC64.asm (rev 0)
+++ trunk/Source/_javascript_Core/jit/JITStubsMSVC64.asm 2013-02-26 13:04:28 UTC (rev 144043)
@@ -0,0 +1,84 @@
+;/*
+; Copyright (C) 2013 Digia Plc. and/or its subsidiary(-ies)
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+; 1. Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+; 2. Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in the
+; documentation and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+; EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+; PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+; OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+;*/
+
+EXTERN cti_vm_throw : near
+PUBLIC ctiTrampoline
+PUBLIC ctiVMThrowTrampoline
+PUBLIC ctiOpThrowNotCaught
+
+_TEXT SEGMENT
+
+ctiTrampoline PROC
+ ; Dump register parameters to their home address
+ mov qword ptr[rsp+20h], r9
+ mov qword ptr[rsp+18h], r8
+ mov qword ptr[rsp+10h], rdx
+ mov qword ptr[rsp+8h], rcx
+
+ push rbp
+ mov rbp, rsp
+ push r12
+ push r13
+ push r14
+ push r15
+ push rbx
+
+ ; Decrease rsp to point to the start of our JITStackFrame
+ sub rsp, 58h
+ mov r12, 512
+ mov r14, 0FFFF000000000000h
+ mov r15, 0FFFF000000000002h
+ mov r13, r8
+ call rcx
+ add rsp, 58h
+ pop rbx
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop rbp
+ ret
+ctiTrampoline ENDP
+
+ctiVMThrowTrampoline PROC
+ mov rcx, rsp
+ call cti_vm_throw
+ int 3
+ctiVMThrowTrampoline ENDP
+
+ctiOpThrowNotCaught PROC
+ add rsp, 58h
+ pop rbx
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop rbp
+ ret
+ctiOpThrowNotCaught ENDP
+
+_TEXT ENDS
+
+END
\ No newline at end of file
Modified: trunk/Source/_javascript_Core/jit/JSInterfaceJIT.h (144042 => 144043)
--- trunk/Source/_javascript_Core/jit/JSInterfaceJIT.h 2013-02-26 13:01:59 UTC (rev 144042)
+++ trunk/Source/_javascript_Core/jit/JSInterfaceJIT.h 2013-02-26 13:04:28 UTC (rev 144043)
@@ -57,22 +57,26 @@
#if CPU(X86_64)
static const RegisterID returnValueRegister = X86Registers::eax;
static const RegisterID cachedResultRegister = X86Registers::eax;
+#if !OS(WINDOWS)
static const RegisterID firstArgumentRegister = X86Registers::edi;
-
+#else
+ static const RegisterID firstArgumentRegister = X86Registers::ecx;
+#endif
+
#if ENABLE(VALUE_PROFILER)
static const RegisterID bucketCounterRegister = X86Registers::r10;
#endif
-
+
static const RegisterID timeoutCheckRegister = X86Registers::r12;
static const RegisterID callFrameRegister = X86Registers::r13;
static const RegisterID tagTypeNumberRegister = X86Registers::r14;
static const RegisterID tagMaskRegister = X86Registers::r15;
-
+
static const RegisterID regT0 = X86Registers::eax;
static const RegisterID regT1 = X86Registers::edx;
static const RegisterID regT2 = X86Registers::ecx;
static const RegisterID regT3 = X86Registers::ebx;
-
+
static const FPRegisterID fpRegT0 = X86Registers::xmm0;
static const FPRegisterID fpRegT1 = X86Registers::xmm1;
static const FPRegisterID fpRegT2 = X86Registers::xmm2;
Modified: trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp (144042 => 144043)
--- trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp 2013-02-26 13:01:59 UTC (rev 144042)
+++ trunk/Source/_javascript_Core/jit/ThunkGenerators.cpp 2013-02-26 13:04:28 UTC (rev 144043)
@@ -264,6 +264,7 @@
jit.peek(JSInterfaceJIT::regT1);
jit.emitPutToCallFrameHeader(JSInterfaceJIT::regT1, JSStack::ReturnPC);
+#if !OS(WINDOWS)
// Calling convention: f(edi, esi, edx, ecx, ...);
// Host function signature: f(ExecState*);
jit.move(JSInterfaceJIT::callFrameRegister, X86Registers::edi);
@@ -276,7 +277,22 @@
jit.call(JSInterfaceJIT::Address(X86Registers::r9, executableOffsetToFunction));
jit.addPtr(JSInterfaceJIT::TrustedImm32(16 - sizeof(int64_t)), JSInterfaceJIT::stackPointerRegister);
+#else
+ // Calling convention: f(ecx, edx, r8, r9, ...);
+ // Host function signature: f(ExecState*);
+ jit.move(JSInterfaceJIT::callFrameRegister, X86Registers::ecx);
+ // Leave space for the callee parameter home addresses and align the stack.
+ jit.subPtr(JSInterfaceJIT::TrustedImm32(4 * sizeof(int64_t) + 16 - sizeof(int64_t)), JSInterfaceJIT::stackPointerRegister);
+
+ jit.emitGetFromCallFrameHeaderPtr(JSStack::Callee, X86Registers::edx);
+ jit.loadPtr(JSInterfaceJIT::Address(X86Registers::edx, JSFunction::offsetOfExecutable()), X86Registers::r9);
+ jit.move(JSInterfaceJIT::regT0, JSInterfaceJIT::callFrameRegister); // Eagerly restore caller frame register to avoid loading from stack.
+ jit.call(JSInterfaceJIT::Address(X86Registers::r9, executableOffsetToFunction));
+
+ jit.addPtr(JSInterfaceJIT::TrustedImm32(4 * sizeof(int64_t) + 16 - sizeof(int64_t)), JSInterfaceJIT::stackPointerRegister);
+#endif
+
#elif CPU(ARM)
// Load caller frame's scope chain into this callframe so that whatever we call can
// get to its global data.
Modified: trunk/Source/_javascript_Core/yarr/YarrJIT.cpp (144042 => 144043)
--- trunk/Source/_javascript_Core/yarr/YarrJIT.cpp 2013-02-26 13:01:59 UTC (rev 144042)
+++ trunk/Source/_javascript_Core/yarr/YarrJIT.cpp 2013-02-26 13:04:28 UTC (rev 144043)
@@ -87,10 +87,20 @@
static const RegisterID returnRegister = X86Registers::eax;
static const RegisterID returnRegister2 = X86Registers::edx;
#elif CPU(X86_64)
+#if !OS(WINDOWS)
static const RegisterID input = X86Registers::edi;
static const RegisterID index = X86Registers::esi;
static const RegisterID length = X86Registers::edx;
static const RegisterID output = X86Registers::ecx;
+#else
+ // If the return value doesn't fit in 64bits, its destination is pointed by rcx and the parameters are shifted.
+ // http://msdn.microsoft.com/en-us/library/7572ztz4.aspx
+ COMPILE_ASSERT(sizeof(MatchResult) > sizeof(void*), MatchResult_does_not_fit_in_64bits);
+ static const RegisterID input = X86Registers::edx;
+ static const RegisterID index = X86Registers::r8;
+ static const RegisterID length = X86Registers::r9;
+ static const RegisterID output = X86Registers::r10;
+#endif
static const RegisterID regT0 = X86Registers::eax;
static const RegisterID regT1 = X86Registers::ebx;
@@ -2514,6 +2524,10 @@
push(X86Registers::ebp);
move(stackPointerRegister, X86Registers::ebp);
push(X86Registers::ebx);
+#if OS(WINDOWS)
+ if (compileMode == IncludeSubpatterns)
+ loadPtr(Address(X86Registers::ebp, 6 * sizeof(void*)), output);
+#endif
#elif CPU(X86)
push(X86Registers::ebp);
move(stackPointerRegister, X86Registers::ebp);
@@ -2552,6 +2566,12 @@
void generateReturn()
{
#if CPU(X86_64)
+#if OS(WINDOWS)
+ // Store the return value in the allocated space pointed by rcx.
+ store64(returnRegister, Address(X86Registers::ecx));
+ store64(returnRegister2, Address(X86Registers::ecx, sizeof(void*)));
+ move(X86Registers::ecx, returnRegister);
+#endif
pop(X86Registers::ebx);
pop(X86Registers::ebp);
#elif CPU(X86)
Modified: trunk/Source/WTF/ChangeLog (144042 => 144043)
--- trunk/Source/WTF/ChangeLog 2013-02-26 13:01:59 UTC (rev 144042)
+++ trunk/Source/WTF/ChangeLog 2013-02-26 13:04:28 UTC (rev 144043)
@@ -1,3 +1,12 @@
+2013-02-26 Jocelyn Turcotte <[email protected]>
+
+ Implement JIT on Windows 64 bits
+ https://bugs.webkit.org/show_bug.cgi?id=107965
+
+ Reviewed by Simon Hausmann.
+
+ * wtf/Platform.h:
+
2013-02-26 Oliver Hunt <[email protected]>
Appease static analyzer warning about null string passed to strlen
Modified: trunk/Source/WTF/wtf/Platform.h (144042 => 144043)
--- trunk/Source/WTF/wtf/Platform.h 2013-02-26 13:01:59 UTC (rev 144042)
+++ trunk/Source/WTF/wtf/Platform.h 2013-02-26 13:04:28 UTC (rev 144043)
@@ -756,12 +756,6 @@
#define ENABLE_JIT 0
#endif
-/* JIT is not implemented for Windows 64-bit */
-#if !defined(ENABLE_JIT) && OS(WINDOWS) && CPU(X86_64)
-#define ENABLE_JIT 0
-#define ENABLE_YARR_JIT 0
-#endif
-
#if !defined(ENABLE_JIT) && CPU(SH4) && PLATFORM(QT)
#define ENABLE_JIT 1
#endif
@@ -906,7 +900,7 @@
/* Pick which allocator to use; we only need an executable allocator if the assembler is compiled in.
On x86-64 we use a single fixed mmap, on other platforms we mmap on demand. */
#if ENABLE(ASSEMBLER)
-#if CPU(X86_64) || PLATFORM(IOS)
+#if CPU(X86_64) && !OS(WINDOWS) || PLATFORM(IOS)
#define ENABLE_EXECUTABLE_ALLOCATOR_FIXED 1
#else
#define ENABLE_EXECUTABLE_ALLOCATOR_DEMAND 1