aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2017-08-16 21:24:33 +0200
committerErik Verbruggen <erik.verbruggen@qt.io>2017-08-25 12:05:45 +0000
commit3c201dd0d95020c4cb4c8ceaf779673d411664e7 (patch)
tree97d4316e6d2ce54c0fa20600dcd1429f1b8ab789
parent34280d266fe4bed0274b260c0091d50908acd087 (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.cpp6
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp4
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h6
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp37
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h1
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp5
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));