Get rid of the ActivationObject
authorLars Knoll <lars.knoll@digia.com>
Tue, 4 Dec 2012 21:46:48 +0000 (13:46 -0800)
committerSimon Hausmann <simon.hausmann@digia.com>
Wed, 5 Dec 2012 00:04:21 +0000 (01:04 +0100)
Also implement __qmljs_xxx_activation_property
in a more correct way.

Change-Id: I60c330bccca21fad99930987ed78153114a80c7d
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
main.cpp
qmljs_engine.cpp
qmljs_engine.h
qmljs_environment.cpp
qmljs_environment.h
qmljs_objects.cpp
qmljs_objects.h
qmljs_runtime.cpp
qmljs_runtime.h
qmljs_value.cpp
qmljs_value.h

index a516953..6f6d512 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -357,6 +357,7 @@ int main(int argc, char *argv[])
                 QQmlJS::IR::Function *f = QQmlJS::VM::EvalFunction::parseSource(ctx, fn, code, QQmlJS::Codegen::GlobalCode);
                 if (!f)
                     continue;
+
                 ctx->strictMode = f->isStrict;
                 if (debugger)
                     debugger->aboutToCall(0, ctx);
index 027cc33..6617810 100644 (file)
@@ -176,9 +176,20 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
     glo->__put__(rootContext, identifier(QStringLiteral("TypeError")), typeErrorCtor);
     glo->__put__(rootContext, identifier(QStringLiteral("URIError")), uRIErrorCtor);
     glo->__put__(rootContext, identifier(QStringLiteral("Math")), Value::fromObject(newMathObject(rootContext)));
-    glo->__put__(rootContext, identifier(QStringLiteral("undefined")), Value::undefinedValue());
-    glo->__put__(rootContext, identifier(QStringLiteral("NaN")), Value::fromDouble(nan("")));
-    glo->__put__(rootContext, identifier(QStringLiteral("Infinity")), Value::fromDouble(INFINITY));
+
+    PropertyDescriptor pd;
+    pd.type = PropertyDescriptor::Data;
+    pd.writable = PropertyDescriptor::Unset;
+    pd.enumberable = PropertyDescriptor::Unset;
+    pd.configurable = PropertyDescriptor::Unset;
+
+    pd.value = Value::undefinedValue();
+    glo->__defineOwnProperty__(rootContext, identifier(QStringLiteral("undefined")), &pd);
+    pd.value = Value::fromDouble(nan(""));
+    glo->__defineOwnProperty__(rootContext, identifier(QStringLiteral("NaN")), &pd);
+    pd.value = Value::fromDouble(INFINITY);
+    glo->__defineOwnProperty__(rootContext, identifier(QStringLiteral("Infinity")), &pd);
+
     glo->__put__(rootContext, identifier(QStringLiteral("eval")), Value::fromObject(new EvalFunction(rootContext)));
 
     // TODO: parseInt [15.1.2.2]
@@ -369,9 +380,9 @@ Object *ExecutionEngine::newMathObject(ExecutionContext *ctx)
     return object;
 }
 
-Object *ExecutionEngine::newActivationObject(ExecutionContext *ctx)
+Object *ExecutionEngine::newActivationObject()
 {
-    return new ActivationObject(ctx);
+    return new Object();
 }
 
 Object *ExecutionEngine::newForEachIteratorObject(Object *o)
index 2b053fd..2837adb 100644 (file)
@@ -65,7 +65,6 @@ struct DateObject;
 struct FunctionObject;
 struct RegExpObject;
 struct ErrorObject;
-struct ActivationObject;
 struct ArgumentsObject;
 struct ExecutionContext;
 struct ExecutionEngine;
@@ -190,7 +189,7 @@ struct ExecutionEngine
     Object *newTypeErrorObject(ExecutionContext *ctx, const QString &message);
 
     Object *newMathObject(ExecutionContext *ctx);
-    Object *newActivationObject(ExecutionContext *ctx);
+    Object *newActivationObject();
 
     Object *newForEachIteratorObject(Object *o);
 };
index 12a2091..c542422 100644 (file)
@@ -90,15 +90,17 @@ bool ExecutionContext::hasBinding(String *name) const
         if (__qmljs_string_equal(function->formalParameterList[i], name))
             return true;
     }
+    if (activation)
+        return activation->__hasProperty__(this, name);
     return false;
 }
 
-void ExecutionContext::createMutableBinding(ExecutionContext *ctx, String *name, bool deletable)
+void ExecutionContext::createMutableBinding(String *name, bool deletable)
 {
     if (!activation)
-        activation = engine->newActivationObject(this);
+        activation = engine->newActivationObject();
 
-    if (activation->__hasProperty__(ctx, name))
+    if (activation->__hasProperty__(this, name))
         return;
     PropertyDescriptor desc;
     desc.value = Value::undefinedValue();
@@ -106,31 +108,33 @@ void ExecutionContext::createMutableBinding(ExecutionContext *ctx, String *name,
     desc.configurable = deletable ? PropertyDescriptor::Set : PropertyDescriptor::Unset;
     desc.writable = PropertyDescriptor::Set;
     desc.enumberable = PropertyDescriptor::Set;
-    activation->__defineOwnProperty__(ctx, name, &desc);
+    activation->__defineOwnProperty__(this, name, &desc);
 }
 
-void ExecutionContext::setMutableBinding(String *name, Value value, bool strict)
+bool ExecutionContext::setMutableBinding(ExecutionContext *scope, String *name, Value value)
 {
-    Q_UNUSED(strict);
-    assert(function);
-
-    // ### throw if strict is true, and it would change an immutable binding
+    // ### throw if scope->strict is true, and it would change an immutable binding
     for (unsigned int i = 0; i < variableCount(); ++i) {
         if (__qmljs_string_equal(variables()[i], name)) {
             locals[i] = value;
-            return;
+            return true;
         }
     }
     for (unsigned int i = 0; i < formalCount(); ++i) {
         if (__qmljs_string_equal(formals()[i], name)) {
             arguments[i] = value;
-            return;
+            return true;
         }
     }
-    assert(false);
+    if (activation && activation->__hasProperty__(scope, name)) {
+        activation->__put__(scope, name, value);
+        return true;
+    }
+
+    return false;
 }
 
-Value ExecutionContext::getBindingValue(String *name, bool strict) const
+Value ExecutionContext::getBindingValue(ExecutionContext *scope, String *name, bool strict) const
 {
     Q_UNUSED(strict);
     assert(function);
@@ -143,16 +147,18 @@ Value ExecutionContext::getBindingValue(String *name, bool strict) const
         if (__qmljs_string_equal(formals()[i], name))
             return arguments[i];
     }
+    if (activation && activation->__hasProperty__(this, name))
+        return activation->__get__(scope, name);
     assert(false);
 }
 
-bool ExecutionContext::deleteBinding(ExecutionContext *ctx, String *name)
+bool ExecutionContext::deleteBinding(ExecutionContext *scope, String *name)
 {
     if (activation)
-        activation->__delete__(ctx, name);
+        activation->__delete__(scope, name);
 
-    if (ctx->strictMode)
-        __qmljs_throw_type_error(ctx);
+    if (scope->strictMode)
+        __qmljs_throw_type_error(scope);
     return false;
 }
 
@@ -251,10 +257,66 @@ bool ExecutionContext::deleteProperty(String *name)
                 ctx->activation->__delete__(this, name);
         }
     }
-    // ### throw syntax error in strict mode
+    if (strictMode)
+        throwSyntaxError(0);
     return true;
 }
 
+void ExecutionContext::setProperty(String *name, Value value)
+{
+    for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer()) {
+        if (ctx->withObject) {
+            With *w = ctx->withObject;
+            while (w) {
+                if (w->object->__hasProperty__(ctx, name)) {
+                    w->object->__put__(ctx, name, value);
+                    return;
+                }
+                w = w->next;
+            }
+        }
+        if (ctx->setMutableBinding(this, name, value))
+            return;
+    }
+    if (strictMode)
+        throwReferenceError(Value::fromString(name));
+    engine->globalObject.objectValue()->__put__(this, name, value);
+}
+
+Value ExecutionContext::getProperty(String *name)
+{
+    PropertyDescriptor tmp;
+    for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer()) {
+        if (ctx->withObject) {
+            With *w = ctx->withObject;
+            while (w) {
+                if (PropertyDescriptor *pd = w->object->__getPropertyDescriptor__(this, name, &tmp))
+                    return pd->value;
+                w = w->next;
+            }
+        }
+
+        for (unsigned int i = 0; i < ctx->variableCount(); ++i)
+            if (__qmljs_string_equal(ctx->variables()[i], name))
+                return ctx->locals[i];
+        for (unsigned int i = 0; i < ctx->formalCount(); ++i)
+            if (__qmljs_string_equal(ctx->formals()[i], name))
+                return ctx->arguments[i];
+        if (ctx->activation && ctx->activation->__hasProperty__(ctx, name))
+            return ctx->activation->__get__(ctx, name);
+        if (name->isEqualTo(ctx->engine->id_arguments)) {
+            Value arguments = Value::fromObject(new ArgumentsObject(this));
+            createMutableBinding(ctx->engine->id_arguments, false);
+            setMutableBinding(this, ctx->engine->id_arguments, arguments);
+            return arguments;
+        }
+    }
+    throwReferenceError(Value::fromString(name));
+    return Value::undefinedValue();
+}
+
+
+
 void ExecutionContext::inplaceBitOp(Value value, String *name, BinOp op)
 {
     for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer()) {
@@ -323,7 +385,7 @@ void ExecutionContext::initCallContext(ExecutionContext *parent, const Value tha
         std::fill(locals, locals + function->varCount, Value::undefinedValue());
 
     if (function->needsActivation)
-        activation = engine->newActivationObject(this);
+        activation = engine->newActivationObject();
     else
         activation = 0;
 
index eb10b66..dca22dc 100644 (file)
@@ -100,9 +100,9 @@ struct ExecutionContext
     void init(ExecutionEngine *e);
 
     bool hasBinding(String *name) const;
-    void createMutableBinding(ExecutionContext *ctx, String *name, bool deletable);
-    void setMutableBinding(String *name, Value value, bool strict);
-    Value getBindingValue(String *name, bool strict) const;
+    void createMutableBinding(String *name, bool deletable);
+    bool setMutableBinding(ExecutionContext *scope, String *name, Value value);
+    Value getBindingValue(ExecutionContext *scope, String *name, bool strict) const;
     bool deleteBinding(ExecutionContext *ctx, String *name);
 
     void pushWithObject(Object *with);
@@ -121,6 +121,8 @@ struct ExecutionContext
     void throwUnimplemented(const QString &message);
 
     PropertyDescriptor *lookupPropertyDescriptor(String *name, PropertyDescriptor *tmp);
+    void setProperty(String *name, Value value);
+    Value getProperty(String *name);
     void inplaceBitOp(Value value, String *name, BinOp op);
     bool deleteProperty(String *name);
 
index 12cc447..7fdb86a 100644 (file)
@@ -216,7 +216,7 @@ void Object::__put__(ExecutionContext *ctx, String *name, Value value)
 }
 
 // Section 8.12.6
-bool Object::__hasProperty__(ExecutionContext *ctx, String *name) const
+bool Object::__hasProperty__(const ExecutionContext *ctx, String *name) const
 {
     if (members)
         return members->find(name) != 0;
@@ -592,12 +592,6 @@ QQmlJS::IR::Function *EvalFunction::parseSource(QQmlJS::VM::ExecutionContext *ct
             __qmljs_throw_type_error(ctx);
     }
 
-    if (!ctx->activation)
-        ctx->activation = new QQmlJS::VM::Object();
-
-    foreach (const QString *local, globalCode->locals) {
-        ctx->activation->__put__(ctx, *local, QQmlJS::VM::Value::undefinedValue());
-    }
     return globalCode;
 }
 
@@ -681,42 +675,6 @@ Value ScriptFunction::construct(VM::ExecutionContext *ctx)
     return ctx->thisObject;
 }
 
-PropertyDescriptor *ActivationObject::__getPropertyDescriptor__(ExecutionContext *ctx, String *name, PropertyDescriptor *to_fill)
-{
-    if (context) {
-        for (unsigned int i = 0; i < context->variableCount(); ++i) {
-            String *var = context->variables()[i];
-            if (__qmljs_string_equal(var, name)) {
-                *to_fill = PropertyDescriptor::fromValue(context->locals[i]);
-                to_fill->writable = PropertyDescriptor::Set;
-                to_fill->enumberable = PropertyDescriptor::Set;
-                return to_fill;
-            }
-        }
-        for (unsigned int i = 0; i < context->formalCount(); ++i) {
-            String *formal = context->formals()[i];
-            if (__qmljs_string_equal(formal, name)) {
-                *to_fill = PropertyDescriptor::fromValue(context->arguments[i]);
-                to_fill->writable = PropertyDescriptor::Set;
-                to_fill->enumberable = PropertyDescriptor::Set;
-                return to_fill;
-            }
-        }
-        if (name->isEqualTo(ctx->engine->id_arguments)) {
-            if (arguments.isUndefined()) {
-                arguments = Value::fromObject(new ArgumentsObject(ctx));
-                arguments.objectValue()->prototype = ctx->engine->objectPrototype;
-            }
-
-            *to_fill = PropertyDescriptor::fromValue(arguments);
-            to_fill->writable = PropertyDescriptor::Unset;
-            to_fill->enumberable = PropertyDescriptor::Unset;
-            return to_fill;
-        }
-    }
-
-    return Object::__getPropertyDescriptor__(ctx, name, to_fill);
-}
 
 Value ArgumentsObject::__get__(ExecutionContext *ctx, String *name)
 {
index 4a98ee1..fc8deed 100644 (file)
@@ -72,7 +72,6 @@ struct DateObject;
 struct FunctionObject;
 struct RegExpObject;
 struct ErrorObject;
-struct ActivationObject;
 struct ArgumentsObject;
 struct ExecutionContext;
 struct ExecutionEngine;
@@ -419,7 +418,6 @@ struct Object {
     virtual FunctionObject *asFunctionObject() { return 0; }
     virtual RegExpObject *asRegExpObject() { return 0; }
     virtual ErrorObject *asErrorObject() { return 0; }
-    virtual ActivationObject *asActivationObject() { return 0; }
     virtual ArgumentsObject *asArgumentsObject() { return 0; }
 
     virtual Value __get__(ExecutionContext *ctx, String *name);
@@ -427,7 +425,7 @@ struct Object {
     virtual PropertyDescriptor *__getPropertyDescriptor__(ExecutionContext *ctx, String *name, PropertyDescriptor *to_fill);
     virtual void __put__(ExecutionContext *ctx, String *name, Value value);
     virtual bool __canPut__(ExecutionContext *ctx, String *name);
-    virtual bool __hasProperty__(ExecutionContext *ctx, String *name) const;
+    virtual bool __hasProperty__(const ExecutionContext *ctx, String *name) const;
     virtual bool __delete__(ExecutionContext *ctx, String *name);
     virtual bool __defineOwnProperty__(ExecutionContext *ctx, String *name, PropertyDescriptor *desc);
 
@@ -641,16 +639,6 @@ struct URIErrorObject: ErrorObject {
     virtual QString className() { return QStringLiteral("URIError"); }
 };
 
-struct ActivationObject: Object {
-    ExecutionContext *context;
-    Value arguments;
-    ActivationObject(ExecutionContext *context)
-        : context(context), arguments(Value::undefinedValue()) {}
-    virtual QString className() { return QStringLiteral("Activation"); }
-    virtual ActivationObject *asActivationObject() { return this; }
-    virtual PropertyDescriptor *__getPropertyDescriptor__(ExecutionContext *ctx, String *name, PropertyDescriptor *to_fill);
-};
-
 struct ArgumentsObject: Object {
     ExecutionContext *context;
     ArgumentsObject(ExecutionContext *context): context(context) {}
index 20002aa..d7bbf0e 100644 (file)
@@ -600,15 +600,7 @@ Value __qmljs_foreach_next_property_name(Value foreach_iterator)
 
 void __qmljs_set_activation_property(ExecutionContext *ctx, String *name, Value value)
 {
-    PropertyDescriptor tmp;
-    PropertyDescriptor *prop = ctx->lookupPropertyDescriptor(name, &tmp);
-    if (prop) {
-        prop->value = value;
-        return;
-    }
-    if (ctx->strictMode)
-        ctx->throwReferenceError(Value::fromString(name));
-    ctx->engine->globalObject.objectValue()->__put__(ctx, name, value);
+    ctx->setProperty(name, value);
 }
 
 Value __qmljs_get_property(ExecutionContext *ctx, Value object, String *name)
@@ -631,11 +623,7 @@ Value __qmljs_get_property(ExecutionContext *ctx, Value object, String *name)
 
 Value __qmljs_get_activation_property(ExecutionContext *ctx, String *name)
 {
-    PropertyDescriptor tmp;
-    PropertyDescriptor *prop = ctx->lookupPropertyDescriptor(name, &tmp);
-    if (!prop)
-        ctx->throwReferenceError(Value::fromString(name));
-    return prop->value;
+    return ctx->getProperty(name);
 }
 
 Value __qmljs_get_thisObject(ExecutionContext *ctx)
@@ -700,7 +688,7 @@ uint __qmljs_equal(Value x, Value y, ExecutionContext *ctx)
 // TODO: remove this function. Backends should just generate a __qmljs_get_activation_property followed by a __qmljs_call_value
 Value __qmljs_call_activation_property(ExecutionContext *context, String *name, Value *args, int argc)
 {
-    Value func = __qmljs_get_activation_property(context, name);
+    Value func = context->getProperty(name);
     Object *o = func.asObject();
     if (!o)
         context->throwReferenceError(Value::fromString(name));
@@ -734,11 +722,8 @@ Value __qmljs_call_value(ExecutionContext *context, Value thisObject, Value func
 
 Value __qmljs_construct_activation_property(ExecutionContext *context, String *name, Value *args, int argc)
 {
-    PropertyDescriptor tmp;
-    PropertyDescriptor *func = context->lookupPropertyDescriptor(name, &tmp);
-    if (! func)
-        context->throwReferenceError(Value::fromString(name));
-    return __qmljs_construct_value(context, func->value, args, argc);
+    Value func = context->getProperty(name);
+    return __qmljs_construct_value(context, func, args, argc);
 }
 
 Value __qmljs_construct_value(ExecutionContext *context, Value func, Value *args, int argc)
@@ -836,7 +821,7 @@ void __qmljs_builtin_pop_with(ExecutionContext *ctx)
 
 void __qmljs_builtin_declare_var(ExecutionContext *ctx, bool deletable, String *name)
 {
-    ctx->createMutableBinding(ctx, name, deletable);
+    ctx->createMutableBinding(name, deletable);
 }
 
 } // extern "C"
index d6a7839..adcdae6 100644 (file)
@@ -85,7 +85,6 @@ struct DateObject;
 struct RegExpObject;
 struct ArrayObject;
 struct ErrorObject;
-struct ActivationObject;
 struct ExecutionEngine;
 
 extern "C" {
index cbf4813..38e1f5d 100644 (file)
@@ -210,11 +210,6 @@ ErrorObject *Value::asErrorObject() const
     return isObject() ? objectValue()->asErrorObject() : 0;
 }
 
-ActivationObject *Value::asArgumentsObject() const
-{
-    return isObject() ? objectValue()->asActivationObject() : 0;
-}
-
 Value Value::property(ExecutionContext *ctx, String *name) const
 {
     return isObject() ? objectValue()->__get__(ctx, name) : undefinedValue();
index e15b970..3d29deb 100644 (file)
@@ -61,7 +61,6 @@ struct DateObject;
 struct FunctionObject;
 struct RegExpObject;
 struct ErrorObject;
-struct ActivationObject;
 struct ArgumentsObject;
 struct ExecutionContext;
 struct ExecutionEngine;
@@ -238,7 +237,6 @@ struct Value
     RegExpObject *asRegExpObject() const;
     ArrayObject *asArrayObject() const;
     ErrorObject *asErrorObject() const;
-    ActivationObject *asArgumentsObject() const;
 
     Value property(ExecutionContext *ctx, String *name) const;