diff options
author | Lars Knoll <lars.knoll@digia.com> | 2013-11-02 21:10:13 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-11-05 22:23:25 +0100 |
commit | 90338de17a56304eace1f64661a9aac21fe4d29c (patch) | |
tree | 0960479c21e3d6f49c60ad7e90ae5fbdf9595ef2 /src | |
parent | b5f76295659dd49d46b306b66807f44841fca992 (diff) |
Move conversion of this object into generated code
When a non strict mode function uses the this object, we
need to make sure it's being correctly converted into a
object before being accessed. So far this was being done
by ScriptFunction::call. Move this into the generated code to
avoid overhead for methods not using 'this', and simplify our
ScriptFunction::call() implementation.
Change-Id: I739f4a89d29ed8082ce59e48d1523776224fc29d
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 12 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 3 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 5 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm.cpp | 5 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 7 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.cpp | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_p.h | 1 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir.cpp | 2 | ||||
-rw-r--r-- | src/qml/compiler/qv4jsir_p.h | 4 | ||||
-rw-r--r-- | src/qml/compiler/qv4regalloc.cpp | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 16 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 12 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime_p.h | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 5 |
17 files changed, 64 insertions, 19 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 58c9fc59bb..4810e4dace 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -355,6 +355,12 @@ bool Codegen::ScanFunctions::visit(LocalForEachStatement *ast) { return false; } +bool Codegen::ScanFunctions::visit(ThisExpression *) +{ + _env->usesThis = true; + return false; +} + bool Codegen::ScanFunctions::visit(Block *ast) { TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _env->isStrict ? false : _allowFuncDecls); Node::accept(ast->statements, this); @@ -1953,6 +1959,7 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, V4IR::BasicBlock *exitBlock = function->newBasicBlock(groupStartBlock(), 0, V4IR::Function::DontInsertBlock); function->hasDirectEval = _env->hasDirectEval; function->usesArgumentsObject = _env->parent && (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed); + function->usesThis = _env->usesThis; function->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, (int)QV4::Global::ReservedArgumentCount); function->isStrict = _env->isStrict; function->isNamedExpression = _env->isNamedFunctionExpression; @@ -2036,6 +2043,11 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, _block->CALL(_block->NAME(V4IR::Name::builtin_setup_argument_object, ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), 0)); } + if (_function->usesThis && !_function->isStrict) { + // make sure we convert this to an object + _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_convert_this_to_object, + ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), 0)); + } sourceElements(body); diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 490e469dc7..b20db26467 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -148,6 +148,7 @@ protected: bool hasNestedFunctions; bool isStrict; bool isNamedFunctionExpression; + bool usesThis; enum UsesArgumentsObject { ArgumentsObjectUnknown, ArgumentsObjectNotUsed, @@ -166,6 +167,7 @@ protected: , hasNestedFunctions(false) , isStrict(false) , isNamedFunctionExpression(false) + , usesThis(false) , usesArgumentsObject(ArgumentsObjectUnknown) , compilationMode(mode) { @@ -513,6 +515,7 @@ protected: virtual bool visit(AST::LocalForStatement *ast); virtual bool visit(AST::ForEachStatement *ast); virtual bool visit(AST::LocalForEachStatement *ast); + virtual bool visit(AST::ThisExpression *ast); virtual bool visit(AST::Block *ast); diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 854b9a3a8d..9aaab2f105 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -95,6 +95,7 @@ QT_BEGIN_NAMESPACE F(CallBuiltinDefineArray, callBuiltinDefineArray) \ F(CallBuiltinDefineObjectLiteral, callBuiltinDefineObjectLiteral) \ F(CallBuiltinSetupArgumentsObject, callBuiltinSetupArgumentsObject) \ + F(CallBuiltinConvertThisToObject, callBuiltinConvertThisToObject) \ F(CreateValue, createValue) \ F(CreateProperty, createProperty) \ F(CreateActivationProperty, createActivationProperty) \ @@ -471,6 +472,9 @@ union Instr MOTH_INSTR_HEADER Param result; }; + struct instr_callBuiltinConvertThisToObject { + MOTH_INSTR_HEADER + }; struct instr_createValue { MOTH_INSTR_HEADER quint32 argc; @@ -704,6 +708,7 @@ union Instr instr_callBuiltinDefineArray callBuiltinDefineArray; instr_callBuiltinDefineObjectLiteral callBuiltinDefineObjectLiteral; instr_callBuiltinSetupArgumentsObject callBuiltinSetupArgumentsObject; + instr_callBuiltinConvertThisToObject callBuiltinConvertThisToObject; instr_createValue createValue; instr_createProperty createProperty; instr_createActivationProperty createActivationProperty; diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index ff6fed2f30..cddaac08bd 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -936,6 +936,11 @@ void InstructionSelection::callBuiltinSetupArgumentObject(V4IR::Temp *result) generateFunctionCall(result, __qmljs_builtin_setup_arguments_object, Assembler::ContextRegister); } +void InstructionSelection::callBuiltinConvertThisToObject() +{ + generateFunctionCall(Assembler::Void, __qmljs_builtin_convert_this_to_object, Assembler::ContextRegister); +} + void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) { Q_ASSERT(value); diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h index bf01d0429d..72251f44d7 100644 --- a/src/qml/compiler/qv4isel_masm_p.h +++ b/src/qml/compiler/qv4isel_masm_p.h @@ -1477,6 +1477,7 @@ protected: virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args); virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args); virtual void callBuiltinSetupArgumentObject(V4IR::Temp *result); + virtual void callBuiltinConvertThisToObject(); virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result); virtual void callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result); virtual void callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args, V4IR::Temp *result); diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index df206d7890..44b4d666ef 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -1174,6 +1174,13 @@ void InstructionSelection::callBuiltinSetupArgumentObject(V4IR::Temp *result) addInstruction(call); } + +void QQmlJS::Moth::InstructionSelection::callBuiltinConvertThisToObject() +{ + Instruction::CallBuiltinConvertThisToObject call; + addInstruction(call); +} + ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &instr) { #ifdef MOTH_THREADED_INTERPRETER diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h index c5ef1e44ba..0bf7444329 100644 --- a/src/qml/compiler/qv4isel_moth_p.h +++ b/src/qml/compiler/qv4isel_moth_p.h @@ -106,6 +106,7 @@ protected: virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args); virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args); virtual void callBuiltinSetupArgumentObject(V4IR::Temp *result); + virtual void callBuiltinConvertThisToObject(); virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result); virtual void callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result); virtual void callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args, V4IR::Temp *result); diff --git a/src/qml/compiler/qv4isel_p.cpp b/src/qml/compiler/qv4isel_p.cpp index 0afd25315e..3f9e666c98 100644 --- a/src/qml/compiler/qv4isel_p.cpp +++ b/src/qml/compiler/qv4isel_p.cpp @@ -383,6 +383,10 @@ void IRDecoder::callBuiltin(V4IR::Call *call, V4IR::Temp *result) callBuiltinSetupArgumentObject(result); return; + case V4IR::Name::builtin_convert_this_to_object: + callBuiltinConvertThisToObject(); + return; + default: break; } diff --git a/src/qml/compiler/qv4isel_p.h b/src/qml/compiler/qv4isel_p.h index fafe741fd5..5fba560d27 100644 --- a/src/qml/compiler/qv4isel_p.h +++ b/src/qml/compiler/qv4isel_p.h @@ -132,6 +132,7 @@ public: // to implement by subclasses: virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args) = 0; virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args) = 0; virtual void callBuiltinSetupArgumentObject(V4IR::Temp *result) = 0; + virtual void callBuiltinConvertThisToObject() = 0; virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) = 0; virtual void callProperty(V4IR::Expr *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0; virtual void callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4IR::ExprList *args, V4IR::Temp *result) = 0; diff --git a/src/qml/compiler/qv4jsir.cpp b/src/qml/compiler/qv4jsir.cpp index b4630793ef..f8189b673d 100644 --- a/src/qml/compiler/qv4jsir.cpp +++ b/src/qml/compiler/qv4jsir.cpp @@ -422,6 +422,8 @@ static const char *builtin_to_string(Name::Builtin b) return "builtin_define_object_literal"; case V4IR::Name::builtin_setup_argument_object: return "builtin_setup_argument_object"; + case V4IR::Name::builtin_convert_this_to_object: + return "builtin_convert_this_to_object"; case V4IR::Name::builtin_qml_id_scope: return "builtin_qml_id_scope"; case V4IR::Name::builtin_qml_imported_scripts_object: diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 933ba1321d..a7bed6419b 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -324,6 +324,7 @@ struct Name: Expr { builtin_define_getter_setter, builtin_define_object_literal, builtin_setup_argument_object, + builtin_convert_this_to_object, builtin_qml_id_scope, builtin_qml_imported_scripts_object, builtin_qml_context_object, @@ -733,12 +734,13 @@ struct Function { uint hasDirectEval: 1; uint usesArgumentsObject : 1; + uint usesThis : 1; uint isStrict: 1; uint isNamedExpression : 1; uint hasTry: 1; uint hasWith: 1; uint hasQmlDependencies : 1; - uint unused : 25; + uint unused : 24; // Location of declaration in source code (-1 if not specified) int line; diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp index 9a1897d494..f746902814 100644 --- a/src/qml/compiler/qv4regalloc.cpp +++ b/src/qml/compiler/qv4regalloc.cpp @@ -207,6 +207,7 @@ protected: // IRDecoder virtual void callBuiltinDefineArray(V4IR::Temp *, V4IR::ExprList *) {} virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *, V4IR::ExprList *) {} virtual void callBuiltinSetupArgumentObject(V4IR::Temp *) {} + virtual void callBuiltinConvertThisToObject() {} virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) { diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index c585714dd0..3413238f3d 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -369,8 +369,7 @@ struct ExecutionContextSaver } ~ExecutionContextSaver() { - while (engine->current != savedContext) - engine->popContext(); + engine->current = savedContext; } }; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index a270689b43..35e4202790 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -471,14 +471,6 @@ ReturnedValue ScriptFunction::call(Managed *that, CallData *callData) CallContext *ctx = context->newCallContext(f, callData); - if (!f->strictMode && !callData->thisObject.isObject()) { - if (callData->thisObject.isNullOrUndefined()) { - ctx->callData->thisObject = v4->globalObject->asReturnedValue(); - } else { - ctx->callData->thisObject = callData->thisObject.toObject(context)->asReturnedValue(); - } - } - if (f->function->compiledFunction->hasQmlDependencies()) QmlContextWrapper::registerQmlDependencies(ctx->engine, f->function->compiledFunction); @@ -568,14 +560,6 @@ ReturnedValue SimpleScriptFunction::call(Managed *that, CallData *callData) ExecutionContext *context = v4->current; ExecutionContext *ctx = context->newCallContext(stackSpace, scope.alloc(f->varCount), f.getPointer(), callData); - if (!f->strictMode && !callData->thisObject.isObject()) { - if (callData->thisObject.isNullOrUndefined()) { - ctx->callData->thisObject = v4->globalObject->asReturnedValue(); - } else { - ctx->callData->thisObject = callData->thisObject.toObject(context)->asReturnedValue(); - } - } - if (f->function->compiledFunction->hasQmlDependencies()) QmlContextWrapper::registerQmlDependencies(v4, f->function->compiledFunction); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index d8ebe635bd..22af24e527 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1277,6 +1277,18 @@ ReturnedValue __qmljs_get_imported_scripts(NoThrowContext *ctx) return context->importedScripts.value(); } +void __qmljs_builtin_convert_this_to_object(ExecutionContext *ctx) +{ + SafeValue *t = &ctx->callData->thisObject; + if (t->isObject()) + return; + if (t->isNullOrUndefined()) { + *t = ctx->engine->globalObject->asReturnedValue(); + } else { + *t = t->toObject(ctx)->asReturnedValue(); + } +} + } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index 4f6f3a33d4..b2d2d211eb 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -144,6 +144,7 @@ QV4::ReturnedValue __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, QV4: void __qmljs_builtin_define_getter_setter(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::StringRef name, const QV4::ValueRef getter, const QV4::ValueRef setter); QV4::ReturnedValue __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, const QV4::Value *args, int classId); QV4::ReturnedValue __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx); +void __qmljs_builtin_convert_this_to_object(ExecutionContext *ctx); QV4::ReturnedValue __qmljs_value_from_string(QV4::String *string); QV4::ReturnedValue __qmljs_lookup_runtime_regexp(QV4::ExecutionContext *ctx, int id); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 82d9599582..74a42b6f2f 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -478,6 +478,11 @@ QV4::ReturnedValue VME::run(QV4::ExecutionContext *context, const uchar *code, STOREVALUE(instr.result, __qmljs_builtin_setup_arguments_object(context)); MOTH_END_INSTR(CallBuiltinSetupArgumentsObject) + MOTH_BEGIN_INSTR(CallBuiltinConvertThisToObject) + __qmljs_builtin_convert_this_to_object(context); + CHECK_EXCEPTION; + MOTH_END_INSTR(CallBuiltinConvertThisToObject) + MOTH_BEGIN_INSTR(CreateValue) Q_ASSERT(instr.callData + instr.argc + qOffsetOf(QV4::CallData, args)/sizeof(QV4::SafeValue) <= stackSize); QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData); |