Generate CallData structures directly in the instruction selection
authorLars Knoll <lars.knoll@digia.com>
Thu, 5 Sep 2013 12:49:55 +0000 (14:49 +0200)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Wed, 11 Sep 2013 11:01:54 +0000 (13:01 +0200)
Like this we can hand the CallData through the runtime methods
without any need to modify them. This simplifies the code in there,
and should also speed them up to some degree.

Change-Id: Ibd92ff4a8f279a5c4a054c5678646f658cfed5ca
Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
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/jsruntime/qv4object.cpp
src/qml/jsruntime/qv4runtime.cpp
src/qml/jsruntime/qv4runtime_p.h
src/qml/jsruntime/qv4scopedvalue_p.h
src/qml/jsruntime/qv4sparsearray.cpp
src/qml/jsruntime/qv4vme_moth.cpp

index 8164e43..68bc109 100644 (file)
@@ -289,7 +289,7 @@ union Instr
     struct instr_callValue {
         MOTH_INSTR_HEADER
         quint32 argc;
-        quint32 args;
+        quint32 callData;
         Param dest;
         Param result;
     };
@@ -297,7 +297,7 @@ union Instr
         MOTH_INSTR_HEADER
         int name;
         quint32 argc;
-        quint32 args;
+        quint32 callData;
         Param base;
         Param result;
     };
@@ -306,14 +306,14 @@ union Instr
         Param base;
         Param index;
         quint32 argc;
-        quint32 args;
+        quint32 callData;
         Param result;
     };
     struct instr_callActivationProperty {
         MOTH_INSTR_HEADER
         int name;
         quint32 argc;
-        quint32 args;
+        quint32 callData;
         Param result;
     };
     struct instr_callBuiltinThrow {
@@ -460,7 +460,7 @@ union Instr
     struct instr_createValue {
         MOTH_INSTR_HEADER
         quint32 argc;
-        quint32 args;
+        quint32 callData;
         Param func;
         Param result;
     };
@@ -468,7 +468,7 @@ union Instr
         MOTH_INSTR_HEADER
         int name;
         quint32 argc;
-        quint32 args;
+        quint32 callData;
         Param base;
         Param result;
     };
@@ -476,7 +476,7 @@ union Instr
         MOTH_INSTR_HEADER
         int name;
         quint32 argc;
-        quint32 args;
+        quint32 callData;
         Param result;
     };
     struct instr_jump {
index a0462d9..6850f41 100644 (file)
@@ -700,21 +700,19 @@ QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep()
 
 void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
 {
-    int argc = prepareVariableArguments(args);
+    int argc = prepareCallData(args, 0);
 
     if (useFastLookups && func->global) {
         uint index = registerGlobalGetterLookup(*func->id);
         generateFunctionCall(Assembler::Void, __qmljs_call_global_lookup,
                              Assembler::ContextRegister, Assembler::PointerToValue(result),
                              Assembler::TrustedImm32(index),
-                             baseAddressForCallArguments(),
-                             Assembler::TrustedImm32(argc));
+                             baseAddressForCallData());
     } else {
         generateFunctionCall(Assembler::Void, __qmljs_call_activation_property,
                              Assembler::ContextRegister, Assembler::PointerToValue(result),
                              Assembler::PointerToString(*func->id),
-                             baseAddressForCallArguments(),
-                             Assembler::TrustedImm32(argc));
+                             baseAddressForCallData());
     }
 }
 
@@ -985,11 +983,10 @@ void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4
 {
     Q_ASSERT(value);
 
-    int argc = prepareVariableArguments(args);
-    V4IR::Temp* thisObject = 0;
+    int argc = prepareCallData(args, 0);
     generateFunctionCall(Assembler::Void, __qmljs_call_value, Assembler::ContextRegister,
-            Assembler::PointerToValue(result), Assembler::PointerToValue(thisObject),
-            Assembler::Reference(value), baseAddressForCallArguments(), Assembler::TrustedImm32(argc));
+                         Assembler::PointerToValue(result), Assembler::Reference(value),
+                         baseAddressForCallData());
 }
 
 void InstructionSelection::loadThisObject(V4IR::Temp *temp)
@@ -1342,19 +1339,19 @@ void InstructionSelection::callProperty(V4IR::Expr *base, const QString &name, V
 {
     assert(base != 0);
 
-    int argc = prepareVariableArguments(args);
+    int argc = prepareCallData(args, base);
 
     if (useFastLookups) {
         uint index = registerGetterLookup(name);
         generateFunctionCall(Assembler::Void, __qmljs_call_property_lookup,
                              Assembler::ContextRegister, Assembler::PointerToValue(result),
-                             Assembler::PointerToValue(base), Assembler::TrustedImm32(index),
-                             baseAddressForCallArguments(),
-                             Assembler::TrustedImm32(argc));
-    } else {
+                             Assembler::TrustedImm32(index),
+                             baseAddressForCallData());
+    } else
+    {
         generateFunctionCall(Assembler::Void, __qmljs_call_property, Assembler::ContextRegister,
-                             Assembler::PointerToValue(result), Assembler::PointerToValue(base), Assembler::PointerToString(name),
-                             baseAddressForCallArguments(), Assembler::TrustedImm32(argc));
+                             Assembler::PointerToValue(result), Assembler::PointerToString(name),
+                             baseAddressForCallData());
     }
 }
 
@@ -1363,11 +1360,10 @@ void InstructionSelection::callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4
 {
     assert(base != 0);
 
-    int argc = prepareVariableArguments(args);
+    int argc = prepareCallData(args, base);
     generateFunctionCall(Assembler::Void, __qmljs_call_element, Assembler::ContextRegister,
-                         Assembler::PointerToValue(result), Assembler::PointerToValue(base),
-                         Assembler::PointerToValue(index), baseAddressForCallArguments(),
-                         Assembler::TrustedImm32(argc));
+                         Assembler::PointerToValue(result), Assembler::PointerToValue(index),
+                         baseAddressForCallData());
 }
 
 void InstructionSelection::convertType(V4IR::Temp *source, V4IR::Temp *target)
@@ -1568,35 +1564,41 @@ void InstructionSelection::convertTypeToSInt32(V4IR::Temp *source, V4IR::Temp *t
 void InstructionSelection::constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
 {
     assert(func != 0);
+    int argc = prepareCallData(args, 0);
 
     if (useFastLookups && func->global) {
-        int argc = prepareVariableArguments(args);
         uint index = registerGlobalGetterLookup(*func->id);
         generateFunctionCall(Assembler::Void, __qmljs_construct_global_lookup,
                              Assembler::ContextRegister, Assembler::PointerToValue(result),
                              Assembler::TrustedImm32(index),
-                             baseAddressForCallArguments(),
-                             Assembler::TrustedImm32(argc));
+                             baseAddressForCallData());
         return;
     }
 
-    callRuntimeMethod(result, __qmljs_construct_activation_property, func, args);
+    generateFunctionCall(Assembler::Void, __qmljs_construct_activation_property,
+                         Assembler::ContextRegister, Assembler::PointerToValue(result),
+                         Assembler::PointerToString(*func->id),
+                         baseAddressForCallData());
 }
 
+
 void InstructionSelection::constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result)
 {
-    int argc = prepareVariableArguments(args);
+    int argc = prepareCallData(args, 0);
     generateFunctionCall(Assembler::Void, __qmljs_construct_property, Assembler::ContextRegister,
-            Assembler::PointerToValue(result), Assembler::Reference(base), Assembler::PointerToString(name), baseAddressForCallArguments(), Assembler::TrustedImm32(argc));
+                         Assembler::PointerToValue(result), Assembler::Reference(base), Assembler::PointerToString(name),
+                         baseAddressForCallData());
 }
 
 void InstructionSelection::constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
 {
     assert(value != 0);
 
-    int argc = prepareVariableArguments(args);
-    generateFunctionCall(Assembler::Void, __qmljs_construct_value, Assembler::ContextRegister,
-            Assembler::PointerToValue(result), Assembler::Reference(value), baseAddressForCallArguments(), Assembler::TrustedImm32(argc));
+    int argc = prepareCallData(args, 0);
+    generateFunctionCall(Assembler::Void, __qmljs_construct_value,
+                         Assembler::ContextRegister, Assembler::PointerToValue(result),
+                         Assembler::Reference(value),
+                         baseAddressForCallData());
 }
 
 void InstructionSelection::visitJump(V4IR::Jump *s)
@@ -1783,6 +1785,33 @@ int InstructionSelection::prepareVariableArguments(V4IR::ExprList* args)
     return argc;
 }
 
+int InstructionSelection::prepareCallData(V4IR::ExprList* args, V4IR::Expr *thisObject)
+{
+    int argc = 0;
+    for (V4IR::ExprList *it = args; it; it = it->next) {
+        ++argc;
+    }
+
+    Pointer p = _as->stackLayout().callDataAddress(offsetof(CallData, tag));
+    _as->store32(Assembler::TrustedImm32(0), p);
+    p = _as->stackLayout().callDataAddress(offsetof(CallData, argc));
+    _as->store32(Assembler::TrustedImm32(argc), p);
+    p = _as->stackLayout().callDataAddress(offsetof(CallData, thisObject));
+    if (!thisObject)
+        _as->storeValue(QV4::Value::undefinedValue(), p);
+    else
+        _as->copyValue(p, thisObject);
+
+    int i = 0;
+    for (V4IR::ExprList *it = args; it; it = it->next, ++i) {
+        V4IR::Expr *arg = it->expr;
+        Q_ASSERT(arg != 0);
+        _as->copyValue(_as->stackLayout().argumentAddressForCall(i), arg);
+    }
+    return argc;
+}
+
+
 void InstructionSelection::callRuntimeMethodImp(V4IR::Temp *result, const char* name, ActivationMethod method, V4IR::Expr *base, V4IR::ExprList *args)
 {
     V4IR::Name *baseName = base->asName();
index 58d3720..1119c43 100644 (file)
@@ -269,7 +269,7 @@ public:
     public:
         StackLayout(V4IR::Function *function, int maxArgCountForBuiltins)
             : calleeSavedRegCount(Assembler::calleeSavedRegisterCount + 1)
-            , maxOutgoingArgumentCount(qMax(function->maxNumberOfArguments, maxArgCountForBuiltins))
+            , maxOutgoingArgumentCount(function->maxNumberOfArguments)
             , localCount(function->tempCount)
             , savedConstCount(maxArgCountForBuiltins)
         {
@@ -295,7 +295,7 @@ public:
                                                      + RegisterSize; // saved StackFrameRegister
 
             // space for the callee saved registers
-            int frameSize = RegisterSize * calleeSavedRegisterCount;
+            int frameSize = RegisterSize * (calleeSavedRegisterCount + savedConstCount);
 
             frameSize = WTF::roundUpToMultipleOf(StackAlignment, frameSize + stackSpaceAllocatedOtherwise);
             frameSize -= stackSpaceAllocatedOtherwise;
@@ -305,7 +305,7 @@ public:
 
         int calculateJSStackFrameSize() const
         {
-            const int locals = (maxOutgoingArgumentCount + localCount + savedConstCount) + 1;
+            const int locals = (localCount + sizeof(QV4::CallData)/sizeof(QV4::Value) - 1 + maxOutgoingArgumentCount) + 1;
             int frameSize = locals * sizeof(QV4::Value);
             return frameSize;
         }
@@ -315,7 +315,7 @@ public:
             Q_ASSERT(idx >= 0);
             Q_ASSERT(idx < localCount);
 
-            Pointer addr = argumentAddressForCall(0);
+            Pointer addr = callDataAddress(0);
             addr.offset -= sizeof(QV4::Value) * (idx + 1);
             return addr;
         }
@@ -328,8 +328,11 @@ public:
             Q_ASSERT(argument < maxOutgoingArgumentCount);
 
             const int index = maxOutgoingArgumentCount - argument;
-            return Pointer(Assembler::LocalsRegister,
-                           sizeof(QV4::Value) * (-index) - calleeSavedRegisterSpace());
+            return Pointer(Assembler::LocalsRegister, sizeof(QV4::Value) * (-index));
+        }
+
+        Pointer callDataAddress(int offset = 0) const {
+            return Pointer(Assembler::LocalsRegister, -(sizeof(QV4::CallData) + sizeof(QV4::Value) * (maxOutgoingArgumentCount - 1)) + offset);
         }
 
         Address savedRegPointer(int offset) const
@@ -1255,6 +1258,11 @@ protected:
         return _as->stackLayout().argumentAddressForCall(0);
     }
 
+    Pointer baseAddressForCallData()
+    {
+        return _as->stackLayout().callDataAddress();
+    }
+
     virtual void constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
     virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
     virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
@@ -1329,6 +1337,7 @@ private:
         _as->generateFunctionCallImp(t, isel_stringIfy(function), function, __VA_ARGS__)
 
     int prepareVariableArguments(V4IR::ExprList* args);
+    int prepareCallData(V4IR::ExprList* args, V4IR::Expr *thisObject);
 
     typedef void (*ActivationMethod)(QV4::ExecutionContext *, QV4::Value *result, QV4::String *name, QV4::Value *args, int argc);
     void callRuntimeMethodImp(V4IR::Temp *result, const char* name, ActivationMethod method, V4IR::Expr *base, V4IR::ExprList *args);
index 3e7b191..1546f19 100644 (file)
@@ -311,7 +311,8 @@ QV4::CompiledData::CompilationUnit *InstructionSelection::backendCompileStep()
 void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
 {
     Instruction::CallValue call;
-    prepareCallArgs(args, call.argc, call.args);
+    prepareCallArgs(args, call.argc);
+    call.callData = callDataStart();
     call.dest = getParam(value);
     call.result = getResultParam(result);
     addInstruction(call);
@@ -324,7 +325,8 @@ void InstructionSelection::callProperty(V4IR::Expr *base, const QString &name, V
     Instruction::CallProperty call;
     call.base = getParam(base);
     call.name = registerString(name);
-    prepareCallArgs(args, call.argc, call.args);
+    prepareCallArgs(args, call.argc);
+    call.callData = callDataStart();
     call.result = getResultParam(result);
     addInstruction(call);
 }
@@ -336,7 +338,8 @@ void InstructionSelection::callSubscript(V4IR::Expr *base, V4IR::Expr *index, V4
     Instruction::CallElement call;
     call.base = getParam(base);
     call.index = getParam(index);
-    prepareCallArgs(args, call.argc, call.args);
+    prepareCallArgs(args, call.argc);
+    call.callData = callDataStart();
     call.result = getResultParam(result);
     addInstruction(call);
 }
@@ -359,7 +362,8 @@ void InstructionSelection::constructActivationProperty(V4IR::Name *func,
 {
     Instruction::CreateActivationProperty create;
     create.name = registerString(*func->id);
-    prepareCallArgs(args, create.argc, create.args);
+    prepareCallArgs(args, create.argc);
+    create.callData = callDataStart();
     create.result = getResultParam(result);
     addInstruction(create);
 }
@@ -369,7 +373,8 @@ void InstructionSelection::constructProperty(V4IR::Temp *base, const QString &na
     Instruction::CreateProperty create;
     create.base = getParam(base);
     create.name = registerString(name);
-    prepareCallArgs(args, create.argc, create.args);
+    prepareCallArgs(args, create.argc);
+    create.callData = callDataStart();
     create.result = getResultParam(result);
     addInstruction(create);
 }
@@ -378,7 +383,8 @@ void InstructionSelection::constructValue(V4IR::Temp *value, V4IR::ExprList *arg
 {
     Instruction::CreateValue create;
     create.func = getParam(value);
-    prepareCallArgs(args, create.argc, create.args);
+    prepareCallArgs(args, create.argc);
+    create.callData = callDataStart();
     create.result = getResultParam(result);
     addInstruction(create);
 }
@@ -667,23 +673,15 @@ void InstructionSelection::inplaceMemberOp(V4IR::AluOp oper, V4IR::Temp *source,
     addInstruction(imo);
 }
 
-void InstructionSelection::prepareCallArgs(V4IR::ExprList *e, quint32 &argc, quint32 &args)
+void InstructionSelection::prepareCallArgs(V4IR::ExprList *e, quint32 &argc, quint32 *args)
 {
-    bool singleArgIsTemp = false;
-    if (e && e->next == 0 && e->expr->asTemp()) {
-        singleArgIsTemp = e->expr->asTemp()->kind == V4IR::Temp::VirtualRegister;
-    }
-
-    if (singleArgIsTemp) {
-        // We pass single arguments as references to the stack, but only if it's not a local or an argument.
-        argc = 1;
-        args = getParam(e->expr).index;
-    } else if (e) {
+    int argLocation = outgoingArgumentTempStart();
+    argc = 0;
+    if (args)
+        *args = argLocation;
+    if (e) {
         // We need to move all the temps into the function arg array
-        int argLocation = outgoingArgumentTempStart();
         assert(argLocation >= 0);
-        argc = 0;
-        args = argLocation;
         while (e) {
             Instruction::MoveTemp move;
             move.source = getParam(e->expr);
@@ -693,9 +691,6 @@ void InstructionSelection::prepareCallArgs(V4IR::ExprList *e, quint32 &argc, qui
             ++argc;
             e = e->next;
         }
-    } else {
-        argc = 0;
-        args = 0;
     }
 }
 
@@ -763,7 +758,8 @@ void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *
 {
     Instruction::CallActivationProperty call;
     call.name = registerString(*func->id);
-    prepareCallArgs(args, call.argc, call.args);
+    prepareCallArgs(args, call.argc);
+    call.callData = callDataStart();
     call.result = getResultParam(result);
     addInstruction(call);
 }
@@ -980,7 +976,7 @@ void InstructionSelection::callBuiltinDefineProperty(V4IR::Temp *object, const Q
 void InstructionSelection::callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args)
 {
     Instruction::CallBuiltinDefineArray call;
-    prepareCallArgs(args, call.argc, call.args);
+    prepareCallArgs(args, call.argc, &call.args);
     call.result = getResultParam(result);
     addInstruction(call);
 }
index 43e792c..826d559 100644 (file)
@@ -161,11 +161,12 @@ private:
     }
 
     void simpleMove(V4IR::Move *);
-    void prepareCallArgs(V4IR::ExprList *, quint32 &, quint32 &);
+    void prepareCallArgs(V4IR::ExprList *, quint32 &, quint32 * = 0);
 
-    int outgoingArgumentTempStart() const { return _function->tempCount; }
-    int scratchTempIndex() const { return outgoingArgumentTempStart() + _function->maxNumberOfArguments; }
-    int frameSize() const { return scratchTempIndex() + 1; }
+    int scratchTempIndex() const { return _function->tempCount; }
+    int callDataStart() const { return scratchTempIndex() + 1; }
+    int outgoingArgumentTempStart() const { return callDataStart() + offsetof(QV4::CallData, args)/sizeof(QV4::Value); }
+    int frameSize() const { return outgoingArgumentTempStart() + _function->maxNumberOfArguments; }
 
     template <int Instr>
     inline ptrdiff_t addInstruction(const InstrData<Instr> &data);
index c99b481..fbee25e 100644 (file)
@@ -1247,6 +1247,9 @@ void Object::arraySort(ExecutionContext *context, Object *thisObject, const Valu
         }
     }
 
+    if (!(comparefn.isUndefined() || comparefn.asObject()))
+        context->throwTypeError();
+
     ArrayElementLessThan lessThan(context, thisObject, comparefn);
 
     Property *begin = arrayData;
index 649baaf..ca6540b 100644 (file)
@@ -720,8 +720,10 @@ Bool __qmljs_strict_equal(const Value &x, const Value &y)
 }
 
 
-void __qmljs_call_global_lookup(ExecutionContext *context, Value *result, uint index, Value *args, int argc)
+void __qmljs_call_global_lookup(ExecutionContext *context, Value *result, uint index, CallData *callData)
 {
+    Q_ASSERT(callData->thisObject.isUndefined());
+
     Lookup *l = context->lookups + index;
     Value v;
     l->globalGetter(l, context, &v);
@@ -729,28 +731,28 @@ void __qmljs_call_global_lookup(ExecutionContext *context, Value *result, uint i
     if (!o)
         context->throwTypeError();
 
-    Value thisObject = Value::undefinedValue();
-
     if (o == context->engine->evalFunction && l->name->isEqualTo(context->engine->id_eval)) {
-        Value res = static_cast<EvalFunction *>(o)->evalCall(thisObject, args, argc, true);
+        Value res = static_cast<EvalFunction *>(o)->evalCall(callData->thisObject, callData->args, callData->argc, true);
         if (result)
             *result = res;
         return;
     }
 
-    ScopedCallData d(context->engine, argc);
-    d->thisObject = thisObject;
-    memcpy(d->args, args, argc*sizeof(Value));
-    Value res = o->call(d);
+    Value res = o->call(*callData);
     if (result)
         *result = res;
 }
 
 
-void __qmljs_call_activation_property(ExecutionContext *context, Value *result, String *name, Value *args, int argc)
+void __qmljs_call_activation_property(ExecutionContext *context, Value *result, String *name, CallData *callData)
 {
+    Q_ASSERT(callData->thisObject.isUndefined());
+
     Object *base;
     Value func = context->getPropertyAndBase(name, &base);
+    if (base)
+        callData->thisObject = Value::fromObject(base);
+
     FunctionObject *o = func.asFunctionObject();
     if (!o) {
         QString objectAsString = QStringLiteral("[null]");
@@ -760,106 +762,88 @@ void __qmljs_call_activation_property(ExecutionContext *context, Value *result,
         context->throwTypeError(msg);
     }
 
-    Value thisObject = base ? Value::fromObject(base) : Value::undefinedValue();
-
     if (o == context->engine->evalFunction && name->isEqualTo(context->engine->id_eval)) {
-        Value res = static_cast<EvalFunction *>(o)->evalCall(thisObject, args, argc, true);
+        Value res = static_cast<EvalFunction *>(o)->evalCall(callData->thisObject, callData->args, callData->argc, true);
         if (result)
             *result = res;
         return;
     }
 
-    ScopedCallData d(context->engine, argc);
-    d->thisObject = thisObject;
-    memcpy(d->args, args, argc*sizeof(Value));
-    Value res = o->call(d);
+    Value res = o->call(*callData);
     if (result)
         *result = res;
 }
 
-void __qmljs_call_property(ExecutionContext *context, Value *result, const Value &thatObject, String *name, Value *args, int argc)
+void __qmljs_call_property(ExecutionContext *context, Value *result, String *name, CallData *callData)
 {
-    Value thisObject = thatObject;
-    Managed *baseObject = thisObject.asManaged();
+    Managed *baseObject = callData->thisObject.asManaged();
     if (!baseObject) {
-        if (thisObject.isNull() || thisObject.isUndefined()) {
-            QString message = QStringLiteral("Cannot call method '%1' of %2").arg(name->toQString()).arg(thisObject.toQString());
+        if (callData->thisObject.isNullOrUndefined()) {
+            QString message = QStringLiteral("Cannot call method '%1' of %2").arg(name->toQString()).arg(callData->thisObject.toQString());
             context->throwTypeError(message);
         }
 
-        baseObject = __qmljs_convert_to_object(context, thisObject);
-        thisObject = Value::fromObject(static_cast<Object *>(baseObject));
+        baseObject = __qmljs_convert_to_object(context, callData->thisObject);
+        callData->thisObject = Value::fromObject(static_cast<Object *>(baseObject));
     }
 
-    Value func = baseObject->get(name);
-    FunctionObject *o = func.asFunctionObject();
+    FunctionObject *o = baseObject->get(name).asFunctionObject();
     if (!o) {
-        QString error = QString("Property '%1' of object %2 is not a function").arg(name->toQString(), thisObject.toQString());
+        QString error = QString("Property '%1' of object %2 is not a function").arg(name->toQString(), callData->thisObject.toQString());
         context->throwTypeError(error);
     }
 
-    ScopedCallData d(context->engine, argc);
-    d->thisObject = thisObject;
-    memcpy(d->args, args, argc*sizeof(Value));
-    Value res = o->call(d);
+    Value res = o->call(*callData);
     if (result)
         *result = res;
 }
 
-void __qmljs_call_property_lookup(ExecutionContext *context, Value *result, const Value &thisObject, uint index, Value *args, int argc)
+void __qmljs_call_property_lookup(ExecutionContext *context, Value *result, uint index, CallData *callData)
 {
     Value func;
 
     Lookup *l = context->lookups + index;
-    l->getter(l, &func, thisObject);
+    l->getter(l, &func, callData->thisObject);
 
     Object *o = func.asObject();
     if (!o)
         context->throwTypeError();
 
-    ScopedCallData d(context->engine, argc);
-    d->thisObject = thisObject;
-    memcpy(d->args, args, argc*sizeof(Value));
-    Value res = o->call(d);
+    Value res = o->call(*callData);
     if (result)
         *result = res;
 }
 
-void __qmljs_call_element(ExecutionContext *context, Value *result, const Value &that, const Value &index, Value *args, int argc)
+void __qmljs_call_element(ExecutionContext *context, Value *result, const Value &index, CallData *callData)
 {
-    Object *baseObject = that.toObject(context);
-    Value thisObject = Value::fromObject(baseObject);
+    Object *baseObject = callData->thisObject.toObject(context);
+    callData->thisObject = Value::fromObject(baseObject);
 
-    Value func = baseObject->get(index.toString(context));
-    Object *o = func.asObject();
+    Object *o = baseObject->get(index.toString(context)).asObject();
     if (!o)
         context->throwTypeError();
 
-    ScopedCallData d(context->engine, argc);
-    d->thisObject = thisObject;
-    memcpy(d->args, args, argc*sizeof(Value));
-    Value res = o->call(d);
+    Value res = o->call(*callData);
     if (result)
         *result = res;
 }
 
-void __qmljs_call_value(ExecutionContext *context, Value *result, const Value *thisObject, const Value &func, Value *args, int argc)
+void __qmljs_call_value(ExecutionContext *context, Value *result, const Value &func, CallData *callData)
 {
     Object *o = func.asObject();
     if (!o)
         context->throwTypeError();
 
-    ScopedCallData d(context->engine, argc);
-    d->thisObject = thisObject ? *thisObject : Value::undefinedValue();
-    memcpy(d->args, args, argc*sizeof(Value));
-    Value res = o->call(d);
+    Value res = o->call(*callData);
     if (result)
         *result = res;
 }
 
 
-void __qmljs_construct_global_lookup(ExecutionContext *context, Value *result, uint index, Value *args, int argc)
+void __qmljs_construct_global_lookup(ExecutionContext *context, Value *result, uint index, CallData *callData)
 {
+    Q_ASSERT(callData->thisObject.isUndefined());
+
     Value func;
 
     Lookup *l = context->lookups + index;
@@ -869,49 +853,47 @@ void __qmljs_construct_global_lookup(ExecutionContext *context, Value *result, u
     if (!f)
         context->throwTypeError();
 
-    ScopedCallData callData(context->engine, argc);
-    memcpy(callData->args, args, argc*sizeof(Value));
-    Value res = f->construct(callData);
+    Value res = f->construct(*callData);
     if (result)
         *result = res;
 }
 
 
-void __qmljs_construct_activation_property(ExecutionContext *context, Value *result, String *name, Value *args, int argc)
+void __qmljs_construct_activation_property(ExecutionContext *context, Value *result, String *name, CallData *callData)
 {
     Value func = context->getProperty(name);
-    __qmljs_construct_value(context, result, func, args, argc);
+    Object *f = func.asObject();
+    if (!f)
+        context->throwTypeError();
+
+    Value res = f->construct(*callData);
+    if (result)
+        *result = res;
 }
 
-void __qmljs_construct_value(ExecutionContext *context, Value *result, const Value &func, Value *args, int argc)
+void __qmljs_construct_value(ExecutionContext *context, Value *result, const Value &func, CallData *callData)
 {
-    if (Object *f = func.asObject()) {
-        ScopedCallData d(context->engine, argc);
-        memcpy(d->args, args, argc*sizeof(Value));
-        Value res = f->construct(d);
-        if (result)
-            *result = res;
-        return;
-    }
+    Object *f = func.asObject();
+    if (!f)
+        context->throwTypeError();
 
-    context->throwTypeError();
+    Value res = f->construct(*callData);
+    if (result)
+        *result = res;
 }
 
-void __qmljs_construct_property(ExecutionContext *context, Value *result, const Value &base, String *name, Value *args, int argc)
+void __qmljs_construct_property(ExecutionContext *context, Value *result, const Value &base, String *name, CallData *callData)
 {
     Object *thisObject = base.toObject(context);
 
     Value func = thisObject->get(name);
-    if (Object *f = func.asObject()) {
-        ScopedCallData d(context->engine, argc);
-        memcpy(d->args, args, argc*sizeof(Value));
-        Value res = f->construct(d);
-        if (result)
-            *result = res;
-        return;
-    }
+    Object *f = func.asObject();
+    if (!f)
+        context->throwTypeError();
 
-    context->throwTypeError();
+    Value res = f->construct(*callData);
+    if (result)
+        *result = res;
 }
 
 void __qmljs_throw(ExecutionContext *context, const Value &value)
index b38f833..c52a79e 100644 (file)
@@ -91,15 +91,15 @@ struct ExecutionEngine;
 struct InternalClass;
 
 // context
-void __qmljs_call_activation_property(QV4::ExecutionContext *, QV4::Value *result, QV4::String *name, QV4::Value *args, int argc);
-void __qmljs_call_property(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &that, QV4::String *name, QV4::Value *args, int argc);
-void __qmljs_call_property_lookup(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &thisObject, uint index, QV4::Value *args, int argc);
-void __qmljs_call_element(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &that, const QV4::Value &index, QV4::Value *args, int argc);
-void __qmljs_call_value(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value *thisObject, const QV4::Value &func, QV4::Value *args, int argc);
+void __qmljs_call_activation_property(QV4::ExecutionContext *, QV4::Value *result, QV4::String *name, CallData *callData);
+void __qmljs_call_property(QV4::ExecutionContext *context, QV4::Value *result, QV4::String *name, CallData *callData);
+void __qmljs_call_property_lookup(ExecutionContext *context, Value *result, uint index, CallData *callData);
+void __qmljs_call_element(ExecutionContext *context, Value *result, const Value &index, CallData *callData);
+void __qmljs_call_value(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &func, CallData *callData);
 
-void __qmljs_construct_activation_property(QV4::ExecutionContext *, QV4::Value *result, QV4::String *name, QV4::Value *args, int argc);
-void __qmljs_construct_property(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &base, QV4::String *name, QV4::Value *args, int argc);
-void __qmljs_construct_value(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &func, QV4::Value *args, int argc);
+void __qmljs_construct_activation_property(QV4::ExecutionContext *, QV4::Value *result, QV4::String *name, CallData *callData);
+void __qmljs_construct_property(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &base, QV4::String *name, CallData *callData);
+void __qmljs_construct_value(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &func, CallData *callData);
 
 void __qmljs_builtin_typeof(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &val);
 void __qmljs_builtin_typeof_name(QV4::ExecutionContext *context, QV4::Value* result, QV4::String *name);
@@ -145,8 +145,8 @@ void __qmljs_set_property(QV4::ExecutionContext *ctx, const QV4::Value &object,
 void __qmljs_get_property(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &object, QV4::String *name);
 void __qmljs_get_activation_property(QV4::ExecutionContext *ctx, QV4::Value *result, QV4::String *name);
 
-void __qmljs_call_global_lookup(QV4::ExecutionContext *context, QV4::Value *result, uint index, QV4::Value *args, int argc);
-void __qmljs_construct_global_lookup(QV4::ExecutionContext *context, QV4::Value *result, uint index, QV4::Value *args, int argc);
+void __qmljs_call_global_lookup(QV4::ExecutionContext *context, QV4::Value *result, uint index, CallData *callData);
+void __qmljs_construct_global_lookup(QV4::ExecutionContext *context, QV4::Value *result, uint index, CallData *callData);
 
 
 void __qmljs_get_element(QV4::ExecutionContext *ctx, QV4::Value *retval, const QV4::Value &object, const QV4::Value &index);
index 4218065..5998fd9 100644 (file)
@@ -140,11 +140,10 @@ struct ScopedCallData {
         : engine(e)
         // ### this check currently won't work because of exceptions
 #if 0 //ndef QT_NO_DEBUG
-        , size(qMax(argc, (int)QV4::Global::ReservedArgumentCount) + 2)
+        , size(qMax(argc, (int)QV4::Global::ReservedArgumentCount) + offsetof(QV4::CallData, args)/sizeof(QV4::Value))
 #endif
     {
-        Q_ASSERT(sizeof(CallData) == 3*sizeof(Value));
-        ptr = reinterpret_cast<CallData *>(e->stackPush(qMax(argc, (int)QV4::Global::ReservedArgumentCount) + 2));
+        ptr = reinterpret_cast<CallData *>(e->stackPush(qMax(argc, (int)QV4::Global::ReservedArgumentCount) + offsetof(QV4::CallData, args)/sizeof(QV4::Value)));
         ptr->tag = 0;
         ptr->argc = argc;
     }
index 835a0d0..5b720d2 100644 (file)
@@ -43,6 +43,7 @@
 #include "qv4runtime_p.h"
 #include "qv4object_p.h"
 #include "qv4functionobject_p.h"
+#include "qv4scopedvalue_p.h"
 #include <stdlib.h>
 
 #ifdef QT_QMAP_DEBUG
@@ -54,20 +55,21 @@ using namespace QV4;
 
 bool ArrayElementLessThan::operator()(const Property &p1, const Property &p2) const
 {
-    Value v1 = p1.value;
-    Value v2 = p2.value;
 
-    if (v1.isUndefined())
+    if (p1.value.isUndefined())
         return false;
-    if (v2.isUndefined())
+    if (p2.value.isUndefined())
         return true;
-    if (!m_comparefn.isUndefined()) {
-        Value args[] = { v1, v2 };
+    if (Object *o = m_comparefn.asObject()) {
+        ScopedCallData callData(o->engine(), 2);
+        callData->thisObject = Value::undefinedValue();
+        callData->args[0] = p1.value;
+        callData->args[1] = p2.value;
         Value result = Value::undefinedValue();
-        __qmljs_call_value(m_context, &result, /*thisObject*/0, m_comparefn, args, 2);
+        __qmljs_call_value(m_context, &result, m_comparefn, callData.ptr);
         return result.toNumber() <= 0;
     }
-    return v1.toString(m_context)->toQString() < v2.toString(m_context)->toQString();
+    return p1.value.toString(m_context)->toQString() < p2.value.toString(m_context)->toQString();
 }
 
 
index 10f09a8..5fef202 100644 (file)
@@ -45,7 +45,7 @@
 #include <private/qv4debugging_p.h>
 #include <private/qv4exception_p.h>
 #include <private/qv4math_p.h>
-
+#include <private/qv4scopedvalue_p.h>
 #include <iostream>
 
 #include "qv4alloca_p.h"
@@ -320,29 +320,41 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
             }
         }
 #endif // DO_TRACE_INSTR
-        Q_ASSERT(instr.args + instr.argc <= stackSize);
-        QV4::Value *args = stack + instr.args;
-        __qmljs_call_value(context, VALUEPTR(instr.result), /*thisObject*/0, VALUE(instr.dest), args, instr.argc);
+        Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+        QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
+        callData->tag = 0;
+        callData->argc = instr.argc;
+        callData->thisObject = QV4::Value::undefinedValue();
+        __qmljs_call_value(context, VALUEPTR(instr.result), VALUE(instr.dest), callData);
     MOTH_END_INSTR(CallValue)
 
     MOTH_BEGIN_INSTR(CallProperty)
         TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(instr.name->toQString()), instr.args, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
-        Q_ASSERT(instr.args + instr.argc <= stackSize);
-        QV4::Value *args = stack + instr.args;
-        __qmljs_call_property(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.name], args, instr.argc);
+        Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+        QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
+        callData->tag = 0;
+        callData->argc = instr.argc;
+        callData->thisObject = VALUE(instr.base);
+        __qmljs_call_property(context, VALUEPTR(instr.result), runtimeStrings[instr.name], callData);
     MOTH_END_INSTR(CallProperty)
 
     MOTH_BEGIN_INSTR(CallElement)
-        Q_ASSERT(instr.args + instr.argc <= stackSize);
-        QV4::Value *args = stack + instr.args;
-        __qmljs_call_element(context, VALUEPTR(instr.result), VALUE(instr.base), VALUE(instr.index), args, instr.argc);
+        Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+        QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
+        callData->tag = 0;
+        callData->argc = instr.argc;
+        callData->thisObject = VALUE(instr.base);
+        __qmljs_call_element(context, VALUEPTR(instr.result), VALUE(instr.index), callData);
     MOTH_END_INSTR(CallElement)
 
     MOTH_BEGIN_INSTR(CallActivationProperty)
-        Q_ASSERT(instr.args + instr.argc <= stackSize);
         TRACE(args, "starting at %d, length %d", instr.args, instr.argc);
-        QV4::Value *args = stack + instr.args;
-        __qmljs_call_activation_property(context, VALUEPTR(instr.result), runtimeStrings[instr.name], args, instr.argc);
+        Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+        QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
+        callData->tag = 0;
+        callData->argc = instr.argc;
+        callData->thisObject = QV4::Value::undefinedValue();
+        __qmljs_call_activation_property(context, VALUEPTR(instr.result), runtimeStrings[instr.name], callData);
     MOTH_END_INSTR(CallActivationProperty)
 
     MOTH_BEGIN_INSTR(CallBuiltinThrow)
@@ -485,22 +497,31 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
     MOTH_END_INSTR(CallBuiltinSetupArgumentsObject)
 
     MOTH_BEGIN_INSTR(CreateValue)
-        Q_ASSERT(instr.args + instr.argc <= stackSize);
-        QV4::Value *args = stack + instr.args;
-        __qmljs_construct_value(context, VALUEPTR(instr.result), VALUE(instr.func), args, instr.argc);
+        Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+        QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
+        callData->tag = 0;
+        callData->argc = instr.argc;
+        callData->thisObject = QV4::Value::undefinedValue();
+        __qmljs_construct_value(context, VALUEPTR(instr.result), VALUE(instr.func), callData);
     MOTH_END_INSTR(CreateValue)
 
     MOTH_BEGIN_INSTR(CreateProperty)
-        Q_ASSERT(instr.args + instr.argc <= stackSize);
-        QV4::Value *args = stack + instr.args;
-        __qmljs_construct_property(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.name], args, instr.argc);
+        Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+        QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
+        callData->tag = 0;
+        callData->argc = instr.argc;
+        callData->thisObject = QV4::Value::undefinedValue();
+        __qmljs_construct_property(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.name], callData);
     MOTH_END_INSTR(CreateProperty)
 
     MOTH_BEGIN_INSTR(CreateActivationProperty)
         TRACE(inline, "property name = %s, args = %d, argc = %d", instr.name->toQString().toUtf8().constData(), instr.args, instr.argc);
-        Q_ASSERT(instr.args + instr.argc <= stackSize);
-        QV4::Value *args = stack + instr.args;
-        __qmljs_construct_activation_property(context, VALUEPTR(instr.result), runtimeStrings[instr.name], args, instr.argc);
+        Q_ASSERT(instr.callData + instr.argc + offsetof(QV4::CallData, args)/sizeof(QV4::Value) <= stackSize);
+        QV4::CallData *callData = reinterpret_cast<QV4::CallData *>(stack + instr.callData);
+        callData->tag = 0;
+        callData->argc = instr.argc;
+        callData->thisObject = QV4::Value::undefinedValue();
+        __qmljs_construct_activation_property(context, VALUEPTR(instr.result), runtimeStrings[instr.name], callData);
     MOTH_END_INSTR(CreateActivationProperty)
 
     MOTH_BEGIN_INSTR(Jump)