diff options
117 files changed, 3236 insertions, 1755 deletions
diff --git a/.qmake.conf b/.qmake.conf index 6b70079d45..10a0930287 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,5 +1,6 @@ load(qt_build_config) CONFIG += qt_example_installs +CONFIG += warning_clean MODULE_VERSION = 5.2.0 diff --git a/examples/quick/externaldraganddrop/DragAndDropTextItem.qml b/examples/quick/externaldraganddrop/DragAndDropTextItem.qml new file mode 100644 index 0000000000..390a4b3abe --- /dev/null +++ b/examples/quick/externaldraganddrop/DragAndDropTextItem.qml @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 + +Rectangle { + id: item + property string display + color: "#EEE" + Text { + anchors.fill: parent + text: item.display + wrapMode: Text.WordWrap + } + DropArea { + anchors.fill: parent + keys: ["text/plain"] + onEntered: { + item.color = "#FCC" + } + onExited: { + item.color = "#EEE" + } + onDropped: { + item.color = "#EEE" + if (drop.hasText) { + if (drop.proposedAction == Qt.MoveAction || drop.proposedAction == Qt.CopyAction) { + item.display = drop.text + drop.acceptProposedAction() + } + } + } + } + MouseArea { + id: mouseArea + anchors.fill: parent + drag.target: draggable + } + Item { + id: draggable + anchors.fill: parent + Drag.active: mouseArea.drag.active + Drag.hotSpot.x: 0 + Drag.hotSpot.y: 0 + Drag.mimeData: { "text/plain": item.display } + Drag.dragType: Drag.Automatic + Drag.onDragStarted: { + } + Drag.onDragFinished: { + if (dropAction == Qt.MoveAction) { + item.display = "" + } + } + } // Item +} diff --git a/examples/quick/externaldraganddrop/doc/images/qml-dnd2-example.png b/examples/quick/externaldraganddrop/doc/images/qml-dnd2-example.png Binary files differnew file mode 100644 index 0000000000..e657d81795 --- /dev/null +++ b/examples/quick/externaldraganddrop/doc/images/qml-dnd2-example.png diff --git a/examples/quick/externaldraganddrop/doc/src/externaldraganddrop.qdoc b/examples/quick/externaldraganddrop/doc/src/externaldraganddrop.qdoc new file mode 100644 index 0000000000..1251e6e1eb --- /dev/null +++ b/examples/quick/externaldraganddrop/doc/src/externaldraganddrop.qdoc @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: http://www.gnu.org/copyleft/fdl.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ +/*! + \title Qt Quick Examples - externaldraganddrop + \example externaldraganddrop + \brief This is an example of drag and drop between Qml and other applications + \image qml-dnd2-example.png + \ingroup qtquickexamples + + This example shows you how to respond to do drag and drop using MouseArea and DropArea. + + Drag text between boxes, out of boxes into other applications, and from other applications into the boxes. Use option/ctrl to copy rather than move text when dragging between boxes. + +*/ diff --git a/examples/quick/externaldraganddrop/externaldraganddrop.pro b/examples/quick/externaldraganddrop/externaldraganddrop.pro new file mode 100644 index 0000000000..646781e7d1 --- /dev/null +++ b/examples/quick/externaldraganddrop/externaldraganddrop.pro @@ -0,0 +1,11 @@ +TEMPLATE = app + +QT += quick qml +SOURCES += main.cpp +RESOURCES += externaldraganddrop.qrc + +EXAMPLE_FILES = \ + DragAndDropTextItem.qml + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/externaldraganddrop +INSTALLS += target diff --git a/examples/quick/externaldraganddrop/externaldraganddrop.qml b/examples/quick/externaldraganddrop/externaldraganddrop.qml new file mode 100644 index 0000000000..f39d33dda7 --- /dev/null +++ b/examples/quick/externaldraganddrop/externaldraganddrop.qml @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.0 + +Item { + id: root + width: 320 + height: 480 + + ColumnLayout { + + anchors.fill: parent + anchors.margins: 8 + + Text { + Layout.fillWidth: true + text: "Drag text into, out of, and between the boxes below." + wrapMode: Text.WordWrap + } + + DragAndDropTextItem { + Layout.fillWidth: true + height: 142 + display: "Sample Text" + } + + DragAndDropTextItem { + Layout.fillWidth: true + height: 142 + display: "Option/ctrl drag to copy instead of move text." + } + + DragAndDropTextItem { + Layout.fillWidth: true + height: 142 + display: "Drag out into other applications." + } + + } +} diff --git a/examples/quick/externaldraganddrop/externaldraganddrop.qmlproject b/examples/quick/externaldraganddrop/externaldraganddrop.qmlproject new file mode 100644 index 0000000000..359efae597 --- /dev/null +++ b/examples/quick/externaldraganddrop/externaldraganddrop.qmlproject @@ -0,0 +1,16 @@ +import QmlProject 1.1 + +Project { + mainFile: "externaldraganddrop.qml" + + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "." + } + JavaScriptFiles { + directory: "." + } + ImageFiles { + directory: "." + } +} diff --git a/examples/quick/externaldraganddrop/externaldraganddrop.qrc b/examples/quick/externaldraganddrop/externaldraganddrop.qrc new file mode 100644 index 0000000000..edac9820c9 --- /dev/null +++ b/examples/quick/externaldraganddrop/externaldraganddrop.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/externaldraganddrop"> + <file>externaldraganddrop.qml</file> + <file>DragAndDropTextItem.qml</file> + </qresource> +</RCC> diff --git a/examples/quick/externaldraganddrop/main.cpp b/examples/quick/externaldraganddrop/main.cpp new file mode 100644 index 0000000000..33600e7983 --- /dev/null +++ b/examples/quick/externaldraganddrop/main.cpp @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the examples of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "../shared/shared.h" +DECLARATIVE_EXAMPLE_MAIN(externaldraganddrop/externaldraganddrop) diff --git a/examples/quick/quick.pro b/examples/quick/quick.pro index e4c00fffa1..c6b7ee1c34 100644 --- a/examples/quick/quick.pro +++ b/examples/quick/quick.pro @@ -2,6 +2,7 @@ TEMPLATE = subdirs SUBDIRS = quick-accessibility \ animation \ draganddrop \ + externaldraganddrop \ canvas \ imageelements \ keyinteraction \ diff --git a/src/imports/localstorage/plugin.cpp b/src/imports/localstorage/plugin.cpp index 578c388b44..405acd0f7c 100644 --- a/src/imports/localstorage/plugin.cpp +++ b/src/imports/localstorage/plugin.cpp @@ -60,6 +60,7 @@ #include <private/qv4functionobject_p.h> #include <private/qv4objectproto_p.h> #include <private/qv4exception_p.h> +#include <private/qv4scopedvalue_p.h> using namespace QV4; @@ -340,11 +341,11 @@ static Value qmlsqldatabase_changeVersion(SimpleCallContext *ctx) ok = false; db.transaction(); - CALLDATA(1); - d.thisObject = engine->global(); - d.args[0] = Value::fromObject(w); + ScopedCallData callData(ctx->engine, 1); + callData->thisObject = engine->global(); + callData->args[0] = Value::fromObject(w); try { - f->call(d); + f->call(callData); } catch (Exception &) { db.rollback(); throw; @@ -394,11 +395,11 @@ static Value qmlsqldatabase_transaction_shared(SimpleCallContext *ctx, bool read db.transaction(); if (callback) { - CALLDATA(1); - d.thisObject = engine->global(); - d.args[0] = Value::fromObject(w); + ScopedCallData callData(ctx->engine, 1); + callData->thisObject = engine->global(); + callData->args[0] = Value::fromObject(w); try { - callback->call(d); + callback->call(callData); } catch (Exception &) { w->inTransaction = false; db.rollback(); @@ -677,10 +678,10 @@ void QQuickLocalStorage::openDatabaseSync(QQmlV4Function *args) db->version = version; if (created && dbcreationCallback) { - CALLDATA(1); - d.thisObject = engine->global(); - d.args[0] = Value::fromObject(db); - dbcreationCallback->call(d); + ScopedCallData callData(ctx->engine, 1); + callData->thisObject = engine->global(); + callData->args[0] = Value::fromObject(db); + dbcreationCallback->call(callData); } args->setReturnValue(Value::fromObject(db)); 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; diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp index 2538cad211..52281a4fbc 100644 --- a/src/quick/items/context2d/qquickcanvasitem.cpp +++ b/src/quick/items/context2d/qquickcanvasitem.cpp @@ -54,6 +54,7 @@ #include <private/qv4value_p.h> #include <private/qv4functionobject_p.h> +#include <private/qv4scopedvalue_p.h> QT_BEGIN_NAMESPACE @@ -663,10 +664,10 @@ void QQuickCanvasItem::updatePolish() QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(qmlEngine(this)); QV4::FunctionObject *f = animationCallbacks.value(key).value().asFunctionObject(); - CALLDATA(1); - d.thisObject = QV4::QObjectWrapper::wrap(v4, this); - d.args[0] = QV4::Value::fromUInt32(QDateTime::currentDateTimeUtc().toTime_t()); - f->call(d); + QV4::ScopedCallData callData(v4, 1); + callData->thisObject = QV4::QObjectWrapper::wrap(v4, this); + callData->args[0] = QV4::Value::fromUInt32(QDateTime::currentDateTimeUtc().toTime_t()); + f->call(callData); } } else { diff --git a/src/quick/items/qquickclipnode.cpp b/src/quick/items/qquickclipnode.cpp index f20ca4a42c..5b3fe19595 100644 --- a/src/quick/items/qquickclipnode.cpp +++ b/src/quick/items/qquickclipnode.cpp @@ -51,6 +51,7 @@ QQuickDefaultClipNode::QQuickDefaultClipNode(const QRectF &rect) , m_dirty_geometry(true) , m_geometry(QSGGeometry::defaultAttributes_Point2D(), 0) { + Q_UNUSED(m_reserved); setGeometry(&m_geometry); setIsRectangular(true); } diff --git a/src/quick/items/qquickdrag.cpp b/src/quick/items/qquickdrag.cpp index f145ce259f..0ae26cb5c3 100644 --- a/src/quick/items/qquickdrag.cpp +++ b/src/quick/items/qquickdrag.cpp @@ -46,7 +46,9 @@ #include <private/qquickitemchangelistener_p.h> #include <private/qv8engine_p.h> #include <QtCore/qcoreapplication.h> +#include <QtCore/qmimedata.h> #include <QtQml/qqmlinfo.h> +#include <QtGui/qdrag.h> #include <QtGui/qevent.h> #ifndef QT_NO_DRAGANDDROP @@ -72,6 +74,7 @@ public: , itemMoved(false) , eventQueued(false) , overrideActions(false) + , dragType(QQuickDrag::Internal) { } @@ -83,8 +86,8 @@ public: void deliverMoveEvent(); void deliverLeaveEvent(); void deliverEvent(QQuickWindow *window, QEvent *event); - void start() { start(supportedActions); } void start(Qt::DropActions supportedActions); + Qt::DropAction startDrag(Qt::DropActions supportedActions); void setTarget(QQuickItem *item); QQuickDragGrabber dragGrabber; @@ -105,6 +108,8 @@ public: bool overrideActions : 1; QPointF hotSpot; QStringList keys; + QVariantMap externalMimeData; + QQuickDrag::DragType dragType; }; /*! @@ -272,7 +277,10 @@ QQuickDragAttached::~QQuickDragAttached() This property holds whether a drag event sequence is currently active. - Setting this property to true will send a QDragEnter event to the scene + Binding this property to the active property of \l MouseArea::drag will + cause \l startDrag to be called when the user starts dragging. + + Setting this property to true will also send a QDragEnter event to the scene with the item's current position. Setting it to false will send a QDragLeave event. @@ -292,8 +300,18 @@ void QQuickDragAttached::setActive(bool active) if (d->active != active) { if (d->inEvent) qmlInfo(this) << "active cannot be changed from within a drag event handler"; - else if (active) - d->start(d->supportedActions); + else if (active) { + if (d->dragType == QQuickDrag::Internal) { + d->start(d->supportedActions); + } + else if (d->dragType == QQuickDrag::Automatic) { + // There are different semantics than start() since startDrag() + // may be called after an internal drag is already started. + active = true; + emit activeChanged(); + d->startDrag(d->supportedActions); + } + } else cancel(); } @@ -411,6 +429,28 @@ void QQuickDragAttached::setKeys(const QStringList &keys) } /*! + \qmlattachedproperty stringlist QtQuick2::Drag::mimeData + \since QtQuick 2.2 + + This property holds a map of mimeData that is used during startDrag. +*/ + +QVariantMap QQuickDragAttached::mimeData() const +{ + Q_D(const QQuickDragAttached); + return d->externalMimeData; +} + +void QQuickDragAttached::setMimeData(const QVariantMap &mimeData) +{ + Q_D(QQuickDragAttached); + if (d->externalMimeData != mimeData) { + d->externalMimeData = mimeData; + emit mimeDataChanged(); + } +} + +/*! \qmlattachedproperty flags QtQuick2::Drag::supportedActions This property holds return values of Drag.drop() supported by the drag source. @@ -465,6 +505,42 @@ void QQuickDragAttached::setProposedAction(Qt::DropAction action) } } +/*! + \qmlattachedproperty enumeration QtQuick2::Drag::dragType + \since QtQuick 2.2 + + This property indicates whether to automatically start drags, do nothing, or + to use backwards compatible internal drags. The default is to use backwards + compatible internal drags. + + A drag can also be started manually using \l startDrag. + + \list + \li Drag.None - do not start drags automatically + \li Drag.Automatic - start drags automatically + \li Drag.Internal (default) - start backwards compatible drags automatically + \endlist + + When using \l Drag.Automatic you should also define \l mimeData and bind the + \active property to the active property of \l MouseArea.drag. + + */ + +QQuickDrag::DragType QQuickDragAttached::dragType() const +{ + Q_D(const QQuickDragAttached); + return d->dragType; +} + +void QQuickDragAttached::setDragType(QQuickDrag::DragType dragType) +{ + Q_D(QQuickDragAttached); + if (d->dragType != dragType) { + d->dragType = dragType; + emit dragTypeChanged(); + } +} + void QQuickDragAttachedPrivate::start(Qt::DropActions supportedActions) { Q_Q(QQuickDragAttached); @@ -496,7 +572,8 @@ void QQuickDragAttachedPrivate::start(Qt::DropActions supportedActions) /*! \qmlattachedmethod void QtQuick2::Drag::start(flags supportedActions) - Starts sending drag events. + Starts sending drag events. Used for starting old-style internal drags. \l startDrag is the + new-style, preferred method of starting drags. The optional \a supportedActions argument can be used to override the \l supportedActions property for the started sequence. @@ -616,6 +693,223 @@ void QQuickDragAttached::cancel() emit activeChanged(); } +/*! + \qmlsignal QtQuick2::DropArea::onDragStarted() + + This handler is called when a drag is started with the \l startDrag method + or when it is started automatically using the \l dragType property. + */ + +/*! + \qmlsignal QtQuick2::DropArea::onDragFinished(DropAction action) + + This handler is called when a drag finishes and the drag was started with the + \l startDrag method or started automatically using the \l dragType property. + */ + +Qt::DropAction QQuickDragAttachedPrivate::startDrag(Qt::DropActions supportedActions) +{ + Q_Q(QQuickDragAttached); + + QDrag *drag = new QDrag(q); + QMimeData *mimeData = new QMimeData(); + + Q_FOREACH (const QString &key, externalMimeData.keys()) { + mimeData->setData(key, externalMimeData[key].toString().toUtf8()); + } + + drag->setMimeData(mimeData); + + // TODO: how to handle drag image? + // drag->setPixmap(iconPixmap); + + emit q->dragStarted(); + + Qt::DropAction dropAction = drag->exec(supportedActions); + + delete drag; + + deliverLeaveEvent(); + + if (target) { + target = 0; + emit q->targetChanged(); + } + + emit q->dragFinished(dropAction); + + active = false; + emit q->activeChanged(); + + return dropAction; +} + + +/*! + \qmlattachedmethod void QtQuick2::Drag::startDrag(flags supportedActions) + + Starts sending drag events. + + The optional \a supportedActions argument can be used to override the \l supportedActions + property for the started sequence. +*/ + +void QQuickDragAttached::startDrag(QQmlV4Function *args) +{ + Q_D(QQuickDragAttached); + + if (d->inEvent) { + qmlInfo(this) << "startDrag() cannot be called from within a drag event handler"; + return; + } + + if (!d->active) { + qmlInfo(this) << "startDrag() drag must be active"; + return; + } + + Qt::DropActions supportedActions = d->supportedActions; + + // check arguments for supportedActions + if (args->length() >= 1) { + QV4::Value v = (*args)[0]; + if (v.isInt32()) { + supportedActions = Qt::DropActions(v.integerValue()); + } + } + + Qt::DropAction dropAction = d->startDrag(supportedActions); + + args->setReturnValue(QV4::Value::fromInt32(dropAction)); +} + +QQuickDrag::QQuickDrag(QObject *parent) +: QObject(parent), _target(0), _axis(XAndYAxis), _xmin(-FLT_MAX), +_xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false) +{ +} + +QQuickDrag::~QQuickDrag() +{ +} + +QQuickItem *QQuickDrag::target() const +{ + return _target; +} + +void QQuickDrag::setTarget(QQuickItem *t) +{ + if (_target == t) + return; + _target = t; + emit targetChanged(); +} + +void QQuickDrag::resetTarget() +{ + if (_target == 0) + return; + _target = 0; + emit targetChanged(); +} + +QQuickDrag::Axis QQuickDrag::axis() const +{ + return _axis; +} + +void QQuickDrag::setAxis(QQuickDrag::Axis a) +{ + if (_axis == a) + return; + _axis = a; + emit axisChanged(); +} + +qreal QQuickDrag::xmin() const +{ + return _xmin; +} + +void QQuickDrag::setXmin(qreal m) +{ + if (_xmin == m) + return; + _xmin = m; + emit minimumXChanged(); +} + +qreal QQuickDrag::xmax() const +{ + return _xmax; +} + +void QQuickDrag::setXmax(qreal m) +{ + if (_xmax == m) + return; + _xmax = m; + emit maximumXChanged(); +} + +qreal QQuickDrag::ymin() const +{ + return _ymin; +} + +void QQuickDrag::setYmin(qreal m) +{ + if (_ymin == m) + return; + _ymin = m; + emit minimumYChanged(); +} + +qreal QQuickDrag::ymax() const +{ + return _ymax; +} + +void QQuickDrag::setYmax(qreal m) +{ + if (_ymax == m) + return; + _ymax = m; + emit maximumYChanged(); +} + +bool QQuickDrag::active() const +{ + return _active; +} + +void QQuickDrag::setActive(bool drag) +{ + if (_active == drag) + return; + _active = drag; + emit activeChanged(); +} + +bool QQuickDrag::filterChildren() const +{ + return _filterChildren; +} + +void QQuickDrag::setFilterChildren(bool filter) +{ + if (_filterChildren == filter) + return; + _filterChildren = filter; + emit filterChildrenChanged(); +} + +QQuickDragAttached *QQuickDrag::qmlAttachedProperties(QObject *obj) +{ + return new QQuickDragAttached(obj); +} + QT_END_NAMESPACE #endif // QT_NO_DRAGANDDROP diff --git a/src/quick/items/qquickdrag_p.h b/src/quick/items/qquickdrag_p.h index 3680fd5754..098fcc61b9 100644 --- a/src/quick/items/qquickdrag_p.h +++ b/src/quick/items/qquickdrag_p.h @@ -143,18 +143,90 @@ private: }; class QQmlV4Function; +class QQuickDragAttached; +class Q_AUTOTEST_EXPORT QQuickDrag : public QObject +{ + Q_OBJECT + + Q_ENUMS(Axis DragType) + Q_PROPERTY(QQuickItem *target READ target WRITE setTarget NOTIFY targetChanged RESET resetTarget) + Q_PROPERTY(Axis axis READ axis WRITE setAxis NOTIFY axisChanged) + Q_PROPERTY(qreal minimumX READ xmin WRITE setXmin NOTIFY minimumXChanged) + Q_PROPERTY(qreal maximumX READ xmax WRITE setXmax NOTIFY maximumXChanged) + Q_PROPERTY(qreal minimumY READ ymin WRITE setYmin NOTIFY minimumYChanged) + Q_PROPERTY(qreal maximumY READ ymax WRITE setYmax NOTIFY maximumYChanged) + Q_PROPERTY(bool active READ active NOTIFY activeChanged) + Q_PROPERTY(bool filterChildren READ filterChildren WRITE setFilterChildren NOTIFY filterChildrenChanged) + //### consider drag and drop + +public: + QQuickDrag(QObject *parent=0); + ~QQuickDrag(); + + enum DragType { None, Automatic, Internal }; + + QQuickItem *target() const; + void setTarget(QQuickItem *target); + void resetTarget(); + + enum Axis { XAxis=0x01, YAxis=0x02, XAndYAxis=0x03, XandYAxis=XAndYAxis }; + Axis axis() const; + void setAxis(Axis); + + qreal xmin() const; + void setXmin(qreal); + qreal xmax() const; + void setXmax(qreal); + qreal ymin() const; + void setYmin(qreal); + qreal ymax() const; + void setYmax(qreal); + + bool active() const; + void setActive(bool); + + bool filterChildren() const; + void setFilterChildren(bool); + + static QQuickDragAttached *qmlAttachedProperties(QObject *obj); + +Q_SIGNALS: + void targetChanged(); + void axisChanged(); + void minimumXChanged(); + void maximumXChanged(); + void minimumYChanged(); + void maximumYChanged(); + void activeChanged(); + void filterChildrenChanged(); + +private: + QQuickItem *_target; + Axis _axis; + qreal _xmin; + qreal _xmax; + qreal _ymin; + qreal _ymax; + bool _active : 1; + bool _filterChildren: 1; + Q_DISABLE_COPY(QQuickDrag) +}; class QQuickDragAttachedPrivate; class QQuickDragAttached : public QObject { Q_OBJECT + Q_DECLARE_PRIVATE(QQuickDragAttached) + Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged) Q_PROPERTY(QObject *source READ source WRITE setSource NOTIFY sourceChanged RESET resetSource) Q_PROPERTY(QObject *target READ target NOTIFY targetChanged) Q_PROPERTY(QPointF hotSpot READ hotSpot WRITE setHotSpot NOTIFY hotSpotChanged) Q_PROPERTY(QStringList keys READ keys WRITE setKeys NOTIFY keysChanged) + Q_PROPERTY(QVariantMap mimeData READ mimeData WRITE setMimeData NOTIFY mimeDataChanged) Q_PROPERTY(Qt::DropActions supportedActions READ supportedActions WRITE setSupportedActions NOTIFY supportedActionsChanged) Q_PROPERTY(Qt::DropAction proposedAction READ proposedAction WRITE setProposedAction NOTIFY proposedActionChanged) + Q_PROPERTY(QQuickDrag::DragType dragType READ dragType WRITE setDragType NOTIFY dragTypeChanged) public: QQuickDragAttached(QObject *parent); ~QQuickDragAttached(); @@ -174,36 +246,47 @@ public: QStringList keys() const; void setKeys(const QStringList &keys); + QVariantMap mimeData() const; + void setMimeData(const QVariantMap &mimeData); + Qt::DropActions supportedActions() const; void setSupportedActions(Qt::DropActions actions); Qt::DropAction proposedAction() const; void setProposedAction(Qt::DropAction action); + QQuickDrag::DragType dragType() const; + void setDragType(QQuickDrag::DragType dragType); + Q_INVOKABLE int drop(); bool event(QEvent *event); public Q_SLOTS: void start(QQmlV4Function *); + void startDrag(QQmlV4Function *); void cancel(); Q_SIGNALS: + void dragStarted(); + void dragFinished(Qt::DropAction dropAction); + void activeChanged(); void sourceChanged(); void targetChanged(); void hotSpotChanged(); void keysChanged(); + void mimeDataChanged(); void supportedActionsChanged(); void proposedActionChanged(); - -private: - Q_DECLARE_PRIVATE(QQuickDragAttached) + void dragTypeChanged(); }; - QT_END_NAMESPACE +QML_DECLARE_TYPE(QQuickDrag) +QML_DECLARE_TYPEINFO(QQuickDrag, QML_HAS_ATTACHED_PROPERTIES) + #endif // QT_NO_DRAGANDDROP #endif diff --git a/src/quick/items/qquickdroparea.cpp b/src/quick/items/qquickdroparea.cpp index f453c42e5b..09dc7eeebb 100644 --- a/src/quick/items/qquickdroparea.cpp +++ b/src/quick/items/qquickdroparea.cpp @@ -77,11 +77,12 @@ public: QPointF dragPosition; QQuickDropAreaDrag *drag; QPointer<QObject> source; - QPointer<QMimeData> mimeData; + bool containsDrag; }; QQuickDropAreaPrivate::QQuickDropAreaPrivate() : drag(0) + , containsDrag(false) { } @@ -133,7 +134,7 @@ QQuickDropArea::~QQuickDropArea() bool QQuickDropArea::containsDrag() const { Q_D(const QQuickDropArea); - return d->mimeData; + return d->containsDrag; } /*! @@ -217,7 +218,7 @@ qreal QQuickDropAreaDrag::y() const void QQuickDropArea::dragMoveEvent(QDragMoveEvent *event) { Q_D(QQuickDropArea); - if (!d->mimeData) + if (!d->containsDrag) return; d->dragPosition = event->pos(); @@ -259,28 +260,27 @@ void QQuickDropArea::dragEnterEvent(QDragEnterEvent *event) { Q_D(QQuickDropArea); const QMimeData *mimeData = event->mimeData(); - if (!d->effectiveEnable || d->mimeData || !mimeData || !d->hasMatchingKey(d->getKeys(mimeData))) + if (!d->effectiveEnable || d->containsDrag || !mimeData || !d->hasMatchingKey(d->getKeys(mimeData))) return; d->dragPosition = event->pos(); event->accept(); + QQuickDropEvent dragTargetEvent(d, event); emit entered(&dragTargetEvent); - if (event->isAccepted()) { - d->mimeData = const_cast<QMimeData *>(mimeData); - if (QQuickDragMimeData *dragMime = qobject_cast<QQuickDragMimeData *>(d->mimeData)) - d->source = dragMime->source(); - else - d->source = event->source(); - d->dragPosition = event->pos(); - if (d->drag) { - emit d->drag->positionChanged(); - emit d->drag->sourceChanged(); - } - emit containsDragChanged(); + d->containsDrag = true; + if (QQuickDragMimeData *dragMime = qobject_cast<QQuickDragMimeData *>(const_cast<QMimeData *>(mimeData))) + d->source = dragMime->source(); + else + d->source = event->source(); + d->dragPosition = event->pos(); + if (d->drag) { + emit d->drag->positionChanged(); + emit d->drag->sourceChanged(); } + emit containsDragChanged(); } /*! @@ -292,12 +292,12 @@ void QQuickDropArea::dragEnterEvent(QDragEnterEvent *event) void QQuickDropArea::dragLeaveEvent(QDragLeaveEvent *) { Q_D(QQuickDropArea); - if (!d->mimeData) + if (!d->containsDrag) return; emit exited(); - d->mimeData = 0; + d->containsDrag = false; d->source = 0; emit containsDragChanged(); if (d->drag) @@ -314,13 +314,13 @@ void QQuickDropArea::dragLeaveEvent(QDragLeaveEvent *) void QQuickDropArea::dropEvent(QDropEvent *event) { Q_D(QQuickDropArea); - if (!d->mimeData) + if (!d->containsDrag) return; QQuickDropEvent dragTargetEvent(d, event); emit dropped(&dragTargetEvent); - d->mimeData = 0; + d->containsDrag = false; d->source = 0; emit containsDragChanged(); if (d->drag) @@ -337,6 +337,16 @@ void QQuickDropArea::dropEvent(QDropEvent *event) The position of the drag event can be obtained from the \l x and \l y properties, and the \l keys property identifies the drag keys of the event \l source. + + The existence of specific drag types can be determined using the \l hasColor, + \l hasHtml, \l hasText, and \l hasUrls properties. + + The list of all supplied formats can be determined using the \l formats property. + + Specific drag types can be obtained using the \l colorData, \l html, \l text, + and \l urls properties. + + A string version of any available mimeType can be obtained using \l getDataAsString. */ /*! @@ -357,14 +367,6 @@ void QQuickDropArea::dropEvent(QDropEvent *event) This property holds the source of a drag event. */ -QObject *QQuickDropEvent::source() -{ - if (const QQuickDragMimeData *dragMime = qobject_cast<const QQuickDragMimeData *>(event->mimeData())) - return dragMime->source(); - else - return event->source(); -} - /*! \qmlproperty stringlist QtQuick2::DragEvent::keys @@ -372,11 +374,6 @@ QObject *QQuickDropEvent::source() drag event. */ -QStringList QQuickDropEvent::keys() const -{ - return d->getKeys(event->mimeData()); -} - /*! \qmlproperty enumeration QtQuick2::DragEvent::action @@ -400,6 +397,14 @@ QStringList QQuickDropEvent::keys() const */ /*! + \qmlproperty flags QtQuick2::DragEvent::proposedAction + \since QtQuick 2.2 + + This property holds the set of \l {action}{actions} proposed by the + drag source. +*/ + +/*! \qmlproperty bool QtQuick2::DragEvent::accepted This property holds whether the drag event was accepted by a handler. @@ -416,6 +421,157 @@ QStringList QQuickDropEvent::keys() const If an \a action is specified it will overwrite the value of the \l action property. */ +/*! + \qmlmethod QtQuick2::DragEvent::acceptProposedAction() + \since QtQuick 2.2 + + Accepts the drag event with the \l proposedAction. +*/ + +/*! + \qmlproperty bool QtQuick2::DragEvent::hasColor + \since QtQuick 2.2 + + This property holds whether the drag event contains a color item. +*/ + +/*! + \qmlproperty bool QtQuick2::DragEvent::hasHtml + \since QtQuick 2.2 + + This property holds whether the drag event contains a html item. +*/ + +/*! + \qmlproperty bool QtQuick2::DragEvent::hasText + \since QtQuick 2.2 + + This property holds whether the drag event contains a text item. +*/ + +/*! + \qmlproperty bool QtQuick2::DragEvent::hasUrls + \since QtQuick 2.2 + + This property holds whether the drag event contains one or more url items. +*/ + +/*! + \qmlproperty color QtQuick2::DragEvent::colorData + \since QtQuick 2.2 + + This property holds color data, if any. +*/ + +/*! + \qmlproperty string QtQuick2::DragEvent::html + \since QtQuick 2.2 + + This property holds html data, if any. +*/ + +/*! + \qmlproperty string QtQuick2::DragEvent::text + \since QtQuick 2.2 + + This property holds text data, if any. +*/ + +/*! + \qmlproperty urllist QtQuick2::DragEvent::urls + \since QtQuick 2.2 + + This property holds a list of urls, if any. +*/ + +/*! + \qmlproperty stringlist QtQuick2::DragEvent::formats + \since QtQuick 2.2 + + This property holds a list of mime type formats contained in the drag data. +*/ + +/*! + \qmlmethod string QtQuick2::DragEvent::getDataAsString(string format) + \since QtQuick 2.2 + + Returns the data for the given \a format converted to a string. \a format should be one contained in the \l formats property. +*/ + +QObject *QQuickDropEvent::source() +{ + if (const QQuickDragMimeData *dragMime = qobject_cast<const QQuickDragMimeData *>(event->mimeData())) + return dragMime->source(); + else + return event->source(); +} + +QStringList QQuickDropEvent::keys() const +{ + return d->getKeys(event->mimeData()); +} + +bool QQuickDropEvent::hasColor() const +{ + return event->mimeData()->hasColor(); +} + +bool QQuickDropEvent::hasHtml() const +{ + return event->mimeData()->hasHtml(); +} + +bool QQuickDropEvent::hasText() const +{ + return event->mimeData()->hasText(); +} + +bool QQuickDropEvent::hasUrls() const +{ + return event->mimeData()->hasUrls(); +} + +QVariant QQuickDropEvent::colorData() const +{ + return event->mimeData()->colorData(); +} + +QString QQuickDropEvent::html() const +{ + return event->mimeData()->html(); +} + +QString QQuickDropEvent::text() const +{ + return event->mimeData()->text(); +} + +QList<QUrl> QQuickDropEvent::urls() const +{ + return event->mimeData()->urls(); +} + +QStringList QQuickDropEvent::formats() const +{ + return event->mimeData()->formats(); +} + +void QQuickDropEvent::getDataAsString(QQmlV4Function *args) +{ + if (args->length() != 0) { + QV4::Value v = (*args)[0]; + QString format = v.toQString(); + QString rv = QString::fromUtf8(event->mimeData()->data(format)); + QV4::ExecutionEngine *v4 = QV8Engine::getV4(args->engine()); + args->setReturnValue(QV4::Value::fromString(v4, rv)); + } +} + +void QQuickDropEvent::acceptProposedAction(QQmlV4Function *) +{ + event->acceptProposedAction(); +} + void QQuickDropEvent::accept(QQmlV4Function *args) { Qt::DropAction action = event->dropAction(); @@ -425,6 +581,7 @@ void QQuickDropEvent::accept(QQmlV4Function *args) if (v.isInt32()) action = Qt::DropAction(v.integerValue()); } + // get action from arguments. event->setDropAction(action); event->accept(); diff --git a/src/quick/items/qquickdroparea_p.h b/src/quick/items/qquickdroparea_p.h index 3bdbe7f72e..6ba876ef34 100644 --- a/src/quick/items/qquickdroparea_p.h +++ b/src/quick/items/qquickdroparea_p.h @@ -62,8 +62,18 @@ class QQuickDropEvent : public QObject Q_PROPERTY(QObject *source READ source) Q_PROPERTY(QStringList keys READ keys) Q_PROPERTY(Qt::DropActions supportedActions READ supportedActions) + Q_PROPERTY(Qt::DropActions proposedAction READ proposedAction) Q_PROPERTY(Qt::DropAction action READ action WRITE setAction RESET resetAction) Q_PROPERTY(bool accepted READ accepted WRITE setAccepted) + Q_PROPERTY(bool hasColor READ hasColor) + Q_PROPERTY(bool hasHtml READ hasHtml) + Q_PROPERTY(bool hasText READ hasText) + Q_PROPERTY(bool hasUrls READ hasUrls) + Q_PROPERTY(QVariant colorData READ colorData) + Q_PROPERTY(QString html READ html) + Q_PROPERTY(QString text READ text) + Q_PROPERTY(QList<QUrl> urls READ urls) + Q_PROPERTY(QStringList formats READ formats) public: QQuickDropEvent(QQuickDropAreaPrivate *d, QDropEvent *event) : d(d), event(event) {} @@ -73,6 +83,7 @@ public: QObject *source(); Qt::DropActions supportedActions() const { return event->possibleActions(); } + Qt::DropActions proposedAction() const { return event->proposedAction(); } Qt::DropAction action() const { return event->dropAction(); } void setAction(Qt::DropAction action) { event->setDropAction(action); } void resetAction() { event->setDropAction(event->proposedAction()); } @@ -82,6 +93,18 @@ public: bool accepted() const { return event->isAccepted(); } void setAccepted(bool accepted) { event->setAccepted(accepted); } + bool hasColor() const; + bool hasHtml() const; + bool hasText() const; + bool hasUrls() const; + QVariant colorData() const; + QString html() const; + QString text() const; + QList<QUrl> urls() const; + QStringList formats() const; + + Q_INVOKABLE void getDataAsString(QQmlV4Function *); + Q_INVOKABLE void acceptProposedAction(QQmlV4Function *); Q_INVOKABLE void accept(QQmlV4Function *); private: diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp index 6fe4b39974..be3011b204 100644 --- a/src/quick/items/qquickimage.cpp +++ b/src/quick/items/qquickimage.cpp @@ -571,14 +571,6 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) node = d->sceneGraphContext()->createImageNode(); } - if (d->pixmapChanged) { - // force update the texture in the node to trigger reconstruction of - // geometry and the likes when a atlas segment has changed. - node->setTexture(0); - node->setTexture(texture); - d->pixmapChanged = false; - } - QRectF targetRect; QRectF sourceRect; QSGTexture::WrapMode hWrap = QSGTexture::ClampToEdge; @@ -671,6 +663,17 @@ QSGNode *QQuickImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) sourceRect.width() / d->pix.width(), sourceRect.height() / d->pix.height()); + if (d->pixmapChanged) { + // force update the texture in the node to trigger reconstruction of + // geometry and the likes when a atlas segment has changed. + node->setTexture(0); + if (texture->isAtlasTexture() && (hWrap == QSGTexture::Repeat || vWrap == QSGTexture::Repeat)) + node->setTexture(texture->removedFromAtlas()); + else + node->setTexture(texture); + d->pixmapChanged = false; + } + node->setHorizontalWrapMode(hWrap); node->setVerticalWrapMode(vWrap); node->setFiltering(d->smooth ? QSGTexture::Linear : QSGTexture::Nearest); diff --git a/src/quick/items/qquickmousearea.cpp b/src/quick/items/qquickmousearea.cpp index 1970a03bee..8a73a5d73d 100644 --- a/src/quick/items/qquickmousearea.cpp +++ b/src/quick/items/qquickmousearea.cpp @@ -61,137 +61,6 @@ DEFINE_BOOL_CONFIG_OPTION(qmlVisualTouchDebugging, QML_VISUAL_TOUCH_DEBUGGING) static const int PressAndHoldDelay = 800; -#ifndef QT_NO_DRAGANDDROP - -QQuickDrag::QQuickDrag(QObject *parent) -: QObject(parent), _target(0), _axis(XAndYAxis), _xmin(-FLT_MAX), -_xmax(FLT_MAX), _ymin(-FLT_MAX), _ymax(FLT_MAX), _active(false), _filterChildren(false) -{ -} - -QQuickDrag::~QQuickDrag() -{ -} - -QQuickItem *QQuickDrag::target() const -{ - return _target; -} - -void QQuickDrag::setTarget(QQuickItem *t) -{ - if (_target == t) - return; - _target = t; - emit targetChanged(); -} - -void QQuickDrag::resetTarget() -{ - if (_target == 0) - return; - _target = 0; - emit targetChanged(); -} - -QQuickDrag::Axis QQuickDrag::axis() const -{ - return _axis; -} - -void QQuickDrag::setAxis(QQuickDrag::Axis a) -{ - if (_axis == a) - return; - _axis = a; - emit axisChanged(); -} - -qreal QQuickDrag::xmin() const -{ - return _xmin; -} - -void QQuickDrag::setXmin(qreal m) -{ - if (_xmin == m) - return; - _xmin = m; - emit minimumXChanged(); -} - -qreal QQuickDrag::xmax() const -{ - return _xmax; -} - -void QQuickDrag::setXmax(qreal m) -{ - if (_xmax == m) - return; - _xmax = m; - emit maximumXChanged(); -} - -qreal QQuickDrag::ymin() const -{ - return _ymin; -} - -void QQuickDrag::setYmin(qreal m) -{ - if (_ymin == m) - return; - _ymin = m; - emit minimumYChanged(); -} - -qreal QQuickDrag::ymax() const -{ - return _ymax; -} - -void QQuickDrag::setYmax(qreal m) -{ - if (_ymax == m) - return; - _ymax = m; - emit maximumYChanged(); -} - -bool QQuickDrag::active() const -{ - return _active; -} - -void QQuickDrag::setActive(bool drag) -{ - if (_active == drag) - return; - _active = drag; - emit activeChanged(); -} - -bool QQuickDrag::filterChildren() const -{ - return _filterChildren; -} - -void QQuickDrag::setFilterChildren(bool filter) -{ - if (_filterChildren == filter) - return; - _filterChildren = filter; - emit filterChildrenChanged(); -} - -QQuickDragAttached *QQuickDrag::qmlAttachedProperties(QObject *obj) -{ - return new QQuickDragAttached(obj); -} - -#endif // QT_NO_DRAGANDDROP - QQuickMouseAreaPrivate::QQuickMouseAreaPrivate() : enabled(true), hovered(false), longPress(false), moved(false), stealMouse(false), doubleClick(false), preventStealing(false), diff --git a/src/quick/items/qquickmousearea_p.h b/src/quick/items/qquickmousearea_p.h index fa32f32b65..ffe75ad843 100644 --- a/src/quick/items/qquickmousearea_p.h +++ b/src/quick/items/qquickmousearea_p.h @@ -49,78 +49,7 @@ QT_BEGIN_NAMESPACE class QQuickMouseEvent; - -#ifndef QT_NO_DRAGANDDROP - -class QQuickDragAttached; -class Q_AUTOTEST_EXPORT QQuickDrag : public QObject -{ - Q_OBJECT - - Q_ENUMS(Axis) - Q_PROPERTY(QQuickItem *target READ target WRITE setTarget NOTIFY targetChanged RESET resetTarget) - Q_PROPERTY(Axis axis READ axis WRITE setAxis NOTIFY axisChanged) - Q_PROPERTY(qreal minimumX READ xmin WRITE setXmin NOTIFY minimumXChanged) - Q_PROPERTY(qreal maximumX READ xmax WRITE setXmax NOTIFY maximumXChanged) - Q_PROPERTY(qreal minimumY READ ymin WRITE setYmin NOTIFY minimumYChanged) - Q_PROPERTY(qreal maximumY READ ymax WRITE setYmax NOTIFY maximumYChanged) - Q_PROPERTY(bool active READ active NOTIFY activeChanged) - Q_PROPERTY(bool filterChildren READ filterChildren WRITE setFilterChildren NOTIFY filterChildrenChanged) - //### consider drag and drop - -public: - QQuickDrag(QObject *parent=0); - ~QQuickDrag(); - - QQuickItem *target() const; - void setTarget(QQuickItem *target); - void resetTarget(); - - enum Axis { XAxis=0x01, YAxis=0x02, XAndYAxis=0x03, XandYAxis=XAndYAxis }; - Axis axis() const; - void setAxis(Axis); - - qreal xmin() const; - void setXmin(qreal); - qreal xmax() const; - void setXmax(qreal); - qreal ymin() const; - void setYmin(qreal); - qreal ymax() const; - void setYmax(qreal); - - bool active() const; - void setActive(bool); - - bool filterChildren() const; - void setFilterChildren(bool); - - static QQuickDragAttached *qmlAttachedProperties(QObject *obj); - -Q_SIGNALS: - void targetChanged(); - void axisChanged(); - void minimumXChanged(); - void maximumXChanged(); - void minimumYChanged(); - void maximumYChanged(); - void activeChanged(); - void filterChildrenChanged(); - -private: - QQuickItem *_target; - Axis _axis; - qreal _xmin; - qreal _xmax; - qreal _ymin; - qreal _ymax; - bool _active : 1; - bool _filterChildren: 1; - Q_DISABLE_COPY(QQuickDrag) -}; - -#endif // QT_NO_DRAGANDDROP - +class QQuickDrag; class QQuickMouseAreaPrivate; class QQuickWheelEvent; // used in Qt Location @@ -244,10 +173,6 @@ private: QT_END_NAMESPACE -#ifndef QT_NO_DRAGANDDROP -QML_DECLARE_TYPE(QQuickDrag) -QML_DECLARE_TYPEINFO(QQuickDrag, QML_HAS_ATTACHED_PROPERTIES) -#endif QML_DECLARE_TYPE(QQuickMouseArea) #endif // QQUICKMOUSEAREA_P_H diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index e91ab778c8..c195994de4 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -48,6 +48,7 @@ #include <QtCore/qcoreapplication.h> +#include <QtCore/qmimedata.h> #include <QtQml/qqmlinfo.h> #include <QtGui/qevent.h> #include <QTextBoundaryFinder> @@ -2235,6 +2236,8 @@ void QQuickTextInput::setPasswordCharacter(const QString &str) same value as the TextInput::text property. Otherwise, this property holds the text visible to the user, while the \l text property holds the actual entered text. + + \readonly */ QString QQuickTextInput::displayText() const { diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index aaadae5d1d..c8bc026868 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -46,6 +46,8 @@ #include "qquickitem_p.h" #include "qquickevents_p_p.h" +#include <private/qquickdrag_p.h> + #include <QtQuick/private/qsgrenderer_p.h> #include <QtQuick/private/qsgtexture_p.h> #include <QtQuick/private/qsgflashnode_p.h> @@ -279,6 +281,26 @@ void QQuickWindow::update() d->windowManager->update(this); } +void forcePolishHelper(QQuickItem *item) +{ + if (item->flags() & QQuickItem::ItemHasContents) { + item->polish(); + } + + QList <QQuickItem *> items = item->childItems(); + for (int i=0; i<items.size(); ++i) + forcePolishHelper(items.at(i)); +} + +/*! + Schedules polish events on all items in the scene. +*/ +void QQuickWindow::forcePolish() +{ + Q_D(QQuickWindow); + forcePolishHelper(d->contentItem); +} + void forceUpdate(QQuickItem *item) { if (item->flags() & QQuickItem::ItemHasContents) @@ -344,6 +366,9 @@ QQuickWindowPrivate::QQuickWindowPrivate() #ifndef QT_NO_CURSOR , cursorItem(0) #endif +#ifndef QT_NO_DRAGANDDROP + , dragGrabber(0) +#endif , touchMouseId(-1) , touchMousePressTimestamp(0) , dirtyItemList(0) @@ -360,6 +385,9 @@ QQuickWindowPrivate::QQuickWindowPrivate() , renderTargetId(0) , incubationController(0) { +#ifndef QT_NO_DRAGANDDROP + dragGrabber = new QQuickDragGrabber; +#endif } QQuickWindowPrivate::~QQuickWindowPrivate() @@ -389,6 +417,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c) QObject::connect(context, SIGNAL(invalidated()), q, SLOT(cleanupSceneGraph()), Qt::DirectConnection); QObject::connect(q, SIGNAL(focusObjectChanged(QObject*)), q, SIGNAL(activeFocusItemChanged())); + QObject::connect(q, SIGNAL(screenChanged(QScreen*)), q, SLOT(forcePolish())); } /*! @@ -963,7 +992,9 @@ QQuickWindow::~QQuickWindow() QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); delete d->incubationController; d->incubationController = 0; - +#ifndef QT_NO_DRAGANDDROP + delete d->dragGrabber; d->dragGrabber = 0; +#endif delete d->contentItem; d->contentItem = 0; } @@ -1181,7 +1212,7 @@ bool QQuickWindow::event(QEvent *e) case QEvent::DragLeave: case QEvent::DragMove: case QEvent::Drop: - d->deliverDragEvent(&d->dragGrabber, e); + d->deliverDragEvent(d->dragGrabber, e); break; #endif case QEvent::WindowDeactivate: @@ -3053,6 +3084,68 @@ void QQuickWindow::setDefaultAlphaBuffer(bool useAlpha) } /*! + \since 5.2 + + Call this function to reset the OpenGL context its default state. + + The scene graph uses the OpenGL context and will both rely on and + clobber its state. When mixing raw OpenGL commands with scene + graph rendering, this function provides a convenient way of + resetting the OpenGL context state back to its default values. + + This function does not touch state in the fixed-function pipeline. + + This function does not clear the color, depth and stencil buffers. Use + QQuickWindow::setClearBeforeRendering to control clearing of the color + buffer. The depth and stencil buffer might be clobbered by the scene + graph renderer. Clear these manually on demand. + + \sa QQuickWindow::beforeRendering() + */ +void QQuickWindow::resetOpenGLState() +{ + if (!openglContext()) + return; + + QOpenGLFunctions *gl = openglContext()->functions(); + + gl->glBindBuffer(GL_ARRAY_BUFFER, 0); + gl->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + + int maxAttribs; + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttribs); + for (int i=0; i<maxAttribs; ++i) { + gl->glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, 0, 0); + gl->glDisableVertexAttribArray(i); + } + + gl->glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_STENCIL_TEST); + glDisable(GL_SCISSOR_TEST); + + glColorMask(true, true, true, true); + glClearColor(0, 0, 0, 0); + + glDepthMask(true); + glDepthFunc(GL_LESS); + gl->glClearDepthf(1); + + glStencilMask(0xff); + glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + glStencilFunc(GL_ALWAYS, 0, 0xff); + + glDisable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ZERO); + + gl->glUseProgram(0); + + QOpenGLFramebufferObject::bindDefault(); +} + +/*! \qmlproperty string QtQuick.Window2::Window::title The window's title in the windowing system. diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h index fad67e9734..a1ef9e1593 100644 --- a/src/quick/items/qquickwindow.h +++ b/src/quick/items/qquickwindow.h @@ -100,6 +100,8 @@ public: uint renderTargetId() const; QSize renderTargetSize() const; + void resetOpenGLState(); + QQmlIncubationController *incubationController() const; #ifndef QT_NO_ACCESSIBILITY @@ -141,6 +143,7 @@ Q_SIGNALS: public Q_SLOTS: void update(); + void forcePolish(); void releaseResources(); protected: diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h index aa7d7c5128..ad861754d7 100644 --- a/src/quick/items/qquickwindow_p.h +++ b/src/quick/items/qquickwindow_p.h @@ -57,7 +57,6 @@ #include "qquickwindow.h" #include <QtQuick/private/qsgcontext_p.h> -#include <private/qquickdrag_p.h> #include <QtCore/qthread.h> #include <QtCore/qmutex.h> @@ -73,6 +72,7 @@ QT_BEGIN_NAMESPACE //Make it easy to identify and customize the root item if needed class QSGRenderLoop; +class QQuickDragGrabber; class QQuickRootItem : public QQuickItem { @@ -116,7 +116,7 @@ public: QQuickItem *cursorItem; #endif #ifndef QT_NO_DRAGANDDROP - QQuickDragGrabber dragGrabber; + QQuickDragGrabber *dragGrabber; #endif int touchMouseId; bool checkIfDoubleClicked(ulong newPressEventTimestamp); diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 8d4b4dd9f6..cf71489f88 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -46,6 +46,10 @@ #include <QtGui/QGuiApplication> #include <QtGui/QOpenGLFramebufferObject> +#ifndef GL_DOUBLE + #define GL_DOUBLE 0x140A +#endif + QT_BEGIN_NAMESPACE extern QByteArray qsgShaderRewriter_insertZAttributes(const char *input); @@ -191,7 +195,7 @@ void qsg_dumpShadowRoots(BatchRootInfo *i, int indent) if (!i) { qDebug() << ind.constData() << "- no info"; } else { - qDebug() << ind.constData() << "- parent:" << i->parentRoot; + qDebug() << ind.constData() << "- parent:" << i->parentRoot << "orders" << i->firstOrder << "->" << i->lastOrder << ", avail:" << i->availableOrders; for (QSet<Node *>::const_iterator it = i->subRoots.constBegin(); it != i->subRoots.constEnd(); ++it) { qDebug() << ind.constData() << "-" << *it; @@ -213,7 +217,10 @@ void qsg_dumpShadowRoots(Node *n) qDebug() << ind.constData() << "[X]" << n->sgNode << hex << uint(n->sgNode->flags()); qsg_dumpShadowRoots(n->rootInfo(), indent); } else { - qDebug() << ind.constData() << "[ ]" << n->sgNode << hex << uint(n->sgNode->flags()); + QDebug d = qDebug(); + d << ind.constData() << "[ ]" << n->sgNode << hex << uint(n->sgNode->flags()); + if (n->type() == QSGNode::GeometryNodeType) + d << "order" << dec << n->element()->order; } SHADOWNODE_TRAVERSE(n) @@ -619,7 +626,8 @@ Renderer::Renderer(QSGContext *ctx) , m_opaqueRenderList(64) , m_alphaRenderList(64) , m_nextRenderOrder(0) - , m_explicitOrdering(false) + , m_partialRebuild(false) + , m_partialRebuildRoot(0) , m_opaqueBatches(16) , m_alphaBatches(16) , m_batchPool(16) @@ -818,14 +826,16 @@ void Renderer::nodeWasTransformed(Node *node, int *vertexCount) e->boundsComputed = false; if (e->batch) { if (!e->batch->isOpaque) { - e->batch->invalidate(); - m_rebuild |= BuildBatches; + if (e->root) { + m_taggedRoots << e->root; + m_rebuild |= BuildRenderListsForTaggedRoots; + } else { + m_rebuild |= FullRebuild; + } } else if (e->batch->merged) { e->batch->needsUpload = true; } } - if (e->batch && e->batch->merged) - e->batch->needsUpload = true; } } @@ -1022,7 +1032,12 @@ void Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state) if (!e->batch->geometryWasChanged(gn)) { m_rebuild |= Renderer::FullRebuild; } else if (!b->isOpaque) { - m_rebuild |= Renderer::BuildBatches; + if (e->root) { + m_taggedRoots << e->root; + m_rebuild |= BuildRenderListsForTaggedRoots; + } else { + m_rebuild |= FullRebuild; + } } else { b->needsUpload = true; } @@ -1030,8 +1045,7 @@ void Renderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state) } } - if (state & QSGNode::DirtyMaterial) { - Q_ASSERT(node->type() == QSGNode::GeometryNodeType); + if (state & QSGNode::DirtyMaterial && node->type() == QSGNode::GeometryNodeType) { Element *e = shadowNode->element(); if (e) { if (e->batch) { @@ -1104,30 +1118,27 @@ void Renderer::buildRenderLists(QSGNode *node) m_alphaRenderList << e; e->order = ++m_nextRenderOrder; - // Used while rebuilding partial roots. - if (m_explicitOrdering) + if (m_partialRebuild) e->orphaned = false; } else if (node->type() == QSGNode::ClipNodeType || shadowNode->isBatchRoot) { Q_ASSERT(m_nodes.contains(node)); BatchRootInfo *info = batchRootInfo(m_nodes.value(node)); - Q_ASSERT(!m_explicitOrdering || info->firstOrder >= 0); - Q_ASSERT(!m_explicitOrdering || info->lastOrder >= 0); - - if (m_explicitOrdering) + if (node == m_partialRebuildRoot) { m_nextRenderOrder = info->firstOrder; - int currentOrder = m_nextRenderOrder; - QSGNODE_TRAVERSE(node) - buildRenderLists(child); - int padding = (m_nextRenderOrder - currentOrder) >> 2; - if (m_explicitOrdering) { + QSGNODE_TRAVERSE(node) + buildRenderLists(child); m_nextRenderOrder = info->lastOrder + 1; } else { + int currentOrder = m_nextRenderOrder; + QSGNODE_TRAVERSE(node) + buildRenderLists(child); + int padding = (m_nextRenderOrder - currentOrder) >> 2; info->firstOrder = currentOrder; info->availableOrders = padding; info->lastOrder = m_nextRenderOrder + padding; - m_nextRenderOrder += padding; + m_nextRenderOrder = info->lastOrder; } return; } else if (node->type() == QSGNode::RenderNodeType) { @@ -1222,7 +1233,7 @@ void Renderer::buildRenderListsForTaggedRoots() m_opaqueRenderList.reset(); m_alphaRenderList.reset(); int maxRenderOrder = m_nextRenderOrder; - m_explicitOrdering = true; + m_partialRebuild = true; // Traverse each root, assigning it for (QSet<Node *>::const_iterator it = m_taggedRoots.constBegin(); it != m_taggedRoots.constEnd(); ++it) { @@ -1231,11 +1242,13 @@ void Renderer::buildRenderListsForTaggedRoots() if ((!i->parentRoot || !m_taggedRoots.contains(i->parentRoot)) && !nodeUpdater()->isNodeBlocked(root->sgNode, rootNode())) { m_nextRenderOrder = i->firstOrder; + m_partialRebuildRoot = root->sgNode; buildRenderLists(root->sgNode); } } + m_partialRebuild = false; + m_partialRebuildRoot = 0; m_taggedRoots.clear(); - m_explicitOrdering = false; m_nextRenderOrder = qMax(m_nextRenderOrder, maxRenderOrder); // Add orphaned elements back into the list and then sort it.. @@ -1783,6 +1796,7 @@ void Renderer::renderMergedBatch(const Batch *batch) if (Q_UNLIKELY(debug_render)) { QDebug debug = qDebug(); debug << " -" + << batch << (batch->uploadedThisFrame ? "[ upload]" : "[retained]") << (e->node->clipList() ? "[ clip]" : "[noclip]") << (batch->isOpaque ? "[opaque]" : "[ alpha]") @@ -1860,6 +1874,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch) if (Q_UNLIKELY(debug_render)) { qDebug() << " -" + << batch << (batch->uploadedThisFrame ? "[ upload]" : "[retained]") << (e->node->clipList() ? "[ clip]" : "[noclip]") << (batch->isOpaque ? "[opaque]" : "[ alpha]") diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h index 6f7694deac..1aa165281a 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h @@ -450,7 +450,8 @@ private: QDataBuffer<Element *> m_opaqueRenderList; QDataBuffer<Element *> m_alphaRenderList; int m_nextRenderOrder; - bool m_explicitOrdering; + bool m_partialRebuild; + QSGNode *m_partialRebuildRoot; QHash<QSGRenderNode *, RenderNodeElement *> m_renderNodeElements; QDataBuffer<Batch *> m_opaqueBatches; diff --git a/src/quick/scenegraph/coreapi/qsggeometry.cpp b/src/quick/scenegraph/coreapi/qsggeometry.cpp index 7f09af4da3..ffb11fc6fa 100644 --- a/src/quick/scenegraph/coreapi/qsggeometry.cpp +++ b/src/quick/scenegraph/coreapi/qsggeometry.cpp @@ -406,6 +406,7 @@ QSGGeometry::QSGGeometry(const QSGGeometry::AttributeSet &attributes, , m_vertex_usage_pattern(AlwaysUploadPattern) , m_line_width(1.0) { + Q_UNUSED(m_reserved_bits); Q_ASSERT(m_attributes.count > 0); Q_ASSERT(m_attributes.stride > 0); diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp index 713469f94a..fab3287087 100644 --- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp +++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp @@ -166,6 +166,7 @@ static bool qsg_leak_check = !qgetenv("QML_LEAK_CHECK").isEmpty(); */ QSGMaterialShader::QSGMaterialShader() { + Q_UNUSED(m_reserved); } /*! @@ -544,6 +545,7 @@ static void qt_print_material_count() QSGMaterial::QSGMaterial() : m_flags(0) { + Q_UNUSED(m_reserved); #ifndef QT_NO_DEBUG if (qsg_leak_check) { ++qt_material_count; diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp index a55a5abb0a..9d3d08e057 100644 --- a/src/quick/scenegraph/coreapi/qsgnode.cpp +++ b/src/quick/scenegraph/coreapi/qsgnode.cpp @@ -1053,6 +1053,7 @@ void QSGGeometryNode::setInheritedOpacity(qreal opacity) QSGClipNode::QSGClipNode() : QSGBasicGeometryNode(ClipNodeType) { + Q_UNUSED(m_reserved); } diff --git a/src/quick/scenegraph/util/qsgsimplerectnode.cpp b/src/quick/scenegraph/util/qsgsimplerectnode.cpp index 1e77ef5b0c..55e5ee9e3b 100644 --- a/src/quick/scenegraph/util/qsgsimplerectnode.cpp +++ b/src/quick/scenegraph/util/qsgsimplerectnode.cpp @@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE QSGSimpleRectNode::QSGSimpleRectNode(const QRectF &rect, const QColor &color) : m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4) { + Q_UNUSED(reserved); QSGGeometry::updateRectGeometry(&m_geometry, rect); m_material.setColor(color); setMaterial(&m_material); diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index 6a6bcbf7f8..c7bc8a4076 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -493,6 +493,8 @@ QSGTexture::WrapMode QSGTexture::verticalWrapMode() const void QSGTexture::updateBindOptions(bool force) { Q_D(QSGTexture); + force |= isAtlasTexture(); + if (force || d->filteringChanged) { bool linear = d->filterMode == Linear; GLint minFilter = linear ? GL_LINEAR : GL_NEAREST; diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp index e0c20307a8..4f21231184 100644 --- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp +++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp @@ -72,6 +72,7 @@ private slots: void qtbug_22535(); void evalAfterInvalidate(); + void qobjectDerived(); private: QQmlEngine engine; @@ -659,6 +660,26 @@ void tst_qqmlcontext::evalAfterInvalidate() QCoreApplication::processEvents(); } +void tst_qqmlcontext::qobjectDerived() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("refreshExpressions.qml")); + + CountCommand command; + // This test is similar to refreshExpressions, but with the key difference that + // we use the QVariant overload of setContextProperty. That way, we test that + // QVariant knowledge that it contains a QObject derived pointer is used. + engine.rootContext()->setContextProperty("countCommand", QVariant::fromValue(&command)); + + // We use a fresh context here to bypass any root-context optimizations in + // the engine + QQmlContext context(engine.rootContext()); + + QObject *o1 = component.create(&context); + + QCOMPARE(command.count, 2); +} + QTEST_MAIN(tst_qqmlcontext) #include "tst_qqmlcontext.moc" diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 1db3bc3fe8..99659fb1eb 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -55,6 +55,7 @@ #include "../../shared/util.h" #include <private/qv4functionobject_p.h> #include <private/qv4exception_p.h> +#include <private/qv4scopedvalue_p.h> #ifdef Q_CC_MSVC #define NO_INLINE __declspec(noinline) @@ -2260,9 +2261,9 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const QV4::FunctionObject *function = program.run().asFunctionObject(); if (!function) return false; - CALLDATA(1); - d.args[0] = o; - d.thisObject = engine->global(); + QV4::ScopedCallData d(ctx->engine, 1); + d->args[0] = o; + d->thisObject = engine->global(); function->call(d); } catch (QV4::Exception &e) { e.accept(ctx); @@ -2285,11 +2286,14 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o, QV4::FunctionObject *function = program.run().asFunctionObject(); if (!function) return false; - CALLDATA(1); - d.args[0] = o; - d.thisObject = engine->global(); - QV4::Value value = function->call(d); - return __qmljs_strict_equal(value, result); + QV4::ValueScope scope(ctx); + QV4::ScopedValue value(scope); + QV4::ScopedValue res(scope, result); + QV4::ScopedCallData d(ctx->engine, 1); + d->args[0] = o; + d->thisObject = engine->global(); + value = function->call(d); + return __qmljs_strict_equal(value, res); } catch (QV4::Exception &e) { e.accept(ctx); } @@ -2309,9 +2313,9 @@ static inline QV4::Value evaluate(QV8Engine *engine, const QV4::Value & o, QV4::FunctionObject *function = program.run().asFunctionObject(); if (!function) return QV4::Value::emptyValue(); - CALLDATA(1); - d.args[0] = o; - d.thisObject = engine->global(); + QV4::ScopedCallData d(ctx->engine, 1); + d->args[0] = o; + d->thisObject = engine->global(); QV4::Value value = function->call(d); return value; } catch (QV4::Exception &e) { diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index b5c8edf5f3..acb623989a 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -198,6 +198,18 @@ private: QStringList defaultImportPathList; void testType(const QString& qml, const QString& type, const QString& error, bool partialMatch = false); + + // When calling into JavaScript, the specific type of the return value can differ if that return + // value is a number. This is not only the case for non-integral numbers, or numbers that do not + // fit into the (signed) integer range, but it also depends on which optimizations are run. So, + // to check if the return value is of a number type, use this method instead of checking against + // a specific userType. + static bool isJSNumberType(int userType) + { + return userType == (int) QVariant::Int + || userType == (int) QVariant::UInt + || userType == (int) QVariant::Double; + } }; #define DETERMINE_ERRORS(errorfile,expected,actual)\ @@ -841,8 +853,8 @@ void tst_qqmllanguage::bindJSValueToVar() QCOMPARE(object->property("test14").userType(), (int)QVariant::PointF); QCOMPARE(object->property("test15").userType(), (int)QVariant::SizeF); QCOMPARE(object->property("test16").userType(), (int)QVariant::Vector3D); - QCOMPARE(object->property("test1Bound").userType(), (int)QVariant::Int); - QCOMPARE(object->property("test20Bound").userType(), (int)QVariant::Double); + QVERIFY(isJSNumberType(object->property("test1Bound").userType())); + QVERIFY(isJSNumberType(object->property("test20Bound").userType())); QCOMPARE(object->property("test1"), QVariant(5)); QCOMPARE(object->property("test2"), QVariant((double)1.7)); @@ -890,8 +902,8 @@ void tst_qqmllanguage::bindJSValueToVariant() QCOMPARE(object->property("test14").userType(), (int)QVariant::PointF); QCOMPARE(object->property("test15").userType(), (int)QVariant::SizeF); QCOMPARE(object->property("test16").userType(), (int)QVariant::Vector3D); - QCOMPARE(object->property("test1Bound").userType(), (int)QVariant::Int); - QCOMPARE(object->property("test20Bound").userType(), (int)QVariant::Double); + QVERIFY(isJSNumberType(object->property("test1Bound").userType())); + QVERIFY(isJSNumberType(object->property("test20Bound").userType())); QCOMPARE(object->property("test1"), QVariant(5)); QCOMPARE(object->property("test2"), QVariant((double)1.7)); @@ -3004,7 +3016,6 @@ void tst_qqmllanguage::signalParameterTypes() QQmlComponent component(&engine, testFileUrl("signalParameterTypes.2.qml")); QObject *obj = component.create(); QVERIFY(obj != 0); - QEXPECT_FAIL("", "Dynamic connections don't enforce type safety - QTBUG-26662", Abort); QVERIFY(obj->property("success").toBool()); delete obj; } diff --git a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp index 5d6d0d66de..b1f83fcd6c 100644 --- a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp +++ b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp @@ -246,7 +246,7 @@ void tst_QQmlMetaObject::property() QCOMPARE(signal.methodType(), QMetaMethod::Signal); QCOMPARE(signal.name(), QByteArray("testChanged")); QCOMPARE(signal.methodSignature(), QByteArray("testChanged()")); - QCOMPARE(signal.access(), QMetaMethod::Protected); + QCOMPARE(signal.access(), QMetaMethod::Public); QCOMPARE(signal.parameterCount(), 0); QCOMPARE(signal.parameterTypes(), QList<QByteArray>()); QCOMPARE(signal.parameterNames(), QList<QByteArray>()); @@ -379,7 +379,7 @@ void tst_QQmlMetaObject::method() QMetaMethod method = mo->method(mo->methodOffset()); QCOMPARE(method.methodType(), methodType); QCOMPARE(QString::fromUtf8(method.methodSignature().constData()), signature); - QCOMPARE(method.access(), QMetaMethod::Protected); + QCOMPARE(method.access(), QMetaMethod::Public); QString computedName = signature.left(signature.indexOf('(')); QCOMPARE(QString::fromUtf8(method.name()), computedName); diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index 418e2edf27..27c3fd985e 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -57,11 +57,24 @@ class MyQmlObject : public QObject { Q_OBJECT public: - MyQmlObject() {} + MyQmlObject(QObject *parent = 0) : QObject(parent) {} }; QML_DECLARE_TYPE(MyQmlObject); +class MyQObject : public QObject +{ + Q_OBJECT +public: + MyQObject(QObject *parent = 0) : QObject(parent), m_i(0) {} + + int inc() { return ++m_i; } + +private: + int m_i; +}; + + class MyAttached : public QObject { Q_OBJECT @@ -316,10 +329,11 @@ class PropertyObject : public QObject Q_PROPERTY(int resettableProperty READ resettableProperty WRITE setResettableProperty RESET resetProperty) Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal) Q_PROPERTY(MyQmlObject *qmlObject READ qmlObject) + Q_PROPERTY(MyQObject *qObject READ qObject WRITE setQObject NOTIFY qObjectChanged) Q_CLASSINFO("DefaultProperty", "defaultProperty") public: - PropertyObject() : m_resetProperty(9) {} + PropertyObject() : m_resetProperty(9), m_qObject(0) {} int defaultProperty() { return 10; } QRect rectProperty() { return QRect(10, 10, 1, 209); } @@ -342,9 +356,19 @@ public: MyQmlObject *qmlObject() { return &m_qmlObject; } + MyQObject *qObject() { return m_qObject; } + void setQObject(MyQObject *object) + { + if (m_qObject != object) { + m_qObject = object; + emit qObjectChanged(); + } + } + signals: void clicked(); void oddlyNamedNotifySignal(); + void qObjectChanged(); private: int m_resetProperty; @@ -353,6 +377,7 @@ private: QVariantMap m_variantMap; int m_propertyWithNotify; MyQmlObject m_qmlObject; + MyQObject *m_qObject; }; QML_DECLARE_TYPE(PropertyObject); @@ -1130,6 +1155,18 @@ void tst_qqmlproperty::read() QCOMPARE(p.read(), QVariant()); } + // Object property registered with Qt, but not registered with QML. + { + PropertyObject o; + QQmlProperty p(&o, "qObject"); + QCOMPARE(p.propertyTypeCategory(), QQmlProperty::Object); + + QCOMPARE(p.propertyType(), qMetaTypeId<MyQObject*>()); + QVariant v = p.read(); + QVERIFY(v.canConvert(QMetaType::QObjectStar)); + QVERIFY(qvariant_cast<QObject *>(v) == o.qObject()); + } + // Object property { PropertyObject o; @@ -1387,6 +1424,23 @@ void tst_qqmlproperty::write() QCOMPARE(p.read(), QVariant(99)); delete object; } + // Writable pointer to QObject derived + { + PropertyObject o; + QQmlProperty p(&o, QString("qObject")); + QCOMPARE(o.qObject(), (QObject*)0); + QObject *newObject = new MyQObject(this); + QCOMPARE(p.write(QVariant::fromValue(newObject)), true); + QCOMPARE(o.qObject(), newObject); + QVariant data = p.read(); + QCOMPARE(data.value<QObject*>(), newObject); + QCOMPARE(data.value<MyQObject*>(), newObject); + // Incompatible types can not be written. + QCOMPARE(p.write(QVariant::fromValue(new MyQmlObject(this))), false); + QVariant newData = p.read(); + QCOMPARE(newData.value<QObject*>(), newObject); + QCOMPARE(newData.value<MyQObject*>(), newObject); + } } void tst_qqmlproperty::reset() diff --git a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp index 7d8f02a952..9da67c3f43 100644 --- a/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/qv4debugger/tst_qv4debugger.cpp @@ -192,7 +192,7 @@ void tst_qv4debugger::breakAnywhere() "var i = 42;\n" "var j = i + 1\n" "var k = i\n"; - m_debuggerAgent->pause(m_v4->debugger); + m_debuggerAgent->pauseAll(); evaluateJavaScript(script, "testFile"); QVERIFY(m_debuggerAgent->m_wasPaused); } @@ -203,7 +203,7 @@ void tst_qv4debugger::pendingBreakpoint() "var i = 42;\n" "var j = i + 1\n" "var k = i\n"; - m_debuggerAgent->addBreakPoint(m_v4->debugger, "testfile", 2); + m_debuggerAgent->addBreakPoint("testfile", 2); evaluateJavaScript(script, "testfile"); QVERIFY(m_debuggerAgent->m_wasPaused); QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 1); @@ -219,7 +219,7 @@ void tst_qv4debugger::liveBreakPoint() "var j = i + 1\n" "var k = i\n"; m_debuggerAgent->m_breakPointsToAddWhenPaused << TestAgent::TestBreakPoint("liveBreakPoint", 3); - m_debuggerAgent->pause(m_v4->debugger); + m_debuggerAgent->pauseAll(); evaluateJavaScript(script, "liveBreakPoint"); QVERIFY(m_debuggerAgent->m_wasPaused); QCOMPARE(m_debuggerAgent->m_statesWhenPaused.count(), 2); @@ -234,8 +234,8 @@ void tst_qv4debugger::removePendingBreakPoint() "var i = 42;\n" "var j = i + 1\n" "var k = i\n"; - m_debuggerAgent->addBreakPoint(m_v4->debugger, "removePendingBreakPoint", 2); - m_debuggerAgent->removeBreakPoint(m_v4->debugger, "removePendingBreakPoint", 2); + m_debuggerAgent->addBreakPoint("removePendingBreakPoint", 2); + m_debuggerAgent->removeBreakPoint("removePendingBreakPoint", 2); evaluateJavaScript(script, "removePendingBreakPoint"); QVERIFY(!m_debuggerAgent->m_wasPaused); } @@ -246,7 +246,7 @@ void tst_qv4debugger::addBreakPointWhilePaused() "var i = 42;\n" "var j = i + 1\n" "var k = i\n"; - m_debuggerAgent->addBreakPoint(m_v4->debugger, "addBreakPointWhilePaused", 1); + m_debuggerAgent->addBreakPoint("addBreakPointWhilePaused", 1); m_debuggerAgent->m_breakPointsToAddWhenPaused << TestAgent::TestBreakPoint("addBreakPointWhilePaused", 2); evaluateJavaScript(script, "addBreakPointWhilePaused"); QVERIFY(m_debuggerAgent->m_wasPaused); @@ -276,7 +276,7 @@ void tst_qv4debugger::removeBreakPointForNextInstruction() QMetaObject::invokeMethod(m_engine, "injectFunction", Qt::BlockingQueuedConnection, Q_ARG(QString, "someCall"), Q_ARG(TestEngine::InjectedFunction, someCall)); - m_debuggerAgent->addBreakPoint(m_v4->debugger, "removeBreakPointForNextInstruction", 2); + m_debuggerAgent->addBreakPoint("removeBreakPointForNextInstruction", 2); evaluateJavaScript(script, "removeBreakPointForNextInstruction"); QVERIFY(!m_debuggerAgent->m_wasPaused); diff --git a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp index 5e7370f8a5..de1c12097b 100644 --- a/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp +++ b/tests/auto/quick/qquickmousearea/tst_qquickmousearea.cpp @@ -41,6 +41,7 @@ #include <QtTest/QtTest> #include <QtTest/QSignalSpy> +#include <QtQuick/private/qquickdrag_p.h> #include <QtQuick/private/qquickmousearea_p.h> #include <QtQuick/private/qquickrectangle_p.h> #include <private/qquickflickable_p.h> diff --git a/tools/v4/main.cpp b/tools/v4/main.cpp index e4a03339e1..a49c7093cf 100644 --- a/tools/v4/main.cpp +++ b/tools/v4/main.cpp @@ -77,10 +77,10 @@ struct Print: FunctionObject name = scope->engine->newString("print"); } - static Value call(Managed *, const CallData &d) + static Value call(Managed *, CallData *callData) { - for (int i = 0; i < d.argc; ++i) { - QString s = d.args[i].toQString(); + for (int i = 0; i < callData->argc; ++i) { + QString s = callData->args[i].toQString(); if (i) std::cout << ' '; std::cout << qPrintable(s); @@ -102,7 +102,7 @@ struct GC: public FunctionObject vtbl = &static_vtbl; name = scope->engine->newString("gc"); } - static Value call(Managed *m, const CallData &) + static Value call(Managed *m, CallData *) { m->engine()->memoryManager->runGC(); return Value::undefinedValue(); |