aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jit
diff options
context:
space:
mode:
authorErik Verbruggen <erik.verbruggen@qt.io>2018-09-04 12:19:10 +0200
committerErik Verbruggen <erik.verbruggen@qt.io>2018-10-05 11:18:16 +0000
commit052d22e116957a170e290a49d077d3e9f290a237 (patch)
tree8d63f1b622a7c93d8b845c3d77f796f5ad18493b /src/qml/jit
parent08342d761369c3755778f6d69fa6f5907ae1aead (diff)
ES7: Implement Tail Position Calls in the runtime
Change-Id: If1629109722496b3fd10b36b2376548440f2fee9 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jit')
-rw-r--r--src/qml/jit/qv4assemblercommon.cpp45
-rw-r--r--src/qml/jit/qv4assemblercommon_p.h61
-rw-r--r--src/qml/jit/qv4baselineassembler.cpp24
-rw-r--r--src/qml/jit/qv4baselineassembler_p.h4
-rw-r--r--src/qml/jit/qv4baselinejit.cpp12
5 files changed, 124 insertions, 22 deletions
diff --git a/src/qml/jit/qv4assemblercommon.cpp b/src/qml/jit/qv4assemblercommon.cpp
index 0ae4da17fa..fadb9dce08 100644
--- a/src/qml/jit/qv4assemblercommon.cpp
+++ b/src/qml/jit/qv4assemblercommon.cpp
@@ -212,6 +212,13 @@ PlatformAssemblerCommon::Address PlatformAssemblerCommon::argStackAddress(int ar
return Address(StackPointerRegister, offset * PointerSize);
}
+JSC::MacroAssemblerBase::Address PlatformAssemblerCommon::inArgStackAddress(int arg)
+{
+ int offset = arg - ArgInRegCount;
+ Q_ASSERT(offset >= 0);
+ return Address(FramePointerRegister, -(offset + 1) * PointerSize);
+}
+
void PlatformAssemblerCommon::passAccumulatorAsArg(int arg)
{
#ifndef QT_NO_DEBUG
@@ -329,12 +336,48 @@ void PlatformAssemblerCommon::callRuntime(const char *functionName, const void *
}
}
-void JIT::PlatformAssemblerCommon::callRuntimeUnchecked(const char *functionName, const void *funcPtr)
+void PlatformAssemblerCommon::callRuntimeUnchecked(const char *functionName, const void *funcPtr)
{
functions.insert(funcPtr, functionName);
callAbsolute(funcPtr);
}
+void PlatformAssemblerCommon::tailCallRuntime(const char *functionName, const void *funcPtr)
+{
+ functions.insert(funcPtr, functionName);
+ setTailCallArg(EngineRegister, 1);
+ setTailCallArg(CppStackFrameRegister, 0);
+ freeStackSpace();
+ generatePlatformFunctionExit(/*tailCall =*/ true);
+ jumpAbsolute(funcPtr);
+}
+
+void PlatformAssemblerCommon::setTailCallArg(RegisterID src, int arg)
+{
+ if (arg < ArgInRegCount)
+ move(src, registerForArg(arg));
+ else
+ storePtr(src, inArgStackAddress(arg));
+}
+
+JSC::MacroAssemblerBase::Address PlatformAssemblerCommon::jsAlloca(int slotCount)
+{
+ Address jsStackTopAddr(EngineRegister, offsetof(EngineBase, jsStackTop));
+ RegisterID jsStackTop = AccumulatorRegisterValue;
+ loadPtr(jsStackTopAddr, jsStackTop);
+ addPtr(TrustedImm32(sizeof(Value) * slotCount), jsStackTop);
+ storePtr(jsStackTop, jsStackTopAddr);
+ return Address(jsStackTop, 0);
+}
+
+void PlatformAssemblerCommon::storeInt32AsValue(int srcInt, Address destAddr)
+{
+ store32(TrustedImm32(srcInt),
+ Address(destAddr.base, destAddr.offset + QV4::Value::valueOffset()));
+ store32(TrustedImm32(int(QV4::Value::ValueTypeInternal::Integer)),
+ Address(destAddr.base, destAddr.offset + QV4::Value::tagOffset()));
+}
+
} // JIT namespace
} // QV4 namepsace
diff --git a/src/qml/jit/qv4assemblercommon_p.h b/src/qml/jit/qv4assemblercommon_p.h
index d64b9d0e5d..cbbd6464d9 100644
--- a/src/qml/jit/qv4assemblercommon_p.h
+++ b/src/qml/jit/qv4assemblercommon_p.h
@@ -116,14 +116,15 @@ public:
move(Arg1Reg, EngineRegister);
}
- void generatePlatformFunctionExit()
+ void generatePlatformFunctionExit(bool tailCall = false)
{
pop(EngineRegister);
pop(CppStackFrameRegister);
pop(JSStackFrameRegister);
pop(); // exceptionHandler
pop(FramePointerRegister);
- ret();
+ if (!tailCall)
+ ret();
}
void callAbsolute(const void *funcPtr)
@@ -132,6 +133,12 @@ public:
call(ScratchRegister);
}
+ void jumpAbsolute(const void *funcPtr)
+ {
+ move(TrustedImmPtr(funcPtr), ScratchRegister);
+ jump(ScratchRegister);
+ }
+
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(PointerSize), StackPointerRegister);
@@ -195,14 +202,15 @@ public:
move(Arg1Reg, EngineRegister);
}
- void generatePlatformFunctionExit()
+ void generatePlatformFunctionExit(bool tailCall = false)
{
pop(EngineRegister);
pop(CppStackFrameRegister);
pop(JSStackFrameRegister);
pop(); // exceptionHandler
pop(FramePointerRegister);
- ret();
+ if (!tailCall)
+ ret();
}
void callAbsolute(const void *funcPtr)
@@ -213,6 +221,12 @@ public:
addPtr(TrustedImm32(4 * PointerSize), StackPointerRegister);
}
+ void jumpAbsolute(const void *funcPtr)
+ {
+ move(TrustedImmPtr(funcPtr), ScratchRegister);
+ jump(ScratchRegister);
+ }
+
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(PointerSize), StackPointerRegister);
@@ -280,7 +294,7 @@ public:
loadPtr(Address(FramePointerRegister, 3 * PointerSize), EngineRegister);
}
- void generatePlatformFunctionExit()
+ void generatePlatformFunctionExit(bool tailCall = false)
{
addPtr(TrustedImm32(8), StackPointerRegister);
pop(EngineRegister);
@@ -288,7 +302,8 @@ public:
pop(JSStackFrameRegister);
pop(); // exceptionHandler
pop(RegisterID::ebp);
- ret();
+ if (!tailCall)
+ ret();
}
void callAbsolute(const void *funcPtr)
@@ -297,6 +312,12 @@ public:
call(ScratchRegister);
}
+ void jumpAbsolute(const void *funcPtr)
+ {
+ move(TrustedImmPtr(funcPtr), ScratchRegister);
+ jump(ScratchRegister);
+ }
+
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(PointerSize), StackPointerRegister);
@@ -375,13 +396,14 @@ public:
move(Arg1Reg, EngineRegister);
}
- void generatePlatformFunctionExit()
+ void generatePlatformFunctionExit(bool tailCall = false)
{
move(AccumulatorRegister, ReturnValueRegister);
popPair(EngineRegister, CppStackFrameRegister);
popPair(JSStackFrameRegister, AccumulatorRegister);
popPair(JSC::ARM64Registers::fp, JSC::ARM64Registers::lr);
- ret();
+ if (!tailCall)
+ ret();
}
void callAbsolute(const void *funcPtr)
@@ -390,6 +412,12 @@ public:
call(ScratchRegister);
}
+ void jumpAbsolute(const void *funcPtr)
+ {
+ move(TrustedImmPtr(funcPtr), ScratchRegister);
+ jump(ScratchRegister);
+ }
+
void pushAligned(RegisterID reg)
{
pushToSave(reg);
@@ -462,7 +490,7 @@ public:
move(Arg1Reg, EngineRegister);
}
- void generatePlatformFunctionExit()
+ void generatePlatformFunctionExit(bool tailCall = false)
{
move(AccumulatorRegisterValue, ReturnValueRegisterValue);
move(AccumulatorRegisterTag, ReturnValueRegisterTag);
@@ -476,7 +504,8 @@ public:
pop(); // exceptionHandler
pop(FramePointerRegister);
pop(JSC::ARMRegisters::lr);
- ret();
+ if (!tailCall)
+ ret();
}
void callAbsolute(const void *funcPtr)
@@ -485,6 +514,12 @@ public:
call(dataTempRegister);
}
+ void jumpAbsolute(const void *funcPtr)
+ {
+ move(TrustedImmPtr(funcPtr), dataTempRegister);
+ jump(dataTempRegister);
+ }
+
void pushAligned(RegisterID reg)
{
subPtr(TrustedImm32(PointerSize), StackPointerRegister);
@@ -663,11 +698,15 @@ public:
void passInt32AsArg(int value, int arg);
void callRuntime(const char *functionName, const void *funcPtr);
void callRuntimeUnchecked(const char *functionName, const void *funcPtr);
-
+ void tailCallRuntime(const char *functionName, const void *funcPtr);
+ void setTailCallArg(RegisterID src, int arg);
+ Address jsAlloca(int slotCount);
+ void storeInt32AsValue(int srcInt, Address destAddr);
private:
void passAccumulatorAsArg_internal(int arg, bool doPush);
static Address argStackAddress(int arg);
+ static Address inArgStackAddress(int arg);
private:
const Value* constantTable;
diff --git a/src/qml/jit/qv4baselineassembler.cpp b/src/qml/jit/qv4baselineassembler.cpp
index d53bb84827..f6b745632b 100644
--- a/src/qml/jit/qv4baselineassembler.cpp
+++ b/src/qml/jit/qv4baselineassembler.cpp
@@ -1446,7 +1446,29 @@ void BaselineAssembler::callRuntime(const char *functionName, const void *funcPt
void BaselineAssembler::saveAccumulatorInFrame()
{
pasm()->storeAccumulator(PlatformAssembler::Address(PlatformAssembler::JSStackFrameRegister,
- offsetof(CallData, accumulator)));
+ offsetof(CallData, accumulator)));
+}
+
+static ReturnedValue TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing(CppStackFrame *frame, ExecutionEngine *engine)
+{
+ return Runtime::method_tailCall(frame, engine);
+}
+
+void BaselineAssembler::jsTailCall(int func, int thisObject, int argc, int argv)
+{
+ Address tos = pasm()->jsAlloca(4);
+
+ int32_t argcOffset = tos.offset + int32_t(sizeof(Value)) * Runtime::StackOffsets::tailCall_argc;
+ int32_t argvOffset = tos.offset + int32_t(sizeof(Value)) * Runtime::StackOffsets::tailCall_argv;
+ int32_t thisOffset = tos.offset + int32_t(sizeof(Value)) * Runtime::StackOffsets::tailCall_thisObject;
+ int32_t funcOffset = tos.offset + int32_t(sizeof(Value)) * Runtime::StackOffsets::tailCall_function;
+
+ pasm()->storeInt32AsValue(argc, Address(tos.base, argcOffset));
+ pasm()->storeInt32AsValue(argv, Address(tos.base, argvOffset));
+ pasm()->moveReg(regAddr(thisObject), Address(tos.base, thisOffset));
+ pasm()->moveReg(regAddr(func), Address(tos.base, funcOffset));
+ pasm()->tailCallRuntime("TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing",
+ reinterpret_cast<void *>(TheJitIs__Tail_Calling__ToTheRuntimeSoTheJitFrameIsMissing));
}
void BaselineAssembler::checkException()
diff --git a/src/qml/jit/qv4baselineassembler_p.h b/src/qml/jit/qv4baselineassembler_p.h
index a2140ce47b..0aa508ae71 100644
--- a/src/qml/jit/qv4baselineassembler_p.h
+++ b/src/qml/jit/qv4baselineassembler_p.h
@@ -67,6 +67,9 @@ namespace JIT {
callRuntime(JIT_STRINGIFY(function), \
reinterpret_cast<void *>(&function), \
destination)
+#define GENERATE_TAIL_CALL(function) \
+ tailCallRuntime(JIT_STRINGIFY(function), \
+ reinterpret_cast<void *>(&function))
class BaselineAssembler {
public:
@@ -149,6 +152,7 @@ public:
void passInt32AsArg(int value, int arg);
void callRuntime(const char *functionName, const void *funcPtr, CallResultDestination dest);
void saveAccumulatorInFrame();
+ void jsTailCall(int func, int thisObject, int argc, int argv);
// exception/context stuff
void checkException();
diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp
index 70d1672689..bbbe0c69c5 100644
--- a/src/qml/jit/qv4baselinejit.cpp
+++ b/src/qml/jit/qv4baselinejit.cpp
@@ -77,6 +77,8 @@ void BaselineJIT::generate()
#define STORE_ACC() as->saveAccumulatorInFrame()
#define BASELINEJIT_GENERATE_RUNTIME_CALL(function, destination) \
as->GENERATE_RUNTIME_CALL(function, destination)
+#define BASELINEJIT_GENERATE_TAIL_CALL(function) \
+ as->GENERATE_TAIL_CALL(function)
void BaselineJIT::generate_Ret()
{
@@ -555,17 +557,9 @@ void BaselineJIT::generate_CallWithSpread(int func, int thisObject, int argc, in
void BaselineJIT::generate_TailCall(int func, int thisObject, int argc, int argv)
{
STORE_IP();
- as->prepareCallWithArgCount(5);
- as->passInt32AsArg(argc, 4);
- as->passJSSlotAsArg(argv, 3);
- as->passJSSlotAsArg(thisObject, 2);
- as->passJSSlotAsArg(func, 1);
- as->passEngineAsArg(0);
- BASELINEJIT_GENERATE_RUNTIME_CALL(Runtime::method_tailCall, CallResultDestination::InAccumulator);
- as->checkException();
+ as->jsTailCall(func, thisObject, argc, argv);
}
-
void BaselineJIT::generate_Construct(int func, int argc, int argv)
{
STORE_IP();