diff options
author | Erik Verbruggen <erik.verbruggen@qt.io> | 2016-06-22 10:12:13 +0200 |
---|---|---|
committer | Erik Verbruggen <erik.verbruggen@qt.io> | 2016-06-22 11:07:05 +0000 |
commit | 702c4247d74ffb7e4fb1aaca96d70f4591203ba2 (patch) | |
tree | 6c0a41332cf4a8ab0051600efdd27b0746574795 /src/qml/jsruntime/qv4functionobject.cpp | |
parent | fd0e3c6d569a7410fff33974ce9f908dc2de0e22 (diff) |
V4: Pass scope around as parameters inside the runtime.
The implementation of many (or all) runtime functions consist of first
creating a QV4::Scope, which saves and restores the JS stack pointer.
It also prevents tail-calls because of that restoring behavior. In many
cases it suffices to do that at the entry-point of the runtime.
The return value of a JS function call is now also stored in the scope.
Previously, all return values were stored in a ScopedValue, got loaded
on return, and immediately stored in another ScopedValue in the caller.
This resulted in a lot of stores, where now there is only one store
needed, and no extra ScopedValue for every function.
Change-Id: I13d80fc0ce72c5702ef1536d41d12f710c5914fa
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4functionobject.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 186 |
1 files changed, 94 insertions, 92 deletions
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 5d2c57a2ba..041044930b 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -166,14 +166,6 @@ ReturnedValue FunctionObject::name() const return get(scope()->engine->id_name()); } - -ReturnedValue FunctionObject::newInstance() -{ - Scope scope(internalClass()->engine); - ScopedCallData callData(scope); - return construct(callData); -} - ReturnedValue FunctionObject::construct(const Managed *that, CallData *) { return static_cast<const FunctionObject *>(that)->engine()->throwTypeError(); @@ -251,9 +243,8 @@ Heap::FunctionCtor::FunctionCtor(QV4::ExecutionContext *scope) } // 15.3.2 -ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) +void FunctionCtor::construct(const Managed *that, Scope &scope, CallData *callData) { - Scope scope(static_cast<const Object *>(that)->engine()); Scoped<FunctionCtor> f(scope, static_cast<const FunctionCtor *>(that)); QString arguments; @@ -266,8 +257,10 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) } body = callData->args[callData->argc - 1].toQString(); } - if (scope.engine->hasException) - return Encode::undefined(); + if (scope.engine->hasException) { + scope.result = Encode::undefined(); + return; + } QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1Char('}'); @@ -278,13 +271,17 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) const bool parsed = parser.parseExpression(); - if (!parsed) - return scope.engine->throwSyntaxError(QLatin1String("Parse error")); + if (!parsed) { + scope.result = scope.engine->throwSyntaxError(QLatin1String("Parse error")); + return; + } using namespace QQmlJS::AST; FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode()); - if (!fe) - return scope.engine->throwSyntaxError(QLatin1String("Parse error")); + if (!fe) { + scope.result = scope.engine->throwSyntaxError(QLatin1String("Parse error")); + return; + } IR::Module module(scope.engine->debugger != 0); @@ -297,13 +294,13 @@ ReturnedValue FunctionCtor::construct(const Managed *that, CallData *callData) Function *vmf = compilationUnit->linkToEngine(scope.engine); ExecutionContext *global = scope.engine->rootContext(); - return FunctionObject::createScriptFunction(global, vmf)->asReturnedValue(); + scope.result = FunctionObject::createScriptFunction(global, vmf); } // 15.3.1: This is equivalent to new Function(...) -ReturnedValue FunctionCtor::call(const Managed *that, CallData *callData) +void FunctionCtor::call(const Managed *that, Scope &scope, CallData *callData) { - return construct(that, callData); + construct(that, scope, callData); } DEFINE_OBJECT_VTABLE(FunctionPrototype); @@ -376,7 +373,8 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx) } callData->thisObject = ctx->argument(0); - return o->call(callData); + o->call(scope, callData); + return scope.result.asReturnedValue(); } ReturnedValue FunctionPrototype::method_call(CallContext *ctx) @@ -393,7 +391,9 @@ ReturnedValue FunctionPrototype::method_call(CallContext *ctx) callData->args[i - 1] = ctx->args()[i]; } callData->thisObject = ctx->argument(0); - return o->call(callData); + + o->call(scope, callData); + return scope.result.asReturnedValue(); } ReturnedValue FunctionPrototype::method_bind(CallContext *ctx) @@ -422,14 +422,15 @@ Heap::ScriptFunction::ScriptFunction(QV4::ExecutionContext *scope, Function *fun { } -ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData) +void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *callData) { - ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); - if (v4->hasException) - return Encode::undefined(); - CHECK_STACK_LIMITS(v4); + ExecutionEngine *v4 = scope.engine; + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + CHECK_STACK_LIMITS(v4, scope); - Scope scope(v4); ExecutionContextSaver ctxSaver(scope); Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); @@ -442,39 +443,37 @@ ReturnedValue ScriptFunction::construct(const Managed *that, CallData *callData) Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData)); v4->pushContext(ctx); - ScopedValue result(scope, Q_V4_PROFILE(v4, f->function())); + scope.result = Q_V4_PROFILE(v4, f->function()); if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction); - - if (v4->hasException) - return Encode::undefined(); + QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); - if (result->isObject()) - return result->asReturnedValue(); - return obj.asReturnedValue(); + if (v4->hasException) { + scope.result = Encode::undefined(); + } else if (!scope.result.isObject()) { + scope.result = obj.asReturnedValue(); + } } -ReturnedValue ScriptFunction::call(const Managed *that, CallData *callData) +void ScriptFunction::call(const Managed *that, Scope &scope, CallData *callData) { - ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); - if (v4->hasException) - return Encode::undefined(); - CHECK_STACK_LIMITS(v4); + ExecutionEngine *v4 = scope.engine; + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + CHECK_STACK_LIMITS(v4, scope); - Scope scope(v4); ExecutionContextSaver ctxSaver(scope); Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that)); Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData)); v4->pushContext(ctx); - ScopedValue result(scope, Q_V4_PROFILE(v4, f->function())); + scope.result = Q_V4_PROFILE(v4, f->function()); if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(scope.engine, f->function()->compiledFunction); - - return result->asReturnedValue(); + QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); } DEFINE_OBJECT_VTABLE(SimpleScriptFunction); @@ -511,14 +510,15 @@ Heap::SimpleScriptFunction::SimpleScriptFunction(QV4::ExecutionContext *scope, F } } -ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *callData) +void SimpleScriptFunction::construct(const Managed *that, Scope &scope, CallData *callData) { - ExecutionEngine *v4 = static_cast<const Object *>(that)->engine(); - if (v4->hasException) - return Encode::undefined(); - CHECK_STACK_LIMITS(v4); + ExecutionEngine *v4 = scope.engine; + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + CHECK_STACK_LIMITS(v4, scope); - Scope scope(v4); ExecutionContextSaver ctxSaver(scope); Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); @@ -542,24 +542,24 @@ ReturnedValue SimpleScriptFunction::construct(const Managed *that, CallData *cal v4->pushContext(&ctx); Q_ASSERT(v4->current == &ctx); - ScopedObject result(scope, Q_V4_PROFILE(v4, f->function())); + scope.result = Q_V4_PROFILE(v4, f->function()); if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction); + QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); - if (!result) - return callData->thisObject.asReturnedValue(); - return result.asReturnedValue(); + if (!scope.result.isManaged() || !scope.result.managed()) + scope.result = callData->thisObject; } -ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData) +void SimpleScriptFunction::call(const Managed *that, Scope &scope, CallData *callData) { - ExecutionEngine *v4 = static_cast<const SimpleScriptFunction *>(that)->internalClass()->engine; - if (v4->hasException) - return Encode::undefined(); - CHECK_STACK_LIMITS(v4); + ExecutionEngine *v4 = scope.engine; + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + CHECK_STACK_LIMITS(v4, scope); - Scope scope(v4); ExecutionContextSaver ctxSaver(scope); Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that)); @@ -579,12 +579,10 @@ ReturnedValue SimpleScriptFunction::call(const Managed *that, CallData *callData v4->pushContext(&ctx); Q_ASSERT(v4->current == &ctx); - ScopedValue result(scope, Q_V4_PROFILE(v4, f->function())); + scope.result = Q_V4_PROFILE(v4, f->function()); if (f->function()->compiledFunction->hasQmlDependencies()) - QQmlPropertyCapture::registerQmlDependencies(v4, f->function()->compiledFunction); - - return result->asReturnedValue(); + QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope); } Heap::Object *SimpleScriptFunction::protoForConstructor() @@ -606,20 +604,21 @@ Heap::BuiltinFunction::BuiltinFunction(QV4::ExecutionContext *scope, QV4::String { } -ReturnedValue BuiltinFunction::construct(const Managed *f, CallData *) +void BuiltinFunction::construct(const Managed *f, Scope &scope, CallData *) { - return static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); + scope.result = static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError(); } -ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData) +void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData) { const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that); - ExecutionEngine *v4 = f->internalClass()->engine; - if (v4->hasException) - return Encode::undefined(); - CHECK_STACK_LIMITS(v4); + ExecutionEngine *v4 = scope.engine; + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + CHECK_STACK_LIMITS(v4, scope); - Scope scope(v4); ExecutionContextSaver ctxSaver(scope); CallContext::Data ctx(v4); @@ -630,18 +629,19 @@ ReturnedValue BuiltinFunction::call(const Managed *that, CallData *callData) v4->pushContext(&ctx); Q_ASSERT(v4->current == &ctx); - return f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext)); + scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext)); } -ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callData) +void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData) { const IndexedBuiltinFunction *f = static_cast<const IndexedBuiltinFunction *>(that); - ExecutionEngine *v4 = f->internalClass()->engine; - if (v4->hasException) - return Encode::undefined(); - CHECK_STACK_LIMITS(v4); + ExecutionEngine *v4 = scope.engine; + if (v4->hasException) { + scope.result = Encode::undefined(); + return; + } + CHECK_STACK_LIMITS(v4, scope); - Scope scope(v4); ExecutionContextSaver ctxSaver(scope); CallContext::Data ctx(v4); @@ -652,7 +652,7 @@ ReturnedValue IndexedBuiltinFunction::call(const Managed *that, CallData *callDa v4->pushContext(&ctx); Q_ASSERT(v4->current == &ctx); - return f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext), f->d()->index); + scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext), f->d()->index); } DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction); @@ -685,12 +685,13 @@ Heap::BoundFunction::BoundFunction(QV4::ExecutionContext *scope, QV4::FunctionOb f->insertMember(s.engine->id_caller(), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable); } -ReturnedValue BoundFunction::call(const Managed *that, CallData *dd) +void BoundFunction::call(const Managed *that, Scope &scope, CallData *dd) { const BoundFunction *f = static_cast<const BoundFunction *>(that); - Scope scope(f->engine()); - if (scope.hasException()) - return Encode::undefined(); + if (scope.hasException()) { + scope.result = Encode::undefined(); + return; + } Scoped<MemberData> boundArgs(scope, f->boundArgs()); ScopedCallData callData(scope, (boundArgs ? boundArgs->size() : 0) + dd->argc); @@ -702,15 +703,16 @@ ReturnedValue BoundFunction::call(const Managed *that, CallData *dd) } memcpy(argp, dd->args, dd->argc*sizeof(Value)); ScopedFunctionObject t(scope, f->target()); - return t->call(callData); + t->call(scope, callData); } -ReturnedValue BoundFunction::construct(const Managed *that, CallData *dd) +void BoundFunction::construct(const Managed *that, Scope &scope, CallData *dd) { const BoundFunction *f = static_cast<const BoundFunction *>(that); - Scope scope(f->engine()); - if (scope.hasException()) - return Encode::undefined(); + if (scope.hasException()) { + scope.result = Encode::undefined(); + return; + } Scoped<MemberData> boundArgs(scope, f->boundArgs()); ScopedCallData callData(scope, (boundArgs ? boundArgs->size() : 0) + dd->argc); @@ -721,7 +723,7 @@ ReturnedValue BoundFunction::construct(const Managed *that, CallData *dd) } memcpy(argp, dd->args, dd->argc*sizeof(Value)); ScopedFunctionObject t(scope, f->target()); - return t->construct(callData); + t->construct(scope, callData); } void BoundFunction::markObjects(Heap::Base *that, ExecutionEngine *e) |