diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2013-09-11 19:05:24 +0200 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@digia.com> | 2013-09-11 19:08:28 +0200 |
commit | 89402e0ef69da3c954a540510e8b4e8501bc1ce3 (patch) | |
tree | cf97d95e1ac837e5d439f2be9125e0a104b5bbce /src/qml | |
parent | 0cce947449fa502fd4bf2aec95fa490c8417cdeb (diff) | |
parent | 262d7261033df7650938c38401112a4767d926ff (diff) |
Merge branch 'dev' of qtdeclarative into wip/v4
Conflicts:
src/qml/jsruntime/qv4script.cpp
Change-Id: I20136cab29d86862b5bd9208003200bc24bcdacf
Diffstat (limited to 'src/qml')
78 files changed, 2048 insertions, 1422 deletions
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 404039d4e4..cdcc407e2a 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -57,7 +57,7 @@ namespace CompiledData { namespace { bool functionSortHelper(QV4::Function *lhs, QV4::Function *rhs) { - return reinterpret_cast<quintptr>(lhs->code) < reinterpret_cast<quintptr>(rhs->code); + return reinterpret_cast<quintptr>(lhs->codePtr) < reinterpret_cast<quintptr>(rhs->codePtr); } } 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 cefc053ac4..19c7039e69 100644 --- a/src/qml/compiler/qv4isel_masm.cpp +++ b/src/qml/compiler/qv4isel_masm.cpp @@ -68,7 +68,7 @@ using namespace QV4; CompilationUnit::~CompilationUnit() { foreach (Function *f, runtimeFunctions) - engine->allFunctions.remove(reinterpret_cast<quintptr>(f->code)); + engine->allFunctions.remove(reinterpret_cast<quintptr>(f->codePtr)); UnwindHelper::deregisterFunctions(runtimeFunctions); } @@ -87,7 +87,7 @@ void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine) UnwindHelper::registerFunctions(runtimeFunctions); foreach (Function *f, runtimeFunctions) - engine->allFunctions.insert(reinterpret_cast<quintptr>(f->code), f); + engine->allFunctions.insert(reinterpret_cast<quintptr>(f->codePtr), f); } QV4::ExecutableAllocator::ChunkOfPages *CompilationUnit::chunkForFunction(int functionIndex) @@ -341,7 +341,7 @@ void Assembler::storeValue(QV4::Value value, V4IR::Temp* destination) storeValue(value, addr); } -void Assembler::enterStandardStackFrame(bool withLocals) +void Assembler::enterStandardStackFrame() { platformEnterStandardStackFrame(); @@ -350,23 +350,22 @@ void Assembler::enterStandardStackFrame(bool withLocals) push(StackFrameRegister); move(StackPointerRegister, StackFrameRegister); - int frameSize = _stackLayout.calculateStackFrameSize(withLocals); + int frameSize = _stackLayout.calculateStackFrameSize(); subPtr(TrustedImm32(frameSize), StackPointerRegister); for (int i = 0; i < calleeSavedRegisterCount; ++i) storePtr(calleeSavedRegisters[i], Address(StackFrameRegister, -(i + 1) * sizeof(void*))); - move(StackFrameRegister, LocalsRegister); } -void Assembler::leaveStandardStackFrame(bool withLocals) +void Assembler::leaveStandardStackFrame() { // restore the callee saved registers for (int i = calleeSavedRegisterCount - 1; i >= 0; --i) loadPtr(Address(StackFrameRegister, -(i + 1) * sizeof(void*)), calleeSavedRegisters[i]); - int frameSize = _stackLayout.calculateStackFrameSize(withLocals); + int frameSize = _stackLayout.calculateStackFrameSize(); // Work around bug in ARMv7Assembler.h where add32(imm, sp, sp) doesn't // work well for large immediates. #if CPU(ARM_THUMB2) @@ -625,7 +624,7 @@ void InstructionSelection::run(V4IR::Function *function) Assembler* oldAssembler = _as; _as = new Assembler(this, _function, executableAllocator, 6); // 6 == max argc for calls to built-ins with an argument array - _as->enterStandardStackFrame(/*withLocals*/true); + _as->enterStandardStackFrame(); int contextPointer = 0; #if !defined(RETURN_VALUE_IN_REGISTER) @@ -641,13 +640,19 @@ void InstructionSelection::run(V4IR::Function *function) _as->loadPtr(addressForArgument(contextPointer), Assembler::ContextRegister); #endif + const int locals = _as->stackLayout().calculateJSStackFrameSize(); + _as->loadPtr(Address(Assembler::ContextRegister, offsetof(ExecutionContext, engine)), Assembler::ScratchRegister); + _as->loadPtr(Address(Assembler::ScratchRegister, offsetof(ExecutionEngine, jsStackTop)), Assembler::LocalsRegister); + _as->addPtr(Assembler::TrustedImm32(sizeof(QV4::Value)*locals), Assembler::LocalsRegister); + _as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, offsetof(ExecutionEngine, jsStackTop))); + for (int i = 0, ei = _function->basicBlocks.size(); i != ei; ++i) { V4IR::BasicBlock *nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0; _block = _function->basicBlocks[i]; _as->registerBlock(_block, nextBlock); if (_reentryBlocks.contains(_block)) { - _as->enterStandardStackFrame(/*locals*/false); + _as->enterStandardStackFrame(); #ifdef ARGUMENTS_IN_REGISTERS _as->move(Assembler::registerForArgument(0), Assembler::ContextRegister); _as->move(Assembler::registerForArgument(1), Assembler::LocalsRegister); @@ -694,21 +699,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()); } } @@ -829,16 +832,21 @@ static void *tryWrapper(ExecutionContext *context, void *localsPtr, MiddleOfFunc { *exceptionVar = Value::undefinedValue(); void *addressToContinueAt = 0; + Value *jsStackTop = context->engine->jsStackTop; try { addressToContinueAt = tryBody(context, localsPtr); } catch (Exception& ex) { + context->engine->jsStackTop = jsStackTop; ex.accept(context); *exceptionVar = ex.value(); try { - ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(exceptionVarName, ex.value(), context); + QV4::ValueScope scope(context); + QV4::ScopedValue exception(scope, ex.value()); + ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(exceptionVarName, exception, context); addressToContinueAt = catchBody(catchContext, localsPtr); context = __qmljs_builtin_pop_scope(catchContext); } catch (Exception& ex) { + context->engine->jsStackTop = jsStackTop; *exceptionVar = ex.value(); ex.accept(context); addressToContinueAt = catchBody(context, localsPtr); @@ -867,7 +875,7 @@ void InstructionSelection::callBuiltinFinishTry() // This assumes that we're in code that was called by tryWrapper, so we return to try wrapper // with the address that we'd like to continue at, which is right after the ret below. Assembler::DataLabelPtr continuation = _as->moveWithPatch(Assembler::TrustedImmPtr(0), Assembler::ReturnValueRegister); - _as->leaveStandardStackFrame(/*locals*/false); + _as->leaveStandardStackFrame(); _as->ret(); _as->addPatch(continuation, _as->label()); } @@ -976,11 +984,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) @@ -1333,19 +1340,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()); } } @@ -1354,11 +1361,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) @@ -1559,35 +1565,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) @@ -1740,7 +1752,12 @@ void InstructionSelection::visitRet(V4IR::Ret *s) Q_UNUSED(s); } - _as->leaveStandardStackFrame(/*withLocals*/true); + const int locals = _as->stackLayout().calculateJSStackFrameSize(); + _as->subPtr(Assembler::TrustedImm32(sizeof(QV4::Value)*locals), Assembler::LocalsRegister); + _as->loadPtr(Address(Assembler::ContextRegister, offsetof(ExecutionContext, engine)), Assembler::ScratchRegister); + _as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, offsetof(ExecutionEngine, jsStackTop))); + + _as->leaveStandardStackFrame(); #if !defined(ARGUMENTS_IN_REGISTERS) && !defined(RETURN_VALUE_IN_REGISTER) // Emulate ret(n) instruction // Pop off return address into scratch register ... @@ -1769,17 +1786,33 @@ int InstructionSelection::prepareVariableArguments(V4IR::ExprList* args) return argc; } -void InstructionSelection::callRuntimeMethodImp(V4IR::Temp *result, const char* name, ActivationMethod method, V4IR::Expr *base, V4IR::ExprList *args) +int InstructionSelection::prepareCallData(V4IR::ExprList* args, V4IR::Expr *thisObject) { - V4IR::Name *baseName = base->asName(); - assert(baseName != 0); + 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 argc = prepareVariableArguments(args); - _as->generateFunctionCallImp(Assembler::Void, name, method, Assembler::ContextRegister, Assembler::PointerToValue(result), - Assembler::PointerToString(*baseName->id), baseAddressForCallArguments(), - Assembler::TrustedImm32(argc)); + 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; } + QT_BEGIN_NAMESPACE namespace QV4 { bool operator==(const Value &v1, const Value &v2) diff --git a/src/qml/compiler/qv4isel_masm_p.h b/src/qml/compiler/qv4isel_masm_p.h index 588e26a566..ec6780a6f3 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) { @@ -289,15 +289,13 @@ public: #endif } - int calculateStackFrameSize(bool withLocals) const + int calculateStackFrameSize() const { const int stackSpaceAllocatedOtherwise = StackSpaceAllocatedUponFunctionEntry + RegisterSize; // saved StackFrameRegister - const int locals = withLocals ? (maxOutgoingArgumentCount + localCount + savedConstCount) : 0; - - // space for the locals and the callee saved registers - int frameSize = locals * sizeof(QV4::Value) + RegisterSize * calleeSavedRegisterCount; + // space for the callee saved registers + int frameSize = RegisterSize * (calleeSavedRegisterCount + savedConstCount); frameSize = WTF::roundUpToMultipleOf(StackAlignment, frameSize + stackSpaceAllocatedOtherwise); frameSize -= stackSpaceAllocatedOtherwise; @@ -305,12 +303,19 @@ public: return frameSize; } + int calculateJSStackFrameSize() const + { + const int locals = (localCount + sizeof(QV4::CallData)/sizeof(QV4::Value) - 1 + maxOutgoingArgumentCount) + 1; + int frameSize = locals * sizeof(QV4::Value); + return frameSize; + } + Address stackSlotPointer(int idx) const { 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; } @@ -323,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 @@ -431,6 +439,38 @@ public: return Pointer(_stackLayout.stackSlotPointer(t->index)); } + template <int argumentNumber> + void saveOutRegister(PointerToValue arg) + { + if (!arg.value) + return; + if (V4IR::Temp *t = arg.value->asTemp()) { + if (t->kind == V4IR::Temp::PhysicalRegister) { + Pointer addr(_stackLayout.savedRegPointer(argumentNumber)); + switch (t->type) { + case V4IR::BoolType: + storeBool((RegisterID) t->index, addr); + break; + case V4IR::SInt32Type: + storeInt32((RegisterID) t->index, addr); + break; + case V4IR::UInt32Type: + storeUInt32((RegisterID) t->index, addr); + break; + case V4IR::DoubleType: + storeDouble((FPRegisterID) t->index, addr); + break; + default: + Q_UNIMPLEMENTED(); + } + } + } + } + + template <int, typename ArgType> + void saveOutRegister(ArgType) + {} + void loadArgumentInRegister(RegisterID source, RegisterID dest, int argumentNumber) { Q_UNUSED(argumentNumber); @@ -684,8 +724,8 @@ public: void storeValue(QV4::Value value, V4IR::Temp* temp); - void enterStandardStackFrame(bool withLocals); - void leaveStandardStackFrame(bool withLocals); + void enterStandardStackFrame(); + void leaveStandardStackFrame(); template <int argumentNumber, typename T> void loadArgumentOnStackOrRegister(const T &value) @@ -747,6 +787,15 @@ public: sub32(TrustedImm32(stackSpaceNeeded), StackPointerRegister); } + // First save any arguments that reside in registers, because they could be overwritten + // if that register is also used to pass arguments. + saveOutRegister<5>(arg6); + saveOutRegister<4>(arg5); + saveOutRegister<3>(arg4); + saveOutRegister<2>(arg3); + saveOutRegister<1>(arg2); + saveOutRegister<0>(arg1); + loadArgumentOnStackOrRegister<5>(arg6); loadArgumentOnStackOrRegister<4>(arg5); loadArgumentOnStackOrRegister<3>(arg4); @@ -967,25 +1016,8 @@ public: if (t->kind != V4IR::Temp::PhysicalRegister) return loadTempAddress(tmpReg, t); - Pointer addr(_stackLayout.savedRegPointer(offset)); - switch (t->type) { - case V4IR::BoolType: - storeBool((RegisterID) t->index, addr); - break; - case V4IR::SInt32Type: - storeInt32((RegisterID) t->index, addr); - break; - case V4IR::UInt32Type: - storeUInt32((RegisterID) t->index, addr); - break; - case V4IR::DoubleType: - storeDouble((FPRegisterID) t->index, addr); - break; - default: - Q_UNIMPLEMENTED(); - } - return addr; + return Pointer(_stackLayout.savedRegPointer(offset)); } void storeBool(RegisterID reg, Pointer addr) @@ -1226,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); @@ -1300,11 +1337,7 @@ private: _as->generateFunctionCallImp(t, isel_stringIfy(function), function, __VA_ARGS__) int prepareVariableArguments(V4IR::ExprList* args); - - 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); -#define callRuntimeMethod(result, function, ...) \ - callRuntimeMethodImp(result, isel_stringIfy(function), function, __VA_ARGS__) + int prepareCallData(V4IR::ExprList* args, V4IR::Expr *thisObject); template <typename Arg1, typename Arg2> void generateLookupCall(uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2) diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp index d4dc5460b7..67433070f6 100644 --- a/src/qml/compiler/qv4isel_moth.cpp +++ b/src/qml/compiler/qv4isel_moth.cpp @@ -310,7 +310,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); @@ -323,7 +324,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); } @@ -335,7 +337,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); } @@ -358,7 +361,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); } @@ -368,7 +372,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); } @@ -377,7 +382,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); } @@ -666,23 +672,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); @@ -692,9 +690,6 @@ void InstructionSelection::prepareCallArgs(V4IR::ExprList *e, quint32 &argc, qui ++argc; e = e->next; } - } else { - argc = 0; - args = 0; } } @@ -762,7 +757,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); } @@ -979,7 +975,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 c33c58b627..cf7d1f43e9 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/compiler/qv4isel_util_p.h b/src/qml/compiler/qv4isel_util_p.h index 2e3b64c360..610988ce0c 100644 --- a/src/qml/compiler/qv4isel_util_p.h +++ b/src/qml/compiler/qv4isel_util_p.h @@ -91,6 +91,8 @@ inline QV4::Value convertToValue(V4IR::Const *c) default: Q_UNREACHABLE(); } + // unreachable, but the function must return something + return QV4::Value::undefinedValue(); } } // namespace QQmlJS diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h index 1e046b83e3..12f69ac92e 100644 --- a/src/qml/compiler/qv4jsir_p.h +++ b/src/qml/compiler/qv4jsir_p.h @@ -183,6 +183,12 @@ enum Type { StringType = 1 << 7, ObjectType = 1 << 8 }; + +inline bool strictlyEqualTypes(Type t1, Type t2) +{ + return t1 == t2 || ((t1 & NumberType) && (t2 & NumberType)); +} + QString typeName(Type t); struct ExprVisitor { diff --git a/src/qml/compiler/qv4regalloc.cpp b/src/qml/compiler/qv4regalloc.cpp index f82a5fcf1c..1c8bb66fc1 100644 --- a/src/qml/compiler/qv4regalloc.cpp +++ b/src/qml/compiler/qv4regalloc.cpp @@ -307,7 +307,6 @@ protected: // IRDecoder virtual void loadThisObject(V4IR::Temp *temp) { addDef(temp); - addCall(); // FIXME: propagate this } virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp) @@ -813,8 +812,8 @@ private: foreach (const Move &m, _moves) if (m.needsSwap) ++swapCount; -#endif Q_ASSERT(output.size() == _moves.size() + swapCount); +#endif } #ifdef DEBUG_REGALLOC diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp index 0b663288ab..528450b73e 100644 --- a/src/qml/compiler/qv4ssa.cpp +++ b/src/qml/compiler/qv4ssa.cpp @@ -1419,11 +1419,28 @@ protected: _ty.fullyTyped &= ty.fullyTyped; } - // TODO: check & double check the next condition! - if (_ty.type & ObjectType || _ty.type & UndefinedType || _ty.type & NullType) - _ty.type = ObjectType; - else if (_ty.type & NumberType) - _ty.type = DoubleType; + switch (_ty.type) { + case UndefinedType: + case NullType: + case BoolType: + case SInt32Type: + case UInt32Type: + case DoubleType: + case StringType: + case ObjectType: + // The type is not a combination of two or more types, so we're done. + break; + + default: + // There are multiple types involved, so: + if ((_ty.type & NumberType) && !(_ty.type & ~NumberType)) + // The type is any combination of double/int32/uint32, but nothing else. So we can + // type it as double. + _ty.type = DoubleType; + else + // There just is no single type that can hold this combination, so: + _ty.type = ObjectType; + } setType(s->targetTemp, _ty.type); } @@ -2083,6 +2100,67 @@ void purgeBB(BasicBlock *bb, Function *func, DefUsesCalculator &defUses, QVector delete bb; } } + +bool tryOptimizingComparison(Expr *&expr) +{ + Binop *b = expr->asBinop(); + if (!b) + return false; + Const *leftConst = b->left->asConst(); + if (!leftConst || leftConst->type == StringType || leftConst->type == ObjectType) + return false; + Const *rightConst = b->right->asConst(); + if (!rightConst || rightConst->type == StringType || rightConst->type == ObjectType) + return false; + + QV4::Value l = convertToValue(leftConst); + QV4::Value r = convertToValue(rightConst); + + switch (b->op) { + case OpGt: + leftConst->value = __qmljs_cmp_gt(&l, &r); + leftConst->type = BoolType; + expr = leftConst; + return true; + case OpLt: + leftConst->value = __qmljs_cmp_lt(&l, &r); + leftConst->type = BoolType; + expr = leftConst; + return true; + case OpGe: + leftConst->value = __qmljs_cmp_ge(&l, &r); + leftConst->type = BoolType; + expr = leftConst; + return true; + case OpLe: + leftConst->value = __qmljs_cmp_le(&l, &r); + leftConst->type = BoolType; + expr = leftConst; + return true; + case OpStrictEqual: + if (!strictlyEqualTypes(leftConst->type, rightConst->type)) + return false; + // intentional fall-through + case OpEqual: + leftConst->value = __qmljs_cmp_eq(&l, &r); + leftConst->type = BoolType; + expr = leftConst; + return true; + case OpStrictNotEqual: + if (!strictlyEqualTypes(leftConst->type, rightConst->type)) + return false; + // intentional fall-through + case OpNotEqual: + leftConst->value = __qmljs_cmp_ne(&l, &r); + leftConst->type = BoolType; + expr = leftConst; + return true; + default: + break; + } + + return false; +} } // anonymous namespace void optimizeSSA(Function *function, DefUsesCalculator &defUses) @@ -2229,7 +2307,61 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses) continue; } - // TODO: Constant binary expression evaluation + if (Binop *b = m->source->asBinop()) { + // TODO: More constant binary expression evaluation + // TODO: If the result of the move is only used in one single cjump, then + // inline the binop into the cjump. + Const *leftConst = b->left->asConst(); + if (!leftConst || leftConst->type == StringType || leftConst->type == ObjectType) + continue; + Const *rightConst = b->right->asConst(); + if (!rightConst || rightConst->type == StringType || rightConst->type == ObjectType) + continue; + + QV4::Value lc = convertToValue(leftConst); + QV4::Value rc = convertToValue(rightConst); + double l = __qmljs_to_number(&lc); + double r = __qmljs_to_number(&rc); + + switch (b->op) { + case OpMul: + leftConst->value = l * r; + leftConst->type = DoubleType; + m->source = leftConst; + W += m; + break; + case OpAdd: + leftConst->value = l + r; + leftConst->type = DoubleType; + m->source = leftConst; + W += m; + break; + case OpSub: + leftConst->value = l - r; + leftConst->type = DoubleType; + m->source = leftConst; + W += m; + break; + case OpDiv: + leftConst->value = l / r; + leftConst->type = DoubleType; + m->source = leftConst; + W += m; + break; + case OpMod: + leftConst->value = std::fmod(l, r); + leftConst->type = DoubleType; + m->source = leftConst; + W += m; + break; + default: + if (tryOptimizingComparison(m->source)) + W += m; + break; + } + + continue; + } } } else if (CJump *cjump = s->asCJump()) { if (Const *c = cjump->cond->asConst()) { @@ -2246,9 +2378,12 @@ void optimizeSSA(Function *function, DefUsesCalculator &defUses) *ref[s] = jump; continue; + } else if (cjump->cond->asBinop()) { + if (tryOptimizingComparison(cjump->cond)) + W += cjump; + continue; } // TODO: Constant unary expression evaluation - // TODO: Constant binary expression evaluation } } @@ -2580,9 +2715,10 @@ void Optimizer::run() // showMeTheCode(function); + static bool doSSA = /*qgetenv("QV4_NO_SSA").isEmpty();*/ false; static bool doOpt = qgetenv("QV4_NO_OPT").isEmpty(); - if (!function->hasTry && !function->hasWith && doOpt) { + if (!function->hasTry && !function->hasWith && doSSA) { // qout << "Starting edge splitting..." << endl; splitCriticalEdges(function); // showMeTheCode(function); @@ -2605,9 +2741,11 @@ void Optimizer::run() DeadCodeElimination(defUses, function).run(); // showMeTheCode(function); -// qout << "Running SSA optimization..." << endl; - optimizeSSA(function, defUses); -// showMeTheCode(function); + if (doOpt) { +// qout << "Running SSA optimization..." << endl; + optimizeSSA(function, defUses); +// showMeTheCode(function); + } // qout << "Running type inference..." << endl; TypeInference(defUses).run(function); diff --git a/src/qml/jsapi/qjsvalue.cpp b/src/qml/jsapi/qjsvalue.cpp index b737ee0073..f18814cedf 100644 --- a/src/qml/jsapi/qjsvalue.cpp +++ b/src/qml/jsapi/qjsvalue.cpp @@ -55,6 +55,7 @@ #include "private/qv8engine_p.h" #include <private/qv4mm_p.h> #include <private/qv4exception_p.h> +#include <private/qv4scopedvalue_p.h> QV4::Value QJSValuePrivate::getValue(QV4::ExecutionEngine *e) { @@ -505,20 +506,20 @@ QJSValue QJSValue::call(const QJSValueList &args) ExecutionEngine *engine = d->engine; assert(engine); - CALLDATA(args.length()); - d.thisObject = Value::fromObject(engine->globalObject); + ScopedCallData callData(engine, args.length()); + callData->thisObject = Value::fromObject(engine->globalObject); for (int i = 0; i < args.size(); ++i) { if (!args.at(i).d->checkEngine(engine)) { qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine"); return QJSValue(); } - d.args[i] = args.at(i).d->getValue(engine); + callData->args[i] = args.at(i).d->getValue(engine); } Value result; QV4::ExecutionContext *ctx = engine->current; try { - result = f->call(d); + result = f->call(callData); } catch (Exception &e) { e.accept(ctx); result = e.value(); @@ -561,20 +562,20 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList return QJSValue(); } - CALLDATA(args.size()); - d.thisObject = instance.d->getValue(engine); + ScopedCallData callData(engine, args.size()); + callData->thisObject = instance.d->getValue(engine); for (int i = 0; i < args.size(); ++i) { if (!args.at(i).d->checkEngine(engine)) { qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine"); return QJSValue(); } - d.args[i] = args.at(i).d->getValue(engine); + callData->args[i] = args.at(i).d->getValue(engine); } Value result; QV4::ExecutionContext *ctx = engine->current; try { - result = f->call(d); + result = f->call(callData); } catch (Exception &e) { e.accept(ctx); result = e.value(); @@ -610,19 +611,19 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args) ExecutionEngine *engine = d->engine; assert(engine); - CALLDATA(args.size()); + ScopedCallData callData(engine, args.size()); for (int i = 0; i < args.size(); ++i) { if (!args.at(i).d->checkEngine(engine)) { qWarning("QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine"); return QJSValue(); } - d.args[i] = args.at(i).d->getValue(engine); + callData->args[i] = args.at(i).d->getValue(engine); } Value result; QV4::ExecutionContext *ctx = engine->current; try { - result = f->construct(d); + result = f->construct(callData); } catch (Exception &e) { e.accept(ctx); result = e.value(); @@ -742,7 +743,7 @@ QJSValue& QJSValue::operator=(const QJSValue& other) */ bool QJSValue::equals(const QJSValue& other) const { - return __qmljs_cmp_eq(d->value, other.d->value); + return __qmljs_cmp_eq(QV4::ValueRef(d), QV4::ValueRef(other.d)); } /*! @@ -769,7 +770,7 @@ bool QJSValue::equals(const QJSValue& other) const */ bool QJSValue::strictlyEquals(const QJSValue& other) const { - return __qmljs_strict_equal(d->value, other.d->value); + return __qmljs_strict_equal(QV4::ValueRef(d), QV4::ValueRef(other.d)); } /*! diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index 9a1325b58a..c504f750e9 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -90,6 +90,7 @@ HEADERS += \ $$PWD/qv4unwindhelper_arm_p.h \ $$PWD/qv4serialize_p.h \ $$PWD/qv4script_p.h \ + $$PWD/qv4scopedvalue_p.h \ $$PWD/qv4util_p.h \ $$PWD/qv4executableallocator_p.h \ $$PWD/qv4sequenceobject_p.h \ diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp index 7ac74c1197..5a53c0fc3e 100644 --- a/src/qml/jsruntime/qv4argumentsobject.cpp +++ b/src/qml/jsruntime/qv4argumentsobject.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include <qv4argumentsobject_p.h> #include <qv4alloca_p.h> +#include <qv4scopedvalue_p.h> using namespace QV4; @@ -129,10 +130,10 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const if (isMapped && attrs.isData()) { if (!attrs.isGeneric()) { - CALLDATA(1); - d.thisObject = Value::fromObject(this); - d.args[0] = desc.value; - map.setter()->call(d); + ScopedCallData callData(ctx->engine, 1); + callData->thisObject = Value::fromObject(this); + callData->args[0] = desc.value; + map.setter()->call(callData); } if (attrs.isWritable()) { *pd = map; @@ -147,10 +148,10 @@ bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const DEFINE_MANAGED_VTABLE(ArgumentsGetterFunction); -Value ArgumentsGetterFunction::call(Managed *getter, const CallData &d) +Value ArgumentsGetterFunction::call(Managed *getter, CallData *callData) { ArgumentsGetterFunction *g = static_cast<ArgumentsGetterFunction *>(getter); - Object *that = d.thisObject.asObject(); + Object *that = callData->thisObject.asObject(); if (!that) getter->engine()->current->throwTypeError(); ArgumentsObject *o = that->asArgumentsObject(); @@ -163,10 +164,10 @@ Value ArgumentsGetterFunction::call(Managed *getter, const CallData &d) DEFINE_MANAGED_VTABLE(ArgumentsSetterFunction); -Value ArgumentsSetterFunction::call(Managed *setter, const CallData &d) +Value ArgumentsSetterFunction::call(Managed *setter, CallData *callData) { ArgumentsSetterFunction *s = static_cast<ArgumentsSetterFunction *>(setter); - Object *that = d.thisObject.asObject(); + Object *that = callData->thisObject.asObject(); if (!that) setter->engine()->current->throwTypeError(); ArgumentsObject *o = that->asArgumentsObject(); @@ -174,7 +175,7 @@ Value ArgumentsSetterFunction::call(Managed *setter, const CallData &d) setter->engine()->current->throwTypeError(); assert(s->index < o->context->argumentCount); - o->context->arguments[s->index] = d.argc ? d.args[0] : Value::undefinedValue(); + o->context->arguments[s->index] = callData->argc ? callData->args[0] : Value::undefinedValue(); return Value::undefinedValue(); } diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h index f48db1f2e6..66ee22c953 100644 --- a/src/qml/jsruntime/qv4argumentsobject_p.h +++ b/src/qml/jsruntime/qv4argumentsobject_p.h @@ -55,7 +55,7 @@ struct ArgumentsGetterFunction: FunctionObject ArgumentsGetterFunction(ExecutionContext *scope, uint index) : FunctionObject(scope), index(index) { vtbl = &static_vtbl; } - static Value call(Managed *that, const CallData &d); + static Value call(Managed *that, CallData *d); protected: static const ManagedVTable static_vtbl; @@ -68,7 +68,7 @@ struct ArgumentsSetterFunction: FunctionObject ArgumentsSetterFunction(ExecutionContext *scope, uint index) : FunctionObject(scope), index(index) { vtbl = &static_vtbl; } - static Value call(Managed *that, const CallData &d); + static Value call(Managed *that, CallData *callData); protected: static const ManagedVTable static_vtbl; diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp index 6fc661565d..e3b08f5941 100644 --- a/src/qml/jsruntime/qv4arrayobject.cpp +++ b/src/qml/jsruntime/qv4arrayobject.cpp @@ -42,6 +42,7 @@ #include "qv4arrayobject_p.h" #include "qv4sparsearray_p.h" #include "qv4objectproto_p.h" +#include "qv4scopedvalue_p.h" using namespace QV4; @@ -53,25 +54,25 @@ ArrayCtor::ArrayCtor(ExecutionContext *scope) vtbl = &static_vtbl; } -Value ArrayCtor::construct(Managed *m, const CallData &d) +Value ArrayCtor::construct(Managed *m, CallData *callData) { ExecutionEngine *v4 = m->engine(); ArrayObject *a = v4->newArrayObject(); uint len; - if (d.argc == 1 && d.args[0].isNumber()) { + if (callData->argc == 1 && callData->args[0].isNumber()) { bool ok; - len = d.args[0].asArrayLength(&ok); + len = callData->args[0].asArrayLength(&ok); if (!ok) - v4->current->throwRangeError(d.args[0]); + v4->current->throwRangeError(callData->args[0]); if (len < 0x1000) a->arrayReserve(len); } else { - len = d.argc; + len = callData->argc; a->arrayReserve(len); for (unsigned int i = 0; i < len; ++i) - a->arrayData[i].value = d.args[i]; + a->arrayData[i].value = callData->args[i]; a->arrayDataLen = len; } a->setArrayLengthUnchecked(len); @@ -79,9 +80,9 @@ Value ArrayCtor::construct(Managed *m, const CallData &d) return Value::fromObject(a); } -Value ArrayCtor::call(Managed *that, const CallData &d) +Value ArrayCtor::call(Managed *that, CallData *callData) { - return construct(that, d); + return construct(that, callData); } ArrayPrototype::ArrayPrototype(InternalClass *ic) @@ -137,8 +138,8 @@ Value ArrayPrototype::method_toString(SimpleCallContext *ctx) QV4::Object *o = ctx->thisObject.toObject(ctx); FunctionObject *f = o->get(ctx->engine->newString("join")).asFunctionObject(); if (f) { - CALLDATA(0); - d.thisObject = ctx->thisObject; + ScopedCallData d(ctx->engine, 0); + d->thisObject = ctx->thisObject; return f->call(d); } return ObjectPrototype::method_toString(ctx); @@ -545,12 +546,14 @@ Value ArrayPrototype::method_unshift(SimpleCallContext *ctx) Value ArrayPrototype::method_indexOf(SimpleCallContext *ctx) { + ValueScope scope(ctx); + Object *instance = ctx->thisObject.toObject(ctx); uint len = getLength(ctx, instance); if (!len) return Value::fromInt32(-1); - Value searchValue; + ScopedValue searchValue(scope); uint fromIndex = 0; if (ctx->argumentCount >= 1) @@ -568,9 +571,10 @@ Value ArrayPrototype::method_indexOf(SimpleCallContext *ctx) } if (instance->isStringObject()) { + ScopedValue v(scope); for (uint k = fromIndex; k < len; ++k) { bool exists; - Value v = instance->getIndexed(k, &exists); + v = instance->getIndexed(k, &exists); if (exists && __qmljs_strict_equal(v, searchValue)) return Value::fromDouble(k); } @@ -582,12 +586,14 @@ Value ArrayPrototype::method_indexOf(SimpleCallContext *ctx) Value ArrayPrototype::method_lastIndexOf(SimpleCallContext *ctx) { + ValueScope scope(ctx); + Object *instance = ctx->thisObject.toObject(ctx); uint len = getLength(ctx, instance); if (!len) return Value::fromInt32(-1); - Value searchValue; + ScopedValue searchValue(scope); uint fromIndex = len; if (ctx->argumentCount >= 1) @@ -607,10 +613,11 @@ Value ArrayPrototype::method_lastIndexOf(SimpleCallContext *ctx) fromIndex = (uint) f + 1; } + ScopedValue v(scope); for (uint k = fromIndex; k > 0;) { --k; bool exists; - Value v = instance->getIndexed(k, &exists); + v = instance->getIndexed(k, &exists); if (exists && __qmljs_strict_equal(v, searchValue)) return Value::fromDouble(k); } @@ -636,12 +643,12 @@ Value ArrayPrototype::method_every(SimpleCallContext *ctx) if (!exists) continue; - CALLDATA(3); - d.args[0] = v; - d.args[1] = Value::fromDouble(k); - d.args[2] = Value::fromObject(instance); - d.thisObject = thisArg; - Value r = callback->call(d); + ScopedCallData callData(ctx->engine, 3); + callData->args[0] = v; + callData->args[1] = Value::fromDouble(k); + callData->args[2] = Value::fromObject(instance); + callData->thisObject = thisArg; + Value r = callback->call(callData); ok = r.toBoolean(); } return Value::fromBoolean(ok); @@ -665,12 +672,12 @@ Value ArrayPrototype::method_some(SimpleCallContext *ctx) if (!exists) continue; - CALLDATA(3); - d.args[0] = v; - d.args[1] = Value::fromDouble(k); - d.args[2] = Value::fromObject(instance); - d.thisObject = thisArg; - Value r = callback->call(d); + ScopedCallData callData(ctx->engine, 3); + callData->thisObject = thisArg; + callData->args[0] = v; + callData->args[1] = Value::fromDouble(k); + callData->args[2] = Value::fromObject(instance); + Value r = callback->call(callData); if (r.toBoolean()) return Value::fromBoolean(true); } @@ -695,12 +702,12 @@ Value ArrayPrototype::method_forEach(SimpleCallContext *ctx) if (!exists) continue; - CALLDATA(3); - d.args[0] = v; - d.args[1] = Value::fromDouble(k); - d.args[2] = Value::fromObject(instance); - d.thisObject = thisArg; - callback->call(d); + ScopedCallData callData(ctx->engine, 3); + callData->thisObject = thisArg; + callData->args[0] = v; + callData->args[1] = Value::fromDouble(k); + callData->args[2] = Value::fromObject(instance); + callback->call(callData); } return Value::undefinedValue(); } @@ -727,12 +734,12 @@ Value ArrayPrototype::method_map(SimpleCallContext *ctx) if (!exists) continue; - CALLDATA(3); - d.args[0] = v; - d.args[1] = Value::fromDouble(k); - d.args[2] = Value::fromObject(instance); - d.thisObject = thisArg; - Value mapped = callback->call(d); + ScopedCallData callData(ctx->engine, 3); + callData->thisObject = thisArg; + callData->args[0] = v; + callData->args[1] = Value::fromDouble(k); + callData->args[2] = Value::fromObject(instance); + Value mapped = callback->call(callData); a->arraySet(k, mapped); } return Value::fromObject(a); @@ -760,12 +767,12 @@ Value ArrayPrototype::method_filter(SimpleCallContext *ctx) if (!exists) continue; - CALLDATA(3); - d.args[0] = v; - d.args[1] = Value::fromDouble(k); - d.args[2] = Value::fromObject(instance); - d.thisObject = thisArg; - Value selected = callback->call(d); + ScopedCallData callData(ctx->engine, 3); + callData->thisObject = thisArg; + callData->args[0] = v; + callData->args[1] = Value::fromDouble(k); + callData->args[2] = Value::fromObject(instance); + Value selected = callback->call(callData); if (selected.toBoolean()) { a->arraySet(to, v); ++to; @@ -804,13 +811,13 @@ Value ArrayPrototype::method_reduce(SimpleCallContext *ctx) bool kPresent; Value v = instance->getIndexed(k, &kPresent); if (kPresent) { - CALLDATA(4); - d.args[0] = acc; - d.args[1] = v; - d.args[2] = Value::fromDouble(k); - d.args[3] = Value::fromObject(instance); - d.thisObject = Value::undefinedValue(); - acc = callback->call(d); + ScopedCallData callData(ctx->engine, 4); + callData->thisObject = Value::undefinedValue(); + callData->args[0] = acc; + callData->args[1] = v; + callData->args[2] = Value::fromDouble(k); + callData->args[3] = Value::fromObject(instance); + acc = callback->call(callData); } ++k; } @@ -853,13 +860,13 @@ Value ArrayPrototype::method_reduceRight(SimpleCallContext *ctx) bool kPresent; Value v = instance->getIndexed(k - 1, &kPresent); if (kPresent) { - CALLDATA(4); - d.args[0] = acc; - d.args[1] = v; - d.args[2] = Value::fromDouble(k - 1); - d.args[3] = Value::fromObject(instance); - d.thisObject = Value::undefinedValue(); - acc = callback->call(d); + ScopedCallData callData(ctx->engine, 4); + callData->thisObject = Value::undefinedValue(); + callData->args[0] = acc; + callData->args[1] = v; + callData->args[2] = Value::fromDouble(k - 1); + callData->args[3] = Value::fromObject(instance); + acc = callback->call(callData); } --k; } diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h index 0d76542535..354ddd0380 100644 --- a/src/qml/jsruntime/qv4arrayobject_p.h +++ b/src/qml/jsruntime/qv4arrayobject_p.h @@ -53,8 +53,8 @@ struct ArrayCtor: FunctionObject { ArrayCtor(ExecutionContext *scope); - static Value construct(Managed *m, const CallData &d); - static Value call(Managed *that, const CallData &d); + static Value construct(Managed *m, CallData *callData); + static Value call(Managed *that, CallData *callData); protected: static const ManagedVTable static_vtbl; diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp index 25c105210a..6b77db3ca7 100644 --- a/src/qml/jsruntime/qv4booleanobject.cpp +++ b/src/qml/jsruntime/qv4booleanobject.cpp @@ -51,15 +51,15 @@ BooleanCtor::BooleanCtor(ExecutionContext *scope) vtbl = &static_vtbl; } -Value BooleanCtor::construct(Managed *m, const CallData &d) +Value BooleanCtor::construct(Managed *m, CallData *callData) { - bool n = d.argc ? d.args[0].toBoolean() : false; + bool n = callData->argc ? callData->args[0].toBoolean() : false; return Value::fromObject(m->engine()->newBooleanObject(Value::fromBoolean(n))); } -Value BooleanCtor::call(Managed *, const CallData &d) +Value BooleanCtor::call(Managed *, CallData *callData) { - bool value = d.argc ? d.args[0].toBoolean() : 0; + bool value = callData->argc ? callData->args[0].toBoolean() : 0; return Value::fromBoolean(value); } diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h index b55f82b76f..35ecf25b6f 100644 --- a/src/qml/jsruntime/qv4booleanobject_p.h +++ b/src/qml/jsruntime/qv4booleanobject_p.h @@ -53,8 +53,8 @@ struct BooleanCtor: FunctionObject { BooleanCtor(ExecutionContext *scope); - static Value construct(Managed *, const CallData &d); - static Value call(Managed *that, const CallData &d); + static Value construct(Managed *, CallData *callData); + static Value call(Managed *that, CallData *callData); protected: static const ManagedVTable static_vtbl; diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 29fdc333f8..1e42a186a0 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -51,7 +51,7 @@ using namespace QV4; -CallContext *ExecutionContext::newCallContext(void *stackSpace, FunctionObject *function, const CallData &d) +CallContext *ExecutionContext::newCallContext(void *stackSpace, FunctionObject *function, CallData *callData) { CallContext *c = (CallContext *)stackSpace; #ifndef QT_NO_DEBUG @@ -63,10 +63,11 @@ CallContext *ExecutionContext::newCallContext(void *stackSpace, FunctionObject * c->initBaseContext(Type_CallContext, engine, this); c->function = function; - c->arguments = d.args; - c->realArgumentCount = d.argc; - c->argumentCount = d.argc; - c->thisObject = d.thisObject; + // ### + c->arguments = const_cast<Value *>(callData->args); + c->realArgumentCount = callData->argc; + c->argumentCount = callData->argc; + c->thisObject = callData->thisObject; c->strictMode = function->strictMode; c->marked = false; @@ -89,30 +90,28 @@ CallContext *ExecutionContext::newCallContext(void *stackSpace, FunctionObject * if (function->varCount) std::fill(c->locals, c->locals + function->varCount, Value::undefinedValue()); - if (d.argc < function->formalParameterCount) { + if (callData->argc < function->formalParameterCount) { #ifndef QT_NO_DEBUG Q_ASSERT(function->formalParameterCount <= QV4::Global::ReservedArgumentCount); #endif - std::fill(c->arguments + d.argc, c->arguments + function->formalParameterCount, Value::undefinedValue()); + std::fill(c->arguments + callData->argc, c->arguments + function->formalParameterCount, Value::undefinedValue()); c->argumentCount = function->formalParameterCount; } return c; } -CallContext *ExecutionContext::newCallContext(FunctionObject *function, const CallData &d) +CallContext *ExecutionContext::newCallContext(FunctionObject *function, CallData *callData) { - CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocContext(requiredMemoryForExecutionContect(function, d.argc))); + CallContext *c = static_cast<CallContext *>(engine->memoryManager->allocContext(requiredMemoryForExecutionContect(function, callData->argc))); engine->current = c; c->initBaseContext(Type_CallContext, engine, this); c->function = function; - c->arguments = d.args; - c->realArgumentCount = d.argc; - c->argumentCount = d.argc; - c->thisObject = d.thisObject; + c->realArgumentCount = callData->argc; + c->thisObject = callData->thisObject; c->strictMode = function->strictMode; c->marked = false; @@ -135,12 +134,12 @@ CallContext *ExecutionContext::newCallContext(FunctionObject *function, const Ca if (function->varCount) std::fill(c->locals, c->locals + function->varCount, Value::undefinedValue()); - c->argumentCount = qMax((uint)d.argc, function->formalParameterCount); + c->argumentCount = qMax((uint)callData->argc, function->formalParameterCount); c->arguments = c->locals + function->varCount; - if (d.argc) - ::memcpy(c->arguments, d.args, c->realArgumentCount * sizeof(Value)); - if (d.argc < function->formalParameterCount) - std::fill(c->arguments + d.argc, c->arguments + function->formalParameterCount, Value::undefinedValue()); + if (callData->argc) + ::memcpy(c->arguments, callData->args, callData->argc * sizeof(Value)); + if (callData->argc < function->formalParameterCount) + std::fill(c->arguments + callData->argc, c->arguments + function->formalParameterCount, Value::undefinedValue()); return c; } @@ -595,18 +594,11 @@ Value ExecutionContext::getPropertyAndBase(String *name, Object **base) } - -void ExecutionContext::inplaceBitOp(String *name, const Value &value, BinOp op) -{ - Value lhs = getProperty(name); - Value result; - op(&result, lhs, value); - setProperty(name, result); -} - void ExecutionContext::throwError(const Value &value) { - __qmljs_throw(this, value); + ValueScope scope(this); + ScopedValue v(scope, value); + __qmljs_throw(this, v); } void ExecutionContext::throwError(const QString &message) diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h index 331c5aa990..fe10e33c5e 100644 --- a/src/qml/jsruntime/qv4context_p.h +++ b/src/qml/jsruntime/qv4context_p.h @@ -42,7 +42,8 @@ #define QMLJS_ENVIRONMENT_H #include "qv4global_p.h" -#include "qv4runtime_p.h" +#include "qv4value_def_p.h" +#include "qv4managed_p.h" QT_BEGIN_NAMESPACE @@ -52,6 +53,7 @@ struct Object; struct ExecutionEngine; struct DeclarativeEnvironment; struct Lookup; +struct Function; namespace CompiledData { struct CompilationUnit; @@ -114,8 +116,8 @@ struct Q_QML_EXPORT ExecutionContext interpreterInstructionPointer = 0; } - CallContext *newCallContext(void *stackSpace, FunctionObject *f, const CallData &d); - CallContext *newCallContext(FunctionObject *f, const CallData &d); + CallContext *newCallContext(void *stackSpace, FunctionObject *f, CallData *callData); + CallContext *newCallContext(FunctionObject *f, CallData *callData); WithContext *newWithContext(Object *with); CatchContext *newCatchContext(String* exceptionVarName, const QV4::Value &exceptionValue); CallContext *newQmlContext(FunctionObject *f, Object *qml); @@ -143,7 +145,6 @@ struct Q_QML_EXPORT ExecutionContext Value getProperty(String *name); Value getPropertyNoThrow(String *name); Value getPropertyAndBase(String *name, Object **base); - void inplaceBitOp(String *name, const QV4::Value &value, BinOp op); bool deleteProperty(String *name); inline Value argument(unsigned int index = 0); diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp index 9f25b8dc40..1ef4aec246 100644 --- a/src/qml/jsruntime/qv4dateobject.cpp +++ b/src/qml/jsruntime/qv4dateobject.cpp @@ -42,7 +42,7 @@ #include "qv4dateobject_p.h" #include "qv4objectproto_p.h" -#include "qv4mm_p.h" +#include "qv4scopedvalue_p.h" #include <QtCore/qnumeric.h> #include <QtCore/qmath.h> #include <QtCore/QDateTime> @@ -55,11 +55,6 @@ #include <time.h> #include <private/qqmljsengine_p.h> -#include <private/qqmljslexer_p.h> -#include <private/qqmljsparser_p.h> -#include <private/qqmljsast_p.h> -#include <qv4jsir_p.h> -#include <qv4codegen_p.h> #include <wtf/MathExtras.h> @@ -659,34 +654,35 @@ DateCtor::DateCtor(ExecutionContext *scope) vtbl = &static_vtbl; } -Value DateCtor::construct(Managed *m, const CallData &d) +Value DateCtor::construct(Managed *m, CallData *callData) { double t = 0; - if (d.argc == 0) + if (callData->argc == 0) t = currentTime(); - else if (d.argc == 1) { - Value arg = d.args[0]; - if (DateObject *d = arg.asDateObject()) + else if (callData->argc == 1) { + ValueScope scope(m->engine()); + ScopedValue arg(scope, callData->args[0]); + if (DateObject *d = arg->asDateObject()) arg = d->value; else arg = __qmljs_to_primitive(arg, PREFERREDTYPE_HINT); - if (arg.isString()) - t = ParseString(arg.stringValue()->toQString()); + if (arg->isString()) + t = ParseString(arg->stringValue()->toQString()); else - t = TimeClip(arg.toNumber()); + t = TimeClip(arg->toNumber()); } else { // d.argc > 1 - double year = d.args[0].toNumber(); - double month = d.args[1].toNumber(); - double day = d.argc >= 3 ? d.args[2].toNumber() : 1; - double hours = d.argc >= 4 ? d.args[3].toNumber() : 0; - double mins = d.argc >= 5 ? d.args[4].toNumber() : 0; - double secs = d.argc >= 6 ? d.args[5].toNumber() : 0; - double ms = d.argc >= 7 ? d.args[6].toNumber() : 0; + double year = callData->args[0].toNumber(); + double month = callData->args[1].toNumber(); + double day = callData->argc >= 3 ? callData->args[2].toNumber() : 1; + double hours = callData->argc >= 4 ? callData->args[3].toNumber() : 0; + double mins = callData->argc >= 5 ? callData->args[4].toNumber() : 0; + double secs = callData->argc >= 6 ? callData->args[5].toNumber() : 0; + double ms = callData->argc >= 7 ? callData->args[6].toNumber() : 0; if (year >= 0 && year <= 99) year += 1900; t = MakeDate(MakeDay(year, month, day), MakeTime(hours, mins, secs, ms)); @@ -697,7 +693,7 @@ Value DateCtor::construct(Managed *m, const CallData &d) return Value::fromObject(o); } -Value DateCtor::call(Managed *m, const CallData &) +Value DateCtor::call(Managed *m, CallData *) { double t = currentTime(); return Value::fromString(m->engine()->current, ToString(t)); @@ -1295,20 +1291,21 @@ Value DatePrototype::method_toISOString(SimpleCallContext *ctx) Value DatePrototype::method_toJSON(SimpleCallContext *ctx) { - Value O = __qmljs_to_object(ctx, ctx->thisObject); - Value tv = __qmljs_to_primitive(O, NUMBER_HINT); + ValueScope scope(ctx); + ScopedValue O(scope, __qmljs_to_object(ctx, ValueRef(&ctx->thisObject))); + ScopedValue tv(scope, __qmljs_to_primitive(O, NUMBER_HINT)); - if (tv.isNumber() && !std::isfinite(tv.toNumber())) + if (tv->isNumber() && !std::isfinite(tv->toNumber())) return Value::nullValue(); - FunctionObject *toIso = O.objectValue()->get(ctx->engine->newString(QStringLiteral("toISOString"))).asFunctionObject(); + FunctionObject *toIso = O->objectValue()->get(ctx->engine->newString(QStringLiteral("toISOString"))).asFunctionObject(); if (!toIso) ctx->throwTypeError(); - CALLDATA(0); - d.thisObject = ctx->thisObject; - return toIso->call(d); + ScopedCallData callData(ctx->engine, 0); + callData->thisObject = ctx->thisObject; + return toIso->call(callData); } void DatePrototype::timezoneUpdated() diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h index 238d10849a..573326adc4 100644 --- a/src/qml/jsruntime/qv4dateobject_p.h +++ b/src/qml/jsruntime/qv4dateobject_p.h @@ -66,8 +66,8 @@ struct DateCtor: FunctionObject { DateCtor(ExecutionContext *scope); - static Value construct(Managed *, const CallData &d); - static Value call(Managed *that, const CallData &); + static Value construct(Managed *, CallData *callData); + static Value call(Managed *that, CallData *); protected: static const ManagedVTable static_vtbl; diff --git a/src/qml/jsruntime/qv4debugging.cpp b/src/qml/jsruntime/qv4debugging.cpp index 5534305068..10f22a11b8 100644 --- a/src/qml/jsruntime/qv4debugging.cpp +++ b/src/qml/jsruntime/qv4debugging.cpp @@ -298,19 +298,27 @@ void DebuggerAgent::removeDebugger(Debugger *debugger) debugger->detachFromAgent(); } -void DebuggerAgent::pause(Debugger *debugger) +void DebuggerAgent::pause(Debugger *debugger) const { debugger->pause(); } -void DebuggerAgent::addBreakPoint(Debugger *debugger, const QString &fileName, int lineNumber) +void DebuggerAgent::pauseAll() const { - debugger->addBreakPoint(fileName, lineNumber); + foreach (Debugger *debugger, m_debuggers) + pause(debugger); } -void DebuggerAgent::removeBreakPoint(Debugger *debugger, const QString &fileName, int lineNumber) +void DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber) const { - debugger->removeBreakPoint(fileName, lineNumber); + foreach (Debugger *debugger, m_debuggers) + debugger->addBreakPoint(fileName, lineNumber); +} + +void DebuggerAgent::removeBreakPoint(const QString &fileName, int lineNumber) const +{ + foreach (Debugger *debugger, m_debuggers) + debugger->removeBreakPoint(fileName, lineNumber); } DebuggerAgent::~DebuggerAgent() diff --git a/src/qml/jsruntime/qv4debugging_p.h b/src/qml/jsruntime/qv4debugging_p.h index d71b25f378..908854865d 100644 --- a/src/qml/jsruntime/qv4debugging_p.h +++ b/src/qml/jsruntime/qv4debugging_p.h @@ -140,9 +140,10 @@ public: void addDebugger(Debugger *debugger); void removeDebugger(Debugger *debugger); - void pause(Debugger *debugger); - void addBreakPoint(Debugger *debugger, const QString &fileName, int lineNumber); - void removeBreakPoint(Debugger *debugger, const QString &fileName, int lineNumber); + void pause(Debugger *debugger) const; + void pauseAll() const; + void addBreakPoint(const QString &fileName, int lineNumber) const; + void removeBreakPoint(const QString &fileName, int lineNumber) const; Q_INVOKABLE virtual void debuggerPaused(QV4::Debugging::Debugger *debugger) = 0; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index ae444ab938..638609de37 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -84,6 +84,7 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory) , executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) , bumperPointerAllocator(new WTF::BumpPointerAllocator) + , jsStack(new WTF::PageAllocation) , debugger(0) , globalObject(0) , globalCode(0) @@ -95,8 +96,13 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory) MemoryManager::GCBlocker gcBlocker(memoryManager); if (!factory) { + #ifdef V4_ENABLE_JIT - factory = new QQmlJS::MASM::ISelFactory; + static const bool forceMoth = !qgetenv("QV4_FORCE_INTERPRETER").isEmpty(); + if (forceMoth) + factory = new QQmlJS::Moth::ISelFactory; + else + factory = new QQmlJS::MASM::ISelFactory; #else // !V4_ENABLE_JIT factory = new QQmlJS::Moth::ISelFactory; #endif // V4_ENABLE_JIT @@ -105,6 +111,11 @@ ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory) memoryManager->setExecutionEngine(this); + // reserve 8MB for the JS stack + *jsStack = WTF::PageAllocation::allocate(8*1024*1024, WTF::OSAllocator::JSVMStackPages, true); + jsStackBase = (Value *)jsStack->base(); + jsStackTop = jsStackBase; + identifierTable = new IdentifierTable(this); emptyClass = new (classPool.allocate(sizeof(InternalClass))) InternalClass(this); @@ -291,6 +302,8 @@ ExecutionEngine::~ExecutionEngine() delete regExpCache; delete regExpAllocator; delete executableAllocator; + jsStack->deallocate(); + delete jsStack; } void ExecutionEngine::enableDebugger() @@ -708,13 +721,13 @@ namespace { { bool operator()(Function *function, quintptr pc) { - return reinterpret_cast<quintptr>(function->code) < pc - && (reinterpret_cast<quintptr>(function->code) + function->codeSize) < pc; + return reinterpret_cast<quintptr>(function->codePtr) < pc + && (reinterpret_cast<quintptr>(function->codePtr) + function->codeSize) < pc; } bool operator()(quintptr pc, Function *function) { - return pc < reinterpret_cast<quintptr>(function->code); + return pc < reinterpret_cast<quintptr>(function->codePtr); } }; } diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index b7b27a48f9..1dbffa28aa 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -50,6 +50,7 @@ namespace WTF { class BumpPointerAllocator; +class PageAllocation; } QT_BEGIN_NAMESPACE @@ -123,6 +124,20 @@ struct Q_QML_EXPORT ExecutionEngine WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine. + WTF::PageAllocation *jsStack; + Value *jsStackBase; + Value *jsStackTop; + + Value *stackPush(uint nValues) { + Value *ptr = jsStackTop; + jsStackTop = ptr + nValues; + return ptr; + } + + void stackPop(uint nValues) { + jsStackTop -= nValues; + } + IdentifierTable *identifierTable; QV4::Debugging::Debugger *debugger; diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp index 04357c393a..6174c9a7f5 100644 --- a/src/qml/jsruntime/qv4errorobject.cpp +++ b/src/qml/jsruntime/qv4errorobject.cpp @@ -240,14 +240,14 @@ ErrorCtor::ErrorCtor(ExecutionContext *scope, String *name) vtbl = &static_vtbl; } -Value ErrorCtor::construct(Managed *m, const CallData &d) +Value ErrorCtor::construct(Managed *m, CallData *callData) { - return Value::fromObject(m->engine()->newErrorObject(d.argc ? d.args[0] : Value::undefinedValue())); + return Value::fromObject(m->engine()->newErrorObject(callData->argc ? callData->args[0] : Value::undefinedValue())); } -Value ErrorCtor::call(Managed *that, const CallData &d) +Value ErrorCtor::call(Managed *that, CallData *callData) { - return that->construct(d); + return that->construct(callData); } EvalErrorCtor::EvalErrorCtor(ExecutionContext *scope) @@ -256,9 +256,9 @@ EvalErrorCtor::EvalErrorCtor(ExecutionContext *scope) vtbl = &static_vtbl; } -Value EvalErrorCtor::construct(Managed *m, const CallData &d) +Value EvalErrorCtor::construct(Managed *m, CallData *callData) { - return Value::fromObject(new (m->engine()->memoryManager) EvalErrorObject(m->engine(), d.argc ? d.args[0] : Value::undefinedValue())); + return Value::fromObject(new (m->engine()->memoryManager) EvalErrorObject(m->engine(), callData->argc ? callData->args[0] : Value::undefinedValue())); } RangeErrorCtor::RangeErrorCtor(ExecutionContext *scope) @@ -267,9 +267,9 @@ RangeErrorCtor::RangeErrorCtor(ExecutionContext *scope) vtbl = &static_vtbl; } -Value RangeErrorCtor::construct(Managed *m, const CallData &d) +Value RangeErrorCtor::construct(Managed *m, CallData *callData) { - return Value::fromObject(new (m->engine()->memoryManager) RangeErrorObject(m->engine(), d.argc ? d.args[0] : Value::undefinedValue())); + return Value::fromObject(new (m->engine()->memoryManager) RangeErrorObject(m->engine(), callData->argc ? callData->args[0] : Value::undefinedValue())); } ReferenceErrorCtor::ReferenceErrorCtor(ExecutionContext *scope) @@ -278,9 +278,9 @@ ReferenceErrorCtor::ReferenceErrorCtor(ExecutionContext *scope) vtbl = &static_vtbl; } -Value ReferenceErrorCtor::construct(Managed *m, const CallData &d) +Value ReferenceErrorCtor::construct(Managed *m, CallData *callData) { - return Value::fromObject(new (m->engine()->memoryManager) ReferenceErrorObject(m->engine(), d.argc ? d.args[0] : Value::undefinedValue())); + return Value::fromObject(new (m->engine()->memoryManager) ReferenceErrorObject(m->engine(), callData->argc ? callData->args[0] : Value::undefinedValue())); } SyntaxErrorCtor::SyntaxErrorCtor(ExecutionContext *scope) @@ -289,9 +289,9 @@ SyntaxErrorCtor::SyntaxErrorCtor(ExecutionContext *scope) vtbl = &static_vtbl; } -Value SyntaxErrorCtor::construct(Managed *m, const CallData &d) +Value SyntaxErrorCtor::construct(Managed *m, CallData *callData) { - return Value::fromObject(new (m->engine()->memoryManager) SyntaxErrorObject(m->engine(), d.argc ? d.args[0] : Value::undefinedValue())); + return Value::fromObject(new (m->engine()->memoryManager) SyntaxErrorObject(m->engine(), callData->argc ? callData->args[0] : Value::undefinedValue())); } TypeErrorCtor::TypeErrorCtor(ExecutionContext *scope) @@ -300,9 +300,9 @@ TypeErrorCtor::TypeErrorCtor(ExecutionContext *scope) vtbl = &static_vtbl; } -Value TypeErrorCtor::construct(Managed *m, const CallData &d) +Value TypeErrorCtor::construct(Managed *m, CallData *callData) { - return Value::fromObject(new (m->engine()->memoryManager) TypeErrorObject(m->engine(), d.argc ? d.args[0] : Value::undefinedValue())); + return Value::fromObject(new (m->engine()->memoryManager) TypeErrorObject(m->engine(), callData->argc ? callData->args[0] : Value::undefinedValue())); } URIErrorCtor::URIErrorCtor(ExecutionContext *scope) @@ -311,9 +311,9 @@ URIErrorCtor::URIErrorCtor(ExecutionContext *scope) vtbl = &static_vtbl; } -Value URIErrorCtor::construct(Managed *m, const CallData &d) +Value URIErrorCtor::construct(Managed *m, CallData *callData) { - return Value::fromObject(new (m->engine()->memoryManager) URIErrorObject(m->engine(), d.argc ? d.args[0] : Value::undefinedValue())); + return Value::fromObject(new (m->engine()->memoryManager) URIErrorObject(m->engine(), callData->argc ? callData->args[0] : Value::undefinedValue())); } void ErrorPrototype::init(ExecutionEngine *engine, const Value &ctor, Object *obj) @@ -327,20 +327,22 @@ void ErrorPrototype::init(ExecutionEngine *engine, const Value &ctor, Object *ob Value ErrorPrototype::method_toString(SimpleCallContext *ctx) { + ValueScope scope(ctx); + Object *o = ctx->thisObject.asObject(); if (!o) ctx->throwTypeError(); - Value name = o->get(ctx->engine->newString(QString::fromLatin1("name"))); + ScopedValue name(scope, o->get(ctx->engine->newString(QString::fromLatin1("name")))); QString qname; - if (name.isUndefined()) + if (name->isUndefined()) qname = QString::fromLatin1("Error"); else qname = __qmljs_to_string(name, ctx).stringValue()->toQString(); - Value message = o->get(ctx->engine->newString(QString::fromLatin1("message"))); + ScopedValue message(scope, o->get(ctx->engine->newString(QString::fromLatin1("message")))); QString qmessage; - if (!message.isUndefined()) + if (!message->isUndefined()) qmessage = __qmljs_to_string(message, ctx).stringValue()->toQString(); QString str; diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h index f8aeae603c..1d82bb7ba2 100644 --- a/src/qml/jsruntime/qv4errorobject_p.h +++ b/src/qml/jsruntime/qv4errorobject_p.h @@ -114,8 +114,8 @@ struct ErrorCtor: FunctionObject ErrorCtor(ExecutionContext *scope); ErrorCtor(ExecutionContext *scope, String *name); - static Value construct(Managed *, const CallData &d); - static Value call(Managed *that, const CallData &d); + static Value construct(Managed *, CallData *callData); + static Value call(Managed *that, CallData *callData); protected: static const ManagedVTable static_vtbl; @@ -125,7 +125,7 @@ struct EvalErrorCtor: ErrorCtor { EvalErrorCtor(ExecutionContext *scope); - static Value construct(Managed *m, const CallData &d); + static Value construct(Managed *m, CallData *callData); protected: static const ManagedVTable static_vtbl; @@ -135,7 +135,7 @@ struct RangeErrorCtor: ErrorCtor { RangeErrorCtor(ExecutionContext *scope); - static Value construct(Managed *m, const CallData &d); + static Value construct(Managed *m, CallData *callData); protected: static const ManagedVTable static_vtbl; @@ -145,7 +145,7 @@ struct ReferenceErrorCtor: ErrorCtor { ReferenceErrorCtor(ExecutionContext *scope); - static Value construct(Managed *m, const CallData &d); + static Value construct(Managed *m, CallData *callData); protected: static const ManagedVTable static_vtbl; @@ -155,7 +155,7 @@ struct SyntaxErrorCtor: ErrorCtor { SyntaxErrorCtor(ExecutionContext *scope); - static Value construct(Managed *m, const CallData &d); + static Value construct(Managed *m, CallData *callData); protected: static const ManagedVTable static_vtbl; @@ -165,7 +165,7 @@ struct TypeErrorCtor: ErrorCtor { TypeErrorCtor(ExecutionContext *scope); - static Value construct(Managed *m, const CallData &d); + static Value construct(Managed *m, CallData *callData); protected: static const ManagedVTable static_vtbl; @@ -175,7 +175,7 @@ struct URIErrorCtor: ErrorCtor { URIErrorCtor(ExecutionContext *scope); - static Value construct(Managed *m, const CallData &d); + static Value construct(Managed *m, CallData *callData); protected: static const ManagedVTable static_vtbl; diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index e989d31c1b..9907f3e2ba 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -54,21 +54,14 @@ using namespace QV4; Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function, Value (*codePtr)(ExecutionContext *, const uchar *), quint32 _codeSize) : name(0) - , compiledFunction(0) - , compilationUnit(0) - , code(0) + , compiledFunction(function) + , compilationUnit(unit) + , codePtr(codePtr) , codeData(0) - , codeSize(0) + , codeSize(_codeSize) { - Q_ASSERT(!compilationUnit); - compilationUnit = unit; - compiledFunction = function; - name = compilationUnit->runtimeStrings[compiledFunction->nameIndex]; - code = codePtr; - codeSize = _codeSize; - formals.resize(compiledFunction->nFormals); const quint32 *formalsIndices = compiledFunction->formalsTable(); for (int i = 0; i < compiledFunction->nFormals; ++i) diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 735dc558e1..1fc40d7209 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -49,6 +49,7 @@ #include "qv4value_def_p.h" #include <private/qv4compileddata_p.h> +#include <private/qv4engine_p.h> QT_BEGIN_NAMESPACE @@ -84,7 +85,17 @@ struct Function { const CompiledData::Function *compiledFunction; CompiledData::CompilationUnit *compilationUnit; - Value (*code)(ExecutionContext *, const uchar *); + inline Value code(ExecutionContext *ctx, const uchar *data) { + Value *stack = ctx->engine->jsStackTop; + try { + return codePtr(ctx, data); + } catch (...) { + ctx->engine->jsStackTop = stack; + throw; + } + } + + Value (*codePtr)(ExecutionContext *, const uchar *); const uchar *codeData; quint32 codeSize; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 925aadcdf1..252481b7f1 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -48,6 +48,7 @@ #include "qv4mm_p.h" #include "qv4exception_p.h" #include "qv4arrayobject_p.h" +#include "qv4scopedvalue_p.h" #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> @@ -122,8 +123,8 @@ FunctionObject::~FunctionObject() Value FunctionObject::newInstance() { - CALLDATA(0); - return construct(d); + ScopedCallData callData(engine(), 0); + return construct(callData); } bool FunctionObject::hasInstance(Managed *that, const Value &value) @@ -151,7 +152,7 @@ bool FunctionObject::hasInstance(Managed *that, const Value &value) return false; } -Value FunctionObject::construct(Managed *that, const CallData &) +Value FunctionObject::construct(Managed *that, CallData *) { FunctionObject *f = static_cast<FunctionObject *>(that); ExecutionEngine *v4 = f->engine(); @@ -164,7 +165,7 @@ Value FunctionObject::construct(Managed *that, const CallData &) return Value::fromObject(obj); } -Value FunctionObject::call(Managed *, const CallData &) +Value FunctionObject::call(Managed *, CallData *) { return Value::undefinedValue(); } @@ -203,7 +204,7 @@ FunctionCtor::FunctionCtor(ExecutionContext *scope) } // 15.3.2 -Value FunctionCtor::construct(Managed *that, const CallData &d) +Value FunctionCtor::construct(Managed *that, CallData *callData) { FunctionCtor *f = static_cast<FunctionCtor *>(that); MemoryManager::GCBlocker gcBlocker(f->engine()->memoryManager); @@ -211,13 +212,13 @@ Value FunctionCtor::construct(Managed *that, const CallData &d) ExecutionContext *ctx = f->engine()->current; QString arguments; QString body; - if (d.argc > 0) { - for (uint i = 0; i < d.argc - 1; ++i) { + if (callData->argc > 0) { + for (uint i = 0; i < callData->argc - 1; ++i) { if (i) arguments += QLatin1String(", "); - arguments += d.args[i].toString(ctx)->toQString(); + arguments += callData->args[i].toString(ctx)->toQString(); } - body = d.args[d.argc - 1].toString(ctx)->toQString(); + body = callData->args[callData->argc - 1].toString(ctx)->toQString(); } QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1String("}"); @@ -252,9 +253,9 @@ Value FunctionCtor::construct(Managed *that, const CallData &d) } // 15.3.1: This is equivalent to new Function(...) -Value FunctionCtor::call(Managed *that, const CallData &d) +Value FunctionCtor::call(Managed *that, CallData *callData) { - return construct(that, d); + return construct(that, callData); } FunctionPrototype::FunctionPrototype(InternalClass *ic) @@ -307,23 +308,23 @@ Value FunctionPrototype::method_apply(SimpleCallContext *ctx) len = ArrayPrototype::getLength(ctx, arr); } - CALLDATA(len); + ScopedCallData callData(ctx->engine, len); if (len) { if (arr->protoHasArray() || arr->hasAccessorProperty) { for (quint32 i = 0; i < len; ++i) - d.args[i] = arr->getIndexed(i); + callData->args[i] = arr->getIndexed(i); } else { int alen = qMin(len, arr->arrayDataLen); for (quint32 i = 0; i < alen; ++i) - d.args[i] = arr->arrayData[i].value; + callData->args[i] = arr->arrayData[i].value; for (quint32 i = alen; i < len; ++i) - d.args[i] = Value::undefinedValue(); + callData->args[i] = Value::undefinedValue(); } } - d.thisObject = thisArg; - return o->call(d); + callData->thisObject = thisArg; + return o->call(callData); } Value FunctionPrototype::method_call(SimpleCallContext *ctx) @@ -334,12 +335,12 @@ Value FunctionPrototype::method_call(SimpleCallContext *ctx) if (!o) ctx->throwTypeError(); - CALLDATA(ctx->argumentCount ? ctx->argumentCount - 1 : 0); + ScopedCallData callData(ctx->engine, ctx->argumentCount ? ctx->argumentCount - 1 : 0); if (ctx->argumentCount) qCopy(ctx->arguments + 1, - ctx->arguments + ctx->argumentCount, d.args); - d.thisObject = thisArg; - return o->call(d); + ctx->arguments + ctx->argumentCount, callData->args); + callData->thisObject = thisArg; + return o->call(callData); } Value FunctionPrototype::method_bind(SimpleCallContext *ctx) @@ -373,8 +374,8 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function) vtbl = &static_vtbl; this->function = function; this->function->compilationUnit->ref(); - assert(function); - assert(function->code); + Q_ASSERT(function); + Q_ASSERT(function->codePtr); // global function if (!scope) @@ -400,9 +401,10 @@ ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function) } } -Value ScriptFunction::construct(Managed *that, const CallData &d) +Value ScriptFunction::construct(Managed *that, CallData *callData) { ScriptFunction *f = static_cast<ScriptFunction *>(that); + SAVE_JS_STACK(f->scope); ExecutionEngine *v4 = f->engine(); InternalClass *ic = v4->objectClass; @@ -412,9 +414,8 @@ Value ScriptFunction::construct(Managed *that, const CallData &d) Object *obj = v4->newObject(ic); ExecutionContext *context = v4->current; - CallData dd = d; - dd.thisObject = Value::fromObject(obj); - ExecutionContext *ctx = context->newCallContext(f, dd); + callData->thisObject = Value::fromObject(obj); + ExecutionContext *ctx = context->newCallContext(f, callData); Value result; try { @@ -425,23 +426,25 @@ Value ScriptFunction::construct(Managed *that, const CallData &d) } ctx->engine->popContext(); + CHECK_JS_STACK(f->scope); if (result.isObject()) return result; return Value::fromObject(obj); } -Value ScriptFunction::call(Managed *that, const CallData &d) +Value ScriptFunction::call(Managed *that, CallData *callData) { ScriptFunction *f = static_cast<ScriptFunction *>(that); + SAVE_JS_STACK(f->scope); void *stackSpace; ExecutionContext *context = f->engine()->current; - ExecutionContext *ctx = context->newCallContext(f, d); + CallContext *ctx = context->newCallContext(f, callData); - if (!f->strictMode && !d.thisObject.isObject()) { - if (d.thisObject.isNullOrUndefined()) { + if (!f->strictMode && !callData->thisObject.isObject()) { + if (callData->thisObject.isNullOrUndefined()) { ctx->thisObject = Value::fromObject(f->engine()->globalObject); } else { - ctx->thisObject = Value::fromObject(d.thisObject.toObject(context)); + ctx->thisObject = Value::fromObject(callData->thisObject.toObject(context)); } } @@ -453,6 +456,7 @@ Value ScriptFunction::call(Managed *that, const CallData &d) throw; } ctx->engine->popContext(); + CHECK_JS_STACK(f->scope); return result; } @@ -464,8 +468,8 @@ SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *fu vtbl = &static_vtbl; this->function = function; this->function->compilationUnit->ref(); - assert(function); - assert(function->code); + Q_ASSERT(function); + Q_ASSERT(function->codePtr); // global function if (!scope) @@ -491,9 +495,10 @@ SimpleScriptFunction::SimpleScriptFunction(ExecutionContext *scope, Function *fu } } -Value SimpleScriptFunction::construct(Managed *that, const CallData &d) +Value SimpleScriptFunction::construct(Managed *that, CallData *callData) { SimpleScriptFunction *f = static_cast<SimpleScriptFunction *>(that); + SAVE_JS_STACK(f->scope); ExecutionEngine *v4 = f->engine(); InternalClass *ic = v4->objectClass; @@ -504,9 +509,8 @@ Value SimpleScriptFunction::construct(Managed *that, const CallData &d) ExecutionContext *context = v4->current; void *stackSpace = alloca(requiredMemoryForExecutionContectSimple(f)); - CallData dd = d; - dd.thisObject = Value::fromObject(obj); - ExecutionContext *ctx = context->newCallContext(stackSpace, f, dd); + callData->thisObject = Value::fromObject(obj); + ExecutionContext *ctx = context->newCallContext(stackSpace, f, callData); Value result; try { @@ -517,23 +521,25 @@ Value SimpleScriptFunction::construct(Managed *that, const CallData &d) } ctx->engine->popContext(); + CHECK_JS_STACK(f->scope); if (result.isObject()) return result; return Value::fromObject(obj); } -Value SimpleScriptFunction::call(Managed *that, const CallData &d) +Value SimpleScriptFunction::call(Managed *that, CallData *callData) { SimpleScriptFunction *f = static_cast<SimpleScriptFunction *>(that); + SAVE_JS_STACK(f->scope); void *stackSpace = alloca(requiredMemoryForExecutionContectSimple(f)); ExecutionContext *context = f->engine()->current; - ExecutionContext *ctx = context->newCallContext(stackSpace, f, d); + ExecutionContext *ctx = context->newCallContext(stackSpace, f, callData); - if (!f->strictMode && !d.thisObject.isObject()) { - if (d.thisObject.isNullOrUndefined()) { + if (!f->strictMode && !callData->thisObject.isObject()) { + if (callData->thisObject.isNullOrUndefined()) { ctx->thisObject = Value::fromObject(f->engine()->globalObject); } else { - ctx->thisObject = Value::fromObject(d.thisObject.toObject(context)); + ctx->thisObject = Value::fromObject(callData->thisObject.toObject(context)); } } @@ -545,6 +551,7 @@ Value SimpleScriptFunction::call(Managed *that, const CallData &d) throw; } ctx->engine->popContext(); + CHECK_JS_STACK(f->scope); return result; } @@ -561,13 +568,13 @@ BuiltinFunctionOld::BuiltinFunctionOld(ExecutionContext *scope, String *name, Va isBuiltinFunction = true; } -Value BuiltinFunctionOld::construct(Managed *f, const CallData &d) +Value BuiltinFunctionOld::construct(Managed *f, CallData *) { f->engine()->current->throwTypeError(); return Value::undefinedValue(); } -Value BuiltinFunctionOld::call(Managed *that, const CallData &d) +Value BuiltinFunctionOld::call(Managed *that, CallData *callData) { BuiltinFunctionOld *f = static_cast<BuiltinFunctionOld *>(that); ExecutionEngine *v4 = f->engine(); @@ -576,9 +583,10 @@ Value BuiltinFunctionOld::call(Managed *that, const CallData &d) SimpleCallContext ctx; ctx.initSimpleCallContext(f->scope->engine); ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context? - ctx.thisObject = d.thisObject; - ctx.arguments = d.args; - ctx.argumentCount = d.argc; + ctx.thisObject = callData->thisObject; + // ### const_cast + ctx.arguments = const_cast<Value *>(callData->args); + ctx.argumentCount = callData->argc; v4->pushContext(&ctx); Value result; @@ -593,7 +601,7 @@ Value BuiltinFunctionOld::call(Managed *that, const CallData &d) return result; } -Value IndexedBuiltinFunction::call(Managed *that, const CallData &d) +Value IndexedBuiltinFunction::call(Managed *that, CallData *callData) { IndexedBuiltinFunction *f = static_cast<IndexedBuiltinFunction *>(that); ExecutionEngine *v4 = f->engine(); @@ -602,9 +610,10 @@ Value IndexedBuiltinFunction::call(Managed *that, const CallData &d) SimpleCallContext ctx; ctx.initSimpleCallContext(f->scope->engine); ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context? - ctx.thisObject = d.thisObject; - ctx.arguments = d.args; - ctx.argumentCount = d.argc; + ctx.thisObject = callData->thisObject; + // ### const_cast + ctx.arguments = const_cast<Value *>(callData->args); + ctx.argumentCount = callData->argc; v4->pushContext(&ctx); Value result; @@ -647,24 +656,24 @@ void BoundFunction::destroy(Managed *that) static_cast<BoundFunction *>(that)->~BoundFunction(); } -Value BoundFunction::call(Managed *that, const CallData &dd) +Value BoundFunction::call(Managed *that, CallData *dd) { BoundFunction *f = static_cast<BoundFunction *>(that); - CALLDATA(f->boundArgs.size() + dd.argc); - d.thisObject = f->boundThis; - memcpy(d.args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(Value)); - memcpy(d.args + f->boundArgs.size(), dd.args, dd.argc*sizeof(Value)); - return f->target->call(d); + ScopedCallData callData(f->scope->engine, f->boundArgs.size() + dd->argc); + callData->thisObject = f->boundThis; + memcpy(callData->args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(Value)); + memcpy(callData->args + f->boundArgs.size(), dd->args, dd->argc*sizeof(Value)); + return f->target->call(callData); } -Value BoundFunction::construct(Managed *that, const CallData &dd) +Value BoundFunction::construct(Managed *that, CallData *dd) { BoundFunction *f = static_cast<BoundFunction *>(that); - CALLDATA(f->boundArgs.size() + dd.argc); - memcpy(d.args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(Value)); - memcpy(d.args + f->boundArgs.size(), dd.args, dd.argc*sizeof(Value)); - return f->target->construct(d); + ScopedCallData callData(f->scope->engine, f->boundArgs.size() + dd->argc); + memcpy(callData->args, f->boundArgs.constData(), f->boundArgs.size()*sizeof(Value)); + memcpy(callData->args + f->boundArgs.size(), dd->args, dd->argc*sizeof(Value)); + return f->target->construct(callData); } bool BoundFunction::hasInstance(Managed *that, const Value &value) diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 4d4174d053..d694d28462 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -117,13 +117,13 @@ struct Q_QML_EXPORT FunctionObject: Object { Value newInstance(); - static Value construct(Managed *that, const CallData &); - static Value call(Managed *that, const CallData &d); - inline Value construct(const CallData &d) { - return vtbl->construct(this, d); + static Value construct(Managed *that, CallData *); + static Value call(Managed *that, CallData *d); + inline Value construct(CallData *callData) { + return vtbl->construct(this, callData); } - inline Value call(const CallData &d) { - return vtbl->call(this, d); + inline Value call(CallData *callData) { + return vtbl->call(this, callData); } static FunctionObject *creatScriptFunction(ExecutionContext *scope, Function *function); @@ -142,8 +142,8 @@ struct FunctionCtor: FunctionObject { FunctionCtor(ExecutionContext *scope); - static Value construct(Managed *that, const CallData &); - static Value call(Managed *that, const CallData &d); + static Value construct(Managed *that, CallData *callData); + static Value call(Managed *that, CallData *callData); protected: static const ManagedVTable static_vtbl; @@ -165,8 +165,8 @@ struct BuiltinFunctionOld: FunctionObject { BuiltinFunctionOld(ExecutionContext *scope, String *name, Value (*code)(SimpleCallContext *)); - static Value construct(Managed *, const CallData &d); - static Value call(Managed *that, const CallData &d); + static Value construct(Managed *, CallData *); + static Value call(Managed *that, CallData *callData); protected: static const ManagedVTable static_vtbl; @@ -188,21 +188,21 @@ struct IndexedBuiltinFunction: FunctionObject isBuiltinFunction = true; } - static Value construct(Managed *m, const CallData &) + static Value construct(Managed *m, CallData *) { m->engine()->current->throwTypeError(); return Value::undefinedValue(); } - static Value call(Managed *that, const CallData &d); + static Value call(Managed *that, CallData *callData); }; struct ScriptFunction: FunctionObject { ScriptFunction(ExecutionContext *scope, Function *function); - static Value construct(Managed *, const CallData &d); - static Value call(Managed *that, const CallData &d); + static Value construct(Managed *, CallData *callData); + static Value call(Managed *that, CallData *callData); protected: static const ManagedVTable static_vtbl; @@ -211,8 +211,8 @@ protected: struct SimpleScriptFunction: FunctionObject { SimpleScriptFunction(ExecutionContext *scope, Function *function); - static Value construct(Managed *, const CallData &d); - static Value call(Managed *that, const CallData &d); + static Value construct(Managed *, CallData *callData); + static Value call(Managed *that, CallData *callData); protected: static const ManagedVTable static_vtbl; @@ -227,8 +227,8 @@ struct BoundFunction: FunctionObject { ~BoundFunction() {} - static Value construct(Managed *, const CallData &d); - static Value call(Managed *that, const CallData &d); + static Value construct(Managed *, CallData *d); + static Value call(Managed *that, CallData *dd); static const ManagedVTable static_vtbl; static void destroy(Managed *); diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index 3b06a6d884..9764a7930f 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -47,6 +47,7 @@ #include "qv4debugging_p.h" #include "qv4script_p.h" #include "qv4exception_p.h" +#include "qv4scopedvalue_p.h" #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> @@ -390,9 +391,9 @@ Value EvalFunction::evalCall(Value /*thisObject*/, Value *args, int argc, bool d if (strictMode) { FunctionObject *e = FunctionObject::creatScriptFunction(ctx, function); - CALLDATA(0); - d.thisObject = ctx->thisObject; - return e->call(d); + ScopedCallData callData(ctx->engine, 0); + callData->thisObject = ctx->thisObject; + return e->call(callData); } ExecutionContext::EvalCode evalCode; @@ -438,10 +439,11 @@ Value EvalFunction::evalCall(Value /*thisObject*/, Value *args, int argc, bool d } -Value EvalFunction::call(Managed *that, const CallData &d) +Value EvalFunction::call(Managed *that, CallData *callData) { // indirect call - return static_cast<EvalFunction *>(that)->evalCall(d.thisObject, d.args, d.argc, false); + // ### const_cast + return static_cast<EvalFunction *>(that)->evalCall(callData->thisObject, const_cast<Value *>(callData->args), callData->argc, false); } diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h index 4ac531c27b..b777bf8915 100644 --- a/src/qml/jsruntime/qv4globalobject_p.h +++ b/src/qml/jsruntime/qv4globalobject_p.h @@ -55,7 +55,7 @@ struct Q_QML_EXPORT EvalFunction : FunctionObject Value evalCall(Value thisObject, Value *args, int argc, bool directCall); using Managed::construct; - static Value call(Managed *that, const CallData &d); + static Value call(Managed *that, CallData *callData); protected: static const ManagedVTable static_vtbl; diff --git a/src/qml/jsruntime/qv4identifier.cpp b/src/qml/jsruntime/qv4identifier.cpp index 5d8077bfdc..08f48c36a4 100644 --- a/src/qml/jsruntime/qv4identifier.cpp +++ b/src/qml/jsruntime/qv4identifier.cpp @@ -114,7 +114,7 @@ const IdentifierHashEntry *IdentifierHashBase::lookup(const Identifier *identifi { if (!d) return 0; - assert(d->entries); + Q_ASSERT(d->entries); uint idx = identifier->hashValue % d->alloc; while (1) { @@ -131,7 +131,7 @@ const IdentifierHashEntry *IdentifierHashBase::lookup(const QString &str) const { if (!d) return 0; - assert(d->entries); + Q_ASSERT(d->entries); uint hash = String::createHashValue(str.constData(), str.length()); uint idx = hash % d->alloc; diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index 9068d573f6..647cc7d2cb 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qv4include_p.h" +#include "qv4scopedvalue_p.h" #include <QtQml/qjsengine.h> #include <QtNetwork/qnetworkrequest.h> @@ -104,10 +105,10 @@ void QV4Include::callback(const QV4::Value &callback, const QV4::Value &status) QV4::ExecutionContext *ctx = f->engine()->current; try { - CALLDATA(1); - d.thisObject = QV4::Value::fromObject(f->engine()->globalObject); - d.args[0] = status; - f->call(d); + QV4::ScopedCallData callData(ctx->engine, 1); + callData->thisObject = QV4::Value::fromObject(f->engine()->globalObject); + callData->args[0] = status; + f->call(callData); } catch (QV4::Exception &e) { e.accept(ctx); } diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp index 9c98d78743..ef1f500580 100644 --- a/src/qml/jsruntime/qv4jsonobject.cpp +++ b/src/qml/jsruntime/qv4jsonobject.cpp @@ -44,6 +44,7 @@ #include <qv4stringobject_p.h> #include <qv4booleanobject_p.h> #include <qv4objectiterator_p.h> +#include <qv4scopedvalue_p.h> #include <qjsondocument.h> #include <qstack.h> #include <qstringlist.h> @@ -702,10 +703,10 @@ QString Stringify::Str(const QString &key, Value value) if (Object *o = value.asObject()) { FunctionObject *toJSON = o->get(ctx->engine->newString(QStringLiteral("toJSON"))).asFunctionObject(); if (toJSON) { - CALLDATA(1); - d.thisObject = value; - d.args[0] = Value::fromString(ctx, key); - value = toJSON->call(d); + ScopedCallData callData(ctx->engine, 1); + callData->thisObject = value; + callData->args[0] = Value::fromString(ctx, key); + value = toJSON->call(callData); } } @@ -713,11 +714,11 @@ QString Stringify::Str(const QString &key, Value value) Object *holder = ctx->engine->newObject(); Value holderValue = Value::fromObject(holder); holder->put(ctx, QString(), value); - CALLDATA(2); - d.args[0] = Value::fromString(ctx, key); - d.args[1] = value; - d.thisObject = holderValue; - value = replacerFunction->call(d); + ScopedCallData callData(ctx->engine, 2); + callData->args[0] = Value::fromString(ctx, key); + callData->args[1] = value; + callData->thisObject = holderValue; + value = replacerFunction->call(callData); } if (Object *o = value.asObject()) { @@ -885,6 +886,8 @@ Value JsonObject::method_parse(SimpleCallContext *ctx) Value JsonObject::method_stringify(SimpleCallContext *ctx) { + ValueScope scope(ctx); + Stringify stringify(ctx); Object *o = ctx->argument(1).asObject(); @@ -892,12 +895,13 @@ Value JsonObject::method_stringify(SimpleCallContext *ctx) stringify.replacerFunction = o->asFunctionObject(); if (o->isArrayObject()) { uint arrayLen = o->arrayLength(); + ScopedValue v(scope); for (uint i = 0; i < arrayLen; ++i) { - Value v = o->getIndexed(i); - if (v.asNumberObject() || v.asStringObject() || v.isNumber()) + v = o->getIndexed(i); + if (v->asNumberObject() || v->asStringObject() || v->isNumber()) v = __qmljs_to_string(v, ctx); - if (v.isString()) { - String *s = v.stringValue(); + if (v->isString()) { + String *s = v->stringValue(); if (!stringify.propertyList.contains(s)) stringify.propertyList.append(s); } diff --git a/src/qml/jsruntime/qv4lookup.cpp b/src/qml/jsruntime/qv4lookup.cpp index e66055653e..2cffa55642 100644 --- a/src/qml/jsruntime/qv4lookup.cpp +++ b/src/qml/jsruntime/qv4lookup.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qv4lookup_p.h" #include "qv4functionobject_p.h" +#include "qv4scopedvalue_p.h" QT_BEGIN_NAMESPACE @@ -202,9 +203,9 @@ void Lookup::getterAccessor0(Lookup *l, Value *result, const Value &object) if (!getter) { res = Value::undefinedValue(); } else { - CALLDATA(0); - d.thisObject = object; - res = getter->call(d); + ScopedCallData callData(o->engine(), 0); + callData->thisObject = object; + res = getter->call(callData); } if (result) *result = res; @@ -225,9 +226,9 @@ void Lookup::getterAccessor1(Lookup *l, Value *result, const Value &object) if (!getter) { res = Value::undefinedValue(); } else { - CALLDATA(0); - d.thisObject = object; - res = getter->call(d); + ScopedCallData callData(o->engine(), 0); + callData->thisObject = object; + res = getter->call(callData); } if (result) *result = res; @@ -251,9 +252,9 @@ void Lookup::getterAccessor2(Lookup *l, Value *result, const Value &object) if (!getter) { res = Value::undefinedValue(); } else { - CALLDATA(0); - d.thisObject = object; - res = getter->call(d); + ScopedCallData callData(o->engine(), 0); + callData->thisObject = object; + res = getter->call(callData); } if (result) *result = res; @@ -306,9 +307,9 @@ void Lookup::primitiveGetterAccessor0(Lookup *l, Value *result, const Value &obj if (!getter) { res = Value::undefinedValue(); } else { - CALLDATA(0); - d.thisObject = object; - res = getter->call(d); + ScopedCallData callData(o->engine(), 0); + callData->thisObject = object; + res = getter->call(callData); } if (result) *result = res; @@ -330,9 +331,9 @@ void Lookup::primitiveGetterAccessor1(Lookup *l, Value *result, const Value &obj if (!getter) { res = Value::undefinedValue(); } else { - CALLDATA(0); - d.thisObject = object; - res = getter->call(d); + ScopedCallData callData(o->engine(), 0); + callData->thisObject = object; + res = getter->call(callData); } if (result) *result = res; @@ -434,9 +435,9 @@ void Lookup::globalGetterAccessor0(Lookup *l, ExecutionContext *ctx, Value *resu if (!getter) { *result = Value::undefinedValue(); } else { - CALLDATA(0); - d.thisObject = Value::undefinedValue(); - *result = getter->call(d); + ScopedCallData callData(ctx->engine, 0); + callData->thisObject = Value::undefinedValue(); + *result = getter->call(callData); } return; } @@ -453,9 +454,9 @@ void Lookup::globalGetterAccessor1(Lookup *l, ExecutionContext *ctx, Value *resu if (!getter) { *result = Value::undefinedValue(); } else { - CALLDATA(0); - d.thisObject = Value::undefinedValue(); - *result = getter->call(d); + ScopedCallData callData(ctx->engine, 0); + callData->thisObject = Value::undefinedValue(); + *result = getter->call(callData); } return; } @@ -475,9 +476,9 @@ void Lookup::globalGetterAccessor2(Lookup *l, ExecutionContext *ctx, Value *resu if (!getter) { *result = Value::undefinedValue(); } else { - CALLDATA(0); - d.thisObject = Value::undefinedValue(); - *result = getter->call(d); + ScopedCallData callData(ctx->engine, 0); + callData->thisObject = Value::undefinedValue(); + *result = getter->call(callData); } return; } @@ -491,7 +492,7 @@ void Lookup::setterGeneric(Lookup *l, const Value &object, const Value &value) { Object *o = object.asObject(); if (!o) { - o = __qmljs_convert_to_object(l->name->engine()->current, object); + o = __qmljs_convert_to_object(l->name->engine()->current, ValueRef::fromRawValue(&object)); o->put(l->name, value); return; } diff --git a/src/qml/jsruntime/qv4managed.cpp b/src/qml/jsruntime/qv4managed.cpp index 955d12a3d0..62491ba7e5 100644 --- a/src/qml/jsruntime/qv4managed.cpp +++ b/src/qml/jsruntime/qv4managed.cpp @@ -176,12 +176,12 @@ bool Managed::hasInstance(Managed *m, const Value &) m->engine()->current->throwTypeError(); } -Value Managed::construct(Managed *m, const CallData &) +Value Managed::construct(Managed *m, CallData *) { m->engine()->current->throwTypeError(); } -Value Managed::call(Managed *m, const CallData &) +Value Managed::call(Managed *m, CallData *) { m->engine()->current->throwTypeError(); } diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index b77b1cd638..50325478f5 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -76,28 +76,23 @@ struct GCDeletable struct CallData { - Value thisObject; - Value *args; + // below is to be compatible with Value. Initialize tag to 0 +#if Q_BYTE_ORDER != Q_LITTLE_ENDIAN + uint tag; +#endif int argc; -}; - -#ifdef QT_NO_DEBUG -#define CALLDATA(argc_) \ - QV4::CallData d; \ - d.argc = argc_; \ - d.args = (QV4::Value *)alloca(qMax((int)(argc_), (int)QV4::Global::ReservedArgumentCount)*sizeof(QV4::Value)) -#else -#define CALLDATA(argc_) \ - QV4::CallData d; \ - d.argc = argc_; \ - d.args = (QV4::Value *)alloca(qMax((int)(argc_), (int)QV4::Global::ReservedArgumentCount)*sizeof(QV4::Value)); \ - for (int iii = 0; iii < qMax((int)(argc_), (int)QV4::Global::ReservedArgumentCount); ++iii) d.args[iii] = QV4::Value::undefinedValue() +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + uint tag; #endif + Value thisObject; + Value args[1]; +}; + struct ManagedVTable { - Value (*call)(Managed *, const CallData &data); - Value (*construct)(Managed *, const CallData &data); + Value (*call)(Managed *, CallData *data); + Value (*construct)(Managed *, CallData *data); void (*markObjects)(Managed *); void (*destroy)(Managed *); void (*collectDeletables)(Managed *, GCDeletable **deletable); @@ -257,8 +252,8 @@ public: inline bool hasInstance(const Value &v) { return vtbl->hasInstance(this, v); } - Value construct(const CallData &d); - Value call(const CallData &d); + Value construct(CallData *d); + Value call(CallData *d); Value get(String *name, bool *hasProperty = 0); Value getIndexed(uint index, bool *hasProperty = 0); void put(String *name, const Value &value) @@ -286,8 +281,8 @@ public: static void destroy(Managed *that) { that->_data = 0; } static bool hasInstance(Managed *that, const Value &value); - static Value construct(Managed *m, const CallData &d); - static Value call(Managed *m, const CallData &); + static Value construct(Managed *m, CallData *d); + static Value call(Managed *m, CallData *); static void getLookup(Managed *m, Lookup *, Value *); static void setLookup(Managed *m, Lookup *l, const Value &v); static bool isEqualTo(Managed *m, Managed *other); diff --git a/src/qml/jsruntime/qv4mm.cpp b/src/qml/jsruntime/qv4mm.cpp index 095d27e1c0..874c349c42 100644 --- a/src/qml/jsruntime/qv4mm.cpp +++ b/src/qml/jsruntime/qv4mm.cpp @@ -293,6 +293,7 @@ void MemoryManager::mark() #endif // COMPILER collectFromStack(); + collectFromJSStack(); // Preserve QObject ownership rules within JavaScript: A parent with c++ ownership // keeps all of its children alive in JavaScript. @@ -602,4 +603,16 @@ void MemoryManager::collectFromStack() const } } +void MemoryManager::collectFromJSStack() const +{ + Value *v = engine()->jsStackBase; + Value *top = engine()->jsStackTop; + while (v < top) { + Managed *m = v->asManaged(); + if (m && m->inUse) + // Skip pointers to already freed objects, they are bogus as well + m->mark(); + ++v; + } +} QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4mm_p.h b/src/qml/jsruntime/qv4mm_p.h index f72d23dc9a..abbc0a7b4e 100644 --- a/src/qml/jsruntime/qv4mm_p.h +++ b/src/qml/jsruntime/qv4mm_p.h @@ -44,6 +44,7 @@ #include "qv4global_p.h" #include "qv4context_p.h" +#include "qv4value_p.h" #include <QScopedPointer> @@ -129,6 +130,7 @@ protected: private: void collectFromStack() const; + void collectFromJSStack() const; void mark(); std::size_t sweep(bool lastSweep = false); std::size_t sweep(char *chunkStart, std::size_t chunkSize, size_t size, GCDeletable **deletable); diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp index 88c61489db..ffcbca2ce5 100644 --- a/src/qml/jsruntime/qv4numberobject.cpp +++ b/src/qml/jsruntime/qv4numberobject.cpp @@ -56,15 +56,15 @@ NumberCtor::NumberCtor(ExecutionContext *scope) vtbl = &static_vtbl; } -Value NumberCtor::construct(Managed *m, const CallData &d) +Value NumberCtor::construct(Managed *m, CallData *callData) { - double dbl = d.argc ? d.args[0].toNumber() : 0.; + double dbl = callData->argc ? callData->args[0].toNumber() : 0.; return Value::fromObject(m->engine()->newNumberObject(Value::fromDouble(dbl))); } -Value NumberCtor::call(Managed *, const CallData &d) +Value NumberCtor::call(Managed *, CallData *callData) { - double dbl = d.argc ? d.args[0].toNumber() : 0.; + double dbl = callData->argc ? callData->args[0].toNumber() : 0.; return Value::fromDouble(dbl); } @@ -225,7 +225,9 @@ Value NumberPrototype::method_toExponential(SimpleCallContext *ctx) Value NumberPrototype::method_toPrecision(SimpleCallContext *ctx) { - Value v = thisNumberValue(ctx); + ValueScope scope(ctx); + + ScopedValue v(scope, thisNumberValue(ctx)); Value prec = ctx->argument(0); if (prec.isUndefined()) @@ -239,7 +241,7 @@ Value NumberPrototype::method_toPrecision(SimpleCallContext *ctx) char str[100]; double_conversion::StringBuilder builder(str, sizeof(str)); - double_conversion::DoubleToStringConverter::EcmaScriptConverter().ToPrecision(v.asDouble(), precision, &builder); + double_conversion::DoubleToStringConverter::EcmaScriptConverter().ToPrecision(v->asDouble(), precision, &builder); QString result = QString::fromLatin1(builder.Finalize()); return Value::fromString(ctx, result); diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h index 096b4b3d9f..a0c2a65e80 100644 --- a/src/qml/jsruntime/qv4numberobject_p.h +++ b/src/qml/jsruntime/qv4numberobject_p.h @@ -53,8 +53,8 @@ struct NumberCtor: FunctionObject { NumberCtor(ExecutionContext *scope); - static Value construct(Managed *that, const CallData &d); - static Value call(Managed *, const CallData &d); + static Value construct(Managed *that, CallData *callData); + static Value call(Managed *, CallData *callData); protected: static const ManagedVTable static_vtbl; diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index c3c444b7b9..14584da46d 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -47,6 +47,7 @@ #include "qv4argumentsobject_p.h" #include "qv4mm_p.h" #include "qv4lookup_p.h" +#include "qv4scopedvalue_p.h" #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> @@ -134,19 +135,19 @@ Value Object::getValue(const Value &thisObject, const Property *p, PropertyAttri if (!getter) return Value::undefinedValue(); - CALLDATA(0); - d.thisObject = thisObject; - return getter->call(d); + ScopedCallData callData(getter->engine(), 0); + callData->thisObject = thisObject; + return getter->call(callData); } void Object::putValue(Property *pd, PropertyAttributes attrs, const Value &value) { if (attrs.isAccessor()) { if (pd->set) { - CALLDATA(1); - d.args[0] = value; - d.thisObject = Value::fromObject(this); - pd->set->call(d); + ScopedCallData callData(pd->set->engine(), 1); + callData->args[0] = value; + callData->thisObject = Value::fromObject(this); + pd->set->call(callData); return; } goto reject; @@ -164,50 +165,54 @@ void Object::putValue(Property *pd, PropertyAttributes attrs, const Value &value } -void Object::inplaceBinOp(ExecutionContext *, BinOp op, String *name, const Value &rhs) +void Object::inplaceBinOp(ExecutionContext *ctx, BinOp op, String *name, const ValueRef rhs) { - Value v = get(name); - Value result; - op(&result, v, rhs); + ValueScope scope(ctx); + ScopedValue v(scope, get(name)); + ScopedValue result(scope); + op(result, v, rhs); put(name, result); } -void Object::inplaceBinOp(ExecutionContext *ctx, BinOp op, const Value &index, const Value &rhs) +void Object::inplaceBinOp(ExecutionContext *ctx, BinOp op, const ValueRef index, const ValueRef rhs) { - uint idx = index.asArrayIndex(); + ValueScope scope(ctx); + uint idx = index->asArrayIndex(); if (idx < UINT_MAX) { bool hasProperty = false; - Value v = getIndexed(idx, &hasProperty); - Value result; - op(&result, v, rhs); + ScopedValue v(scope, getIndexed(idx, &hasProperty)); + ScopedValue result(scope); + op(result, v, rhs); putIndexed(idx, result); return; } - String *name = index.toString(ctx); + String *name = index->toString(ctx); assert(name); inplaceBinOp(ctx, op, name, rhs); } -void Object::inplaceBinOp(ExecutionContext *ctx, BinOpContext op, String *name, const Value &rhs) +void Object::inplaceBinOp(ExecutionContext *ctx, BinOpContext op, String *name, const ValueRef rhs) { - Value v = get(name); - Value result; - op(ctx, &result, v, rhs); + ValueScope scope(ctx); + ScopedValue v(scope, get(name)); + ScopedValue result(scope); + op(ctx, result, v, rhs); put(name, result); } -void Object::inplaceBinOp(ExecutionContext *ctx, BinOpContext op, const Value &index, const Value &rhs) +void Object::inplaceBinOp(ExecutionContext *ctx, BinOpContext op, const ValueRef index, const ValueRef rhs) { - uint idx = index.asArrayIndex(); + ValueScope scope(ctx); + uint idx = index->asArrayIndex(); if (idx < UINT_MAX) { bool hasProperty = false; - Value v = getIndexed(idx, &hasProperty); - Value result; - op(ctx, &result, v, rhs); + ScopedValue v(scope, getIndexed(idx, &hasProperty)); + ScopedValue result(scope); + op(ctx, result, v, rhs); putIndexed(idx, result); return; } - String *name = index.toString(ctx); + String *name = index->toString(ctx); assert(name); inplaceBinOp(ctx, op, name, rhs); } @@ -773,10 +778,10 @@ void Object::internalPut(String *name, const Value &value) if (pd && attrs.isAccessor()) { assert(pd->setter() != 0); - CALLDATA(1); - d.args[0] = value; - d.thisObject = Value::fromObject(this); - pd->setter()->call(d); + ScopedCallData callData(engine(), 1); + callData->args[0] = value; + callData->thisObject = Value::fromObject(this); + pd->setter()->call(callData); return; } @@ -851,10 +856,10 @@ void Object::internalPutIndexed(uint index, const Value &value) if (pd && attrs.isAccessor()) { assert(pd->setter() != 0); - CALLDATA(1); - d.args[0] = value; - d.thisObject = Value::fromObject(this); - pd->setter()->call(d); + ScopedCallData callData(engine(), 1); + callData->args[0] = value; + callData->thisObject = Value::fromObject(this); + pd->setter()->call(callData); return; } @@ -1132,18 +1137,21 @@ void Object::copyArrayData(Object *other) Value Object::arrayIndexOf(Value v, uint fromIndex, uint endIndex, ExecutionContext *ctx, Object *o) { + ValueScope scope(engine()); + ScopedValue value(scope); + if (o->protoHasArray() || o->arrayAttributes) { // lets be safe and slow for (uint i = fromIndex; i < endIndex; ++i) { bool exists; - Value value = o->getIndexed(i, &exists); - if (exists && __qmljs_strict_equal(value, v)) + value = o->getIndexed(i, &exists); + if (exists && __qmljs_strict_equal(value, ValueRef(&v))) return Value::fromDouble(i); } } else if (sparseArray) { for (SparseArrayNode *n = sparseArray->lowerBound(fromIndex); n != sparseArray->end() && n->key() < endIndex; n = n->nextNode()) { - Value value = o->getValue(arrayData + n->value, arrayAttributes ? arrayAttributes[n->value] : Attr_Data); - if (__qmljs_strict_equal(value, v)) + value = o->getValue(arrayData + n->value, arrayAttributes ? arrayAttributes[n->value] : Attr_Data); + if (__qmljs_strict_equal(value, ValueRef(&v))) return Value::fromDouble(n->key()); } } else { @@ -1154,8 +1162,8 @@ Value Object::arrayIndexOf(Value v, uint fromIndex, uint endIndex, ExecutionCont pd += fromIndex; while (pd < end) { if (!arrayAttributes || !arrayAttributes[pd - arrayData].isGeneric()) { - Value value = o->getValue(pd, arrayAttributes ? arrayAttributes[pd - arrayData] : Attr_Data); - if (__qmljs_strict_equal(value, v)) + value = o->getValue(pd, arrayAttributes ? arrayAttributes[pd - arrayData] : Attr_Data); + if (__qmljs_strict_equal(value, ValueRef(&v))) return Value::fromDouble(pd - arrayData); } ++pd; @@ -1246,6 +1254,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/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 995749ff74..c6329b9665 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -156,10 +156,10 @@ struct Q_QML_EXPORT Object: Managed { void putValue(Property *pd, PropertyAttributes attrs, const Value &value); - void inplaceBinOp(ExecutionContext *, BinOp op, String *name, const Value &rhs); - void inplaceBinOp(ExecutionContext *ctx, BinOp op, const Value &index, const Value &rhs); - void inplaceBinOp(ExecutionContext *ctx, BinOpContext op, String *name, const Value &rhs); - void inplaceBinOp(ExecutionContext *ctx, BinOpContext op, const Value &index, const Value &rhs); + void inplaceBinOp(ExecutionContext *, BinOp op, String *name, const ValueRef rhs); + void inplaceBinOp(ExecutionContext *ctx, BinOp op, const ValueRef index, const ValueRef rhs); + void inplaceBinOp(ExecutionContext *ctx, BinOpContext op, String *name, const ValueRef rhs); + void inplaceBinOp(ExecutionContext *ctx, BinOpContext op, const ValueRef index, const ValueRef rhs); /* The spec default: Writable: true, Enumerable: false, Configurable: true */ void defineDefaultProperty(String *name, Value value); diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index fbf86645e2..2f8f6375f0 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -42,6 +42,7 @@ #include "qv4objectproto_p.h" #include "qv4mm_p.h" +#include "qv4scopedvalue_p.h" #include <QtCore/qnumeric.h> #include <QtCore/qmath.h> #include <QtCore/QDateTime> @@ -78,25 +79,25 @@ ObjectCtor::ObjectCtor(ExecutionContext *scope) vtbl = &static_vtbl; } -Value ObjectCtor::construct(Managed *that, const CallData &d) +Value ObjectCtor::construct(Managed *that, CallData *callData) { ObjectCtor *ctor = static_cast<ObjectCtor *>(that); ExecutionEngine *v4 = that->engine(); - if (!d.argc || d.args[0].isUndefined() || d.args[0].isNull()) { + if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) { Object *obj = v4->newObject(); Value proto = ctor->get(v4->id_prototype); if (proto.isObject()) obj->setPrototype(proto.objectValue()); return Value::fromObject(obj); } - return __qmljs_to_object(v4->current, d.args[0]); + return __qmljs_to_object(v4->current, ValueRef(&callData->args[0])); } -Value ObjectCtor::call(Managed *m, const CallData &d) +Value ObjectCtor::call(Managed *m, CallData *callData) { - if (!d.argc || d.args[0].isUndefined() || d.args[0].isNull()) + if (!callData->argc || callData->args[0].isUndefined() || callData->args[0].isNull()) return Value::fromObject(m->engine()->newObject()); - return __qmljs_to_object(m->engine()->current, d.args[0]); + return __qmljs_to_object(m->engine()->current, ValueRef(&callData->args[0])); } void ObjectPrototype::init(ExecutionContext *ctx, const Value &ctor) @@ -372,7 +373,7 @@ Value ObjectPrototype::method_toString(SimpleCallContext *ctx) } else if (ctx->thisObject.isNull()) { return Value::fromString(ctx, QStringLiteral("[object Null]")); } else { - Value obj = __qmljs_to_object(ctx, ctx->thisObject); + Value obj = __qmljs_to_object(ctx, ValueRef(&ctx->thisObject)); QString className = obj.objectValue()->className(); return Value::fromString(ctx, QString::fromUtf8("[object %1]").arg(className)); } @@ -385,9 +386,9 @@ Value ObjectPrototype::method_toLocaleString(SimpleCallContext *ctx) FunctionObject *f = ts.asFunctionObject(); if (!f) ctx->throwTypeError(); - CALLDATA(0); - d.thisObject = Value::fromObject(o); - return f->call(d); + ScopedCallData callData(ctx->engine, 0); + callData->thisObject = Value::fromObject(o); + return f->call(callData); } Value ObjectPrototype::method_valueOf(SimpleCallContext *ctx) diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h index be51c41580..33a115f203 100644 --- a/src/qml/jsruntime/qv4objectproto_p.h +++ b/src/qml/jsruntime/qv4objectproto_p.h @@ -53,8 +53,8 @@ struct ObjectCtor: FunctionObject { ObjectCtor(ExecutionContext *scope); - static Value construct(Managed *that, const CallData &d); - static Value call(Managed *that, const CallData &d); + static Value construct(Managed *that, CallData *callData); + static Value call(Managed *that, CallData *callData); protected: static const ManagedVTable static_vtbl; diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index 9e80c82165..1e868ef3fe 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -62,6 +62,7 @@ #include <private/qv4objectproto_p.h> #include <private/qv4jsonobject_p.h> #include <private/qv4regexpobject_p.h> +#include <private/qv4scopedvalue_p.h> #include <QtQml/qjsvalue.h> #include <QtCore/qjsonarray.h> @@ -700,19 +701,19 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase QV4::ExecutionEngine *v4 = f->internalClass->engine; QV4::ExecutionContext *ctx = v4->current; - CALLDATA(argCount); - d.thisObject = This->thisObject.isEmpty() ? Value::fromObject(v4->globalObject) : This->thisObject.value(); + QV4::ScopedCallData callData(v4, argCount); + callData->thisObject = This->thisObject.isEmpty() ? Value::fromObject(v4->globalObject) : This->thisObject.value(); for (int ii = 0; ii < argCount; ++ii) { int type = argsTypes[ii + 1]; if (type == qMetaTypeId<QVariant>()) { - d.args[ii] = v4->v8Engine->fromVariant(*((QVariant *)metaArgs[ii + 1])); + callData->args[ii] = v4->v8Engine->fromVariant(*((QVariant *)metaArgs[ii + 1])); } else { - d.args[ii] = v4->v8Engine->fromVariant(QVariant(type, metaArgs[ii + 1])); + callData->args[ii] = v4->v8Engine->fromVariant(QVariant(type, metaArgs[ii + 1])); } } try { - f->call(d); + f->call(callData); } catch (QV4::Exception &e) { e.accept(ctx); QQmlError error; @@ -739,14 +740,15 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase return; } - QV4::Value function = *reinterpret_cast<QV4::Value*>(metaArgs[1]); - QV4::Value thisObject = *reinterpret_cast<QV4::Value*>(metaArgs[2]); + QV4::ValueScope scope(v4); + QV4::ScopedValue function(scope, *reinterpret_cast<QV4::Value*>(metaArgs[1])); + QV4::ScopedValue thisObject(scope, *reinterpret_cast<QV4::Value*>(metaArgs[2])); QObject *receiverToDisconnect = reinterpret_cast<QObject*>(metaArgs[3]); int slotIndexToDisconnect = *reinterpret_cast<int*>(metaArgs[4]); if (slotIndexToDisconnect != -1) { // This is a QObject function wrapper - if (connection->thisObject.isEmpty() == thisObject.isEmpty() && + if (connection->thisObject.isEmpty() == thisObject->isEmpty() && (connection->thisObject.isEmpty() || __qmljs_strict_equal(connection->thisObject, thisObject))) { QPair<QObject *, int> connectedFunctionData = extractQtMethod(connection->function.value().asFunctionObject()); @@ -759,7 +761,7 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase } else { // This is a normal JS function if (__qmljs_strict_equal(connection->function, function) && - connection->thisObject.isEmpty() == thisObject.isEmpty() && + connection->thisObject.isEmpty() == thisObject->isEmpty() && (connection->thisObject.isEmpty() || __qmljs_strict_equal(connection->thisObject, thisObject))) { *ret = true; return; @@ -1009,13 +1011,13 @@ private: namespace { struct CallArgs { - CallArgs(int length, QV4::Value *args) : _length(length), _args(args) {} + CallArgs(int length, const QV4::Value *args) : _length(length), _args(args) {} int Length() const { return _length; } QV4::Value operator[](int idx) { return _args[idx]; } private: int _length; - QV4::Value *_args; + const QV4::Value *_args; }; } @@ -1667,7 +1669,7 @@ QV4::Value QObjectMethod::method_toString(QV4::ExecutionContext *ctx) return QV4::Value::fromString(ctx, result); } -QV4::Value QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, Value *args, int argc) +QV4::Value QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) { if (!m_object) return QV4::Value::undefinedValue(); @@ -1686,17 +1688,17 @@ QV4::Value QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, Value *args return QV4::Value::undefinedValue(); } -Value QObjectMethod::call(Managed *m, const CallData &d) +Value QObjectMethod::call(Managed *m, CallData *callData) { QObjectMethod *This = static_cast<QObjectMethod*>(m); - return This->callInternal(d); + return This->callInternal(callData); } -Value QObjectMethod::callInternal(const CallData &d) +Value QObjectMethod::callInternal(CallData *callData) { ExecutionContext *context = engine()->current; if (m_index == DestroyMethod) - return method_destroy(context, d.args, d.argc); + return method_destroy(context, callData->args, callData->argc); else if (m_index == ToStringMethod) return method_toString(context); @@ -1731,7 +1733,7 @@ Value QObjectMethod::callInternal(const CallData &d) if (method.isV4Function()) { QV4::Value rv = QV4::Value::undefinedValue(); - QQmlV4Function func(d.argc, d.args, &rv, m_qmlGlobal.value(), + QQmlV4Function func(callData->argc, callData->args, &rv, m_qmlGlobal.value(), QmlContextWrapper::getContext(m_qmlGlobal.value()), v8Engine); QQmlV4Function *funcptr = &func; @@ -1742,7 +1744,7 @@ Value QObjectMethod::callInternal(const CallData &d) return rv; } - CallArgs callArgs(d.argc, d.args); + CallArgs callArgs(callData->argc, callData->args); if (!method.isOverload()) { return CallPrecise(object, method, v8Engine, callArgs); } else { diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 39af02f38b..3a48fee1ec 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -135,15 +135,15 @@ private: QObjectMethod(QV4::ExecutionContext *scope, QObject *object, int index, const QV4::Value &qmlGlobal); QV4::Value method_toString(QV4::ExecutionContext *ctx); - QV4::Value method_destroy(QV4::ExecutionContext *ctx, Value *args, int argc); + QV4::Value method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc); QPointer<QObject> m_object; int m_index; QV4::PersistentValue m_qmlGlobal; - static Value call(Managed *, const CallData &d); + static Value call(Managed *, CallData *callData); - Value callInternal(const CallData &d); + Value callInternal(CallData *callData); static void destroy(Managed *that) { diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index c213c78aeb..448d10180c 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -45,6 +45,7 @@ #include "qv4objectproto_p.h" #include "qv4stringobject_p.h" #include "qv4mm_p.h" +#include "qv4scopedvalue_p.h" #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> @@ -228,13 +229,15 @@ RegExpCtor::RegExpCtor(ExecutionContext *scope) vtbl = &static_vtbl; } -Value RegExpCtor::construct(Managed *m, const CallData &d) +Value RegExpCtor::construct(Managed *m, CallData *callData) { - Value r = d.argc > 0 ? d.args[0] : Value::undefinedValue(); - Value f = d.argc > 1 ? d.args[1] : Value::undefinedValue(); ExecutionContext *ctx = m->engine()->current; - if (RegExpObject *re = r.as<RegExpObject>()) { - if (!f.isUndefined()) + ValueScope scope(ctx); + + ScopedValue r(scope, callData->argc > 0 ? callData->args[0] : Value::undefinedValue()); + ScopedValue f(scope, callData->argc > 1 ? callData->args[1] : Value::undefinedValue()); + if (RegExpObject *re = r->as<RegExpObject>()) { + if (!f->isUndefined()) ctx->throwTypeError(); RegExpObject *o = ctx->engine->newRegExpObject(re->value, re->global); @@ -242,15 +245,15 @@ Value RegExpCtor::construct(Managed *m, const CallData &d) } QString pattern; - if (!r.isUndefined()) - pattern = r.toString(ctx)->toQString(); + if (!r->isUndefined()) + pattern = r->toString(ctx)->toQString(); bool global = false; bool ignoreCase = false; bool multiLine = false; - if (!f.isUndefined()) { + if (!f->isUndefined()) { f = __qmljs_to_string(f, ctx); - QString str = f.stringValue()->toQString(); + QString str = f->stringValue()->toQString(); for (int i = 0; i < str.length(); ++i) { if (str.at(i) == QChar('g') && !global) { global = true; @@ -272,14 +275,14 @@ Value RegExpCtor::construct(Managed *m, const CallData &d) return Value::fromObject(o); } -Value RegExpCtor::call(Managed *that, const CallData &d) +Value RegExpCtor::call(Managed *that, CallData *callData) { - if (d.argc > 0 && d.args[0].as<RegExpObject>()) { - if (d.argc == 1 || d.args[1].isUndefined()) - return d.args[0]; + if (callData->argc > 0 && callData->args[0].as<RegExpObject>()) { + if (callData->argc == 1 || callData->args[1].isUndefined()) + return callData->args[0]; } - return construct(that, d); + return construct(that, callData); } void RegExpPrototype::init(ExecutionContext *ctx, const Value &ctor) @@ -295,13 +298,15 @@ void RegExpPrototype::init(ExecutionContext *ctx, const Value &ctor) Value RegExpPrototype::method_exec(SimpleCallContext *ctx) { + ValueScope scope(ctx); + RegExpObject *r = ctx->thisObject.as<RegExpObject>(); if (!r) ctx->throwTypeError(); - Value arg = ctx->argument(0); + ScopedValue arg(scope, ctx->argument(0)); arg = __qmljs_to_string(arg, ctx); - QString s = arg.stringValue()->toQString(); + QString s = arg->stringValue()->toQString(); int offset = r->global ? r->lastIndexProperty(ctx)->value.toInt32() : 0; if (offset < 0 || offset > s.length()) { @@ -358,10 +363,9 @@ Value RegExpPrototype::method_compile(SimpleCallContext *ctx) if (!r) ctx->throwTypeError(); - CallData d; - d.args = ctx->arguments; - d.argc = ctx->argumentCount; - RegExpObject *re = ctx->engine->regExpCtor.asFunctionObject()->construct(d).as<RegExpObject>(); + ScopedCallData callData(ctx->engine, ctx->argumentCount); + memcpy(callData->args, ctx->arguments, ctx->argumentCount*sizeof(Value)); + RegExpObject *re = ctx->engine->regExpCtor.asFunctionObject()->construct(callData).as<RegExpObject>(); r->value = re->value; r->global = re->global; diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index 80868d90db..a17802e2ff 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -105,8 +105,8 @@ struct RegExpCtor: FunctionObject { RegExpCtor(ExecutionContext *scope); - static Value construct(Managed *m, const CallData &d); - static Value call(Managed *that, const CallData &d); + static Value construct(Managed *m, CallData *callData); + static Value call(Managed *that, CallData *callData); protected: static const ManagedVTable static_vtbl; diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 33521efb02..733f353330 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -51,6 +51,7 @@ #include "qv4function_p.h" #include "qv4exception_p.h" #include "private/qlocale_tools_p.h" +#include "qv4scopedvalue_p.h" #include <QtCore/qmath.h> #include <QtCore/qnumeric.h> @@ -119,17 +120,17 @@ void __qmljs_numberToString(QString *result, double num, int radix) result->prepend(QLatin1Char('-')); } -void __qmljs_init_closure(ExecutionContext *ctx, Value *result, int functionId) +void __qmljs_init_closure(ExecutionContext *ctx, ValueRef result, int functionId) { QV4::Function *clos = ctx->compilationUnit->runtimeFunctions[functionId]; assert(clos); *result = Value::fromObject(FunctionObject::creatScriptFunction(ctx, clos)); } -void __qmljs_delete_subscript(ExecutionContext *ctx, Value *result, const Value &base, const Value &index) +void __qmljs_delete_subscript(ExecutionContext *ctx, ValueRef result, const ValueRef base, const ValueRef index) { - if (Object *o = base.asObject()) { - uint n = index.asArrayIndex(); + if (Object *o = base->asObject()) { + uint n = index->asArrayIndex(); if (n < UINT_MAX) { Value res = Value::fromBoolean(o->deleteIndexedProperty(n)); if (result) @@ -138,35 +139,37 @@ void __qmljs_delete_subscript(ExecutionContext *ctx, Value *result, const Value } } - String *name = index.toString(ctx); + String *name = index->toString(ctx); __qmljs_delete_member(ctx, result, base, name); } -void __qmljs_delete_member(ExecutionContext *ctx, Value *result, const Value &base, String *name) +void __qmljs_delete_member(ExecutionContext *ctx, ValueRef result, const ValueRef base, String *name) { - Object *obj = base.toObject(ctx); + Object *obj = base->toObject(ctx); Value res = Value::fromBoolean(obj->deleteProperty(name)); if (result) *result = res; } -void __qmljs_delete_name(ExecutionContext *ctx, Value *result, String *name) +void __qmljs_delete_name(ExecutionContext *ctx, ValueRef result, String *name) { Value res = Value::fromBoolean(ctx->deleteProperty(name)); if (result) *result = res; } -void __qmljs_add_helper(ExecutionContext *ctx, Value *result, const Value &left, const Value &right) +void __qmljs_add_helper(ExecutionContext *ctx, ValueRef result, const ValueRef left, const ValueRef right) { - Value pleft = __qmljs_to_primitive(left, PREFERREDTYPE_HINT); - Value pright = __qmljs_to_primitive(right, PREFERREDTYPE_HINT); - if (pleft.isString() || pright.isString()) { - if (!pleft.isString()) + ValueScope scope(ctx); + + ScopedValue pleft(scope, __qmljs_to_primitive(left, PREFERREDTYPE_HINT)); + ScopedValue pright(scope, __qmljs_to_primitive(right, PREFERREDTYPE_HINT)); + if (pleft->isString() || pright->isString()) { + if (!pleft->isString()) pleft = __qmljs_to_string(pleft, ctx); - if (!pright.isString()) + if (!pright->isString()) pright = __qmljs_to_string(pright, ctx); - String *string = __qmljs_string_concat(ctx, pleft.stringValue(), pright.stringValue()); + String *string = __qmljs_string_concat(ctx, pleft->stringValue(), pright->stringValue()); *result = Value::fromString(string); return; } @@ -175,212 +178,223 @@ void __qmljs_add_helper(ExecutionContext *ctx, Value *result, const Value &left, *result = Value::fromDouble(x + y); } -void __qmljs_instanceof(ExecutionContext *ctx, Value *result, const Value &left, const Value &right) +void __qmljs_instanceof(ExecutionContext *ctx, ValueRef result, const ValueRef left, const ValueRef right) { - Object *o = right.asObject(); + Object *o = right->asObject(); if (!o) ctx->throwTypeError(); - bool r = o->hasInstance(left); + bool r = o->hasInstance(*left); *result = Value::fromBoolean(r); } -void __qmljs_in(ExecutionContext *ctx, Value *result, const Value &left, const Value &right) +void __qmljs_in(ExecutionContext *ctx, ValueRef result, const ValueRef left, const ValueRef right) { - if (!right.isObject()) + if (!right->isObject()) ctx->throwTypeError(); - String *s = left.toString(ctx); - bool r = right.objectValue()->__hasProperty__(s); + String *s = left->toString(ctx); + bool r = right->objectValue()->__hasProperty__(s); *result = Value::fromBoolean(r); } -void __qmljs_inplace_bit_and_name(ExecutionContext *ctx, String *name, const Value &value) +static void inplaceBitOp(ExecutionContext *ctx, String *name, const ValueRef value, BinOp op) +{ + ValueScope scope(ctx); + ScopedValue lhs(scope, ctx->getProperty(name)); + ScopedValue result(scope); + op(result, lhs, value); + ctx->setProperty(name, result); +} + + +void __qmljs_inplace_bit_and_name(ExecutionContext *ctx, String *name, const ValueRef value) { - ctx->inplaceBitOp(name, value, __qmljs_bit_and); + inplaceBitOp(ctx, name, value, __qmljs_bit_and); } -void __qmljs_inplace_bit_or_name(ExecutionContext *ctx, String *name, const Value &value) +void __qmljs_inplace_bit_or_name(ExecutionContext *ctx, String *name, const ValueRef value) { - ctx->inplaceBitOp(name, value, __qmljs_bit_or); + inplaceBitOp(ctx, name, value, __qmljs_bit_or); } -void __qmljs_inplace_bit_xor_name(ExecutionContext *ctx, String *name, const Value &value) +void __qmljs_inplace_bit_xor_name(ExecutionContext *ctx, String *name, const ValueRef value) { - ctx->inplaceBitOp(name, value, __qmljs_bit_xor); + inplaceBitOp(ctx, name, value, __qmljs_bit_xor); } -void __qmljs_inplace_add_name(ExecutionContext *ctx, String *name, const Value &value) +void __qmljs_inplace_add_name(ExecutionContext *ctx, String *name, const ValueRef value) { - Value lhs = ctx->getProperty(name); - Value result; - __qmljs_add(ctx, &result, lhs, value); + ValueScope scope(ctx); + ScopedValue lhs(scope, ctx->getProperty(name)); + ScopedValue result(scope); + __qmljs_add(ctx, result, lhs, value); ctx->setProperty(name, result); } -void __qmljs_inplace_sub_name(ExecutionContext *ctx, String *name, const Value &value) +void __qmljs_inplace_sub_name(ExecutionContext *ctx, String *name, const ValueRef value) { - ctx->inplaceBitOp(name, value, __qmljs_sub); + inplaceBitOp(ctx, name, value, __qmljs_sub); } -void __qmljs_inplace_mul_name(ExecutionContext *ctx, String *name, const Value &value) +void __qmljs_inplace_mul_name(ExecutionContext *ctx, String *name, const ValueRef value) { - ctx->inplaceBitOp(name, value, __qmljs_mul); + inplaceBitOp(ctx, name, value, __qmljs_mul); } -void __qmljs_inplace_div_name(ExecutionContext *ctx, String *name, const Value &value) +void __qmljs_inplace_div_name(ExecutionContext *ctx, String *name, const ValueRef value) { - ctx->inplaceBitOp(name, value, __qmljs_div); + inplaceBitOp(ctx, name, value, __qmljs_div); } -void __qmljs_inplace_mod_name(ExecutionContext *ctx, String *name, const Value &value) +void __qmljs_inplace_mod_name(ExecutionContext *ctx, String *name, const ValueRef value) { - ctx->inplaceBitOp(name, value, __qmljs_mod); + inplaceBitOp(ctx, name, value, __qmljs_mod); } -void __qmljs_inplace_shl_name(ExecutionContext *ctx, String *name, const Value &value) +void __qmljs_inplace_shl_name(ExecutionContext *ctx, String *name, const ValueRef value) { - ctx->inplaceBitOp(name, value, __qmljs_shl); + inplaceBitOp(ctx, name, value, __qmljs_shl); } -void __qmljs_inplace_shr_name(ExecutionContext *ctx, String *name, const Value &value) +void __qmljs_inplace_shr_name(ExecutionContext *ctx, String *name, const ValueRef value) { - ctx->inplaceBitOp(name, value, __qmljs_shr); + inplaceBitOp(ctx, name, value, __qmljs_shr); } -void __qmljs_inplace_ushr_name(ExecutionContext *ctx, String *name, const Value &value) +void __qmljs_inplace_ushr_name(ExecutionContext *ctx, String *name, const ValueRef value) { - ctx->inplaceBitOp(name, value, __qmljs_ushr); + inplaceBitOp(ctx, name, value, __qmljs_ushr); } -void __qmljs_inplace_bit_and_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs) +void __qmljs_inplace_bit_and_element(ExecutionContext *ctx, const ValueRef base, const ValueRef index, const ValueRef rhs) { - Object *obj = base.toObject(ctx); + Object *obj = base->toObject(ctx); obj->inplaceBinOp(ctx, __qmljs_bit_and, index, rhs); } -void __qmljs_inplace_bit_or_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs) +void __qmljs_inplace_bit_or_element(ExecutionContext *ctx, const ValueRef base, const ValueRef index, const ValueRef rhs) { - Object *obj = base.toObject(ctx); + Object *obj = base->toObject(ctx); obj->inplaceBinOp(ctx, __qmljs_bit_or, index, rhs); } -void __qmljs_inplace_bit_xor_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs) +void __qmljs_inplace_bit_xor_element(ExecutionContext *ctx, const ValueRef base, const ValueRef index, const ValueRef rhs) { - Object *obj = base.toObject(ctx); + Object *obj = base->toObject(ctx); obj->inplaceBinOp(ctx, __qmljs_bit_xor, index, rhs); } -void __qmljs_inplace_add_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs) +void __qmljs_inplace_add_element(ExecutionContext *ctx, const ValueRef base, const ValueRef index, const ValueRef rhs) { - Object *obj = base.toObject(ctx); + Object *obj = base->toObject(ctx); obj->inplaceBinOp(ctx, __qmljs_add, index, rhs); } -void __qmljs_inplace_sub_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs) +void __qmljs_inplace_sub_element(ExecutionContext *ctx, const ValueRef base, const ValueRef index, const ValueRef rhs) { - Object *obj = base.toObject(ctx); + Object *obj = base->toObject(ctx); obj->inplaceBinOp(ctx, __qmljs_sub, index, rhs); } -void __qmljs_inplace_mul_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs) +void __qmljs_inplace_mul_element(ExecutionContext *ctx, const ValueRef base, const ValueRef index, const ValueRef rhs) { - Object *obj = base.toObject(ctx); + Object *obj = base->toObject(ctx); obj->inplaceBinOp(ctx, __qmljs_mul, index, rhs); } -void __qmljs_inplace_div_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs) +void __qmljs_inplace_div_element(ExecutionContext *ctx, const ValueRef base, const ValueRef index, const ValueRef rhs) { - Object *obj = base.toObject(ctx); + Object *obj = base->toObject(ctx); obj->inplaceBinOp(ctx, __qmljs_div, index, rhs); } -void __qmljs_inplace_mod_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs) +void __qmljs_inplace_mod_element(ExecutionContext *ctx, const ValueRef base, const ValueRef index, const ValueRef rhs) { - Object *obj = base.toObject(ctx); + Object *obj = base->toObject(ctx); obj->inplaceBinOp(ctx, __qmljs_mod, index, rhs); } -void __qmljs_inplace_shl_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs) +void __qmljs_inplace_shl_element(ExecutionContext *ctx, const ValueRef base, const ValueRef index, const ValueRef rhs) { - Object *obj = base.toObject(ctx); + Object *obj = base->toObject(ctx); obj->inplaceBinOp(ctx, __qmljs_shl, index, rhs); } -void __qmljs_inplace_shr_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs) +void __qmljs_inplace_shr_element(ExecutionContext *ctx, const ValueRef base, const ValueRef index, const ValueRef rhs) { - Object *obj = base.toObject(ctx); + Object *obj = base->toObject(ctx); obj->inplaceBinOp(ctx, __qmljs_shr, index, rhs); } -void __qmljs_inplace_ushr_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs) +void __qmljs_inplace_ushr_element(ExecutionContext *ctx, const ValueRef base, const ValueRef index, const ValueRef rhs) { - Object *obj = base.toObject(ctx); + Object *obj = base->toObject(ctx); obj->inplaceBinOp(ctx, __qmljs_ushr, index, rhs); } -void __qmljs_inplace_bit_and_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs) +void __qmljs_inplace_bit_and_member(ExecutionContext *ctx, const ValueRef base, String *name, const ValueRef rhs) { - Object *o = base.toObject(ctx); + Object *o = base->toObject(ctx); o->inplaceBinOp(ctx, __qmljs_bit_and, name, rhs); } -void __qmljs_inplace_bit_or_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs) +void __qmljs_inplace_bit_or_member(ExecutionContext *ctx, const ValueRef base, String *name, const ValueRef rhs) { - Object *o = base.toObject(ctx); + Object *o = base->toObject(ctx); o->inplaceBinOp(ctx, __qmljs_bit_or, name, rhs); } -void __qmljs_inplace_bit_xor_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs) +void __qmljs_inplace_bit_xor_member(ExecutionContext *ctx, const ValueRef base, String *name, const ValueRef rhs) { - Object *o = base.toObject(ctx); + Object *o = base->toObject(ctx); o->inplaceBinOp(ctx, __qmljs_bit_xor, name, rhs); } -void __qmljs_inplace_add_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs) +void __qmljs_inplace_add_member(ExecutionContext *ctx, const ValueRef base, String *name, const ValueRef rhs) { - Object *o = base.toObject(ctx); + Object *o = base->toObject(ctx); o->inplaceBinOp(ctx, __qmljs_add, name, rhs); } -void __qmljs_inplace_sub_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs) +void __qmljs_inplace_sub_member(ExecutionContext *ctx, const ValueRef base, String *name, const ValueRef rhs) { - Object *o = base.toObject(ctx); + Object *o = base->toObject(ctx); o->inplaceBinOp(ctx, __qmljs_sub, name, rhs); } -void __qmljs_inplace_mul_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs) +void __qmljs_inplace_mul_member(ExecutionContext *ctx, const ValueRef base, String *name, const ValueRef rhs) { - Object *o = base.toObject(ctx); + Object *o = base->toObject(ctx); o->inplaceBinOp(ctx, __qmljs_mul, name, rhs); } -void __qmljs_inplace_div_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs) +void __qmljs_inplace_div_member(ExecutionContext *ctx, const ValueRef base, String *name, const ValueRef rhs) { - Object *o = base.toObject(ctx); + Object *o = base->toObject(ctx); o->inplaceBinOp(ctx, __qmljs_div, name, rhs); } -void __qmljs_inplace_mod_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs) +void __qmljs_inplace_mod_member(ExecutionContext *ctx, const ValueRef base, String *name, const ValueRef rhs) { - Object *o = base.toObject(ctx); + Object *o = base->toObject(ctx); o->inplaceBinOp(ctx, __qmljs_mod, name, rhs); } -void __qmljs_inplace_shl_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs) +void __qmljs_inplace_shl_member(ExecutionContext *ctx, const ValueRef base, String *name, const ValueRef rhs) { - Object *o = base.toObject(ctx); + Object *o = base->toObject(ctx); o->inplaceBinOp(ctx, __qmljs_shl, name, rhs); } -void __qmljs_inplace_shr_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs) +void __qmljs_inplace_shr_member(ExecutionContext *ctx, const ValueRef base, String *name, const ValueRef rhs) { - Object *o = base.toObject(ctx); + Object *o = base->toObject(ctx); o->inplaceBinOp(ctx, __qmljs_shr, name, rhs); } -void __qmljs_inplace_ushr_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs) +void __qmljs_inplace_ushr_member(ExecutionContext *ctx, const ValueRef base, String *name, const ValueRef rhs) { - Object *o = base.toObject(ctx); + Object *o = base->toObject(ctx); o->inplaceBinOp(ctx, __qmljs_ushr, name, rhs); } @@ -446,18 +460,18 @@ Value __qmljs_object_default_value(Object *object, int typeHint) Value conv = object->get(meth1); if (FunctionObject *o = conv.asFunctionObject()) { - CALLDATA(0); - d.thisObject = Value::fromObject(object); - Value r = o->call(d); + ScopedCallData callData(engine, 0); + callData->thisObject = Value::fromObject(object); + Value r = o->call(callData); if (r.isPrimitive()) return r; } conv = object->get(meth2); if (FunctionObject *o = conv.asFunctionObject()) { - CALLDATA(0); - d.thisObject = Value::fromObject(object); - Value r = o->call(d); + ScopedCallData callData(engine, 0); + callData->thisObject = Value::fromObject(object); + Value r = o->call(callData); if (r.isPrimitive()) return r; } @@ -466,74 +480,74 @@ Value __qmljs_object_default_value(Object *object, int typeHint) return Value::undefinedValue(); } -Bool __qmljs_to_boolean(const Value &value) +Bool __qmljs_to_boolean(const ValueRef value) { - return value.toBoolean(); + return value->toBoolean(); } -Object *__qmljs_convert_to_object(ExecutionContext *ctx, const Value &value) +Object *__qmljs_convert_to_object(ExecutionContext *ctx, const ValueRef value) { - assert(!value.isObject()); - switch (value.type()) { + assert(!value->isObject()); + switch (value->type()) { case Value::Undefined_Type: case Value::Null_Type: ctx->throwTypeError(); case Value::Boolean_Type: - return ctx->engine->newBooleanObject(value); + return ctx->engine->newBooleanObject(*value); case Value::String_Type: - return ctx->engine->newStringObject(value); + return ctx->engine->newStringObject(*value); break; case Value::Object_Type: Q_UNREACHABLE(); case Value::Integer_Type: default: // double - return ctx->engine->newNumberObject(value); + return ctx->engine->newNumberObject(*value); } } -String *__qmljs_convert_to_string(ExecutionContext *ctx, const Value &value) +String *__qmljs_convert_to_string(ExecutionContext *ctx, const ValueRef value) { - switch (value.type()) { + switch (value->type()) { case Value::Undefined_Type: return ctx->engine->id_undefined; case Value::Null_Type: return ctx->engine->id_null; case Value::Boolean_Type: - if (value.booleanValue()) + if (value->booleanValue()) return ctx->engine->id_true; else return ctx->engine->id_false; case Value::String_Type: - return value.stringValue(); + return value->stringValue(); case Value::Object_Type: { Value prim = __qmljs_to_primitive(value, STRING_HINT); if (prim.isPrimitive()) - return __qmljs_convert_to_string(ctx, prim); + return __qmljs_convert_to_string(ctx, ValueRef(&prim)); else ctx->throwTypeError(); } case Value::Integer_Type: - return __qmljs_string_from_number(ctx, value.int_32).stringValue(); + return __qmljs_string_from_number(ctx, value->int_32).stringValue(); default: // double - return __qmljs_string_from_number(ctx, value.doubleValue()).stringValue(); + return __qmljs_string_from_number(ctx, value->doubleValue()).stringValue(); } // switch } -void __qmljs_set_property(ExecutionContext *ctx, const Value &object, String *name, const Value &value) +void __qmljs_set_property(ExecutionContext *ctx, const ValueRef object, String *name, const ValueRef value) { - Object *o = object.toObject(ctx); - o->put(name, value); + Object *o = object->toObject(ctx); + o->put(name, *value); } -void __qmljs_get_element(ExecutionContext *ctx, Value *result, const Value &object, const Value &index) +void __qmljs_get_element(ExecutionContext *ctx, ValueRef result, const ValueRef object, const ValueRef index) { - uint idx = index.asArrayIndex(); + uint idx = index->asArrayIndex(); - Object *o = object.asObject(); + Object *o = object->asObject(); if (!o) { if (idx < UINT_MAX) { - if (String *str = object.asString()) { + if (String *str = object->asString()) { if (idx >= (uint)str->toQString().length()) { if (result) *result = Value::undefinedValue(); @@ -546,8 +560,8 @@ void __qmljs_get_element(ExecutionContext *ctx, Value *result, const Value &obje } } - if (object.isNull() || object.isUndefined()) { - QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQString()).arg(object.toQString()); + if (object->isNullOrUndefined()) { + QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index->toQString()).arg(object->toQString()); ctx->throwTypeError(message); } @@ -570,17 +584,17 @@ void __qmljs_get_element(ExecutionContext *ctx, Value *result, const Value &obje return; } - String *name = index.toString(ctx); + String *name = index->toString(ctx); Value res = o->get(name); if (result) *result = res; } -void __qmljs_set_element(ExecutionContext *ctx, const Value &object, const Value &index, const Value &value) +void __qmljs_set_element(ExecutionContext *ctx, const ValueRef object, const ValueRef index, const ValueRef value) { - Object *o = object.toObject(ctx); + Object *o = object->toObject(ctx); - uint idx = index.asArrayIndex(); + uint idx = index->asArrayIndex(); if (idx < UINT_MAX) { uint pidx = o->propertyIndexFromArrayIndex(idx); if (pidx < UINT_MAX) { @@ -592,7 +606,7 @@ void __qmljs_set_element(ExecutionContext *ctx, const Value &object, const Value Property *p = o->arrayData + pidx; if (!o->arrayAttributes || o->arrayAttributes[pidx].isData()) { - p->value = value; + p->value = *value; return; } @@ -604,55 +618,55 @@ void __qmljs_set_element(ExecutionContext *ctx, const Value &object, const Value return; } - CALLDATA(1); - d.args[0] = value; - d.thisObject = Value::fromObject(o); - setter->call(d); + ScopedCallData callData(ctx->engine, 1); + callData->thisObject = Value::fromObject(o); + callData->args[0] = *value; + setter->call(callData); return; } } - o->putIndexed(idx, value); + o->putIndexed(idx, *value); return; } - String *name = index.toString(ctx); - o->put(name, value); + String *name = index->toString(ctx); + o->put(name, *value); } -void __qmljs_foreach_iterator_object(ExecutionContext *ctx, Value *result, const Value &in) +void __qmljs_foreach_iterator_object(ExecutionContext *ctx, ValueRef result, const ValueRef in) { Object *o = 0; - if (!in.isNull() && !in.isUndefined()) - o = in.toObject(ctx); + if (!in->isNullOrUndefined()) + o = in->toObject(ctx); Object *it = ctx->engine->newForEachIteratorObject(ctx, o); *result = Value::fromObject(it); } -void __qmljs_foreach_next_property_name(Value *result, const Value &foreach_iterator) +void __qmljs_foreach_next_property_name(ValueRef result, const ValueRef foreach_iterator) { - assert(foreach_iterator.isObject()); + assert(foreach_iterator->isObject()); - ForEachIteratorObject *it = static_cast<ForEachIteratorObject *>(foreach_iterator.objectValue()); + ForEachIteratorObject *it = static_cast<ForEachIteratorObject *>(foreach_iterator->objectValue()); assert(it->as<ForEachIteratorObject>()); *result = it->nextPropertyName(); } -void __qmljs_set_activation_property(ExecutionContext *ctx, String *name, const Value &value) +void __qmljs_set_activation_property(ExecutionContext *ctx, String *name, const ValueRef value) { - ctx->setProperty(name, value); + ctx->setProperty(name, *value); } -void __qmljs_get_property(ExecutionContext *ctx, Value *result, const Value &object, String *name) +void __qmljs_get_property(ExecutionContext *ctx, ValueRef result, const ValueRef object, String *name) { Value res; - Managed *m = object.asManaged(); + Managed *m = object->asManaged(); if (m) { res = m->get(name); } else { - if (object.isNull() || object.isUndefined()) { - QString message = QStringLiteral("Cannot read property '%1' of %2").arg(name->toQString()).arg(object.toQString()); + if (object->isNullOrUndefined()) { + QString message = QStringLiteral("Cannot read property '%1' of %2").arg(name->toQString()).arg(object->toQString()); ctx->throwTypeError(message); } @@ -663,62 +677,64 @@ void __qmljs_get_property(ExecutionContext *ctx, Value *result, const Value &obj *result = res; } -void __qmljs_get_activation_property(ExecutionContext *ctx, Value *result, String *name) +void __qmljs_get_activation_property(ExecutionContext *ctx, ValueRef result, String *name) { *result = ctx->getProperty(name); } -uint __qmljs_equal_helper(const Value &x, const Value &y) +uint __qmljs_equal_helper(const ValueRef x, const ValueRef y) { - Q_ASSERT(x.type() != y.type()); + Q_ASSERT(x->type() != y->type()); - if (x.isNumber() && y.isNumber()) - return x.asDouble() == y.asDouble(); - if (x.isNull() && y.isUndefined()) { + if (x->isNumber() && y->isNumber()) + return x->asDouble() == y->asDouble(); + if (x->isNull() && y->isUndefined()) { return true; - } else if (x.isUndefined() && y.isNull()) { + } else if (x->isUndefined() && y->isNull()) { return true; - } else if (x.isNumber() && y.isString()) { + } else if (x->isNumber() && y->isString()) { double dy = __qmljs_to_number(y); - return x.asDouble() == dy; - } else if (x.isString() && y.isNumber()) { + return x->asDouble() == dy; + } else if (x->isString() && y->isNumber()) { double dx = __qmljs_to_number(x); - return dx == y.asDouble(); - } else if (x.isBoolean()) { - Value nx = Value::fromDouble((double) x.booleanValue()); - return __qmljs_cmp_eq(nx, y); - } else if (y.isBoolean()) { - Value ny = Value::fromDouble((double) y.booleanValue()); - return __qmljs_cmp_eq(x, ny); - } else if ((x.isNumber() || x.isString()) && y.isObject()) { + return dx == y->asDouble(); + } else if (x->isBoolean()) { + Value nx = Value::fromDouble((double) x->booleanValue()); + return __qmljs_cmp_eq(ValueRef(&nx), y); + } else if (y->isBoolean()) { + Value ny = Value::fromDouble((double) y->booleanValue()); + return __qmljs_cmp_eq(x, ValueRef(&ny)); + } else if ((x->isNumber() || x->isString()) && y->isObject()) { Value py = __qmljs_to_primitive(y, PREFERREDTYPE_HINT); - return __qmljs_cmp_eq(x, py); - } else if (x.isObject() && (y.isNumber() || y.isString())) { + return __qmljs_cmp_eq(x, ValueRef(&py)); + } else if (x->isObject() && (y->isNumber() || y->isString())) { Value px = __qmljs_to_primitive(x, PREFERREDTYPE_HINT); - return __qmljs_cmp_eq(px, y); + return __qmljs_cmp_eq(ValueRef(&px), y); } return false; } -Bool __qmljs_strict_equal(const Value &x, const Value &y) +Bool __qmljs_strict_equal(const ValueRef x, const ValueRef y) { TRACE2(x, y); - if (x.rawValue() == y.rawValue()) + if (x->rawValue() == y->rawValue()) // NaN != NaN - return (x.tag & QV4::Value::NotDouble_Mask) != QV4::Value::NaN_Mask; + return (x->tag & QV4::Value::NotDouble_Mask) != QV4::Value::NaN_Mask; - if (x.isNumber()) - return y.isNumber() && x.asDouble() == y.asDouble(); - if (x.isString()) - return y.isString() && x.stringValue()->isEqualTo(y.stringValue()); + if (x->isNumber()) + return y->isNumber() && x->asDouble() == y->asDouble(); + if (x->isString()) + return y->isString() && x->stringValue()->isEqualTo(y->stringValue()); return false; } -void __qmljs_call_global_lookup(ExecutionContext *context, Value *result, uint index, Value *args, int argc) +void __qmljs_call_global_lookup(ExecutionContext *context, ValueRef result, uint index, CallDataRef callData) { + Q_ASSERT(callData->thisObject.isUndefined()); + Lookup *l = context->lookups + index; Value v; l->globalGetter(l, context, &v); @@ -726,29 +742,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; } - CallData d; - d.thisObject = thisObject; - d.args = args; - d.argc = argc; - 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, ValueRef result, String *name, CallDataRef 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]"); @@ -758,110 +773,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; } - CallData d; - d.thisObject = thisObject; - d.args = args; - d.argc = argc; - 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, ValueRef result, String *name, CallDataRef 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, ValueRef(&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); } - CallData d; - d.thisObject = thisObject; - d.args = args; - d.argc = argc; - 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, ValueRef result, uint index, CallDataRef 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(); - CallData d; - d.thisObject = thisObject; - d.args = args; - d.argc = argc; - 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, ValueRef result, const ValueRef index, CallDataRef 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(); - CallData d; - d.thisObject = thisObject; - d.args = args; - d.argc = argc; - 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, ValueRef result, const ValueRef func, CallDataRef callData) { - Object *o = func.asObject(); + Object *o = func->asObject(); if (!o) context->throwTypeError(); - CallData d; - d.thisObject = thisObject ? *thisObject : Value::undefinedValue(); - d.args = args; - d.argc = argc; - 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, ValueRef result, uint index, CallDataRef callData) { + Q_ASSERT(callData->thisObject.isUndefined()); + Value func; Lookup *l = context->lookups + index; @@ -871,65 +864,60 @@ void __qmljs_construct_global_lookup(ExecutionContext *context, Value *result, u if (!f) context->throwTypeError(); - CallData d; - d.args = args; - d.argc = argc; - Value res = f->construct(d); + 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, ValueRef result, String *name, CallDataRef 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, ValueRef result, const ValueRef func, CallDataRef callData) { - if (Object *f = func.asObject()) { - CallData d; - d.args = args; - d.argc = argc; - 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, ValueRef result, const ValueRef base, String *name, CallDataRef callData) { - Object *thisObject = base.toObject(context); + Object *thisObject = base->toObject(context); Value func = thisObject->get(name); - if (Object *f = func.asObject()) { - CallData d; - d.args = args; - d.argc = argc; - 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) +void __qmljs_throw(ExecutionContext *context, const ValueRef value) { - Exception::throwException(context, value); + Exception::throwException(context, *value); } -void __qmljs_builtin_typeof(ExecutionContext *ctx, Value *result, const Value &value) +void __qmljs_builtin_typeof(ExecutionContext *ctx, ValueRef result, const ValueRef value) { if (!result) return; String *res = 0; - switch (value.type()) { + switch (value->type()) { case Value::Undefined_Type: res = ctx->engine->id_undefined; break; @@ -943,7 +931,7 @@ void __qmljs_builtin_typeof(ExecutionContext *ctx, Value *result, const Value &v res = ctx->engine->id_string; break; case Value::Object_Type: - if (value.objectValue()->asFunctionObject()) + if (value->objectValue()->asFunctionObject()) res = ctx->engine->id_function; else res = ctx->engine->id_object; // ### implementation-defined @@ -955,36 +943,41 @@ void __qmljs_builtin_typeof(ExecutionContext *ctx, Value *result, const Value &v *result = Value::fromString(res); } -void __qmljs_builtin_typeof_name(ExecutionContext *context, Value *result, String *name) +void __qmljs_builtin_typeof_name(ExecutionContext *context, ValueRef result, String *name) { - Value res; - __qmljs_builtin_typeof(context, &res, context->getPropertyNoThrow(name)); + ValueScope scope(context); + ScopedValue res(scope); + ScopedValue prop(scope, context->getPropertyNoThrow(name)); + __qmljs_builtin_typeof(context, res, prop); if (result) *result = res; } -void __qmljs_builtin_typeof_member(ExecutionContext *context, Value *result, const Value &base, +void __qmljs_builtin_typeof_member(ExecutionContext *context, ValueRef result, const ValueRef base, String *name) { - Object *obj = base.toObject(context); - Value res; - __qmljs_builtin_typeof(context, &res, obj->get(name)); + ValueScope scope(context); + Object *obj = base->toObject(context); + ScopedValue res(scope); + ScopedValue prop(scope, obj->get(name)); + __qmljs_builtin_typeof(context, res, prop); if (result) *result = res; } -void __qmljs_builtin_typeof_element(ExecutionContext *context, Value *result, const Value &base, - const Value &index) +void __qmljs_builtin_typeof_element(ExecutionContext *context, ValueRef result, const ValueRef base, const ValueRef index) { - String *name = index.toString(context); - Object *obj = base.toObject(context); - Value res; - __qmljs_builtin_typeof(context, &res, obj->get(name)); + ValueScope scope(context); + String *name = index->toString(context); + Object *obj = base->toObject(context); + ScopedValue res(scope); + ScopedValue prop(scope, obj->get(name)); + __qmljs_builtin_typeof(context, res, prop); if (result) *result = res; } -void __qmljs_builtin_post_increment(Value *result, Value *val) +void __qmljs_builtin_post_increment(ValueRef result, ValueRef val) { if (val->isInteger() && val->integerValue() < INT_MAX) { if (result) @@ -993,13 +986,13 @@ void __qmljs_builtin_post_increment(Value *result, Value *val) return; } - double d = __qmljs_to_number(*val); + double d = val->toNumber(); *val = Value::fromDouble(d + 1); if (result) *result = Value::fromDouble(d); } -void __qmljs_builtin_post_increment_name(ExecutionContext *context, Value *result, String *name) +void __qmljs_builtin_post_increment_name(ExecutionContext *context, ValueRef result, String *name) { Value v = context->getProperty(name); @@ -1008,7 +1001,7 @@ void __qmljs_builtin_post_increment_name(ExecutionContext *context, Value *resul *result = v; v.int_32 += 1; } else { - double d = __qmljs_to_number(v); + double d = v.toNumber(); if (result) *result = Value::fromDouble(d); v = Value::fromDouble(d + 1); @@ -1017,9 +1010,9 @@ void __qmljs_builtin_post_increment_name(ExecutionContext *context, Value *resul context->setProperty(name, v); } -void __qmljs_builtin_post_increment_member(ExecutionContext *context, Value *result, const Value &base, String *name) +void __qmljs_builtin_post_increment_member(ExecutionContext *context, ValueRef result, const ValueRef base, String *name) { - Object *o = base.toObject(context); + Object *o = base->toObject(context); Value v = o->get(name); @@ -1028,7 +1021,7 @@ void __qmljs_builtin_post_increment_member(ExecutionContext *context, Value *res *result = v; v.int_32 += 1; } else { - double d = __qmljs_to_number(v); + double d = v.toNumber(); if (result) *result = Value::fromDouble(d); v = Value::fromDouble(d + 1); @@ -1037,9 +1030,9 @@ void __qmljs_builtin_post_increment_member(ExecutionContext *context, Value *res o->put(name, v); } -void __qmljs_builtin_post_increment_element(ExecutionContext *context, Value *result, const Value &base, const Value *index) +void __qmljs_builtin_post_increment_element(ExecutionContext *context, ValueRef result, const ValueRef base, const ValueRef index) { - Object *o = base.toObject(context); + Object *o = base->toObject(context); uint idx = index->asArrayIndex(); @@ -1055,7 +1048,7 @@ void __qmljs_builtin_post_increment_element(ExecutionContext *context, Value *re *result = v; v.int_32 += 1; } else { - double d = __qmljs_to_number(v); + double d = v.toNumber(); if (result) *result = Value::fromDouble(d); v = Value::fromDouble(d + 1); @@ -1064,7 +1057,7 @@ void __qmljs_builtin_post_increment_element(ExecutionContext *context, Value *re o->putIndexed(idx, v); } -void __qmljs_builtin_post_decrement(Value *result, Value *val) +void __qmljs_builtin_post_decrement(ValueRef result, ValueRef val) { if (val->isInteger() && val->integerValue() > INT_MIN) { if (result) @@ -1073,13 +1066,13 @@ void __qmljs_builtin_post_decrement(Value *result, Value *val) return; } - double d = __qmljs_to_number(*val); + double d = val->toNumber(); *val = Value::fromDouble(d - 1); if (result) *result = Value::fromDouble(d); } -void __qmljs_builtin_post_decrement_name(ExecutionContext *context, Value *result, String *name) +void __qmljs_builtin_post_decrement_name(ExecutionContext *context, ValueRef result, String *name) { Value v = context->getProperty(name); @@ -1088,7 +1081,7 @@ void __qmljs_builtin_post_decrement_name(ExecutionContext *context, Value *resul *result = v; v.int_32 -= 1; } else { - double d = __qmljs_to_number(v); + double d = v.toNumber(); if (result) *result = Value::fromDouble(d); v = Value::fromDouble(d - 1); @@ -1097,9 +1090,9 @@ void __qmljs_builtin_post_decrement_name(ExecutionContext *context, Value *resul context->setProperty(name, v); } -void __qmljs_builtin_post_decrement_member(ExecutionContext *context, Value *result, const Value &base, String *name) +void __qmljs_builtin_post_decrement_member(ExecutionContext *context, ValueRef result, const ValueRef base, String *name) { - Object *o = base.toObject(context); + Object *o = base->toObject(context); Value v = o->get(name); @@ -1108,7 +1101,7 @@ void __qmljs_builtin_post_decrement_member(ExecutionContext *context, Value *res *result = v; v.int_32 -= 1; } else { - double d = __qmljs_to_number(v); + double d = v.toNumber(); if (result) *result = Value::fromDouble(d); v = Value::fromDouble(d - 1); @@ -1117,14 +1110,14 @@ void __qmljs_builtin_post_decrement_member(ExecutionContext *context, Value *res o->put(name, v); } -void __qmljs_builtin_post_decrement_element(ExecutionContext *context, Value *result, const Value &base, const Value &index) +void __qmljs_builtin_post_decrement_element(ExecutionContext *context, ValueRef result, const ValueRef base, const ValueRef index) { - Object *o = base.toObject(context); + Object *o = base->toObject(context); - uint idx = index.asArrayIndex(); + uint idx = index->asArrayIndex(); if (idx == UINT_MAX) { - String *s = index.toString(context); + String *s = index->toString(context); return __qmljs_builtin_post_decrement_member(context, result, base, s); } @@ -1135,7 +1128,7 @@ void __qmljs_builtin_post_decrement_element(ExecutionContext *context, Value *re *result = v; v.int_32 -= 1; } else { - double d = __qmljs_to_number(v); + double d = v.toNumber(); if (result) *result = Value::fromDouble(d); v = Value::fromDouble(d - 1); @@ -1144,15 +1137,15 @@ void __qmljs_builtin_post_decrement_element(ExecutionContext *context, Value *re o->putIndexed(idx, v); } -ExecutionContext *__qmljs_builtin_push_with_scope(const Value &o, ExecutionContext *ctx) +ExecutionContext *__qmljs_builtin_push_with_scope(const ValueRef o, ExecutionContext *ctx) { - Object *obj = o.toObject(ctx); + Object *obj = o->toObject(ctx); return ctx->newWithContext(obj); } -ExecutionContext *__qmljs_builtin_push_catch_scope(String *exceptionVarName, const Value &exceptionValue, ExecutionContext *ctx) +ExecutionContext *__qmljs_builtin_push_catch_scope(String *exceptionVarName, const ValueRef exceptionValue, ExecutionContext *ctx) { - return ctx->newCatchContext(exceptionVarName, exceptionValue); + return ctx->newCatchContext(exceptionVarName, *exceptionValue); } ExecutionContext *__qmljs_builtin_pop_scope(ExecutionContext *ctx) @@ -1165,9 +1158,9 @@ void __qmljs_builtin_declare_var(ExecutionContext *ctx, bool deletable, String * ctx->createMutableBinding(name, deletable); } -void __qmljs_builtin_define_property(ExecutionContext *ctx, const Value &object, String *name, Value *val) +void __qmljs_builtin_define_property(ExecutionContext *ctx, const ValueRef object, String *name, ValueRef val) { - Object *o = object.asObject(); + Object *o = object->asObject(); assert(o); uint idx = name->asArrayIndex(); @@ -1175,7 +1168,7 @@ void __qmljs_builtin_define_property(ExecutionContext *ctx, const Value &object, pd->value = val ? *val : Value::undefinedValue(); } -void __qmljs_builtin_define_array(ExecutionContext *ctx, Value *array, Value *values, uint length) +void __qmljs_builtin_define_array(ExecutionContext *ctx, ValueRef array, Value *values, uint length) { ArrayObject *a = ctx->engine->newArrayObject(); @@ -1200,9 +1193,9 @@ void __qmljs_builtin_define_array(ExecutionContext *ctx, Value *array, Value *va *array = Value::fromObject(a); } -void __qmljs_builtin_define_getter_setter(ExecutionContext *ctx, const Value &object, String *name, const Value *getter, const Value *setter) +void __qmljs_builtin_define_getter_setter(ExecutionContext *ctx, const ValueRef object, String *name, const ValueRef getter, const ValueRef setter) { - Object *o = object.asObject(); + Object *o = object->asObject(); assert(o); uint idx = name->asArrayIndex(); @@ -1211,7 +1204,7 @@ void __qmljs_builtin_define_getter_setter(ExecutionContext *ctx, const Value &ob pd->setSetter(setter ? setter->asFunctionObject() : 0); } -void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value *args, int classId) +void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, ValueRef result, const QV4::Value *args, int classId) { QV4::InternalClass *klass = ctx->compilationUnit->runtimeClasses[classId]; Object *o = ctx->engine->newObject(klass); @@ -1230,7 +1223,7 @@ 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) +void __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx, ValueRef result) { assert(ctx->type >= ExecutionContext::Type_CallContext); CallContext *c = static_cast<CallContext *>(ctx); @@ -1238,38 +1231,38 @@ void __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx, Value *result *result = Value::fromObject(args); } -void __qmljs_increment(Value *result, const Value &value) +void __qmljs_increment(QV4::ValueRef result, const QV4::ValueRef value) { TRACE1(value); - if (value.isInteger()) - *result = Value::fromInt32(value.integerValue() + 1); + if (value->isInteger()) + *result = Value::fromInt32(value->integerValue() + 1); else { - double d = __qmljs_to_number(value); + double d = value->toNumber(); *result = Value::fromDouble(d + 1); } } -void __qmljs_decrement(Value *result, const Value &value) +void __qmljs_decrement(QV4::ValueRef result, const QV4::ValueRef value) { TRACE1(value); - if (value.isInteger()) - *result = Value::fromInt32(value.integerValue() - 1); + if (value->isInteger()) + *result = Value::fromInt32(value->integerValue() - 1); else { - double d = __qmljs_to_number(value); + double d = value->toNumber(); *result = Value::fromDouble(d - 1); } } -void __qmljs_value_to_double(double *result, const Value &value) +void __qmljs_value_to_double(double *result, const ValueRef value) { - *result = __qmljs_to_number(value); + *result = value->toNumber(); } -int __qmljs_value_to_int32(const Value &value) +int __qmljs_value_to_int32(const ValueRef value) { - return value.toInt32(); + return value->toInt32(); } int __qmljs_double_to_int32(const double &d) @@ -1277,9 +1270,9 @@ int __qmljs_double_to_int32(const double &d) return Value::toInt32(d); } -unsigned __qmljs_value_to_uint32(const Value &value) +unsigned __qmljs_value_to_uint32(const ValueRef value) { - return value.toUInt32(); + return value->toUInt32(); } unsigned __qmljs_double_to_uint32(const double &d) @@ -1287,12 +1280,12 @@ unsigned __qmljs_double_to_uint32(const double &d) return Value::toUInt32(d); } -void __qmljs_value_from_string(Value *result, String *string) +void __qmljs_value_from_string(ValueRef result, String *string) { *result = Value::fromString(string); } -void __qmljs_lookup_runtime_regexp(ExecutionContext *ctx, Value *result, int id) +void __qmljs_lookup_runtime_regexp(ExecutionContext *ctx, ValueRef result, int id) { *result = ctx->compilationUnit->runtimeRegularExpressions[id]; } diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index b38f833ad0..d1ca86fddd 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -44,7 +44,7 @@ #include "qv4global_p.h" #include "qv4value_p.h" #include "qv4math_p.h" - +#include "qv4scopedvalue_p.h" #include <QtCore/QString> #include <QtCore/qnumeric.h> @@ -91,47 +91,47 @@ 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_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_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); -void __qmljs_builtin_typeof_member(QV4::ExecutionContext* context, QV4::Value* result, const QV4::Value &base, QV4::String *name); -void __qmljs_builtin_typeof_element(QV4::ExecutionContext* context, QV4::Value *result, const QV4::Value &base, const QV4::Value &index); - -void __qmljs_builtin_post_increment(QV4::Value *result, QV4::Value *val); -void __qmljs_builtin_post_increment_name(QV4::ExecutionContext *context, QV4::Value *result, QV4::String *name); -void __qmljs_builtin_post_increment_member(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &base, QV4::String *name); -void __qmljs_builtin_post_increment_element(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &base, const QV4::Value *index); - -void __qmljs_builtin_post_decrement(QV4::Value *result, QV4::Value *val); -void __qmljs_builtin_post_decrement_name(QV4::ExecutionContext *context, QV4::Value *result, QV4::String *name); -void __qmljs_builtin_post_decrement_member(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &base, QV4::String *name); -void __qmljs_builtin_post_decrement_element(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &base, const QV4::Value &index); +void __qmljs_call_activation_property(QV4::ExecutionContext *, QV4::ValueRef result, QV4::String *name, CallDataRef callData); +void __qmljs_call_property(QV4::ExecutionContext *context, QV4::ValueRef result, QV4::String *name, CallDataRef callData); +void __qmljs_call_property_lookup(ExecutionContext *context, ValueRef result, uint index, CallDataRef callData); +void __qmljs_call_element(ExecutionContext *context, ValueRef result, const ValueRef index, CallDataRef callData); +void __qmljs_call_value(QV4::ExecutionContext *context, QV4::ValueRef result, const QV4::ValueRef func, CallDataRef callData); + +void __qmljs_construct_activation_property(QV4::ExecutionContext *, QV4::ValueRef result, QV4::String *name, CallDataRef callData); +void __qmljs_construct_property(QV4::ExecutionContext *context, QV4::ValueRef result, const QV4::ValueRef base, QV4::String *name, CallDataRef callData); +void __qmljs_construct_value(QV4::ExecutionContext *context, QV4::ValueRef result, const QV4::ValueRef func, CallDataRef callData); + +void __qmljs_builtin_typeof(QV4::ExecutionContext *ctx, QV4::ValueRef result, const QV4::ValueRef val); +void __qmljs_builtin_typeof_name(QV4::ExecutionContext *context, QV4::ValueRef result, QV4::String *name); +void __qmljs_builtin_typeof_member(QV4::ExecutionContext* context, QV4::ValueRef result, const QV4::ValueRef base, QV4::String *name); +void __qmljs_builtin_typeof_element(QV4::ExecutionContext* context, QV4::ValueRef result, const QV4::ValueRef base, const QV4::ValueRef index); + +void __qmljs_builtin_post_increment(QV4::ValueRef result, QV4::ValueRef val); +void __qmljs_builtin_post_increment_name(QV4::ExecutionContext *context, QV4::ValueRef result, QV4::String *name); +void __qmljs_builtin_post_increment_member(QV4::ExecutionContext *context, QV4::ValueRef result, const QV4::ValueRef base, QV4::String *name); +void __qmljs_builtin_post_increment_element(QV4::ExecutionContext *context, QV4::ValueRef result, const QV4::ValueRef base, const QV4::ValueRef index); + +void __qmljs_builtin_post_decrement(QV4::ValueRef result, QV4::ValueRef val); +void __qmljs_builtin_post_decrement_name(QV4::ExecutionContext *context, QV4::ValueRef result, QV4::String *name); +void __qmljs_builtin_post_decrement_member(QV4::ExecutionContext *context, QV4::ValueRef result, const QV4::ValueRef base, QV4::String *name); +void __qmljs_builtin_post_decrement_element(QV4::ExecutionContext *context, QV4::ValueRef result, const QV4::ValueRef base, const QV4::ValueRef index); void Q_NORETURN __qmljs_builtin_rethrow(QV4::ExecutionContext *context); -QV4::ExecutionContext *__qmljs_builtin_push_with_scope(const QV4::Value &o, QV4::ExecutionContext *ctx); -QV4::ExecutionContext *__qmljs_builtin_push_catch_scope(QV4::String *exceptionVarName, const QV4::Value &exceptionValue, QV4::ExecutionContext *ctx); +QV4::ExecutionContext *__qmljs_builtin_push_with_scope(const QV4::ValueRef o, QV4::ExecutionContext *ctx); +QV4::ExecutionContext *__qmljs_builtin_push_catch_scope(QV4::String *exceptionVarName, const QV4::ValueRef exceptionValue, QV4::ExecutionContext *ctx); QV4::ExecutionContext *__qmljs_builtin_pop_scope(QV4::ExecutionContext *ctx); void __qmljs_builtin_declare_var(QV4::ExecutionContext *ctx, bool deletable, QV4::String *name); -void __qmljs_builtin_define_property(QV4::ExecutionContext *ctx, const QV4::Value &object, QV4::String *name, QV4::Value *val); -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, int classId); -void __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx, QV4::Value *result); +void __qmljs_builtin_define_property(QV4::ExecutionContext *ctx, const QV4::ValueRef object, QV4::String *name, QV4::ValueRef val); +void __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, QV4::ValueRef array, QV4::Value *values, uint length); +void __qmljs_builtin_define_getter_setter(QV4::ExecutionContext *ctx, const QV4::ValueRef object, QV4::String *name, const QV4::ValueRef getter, const QV4::ValueRef setter); +void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::ValueRef result, const QV4::Value *args, int classId); +void __qmljs_builtin_setup_arguments_object(ExecutionContext *ctx, QV4::ValueRef result); -void __qmljs_value_from_string(QV4::Value *result, QV4::String *string); -void __qmljs_lookup_runtime_regexp(QV4::ExecutionContext *ctx, QV4::Value *result, int id); +void __qmljs_value_from_string(QV4::ValueRef result, QV4::String *string); +void __qmljs_lookup_runtime_regexp(QV4::ExecutionContext *ctx, QV4::ValueRef result, int id); // constructors -void __qmljs_init_closure(QV4::ExecutionContext *ctx, QV4::Value *result, int functionId); +void __qmljs_init_closure(QV4::ExecutionContext *ctx, QV4::ValueRef result, int functionId); // strings Q_QML_EXPORT double __qmljs_string_to_number(const QString &s); @@ -140,192 +140,172 @@ QV4::String *__qmljs_string_concat(QV4::ExecutionContext *ctx, QV4::String *firs // objects Q_QML_EXPORT QV4::Value __qmljs_object_default_value(QV4::Object *object, int typeHint); -void __qmljs_set_activation_property(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value& value); -void __qmljs_set_property(QV4::ExecutionContext *ctx, const QV4::Value &object, QV4::String *name, const QV4::Value &value); -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_set_activation_property(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::ValueRef value); +void __qmljs_set_property(QV4::ExecutionContext *ctx, const QV4::ValueRef object, QV4::String *name, const QV4::ValueRef value); +void __qmljs_get_property(QV4::ExecutionContext *ctx, QV4::ValueRef result, const QV4::ValueRef object, QV4::String *name); +void __qmljs_get_activation_property(QV4::ExecutionContext *ctx, QV4::ValueRef 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::ValueRef result, uint index, CallDataRef callData); +void __qmljs_construct_global_lookup(QV4::ExecutionContext *context, QV4::ValueRef result, uint index, CallDataRef callData); -void __qmljs_get_element(QV4::ExecutionContext *ctx, QV4::Value *retval, const QV4::Value &object, const QV4::Value &index); -void __qmljs_set_element(QV4::ExecutionContext *ctx, const QV4::Value &object, const QV4::Value &index, const QV4::Value &value); +void __qmljs_get_element(QV4::ExecutionContext *ctx, QV4::ValueRef retval, const QV4::ValueRef object, const QV4::ValueRef index); +void __qmljs_set_element(QV4::ExecutionContext *ctx, const QV4::ValueRef object, const QV4::ValueRef index, const QV4::ValueRef value); // For each -void __qmljs_foreach_iterator_object(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &in); -void __qmljs_foreach_next_property_name(QV4::Value *result, const QV4::Value &foreach_iterator); +void __qmljs_foreach_iterator_object(QV4::ExecutionContext *ctx, QV4::ValueRef result, const QV4::ValueRef in); +void __qmljs_foreach_next_property_name(QV4::ValueRef result, const ValueRef foreach_iterator); // type conversion and testing -QV4::Value __qmljs_to_primitive(const QV4::Value &value, int typeHint); -Q_QML_EXPORT QV4::Bool __qmljs_to_boolean(const QV4::Value &value); -double __qmljs_to_number(const QV4::Value &value); -QV4::Value __qmljs_to_string(const QV4::Value &value, QV4::ExecutionContext *ctx); -Q_QML_EXPORT QV4::String *__qmljs_convert_to_string(QV4::ExecutionContext *ctx, const QV4::Value &value); +QV4::Value __qmljs_to_primitive(const ValueRef value, int typeHint); +Q_QML_EXPORT QV4::Bool __qmljs_to_boolean(const QV4::ValueRef value); +double __qmljs_to_number(const QV4::ValueRef value); +QV4::Value __qmljs_to_string(const ValueRef value, QV4::ExecutionContext *ctx); +Q_QML_EXPORT QV4::String *__qmljs_convert_to_string(QV4::ExecutionContext *ctx, const ValueRef value); void __qmljs_numberToString(QString *result, double num, int radix = 10); -QV4::Value __qmljs_to_object(QV4::ExecutionContext *ctx, const QV4::Value &value); -QV4::Object *__qmljs_convert_to_object(QV4::ExecutionContext *ctx, const QV4::Value &value); +QV4::Value __qmljs_to_object(QV4::ExecutionContext *ctx, const ValueRef value); +QV4::Object *__qmljs_convert_to_object(QV4::ExecutionContext *ctx, const ValueRef value); -QV4::Bool __qmljs_equal_helper(const Value &x, const Value &y); -Q_QML_EXPORT QV4::Bool __qmljs_strict_equal(const QV4::Value &x, const QV4::Value &y); +QV4::Bool __qmljs_equal_helper(const ValueRef x, const ValueRef y); +Q_QML_EXPORT QV4::Bool __qmljs_strict_equal(const ValueRef x, const ValueRef y); // unary operators -typedef void (*UnaryOpName)(QV4::Value *, const QV4::Value &); -void __qmljs_uplus(QV4::Value *result, const QV4::Value &value); -void __qmljs_uminus(QV4::Value *result, const QV4::Value &value); -void __qmljs_compl(QV4::Value *result, const QV4::Value &value); -void __qmljs_not(QV4::Value *result, const QV4::Value &value); -void __qmljs_increment(QV4::Value *result, const QV4::Value &value); -void __qmljs_decrement(QV4::Value *result, const QV4::Value &value); - -Q_QML_EXPORT void __qmljs_value_to_double(double *result, const Value &value); -Q_QML_EXPORT int __qmljs_value_to_int32(const Value &value); +typedef void (*UnaryOpName)(QV4::ValueRef, const QV4::ValueRef); +void __qmljs_uplus(QV4::ValueRef result, const QV4::ValueRef value); +void __qmljs_uminus(QV4::ValueRef result, const QV4::ValueRef value); +void __qmljs_compl(QV4::ValueRef result, const QV4::ValueRef value); +void __qmljs_not(QV4::ValueRef result, const QV4::ValueRef value); +void __qmljs_increment(QV4::ValueRef result, const QV4::ValueRef value); +void __qmljs_decrement(QV4::ValueRef result, const QV4::ValueRef value); + +Q_QML_EXPORT void __qmljs_value_to_double(double *result, const ValueRef value); +Q_QML_EXPORT int __qmljs_value_to_int32(const ValueRef value); Q_QML_EXPORT int __qmljs_double_to_int32(const double &d); -Q_QML_EXPORT unsigned __qmljs_value_to_uint32(const Value &value); +Q_QML_EXPORT unsigned __qmljs_value_to_uint32(const ValueRef value); Q_QML_EXPORT unsigned __qmljs_double_to_uint32(const double &d); -void __qmljs_delete_subscript(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &base, const QV4::Value &index); -void __qmljs_delete_member(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &base, QV4::String *name); -void __qmljs_delete_name(QV4::ExecutionContext *ctx, QV4::Value *result, QV4::String *name); +void __qmljs_delete_subscript(QV4::ExecutionContext *ctx, QV4::ValueRef result, const QV4::ValueRef base, const QV4::ValueRef index); +void __qmljs_delete_member(QV4::ExecutionContext *ctx, QV4::ValueRef result, const QV4::ValueRef base, QV4::String *name); +void __qmljs_delete_name(QV4::ExecutionContext *ctx, QV4::ValueRef result, QV4::String *name); -void Q_NORETURN __qmljs_throw(QV4::ExecutionContext*, const QV4::Value &value); +void Q_NORETURN __qmljs_throw(QV4::ExecutionContext*, const QV4::ValueRef value); // binary operators -typedef void (*BinOp)(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -typedef void (*BinOpContext)(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right); - -void __qmljs_instanceof(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_in(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_add(ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_bit_or(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_bit_xor(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_bit_and(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_sub(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_mul(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_div(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_mod(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_shl(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_shr(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_ushr(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_gt(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_lt(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_ge(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_le(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_eq(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_ne(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_se(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); -void __qmljs_sne(QV4::Value *result, const QV4::Value &left, const QV4::Value &right); - -void __qmljs_add_helper(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right); - - -typedef void (*InplaceBinOpName)(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value); -void __qmljs_inplace_bit_and_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value); -void __qmljs_inplace_bit_or_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value); -void __qmljs_inplace_bit_xor_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value); -void __qmljs_inplace_add_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value); -void __qmljs_inplace_sub_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value); -void __qmljs_inplace_mul_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value); -void __qmljs_inplace_div_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value); -void __qmljs_inplace_mod_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value); -void __qmljs_inplace_shl_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value); -void __qmljs_inplace_shr_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value); -void __qmljs_inplace_ushr_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value); - -typedef void (*InplaceBinOpElement)(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs); -void __qmljs_inplace_bit_and_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs); -void __qmljs_inplace_bit_or_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs); -void __qmljs_inplace_bit_xor_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs); -void __qmljs_inplace_add_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs); -void __qmljs_inplace_sub_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs); -void __qmljs_inplace_mul_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs); -void __qmljs_inplace_div_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs); -void __qmljs_inplace_mod_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs); -void __qmljs_inplace_shl_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs); -void __qmljs_inplace_shr_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs); -void __qmljs_inplace_ushr_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs); - -typedef void (*InplaceBinOpMember)(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs); -void __qmljs_inplace_bit_and_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs); -void __qmljs_inplace_bit_or_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs); -void __qmljs_inplace_bit_xor_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs); -void __qmljs_inplace_add_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs); -void __qmljs_inplace_sub_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs); -void __qmljs_inplace_mul_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs); -void __qmljs_inplace_div_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs); -void __qmljs_inplace_mod_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs); -void __qmljs_inplace_shl_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs); -void __qmljs_inplace_shr_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs); -void __qmljs_inplace_ushr_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs); - -typedef QV4::Bool (*CmpOp)(const QV4::Value &left, const QV4::Value &right); -QV4::Bool __qmljs_cmp_gt(const QV4::Value &left, const QV4::Value &right); -QV4::Bool __qmljs_cmp_lt(const QV4::Value &left, const QV4::Value &right); -QV4::Bool __qmljs_cmp_ge(const QV4::Value &left, const QV4::Value &right); -QV4::Bool __qmljs_cmp_le(const QV4::Value &left, const QV4::Value &right); -QV4::Bool __qmljs_cmp_eq(const QV4::Value &left, const QV4::Value &right); -QV4::Bool __qmljs_cmp_ne(const QV4::Value &left, const QV4::Value &right); -QV4::Bool __qmljs_cmp_se(const QV4::Value &left, const QV4::Value &right); -QV4::Bool __qmljs_cmp_sne(const QV4::Value &left, const QV4::Value &right); - -typedef QV4::Bool (*CmpOpContext)(QV4::ExecutionContext *ctx, const QV4::Value &left, const QV4::Value &right); -QV4::Bool __qmljs_cmp_instanceof(QV4::ExecutionContext *ctx, const QV4::Value &left, const QV4::Value &right); -QV4::Bool __qmljs_cmp_in(QV4::ExecutionContext *ctx, const QV4::Value &left, const QV4::Value &right); +typedef void (*BinOp)(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +typedef void (*BinOpContext)(QV4::ExecutionContext *ctx, QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); + +void __qmljs_instanceof(QV4::ExecutionContext *ctx, QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_in(QV4::ExecutionContext *ctx, QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_add(ExecutionContext *ctx, QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_bit_or(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_bit_xor(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_bit_and(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_sub(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_mul(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_div(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_mod(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_shl(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_shr(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_ushr(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_gt(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_lt(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_ge(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_le(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_eq(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_ne(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_se(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); +void __qmljs_sne(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); + +void __qmljs_add_helper(QV4::ExecutionContext *ctx, QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right); + + +typedef void (*InplaceBinOpName)(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::ValueRef value); +void __qmljs_inplace_bit_and_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::ValueRef value); +void __qmljs_inplace_bit_or_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::ValueRef value); +void __qmljs_inplace_bit_xor_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::ValueRef value); +void __qmljs_inplace_add_name(QV4::ExecutionContext *ctx, QV4::String *name, const ValueRef value); +void __qmljs_inplace_sub_name(QV4::ExecutionContext *ctx, QV4::String *name, const ValueRef value); +void __qmljs_inplace_mul_name(QV4::ExecutionContext *ctx, QV4::String *name, const ValueRef value); +void __qmljs_inplace_div_name(QV4::ExecutionContext *ctx, QV4::String *name, const ValueRef value); +void __qmljs_inplace_mod_name(QV4::ExecutionContext *ctx, QV4::String *name, const ValueRef value); +void __qmljs_inplace_shl_name(QV4::ExecutionContext *ctx, QV4::String *name, const ValueRef value); +void __qmljs_inplace_shr_name(QV4::ExecutionContext *ctx, QV4::String *name, const ValueRef value); +void __qmljs_inplace_ushr_name(QV4::ExecutionContext *ctx, QV4::String *name, const ValueRef value); + +typedef void (*InplaceBinOpElement)(QV4::ExecutionContext *ctx, const QV4::ValueRef base, const QV4::ValueRef index, const QV4::ValueRef rhs); +void __qmljs_inplace_bit_and_element(QV4::ExecutionContext *ctx, const QV4::ValueRef base, const QV4::ValueRef index, const QV4::ValueRef rhs); +void __qmljs_inplace_bit_or_element(QV4::ExecutionContext *ctx, const QV4::ValueRef base, const QV4::ValueRef index, const QV4::ValueRef rhs); +void __qmljs_inplace_bit_xor_element(QV4::ExecutionContext *ctx, const QV4::ValueRef base, const QV4::ValueRef index, const QV4::ValueRef rhs); +void __qmljs_inplace_add_element(QV4::ExecutionContext *ctx, const QV4::ValueRef base, const QV4::ValueRef index, const QV4::ValueRef rhs); +void __qmljs_inplace_sub_element(QV4::ExecutionContext *ctx, const QV4::ValueRef base, const QV4::ValueRef index, const QV4::ValueRef rhs); +void __qmljs_inplace_mul_element(QV4::ExecutionContext *ctx, const QV4::ValueRef base, const QV4::ValueRef index, const QV4::ValueRef rhs); +void __qmljs_inplace_div_element(QV4::ExecutionContext *ctx, const QV4::ValueRef base, const QV4::ValueRef index, const QV4::ValueRef rhs); +void __qmljs_inplace_mod_element(QV4::ExecutionContext *ctx, const QV4::ValueRef base, const QV4::ValueRef index, const QV4::ValueRef rhs); +void __qmljs_inplace_shl_element(QV4::ExecutionContext *ctx, const QV4::ValueRef base, const QV4::ValueRef index, const QV4::ValueRef rhs); +void __qmljs_inplace_shr_element(QV4::ExecutionContext *ctx, const QV4::ValueRef base, const QV4::ValueRef index, const QV4::ValueRef rhs); +void __qmljs_inplace_ushr_element(QV4::ExecutionContext *ctx, const QV4::ValueRef base, const QV4::ValueRef index, const QV4::ValueRef rhs); + +typedef void (*InplaceBinOpMember)(QV4::ExecutionContext *ctx, const QV4::ValueRef base, QV4::String *name, const QV4::ValueRef rhs); +void __qmljs_inplace_bit_and_member(QV4::ExecutionContext *ctx, const QV4::ValueRef base, QV4::String *name, const QV4::ValueRef rhs); +void __qmljs_inplace_bit_or_member(QV4::ExecutionContext *ctx, const QV4::ValueRef base, QV4::String *name, const QV4::ValueRef rhs); +void __qmljs_inplace_bit_xor_member(QV4::ExecutionContext *ctx, const QV4::ValueRef base, QV4::String *name, const QV4::ValueRef rhs); +void __qmljs_inplace_add_member(QV4::ExecutionContext *ctx, const QV4::ValueRef base, QV4::String *name, const QV4::ValueRef rhs); +void __qmljs_inplace_sub_member(QV4::ExecutionContext *ctx, const QV4::ValueRef base, QV4::String *name, const QV4::ValueRef rhs); +void __qmljs_inplace_mul_member(QV4::ExecutionContext *ctx, const QV4::ValueRef base, QV4::String *name, const QV4::ValueRef rhs); +void __qmljs_inplace_div_member(QV4::ExecutionContext *ctx, const QV4::ValueRef base, QV4::String *name, const QV4::ValueRef rhs); +void __qmljs_inplace_mod_member(QV4::ExecutionContext *ctx, const QV4::ValueRef base, QV4::String *name, const QV4::ValueRef rhs); +void __qmljs_inplace_shl_member(QV4::ExecutionContext *ctx, const QV4::ValueRef base, QV4::String *name, const QV4::ValueRef rhs); +void __qmljs_inplace_shr_member(QV4::ExecutionContext *ctx, const QV4::ValueRef base, QV4::String *name, const QV4::ValueRef rhs); +void __qmljs_inplace_ushr_member(QV4::ExecutionContext *ctx, const QV4::ValueRef base, QV4::String *name, const QV4::ValueRef rhs); + +typedef QV4::Bool (*CmpOp)(const QV4::ValueRef left, const QV4::ValueRef right); +QV4::Bool __qmljs_cmp_gt(const QV4::ValueRef left, const QV4::ValueRef right); +QV4::Bool __qmljs_cmp_lt(const QV4::ValueRef left, const QV4::ValueRef right); +QV4::Bool __qmljs_cmp_ge(const QV4::ValueRef left, const QV4::ValueRef right); +QV4::Bool __qmljs_cmp_le(const QV4::ValueRef left, const QV4::ValueRef right); +QV4::Bool __qmljs_cmp_eq(const QV4::ValueRef left, const QV4::ValueRef right); +QV4::Bool __qmljs_cmp_ne(const QV4::ValueRef left, const QV4::ValueRef right); +QV4::Bool __qmljs_cmp_se(const QV4::ValueRef left, const QV4::ValueRef right); +QV4::Bool __qmljs_cmp_sne(const QV4::ValueRef left, const QV4::ValueRef right); + +typedef QV4::Bool (*CmpOpContext)(QV4::ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right); +QV4::Bool __qmljs_cmp_instanceof(QV4::ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right); +QV4::Bool __qmljs_cmp_in(QV4::ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right); // type conversion and testing -inline QV4::Value __qmljs_to_primitive(const QV4::Value &value, int typeHint) +inline QV4::Value __qmljs_to_primitive(const QV4::ValueRef value, int typeHint) { - QV4::Object *o = value.asObject(); + QV4::Object *o = value->asObject(); if (!o) - return value; + return *value; return __qmljs_object_default_value(o, typeHint); } -inline double __qmljs_to_number(const QV4::Value &value) -{ - switch (value.type()) { - case QV4::Value::Undefined_Type: - return std::numeric_limits<double>::quiet_NaN(); - case QV4::Value::Null_Type: - return 0; - case QV4::Value::Boolean_Type: - return (value.booleanValue() ? 1. : 0.); - case QV4::Value::Integer_Type: - return value.int_32; - case QV4::Value::String_Type: - return __qmljs_string_to_number(value.stringValue()->toQString()); - case QV4::Value::Object_Type: { - QV4::Value prim = __qmljs_to_primitive(value, QV4::NUMBER_HINT); - return __qmljs_to_number(prim); - } - default: // double - return value.doubleValue(); - } +inline double __qmljs_to_number(const ValueRef value) +{ + return value->toNumber(); } -Q_QML_EXPORT int __qmljs_value_to_int32(const QV4::Value &value); -Q_QML_EXPORT unsigned __qmljs_value_to_uint32(const QV4::Value &value); - -inline QV4::Value __qmljs_to_string(const QV4::Value &value, QV4::ExecutionContext *ctx) +inline QV4::Value __qmljs_to_string(const QV4::ValueRef value, QV4::ExecutionContext *ctx) { - if (value.isString()) - return value; + if (value->isString()) + return *value; return QV4::Value::fromString(__qmljs_convert_to_string(ctx, value)); } -inline QV4::Value __qmljs_to_object(QV4::ExecutionContext *ctx, const QV4::Value &value) +inline QV4::Value __qmljs_to_object(QV4::ExecutionContext *ctx, const QV4::ValueRef value) { - if (value.isObject()) - return value; + if (value->isObject()) + return *value; return QV4::Value::fromObject(__qmljs_convert_to_object(ctx, value)); } -inline void __qmljs_uplus(QV4::Value *result, const QV4::Value &value) +inline void __qmljs_uplus(QV4::ValueRef result, const QV4::ValueRef value) { TRACE1(value); - *result = value; + result = value; if (result->tryIntegerConversion()) return; @@ -333,47 +313,47 @@ inline void __qmljs_uplus(QV4::Value *result, const QV4::Value &value) *result = QV4::Value::fromDouble(n); } -inline void __qmljs_uminus(QV4::Value *result, const QV4::Value &value) +inline void __qmljs_uminus(QV4::ValueRef result, const QV4::ValueRef value) { TRACE1(value); // +0 != -0, so we need to convert to double when negating 0 - if (value.isInteger() && value.integerValue()) - *result = QV4::Value::fromInt32(-value.integerValue()); + if (value->isInteger() && value->integerValue()) + *result = QV4::Value::fromInt32(-value->integerValue()); else { double n = __qmljs_to_number(value); *result = QV4::Value::fromDouble(-n); } } -inline void __qmljs_compl(QV4::Value *result, const QV4::Value &value) +inline void __qmljs_compl(QV4::ValueRef result, const QV4::ValueRef value) { TRACE1(value); int n; - if (value.isConvertibleToInt()) - n = value.int_32; + if (value->isConvertibleToInt()) + n = value->int_32; else n = QV4::Value::toInt32(__qmljs_to_number(value)); *result = QV4::Value::fromInt32(~n); } -inline void __qmljs_not(QV4::Value *result, const QV4::Value &value) +inline void __qmljs_not(QV4::ValueRef result, const QV4::ValueRef value) { TRACE1(value); - bool b = value.toBoolean(); + bool b = value->toBoolean(); *result = QV4::Value::fromBoolean(!b); } // binary operators -inline void __qmljs_bit_or(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_bit_or(ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); - if (QV4::Value::integerCompatible(left, right)) { - *result = QV4::Value::fromInt32(left.integerValue() | right.integerValue()); + if (QV4::Value::integerCompatible(*left, *right)) { + *result = QV4::Value::fromInt32(left->integerValue() | right->integerValue()); return; } @@ -382,12 +362,12 @@ inline void __qmljs_bit_or(QV4::Value *result, const QV4::Value &left, const QV4 *result = QV4::Value::fromInt32(lval | rval); } -inline void __qmljs_bit_xor(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_bit_xor(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); - if (QV4::Value::integerCompatible(left, right)) { - *result = QV4::Value::fromInt32(left.integerValue() ^ right.integerValue()); + if (QV4::Value::integerCompatible(*left, *right)) { + *result = QV4::Value::fromInt32(left->integerValue() ^ right->integerValue()); return; } @@ -396,12 +376,12 @@ inline void __qmljs_bit_xor(QV4::Value *result, const QV4::Value &left, const QV *result = QV4::Value::fromInt32(lval ^ rval); } -inline void __qmljs_bit_and(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_bit_and(ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); - if (QV4::Value::integerCompatible(left, right)) { - *result = QV4::Value::fromInt32(left.integerValue() & right.integerValue()); + if (QV4::Value::integerCompatible(*left, *right)) { + *result = QV4::Value::fromInt32(left->integerValue() & right->integerValue()); return; } @@ -410,29 +390,29 @@ inline void __qmljs_bit_and(QV4::Value *result, const QV4::Value &left, const QV *result = QV4::Value::fromInt32(lval & rval); } -inline void __qmljs_add(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_add(QV4::ExecutionContext *ctx, ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); - if (QV4::Value::integerCompatible(left, right)) { - *result = add_int32(left.integerValue(), right.integerValue()); + if (QV4::Value::integerCompatible(*left, *right)) { + *result = add_int32(left->integerValue(), right->integerValue()); return; } - if (QV4::Value::bothDouble(left, right)) { - *result = QV4::Value::fromDouble(left.doubleValue() + right.doubleValue()); + if (QV4::Value::bothDouble(*left, *right)) { + *result = QV4::Value::fromDouble(left->doubleValue() + right->doubleValue()); return; } __qmljs_add_helper(ctx, result, left, right); } -inline void __qmljs_sub(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_sub(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); - if (QV4::Value::integerCompatible(left, right)) { - *result = sub_int32(left.integerValue(), right.integerValue()); + if (QV4::Value::integerCompatible(*left, *right)) { + *result = sub_int32(left->integerValue(), right->integerValue()); return; } @@ -441,12 +421,12 @@ inline void __qmljs_sub(QV4::Value *result, const QV4::Value &left, const QV4::V *result = QV4::Value::fromDouble(lval - rval); } -inline void __qmljs_mul(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_mul(ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); - if (QV4::Value::integerCompatible(left, right)) { - *result = mul_int32(left.integerValue(), right.integerValue()); + if (QV4::Value::integerCompatible(*left, *right)) { + *result = mul_int32(left->integerValue(), right->integerValue()); return; } @@ -455,7 +435,7 @@ inline void __qmljs_mul(QV4::Value *result, const QV4::Value &left, const QV4::V *result = QV4::Value::fromDouble(lval * rval); } -inline void __qmljs_div(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_div(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); @@ -464,13 +444,13 @@ inline void __qmljs_div(QV4::Value *result, const QV4::Value &left, const QV4::V *result = QV4::Value::fromDouble(lval / rval); } -inline void __qmljs_mod(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_mod(ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); - if (QV4::Value::integerCompatible(left, right) && right.integerValue() != 0) { - int intRes = left.integerValue() % right.integerValue(); - if (intRes != 0 || left.integerValue() >= 0) { + if (QV4::Value::integerCompatible(*left, *right) && right->integerValue() != 0) { + int intRes = left->integerValue() % right->integerValue(); + if (intRes != 0 || left->integerValue() >= 0) { *result = QV4::Value::fromInt32(intRes); return; } @@ -481,12 +461,12 @@ inline void __qmljs_mod(QV4::Value *result, const QV4::Value &left, const QV4::V *result = QV4::Value::fromDouble(std::fmod(lval, rval)); } -inline void __qmljs_shl(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_shl(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); - if (QV4::Value::integerCompatible(left, right)) { - *result = QV4::Value::fromInt32(left.integerValue() << ((uint(right.integerValue()) & 0x1f))); + if (QV4::Value::integerCompatible(*left, *right)) { + *result = QV4::Value::fromInt32(left->integerValue() << ((uint(right->integerValue()) & 0x1f))); return; } @@ -495,12 +475,12 @@ inline void __qmljs_shl(QV4::Value *result, const QV4::Value &left, const QV4::V *result = QV4::Value::fromInt32(lval << rval); } -inline void __qmljs_shr(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_shr(ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); - if (QV4::Value::integerCompatible(left, right)) { - *result = QV4::Value::fromInt32(left.integerValue() >> ((uint(right.integerValue()) & 0x1f))); + if (QV4::Value::integerCompatible(*left, *right)) { + *result = QV4::Value::fromInt32(left->integerValue() >> ((uint(right->integerValue()) & 0x1f))); return; } @@ -509,13 +489,13 @@ inline void __qmljs_shr(QV4::Value *result, const QV4::Value &left, const QV4::V *result = QV4::Value::fromInt32(lval >> rval); } -inline void __qmljs_ushr(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_ushr(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); uint res; - if (QV4::Value::integerCompatible(left, right)) { - res = uint(left.integerValue()) >> (uint(right.integerValue()) & 0x1f); + if (QV4::Value::integerCompatible(*left, *right)) { + res = uint(left->integerValue()) >> (uint(right->integerValue()) & 0x1f); } else { unsigned lval = QV4::Value::toUInt32(__qmljs_to_number(left)); unsigned rval = QV4::Value::toUInt32(__qmljs_to_number(right)) & 0x1f; @@ -528,49 +508,49 @@ inline void __qmljs_ushr(QV4::Value *result, const QV4::Value &left, const QV4:: *result = QV4::Value::fromInt32(res); } -inline void __qmljs_gt(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_gt(ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); *result = QV4::Value::fromBoolean(__qmljs_cmp_gt(left, right)); } -inline void __qmljs_lt(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_lt(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); *result = QV4::Value::fromBoolean(__qmljs_cmp_lt(left, right)); } -inline void __qmljs_ge(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_ge(ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); *result = QV4::Value::fromBoolean(__qmljs_cmp_ge(left, right)); } -inline void __qmljs_le(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_le(ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); *result = QV4::Value::fromBoolean(__qmljs_cmp_le(left, right)); } -inline void __qmljs_eq(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_eq(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); *result = QV4::Value::fromBoolean(__qmljs_cmp_eq(left, right)); } -inline void __qmljs_ne(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_ne(ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); *result = QV4::Value::fromBoolean(!__qmljs_cmp_eq(left, right)); } -inline void __qmljs_se(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_se(QV4::ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); @@ -578,7 +558,7 @@ inline void __qmljs_se(QV4::Value *result, const QV4::Value &left, const QV4::Va *result = QV4::Value::fromBoolean(r); } -inline void __qmljs_sne(QV4::Value *result, const QV4::Value &left, const QV4::Value &right) +inline void __qmljs_sne(ValueRef result, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); @@ -586,12 +566,13 @@ inline void __qmljs_sne(QV4::Value *result, const QV4::Value &left, const QV4::V *result = QV4::Value::fromBoolean(r); } -inline QV4::Bool __qmljs_cmp_gt(const QV4::Value &left, const QV4::Value &right) +inline QV4::Bool __qmljs_cmp_gt(const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); - if (QV4::Value::integerCompatible(left, right)) - return left.integerValue() > right.integerValue(); + if (QV4::Value::integerCompatible(*left, *right)) + return left->integerValue() > right->integerValue(); + // Safe, as l & r are primitive values QV4::Value l = __qmljs_to_primitive(left, QV4::NUMBER_HINT); QV4::Value r = __qmljs_to_primitive(right, QV4::NUMBER_HINT); @@ -600,17 +581,17 @@ inline QV4::Bool __qmljs_cmp_gt(const QV4::Value &left, const QV4::Value &right) } else if (l.isString() && r.isString()) { return r.stringValue()->compare(l.stringValue()); } else { - double dl = __qmljs_to_number(l); - double dr = __qmljs_to_number(r); + double dl = __qmljs_to_number(ValueRef(&l)); + double dr = __qmljs_to_number(ValueRef(&r)); return dl > dr; } } -inline QV4::Bool __qmljs_cmp_lt(const QV4::Value &left, const QV4::Value &right) +inline QV4::Bool __qmljs_cmp_lt(const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); - if (QV4::Value::integerCompatible(left, right)) - return left.integerValue() < right.integerValue(); + if (QV4::Value::integerCompatible(*left, *right)) + return left->integerValue() < right->integerValue(); QV4::Value l = __qmljs_to_primitive(left, QV4::NUMBER_HINT); QV4::Value r = __qmljs_to_primitive(right, QV4::NUMBER_HINT); @@ -620,17 +601,17 @@ inline QV4::Bool __qmljs_cmp_lt(const QV4::Value &left, const QV4::Value &right) } else if (l.isString() && r.isString()) { return l.stringValue()->compare(r.stringValue()); } else { - double dl = __qmljs_to_number(l); - double dr = __qmljs_to_number(r); + double dl = __qmljs_to_number(ValueRef(&l)); + double dr = __qmljs_to_number(ValueRef(&r)); return dl < dr; } } -inline QV4::Bool __qmljs_cmp_ge(const QV4::Value &left, const QV4::Value &right) +inline QV4::Bool __qmljs_cmp_ge(const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); - if (QV4::Value::integerCompatible(left, right)) - return left.integerValue() >= right.integerValue(); + if (QV4::Value::integerCompatible(*left, *right)) + return left->integerValue() >= right->integerValue(); QV4::Value l = __qmljs_to_primitive(left, QV4::NUMBER_HINT); QV4::Value r = __qmljs_to_primitive(right, QV4::NUMBER_HINT); @@ -640,17 +621,17 @@ inline QV4::Bool __qmljs_cmp_ge(const QV4::Value &left, const QV4::Value &right) } else if (l.isString() && r.isString()) { return !l.stringValue()->compare(r.stringValue()); } else { - double dl = __qmljs_to_number(l); - double dr = __qmljs_to_number(r); + double dl = __qmljs_to_number(ValueRef(&l)); + double dr = __qmljs_to_number(ValueRef(&r)); return dl >= dr; } } -inline QV4::Bool __qmljs_cmp_le(const QV4::Value &left, const QV4::Value &right) +inline QV4::Bool __qmljs_cmp_le(const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); - if (QV4::Value::integerCompatible(left, right)) - return left.integerValue() <= right.integerValue(); + if (QV4::Value::integerCompatible(*left, *right)) + return left->integerValue() <= right->integerValue(); QV4::Value l = __qmljs_to_primitive(left, QV4::NUMBER_HINT); QV4::Value r = __qmljs_to_primitive(right, QV4::NUMBER_HINT); @@ -660,51 +641,51 @@ inline QV4::Bool __qmljs_cmp_le(const QV4::Value &left, const QV4::Value &right) } else if (l.isString() && r.isString()) { return !r.stringValue()->compare(l.stringValue()); } else { - double dl = __qmljs_to_number(l); - double dr = __qmljs_to_number(r); + double dl = __qmljs_to_number(ValueRef(&l)); + double dr = __qmljs_to_number(ValueRef(&r)); return dl <= dr; } } -inline QV4::Bool __qmljs_cmp_eq(const QV4::Value &left, const QV4::Value &right) +inline QV4::Bool __qmljs_cmp_eq(const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); - if (left.val == right.val) + if (left->val == right->val) // NaN != NaN - return (left.tag & QV4::Value::NotDouble_Mask) != QV4::Value::NaN_Mask; + return (left->tag & QV4::Value::NotDouble_Mask) != QV4::Value::NaN_Mask; - if (left.type() == right.type()) { - if (left.isManaged()) - return left.managed()->isEqualTo(right.managed()); + if (left->type() == right->type()) { + if (left->isManaged()) + return left->managed()->isEqualTo(right->managed()); return false; } return __qmljs_equal_helper(left, right); } -inline QV4::Bool __qmljs_cmp_ne(const QV4::Value &left, const QV4::Value &right) +inline QV4::Bool __qmljs_cmp_ne(const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); return !__qmljs_cmp_eq(left, right); } -inline QV4::Bool __qmljs_cmp_se(const QV4::Value &left, const QV4::Value &right) +inline QV4::Bool __qmljs_cmp_se(const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); return __qmljs_strict_equal(left, right); } -inline QV4::Bool __qmljs_cmp_sne(const QV4::Value &left, const QV4::Value &right) +inline QV4::Bool __qmljs_cmp_sne(const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); return ! __qmljs_strict_equal(left, right); } -inline QV4::Bool __qmljs_cmp_instanceof(QV4::ExecutionContext *ctx, const QV4::Value &left, const QV4::Value &right) +inline QV4::Bool __qmljs_cmp_instanceof(QV4::ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); @@ -713,7 +694,7 @@ inline QV4::Bool __qmljs_cmp_instanceof(QV4::ExecutionContext *ctx, const QV4::V return v.booleanValue(); } -inline uint __qmljs_cmp_in(QV4::ExecutionContext *ctx, const QV4::Value &left, const QV4::Value &right) +inline uint __qmljs_cmp_in(QV4::ExecutionContext *ctx, const QV4::ValueRef left, const QV4::ValueRef right) { TRACE2(left, right); diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h new file mode 100644 index 0000000000..a0e0d784a7 --- /dev/null +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -0,0 +1,287 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QV4SCOPEDVALUE_P_H +#define QV4SCOPEDVALUE_P_H + +#include "qv4engine_p.h" +#include "qv4value_def_p.h" + +QT_BEGIN_NAMESPACE + +#define SAVE_JS_STACK(ctx) Value *__jsStack = ctx->engine->jsStackTop +#define CHECK_JS_STACK(ctx) Q_ASSERT(__jsStack == ctx->engine->jsStackTop) + +namespace QV4 { + +struct ScopedValueArray { + ScopedValueArray(ExecutionEngine *e, int size) + : engine(e) +#ifndef QT_NO_DEBUG + , size(size) +#endif + { + ptr = e->stackPush(size); + } + + ~ScopedValueArray() { +#ifndef QT_NO_DEBUG + engine->stackPop(size); + Q_ASSERT(engine->jsStackTop == ptr); +#else + engine->jsStackTop = ptr; +#endif + } + + ExecutionEngine *engine; +#ifndef QT_NO_DEBUG + int size; +#endif + Value *ptr; +}; + +struct ScopedValue; + +struct ValueScope { + ValueScope(ExecutionContext *ctx) + : engine(ctx->engine) + { + mark = ctx->engine->jsStackTop; + } + + ValueScope(ExecutionEngine *e) + : engine(e) + { + mark = e->jsStackTop; + } + + ~ValueScope() { + Q_ASSERT(engine->jsStackTop >= mark); + engine->jsStackTop = mark; + } + + ExecutionEngine *engine; + Value *mark; +}; + +struct ScopedValue; +struct ValueRef; + +struct ReturnedValue +{ + ReturnedValue(const Value &v) + : v(v) {} + // no destructor + + +private: + friend struct ValueRef; + friend struct ScopedValue; + QV4::Value v; +}; + +struct ScopedValue +{ + ScopedValue(const ValueScope &scope) + { + ptr = scope.engine->jsStackTop++; + } + + ScopedValue(const ValueScope &scope, const Value &v) + { + ptr = scope.engine->jsStackTop++; + *ptr = v; + } + + ScopedValue(const ValueScope &scope, const ReturnedValue &v) + { + ptr = scope.engine->jsStackTop++; + *ptr = v.v; + } + + ScopedValue &operator=(const Value &v) { + *ptr = v; + return *this; + } + + ScopedValue &operator=(const ReturnedValue &v) { + *ptr = v.v; + return *this; + } + + ScopedValue &operator=(const ScopedValue &other) { + *ptr = *other.ptr; + return *this; + } + + Value *operator->() { + return ptr; + } + + operator const Value &() const { + return *ptr; + } + + Value *ptr; +}; + +struct ScopedCallData { + ScopedCallData(ExecutionEngine *e, int argc) + : engine(e) + // ### this check currently won't work because of exceptions +#ifndef QT_NO_DEBUG + , size(qMax(argc, (int)QV4::Global::ReservedArgumentCount) + offsetof(QV4::CallData, args)/sizeof(QV4::Value)) +#endif + { + 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; + } + + ~ScopedCallData() { +#ifndef QT_NO_DEBUG + engine->stackPop(size); + Q_ASSERT((void *)engine->jsStackTop == (void *)ptr); +#else + engine->jsStackTop = reinterpret_cast<Value *>(ptr); +#endif + } + + CallData *operator->() { + return ptr; + } + + operator CallData *() const { + return ptr; + } + + + ExecutionEngine *engine; +#ifndef QT_NO_DEBUG + int size; +#endif + CallData *ptr; +}; + +struct ValueRef { + ValueRef(const ScopedValue &v) + : ptr(v.ptr) {} + ValueRef(const PersistentValue &v) + : ptr(&v.d->value) {} + ValueRef(PersistentValuePrivate *p) + : ptr(&p->value) {} + // Important: Do NOT add a copy constructor to this class + // adding a copy constructor actually changes the calling convention, ie. + // is not even binary compatible. Adding it would break assumptions made + // in the jit'ed code. + ValueRef &operator=(const ScopedValue &o) + { *ptr = *o.ptr; return *this; } + ValueRef &operator=(const ValueRef &o) + { *ptr = *o.ptr; return *this; } + ValueRef &operator=(const Value &v) + { *ptr = v; return *this; } + ValueRef &operator=(const ReturnedValue &v) { + *ptr = v.v; + return *this; + } + + operator const Value *() const { + return ptr; + } + const Value *operator->() const { + return ptr; + } + + operator Value *() { + return ptr; + } + Value *operator->() { + return ptr; + } + + static ValueRef fromRawValue(Value *v) { + return ValueRef(v); + } + static const ValueRef fromRawValue(const Value *v) { + return ValueRef(const_cast<Value *>(v)); + } + // ### get rid of this one! + ValueRef(Value *v) { ptr = v; } +private: + Value *ptr; +}; + + +struct CallDataRef { + CallDataRef(const ScopedCallData &c) + : ptr(c.ptr) {} + CallDataRef(CallData *v) { ptr = v; } + // Important: Do NOT add a copy constructor to this class + // adding a copy constructor actually changes the calling convention, ie. + // is not even binary compatible. Adding it would break assumptions made + // in the jit'ed code. + CallDataRef &operator=(const ScopedCallData &c) + { *ptr = *c.ptr; return *this; } + CallDataRef &operator=(const CallDataRef &o) + { *ptr = *o.ptr; return *this; } + + operator const CallData *() const { + return ptr; + } + const CallData *operator->() const { + return ptr; + } + + operator CallData *() { + return ptr; + } + CallData *operator->() { + return ptr; + } + +private: + CallData *ptr; +}; + +} + +QT_END_NAMESPACE + +#endif diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index aef8ac8838..16bab966e9 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -46,6 +46,7 @@ #include "qv4context_p.h" #include "qv4debugging_p.h" #include "qv4exception_p.h" +#include "qv4scopedvalue_p.h" #include <private/qqmljsengine_p.h> #include <private/qqmljslexer_p.h> @@ -74,7 +75,7 @@ QmlBindingWrapper::QmlBindingWrapper(ExecutionContext *scope, Function *f, Objec scope->engine->popContext(); } -Value QmlBindingWrapper::call(Managed *that, const CallData &) +Value QmlBindingWrapper::call(Managed *that, CallData *) { ExecutionEngine *engine = that->engine(); QmlBindingWrapper *This = static_cast<QmlBindingWrapper *>(that); @@ -237,9 +238,9 @@ Value Script::run() } else { FunctionObject *f = new (engine->memoryManager) QmlBindingWrapper(scope, vmFunction, qml.value().asObject()); - CALLDATA(0); - d.thisObject = Value::undefinedValue(); - return f->call(d); + ScopedCallData callData(scope->engine, 0); + callData->thisObject = Value::undefinedValue(); + return f->call(callData); } } diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index b3bce6b427..b00e076a2b 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -56,7 +56,7 @@ struct QmlBindingWrapper : FunctionObject { QmlBindingWrapper(ExecutionContext *scope, Function *f, Object *qml); - static Value call(Managed *that, const CallData &); + static Value call(Managed *that, CallData *); static void markObjects(Managed *m); private: diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp index b7f7317c76..29ca34910c 100644 --- a/src/qml/jsruntime/qv4sequenceobject.cpp +++ b/src/qml/jsruntime/qv4sequenceobject.cpp @@ -46,6 +46,7 @@ #include <private/qv4functionobject_p.h> #include <private/qv4arrayobject_p.h> #include <private/qqmlengine_p.h> +#include <private/qv4scopedvalue_p.h> QT_BEGIN_NAMESPACE @@ -351,11 +352,11 @@ public: bool operator()(typename Container::value_type lhs, typename Container::value_type rhs) { QV4::Managed *fun = this->m_compareFn.asManaged(); - CALLDATA(2); - d.args[0] = convertElementToValue(this->m_ctx->engine, lhs); - d.args[1] = convertElementToValue(this->m_ctx->engine, rhs); - d.thisObject = QV4::Value::fromObject(this->m_ctx->engine->globalObject); - QV4::Value result = fun->call(d); + ScopedCallData callData(fun->engine(), 2); + callData->args[0] = convertElementToValue(this->m_ctx->engine, lhs); + callData->args[1] = convertElementToValue(this->m_ctx->engine, rhs); + callData->thisObject = QV4::Value::fromObject(this->m_ctx->engine->globalObject); + QV4::Value result = fun->call(callData); return result.toNumber() < 0; } diff --git a/src/qml/jsruntime/qv4sparsearray.cpp b/src/qml/jsruntime/qv4sparsearray.cpp index 835a0d004f..f21855ebc9 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, QV4::ValueRef::fromRawValue(&m_comparefn), callData); 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/qv4stacktrace.cpp b/src/qml/jsruntime/qv4stacktrace.cpp index b0fabfd42e..2a27c57e46 100644 --- a/src/qml/jsruntime/qv4stacktrace.cpp +++ b/src/qml/jsruntime/qv4stacktrace.cpp @@ -137,7 +137,7 @@ NativeFrame NativeStackTrace::nextFrame() { continue; frame.function = f; - frame.line = f->lineNumberForProgramCounter(pc - reinterpret_cast<quintptr>(f->code)); + frame.line = f->lineNumberForProgramCounter(pc - reinterpret_cast<quintptr>(f->codePtr)); } return frame; diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp index 52d98502a3..0a9cb32e6f 100644 --- a/src/qml/jsruntime/qv4stringobject.cpp +++ b/src/qml/jsruntime/qv4stringobject.cpp @@ -44,6 +44,7 @@ #include "qv4regexpobject_p.h" #include "qv4objectproto_p.h" #include "qv4mm_p.h" +#include "qv4scopedvalue_p.h" #include <QtCore/qnumeric.h> #include <QtCore/qmath.h> #include <QtCore/QDateTime> @@ -159,21 +160,21 @@ StringCtor::StringCtor(ExecutionContext *scope) vtbl = &static_vtbl; } -Value StringCtor::construct(Managed *m, const CallData &d) +Value StringCtor::construct(Managed *m, CallData *callData) { Value value; - if (d.argc) - value = Value::fromString(d.args[0].toString(m->engine()->current)); + if (callData->argc) + value = Value::fromString(callData->args[0].toString(m->engine()->current)); else value = Value::fromString(m->engine()->current, QString()); return Value::fromObject(m->engine()->newStringObject(value)); } -Value StringCtor::call(Managed *m, const CallData &d) +Value StringCtor::call(Managed *m, CallData *callData) { Value value; - if (d.argc) - value = Value::fromString(d.args[0].toString(m->engine()->current)); + if (callData->argc) + value = Value::fromString(callData->args[0].toString(m->engine()->current)); else value = Value::fromString(m->engine()->current, QString()); return value; @@ -279,12 +280,15 @@ Value StringPrototype::method_charCodeAt(SimpleCallContext *context) Value StringPrototype::method_concat(SimpleCallContext *context) { + ValueScope scope(context); + QString value = getThisString(context, context->thisObject); + ScopedValue v(scope); for (int i = 0; i < context->argumentCount; ++i) { - Value v = __qmljs_to_string(context->arguments[i], context); - assert(v.isString()); - value += v.stringValue()->toQString(); + v = __qmljs_to_string(ValueRef(&context->arguments[i]), context); + assert(v->isString()); + value += v->stringValue()->toQString(); } return Value::fromString(context, value); @@ -311,15 +315,17 @@ Value StringPrototype::method_indexOf(SimpleCallContext *context) Value StringPrototype::method_lastIndexOf(SimpleCallContext *context) { + ValueScope scope(context); + const QString value = getThisString(context, context->thisObject); QString searchString; if (context->argumentCount) { - Value v = __qmljs_to_string(context->arguments[0], context); + Value v = __qmljs_to_string(ValueRef(&context->arguments[0]), context); searchString = v.stringValue()->toQString(); } - Value posArg = context->argumentCount > 1 ? context->arguments[1] : Value::undefinedValue(); + ScopedValue posArg(scope, context->argumentCount > 1 ? context->arguments[1] : Value::undefinedValue()); double position = __qmljs_to_number(posArg); if (std::isnan(position)) position = +qInf(); @@ -352,9 +358,9 @@ Value StringPrototype::method_match(SimpleCallContext *context) Value regexp = context->argumentCount ? context->arguments[0] : Value::undefinedValue(); RegExpObject *rx = regexp.as<RegExpObject>(); if (!rx) { - CALLDATA(1); - d.args[0] = regexp; - rx = context->engine->regExpCtor.asFunctionObject()->construct(d).as<RegExpObject>(); + ScopedCallData callData(context->engine, 1); + callData->args[0] = regexp; + rx = context->engine->regExpCtor.asFunctionObject()->construct(callData).as<RegExpObject>(); } if (!rx) @@ -366,11 +372,11 @@ Value StringPrototype::method_match(SimpleCallContext *context) // ### use the standard builtin function, not the one that might be redefined in the proto FunctionObject *exec = context->engine->regExpClass->prototype->get(context->engine->newString(QStringLiteral("exec")), 0).asFunctionObject(); - CALLDATA(1); - d.thisObject = Value::fromObject(rx); - d.args[0] = Value::fromString(s); + ScopedCallData callData(context->engine, 1); + callData->thisObject = Value::fromObject(rx); + callData->args[0] = Value::fromString(s); if (!global) - return exec->call(d); + return exec->call(callData); String *lastIndex = context->engine->newString(QStringLiteral("lastIndex")); rx->put(lastIndex, Value::fromInt32(0)); @@ -379,7 +385,7 @@ Value StringPrototype::method_match(SimpleCallContext *context) double previousLastIndex = 0; uint n = 0; while (1) { - Value result = exec->call(d); + Value result = exec->call(callData); if (result.isNull()) break; assert(result.isObject()); @@ -505,8 +511,8 @@ Value StringPrototype::method_replace(SimpleCallContext *ctx) Value replaceValue = ctx->argument(1); if (FunctionObject* searchCallback = replaceValue.asFunctionObject()) { result.reserve(string.length() + 10*numStringMatches); - CALLDATA(numCaptures + 2); - d.thisObject = Value::undefinedValue(); + ScopedCallData callData(ctx->engine, numCaptures + 2); + callData->thisObject = Value::undefinedValue(); int lastEnd = 0; for (int i = 0; i < numStringMatches; ++i) { for (int k = 0; k < numCaptures; ++k) { @@ -516,15 +522,15 @@ Value StringPrototype::method_replace(SimpleCallContext *ctx) Value entry = Value::undefinedValue(); if (start != JSC::Yarr::offsetNoMatch && end != JSC::Yarr::offsetNoMatch) entry = Value::fromString(ctx, string.mid(start, end - start)); - d.args[k] = entry; + callData->args[k] = entry; } uint matchStart = matchOffsets[i * numCaptures * 2]; Q_ASSERT(matchStart >= lastEnd); uint matchEnd = matchOffsets[i * numCaptures * 2 + 1]; - d.args[numCaptures] = Value::fromUInt32(matchStart); - d.args[numCaptures + 1] = Value::fromString(ctx, string); + callData->args[numCaptures] = Value::fromUInt32(matchStart); + callData->args[numCaptures + 1] = Value::fromString(ctx, string); - Value replacement = searchCallback->call(d); + Value replacement = searchCallback->call(callData); result += string.midRef(lastEnd, matchStart - lastEnd); result += replacement.toString(ctx)->toQString(); lastEnd = matchEnd; @@ -566,9 +572,9 @@ Value StringPrototype::method_search(SimpleCallContext *ctx) Value regExpValue = ctx->argument(0); RegExpObject *regExp = regExpValue.as<RegExpObject>(); if (!regExp) { - CALLDATA(1); - d.args[0] = regExpValue; - regExpValue = ctx->engine->regExpCtor.asFunctionObject()->construct(d); + ScopedCallData callData(ctx->engine, 1); + callData->args[0] = regExpValue; + regExpValue = ctx->engine->regExpCtor.asFunctionObject()->construct(callData); regExp = regExpValue.as<RegExpObject>(); } uint* matchOffsets = (uint*)alloca(regExp->value->captureCount() * 2 * sizeof(uint)); @@ -783,7 +789,7 @@ Value StringPrototype::method_trim(SimpleCallContext *ctx) if (ctx->thisObject.isNull() || ctx->thisObject.isUndefined()) ctx->throwTypeError(); - QString s = __qmljs_to_string(ctx->thisObject, ctx).stringValue()->toQString(); + QString s = __qmljs_to_string(ValueRef(&ctx->thisObject), ctx).stringValue()->toQString(); const QChar *chars = s.constData(); int start, end; for (start = 0; start < s.length(); ++start) { diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h index 38d6eeeac5..f9cf89e9d9 100644 --- a/src/qml/jsruntime/qv4stringobject_p.h +++ b/src/qml/jsruntime/qv4stringobject_p.h @@ -70,8 +70,8 @@ struct StringCtor: FunctionObject { StringCtor(ExecutionContext *scope); - static Value construct(Managed *m, const CallData &d); - static Value call(Managed *that, const CallData &d); + static Value construct(Managed *m, CallData *callData); + static Value call(Managed *that, CallData *callData); protected: static const ManagedVTable static_vtbl; diff --git a/src/qml/jsruntime/qv4unwindhelper_arm_p.h b/src/qml/jsruntime/qv4unwindhelper_arm_p.h index 6cfdce0e7d..e768544e11 100644 --- a/src/qml/jsruntime/qv4unwindhelper_arm_p.h +++ b/src/qml/jsruntime/qv4unwindhelper_arm_p.h @@ -79,7 +79,7 @@ static Function *lookupFunction(void *pc) if (it == allFunctions.end()) return 0; - quintptr codeStart = reinterpret_cast<quintptr>(removeThumbBit((void*)(*it)->code)); + quintptr codeStart = reinterpret_cast<quintptr>(removeThumbBit((void*)(*it)->codePtr)); if (key < codeStart || key >= codeStart + (*it)->codeSize) return 0; return *it; @@ -137,27 +137,27 @@ static unsigned write_prel31(unsigned *addr, void *ptr) void UnwindHelper::deregisterFunction(Function *function) { QMutexLocker locker(&functionProtector); - allFunctions.remove(reinterpret_cast<quintptr>(function->code)); + allFunctions.remove(reinterpret_cast<quintptr>(function->codePtr)); } void UnwindHelper::deregisterFunctions(const QVector<Function *> &functions) { QMutexLocker locker(&functionProtector); foreach (Function *f, functions) - allFunctions.remove(reinterpret_cast<quintptr>(f->code)); + allFunctions.remove(reinterpret_cast<quintptr>(f->codePtr)); } void UnwindHelper::registerFunction(Function *function) { QMutexLocker locker(&functionProtector); - allFunctions.insert(reinterpret_cast<quintptr>(function->code), function); + allFunctions.insert(reinterpret_cast<quintptr>(function->codePtr), function); } void UnwindHelper::registerFunctions(const QVector<Function *> &functions) { QMutexLocker locker(&functionProtector); foreach (Function *f, functions) - allFunctions.insert(reinterpret_cast<quintptr>(f->code), f); + allFunctions.insert(reinterpret_cast<quintptr>(f->codePtr), f); } void UnwindHelper::prepareForUnwind(ExecutionContext *) @@ -217,7 +217,7 @@ extern "C" Q_DECL_EXPORT void *__gnu_Unwind_Find_exidx(void *pc, int *entryCount QV4::Function *function = QT_PREPEND_NAMESPACE(QV4::lookupFunction(pc)); if (function) { *entryCount = 1; - void * codeStart = QT_PREPEND_NAMESPACE(QV4::removeThumbBit((void*)function->code)); + void * codeStart = QT_PREPEND_NAMESPACE(QV4::removeThumbBit((void*)function->codePtr)); // At the end of the function we store our synthetic exception table entry. return (char *)codeStart + function->codeSize; } diff --git a/src/qml/jsruntime/qv4unwindhelper_dw2_p.h b/src/qml/jsruntime/qv4unwindhelper_dw2_p.h index c53d20612c..03533ba526 100644 --- a/src/qml/jsruntime/qv4unwindhelper_dw2_p.h +++ b/src/qml/jsruntime/qv4unwindhelper_dw2_p.h @@ -127,7 +127,7 @@ UnwindInfo::~UnwindInfo() static void ensureUnwindInfo(Function *f) { - if (!f->code) + if (!f->codePtr) return; // Not a JIT generated function ExecutableAllocator::ChunkOfPages *chunk = f->compilationUnit->chunkForFunction(f->compiledFunction->index); diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index a41262f12f..718b87d2c9 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -48,12 +48,47 @@ using namespace QV4; +int Value::toInt32() const +{ + if (isConvertibleToInt()) + return int_32; + double d; + if (isDouble()) + d = dbl; + else + d = toNumber(); + + const double D32 = 4294967296.0; + const double D31 = D32 / 2.0; + + if ((d >= -D31 && d < D31)) + return static_cast<int>(d); + + return Value::toInt32(d); +} + +unsigned int Value::toUInt32() const +{ + if (isConvertibleToInt()) + return (unsigned) int_32; + double d; + if (isDouble()) + d = dbl; + else + d = toNumber(); + + const double D32 = 4294967296.0; + if (d >= 0 && d < D32) + return static_cast<uint>(d); + return toUInt32(d); +} + int Value::toUInt16() const { if (isConvertibleToInt()) return (ushort)(uint)integerValue(); - double number = __qmljs_to_number(*this); + double number = toNumber(); double D16 = 65536.0; if ((number >= 0 && number < D16)) @@ -79,12 +114,32 @@ double Value::toInteger() const if (isConvertibleToInt()) return int_32; - return Value::toInteger(__qmljs_to_number(*this)); + return Value::toInteger(toNumber()); } double Value::toNumber() const { - return __qmljs_to_number(*this); + QV4::Value v = *this; + + redo: + switch (v.type()) { + case QV4::Value::Undefined_Type: + return std::numeric_limits<double>::quiet_NaN(); + case QV4::Value::Null_Type: + return 0; + case QV4::Value::Boolean_Type: + return (v.booleanValue() ? 1. : 0.); + case QV4::Value::Integer_Type: + return v.int_32; + case QV4::Value::String_Type: + return __qmljs_string_to_number(v.toQString()); + case QV4::Value::Object_Type: { + v = __qmljs_to_primitive(ValueRef::fromRawValue(this), QV4::NUMBER_HINT); + goto redo; + } + default: // double + return v.doubleValue(); + } } QString Value::toQString() const @@ -103,16 +158,18 @@ QString Value::toQString() const return stringValue()->toQString(); case Value::Object_Type: { ExecutionContext *ctx = objectValue()->internalClass->engine->current; + ValueScope scope(ctx); try { - Value prim = __qmljs_to_primitive(*this, STRING_HINT); - if (prim.isPrimitive()) - return prim.toQString(); + ScopedValue prim(scope, __qmljs_to_primitive(ValueRef::fromRawValue(this), STRING_HINT)); + if (prim->isPrimitive()) + return prim->toQString(); } catch (Exception &e) { e.accept(ctx); try { - Value prim = __qmljs_to_primitive(e.value(), STRING_HINT); - if (prim.isPrimitive()) - return prim.toQString(); + ScopedValue ex(scope, e.value()); + ScopedValue prim(scope, __qmljs_to_primitive(ex, STRING_HINT)); + if (prim->isPrimitive()) + return prim->toQString(); } catch(Exception &e) { e.accept(ctx); } @@ -216,9 +273,17 @@ String *Value::toString(ExecutionContext *ctx) const { if (isString()) return stringValue(); - return __qmljs_convert_to_string(ctx, *this); + return __qmljs_convert_to_string(ctx, ValueRef::fromRawValue(this)); +} + +Object *Value::toObject(ExecutionContext *ctx) const +{ + if (isObject()) + return objectValue(); + return __qmljs_convert_to_object(ctx, ValueRef::fromRawValue(this)); } + Value Value::property(ExecutionContext *ctx, String *name) const { return isObject() ? objectValue()->get(name) : undefinedValue(); diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h index 73d5d0479d..8d6f26ea57 100644 --- a/src/qml/jsruntime/qv4value_p.h +++ b/src/qml/jsruntime/qv4value_p.h @@ -59,8 +59,6 @@ QT_BEGIN_NAMESPACE namespace QV4 { -double __qmljs_to_number(const QV4::Value &value); -Q_QML_EXPORT QV4::String *__qmljs_convert_to_string(QV4::ExecutionContext *ctx, const QV4::Value &value); QV4::Object *__qmljs_convert_to_object(QV4::ExecutionContext *ctx, const QV4::Value &value); inline Managed *Value::asManaged() const @@ -193,48 +191,6 @@ inline bool Value::toBoolean() const } } -inline Object *Value::toObject(ExecutionContext *ctx) const -{ - if (isObject()) - return objectValue(); - return __qmljs_convert_to_object(ctx, *this); -} - -inline int Value::toInt32() const -{ - if (isConvertibleToInt()) - return int_32; - double d; - if (isDouble()) - d = dbl; - else - d = __qmljs_to_number(*this); - - const double D32 = 4294967296.0; - const double D31 = D32 / 2.0; - - if ((d >= -D31 && d < D31)) - return static_cast<int>(d); - - return Value::toInt32(d); -} - -inline unsigned int Value::toUInt32() const -{ - if (isConvertibleToInt()) - return (unsigned) int_32; - double d; - if (isDouble()) - d = dbl; - else - d = __qmljs_to_number(*this); - - const double D32 = 4294967296.0; - if (d >= 0 && d < D32) - return static_cast<uint>(d); - return toUInt32(d); -} - inline uint Value::asArrayIndex() const { if (isInteger() && int_32 >= 0) @@ -320,10 +276,10 @@ inline ErrorObject *Value::asErrorObject() const } // ### -inline Value Managed::construct(const CallData &d) { +inline Value Managed::construct(CallData *d) { return vtbl->construct(this, d); } -inline Value Managed::call(const CallData &d) { +inline Value Managed::call(CallData *d) { return vtbl->call(this, d); } @@ -380,6 +336,7 @@ public: } private: + friend struct ValueRef; PersistentValuePrivate *d; }; @@ -414,6 +371,7 @@ public: void markOnce(); private: + friend struct ValueRef; PersistentValuePrivate *d; }; diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index d5416105fa..92b0c75e8c 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" @@ -183,7 +183,9 @@ static inline QV4::Value *getValueRef(QV4::ExecutionContext *context, return c->locals + index; } else if (param.isTemp()) { VMSTATS(paramIsTemp); +#if !defined(QT_NO_DEBUG) Q_ASSERT(param.index < stackSize); +#endif return stack + param.index; } else if (param.isScopedLocal()) { VMSTATS(paramIsScopedLocal); @@ -281,29 +283,29 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code, MOTH_BEGIN_INSTR(StoreName) TRACE(inline, "property name = %s", instr.name->toQString().toUtf8().constData()); - __qmljs_set_activation_property(context, runtimeStrings[instr.name], VALUE(instr.source)); + __qmljs_set_activation_property(context, runtimeStrings[instr.name], VALUEPTR(instr.source)); MOTH_END_INSTR(StoreName) MOTH_BEGIN_INSTR(LoadElement) - __qmljs_get_element(context, VALUEPTR(instr.result), VALUE(instr.base), VALUE(instr.index)); + __qmljs_get_element(context, VALUEPTR(instr.result), VALUEPTR(instr.base), VALUEPTR(instr.index)); MOTH_END_INSTR(LoadElement) MOTH_BEGIN_INSTR(StoreElement) - __qmljs_set_element(context, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source)); + __qmljs_set_element(context, VALUEPTR(instr.base), VALUEPTR(instr.index), VALUEPTR(instr.source)); MOTH_END_INSTR(StoreElement) MOTH_BEGIN_INSTR(LoadProperty) - __qmljs_get_property(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.name]); + __qmljs_get_property(context, VALUEPTR(instr.result), VALUEPTR(instr.base), runtimeStrings[instr.name]); MOTH_END_INSTR(LoadProperty) MOTH_BEGIN_INSTR(StoreProperty) - __qmljs_set_property(context, VALUE(instr.base), runtimeStrings[instr.name], VALUE(instr.source)); + __qmljs_set_property(context, VALUEPTR(instr.base), runtimeStrings[instr.name], VALUEPTR(instr.source)); MOTH_END_INSTR(StoreProperty) MOTH_BEGIN_INSTR(Push) TRACE(inline, "stack size: %u", instr.value); stackSize = instr.value; - stack = static_cast<QV4::Value *>(alloca(stackSize * sizeof(QV4::Value))); + stack = context->engine->stackPush(stackSize); memset(stack, 0, stackSize * sizeof(QV4::Value)); MOTH_END_INSTR(Push) @@ -318,33 +320,45 @@ 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), VALUEPTR(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, QV4::ValueRef::fromRawValue(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), VALUEPTR(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) - __qmljs_throw(context, VALUE(instr.arg)); + __qmljs_throw(context, VALUEPTR(instr.arg)); MOTH_END_INSTR(CallBuiltinThrow) MOTH_BEGIN_INSTR(EnterTry) @@ -358,7 +372,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code, ex.accept(context); VALUE(instr.exceptionVar) = ex.value(); try { - QV4::ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(runtimeStrings[instr.exceptionVarName], ex.value(), context); + QV4::ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(runtimeStrings[instr.exceptionVarName], VALUEPTR(instr.exceptionVar), context); const uchar *catchCode = ((uchar *)&instr.catchOffset) + instr.catchOffset; run(catchContext, catchCode, stack, stackSize); code = catchCode; @@ -380,7 +394,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code, MOTH_END_INSTR(CallBuiltinFinishTry) MOTH_BEGIN_INSTR(CallBuiltinPushScope) - context = __qmljs_builtin_push_with_scope(VALUE(instr.arg), context); + context = __qmljs_builtin_push_with_scope(VALUEPTR(instr.arg), context); MOTH_END_INSTR(CallBuiltinPushScope) MOTH_BEGIN_INSTR(CallBuiltinPopScope) @@ -388,19 +402,19 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code, MOTH_END_INSTR(CallBuiltinPopScope) MOTH_BEGIN_INSTR(CallBuiltinForeachIteratorObject) - __qmljs_foreach_iterator_object(context, VALUEPTR(instr.result), VALUE(instr.arg)); + __qmljs_foreach_iterator_object(context, VALUEPTR(instr.result), VALUEPTR(instr.arg)); MOTH_END_INSTR(CallBuiltinForeachIteratorObject) MOTH_BEGIN_INSTR(CallBuiltinForeachNextPropertyName) - __qmljs_foreach_next_property_name(VALUEPTR(instr.result), VALUE(instr.arg)); + __qmljs_foreach_next_property_name(VALUEPTR(instr.result), VALUEPTR(instr.arg)); MOTH_END_INSTR(CallBuiltinForeachNextPropertyName) MOTH_BEGIN_INSTR(CallBuiltinDeleteMember) - __qmljs_delete_member(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.member]); + __qmljs_delete_member(context, VALUEPTR(instr.result), VALUEPTR(instr.base), runtimeStrings[instr.member]); MOTH_END_INSTR(CallBuiltinDeleteMember) MOTH_BEGIN_INSTR(CallBuiltinDeleteSubscript) - __qmljs_delete_subscript(context, VALUEPTR(instr.result), VALUE(instr.base), VALUE(instr.index)); + __qmljs_delete_subscript(context, VALUEPTR(instr.result), VALUEPTR(instr.base), VALUEPTR(instr.index)); MOTH_END_INSTR(CallBuiltinDeleteSubscript) MOTH_BEGIN_INSTR(CallBuiltinDeleteName) @@ -408,11 +422,11 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code, MOTH_END_INSTR(CallBuiltinDeleteName) MOTH_BEGIN_INSTR(CallBuiltinTypeofMember) - __qmljs_builtin_typeof_member(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.member]); + __qmljs_builtin_typeof_member(context, VALUEPTR(instr.result), VALUEPTR(instr.base), runtimeStrings[instr.member]); MOTH_END_INSTR(CallBuiltinTypeofMember) MOTH_BEGIN_INSTR(CallBuiltinTypeofSubscript) - __qmljs_builtin_typeof_element(context, VALUEPTR(instr.result), VALUE(instr.base), VALUE(instr.index)); + __qmljs_builtin_typeof_element(context, VALUEPTR(instr.result), VALUEPTR(instr.base), VALUEPTR(instr.index)); MOTH_END_INSTR(CallBuiltinTypeofSubscript) MOTH_BEGIN_INSTR(CallBuiltinTypeofName) @@ -420,15 +434,15 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code, MOTH_END_INSTR(CallBuiltinTypeofName) MOTH_BEGIN_INSTR(CallBuiltinTypeofValue) - __qmljs_builtin_typeof(context, VALUEPTR(instr.result), VALUE(instr.value)); + __qmljs_builtin_typeof(context, VALUEPTR(instr.result), VALUEPTR(instr.value)); MOTH_END_INSTR(CallBuiltinTypeofValue) MOTH_BEGIN_INSTR(CallBuiltinPostIncMember) - __qmljs_builtin_post_increment_member(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.member]); + __qmljs_builtin_post_increment_member(context, VALUEPTR(instr.result), VALUEPTR(instr.base), runtimeStrings[instr.member]); MOTH_END_INSTR(CallBuiltinTypeofMember) MOTH_BEGIN_INSTR(CallBuiltinPostIncSubscript) - __qmljs_builtin_post_increment_element(context, VALUEPTR(instr.result), VALUE(instr.base), VALUEPTR(instr.index)); + __qmljs_builtin_post_increment_element(context, VALUEPTR(instr.result), VALUEPTR(instr.base), VALUEPTR(instr.index)); MOTH_END_INSTR(CallBuiltinTypeofSubscript) MOTH_BEGIN_INSTR(CallBuiltinPostIncName) @@ -440,11 +454,11 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code, MOTH_END_INSTR(CallBuiltinTypeofValue) MOTH_BEGIN_INSTR(CallBuiltinPostDecMember) - __qmljs_builtin_post_decrement_member(context, VALUEPTR(instr.result), VALUE(instr.base), runtimeStrings[instr.member]); + __qmljs_builtin_post_decrement_member(context, VALUEPTR(instr.result), VALUEPTR(instr.base), runtimeStrings[instr.member]); MOTH_END_INSTR(CallBuiltinTypeofMember) MOTH_BEGIN_INSTR(CallBuiltinPostDecSubscript) - __qmljs_builtin_post_decrement_element(context, VALUEPTR(instr.result), VALUE(instr.base), VALUE(instr.index)); + __qmljs_builtin_post_decrement_element(context, VALUEPTR(instr.result), VALUEPTR(instr.base), VALUEPTR(instr.index)); MOTH_END_INSTR(CallBuiltinTypeofSubscript) MOTH_BEGIN_INSTR(CallBuiltinPostDecName) @@ -460,11 +474,11 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code, MOTH_END_INSTR(CallBuiltinDeclareVar) MOTH_BEGIN_INSTR(CallBuiltinDefineGetterSetter) - __qmljs_builtin_define_getter_setter(context, VALUE(instr.object), runtimeStrings[instr.name], VALUEPTR(instr.getter), VALUEPTR(instr.setter)); + __qmljs_builtin_define_getter_setter(context, VALUEPTR(instr.object), runtimeStrings[instr.name], VALUEPTR(instr.getter), VALUEPTR(instr.setter)); MOTH_END_INSTR(CallBuiltinDefineGetterSetter) MOTH_BEGIN_INSTR(CallBuiltinDefineProperty) - __qmljs_builtin_define_property(context, VALUE(instr.object), runtimeStrings[instr.name], VALUEPTR(instr.value)); + __qmljs_builtin_define_property(context, VALUEPTR(instr.object), runtimeStrings[instr.name], VALUEPTR(instr.value)); MOTH_END_INSTR(CallBuiltinDefineProperty) MOTH_BEGIN_INSTR(CallBuiltinDefineArray) @@ -483,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), VALUEPTR(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), VALUEPTR(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) @@ -506,22 +529,22 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code, MOTH_END_INSTR(Jump) MOTH_BEGIN_INSTR(CJump) - uint cond = __qmljs_to_boolean(VALUE(instr.condition)); + uint cond = __qmljs_to_boolean(VALUEPTR(instr.condition)); TRACE(condition, "%s", cond ? "TRUE" : "FALSE"); if (cond) code = ((uchar *)&instr.offset) + instr.offset; MOTH_END_INSTR(CJump) MOTH_BEGIN_INSTR(Unop) - instr.alu(VALUEPTR(instr.result), VALUE(instr.source)); + instr.alu(QV4::ValueRef::fromRawValue(VALUEPTR(instr.result)), QV4::ValueRef::fromRawValue(VALUEPTR(instr.source))); MOTH_END_INSTR(Unop) MOTH_BEGIN_INSTR(Binop) - instr.alu(VALUEPTR(instr.result), VALUE(instr.lhs), VALUE(instr.rhs)); + instr.alu(VALUEPTR(instr.result), VALUEPTR(instr.lhs), VALUEPTR(instr.rhs)); MOTH_END_INSTR(Binop) MOTH_BEGIN_INSTR(BinopContext) - instr.alu(context, VALUEPTR(instr.result), VALUE(instr.lhs), VALUE(instr.rhs)); + instr.alu(context, VALUEPTR(instr.result), VALUEPTR(instr.lhs), VALUEPTR(instr.rhs)); MOTH_END_INSTR(BinopContext) MOTH_BEGIN_INSTR(AddNumberParams) @@ -552,6 +575,7 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code, MOTH_END_INSTR(SubNumberParams) MOTH_BEGIN_INSTR(Ret) + context->engine->stackPop(stackSize); QV4::Value &result = VALUE(instr.result); // TRACE(Ret, "returning value %s", result.toString(context)->toQString().toUtf8().constData()); return result; @@ -563,21 +587,21 @@ QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code, MOTH_BEGIN_INSTR(InplaceElementOp) instr.alu(context, - VALUE(instr.base), - VALUE(instr.index), - VALUE(instr.source)); + VALUEPTR(instr.base), + VALUEPTR(instr.index), + VALUEPTR(instr.source)); MOTH_END_INSTR(InplaceElementOp) MOTH_BEGIN_INSTR(InplaceMemberOp) instr.alu(context, - VALUE(instr.base), + VALUEPTR(instr.base), runtimeStrings[instr.member], - VALUE(instr.source)); + VALUEPTR(instr.source)); MOTH_END_INSTR(InplaceMemberOp) MOTH_BEGIN_INSTR(InplaceNameOp) TRACE(name, "%s", instr.name->toQString().toUtf8().constData()); - instr.alu(context, runtimeStrings[instr.name], VALUE(instr.source)); + instr.alu(context, runtimeStrings[instr.name], VALUEPTR(instr.source)); MOTH_END_INSTR(InplaceNameOp) #ifdef MOTH_THREADED_INTERPRETER diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index a70b9064d9..475e69cd77 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -62,6 +62,7 @@ #include <private/qv4functionobject_p.h> #include <private/qv4script_p.h> +#include <private/qv4scopedvalue_p.h> #include <QStack> #include <QStringList> @@ -1240,12 +1241,12 @@ void QQmlComponent::createObject(QQmlV4Function *args) if (!valuemap.isEmpty()) { QQmlComponentExtension *e = componentExtension(v8engine); - QV4::Value f = QV4::Script::evaluate(QV8Engine::getV4(v8engine), QString::fromLatin1(INITIALPROPERTIES_SOURCE), args->qmlGlobal().asObject()); - CALLDATA(2); - d.thisObject = QV4::Value::fromObject(v4engine->globalObject); - d.args[0] = object; - d.args[1] = valuemap; - f.asFunctionObject()->call(d); + QV4::Value f = QV4::Script::evaluate(v4engine, QString::fromLatin1(INITIALPROPERTIES_SOURCE), args->qmlGlobal().asObject()); + QV4::ScopedCallData callData(v4engine, 2); + callData->thisObject = QV4::Value::fromObject(v4engine->globalObject); + callData->args[0] = object; + callData->args[1] = valuemap; + f.asFunctionObject()->call(callData); } d->completeCreate(); @@ -1388,11 +1389,11 @@ void QQmlComponentPrivate::initializeObjectWithInitialProperties(const QV4::Valu if (!valuemap.isEmpty()) { QQmlComponentExtension *e = componentExtension(v8engine); QV4::Value f = QV4::Script::evaluate(QV8Engine::getV4(v8engine), QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlGlobal.asObject()); - CALLDATA(2); - d.thisObject = QV4::Value::fromObject(v4engine->globalObject); - d.args[0] = object; - d.args[1] = valuemap; - f.asFunctionObject()->call(d); + QV4::ScopedCallData callData(v4engine, 2); + callData->thisObject = QV4::Value::fromObject(v4engine->globalObject); + callData->args[0] = object; + callData->args[1] = valuemap; + f.asFunctionObject()->call(callData); } } @@ -1487,11 +1488,11 @@ void QmlIncubatorObject::setInitialState(QObject *o) QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8); QV4::Value f = QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlGlobal.asObject()); - CALLDATA(2); - d.thisObject = QV4::Value::fromObject(v4->globalObject); - d.args[0] = QV4::QObjectWrapper::wrap(v4, o); - d.args[1] = valuemap; - f.asFunctionObject()->call(d); + QV4::ScopedCallData callData(v4, 2); + callData->thisObject = QV4::Value::fromObject(v4->globalObject); + callData->args[0] = QV4::QObjectWrapper::wrap(v4, o); + callData->args[1] = valuemap; + f.asFunctionObject()->call(callData); } } @@ -1524,10 +1525,10 @@ void QmlIncubatorObject::statusChanged(Status s) if (QV4::FunctionObject *f = callback.asFunctionObject()) { QV4::ExecutionContext *ctx = f->engine()->current; try { - CALLDATA(1); - d.thisObject = QV4::Value::fromObject(this); - d.args[0] = QV4::Value::fromUInt32(s); - f->call(d); + QV4::ScopedCallData callData(ctx->engine, 1); + callData->thisObject = QV4::Value::fromObject(this); + callData->args[0] = QV4::Value::fromUInt32(s); + f->call(callData); } catch (QV4::Exception &e) { e.accept(ctx); QQmlError error; diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 41be44a0a7..2974bbcfbe 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -47,6 +47,7 @@ #include <private/qv4functionobject_p.h> #include <private/qv4script_p.h> #include <private/qv4errorobject_p.h> +#include <private/qv4scopedvalue_p.h> QT_BEGIN_NAMESPACE @@ -125,8 +126,7 @@ QV4::Value QQmlJavaScriptExpression::evaluate(QQmlContextData *context, const QV4::Value &function, bool *isUndefined) { - QV4::Value args[QV4::Global::ReservedArgumentCount]; - return evaluate(context, function, 0, args, isUndefined); + return evaluate(context, function, 0, 0, isUndefined); } QV4::Value @@ -173,11 +173,10 @@ QQmlJavaScriptExpression::evaluate(QQmlContextData *context, This = value; } - QV4::CallData d; - d.thisObject = This; - d.args = args; - d.argc = argc; - result = function.asFunctionObject()->call(d); + QV4::ScopedCallData callData(v4, argc); + callData->thisObject = This; + memcpy(callData->args, args, argc*sizeof(QV4::Value)); + result = function.asFunctionObject()->call(callData); if (isUndefined) *isUndefined = result.isUndefined(); diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp index d1ecfdc52d..cf1b5ffd18 100644 --- a/src/qml/qml/qqmlproperty.cpp +++ b/src/qml/qml/qqmlproperty.cpp @@ -1611,10 +1611,14 @@ QQmlMetaObject QQmlPropertyPrivate::rawMetaObjectForType(QQmlEnginePrivate *engi { if (engine) { return engine->rawMetaObjectForType(userType); - } else { - QQmlType *type = QQmlMetaType::qmlType(userType); - return QQmlMetaObject(type?type->baseMetaObject():0); } + QQmlType *type = QQmlMetaType::qmlType(userType); + if (type) + return QQmlMetaObject(type->baseMetaObject()); + QMetaType metaType(userType); + if ((metaType.flags() & QMetaType::PointerToQObject) && metaType.metaObject()) + return metaType.metaObject(); + return QQmlMetaObject((QObject*)0); } /*! diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index d10af391f5..a1385e06fc 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -124,7 +124,7 @@ static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *en engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType) : QQmlMetaType::typeCategory(propType); - if (cat == QQmlMetaType::Object) + if (cat == QQmlMetaType::Object || QMetaType::typeFlags(propType) & QMetaType::PointerToQObject) flags |= QQmlPropertyData::IsQObjectDerived; else if (cat == QQmlMetaType::List) flags |= QQmlPropertyData::IsQList; @@ -1553,7 +1553,7 @@ void QQmlPropertyCache::toMetaObjectBuilder(QMetaObjectBuilder &builder) } else { method = builder.addSlot(signature); } - method.setAccess(QMetaMethod::Protected); + method.setAccess(QMetaMethod::Public); if (arguments && arguments->names) method.setParameterNames(*arguments->names); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 3d2d54ccfa..0079b9580f 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -55,6 +55,7 @@ #include <private/qv4object_p.h> #include <private/qv4variantobject_p.h> #include <private/qv4functionobject_p.h> +#include <private/qv4scopedvalue_p.h> QT_BEGIN_NAMESPACE @@ -926,16 +927,16 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a) QQmlVMEMetaData::MethodData *data = metaData->methodData() + id; - CALLDATA(data->parameterCount); - d.thisObject = ep->v8engine()->global(); + QV4::ScopedCallData callData(function->engine(), data->parameterCount); + callData->thisObject = ep->v8engine()->global(); for (int ii = 0; ii < data->parameterCount; ++ii) - d.args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]); + callData->args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]); QV4::Value result = QV4::Value::undefinedValue(); QV4::ExecutionContext *ctx = function->engine()->current; try { - result = function->call(d); + result = function->call(callData); if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result, 0); } catch (QV4::Exception &e) { e.accept(ctx); diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index 211383ae58..ddc7a4894b 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -53,6 +53,7 @@ #include <private/qv4engine_p.h> #include <private/qv4functionobject_p.h> #include <private/qqmlcontextwrapper_p.h> +#include <private/qv4scopedvalue_p.h> #include <QtCore/qobject.h> #include <QtQml/qjsvalue.h> @@ -1481,9 +1482,9 @@ void QQmlXMLHttpRequest::dispatchCallback(const Value &me) QQmlContextData *callingContext = QmlContextWrapper::getContext(activationObject); if (callingContext) { - CALLDATA(0); - d.thisObject = activationObject; - callback->call(d); + QV4::ScopedCallData callData(v4, 0); + callData->thisObject = activationObject; + callback->call(callData); } // if the callingContext object is no longer valid, then it has been @@ -1563,7 +1564,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject if (c->proto) c->proto->mark(); } - static Value construct(Managed *that, const QV4::CallData &) + static Value construct(Managed *that, QV4::CallData *) { QQmlXMLHttpRequestCtor *ctor = that->as<QQmlXMLHttpRequestCtor>(); if (!ctor) @@ -1576,7 +1577,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject return Value::fromObject(w); } - static Value call(Managed *, const QV4::CallData &) { + static Value call(Managed *, QV4::CallData *) { return Value::undefinedValue(); } diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 8a636cdb99..2321e27bc6 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1184,10 +1184,10 @@ struct BindingFunction : public QV4::FunctionObject bindingKeyFlag = true; } - static Value call(Managed *that, const CallData &d) + static Value call(Managed *that, CallData *callData) { BindingFunction *This = static_cast<BindingFunction*>(that); - return This->originalFunction->call(d); + return This->originalFunction->call(callData); } static void markObjects(Managed *that) diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index 117fea272c..5b43dd6192 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -57,6 +57,7 @@ #include <private/qqmlcontextwrapper_p.h> #include <private/qqmlvaluetypewrapper_p.h> #include <private/qqmllistwrapper_p.h> +#include <private/qv4scopedvalue_p.h> #include "qv4domerrors_p.h" #include "qv4sqlerrors_p.h" @@ -310,6 +311,8 @@ QV4::Value QV8Engine::fromVariant(const QVariant &variant) a->arrayData[ii].value = QV4::QObjectWrapper::wrap(m_v4Engine, list.at(ii)); a->setArrayLengthUnchecked(list.count()); return QV4::Value::fromObject(a); + } else if (QMetaType::typeFlags(type) & QMetaType::PointerToQObject) { + return QV4::QObjectWrapper::wrap(m_v4Engine, *reinterpret_cast<QObject* const *>(ptr)); } bool objOk; @@ -440,10 +443,10 @@ void QV8Engine::initializeGlobal() void QV8Engine::freezeObject(const QV4::Value &value) { - CALLDATA(1); - d.args[0] = value; - d.thisObject = QV4::Value::fromObject(m_v4Engine->globalObject); - m_freezeObject.value().asFunctionObject()->call(d); + QV4::ScopedCallData callData(m_v4Engine, 1); + callData->args[0] = value; + callData->thisObject = QV4::Value::fromObject(m_v4Engine->globalObject); + m_freezeObject.value().asFunctionObject()->call(callData); } void QV8Engine::gc() diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h index 9c486d9809..8f724fa2eb 100644 --- a/src/qml/qml/v8/qv8engine_p.h +++ b/src/qml/qml/v8/qv8engine_p.h @@ -136,13 +136,13 @@ private: QQmlV4Function(const QQmlV4Function &); QQmlV4Function &operator=(const QQmlV4Function &); - QQmlV4Function(int length, QV4::Value *args, + QQmlV4Function(int length, const QV4::Value *args, QV4::Value *rv, const QV4::Value &global, QQmlContextData *c, QV8Engine *e) : argc(length), args(args), retVal(rv), global(global), ctx(c), e(e) {} int argc; - QV4::Value *args; + const QV4::Value *args; QV4::Value *retVal; QV4::Value global; QQmlContextData *ctx; diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp index b1b4862b18..bc52da6151 100644 --- a/src/qml/types/qqmldelegatemodel.cpp +++ b/src/qml/types/qqmldelegatemodel.cpp @@ -75,20 +75,20 @@ struct DelegateModelGroupFunction: QV4::FunctionObject isBuiltinFunction = true; } - static QV4::Value construct(QV4::Managed *m, const QV4::CallData &) + static QV4::Value construct(QV4::Managed *m, QV4::CallData *) { m->engine()->current->throwTypeError(); return QV4::Value::undefinedValue(); } - static QV4::Value call(QV4::Managed *that, const QV4::CallData &d) + static QV4::Value call(QV4::Managed *that, QV4::CallData *callData) { DelegateModelGroupFunction *f = static_cast<DelegateModelGroupFunction *>(that); - QQmlDelegateModelItemObject *o = d.thisObject.as<QQmlDelegateModelItemObject>(); + QQmlDelegateModelItemObject *o = callData->thisObject.as<QQmlDelegateModelItemObject>(); if (!o) that->engine()->current->throwTypeError(QStringLiteral("Not a valid VisualData object")); - QV4::Value v = d.argc ? d.args[0] : QV4::Value::undefinedValue(); + QV4::Value v = callData->argc ? callData->args[0] : QV4::Value::undefinedValue(); return f->code(o->item, f->flag, v); } }; diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp index 8822eaecd0..26514ac6db 100644 --- a/src/qml/types/qquickworkerscript.cpp +++ b/src/qml/types/qquickworkerscript.cpp @@ -65,6 +65,7 @@ #include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> #include <private/qv4script_p.h> +#include <private/qv4scopedvalue_p.h> QT_BEGIN_NAMESPACE @@ -233,10 +234,10 @@ void QQuickWorkerScriptEnginePrivate::WorkerEngine::init() QV4::Value function = QV4::Value::fromObject(m_v4Engine->newBuiltinFunction(m_v4Engine->rootContext, m_v4Engine->newString(QStringLiteral("sendMessage")), QQuickWorkerScriptEnginePrivate::sendMessage)); - CALLDATA(1); - d.args[0] = function; - d.thisObject = global(); - createsend = createsendconstructor->call(d); + QV4::ScopedCallData callData(m_v4Engine, 1); + callData->args[0] = function; + callData->thisObject = global(); + createsend = createsendconstructor->call(callData); } // Requires handle and context scope @@ -246,10 +247,10 @@ QV4::Value QQuickWorkerScriptEnginePrivate::WorkerEngine::sendFunction(int id) QV4::Value v = QV4::Value::undefinedValue(); QV4::ExecutionContext *ctx = f->internalClass->engine->current; try { - CALLDATA(1); - d.args[0] = QV4::Value::fromInt32(id); - d.thisObject = global(); - v = f->call(d); + QV4::ScopedCallData callData(m_v4Engine, 1); + callData->args[0] = QV4::Value::fromInt32(id); + callData->thisObject = global(); + v = f->call(callData); } catch (QV4::Exception &e) { e.accept(ctx); v = e.value(); @@ -351,11 +352,11 @@ void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &d QV4::ExecutionContext *ctx = f->internalClass->engine->current; try { - CALLDATA(2); - d.thisObject = workerEngine->global(); - d.args[0] = script->object.value(); - d.args[1] = value; - f->call(d); + QV4::ScopedCallData callData(ctx->engine, 2); + callData->thisObject = workerEngine->global(); + callData->args[0] = script->object.value(); + callData->args[1] = value; + f->call(callData); } catch (QV4::Exception &e) { e.accept(ctx); QQmlError error; |