diff options
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 14 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm.cpp | 87 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_masm_p.h | 21 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth.cpp | 46 | ||||
-rw-r--r-- | src/qml/compiler/qv4isel_moth_p.h | 9 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4object.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 134 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime_p.h | 20 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4scopedvalue_p.h | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4sparsearray.cpp | 18 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 65 |
11 files changed, 232 insertions, 190 deletions
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 8164e439f0..68bc109eb4 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -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 { diff --git a/src/qml/compiler/qv4isel_masm.cpp b/src/qml/compiler/qv4isel_masm.cpp index a0462d927f..6850f413e0 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -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(); diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h index 58d37208b9..1119c433a3 100644 --- a/src/qml/compiler/qv4isel_masm_p.h +++ b/src/qml/compiler/qv4isel_masm_p.h @@ -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); diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index 3e7b1911e9..1546f19ec8 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -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); } diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h index 43e792ccc7..826d559dbc 100644 --- a/src/qml/compiler/qv4isel_moth_p.h +++ b/src/qml/compiler/qv4isel_moth_p.h @@ -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); diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index c99b48191a..fbee25e68b 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -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; diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 649baaf441..ca6540b920 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -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) diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index b38f833ad0..c52a79e2f5 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -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); diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 4218065768..5998fd92a1 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -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; } diff --git a/src/qml/jsruntime/qv4sparsearray.cpp b/src/qml/jsruntime/qv4sparsearray.cpp index 835a0d004f..5b720d2fef 100644 --- a/src/qml/jsruntime/qv4sparsearray.cpp +++ b/src/qml/jsruntime/qv4sparsearray.cpp @@ -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(); } diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 10f09a8c82..5fef202cc6 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -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) |