diff options
author | Lars Knoll <lars.knoll@qt.io> | 2017-10-24 14:57:53 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2017-11-13 08:56:11 +0000 |
commit | 831ddc54932d2681712ca9fa3e94484ae11d59f7 (patch) | |
tree | 0cf4ad8756d9cae65f3c57f1c77c946eaf1f5749 | |
parent | d9b0878595e7ee2698ddc8c724657574d5fe4d4c (diff) |
Cut out one more C++ layer when doing JS function calls
Change-Id: I0e2ac30b7e6d77fe41deb84a97b0a7f220437c6a
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
-rw-r--r-- | src/qml/jsruntime/qv4function_p.h | 8 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 22 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4globalobject.cpp | 15 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4script.cpp | 11 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 74 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth_p.h | 14 | ||||
-rw-r--r-- | src/qml/qml/qqmljavascriptexpression.cpp | 10 |
7 files changed, 74 insertions, 80 deletions
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 03529407ab..6c62881998 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -54,6 +54,7 @@ #include <private/qqmlglobal_p.h> #include <private/qv4compileddata_p.h> #include <private/qv4context_p.h> +#include <private/qv4vme_moth_p.h> QT_BEGIN_NAMESPACE @@ -63,12 +64,11 @@ struct Q_QML_EXPORT Function { const CompiledData::Function *compiledFunction; CompiledData::CompilationUnit *compilationUnit; - ReturnedValue call(CallData *callData) { - return code(callData, this); + ReturnedValue call(const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context) { + return Moth::VME::exec(this, thisObject, argv, argc, context); } - - typedef ReturnedValue (*Code)(CallData *, Function *); + typedef ReturnedValue (*Code)(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc); Code code; const uchar *codeData; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index bd8bb9c8fb..1f86672a62 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -367,35 +367,21 @@ ReturnedValue ScriptFunction::callAsConstructor(const FunctionObject *fo, const const ScriptFunction *f = static_cast<const ScriptFunction *>(fo); Scope scope(v4); - JSCallData callData(scope, argc, argv); - CallData *cData = callData.callData(f); InternalClass *ic = f->classForConstructor(); - cData->context = f->scope(); - cData->thisObject = v4->memoryManager->allocObject<Object>(ic); + ScopedValue thisObject(scope, v4->memoryManager->allocObject<Object>(ic)); - QV4::Function *v4Function = f->function(); - Q_ASSERT(v4Function); - - ReturnedValue result = v4Function->call(cData); + ReturnedValue result = Moth::VME::exec(fo, thisObject, argv, argc); if (Q_UNLIKELY(v4->hasException)) return Encode::undefined(); else if (!Value::fromReturnedValue(result).isObject()) - return cData->thisObject.asReturnedValue(); + return thisObject->asReturnedValue(); return result; } ReturnedValue ScriptFunction::call(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc) { - const ScriptFunction *f = static_cast<const ScriptFunction *>(fo); - Scope scope(f->engine()); - JSCallData callData(scope, argc, argv, thisObject); - CallData *cData = callData.callData(f); - cData->context = f->scope(); - - QV4::Function *v4Function = f->function(); - Q_ASSERT(v4Function); - return v4Function->call(cData); + return Moth::VME::exec(fo, thisObject, argv, argc); } void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function) diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 9ba65b2ce1..1049c5d3fa 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -374,20 +374,13 @@ ReturnedValue EvalFunction::evalCall(const Value *, const Value *argv, int argc, if (function->isStrict() || isStrict) { ScopedFunctionObject e(scope, FunctionObject::createScriptFunction(ctx, function)); - JSCallData jsCallData(scope, 0); - if (directCall) - *jsCallData->thisObject = scope.engine->currentStackFrame->thisObject(); - else - *jsCallData->thisObject = scope.engine->globalObject; - return e->call(jsCallData); + ScopedValue thisObject(scope, directCall ? scope.engine->currentStackFrame->thisObject() : scope.engine->globalObject->asReturnedValue()); + return e->call(thisObject, 0, 0); } - JSCallData jsCallData(scope); - *jsCallData->thisObject = scope.engine->currentStackFrame->thisObject(); - CallData *cData = jsCallData.callData(); - cData->context = *ctx; + ScopedValue thisObject(scope, scope.engine->currentStackFrame->thisObject()); - return function->call(cData); + return function->call(thisObject, 0, 0, ctx); } diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 7ac46bf594..901f2574da 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -149,17 +149,10 @@ ReturnedValue Script::run() if (qmlContext.isUndefined()) { TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction); - QV4::JSCallData jsCall(valueScope); - jsCall->thisObject = engine->globalObject; - QV4::CallData *cData = jsCall.callData(); - cData->context = *context; - return vmFunction->call(cData); + return vmFunction->call(engine->globalObject, 0, 0, context); } else { Scoped<QmlContext> qml(valueScope, qmlContext.value()); - JSCallData jsCall(valueScope); - QV4::CallData *cData = jsCall.callData(); - cData->context = *qml; - return vmFunction->call(cData); + return vmFunction->call(0, 0, 0, qml); } } diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 5b01e5a26b..58b54cf86c 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -497,46 +497,66 @@ static bool compareEqualInt(Value &accumulator, Value lhs, int rhs) } \ } while (false) -QV4::ReturnedValue VME::exec(CallData *callData, QV4::Function *function) +QV4::ReturnedValue VME::exec(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc) { qt_v4ResolvePendingBreakpointsHook(); + ExecutionEngine *engine; + Value *stack; + CppStackFrame frame; + Function *function; - MOTH_JUMP_TABLE; + { + Heap::ExecutionContext *scope; + + quintptr d = reinterpret_cast<quintptr>(fo); + if (d & 0x1) { + // we don't have a FunctionObject, but a ExecData + ExecData *data = reinterpret_cast<ExecData *>(d - 1); + function = data->function; + scope = data->scope->d(); + fo = nullptr; + } else { + function = fo->function(); + scope = fo->scope(); + } - ExecutionEngine *engine = function->internalClass->engine; - CHECK_STACK_LIMITS(engine); - Profiling::FunctionCallProfiler profiler(engine, function); - Q_UNUSED(profiler) - - Value *jsStackTop = engine->jsStackTop; - - Q_ASSERT(engine->jsStackTop == callData->args + callData->argc()); - Value *stack = reinterpret_cast<Value *>(callData); - int stackSpaceToAdd = int(function->compiledFunction->nRegisters) - callData->argc(); - if (stackSpaceToAdd > 0) { - // clear out remaining arguments and local registers - for (int i = 0; i < stackSpaceToAdd; ++i) - engine->jsStackTop[i] = Encode::undefined(); - engine->jsStackTop += stackSpaceToAdd; + engine = function->internalClass->engine; + + stack = engine->jsStackTop; + CallData *callData = reinterpret_cast<CallData *>(stack); + callData->function = fo ? fo->asReturnedValue() : Encode::undefined(); + callData->context = scope; + callData->accumulator = Encode::undefined(); + callData->thisObject = thisObject ? *thisObject : Primitive::undefinedValue(); + callData->setArgc(argc); + + int jsStackFrameSize = offsetof(CallData, args)/sizeof(Value) + function->compiledFunction->nRegisters; + engine->jsStackTop += jsStackFrameSize; + memcpy(callData->args, argv, argc*sizeof(Value)); // ### Fixme: only copy nFormals + for (Value *v = callData->args + argc; v < engine->jsStackTop; ++v) + *v = Encode::undefined(); + + frame.parent = engine->currentStackFrame; + frame.v4Function = function; + frame.instructionPointer = function->codeData; + frame.jsFrame = callData; + engine->currentStackFrame = &frame; } + CHECK_STACK_LIMITS(engine); - CppStackFrame frame; - frame.parent = engine->currentStackFrame; - frame.v4Function = function; - frame.instructionPointer = function->codeData; - frame.jsFrame = callData; - engine->currentStackFrame = &frame; + Profiling::FunctionCallProfiler profiler(engine, function); + if (QV4::Debugging::Debugger *debugger = engine->debugger()) + debugger->enteringFunction(); const uchar *exceptionHandler = 0; QV4::Value &accumulator = frame.jsFrame->accumulator; QV4::ReturnedValue acc = Encode::undefined(); - if (QV4::Debugging::Debugger *debugger = engine->debugger()) - debugger->enteringFunction(); - const uchar *code = function->codeData; + MOTH_JUMP_TABLE; + for (;;) { MOTH_DISPATCH() Q_UNREACHABLE(); // only reached when the dispatch doesn't jump somewhere @@ -1321,7 +1341,7 @@ functionExit: if (QV4::Debugging::Debugger *debugger = engine->debugger()) debugger->leavingFunction(ACC.asReturnedValue()); engine->currentStackFrame = frame.parent; - engine->jsStackTop = jsStackTop; + engine->jsStackTop = stack; return acc; } diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h index 3a1e7b6637..dbf9ed3550 100644 --- a/src/qml/jsruntime/qv4vme_moth_p.h +++ b/src/qml/jsruntime/qv4vme_moth_p.h @@ -52,8 +52,6 @@ // #include <private/qv4global_p.h> -#include <private/qv4runtime_p.h> -#include <private/qv4instr_moth_p.h> QT_REQUIRE_CONFIG(qml_interpreter); @@ -65,7 +63,17 @@ namespace Moth { class VME { public: - static QV4::ReturnedValue exec(CallData *callData, QV4::Function *); + struct ExecData { + QV4::Function *function; + const QV4::ExecutionContext *scope; + }; + static inline + QV4::ReturnedValue exec(Function *v4Function, const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context) { + ExecData data{v4Function, context}; + quintptr d = reinterpret_cast<quintptr>(&data) | 0x1; + return exec(reinterpret_cast<const FunctionObject *>(d), thisObject, argv, argc); + } + static QV4::ReturnedValue exec(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc); }; } // namespace Moth diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 0208db2d48..006611e089 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -226,17 +226,11 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b } Q_ASSERT(m_qmlScope.valueRef()); - callData->context = *m_qmlScope.valueRef(); - QV4::ReturnedValue res = v4Function->call(callData); + QV4::ReturnedValue res = v4Function->call(&callData->thisObject, callData->args, callData->argc(), static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef())); QV4::Scope scope(v4); QV4::ScopedValue result(scope, res); if (v4Function->hasQmlDependencies) { - QV4::Heap::ExecutionContext *c = static_cast<QV4::Heap::ExecutionContext *>(callData->context.m()); - // CreateCallContext might have been executed, and that will push a CallContext on top of - // the current one. So, search back to the original QMLContext. - while (c->type != QV4::Heap::ExecutionContext::Type_QmlContext) - c = c->outer; - QV4::Heap::QmlContext *qc = static_cast<QV4::Heap::QmlContext *>(c); + QV4::Heap::QmlContext *qc = m_qmlScope.as<QV4::QmlContext>()->d(); QQmlPropertyCapture::registerQmlDependencies(qc, v4, v4Function->compiledFunction); } |