aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2016-12-01 15:37:32 +0100
committerLars Knoll <lars.knoll@qt.io>2016-12-09 08:31:01 +0000
commitdeec039008c4df5ec2686459ee8c00801ee9d852 (patch)
tree0998823cc67809bbdf83424edd07d9175ea6c613
parente54e4408bd03edc789370dd7670eb6da25e8a9bb (diff)
Refactor the calling code for (Simple)ScriptFunction
Factor the common code out into separate methods that can later on be reused by the QQmlJavaScriptExpression. Also ensure a CallContext is safe to use with a 0 FunctionObject. Change-Id: I1181a8e320b8c931d9df5b2c91bc143d8587fb60 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp2
-rw-r--r--src/qml/jsruntime/qv4context.cpp76
-rw-r--r--src/qml/jsruntime/qv4context_p.h9
-rw-r--r--src/qml/jsruntime/qv4engine.cpp5
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp73
-rw-r--r--src/qml/jsruntime/qv4script.cpp34
6 files changed, 93 insertions, 106 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
index b2db23d78c..aed2759383 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
@@ -60,7 +60,7 @@ QV4::CallContext *QV4DataCollector::findContext(int frame)
QV4::ExecutionContext *ctx = engine()->currentContext;
while (ctx) {
QV4::CallContext *cCtxt = ctx->asCallContext();
- if (cCtxt && cCtxt->d()->function) {
+ if (cCtxt && cCtxt->d()->v4Function) {
if (frame < 1)
return cCtxt;
--frame;
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 26f2f996a6..df0ecdd5d3 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -48,6 +48,8 @@
#include "qv4errorobject_p.h"
#include "qv4string_p.h"
#include "qv4qmlcontext_p.h"
+#include "qv4profiling_p.h"
+#include <private/qqmljavascriptexpression_p.h>
using namespace QV4;
@@ -57,28 +59,30 @@ DEFINE_MANAGED_VTABLE(WithContext);
DEFINE_MANAGED_VTABLE(CatchContext);
DEFINE_MANAGED_VTABLE(GlobalContext);
-Heap::CallContext *ExecutionContext::newCallContext(const FunctionObject *function, CallData *callData)
-{
- Q_ASSERT(function->function());
+/* Function *f, int argc */
+#define requiredMemoryForExecutionContect(f, argc) \
+ ((sizeof(CallContext::Data) + 7) & ~7) + \
+ sizeof(Value) * (f->compiledFunction->nLocals + qMax((uint)argc, f->nFormals)) + sizeof(CallData)
+Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData *callData)
+{
Heap::CallContext *c = d()->engine->memoryManager->allocManaged<CallContext>(
requiredMemoryForExecutionContect(function, callData->argc));
c->init(d()->engine, Heap::ExecutionContext::Type_CallContext);
- c->function = function->d();
- c->v4Function = function->d()->function;
+ c->v4Function = function;
- c->strictMode = function->strictMode();
- c->outer = function->scope();
+ c->strictMode = function->isStrict();
+ c->outer = this->d();
c->activation = 0;
- c->compilationUnit = function->function()->compilationUnit;
+ c->compilationUnit = function->compilationUnit;
c->lookups = c->compilationUnit->runtimeLookups;
c->constantTable = c->compilationUnit->constants;
c->locals = (Value *)((quintptr(c + 1) + 7) & ~7);
- const CompiledData::Function *compiledFunction = function->function()->compiledFunction;
+ const CompiledData::Function *compiledFunction = function->compiledFunction;
int nLocals = compiledFunction->nLocals;
if (nLocals)
std::fill(c->locals, c->locals + nLocals, Primitive::undefinedValue());
@@ -278,7 +282,7 @@ void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine)
break;
case Heap::ExecutionContext::Type_CallContext: {
QV4::Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx);
- Q_ASSERT(c->v4Function && c->function);
+ Q_ASSERT(c->v4Function);
ctx->callData->thisObject.mark(engine);
for (int arg = 0; arg < qMax(ctx->callData->argc, (int)c->v4Function->nFormals); ++arg)
ctx->callData->args[arg].mark(engine);
@@ -286,7 +290,8 @@ void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine)
c->locals[local].mark(engine);
if (c->activation)
c->activation->mark(engine);
- c->function->mark(engine);
+ if (c->function)
+ c->function->mark(engine);
break;
}
case Heap::ExecutionContext::Type_QmlContext: {
@@ -297,6 +302,51 @@ void ExecutionContext::markObjects(Heap::Base *m, ExecutionEngine *engine)
}
}
+// Do a standard call with this execution context as the outer scope
+void ExecutionContext::call(Scope &scope, CallData *callData, Function *function, const FunctionObject *f)
+{
+ ExecutionContextSaver ctxSaver(scope);
+
+ Scoped<CallContext> ctx(scope, newCallContext(function, callData));
+ if (f)
+ ctx->d()->function = f->d();
+ scope.engine->pushContext(ctx);
+
+ scope.result = Q_V4_PROFILE(scope.engine, function);
+
+ if (function->hasQmlDependencies)
+ QQmlPropertyCapture::registerQmlDependencies(function->compiledFunction, scope);
+}
+
+// Do a simple, fast call with this execution context as the outer scope
+void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Function *function)
+{
+ Q_ASSERT(function->canUseSimpleFunction());
+
+ ExecutionContextSaver ctxSaver(scope);
+
+ CallContext::Data ctx = CallContext::Data::createOnStack(scope.engine);
+
+ ctx.strictMode = function->isStrict();
+ ctx.callData = callData;
+ ctx.v4Function = function;
+ ctx.compilationUnit = function->compilationUnit;
+ ctx.lookups = function->compilationUnit->runtimeLookups;
+ ctx.constantTable = function->compilationUnit->constants;
+ ctx.outer = this->d();
+ ctx.locals = scope.alloc(function->compiledFunction->nLocals);
+ for (int i = callData->argc; i < (int)function->nFormals; ++i)
+ callData->args[i] = Encode::undefined();
+
+ scope.engine->pushContext(&ctx);
+ Q_ASSERT(scope.engine->current == &ctx);
+
+ scope.result = Q_V4_PROFILE(scope.engine, function);
+
+ if (function->compiledFunction->hasQmlDependencies())
+ QQmlPropertyCapture::registerQmlDependencies(function->compiledFunction, scope);
+}
+
void ExecutionContext::setProperty(String *name, const Value &value)
{
Scope scope(this);
@@ -425,7 +475,7 @@ ReturnedValue ExecutionContext::getProperty(String *name)
if (hasProperty)
return v->asReturnedValue();
}
- if (c->v4Function && c->v4Function->isNamedExpression()
+ if (c->function && c->v4Function->isNamedExpression()
&& name->equals(ScopedString(scope, c->v4Function->name())))
return c->function->asReturnedValue();
break;
@@ -503,7 +553,7 @@ ReturnedValue ExecutionContext::getPropertyAndBase(String *name, Value *base)
if (hasProperty)
return v->asReturnedValue();
}
- if (c->v4Function && c->v4Function->isNamedExpression()
+ if (c->function && c->v4Function->isNamedExpression()
&& name->equals(ScopedString(scope, c->v4Function->name())))
return c->function->asReturnedValue();
break;
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 7bf58ab5c6..c985fdb24d 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -198,7 +198,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
ExecutionEngine *engine() const { return d()->engine; }
- Heap::CallContext *newCallContext(const FunctionObject *f, CallData *callData);
+ Heap::CallContext *newCallContext(Function *f, CallData *callData);
Heap::WithContext *newWithContext(Heap::Object *with);
Heap::CatchContext *newCatchContext(Heap::String *exceptionVarName, ReturnedValue exceptionValue);
@@ -230,6 +230,9 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
ReturnedValue argument(int i) const {
return d()->callData->argument(i);
}
+
+ void call(Scope &scope, CallData *callData, QV4::Function *function, const QV4::FunctionObject *f = 0);
+ void simpleCall(Scope &scope, CallData *callData, QV4::Function *function);
};
struct Q_QML_EXPORT CallContext : public ExecutionContext
@@ -296,10 +299,6 @@ inline Heap::CallContext Heap::CallContext::createOnStack(ExecutionEngine *v4)
return ctxt;
}
-/* Function *f, int argc */
-#define requiredMemoryForExecutionContect(f, argc) \
- ((sizeof(CallContext::Data) + 7) & ~7) + sizeof(Value) * (f->varCount() + qMax((uint)argc, f->formalParameterCount())) + sizeof(CallData)
-
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index c438b99cf0..0520bfe216 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -866,9 +866,8 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
ExecutionContext *c = currentContext;
while (c) {
CallContext *callCtx = c->asCallContext();
- if (callCtx && callCtx->d()->function) {
- if (callCtx->d()->function->function)
- base.setUrl(callCtx->d()->function->function->sourceFile());
+ if (callCtx && callCtx->d()->v4Function) {
+ base.setUrl(callCtx->d()->v4Function->sourceFile());
break;
}
c = parentContext(c);
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 21edf1d8d3..08d66bec6f 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -441,15 +441,13 @@ void ScriptFunction::construct(const Managed *that, Scope &scope, CallData *call
InternalClass *ic = v4->emptyClass;
ScopedObject proto(scope, f->protoForConstructor());
ScopedObject obj(scope, v4->newObject(ic, proto));
-
callData->thisObject = obj.asReturnedValue();
- Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData));
- v4->pushContext(ctx);
- scope.result = Q_V4_PROFILE(v4, f->function());
+ QV4::Function *v4Function = f->function();
+ Q_ASSERT(v4Function);
- if (f->function()->hasQmlDependencies)
- QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope);
+ ScopedContext c(scope, f->scope());
+ c->call(scope, callData, v4Function, f);
if (Q_UNLIKELY(v4->hasException)) {
scope.result = Encode::undefined();
@@ -467,16 +465,13 @@ void ScriptFunction::call(const Managed *that, Scope &scope, CallData *callData)
}
CHECK_STACK_LIMITS(v4, scope);
- ExecutionContextSaver ctxSaver(scope);
-
Scoped<ScriptFunction> f(scope, static_cast<const ScriptFunction *>(that));
- Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(f, callData));
- v4->pushContext(ctx);
- scope.result = Q_V4_PROFILE(v4, f->function());
+ QV4::Function *v4Function = f->function();
+ Q_ASSERT(v4Function);
- if (f->function()->hasQmlDependencies)
- QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope);
+ ScopedContext c(scope, f->scope());
+ c->call(scope, callData, v4Function, f);
}
DEFINE_OBJECT_VTABLE(SimpleScriptFunction);
@@ -523,35 +518,17 @@ void SimpleScriptFunction::construct(const Managed *that, Scope &scope, CallData
}
CHECK_STACK_LIMITS(v4, scope);
- ExecutionContextSaver ctxSaver(scope);
-
Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that));
InternalClass *ic = scope.engine->emptyClass;
ScopedObject proto(scope, f->protoForConstructor());
callData->thisObject = v4->newObject(ic, proto);
- CallContext::Data ctx = CallContext::Data::createOnStack(v4);
- ctx.function = f->d();
- QV4::Function *ff = ctx.function->function;
- ctx.v4Function = ff;
- ctx.strictMode = ff->isStrict();
- ctx.callData = callData;
- ctx.compilationUnit = ff->compilationUnit;
- ctx.lookups = ctx.compilationUnit->runtimeLookups;
- ctx.constantTable = ctx.compilationUnit->constants;
- ctx.outer = ctx.function->scope;
- if (unsigned varCount = f->varCount())
- ctx.locals = scope.alloc(varCount);
- for (int i = callData->argc; i < static_cast<int>(ff->nFormals); ++i)
- callData->args[i] = Encode::undefined();
- v4->pushContext(&ctx);
- Q_ASSERT(v4->current == &ctx);
+ QV4::Function *v4Function = f->function();
+ Q_ASSERT(v4Function);
- scope.result = Q_V4_PROFILE(v4, ff);
-
- if (ff->hasQmlDependencies)
- QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope);
+ ScopedContext c(scope, f->scope());
+ c->simpleCall(scope, callData, v4Function);
if (Q_UNLIKELY(v4->hasException)) {
scope.result = Encode::undefined();
@@ -569,31 +546,13 @@ void SimpleScriptFunction::call(const Managed *that, Scope &scope, CallData *cal
}
CHECK_STACK_LIMITS(v4, scope);
- ExecutionContextSaver ctxSaver(scope);
-
Scoped<SimpleScriptFunction> f(scope, static_cast<const SimpleScriptFunction *>(that));
- CallContext::Data ctx = CallContext::Data::createOnStack(v4);
- ctx.function = f->d();
- QV4::Function *ff = ctx.function->function;
- ctx.v4Function = ff;
- ctx.strictMode = ff->isStrict();
- ctx.callData = callData;
- ctx.compilationUnit = ff->compilationUnit;
- ctx.lookups = ctx.compilationUnit->runtimeLookups;
- ctx.constantTable = ctx.compilationUnit->constants;
- ctx.outer = ctx.function->scope;
- if (unsigned varCount = f->varCount())
- ctx.locals = scope.alloc(varCount);
- for (int i = callData->argc; i < static_cast<int>(ff->nFormals); ++i)
- callData->args[i] = Encode::undefined();
- v4->pushContext(&ctx);
- Q_ASSERT(v4->current == &ctx);
-
- scope.result = Q_V4_PROFILE(v4, ff);
+ QV4::Function *v4Function = f->function();
+ Q_ASSERT(v4Function);
- if (ff->hasQmlDependencies)
- QQmlPropertyCapture::registerQmlDependencies(f->function()->compiledFunction, scope);
+ ScopedContext c(scope, f->scope());
+ c->simpleCall(scope, callData, v4Function);
}
Heap::Object *SimpleScriptFunction::protoForConstructor() const
diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp
index 8c27d36f50..25089855bb 100644
--- a/src/qml/jsruntime/qv4script.cpp
+++ b/src/qml/jsruntime/qv4script.cpp
@@ -72,7 +72,9 @@ struct QmlBindingWrapper : FunctionObject {
struct QmlBindingWrapper : FunctionObject {
V4_OBJECT2(QmlBindingWrapper, FunctionObject)
- static void call(const Managed *that, Scope &scope, CallData *callData);
+ static void call(const Managed *that, Scope &scope, CallData *callData) {
+ QV4::ScriptFunction::call(that, scope, callData);
+ }
};
}
@@ -94,30 +96,6 @@ void Heap::QmlBindingWrapper::init(QV4::QmlContext *scope, Function *f)
function->compilationUnit->addref();
}
-void QmlBindingWrapper::call(const Managed *that, Scope &scope, CallData *callData)
-{
- const QmlBindingWrapper *This = static_cast<const QmlBindingWrapper *>(that);
- ExecutionEngine *v4 = static_cast<const Object *>(that)->engine();
- if (v4->hasException) {
- scope.result = Encode::undefined();
- return;
- }
- CHECK_STACK_LIMITS(v4, scope);
-
- ExecutionContextSaver ctxSaver(scope);
-
- QV4::Function *f = This->function();
- if (!f) {
- scope.result = QV4::Encode::undefined();
- return;
- }
-
- Scoped<CallContext> ctx(scope, v4->currentContext->newCallContext(This, callData));
- v4->pushContext(ctx);
-
- scope.result = Q_V4_PROFILE(v4, f);
-}
-
Script::Script(ExecutionEngine *v4, QmlContext *qml, CompiledData::CompilationUnit *compilationUnit)
: line(0), column(0), scope(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false)
, compilationUnit(compilationUnit), vmFunction(0), parseAsBinding(true)
@@ -228,10 +206,12 @@ ReturnedValue Script::run()
return Q_V4_PROFILE(engine, vmFunction);
} else {
Scoped<QmlContext> qml(valueScope, qmlContext.value());
- ScopedFunctionObject f(valueScope, engine->memoryManager->allocObject<QmlBindingWrapper>(qml, vmFunction));
ScopedCallData callData(valueScope);
callData->thisObject = Primitive::undefinedValue();
- f->call(valueScope, callData);
+ if (vmFunction->canUseSimpleFunction())
+ qml->simpleCall(valueScope, callData, vmFunction);
+ else
+ qml->call(valueScope, callData, vmFunction);
return valueScope.result.asReturnedValue();
}
}