Fix eval when a context gets inherited.
authorErik Verbruggen <erik.verbruggen@me.com>
Wed, 23 Jan 2013 09:12:51 +0000 (10:12 +0100)
committerLars Knoll <lars.knoll@digia.com>
Wed, 23 Jan 2013 10:54:01 +0000 (11:54 +0100)
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 <lars.knoll@digia.com>
main.cpp
qmljs_environment.cpp
qv4codegen.cpp
qv4codegen_p.h
qv4globalobject.cpp
qv4globalobject.h
tests/TestExpectations

index 3a7911e..af14fb7 100644 (file)
--- 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)
 }
index d01b038..9d81bb7 100644 (file)
@@ -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;
index 7948ff1..7d530ff 100644 (file)
@@ -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();
index f84c542..8a83908 100644 (file)
@@ -43,6 +43,7 @@
 
 #include "qv4ir_p.h"
 #include <private/qqmljsastvisitor_p.h>
+#include <QtCore/QStringList>
 #include <assert.h>
 
 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);
index 3a6b34d..1857eee 100644 (file)
@@ -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<EvalInstructionSelection> isel(ctx->engine->iselFactory->create(vm, &module));
             if (globalIRCode)
                 globalCode = isel->vmFunction(globalIRCode);
index c335029..84668cf 100644 (file)
@@ -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);
index 0eb51ee..b0a00e6 100644 (file)
@@ -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