aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4runtime.cpp
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/jsruntime/qv4runtime.cpp
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/jsruntime/qv4runtime.cpp')
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp25
1 files changed, 22 insertions, 3 deletions
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 470629bd1f..66cd06ee1f 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1536,13 +1536,32 @@ ReturnedValue Runtime::method_constructWithSpread(ExecutionEngine *engine, const
return static_cast<const FunctionObject &>(function).callAsConstructor(arguments.argv, arguments.argc, &newTarget);
}
-ReturnedValue Runtime::method_tailCall(ExecutionEngine *engine, const Value &function, const Value &thisObject, Value *argv, int argc)
+ReturnedValue Runtime::method_tailCall(CppStackFrame *frame, ExecutionEngine *engine)
{
- //### unwinding the stack, etc, is done in a subsequent patch
+ // IMPORTANT! The JIT assumes that this method has the same amount (or less) arguments than
+ // the jitted function, so it can safely do a tail call.
+
+ Value *tos = engine->jsStackTop;
+ const Value &function = tos[StackOffsets::tailCall_function];
+ const Value &thisObject = tos[StackOffsets::tailCall_thisObject];
+ Value *argv = reinterpret_cast<Value *>(frame->jsFrame) + tos[StackOffsets::tailCall_argv].int_32();
+ int argc = tos[StackOffsets::tailCall_argc].int_32();
+
if (!function.isFunctionObject())
return engine->throwTypeError();
- return static_cast<const FunctionObject &>(function).call(&thisObject, argv, argc);
+ const FunctionObject &fo = static_cast<const FunctionObject &>(function);
+ if (!frame->callerCanHandleTailCall || !fo.canBeTailCalled() || engine->debugger()) {
+ // Cannot tailcall, do a normal call:
+ return fo.call(&thisObject, argv, argc);
+ }
+
+ memcpy(frame->jsFrame->args, argv, argc * sizeof(Value));
+ frame->init(engine, fo.function(), frame->jsFrame->args, argc, frame->callerCanHandleTailCall);
+ frame->setupJSFrame(frame->savedStackTop, fo, fo.scope(), thisObject, Primitive::undefinedValue());
+ engine->jsStackTop = frame->savedStackTop + frame->requiredJSStackFrameSize();
+ frame->pendingTailCall = true;
+ return Encode::undefined();
}
void Runtime::method_throwException(ExecutionEngine *engine, const Value &value)