Refactored the stack frames.
authorRoberto Raggi <roberto.raggi@nokia.com>
Wed, 16 May 2012 14:19:55 +0000 (16:19 +0200)
committerRoberto Raggi <roberto.raggi@nokia.com>
Wed, 16 May 2012 14:29:07 +0000 (16:29 +0200)
The new layout should simplify the use of static context
environments while compiling the code.

qmljs_objects.cpp
qmljs_objects.h
qmljs_runtime.cpp
qmljs_runtime.h
qv4codegen.cpp
qv4codegen_p.h
qv4isel.cpp

index 011b39c..44d8430 100644 (file)
@@ -328,3 +328,62 @@ Object *ExecutionEngine::newArgumentsObject(Context *ctx)
 {
     return new ArgumentsObject(ctx);
 }
+
+void Context::initCallContext(ExecutionEngine *e, const Value *object, FunctionObject *f, Value *args, int argc)
+{
+    engine = e;
+    parent = f->scope;
+
+    if (f->needsActivation)
+        __qmljs_init_object(&activation, engine->newArgumentsObject(this));
+    else
+        __qmljs_init_null(&activation);
+
+    if (object)
+        thisObject = *object;
+    else
+        __qmljs_init_null(&thisObject);
+
+    formals = f->formalParameterList;
+    formalCount = f->formalParameterCount;
+    arguments = args;
+    argumentCount = argc;
+    if (argc && f->needsActivation) {
+        arguments = new Value[argc];
+        std::copy(args, args + argc, arguments);
+    }
+    vars = f->varList;
+    varCount = f->varCount;
+    locals = varCount ? new Value[varCount] : 0;
+    std::fill(locals, locals + varCount, Value::undefinedValue());
+}
+
+void Context::leaveCallContext(FunctionObject *f, Value *returnValue)
+{
+    if (returnValue)
+        __qmljs_copy(returnValue, &result);
+
+    if (! f->needsActivation) {
+        delete[] locals;
+        locals = 0;
+    }
+}
+
+void Context::initConstructorContext(ExecutionEngine *e, const Value *object, FunctionObject *f, Value *args, int argc)
+{
+    initCallContext(e, object, f, args, argc);
+    calledAsConstructor = true;
+}
+
+void Context::leaveConstructorContext(FunctionObject *f, Value *returnValue)
+{
+    assert(thisObject.is(OBJECT_TYPE));
+    result = thisObject;
+
+    Value proto;
+    if (f->get(engine->identifier(QLatin1String("prototype")), &proto)) {
+        if (proto.type == OBJECT_TYPE)
+            thisObject.objectValue->prototype = proto.objectValue;
+    }
+    leaveCallContext(f, returnValue);
+}
index fdb0b98..08f9bcb 100644 (file)
@@ -301,13 +301,16 @@ struct Context {
     size_t varCount;
     bool calledAsConstructor;
 
-    Value *lookup(String *name) {
-        if (activation.is(OBJECT_TYPE)) {
-            if (Value *prop = activation.objectValue->getProperty(name)) {
-                return prop;
+    Value *lookup(String *name)
+    {
+        for (Context *ctx = this; ctx; ctx = ctx->parent) {
+            if (ctx->activation.is(OBJECT_TYPE)) {
+                if (Value *prop = ctx->activation.objectValue->getProperty(name)) {
+                    return prop;
+                }
             }
         }
-        return parent ? parent->lookup(name) : 0;
+        return 0;
     }
 
     inline Value argument(size_t index = 0)
@@ -341,6 +344,12 @@ struct Context {
         varCount = 0;
         calledAsConstructor = false;
     }
+
+    void initCallContext(ExecutionEngine *e, const Value *object, FunctionObject *f, Value *args, int argc);
+    void leaveCallContext(FunctionObject *f, Value *r);
+
+    void initConstructorContext(ExecutionEngine *e, const Value *object, FunctionObject *f, Value *args, int argc);
+    void leaveConstructorContext(FunctionObject *f, Value *returnValue);
 };
 
 struct ExecutionEngine
index e52ef24..337f2f7 100644 (file)
@@ -238,6 +238,7 @@ void __qmljs_set_property(Context *ctx, Value *object, String *name, Value *valu
 
 void __qmljs_set_property_boolean(Context *ctx, Value *object, String *name, bool number)
 {
+    Q_UNUSED(ctx);
     Value value;
     __qmljs_init_boolean(&value, number);
     object->objectValue->put(name, value, /*flag*/ 0);
@@ -245,6 +246,7 @@ void __qmljs_set_property_boolean(Context *ctx, Value *object, String *name, boo
 
 void __qmljs_set_property_number(Context *ctx, Value *object, String *name, double number)
 {
+    Q_UNUSED(ctx);
     Value value;
     __qmljs_init_number(&value, number);
     object->objectValue->put(name, value, /*flag*/ 0);
@@ -252,6 +254,7 @@ void __qmljs_set_property_number(Context *ctx, Value *object, String *name, doub
 
 void __qmljs_set_property_string(Context *ctx, Value *object, String *name, String *s)
 {
+    Q_UNUSED(ctx);
     Value value;
     __qmljs_init_string(&value, s);
     object->objectValue->put(name, value, /*flag*/ 0);
@@ -266,9 +269,9 @@ void __qmljs_set_property_closure(Context *ctx, Value *object, String *name, IR:
 
 void __qmljs_set_activation_property(Context *ctx, String *name, Value *value)
 {
-    if (Value *prop = ctx->lookup(name))
-        __qmljs_copy(prop, value);
-    else
+    if (Value *prop = ctx->lookup(name)) {
+        *prop = *value;
+    else
         ctx->activation.objectValue->put(name, *value);
 }
 
@@ -455,24 +458,9 @@ void __qmljs_call_property(Context *context, Value *result, const Value *base, S
         if (FunctionObject *f = func.objectValue->asFunctionObject()) {
             Context k;
             Context *ctx = f->needsActivation ? context->engine->newContext() : &k;
-            ctx->init(context->engine);
-            ctx->parent = f->scope;
-            if (f->needsActivation)
-                __qmljs_init_object(&ctx->activation, ctx->engine->newArgumentsObject(ctx));
-            else
-                __qmljs_init_null(&ctx->activation);
-            ctx->thisObject = thisObject;
-            ctx->formals = f->formalParameterList;
-            ctx->formalCount = f->formalParameterCount;
-            ctx->arguments = args;
-            ctx->argumentCount = argc;
-            if (argc && f->needsActivation) {
-                ctx->arguments = new Value[argc];
-                std::copy(args, args + argc, ctx->arguments);
-            }
+            ctx->initCallContext(context->engine, &thisObject, f, args, argc);
             f->call(ctx);
-            if (result)
-                __qmljs_copy(result, &ctx->result);
+            ctx->leaveCallContext(f, result);
         } else {
             assert(!"not a function");
         }
@@ -483,33 +471,13 @@ void __qmljs_call_property(Context *context, Value *result, const Value *base, S
 
 void __qmljs_call_value(Context *context, Value *result, const Value *func, Value *args, int argc)
 {
-    Q_UNUSED(context);
-
     if (func->type == OBJECT_TYPE) {
         if (FunctionObject *f = func->objectValue->asFunctionObject()) {
             Context k;
             Context *ctx = f->needsActivation ? context->engine->newContext() : &k;
-            ctx->init(context->engine);
-            ctx->parent = f->scope;
-            if (f->needsActivation)
-                __qmljs_init_object(&ctx->activation, ctx->engine->newArgumentsObject(ctx));
-            else
-                __qmljs_init_null(&ctx->activation);
-            __qmljs_init_null(&ctx->thisObject);
-            ctx->formals = f->formalParameterList;
-            ctx->formalCount = f->formalParameterCount;
-            ctx->arguments = args;
-            ctx->argumentCount = argc;
-            if (argc && f->needsActivation) {
-                ctx->arguments = new Value[argc];
-                std::copy(args, args + argc, ctx->arguments);
-            }
-            ctx->vars = f->varList;
-            ctx->varCount = f->varCount;
-            ctx->locals = 0;
+            ctx->initCallContext(context->engine, 0, f, args, argc);
             f->call(ctx);
-            if (result)
-                __qmljs_copy(result, &ctx->result);
+            ctx->leaveCallContext(f, result);
         } else {
             assert(!"not a function");
         }
@@ -534,33 +502,9 @@ void __qmljs_construct_value(Context *context, Value *result, const Value *func,
         if (FunctionObject *f = func->objectValue->asFunctionObject()) {
             Context k;
             Context *ctx = f->needsActivation ? context->engine->newContext() : &k;
-            ctx->init(context->engine);
-            ctx->parent = f->scope;
-            if (f->needsActivation)
-                __qmljs_init_object(&ctx->activation, ctx->engine->newArgumentsObject(ctx));
-            else
-                __qmljs_init_null(&ctx->activation);
-            __qmljs_init_null(&ctx->thisObject);
-            ctx->formals = f->formalParameterList;
-            ctx->formalCount = f->formalParameterCount;
-            ctx->arguments = args;
-            ctx->argumentCount = argc;
-            if (argc && f->needsActivation) {
-                ctx->arguments = new Value[argc];
-                std::copy(args, args + argc, ctx->arguments);
-            }
-            ctx->calledAsConstructor = true;
+            ctx->initConstructorContext(context->engine, 0, f, args, argc);
             f->construct(ctx);
-            assert(ctx->thisObject.is(OBJECT_TYPE));
-            ctx->result = ctx->thisObject;
-            Value proto;
-            if (f->get(ctx->engine->identifier(QLatin1String("prototype")), &proto)) { // ### `prototype' should be a unique symbol
-                if (proto.type == OBJECT_TYPE)
-                    ctx->thisObject.objectValue->prototype = proto.objectValue;
-            }
-
-            if (result)
-                __qmljs_copy(result, &ctx->thisObject);
+            ctx->leaveConstructorContext(f, result);
         } else {
             assert(!"not a function");
         }
@@ -582,33 +526,10 @@ void __qmljs_construct_property(Context *context, Value *result, const Value *ba
         if (FunctionObject *f = func.objectValue->asFunctionObject()) {
             Context k;
             Context *ctx = f->needsActivation ? context->engine->newContext() : &k;
-            ctx->init(context->engine);
-            ctx->parent = f->scope;
-            if (f->needsActivation)
-                __qmljs_init_object(&ctx->activation, ctx->engine->newArgumentsObject(ctx));
-            else
-                __qmljs_init_null(&ctx->activation);
-            ctx->thisObject = thisObject;
-            ctx->formals = f->formalParameterList;
-            ctx->formalCount = f->formalParameterCount;
-            ctx->arguments = args;
-            ctx->argumentCount = argc;
-            if (argc && f->needsActivation) {
-                ctx->arguments = new Value[argc];
-                std::copy(args, args + argc, ctx->arguments);
-            }
+            ctx->initConstructorContext(context->engine, 0, f, args, argc);
             ctx->calledAsConstructor = true;
             f->construct(ctx);
-            assert(ctx->thisObject.is(OBJECT_TYPE));
-
-            Value proto;
-            if (f->get(ctx->engine->identifier(QLatin1String("prototype")), &proto)) { // ### `prototype' should be a unique symbol
-                if (proto.type == OBJECT_TYPE)
-                    ctx->thisObject.objectValue->prototype = proto.objectValue;
-            }
-
-            if (result)
-                __qmljs_copy(result, &ctx->thisObject);
+            ctx->leaveConstructorContext(f, result);
         } else {
             assert(!"not a function");
         }
index b2b9987..467e302 100644 (file)
@@ -174,6 +174,18 @@ struct Value {
     inline bool is(ValueType t) const { return type == t; }
     inline bool isNot(ValueType t) const { return type != t; }
 
+    static inline Value undefinedValue() {
+        Value v;
+        v.type = UNDEFINED_TYPE;
+        return v;
+    }
+
+    static inline Value nullValue() {
+        Value v;
+        v.type = NULL_TYPE;
+        return v;
+    }
+
     static inline Value fromBoolean(bool value) {
         Value v;
         __qmljs_init_boolean(&v, value);
index 97b004b..ff50fb9 100644 (file)
@@ -256,6 +256,7 @@ Codegen::Codegen()
 void Codegen::operator()(AST::Program *node, IR::Module *module)
 {
     _module = module;
+    _env = 0;
 
     Scope scope(this, newEnvironment());
     ScanFunctionBody globalCodeInfo;
@@ -1385,11 +1386,12 @@ void Codegen::defineFunction(FunctionExpression *ast, bool /*isDeclaration*/)
     function->hasNestedFunctions = functionInfo.hasNestedFunctions;
     function->maxNumberOfArguments = functionInfo.maxNumberOfArguments;
 
-    if (! function->needsActivation()) {
+    //if (! function->needsActivation())
+    {
         for (int i = 0; i < functionInfo.locals.size(); ++i) {
             unsigned t = entryBlock->newTemp();
             Q_ASSERT(t == unsigned(i));
-            entryBlock->MOVE(entryBlock->TEMP(t), entryBlock->CONST(IR::UndefinedType, 0));
+            //entryBlock->MOVE(entryBlock->TEMP(t), entryBlock->CONST(IR::UndefinedType, 0));
         }
     }
 
index 92afa90..c443413 100644 (file)
@@ -105,7 +105,7 @@ protected:
     struct Scope {
         Codegen *cg;
         Environment *previous;
-        inline Scope(Codegen *cg, Environment *env) { previous = cg->changeEnvironment(env); }
+        inline Scope(Codegen *cg, Environment *env): cg(cg) { previous = cg->changeEnvironment(env); }
         inline ~Scope() { cg->changeEnvironment(previous); }
 
     private:
index b50dd83..77e2e06 100644 (file)
@@ -104,7 +104,7 @@ void InstructionSelection::operator()(IR::Function *function)
     _function->code = (void (*)(VM::Context *)) _code;
     _codePtr = _code;
 
-    int locals = (_function->tempCount + _function->maxNumberOfArguments) * sizeof(Value);
+    int locals = (_function->tempCount - _function->locals.size() + _function->maxNumberOfArguments) * sizeof(Value);
     locals = (locals + 15) & ~15;
 
     amd64_push_reg(_codePtr, AMD64_RBP);
@@ -115,12 +115,6 @@ void InstructionSelection::operator()(IR::Function *function)
     amd64_mov_reg_reg(_codePtr, AMD64_R14, AMD64_RDI, 8);
     amd64_alu_reg_imm(_codePtr, X86_SUB, AMD64_RSP, locals);
 
-    amd64_alu_reg_reg(_codePtr, X86_XOR, AMD64_R15, AMD64_R15);
-
-    amd64_lea_membase(_codePtr, AMD64_RAX, AMD64_RSP, _function->maxNumberOfArguments * sizeof(Value));
-    amd64_mov_membase_reg(_codePtr, AMD64_R14, offsetof(Context, locals), AMD64_RAX, 8);
-
-
     foreach (IR::BasicBlock *block, _function->basicBlocks) {
         _block = block;
         _addrs[block] = _codePtr;
@@ -174,8 +168,11 @@ void InstructionSelection::loadTempAddress(int reg, IR::Temp *t)
         const int arg = -t->index - 1;
         amd64_mov_reg_membase(_codePtr, reg, AMD64_R14, offsetof(Context, arguments), 8);
         amd64_lea_membase(_codePtr, reg, reg, sizeof(Value) * arg);
+    } else if (t->index < _function->locals.size()) {
+        amd64_mov_reg_membase(_codePtr, reg, AMD64_R14, offsetof(Context, locals), 8);
+        amd64_lea_membase(_codePtr, reg, reg, sizeof(Value) * t->index);
     } else {
-        amd64_lea_membase(_codePtr, reg, AMD64_RSP, sizeof(Value) * (_function->maxNumberOfArguments + t->index));
+        amd64_lea_membase(_codePtr, reg, AMD64_RSP, sizeof(Value) * (_function->maxNumberOfArguments + t->index - _function->locals.size()));
     }
 }