diff options
author | Lars Knoll <lars.knoll@qt.io> | 2017-08-16 21:24:33 +0200 |
---|---|---|
committer | Erik Verbruggen <erik.verbruggen@qt.io> | 2017-08-25 12:05:45 +0000 |
commit | 3c201dd0d95020c4cb4c8ceaf779673d411664e7 (patch) | |
tree | 97d4316e6d2ce54c0fa20600dcd1429f1b8ab789 | |
parent | 34280d266fe4bed0274b260c0091d50908acd087 (diff) |
Specialize possible direct calls to eval
To avoid additional overhead on most function calls
Change-Id: I2477b91fda6216b508c8331884a02b601f65590c
Reviewed-by: Erik Verbruggen <erik.verbruggen@qt.io>
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth.cpp | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 37 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtimeapi_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 5 |
6 files changed, 50 insertions, 9 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 0b8091d70e..273856e541 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1199,7 +1199,11 @@ bool Codegen::visit(CallExpression *ast) call.callData = calldata; bytecodeGenerator->addInstruction(call); } else if (base.type == Reference::Name) { - if (useFastLookups && base.global) { + if (base.name == QStringLiteral("eval")) { + Instruction::CallPossiblyDirectEval call; + call.callData = calldata; + bytecodeGenerator->addInstruction(call); + } else if (useFastLookups && base.global) { Instruction::CallGlobalLookup call; call.index = registerGlobalGetterLookup(base.nameAsIndex()); call.callData = calldata; diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp index a6d0691db7..9101537236 100644 --- a/src/qml/compiler/qv4instr_moth.cpp +++ b/src/qml/compiler/qv4instr_moth.cpp @@ -274,6 +274,10 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals) d << instr.name << "(" << instr.callData.dump(nFormals) << ")"; MOTH_END_INSTR(CallName) + MOTH_BEGIN_INSTR(CallPossiblyDirectEval) + d << "(" << instr.callData.dump(nFormals) << ")"; + MOTH_END_INSTR(CallPossiblyDirectEval) + MOTH_BEGIN_INSTR(CallGlobalLookup) d << instr.index << "(" << instr.callData.dump(nFormals) << ")"; MOTH_END_INSTR(CallGlobalLookup) diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 3d004d10e9..2ce0ff7b22 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -110,6 +110,7 @@ QT_BEGIN_NAMESPACE F(CallPropertyLookup, callPropertyLookup) \ F(CallElement, callElement) \ F(CallName, callName) \ + F(CallPossiblyDirectEval, callPossiblyDirectEval) \ F(CallGlobalLookup, callGlobalLookup) \ F(SetExceptionHandler, setExceptionHandler) \ F(ThrowException, throwException) \ @@ -440,6 +441,10 @@ union Instr int name; StackSlot callData; }; + struct instr_callPossiblyDirectEval { + MOTH_INSTR_HEADER + StackSlot callData; + }; struct instr_callGlobalLookup { MOTH_INSTR_HEADER int index; @@ -750,6 +755,7 @@ union Instr instr_callPropertyLookup callPropertyLookup; instr_callElement callElement; instr_callName callName; + instr_callPossiblyDirectEval callPossiblyDirectEval; instr_callGlobalLookup callGlobalLookup; instr_throwException throwException; instr_getException getException; diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index a1d480160f..9c5ddece2a 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1023,13 +1023,36 @@ ReturnedValue Runtime::method_callGlobalLookup(ExecutionEngine *engine, uint ind if (!o) return engine->throwTypeError(); - ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]); - if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) - return static_cast<EvalFunction *>(o.getPointer())->evalCall(callData, true); - return o->call(callData); } +ReturnedValue Runtime::method_callPossiblyDirectEval(ExecutionEngine *engine, CallData *callData) +{ + Q_ASSERT(callData->thisObject.isUndefined()); + Scope scope(engine); + ScopedObject base(scope); + ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context); + ScopedValue func(scope, ctx.getPropertyAndBase(engine->id_eval(), base.getRef())); + if (scope.engine->hasException) + return Encode::undefined(); + + if (base) + callData->thisObject = base; + + FunctionObject *o = func->as<FunctionObject>(); + if (!o) { + QString objectAsString = QStringLiteral("[null]"); + if (base) + objectAsString = ScopedValue(scope, base.asReturnedValue())->toQStringNoThrow(); + QString msg = QStringLiteral("Property 'eval' of object %2 is not a function").arg(objectAsString); + return engine->throwTypeError(msg); + } + + if (o->d() == scope.engine->evalFunction()->d()) + return static_cast<EvalFunction *>(o)->evalCall(callData, true); + + return o->call(callData); +} ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, CallData *callData) { @@ -1038,7 +1061,8 @@ ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, C ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); ScopedObject base(scope); - ScopedValue func(scope, static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getPropertyAndBase(name, base.getRef())); + ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context); + ScopedValue func(scope, ctx.getPropertyAndBase(name, base.getRef())); if (scope.engine->hasException) return Encode::undefined(); @@ -1054,9 +1078,6 @@ ReturnedValue Runtime::method_callName(ExecutionEngine *engine, int nameIndex, C return engine->throwTypeError(msg); } - if (o->d() == scope.engine->evalFunction()->d() && name->equals(scope.engine->id_eval())) - return static_cast<EvalFunction *>(o)->evalCall(callData, true); - return o->call(callData); } diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index d8e1b4f443..c46e848ca4 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -98,6 +98,7 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> { F(ReturnedValue, callPropertyLookup, (ExecutionEngine *engine, uint index, CallData *callData)) \ F(ReturnedValue, callElement, (ExecutionEngine *engine, const Value &index, CallData *callData)) \ F(ReturnedValue, callValue, (ExecutionEngine *engine, const Value &func, CallData *callData)) \ + F(ReturnedValue, callPossiblyDirectEval, (ExecutionEngine *engine, CallData *callData)) \ \ /* construct */ \ F(ReturnedValue, construct, (ExecutionEngine *engine, const Value &func, CallData *callData)) \ diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 6d20fcc426..6aad96c0c8 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -744,6 +744,11 @@ QV4::ReturnedValue VME::exec(const FunctionObject *jsFunction, CallData *callDat STORE_ACCUMULATOR(Runtime::method_callName(engine, instr.name, callData)); MOTH_END_INSTR(CallName) + MOTH_BEGIN_INSTR(CallPossiblyDirectEval) + QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData.stackSlot()); + STORE_ACCUMULATOR(Runtime::method_callPossiblyDirectEval(engine, callData)); + MOTH_END_INSTR(CallPossiblyDirectEval) + MOTH_BEGIN_INSTR(CallGlobalLookup) QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData.stackSlot()); STORE_ACCUMULATOR(Runtime::method_callGlobalLookup(engine, instr.index, callData)); |