aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2013-11-02 21:10:13 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-11-05 22:23:25 +0100
commit90338de17a56304eace1f64661a9aac21fe4d29c (patch)
tree0960479c21e3d6f49c60ad7e90ae5fbdf9595ef2 /src
parentb5f76295659dd49d46b306b66807f44841fca992 (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.cpp12
-rw-r--r--src/qml/compiler/qv4codegen_p.h3
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h5
-rw-r--r--src/qml/compiler/qv4isel_masm.cpp5
-rw-r--r--src/qml/compiler/qv4isel_masm_p.h1
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp7
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h1
-rw-r--r--src/qml/compiler/qv4isel_p.cpp4
-rw-r--r--src/qml/compiler/qv4isel_p.h1
-rw-r--r--src/qml/compiler/qv4jsir.cpp2
-rw-r--r--src/qml/compiler/qv4jsir_p.h4
-rw-r--r--src/qml/compiler/qv4regalloc.cpp1
-rw-r--r--src/qml/jsruntime/qv4engine_p.h3
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp16
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp12
-rw-r--r--src/qml/jsruntime/qv4runtime_p.h1
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp5
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);