From 9c2327d25cb6b28ddf9c0e83f57cab129b9a446b Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Wed, 23 Jan 2013 10:12:51 +0100 Subject: [PATCH] Fix eval when a context gets inherited. When a context gets inherited, the locals have to be passed into the CodeGen class, so the indexes in the caller and callee match up. Change-Id: I21f496e8355a5dd7f13c06e011ede60fc04ccba0 Reviewed-by: Lars Knoll --- main.cpp | 4 ++-- qmljs_environment.cpp | 2 +- qv4codegen.cpp | 19 ++++++++++++++++--- qv4codegen_p.h | 10 +++++++--- qv4globalobject.cpp | 29 +++++++++++++++++++---------- qv4globalobject.h | 3 ++- tests/TestExpectations | 1 - 7 files changed, 47 insertions(+), 21 deletions(-) diff --git a/main.cpp b/main.cpp index 3a7911e..af14fb7 100644 --- a/main.cpp +++ b/main.cpp @@ -395,7 +395,7 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - QQmlJS::VM::Function *f = QQmlJS::VM::EvalFunction::parseSource(ctx, fn, code, QQmlJS::Codegen::GlobalCode); + QQmlJS::VM::Function *f = QQmlJS::VM::EvalFunction::parseSource(ctx, fn, code, QQmlJS::Codegen::GlobalCode, /*inheritContext =*/ false); if (!f) continue; @@ -420,5 +420,5 @@ int main(int argc, char *argv[]) vm.memoryManager->dumpStats(); } return EXIT_SUCCESS; - } + } // switch (mode) } diff --git a/qmljs_environment.cpp b/qmljs_environment.cpp index d01b038..9d81bb7 100644 --- a/qmljs_environment.cpp +++ b/qmljs_environment.cpp @@ -476,7 +476,7 @@ void ExecutionContext::initCallContext(ExecutionContext *parent, const Value tha } locals = function->varCount ? new Value[function->varCount] : 0; - if (function->varCount) + if (locals) std::fill(locals, locals + function->varCount, Value::undefinedValue()); activation = 0; diff --git a/qv4codegen.cpp b/qv4codegen.cpp index 7948ff1..7d530ff 100644 --- a/qv4codegen.cpp +++ b/qv4codegen.cpp @@ -438,7 +438,9 @@ Codegen::Codegen(ErrorHandler *errorHandler, bool strictMode) { } -IR::Function *Codegen::operator()(const QString &fileName, Program *node, IR::Module *module, Mode mode) +IR::Function *Codegen::operator()(const QString &fileName, Program *node, + IR::Module *module, Mode mode, + const QStringList &inheritedLocals) { assert(node); @@ -449,7 +451,8 @@ IR::Function *Codegen::operator()(const QString &fileName, Program *node, IR::Mo ScanFunctions scan(this); scan(node); - IR::Function *globalCode = defineFunction(QStringLiteral("%entry"), node, 0, node->elements, mode); + IR::Function *globalCode = defineFunction(QStringLiteral("%entry"), node, 0, + node->elements, mode, inheritedLocals); if (_debugger) { if (node->elements->element) { SourceLocation loc = node->elements->element->firstSourceLocation(); @@ -1815,7 +1818,8 @@ void Codegen::linearize(IR::Function *function) IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast, AST::FormalParameterList *formals, - AST::SourceElements *body, Mode mode) + AST::SourceElements *body, Mode mode, + const QStringList &inheritedLocals) { qSwap(_mode, mode); // enter function code. @@ -1843,6 +1847,15 @@ IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast, (*it).index = t; } } else { + if (!_env->isStrict) { + foreach (const QString &inheritedLocal, inheritedLocals) { + function->LOCAL(inheritedLocal); + unsigned tempIndex = entryBlock->newTemp(); + Environment::Member member = { Environment::UndefinedMember, tempIndex, 0 }; + _env->members.insert(inheritedLocal, member); + } + } + IR::ExprList *args = 0; for (Environment::MemberMap::const_iterator it = _env->members.constBegin(); it != _env->members.constEnd(); ++it) { const QString &local = it.key(); diff --git a/qv4codegen_p.h b/qv4codegen_p.h index f84c542..8a83908 100644 --- a/qv4codegen_p.h +++ b/qv4codegen_p.h @@ -43,6 +43,7 @@ #include "qv4ir_p.h" #include +#include #include namespace QQmlJS { @@ -78,7 +79,7 @@ public: FunctionCode }; - IR::Function *operator()(const QString &fileName, AST::Program *ast, IR::Module *module, Mode mode = GlobalCode); + IR::Function *operator()(const QString &fileName, AST::Program *ast, IR::Module *module, Mode mode = GlobalCode, const QStringList &inheritedLocals = QStringList()); IR::Function *operator()(const QString &fileName, AST::FunctionExpression *ast, IR::Module *module); protected: @@ -252,8 +253,11 @@ protected: void cjump(IR::Expr *cond, IR::BasicBlock *iftrue, IR::BasicBlock *iffalse); void linearize(IR::Function *function); - IR::Function *defineFunction(const QString &name, AST::Node *ast, AST::FormalParameterList *formals, - AST::SourceElements *body, Mode mode = FunctionCode); + IR::Function *defineFunction(const QString &name, AST::Node *ast, + AST::FormalParameterList *formals, + AST::SourceElements *body, + Mode mode = FunctionCode, + const QStringList &inheritedLocals = QStringList()); int indexOfArgument(const QStringRef &string) const; void unwindException(TryCleanup *outest); diff --git a/qv4globalobject.cpp b/qv4globalobject.cpp index 3a6b34d..1857eee 100644 --- a/qv4globalobject.cpp +++ b/qv4globalobject.cpp @@ -318,11 +318,21 @@ Value EvalFunction::call(ExecutionContext *context, Value /*thisObject*/, Value if (argc < 1) return Value::undefinedValue(); + ExecutionContext *ctx = context; + if (!directCall) { + // the context for eval should be the global scope + while (ctx->parent) + ctx = ctx->parent; + } + if (!args[0].isString()) return args[0]; const QString code = args[0].stringValue()->toQString(); - QQmlJS::VM::Function *f = parseSource(context, QStringLiteral("eval code"), code, QQmlJS::Codegen::EvalCode); + bool inheritContext = !context->strictMode; + QQmlJS::VM::Function *f = parseSource(context, QStringLiteral("eval code"), + code, QQmlJS::Codegen::EvalCode, + inheritContext); if (!f) return Value::undefinedValue(); @@ -330,13 +340,6 @@ Value EvalFunction::call(ExecutionContext *context, Value /*thisObject*/, Value ExecutionContext k; - ExecutionContext *ctx = context; - if (!directCall) { - // the context for eval should be the global scope - while (ctx->parent) - ctx = ctx->parent; - } - if (strict) { ctx = &k; ctx->initCallContext(context, context->thisObject, this, args, argc); @@ -365,7 +368,8 @@ Value EvalFunction::call(ExecutionContext *context, Value thisObject, Value *arg QQmlJS::VM::Function *EvalFunction::parseSource(QQmlJS::VM::ExecutionContext *ctx, const QString &fileName, const QString &source, - QQmlJS::Codegen::Mode mode) + QQmlJS::Codegen::Mode mode, + bool inheritContext) { using namespace QQmlJS; @@ -412,8 +416,13 @@ QQmlJS::VM::Function *EvalFunction::parseSource(QQmlJS::VM::ExecutionContext *ct return 0; } + QStringList inheritedLocals; + if (inheritContext) + for (String **i = ctx->variables(), **ei = i + ctx->variableCount(); i < ei; ++i) + inheritedLocals.append(*i ? (*i)->toQString() : QString()); + Codegen cg(ctx); - IR::Function *globalIRCode = cg(fileName, program, &module, mode); + IR::Function *globalIRCode = cg(fileName, program, &module, mode, inheritedLocals); QScopedPointer isel(ctx->engine->iselFactory->create(vm, &module)); if (globalIRCode) globalCode = isel->vmFunction(globalIRCode); diff --git a/qv4globalobject.h b/qv4globalobject.h index c335029..84668cf 100644 --- a/qv4globalobject.h +++ b/qv4globalobject.h @@ -54,7 +54,8 @@ struct EvalFunction : FunctionObject static QQmlJS::VM::Function *parseSource(QQmlJS::VM::ExecutionContext *ctx, const QString &fileName, const QString &source, - QQmlJS::Codegen::Mode mode); + QQmlJS::Codegen::Mode mode, + bool inheritContext); virtual Value call(ExecutionContext *context, Value thisObject, Value *args, int argc); Value call(ExecutionContext *context, Value thisObject, Value *args, int argc, bool directCall); diff --git a/tests/TestExpectations b/tests/TestExpectations index 0eb51ee..b0a00e6 100644 --- a/tests/TestExpectations +++ b/tests/TestExpectations @@ -99,7 +99,6 @@ S11.3.2_A4_T4 failing 11.4.1-2-5 failing 11.4.1-2-6 failing 11.4.1-4.a-5 failing -11.4.1-4.a-7 failing 11.4.1-5-2 failing S11.4.1_A1 failing S11.4.1_A2.1 failing -- 2.7.4