Commit 4655f790 authored by msaboff@apple.com's avatar msaboff@apple.com

Change callToJavaScript thunk into an offline assembled stub

https://bugs.webkit.org/show_bug.cgi?id=124251

Reviewed by Geoffrey Garen.

Changed callToJavaScript and throwNotCaught into stubs generated by the offline assembler.
Added popCalleeSaves and pushCalleeSaves pseudo ops to the offline assembler to handle
the saving and restoring of callee save registers.  Fixed callFrameRegister differences
between arm traditional (r11) and arm Thumb2 (r7) in GPRInfo.h.  Also fixed implementation
of pop & push in arm.rb.

Since the offline assembler and therefore the LLInt don't work on Windows, the Windows stubs
are handled as inline assembly in JITStubsX86.h and JITStubsMSVC64.asm.

* dfg/DFGDriver.cpp:
(JSC::DFG::compileImpl):
* jit/GPRInfo.h:
(JSC::GPRInfo::toIndex):
(JSC::GPRInfo::debugName):
* jit/JITCode.cpp:
(JSC::JITCode::execute):
* jit/JITExceptions.cpp:
(JSC::genericUnwind):
* jit/JITStubs.h:
* jit/JITStubsMSVC64.asm:
* jit/JITStubsX86.h:
* jit/ThunkGenerators.cpp:
* jit/ThunkGenerators.h:
* llint/LLIntThunks.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* offlineasm/arm.rb:
* offlineasm/arm64.rb:
* offlineasm/instructions.rb:
* offlineasm/mips.rb:
* offlineasm/registers.rb:
* offlineasm/sh4.rb:
* offlineasm/x86.rb:
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@159276 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 847e8c7e
2013-11-13 Michael Saboff <msaboff@apple.com>
Change callToJavaScript thunk into an offline assembled stub
https://bugs.webkit.org/show_bug.cgi?id=124251
Reviewed by Geoffrey Garen.
Changed callToJavaScript and throwNotCaught into stubs generated by the offline assembler.
Added popCalleeSaves and pushCalleeSaves pseudo ops to the offline assembler to handle
the saving and restoring of callee save registers. Fixed callFrameRegister differences
between arm traditional (r11) and arm Thumb2 (r7) in GPRInfo.h. Also fixed implementation
of pop & push in arm.rb.
Since the offline assembler and therefore the LLInt don't work on Windows, the Windows stubs
are handled as inline assembly in JITStubsX86.h and JITStubsMSVC64.asm.
* dfg/DFGDriver.cpp:
(JSC::DFG::compileImpl):
* jit/GPRInfo.h:
(JSC::GPRInfo::toIndex):
(JSC::GPRInfo::debugName):
* jit/JITCode.cpp:
(JSC::JITCode::execute):
* jit/JITExceptions.cpp:
(JSC::genericUnwind):
* jit/JITStubs.h:
* jit/JITStubsMSVC64.asm:
* jit/JITStubsX86.h:
* jit/ThunkGenerators.cpp:
* jit/ThunkGenerators.h:
* llint/LLIntThunks.h:
* llint/LowLevelInterpreter.asm:
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* offlineasm/arm.rb:
* offlineasm/arm64.rb:
* offlineasm/instructions.rb:
* offlineasm/mips.rb:
* offlineasm/registers.rb:
* offlineasm/sh4.rb:
* offlineasm/x86.rb:
* runtime/VM.cpp:
(JSC::VM::VM):
* runtime/VM.h:
2013-11-13 Andy Estes <aestes@apple.com>
Fix the ARM64 build after recent JavaScriptCore changes
......
......@@ -78,8 +78,6 @@ static CompilationResult compileImpl(
// Make sure that any stubs that the DFG is going to use are initialized. We want to
// make sure that all JIT code generation does finalization on the main thread.
vm.getCTIStub(callToJavaScript);
vm.getCTIStub(throwNotCaught);
vm.getCTIStub(osrExitGenerationThunkGenerator);
vm.getCTIStub(throwExceptionFromCallSlowPathGenerator);
vm.getCTIStub(linkCallThunkGenerator);
......
......@@ -460,7 +460,11 @@ public:
static const GPRReg regT4 = ARMRegisters::r8;
static const GPRReg regT5 = ARMRegisters::r9;
static const GPRReg regT6 = ARMRegisters::r10;
static const GPRReg regT7 = ARMRegisters::r5;
#if CPU(ARM_THUMB2)
static const GPRReg regT7 = ARMRegisters::r11;
#else
static const GPRReg regT7 = ARMRegisters::r7;
#endif
static const GPRReg regT8 = ARMRegisters::r3;
// These registers match the baseline JIT.
static const GPRReg cachedResultRegister = regT0;
......@@ -488,8 +492,13 @@ public:
static unsigned toIndex(GPRReg reg)
{
ASSERT(reg != InvalidGPRReg);
ASSERT(reg < 16);
static const unsigned indexForRegister[16] = { 0, 1, 2, 8, 3, 7, InvalidIndex, InvalidIndex, 4, 5, 6, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };
ASSERT(static_cast<int>(reg) < 16);
static const unsigned indexForRegister[16] =
#if CPU(ARM_THUMB2)
{ 0, 1, 2, 8, 3, 9, InvalidIndex, InvalidIndex, 4, 5, 6, 7, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };
#else
{ 0, 1, 2, 8, 3, 9, InvalidIndex, 7, 4, 5, 6, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex, InvalidIndex };
#endif
unsigned result = indexForRegister[reg];
ASSERT(result != InvalidIndex);
return result;
......@@ -498,7 +507,7 @@ public:
static const char* debugName(GPRReg reg)
{
ASSERT(reg != InvalidGPRReg);
ASSERT(reg < 16);
ASSERT(static_cast<int>(reg) < 16);
static const char* nameForRegister[16] = {
"r0", "r1", "r2", "r3",
"r4", "r5", "r6", "r7",
......
......@@ -26,8 +26,8 @@
#include "config.h"
#include "JITCode.h"
#include "LLIntThunks.h"
#include "Operations.h"
#include "ThunkGenerators.h"
#include <wtf/PrintStream.h>
namespace JSC {
......@@ -46,7 +46,7 @@ JSValue JITCode::execute(JSStack* stack, CallFrame* callFrame, VM* vm)
{
UNUSED_PARAM(stack);
JSValue result = JSValue::decode(vm->callJavaScriptJITFunction(executableAddress(), callFrame));
JSValue result = JSValue::decode(callToJavaScript(executableAddress(), callFrame));
return vm->exception() ? jsNull() : result;
}
#endif
......
......@@ -30,7 +30,9 @@
#include "CallFrameInlines.h"
#include "CodeBlock.h"
#include "Interpreter.h"
#include "JITStubs.h"
#include "JSCJSValue.h"
#include "LLIntThunks.h"
#include "VM.h"
#include "Operations.h"
......@@ -49,7 +51,7 @@ void genericUnwind(VM* vm, ExecState* callFrame, JSValue exceptionValue)
catchPCForInterpreter = &callFrame->codeBlock()->instructions()[handler->target];
catchRoutine = ExecutableBase::catchRoutineFor(handler, catchPCForInterpreter);
} else
catchRoutine = vm->getCTIStub(throwNotCaught).code().executableAddress();
catchRoutine = FunctionPtr(LLInt::getCodePtr(returnFromJavaScript)).value();
vm->callFrameForThrow = callFrame;
vm->targetMachinePCForThrow = catchRoutine;
......
......@@ -30,10 +30,21 @@
#ifndef JITStubs_h
#define JITStubs_h
#include "JSCJSValue.h"
namespace JSC {
#if ENABLE(JIT)
#if OS(WINDOWS)
class ExecState;
extern "C" {
EncodedJSValue callToJavaScript(void*, ExecState*);
void returnFromJavaScript();
}
#endif
#if USE(MASM_PROBE)
extern "C" void ctiMasmProbeTrampoline();
#endif
......
......@@ -25,10 +25,54 @@
EXTERN getHostCallReturnValueWithExecState : near
PUBLIC callToJavaScript
PUBLIC returnFromJavaScript
PUBLIC getHostCallReturnValue
_TEXT SEGMENT
callToJavaScript PROC
push rbp
mov rbp, rax ; Save previous frame pointer
mov rbp, rsp
push r12
push r13
push r14
push r15
push rbx
; JIT operations can use up to 6 args (4 in registers and 2 on the stack).
; In addition, X86_64 ABI specifies that the worse case stack alignment
; requirement is 32 bytes. Based on these factors, we need to pad the stack
; an additional 28h bytes.
sub rsp, 28h
mov rbp, rdx
mov r11, qword ptr[rbp] ; Put the previous frame pointer in the sentinel call frame above us
mov qword ptr[r11], rax
mov r14, 0FFFF000000000000h
mov r15, 0FFFF000000000002h
call rcx
add rsp, 28h
pop rbx
pop r15
pop r14
pop r13
pop r12
pop rbp
ret
callToJavaScript ENDP
returnFromJavaScript PROC
add rsp, 28h
pop rbx
pop r15
pop r14
pop r13
pop r12
pop rbp
ret
returnFromJavaScript ENDP
getHostCallReturnValue PROC
sub r13, 40
mov r13, rdi
......
......@@ -200,6 +200,50 @@ SYMBOL_STRING(ctiMasmProbeTrampolineEnd) ":" "\n"
#endif // COMPILER(GCC)
#if COMPILER(MSVC)
extern "C" {
// FIXME: Since Windows doesn't use the LLInt, we have inline stubs here.
// Until the LLInt is changed to support Windows, these stub needs to be updated.
__declspec(naked) EncodedJSValue callToJavaScript(void* code, ExecState*)
{
__asm {
push ebp;
mov eax, ebp;
mov ebp, esp;
push esi;
push edi;
push ebx;
sub esp, 0x1c;
mov ebp, [esp + 0x34];
mov ebx, [ebp];
mov [ebx], eax;
call [esp + 0x30];
add esp, 0x1c;
pop ebx;
pop edi;
pop esi;
pop ebp;
ret;
}
}
__declspec(naked) void returnFromJavaScript()
{
__asm {
add esp, 0x1c;
pop ebx;
pop edi;
pop esi;
pop ebp;
ret;
}
}
}
#endif // COMPILER(MSVC)
} // namespace JSC
#endif // JITStubsX86_h
......@@ -31,9 +31,6 @@
#if ENABLE(JIT)
namespace JSC {
MacroAssemblerCodeRef callToJavaScript(VM*);
MacroAssemblerCodeRef throwNotCaught(VM*);
MacroAssemblerCodeRef throwExceptionFromCallSlowPathGenerator(VM*);
MacroAssemblerCodeRef linkCallThunkGenerator(VM*);
......
......@@ -34,8 +34,14 @@
namespace JSC {
class ExecState;
class VM;
extern "C" {
EncodedJSValue callToJavaScript(void*, ExecState*);
void returnFromJavaScript();
}
namespace LLInt {
MacroAssemblerCodeRef functionForCallEntryThunkGenerator(VM*);
......
......@@ -421,6 +421,12 @@ macro doReturn()
ret
end
# stub to call into JavaScript
# EncodedJSValue callToJavaScript(void* code, Register* topOfStack)
# Note, if this stub or one of it's related macros is changed, make the
# equivalent changes in jit/JITStubsX86.h and/or jit/JITStubsMSVC64.asm
_callToJavaScript:
doCallToJavaScript()
# Indicate the beginning of LLInt.
_llint_begin:
......
......@@ -149,6 +149,80 @@ macro callSlowPath(slowPath)
move t1, cfr
end
macro functionPrologue(extraStackSpace)
if X86
push cfr
move sp, cfr
end
pushCalleeSaves
if ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS
push cfr
push lr
end
subp extraStackSpace, sp
end
macro functionEpilogue(extraStackSpace)
addp extraStackSpace, sp
if ARM or ARMv7 or ARMv7_TRADITIONAL or MIPS
pop lr
pop cfr
end
popCalleeSaves
if X86
pop cfr
end
end
macro doCallToJavaScript()
if X86
const extraStackSpace = 28
const previousCFR = t0
const entry = t5
const newCallFrame = t4
elsif ARM or ARMv7_TRADITIONAL
const extraStackSpace = 16
const previousCFR = t3
const entry = a0
const newCallFrame = a1
elsif ARMv7
const extraStackSpace = 28
const previousCFR = t3
const entry = a0
const newCallFrame = a1
elsif MIPS
const extraStackSpace = 20
const previousCFR = t2
const entry = a0
const newCallFrame = a1
elsif SH4
const extraStackSpace = 20
const previousCFR = t3
const entry = a0
const newCallFrame = a1
end
if X86
move cfr, previousCFR
end
functionPrologue(extraStackSpace)
if X86
loadp extraStackSpace+20[sp], entry
loadp extraStackSpace+24[sp], newCallFrame
else
move cfr, previousCFR
end
move newCallFrame, cfr
loadp [cfr], newCallFrame
storep previousCFR, [newCallFrame]
call entry
_returnFromJavaScript:
functionEpilogue(extraStackSpace)
ret
end
# Debugging operation if you'd like to print an operand in the instruction stream. fromWhere
# should be an immediate integer - any integer you like; use it to identify the place you're
# debugging from. operand should likewise be an immediate, and should identify the operand
......
......@@ -88,6 +88,61 @@ macro cCall4(function, arg1, arg2, arg3, arg4)
end
end
macro functionPrologue(extraStackSpace)
if X86_64
push cfr
move sp, cfr
elsif ARM64
push lr
end
pushCalleeSaves
if X86_64
subp extraStackSpace, sp
elsif ARM64
push cfr
end
end
macro functionEpilogue(extraStackSpace)
if X86_64
addp extraStackSpace, sp
end
popCalleeSaves
if X86_64
pop cfr
elsif ARM64
pop lr
end
end
macro doCallToJavaScript()
if X86_64
const extraStackSpace = 8
const previousCFR = t0
const entry = t5
const newCallFrame = t4
elsif ARM64
const extraStackSpace = 0
const previousCFR = t4
const entry = a0
const newCallFrame = a1
end
move cfr, previousCFR
functionPrologue(extraStackSpace)
move newCallFrame, cfr
loadp [cfr], newCallFrame
storep previousCFR, [newCallFrame]
move 0xffff000000000000, csr1
addp 2, csr1, csr2
call entry
_returnFromJavaScript:
functionEpilogue(extraStackSpace)
ret
end
macro prepareStateForCCall()
leap [PB, PC, 8], PC
move PB, t3
......
......@@ -97,7 +97,9 @@ class RegisterID
when "t3"
"r4"
when "t4"
"r10"
"r8"
when "t5"
"r9"
when "cfr"
isARMv7 ? "r7" : "r11"
when "lr"
......@@ -451,9 +453,21 @@ class Instruction
# FIXME: either support this or remove it.
raise "ARM does not support this opcode yet, #{codeOrigin}"
when "pop"
$asm.puts "pop #{operands[0].armOperand}"
$asm.puts "pop { #{operands[0].armOperand} }"
when "push"
$asm.puts "push #{operands[0].armOperand}"
$asm.puts "push { #{operands[0].armOperand} }"
when "popCalleeSaves"
if isARMv7
$asm.puts "pop {r4-r6, r8-r11}"
else
$asm.puts "pop {r4-r10}"
end
when "pushCalleeSaves"
if isARMv7
$asm.puts "push {r4-r6, r8-r11}"
else
$asm.puts "push {r4-r10}"
end
when "move"
if operands[0].immediate?
armMoveImmediate(operands[0].value, operands[1])
......
......@@ -38,7 +38,8 @@ require "risc"
#
# x0 => return value, cached result, first argument, t0, a0, r0
# x1 => t1, a1, r1
# x2 => t2
# x2 => t2, a2
# x3 => a3
# x9 => (nonArgGPR1 in baseline)
# x10 => t4 (unused in baseline)
# x11 => t5 (unused in baseline)
......@@ -47,10 +48,9 @@ require "risc"
# x16 => scratch
# x17 => scratch
# x23 => t3
# x25 => cfr
# x26 => timeout check (i.e. not touched by LLInt)
# x27 => csr1 (tagTypeNumber)
# x28 => csr2 (tagMask)
# x29 => cfr
# sp => sp
# lr => lr
#
......@@ -106,8 +106,10 @@ class RegisterID
arm64GPRName('x0', kind)
when 't1', 'a1', 'r1'
arm64GPRName('x1', kind)
when 't2'
when 't2', 'a2'
arm64GPRName('x2', kind)
when 'a3'
arm64GPRName('x3', kind)
when 't3'
arm64GPRName('x23', kind)
when 't4'
......@@ -567,6 +569,28 @@ class Instruction
emitARM64Unflipped("pop", operands, :ptr)
when "push"
emitARM64Unflipped("push", operands, :ptr)
when "popCalleeSaves"
emitARM64Unflipped("pop", "x28", :ptr)
emitARM64Unflipped("pop", "x27", :ptr)
emitARM64Unflipped("pop", "x26", :ptr)
emitARM64Unflipped("pop", "x25", :ptr)
emitARM64Unflipped("pop", "x24", :ptr)
emitARM64Unflipped("pop", "x23", :ptr)
emitARM64Unflipped("pop", "x22", :ptr)
emitARM64Unflipped("pop", "x21", :ptr)
emitARM64Unflipped("pop", "x20", :ptr)
emitARM64Unflipped("pop", "x19", :ptr)
when "pushCalleeSaves"
emitARM64Unflipped("push", "x19", :ptr)
emitARM64Unflipped("push", "x20", :ptr)
emitARM64Unflipped("push", "x21", :ptr)
emitARM64Unflipped("push", "x22", :ptr)
emitARM64Unflipped("push", "x23", :ptr)
emitARM64Unflipped("push", "x24", :ptr)
emitARM64Unflipped("push", "x25", :ptr)
emitARM64Unflipped("push", "x26", :ptr)
emitARM64Unflipped("push", "x27", :ptr)
emitARM64Unflipped("push", "x28", :ptr)
when "move"
if operands[0].immediate?
emitARM64MoveImmediate(operands[0].value, operands[1])
......
......@@ -249,6 +249,8 @@ MACRO_INSTRUCTIONS =
"bnz",
"leai",
"leap",
"pushCalleeSaves",
"popCalleeSaves"
]
X86_INSTRUCTIONS =
......
......@@ -82,6 +82,10 @@ class RegisterID
"$a0"
when "a1"
"$a1"
when "a2"
"$a2"
when "a3"
"$a3"
when "r0", "t0"
"$v0"
when "r1", "t1"
......@@ -792,6 +796,20 @@ class Instruction
when "push"
$asm.puts "addiu $sp, $sp, -4"
$asm.puts "sw #{operands[0].mipsOperand}, 0($sp)"
when "popCalleeSaves"
$asm.puts "lw $16, 0($sp)"
$asm.puts "lw $17, 4($sp)"
$asm.puts "lw $18, 8($sp)"
$asm.puts "lw $19, 12($sp)"
$asm.puts "lw $20, 16($sp)"
$asm.puts "addiu $sp, $sp, 20"
when "pushCalleeSaves"
$asm.puts "addiu $sp, $sp, -20"
$asm.puts "sw $20, 16($sp)"
$asm.puts "sw $19, 12($sp)"
$asm.puts "sw $18, 8($sp)"
$asm.puts "sw $17, 4($sp)"
$asm.puts "sw $16, 0($sp)"
when "move", "sxi2p", "zxi2p"
if operands[0].is_a? Immediate
mipsMoveImmediate(operands[0].value, operands[1])
......
......@@ -30,19 +30,21 @@ GPRS =
"t2",
"t3",
"t4",
"t5",
"cfr",
"a0",
"a1",
"a2",
"a3",
"r0",
"r1",
"sp",
"lr",
# 64-bit only registers:
"t5",
"t6", # r10
"csr1", # r14, tag type number register
"csr2" # r15, tag mask register
"t6",
"csr1", # tag type number register
"csr2" # tag mask register
]
FPRS =
......
......@@ -61,6 +61,10 @@ class RegisterID
"r4"
when "a1"
"r5"
when "a2"
"r6"
when "a3"
"r7"
when "t0"
"r0"
when "t1"
......@@ -70,7 +74,9 @@ class RegisterID
when "t3"
"r10"
when "t4"
"r6"
"r4"
when "t5"
"r5"
when "cfr"
"r14"
when "sp"
......@@ -905,6 +911,22 @@ class Instruction
$asm.puts "lds #{sh4Operands(operands)}, pr"
when "stspr"
$asm.puts "sts pr, #{sh4Operands(operands)}"
when "popCalleeSaves"
$asm.puts "mov.l @r15+, r8"
$asm.puts "mov.l @r15+, r9"
$asm.puts "mov.l @r15+, r10"
$asm.puts "mov.l @r15+, r11"
$asm.puts "mov.l @r15+, r13"
$asm.puts "lds.l @r15+,pr"
$asm.puts "mov.l @r15+, fp"
when "pushCalleeSaves"
$asm.puts "mov.l fp, @-r15"
$asm.puts "sts.l pr, @-r15"
$asm.puts "mov.l r13, @-r15"
$asm.puts "mov.l r11, @-r15"
$asm.puts "mov.l r10, @-r15"
$asm.puts "mov.l r9, @-r15"
$asm.puts "mov.l r8, @-r15"
when "break"
# This special opcode always generates an illegal instruction exception.
$asm.puts ".word 0xfffd"
......
......@@ -74,11 +74,11 @@ X64_SCRATCH_REGISTER = SpecialRegister.new("r11")
class RegisterID
def supports8BitOnX86
case name
when "t0", "a0", "r0", "t1", "a1", "r1", "t2", "t3"
when "t0", "a0", "r0", "t1", "a1", "r1", "t2", "t3", "t4", "t5"
true
when "cfr", "ttnr", "tmr"
false
when "t4", "t5"
when "t6"
isX64
else
raise
......@@ -204,7 +204,6 @@ class RegisterID
raise
end
when "t5"
raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
case kind
when :byte
"%dil"
......@@ -213,9 +212,9 @@ class RegisterID
when :int
"%edi"
when :ptr
"%rdi"
isX64 ? "%rdi" : "%edi"
when :quad
"%rdi"
isX64 ? "%rdi" : raise
end
when "t6"
raise "Cannot use #{name} in 32-bit X86 at #{codeOriginString}" unless isX64
......@@ -982,6 +981,30 @@ class Instruction
$asm.puts "pop #{operands[0].x86Operand(:ptr)}"
when "push"
$asm.puts "push #{operands[0].x86Operand(:ptr)}"
when "popCalleeSaves"
if isX64
$asm.puts "pop %rbx"
$asm.puts "pop %r15"
$asm.puts "pop %r14"
$asm.puts "pop %r13"