diff options
author | Erik Verbruggen <erik.verbruggen@qt.io> | 2018-09-04 12:19:10 +0200 |
---|---|---|
committer | Erik Verbruggen <erik.verbruggen@qt.io> | 2018-10-05 11:18:16 +0000 |
commit | 052d22e116957a170e290a49d077d3e9f290a237 (patch) | |
tree | 8d63f1b622a7c93d8b845c3d77f796f5ad18493b /src/qml/jit | |
parent | 08342d761369c3755778f6d69fa6f5907ae1aead (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.cpp | 45 | ||||
-rw-r--r-- | src/qml/jit/qv4assemblercommon_p.h | 61 | ||||
-rw-r--r-- | src/qml/jit/qv4baselineassembler.cpp | 24 | ||||
-rw-r--r-- | src/qml/jit/qv4baselineassembler_p.h | 4 | ||||
-rw-r--r-- | src/qml/jit/qv4baselinejit.cpp | 12 |
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(); |