Move arguments object creation into the generated code
authorLars Knoll <lars.knoll@digia.com>
Fri, 16 Aug 2013 10:54:30 +0000 (12:54 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Sat, 17 Aug 2013 07:26:30 +0000 (09:26 +0200)
So far we've been creating the arguments object at runtime
in initCallContext(). It's much more efficient to simply add
arguments as a local variable in qv4codegen if it's being used
and initialize it through a builtin method.

Change-Id: I6913f3565adf3aa1917adae8dceef9f50ecf1722
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
17 files changed:
src/qml/compiler/qv4codegen.cpp
src/qml/compiler/qv4instr_moth_p.h
src/qml/compiler/qv4isel_masm.cpp
src/qml/compiler/qv4isel_masm_p.h
src/qml/compiler/qv4isel_moth.cpp
src/qml/compiler/qv4isel_moth_p.h
src/qml/compiler/qv4isel_p.cpp
src/qml/compiler/qv4isel_p.h
src/qml/compiler/qv4jsir.cpp
src/qml/compiler/qv4jsir_p.h
src/qml/jsruntime/qv4argumentsobject.cpp
src/qml/jsruntime/qv4argumentsobject_p.h
src/qml/jsruntime/qv4context.cpp
src/qml/jsruntime/qv4context_p.h
src/qml/jsruntime/qv4runtime.cpp
src/qml/jsruntime/qv4runtime_p.h
src/qml/jsruntime/qv4vme_moth.cpp

index e0c77cf..8c75124 100644 (file)
@@ -1820,11 +1820,14 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
     V4IR::BasicBlock *exitBlock = function->newBasicBlock(groupStartBlock(), V4IR::Function::DontInsertBlock);
     V4IR::BasicBlock *throwBlock = function->newBasicBlock(groupStartBlock());
     function->hasDirectEval = _env->hasDirectEval;
-    function->usesArgumentsObject = (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed);
+    function->usesArgumentsObject = _env->parent && (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed);
     function->maxNumberOfArguments = _env->maxNumberOfArguments;
     function->isStrict = _env->isStrict;
     function->isNamedExpression = _env->isNamedFunctionExpression;
 
+    if (function->usesArgumentsObject)
+        _env->enter("arguments", Environment::VariableDeclaration);
+
     // variables in global code are properties of the global context object, not locals as with other functions.
     if (_mode == FunctionCode) {
         unsigned t = 0;
@@ -1897,6 +1900,11 @@ V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
             }
         }
     }
+    if (_function->usesArgumentsObject) {
+        move(_block->NAME("arguments", ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn),
+             _block->CALL(_block->NAME(V4IR::Name::builtin_setup_argument_object,
+                     ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), 0));
+    }
 
     sourceElements(body);
 
index 8ddecd0..5e1fb6f 100644 (file)
@@ -92,6 +92,7 @@ QT_BEGIN_NAMESPACE
     F(CallBuiltinDefineProperty, callBuiltinDefineProperty) \
     F(CallBuiltinDefineArray, callBuiltinDefineArray) \
     F(CallBuiltinDefineObjectLiteral, callBuiltinDefineObjectLiteral) \
+    F(CallBuiltinSetupArgumentsObject, callBuiltinSetupArgumentsObject) \
     F(CreateValue, createValue) \
     F(CreateProperty, createProperty) \
     F(CreateActivationProperty, createActivationProperty) \
@@ -440,6 +441,10 @@ union Instr
         quint32 args;
         Param result;
     };
+    struct instr_callBuiltinSetupArgumentsObject {
+        MOTH_INSTR_HEADER
+        Param result;
+    };
     struct instr_createValue {
         MOTH_INSTR_HEADER
         quint32 argc;
@@ -577,6 +582,7 @@ union Instr
     instr_callBuiltinDefineProperty callBuiltinDefineProperty;
     instr_callBuiltinDefineArray callBuiltinDefineArray;
     instr_callBuiltinDefineObjectLiteral callBuiltinDefineObjectLiteral;
+    instr_callBuiltinSetupArgumentsObject callBuiltinSetupArgumentsObject;
     instr_createValue createValue;
     instr_createProperty createProperty;
     instr_createActivationProperty createActivationProperty;
index 861ffbf..b1418e5 100644 (file)
@@ -977,6 +977,12 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4
                          Assembler::TrustedImmPtr(klass));
 }
 
+void InstructionSelection::callBuiltinSetupArgumentObject(V4IR::Temp *result)
+{
+    generateFunctionCall(Assembler::Void, __qmljs_builtin_setup_arguments_object, Assembler::ContextRegister,
+                         Assembler::PointerToValue(result));
+}
+
 void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
 {
     int argc = prepareVariableArguments(args);
index c2f6604..9c91bfb 100644 (file)
@@ -815,6 +815,7 @@ protected:
     virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value);
     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 callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
     virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
     virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result);
index 6edb2e4..813acde 100644 (file)
@@ -1003,6 +1003,13 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4
     addInstruction(call);
 }
 
+void InstructionSelection::callBuiltinSetupArgumentObject(V4IR::Temp *result)
+{
+    Instruction::CallBuiltinSetupArgumentsObject call;
+    call.result = getResultParam(result);
+    addInstruction(call);
+}
+
 ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &instr)
 {
 #ifdef MOTH_THREADED_INTERPRETER
index f5fffe7..b6e4b43 100644 (file)
@@ -100,6 +100,7 @@ protected:
     virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value);
     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 callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
     virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
     virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result);
index c864378..7194473 100644 (file)
@@ -428,6 +428,10 @@ void IRDecoder::callBuiltin(V4IR::Call *call, V4IR::Temp *result)
         callBuiltinDefineObjectLiteral(result, call->args);
         return;
 
+    case V4IR::Name::builtin_setup_argument_object:
+        callBuiltinSetupArgumentObject(result);
+        return;
+
     default:
         break;
     }
index 965caf2..2de7ba6 100644 (file)
@@ -128,6 +128,7 @@ public: // to implement by subclasses:
     virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value) = 0;
     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 callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) = 0;
     virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0;
     virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result) = 0;
index f10c869..3c5ba72 100644 (file)
@@ -413,6 +413,8 @@ static const char *builtin_to_string(Name::Builtin b)
         return "builtin_define_getter_setter";
     case V4IR::Name::builtin_define_object_literal:
         return "builtin_define_object_literal";
+    case V4IR::Name::builtin_setup_argument_object:
+        return "builtin_setup_argument_object";
     }
     return "builtin_(###FIXME)";
 };
index 30e9074..82dc098 100644 (file)
@@ -314,7 +314,8 @@ struct Name: Expr {
         builtin_define_property,
         builtin_define_array,
         builtin_define_getter_setter,
-        builtin_define_object_literal
+        builtin_define_object_literal,
+        builtin_setup_argument_object
     };
 
     const QString *id;
index 07374a0..1670f69 100644 (file)
@@ -50,7 +50,7 @@ static Value throwTypeError(SimpleCallContext *ctx)
 
 DEFINE_MANAGED_VTABLE(ArgumentsObject);
 
-ArgumentsObject::ArgumentsObject(CallContext *context, int formalParameterCount, int actualParameterCount)
+ArgumentsObject::ArgumentsObject(CallContext *context)
     : Object(context->engine), context(context)
 {
     vtbl = &static_vtbl;
@@ -76,8 +76,8 @@ ArgumentsObject::ArgumentsObject(CallContext *context, int formalParameterCount,
         memberData[CalleePropertyIndex].value = Value::fromObject(context->function);
         isNonStrictArgumentsObject = true;
 
-        uint numAccessors = qMin(formalParameterCount, actualParameterCount);
-        uint argCount = qMin((uint)actualParameterCount, context->argumentCount);
+        uint numAccessors = qMin(context->function->formalParameterCount, context->realArgumentCount);
+        uint argCount = qMin((uint)context->realArgumentCount, context->argumentCount);
         arrayReserve(argCount);
         ensureArrayAttributes();
         context->engine->requireArgumentsAccessors(numAccessors);
@@ -94,7 +94,7 @@ ArgumentsObject::ArgumentsObject(CallContext *context, int formalParameterCount,
     }
     assert(LengthPropertyIndex == internalClass->find(context->engine->id_length));
     Property *lp = memberData + ArrayObject::LengthPropertyIndex;
-    lp->value = Value::fromInt32(actualParameterCount);
+    lp->value = Value::fromInt32(context->realArgumentCount);
 }
 
 void ArgumentsObject::destroy(Managed *that)
index 05016cc..097bc4c 100644 (file)
@@ -78,7 +78,7 @@ protected:
 struct ArgumentsObject: Object {
     CallContext *context;
     QVector<Value> mappedArguments;
-    ArgumentsObject(CallContext *context, int formalParameterCount, int actualParameterCount);
+    ArgumentsObject(CallContext *context);
     ~ArgumentsObject() {}
 
     enum {
index ce947e5..c67b105 100644 (file)
@@ -160,6 +160,7 @@ void CallContext::initCallContext(ExecutionContext *parentContext, FunctionObjec
 
     this->function = function;
     this->arguments = _arguments;
+    this->realArgumentCount = _argumentCount;
     this->argumentCount = _argumentCount;
     this->thisObject = _thisObject;
 
@@ -191,14 +192,6 @@ void CallContext::initCallContext(ExecutionContext *parentContext, FunctionObjec
             std::fill(arguments + argc, arguments + function->formalParameterCount, Value::undefinedValue());
 
     }
-
-    if (function->usesArgumentsObject) {
-        ArgumentsObject *args = new (engine->memoryManager) ArgumentsObject(this, function->formalParameterCount, argc);
-        args->prototype = engine->objectPrototype;
-        activation = engine->newObject();
-        Property desc = Property::fromValue(Value::fromObject(args));
-        activation->__defineOwnProperty__(this, engine->id_arguments, desc, Attr_NotConfigurable);
-    }
 }
 
 void CallContext::initQmlContext(ExecutionContext *parentContext, Object *qml, FunctionObject *function)
index dfe02bd..79d43c6 100644 (file)
@@ -157,6 +157,7 @@ struct SimpleCallContext : public ExecutionContext
     void initSimpleCallContext(ExecutionEngine *engine);
     FunctionObject *function;
     Value *arguments;
+    unsigned int realArgumentCount;
     unsigned int argumentCount;
 };
 
index 76e908c..79bbbf6 100644 (file)
@@ -46,6 +46,7 @@
 #include "qv4objectproto_p.h"
 #include "qv4globalobject_p.h"
 #include "qv4stringobject_p.h"
+#include "qv4argumentsobject_p.h"
 #include "qv4lookup_p.h"
 #include "qv4function_p.h"
 #include "qv4exception_p.h"
@@ -1221,6 +1222,15 @@ void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Valu
     *result = Value::fromObject(o);
 }
 
+void __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx, Value *result)
+{
+    assert(ctx->type >= ExecutionContext::Type_CallContext);
+    CallContext *c = static_cast<CallContext *>(ctx);
+    ArgumentsObject *args = new (c->engine->memoryManager) ArgumentsObject(c);
+    args->prototype = c->engine->objectPrototype;
+    *result = Value::fromObject(args);
+}
+
 void __qmljs_increment(Value *result, const Value &value)
 {
     TRACE1(value);
@@ -1264,6 +1274,7 @@ unsigned __qmljs_double_to_uint32(double d)
 {
     return Value::toUInt32(d);
 }
+
 } // namespace QV4
 
 QT_END_NAMESPACE
index dd75e6f..bce9508 100644 (file)
@@ -125,7 +125,7 @@ void __qmljs_builtin_define_property(QV4::ExecutionContext *ctx, const QV4::Valu
 void __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, QV4::Value *array, QV4::Value *values, uint length);
 void __qmljs_builtin_define_getter_setter(QV4::ExecutionContext *ctx, const QV4::Value &object, QV4::String *name, const QV4::Value *getter, const QV4::Value *setter);
 void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value *args, QV4::InternalClass *klass);
-
+void __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx, QV4::Value *result);
 // constructors
 void __qmljs_init_closure(QV4::ExecutionContext *ctx, QV4::Value *result, QV4::Function *clos);
 QV4::Function *__qmljs_register_function(QV4::ExecutionContext *ctx, QV4::String *name,
index 32313c3..7fc52ff 100644 (file)
@@ -467,6 +467,10 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
         __qmljs_builtin_define_object_literal(context, VALUEPTR(instr.result), args, instr.internalClass);
     MOTH_END_INSTR(CallBuiltinDefineObjectLiteral)
 
+    MOTH_BEGIN_INSTR(CallBuiltinSetupArgumentsObject)
+        __qmljs_builtin_setup_arguments_object(context, VALUEPTR(instr.result));
+    MOTH_END_INSTR(CallBuiltinSetupArgumentsObject)
+
     MOTH_BEGIN_INSTR(CreateValue)
         Q_ASSERT(instr.args + instr.argc <= stackSize);
         QV4::Value *args = stack + instr.args;