aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-02-01 20:43:29 +0100
committerOswald Buddenhagen <oswald.buddenhagen@qt.io>2017-02-01 20:43:30 +0100
commit6ba26317d0fc0573aca7638eda8bdb91e52d1ab3 (patch)
tree061ddc3d0977fc6364eb3275a3da4287fd1a7869
parentcd39a62bbd5c6e725547a696c297c46f929b3439 (diff)
parent835f8a90387c8d62e7ab262d23e3ab103aa6d133 (diff)
Merge dev into 5.9
-rw-r--r--examples/quick/demos/stocqt/doc/src/stocqt.qdoc2
-rw-r--r--examples/quick/window/CurrentScreen.qml7
-rw-r--r--src/3rdparty/masm/assembler/ARMv7Assembler.h88
-rw-r--r--src/3rdparty/masm/assembler/AbstractMacroAssembler.h42
-rw-r--r--src/3rdparty/masm/assembler/LinkBuffer.cpp134
-rw-r--r--src/3rdparty/masm/assembler/LinkBuffer.h292
-rw-r--r--src/3rdparty/masm/assembler/MacroAssembler.h171
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerARM.h2
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerARM64.h2
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerARMv7.h84
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerMIPS.h2
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerSH4.h2
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerX86.h34
-rw-r--r--src/3rdparty/masm/assembler/MacroAssemblerX86_64.h29
-rw-r--r--src/3rdparty/masm/assembler/X86Assembler.h40
-rw-r--r--src/3rdparty/masm/masm.pri1
-rw-r--r--src/3rdparty/masm/stubs/ExecutableAllocator.h8
-rw-r--r--src/3rdparty/masm/wtf/MathExtras.h2
-rw-r--r--src/3rdparty/masm/wtf/OSAllocatorIntegrity.cpp232
-rw-r--r--src/3rdparty/masm/wtf/Platform.h4
-rw-r--r--src/3rdparty/masm/yarr/YarrJIT.cpp6
-rw-r--r--src/imports/imports.pro5
-rw-r--r--src/imports/layouts/qquickstacklayout.cpp6
-rw-r--r--src/imports/sharedimage/plugin.cpp134
-rw-r--r--src/imports/sharedimage/qmldir3
-rw-r--r--src/imports/sharedimage/qsharedimageloader.cpp265
-rw-r--r--src/imports/sharedimage/qsharedimageloader_p.h81
-rw-r--r--src/imports/sharedimage/sharedimage.pro17
-rw-r--r--src/imports/sharedimage/sharedimageprovider.cpp156
-rw-r--r--src/imports/sharedimage/sharedimageprovider.h58
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp3
-rw-r--r--src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp6
-rw-r--r--src/qml/compiler/compiler.pri8
-rw-r--r--src/qml/compiler/qqmlirbuilder.cpp152
-rw-r--r--src/qml/compiler/qqmlirbuilder_p.h15
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp8
-rw-r--r--src/qml/compiler/qqmltypecompiler_p.h4
-rw-r--r--src/qml/compiler/qv4codegen.cpp31
-rw-r--r--src/qml/compiler/qv4compileddata.cpp236
-rw-r--r--src/qml/compiler/qv4compileddata_p.h87
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h3
-rw-r--r--src/qml/compiler/qv4isel_moth.cpp70
-rw-r--r--src/qml/compiler/qv4isel_moth_p.h6
-rw-r--r--src/qml/compiler/qv4jsir_p.h62
-rw-r--r--src/qml/compiler/qv4ssa.cpp14
-rw-r--r--src/qml/compiler/qv4ssa_p.h35
-rw-r--r--src/qml/debugger/qqmlprofiler_p.h2
-rw-r--r--src/qml/doc/src/qmltypereference.qdoc4
-rw-r--r--src/qml/jit/qv4assembler.cpp213
-rw-r--r--src/qml/jit/qv4assembler_p.h890
-rw-r--r--src/qml/jit/qv4binop.cpp116
-rw-r--r--src/qml/jit/qv4binop_p.h67
-rw-r--r--src/qml/jit/qv4isel_masm.cpp1195
-rw-r--r--src/qml/jit/qv4isel_masm_p.h73
-rw-r--r--src/qml/jit/qv4regalloc.cpp16
-rw-r--r--src/qml/jit/qv4targetplatform_p.h269
-rw-r--r--src/qml/jit/qv4unop.cpp55
-rw-r--r--src/qml/jit/qv4unop_p.h12
-rw-r--r--src/qml/jsruntime/jsruntime.pri4
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp10
-rw-r--r--src/qml/jsruntime/qv4arraybuffer.cpp69
-rw-r--r--src/qml/jsruntime/qv4arraybuffer_p.h8
-rw-r--r--src/qml/jsruntime/qv4arraydata.cpp10
-rw-r--r--src/qml/jsruntime/qv4arrayobject.cpp675
-rw-r--r--src/qml/jsruntime/qv4arrayobject_p.h48
-rw-r--r--src/qml/jsruntime/qv4booleanobject.cpp26
-rw-r--r--src/qml/jsruntime/qv4booleanobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4context.cpp34
-rw-r--r--src/qml/jsruntime/qv4context_p.h24
-rw-r--r--src/qml/jsruntime/qv4dataview.cpp133
-rw-r--r--src/qml/jsruntime/qv4dataview_p.h18
-rw-r--r--src/qml/jsruntime/qv4dateobject.cpp475
-rw-r--r--src/qml/jsruntime/qv4dateobject_p.h102
-rw-r--r--src/qml/jsruntime/qv4engine.cpp10
-rw-r--r--src/qml/jsruntime/qv4errorobject.cpp25
-rw-r--r--src/qml/jsruntime/qv4errorobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp134
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h32
-rw-r--r--src/qml/jsruntime/qv4global_p.h1
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp146
-rw-r--r--src/qml/jsruntime/qv4globalobject_p.h20
-rw-r--r--src/qml/jsruntime/qv4include.cpp19
-rw-r--r--src/qml/jsruntime/qv4include_p.h2
-rw-r--r--src/qml/jsruntime/qv4internalclass.cpp32
-rw-r--r--src/qml/jsruntime/qv4internalclass_p.h2
-rw-r--r--src/qml/jsruntime/qv4jsonobject.cpp23
-rw-r--r--src/qml/jsruntime/qv4jsonobject_p.h4
-rw-r--r--src/qml/jsruntime/qv4lookup_p.h3
-rw-r--r--src/qml/jsruntime/qv4mathobject.cpp186
-rw-r--r--src/qml/jsruntime/qv4mathobject_p.h38
-rw-r--r--src/qml/jsruntime/qv4memberdata.cpp7
-rw-r--r--src/qml/jsruntime/qv4numberobject.cpp160
-rw-r--r--src/qml/jsruntime/qv4numberobject_p.h16
-rw-r--r--src/qml/jsruntime/qv4object.cpp96
-rw-r--r--src/qml/jsruntime/qv4object_p.h21
-rw-r--r--src/qml/jsruntime/qv4objectproto.cpp412
-rw-r--r--src/qml/jsruntime/qv4objectproto_p.h52
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp65
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper_p.h4
-rw-r--r--src/qml/jsruntime/qv4regexpobject.cpp94
-rw-r--r--src/qml/jsruntime/qv4regexpobject_p.h18
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp34
-rw-r--r--src/qml/jsruntime/qv4scopedvalue_p.h32
-rw-r--r--src/qml/jsruntime/qv4sequenceobject.cpp64
-rw-r--r--src/qml/jsruntime/qv4sequenceobject_p.h6
-rw-r--r--src/qml/jsruntime/qv4stringobject.cpp395
-rw-r--r--src/qml/jsruntime/qv4stringobject_p.h46
-rw-r--r--src/qml/jsruntime/qv4typedarray.cpp101
-rw-r--r--src/qml/jsruntime/qv4typedarray_p.h12
-rw-r--r--src/qml/jsruntime/qv4value_p.h47
-rw-r--r--src/qml/jsruntime/qv4variantobject.cpp47
-rw-r--r--src/qml/jsruntime/qv4variantobject_p.h8
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp4
-rw-r--r--src/qml/memory/memory.pri4
-rw-r--r--src/qml/memory/qv4heap_p.h43
-rw-r--r--src/qml/memory/qv4mm.cpp929
-rw-r--r--src/qml/memory/qv4mm_p.h196
-rw-r--r--src/qml/memory/qv4mmdefs_p.h262
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp2
-rw-r--r--src/qml/qml/qqmlcomponent.cpp59
-rw-r--r--src/qml/qml/qqmldelayedcallqueue.cpp10
-rw-r--r--src/qml/qml/qqmldelayedcallqueue_p.h2
-rw-r--r--src/qml/qml/qqmlimport.cpp276
-rw-r--r--src/qml/qml/qqmlimport_p.h42
-rw-r--r--src/qml/qml/qqmllocale.cpp485
-rw-r--r--src/qml/qml/qqmllocale_p.h82
-rw-r--r--src/qml/qml/qqmlmetatype.cpp2
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp4
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp5
-rw-r--r--src/qml/qml/qqmltypeloader.cpp104
-rw-r--r--src/qml/qml/qqmltypeloader_p.h69
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp57
-rw-r--r--src/qml/qml/qqmltypenamecache_p.h8
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp12
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h2
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp9
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp496
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp865
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h118
-rw-r--r--src/qml/qml/v8/qv4domerrors_p.h5
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp79
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h6
-rw-r--r--src/qml/types/qquickworkerscript.cpp13
-rw-r--r--src/qmldevtools/qmldevtools.pro1
-rw-r--r--src/quick/items/context2d/qquickcontext2d.cpp1297
-rw-r--r--src/quick/items/qquickevents_p_p.h2
-rw-r--r--src/quick/items/qquickitemgrabresult.cpp2
-rw-r--r--src/quick/items/qquicktext.cpp89
-rw-r--r--src/quick/items/qquicktext_p.h5
-rw-r--r--src/quick/items/qquicktext_p_p.h1
-rw-r--r--src/quick/items/qquickwindow.cpp9
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h9
-rw-r--r--src/quick/scenegraph/coreapi/qsgnode.cpp7
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h98
-rw-r--r--src/quick/scenegraph/scenegraph.pri2
-rw-r--r--src/quick/scenegraph/util/qsgdefaultimagenode.cpp15
-rw-r--r--src/quick/scenegraph/util/qsgdefaultimagenode_p.h4
-rw-r--r--src/quick/scenegraph/util/qsgimagenode.h2
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp53
-rw-r--r--src/quick/scenegraph/util/qsgtexture.h11
-rw-r--r--src/quick/scenegraph/util/qsgtexture_p.h2
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.cpp2
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.h7
-rw-r--r--src/quick/util/qquickpixmapcache.cpp12
-rw-r--r--src/quick/util/qquickpixmapcache_p.h2
-rw-r--r--src/quick/util/qquickutilmodule.cpp9
-rw-r--r--src/quick/util/util.pri9
-rw-r--r--src/src.pro6
-rw-r--r--tests/auto/auto.pro2
-rw-r--r--tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp4
-rw-r--r--tests/auto/qml/qml.pro2
-rw-r--r--tests/auto/qml/qqmlecmascript/data/signalParameterTypes.qml8
-rw-r--r--tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp7
-rw-r--r--tests/auto/qml/qqmllanguage/data/compositeTypeByName_anon_qmldir.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/compositeTypeByName_named_qmldir.qml9
-rw-r--r--tests/auto/qml/qqmllanguage/data/quickTypeByName_anon.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/data/quickTypeByName_named.qml8
-rw-r--r--tests/auto/qml/qqmllanguage/data/simpleimportByName/SimpleType.qml4
-rw-r--r--tests/auto/qml/qqmllanguage/data/simpleimportByName/qmldir1
-rw-r--r--tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp29
-rw-r--r--tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml41
-rw-r--r--tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml107
-rw-r--r--tests/auto/quick/qquicklayouts/qquicklayouts.pro3
-rw-r--r--tests/auto/quick/qquickloader/tst_qquickloader.cpp3
-rw-r--r--tests/auto/quick/qquicktext/data/fontInfo.qml24
-rw-r--r--tests/auto/quick/qquicktext/tst_qquicktext.cpp19
-rw-r--r--tools/qmlcachegen/qmlcache.prf12
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp309
-rw-r--r--tools/qmlcachegen/qmlcachegen.pro24
-rw-r--r--tools/qmljs/qmljs.cpp2
-rw-r--r--tools/qmllint/main.cpp11
-rw-r--r--tools/tools.pro3
192 files changed, 9997 insertions, 6177 deletions
diff --git a/examples/quick/demos/stocqt/doc/src/stocqt.qdoc b/examples/quick/demos/stocqt/doc/src/stocqt.qdoc
index bd204c8211..800bba570c 100644
--- a/examples/quick/demos/stocqt/doc/src/stocqt.qdoc
+++ b/examples/quick/demos/stocqt/doc/src/stocqt.qdoc
@@ -69,7 +69,7 @@
\quotefromfile demos/stocqt/content/StockChart.qml
\skipto Rectangle
- \printuntil height
+ \printuntil id
\dots
\skipto Canvas
\printuntil id
diff --git a/examples/quick/window/CurrentScreen.qml b/examples/quick/window/CurrentScreen.qml
index c65baab1f4..09fbce9a74 100644
--- a/examples/quick/window/CurrentScreen.qml
+++ b/examples/quick/window/CurrentScreen.qml
@@ -101,5 +101,12 @@ Item {
Shared.Label { text: "primary orientation" }
Shared.Label { text: orientationToString(Screen.primaryOrientation) + " (" + Screen.primaryOrientation + ")" }
//! [screen]
+
+ Shared.Label { text: "10mm rectangle" }
+ Rectangle {
+ color: "red"
+ width: Screen.pixelDensity * 10
+ height: width
+ }
}
}
diff --git a/src/3rdparty/masm/assembler/ARMv7Assembler.h b/src/3rdparty/masm/assembler/ARMv7Assembler.h
index f0fa07a1bf..6b32fbf487 100644
--- a/src/3rdparty/masm/assembler/ARMv7Assembler.h
+++ b/src/3rdparty/masm/assembler/ARMv7Assembler.h
@@ -27,10 +27,11 @@
#ifndef ARMAssembler_h
#define ARMAssembler_h
-#if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
+#if ENABLE(ASSEMBLER) && (CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP))
#include "AssemblerBuffer.h"
#include "MacroAssemblerCodeRef.h"
+#include "AbstractMacroAssembler.h"
#include <wtf/Assertions.h>
#include <wtf/Vector.h>
#include <stdint.h>
@@ -491,8 +492,8 @@ public:
private:
union {
struct RealTypes {
- intptr_t m_from : 31;
- intptr_t m_to : 31;
+ int32_t m_from : 31;
+ int32_t m_to : 31;
JumpType m_type : 8;
JumpLinkType m_linkType : 8;
Condition m_condition : 16;
@@ -510,6 +511,56 @@ public:
{
}
+
+ // Jump:
+ //
+ // A jump object is a reference to a jump instruction that has been planted
+ // into the code buffer - it is typically used to link the jump, setting the
+ // relative offset such that when executed it will jump to the desired
+ // destination.
+ template <typename LabelType>
+ class Jump {
+ template<class TemplateAssemblerType> friend class AbstractMacroAssembler;
+ friend class Call;
+ template <typename, template <typename> class> friend class LinkBufferBase;;
+ public:
+ Jump()
+ {
+ }
+
+ // Fixme: this information should be stored in the instruction stream, not in the Jump object.
+ Jump(AssemblerLabel jmp, ARMv7Assembler::JumpType type = ARMv7Assembler::JumpNoCondition, ARMv7Assembler::Condition condition = ARMv7Assembler::ConditionInvalid)
+ : m_label(jmp)
+ , m_type(type)
+ , m_condition(condition)
+ {
+ }
+
+ LabelType label() const
+ {
+ LabelType result;
+ result.m_label = m_label;
+ return result;
+ }
+
+ void link(AbstractMacroAssembler<ARMv7Assembler>* masm) const
+ {
+ masm->m_assembler.linkJump(m_label, masm->m_assembler.label(), m_type, m_condition);
+ }
+
+ void linkTo(LabelType label, AbstractMacroAssembler<ARMv7Assembler>* masm) const
+ {
+ masm->m_assembler.linkJump(m_label, label.label(), m_type, m_condition);
+ }
+
+ bool isSet() const { return m_label.isSet(); }
+
+ private:
+ AssemblerLabel m_label;
+ ARMv7Assembler::JumpType m_type;
+ ARMv7Assembler::Condition m_condition;
+ };
+
private:
// ARMv7, Appx-A.6.3
@@ -2115,6 +2166,7 @@ public:
linkJumpAbsolute(location, to);
}
+#if !defined(V4_BOOTSTRAP)
static void linkCall(void* code, AssemblerLabel from, void* to)
{
ASSERT(!(reinterpret_cast<intptr_t>(code) & 1));
@@ -2123,12 +2175,14 @@ public:
setPointer(reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset) - 1, to, false);
}
+#endif
static void linkPointer(void* code, AssemblerLabel where, void* value)
{
setPointer(reinterpret_cast<char*>(code) + where.m_offset, value, false);
}
+#if !defined(V4_BOOTSTRAP)
static void relinkJump(void* from, void* to)
{
ASSERT(!(reinterpret_cast<intptr_t>(from) & 1));
@@ -2146,11 +2200,12 @@ public:
setPointer(reinterpret_cast<uint16_t*>(from) - 1, to, true);
}
-
+
static void* readCallTarget(void* from)
{
return readPointer(reinterpret_cast<uint16_t*>(from) - 1);
}
+#endif
static void repatchInt32(void* where, int32_t value)
{
@@ -2179,6 +2234,7 @@ public:
cacheFlush(location, sizeof(uint16_t) * 2);
}
+#if !defined(V4_BOOTSTRAP)
static void repatchPointer(void* where, void* value)
{
ASSERT(!(reinterpret_cast<intptr_t>(where) & 1));
@@ -2190,7 +2246,8 @@ public:
{
return reinterpret_cast<void*>(readInt32(where));
}
-
+#endif
+
static void replaceWithJump(void* instructionStart, void* to)
{
ASSERT(!(bitwise_cast<uintptr_t>(instructionStart) & 1));
@@ -2264,7 +2321,7 @@ public:
unsigned debugOffset() { return m_formatter.debugOffset(); }
-#if OS(LINUX)
+#if OS(LINUX) && !defined(V4_BOOTSTRAP)
static inline void linuxPageFlush(uintptr_t begin, uintptr_t end)
{
asm volatile(
@@ -2284,7 +2341,10 @@ public:
static void cacheFlush(void* code, size_t size)
{
-#if OS(IOS)
+#if defined(V4_BOOTSTRAP)
+ UNUSED_PARAM(code)
+ UNUSED_PARAM(size)
+#elif OS(IOS)
sys_cache_control(kCacheFunctionPrepareForExecution, code, size);
#elif OS(LINUX)
size_t page = pageSize();
@@ -2430,7 +2490,9 @@ private:
static void setPointer(void* code, void* value, bool flush)
{
- setInt32(code, reinterpret_cast<uint32_t>(value), flush);
+ // ### Deliberate "loss" of precision here. On 64-bit hosts void* is wider
+ // than uint32_t, but the target is 32-bit ARM anyway.
+ setInt32(code, static_cast<uint32_t>(reinterpret_cast<uintptr_t>(value)), flush);
}
static bool isB(void* address)
@@ -2594,6 +2656,11 @@ private:
static void linkBX(uint16_t* instruction, void* target)
{
+#if defined(V4_BOOTSTRAP)
+ UNUSED_PARAM(instruction);
+ UNUSED_PARAM(target);
+ RELEASE_ASSERT_NOT_REACHED();
+#else
// FIMXE: this should be up in the MacroAssembler layer. :-(
ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1));
ASSERT(!(reinterpret_cast<intptr_t>(target) & 1));
@@ -2606,6 +2673,7 @@ private:
instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16);
instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3);
+#endif
}
void linkConditionalBX(Condition cond, uint16_t* instruction, void* target)
@@ -2638,6 +2706,9 @@ private:
instruction[-3] = OP_NOP_T2b;
linkJumpT4(instruction, target);
} else {
+#if defined(V4_BOOTSTRAP)
+ RELEASE_ASSERT_NOT_REACHED();
+#else
const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip;
ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) + 1));
ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) >> 16));
@@ -2646,6 +2717,7 @@ private:
instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16);
instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16);
instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3);
+#endif
}
}
diff --git a/src/3rdparty/masm/assembler/AbstractMacroAssembler.h b/src/3rdparty/masm/assembler/AbstractMacroAssembler.h
index e90dd235c6..4f27e85c98 100644
--- a/src/3rdparty/masm/assembler/AbstractMacroAssembler.h
+++ b/src/3rdparty/masm/assembler/AbstractMacroAssembler.h
@@ -47,7 +47,10 @@
namespace JSC {
class JumpReplacementWatchpoint;
-class LinkBuffer;
+template <typename, template <typename> class>
+class LinkBufferBase;
+template <typename>
+class BranchCompactingLinkBuffer;
class RepatchBuffer;
class Watchpoint;
namespace DFG {
@@ -63,7 +66,9 @@ public:
typedef MacroAssemblerCodePtr CodePtr;
typedef MacroAssemblerCodeRef CodeRef;
+#if !CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP)
class Jump;
+#endif
typedef typename AssemblerType::RegisterID RegisterID;
typedef typename AssemblerType::FPRegisterID FPRegisterID;
@@ -325,7 +330,7 @@ public:
friend class Jump;
friend class JumpReplacementWatchpoint;
friend class MacroAssemblerCodeRef;
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
friend class Watchpoint;
public:
@@ -339,6 +344,8 @@ public:
}
bool isSet() const { return m_label.isSet(); }
+
+ const AssemblerLabel &label() const { return m_label; }
private:
AssemblerLabel m_label;
};
@@ -356,7 +363,7 @@ public:
class ConvertibleLoadLabel {
template<class TemplateAssemblerType>
friend class AbstractMacroAssembler;
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
public:
ConvertibleLoadLabel()
@@ -380,7 +387,7 @@ public:
class DataLabelPtr {
template<class TemplateAssemblerType>
friend class AbstractMacroAssembler;
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
public:
DataLabelPtr()
{
@@ -404,7 +411,7 @@ public:
class DataLabel32 {
template<class TemplateAssemblerType>
friend class AbstractMacroAssembler;
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
public:
DataLabel32()
{
@@ -428,7 +435,7 @@ public:
class DataLabelCompact {
template<class TemplateAssemblerType>
friend class AbstractMacroAssembler;
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
public:
DataLabelCompact()
{
@@ -448,6 +455,11 @@ public:
AssemblerLabel m_label;
};
+#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP)
+ using Jump = typename AssemblerType::template Jump<Label>;
+ friend Jump;
+#endif
+
// Call:
//
// A Call object is a reference to a call instruction that has been planted
@@ -498,18 +510,19 @@ public:
// into the code buffer - it is typically used to link the jump, setting the
// relative offset such that when executed it will jump to the desired
// destination.
+#if !CPU(ARM_THUMB2) && !defined(V4_BOOTSTRAP)
class Jump {
template<class TemplateAssemblerType>
friend class AbstractMacroAssembler;
friend class Call;
friend struct DFG::OSRExit;
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
public:
Jump()
{
}
-#if CPU(ARM_THUMB2)
+#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP)
// Fixme: this information should be stored in the instruction stream, not in the Jump object.
Jump(AssemblerLabel jmp, ARMv7Assembler::JumpType type = ARMv7Assembler::JumpNoCondition, ARMv7Assembler::Condition condition = ARMv7Assembler::ConditionInvalid)
: m_label(jmp)
@@ -610,10 +623,11 @@ public:
private:
AssemblerLabel m_label;
-#if CPU(ARM_THUMB2)
+#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP)
ARMv7Assembler::JumpType m_type;
ARMv7Assembler::Condition m_condition;
-#elif CPU(ARM64)
+#endif
+#if CPU(ARM64)
ARM64Assembler::JumpType m_type;
ARM64Assembler::Condition m_condition;
bool m_is64Bit;
@@ -624,6 +638,7 @@ public:
SH4Assembler::JumpType m_type;
#endif
};
+#endif
struct PatchableJump {
PatchableJump()
@@ -645,7 +660,7 @@ public:
// A JumpList is a set of Jump objects.
// All jumps in the set will be linked to the same destination.
class JumpList {
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
public:
typedef Vector<Jump, 2> JumpVector;
@@ -819,7 +834,8 @@ protected:
static bool shouldBlindForSpecificArch(uint64_t) { return true; }
#endif
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
+ template <typename> friend class BranchCompactingLinkBuffer;
friend class RepatchBuffer;
static void linkJump(void* code, Jump jump, CodeLocationLabel target)
@@ -867,10 +883,12 @@ protected:
AssemblerType::repatchPointer(dataLabelPtr.dataLocation(), value);
}
+#if !defined(V4_BOOTSTRAP)
static void* readPointer(CodeLocationDataLabelPtr dataLabelPtr)
{
return AssemblerType::readPointer(dataLabelPtr.dataLocation());
}
+#endif
static void replaceWithLoad(CodeLocationConvertibleLoad label)
{
diff --git a/src/3rdparty/masm/assembler/LinkBuffer.cpp b/src/3rdparty/masm/assembler/LinkBuffer.cpp
index 432a7ee227..74c278135b 100644
--- a/src/3rdparty/masm/assembler/LinkBuffer.cpp
+++ b/src/3rdparty/masm/assembler/LinkBuffer.cpp
@@ -32,140 +32,6 @@
namespace JSC {
-LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithoutDisassembly()
-{
- performFinalization();
-
- return CodeRef(m_executableMemory);
-}
-
-LinkBuffer::CodeRef LinkBuffer::finalizeCodeWithDisassembly(const char* format, ...)
-{
- ASSERT(Options::showDisassembly() || Options::showDFGDisassembly());
-
- CodeRef result = finalizeCodeWithoutDisassembly();
-
- dataLogF("Generated JIT code for ");
- va_list argList;
- va_start(argList, format);
- WTF::dataLogFV(format, argList);
- va_end(argList);
- dataLogF(":\n");
-
- dataLogF(
-#if OS(WINDOWS)
- " Code at [0x%p, 0x%p):\n",
-#else
- " Code at [%p, %p):\n",
-#endif
- result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size());
- disassemble(result.code(), m_size, " ", WTF::dataFile());
-
- return result;
-}
-
-void LinkBuffer::linkCode(void* ownerUID, JITCompilationEffort effort)
-{
- ASSERT(!m_code);
-#if !ENABLE(BRANCH_COMPACTION)
- m_executableMemory = m_assembler->m_assembler.executableCopy(*m_globalData, ownerUID, effort);
- if (!m_executableMemory)
- return;
- m_code = m_executableMemory->start();
- m_size = m_assembler->m_assembler.codeSize();
- ASSERT(m_code);
-#else
- m_initialSize = m_assembler->m_assembler.codeSize();
- m_executableMemory = m_globalData->executableAllocator.allocate(*m_globalData, m_initialSize, ownerUID, effort);
- if (!m_executableMemory)
- return;
- m_code = (uint8_t*)m_executableMemory->start();
- ASSERT(m_code);
- ExecutableAllocator::makeWritable(m_code, m_initialSize);
- uint8_t* inData = (uint8_t*)m_assembler->unlinkedCode();
- uint8_t* outData = reinterpret_cast<uint8_t*>(m_code);
- int readPtr = 0;
- int writePtr = 0;
- Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink = m_assembler->jumpsToLink();
- unsigned jumpCount = jumpsToLink.size();
- for (unsigned i = 0; i < jumpCount; ++i) {
- int offset = readPtr - writePtr;
- ASSERT(!(offset & 1));
-
- // Copy the instructions from the last jump to the current one.
- size_t regionSize = jumpsToLink[i].from() - readPtr;
- uint16_t* copySource = reinterpret_cast_ptr<uint16_t*>(inData + readPtr);
- uint16_t* copyEnd = reinterpret_cast_ptr<uint16_t*>(inData + readPtr + regionSize);
- uint16_t* copyDst = reinterpret_cast_ptr<uint16_t*>(outData + writePtr);
- ASSERT(!(regionSize % 2));
- ASSERT(!(readPtr % 2));
- ASSERT(!(writePtr % 2));
- while (copySource != copyEnd)
- *copyDst++ = *copySource++;
- m_assembler->recordLinkOffsets(readPtr, jumpsToLink[i].from(), offset);
- readPtr += regionSize;
- writePtr += regionSize;
-
- // Calculate absolute address of the jump target, in the case of backwards
- // branches we need to be precise, forward branches we are pessimistic
- const uint8_t* target;
- if (jumpsToLink[i].to() >= jumpsToLink[i].from())
- target = outData + jumpsToLink[i].to() - offset; // Compensate for what we have collapsed so far
- else
- target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to());
-
- JumpLinkType jumpLinkType = m_assembler->computeJumpType(jumpsToLink[i], outData + writePtr, target);
- // Compact branch if we can...
- if (m_assembler->canCompact(jumpsToLink[i].type())) {
- // Step back in the write stream
- int32_t delta = m_assembler->jumpSizeDelta(jumpsToLink[i].type(), jumpLinkType);
- if (delta) {
- writePtr -= delta;
- m_assembler->recordLinkOffsets(jumpsToLink[i].from() - delta, readPtr, readPtr - writePtr);
- }
- }
- jumpsToLink[i].setFrom(writePtr);
- }
- // Copy everything after the last jump
- memcpy(outData + writePtr, inData + readPtr, m_initialSize - readPtr);
- m_assembler->recordLinkOffsets(readPtr, m_initialSize, readPtr - writePtr);
-
- for (unsigned i = 0; i < jumpCount; ++i) {
- uint8_t* location = outData + jumpsToLink[i].from();
- uint8_t* target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to());
- m_assembler->link(jumpsToLink[i], location, target);
- }
-
- jumpsToLink.clear();
- m_size = writePtr + m_initialSize - readPtr;
- m_executableMemory->shrink(m_size);
-
-#if DUMP_LINK_STATISTICS
- dumpLinkStatistics(m_code, m_initialSize, m_size);
-#endif
-#if DUMP_CODE
- dumpCode(m_code, m_size);
-#endif
-#endif
-}
-
-void LinkBuffer::performFinalization()
-{
-#ifndef NDEBUG
- ASSERT(!m_completed);
- ASSERT(isValid());
- m_completed = true;
-#endif
-
-#if ENABLE(BRANCH_COMPACTION)
- ExecutableAllocator::makeExecutable(code(), m_initialSize);
-#else
- ASSERT(m_size <= INT_MAX);
- ExecutableAllocator::makeExecutable(code(), static_cast<int>(m_size));
-#endif
- MacroAssembler::cacheFlush(code(), m_size);
-}
-
#if DUMP_LINK_STATISTICS
void LinkBuffer::dumpLinkStatistics(void* code, size_t initializeSize, size_t finalSize)
{
diff --git a/src/3rdparty/masm/assembler/LinkBuffer.h b/src/3rdparty/masm/assembler/LinkBuffer.h
index e1882433c1..3a659a23ce 100644
--- a/src/3rdparty/masm/assembler/LinkBuffer.h
+++ b/src/3rdparty/masm/assembler/LinkBuffer.h
@@ -36,6 +36,7 @@
#include "JITCompilationEffort.h"
#include "MacroAssembler.h"
+#include "Options.h"
#include <wtf/DataLog.h>
#include <wtf/Noncopyable.h>
@@ -43,6 +44,12 @@ namespace JSC {
class JSGlobalData;
+template <typename T>
+struct DefaultExecutableOffsetCalculator {
+ template <typename Assembler>
+ static T applyOffset(Assembler *, T src) { return src; }
+};
+
// LinkBuffer:
//
// This class assists in linking code generated by the macro assembler, once code generation
@@ -57,30 +64,24 @@ class JSGlobalData;
// * The address of a Label pointing into the code may be resolved.
// * The value referenced by a DataLabel may be set.
//
-class LinkBuffer {
- WTF_MAKE_NONCOPYABLE(LinkBuffer);
+template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator>
+class LinkBufferBase {
+ WTF_MAKE_NONCOPYABLE(LinkBufferBase);
typedef MacroAssemblerCodeRef CodeRef;
typedef MacroAssemblerCodePtr CodePtr;
- typedef MacroAssembler::Label Label;
- typedef MacroAssembler::Jump Jump;
- typedef MacroAssembler::PatchableJump PatchableJump;
- typedef MacroAssembler::JumpList JumpList;
- typedef MacroAssembler::Call Call;
- typedef MacroAssembler::DataLabelCompact DataLabelCompact;
- typedef MacroAssembler::DataLabel32 DataLabel32;
- typedef MacroAssembler::DataLabelPtr DataLabelPtr;
- typedef MacroAssembler::ConvertibleLoadLabel ConvertibleLoadLabel;
-#if ENABLE(BRANCH_COMPACTION)
- typedef MacroAssembler::LinkRecord LinkRecord;
- typedef MacroAssembler::JumpLinkType JumpLinkType;
-#endif
+ typedef typename MacroAssembler::Label Label;
+ typedef typename MacroAssembler::Jump Jump;
+ typedef typename MacroAssembler::PatchableJump PatchableJump;
+ typedef typename MacroAssembler::JumpList JumpList;
+ typedef typename MacroAssembler::Call Call;
+ typedef typename MacroAssembler::DataLabelCompact DataLabelCompact;
+ typedef typename MacroAssembler::DataLabel32 DataLabel32;
+ typedef typename MacroAssembler::DataLabelPtr DataLabelPtr;
+ typedef typename MacroAssembler::ConvertibleLoadLabel ConvertibleLoadLabel;
public:
- LinkBuffer(JSGlobalData& globalData, MacroAssembler* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed)
+ LinkBufferBase(JSGlobalData& globalData, MacroAssembler* masm, JITCompilationEffort effort = JITCompilationMustSucceed)
: m_size(0)
-#if ENABLE(BRANCH_COMPACTION)
- , m_initialSize(0)
-#endif
, m_code(0)
, m_assembler(masm)
, m_globalData(&globalData)
@@ -89,10 +90,13 @@ public:
, m_effort(effort)
#endif
{
- linkCode(ownerUID, effort);
+#ifdef NDEBUG
+ UNUSED_PARAM(effort)
+#endif
+ // Simon: Moved this to the sub-classes linkCode(ownerUID, effort);
}
- ~LinkBuffer()
+ ~LinkBufferBase()
{
ASSERT(m_completed || (!m_executableMemory && m_effort == JITCompilationCanFail));
}
@@ -204,8 +208,8 @@ public:
// finalizeCodeWithoutDisassembly() directly if you have your own way of
// displaying disassembly.
- CodeRef finalizeCodeWithoutDisassembly();
- CodeRef finalizeCodeWithDisassembly(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
+ inline CodeRef finalizeCodeWithoutDisassembly();
+ inline CodeRef finalizeCodeWithDisassembly(const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
CodePtr trampolineAt(Label label)
{
@@ -225,21 +229,19 @@ public:
private:
template <typename T> T applyOffset(T src)
{
-#if ENABLE(BRANCH_COMPACTION)
- src.m_offset -= m_assembler->executableOffsetFor(src.m_offset);
-#endif
- return src;
+ return ExecutableOffsetCalculator<T>::applyOffset(m_assembler, src);
}
+protected:
// Keep this private! - the underlying code should only be obtained externally via finalizeCode().
void* code()
{
return m_code;
}
- void linkCode(void* ownerUID, JITCompilationEffort);
+ inline void linkCode(void* ownerUID, JITCompilationEffort);
- void performFinalization();
+ inline void performFinalization();
#if DUMP_LINK_STATISTICS
static void dumpLinkStatistics(void* code, size_t initialSize, size_t finalSize);
@@ -251,12 +253,10 @@ private:
RefPtr<ExecutableMemoryHandle> m_executableMemory;
size_t m_size;
-#if ENABLE(BRANCH_COMPACTION)
- size_t m_initialSize;
-#endif
void* m_code;
MacroAssembler* m_assembler;
JSGlobalData* m_globalData;
+protected:
#ifndef NDEBUG
bool m_completed;
JITCompilationEffort m_effort;
@@ -290,6 +290,234 @@ private:
#define FINALIZE_DFG_CODE(linkBufferReference, dataLogFArgumentsForHeading) \
FINALIZE_CODE_IF((Options::showDisassembly() || Options::showDFGDisassembly()), linkBufferReference, dataLogFArgumentsForHeading)
+
+template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator>
+inline typename LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::CodeRef LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::finalizeCodeWithoutDisassembly()
+{
+ performFinalization();
+
+ return CodeRef(m_executableMemory);
+}
+
+template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator>
+inline typename LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::CodeRef LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::finalizeCodeWithDisassembly(const char* format, ...)
+{
+ ASSERT(Options::showDisassembly() || Options::showDFGDisassembly());
+
+ CodeRef result = finalizeCodeWithoutDisassembly();
+
+ dataLogF("Generated JIT code for ");
+ va_list argList;
+ va_start(argList, format);
+ WTF::dataLogFV(format, argList);
+ va_end(argList);
+ dataLogF(":\n");
+
+ dataLogF(
+#if OS(WINDOWS)
+ " Code at [0x%p, 0x%p):\n",
+#else
+ " Code at [%p, %p):\n",
+#endif
+ result.code().executableAddress(), static_cast<char*>(result.code().executableAddress()) + result.size());
+ disassemble(result.code(), m_size, " ", WTF::dataFile());
+
+ return result;
+}
+
+template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator>
+inline void LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::linkCode(void* ownerUID, JITCompilationEffort effort)
+{
+ UNUSED_PARAM(ownerUID)
+ UNUSED_PARAM(effort)
+ ASSERT(!m_code);
+ m_executableMemory = m_assembler->m_assembler.executableCopy(*m_globalData, ownerUID, effort);
+ if (!m_executableMemory)
+ return;
+ m_code = m_executableMemory->start();
+ m_size = m_assembler->m_assembler.codeSize();
+ ASSERT(m_code);
+}
+
+template <typename MacroAssembler, template <typename T> class ExecutableOffsetCalculator>
+inline void LinkBufferBase<MacroAssembler, ExecutableOffsetCalculator>::performFinalization()
+{
+ // NOTE: This function is specialized in LinkBuffer<MacroAssemblerARMv7>
+#ifndef NDEBUG
+ ASSERT(!m_completed);
+ ASSERT(isValid());
+ m_completed = true;
+#endif
+
+ ASSERT(m_size <= INT_MAX);
+ ExecutableAllocator::makeExecutable(code(), static_cast<int>(m_size));
+ MacroAssembler::cacheFlush(code(), m_size);
+}
+
+template <typename MacroAssembler>
+class LinkBuffer : public LinkBufferBase<MacroAssembler, DefaultExecutableOffsetCalculator>
+{
+public:
+ LinkBuffer(JSGlobalData& globalData, MacroAssembler* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed)
+ : LinkBufferBase<MacroAssembler, DefaultExecutableOffsetCalculator>(globalData, masm, effort)
+ {
+ this->linkCode(ownerUID, effort);
+ }
+};
+
+#if CPU(ARM_THUMB2) || CPU(ARM64) || defined(V4_BOOTSTRAP)
+
+template <typename T>
+struct BranchCompactingExecutableOffsetCalculator {
+ template <typename Assembler>
+ static T applyOffset(Assembler *as, T src) {
+ src.m_offset -= as->executableOffsetFor(src.m_offset);
+ return src;
+ }
+};
+
+template <typename MacroAssembler>
+class BranchCompactingLinkBuffer : public LinkBufferBase<MacroAssembler, BranchCompactingExecutableOffsetCalculator>
+{
+public:
+ BranchCompactingLinkBuffer(JSGlobalData& globalData, MacroAssembler* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed)
+ : LinkBufferBase<MacroAssembler, BranchCompactingExecutableOffsetCalculator>(globalData, masm, effort)
+ {
+ linkCode(ownerUID, effort);
+ }
+
+ inline void performFinalization();
+
+ inline void linkCode(void* ownerUID, JITCompilationEffort);
+
+private:
+ using Base = LinkBufferBase<MacroAssembler, BranchCompactingExecutableOffsetCalculator>;
+#ifndef NDEBUG
+ using Base::m_completed;
+#endif
+ using Base::isValid;
+ using Base::code;
+ using Base::m_code;
+ using Base::m_size;
+ using Base::m_assembler;
+ using Base::m_executableMemory;
+ using Base::m_globalData;
+
+ using LinkRecord = typename MacroAssembler::LinkRecord;
+ using JumpLinkType = typename MacroAssembler::JumpLinkType;
+
+ size_t m_initialSize = 0;
+};
+
+template <typename MacroAssembler>
+inline void BranchCompactingLinkBuffer<MacroAssembler>::performFinalization()
+{
+#ifndef NDEBUG
+ ASSERT(!m_completed);
+ ASSERT(isValid());
+ this->m_completed = true;
+#endif
+
+ ExecutableAllocator::makeExecutable(code(), m_initialSize);
+ MacroAssembler::cacheFlush(code(), m_size);
+}
+
+template <typename MacroAssembler>
+inline void BranchCompactingLinkBuffer<MacroAssembler>::linkCode(void* ownerUID, JITCompilationEffort effort)
+{
+ UNUSED_PARAM(ownerUID)
+ UNUSED_PARAM(effort)
+ ASSERT(!m_code);
+ m_initialSize = m_assembler->m_assembler.codeSize();
+ m_executableMemory = m_globalData->executableAllocator.allocate(*m_globalData, m_initialSize, ownerUID, effort);
+ if (!m_executableMemory)
+ return;
+ m_code = (uint8_t*)m_executableMemory->start();
+ ASSERT(m_code);
+ ExecutableAllocator::makeWritable(m_code, m_initialSize);
+ uint8_t* inData = (uint8_t*)m_assembler->unlinkedCode();
+ uint8_t* outData = reinterpret_cast<uint8_t*>(m_code);
+ int readPtr = 0;
+ int writePtr = 0;
+ Vector<LinkRecord, 0, UnsafeVectorOverflow>& jumpsToLink = m_assembler->jumpsToLink();
+ unsigned jumpCount = unsigned(jumpsToLink.size());
+ for (unsigned i = 0; i < jumpCount; ++i) {
+ int offset = readPtr - writePtr;
+ ASSERT(!(offset & 1));
+
+ // Copy the instructions from the last jump to the current one.
+ unsigned regionSize = unsigned(jumpsToLink[i].from() - readPtr);
+ uint16_t* copySource = reinterpret_cast_ptr<uint16_t*>(inData + readPtr);
+ uint16_t* copyEnd = reinterpret_cast_ptr<uint16_t*>(inData + readPtr + regionSize);
+ uint16_t* copyDst = reinterpret_cast_ptr<uint16_t*>(outData + writePtr);
+ ASSERT(!(regionSize % 2));
+ ASSERT(!(readPtr % 2));
+ ASSERT(!(writePtr % 2));
+ while (copySource != copyEnd)
+ *copyDst++ = *copySource++;
+ m_assembler->recordLinkOffsets(readPtr, jumpsToLink[i].from(), offset);
+ readPtr += regionSize;
+ writePtr += regionSize;
+
+ // Calculate absolute address of the jump target, in the case of backwards
+ // branches we need to be precise, forward branches we are pessimistic
+ const uint8_t* target;
+ if (jumpsToLink[i].to() >= jumpsToLink[i].from())
+ target = outData + jumpsToLink[i].to() - offset; // Compensate for what we have collapsed so far
+ else
+ target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to());
+
+ JumpLinkType jumpLinkType = m_assembler->computeJumpType(jumpsToLink[i], outData + writePtr, target);
+ // Compact branch if we can...
+ if (m_assembler->canCompact(jumpsToLink[i].type())) {
+ // Step back in the write stream
+ int32_t delta = m_assembler->jumpSizeDelta(jumpsToLink[i].type(), jumpLinkType);
+ if (delta) {
+ writePtr -= delta;
+ m_assembler->recordLinkOffsets(jumpsToLink[i].from() - delta, readPtr, readPtr - writePtr);
+ }
+ }
+ jumpsToLink[i].setFrom(writePtr);
+ }
+ // Copy everything after the last jump
+ memcpy(outData + writePtr, inData + readPtr, m_initialSize - readPtr);
+ m_assembler->recordLinkOffsets(readPtr, unsigned(m_initialSize), readPtr - writePtr);
+
+ for (unsigned i = 0; i < jumpCount; ++i) {
+ uint8_t* location = outData + jumpsToLink[i].from();
+ uint8_t* target = outData + jumpsToLink[i].to() - m_assembler->executableOffsetFor(jumpsToLink[i].to());
+ m_assembler->link(jumpsToLink[i], location, target);
+ }
+
+ jumpsToLink.clear();
+ m_size = writePtr + m_initialSize - readPtr;
+ m_executableMemory->shrink(m_size);
+}
+
+#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP)
+template <>
+class LinkBuffer<JSC::MacroAssembler<MacroAssemblerARMv7>> : public BranchCompactingLinkBuffer<JSC::MacroAssembler<MacroAssemblerARMv7>>
+{
+public:
+ LinkBuffer(JSGlobalData& globalData, JSC::MacroAssembler<MacroAssemblerARMv7>* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed)
+ : BranchCompactingLinkBuffer<JSC::MacroAssembler<MacroAssemblerARMv7>>(globalData, masm, ownerUID, effort)
+ {}
+};
+#endif
+
+#if CPU(ARM64)
+template <>
+class LinkBuffer<JSC::MacroAssembler<MacroAssemblerARM64>> : public BranchCompactingLinkBuffer<JSC::MacroAssembler<MacroAssemblerARM64>>
+{
+public:
+ LinkBuffer(JSGlobalData& globalData, JSC::MacroAssembler<MacroAssemblerARM64>* masm, void* ownerUID, JITCompilationEffort effort = JITCompilationMustSucceed)
+ : BranchCompactingLinkBuffer<JSC::MacroAssembler<JSC::MacroAssemblerARM64>>(globalData, masm, ownerUID, effort)
+ {}
+};
+#endif
+
+#endif
+
} // namespace JSC
#endif // ENABLE(ASSEMBLER)
diff --git a/src/3rdparty/masm/assembler/MacroAssembler.h b/src/3rdparty/masm/assembler/MacroAssembler.h
index e122e2f3ae..87794c8ef4 100644
--- a/src/3rdparty/masm/assembler/MacroAssembler.h
+++ b/src/3rdparty/masm/assembler/MacroAssembler.h
@@ -30,8 +30,9 @@
#if ENABLE(ASSEMBLER)
-#if CPU(ARM_THUMB2)
#include "MacroAssemblerARMv7.h"
+
+#if CPU(ARM_THUMB2)
namespace JSC { typedef MacroAssemblerARMv7 MacroAssemblerBase; };
#elif CPU(ARM64)
@@ -68,13 +69,53 @@ typedef MacroAssemblerSH4 MacroAssemblerBase;
namespace JSC {
+template <typename MacroAssemblerBase>
class MacroAssembler : public MacroAssemblerBase {
public:
+ using DoubleCondition = typename MacroAssemblerBase::DoubleCondition;
+ using ResultCondition = typename MacroAssemblerBase::ResultCondition;
+ using RelationalCondition = typename MacroAssemblerBase::RelationalCondition;
+ using RegisterID = typename MacroAssemblerBase::RegisterID;
+ using Address = typename MacroAssemblerBase::Address;
+ using ExtendedAddress = typename MacroAssemblerBase::ExtendedAddress;
+ using BaseIndex = typename MacroAssemblerBase::BaseIndex;
+ using ImplicitAddress = typename MacroAssemblerBase::ImplicitAddress;
+ using AbsoluteAddress = typename MacroAssemblerBase::AbsoluteAddress;
+ using TrustedImm32 = typename MacroAssemblerBase::TrustedImm32;
+ using TrustedImm64 = typename MacroAssemblerBase::TrustedImm64;
+ using TrustedImmPtr = typename MacroAssemblerBase::TrustedImmPtr;
+ using Imm32 = typename MacroAssemblerBase::Imm32;
+ using Imm64 = typename MacroAssemblerBase::Imm64;
+ using ImmPtr = typename MacroAssemblerBase::ImmPtr;
+ using Label = typename MacroAssemblerBase::Label;
+ using DataLabelPtr = typename MacroAssemblerBase::DataLabelPtr;
+ using DataLabel32 = typename MacroAssemblerBase::DataLabel32;
+ using DataLabelCompact = typename MacroAssemblerBase::DataLabelCompact;
+ using Jump = typename MacroAssemblerBase::Jump;
+ using PatchableJump = typename MacroAssemblerBase::PatchableJump;
+
using MacroAssemblerBase::pop;
using MacroAssemblerBase::jump;
using MacroAssemblerBase::branch32;
using MacroAssemblerBase::move;
+ using MacroAssemblerBase::store32;
+ using MacroAssemblerBase::add32;
+ using MacroAssemblerBase::xor32;
+ using MacroAssemblerBase::sub32;
+ using MacroAssemblerBase::load32;
+
+
+#if defined(V4_BOOTSTRAP)
+ using MacroAssemblerBase::loadPtr;
+ using MacroAssemblerBase::storePtr;
+#elif CPU(X86_64) || CPU(ARM64)
+ using MacroAssemblerBase::add64;
+ using MacroAssemblerBase::sub64;
+ using MacroAssemblerBase::xor64;
+ using MacroAssemblerBase::load64;
+ using MacroAssemblerBase::store64;
+#endif
#if ENABLE(JIT_CONSTANT_BLINDING)
using MacroAssemblerBase::add32;
@@ -100,41 +141,41 @@ public:
static DoubleCondition invert(DoubleCondition cond)
{
switch (cond) {
- case DoubleEqual:
- return DoubleNotEqualOrUnordered;
- case DoubleNotEqual:
- return DoubleEqualOrUnordered;
- case DoubleGreaterThan:
- return DoubleLessThanOrEqualOrUnordered;
- case DoubleGreaterThanOrEqual:
- return DoubleLessThanOrUnordered;
- case DoubleLessThan:
- return DoubleGreaterThanOrEqualOrUnordered;
- case DoubleLessThanOrEqual:
- return DoubleGreaterThanOrUnordered;
- case DoubleEqualOrUnordered:
- return DoubleNotEqual;
- case DoubleNotEqualOrUnordered:
- return DoubleEqual;
- case DoubleGreaterThanOrUnordered:
- return DoubleLessThanOrEqual;
- case DoubleGreaterThanOrEqualOrUnordered:
- return DoubleLessThan;
- case DoubleLessThanOrUnordered:
- return DoubleGreaterThanOrEqual;
- case DoubleLessThanOrEqualOrUnordered:
- return DoubleGreaterThan;
+ case DoubleCondition::DoubleEqual:
+ return DoubleCondition::DoubleNotEqualOrUnordered;
+ case DoubleCondition::DoubleNotEqual:
+ return DoubleCondition::DoubleEqualOrUnordered;
+ case DoubleCondition::DoubleGreaterThan:
+ return DoubleCondition::DoubleLessThanOrEqualOrUnordered;
+ case DoubleCondition::DoubleGreaterThanOrEqual:
+ return DoubleCondition::DoubleLessThanOrUnordered;
+ case DoubleCondition::DoubleLessThan:
+ return DoubleCondition::DoubleGreaterThanOrEqualOrUnordered;
+ case DoubleCondition::DoubleLessThanOrEqual:
+ return DoubleCondition::DoubleGreaterThanOrUnordered;
+ case DoubleCondition::DoubleEqualOrUnordered:
+ return DoubleCondition::DoubleNotEqual;
+ case DoubleCondition::DoubleNotEqualOrUnordered:
+ return DoubleCondition::DoubleEqual;
+ case DoubleCondition::DoubleGreaterThanOrUnordered:
+ return DoubleCondition::DoubleLessThanOrEqual;
+ case DoubleCondition::DoubleGreaterThanOrEqualOrUnordered:
+ return DoubleCondition::DoubleLessThan;
+ case DoubleCondition::DoubleLessThanOrUnordered:
+ return DoubleCondition::DoubleGreaterThanOrEqual;
+ case DoubleCondition::DoubleLessThanOrEqualOrUnordered:
+ return DoubleCondition::DoubleGreaterThan;
default:
RELEASE_ASSERT_NOT_REACHED();
- return DoubleEqual; // make compiler happy
+ return DoubleCondition::DoubleEqual; // make compiler happy
}
}
static bool isInvertible(ResultCondition cond)
{
switch (cond) {
- case Zero:
- case NonZero:
+ case ResultCondition::Zero:
+ case ResultCondition::NonZero:
return true;
default:
return false;
@@ -144,13 +185,13 @@ public:
static ResultCondition invert(ResultCondition cond)
{
switch (cond) {
- case Zero:
- return NonZero;
- case NonZero:
- return Zero;
+ case ResultCondition::Zero:
+ return ResultCondition::NonZero;
+ case ResultCondition::NonZero:
+ return ResultCondition::Zero;
default:
RELEASE_ASSERT_NOT_REACHED();
- return Zero; // Make compiler happy for release builds.
+ return ResultCondition::Zero; // Make compiler happy for release builds.
}
}
#endif
@@ -159,17 +200,17 @@ public:
// described in terms of other macro assembly methods.
void pop()
{
- addPtr(TrustedImm32(sizeof(void*)), stackPointerRegister);
+ addPtr(TrustedImm32(sizeof(void*)), MacroAssemblerBase::stackPointerRegister);
}
void peek(RegisterID dest, int index = 0)
{
- loadPtr(Address(stackPointerRegister, (index * sizeof(void*))), dest);
+ loadPtr(Address(MacroAssemblerBase::stackPointerRegister, (index * sizeof(void*))), dest);
}
Address addressForPoke(int index)
{
- return Address(stackPointerRegister, (index * sizeof(void*)));
+ return Address(MacroAssemblerBase::stackPointerRegister, (index * sizeof(void*)));
}
void poke(RegisterID src, int index = 0)
@@ -187,10 +228,10 @@ public:
storePtr(imm, addressForPoke(index));
}
-#if CPU(X86_64) || CPU(ARM64)
+#if (CPU(X86_64) || CPU(ARM64)) && !defined(V4_BOOTSTRAP)
void peek64(RegisterID dest, int index = 0)
{
- load64(Address(stackPointerRegister, (index * sizeof(void*))), dest);
+ load64(Address(MacroAssemblerBase::stackPointerRegister, (index * sizeof(void*))), dest);
}
void poke(TrustedImm64 value, int index = 0)
@@ -296,36 +337,37 @@ public:
static RelationalCondition commute(RelationalCondition condition)
{
switch (condition) {
- case Above:
- return Below;
- case AboveOrEqual:
- return BelowOrEqual;
- case Below:
- return Above;
- case BelowOrEqual:
- return AboveOrEqual;
- case GreaterThan:
- return LessThan;
- case GreaterThanOrEqual:
- return LessThanOrEqual;
- case LessThan:
- return GreaterThan;
- case LessThanOrEqual:
- return GreaterThanOrEqual;
+ case RelationalCondition::Above:
+ return RelationalCondition::Below;
+ case RelationalCondition::AboveOrEqual:
+ return RelationalCondition::BelowOrEqual;
+ case RelationalCondition::Below:
+ return RelationalCondition::Above;
+ case RelationalCondition::BelowOrEqual:
+ return RelationalCondition::AboveOrEqual;
+ case RelationalCondition::GreaterThan:
+ return RelationalCondition::LessThan;
+ case RelationalCondition::GreaterThanOrEqual:
+ return RelationalCondition::LessThanOrEqual;
+ case RelationalCondition::LessThan:
+ return RelationalCondition::GreaterThan;
+ case RelationalCondition::LessThanOrEqual:
+ return RelationalCondition::GreaterThanOrEqual;
default:
break;
}
- ASSERT(condition == Equal || condition == NotEqual);
+ ASSERT(condition == RelationalCondition::Equal || condition == RelationalCondition::NotEqual);
return condition;
}
static const unsigned BlindingModulus = 64;
bool shouldConsiderBlinding()
{
- return !(random() & (BlindingModulus - 1));
+ return !(this->random() & (BlindingModulus - 1));
}
+#if !defined(V4_BOOTSTRAP)
// Ptr methods
// On 32-bit platforms (i.e. x86), these methods directly map onto their 32-bit equivalents.
// FIXME: should this use a test for 32-bitness instead of this specific exception?
@@ -850,6 +892,7 @@ public:
{
return branchSub64(cond, src1, src2, dest);
}
+#endif // !defined(V4_BOOTSTRAP)
#if ENABLE(JIT_CONSTANT_BLINDING)
using MacroAssemblerBase::and64;
@@ -1447,6 +1490,22 @@ public:
#endif
};
+#if CPU(ARM_THUMB2)
+typedef MacroAssembler<MacroAssemblerARMv7> DefaultMacroAssembler;
+#elif CPU(ARM64)
+typedef MacroAssembler<MacroAssemblerARM64> DefaultMacroAssembler;
+#elif CPU(ARM_TRADITIONAL)
+typedef MacroAssembler<MacroAssemblerARM> DefaultMacroAssembler;
+#elif CPU(MIPS)
+typedef MacroAssembler<MacroAssemblerMIPS> DefaultMacroAssembler;
+#elif CPU(X86)
+typedef MacroAssembler<MacroAssemblerX86> DefaultMacroAssembler;
+#elif CPU(X86_64)
+typedef MacroAssembler<MacroAssemblerX86_64> DefaultMacroAssembler;
+#elif CPU(SH4)
+typedef JSC::MacroAssemblerSH4 DefaultMacroAssembler;
+#endif
+
} // namespace JSC
#else // ENABLE(ASSEMBLER)
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARM.h b/src/3rdparty/masm/assembler/MacroAssemblerARM.h
index 01e34c97cd..268fe5fe73 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerARM.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerARM.h
@@ -1349,7 +1349,7 @@ protected:
}
private:
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
friend class RepatchBuffer;
void internalCompare32(RegisterID left, TrustedImm32 right)
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARM64.h b/src/3rdparty/masm/assembler/MacroAssemblerARM64.h
index bd85b6b2c1..3e425a0246 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerARM64.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerARM64.h
@@ -3353,7 +3353,7 @@ private:
return makeBranch(cond);
}
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
void recordLinkOffsets(int32_t regionStart, int32_t regionEnd, int32_t offset) {return m_assembler.recordLinkOffsets(regionStart, regionEnd, offset); }
int executableOffsetFor(int location) { return m_assembler.executableOffsetFor(location); }
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
index 0938383513..806f2e13b6 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerARMv7.h
@@ -27,7 +27,7 @@
#ifndef MacroAssemblerARMv7_h
#define MacroAssemblerARMv7_h
-#if ENABLE(ASSEMBLER) && CPU(ARM_THUMB2)
+#if ENABLE(ASSEMBLER) && (CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP))
#include "ARMv7Assembler.h"
#include "AbstractMacroAssembler.h"
@@ -160,12 +160,41 @@ public:
{
add32(imm, dest, dest);
}
+
+#if defined(V4_BOOTSTRAP)
+ void loadPtr(ImplicitAddress address, RegisterID dest)
+ {
+ load32(address, dest);
+ }
+
+ void subPtr(TrustedImm32 imm, RegisterID dest)
+ {
+ sub32(imm, dest);
+ }
+
+ void addPtr(TrustedImm32 imm, RegisterID dest)
+ {
+ add32(imm, dest);
+ }
+
+ void addPtr(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ add32(imm, src, dest);
+ }
+
+ void storePtr(RegisterID src, ImplicitAddress address)
+ {
+ store32(src, address);
+ }
+#endif
+#if !defined(V4_BOOTSTRAP)
void add32(AbsoluteAddress src, RegisterID dest)
{
load32(src.m_ptr, dataTempRegister);
add32(dataTempRegister, dest);
}
+#endif
void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
@@ -206,6 +235,7 @@ public:
add32(dataTempRegister, dest);
}
+#if !defined(V4_BOOTSTRAP)
void add32(TrustedImm32 imm, AbsoluteAddress address)
{
load32(address.m_ptr, dataTempRegister);
@@ -242,6 +272,7 @@ public:
m_assembler.adc(dataTempRegister, dataTempRegister, ARMThumbImmediate::makeEncodedImm(imm.m_value >> 31));
m_assembler.str(dataTempRegister, addressTempRegister, ARMThumbImmediate::makeUInt12(4));
}
+#endif
void and32(RegisterID op1, RegisterID op2, RegisterID dest)
{
@@ -343,6 +374,7 @@ public:
or32(dataTempRegister, dest);
}
+#if !defined(V4_BOOTSTRAP)
void or32(RegisterID src, AbsoluteAddress dest)
{
move(TrustedImmPtr(dest.m_ptr), addressTempRegister);
@@ -350,6 +382,7 @@ public:
or32(src, dataTempRegister);
store32(dataTempRegister, addressTempRegister);
}
+#endif
void or32(TrustedImm32 imm, RegisterID dest)
{
@@ -461,6 +494,7 @@ public:
sub32(dataTempRegister, dest);
}
+#if !defined(V4_BOOTSTRAP)
void sub32(TrustedImm32 imm, AbsoluteAddress address)
{
load32(address.m_ptr, dataTempRegister);
@@ -477,6 +511,7 @@ public:
store32(dataTempRegister, address.m_ptr);
}
+#endif
void xor32(Address src, RegisterID dest)
{
@@ -526,7 +561,8 @@ public:
// operand objects to loads and store will be implicitly constructed if a
// register is passed.
-private:
+ // internal function, but public because of "using load32;" in template sub-classes to pull
+ // in the other public overloads.
void load32(ArmAddress address, RegisterID dest)
{
if (address.type == ArmAddress::HasIndex)
@@ -541,6 +577,7 @@ private:
}
}
+private:
void load16(ArmAddress address, RegisterID dest)
{
if (address.type == ArmAddress::HasIndex)
@@ -646,11 +683,13 @@ public:
load16(setupArmAddress(address), dest);
}
+#if !defined(V4_BOOTSTRAP)
void load32(const void* address, RegisterID dest)
{
move(TrustedImmPtr(address), addressTempRegister);
m_assembler.ldr(dest, addressTempRegister, ARMThumbImmediate::makeUInt16(0));
}
+#endif
ConvertibleLoadLabel convertibleLoadPtr(Address address, RegisterID dest)
{
@@ -755,6 +794,7 @@ public:
store32(dataTempRegister, setupArmAddress(address));
}
+#if !defined(V4_BOOTSTRAP)
void store32(RegisterID src, const void* address)
{
move(TrustedImmPtr(address), addressTempRegister);
@@ -766,12 +806,14 @@ public:
move(imm, dataTempRegister);
store32(dataTempRegister, address);
}
+#endif
void store8(RegisterID src, BaseIndex address)
{
store8(src, setupArmAddress(address));
}
+#if !defined(V4_BOOTSTRAP)
void store8(RegisterID src, void* address)
{
move(TrustedImmPtr(address), addressTempRegister);
@@ -783,6 +825,7 @@ public:
move(imm, dataTempRegister);
store8(dataTempRegister, address);
}
+#endif
void store16(RegisterID src, BaseIndex address)
{
@@ -880,11 +923,13 @@ public:
m_assembler.vmov(dest, src);
}
+#if !defined(V4_BOOTSTRAP)
void loadDouble(const void* address, FPRegisterID dest)
{
move(TrustedImmPtr(address), addressTempRegister);
m_assembler.vldr(dest, addressTempRegister, 0);
}
+#endif
void storeDouble(FPRegisterID src, ImplicitAddress address)
{
@@ -916,11 +961,13 @@ public:
m_assembler.fsts(ARMRegisters::asSingle(src), base, offset);
}
+#if !defined(V4_BOOTSTRAP)
void storeDouble(FPRegisterID src, const void* address)
{
move(TrustedImmPtr(address), addressTempRegister);
storeDouble(src, addressTempRegister);
}
+#endif
void storeDouble(FPRegisterID src, BaseIndex address)
{
@@ -954,11 +1001,13 @@ public:
m_assembler.vadd(dest, op1, op2);
}
+#if !defined(V4_BOOTSTRAP)
void addDouble(AbsoluteAddress address, FPRegisterID dest)
{
loadDouble(address.m_ptr, fpTempRegister);
m_assembler.vadd(dest, dest, fpTempRegister);
}
+#endif
void divDouble(FPRegisterID src, FPRegisterID dest)
{
@@ -1037,6 +1086,7 @@ public:
m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
}
+#if !defined(V4_BOOTSTRAP)
void convertInt32ToDouble(AbsoluteAddress address, FPRegisterID dest)
{
// Fixme: load directly into the fpr!
@@ -1044,6 +1094,7 @@ public:
m_assembler.vmov(fpTempRegister, dataTempRegister, dataTempRegister);
m_assembler.vcvt_signedToFloatingPoint(dest, fpTempRegisterAsSingle());
}
+#endif
void convertUInt32ToDouble(RegisterID src, FPRegisterID dest, RegisterID /*scratch*/)
{
@@ -1197,7 +1248,7 @@ public:
void push(RegisterID src)
{
// store preindexed with writeback
- m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true);
+ m_assembler.str(src, ARMRegisters::sp, -4 /*sizeof(void*)*/, true, true);
}
void push(Address address)
@@ -1239,10 +1290,12 @@ public:
m_assembler.mov(dest, src);
}
+#if !defined(V4_BOOTSTRAP)
void move(TrustedImmPtr imm, RegisterID dest)
{
move(TrustedImm32(imm), dest);
}
+#endif
void swap(RegisterID reg1, RegisterID reg2)
{
@@ -1383,6 +1436,7 @@ public:
return branch32(cond, addressTempRegister, right);
}
+#if !defined(V4_BOOTSTRAP)
Jump branch32(RelationalCondition cond, AbsoluteAddress left, RegisterID right)
{
load32(left.m_ptr, dataTempRegister);
@@ -1395,6 +1449,7 @@ public:
load32(left.m_ptr, addressTempRegister);
return branch32(cond, addressTempRegister, right);
}
+#endif
Jump branch8(RelationalCondition cond, RegisterID left, TrustedImm32 right)
{
@@ -1451,6 +1506,7 @@ public:
return branchTest32(cond, addressTempRegister, mask);
}
+#if !defined(V4_BOOTSTRAP)
Jump branchTest8(ResultCondition cond, AbsoluteAddress address, TrustedImm32 mask = TrustedImm32(-1))
{
// use addressTempRegister incase the branchTest8 we call uses dataTempRegister. :-/
@@ -1458,6 +1514,7 @@ public:
load8(Address(addressTempRegister), addressTempRegister);
return branchTest32(cond, addressTempRegister, mask);
}
+#endif
void jump(RegisterID target)
{
@@ -1471,12 +1528,14 @@ public:
m_assembler.bx(dataTempRegister);
}
+#if !defined(V4_BOOTSTRAP)
void jump(AbsoluteAddress address)
{
move(TrustedImmPtr(address.m_ptr), dataTempRegister);
load32(Address(dataTempRegister), dataTempRegister);
m_assembler.bx(dataTempRegister);
}
+#endif
// Arithmetic control flow operations:
@@ -1517,6 +1576,7 @@ public:
return branchAdd32(cond, dest, imm, dest);
}
+#if !defined(V4_BOOTSTRAP)
Jump branchAdd32(ResultCondition cond, TrustedImm32 imm, AbsoluteAddress dest)
{
// Move the high bits of the address into addressTempRegister,
@@ -1542,6 +1602,7 @@ public:
return Jump(makeBranch(cond));
}
+#endif
Jump branchMul32(ResultCondition cond, RegisterID src1, RegisterID src2, RegisterID dest)
{
@@ -1712,6 +1773,7 @@ public:
return DataLabel32(this);
}
+#if !defined(V4_BOOTSTRAP)
ALWAYS_INLINE DataLabelPtr moveWithPatch(TrustedImmPtr imm, RegisterID dst)
{
padBeforePatch();
@@ -1739,7 +1801,8 @@ public:
m_makeJumpPatchable = false;
return PatchableJump(result);
}
-
+#endif
+
PatchableJump patchableBranchTest32(ResultCondition cond, RegisterID reg, TrustedImm32 mask = TrustedImm32(-1))
{
m_makeJumpPatchable = true;
@@ -1756,6 +1819,7 @@ public:
return PatchableJump(result);
}
+#if !defined(V4_BOOTSTRAP)
PatchableJump patchableBranchPtrWithPatch(RelationalCondition cond, Address left, DataLabelPtr& dataLabel, TrustedImmPtr initialRightValue = TrustedImmPtr(0))
{
m_makeJumpPatchable = true;
@@ -1763,6 +1827,7 @@ public:
m_makeJumpPatchable = false;
return PatchableJump(result);
}
+#endif
PatchableJump patchableJump()
{
@@ -1773,6 +1838,7 @@ public:
return PatchableJump(result);
}
+#if !defined(V4_BOOTSTRAP)
ALWAYS_INLINE DataLabelPtr storePtrWithPatch(TrustedImmPtr initialValue, ImplicitAddress address)
{
DataLabelPtr label = moveWithPatch(initialValue, dataTempRegister);
@@ -1780,7 +1846,7 @@ public:
return label;
}
ALWAYS_INLINE DataLabelPtr storePtrWithPatch(ImplicitAddress address) { return storePtrWithPatch(TrustedImmPtr(0), address); }
-
+#endif
ALWAYS_INLINE Call tailRecursiveCall()
{
@@ -1801,6 +1867,7 @@ public:
return m_assembler.executableOffsetFor(location);
}
+#if !defined(V4_BOOTSTRAP)
static FunctionPtr readCallTarget(CodeLocationCall call)
{
return FunctionPtr(reinterpret_cast<void(*)()>(ARMv7Assembler::readCallTarget(call.dataLocation())));
@@ -1813,7 +1880,8 @@ public:
const unsigned twoWordOpSize = 4;
return label.labelAtOffset(-twoWordOpSize * 2);
}
-
+#endif
+
static void revertJumpReplacementToBranchPtrWithPatch(CodeLocationLabel instructionStart, RegisterID rd, void* initialValue)
{
#if OS(LINUX) || OS(QNX)
@@ -1927,9 +1995,10 @@ protected:
}
private:
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
friend class RepatchBuffer;
+#if !defined(V4_BOOTSTRAP)
static void linkCall(void* code, Call call, FunctionPtr function)
{
ARMv7Assembler::linkCall(code, call.m_label, function.value());
@@ -1944,6 +2013,7 @@ private:
{
ARMv7Assembler::relinkCall(call.dataLocation(), destination.executableAddress());
}
+#endif
bool m_makeJumpPatchable;
};
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h b/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h
index 734e779c70..68584527fc 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerMIPS.h
@@ -2802,7 +2802,7 @@ private:
// Otherwise, we can emit any number of instructions.
bool m_fixedWidth;
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
friend class RepatchBuffer;
static void linkCall(void* code, Call call, FunctionPtr function)
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerSH4.h b/src/3rdparty/masm/assembler/MacroAssemblerSH4.h
index 56fb74d45b..1e5a3113bb 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerSH4.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerSH4.h
@@ -2278,7 +2278,7 @@ protected:
return static_cast<SH4Assembler::Condition>(cond);
}
private:
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
friend class RepatchBuffer;
static void linkCall(void*, Call, FunctionPtr);
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86.h b/src/3rdparty/masm/assembler/MacroAssemblerX86.h
index 9a33fe870e..742a4b48f7 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerX86.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerX86.h
@@ -54,6 +54,38 @@ public:
using MacroAssemblerX86Common::convertInt32ToDouble;
using MacroAssemblerX86Common::branchTest8;
+#if defined(V4_BOOTSTRAP)
+ void loadPtr(ImplicitAddress address, RegisterID dest)
+ {
+ load32(address, dest);
+ }
+
+ void subPtr(TrustedImm32 imm, RegisterID dest)
+ {
+ sub32(imm, dest);
+ }
+
+ void addPtr(TrustedImm32 imm, RegisterID dest)
+ {
+ add32(imm, dest);
+ }
+
+ void addPtr(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ add32(imm, src, dest);
+ }
+
+ void storePtr(RegisterID src, ImplicitAddress address)
+ {
+ store32(src, address);
+ }
+
+ Jump branchTest8(ResultCondition cond, ExtendedAddress address, TrustedImm32 mask = TrustedImm32(-1))
+ {
+ return branchTest8(cond, Address(address.base, address.offset), mask);
+ }
+#endif
+
void add32(TrustedImm32 imm, RegisterID src, RegisterID dest)
{
m_assembler.leal_mr(imm.m_value, src, dest);
@@ -306,7 +338,7 @@ public:
}
private:
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
friend class RepatchBuffer;
static void linkCall(void* code, Call call, FunctionPtr function)
diff --git a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
index 9e74f1c29f..3566702413 100644
--- a/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
+++ b/src/3rdparty/masm/assembler/MacroAssemblerX86_64.h
@@ -52,6 +52,33 @@ public:
using MacroAssemblerX86Common::loadDouble;
using MacroAssemblerX86Common::convertInt32ToDouble;
+#if defined(V4_BOOTSTRAP)
+ void loadPtr(ImplicitAddress address, RegisterID dest)
+ {
+ load64(address, dest);
+ }
+
+ void subPtr(TrustedImm32 imm, RegisterID dest)
+ {
+ sub64(imm, dest);
+ }
+
+ void addPtr(TrustedImm32 imm, RegisterID dest)
+ {
+ add64(imm, dest);
+ }
+
+ void addPtr(TrustedImm32 imm, RegisterID src, RegisterID dest)
+ {
+ add64(imm, src, dest);
+ }
+
+ void storePtr(RegisterID src, ImplicitAddress address)
+ {
+ store64(src, address);
+ }
+#endif
+
void add32(TrustedImm32 imm, AbsoluteAddress address)
{
move(TrustedImmPtr(address.m_ptr), scratchRegister);
@@ -634,7 +661,7 @@ public:
}
private:
- friend class LinkBuffer;
+ template <typename, template <typename> class> friend class LinkBufferBase;
friend class RepatchBuffer;
static void linkCall(void* code, Call call, FunctionPtr function)
diff --git a/src/3rdparty/masm/assembler/X86Assembler.h b/src/3rdparty/masm/assembler/X86Assembler.h
index 1875ebaff0..24462ef38f 100644
--- a/src/3rdparty/masm/assembler/X86Assembler.h
+++ b/src/3rdparty/masm/assembler/X86Assembler.h
@@ -29,6 +29,7 @@
#if ENABLE(ASSEMBLER) && (CPU(X86) || CPU(X86_64))
#include "AssemblerBuffer.h"
+#include "AbstractMacroAssembler.h"
#include "JITCompilationEffort.h"
#include <stdint.h>
#include <wtf/Assertions.h>
@@ -252,6 +253,45 @@ public:
{
}
+ template <typename LabelType>
+ class Jump {
+ template<class TemplateAssemblerType>
+ friend class AbstractMacroAssembler;
+ friend class Call;
+ template <typename, template <typename> class> friend class LinkBufferBase;
+ public:
+ Jump()
+ {
+ }
+
+ Jump(AssemblerLabel jmp)
+ : m_label(jmp)
+ {
+ }
+
+ LabelType label() const
+ {
+ LabelType result;
+ result.m_label = m_label;
+ return result;
+ }
+
+ void link(AbstractMacroAssembler<X86Assembler>* masm) const
+ {
+ masm->m_assembler.linkJump(m_label, masm->m_assembler.label());
+ }
+
+ void linkTo(LabelType label, AbstractMacroAssembler<X86Assembler>* masm) const
+ {
+ masm->m_assembler.linkJump(m_label, label.label());
+ }
+
+ bool isSet() const { return m_label.isSet(); }
+
+ private:
+ AssemblerLabel m_label;
+ };
+
// Stack operations:
void push_r(RegisterID reg)
diff --git a/src/3rdparty/masm/masm.pri b/src/3rdparty/masm/masm.pri
index afa1438974..c63cd5da66 100644
--- a/src/3rdparty/masm/masm.pri
+++ b/src/3rdparty/masm/masm.pri
@@ -13,6 +13,7 @@ HEADERS += $$PWD/wtf/RawPointer.h
winrt: SOURCES += $$PWD/wtf/OSAllocatorWinRT.cpp
else:win32: SOURCES += $$PWD/wtf/OSAllocatorWin.cpp
+else:integrity: SOURCES += $$PWD/wtf/OSAllocatorIntegrity.cpp
else: SOURCES += $$PWD/wtf/OSAllocatorPosix.cpp
HEADERS += $$PWD/wtf/OSAllocator.h
diff --git a/src/3rdparty/masm/stubs/ExecutableAllocator.h b/src/3rdparty/masm/stubs/ExecutableAllocator.h
index 8617229b06..9a2a9773b5 100644
--- a/src/3rdparty/masm/stubs/ExecutableAllocator.h
+++ b/src/3rdparty/masm/stubs/ExecutableAllocator.h
@@ -61,7 +61,7 @@ namespace JSC {
class JSGlobalData;
struct ExecutableMemoryHandle : public RefCounted<ExecutableMemoryHandle> {
- ExecutableMemoryHandle(QV4::ExecutableAllocator *allocator, int size)
+ ExecutableMemoryHandle(QV4::ExecutableAllocator *allocator, size_t size)
: m_allocator(allocator)
, m_size(size)
{
@@ -79,14 +79,14 @@ struct ExecutableMemoryHandle : public RefCounted<ExecutableMemoryHandle> {
inline bool isManaged() const { return true; }
void* start() { return m_allocation->start(); }
- int sizeInBytes() { return m_size; }
+ size_t sizeInBytes() { return m_size; }
QV4::ExecutableAllocator::ChunkOfPages *chunk() const
{ return m_allocator->chunkForAllocation(m_allocation); }
QV4::ExecutableAllocator *m_allocator;
QV4::ExecutableAllocator::Allocation *m_allocation;
- int m_size;
+ size_t m_size;
};
struct ExecutableAllocator {
@@ -94,7 +94,7 @@ struct ExecutableAllocator {
: realAllocator(alloc)
{}
- PassRefPtr<ExecutableMemoryHandle> allocate(JSGlobalData&, int size, void*, int)
+ PassRefPtr<ExecutableMemoryHandle> allocate(JSGlobalData&, size_t size, void*, int)
{
return adoptRef(new ExecutableMemoryHandle(realAllocator, size));
}
diff --git a/src/3rdparty/masm/wtf/MathExtras.h b/src/3rdparty/masm/wtf/MathExtras.h
index 75e3670367..3740d54beb 100644
--- a/src/3rdparty/masm/wtf/MathExtras.h
+++ b/src/3rdparty/masm/wtf/MathExtras.h
@@ -88,7 +88,7 @@ inline double wtf_ceil(double x) { return copysign(ceil(x), x); }
#endif
-#if OS(SOLARIS)
+#if OS(SOLARIS) && __cplusplus < 201103L
namespace std {
diff --git a/src/3rdparty/masm/wtf/OSAllocatorIntegrity.cpp b/src/3rdparty/masm/wtf/OSAllocatorIntegrity.cpp
new file mode 100644
index 0000000000..451ca147d1
--- /dev/null
+++ b/src/3rdparty/masm/wtf/OSAllocatorIntegrity.cpp
@@ -0,0 +1,232 @@
+/****************************************************************************
+**
+** Copyright (C) Rolland Dudemaine All rights reserved.
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "config.h"
+#include "OSAllocator.h"
+
+#include <INTEGRITY.h>
+#include <memory_region.h>
+#include <set>
+#include <wtf/Assertions.h>
+#include <wtf/UnusedParam.h>
+
+#define ASP_PAGESIZE 0x1000
+
+namespace WTF {
+struct MRPair {
+ mutable MemoryRegion pmr;
+ mutable MemoryRegion vmr;
+
+ mutable bool mapped;
+
+ Address start;
+
+ MRPair(Address _start = 0) :
+ pmr(0),
+ vmr(0),
+ mapped(false),
+ start(_start)
+ {}
+
+ bool operator<(const MRPair& rhs) const
+ {
+ return this->start < rhs.start;
+ }
+};
+
+class MRContainer
+{
+private:
+ std::set<MRPair> mrset;
+ LocalMutex iteratorGuard;
+public:
+ MRContainer() {
+ CheckSuccess(CreateLocalMutex(&iteratorGuard));
+ }
+ const MRPair* getMRPair(Address start) {
+ WaitForLocalMutex(iteratorGuard);
+ auto pairIterator = mrset.find(MRPair(start));
+ const MRPair* result = ((pairIterator == mrset.end()) ? NULL : &(*pairIterator));
+ ReleaseLocalMutex(iteratorGuard);
+ return result;
+ }
+ Error deleteMRPair(const MRPair* pair) {
+ int erased = 0;
+ WaitForLocalMutex(iteratorGuard);
+ erased = mrset.erase(*pair);
+ ReleaseLocalMutex(iteratorGuard);
+ if(erased == 1)
+ return Success;
+ else
+ return ArgumentError; /* An exception could be thrown in this case */
+ }
+ Error insertMRPair(MRPair* pair) {
+ WaitForLocalMutex(iteratorGuard);
+ auto inserted = mrset.insert(*pair);
+ ReleaseLocalMutex(iteratorGuard);
+ if(inserted.second == true)
+ return Success;
+ else
+ return Failure; /* An exception could be thrown in this case */
+ }
+ ~MRContainer() {
+ CheckSuccess(CloseLocalMutex(iteratorGuard));
+ }
+};
+
+static MRContainer memoryRegionsContainer;
+
+Error setAttributes(MemoryRegion mr, bool writable, bool executable)
+{
+ Value attributes = MEMORY_READ;
+ if(writable)
+ attributes |= MEMORY_WRITE;
+ if(executable)
+ attributes |= MEMORY_EXEC;
+ return SetMemoryRegionAttributes(mr, attributes);
+}
+
+void* OSAllocator::reserveUncommitted(size_t bytes, Usage usage, bool writable, bool executable)
+{
+ MemoryRegion VMR;
+
+ Address virtualStart, length;
+
+ CheckSuccess(AllocateAnyMemoryRegion(__ghs_VirtualMemoryRegionPool, bytes, &VMR));
+ CheckSuccess(GetMemoryRegionAddresses(VMR, &virtualStart, &length));
+ Address addressIterator = virtualStart;
+ for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++) {
+ MRPair pair;
+ CheckSuccess(SplitMemoryRegion(VMR, ASP_PAGESIZE, &pair.vmr));
+ CheckSuccess(setAttributes(pair.vmr, writable, executable));
+ pair.start = addressIterator;
+
+ memoryRegionsContainer.insertMRPair(&pair);
+ addressIterator += ASP_PAGESIZE;
+ }
+
+ CheckSuccess(CloseMemoryRegion(VMR));
+ return (void*)virtualStart;
+}
+
+void* OSAllocator::reserveAndCommit(size_t bytes, Usage usage, bool writable, bool executable, bool includesGuardPages)
+{
+ MemoryRegion VMR;
+
+ Address virtualStart, length;
+
+ CheckSuccess(AllocateAnyMemoryRegion(__ghs_VirtualMemoryRegionPool, bytes, &VMR));
+ CheckSuccess(GetMemoryRegionAddresses(VMR, &virtualStart, &length));
+
+ Address addressIterator = virtualStart;
+ for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++) {
+ MRPair pair;
+ pair.start = addressIterator;
+ CheckSuccess(SplitMemoryRegion(VMR, ASP_PAGESIZE, &pair.vmr));
+ CheckSuccess(setAttributes(pair.vmr, writable, executable));
+ /* Do not map the first and the last pages if guard pages are required */
+ if(!includesGuardPages || (i!=0 && i!= (bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE -1))
+ {
+ CheckSuccess(GetPageFromAddressSpaceFreeList(GetCurrentAddressSpace(), &pair.pmr));
+ CheckSuccess(MapMemoryRegion(pair.vmr, pair.pmr));
+ pair.mapped = true;
+ }
+
+ memoryRegionsContainer.insertMRPair(&pair);
+ addressIterator += ASP_PAGESIZE;
+ }
+
+ CheckSuccess(CloseMemoryRegion(VMR));
+ return (void*)virtualStart;
+}
+
+void OSAllocator::commit(void* address, size_t bytes, bool writable, bool executable)
+{
+ for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
+ {
+ const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
+ if(pair == NULL)
+ return;
+ CheckSuccess(setAttributes(pair->vmr, writable, executable));
+ CheckSuccess(GetPageFromAddressSpaceFreeList(GetCurrentAddressSpace(), &pair->pmr));
+ CheckSuccess(MapMemoryRegion(pair->vmr, pair->pmr));
+ pair->mapped = true;
+ address = (char*)address + ASP_PAGESIZE;
+ }
+}
+
+void OSAllocator::decommit(void* address, size_t bytes)
+{
+ for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
+ {
+ const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
+ if(pair == NULL)
+ return;
+ if(pair->mapped == false)
+ continue;
+
+ CheckSuccess(UnmapMemoryRegion(pair->vmr));
+ CheckSuccess(PutPageOnAddressSpaceFreeList(GetCurrentAddressSpace(), pair->pmr));
+ pair->mapped = false;
+ address = (char*)address + ASP_PAGESIZE;
+ }
+}
+
+void OSAllocator::releaseDecommitted(void* address, size_t bytes)
+{
+ for(int i=0; i<(bytes + ASP_PAGESIZE -1)/ASP_PAGESIZE; i++)
+ {
+ const MRPair* pair = memoryRegionsContainer.getMRPair((Address)address);
+ if(pair == NULL)
+ return;
+ /* Check if the memory is still committed */
+ if(pair->mapped == true)
+ {
+ CheckSuccess(UnmapMemoryRegion(pair->vmr));
+ CheckSuccess(PutPageOnAddressSpaceFreeList(GetCurrentAddressSpace(), pair->pmr));
+ pair->mapped = false;
+ }
+ CheckSuccess(AddToMemoryPool(__ghs_VirtualMemoryRegionPool, pair->vmr));
+ address = (char*)address + ASP_PAGESIZE;
+
+ memoryRegionsContainer.deleteMRPair(pair);
+ }
+}
+} // namespace WTF
diff --git a/src/3rdparty/masm/wtf/Platform.h b/src/3rdparty/masm/wtf/Platform.h
index bc62c381db..7f2023a68a 100644
--- a/src/3rdparty/masm/wtf/Platform.h
+++ b/src/3rdparty/masm/wtf/Platform.h
@@ -949,10 +949,6 @@
#define WTF_USE_ACCESSIBILITY_CONTEXT_MENUS 1
#endif
-#if CPU(ARM_THUMB2) || CPU(ARM64)
-#define ENABLE_BRANCH_COMPACTION 1
-#endif
-
#if !defined(ENABLE_THREADING_LIBDISPATCH) && HAVE(DISPATCH_H)
#define ENABLE_THREADING_LIBDISPATCH 1
#elif !defined(ENABLE_THREADING_OPENMP) && defined(_OPENMP)
diff --git a/src/3rdparty/masm/yarr/YarrJIT.cpp b/src/3rdparty/masm/yarr/YarrJIT.cpp
index d8211ec4b2..e4f2d97759 100644
--- a/src/3rdparty/masm/yarr/YarrJIT.cpp
+++ b/src/3rdparty/masm/yarr/YarrJIT.cpp
@@ -39,7 +39,7 @@ using namespace WTF;
namespace JSC { namespace Yarr {
template<YarrJITCompileMode compileMode>
-class YarrGenerator : private MacroAssembler {
+class YarrGenerator : private DefaultMacroAssembler {
friend void jitCompile(JSGlobalData*, YarrCodeBlock& jitObject, const String& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline);
#if CPU(ARM)
@@ -599,7 +599,7 @@ class YarrGenerator : private MacroAssembler {
}
// Called at the end of code generation to link all return addresses.
- void linkDataLabels(LinkBuffer& linkBuffer)
+ void linkDataLabels(LinkBuffer<JSC::DefaultMacroAssembler>& linkBuffer)
{
ASSERT(isEmpty());
for (unsigned i = 0; i < m_backtrackRecords.size(); ++i)
@@ -2676,7 +2676,7 @@ public:
backtrack();
// Link & finalize the code.
- LinkBuffer linkBuffer(*globalData, this, REGEXP_CODE_ID);
+ LinkBuffer<JSC::DefaultMacroAssembler> linkBuffer(*globalData, this, REGEXP_CODE_ID);
m_backtrackingState.linkDataLabels(linkBuffer);
if (compileMode == MatchOnly) {
diff --git a/src/imports/imports.pro b/src/imports/imports.pro
index cad02a2980..20ade45fc8 100644
--- a/src/imports/imports.pro
+++ b/src/imports/imports.pro
@@ -5,16 +5,17 @@ SUBDIRS += \
qtqml \
folderlistmodel \
localstorage \
- models \
- statemachine
+ models
qtConfig(settings): SUBDIRS += settings
+qtConfig(statemachine): SUBDIRS += statemachine
qtHaveModule(quick) {
SUBDIRS += \
layouts \
qtquick2 \
window \
+ sharedimage \
testlib
qtConfig(opengl(es1|es2)?): \
diff --git a/src/imports/layouts/qquickstacklayout.cpp b/src/imports/layouts/qquickstacklayout.cpp
index a223dd0374..0bfe63816d 100644
--- a/src/imports/layouts/qquickstacklayout.cpp
+++ b/src/imports/layouts/qquickstacklayout.cpp
@@ -307,7 +307,11 @@ void QQuickStackLayout::rearrange(const QSizeF &newSize)
QQuickItem *item = itemAt(d->currentIndex);
Q_ASSERT(item);
item->setPosition(QPointF(0,0)); // ### respect alignment?
- item->setSize(newSize.expandedTo(hints.min()).boundedTo(hints.max()));
+ const QSizeF oldSize(item->width(), item->height());
+ const QSizeF effectiveNewSize = newSize.expandedTo(hints.min()).boundedTo(hints.max());
+ item->setSize(effectiveNewSize);
+ if (effectiveNewSize == oldSize)
+ item->polish();
QQuickLayout::rearrange(newSize);
}
diff --git a/src/imports/sharedimage/plugin.cpp b/src/imports/sharedimage/plugin.cpp
new file mode 100644
index 0000000000..f20edc641c
--- /dev/null
+++ b/src/imports/sharedimage/plugin.cpp
@@ -0,0 +1,134 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qqmlextensionplugin.h>
+#include <qqmlengine.h>
+#include <sharedimageprovider.h>
+
+
+/*!
+ \qmlmodule QtQuick.SharedImage 1
+ \title Qt Quick Shared Image Provider
+ \ingroup qmlmodules
+ \brief Adds an image provider which utilizes shared CPU memory
+
+ \section2 Summary
+
+ This module provides functionality to save memory in use cases where
+ several Qt Quick applications use the same local image files. It does this
+ by placing the decoded QImage data in shared system memory, making it
+ accessible to all the processes (see QSharedMemory).
+
+ This module only shares CPU memory. It does not provide sharing of GPU
+ memory or textures.
+
+ \section2 Usage
+
+ To use this module, import it like this:
+ \code
+ import QtQuick.SharedImage 1.0
+ \endcode
+
+ The sharing functionality is provided through a QQuickImageProvider. Use
+ the "image:" scheme for the URL source of the image, followed by the
+ identifier \e shared, followed by the image file path. For example:
+
+ \code
+ Image { source: "image://shared/usr/share/wallpapers/mybackground.jpg" }
+ \endcode
+
+ This will look for the file \e /usr/share/wallpapers/mybackground.jpg.
+ The first process that does this will read the image file
+ using normal Qt image loading. The decoded image data will then be placed
+ in shared memory, using the full file path as key. Later processes
+ requesting the same image will discover that the data is already available
+ in shared memory. They will then use that instead of loading the image file
+ again.
+
+ The shared image data will be kept available until the last process has deleted
+ its last reference to the shared image, at which point it is automatically released.
+
+ If system memory sharing is not available, the shared image provider falls
+ back to normal, unshared image loading.
+
+ The file path must be absolute. To use a relative path, make it absolute
+ using \e Qt.resolvedUrl() and replace the URL scheme. For example:
+
+ \code
+ ...
+ property string imagePrefix: Qt.resolvedUrl("../myimages/").replace("file://", "image://shared/")
+ Image { source: imagePrefix + "myimage.png" }
+ \endcode
+
+ The shared image module does not provide any directly usable QML types.
+*/
+
+static void initResources()
+{
+#ifdef QT_STATIC
+ Q_INIT_RESOURCE(qmake_QtQuick_SharedImage);
+#endif
+}
+
+QT_BEGIN_NAMESPACE
+
+class QtQuickSharedImagePlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+public:
+ QtQuickSharedImagePlugin(QObject *parent = 0) : QQmlExtensionPlugin(parent) { initResources(); }
+
+ void registerTypes(const char *uri) Q_DECL_OVERRIDE
+ {
+ Q_ASSERT(uri == QStringLiteral("QtQuick.SharedImage"));
+ // Need to register *something* to let our version number be known:
+ qmlRegisterTypeNotAvailable(uri, 1, 0, "nosuchtype", QStringLiteral("Just a dummy type, do not use"));
+ }
+
+ void initializeEngine(QQmlEngine *engine, const char *uri) override
+ {
+ Q_UNUSED(uri);
+ engine->addImageProvider("shared", new SharedImageProvider);
+ }
+};
+
+QT_END_NAMESPACE
+
+#include "plugin.moc"
diff --git a/src/imports/sharedimage/qmldir b/src/imports/sharedimage/qmldir
new file mode 100644
index 0000000000..64a5aa8ac1
--- /dev/null
+++ b/src/imports/sharedimage/qmldir
@@ -0,0 +1,3 @@
+module QtQuick.SharedImage
+plugin sharedimageplugin
+classname QtQuickSharedImagePlugin
diff --git a/src/imports/sharedimage/qsharedimageloader.cpp b/src/imports/sharedimage/qsharedimageloader.cpp
new file mode 100644
index 0000000000..65cbd92bb4
--- /dev/null
+++ b/src/imports/sharedimage/qsharedimageloader.cpp
@@ -0,0 +1,265 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsharedimageloader_p.h"
+#include <private/qobject_p.h>
+#include <private/qimage_p.h>
+#include <QSharedMemory>
+
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(lcSharedImage, "qt.quick.sharedimage");
+
+struct SharedImageHeader {
+ quint8 magic;
+ quint8 version;
+ quint16 offset;
+ qint32 width;
+ qint32 height;
+ qint32 bpl;
+ QImage::Format format;
+};
+Q_STATIC_ASSERT(sizeof(SharedImageHeader) % 4 == 0);
+
+#ifndef QT_NO_SHAREDMEMORY
+struct SharedImageInfo {
+ QString path;
+ QPointer<QSharedMemory> shmp;
+};
+
+void cleanupSharedImage(void *cleanupInfo)
+{
+ if (!cleanupInfo)
+ return;
+ SharedImageInfo *sii = static_cast<SharedImageInfo *>(cleanupInfo);
+ qCDebug(lcSharedImage) << "Cleanup called for" << sii->path;
+ if (sii->shmp.isNull()) {
+ qCDebug(lcSharedImage) << "shm is 0 for" << sii->path;
+ return;
+ }
+ QSharedMemory *shm = sii->shmp.data();
+ sii->shmp.clear();
+ delete shm; // destructor detaches
+ delete sii;
+}
+#else
+void cleanupSharedImage(void *) {}
+#endif
+
+class QSharedImageLoaderPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QSharedImageLoader)
+
+public:
+ QSharedImageLoaderPrivate()
+ : QObjectPrivate()
+ {}
+
+ QImage load(const QString &path, QSharedImageLoader::ImageParameters *params);
+
+ void storeImageToMem(void *data, const QImage &img);
+
+ bool verifyMem(const void *data, int size);
+
+ QImage createImageFromMem(const void *data, void *cleanupInfo);
+
+};
+
+
+void QSharedImageLoaderPrivate::storeImageToMem(void *data, const QImage &img)
+{
+ Q_ASSERT(data && !img.isNull());
+
+ SharedImageHeader *h = static_cast<SharedImageHeader *>(data);
+ h->magic = 'Q';
+ h->version = 1;
+ h->offset = sizeof(SharedImageHeader);
+ h->width = img.width();
+ h->height = img.height();
+ h->bpl = img.bytesPerLine();
+ h->format = img.format();
+
+ uchar *p = static_cast<uchar *>(data) + sizeof(SharedImageHeader);
+ memcpy(p, img.constBits(), img.byteCount());
+}
+
+
+bool QSharedImageLoaderPrivate::verifyMem(const void *data, int size)
+{
+ if (!data || size < int(sizeof(SharedImageHeader)))
+ return false;
+
+ const SharedImageHeader *h = static_cast<const SharedImageHeader *>(data);
+ if ((h->magic != 'Q')
+ || (h->version < 1)
+ || (h->offset < sizeof(SharedImageHeader))
+ || (h->width <= 0)
+ || (h->height <= 0)
+ || (h->bpl <= 0)
+ || (h->format <= QImage::Format_Invalid)
+ || (h->format >= QImage::NImageFormats)) {
+ return false;
+ }
+
+ int availSize = size - h->offset;
+ if (h->height * h->bpl > availSize)
+ return false;
+ if ((qt_depthForFormat(h->format) * h->width * h->height) > (8 * availSize))
+ return false;
+
+ return true;
+}
+
+
+QImage QSharedImageLoaderPrivate::createImageFromMem(const void *data, void *cleanupInfo)
+{
+ const SharedImageHeader *h = static_cast<const SharedImageHeader *>(data);
+ const uchar *p = static_cast<const uchar *>(data) + h->offset;
+
+ QImage img(p, h->width, h->height, h->bpl, h->format, cleanupSharedImage, cleanupInfo);
+ return img;
+}
+
+
+QImage QSharedImageLoaderPrivate::load(const QString &path, QSharedImageLoader::ImageParameters *params)
+{
+#ifndef QT_NO_SHAREDMEMORY
+ Q_Q(QSharedImageLoader);
+
+ QImage nil;
+ if (path.isEmpty())
+ return nil;
+
+ QScopedPointer<QSharedMemory> shm(new QSharedMemory(q->key(path, params)));
+ bool locked = false;
+
+ if (!shm->attach(QSharedMemory::ReadOnly)) {
+ QImage img = q->loadFile(path, params);
+ if (img.isNull())
+ return nil;
+ int size = sizeof(SharedImageHeader) + img.byteCount();
+ if (shm->create(size)) {
+ qCDebug(lcSharedImage) << "Created new shm segment of size" << size << "for image" << path;
+ if (!shm->lock()) {
+ qCDebug(lcSharedImage) << "Lock1 failed!?" << shm->errorString();
+ return nil;
+ }
+ locked = true;
+ storeImageToMem(shm->data(), img);
+ } else if (shm->error() == QSharedMemory::AlreadyExists) {
+ // race handling: other process may have created the share while
+ // we loaded the image, so try again to just attach
+ if (!shm->attach(QSharedMemory::ReadOnly)) {
+ qCDebug(lcSharedImage) << "Attach to existing failed?" << shm->errorString();
+ return nil;
+ }
+ } else {
+ qCDebug(lcSharedImage) << "Create failed?" << shm->errorString();
+ return nil;
+ }
+ }
+
+ Q_ASSERT(shm->isAttached());
+
+ if (!locked) {
+ if (!shm->lock()) {
+ qCDebug(lcSharedImage) << "Lock2 failed!?" << shm->errorString();
+ return nil;
+ }
+ locked = true;
+ }
+
+ if (!verifyMem(shm->constData(), shm->size())) {
+ qCDebug(lcSharedImage) << "Verifymem failed!?";
+ shm->unlock();
+ return nil;
+ }
+
+ QSharedMemory *shmp = shm.take();
+ SharedImageInfo *sii = new SharedImageInfo;
+ sii->path = path;
+ sii->shmp = shmp;
+ QImage shImg = createImageFromMem(shmp->constData(), sii);
+
+ if (!shmp->unlock()) {
+ qCDebug(lcSharedImage) << "UnLock failed!?";
+ }
+
+ return shImg;
+#else
+ Q_UNUSED(path);
+ Q_UNUSED(params);
+ return QImage();
+#endif
+}
+
+
+QSharedImageLoader::QSharedImageLoader(QObject *parent)
+ : QObject(*new QSharedImageLoaderPrivate, parent)
+{
+}
+
+QSharedImageLoader::~QSharedImageLoader()
+{
+}
+
+QImage QSharedImageLoader::load(const QString &path, ImageParameters *params)
+{
+ Q_D(QSharedImageLoader);
+
+ return d->load(path, params);
+}
+
+QImage QSharedImageLoader::loadFile(const QString &path, ImageParameters *params)
+{
+ Q_UNUSED(params);
+
+ return QImage(path);
+}
+
+QString QSharedImageLoader::key(const QString &path, ImageParameters *params)
+{
+ Q_UNUSED(params);
+
+ return path;
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/imports/sharedimage/qsharedimageloader_p.h b/src/imports/sharedimage/qsharedimageloader_p.h
new file mode 100644
index 0000000000..afb50e5088
--- /dev/null
+++ b/src/imports/sharedimage/qsharedimageloader_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSHAREDIMAGELOADER_H
+#define QSHAREDIMAGELOADER_H
+
+#include <QImage>
+#include <QVariant>
+#include <QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(lcSharedImage);
+
+class QSharedImageLoaderPrivate;
+
+class QSharedImageLoader : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSharedImageLoader)
+
+public:
+ enum ImageParameter {
+ OriginalSize = 0,
+ RequestedSize,
+ NumImageParameters
+ };
+ typedef QVector<QVariant> ImageParameters;
+
+ QSharedImageLoader(QObject *parent = Q_NULLPTR);
+ ~QSharedImageLoader();
+
+ QImage load(const QString &path, ImageParameters *params = Q_NULLPTR);
+
+protected:
+ virtual QImage loadFile(const QString &path, ImageParameters *params);
+ virtual QString key(const QString &path, ImageParameters *params);
+
+private:
+ Q_DISABLE_COPY(QSharedImageLoader)
+};
+
+QT_END_NAMESPACE
+
+#endif // QSHAREDIMAGELOADER_H
diff --git a/src/imports/sharedimage/sharedimage.pro b/src/imports/sharedimage/sharedimage.pro
new file mode 100644
index 0000000000..523de66ac1
--- /dev/null
+++ b/src/imports/sharedimage/sharedimage.pro
@@ -0,0 +1,17 @@
+CXX_MODULE = qml
+TARGET = sharedimageplugin
+TARGETPATH = QtQuick/SharedImage
+IMPORT_VERSION = 1.0
+
+QT *= quick qml gui-private core-private
+
+SOURCES += \
+ plugin.cpp \
+ sharedimageprovider.cpp \
+ qsharedimageloader.cpp
+
+HEADERS += \
+ sharedimageprovider.h \
+ qsharedimageloader_p.h
+
+load(qml_plugin)
diff --git a/src/imports/sharedimage/sharedimageprovider.cpp b/src/imports/sharedimage/sharedimageprovider.cpp
new file mode 100644
index 0000000000..2dd3a130e9
--- /dev/null
+++ b/src/imports/sharedimage/sharedimageprovider.cpp
@@ -0,0 +1,156 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <sharedimageprovider.h>
+#include <qsharedimageloader_p.h>
+#include <qquickimageprovider.h>
+#include <private/qimage_p.h>
+#include <QImageReader>
+#include <QFileInfo>
+#include <QDir>
+
+class QuickSharedImageLoader : public QSharedImageLoader
+{
+ Q_OBJECT
+ friend class SharedImageProvider;
+
+public:
+ QuickSharedImageLoader(QObject *parent = Q_NULLPTR)
+ : QSharedImageLoader(parent)
+ {
+ }
+
+protected:
+ QImage loadFile(const QString &path, ImageParameters *params) override
+ {
+ QImageReader imgio(path);
+ QSize realSize = imgio.size();
+ QSize requestSize = params ? params->value(RequestedSize).toSize() : QSize();
+
+ // Following qquickpixmapcache's readImage, from here...
+ const bool force_scale = imgio.format() == "svg" || imgio.format() == "svgz";
+
+ if (requestSize.width() > 0 || requestSize.height() > 0) {
+ QSize s = realSize;
+ qreal ratio = 0.0;
+ if (requestSize.width() && (force_scale || requestSize.width() < s.width())) {
+ ratio = qreal(requestSize.width())/s.width();
+ }
+ if (requestSize.height() && (force_scale || requestSize.height() < s.height())) {
+ qreal hr = qreal(requestSize.height())/s.height();
+ if (ratio == 0.0 || hr < ratio)
+ ratio = hr;
+ }
+ if (ratio > 0.0) {
+ s.setHeight(qRound(s.height() * ratio));
+ s.setWidth(qRound(s.width() * ratio));
+ imgio.setScaledSize(s);
+ }
+ }
+ // ... to here
+
+ QImage image;
+ if (imgio.read(&image)) {
+ if (realSize.isEmpty())
+ realSize = image.size();
+ // Make sure we have acceptable format for texture uploader, or it will convert & lose sharing
+ // This mimics the testing & conversion normally done by the quick pixmapcache & texturefactory
+ if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_ARGB32_Premultiplied) {
+ QImage::Format newFmt = QImage::Format_RGB32;
+ if (image.hasAlphaChannel() && image.data_ptr()->checkForAlphaPixels())
+ newFmt = QImage::Format_ARGB32_Premultiplied;
+ qCDebug(lcSharedImage) << "Convert on load from format" << image.format() << "to" << newFmt;
+ image = image.convertToFormat(newFmt);
+ }
+ }
+
+ if (params && params->count() > OriginalSize)
+ params->replace(OriginalSize, realSize);
+
+ return image;
+ }
+
+ QString key(const QString &path, ImageParameters *params) override
+ {
+ QSize reqSz = params->value(RequestedSize).toSize();
+ if (!reqSz.isValid())
+ return path;
+
+ QString key = path + QStringLiteral("_%1x%2").arg(reqSz.width()).arg(reqSz.height());
+ qCDebug(lcSharedImage) << "KEY:" << key;
+ return key;
+ }
+};
+
+
+SharedImageProvider::SharedImageProvider()
+ : QQuickImageProvider(QQuickImageProvider::Image), loader(new QuickSharedImageLoader)
+{
+}
+
+QImage SharedImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize)
+{
+ QFileInfo fi(QDir::root(), id);
+ QString path = fi.canonicalFilePath();
+ if (path.isEmpty())
+ return QImage();
+
+ QSharedImageLoader::ImageParameters params(QSharedImageLoader::NumImageParameters);
+ params[QSharedImageLoader::RequestedSize].setValue(requestedSize);
+
+ QImage img = loader->load(path, &params);
+ if (img.isNull()) {
+ // May be sharing problem, fall back to normal local load
+ img = loader->loadFile(path, &params);
+ if (!img.isNull())
+ qCWarning(lcSharedImage) << "Sharing problem; loading" << id << "unshared";
+ }
+
+ //... QSize realSize = params.value(QSharedImageLoader::OriginalSize).toSize();
+ // quickpixmapcache's readImage() reports back the original size, prior to requestedSize scaling, in the *size
+ // parameter. That value is currently ignored by quick however, which only cares about the present size of the
+ // returned image. So handling and sharing of info on pre-scaled size is currently not implemented.
+ if (size) {
+ *size = img.size();
+ }
+
+ return img;
+}
+
+#include "sharedimageprovider.moc"
diff --git a/src/imports/sharedimage/sharedimageprovider.h b/src/imports/sharedimage/sharedimageprovider.h
new file mode 100644
index 0000000000..a2f6b6ef2f
--- /dev/null
+++ b/src/imports/sharedimage/sharedimageprovider.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the plugins 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SHAREDIMAGEPROVIDER_H
+#define SHAREDIMAGEPROVIDER_H
+
+#include <QQuickImageProvider>
+#include <QScopedPointer>
+
+class QuickSharedImageLoader;
+
+class SharedImageProvider : public QQuickImageProvider
+{
+public:
+ SharedImageProvider();
+
+ QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize) override;
+
+protected:
+ QScopedPointer<QuickSharedImageLoader> loader;
+};
+#endif // SHAREDIMAGEPROVIDER_H
diff --git a/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp b/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp
index 8be2a97034..9cf4184c20 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvgglyphnode.cpp
@@ -43,6 +43,7 @@
#include "qsgopenvghelpers.h"
#include "qsgopenvgfontglyphcache.h"
#include "qopenvgoffscreensurface.h"
+#include <cmath>
QT_BEGIN_NAMESPACE
@@ -143,7 +144,7 @@ void QSGOpenVGGlyphNode::render()
vgLoadMatrix(transform().constData());
} else {
vgLoadIdentity();
- offscreenSurface = new QOpenVGOffscreenSurface(QSize(ceil(m_bounding_rect.width()), ceil(m_bounding_rect.height())));
+ offscreenSurface = new QOpenVGOffscreenSurface(QSize(std::ceil(m_bounding_rect.width()), std::ceil(m_bounding_rect.height())));
offscreenSurface->makeCurrent();
}
diff --git a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp
index be437303bc..0bd51cbf46 100644
--- a/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp
+++ b/src/plugins/scenegraph/openvg/qsgopenvginternalrectanglenode.cpp
@@ -39,7 +39,7 @@
#include "qsgopenvginternalrectanglenode.h"
#include "qsgopenvghelpers.h"
-
+#include <cmath>
#include <VG/vgu.h>
QSGOpenVGInternalRectangleNode::QSGOpenVGInternalRectangleNode()
@@ -207,9 +207,9 @@ void QSGOpenVGInternalRectangleNode::render()
vgLoadIdentity();
if (m_radius > 0) {
// Fallback to rendering to an image for rounded rects with perspective transforms
- if (m_offscreenSurface == nullptr || m_offscreenSurface->size() != QSize(ceil(m_rect.width()), ceil(m_rect.height()))) {
+ if (m_offscreenSurface == nullptr || m_offscreenSurface->size() != QSize(std::ceil(m_rect.width()), std::ceil(m_rect.height()))) {
delete m_offscreenSurface;
- m_offscreenSurface = new QOpenVGOffscreenSurface(QSize(ceil(m_rect.width()), ceil(m_rect.height())));
+ m_offscreenSurface = new QOpenVGOffscreenSurface(QSize(std::ceil(m_rect.width()), std::ceil(m_rect.height())));
}
m_offscreenSurface->makeCurrent();
diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri
index 1de5dfa6fa..fa66d3a6e3 100644
--- a/src/qml/compiler/compiler.pri
+++ b/src/qml/compiler/compiler.pri
@@ -39,7 +39,10 @@ SOURCES += \
unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp
else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp
-qtConfig(qml-interpreter) {
+qtConfig(private_tests): LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD
+}
+
+qmldevtools_build|qtConfig(qml-interpreter) {
HEADERS += \
$$PWD/qv4instr_moth_p.h \
$$PWD/qv4isel_moth_p.h
@@ -48,6 +51,3 @@ qtConfig(qml-interpreter) {
$$PWD/qv4isel_moth.cpp
}
-
-qtConfig(private_tests): LIBS_PRIVATE += $$QMAKE_LIBS_DYNLOAD
-}
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp
index 54d0cb4f46..8a7507c92e 100644
--- a/src/qml/compiler/qqmlirbuilder.cpp
+++ b/src/qml/compiler/qqmlirbuilder.cpp
@@ -2061,4 +2061,156 @@ QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevis
return 0;
}
+IRLoader::IRLoader(const QV4::CompiledData::Unit *qmlData, QmlIR::Document *output)
+ : unit(qmlData)
+ , output(output)
+{
+ pool = output->jsParserEngine.pool();
+}
+
+void IRLoader::load()
+{
+ output->jsGenerator.stringTable.clear();
+ for (uint i = 0; i < unit->stringTableSize; ++i)
+ output->jsGenerator.stringTable.registerString(unit->stringAt(i));
+
+ for (quint32 i = 0; i < unit->nImports; ++i)
+ output->imports << unit->importAt(i);
+
+ if (unit->flags & QV4::CompiledData::Unit::IsSingleton) {
+ QmlIR::Pragma *p = New<QmlIR::Pragma>();
+ p->location = QV4::CompiledData::Location();
+ p->type = QmlIR::Pragma::PragmaSingleton;
+ output->pragmas << p;
+ }
+
+ output->indexOfRootObject = unit->indexOfRootObject;
+
+ for (uint i = 0; i < unit->nObjects; ++i) {
+ const QV4::CompiledData::Object *serializedObject = unit->objectAt(i);
+ QmlIR::Object *object = loadObject(serializedObject);
+ output->objects.append(object);
+ }
+}
+
+struct FakeExpression : public QQmlJS::AST::NullExpression
+{
+ FakeExpression(int start, int length)
+ : location(start, length)
+ {}
+
+ virtual QQmlJS::AST::SourceLocation firstSourceLocation() const
+ { return location; }
+
+ virtual QQmlJS::AST::SourceLocation lastSourceLocation() const
+ { return location; }
+
+private:
+ QQmlJS::AST::SourceLocation location;
+};
+
+QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedObject)
+{
+ QmlIR::Object *object = pool->New<QmlIR::Object>();
+ object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex);
+
+ object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias;
+ object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias;
+
+ object->location = serializedObject->location;
+ object->locationOfIdProperty = serializedObject->locationOfIdProperty;
+
+ QVector<int> functionIndices;
+ functionIndices.reserve(serializedObject->nFunctions + serializedObject->nBindings / 2);
+
+ for (uint i = 0; i < serializedObject->nBindings; ++i) {
+ QmlIR::Binding *b = pool->New<QmlIR::Binding>();
+ *static_cast<QV4::CompiledData::Binding*>(b) = serializedObject->bindingTable()[i];
+ object->bindings->append(b);
+ if (b->type == QV4::CompiledData::Binding::Type_Script) {
+ functionIndices.append(b->value.compiledScriptIndex);
+ b->value.compiledScriptIndex = functionIndices.count() - 1;
+
+ QmlIR::CompiledFunctionOrExpression *foe = pool->New<QmlIR::CompiledFunctionOrExpression>();
+ foe->disableAcceleratedLookups = true;
+ foe->nameIndex = 0;
+
+ QQmlJS::AST::ExpressionNode *expr;
+
+ if (b->stringIndex != quint32(0)) {
+ const int start = output->code.length();
+ const QString script = output->stringAt(b->stringIndex);
+ const int length = script.length();
+ output->code.append(script);
+ expr = new (pool) FakeExpression(start, length);
+ } else
+ expr = new (pool) QQmlJS::AST::NullExpression();
+ foe->node = new (pool) QQmlJS::AST::ExpressionStatement(expr); // dummy
+ object->functionsAndExpressions->append(foe);
+ }
+ }
+
+ Q_ASSERT(object->functionsAndExpressions->count == functionIndices.count());
+
+ for (uint i = 0; i < serializedObject->nSignals; ++i) {
+ const QV4::CompiledData::Signal *serializedSignal = serializedObject->signalAt(i);
+ QmlIR::Signal *s = pool->New<QmlIR::Signal>();
+ s->nameIndex = serializedSignal->nameIndex;
+ s->location = serializedSignal->location;
+ s->parameters = pool->New<QmlIR::PoolList<QmlIR::SignalParameter> >();
+
+ for (uint i = 0; i < serializedSignal->nParameters; ++i) {
+ QmlIR::SignalParameter *p = pool->New<QmlIR::SignalParameter>();
+ *static_cast<QV4::CompiledData::Parameter*>(p) = *serializedSignal->parameterAt(i);
+ s->parameters->append(p);
+ }
+
+ object->qmlSignals->append(s);
+ }
+
+ const QV4::CompiledData::Property *serializedProperty = serializedObject->propertyTable();
+ for (uint i = 0; i < serializedObject->nProperties; ++i, ++serializedProperty) {
+ QmlIR::Property *p = pool->New<QmlIR::Property>();
+ *static_cast<QV4::CompiledData::Property*>(p) = *serializedProperty;
+ object->properties->append(p);
+ }
+
+ QQmlJS::Engine *jsParserEngine = &output->jsParserEngine;
+
+ const QV4::CompiledData::LEUInt32 *functionIdx = serializedObject->functionOffsetTable();
+ for (uint i = 0; i < serializedObject->nFunctions; ++i, ++functionIdx) {
+ QmlIR::Function *f = pool->New<QmlIR::Function>();
+ const QV4::CompiledData::Function *compiledFunction = unit->functionAt(*functionIdx);
+
+ functionIndices.append(*functionIdx);
+ f->index = functionIndices.count() - 1;
+ f->location = compiledFunction->location;
+ f->nameIndex = compiledFunction->nameIndex;
+
+ QQmlJS::AST::FormalParameterList *paramList = 0;
+ const QV4::CompiledData::LEUInt32 *formalNameIdx = compiledFunction->formalsTable();
+ for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx) {
+ const QString formal = unit->stringAt(*formalNameIdx);
+ QStringRef paramNameRef = jsParserEngine->newStringRef(formal);
+
+ if (paramList)
+ paramList = new (pool) QQmlJS::AST::FormalParameterList(paramList, paramNameRef);
+ else
+ paramList = new (pool) QQmlJS::AST::FormalParameterList(paramNameRef);
+ }
+
+ if (paramList)
+ paramList = paramList->finish();
+
+ const QString name = unit->stringAt(compiledFunction->nameIndex);
+ f->functionDeclaration = new(pool) QQmlJS::AST::FunctionDeclaration(jsParserEngine->newStringRef(name), paramList, /*body*/0);
+
+ object->functions->append(f);
+ }
+
+ object->runtimeFunctionIndices.allocate(pool, functionIndices);
+
+ return object;
+}
+
#endif // V4_BOOTSTRAP
diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h
index 95756845c3..2022112e07 100644
--- a/src/qml/compiler/qqmlirbuilder_p.h
+++ b/src/qml/compiler/qqmlirbuilder_p.h
@@ -622,6 +622,21 @@ private:
int _importedScriptsTemp;
};
+struct IRLoader {
+ IRLoader(const QV4::CompiledData::Unit *unit, QmlIR::Document *output);
+
+ void load();
+
+private:
+ QmlIR::Object *loadObject(const QV4::CompiledData::Object *serializedObject);
+
+ template <typename _Tp> _Tp *New() { return pool->New<_Tp>(); }
+
+ const QV4::CompiledData::Unit *unit;
+ QmlIR::Document *output;
+ QQmlJS::MemoryPool *pool;
+};
+
} // namespace QmlIR
QT_END_NAMESPACE
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index ab2b0553a9..85267225be 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -57,12 +57,12 @@
QT_BEGIN_NAMESPACE
QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData,
- QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ QmlIR::Document *parsedQML, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
: resolvedTypes(resolvedTypeCache)
, engine(engine)
, typeData(typeData)
- , importCache(importCache)
+ , typeNameCache(typeNameCache)
, document(parsedQML)
{
}
@@ -138,7 +138,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
sss.scan();
}
- QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, importCache, &document->jsGenerator.stringTable);
+ QmlIR::JSCodeGen v4CodeGenerator(typeData->finalUrlString(), document->code, &document->jsModule, &document->jsParserEngine, document->program, typeNameCache, &document->jsGenerator.stringTable);
QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator);
if (!jsCodeGen.generateCodeForComponents())
return nullptr;
@@ -164,7 +164,7 @@ QV4::CompiledData::CompilationUnit *QQmlTypeCompiler::compile()
QV4::CompiledData::CompilationUnit *compilationUnit = document->javaScriptCompilationUnit;
compilationUnit = document->javaScriptCompilationUnit;
- compilationUnit->importCache = importCache;
+ compilationUnit->typeNameCache = typeNameCache;
compilationUnit->resolvedTypes = resolvedTypes;
compilationUnit->propertyCaches = std::move(m_propertyCaches);
Q_ASSERT(compilationUnit->propertyCaches.count() == static_cast<int>(compilationUnit->data->nObjects));
diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h
index de6abb4ced..2b59e7e42f 100644
--- a/src/qml/compiler/qqmltypecompiler_p.h
+++ b/src/qml/compiler/qqmltypecompiler_p.h
@@ -89,7 +89,7 @@ struct QQmlTypeCompiler
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeCompiler)
public:
- QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer<QQmlTypeNameCache> &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
+ QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
// --- interface used by QQmlPropertyCacheCreator
typedef QmlIR::Object CompiledObject;
@@ -139,7 +139,7 @@ private:
QList<QQmlError> errors;
QQmlEnginePrivate *engine;
QQmlTypeData *typeData;
- QQmlRefPointer<QQmlTypeNameCache> importCache;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QmlIR::Document *document;
// index is string index of type name (use obj->inheritedTypeNameIndex)
QHash<int, QQmlCustomParser*> customParsers;
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp
index e0def1021b..7d3ad38f97 100644
--- a/src/qml/compiler/qv4codegen.cpp
+++ b/src/qml/compiler/qv4codegen.cpp
@@ -526,21 +526,21 @@ IR::Expr *Codegen::subscript(IR::Expr *base, IR::Expr *index)
if (hasError)
return 0;
- if (! base->asTemp() || base->asArgLocal()) {
+ if (! base->asTemp() && !base->asArgLocal()) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), base);
base = _block->TEMP(t);
}
- if (! index->asTemp() || index->asArgLocal()) {
+ if (! index->asTemp() && !index->asArgLocal() && !index->asConst()) {
const unsigned t = _block->newTemp();
move(_block->TEMP(t), index);
index = _block->TEMP(t);
}
Q_ASSERT(base->asTemp() || base->asArgLocal());
- Q_ASSERT(index->asTemp() || index->asArgLocal());
- return _block->SUBSCRIPT(base->asTemp(), index->asTemp());
+ Q_ASSERT(index->asTemp() || index->asArgLocal() || index->asConst());
+ return _block->SUBSCRIPT(base, index);
}
IR::Expr *Codegen::argument(IR::Expr *expr)
@@ -611,7 +611,7 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right, const AS
if (IR::Const *c1 = left->asConst()) {
if (IR::Const *c2 = right->asConst()) {
- if (c1->type == IR::NumberType && c2->type == IR::NumberType) {
+ if ((c1->type & IR::NumberType) && (c2->type & IR::NumberType)) {
switch (op) {
case IR::OpAdd: return _block->CONST(IR::NumberType, c1->value + c2->value);
case IR::OpAnd: return _block->CONST(IR::BoolType, c1->value ? c2->value : 0);
@@ -659,20 +659,20 @@ IR::Expr *Codegen::binop(IR::AluOp op, IR::Expr *left, IR::Expr *right, const AS
}
}
- if (!left->asTemp() && !left->asArgLocal()) {
+ if (!left->asTemp() && !left->asArgLocal() && !left->asConst()) {
const unsigned t = _block->newTemp();
setLocation(move(_block->TEMP(t), left), loc);
left = _block->TEMP(t);
}
- if (!right->asTemp() && !right->asArgLocal()) {
+ if (!right->asTemp() && !right->asArgLocal() && !right->asConst()) {
const unsigned t = _block->newTemp();
setLocation(move(_block->TEMP(t), right), loc);
right = _block->TEMP(t);
}
- Q_ASSERT(left->asTemp() || left->asArgLocal());
- Q_ASSERT(right->asTemp() || right->asArgLocal());
+ Q_ASSERT(left->asTemp() || left->asArgLocal() || left->asConst());
+ Q_ASSERT(right->asTemp() || right->asArgLocal() || right->asConst());
return _block->BINOP(op, left, right);
}
@@ -842,9 +842,16 @@ void Codegen::variableDeclaration(VariableDeclaration *ast)
Q_ASSERT(expr.code);
initializer = *expr;
- int initialized = _block->newTemp();
- move(_block->TEMP(initialized), initializer);
- move(identifier(ast->name.toString(), ast->identifierToken.startLine, ast->identifierToken.startColumn), _block->TEMP(initialized));
+ IR::Expr *lhs = identifier(ast->name.toString(), ast->identifierToken.startLine,
+ ast->identifierToken.startColumn);
+
+ if (lhs->asArgLocal()) {
+ move(lhs, initializer);
+ } else {
+ int initialized = _block->newTemp();
+ move(_block->TEMP(initialized), initializer);
+ move(lhs, _block->TEMP(initialized));
+ }
}
void Codegen::variableDeclarationList(VariableDeclarationList *ast)
diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp
index 6aac111897..8f8d374e24 100644
--- a/src/qml/compiler/qv4compileddata.cpp
+++ b/src/qml/compiler/qv4compileddata.cpp
@@ -52,7 +52,6 @@
#include "qv4compilationunitmapper_p.h"
#include <QQmlPropertyMap>
#include <QDateTime>
-#include <QSaveFile>
#include <QFile>
#include <QFileInfo>
#include <QScopedValueRollback>
@@ -62,6 +61,7 @@
#include <private/qqmlirbuilder_p.h>
#include <QCoreApplication>
#include <QCryptographicHash>
+#include <QSaveFile>
#include <algorithm>
@@ -77,6 +77,27 @@ namespace QV4 {
namespace CompiledData {
+#ifdef V4_BOOTSTRAP
+static QString cacheFilePath(const QString &localSourcePath)
+{
+ const QString localCachePath = localSourcePath + QLatin1Char('c');
+ return localCachePath;
+}
+#else
+static QString cacheFilePath(const QUrl &url)
+{
+ const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
+ const QString localCachePath = localSourcePath + QLatin1Char('c');
+ if (QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable())
+ return localCachePath;
+ QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
+ fileNameHash.addData(localSourcePath.toUtf8());
+ QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
+ QDir::root().mkpath(directory);
+ return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + QFileInfo(localCachePath).completeSuffix();
+}
+#endif
+
#ifndef V4_BOOTSTRAP
CompilationUnit::CompilationUnit()
: data(0)
@@ -207,7 +228,7 @@ void CompilationUnit::unlink()
dependentScripts.at(ii)->release();
dependentScripts.clear();
- importCache = nullptr;
+ typeNameCache = nullptr;
qDeleteAll(resolvedTypes);
resolvedTypes.clear();
@@ -329,20 +350,68 @@ bool CompilationUnit::verifyChecksum(QQmlEngine *engine,
sizeof(data->dependencyMD5Checksum)) == 0;
}
-static QString cacheFilePath(const QUrl &url)
+bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString)
{
- const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- const QString localCachePath = localSourcePath + QLatin1Char('c');
- if (QFileInfo(QFileInfo(localSourcePath).dir().absolutePath()).isWritable())
- return localCachePath;
- QCryptographicHash fileNameHash(QCryptographicHash::Sha1);
- fileNameHash.addData(localSourcePath.toUtf8());
- QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/");
- QDir::root().mkpath(directory);
- return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + QFileInfo(localCachePath).completeSuffix();
+ if (!QQmlFile::isLocalFile(url)) {
+ *errorString = QStringLiteral("File has to be a local file.");
+ return false;
+ }
+
+ const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
+ QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
+
+ CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourcePath, errorString);
+ if (!mappedUnit)
+ return false;
+
+ const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
+ QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit);
+
+ if (sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
+ *errorString = QStringLiteral("QML source file has moved to a different location.");
+ return false;
+ }
+
+ {
+ const QString foundArchitecture = stringAt(data->architectureIndex);
+ const QString expectedArchitecture = QSysInfo::buildAbi();
+ if (foundArchitecture != expectedArchitecture) {
+ *errorString = QString::fromUtf8("Architecture mismatch. Found %1 expected %2").arg(foundArchitecture).arg(expectedArchitecture);
+ return false;
+ }
+ }
+
+ {
+ const QString foundCodeGenerator = stringAt(data->codeGeneratorIndex);
+ const QString expectedCodeGenerator = iselFactory->codeGeneratorName;
+ if (foundCodeGenerator != expectedCodeGenerator) {
+ *errorString = QString::fromUtf8("Code generator mismatch. Found code generated by %1 but expected %2").arg(foundCodeGenerator).arg(expectedCodeGenerator);
+ return false;
+ }
+ }
+
+ if (!memoryMapCode(errorString))
+ return false;
+
+ dataPtrChange.commit();
+ free(const_cast<Unit*>(oldDataPtr));
+ backingFile.reset(cacheFile.take());
+ return true;
+}
+
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ *errorString = QStringLiteral("Missing code mapping backend");
+ return false;
}
+#endif // V4_BOOTSTRAP
+
+#if defined(V4_BOOTSTRAP)
+bool CompilationUnit::saveToDisk(const QString &unitUrl, QString *errorString)
+#else
bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
+#endif
{
errorString->clear();
@@ -351,10 +420,12 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
return false;
}
+#if !defined(V4_BOOTSTRAP)
if (!QQmlFile::isLocalFile(unitUrl)) {
*errorString = QStringLiteral("File has to be a local file.");
return false;
}
+#endif
// Foo.qml -> Foo.qmlc
QSaveFile cacheFile(cacheFilePath(unitUrl));
@@ -390,78 +461,105 @@ bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString)
return true;
}
-bool CompilationUnit::loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString)
+void CompilationUnit::prepareCodeOffsetsForDiskStorage(Unit *unit)
{
- if (!QQmlFile::isLocalFile(url)) {
- *errorString = QStringLiteral("File has to be a local file.");
- return false;
- }
+ Q_UNUSED(unit);
+}
- const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url);
- QScopedPointer<CompilationUnitMapper> cacheFile(new CompilationUnitMapper());
+bool CompilationUnit::saveCodeToDisk(QIODevice *device, const Unit *unit, QString *errorString)
+{
+ Q_UNUSED(device);
+ Q_UNUSED(unit);
+ *errorString = QStringLiteral("Saving code to disk is not supported in this configuration");
+ return false;
+}
- CompiledData::Unit *mappedUnit = cacheFile->open(cacheFilePath(url), sourcePath, errorString);
- if (!mappedUnit)
- return false;
+Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
+{
+ if (!irDocument->javaScriptCompilationUnit->data)
+ return irDocument->jsGenerator.generateUnit(QV4::Compiler::JSUnitGenerator::GenerateWithoutStringTable);
- const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr;
- QScopedValueRollback<const Unit *> dataPtrChange(data, mappedUnit);
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit = irDocument->javaScriptCompilationUnit;
+ QV4::CompiledData::Unit *jsUnit = const_cast<QV4::CompiledData::Unit*>(irDocument->javaScriptCompilationUnit->data);
- if (sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) {
- *errorString = QStringLiteral("QML source file has moved to a different location.");
- return false;
- }
+ QV4::Compiler::StringTableGenerator &stringTable = irDocument->jsGenerator.stringTable;
- {
- const QString foundArchitecture = stringAt(data->architectureIndex);
- const QString expectedArchitecture = QSysInfo::buildAbi();
- if (foundArchitecture != expectedArchitecture) {
- *errorString = QString::fromUtf8("Architecture mismatch. Found %1 expected %2").arg(foundArchitecture).arg(expectedArchitecture);
- return false;
+ // Collect signals that have had a change in signature (from onClicked to onClicked(mouse) for example)
+ // and now need fixing in the QV4::CompiledData. Also register strings at the same time, to finalize
+ // the string table.
+ QVector<quint32> changedSignals;
+ QVector<QQmlJS::AST::FormalParameterList*> changedSignalParameters;
+ for (QmlIR::Object *o: qAsConst(irDocument->objects)) {
+ for (QmlIR::Binding *binding = o->firstBinding(); binding; binding = binding->next) {
+ if (!(binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression))
+ continue;
+
+ quint32 functionIndex = binding->value.compiledScriptIndex;
+ QmlIR::CompiledFunctionOrExpression *foe = o->functionsAndExpressions->slowAt(functionIndex);
+ if (!foe)
+ continue;
+
+ // save absolute index
+ changedSignals << o->runtimeFunctionIndices.at(functionIndex);
+
+ Q_ASSERT(foe->node);
+ Q_ASSERT(QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(foe->node));
+
+ QQmlJS::AST::FormalParameterList *parameters = QQmlJS::AST::cast<QQmlJS::AST::FunctionDeclaration*>(foe->node)->formals;
+ changedSignalParameters << parameters;
+
+ for (; parameters; parameters = parameters->next)
+ stringTable.registerString(parameters->name.toString());
}
}
- {
- const QString foundCodeGenerator = stringAt(data->codeGeneratorIndex);
- const QString expectedCodeGenerator = iselFactory->codeGeneratorName;
- if (foundCodeGenerator != expectedCodeGenerator) {
- *errorString = QString::fromUtf8("Code generator mismatch. Found code generated by %1 but expected %2").arg(foundCodeGenerator).arg(expectedCodeGenerator);
- return false;
+ QVector<quint32> signalParameterNameTable;
+ quint32 signalParameterNameTableOffset = jsUnit->unitSize;
+
+ // Update signal signatures
+ if (!changedSignals.isEmpty()) {
+ if (jsUnit == compilationUnit->data) {
+ char *unitCopy = (char*)malloc(jsUnit->unitSize);
+ memcpy(unitCopy, jsUnit, jsUnit->unitSize);
+ jsUnit = reinterpret_cast<QV4::CompiledData::Unit*>(unitCopy);
}
- }
- if (!memoryMapCode(errorString))
- return false;
+ for (int i = 0; i < changedSignals.count(); ++i) {
+ const uint functionIndex = changedSignals.at(i);
+ // The data is now read-write due to the copy above, so the const_cast is ok.
+ QV4::CompiledData::Function *function = const_cast<QV4::CompiledData::Function *>(jsUnit->functionAt(functionIndex));
+ Q_ASSERT(function->nFormals == quint32(0));
- dataPtrChange.commit();
- free(const_cast<Unit*>(oldDataPtr));
- backingFile.reset(cacheFile.take());
- return true;
-}
+ function->formalsOffset = signalParameterNameTableOffset - jsUnit->functionOffsetTable()[functionIndex];
-void CompilationUnit::prepareCodeOffsetsForDiskStorage(Unit *unit)
-{
- Q_UNUSED(unit);
-}
+ for (QQmlJS::AST::FormalParameterList *parameters = changedSignalParameters.at(i);
+ parameters; parameters = parameters->next) {
+ signalParameterNameTable.append(stringTable.getStringId(parameters->name.toString()));
+ function->nFormals = function->nFormals + 1;
+ }
-bool CompilationUnit::saveCodeToDisk(QIODevice *device, const Unit *unit, QString *errorString)
-{
- Q_UNUSED(device);
- Q_UNUSED(unit);
- *errorString = QStringLiteral("Saving code to disk is not supported in this configuration");
- return false;
-}
+ // Hack to ensure an activation is created.
+ function->flags |= QV4::CompiledData::Function::HasCatchOrWith | QV4::CompiledData::Function::HasDirectEval;
-bool CompilationUnit::memoryMapCode(QString *errorString)
-{
- *errorString = QStringLiteral("Missing code mapping backend");
- return false;
-}
-#endif // V4_BOOTSTRAP
+ signalParameterNameTableOffset += function->nFormals * sizeof(quint32);
+ }
+ }
-Unit *CompilationUnit::createUnitData(QmlIR::Document *irDocument)
-{
- return irDocument->jsGenerator.generateUnit(QV4::Compiler::JSUnitGenerator::GenerateWithoutStringTable);
+ if (!signalParameterNameTable.isEmpty()) {
+ Q_ASSERT(jsUnit != compilationUnit->data);
+ const uint signalParameterTableSize = signalParameterNameTable.count() * sizeof(quint32);
+ uint newSize = jsUnit->unitSize + signalParameterTableSize;
+ const uint oldSize = jsUnit->unitSize;
+ char *unitWithSignalParameters = (char*)realloc(jsUnit, newSize);
+ memcpy(unitWithSignalParameters + oldSize, signalParameterNameTable.constData(), signalParameterTableSize);
+ jsUnit = reinterpret_cast<QV4::CompiledData::Unit*>(unitWithSignalParameters);
+ jsUnit->unitSize = newSize;
+ }
+
+ if (jsUnit != compilationUnit->data)
+ jsUnit->flags &= ~QV4::CompiledData::Unit::StaticData;
+
+ return jsUnit;
}
QString Binding::valueAsString(const Unit *unit) const
@@ -624,7 +722,7 @@ static QByteArray ownLibraryChecksum()
if (checksumInitialized)
return libraryChecksum;
checksumInitialized = true;
-#if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST)
+#if defined(Q_OS_UNIX) && !defined(QT_NO_DYNAMIC_CAST) && !defined(Q_OS_INTEGRITY)
Dl_info libInfo;
if (dladdr(reinterpret_cast<const void *>(&ownLibraryChecksum), &libInfo) != 0) {
QFile library(QFile::decodeName(libInfo.dli_fname));
diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h
index 2682365182..13a0c4b075 100644
--- a/src/qml/compiler/qv4compileddata_p.h
+++ b/src/qml/compiler/qv4compileddata_p.h
@@ -71,7 +71,7 @@
QT_BEGIN_NAMESPACE
// Bump this whenever the compiler data structures change in an incompatible way.
-#define QV4_DATA_STRUCTURE_VERSION 0x08
+#define QV4_DATA_STRUCTURE_VERSION 0x09
class QIODevice;
class QQmlPropertyCache;
@@ -133,7 +133,7 @@ struct Location
QJsonPrivate::qle_bitfield<20, 12> column;
};
- Location() { line = 0; column = 0; }
+ Location() { line.val = 0; column.val = 0; }
inline bool operator<(const Location &other) const {
return line < other.line ||
@@ -153,7 +153,7 @@ struct RegExp
QJsonPrivate::qle_bitfield<4, 28> stringIndex;
};
- RegExp() { flags = 0; stringIndex = 0; }
+ RegExp() { flags.val = 0; stringIndex.val = 0; }
};
struct Lookup
@@ -171,7 +171,7 @@ struct Lookup
QJsonPrivate::qle_bitfield<4, 28> nameIndex;
};
- Lookup() { type_and_flags = 0; nameIndex = 0; }
+ Lookup() { type_and_flags.val = 0; nameIndex.val = 0; }
};
struct JSClassMember
@@ -625,7 +625,8 @@ struct Unit
StaticData = 0x4, // Unit data persistent in memory?
IsSingleton = 0x8,
IsSharedLibrary = 0x10, // .pragma shared?
- ContainsMachineCode = 0x20 // used to determine if we need to mmap with execute permissions
+ ContainsMachineCode = 0x20, // used to determine if we need to mmap with execute permissions
+ PendingTypeCompilation = 0x40 // the QML data structures present are incomplete and require type compilation
};
LEUInt32 flags;
LEUInt32 stringTableSize;
@@ -777,31 +778,7 @@ struct TypeReferenceMap : QHash<int, TypeReference>
};
#ifndef V4_BOOTSTRAP
-struct ResolvedTypeReference
-{
- ResolvedTypeReference()
- : type(0)
- , majorVersion(0)
- , minorVersion(0)
- , isFullyDynamicType(false)
- {}
-
- QQmlType *type;
- QQmlRefPointer<QQmlPropertyCache> typePropertyCache;
- QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
-
- int majorVersion;
- int minorVersion;
- // Types such as QQmlPropertyMap can add properties dynamically at run-time and
- // therefore cannot have a property cache installed when instantiated.
- bool isFullyDynamicType;
-
- QQmlPropertyCache *propertyCache() const;
- QQmlPropertyCache *createPropertyCache(QQmlEngine *);
- bool addToHash(QCryptographicHash *hash, QQmlEngine *engine);
-
- void doDynamicTypeCheck();
-};
+struct ResolvedTypeReference;
// map from name index
// While this could be a hash, a map is chosen here to provide a stable
// order, which is used to calculating a check-sum on dependent meta-objects.
@@ -841,10 +818,14 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
#ifndef V4_BOOTSTRAP
ExecutionEngine *engine;
+#endif
+
+ QV4::Heap::String **runtimeStrings; // Array
+
+#ifndef V4_BOOTSTRAP
QString fileName() const { return data->stringAt(data->sourceFileIndex); }
QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; }
- QV4::Heap::String **runtimeStrings; // Array
QV4::Lookup *runtimeLookups;
QV4::Value *runtimeRegularExpressions;
QV4::InternalClass **runtimeClasses;
@@ -855,7 +836,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
QQmlPropertyCacheVector propertyCaches;
QQmlPropertyCache *rootPropertyCache() const { return propertyCaches.at(data->indexOfRootObject); }
- QQmlRefPointer<QQmlTypeNameCache> importCache;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
// index is object index. This allows fast access to the
// property data when initializing bindings, avoiding expensive
@@ -918,17 +899,53 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit : public QQmlRefCount
void destroy() Q_DECL_OVERRIDE;
- bool saveToDisk(const QUrl &unitUrl, QString *errorString);
bool loadFromDisk(const QUrl &url, EvalISelFactory *iselFactory, QString *errorString);
protected:
virtual void linkBackendToEngine(QV4::ExecutionEngine *engine) = 0;
- virtual void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit);
- virtual bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString);
virtual bool memoryMapCode(QString *errorString);
#endif // V4_BOOTSTRAP
+
+public:
+#if defined(V4_BOOTSTRAP)
+ bool saveToDisk(const QString &unitUrl, QString *errorString);
+#else
+ bool saveToDisk(const QUrl &unitUrl, QString *errorString);
+#endif
+
+protected:
+ virtual void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit);
+ virtual bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString);
};
+#ifndef V4_BOOTSTRAP
+struct ResolvedTypeReference
+{
+ ResolvedTypeReference()
+ : type(0)
+ , majorVersion(0)
+ , minorVersion(0)
+ , isFullyDynamicType(false)
+ {}
+
+ QQmlType *type;
+ QQmlRefPointer<QQmlPropertyCache> typePropertyCache;
+ QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit;
+
+ int majorVersion;
+ int minorVersion;
+ // Types such as QQmlPropertyMap can add properties dynamically at run-time and
+ // therefore cannot have a property cache installed when instantiated.
+ bool isFullyDynamicType;
+
+ QQmlPropertyCache *propertyCache() const;
+ QQmlPropertyCache *createPropertyCache(QQmlEngine *);
+ bool addToHash(QCryptographicHash *hash, QQmlEngine *engine);
+
+ void doDynamicTypeCheck();
+};
+#endif
+
}
}
diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h
index ca4e0b73d4..53d9956315 100644
--- a/src/qml/compiler/qv4instr_moth_p.h
+++ b/src/qml/compiler/qv4instr_moth_p.h
@@ -52,10 +52,11 @@
//
#include <private/qv4global_p.h>
#include <private/qv4value_p.h>
-#include <private/qv4function_p.h>
#include <private/qv4runtime_p.h>
+#if !defined(V4_BOOTSTRAP)
QT_REQUIRE_CONFIG(qml_interpreter);
+#endif
QT_BEGIN_NAMESPACE
diff --git a/src/qml/compiler/qv4isel_moth.cpp b/src/qml/compiler/qv4isel_moth.cpp
index 9dbebd1128..04844302d9 100644
--- a/src/qml/compiler/qv4isel_moth.cpp
+++ b/src/qml/compiler/qv4isel_moth.cpp
@@ -39,15 +39,15 @@
#include "qv4isel_util_p.h"
#include "qv4isel_moth_p.h"
-#include "qv4vme_moth_p.h"
#include "qv4ssa_p.h"
-#include <private/qv4debugging_p.h>
-#include <private/qv4function_p.h>
-#include <private/qv4regexpobject_p.h>
#include <private/qv4compileddata_p.h>
-#include <private/qqmlengine_p.h>
#include <wtf/MathExtras.h>
+#if !defined(V4_BOOTSTRAP)
+#include "qv4vme_moth_p.h"
+#include <private/qv4function_p.h>
+#endif
+
#undef USE_TYPE_INFO
using namespace QV4;
@@ -1185,8 +1185,11 @@ void InstructionSelection::callBuiltinPushWithScope(IR::Expr *arg)
void InstructionSelection::callBuiltinPopScope()
{
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_GCC("-Wuninitialized")
Instruction::CallBuiltinPopScope call;
addInstruction(call);
+ QT_WARNING_POP
}
void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &name)
@@ -1335,8 +1338,11 @@ void InstructionSelection::callBuiltinSetupArgumentObject(IR::Expr *result)
void QV4::Moth::InstructionSelection::callBuiltinConvertThisToObject()
{
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_GCC("-Wuninitialized")
Instruction::CallBuiltinConvertThisToObject call;
addInstruction(call);
+ QT_WARNING_POP
}
ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &instr)
@@ -1425,6 +1431,8 @@ CompilationUnit::~CompilationUnit()
{
}
+#if !defined(V4_BOOTSTRAP)
+
void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine)
{
#ifdef MOTH_THREADED_INTERPRETER
@@ -1461,6 +1469,31 @@ void CompilationUnit::linkBackendToEngine(QV4::ExecutionEngine *engine)
}
}
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ Q_UNUSED(errorString);
+ codeRefs.resize(data->functionTableSize);
+
+ const char *basePtr = reinterpret_cast<const char *>(data);
+
+ for (uint i = 0; i < data->functionTableSize; ++i) {
+ const CompiledData::Function *compiledFunction = data->functionAt(i);
+ const char *codePtr = const_cast<const char *>(reinterpret_cast<const char *>(basePtr + compiledFunction->codeOffset));
+#ifdef MOTH_THREADED_INTERPRETER
+ // for the threaded interpreter we need to make a copy of the data because it needs to be
+ // modified for the instruction handler addresses.
+ QByteArray code(codePtr, compiledFunction->codeSize);
+#else
+ QByteArray code = QByteArray::fromRawData(codePtr, compiledFunction->codeSize);
+#endif
+ codeRefs[i] = code;
+ }
+
+ return true;
+}
+
+#endif // V4_BOOTSTRAP
+
void CompilationUnit::prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit)
{
const int codeAlignment = 16;
@@ -1482,7 +1515,7 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
QByteArray padding;
-#ifdef MOTH_THREADED_INTERPRETER
+#if defined(MOTH_THREADED_INTERPRETER) && !defined(V4_BOOTSTRAP)
// Map from instruction label back to instruction type. Only needed when persisting
// already linked compilation units;
QHash<void*, int> reverseInstructionMapping;
@@ -1511,7 +1544,7 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
QByteArray code = codeRefs.at(i);
-#ifdef MOTH_THREADED_INTERPRETER
+#if defined(MOTH_THREADED_INTERPRETER) && !defined(V4_BOOTSTRAP)
if (!reverseInstructionMapping.isEmpty()) {
char *codePtr = code.data(); // detaches
int index = 0;
@@ -1541,29 +1574,6 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
return true;
}
-bool CompilationUnit::memoryMapCode(QString *errorString)
-{
- Q_UNUSED(errorString);
- codeRefs.resize(data->functionTableSize);
-
- const char *basePtr = reinterpret_cast<const char *>(data);
-
- for (uint i = 0; i < data->functionTableSize; ++i) {
- const CompiledData::Function *compiledFunction = data->functionAt(i);
- const char *codePtr = const_cast<const char *>(reinterpret_cast<const char *>(basePtr + compiledFunction->codeOffset));
-#ifdef MOTH_THREADED_INTERPRETER
- // for the threaded interpreter we need to make a copy of the data because it needs to be
- // modified for the instruction handler addresses.
- QByteArray code(codePtr, compiledFunction->codeSize);
-#else
- QByteArray code = QByteArray::fromRawData(codePtr, compiledFunction->codeSize);
-#endif
- codeRefs[i] = code;
- }
-
- return true;
-}
-
QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory::createUnitForLoading()
{
QQmlRefPointer<CompiledData::CompilationUnit> result;
diff --git a/src/qml/compiler/qv4isel_moth_p.h b/src/qml/compiler/qv4isel_moth_p.h
index afe5fe342e..41469f1985 100644
--- a/src/qml/compiler/qv4isel_moth_p.h
+++ b/src/qml/compiler/qv4isel_moth_p.h
@@ -59,7 +59,9 @@
#include <private/qv4value_p.h>
#include "qv4instr_moth_p.h"
+#if !defined(V4_BOOTSTRAP)
QT_REQUIRE_CONFIG(qml_interpreter);
+#endif
QT_BEGIN_NAMESPACE
@@ -69,10 +71,12 @@ namespace Moth {
struct CompilationUnit : public QV4::CompiledData::CompilationUnit
{
virtual ~CompilationUnit();
+#if !defined(V4_BOOTSTRAP)
void linkBackendToEngine(QV4::ExecutionEngine *engine) Q_DECL_OVERRIDE;
+ bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
+#endif
void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit) Q_DECL_OVERRIDE;
bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString) Q_DECL_OVERRIDE;
- bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
QVector<QByteArray> codeRefs;
diff --git a/src/qml/compiler/qv4jsir_p.h b/src/qml/compiler/qv4jsir_p.h
index 73aa6c4975..04bc3d86e5 100644
--- a/src/qml/compiler/qv4jsir_p.h
+++ b/src/qml/compiler/qv4jsir_p.h
@@ -315,20 +315,20 @@ struct Q_AUTOTEST_EXPORT Expr {
Expr(ExprKind exprKind): type(UnknownType), exprKind(exprKind) {}
bool isLValue() const;
- Const *asConst() { return as<Const>(); }
- String *asString() { return as<String>(); }
- RegExp *asRegExp() { return as<RegExp>(); }
- Name *asName() { return as<Name>(); }
- Temp *asTemp() { return as<Temp>(); }
- ArgLocal *asArgLocal() { return as<ArgLocal>(); }
- Closure *asClosure() { return as<Closure>(); }
- Convert *asConvert() { return as<Convert>(); }
- Unop *asUnop() { return as<Unop>(); }
- Binop *asBinop() { return as<Binop>(); }
- Call *asCall() { return as<Call>(); }
- New *asNew() { return as<New>(); }
- Subscript *asSubscript() { return as<Subscript>(); }
- Member *asMember() { return as<Member>(); }
+ Const *asConst();
+ String *asString();
+ RegExp *asRegExp();
+ Name *asName();
+ Temp *asTemp();
+ ArgLocal *asArgLocal();
+ Closure *asClosure();
+ Convert *asConvert();
+ Unop *asUnop();
+ Binop *asBinop();
+ Call *asCall();
+ New *asNew();
+ Subscript *asSubscript();
+ Member *asMember();
};
#define EXPR_VISIT_ALL_KINDS(e) \
@@ -773,12 +773,12 @@ struct Stmt {
Stmt *asTerminator();
- Exp *asExp() { return as<Exp>(); }
- Move *asMove() { return as<Move>(); }
- Jump *asJump() { return as<Jump>(); }
- CJump *asCJump() { return as<CJump>(); }
- Ret *asRet() { return as<Ret>(); }
- Phi *asPhi() { return as<Phi>(); }
+ Exp *asExp();
+ Move *asMove();
+ Jump *asJump();
+ CJump *asCJump();
+ Ret *asRet();
+ Phi *asPhi();
int id() const { return _id; }
@@ -1720,6 +1720,28 @@ inline Stmt *BasicBlock::RET(Expr *expr)
return s;
}
+inline Const *Expr::asConst() { return as<Const>(); }
+inline String *Expr::asString() { return as<String>(); }
+inline RegExp *Expr::asRegExp() { return as<RegExp>(); }
+inline Name *Expr::asName() { return as<Name>(); }
+inline Temp *Expr::asTemp() { return as<Temp>(); }
+inline ArgLocal *Expr::asArgLocal() { return as<ArgLocal>(); }
+inline Closure *Expr::asClosure() { return as<Closure>(); }
+inline Convert *Expr::asConvert() { return as<Convert>(); }
+inline Unop *Expr::asUnop() { return as<Unop>(); }
+inline Binop *Expr::asBinop() { return as<Binop>(); }
+inline Call *Expr::asCall() { return as<Call>(); }
+inline New *Expr::asNew() { return as<New>(); }
+inline Subscript *Expr::asSubscript() { return as<Subscript>(); }
+inline Member *Expr::asMember() { return as<Member>(); }
+
+inline Exp *Stmt::asExp() { return as<Exp>(); }
+inline Move *Stmt::asMove() { return as<Move>(); }
+inline Jump *Stmt::asJump() { return as<Jump>(); }
+inline CJump *Stmt::asCJump() { return as<CJump>(); }
+inline Ret *Stmt::asRet() { return as<Ret>(); }
+inline Phi *Stmt::asPhi() { return as<Phi>(); }
+
} // end of namespace IR
} // end of namespace QV4
diff --git a/src/qml/compiler/qv4ssa.cpp b/src/qml/compiler/qv4ssa.cpp
index 1d512711b8..10f0bbcf8f 100644
--- a/src/qml/compiler/qv4ssa.cpp
+++ b/src/qml/compiler/qv4ssa.cpp
@@ -5123,7 +5123,7 @@ void LifeTimeInterval::setFrom(int from) {
Q_ASSERT(from > 0);
if (_ranges.isEmpty()) { // this is the case where there is no use, only a define
- _ranges.prepend(Range(from, from));
+ _ranges.prepend(LifeTimeIntervalRange(from, from));
if (_end == InvalidPosition)
_end = from;
} else {
@@ -5137,17 +5137,17 @@ void LifeTimeInterval::addRange(int from, int to) {
Q_ASSERT(to >= from);
if (_ranges.isEmpty()) {
- _ranges.prepend(Range(from, to));
+ _ranges.prepend(LifeTimeIntervalRange(from, to));
_end = to;
return;
}
- Range *p = &_ranges.first();
+ LifeTimeIntervalRange *p = &_ranges.first();
if (to + 1 >= p->start && p->end + 1 >= from) {
p->start = qMin(p->start, from);
p->end = qMax(p->end, to);
while (_ranges.count() > 1) {
- Range *p1 = p + 1;
+ LifeTimeIntervalRange *p1 = p + 1;
if (p->end + 1 < p1->start || p1->end + 1 < p->start)
break;
p1->start = qMin(p->start, p1->start);
@@ -5157,10 +5157,10 @@ void LifeTimeInterval::addRange(int from, int to) {
}
} else {
if (to < p->start) {
- _ranges.prepend(Range(from, to));
+ _ranges.prepend(LifeTimeIntervalRange(from, to));
} else {
Q_ASSERT(from > _ranges.last().end);
- _ranges.push_back(Range(from, to));
+ _ranges.push_back(LifeTimeIntervalRange(from, to));
}
}
@@ -5206,7 +5206,7 @@ LifeTimeInterval LifeTimeInterval::split(int atPosition, int newStart)
} else {
// find the first range where the temp will get active again:
while (!newInterval._ranges.isEmpty()) {
- const Range &range = newInterval._ranges.first();
+ const LifeTimeIntervalRange &range = newInterval._ranges.first();
if (range.start > newStart) {
// The split position is before the start of the range. Either we managed to skip
// over the correct range, or we got an invalid split request. Either way, this
diff --git a/src/qml/compiler/qv4ssa_p.h b/src/qml/compiler/qv4ssa_p.h
index db8b6edd1a..c07abd04c4 100644
--- a/src/qml/compiler/qv4ssa_p.h
+++ b/src/qml/compiler/qv4ssa_p.h
@@ -63,20 +63,28 @@ class QQmlEnginePrivate;
namespace QV4 {
namespace IR {
-class Q_AUTOTEST_EXPORT LifeTimeInterval {
-public:
- struct Range {
- int start;
- int end;
+struct LifeTimeIntervalRange {
+ int start;
+ int end;
- Range(int start = InvalidPosition, int end = InvalidPosition)
- : start(start)
- , end(end)
- {}
+ LifeTimeIntervalRange(int start = -1, int end = -1)
+ : start(start)
+ , end(end)
+ {}
- bool covers(int position) const { return start <= position && position <= end; }
- };
- typedef QVarLengthArray<Range, 4> Ranges;
+ bool covers(int position) const { return start <= position && position <= end; }
+};
+} // IR namespace
+} // QV4 namespace
+
+Q_DECLARE_TYPEINFO(QV4::IR::LifeTimeIntervalRange, Q_PRIMITIVE_TYPE);
+
+namespace QV4 {
+namespace IR {
+
+class Q_AUTOTEST_EXPORT LifeTimeInterval {
+public:
+ typedef QVarLengthArray<LifeTimeIntervalRange, 4> Ranges;
private:
Temp _temp;
@@ -137,7 +145,7 @@ public:
// Validate the new range
if (_end != InvalidPosition) {
Q_ASSERT(!_ranges.isEmpty());
- for (const Range &range : qAsConst(_ranges)) {
+ for (const LifeTimeIntervalRange &range : qAsConst(_ranges)) {
Q_ASSERT(range.start >= 0);
Q_ASSERT(range.end >= 0);
Q_ASSERT(range.start <= range.end);
@@ -457,7 +465,6 @@ protected:
Q_DECLARE_TYPEINFO(QV4::IR::LifeTimeInterval, Q_MOVABLE_TYPE);
-Q_DECLARE_TYPEINFO(QV4::IR::LifeTimeInterval::Range, Q_PRIMITIVE_TYPE);
QT_END_NAMESPACE
diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h
index 3a507bef74..41fb2c5b7b 100644
--- a/src/qml/debugger/qqmlprofiler_p.h
+++ b/src/qml/debugger/qqmlprofiler_p.h
@@ -73,7 +73,7 @@ struct QQmlProfiler {};
struct QQmlBindingProfiler
{
- QQmlBindingProfiler(quintptr, QQmlBinding *, QV4::FunctionObject *) {}
+ QQmlBindingProfiler(quintptr, QV4::Function *) {}
};
struct QQmlHandlingSignalProfiler
diff --git a/src/qml/doc/src/qmltypereference.qdoc b/src/qml/doc/src/qmltypereference.qdoc
index f32574fcc1..b2bb9ebd18 100644
--- a/src/qml/doc/src/qmltypereference.qdoc
+++ b/src/qml/doc/src/qmltypereference.qdoc
@@ -89,7 +89,7 @@ provided:
\ingroup qtquickbasictypes
\brief a date value.
-The \c date type refers to a date value.
+The \c date type refers to a date value, including the time of the day.
To create a \c date value, specify it as a "YYYY-MM-DD" string:
@@ -100,7 +100,7 @@ MyDatePicker { minDate: "2000-01-01"; maxDate: "2020-12-31" }
To read a date value returned from a C++ extension class, use
\l{QtQml::Qt::formatDate()}{Qt.formatDate()} and \l{QtQml::Qt::formatDateTime()}{Qt.formatDateTime()}.
-When integrating with C++, note that any QDate value
+When integrating with C++, note that any QDate or QDateTime value
\l{qtqml-cppintegration-data.html}{passed into QML from C++} is automatically
converted into a \c date value, and vice-versa.
diff --git a/src/qml/jit/qv4assembler.cpp b/src/qml/jit/qv4assembler.cpp
index 018396318e..646d9a8871 100644
--- a/src/qml/jit/qv4assembler.cpp
+++ b/src/qml/jit/qv4assembler.cpp
@@ -39,11 +39,6 @@
#include "qv4isel_masm_p.h"
#include "qv4runtime_p.h"
-#include "qv4object_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4regexpobject_p.h"
-#include "qv4lookup_p.h"
-#include "qv4function_p.h"
#include "qv4ssa_p.h"
#include "qv4regalloc_p.h"
#include "qv4assembler_p.h"
@@ -51,6 +46,10 @@
#include <assembler/LinkBuffer.h>
#include <WTFStubs.h>
+#if !defined(V4_BOOTSTRAP)
+#include "qv4function_p.h"
+#endif
+
#include <iostream>
#include <QBuffer>
#include <QCoreApplication>
@@ -68,6 +67,8 @@ CompilationUnit::~CompilationUnit()
{
}
+#if !defined(V4_BOOTSTRAP)
+
void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
{
runtimeFunctions.resize(data->functionTableSize);
@@ -81,6 +82,26 @@ void CompilationUnit::linkBackendToEngine(ExecutionEngine *engine)
}
}
+bool CompilationUnit::memoryMapCode(QString *errorString)
+{
+ Q_UNUSED(errorString);
+ codeRefs.resize(data->functionTableSize);
+
+ const char *basePtr = reinterpret_cast<const char *>(data);
+
+ for (uint i = 0; i < data->functionTableSize; ++i) {
+ const CompiledData::Function *compiledFunction = data->functionAt(i);
+ void *codePtr = const_cast<void *>(reinterpret_cast<const void *>(basePtr + compiledFunction->codeOffset));
+ JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr));
+ JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize);
+ codeRefs[i] = codeRef;
+ }
+
+ return true;
+}
+
+#endif // !defined(V4_BOOTSTRAP)
+
void CompilationUnit::prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit)
{
const int codeAlignment = 16;
@@ -128,27 +149,11 @@ bool CompilationUnit::saveCodeToDisk(QIODevice *device, const CompiledData::Unit
return true;
}
-bool CompilationUnit::memoryMapCode(QString *errorString)
-{
- Q_UNUSED(errorString);
- codeRefs.resize(data->functionTableSize);
-
- const char *basePtr = reinterpret_cast<const char *>(data);
-
- for (uint i = 0; i < data->functionTableSize; ++i) {
- const CompiledData::Function *compiledFunction = data->functionAt(i);
- void *codePtr = const_cast<void *>(reinterpret_cast<const void *>(basePtr + compiledFunction->codeOffset));
- JSC::MacroAssemblerCodeRef codeRef = JSC::MacroAssemblerCodeRef::createSelfManagedCodeRef(JSC::MacroAssemblerCodePtr(codePtr));
- JSC::ExecutableAllocator::makeExecutable(codePtr, compiledFunction->codeSize);
- codeRefs[i] = codeRef;
- }
-
- return true;
-}
-
-const Assembler::VoidType Assembler::Void;
+template <typename TargetConfiguration>
+const typename Assembler<TargetConfiguration>::VoidType Assembler<TargetConfiguration>::Void;
-Assembler::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator)
+template <typename TargetConfiguration>
+Assembler<TargetConfiguration>::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator)
: _function(function)
, _nextBlock(0)
, _executableAllocator(executableAllocator)
@@ -159,14 +164,16 @@ Assembler::Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function*
_labelPatches.resize(_function->basicBlockCount());
}
-void Assembler::registerBlock(IR::BasicBlock* block, IR::BasicBlock *nextBlock)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::registerBlock(IR::BasicBlock* block, IR::BasicBlock *nextBlock)
{
_addrs[block->index()] = label();
catchBlock = block->catchBlock;
_nextBlock = nextBlock;
}
-void Assembler::jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target)
{
Q_UNUSED(current);
@@ -174,12 +181,14 @@ void Assembler::jumpToBlock(IR::BasicBlock* current, IR::BasicBlock *target)
_patches[target->index()].push_back(jump());
}
-void Assembler::addPatch(IR::BasicBlock* targetBlock, Jump targetJump)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::addPatch(IR::BasicBlock* targetBlock, Jump targetJump)
{
_patches[targetBlock->index()].push_back(targetJump);
}
-void Assembler::addPatch(DataLabelPtr patch, Label target)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::addPatch(DataLabelPtr patch, Label target)
{
DataLabelPatch p;
p.dataLabel = patch;
@@ -187,37 +196,21 @@ void Assembler::addPatch(DataLabelPtr patch, Label target)
_dataLabelPatches.push_back(p);
}
-void Assembler::addPatch(DataLabelPtr patch, IR::BasicBlock *target)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::addPatch(DataLabelPtr patch, IR::BasicBlock *target)
{
_labelPatches[target->index()].push_back(patch);
}
-void Assembler::generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock,
IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
{
- generateCJumpOnCompare(NotEqual, reg, TrustedImm32(0), currentBlock, trueBlock, falseBlock);
-}
-
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
-void Assembler::generateCJumpOnCompare(RelationalCondition cond,
- RegisterID left,
- TrustedImm64 right,
- IR::BasicBlock *currentBlock,
- IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock)
-{
- if (trueBlock == _nextBlock) {
- Jump target = branch64(invert(cond), left, right);
- addPatch(falseBlock, target);
- } else {
- Jump target = branch64(cond, left, right);
- addPatch(trueBlock, target);
- jumpToBlock(currentBlock, falseBlock);
- }
+ generateCJumpOnCompare(RelationalCondition::NotEqual, reg, TrustedImm32(0), currentBlock, trueBlock, falseBlock);
}
-#endif
-void Assembler::generateCJumpOnCompare(RelationalCondition cond,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::generateCJumpOnCompare(RelationalCondition cond,
RegisterID left,
TrustedImm32 right,
IR::BasicBlock *currentBlock,
@@ -234,7 +227,8 @@ void Assembler::generateCJumpOnCompare(RelationalCondition cond,
}
}
-void Assembler::generateCJumpOnCompare(RelationalCondition cond,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::generateCJumpOnCompare(RelationalCondition cond,
RegisterID left,
RegisterID right,
IR::BasicBlock *currentBlock,
@@ -251,7 +245,8 @@ void Assembler::generateCJumpOnCompare(RelationalCondition cond,
}
}
-Assembler::Pointer Assembler::loadAddress(RegisterID tmp, IR::Expr *e)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadAddress(RegisterID tmp, IR::Expr *e)
{
IR::Temp *t = e->asTemp();
if (t)
@@ -260,7 +255,8 @@ Assembler::Pointer Assembler::loadAddress(RegisterID tmp, IR::Expr *e)
return loadArgLocalAddress(tmp, e->asArgLocal());
}
-Assembler::Pointer Assembler::loadTempAddress(IR::Temp *t)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadTempAddress(IR::Temp *t)
{
if (t->kind == IR::Temp::StackSlot)
return stackSlotPointer(t);
@@ -268,7 +264,8 @@ Assembler::Pointer Assembler::loadTempAddress(IR::Temp *t)
Q_UNREACHABLE();
}
-Assembler::Pointer Assembler::loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadArgLocalAddress(RegisterID baseReg, IR::ArgLocal *al)
{
int32_t offset = 0;
int scope = al->scope;
@@ -298,7 +295,8 @@ Assembler::Pointer Assembler::loadArgLocalAddress(RegisterID baseReg, IR::ArgLoc
return Pointer(baseReg, offset);
}
-Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &string)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Pointer Assembler<TargetConfiguration>::loadStringAddress(RegisterID reg, const QString &string)
{
loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, compilationUnit)), Assembler::ScratchRegister);
@@ -307,12 +305,14 @@ Assembler::Pointer Assembler::loadStringAddress(RegisterID reg, const QString &s
return Pointer(reg, id * sizeof(QV4::String*));
}
-Assembler::Address Assembler::loadConstant(IR::Const *c, RegisterID baseReg)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(IR::Const *c, RegisterID baseReg)
{
return loadConstant(convertToValue(c), baseReg);
}
-Assembler::Address Assembler::loadConstant(const Primitive &v, RegisterID baseReg)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Address Assembler<TargetConfiguration>::loadConstant(const Primitive &v, RegisterID baseReg)
{
loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), baseReg);
loadPtr(Address(baseReg, qOffsetOf(QV4::Heap::ExecutionContext, constantTable)), baseReg);
@@ -320,33 +320,36 @@ Assembler::Address Assembler::loadConstant(const Primitive &v, RegisterID baseRe
return Address(baseReg, index * sizeof(QV4::Value));
}
-void Assembler::loadStringRef(RegisterID reg, const QString &string)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::loadStringRef(RegisterID reg, const QString &string)
{
const int id = _jsGenerator->registerString(string);
move(TrustedImm32(id), reg);
}
-void Assembler::storeValue(QV4::Primitive value, IR::Expr *destination)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::storeValue(QV4::Primitive value, IR::Expr *destination)
{
Address addr = loadAddress(ScratchRegister, destination);
storeValue(value, addr);
}
-void Assembler::enterStandardStackFrame(const RegisterInformation &regularRegistersToSave,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::enterStandardStackFrame(const RegisterInformation &regularRegistersToSave,
const RegisterInformation &fpRegistersToSave)
{
platformEnterStandardStackFrame(this);
- move(StackPointerRegister, FramePointerRegister);
+ move(StackPointerRegister, JITTargetPlatform::FramePointerRegister);
const int frameSize = _stackLayout->calculateStackFrameSize();
subPtr(TrustedImm32(frameSize), StackPointerRegister);
- Address slotAddr(FramePointerRegister, 0);
+ Address slotAddr(JITTargetPlatform::FramePointerRegister, 0);
for (int i = 0, ei = fpRegistersToSave.size(); i < ei; ++i) {
Q_ASSERT(fpRegistersToSave.at(i).isFloatingPoint());
slotAddr.offset -= sizeof(double);
- JSC::MacroAssembler::storeDouble(fpRegistersToSave.at(i).reg<FPRegisterID>(), slotAddr);
+ TargetConfiguration::MacroAssembler::storeDouble(fpRegistersToSave.at(i).reg<FPRegisterID>(), slotAddr);
}
for (int i = 0, ei = regularRegistersToSave.size(); i < ei; ++i) {
Q_ASSERT(regularRegistersToSave.at(i).isRegularRegister());
@@ -355,10 +358,11 @@ void Assembler::enterStandardStackFrame(const RegisterInformation &regularRegist
}
}
-void Assembler::leaveStandardStackFrame(const RegisterInformation &regularRegistersToSave,
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::leaveStandardStackFrame(const RegisterInformation &regularRegistersToSave,
const RegisterInformation &fpRegistersToSave)
{
- Address slotAddr(FramePointerRegister, -regularRegistersToSave.size() * RegisterSize - fpRegistersToSave.size() * sizeof(double));
+ Address slotAddr(JITTargetPlatform::FramePointerRegister, -regularRegistersToSave.size() * RegisterSize - fpRegistersToSave.size() * sizeof(double));
// restore the callee saved registers
for (int i = regularRegistersToSave.size() - 1; i >= 0; --i) {
@@ -368,7 +372,7 @@ void Assembler::leaveStandardStackFrame(const RegisterInformation &regularRegist
}
for (int i = fpRegistersToSave.size() - 1; i >= 0; --i) {
Q_ASSERT(fpRegistersToSave.at(i).isFloatingPoint());
- JSC::MacroAssembler::loadDouble(slotAddr, fpRegistersToSave.at(i).reg<FPRegisterID>());
+ TargetConfiguration::MacroAssembler::loadDouble(slotAddr, fpRegistersToSave.at(i).reg<FPRegisterID>());
slotAddr.offset += sizeof(double);
}
@@ -393,7 +397,8 @@ void Assembler::leaveStandardStackFrame(const RegisterInformation &regularRegist
// Try to load the source expression into the destination FP register. This assumes that two
// general purpose (integer) registers are available: the ScratchRegister and the
// ReturnValueRegister. It returns a Jump if no conversion can be performed.
-Assembler::Jump Assembler::genTryDoubleConversion(IR::Expr *src, Assembler::FPRegisterID dest)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::genTryDoubleConversion(IR::Expr *src, FPRegisterID dest)
{
switch (src->type) {
case IR::DoubleType:
@@ -436,11 +441,10 @@ Assembler::Jump Assembler::genTryDoubleConversion(IR::Expr *src, Assembler::FPRe
isNoInt.link(this);
#ifdef QV4_USE_64_BIT_VALUE_ENCODING
rshift32(TrustedImm32(Value::IsDoubleTag_Shift), ScratchRegister);
- Assembler::Jump isNoDbl = branch32(Equal, ScratchRegister, TrustedImm32(0));
+ Assembler::Jump isNoDbl = branch32(RelationalCondition::Equal, JITTargetPlatform::ScratchRegister, TrustedImm32(0));
#else
and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister);
- Assembler::Jump isNoDbl = branch32(Assembler::Equal, Assembler::ScratchRegister,
- Assembler::TrustedImm32(Value::NotDouble_Mask));
+ Assembler::Jump isNoDbl = branch32(RelationalCondition::Equal, JITTargetPlatform::ScratchRegister, TrustedImm32(Value::NotDouble_Mask));
#endif
toDoubleRegister(src, dest);
intDone.link(this);
@@ -448,10 +452,11 @@ Assembler::Jump Assembler::genTryDoubleConversion(IR::Expr *src, Assembler::FPRe
return isNoDbl;
}
-Assembler::Jump Assembler::branchDouble(bool invertCondition, IR::AluOp op,
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::branchDouble(bool invertCondition, IR::AluOp op,
IR::Expr *left, IR::Expr *right)
{
- Assembler::DoubleCondition cond;
+ DoubleCondition cond;
switch (op) {
case IR::OpGt: cond = Assembler::DoubleGreaterThan; break;
case IR::OpLt: cond = Assembler::DoubleLessThan; break;
@@ -465,12 +470,13 @@ Assembler::Jump Assembler::branchDouble(bool invertCondition, IR::AluOp op,
Q_UNREACHABLE();
}
if (invertCondition)
- cond = JSC::MacroAssembler::invert(cond);
+ cond = TargetConfiguration::MacroAssembler::invert(cond);
- return JSC::MacroAssembler::branchDouble(cond, toDoubleRegister(left, FPGpr0), toDoubleRegister(right, FPGpr1));
+ return TargetConfiguration::MacroAssembler::branchDouble(cond, toDoubleRegister(left, FPGpr0), toDoubleRegister(right, JITTargetPlatform::FPGpr1));
}
-Assembler::Jump Assembler::branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right)
+template <typename TargetConfiguration>
+typename Assembler<TargetConfiguration>::Jump Assembler<TargetConfiguration>::branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right)
{
Assembler::RelationalCondition cond;
switch (op) {
@@ -486,18 +492,51 @@ Assembler::Jump Assembler::branchInt32(bool invertCondition, IR::AluOp op, IR::E
Q_UNREACHABLE();
}
if (invertCondition)
- cond = JSC::MacroAssembler::invert(cond);
+ cond = TargetConfiguration::MacroAssembler::invert(cond);
- return JSC::MacroAssembler::branch32(cond,
- toInt32Register(left, Assembler::ScratchRegister),
- toInt32Register(right, Assembler::ReturnValueRegister));
+ return TargetConfiguration::MacroAssembler::branch32(cond,
+ toInt32Register(left, Assembler::ScratchRegister),
+ toInt32Register(right, Assembler::ReturnValueRegister));
}
-void Assembler::setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave)
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave)
{
_stackLayout.reset(new StackLayout(_function, maxArgCountForBuiltins, regularRegistersToSave, fpRegistersToSave));
}
+template <typename TargetConfiguration>
+void Assembler<TargetConfiguration>::returnFromFunction(IR::Ret *s, RegisterInformation regularRegistersToSave, RegisterInformation fpRegistersToSave)
+{
+ if (!s) {
+ // this only happens if the method doesn't have a return statement and can
+ // only exit through an exception
+ } else if (IR::Temp *t = s->expr->asTemp()) {
+ RegisterSizeDependentOps::setFunctionReturnValueFromTemp(this, t);
+ } else if (IR::Const *c = s->expr->asConst()) {
+ QV4::Primitive retVal = convertToValue(c);
+ RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal);
+ } else {
+ Q_UNREACHABLE();
+ Q_UNUSED(s);
+ }
+
+ Label leaveStackFrame = label();
+
+ const int locals = stackLayout().calculateJSStackFrameSize();
+ subPtr(TrustedImm32(sizeof(QV4::Value)*locals), JITTargetPlatform::LocalsRegister);
+ loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister);
+ loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, engine)), JITTargetPlatform::ScratchRegister);
+ storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
+
+ leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
+ ret();
+
+ exceptionReturnLabel = label();
+ QV4::Primitive retVal = Primitive::undefinedValue();
+ RegisterSizeDependentOps::setFunctionReturnValueFromConst(this, retVal);
+ jump(leaveStackFrame);
+}
namespace {
class QIODevicePrintStream: public FilePrintStream
@@ -563,7 +602,8 @@ static void qt_closePmap()
#endif
-JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
+template <typename TargetConfiguration>
+JSC::MacroAssemblerCodeRef Assembler<TargetConfiguration>::link(int *codeSize)
{
Label endOfCode = label();
@@ -577,7 +617,7 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
}
JSC::JSGlobalData dummy(_executableAllocator);
- JSC::LinkBuffer linkBuffer(dummy, this, 0);
+ JSC::LinkBuffer<typename TargetConfiguration::MacroAssembler> linkBuffer(dummy, this, 0);
for (const DataLabelPatch &p : qAsConst(_dataLabelPatches))
linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target));
@@ -668,4 +708,9 @@ JSC::MacroAssemblerCodeRef Assembler::link(int *codeSize)
return codeRef;
}
+template class QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>;
+#if defined(V4_BOOTSTRAP) && CPU(X86_64)
+template class QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
+#endif
+
#endif
diff --git a/src/qml/jit/qv4assembler_p.h b/src/qml/jit/qv4assembler_p.h
index de9c246ed6..6d8d773ff0 100644
--- a/src/qml/jit/qv4assembler_p.h
+++ b/src/qml/jit/qv4assembler_p.h
@@ -55,7 +55,8 @@
#include "private/qv4isel_p.h"
#include "private/qv4isel_util_p.h"
#include "private/qv4value_p.h"
-#include "private/qv4lookup_p.h"
+#include "private/qv4context_p.h"
+#include "private/qv4engine_p.h"
#include "qv4targetplatform_p.h"
#include <config.h>
@@ -73,46 +74,637 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
-class InstructionSelection;
-
struct CompilationUnit : public QV4::CompiledData::CompilationUnit
{
virtual ~CompilationUnit();
+#if !defined(V4_BOOTSTRAP)
void linkBackendToEngine(QV4::ExecutionEngine *engine) Q_DECL_OVERRIDE;
+ bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
+#endif
void prepareCodeOffsetsForDiskStorage(CompiledData::Unit *unit) Q_DECL_OVERRIDE;
bool saveCodeToDisk(QIODevice *device, const CompiledData::Unit *unit, QString *errorString) Q_DECL_OVERRIDE;
- bool memoryMapCode(QString *errorString) Q_DECL_OVERRIDE;
// Coderef + execution engine
QVector<JSC::MacroAssemblerCodeRef> codeRefs;
};
-struct LookupCall {
- JSC::MacroAssembler::Address addr;
- uint getterSetterOffset;
+template <typename PlatformAssembler, TargetOperatingSystemSpecialization Specialization>
+struct AssemblerTargetConfiguration
+{
+ typedef JSC::MacroAssembler<PlatformAssembler> MacroAssembler;
+ typedef TargetPlatform<PlatformAssembler, Specialization> Platform;
+ // More things coming here in the future, such as Target OS
+};
+
+#if CPU(ARM_THUMB2)
+typedef JSC::MacroAssemblerARMv7 DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(ARM64)
+typedef JSC::MacroAssemblerARM64 DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(ARM_TRADITIONAL)
+typedef JSC::MacroAssemblerARM DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(MIPS)
+typedef JSC::MacroAssemblerMIPS DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(X86)
+typedef JSC::MacroAssemblerX86 DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#elif CPU(X86_64)
+typedef JSC::MacroAssemblerX86_64 DefaultPlatformMacroAssembler;
+
+#if OS(WINDOWS)
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, WindowsSpecialization> DefaultAssemblerTargetConfiguration;
+#else
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#endif
- LookupCall(const JSC::MacroAssembler::Address &addr, uint getterSetterOffset)
- : addr(addr)
- , getterSetterOffset(getterSetterOffset)
- {}
+#elif CPU(SH4)
+typedef JSC::MacroAssemblerSH4 DefaultPlatformMacroAssembler;
+typedef AssemblerTargetConfiguration<DefaultPlatformMacroAssembler, NoOperatingSystemSpecialization> DefaultAssemblerTargetConfiguration;
+#endif
+
+#define isel_stringIfyx(s) #s
+#define isel_stringIfy(s) isel_stringIfyx(s)
+
+#define generateRuntimeCall(as, t, function, ...) \
+ as->generateFunctionCallImp(Runtime::Method_##function##_NeedsExceptionCheck, t, "Runtime::" isel_stringIfy(function), typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, function)), __VA_ARGS__)
+
+
+template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform, int RegisterSize>
+struct RegisterSizeDependentAssembler
+{
};
-struct RuntimeCall {
- JSC::MacroAssembler::Address addr;
+template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform>
+struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatform, 4>
+{
+ using RegisterID = typename JITAssembler::RegisterID;
+ using FPRegisterID = typename JITAssembler::FPRegisterID;
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using Address = typename JITAssembler::Address;
+ using Pointer = typename JITAssembler::Pointer;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+ using TrustedImm64 = typename JITAssembler::TrustedImm64;
+ using Jump = typename JITAssembler::Jump;
+
+ static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
+ {
+ as->MacroAssembler::loadDouble(addr, dest);
+ }
+
+ static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr)
+ {
+ as->MacroAssembler::storeDouble(source, addr);
+ }
+
+ static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target)
+ {
+ Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ as->storeDouble(source, ptr);
+ }
+
+ static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination)
+ {
+ as->store32(TrustedImm32(value.int_32()), destination);
+ destination.offset += 4;
+ as->store32(TrustedImm32(value.tag()), destination);
+ }
+
+ template <typename Source, typename Destination>
+ static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination)
+ {
+ as->loadDouble(source, TargetPlatform::FPGpr0);
+ as->storeDouble(TargetPlatform::FPGpr0, destination);
+ }
+
+ static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target)
+ {
+ as->MacroAssembler::loadDouble(as->loadConstant(c, TargetPlatform::ScratchRegister), target);
+ }
+
+ static void storeReturnValue(JITAssembler *as, FPRegisterID dest)
+ {
+ as->moveIntsToDouble(TargetPlatform::LowReturnValueRegister, TargetPlatform::HighReturnValueRegister, dest, TargetPlatform::FPGpr0);
+ }
+
+ static void storeReturnValue(JITAssembler *as, const Pointer &dest)
+ {
+ Address destination = dest;
+ as->store32(TargetPlatform::LowReturnValueRegister, destination);
+ destination.offset += 4;
+ as->store32(TargetPlatform::HighReturnValueRegister, destination);
+ }
+
+ static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t)
+ {
+ const auto lowReg = TargetPlatform::LowReturnValueRegister;
+ const auto highReg = TargetPlatform::HighReturnValueRegister;
+
+ if (t->kind == IR::Temp::PhysicalRegister) {
+ switch (t->type) {
+ case IR::DoubleType:
+ as->moveDoubleToInts((FPRegisterID) t->index, lowReg, highReg);
+ break;
+ case IR::UInt32Type: {
+ RegisterID srcReg = (RegisterID) t->index;
+ Jump intRange = as->branch32(JITAssembler::GreaterThanOrEqual, srcReg, TrustedImm32(0));
+ as->convertUInt32ToDouble(srcReg, TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister);
+ as->moveDoubleToInts(TargetPlatform::FPGpr0, lowReg, highReg);
+ Jump done = as->jump();
+ intRange.link(as);
+ as->move(srcReg, lowReg);
+ as->move(TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
+ done.link(as);
+ } break;
+ case IR::SInt32Type:
+ as->move((RegisterID) t->index, lowReg);
+ as->move(TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
+ break;
+ case IR::BoolType:
+ as->move((RegisterID) t->index, lowReg);
+ as->move(TrustedImm32(QV4::Value::Boolean_Type_Internal), highReg);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+ } else {
+ Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, t);
+ as->load32(addr, lowReg);
+ addr.offset += 4;
+ as->load32(addr, highReg);
+ }
+ }
+
+ static void setFunctionReturnValueFromConst(JITAssembler *as, QV4::Primitive retVal)
+ {
+ as->move(TrustedImm32(retVal.int_32()), TargetPlatform::LowReturnValueRegister);
+ as->move(TrustedImm32(retVal.tag()), TargetPlatform::HighReturnValueRegister);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Temp* temp, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(as);
+ Q_UNUSED(temp);
+ Q_UNUSED(dest);
+ Q_UNUSED(argumentNumber);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::ArgLocal* al, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(as);
+ Q_UNUSED(al);
+ Q_UNUSED(dest);
+ Q_UNUSED(argumentNumber);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Const* c, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(as);
+ Q_UNUSED(c);
+ Q_UNUSED(dest);
+ Q_UNUSED(argumentNumber);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Expr* expr, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(as);
+ Q_UNUSED(expr);
+ Q_UNUSED(dest);
+ Q_UNUSED(argumentNumber);
+ }
+
+ static void zeroRegister(JITAssembler *as, RegisterID reg)
+ {
+ as->move(TrustedImm32(0), reg);
+ }
+
+ static void zeroStackSlot(JITAssembler *as, int slot)
+ {
+ as->poke(TrustedImm32(0), slot);
+ }
+
+ static void generateCJumpOnUndefined(JITAssembler *as,
+ RelationalCondition cond, IR::Expr *right,
+ RegisterID scratchRegister, RegisterID tagRegister,
+ IR::BasicBlock *nextBlock, IR::BasicBlock *currentBlock,
+ IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
+ {
+ Pointer tagAddr = as->loadAddress(scratchRegister, right);
+ as->load32(tagAddr, tagRegister);
+ Jump j = as->branch32(JITAssembler::invert(cond), tagRegister, TrustedImm32(0));
+ as->addPatch(falseBlock, j);
+
+ tagAddr.offset += 4;
+ as->load32(tagAddr, tagRegister);
+ const TrustedImm32 tag(QV4::Value::Managed_Type_Internal);
+ Q_ASSERT(nextBlock == as->nextBlock());
+ Q_UNUSED(nextBlock);
+ as->generateCJumpOnCompare(cond, tagRegister, tag, currentBlock, trueBlock, falseBlock);
+ }
+
+ static void convertVarToSInt32(JITAssembler *as, IR::Expr *source, IR::Expr *target)
+ {
+ Q_ASSERT(source->type == IR::VarType);
+ // load the tag:
+ Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, source);
+ Pointer tagAddr = addr;
+ tagAddr.offset += 4;
+ as->load32(tagAddr, TargetPlatform::ReturnValueRegister);
+
+ // check if it's an int32:
+ Jump fallback = as->branch32(RelationalCondition::NotEqual, TargetPlatform::ReturnValueRegister,
+ TrustedImm32(Value::Integer_Type_Internal));
+ IR::Temp *targetTemp = target->asTemp();
+ if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
+ as->load32(addr, TargetPlatform::ReturnValueRegister);
+ Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ as->store32(TargetPlatform::ReturnValueRegister, targetAddr);
+ targetAddr.offset += 4;
+ as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr);
+ } else {
+ as->load32(addr, (RegisterID) targetTemp->index);
+ }
+ Jump intDone = as->jump();
+
+ // not an int:
+ fallback.link(as);
+ generateRuntimeCall(as, TargetPlatform::ReturnValueRegister, toInt,
+ as->loadAddress(TargetPlatform::ScratchRegister, source));
+ as->storeInt32(TargetPlatform::ReturnValueRegister, target);
+
+ intDone.link(as);
+ }
+
+ static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr)
+ {
+ as->store32(registerWithPtr, destAddr);
+ destAddr.offset += 4;
+ as->store32(TrustedImm32(QV4::Value::Managed_Type_Internal_32), destAddr);
+ }
+
+ static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister)
+ {
+ as->and32(TrustedImm32(Value::NotDouble_Mask), tagOrValueRegister);
+ return as->branch32(RelationalCondition::NotEqual, tagOrValueRegister,
+ TrustedImm32(Value::NotDouble_Mask));
+ }
+};
+
+template <typename JITAssembler, typename MacroAssembler, typename TargetPlatform>
+struct RegisterSizeDependentAssembler<JITAssembler, MacroAssembler, TargetPlatform, 8>
+{
+ using RegisterID = typename JITAssembler::RegisterID;
+ using FPRegisterID = typename JITAssembler::FPRegisterID;
+ using Address = typename JITAssembler::Address;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+ using TrustedImm64 = typename JITAssembler::TrustedImm64;
+ using Pointer = typename JITAssembler::Pointer;
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using BranchTruncateType = typename JITAssembler::BranchTruncateType;
+ using Jump = typename JITAssembler::Jump;
+
+ static void loadDouble(JITAssembler *as, Address addr, FPRegisterID dest)
+ {
+ as->load64(addr, TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest);
+ }
+
+ static void storeDouble(JITAssembler *as, FPRegisterID source, Address addr)
+ {
+ as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->store64(TargetPlatform::ReturnValueRegister, addr);
+ }
+
+ static void storeDouble(JITAssembler *as, FPRegisterID source, IR::Expr* target)
+ {
+ as->moveDoubleTo64(source, TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ Pointer ptr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ as->store64(TargetPlatform::ReturnValueRegister, ptr);
+ }
+
+ static void storeReturnValue(JITAssembler *as, FPRegisterID dest)
+ {
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->move64ToDouble(TargetPlatform::ReturnValueRegister, dest);
+ }
+
+ static void storeReturnValue(JITAssembler *as, const Pointer &dest)
+ {
+ as->store64(TargetPlatform::ReturnValueRegister, dest);
+ }
+
+ static void setFunctionReturnValueFromTemp(JITAssembler *as, IR::Temp *t)
+ {
+ if (t->kind == IR::Temp::PhysicalRegister) {
+ if (t->type == IR::DoubleType) {
+ as->moveDoubleTo64((FPRegisterID) t->index,
+ TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask),
+ TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ } else if (t->type == IR::UInt32Type) {
+ RegisterID srcReg = (RegisterID) t->index;
+ Jump intRange = as->branch32(RelationalCondition::GreaterThanOrEqual, srcReg, TrustedImm32(0));
+ as->convertUInt32ToDouble(srcReg, TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister);
+ as->moveDoubleTo64(TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister);
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ Jump done = as->jump();
+ intRange.link(as);
+ as->zeroExtend32ToPtr(srcReg, TargetPlatform::ReturnValueRegister);
+ quint64 tag = QV4::Value::Integer_Type_Internal;
+ as->or64(TrustedImm64(tag << 32),
+ TargetPlatform::ReturnValueRegister);
+ done.link(as);
+ } else {
+ as->zeroExtend32ToPtr((RegisterID) t->index, TargetPlatform::ReturnValueRegister);
+ quint64 tag;
+ switch (t->type) {
+ case IR::SInt32Type:
+ tag = QV4::Value::Integer_Type_Internal;
+ break;
+ case IR::BoolType:
+ tag = QV4::Value::Boolean_Type_Internal;
+ break;
+ default:
+ tag = 31337; // bogus value
+ Q_UNREACHABLE();
+ }
+ as->or64(TrustedImm64(tag << 32),
+ TargetPlatform::ReturnValueRegister);
+ }
+ } else {
+ as->copyValue(TargetPlatform::ReturnValueRegister, t);
+ }
+ }
+
+ static void setFunctionReturnValueFromConst(JITAssembler *as, QV4::Primitive retVal)
+ {
+ as->move(TrustedImm64(retVal.rawValue()), TargetPlatform::ReturnValueRegister);
+ }
+
+ static void storeValue(JITAssembler *as, QV4::Primitive value, Address destination)
+ {
+ as->store64(TrustedImm64(value.rawValue()), destination);
+ }
+
+ template <typename Source, typename Destination>
+ static void copyValueViaRegisters(JITAssembler *as, Source source, Destination destination)
+ {
+ // Use ReturnValueRegister as "scratch" register because loadArgument
+ // and storeArgument are functions that may need a scratch register themselves.
+ as->loadArgumentInRegister(source, TargetPlatform::ReturnValueRegister, 0);
+ as->storeReturnValue(destination);
+ }
+
+ static void loadDoubleConstant(JITAssembler *as, IR::Const *c, FPRegisterID target)
+ {
+ Q_STATIC_ASSERT(sizeof(int64_t) == sizeof(double));
+ int64_t i;
+ memcpy(&i, &c->value, sizeof(double));
+ as->move(TrustedImm64(i), TargetPlatform::ReturnValueRegister);
+ as->move64ToDouble(TargetPlatform::ReturnValueRegister, target);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Temp* temp, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(argumentNumber);
+
+ if (temp) {
+ Pointer addr = as->loadTempAddress(temp);
+ as->load64(addr, dest);
+ } else {
+ QV4::Value undefined = QV4::Primitive::undefinedValue();
+ as->move(TrustedImm64(undefined.rawValue()), dest);
+ }
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::ArgLocal* al, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(argumentNumber);
+
+ if (al) {
+ Pointer addr = as->loadArgLocalAddress(dest, al);
+ as->load64(addr, dest);
+ } else {
+ QV4::Value undefined = QV4::Primitive::undefinedValue();
+ as->move(TrustedImm64(undefined.rawValue()), dest);
+ }
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Const* c, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(argumentNumber);
+
+ QV4::Value v = convertToValue(c);
+ as->move(TrustedImm64(v.rawValue()), dest);
+ }
+
+ static void loadArgumentInRegister(JITAssembler *as, IR::Expr* expr, RegisterID dest, int argumentNumber)
+ {
+ Q_UNUSED(argumentNumber);
+
+ if (!expr) {
+ QV4::Value undefined = QV4::Primitive::undefinedValue();
+ as->move(TrustedImm64(undefined.rawValue()), dest);
+ } else if (IR::Temp *t = expr->asTemp()){
+ loadArgumentInRegister(as, t, dest, argumentNumber);
+ } else if (IR::ArgLocal *al = expr->asArgLocal()) {
+ loadArgumentInRegister(as, al, dest, argumentNumber);
+ } else if (IR::Const *c = expr->asConst()) {
+ loadArgumentInRegister(as, c, dest, argumentNumber);
+ } else {
+ Q_ASSERT(!"unimplemented expression type in loadArgument");
+ }
+ }
+
+ static void zeroRegister(JITAssembler *as, RegisterID reg)
+ {
+ as->move(TrustedImm64(0), reg);
+ }
- inline RuntimeCall(uint offset = uint(INT_MIN));
- bool isValid() const { return addr.offset >= 0; }
+ static void zeroStackSlot(JITAssembler *as, int slot)
+ {
+ as->store64(TrustedImm64(0), as->addressForPoke(slot));
+ }
+
+ static void generateCJumpOnCompare(JITAssembler *as,
+ RelationalCondition cond,
+ RegisterID left,
+ TrustedImm64 right,
+ IR::BasicBlock *nextBlock,
+ IR::BasicBlock *currentBlock,
+ IR::BasicBlock *trueBlock,
+ IR::BasicBlock *falseBlock)
+ {
+ if (trueBlock == nextBlock) {
+ Jump target = as->branch64(as->invert(cond), left, right);
+ as->addPatch(falseBlock, target);
+ } else {
+ Jump target = as->branch64(cond, left, right);
+ as->addPatch(trueBlock, target);
+ as->jumpToBlock(currentBlock, falseBlock);
+ }
+ }
+
+ static void generateCJumpOnUndefined(JITAssembler *as,
+ RelationalCondition cond, IR::Expr *right,
+ RegisterID scratchRegister, RegisterID tagRegister,
+ IR::BasicBlock *nextBlock, IR::BasicBlock *currentBlock,
+ IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock)
+ {
+ Pointer addr = as->loadAddress(scratchRegister, right);
+ as->load64(addr, tagRegister);
+ const TrustedImm64 tag(0);
+ generateCJumpOnCompare(as, cond, tagRegister, tag, nextBlock, currentBlock, trueBlock, falseBlock);
+ }
+
+ static void convertVarToSInt32(JITAssembler *as, IR::Expr *source, IR::Expr *target)
+ {
+ Q_ASSERT(source->type == IR::VarType);
+ Pointer addr = as->loadAddress(TargetPlatform::ScratchRegister, source);
+ as->load64(addr, TargetPlatform::ScratchRegister);
+ as->move(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+
+ // check if it's integer convertible
+ as->urshift64(TrustedImm32(QV4::Value::IsIntegerConvertible_Shift), TargetPlatform::ScratchRegister);
+ Jump isIntConvertible = as->branch32(RelationalCondition::Equal, TargetPlatform::ScratchRegister, TrustedImm32(3));
+
+ // nope, not integer convertible, so check for a double:
+ as->urshift64(TrustedImm32(
+ QV4::Value::IsDoubleTag_Shift - QV4::Value::IsIntegerConvertible_Shift),
+ TargetPlatform::ScratchRegister);
+ Jump fallback = as->branch32(RelationalCondition::GreaterThan, TargetPlatform::ScratchRegister, TrustedImm32(0));
+
+ // it's a double
+ as->move(TrustedImm64(QV4::Value::NaNEncodeMask), TargetPlatform::ScratchRegister);
+ as->xor64(TargetPlatform::ScratchRegister, TargetPlatform::ReturnValueRegister);
+ as->move64ToDouble(TargetPlatform::ReturnValueRegister, TargetPlatform::FPGpr0);
+ Jump success =
+ as->branchTruncateDoubleToInt32(TargetPlatform::FPGpr0, TargetPlatform::ReturnValueRegister,
+ BranchTruncateType::BranchIfTruncateSuccessful);
+
+ // not an int:
+ fallback.link(as);
+ generateRuntimeCall(as, TargetPlatform::ReturnValueRegister, toInt,
+ as->loadAddress(TargetPlatform::ScratchRegister, source));
+
+
+ isIntConvertible.link(as);
+ success.link(as);
+ IR::Temp *targetTemp = target->asTemp();
+ if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
+ Pointer targetAddr = as->loadAddress(TargetPlatform::ScratchRegister, target);
+ as->store32(TargetPlatform::ReturnValueRegister, targetAddr);
+ targetAddr.offset += 4;
+ as->store32(TrustedImm32(Value::Integer_Type_Internal), targetAddr);
+ } else {
+ as->storeInt32(TargetPlatform::ReturnValueRegister, target);
+ }
+ }
+
+ static void loadManagedPointer(JITAssembler *as, RegisterID registerWithPtr, Pointer destAddr)
+ {
+ as->store64(registerWithPtr, destAddr);
+ }
+
+ static Jump generateIsDoubleCheck(JITAssembler *as, RegisterID tagOrValueRegister)
+ {
+ as->rshift32(TrustedImm32(Value::IsDoubleTag_Shift), tagOrValueRegister);
+ return as->branch32(RelationalCondition::NotEqual, tagOrValueRegister,
+ TrustedImm32(0));
+ }
};
-class Assembler : public JSC::MacroAssembler, public TargetPlatform
+template <typename TargetConfiguration>
+class Assembler : public TargetConfiguration::MacroAssembler, public TargetConfiguration::Platform
{
Q_DISABLE_COPY(Assembler)
public:
Assembler(QV4::Compiler::JSUnitGenerator *jsGenerator, IR::Function* function, QV4::ExecutableAllocator *executableAllocator);
+ using MacroAssembler = typename TargetConfiguration::MacroAssembler;
+ using RegisterID = typename MacroAssembler::RegisterID;
+ using FPRegisterID = typename MacroAssembler::FPRegisterID;
+ using Address = typename MacroAssembler::Address;
+ using Label = typename MacroAssembler::Label;
+ using Jump = typename MacroAssembler::Jump;
+ using DataLabelPtr = typename MacroAssembler::DataLabelPtr;
+ using TrustedImm32 = typename MacroAssembler::TrustedImm32;
+ using TrustedImm64 = typename MacroAssembler::TrustedImm64;
+ using TrustedImmPtr = typename MacroAssembler::TrustedImmPtr;
+ using RelationalCondition = typename MacroAssembler::RelationalCondition;
+ using typename MacroAssembler::DoubleCondition;
+ using MacroAssembler::label;
+ using MacroAssembler::move;
+ using MacroAssembler::jump;
+ using MacroAssembler::add32;
+ using MacroAssembler::and32;
+ using MacroAssembler::store32;
+ using MacroAssembler::loadPtr;
+ using MacroAssembler::load32;
+ using MacroAssembler::branch32;
+ using MacroAssembler::subDouble;
+ using MacroAssembler::subPtr;
+ using MacroAssembler::addPtr;
+ using MacroAssembler::call;
+ using MacroAssembler::poke;
+ using MacroAssembler::branchTruncateDoubleToUint32;
+ using MacroAssembler::or32;
+ using MacroAssembler::moveDouble;
+ using MacroAssembler::convertUInt32ToDouble;
+ using MacroAssembler::invert;
+ using MacroAssembler::convertInt32ToDouble;
+ using MacroAssembler::rshift32;
+ using MacroAssembler::storePtr;
+ using MacroAssembler::ret;
+
+ using JITTargetPlatform = typename TargetConfiguration::Platform;
+ using JITTargetPlatform::RegisterArgumentCount;
+ using JITTargetPlatform::StackSpaceAllocatedUponFunctionEntry;
+ using JITTargetPlatform::RegisterSize;
+ using JITTargetPlatform::StackAlignment;
+ using JITTargetPlatform::ReturnValueRegister;
+ using JITTargetPlatform::StackPointerRegister;
+ using JITTargetPlatform::ScratchRegister;
+ using JITTargetPlatform::EngineRegister;
+ using JITTargetPlatform::StackShadowSpace;
+ using JITTargetPlatform::registerForArgument;
+ using JITTargetPlatform::FPGpr0;
+ using JITTargetPlatform::platformEnterStandardStackFrame;
+ using JITTargetPlatform::platformLeaveStandardStackFrame;
+
+ using RegisterSizeDependentOps = RegisterSizeDependentAssembler<Assembler<TargetConfiguration>, MacroAssembler, JITTargetPlatform, RegisterSize>;
+
+ struct LookupCall {
+ Address addr;
+ uint getterSetterOffset;
+
+ LookupCall(const Address &addr, uint getterSetterOffset)
+ : addr(addr)
+ , getterSetterOffset(getterSetterOffset)
+ {}
+ };
+
+ struct RuntimeCall {
+ Address addr;
+
+ inline RuntimeCall(uint offset = uint(INT_MIN));
+ bool isValid() const { return addr.offset >= 0; }
+ };
+
// Explicit type to allow distinguishing between
// pushing an address itself or the value it points
// to onto the stack when calling functions.
@@ -319,20 +911,29 @@ public:
void addPatch(DataLabelPtr patch, IR::BasicBlock *target);
void generateCJumpOnNonZero(RegisterID reg, IR::BasicBlock *currentBlock,
IR::BasicBlock *trueBlock, IR::BasicBlock *falseBlock);
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, TrustedImm64 right,
- IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
- IR::BasicBlock *falseBlock);
-#endif
void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, TrustedImm32 right,
IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock);
void generateCJumpOnCompare(RelationalCondition cond, RegisterID left, RegisterID right,
IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock);
- Jump genTryDoubleConversion(IR::Expr *src, Assembler::FPRegisterID dest);
- Assembler::Jump branchDouble(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
- Assembler::Jump branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
+ void generateCJumpOnUndefined(RelationalCondition cond, IR::Expr *right,
+ RegisterID scratchRegister, RegisterID tagRegister,
+ IR::BasicBlock *currentBlock, IR::BasicBlock *trueBlock,
+ IR::BasicBlock *falseBlock)
+ {
+ RegisterSizeDependentOps::generateCJumpOnUndefined(this, cond, right, scratchRegister, tagRegister,
+ _nextBlock, currentBlock, trueBlock, falseBlock);
+ }
+
+ Jump generateIsDoubleCheck(RegisterID tagOrValueRegister)
+ {
+ return RegisterSizeDependentOps::generateIsDoubleCheck(this, tagOrValueRegister);
+ }
+
+ Jump genTryDoubleConversion(IR::Expr *src, FPRegisterID dest);
+ Jump branchDouble(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
+ Jump branchInt32(bool invertCondition, IR::AluOp op, IR::Expr *left, IR::Expr *right);
Pointer loadAddress(RegisterID tmp, IR::Expr *t);
Pointer loadTempAddress(IR::Temp *t);
@@ -396,7 +997,7 @@ public:
void loadArgumentInRegister(PointerToValue temp, RegisterID dest, int argumentNumber)
{
if (!temp.value) {
- move(TrustedImmPtr(0), dest);
+ RegisterSizeDependentOps::zeroRegister(this, dest);
} else {
Pointer addr = toAddress(dest, temp.value, argumentNumber);
loadArgumentInRegister(addr, dest, argumentNumber);
@@ -415,70 +1016,31 @@ public:
loadArgumentInRegister(addr, dest, argumentNumber);
}
-#ifdef VALUE_FITS_IN_REGISTER
void loadArgumentInRegister(IR::Temp* temp, RegisterID dest, int argumentNumber)
{
- Q_UNUSED(argumentNumber);
-
- if (temp) {
- Pointer addr = loadTempAddress(temp);
- load64(addr, dest);
- } else {
- QV4::Value undefined = QV4::Primitive::undefinedValue();
- move(TrustedImm64(undefined.rawValue()), dest);
- }
+ RegisterSizeDependentOps::loadArgumentInRegister(this, temp, dest, argumentNumber);
}
void loadArgumentInRegister(IR::ArgLocal* al, RegisterID dest, int argumentNumber)
{
- Q_UNUSED(argumentNumber);
-
- if (al) {
- Pointer addr = loadArgLocalAddress(dest, al);
- load64(addr, dest);
- } else {
- QV4::Value undefined = QV4::Primitive::undefinedValue();
- move(TrustedImm64(undefined.rawValue()), dest);
- }
+ RegisterSizeDependentOps::loadArgumentInRegister(this, al, dest, argumentNumber);
}
void loadArgumentInRegister(IR::Const* c, RegisterID dest, int argumentNumber)
{
- Q_UNUSED(argumentNumber);
-
- QV4::Value v = convertToValue(c);
- move(TrustedImm64(v.rawValue()), dest);
+ RegisterSizeDependentOps::loadArgumentInRegister(this, c, dest, argumentNumber);
}
void loadArgumentInRegister(IR::Expr* expr, RegisterID dest, int argumentNumber)
{
- Q_UNUSED(argumentNumber);
-
- if (!expr) {
- QV4::Value undefined = QV4::Primitive::undefinedValue();
- move(TrustedImm64(undefined.rawValue()), dest);
- } else if (IR::Temp *t = expr->asTemp()){
- loadArgumentInRegister(t, dest, argumentNumber);
- } else if (IR::ArgLocal *al = expr->asArgLocal()) {
- loadArgumentInRegister(al, dest, argumentNumber);
- } else if (IR::Const *c = expr->asConst()) {
- loadArgumentInRegister(c, dest, argumentNumber);
- } else {
- Q_ASSERT(!"unimplemented expression type in loadArgument");
- }
- }
-#else
- void loadArgumentInRegister(IR::Expr*, RegisterID)
- {
- Q_ASSERT(!"unimplemented: expression in loadArgument");
+ RegisterSizeDependentOps::loadArgumentInRegister(this, expr, dest, argumentNumber);
}
-#endif
void loadArgumentInRegister(TrustedImm32 imm32, RegisterID dest, int argumentNumber)
{
Q_UNUSED(argumentNumber);
- xorPtr(dest, dest);
+ RegisterSizeDependentOps::zeroRegister(this, dest);
if (imm32.m_value)
move(imm32, dest);
}
@@ -499,55 +1061,13 @@ public:
void storeReturnValue(FPRegisterID dest)
{
-#ifdef VALUE_FITS_IN_REGISTER
- move(TrustedImm64(QV4::Value::NaNEncodeMask), ScratchRegister);
- xor64(ScratchRegister, ReturnValueRegister);
- move64ToDouble(ReturnValueRegister, dest);
-#elif defined(Q_PROCESSOR_ARM)
- moveIntsToDouble(JSC::ARMRegisters::r0, JSC::ARMRegisters::r1, dest, FPGpr0);
-#elif defined(Q_PROCESSOR_X86)
- moveIntsToDouble(JSC::X86Registers::eax, JSC::X86Registers::edx, dest, FPGpr0);
-#elif defined(Q_PROCESSOR_MIPS)
- moveIntsToDouble(JSC::MIPSRegisters::v0, JSC::MIPSRegisters::v1, dest, FPGpr0);
-#else
- subPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister);
- Pointer tmp(StackPointerRegister, 0);
- storeReturnValue(tmp);
- loadDouble(tmp, dest);
- addPtr(TrustedImm32(sizeof(QV4::Value)), StackPointerRegister);
-#endif
+ RegisterSizeDependentOps::storeReturnValue(this, dest);
}
-#ifdef VALUE_FITS_IN_REGISTER
- void storeReturnValue(const Pointer &dest)
- {
- store64(ReturnValueRegister, dest);
- }
-#elif defined(Q_PROCESSOR_X86)
- void storeReturnValue(const Pointer &dest)
- {
- Pointer destination = dest;
- store32(JSC::X86Registers::eax, destination);
- destination.offset += 4;
- store32(JSC::X86Registers::edx, destination);
- }
-#elif defined(Q_PROCESSOR_ARM)
- void storeReturnValue(const Pointer &dest)
- {
- Pointer destination = dest;
- store32(JSC::ARMRegisters::r0, destination);
- destination.offset += 4;
- store32(JSC::ARMRegisters::r1, destination);
- }
-#elif defined(Q_PROCESSOR_MIPS)
void storeReturnValue(const Pointer &dest)
{
- Pointer destination = dest;
- store32(JSC::MIPSRegisters::v0, destination);
- destination.offset += 4;
- store32(JSC::MIPSRegisters::v1, destination);
+ RegisterSizeDependentOps::storeReturnValue(this, dest);
}
-#endif
void storeReturnValue(IR::Expr *target)
{
@@ -609,7 +1129,7 @@ public:
Pointer ptr = toAddress(ScratchRegister, temp.value, argumentNumber);
loadArgumentOnStack<StackSlot>(ptr, argumentNumber);
} else {
- poke(TrustedImmPtr(0), StackSlot);
+ RegisterSizeDependentOps::zeroStackSlot(this, StackSlot);
}
}
@@ -648,38 +1168,18 @@ public:
moveDouble(source, (FPRegisterID) targetTemp->index);
return;
}
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- moveDoubleTo64(source, ReturnValueRegister);
- move(TrustedImm64(QV4::Value::NaNEncodeMask), ScratchRegister);
- xor64(ScratchRegister, ReturnValueRegister);
- Pointer ptr = loadAddress(ScratchRegister, target);
- store64(ReturnValueRegister, ptr);
-#else
- Pointer ptr = loadAddress(ScratchRegister, target);
- storeDouble(source, ptr);
-#endif
+ RegisterSizeDependentOps::storeDouble(this, source, target);
}
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- // We need to (de)mangle the double
+
void loadDouble(Address addr, FPRegisterID dest)
{
- load64(addr, ReturnValueRegister);
- move(TrustedImm64(QV4::Value::NaNEncodeMask), ScratchRegister);
- xor64(ScratchRegister, ReturnValueRegister);
- move64ToDouble(ReturnValueRegister, dest);
+ RegisterSizeDependentOps::loadDouble(this, addr, dest);
}
void storeDouble(FPRegisterID source, Address addr)
{
- moveDoubleTo64(source, ReturnValueRegister);
- move(TrustedImm64(QV4::Value::NaNEncodeMask), ScratchRegister);
- xor64(ScratchRegister, ReturnValueRegister);
- store64(ReturnValueRegister, addr);
+ RegisterSizeDependentOps::storeDouble(this, source, addr);
}
-#else
- using JSC::MacroAssembler::loadDouble;
- using JSC::MacroAssembler::storeDouble;
-#endif
template <typename Result, typename Source>
void copyValue(Result result, Source source);
@@ -691,8 +1191,15 @@ public:
{
Q_ASSERT(!source->asTemp() || source->asTemp()->kind != IR::Temp::PhysicalRegister);
Q_ASSERT(target.base != scratchRegister);
- JSC::MacroAssembler::loadDouble(loadAddress(scratchRegister, source), FPGpr0);
- JSC::MacroAssembler::storeDouble(FPGpr0, target);
+ TargetConfiguration::MacroAssembler::loadDouble(loadAddress(scratchRegister, source), FPGpr0);
+ TargetConfiguration::MacroAssembler::storeDouble(FPGpr0, target);
+ }
+
+ // The scratch register is used to calculate the temp address for the source.
+ void memcopyValue(IR::Expr *target, Pointer source, FPRegisterID fpScratchRegister, RegisterID scratchRegister)
+ {
+ TargetConfiguration::MacroAssembler::loadDouble(source, fpScratchRegister);
+ TargetConfiguration::MacroAssembler::storeDouble(fpScratchRegister, loadAddress(scratchRegister, target));
}
void storeValue(QV4::Primitive value, RegisterID destination)
@@ -704,13 +1211,7 @@ public:
void storeValue(QV4::Primitive value, Address destination)
{
-#ifdef VALUE_FITS_IN_REGISTER
- store64(TrustedImm64(value.rawValue()), destination);
-#else
- store32(TrustedImm32(value.int_32()), destination);
- destination.offset += 4;
- store32(TrustedImm32(value.tag()), destination);
-#endif
+ RegisterSizeDependentOps::storeValue(this, value, destination);
}
void storeValue(QV4::Primitive value, IR::Expr* temp);
@@ -722,7 +1223,7 @@ public:
void checkException() {
load32(Address(EngineRegister, qOffsetOf(QV4::ExecutionEngine, hasException)), ScratchRegister);
- Jump exceptionThrown = branch32(NotEqual, ScratchRegister, TrustedImm32(0));
+ Jump exceptionThrown = branch32(RelationalCondition::NotEqual, ScratchRegister, TrustedImm32(0));
if (catchBlock)
addPatch(catchBlock, exceptionThrown);
else
@@ -781,6 +1282,27 @@ public:
enum { Size = 0 };
};
+ template <typename T> bool prepareCall(T &)
+ { return true; }
+
+ bool prepareCall(LookupCall &lookupCall)
+ {
+ // IMPORTANT! See generateLookupCall in qv4isel_masm_p.h for details!
+
+ // load the table from the context
+ loadPtr(Address(EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), ScratchRegister);
+ loadPtr(Address(ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, lookups)),
+ lookupCall.addr.base);
+ // pre-calculate the indirect address for the lookupCall table:
+ if (lookupCall.addr.offset)
+ addPtr(TrustedImm32(lookupCall.addr.offset), lookupCall.addr.base);
+ // store it as the first argument
+ loadArgumentOnStackOrRegister<0>(lookupCall.addr.base);
+ // set the destination addresses offset to the getterSetterOffset. The base is the lookupCall table's address
+ lookupCall.addr.offset = lookupCall.getterSetterOffset;
+ return false;
+ }
+
template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6>
void generateFunctionCallImp(bool needsExceptionCheck, ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6)
{
@@ -813,11 +1335,11 @@ public:
loadArgumentOnStackOrRegister<2>(arg3);
loadArgumentOnStackOrRegister<1>(arg2);
- if (prepareCall(function, this))
+ if (prepareCall(function))
loadArgumentOnStackOrRegister<0>(arg1);
#ifdef RESTORE_EBX_ON_CALL
- load32(ebxAddressOnStack(), JSC::X86Registers::ebx); // restore the GOT ptr
+ load32(this->ebxAddressOnStack(), JSC::X86Registers::ebx); // restore the GOT ptr
#endif
callAbsolute(functionName, function);
@@ -957,7 +1479,7 @@ public:
void storeUInt32(RegisterID reg, Pointer addr)
{
// The UInt32 representation in QV4::Value is really convoluted. See also toUInt32Register.
- Jump intRange = branch32(GreaterThanOrEqual, reg, TrustedImm32(0));
+ Jump intRange = branch32(RelationalCondition::GreaterThanOrEqual, reg, TrustedImm32(0));
convertUInt32ToDouble(reg, FPGpr0, ReturnValueRegister);
storeDouble(FPGpr0, addr);
Jump done = jump();
@@ -980,15 +1502,7 @@ public:
FPRegisterID toDoubleRegister(IR::Expr *e, FPRegisterID target = FPGpr0)
{
if (IR::Const *c = e->asConst()) {
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- Q_STATIC_ASSERT(sizeof(int64_t) == sizeof(double));
- int64_t i;
- memcpy(&i, &c->value, sizeof(double));
- move(TrustedImm64(i), ReturnValueRegister);
- move64ToDouble(ReturnValueRegister, target);
-#else
- JSC::MacroAssembler::loadDouble(loadConstant(c, ScratchRegister), target);
-#endif
+ RegisterSizeDependentOps::loadDoubleConstant(this, c, target);
return target;
}
@@ -1047,7 +1561,7 @@ public:
Pointer tagAddr = addr;
tagAddr.offset += 4;
load32(tagAddr, scratchReg);
- Jump inIntRange = branch32(Equal, scratchReg, TrustedImm32(QV4::Value::Integer_Type_Internal));
+ Jump inIntRange = branch32(RelationalCondition::Equal, scratchReg, TrustedImm32(QV4::Value::Integer_Type_Internal));
// it's not in signed int range, so load it as a double, and truncate it down
loadDouble(addr, FPGpr0);
@@ -1065,6 +1579,8 @@ public:
return scratchReg;
}
+ void returnFromFunction(IR::Ret *s, RegisterInformation regularRegistersToSave, RegisterInformation fpRegistersToSave);
+
JSC::MacroAssemblerCodeRef link(int *codeSize);
void setStackLayout(int maxArgCountForBuiltins, int regularRegistersToSave, int fpRegistersToSave);
@@ -1095,22 +1611,16 @@ private:
QV4::Compiler::JSUnitGenerator *_jsGenerator;
};
+template <typename TargetConfiguration>
template <typename Result, typename Source>
-void Assembler::copyValue(Result result, Source source)
+void Assembler<TargetConfiguration>::copyValue(Result result, Source source)
{
-#ifdef VALUE_FITS_IN_REGISTER
- // Use ReturnValueRegister as "scratch" register because loadArgument
- // and storeArgument are functions that may need a scratch register themselves.
- loadArgumentInRegister(source, ReturnValueRegister, 0);
- storeReturnValue(result);
-#else
- loadDouble(source, FPGpr0);
- storeDouble(FPGpr0, result);
-#endif
+ RegisterSizeDependentOps::copyValueViaRegisters(this, source, result);
}
+template <typename TargetConfiguration>
template <typename Result>
-void Assembler::copyValue(Result result, IR::Expr* source)
+void Assembler<TargetConfiguration>::copyValue(Result result, IR::Expr* source)
{
if (source->type == IR::BoolType) {
RegisterID reg = toInt32Register(source, ScratchRegister);
@@ -1124,15 +1634,7 @@ void Assembler::copyValue(Result result, IR::Expr* source)
} else if (source->type == IR::DoubleType) {
storeDouble(toDoubleRegister(source), result);
} else if (source->asTemp() || source->asArgLocal()) {
-#ifdef VALUE_FITS_IN_REGISTER
- // Use ReturnValueRegister as "scratch" register because loadArgument
- // and storeArgument are functions that may need a scratch register themselves.
- loadArgumentInRegister(source, ReturnValueRegister, 0);
- storeReturnValue(result);
-#else
- loadDouble(source, FPGpr0);
- storeDouble(FPGpr0, result);
-#endif
+ RegisterSizeDependentOps::copyValueViaRegisters(this, source, result);
} else if (IR::Const *c = source->asConst()) {
QV4::Primitive v = convertToValue(c);
storeValue(v, result);
@@ -1141,34 +1643,12 @@ void Assembler::copyValue(Result result, IR::Expr* source)
}
}
-inline RuntimeCall::RuntimeCall(uint offset)
+template <typename TargetConfiguration>
+inline Assembler<TargetConfiguration>::RuntimeCall::RuntimeCall(uint offset)
: addr(Assembler::EngineRegister, offset + qOffsetOf(QV4::ExecutionEngine, runtime))
{
}
-
-
-template <typename T> inline bool prepareCall(T &, Assembler *)
-{ return true; }
-
-template <> inline bool prepareCall(LookupCall &lookupCall, Assembler *as)
-{
- // IMPORTANT! See generateLookupCall in qv4isel_masm_p.h for details!
-
- // load the table from the context
- as->loadPtr(Assembler::Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
- as->loadPtr(Assembler::Address(Assembler::ScratchRegister, qOffsetOf(QV4::Heap::ExecutionContext, lookups)),
- lookupCall.addr.base);
- // pre-calculate the indirect address for the lookupCall table:
- if (lookupCall.addr.offset)
- as->addPtr(Assembler::TrustedImm32(lookupCall.addr.offset), lookupCall.addr.base);
- // store it as the first argument
- as->loadArgumentOnStackOrRegister<0>(lookupCall.addr.base);
- // set the destination addresses offset to the getterSetterOffset. The base is the lookupCall table's address
- lookupCall.addr.offset = lookupCall.getterSetterOffset;
- return false;
-}
-
} // end of namespace JIT
} // end of namespace QV4
diff --git a/src/qml/jit/qv4binop.cpp b/src/qml/jit/qv4binop.cpp
index d2758c4a47..8468bf65a6 100644
--- a/src/qml/jit/qv4binop.cpp
+++ b/src/qml/jit/qv4binop.cpp
@@ -57,7 +57,8 @@ using namespace JIT;
#define NULL_OP \
{ 0, 0, 0, 0, 0, false }
-const Binop::OpInfo Binop::operations[IR::LastAluOp + 1] = {
+template <typename JITAssembler>
+const typename Binop<JITAssembler>::OpInfo Binop<JITAssembler>::operations[IR::LastAluOp + 1] = {
NULL_OP, // OpInvalid
NULL_OP, // OpIfTrue
NULL_OP, // OpNot
@@ -67,20 +68,20 @@ const Binop::OpInfo Binop::operations[IR::LastAluOp + 1] = {
NULL_OP, // OpIncrement
NULL_OP, // OpDecrement
- INLINE_OP(bitAnd, &Binop::inline_and32, &Binop::inline_and32), // OpBitAnd
- INLINE_OP(bitOr, &Binop::inline_or32, &Binop::inline_or32), // OpBitOr
- INLINE_OP(bitXor, &Binop::inline_xor32, &Binop::inline_xor32), // OpBitXor
+ INLINE_OP(bitAnd, &Binop<JITAssembler>::inline_and32, &Binop<JITAssembler>::inline_and32), // OpBitAnd
+ INLINE_OP(bitOr, &Binop<JITAssembler>::inline_or32, &Binop<JITAssembler>::inline_or32), // OpBitOr
+ INLINE_OP(bitXor, &Binop<JITAssembler>::inline_xor32, &Binop<JITAssembler>::inline_xor32), // OpBitXor
- INLINE_OPCONTEXT(add, &Binop::inline_add32, &Binop::inline_add32), // OpAdd
- INLINE_OP(sub, &Binop::inline_sub32, &Binop::inline_sub32), // OpSub
- INLINE_OP(mul, &Binop::inline_mul32, &Binop::inline_mul32), // OpMul
+ INLINE_OPCONTEXT(add, &Binop<JITAssembler>::inline_add32, &Binop<JITAssembler>::inline_add32), // OpAdd
+ INLINE_OP(sub, &Binop<JITAssembler>::inline_sub32, &Binop<JITAssembler>::inline_sub32), // OpSub
+ INLINE_OP(mul, &Binop<JITAssembler>::inline_mul32, &Binop<JITAssembler>::inline_mul32), // OpMul
OP(div), // OpDiv
OP(mod), // OpMod
- INLINE_OP(shl, &Binop::inline_shl32, &Binop::inline_shl32), // OpLShift
- INLINE_OP(shr, &Binop::inline_shr32, &Binop::inline_shr32), // OpRShift
- INLINE_OP(ushr, &Binop::inline_ushr32, &Binop::inline_ushr32), // OpURShift
+ INLINE_OP(shl, &Binop<JITAssembler>::inline_shl32, &Binop<JITAssembler>::inline_shl32), // OpLShift
+ INLINE_OP(shr, &Binop<JITAssembler>::inline_shr32, &Binop<JITAssembler>::inline_shr32), // OpRShift
+ INLINE_OP(ushr, &Binop<JITAssembler>::inline_ushr32, &Binop<JITAssembler>::inline_ushr32), // OpURShift
OP(greaterThan), // OpGt
OP(lessThan), // OpLt
@@ -100,7 +101,8 @@ const Binop::OpInfo Binop::operations[IR::LastAluOp + 1] = {
-void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
+template <typename JITAssembler>
+void Binop<JITAssembler>::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
{
if (op != IR::OpMod
&& lhs->type == IR::DoubleType && rhs->type == IR::DoubleType) {
@@ -125,15 +127,15 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
info = stringAdd;
}
- RuntimeCall fallBack(info.fallbackImplementation);
- RuntimeCall context(info.contextImplementation);
+ typename JITAssembler::RuntimeCall fallBack(info.fallbackImplementation);
+ typename JITAssembler::RuntimeCall context(info.contextImplementation);
if (fallBack.isValid()) {
as->generateFunctionCallImp(info.needsExceptionCheck, target, info.name, fallBack,
PointerToValue(lhs),
PointerToValue(rhs));
} else if (context.isValid()) {
as->generateFunctionCallImp(info.needsExceptionCheck, target, info.name, context,
- Assembler::EngineRegister,
+ JITAssembler::EngineRegister,
PointerToValue(lhs),
PointerToValue(rhs));
} else {
@@ -145,14 +147,15 @@ void Binop::generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
}
-void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
+template <typename JITAssembler>
+void Binop<JITAssembler>::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
{
IR::Temp *targetTemp = target->asTemp();
FPRegisterID targetReg;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
targetReg = (FPRegisterID) targetTemp->index;
else
- targetReg = Assembler::FPGpr0;
+ targetReg = JITAssembler::FPGpr0;
switch (op) {
case IR::OpAdd:
@@ -162,7 +165,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
#if CPU(X86)
if (IR::Const *c = rhs->asConst()) { // Y = X + constant -> Y = X; Y += [constant-address]
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Address addr = as->loadConstant(c, Assembler::ScratchRegister);
+ Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
as->addDouble(addr, targetReg);
break;
}
@@ -174,7 +177,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
}
}
#endif
- as->addDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), as->toDoubleRegister(rhs, Assembler::FPGpr1), targetReg);
+ as->addDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
break;
case IR::OpMul:
@@ -184,7 +187,7 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
#if CPU(X86)
if (IR::Const *c = rhs->asConst()) { // Y = X * constant -> Y = X; Y *= [constant-address]
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Address addr = as->loadConstant(c, Assembler::ScratchRegister);
+ Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
as->mulDouble(addr, targetReg);
break;
}
@@ -196,14 +199,14 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
}
}
#endif
- as->mulDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), as->toDoubleRegister(rhs, Assembler::FPGpr1), targetReg);
+ as->mulDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
break;
case IR::OpSub:
#if CPU(X86)
if (IR::Const *c = rhs->asConst()) { // Y = X - constant -> Y = X; Y -= [constant-address]
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Address addr = as->loadConstant(c, Assembler::ScratchRegister);
+ Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
as->subDouble(addr, targetReg);
break;
}
@@ -219,19 +222,19 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
&& targetTemp
&& targetTemp->kind == IR::Temp::PhysicalRegister
&& targetTemp->index == rhs->asTemp()->index) { // Y = X - Y -> Tmp = Y; Y = X - Tmp
- as->moveDouble(as->toDoubleRegister(rhs, Assembler::FPGpr1), Assembler::FPGpr1);
- as->subDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), Assembler::FPGpr1, targetReg);
+ as->moveDouble(as->toDoubleRegister(rhs, JITAssembler::FPGpr1), JITAssembler::FPGpr1);
+ as->subDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), JITAssembler::FPGpr1, targetReg);
break;
}
- as->subDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), as->toDoubleRegister(rhs, Assembler::FPGpr1), targetReg);
+ as->subDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
break;
case IR::OpDiv:
#if CPU(X86)
if (IR::Const *c = rhs->asConst()) { // Y = X / constant -> Y = X; Y /= [constant-address]
as->moveDouble(as->toDoubleRegister(lhs, targetReg), targetReg);
- Address addr = as->loadConstant(c, Assembler::ScratchRegister);
+ Address addr = as->loadConstant(c, JITAssembler::ScratchRegister);
as->divDouble(addr, targetReg);
break;
}
@@ -248,12 +251,12 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
&& targetTemp
&& targetTemp->kind == IR::Temp::PhysicalRegister
&& targetTemp->index == rhs->asTemp()->index) { // Y = X / Y -> Tmp = Y; Y = X / Tmp
- as->moveDouble(as->toDoubleRegister(rhs, Assembler::FPGpr1), Assembler::FPGpr1);
- as->divDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), Assembler::FPGpr1, targetReg);
+ as->moveDouble(as->toDoubleRegister(rhs, JITAssembler::FPGpr1), JITAssembler::FPGpr1);
+ as->divDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), JITAssembler::FPGpr1, targetReg);
break;
}
- as->divDouble(as->toDoubleRegister(lhs, Assembler::FPGpr0), as->toDoubleRegister(rhs, Assembler::FPGpr1), targetReg);
+ as->divDouble(as->toDoubleRegister(lhs, JITAssembler::FPGpr0), as->toDoubleRegister(rhs, JITAssembler::FPGpr1), targetReg);
break;
default: {
@@ -271,8 +274,8 @@ void Binop::doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target)
as->storeDouble(targetReg, target);
}
-
-bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
+template <typename JITAssembler>
+bool Binop<JITAssembler>::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
{
Q_ASSERT(leftSource->type == IR::SInt32Type);
Q_ASSERT(rightSource->type == IR::SInt32Type);
@@ -305,7 +308,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
bool inplaceOpWithAddress = false;
IR::Temp *targetTemp = target->asTemp();
- RegisterID targetReg = Assembler::ReturnValueRegister;
+ RegisterID targetReg = JITAssembler::ReturnValueRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
IR::Temp *rhs = rightSource->asTemp();
if (!rhs || rhs->kind != IR::Temp::PhysicalRegister || rhs->index != targetTemp->index) {
@@ -369,12 +372,12 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
&& targetTemp->index == rightSource->asTemp()->index) {
// X = Y - X -> Tmp = X; X = Y; X -= Tmp
targetReg = (RegisterID) targetTemp->index;
- as->move(targetReg, Assembler::ScratchRegister);
+ as->move(targetReg, JITAssembler::ScratchRegister);
as->move(as->toInt32Register(leftSource, targetReg), targetReg);
- as->sub32(Assembler::ScratchRegister, targetReg);
+ as->sub32(JITAssembler::ScratchRegister, targetReg);
} else {
as->move(as->toInt32Register(leftSource, targetReg), targetReg);
- as->sub32(as->toInt32Register(rightSource, Assembler::ScratchRegister), targetReg);
+ as->sub32(as->toInt32Register(rightSource, JITAssembler::ScratchRegister), targetReg);
}
as->storeInt32(targetReg, target);
return true;
@@ -419,7 +422,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
return false;
}
} else if (inplaceOpWithAddress) { // All cases of X = X op [address-of-Y]
- Pointer rhsAddr = as->loadAddress(Assembler::ScratchRegister, rightSource);
+ Pointer rhsAddr = as->loadAddress(JITAssembler::ScratchRegister, rightSource);
switch (op) {
case IR::OpBitAnd: as->and32(rhsAddr, targetReg); break;
case IR::OpBitOr: as->or32 (rhsAddr, targetReg); break;
@@ -433,7 +436,7 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
return false;
}
} else { // All cases of Z = X op Y
- RegisterID r = as->toInt32Register(rightSource, Assembler::ScratchRegister);
+ RegisterID r = as->toInt32Register(rightSource, JITAssembler::ScratchRegister);
switch (op) {
case IR::OpBitAnd: as->and32(l, r, targetReg); break;
case IR::OpBitOr: as->or32 (l, r, targetReg); break;
@@ -452,18 +455,18 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
// Not all CPUs accept shifts over more than 31 bits, and some CPUs (like ARM) will do
// surprising stuff when shifting over 0 bits.
#define CHECK_RHS(op) { \
- as->and32(TrustedImm32(0x1f), r, Assembler::ScratchRegister); \
- Jump notZero = as->branch32(RelationalCondition::NotEqual, Assembler::ScratchRegister, TrustedImm32(0)); \
+ as->and32(TrustedImm32(0x1f), r, JITAssembler::ScratchRegister); \
+ Jump notZero = as->branch32(RelationalCondition::NotEqual, JITAssembler::ScratchRegister, TrustedImm32(0)); \
as->move(l, targetReg); \
Jump done = as->jump(); \
notZero.link(as); \
op; \
done.link(as); \
}
- case IR::OpLShift: CHECK_RHS(as->lshift32(l, Assembler::ScratchRegister, targetReg)); break;
- case IR::OpRShift: CHECK_RHS(as->rshift32(l, Assembler::ScratchRegister, targetReg)); break;
+ case IR::OpLShift: CHECK_RHS(as->lshift32(l, JITAssembler::ScratchRegister, targetReg)); break;
+ case IR::OpRShift: CHECK_RHS(as->rshift32(l, JITAssembler::ScratchRegister, targetReg)); break;
case IR::OpURShift:
- CHECK_RHS(as->urshift32(l, Assembler::ScratchRegister, targetReg));
+ CHECK_RHS(as->urshift32(l, JITAssembler::ScratchRegister, targetReg));
as->storeUInt32(targetReg, target);
// IMPORTANT: do NOT do a break here! The stored type of an urshift is different from the other binary operations!
return true;
@@ -481,17 +484,19 @@ bool Binop::int32Binop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *ta
return true;
}
-static inline Assembler::FPRegisterID getFreeFPReg(IR::Expr *shouldNotOverlap, unsigned hint)
+template <typename JITAssembler>
+inline typename JITAssembler::FPRegisterID getFreeFPReg(IR::Expr *shouldNotOverlap, unsigned hint)
{
if (IR::Temp *t = shouldNotOverlap->asTemp())
if (t->type == IR::DoubleType)
if (t->kind == IR::Temp::PhysicalRegister)
if (t->index == hint)
- return Assembler::FPRegisterID(hint + 1);
- return Assembler::FPRegisterID(hint);
+ return typename JITAssembler::FPRegisterID(hint + 1);
+ return typename JITAssembler::FPRegisterID(hint);
}
-Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
+template <typename JITAssembler>
+typename JITAssembler::Jump Binop<JITAssembler>::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
{
Jump done;
@@ -505,8 +510,8 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
// register.
switch (op) {
case IR::OpAdd: {
- FPRegisterID lReg = getFreeFPReg(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg(leftSource, 4);
+ FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
+ FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
@@ -520,8 +525,8 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
rightIsNoDbl.link(as);
} break;
case IR::OpMul: {
- FPRegisterID lReg = getFreeFPReg(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg(leftSource, 4);
+ FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
+ FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
@@ -535,8 +540,8 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
rightIsNoDbl.link(as);
} break;
case IR::OpSub: {
- FPRegisterID lReg = getFreeFPReg(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg(leftSource, 4);
+ FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
+ FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
@@ -550,8 +555,8 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
rightIsNoDbl.link(as);
} break;
case IR::OpDiv: {
- FPRegisterID lReg = getFreeFPReg(rightSource, 2);
- FPRegisterID rReg = getFreeFPReg(leftSource, 4);
+ FPRegisterID lReg = getFreeFPReg<JITAssembler>(rightSource, 2);
+ FPRegisterID rReg = getFreeFPReg<JITAssembler>(leftSource, 4);
Jump leftIsNoDbl = as->genTryDoubleConversion(leftSource, lReg);
Jump rightIsNoDbl = as->genTryDoubleConversion(rightSource, rReg);
@@ -571,4 +576,9 @@ Assembler::Jump Binop::genInlineBinop(IR::Expr *leftSource, IR::Expr *rightSourc
return done;
}
+template struct QV4::JIT::Binop<QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>>;
+#if defined(V4_BOOTSTRAP) && CPU(X86_64)
+template struct QV4::JIT::Binop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>>;
+#endif
+
#endif
diff --git a/src/qml/jit/qv4binop_p.h b/src/qml/jit/qv4binop_p.h
index 3742e99e5a..d2d9ba7753 100644
--- a/src/qml/jit/qv4binop_p.h
+++ b/src/qml/jit/qv4binop_p.h
@@ -61,21 +61,22 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
+template <typename JITAssembler>
struct Binop {
- Binop(Assembler *assembler, IR::AluOp operation)
+ Binop(JITAssembler *assembler, IR::AluOp operation)
: as(assembler)
, op(operation)
{}
- using Jump = Assembler::Jump;
- using Address = Assembler::Address;
- using RegisterID = Assembler::RegisterID;
- using FPRegisterID = Assembler::FPRegisterID;
- using TrustedImm32 = Assembler::TrustedImm32;
- using ResultCondition = Assembler::ResultCondition;
- using RelationalCondition = Assembler::RelationalCondition;
- using Pointer = Assembler::Pointer;
- using PointerToValue = Assembler::PointerToValue;
+ using Jump = typename JITAssembler::Jump;
+ using Address = typename JITAssembler::Address;
+ using RegisterID = typename JITAssembler::RegisterID;
+ using FPRegisterID = typename JITAssembler::FPRegisterID;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+ using ResultCondition = typename JITAssembler::ResultCondition;
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using Pointer = typename JITAssembler::Pointer;
+ using PointerToValue = typename JITAssembler::PointerToValue;
void generate(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target);
void doubleBinop(IR::Expr *lhs, IR::Expr *rhs, IR::Expr *target);
@@ -103,8 +104,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
return as->branchAdd32(ResultCondition::Overflow, addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- return as->branchAdd32(ResultCondition::Overflow, Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ return as->branchAdd32(ResultCondition::Overflow, JITAssembler::ScratchRegister, reg);
#endif
}
@@ -118,8 +119,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
return as->branchSub32(ResultCondition::Overflow, addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- return as->branchSub32(ResultCondition::Overflow, Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ return as->branchSub32(ResultCondition::Overflow, JITAssembler::ScratchRegister, reg);
#endif
}
@@ -131,10 +132,10 @@ struct Binop {
Jump inline_mul32(Address addr, RegisterID reg)
{
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
- return as->branchMul32(Assembler::Overflow, addr, reg);
+ return as->branchMul32(JITAssembler::Overflow, addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- return as->branchMul32(ResultCondition::Overflow, Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ return as->branchMul32(ResultCondition::Overflow, JITAssembler::ScratchRegister, reg);
#endif
}
@@ -145,9 +146,9 @@ struct Binop {
Jump inline_shl32(Address addr, RegisterID reg)
{
- as->load32(addr, Assembler::ScratchRegister);
- as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister);
- as->lshift32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->and32(TrustedImm32(0x1f), JITAssembler::ScratchRegister);
+ as->lshift32(JITAssembler::ScratchRegister, reg);
return Jump();
}
@@ -160,9 +161,9 @@ struct Binop {
Jump inline_shr32(Address addr, RegisterID reg)
{
- as->load32(addr, Assembler::ScratchRegister);
- as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister);
- as->rshift32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->and32(TrustedImm32(0x1f), JITAssembler::ScratchRegister);
+ as->rshift32(JITAssembler::ScratchRegister, reg);
return Jump();
}
@@ -175,9 +176,9 @@ struct Binop {
Jump inline_ushr32(Address addr, RegisterID reg)
{
- as->load32(addr, Assembler::ScratchRegister);
- as->and32(TrustedImm32(0x1f), Assembler::ScratchRegister);
- as->urshift32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->and32(TrustedImm32(0x1f), JITAssembler::ScratchRegister);
+ as->urshift32(JITAssembler::ScratchRegister, reg);
return as->branchTest32(ResultCondition::Signed, reg, reg);
}
@@ -193,8 +194,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
as->and32(addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- as->and32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->and32(JITAssembler::ScratchRegister, reg);
#endif
return Jump();
}
@@ -210,8 +211,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
as->or32(addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- as->or32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->or32(JITAssembler::ScratchRegister, reg);
#endif
return Jump();
}
@@ -227,8 +228,8 @@ struct Binop {
#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
as->xor32(addr, reg);
#else
- as->load32(addr, Assembler::ScratchRegister);
- as->xor32(Assembler::ScratchRegister, reg);
+ as->load32(addr, JITAssembler::ScratchRegister);
+ as->xor32(JITAssembler::ScratchRegister, reg);
#endif
return Jump();
}
@@ -241,7 +242,7 @@ struct Binop {
- Assembler *as;
+ JITAssembler *as;
IR::AluOp op;
};
diff --git a/src/qml/jit/qv4isel_masm.cpp b/src/qml/jit/qv4isel_masm.cpp
index 20752b5c34..b1134d2bec 100644
--- a/src/qml/jit/qv4isel_masm.cpp
+++ b/src/qml/jit/qv4isel_masm.cpp
@@ -39,11 +39,7 @@
#include "qv4isel_masm_p.h"
#include "qv4runtime_p.h"
-#include "qv4object_p.h"
-#include "qv4functionobject_p.h"
-#include "qv4regexpobject_p.h"
#include "qv4lookup_p.h"
-#include "qv4function_p.h"
#include "qv4ssa_p.h"
#include "qv4regalloc_p.h"
#include "qv4assembler_p.h"
@@ -68,7 +64,8 @@ using namespace QV4;
using namespace QV4::JIT;
-InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
+template <typename JITAssembler>
+InstructionSelection<JITAssembler>::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, Compiler::JSUnitGenerator *jsGenerator, EvalISelFactory *iselFactory)
: EvalInstructionSelection(execAllocator, module, jsGenerator, iselFactory)
, _block(0)
, _as(0)
@@ -79,12 +76,14 @@ InstructionSelection::InstructionSelection(QQmlEnginePrivate *qmlEngine, QV4::Ex
module->unitFlags |= QV4::CompiledData::Unit::ContainsMachineCode;
}
-InstructionSelection::~InstructionSelection()
+template <typename JITAssembler>
+InstructionSelection<JITAssembler>::~InstructionSelection()
{
delete _as;
}
-void InstructionSelection::run(int functionIndex)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::run(int functionIndex)
{
IR::Function *function = irModule->functions[functionIndex];
qSwap(_function, function);
@@ -93,8 +92,8 @@ void InstructionSelection::run(int functionIndex)
opt.run(qmlEngine);
static const bool withRegisterAllocator = qEnvironmentVariableIsEmpty("QV4_NO_REGALLOC");
- if (Assembler::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) {
- RegisterAllocator regalloc(Assembler::getRegisterInfo());
+ if (JITTargetPlatform::RegAllocIsSupported && opt.isInSSA() && withRegisterAllocator) {
+ RegisterAllocator regalloc(JITTargetPlatform::getRegisterInfo());
regalloc.run(_function, opt);
calculateRegistersToSave(regalloc.usedRegisters());
} else {
@@ -103,47 +102,47 @@ void InstructionSelection::run(int functionIndex)
opt.convertOutOfSSA();
ConvertTemps().toStackSlots(_function);
IR::Optimizer::showMeTheCode(_function, "After stack slot allocation");
- calculateRegistersToSave(Assembler::getRegisterInfo()); // FIXME: this saves all registers. We can probably do with a subset: those that are not used by the register allocator.
+ calculateRegistersToSave(JITTargetPlatform::getRegisterInfo()); // FIXME: this saves all registers. We can probably do with a subset: those that are not used by the register allocator.
}
BitVector removableJumps = opt.calculateOptionalJumps();
qSwap(_removableJumps, removableJumps);
- Assembler* oldAssembler = _as;
- _as = new Assembler(jsGenerator, _function, executableAllocator);
+ JITAssembler* oldAssembler = _as;
+ _as = new JITAssembler(jsGenerator, _function, executableAllocator);
_as->setStackLayout(6, // 6 == max argc for calls to built-ins with an argument array
regularRegistersToSave.size(),
fpRegistersToSave.size());
_as->enterStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
#ifdef ARGUMENTS_IN_REGISTERS
- _as->move(_as->registerForArgument(0), Assembler::EngineRegister);
+ _as->move(_as->registerForArgument(0), JITTargetPlatform::EngineRegister);
#else
- _as->loadPtr(addressForArgument(0), Assembler::EngineRegister);
+ _as->loadPtr(addressForArgument(0), JITTargetPlatform::EngineRegister);
#endif
const int locals = _as->stackLayout().calculateJSStackFrameSize();
if (locals > 0) {
- _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)), Assembler::LocalsRegister);
+ _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)), JITTargetPlatform::LocalsRegister);
#ifdef VALUE_FITS_IN_REGISTER
- _as->move(Assembler::TrustedImm64(0), Assembler::ReturnValueRegister);
- _as->move(Assembler::TrustedImm32(locals), Assembler::ScratchRegister);
- Assembler::Label loop = _as->label();
- _as->store64(Assembler::ReturnValueRegister, Assembler::Address(Assembler::LocalsRegister));
- _as->add64(Assembler::TrustedImm32(8), Assembler::LocalsRegister);
- Assembler::Jump jump = _as->branchSub32(Assembler::NonZero, Assembler::TrustedImm32(1), Assembler::ScratchRegister);
+ _as->move(TrustedImm64(0), JITTargetPlatform::ReturnValueRegister);
+ _as->move(TrustedImm32(locals), JITTargetPlatform::ScratchRegister);
+ Label loop = _as->label();
+ _as->store64(JITTargetPlatform::ReturnValueRegister, Address(JITTargetPlatform::LocalsRegister));
+ _as->add64(TrustedImm32(8), JITTargetPlatform::LocalsRegister);
+ Jump jump = _as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), JITTargetPlatform::ScratchRegister);
jump.linkTo(loop, _as);
#else
- _as->move(Assembler::TrustedImm32(0), Assembler::ReturnValueRegister);
- _as->move(Assembler::TrustedImm32(locals), Assembler::ScratchRegister);
- Assembler::Label loop = _as->label();
- _as->store32(Assembler::ReturnValueRegister, Assembler::Address(Assembler::LocalsRegister));
- _as->add32(Assembler::TrustedImm32(4), Assembler::LocalsRegister);
- _as->store32(Assembler::ReturnValueRegister, Assembler::Address(Assembler::LocalsRegister));
- _as->add32(Assembler::TrustedImm32(4), Assembler::LocalsRegister);
- Assembler::Jump jump = _as->branchSub32(Assembler::NonZero, Assembler::TrustedImm32(1), Assembler::ScratchRegister);
+ _as->move(TrustedImm32(0), JITTargetPlatform::ReturnValueRegister);
+ _as->move(TrustedImm32(locals), JITTargetPlatform::ScratchRegister);
+ Label loop = _as->label();
+ _as->store32(JITTargetPlatform::ReturnValueRegister, Address(JITTargetPlatform::LocalsRegister));
+ _as->add32(TrustedImm32(4), JITTargetPlatform::LocalsRegister);
+ _as->store32(JITTargetPlatform::ReturnValueRegister, Address(JITTargetPlatform::LocalsRegister));
+ _as->add32(TrustedImm32(4), JITTargetPlatform::LocalsRegister);
+ Jump jump = _as->branchSub32(ResultCondition::NonZero, TrustedImm32(1), JITTargetPlatform::ScratchRegister);
jump.linkTo(loop, _as);
#endif
- _as->storePtr(Assembler::LocalsRegister, Address(Assembler::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
+ _as->storePtr(JITTargetPlatform::LocalsRegister, Address(JITTargetPlatform::EngineRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
}
@@ -158,9 +157,9 @@ void InstructionSelection::run(int functionIndex)
for (IR::Stmt *s : _block->statements()) {
if (s->location.isValid()) {
if (int(s->location.startLine) != lastLine) {
- _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
- Assembler::Address lineAddr(Assembler::ScratchRegister, qOffsetOf(QV4::ExecutionContext::Data, lineNumber));
- _as->store32(Assembler::TrustedImm32(s->location.startLine), lineAddr);
+ _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister);
+ Address lineAddr(JITTargetPlatform::ScratchRegister, qOffsetOf(QV4::ExecutionContext::Data, lineNumber));
+ _as->store32(TrustedImm32(s->location.startLine), lineAddr);
lastLine = s->location.startLine;
}
}
@@ -181,165 +180,187 @@ void InstructionSelection::run(int functionIndex)
qSwap(_removableJumps, removableJumps);
}
-QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection::backendCompileStep()
+template <typename JITAssembler>
+QQmlRefPointer<QV4::CompiledData::CompilationUnit> InstructionSelection<JITAssembler>::backendCompileStep()
{
QQmlRefPointer<QV4::CompiledData::CompilationUnit> result;
result.adopt(compilationUnit.take());
return result;
}
-void InstructionSelection::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinInvalid(IR::Name *func, IR::ExprList *args, IR::Expr *result)
{
prepareCallData(args, 0);
if (useFastLookups && func->global) {
uint index = registerGlobalGetterLookup(*func->id);
- generateRuntimeCall(result, callGlobalLookup,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(index),
+ generateRuntimeCall(_as, result, callGlobalLookup,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(index),
baseAddressForCallData());
} else {
- generateRuntimeCall(result, callActivationProperty,
- Assembler::EngineRegister,
- Assembler::StringToIndex(*func->id),
+ generateRuntimeCall(_as, result, callActivationProperty,
+ JITTargetPlatform::EngineRegister,
+ StringToIndex(*func->id),
baseAddressForCallData());
}
}
-void InstructionSelection::callBuiltinTypeofQmlContextProperty(IR::Expr *base,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofQmlContextProperty(IR::Expr *base,
IR::Member::MemberKind kind,
int propertyIndex, IR::Expr *result)
{
if (kind == IR::Member::MemberOfQmlScopeObject) {
- generateRuntimeCall(result, typeofScopeObjectProperty, Assembler::EngineRegister,
- Assembler::PointerToValue(base),
- Assembler::TrustedImm32(propertyIndex));
+ generateRuntimeCall(_as, result, typeofScopeObjectProperty, JITTargetPlatform::EngineRegister,
+ PointerToValue(base),
+ TrustedImm32(propertyIndex));
} else if (kind == IR::Member::MemberOfQmlContextObject) {
- generateRuntimeCall(result, typeofContextObjectProperty,
- Assembler::EngineRegister, Assembler::PointerToValue(base),
- Assembler::TrustedImm32(propertyIndex));
+ generateRuntimeCall(_as, result, typeofContextObjectProperty,
+ JITTargetPlatform::EngineRegister, PointerToValue(base),
+ TrustedImm32(propertyIndex));
} else {
Q_UNREACHABLE();
}
}
-void InstructionSelection::callBuiltinTypeofMember(IR::Expr *base, const QString &name,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofMember(IR::Expr *base, const QString &name,
IR::Expr *result)
{
- generateRuntimeCall(result, typeofMember, Assembler::EngineRegister,
- Assembler::PointerToValue(base), Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, result, typeofMember, JITTargetPlatform::EngineRegister,
+ PointerToValue(base), StringToIndex(name));
}
-void InstructionSelection::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofSubscript(IR::Expr *base, IR::Expr *index,
IR::Expr *result)
{
- generateRuntimeCall(result, typeofElement,
- Assembler::EngineRegister,
- Assembler::PointerToValue(base), Assembler::PointerToValue(index));
+ generateRuntimeCall(_as, result, typeofElement,
+ JITTargetPlatform::EngineRegister,
+ PointerToValue(base), PointerToValue(index));
}
-void InstructionSelection::callBuiltinTypeofName(const QString &name, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofName(const QString &name, IR::Expr *result)
{
- generateRuntimeCall(result, typeofName, Assembler::EngineRegister,
- Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, result, typeofName, JITTargetPlatform::EngineRegister,
+ StringToIndex(name));
}
-void InstructionSelection::callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinTypeofValue(IR::Expr *value, IR::Expr *result)
{
- generateRuntimeCall(result, typeofValue, Assembler::EngineRegister,
- Assembler::PointerToValue(value));
+ generateRuntimeCall(_as, result, typeofValue, JITTargetPlatform::EngineRegister,
+ PointerToValue(value));
}
-void InstructionSelection::callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeleteMember(IR::Expr *base, const QString &name, IR::Expr *result)
{
- generateRuntimeCall(result, deleteMember, Assembler::EngineRegister,
- Assembler::Reference(base), Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, result, deleteMember, JITTargetPlatform::EngineRegister,
+ Reference(base), StringToIndex(name));
}
-void InstructionSelection::callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeleteSubscript(IR::Expr *base, IR::Expr *index,
IR::Expr *result)
{
- generateRuntimeCall(result, deleteElement, Assembler::EngineRegister,
- Assembler::Reference(base), Assembler::PointerToValue(index));
+ generateRuntimeCall(_as, result, deleteElement, JITTargetPlatform::EngineRegister,
+ Reference(base), PointerToValue(index));
}
-void InstructionSelection::callBuiltinDeleteName(const QString &name, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeleteName(const QString &name, IR::Expr *result)
{
- generateRuntimeCall(result, deleteName, Assembler::EngineRegister,
- Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, result, deleteName, JITTargetPlatform::EngineRegister,
+ StringToIndex(name));
}
-void InstructionSelection::callBuiltinDeleteValue(IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeleteValue(IR::Expr *result)
{
_as->storeValue(Primitive::fromBoolean(false), result);
}
-void InstructionSelection::callBuiltinThrow(IR::Expr *arg)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinThrow(IR::Expr *arg)
{
- generateRuntimeCall(Assembler::ReturnValueRegister, throwException, Assembler::EngineRegister,
- Assembler::PointerToValue(arg));
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, throwException, JITTargetPlatform::EngineRegister,
+ PointerToValue(arg));
}
-void InstructionSelection::callBuiltinReThrow()
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinReThrow()
{
_as->jumpToExceptionHandler();
}
-void InstructionSelection::callBuiltinUnwindException(IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinUnwindException(IR::Expr *result)
{
- generateRuntimeCall(result, unwindException, Assembler::EngineRegister);
+ generateRuntimeCall(_as, result, unwindException, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callBuiltinPushCatchScope(const QString &exceptionName)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinPushCatchScope(const QString &exceptionName)
{
- generateRuntimeCall(Assembler::Void, pushCatchScope, Assembler::EngineRegister, Assembler::StringToIndex(exceptionName));
+ generateRuntimeCall(_as, JITAssembler::Void, pushCatchScope, JITTargetPlatform::EngineRegister, StringToIndex(exceptionName));
}
-void InstructionSelection::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinForeachIteratorObject(IR::Expr *arg, IR::Expr *result)
{
Q_ASSERT(arg);
Q_ASSERT(result);
- generateRuntimeCall(result, foreachIterator, Assembler::EngineRegister, Assembler::PointerToValue(arg));
+ generateRuntimeCall(_as, result, foreachIterator, JITTargetPlatform::EngineRegister, PointerToValue(arg));
}
-void InstructionSelection::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinForeachNextPropertyname(IR::Expr *arg, IR::Expr *result)
{
Q_ASSERT(arg);
Q_ASSERT(result);
- generateRuntimeCall(result, foreachNextPropertyName, Assembler::Reference(arg));
+ generateRuntimeCall(_as, result, foreachNextPropertyName, Reference(arg));
}
-void InstructionSelection::callBuiltinPushWithScope(IR::Expr *arg)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinPushWithScope(IR::Expr *arg)
{
Q_ASSERT(arg);
- generateRuntimeCall(Assembler::Void, pushWithScope, Assembler::Reference(arg), Assembler::EngineRegister);
+ generateRuntimeCall(_as, JITAssembler::Void, pushWithScope, Reference(arg), JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callBuiltinPopScope()
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinPopScope()
{
- generateRuntimeCall(Assembler::Void, popScope, Assembler::EngineRegister);
+ generateRuntimeCall(_as, JITAssembler::Void, popScope, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &name)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDeclareVar(bool deletable, const QString &name)
{
- generateRuntimeCall(Assembler::Void, declareVar, Assembler::EngineRegister,
- Assembler::TrustedImm32(deletable), Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, JITAssembler::Void, declareVar, JITTargetPlatform::EngineRegister,
+ TrustedImm32(deletable), StringToIndex(name));
}
-void InstructionSelection::callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDefineArray(IR::Expr *result, IR::ExprList *args)
{
Q_ASSERT(result);
int length = prepareVariableArguments(args);
- generateRuntimeCall(result, arrayLiteral, Assembler::EngineRegister,
- baseAddressForCallArguments(), Assembler::TrustedImm32(length));
+ generateRuntimeCall(_as, result, arrayLiteral, JITTargetPlatform::EngineRegister,
+ baseAddressForCallArguments(), TrustedImm32(length));
}
-void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinDefineObjectLiteral(IR::Expr *result, int keyValuePairCount, IR::ExprList *keyValuePairs, IR::ExprList *arrayEntries, bool needSparseArray)
{
Q_ASSERT(result);
@@ -415,81 +436,89 @@ void InstructionSelection::callBuiltinDefineObjectLiteral(IR::Expr *result, int
it = it->next;
}
- generateRuntimeCall(result, objectLiteral, Assembler::EngineRegister,
- baseAddressForCallArguments(), Assembler::TrustedImm32(classId),
- Assembler::TrustedImm32(arrayValueCount), Assembler::TrustedImm32(arrayGetterSetterCount | (needSparseArray << 30)));
+ generateRuntimeCall(_as, result, objectLiteral, JITTargetPlatform::EngineRegister,
+ baseAddressForCallArguments(), TrustedImm32(classId),
+ TrustedImm32(arrayValueCount), TrustedImm32(arrayGetterSetterCount | (needSparseArray << 30)));
}
-void InstructionSelection::callBuiltinSetupArgumentObject(IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinSetupArgumentObject(IR::Expr *result)
{
- generateRuntimeCall(result, setupArgumentsObject, Assembler::EngineRegister);
+ generateRuntimeCall(_as, result, setupArgumentsObject, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callBuiltinConvertThisToObject()
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callBuiltinConvertThisToObject()
{
- generateRuntimeCall(Assembler::Void, convertThisToObject, Assembler::EngineRegister);
+ generateRuntimeCall(_as, JITAssembler::Void, convertThisToObject, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
{
Q_ASSERT(value);
prepareCallData(args, 0);
if (value->asConst())
- generateRuntimeCall(result, callValue, Assembler::EngineRegister,
- Assembler::PointerToValue(value),
+ generateRuntimeCall(_as, result, callValue, JITTargetPlatform::EngineRegister,
+ PointerToValue(value),
baseAddressForCallData());
else
- generateRuntimeCall(result, callValue, Assembler::EngineRegister,
- Assembler::Reference(value),
+ generateRuntimeCall(_as, result, callValue, JITTargetPlatform::EngineRegister,
+ Reference(value),
baseAddressForCallData());
}
-void InstructionSelection::loadThisObject(IR::Expr *temp)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadThisObject(IR::Expr *temp)
{
- _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
- _as->loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), Assembler::ScratchRegister);
+ _as->loadPtr(Address(JITTargetPlatform::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), JITTargetPlatform::ScratchRegister);
+ _as->loadPtr(Address(JITTargetPlatform::ScratchRegister, qOffsetOf(ExecutionContext::Data, callData)), JITTargetPlatform::ScratchRegister);
#if defined(VALUE_FITS_IN_REGISTER)
- _as->load64(Pointer(Assembler::ScratchRegister, qOffsetOf(CallData, thisObject)),
- Assembler::ReturnValueRegister);
+ _as->load64(Pointer(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject)),
+ JITTargetPlatform::ReturnValueRegister);
_as->storeReturnValue(temp);
#else
- _as->copyValue(temp, Pointer(Assembler::ScratchRegister, qOffsetOf(CallData, thisObject)));
+ _as->copyValue(temp, Pointer(JITTargetPlatform::ScratchRegister, qOffsetOf(CallData, thisObject)));
#endif
}
-void InstructionSelection::loadQmlContext(IR::Expr *temp)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadQmlContext(IR::Expr *temp)
{
- generateRuntimeCall(temp, getQmlContext, Assembler::EngineRegister);
+ generateRuntimeCall(_as, temp, getQmlContext, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::loadQmlImportedScripts(IR::Expr *temp)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadQmlImportedScripts(IR::Expr *temp)
{
- generateRuntimeCall(temp, getQmlImportedScripts, Assembler::EngineRegister);
+ generateRuntimeCall(_as, temp, getQmlImportedScripts, JITTargetPlatform::EngineRegister);
}
-void InstructionSelection::loadQmlSingleton(const QString &name, IR::Expr *temp)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadQmlSingleton(const QString &name, IR::Expr *temp)
{
- generateRuntimeCall(temp, getQmlSingleton, Assembler::EngineRegister, Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, temp, getQmlSingleton, JITTargetPlatform::EngineRegister, StringToIndex(name));
}
-void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadConst(IR::Const *sourceConst, IR::Expr *target)
{
if (IR::Temp *targetTemp = target->asTemp()) {
if (targetTemp->kind == IR::Temp::PhysicalRegister) {
if (targetTemp->type == IR::DoubleType) {
Q_ASSERT(sourceConst->type == IR::DoubleType);
- _as->toDoubleRegister(sourceConst, (Assembler::FPRegisterID) targetTemp->index);
+ _as->toDoubleRegister(sourceConst, (FPRegisterID) targetTemp->index);
} else if (targetTemp->type == IR::SInt32Type) {
Q_ASSERT(sourceConst->type == IR::SInt32Type);
- _as->toInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index);
+ _as->toInt32Register(sourceConst, (RegisterID) targetTemp->index);
} else if (targetTemp->type == IR::UInt32Type) {
Q_ASSERT(sourceConst->type == IR::UInt32Type);
- _as->toUInt32Register(sourceConst, (Assembler::RegisterID) targetTemp->index);
+ _as->toUInt32Register(sourceConst, (RegisterID) targetTemp->index);
} else if (targetTemp->type == IR::BoolType) {
Q_ASSERT(sourceConst->type == IR::BoolType);
- _as->move(Assembler::TrustedImm32(convertToValue(sourceConst).int_32()),
- (Assembler::RegisterID) targetTemp->index);
+ _as->move(TrustedImm32(convertToValue(sourceConst).int_32()),
+ (RegisterID) targetTemp->index);
} else {
Q_UNREACHABLE();
}
@@ -500,147 +529,155 @@ void InstructionSelection::loadConst(IR::Const *sourceConst, IR::Expr *target)
_as->storeValue(convertToValue(sourceConst), target);
}
-void InstructionSelection::loadString(const QString &str, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadString(const QString &str, IR::Expr *target)
{
- Pointer srcAddr = _as->loadStringAddress(Assembler::ReturnValueRegister, str);
- _as->loadPtr(srcAddr, Assembler::ReturnValueRegister);
- Pointer destAddr = _as->loadAddress(Assembler::ScratchRegister, target);
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- _as->store64(Assembler::ReturnValueRegister, destAddr);
-#else
- _as->store32(Assembler::ReturnValueRegister, destAddr);
- destAddr.offset += 4;
- _as->store32(Assembler::TrustedImm32(QV4::Value::Managed_Type_Internal), destAddr);
-#endif
+ Pointer srcAddr = _as->loadStringAddress(JITTargetPlatform::ReturnValueRegister, str);
+ _as->loadPtr(srcAddr, JITTargetPlatform::ReturnValueRegister);
+ Pointer destAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, target);
+ JITAssembler::RegisterSizeDependentOps::loadManagedPointer(_as, JITTargetPlatform::ReturnValueRegister, destAddr);
}
-void InstructionSelection::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::loadRegexp(IR::RegExp *sourceRegexp, IR::Expr *target)
{
int id = registerRegExp(sourceRegexp);
- generateRuntimeCall(target, regexpLiteral, Assembler::EngineRegister, Assembler::TrustedImm32(id));
+ generateRuntimeCall(_as, target, regexpLiteral, JITTargetPlatform::EngineRegister, TrustedImm32(id));
}
-void InstructionSelection::getActivationProperty(const IR::Name *name, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getActivationProperty(const IR::Name *name, IR::Expr *target)
{
if (useFastLookups && name->global) {
uint index = registerGlobalGetterLookup(*name->id);
- generateLookupCall(target, index, qOffsetOf(QV4::Lookup, globalGetter), Assembler::EngineRegister, Assembler::Void);
+ generateLookupCall(target, index, qOffsetOf(QV4::Lookup, globalGetter), JITTargetPlatform::EngineRegister, JITAssembler::Void);
return;
}
- generateRuntimeCall(target, getActivationProperty, Assembler::EngineRegister, Assembler::StringToIndex(*name->id));
+ generateRuntimeCall(_as, target, getActivationProperty, JITTargetPlatform::EngineRegister, StringToIndex(*name->id));
}
-void InstructionSelection::setActivationProperty(IR::Expr *source, const QString &targetName)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setActivationProperty(IR::Expr *source, const QString &targetName)
{
// ### should use a lookup call here
- generateRuntimeCall(Assembler::Void, setActivationProperty,
- Assembler::EngineRegister, Assembler::StringToIndex(targetName), Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setActivationProperty,
+ JITTargetPlatform::EngineRegister, StringToIndex(targetName), PointerToValue(source));
}
-void InstructionSelection::initClosure(IR::Closure *closure, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::initClosure(IR::Closure *closure, IR::Expr *target)
{
int id = closure->value;
- generateRuntimeCall(target, closure, Assembler::EngineRegister, Assembler::TrustedImm32(id));
+ generateRuntimeCall(_as, target, closure, JITTargetPlatform::EngineRegister, TrustedImm32(id));
}
-void InstructionSelection::getProperty(IR::Expr *base, const QString &name, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getProperty(IR::Expr *base, const QString &name, IR::Expr *target)
{
if (useFastLookups) {
uint index = registerGetterLookup(name);
- generateLookupCall(target, index, qOffsetOf(QV4::Lookup, getter), Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::Void);
+ generateLookupCall(target, index, qOffsetOf(QV4::Lookup, getter), JITTargetPlatform::EngineRegister, PointerToValue(base), JITAssembler::Void);
} else {
- generateRuntimeCall(target, getProperty, Assembler::EngineRegister,
- Assembler::PointerToValue(base), Assembler::StringToIndex(name));
+ generateRuntimeCall(_as, target, getProperty, JITTargetPlatform::EngineRegister,
+ PointerToValue(base), StringToIndex(name));
}
}
-void InstructionSelection::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int index, bool captureRequired, IR::Expr *target)
{
if (kind == IR::Member::MemberOfQmlScopeObject)
- generateRuntimeCall(target, getQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index), Assembler::TrustedImm32(captureRequired));
+ generateRuntimeCall(_as, target, getQmlScopeObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index), TrustedImm32(captureRequired));
else if (kind == IR::Member::MemberOfQmlContextObject)
- generateRuntimeCall(target, getQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index), Assembler::TrustedImm32(captureRequired));
+ generateRuntimeCall(_as, target, getQmlContextObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index), TrustedImm32(captureRequired));
else if (kind == IR::Member::MemberOfIdObjectsArray)
- generateRuntimeCall(target, getQmlIdObject, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(index));
+ generateRuntimeCall(_as, target, getQmlIdObject, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(index));
else
Q_ASSERT(false);
}
-void InstructionSelection::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getQObjectProperty(IR::Expr *base, int propertyIndex, bool captureRequired, bool isSingleton, int attachedPropertiesId, IR::Expr *target)
{
if (attachedPropertiesId != 0)
- generateRuntimeCall(target, getQmlAttachedProperty, Assembler::EngineRegister, Assembler::TrustedImm32(attachedPropertiesId), Assembler::TrustedImm32(propertyIndex));
+ generateRuntimeCall(_as, target, getQmlAttachedProperty, JITTargetPlatform::EngineRegister, TrustedImm32(attachedPropertiesId), TrustedImm32(propertyIndex));
else if (isSingleton)
- generateRuntimeCall(target, getQmlSingletonQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
- Assembler::TrustedImm32(captureRequired));
+ generateRuntimeCall(_as, target, getQmlSingletonQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(propertyIndex),
+ TrustedImm32(captureRequired));
else
- generateRuntimeCall(target, getQmlQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(base), Assembler::TrustedImm32(propertyIndex),
- Assembler::TrustedImm32(captureRequired));
+ generateRuntimeCall(_as, target, getQmlQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(base), TrustedImm32(propertyIndex),
+ TrustedImm32(captureRequired));
}
-void InstructionSelection::setProperty(IR::Expr *source, IR::Expr *targetBase,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setProperty(IR::Expr *source, IR::Expr *targetBase,
const QString &targetName)
{
if (useFastLookups) {
uint index = registerSetterLookup(targetName);
- generateLookupCall(Assembler::Void, index, qOffsetOf(QV4::Lookup, setter),
- Assembler::EngineRegister,
- Assembler::PointerToValue(targetBase),
- Assembler::PointerToValue(source));
+ generateLookupCall(JITAssembler::Void, index, qOffsetOf(QV4::Lookup, setter),
+ JITTargetPlatform::EngineRegister,
+ PointerToValue(targetBase),
+ PointerToValue(source));
} else {
- generateRuntimeCall(Assembler::Void, setProperty, Assembler::EngineRegister,
- Assembler::PointerToValue(targetBase), Assembler::StringToIndex(targetName),
- Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setProperty, JITTargetPlatform::EngineRegister,
+ PointerToValue(targetBase), StringToIndex(targetName),
+ PointerToValue(source));
}
}
-void InstructionSelection::setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setQmlContextProperty(IR::Expr *source, IR::Expr *targetBase, IR::Member::MemberKind kind, int propertyIndex)
{
if (kind == IR::Member::MemberOfQmlScopeObject)
- generateRuntimeCall(Assembler::Void, setQmlScopeObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
- Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setQmlScopeObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase),
+ TrustedImm32(propertyIndex), PointerToValue(source));
else if (kind == IR::Member::MemberOfQmlContextObject)
- generateRuntimeCall(Assembler::Void, setQmlContextObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
- Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setQmlContextObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase),
+ TrustedImm32(propertyIndex), PointerToValue(source));
else
Q_ASSERT(false);
}
-void InstructionSelection::setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setQObjectProperty(IR::Expr *source, IR::Expr *targetBase, int propertyIndex)
{
- generateRuntimeCall(Assembler::Void, setQmlQObjectProperty, Assembler::EngineRegister, Assembler::PointerToValue(targetBase),
- Assembler::TrustedImm32(propertyIndex), Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setQmlQObjectProperty, JITTargetPlatform::EngineRegister, PointerToValue(targetBase),
+ TrustedImm32(propertyIndex), PointerToValue(source));
}
-void InstructionSelection::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::getElement(IR::Expr *base, IR::Expr *index, IR::Expr *target)
{
if (useFastLookups) {
uint lookup = registerIndexedGetterLookup();
generateLookupCall(target, lookup, qOffsetOf(QV4::Lookup, indexedGetter),
- Assembler::PointerToValue(base),
- Assembler::PointerToValue(index));
+ PointerToValue(base),
+ PointerToValue(index));
return;
}
- generateRuntimeCall(target, getElement, Assembler::EngineRegister,
- Assembler::PointerToValue(base), Assembler::PointerToValue(index));
+ generateRuntimeCall(_as, target, getElement, JITTargetPlatform::EngineRegister,
+ PointerToValue(base), PointerToValue(index));
}
-void InstructionSelection::setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::setElement(IR::Expr *source, IR::Expr *targetBase, IR::Expr *targetIndex)
{
if (useFastLookups) {
uint lookup = registerIndexedSetterLookup();
- generateLookupCall(Assembler::Void, lookup, qOffsetOf(QV4::Lookup, indexedSetter),
- Assembler::PointerToValue(targetBase), Assembler::PointerToValue(targetIndex),
- Assembler::PointerToValue(source));
+ generateLookupCall(JITAssembler::Void, lookup, qOffsetOf(QV4::Lookup, indexedSetter),
+ PointerToValue(targetBase), PointerToValue(targetIndex),
+ PointerToValue(source));
return;
}
- generateRuntimeCall(Assembler::Void, setElement, Assembler::EngineRegister,
- Assembler::PointerToValue(targetBase), Assembler::PointerToValue(targetIndex),
- Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITAssembler::Void, setElement, JITTargetPlatform::EngineRegister,
+ PointerToValue(targetBase), PointerToValue(targetIndex),
+ PointerToValue(source));
}
-void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::copyValue(IR::Expr *source, IR::Expr *target)
{
IR::Temp *sourceTemp = source->asTemp();
IR::Temp *targetTemp = target->asTemp();
@@ -655,25 +692,25 @@ void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target)
if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister) {
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister) {
if (sourceTemp->type == IR::DoubleType)
- _as->moveDouble((Assembler::FPRegisterID) sourceTemp->index,
- (Assembler::FPRegisterID) targetTemp->index);
+ _as->moveDouble((FPRegisterID) sourceTemp->index,
+ (FPRegisterID) targetTemp->index);
else
- _as->move((Assembler::RegisterID) sourceTemp->index,
- (Assembler::RegisterID) targetTemp->index);
+ _as->move((RegisterID) sourceTemp->index,
+ (RegisterID) targetTemp->index);
return;
} else {
switch (sourceTemp->type) {
case IR::DoubleType:
- _as->storeDouble((Assembler::FPRegisterID) sourceTemp->index, target);
+ _as->storeDouble((FPRegisterID) sourceTemp->index, target);
break;
case IR::SInt32Type:
- _as->storeInt32((Assembler::RegisterID) sourceTemp->index, target);
+ _as->storeInt32((RegisterID) sourceTemp->index, target);
break;
case IR::UInt32Type:
- _as->storeUInt32((Assembler::RegisterID) sourceTemp->index, target);
+ _as->storeUInt32((RegisterID) sourceTemp->index, target);
break;
case IR::BoolType:
- _as->storeBool((Assembler::RegisterID) sourceTemp->index, target);
+ _as->storeBool((RegisterID) sourceTemp->index, target);
break;
default:
Q_ASSERT(!"Unreachable");
@@ -685,19 +722,19 @@ void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target)
switch (targetTemp->type) {
case IR::DoubleType:
Q_ASSERT(source->type == IR::DoubleType);
- _as->toDoubleRegister(source, (Assembler::FPRegisterID) targetTemp->index);
+ _as->toDoubleRegister(source, (FPRegisterID) targetTemp->index);
return;
case IR::BoolType:
Q_ASSERT(source->type == IR::BoolType);
- _as->toInt32Register(source, (Assembler::RegisterID) targetTemp->index);
+ _as->toInt32Register(source, (RegisterID) targetTemp->index);
return;
case IR::SInt32Type:
Q_ASSERT(source->type == IR::SInt32Type);
- _as->toInt32Register(source, (Assembler::RegisterID) targetTemp->index);
+ _as->toInt32Register(source, (RegisterID) targetTemp->index);
return;
case IR::UInt32Type:
Q_ASSERT(source->type == IR::UInt32Type);
- _as->toUInt32Register(source, (Assembler::RegisterID) targetTemp->index);
+ _as->toUInt32Register(source, (RegisterID) targetTemp->index);
return;
default:
Q_ASSERT(!"Unreachable");
@@ -706,10 +743,11 @@ void InstructionSelection::copyValue(IR::Expr *source, IR::Expr *target)
}
// The target is not a physical register, nor is the source. So we can do a memory-to-memory copy:
- _as->memcopyValue(_as->loadAddress(Assembler::ReturnValueRegister, target), source, Assembler::ScratchRegister);
+ _as->memcopyValue(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, target), source, JITTargetPlatform::ScratchRegister);
}
-void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::swapValues(IR::Expr *source, IR::Expr *target)
{
IR::Temp *sourceTemp = source->asTemp();
IR::Temp *targetTemp = target->asTemp();
@@ -719,26 +757,27 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
Q_ASSERT(sourceTemp->type == targetTemp->type);
if (sourceTemp->type == IR::DoubleType) {
- _as->moveDouble((Assembler::FPRegisterID) targetTemp->index, Assembler::FPGpr0);
- _as->moveDouble((Assembler::FPRegisterID) sourceTemp->index,
- (Assembler::FPRegisterID) targetTemp->index);
- _as->moveDouble(Assembler::FPGpr0, (Assembler::FPRegisterID) sourceTemp->index);
+ _as->moveDouble((FPRegisterID) targetTemp->index, JITTargetPlatform::FPGpr0);
+ _as->moveDouble((FPRegisterID) sourceTemp->index,
+ (FPRegisterID) targetTemp->index);
+ _as->moveDouble(JITTargetPlatform::FPGpr0, (FPRegisterID) sourceTemp->index);
} else {
- _as->swap((Assembler::RegisterID) sourceTemp->index,
- (Assembler::RegisterID) targetTemp->index);
+ _as->swap((RegisterID) sourceTemp->index,
+ (RegisterID) targetTemp->index);
}
return;
}
} else if (!sourceTemp || sourceTemp->kind == IR::Temp::StackSlot) {
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
// Note: a swap for two stack-slots can involve different types.
- Assembler::Pointer sAddr = _as->loadAddress(Assembler::ScratchRegister, source);
- Assembler::Pointer tAddr = _as->loadAddress(Assembler::ReturnValueRegister, target);
+ Pointer sAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer tAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target);
// use the implementation in JSC::MacroAssembler, as it doesn't do bit swizzling
- _as->JSC::MacroAssembler::loadDouble(sAddr, Assembler::FPGpr0);
- _as->JSC::MacroAssembler::loadDouble(tAddr, Assembler::FPGpr1);
- _as->JSC::MacroAssembler::storeDouble(Assembler::FPGpr1, sAddr);
- _as->JSC::MacroAssembler::storeDouble(Assembler::FPGpr0, tAddr);
+ auto platformAs = static_cast<typename JITAssembler::MacroAssembler*>(_as);
+ platformAs->loadDouble(sAddr, JITTargetPlatform::FPGpr0);
+ platformAs->loadDouble(tAddr, JITTargetPlatform::FPGpr1);
+ platformAs->storeDouble(JITTargetPlatform::FPGpr1, sAddr);
+ platformAs->storeDouble(JITTargetPlatform::FPGpr0, tAddr);
return;
}
}
@@ -749,18 +788,18 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
Q_ASSERT(memExpr);
Q_ASSERT(regTemp);
- Assembler::Pointer addr = _as->loadAddress(Assembler::ReturnValueRegister, memExpr);
+ Pointer addr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, memExpr);
if (regTemp->type == IR::DoubleType) {
- _as->loadDouble(addr, Assembler::FPGpr0);
- _as->storeDouble((Assembler::FPRegisterID) regTemp->index, addr);
- _as->moveDouble(Assembler::FPGpr0, (Assembler::FPRegisterID) regTemp->index);
+ _as->loadDouble(addr, JITTargetPlatform::FPGpr0);
+ _as->storeDouble((FPRegisterID) regTemp->index, addr);
+ _as->moveDouble(JITTargetPlatform::FPGpr0, (FPRegisterID) regTemp->index);
} else if (regTemp->type == IR::UInt32Type) {
- _as->toUInt32Register(addr, Assembler::ScratchRegister);
- _as->storeUInt32((Assembler::RegisterID) regTemp->index, addr);
- _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) regTemp->index);
+ _as->toUInt32Register(addr, JITTargetPlatform::ScratchRegister);
+ _as->storeUInt32((RegisterID) regTemp->index, addr);
+ _as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index);
} else {
- _as->load32(addr, Assembler::ScratchRegister);
- _as->store32((Assembler::RegisterID) regTemp->index, addr);
+ _as->load32(addr, JITTargetPlatform::ScratchRegister);
+ _as->store32((RegisterID) regTemp->index, addr);
if (regTemp->type != memExpr->type) {
addr.offset += 4;
quint32 tag;
@@ -775,55 +814,59 @@ void InstructionSelection::swapValues(IR::Expr *source, IR::Expr *target)
tag = 31337; // bogus value
Q_UNREACHABLE();
}
- _as->store32(Assembler::TrustedImm32(tag), addr);
+ _as->store32(TrustedImm32(tag), addr);
}
- _as->move(Assembler::ScratchRegister, (Assembler::RegisterID) regTemp->index);
+ _as->move(JITTargetPlatform::ScratchRegister, (RegisterID) regTemp->index);
}
}
#define setOp(op, opName, operation) \
do { \
- op = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
+ op = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \
} while (0)
#define setOpContext(op, opName, operation) \
do { \
- opContext = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
+ opContext = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); opName = "Runtime::" isel_stringIfy(operation); \
needsExceptionCheck = QV4::Runtime::Method_##operation##_NeedsExceptionCheck; \
} while (0)
-void InstructionSelection::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::unop(IR::AluOp oper, IR::Expr *source, IR::Expr *target)
{
- QV4::JIT::Unop unop(_as, oper);
+ QV4::JIT::Unop<JITAssembler> unop(_as, oper);
unop.generate(source, target);
}
-void InstructionSelection::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target)
{
- QV4::JIT::Binop binop(_as, oper);
+ QV4::JIT::Binop<JITAssembler> binop(_as, oper);
binop.generate(leftSource, rightSource, target);
}
-void InstructionSelection::callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callQmlContextProperty(IR::Expr *base, IR::Member::MemberKind kind, int propertyIndex, IR::ExprList *args, IR::Expr *result)
{
prepareCallData(args, base);
if (kind == IR::Member::MemberOfQmlScopeObject)
- generateRuntimeCall(result, callQmlScopeObjectProperty,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(propertyIndex),
+ generateRuntimeCall(_as, result, callQmlScopeObjectProperty,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(propertyIndex),
baseAddressForCallData());
else if (kind == IR::Member::MemberOfQmlContextObject)
- generateRuntimeCall(result, callQmlContextObjectProperty,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(propertyIndex),
+ generateRuntimeCall(_as, result, callQmlContextObjectProperty,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(propertyIndex),
baseAddressForCallData());
else
Q_ASSERT(false);
}
-void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callProperty(IR::Expr *base, const QString &name, IR::ExprList *args,
IR::Expr *result)
{
Q_ASSERT(base != 0);
@@ -832,29 +875,31 @@ void InstructionSelection::callProperty(IR::Expr *base, const QString &name, IR:
if (useFastLookups) {
uint index = registerGetterLookup(name);
- generateRuntimeCall(result, callPropertyLookup,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(index),
+ generateRuntimeCall(_as, result, callPropertyLookup,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(index),
baseAddressForCallData());
} else {
- generateRuntimeCall(result, callProperty, Assembler::EngineRegister,
- Assembler::StringToIndex(name),
+ generateRuntimeCall(_as, result, callProperty, JITTargetPlatform::EngineRegister,
+ StringToIndex(name),
baseAddressForCallData());
}
}
-void InstructionSelection::callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::callSubscript(IR::Expr *base, IR::Expr *index, IR::ExprList *args,
IR::Expr *result)
{
Q_ASSERT(base != 0);
prepareCallData(args, base);
- generateRuntimeCall(result, callElement, Assembler::EngineRegister,
- Assembler::PointerToValue(index),
+ generateRuntimeCall(_as, result, callElement, JITTargetPlatform::EngineRegister,
+ PointerToValue(index),
baseAddressForCallData());
}
-void InstructionSelection::convertType(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertType(IR::Expr *source, IR::Expr *target)
{
switch (target->type) {
case IR::DoubleType:
@@ -875,7 +920,8 @@ void InstructionSelection::convertType(IR::Expr *source, IR::Expr *target)
}
}
-void InstructionSelection::convertTypeSlowPath(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeSlowPath(IR::Expr *source, IR::Expr *target)
{
Q_ASSERT(target->type != IR::BoolType);
@@ -885,7 +931,8 @@ void InstructionSelection::convertTypeSlowPath(IR::Expr *source, IR::Expr *targe
copyValue(source, target);
}
-void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeToDouble(IR::Expr *source, IR::Expr *target)
{
switch (source->type) {
case IR::SInt32Type:
@@ -897,51 +944,37 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *targe
convertUIntToDouble(source, target);
break;
case IR::UndefinedType:
- _as->loadDouble(_as->loadAddress(Assembler::ScratchRegister, source), Assembler::FPGpr0);
- _as->storeDouble(Assembler::FPGpr0, target);
+ _as->loadDouble(_as->loadAddress(JITTargetPlatform::ScratchRegister, source), JITTargetPlatform::FPGpr0);
+ _as->storeDouble(JITTargetPlatform::FPGpr0, target);
break;
case IR::StringType:
case IR::VarType: {
// load the tag:
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, source);
+ Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
tagAddr.offset += 4;
- _as->load32(tagAddr, Assembler::ScratchRegister);
+ _as->load32(tagAddr, JITTargetPlatform::ScratchRegister);
// check if it's an int32:
- Assembler::Jump isNoInt = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(Value::Integer_Type_Internal));
+ Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
+ TrustedImm32(Value::Integer_Type_Internal));
convertIntToDouble(source, target);
- Assembler::Jump intDone = _as->jump();
+ Jump intDone = _as->jump();
// not an int, check if it's NOT a double:
isNoInt.link(_as);
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- _as->rshift32(Assembler::TrustedImm32(Value::IsDoubleTag_Shift), Assembler::ScratchRegister);
- Assembler::Jump isDbl = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(0));
-#else
- _as->and32(Assembler::TrustedImm32(Value::NotDouble_Mask), Assembler::ScratchRegister);
- Assembler::Jump isDbl = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(Value::NotDouble_Mask));
-#endif
+ Jump isDbl = _as->generateIsDoubleCheck(JITTargetPlatform::ScratchRegister);
- generateRuntimeCall(target, toDouble, Assembler::PointerToValue(source));
- Assembler::Jump noDoubleDone = _as->jump();
+ generateRuntimeCall(_as, target, toDouble, PointerToValue(source));
+ Jump noDoubleDone = _as->jump();
// it is a double:
isDbl.link(_as);
- Assembler::Pointer addr2 = _as->loadAddress(Assembler::ScratchRegister, source);
+ Pointer addr2 = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
IR::Temp *targetTemp = target->asTemp();
if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
-#if Q_PROCESSOR_WORDSIZE == 8
- _as->load64(addr2, Assembler::ScratchRegister);
- _as->store64(Assembler::ScratchRegister, _as->loadAddress(Assembler::ReturnValueRegister, target));
-#else
- _as->loadDouble(addr2, Assembler::FPGpr0);
- _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(Assembler::ReturnValueRegister, target));
-#endif
+ _as->memcopyValue(target, addr2, JITTargetPlatform::FPGpr0, JITTargetPlatform::ReturnValueRegister);
} else {
- _as->loadDouble(addr2, (Assembler::FPRegisterID) targetTemp->index);
+ _as->loadDouble(addr2, (FPRegisterID) targetTemp->index);
}
noDoubleDone.link(_as);
@@ -953,7 +986,8 @@ void InstructionSelection::convertTypeToDouble(IR::Expr *source, IR::Expr *targe
}
}
-void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeToBool(IR::Expr *source, IR::Expr *target)
{
IR::Temp *sourceTemp = source->asTemp();
switch (source->type) {
@@ -965,16 +999,16 @@ void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target)
// The source is in a register if the register allocator is used. If the register
// allocator was not used, then that means that we can use any register for to
// load the double into.
- Assembler::FPRegisterID reg;
+ FPRegisterID reg;
if (sourceTemp && sourceTemp->kind == IR::Temp::PhysicalRegister)
- reg = (Assembler::FPRegisterID) sourceTemp->index;
+ reg = (FPRegisterID) sourceTemp->index;
else
- reg = _as->toDoubleRegister(source, (Assembler::FPRegisterID) 1);
- Assembler::Jump nonZero = _as->branchDoubleNonZero(reg, Assembler::FPGpr0);
+ reg = _as->toDoubleRegister(source, (FPRegisterID) 1);
+ Jump nonZero = _as->branchDoubleNonZero(reg, JITTargetPlatform::FPGpr0);
// it's 0, so false:
_as->storeBool(false, target);
- Assembler::Jump done = _as->jump();
+ Jump done = _as->jump();
// it's non-zero, so true:
nonZero.link(_as);
@@ -988,283 +1022,220 @@ void InstructionSelection::convertTypeToBool(IR::Expr *source, IR::Expr *target)
_as->storeBool(false, target);
break;
case IR::StringType:
- generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean,
- Assembler::PointerToValue(source));
- _as->storeBool(Assembler::ReturnValueRegister, target);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean,
+ PointerToValue(source));
+ _as->storeBool(JITTargetPlatform::ReturnValueRegister, target);
case IR::VarType:
default:
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
- Assembler::Pointer tagAddr = addr;
+ Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ Pointer tagAddr = addr;
tagAddr.offset += 4;
- _as->load32(tagAddr, Assembler::ReturnValueRegister);
+ _as->load32(tagAddr, JITTargetPlatform::ReturnValueRegister);
// checkif it's a bool:
- Assembler::Jump notBool = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister,
- Assembler::TrustedImm32(Value::Boolean_Type_Internal));
- _as->load32(addr, Assembler::ReturnValueRegister);
- Assembler::Jump boolDone = _as->jump();
+ Jump notBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister,
+ TrustedImm32(Value::Boolean_Type_Internal));
+ _as->load32(addr, JITTargetPlatform::ReturnValueRegister);
+ Jump boolDone = _as->jump();
// check if it's an int32:
notBool.link(_as);
- Assembler::Jump fallback = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister,
- Assembler::TrustedImm32(Value::Integer_Type_Internal));
- _as->load32(addr, Assembler::ReturnValueRegister);
- Assembler::Jump isZero = _as->branch32(Assembler::Equal, Assembler::ReturnValueRegister,
- Assembler::TrustedImm32(0));
- _as->move(Assembler::TrustedImm32(1), Assembler::ReturnValueRegister);
- Assembler::Jump intDone = _as->jump();
+ Jump fallback = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ReturnValueRegister,
+ TrustedImm32(Value::Integer_Type_Internal));
+ _as->load32(addr, JITTargetPlatform::ReturnValueRegister);
+ Jump isZero = _as->branch32(RelationalCondition::Equal, JITTargetPlatform::ReturnValueRegister,
+ TrustedImm32(0));
+ _as->move(TrustedImm32(1), JITTargetPlatform::ReturnValueRegister);
+ Jump intDone = _as->jump();
// not an int:
fallback.link(_as);
- generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean,
- Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean,
+ PointerToValue(source));
isZero.link(_as);
intDone.link(_as);
boolDone.link(_as);
- _as->storeBool(Assembler::ReturnValueRegister, target);
+ _as->storeBool(JITTargetPlatform::ReturnValueRegister, target);
break;
}
}
-void InstructionSelection::convertTypeToSInt32(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeToSInt32(IR::Expr *source, IR::Expr *target)
{
switch (source->type) {
case IR::VarType: {
-
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
- _as->load64(addr, Assembler::ScratchRegister);
- _as->move(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
-
- // check if it's integer convertible
- _as->urshift64(Assembler::TrustedImm32(QV4::Value::IsIntegerConvertible_Shift), Assembler::ScratchRegister);
- Assembler::Jump isIntConvertible = _as->branch32(Assembler::Equal, Assembler::ScratchRegister, Assembler::TrustedImm32(3));
-
- // nope, not integer convertible, so check for a double:
- _as->urshift64(Assembler::TrustedImm32(
- QV4::Value::IsDoubleTag_Shift - QV4::Value::IsIntegerConvertible_Shift),
- Assembler::ScratchRegister);
- Assembler::Jump fallback = _as->branch32(Assembler::GreaterThan, Assembler::ScratchRegister, Assembler::TrustedImm32(0));
-
- // it's a double
- _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ScratchRegister);
- _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
- _as->move64ToDouble(Assembler::ReturnValueRegister, Assembler::FPGpr0);
- Assembler::Jump success =
- _as->branchTruncateDoubleToInt32(Assembler::FPGpr0, Assembler::ReturnValueRegister,
- Assembler::BranchIfTruncateSuccessful);
-
- // not an int:
- fallback.link(_as);
- generateRuntimeCall(Assembler::ReturnValueRegister, toInt,
- _as->loadAddress(Assembler::ScratchRegister, source));
-
- isIntConvertible.link(_as);
- success.link(_as);
- IR::Temp *targetTemp = target->asTemp();
- if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
- Assembler::Pointer targetAddr = _as->loadAddress(Assembler::ScratchRegister, target);
- _as->store32(Assembler::ReturnValueRegister, targetAddr);
- targetAddr.offset += 4;
- _as->store32(Assembler::TrustedImm32(Value::Integer_Type_Internal), targetAddr);
- } else {
- _as->storeInt32(Assembler::ReturnValueRegister, target);
- }
-#else
- // load the tag:
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
- Assembler::Pointer tagAddr = addr;
- tagAddr.offset += 4;
- _as->load32(tagAddr, Assembler::ReturnValueRegister);
-
- // check if it's an int32:
- Assembler::Jump fallback = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister,
- Assembler::TrustedImm32(Value::Integer_Type_Internal));
- IR::Temp *targetTemp = target->asTemp();
- if (!targetTemp || targetTemp->kind == IR::Temp::StackSlot) {
- _as->load32(addr, Assembler::ReturnValueRegister);
- Assembler::Pointer targetAddr = _as->loadAddress(Assembler::ScratchRegister, target);
- _as->store32(Assembler::ReturnValueRegister, targetAddr);
- targetAddr.offset += 4;
- _as->store32(Assembler::TrustedImm32(Value::Integer_Type_Internal), targetAddr);
- } else {
- _as->load32(addr, (Assembler::RegisterID) targetTemp->index);
- }
- Assembler::Jump intDone = _as->jump();
-
- // not an int:
- fallback.link(_as);
- generateRuntimeCall(Assembler::ReturnValueRegister, toInt,
- _as->loadAddress(Assembler::ScratchRegister, source));
- _as->storeInt32(Assembler::ReturnValueRegister, target);
-
- intDone.link(_as);
-#endif
-
+ JITAssembler::RegisterSizeDependentOps::convertVarToSInt32(_as, source, target);
} break;
case IR::DoubleType: {
- Assembler::Jump success =
+ Jump success =
_as->branchTruncateDoubleToInt32(_as->toDoubleRegister(source),
- Assembler::ReturnValueRegister,
- Assembler::BranchIfTruncateSuccessful);
- generateRuntimeCall(Assembler::ReturnValueRegister, doubleToInt,
- Assembler::PointerToValue(source));
+ JITTargetPlatform::ReturnValueRegister,
+ BranchTruncateType::BranchIfTruncateSuccessful);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, doubleToInt,
+ PointerToValue(source));
success.link(_as);
- _as->storeInt32(Assembler::ReturnValueRegister, target);
+ _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
} break;
case IR::UInt32Type:
- _as->storeInt32(_as->toUInt32Register(source, Assembler::ReturnValueRegister), target);
+ _as->storeInt32(_as->toUInt32Register(source, JITTargetPlatform::ReturnValueRegister), target);
break;
case IR::NullType:
case IR::UndefinedType:
- _as->move(Assembler::TrustedImm32(0), Assembler::ReturnValueRegister);
- _as->storeInt32(Assembler::ReturnValueRegister, target);
+ _as->move(TrustedImm32(0), JITTargetPlatform::ReturnValueRegister);
+ _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
break;
case IR::BoolType:
- _as->storeInt32(_as->toInt32Register(source, Assembler::ReturnValueRegister), target);
+ _as->storeInt32(_as->toInt32Register(source, JITTargetPlatform::ReturnValueRegister), target);
break;
case IR::StringType:
default:
- generateRuntimeCall(Assembler::ReturnValueRegister, toInt,
- _as->loadAddress(Assembler::ScratchRegister, source));
- _as->storeInt32(Assembler::ReturnValueRegister, target);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toInt,
+ _as->loadAddress(JITTargetPlatform::ScratchRegister, source));
+ _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
break;
} // switch (source->type)
}
-void InstructionSelection::convertTypeToUInt32(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::convertTypeToUInt32(IR::Expr *source, IR::Expr *target)
{
switch (source->type) {
case IR::VarType: {
// load the tag:
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, source);
+ Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
tagAddr.offset += 4;
- _as->load32(tagAddr, Assembler::ScratchRegister);
+ _as->load32(tagAddr, JITTargetPlatform::ScratchRegister);
// check if it's an int32:
- Assembler::Jump isNoInt = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(Value::Integer_Type_Internal));
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, source);
- _as->storeUInt32(_as->toInt32Register(addr, Assembler::ScratchRegister), target);
- Assembler::Jump intDone = _as->jump();
+ Jump isNoInt = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
+ TrustedImm32(Value::Integer_Type_Internal));
+ Pointer addr = _as->loadAddress(JITTargetPlatform::ScratchRegister, source);
+ _as->storeUInt32(_as->toInt32Register(addr, JITTargetPlatform::ScratchRegister), target);
+ Jump intDone = _as->jump();
// not an int:
isNoInt.link(_as);
- generateRuntimeCall(Assembler::ReturnValueRegister, toUInt,
- _as->loadAddress(Assembler::ScratchRegister, source));
- _as->storeInt32(Assembler::ReturnValueRegister, target);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toUInt,
+ _as->loadAddress(JITTargetPlatform::ScratchRegister, source));
+ _as->storeInt32(JITTargetPlatform::ReturnValueRegister, target);
intDone.link(_as);
} break;
case IR::DoubleType: {
- Assembler::FPRegisterID reg = _as->toDoubleRegister(source);
- Assembler::Jump success =
- _as->branchTruncateDoubleToUint32(reg, Assembler::ReturnValueRegister,
- Assembler::BranchIfTruncateSuccessful);
- generateRuntimeCall(Assembler::ReturnValueRegister, doubleToUInt,
- Assembler::PointerToValue(source));
+ FPRegisterID reg = _as->toDoubleRegister(source);
+ Jump success =
+ _as->branchTruncateDoubleToUint32(reg, JITTargetPlatform::ReturnValueRegister,
+ BranchTruncateType::BranchIfTruncateSuccessful);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, doubleToUInt,
+ PointerToValue(source));
success.link(_as);
- _as->storeUInt32(Assembler::ReturnValueRegister, target);
+ _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target);
} break;
case IR::NullType:
case IR::UndefinedType:
- _as->move(Assembler::TrustedImm32(0), Assembler::ReturnValueRegister);
- _as->storeUInt32(Assembler::ReturnValueRegister, target);
+ _as->move(TrustedImm32(0), JITTargetPlatform::ReturnValueRegister);
+ _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target);
break;
case IR::StringType:
- generateRuntimeCall(Assembler::ReturnValueRegister, toUInt,
- Assembler::PointerToValue(source));
- _as->storeUInt32(Assembler::ReturnValueRegister, target);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toUInt,
+ PointerToValue(source));
+ _as->storeUInt32(JITTargetPlatform::ReturnValueRegister, target);
break;
case IR::SInt32Type:
case IR::BoolType:
- _as->storeUInt32(_as->toInt32Register(source, Assembler::ReturnValueRegister), target);
+ _as->storeUInt32(_as->toInt32Register(source, JITTargetPlatform::ReturnValueRegister), target);
break;
default:
break;
} // switch (source->type)
}
-void InstructionSelection::constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::constructActivationProperty(IR::Name *func, IR::ExprList *args, IR::Expr *result)
{
Q_ASSERT(func != 0);
prepareCallData(args, 0);
if (useFastLookups && func->global) {
uint index = registerGlobalGetterLookup(*func->id);
- generateRuntimeCall(result, constructGlobalLookup,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(index), baseAddressForCallData());
+ generateRuntimeCall(_as, result, constructGlobalLookup,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(index), baseAddressForCallData());
return;
}
- generateRuntimeCall(result, constructActivationProperty,
- Assembler::EngineRegister,
- Assembler::StringToIndex(*func->id),
+ generateRuntimeCall(_as, result, constructActivationProperty,
+ JITTargetPlatform::EngineRegister,
+ StringToIndex(*func->id),
baseAddressForCallData());
}
-void InstructionSelection::constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::constructProperty(IR::Expr *base, const QString &name, IR::ExprList *args, IR::Expr *result)
{
prepareCallData(args, base);
if (useFastLookups) {
uint index = registerGetterLookup(name);
- generateRuntimeCall(result, constructPropertyLookup,
- Assembler::EngineRegister,
- Assembler::TrustedImm32(index),
+ generateRuntimeCall(_as, result, constructPropertyLookup,
+ JITTargetPlatform::EngineRegister,
+ TrustedImm32(index),
baseAddressForCallData());
return;
}
- generateRuntimeCall(result, constructProperty, Assembler::EngineRegister,
- Assembler::StringToIndex(name),
+ generateRuntimeCall(_as, result, constructProperty, JITTargetPlatform::EngineRegister,
+ StringToIndex(name),
baseAddressForCallData());
}
-void InstructionSelection::constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::constructValue(IR::Expr *value, IR::ExprList *args, IR::Expr *result)
{
Q_ASSERT(value != 0);
prepareCallData(args, 0);
- generateRuntimeCall(result, constructValue,
- Assembler::EngineRegister,
- Assembler::Reference(value),
+ generateRuntimeCall(_as, result, constructValue,
+ JITTargetPlatform::EngineRegister,
+ Reference(value),
baseAddressForCallData());
}
-void InstructionSelection::visitJump(IR::Jump *s)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitJump(IR::Jump *s)
{
if (!_removableJumps.at(_block->index()))
_as->jumpToBlock(_block, s->target);
}
-void InstructionSelection::visitCJump(IR::CJump *s)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitCJump(IR::CJump *s)
{
IR::Temp *t = s->cond->asTemp();
if (t || s->cond->asArgLocal()) {
- Assembler::RegisterID reg;
+ RegisterID reg;
if (t && t->kind == IR::Temp::PhysicalRegister) {
Q_ASSERT(t->type == IR::BoolType);
- reg = (Assembler::RegisterID) t->index;
+ reg = (RegisterID) t->index;
} else if (t && t->kind == IR::Temp::StackSlot && t->type == IR::BoolType) {
- reg = Assembler::ReturnValueRegister;
+ reg = JITTargetPlatform::ReturnValueRegister;
_as->toInt32Register(t, reg);
} else {
- Address temp = _as->loadAddress(Assembler::ScratchRegister, s->cond);
+ Address temp = _as->loadAddress(JITTargetPlatform::ScratchRegister, s->cond);
Address tag = temp;
tag.offset += QV4::Value::tagOffset();
- Assembler::Jump booleanConversion = _as->branch32(Assembler::NotEqual, tag, Assembler::TrustedImm32(QV4::Value::Boolean_Type_Internal));
+ Jump booleanConversion = _as->branch32(RelationalCondition::NotEqual, tag, TrustedImm32(QV4::Value::Boolean_Type_Internal));
Address data = temp;
data.offset += QV4::Value::valueOffset();
- _as->load32(data, Assembler::ReturnValueRegister);
- Assembler::Jump testBoolean = _as->jump();
+ _as->load32(data, JITTargetPlatform::ReturnValueRegister);
+ Jump testBoolean = _as->jump();
booleanConversion.link(_as);
- reg = Assembler::ReturnValueRegister;
- generateRuntimeCall(reg, toBoolean, Assembler::Reference(s->cond));
+ reg = JITTargetPlatform::ReturnValueRegister;
+ generateRuntimeCall(_as, reg, toBoolean, Reference(s->cond));
testBoolean.link(_as);
}
@@ -1274,9 +1245,9 @@ void InstructionSelection::visitCJump(IR::CJump *s)
} else if (IR::Const *c = s->cond->asConst()) {
// TODO: SSA optimization for constant condition evaluation should remove this.
// See also visitCJump() in RegAllocInfo.
- generateRuntimeCall(Assembler::ReturnValueRegister, toBoolean,
- Assembler::PointerToValue(c));
- _as->generateCJumpOnNonZero(Assembler::ReturnValueRegister, _block, s->iftrue, s->iffalse);
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, toBoolean,
+ PointerToValue(c));
+ _as->generateCJumpOnNonZero(JITTargetPlatform::ReturnValueRegister, _block, s->iftrue, s->iffalse);
return;
} else if (IR::Binop *b = s->cond->asBinop()) {
if (b->left->type == IR::DoubleType && b->right->type == IR::DoubleType
@@ -1296,8 +1267,8 @@ void InstructionSelection::visitCJump(IR::CJump *s)
return;
}
- RuntimeCall op;
- RuntimeCall opContext;
+ typename JITAssembler::RuntimeCall op;
+ typename JITAssembler::RuntimeCall opContext;
const char *opName = 0;
bool needsExceptionCheck;
switch (b->op) {
@@ -1321,165 +1292,30 @@ void InstructionSelection::visitCJump(IR::CJump *s)
// elimination (which isn't there either) would remove the whole else block.
if (opContext.isValid())
_as->generateFunctionCallImp(needsExceptionCheck,
- Assembler::ReturnValueRegister, opName, opContext,
- Assembler::EngineRegister,
- Assembler::PointerToValue(b->left),
- Assembler::PointerToValue(b->right));
+ JITTargetPlatform::ReturnValueRegister, opName, opContext,
+ JITTargetPlatform::EngineRegister,
+ PointerToValue(b->left),
+ PointerToValue(b->right));
else
_as->generateFunctionCallImp(needsExceptionCheck,
- Assembler::ReturnValueRegister, opName, op,
- Assembler::PointerToValue(b->left),
- Assembler::PointerToValue(b->right));
+ JITTargetPlatform::ReturnValueRegister, opName, op,
+ PointerToValue(b->left),
+ PointerToValue(b->right));
- _as->generateCJumpOnNonZero(Assembler::ReturnValueRegister, _block, s->iftrue, s->iffalse);
+ _as->generateCJumpOnNonZero(JITTargetPlatform::ReturnValueRegister, _block, s->iftrue, s->iffalse);
return;
}
Q_UNREACHABLE();
}
-void InstructionSelection::visitRet(IR::Ret *s)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitRet(IR::Ret *s)
{
- if (!s) {
- // this only happens if the method doesn't have a return statement and can
- // only exit through an exception
- } else if (IR::Temp *t = s->expr->asTemp()) {
-#if CPU(X86) || CPU(ARM) || CPU(MIPS)
-
-# if CPU(X86)
- Assembler::RegisterID lowReg = JSC::X86Registers::eax;
- Assembler::RegisterID highReg = JSC::X86Registers::edx;
-# elif CPU(MIPS)
- Assembler::RegisterID lowReg = JSC::MIPSRegisters::v0;
- Assembler::RegisterID highReg = JSC::MIPSRegisters::v1;
-# else // CPU(ARM)
- Assembler::RegisterID lowReg = JSC::ARMRegisters::r0;
- Assembler::RegisterID highReg = JSC::ARMRegisters::r1;
-# endif
-
- if (t->kind == IR::Temp::PhysicalRegister) {
- switch (t->type) {
- case IR::DoubleType:
- _as->moveDoubleToInts((Assembler::FPRegisterID) t->index, lowReg, highReg);
- break;
- case IR::UInt32Type: {
- Assembler::RegisterID srcReg = (Assembler::RegisterID) t->index;
- Assembler::Jump intRange = _as->branch32(Assembler::GreaterThanOrEqual, srcReg, Assembler::TrustedImm32(0));
- _as->convertUInt32ToDouble(srcReg, Assembler::FPGpr0, Assembler::ReturnValueRegister);
- _as->moveDoubleToInts(Assembler::FPGpr0, lowReg, highReg);
- Assembler::Jump done = _as->jump();
- intRange.link(_as);
- _as->move(srcReg, lowReg);
- _as->move(Assembler::TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
- done.link(_as);
- } break;
- case IR::SInt32Type:
- _as->move((Assembler::RegisterID) t->index, lowReg);
- _as->move(Assembler::TrustedImm32(QV4::Value::Integer_Type_Internal), highReg);
- break;
- case IR::BoolType:
- _as->move((Assembler::RegisterID) t->index, lowReg);
- _as->move(Assembler::TrustedImm32(QV4::Value::Boolean_Type_Internal), highReg);
- break;
- default:
- Q_UNREACHABLE();
- }
- } else {
- Pointer addr = _as->loadAddress(Assembler::ScratchRegister, t);
- _as->load32(addr, lowReg);
- addr.offset += 4;
- _as->load32(addr, highReg);
- }
-#else
- if (t->kind == IR::Temp::PhysicalRegister) {
- if (t->type == IR::DoubleType) {
- _as->moveDoubleTo64((Assembler::FPRegisterID) t->index,
- Assembler::ReturnValueRegister);
- _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask),
- Assembler::ScratchRegister);
- _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
- } else if (t->type == IR::UInt32Type) {
- Assembler::RegisterID srcReg = (Assembler::RegisterID) t->index;
- Assembler::Jump intRange = _as->branch32(Assembler::GreaterThanOrEqual, srcReg, Assembler::TrustedImm32(0));
- _as->convertUInt32ToDouble(srcReg, Assembler::FPGpr0, Assembler::ReturnValueRegister);
- _as->moveDoubleTo64(Assembler::FPGpr0, Assembler::ReturnValueRegister);
- _as->move(Assembler::TrustedImm64(QV4::Value::NaNEncodeMask), Assembler::ScratchRegister);
- _as->xor64(Assembler::ScratchRegister, Assembler::ReturnValueRegister);
- Assembler::Jump done = _as->jump();
- intRange.link(_as);
- _as->zeroExtend32ToPtr(srcReg, Assembler::ReturnValueRegister);
- quint64 tag = QV4::Value::Integer_Type_Internal;
- _as->or64(Assembler::TrustedImm64(tag << 32),
- Assembler::ReturnValueRegister);
- done.link(_as);
- } else {
- _as->zeroExtend32ToPtr((Assembler::RegisterID) t->index, Assembler::ReturnValueRegister);
- quint64 tag;
- switch (t->type) {
- case IR::SInt32Type:
- tag = QV4::Value::Integer_Type_Internal;
- break;
- case IR::BoolType:
- tag = QV4::Value::Boolean_Type_Internal;
- break;
- default:
- tag = 31337; // bogus value
- Q_UNREACHABLE();
- }
- _as->or64(Assembler::TrustedImm64(tag << 32),
- Assembler::ReturnValueRegister);
- }
- } else {
- _as->copyValue(Assembler::ReturnValueRegister, t);
- }
-#endif
- } else if (IR::Const *c = s->expr->asConst()) {
- QV4::Primitive retVal = convertToValue(c);
-#if CPU(X86)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::X86Registers::eax);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::X86Registers::edx);
-#elif CPU(ARM)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::ARMRegisters::r0);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::ARMRegisters::r1);
-#elif CPU(MIPS)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::MIPSRegisters::v0);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::MIPSRegisters::v1);
-#else
- _as->move(Assembler::TrustedImm64(retVal.rawValue()), Assembler::ReturnValueRegister);
-#endif
- } else {
- Q_UNREACHABLE();
- Q_UNUSED(s);
- }
-
- Assembler::Label leaveStackFrame = _as->label();
-
- const int locals = _as->stackLayout().calculateJSStackFrameSize();
- _as->subPtr(Assembler::TrustedImm32(sizeof(QV4::Value)*locals), Assembler::LocalsRegister);
- _as->loadPtr(Address(Assembler::EngineRegister, qOffsetOf(QV4::ExecutionEngine, current)), Assembler::ScratchRegister);
- _as->loadPtr(Address(Assembler::ScratchRegister, qOffsetOf(ExecutionContext::Data, engine)), Assembler::ScratchRegister);
- _as->storePtr(Assembler::LocalsRegister, Address(Assembler::ScratchRegister, qOffsetOf(ExecutionEngine, jsStackTop)));
-
- _as->leaveStandardStackFrame(regularRegistersToSave, fpRegistersToSave);
- _as->ret();
-
- _as->exceptionReturnLabel = _as->label();
- QV4::Primitive retVal = Primitive::undefinedValue();
-#if CPU(X86)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::X86Registers::eax);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::X86Registers::edx);
-#elif CPU(ARM)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::ARMRegisters::r0);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::ARMRegisters::r1);
-#elif CPU(MIPS)
- _as->move(Assembler::TrustedImm32(retVal.int_32()), JSC::MIPSRegisters::v0);
- _as->move(Assembler::TrustedImm32(retVal.tag()), JSC::MIPSRegisters::v1);
-#else
- _as->move(Assembler::TrustedImm64(retVal.rawValue()), Assembler::ReturnValueRegister);
-#endif
- _as->jump(leaveStackFrame);
+ _as->returnFromFunction(s, regularRegistersToSave, fpRegistersToSave);
}
-int InstructionSelection::prepareVariableArguments(IR::ExprList* args)
+template <typename JITAssembler>
+int InstructionSelection<JITAssembler>::prepareVariableArguments(IR::ExprList* args)
{
int argc = 0;
for (IR::ExprList *it = args; it; it = it->next) {
@@ -1492,7 +1328,7 @@ int InstructionSelection::prepareVariableArguments(IR::ExprList* args)
Q_ASSERT(arg != 0);
Pointer dst(_as->stackLayout().argumentAddressForCall(i));
if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister)
- _as->memcopyValue(dst, arg->asTemp(), Assembler::ScratchRegister);
+ _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister);
else
_as->copyValue(dst, arg);
}
@@ -1500,7 +1336,8 @@ int InstructionSelection::prepareVariableArguments(IR::ExprList* args)
return argc;
}
-int InstructionSelection::prepareCallData(IR::ExprList* args, IR::Expr *thisObject)
+template <typename JITAssembler>
+int InstructionSelection<JITAssembler>::prepareCallData(IR::ExprList* args, IR::Expr *thisObject)
{
int argc = 0;
for (IR::ExprList *it = args; it; it = it->next) {
@@ -1508,9 +1345,9 @@ int InstructionSelection::prepareCallData(IR::ExprList* args, IR::Expr *thisObje
}
Pointer p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, tag));
- _as->store32(Assembler::TrustedImm32(QV4::Value::Integer_Type_Internal), p);
+ _as->store32(TrustedImm32(QV4::Value::Integer_Type_Internal), p);
p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, argc));
- _as->store32(Assembler::TrustedImm32(argc), p);
+ _as->store32(TrustedImm32(argc), p);
p = _as->stackLayout().callDataAddress(qOffsetOf(CallData, thisObject));
if (!thisObject)
_as->storeValue(QV4::Primitive::undefinedValue(), p);
@@ -1523,19 +1360,20 @@ int InstructionSelection::prepareCallData(IR::ExprList* args, IR::Expr *thisObje
Q_ASSERT(arg != 0);
Pointer dst(_as->stackLayout().argumentAddressForCall(i));
if (arg->asTemp() && arg->asTemp()->kind != IR::Temp::PhysicalRegister)
- _as->memcopyValue(dst, arg->asTemp(), Assembler::ScratchRegister);
+ _as->memcopyValue(dst, arg->asTemp(), JITTargetPlatform::ScratchRegister);
else
_as->copyValue(dst, arg);
}
return argc;
}
-void InstructionSelection::calculateRegistersToSave(const RegisterInformation &used)
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::calculateRegistersToSave(const RegisterInformation &used)
{
regularRegistersToSave.clear();
fpRegistersToSave.clear();
- for (const RegisterInfo &ri : Assembler::getRegisterInfo()) {
+ for (const RegisterInfo &ri : JITTargetPlatform::getRegisterInfo()) {
#if defined(RESTORE_EBX_ON_CALL)
if (ri.isRegularRegister() && ri.reg<JSC::X86Registers::RegisterID>() == JSC::X86Registers::ebx) {
regularRegistersToSave.append(ri);
@@ -1564,35 +1402,38 @@ bool operator==(const Primitive &v1, const Primitive &v2)
} // QV4 namespace
QT_END_NAMESPACE
-bool InstructionSelection::visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Expr *right,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpDouble(IR::AluOp op, IR::Expr *left, IR::Expr *right,
IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
{
if (_as->nextBlock() == iftrue) {
- Assembler::Jump target = _as->branchDouble(true, op, left, right);
+ Jump target = _as->branchDouble(true, op, left, right);
_as->addPatch(iffalse, target);
} else {
- Assembler::Jump target = _as->branchDouble(false, op, left, right);
+ Jump target = _as->branchDouble(false, op, left, right);
_as->addPatch(iftrue, target);
_as->jumpToBlock(_block, iffalse);
}
return true;
}
-bool InstructionSelection::visitCJumpSInt32(IR::AluOp op, IR::Expr *left, IR::Expr *right,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpSInt32(IR::AluOp op, IR::Expr *left, IR::Expr *right,
IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
{
if (_as->nextBlock() == iftrue) {
- Assembler::Jump target = _as->branchInt32(true, op, left, right);
+ Jump target = _as->branchInt32(true, op, left, right);
_as->addPatch(iffalse, target);
} else {
- Assembler::Jump target = _as->branchInt32(false, op, left, right);
+ Jump target = _as->branchInt32(false, op, left, right);
_as->addPatch(iftrue, target);
_as->jumpToBlock(_block, iffalse);
}
return true;
}
-void InstructionSelection::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *trueBlock,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
Q_ASSERT(binop->op == IR::OpStrictEqual || binop->op == IR::OpStrictNotEqual);
@@ -1607,15 +1448,16 @@ void InstructionSelection::visitCJumpStrict(IR::Binop *binop, IR::BasicBlock *tr
IR::Expr *left = binop->left;
IR::Expr *right = binop->right;
- generateRuntimeCall(Assembler::ReturnValueRegister, compareStrictEqual,
- Assembler::PointerToValue(left), Assembler::PointerToValue(right));
- _as->generateCJumpOnCompare(binop->op == IR::OpStrictEqual ? Assembler::NotEqual : Assembler::Equal,
- Assembler::ReturnValueRegister, Assembler::TrustedImm32(0),
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, compareStrictEqual,
+ PointerToValue(left), PointerToValue(right));
+ _as->generateCJumpOnCompare(binop->op == IR::OpStrictEqual ? RelationalCondition::NotEqual : RelationalCondition::Equal,
+ JITTargetPlatform::ReturnValueRegister, TrustedImm32(0),
_block, trueBlock, falseBlock);
}
// Only load the non-null temp.
-bool InstructionSelection::visitCJumpStrictNull(IR::Binop *binop,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpStrictNull(IR::Binop *binop,
IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
@@ -1640,19 +1482,20 @@ bool InstructionSelection::visitCJumpStrictNull(IR::Binop *binop,
return true;
}
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
+ Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc);
tagAddr.offset += 4;
- const Assembler::RegisterID tagReg = Assembler::ScratchRegister;
+ const RegisterID tagReg = JITTargetPlatform::ScratchRegister;
_as->load32(tagAddr, tagReg);
- Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal
- : Assembler::NotEqual;
- const Assembler::TrustedImm32 tag(QV4::Value::Null_Type_Internal);
+ RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal
+ : RelationalCondition::NotEqual;
+ const TrustedImm32 tag(QV4::Value::Null_Type_Internal);
_as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock);
return true;
}
-bool InstructionSelection::visitCJumpStrictUndefined(IR::Binop *binop,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpStrictUndefined(IR::Binop *binop,
IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
@@ -1677,28 +1520,15 @@ bool InstructionSelection::visitCJumpStrictUndefined(IR::Binop *binop,
return true;
}
- Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal
- : Assembler::NotEqual;
- const Assembler::RegisterID tagReg = Assembler::ReturnValueRegister;
-#ifdef QV4_USE_64_BIT_VALUE_ENCODING
- Assembler::Pointer addr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
- _as->load64(addr, tagReg);
- const Assembler::TrustedImm64 tag(0);
-#else // !QV4_USE_64_BIT_VALUE_ENCODING
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
- _as->load32(tagAddr, tagReg);
- Assembler::Jump j = _as->branch32(Assembler::invert(cond), tagReg, Assembler::TrustedImm32(0));
- _as->addPatch(falseBlock, j);
-
- tagAddr.offset += 4;
- _as->load32(tagAddr, tagReg);
- const Assembler::TrustedImm32 tag(QV4::Value::Managed_Type_Internal);
-#endif
- _as->generateCJumpOnCompare(cond, tagReg, tag, _block, trueBlock, falseBlock);
+ RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal
+ : RelationalCondition::NotEqual;
+ const RegisterID tagReg = JITTargetPlatform::ReturnValueRegister;
+ _as->generateCJumpOnUndefined(cond, varSrc, JITTargetPlatform::ScratchRegister, tagReg, _block, trueBlock, falseBlock);
return true;
}
-bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock *trueBlock,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
IR::Expr *boolSrc = 0, *otherSrc = 0;
@@ -1712,13 +1542,20 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock
// neither operands are statically typed as bool, so bail out.
return false;
}
+ if (otherSrc->type == IR::UnknownType) {
+ // Ok, we really need to call into the runtime.
+ // (This case doesn't happen when the optimizer ran, because everything will be typed (yes,
+ // possibly as "var" meaning anything), but it does happen for $0===true, which is generated
+ // for things where the optimizer didn't run (like functions with a try block).)
+ return false;
+ }
- Assembler::RelationalCondition cond = binop->op == IR::OpStrictEqual ? Assembler::Equal
- : Assembler::NotEqual;
+ RelationalCondition cond = binop->op == IR::OpStrictEqual ? RelationalCondition::Equal
+ : RelationalCondition::NotEqual;
if (otherSrc->type == IR::BoolType) { // both are boolean
- Assembler::RegisterID one = _as->toBoolRegister(boolSrc, Assembler::ReturnValueRegister);
- Assembler::RegisterID two = _as->toBoolRegister(otherSrc, Assembler::ScratchRegister);
+ RegisterID one = _as->toBoolRegister(boolSrc, JITTargetPlatform::ReturnValueRegister);
+ RegisterID two = _as->toBoolRegister(otherSrc, JITTargetPlatform::ScratchRegister);
_as->generateCJumpOnCompare(cond, one, two, _block, trueBlock, falseBlock);
return true;
}
@@ -1728,13 +1565,13 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock
return true;
}
- Assembler::Pointer otherAddr = _as->loadAddress(Assembler::ReturnValueRegister, otherSrc);
+ Pointer otherAddr = _as->loadAddress(JITTargetPlatform::ReturnValueRegister, otherSrc);
otherAddr.offset += 4; // tag address
// check if the tag of the var operand is indicates 'boolean'
- _as->load32(otherAddr, Assembler::ScratchRegister);
- Assembler::Jump noBool = _as->branch32(Assembler::NotEqual, Assembler::ScratchRegister,
- Assembler::TrustedImm32(QV4::Value::Boolean_Type_Internal));
+ _as->load32(otherAddr, JITTargetPlatform::ScratchRegister);
+ Jump noBool = _as->branch32(RelationalCondition::NotEqual, JITTargetPlatform::ScratchRegister,
+ TrustedImm32(QV4::Value::Boolean_Type_Internal));
if (binop->op == IR::OpStrictEqual)
_as->addPatch(falseBlock, noBool);
else
@@ -1742,14 +1579,15 @@ bool InstructionSelection::visitCJumpStrictBool(IR::Binop *binop, IR::BasicBlock
// ok, both are boolean, so let's load them and compare them.
otherAddr.offset -= 4; // int_32 address
- _as->load32(otherAddr, Assembler::ReturnValueRegister);
- Assembler::RegisterID boolReg = _as->toBoolRegister(boolSrc, Assembler::ScratchRegister);
- _as->generateCJumpOnCompare(cond, boolReg, Assembler::ReturnValueRegister, _block, trueBlock,
+ _as->load32(otherAddr, JITTargetPlatform::ReturnValueRegister);
+ RegisterID boolReg = _as->toBoolRegister(boolSrc, JITTargetPlatform::ScratchRegister);
+ _as->generateCJumpOnCompare(cond, boolReg, JITTargetPlatform::ReturnValueRegister, _block, trueBlock,
falseBlock);
return true;
}
-bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Binop *binop,
+template <typename JITAssembler>
+bool InstructionSelection<JITAssembler>::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Binop *binop,
IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
@@ -1776,18 +1614,18 @@ bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Bin
return true;
}
- Assembler::Pointer tagAddr = _as->loadAddress(Assembler::ScratchRegister, varSrc);
+ Pointer tagAddr = _as->loadAddress(JITTargetPlatform::ScratchRegister, varSrc);
tagAddr.offset += 4;
- const Assembler::RegisterID tagReg = Assembler::ReturnValueRegister;
+ const RegisterID tagReg = JITTargetPlatform::ReturnValueRegister;
_as->load32(tagAddr, tagReg);
if (binop->op == IR::OpNotEqual)
qSwap(trueBlock, falseBlock);
- Assembler::Jump isNull = _as->branch32(Assembler::Equal, tagReg, Assembler::TrustedImm32(int(QV4::Value::Null_Type_Internal)));
- Assembler::Jump isNotUndefinedTag = _as->branch32(Assembler::NotEqual, tagReg, Assembler::TrustedImm32(int(QV4::Value::Managed_Type_Internal)));
+ Jump isNull = _as->branch32(RelationalCondition::Equal, tagReg, TrustedImm32(int(QV4::Value::Null_Type_Internal)));
+ Jump isNotUndefinedTag = _as->branch32(RelationalCondition::NotEqual, tagReg, TrustedImm32(int(QV4::Value::Managed_Type_Internal)));
tagAddr.offset -= 4;
_as->load32(tagAddr, tagReg);
- Assembler::Jump isNotUndefinedValue = _as->branch32(Assembler::NotEqual, tagReg, Assembler::TrustedImm32(0));
+ Jump isNotUndefinedValue = _as->branch32(RelationalCondition::NotEqual, tagReg, TrustedImm32(0));
_as->addPatch(trueBlock, isNull);
_as->addPatch(falseBlock, isNotUndefinedTag);
_as->addPatch(falseBlock, isNotUndefinedValue);
@@ -1797,7 +1635,8 @@ bool InstructionSelection::visitCJumpNullUndefined(IR::Type nullOrUndef, IR::Bin
}
-void InstructionSelection::visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *trueBlock,
+template <typename JITAssembler>
+void InstructionSelection<JITAssembler>::visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *trueBlock,
IR::BasicBlock *falseBlock)
{
Q_ASSERT(binop->op == IR::OpEqual || binop->op == IR::OpNotEqual);
@@ -1808,18 +1647,54 @@ void InstructionSelection::visitCJumpEqual(IR::Binop *binop, IR::BasicBlock *tru
IR::Expr *left = binop->left;
IR::Expr *right = binop->right;
- generateRuntimeCall(Assembler::ReturnValueRegister, compareEqual,
- Assembler::PointerToValue(left), Assembler::PointerToValue(right));
- _as->generateCJumpOnCompare(binop->op == IR::OpEqual ? Assembler::NotEqual : Assembler::Equal,
- Assembler::ReturnValueRegister, Assembler::TrustedImm32(0),
+ generateRuntimeCall(_as, JITTargetPlatform::ReturnValueRegister, compareEqual,
+ PointerToValue(left), PointerToValue(right));
+ _as->generateCJumpOnCompare(binop->op == IR::OpEqual ? RelationalCondition::NotEqual : RelationalCondition::Equal,
+ JITTargetPlatform::ReturnValueRegister, TrustedImm32(0),
_block, trueBlock, falseBlock);
}
-QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory::createUnitForLoading()
+template <typename JITAssembler>
+QQmlRefPointer<CompiledData::CompilationUnit> ISelFactory<JITAssembler>::createUnitForLoading()
{
QQmlRefPointer<CompiledData::CompilationUnit> result;
result.adopt(new JIT::CompilationUnit);
return result;
}
+QT_BEGIN_NAMESPACE
+namespace QV4 { namespace JIT {
+template class Q_QML_EXPORT InstructionSelection<>;
+template class Q_QML_EXPORT ISelFactory<>;
+#if defined(V4_BOOTSTRAP) && CPU(X86_64)
+
+Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &architecture)
+{
+ using ARMv7CrossAssembler = QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>;
+
+ if (architecture == QLatin1String("armv7"))
+ return new ISelFactory<ARMv7CrossAssembler>;
+
+ QString hostArch;
+#if CPU(ARM_THUMB2)
+ hostArch = QStringLiteral("armv7");
+#elif CPU(ARM64)
+ hostArch = QStringLiteral("armv8");
+#elif CPU(MIPS)
+ hostArch = QStringLiteral("mips");
+#elif CPU(X86)
+ hostArch = QStringLiteral("x86");
+#elif CPU(X86_64)
+ hostArch = QStringLiteral("x86_64");
+#endif
+ if (!hostArch.isEmpty() && architecture == hostArch)
+ return new ISelFactory<>;
+
+ return nullptr;
+}
+
+#endif
+} }
+QT_END_NAMESPACE
+
#endif // ENABLE(ASSEMBLER)
diff --git a/src/qml/jit/qv4isel_masm_p.h b/src/qml/jit/qv4isel_masm_p.h
index 012745c5f2..6ae50c3260 100644
--- a/src/qml/jit/qv4isel_masm_p.h
+++ b/src/qml/jit/qv4isel_masm_p.h
@@ -72,6 +72,7 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
+template <typename JITAssembler = Assembler<DefaultAssemblerTargetConfiguration>>
class Q_QML_EXPORT InstructionSelection:
protected IR::IRDecoder,
public EvalInstructionSelection
@@ -136,8 +137,23 @@ protected:
void unop(IR::AluOp oper, IR::Expr *sourceTemp, IR::Expr *target) override;
void binop(IR::AluOp oper, IR::Expr *leftSource, IR::Expr *rightSource, IR::Expr *target) override;
- typedef Assembler::Address Address;
- typedef Assembler::Pointer Pointer;
+ using Address = typename JITAssembler::Address;
+ using Pointer = typename JITAssembler::Pointer;
+ using PointerToValue = typename JITAssembler::PointerToValue;
+ using RegisterID = typename JITAssembler::RegisterID;
+ using FPRegisterID = typename JITAssembler::FPRegisterID;
+ using ResultCondition = typename JITAssembler::ResultCondition;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+ using TrustedImm64 = typename JITAssembler::TrustedImm64;
+ using Label = typename JITAssembler::Label;
+ using Jump = typename JITAssembler::Jump;
+ using StringToIndex = typename JITAssembler::StringToIndex;
+ using Reference = typename JITAssembler::Reference;
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using BranchTruncateType = typename JITAssembler::BranchTruncateType;
+ using RuntimeCall = typename JITAssembler::RuntimeCall;
+
+ using JITTargetPlatform = typename JITAssembler::JITTargetPlatform;
#if !defined(ARGUMENTS_IN_REGISTERS)
Address addressForArgument(int index) const
@@ -145,7 +161,7 @@ protected:
// FramePointerRegister points to its old value on the stack, and above
// it we have the return address, hence the need to step over two
// values before reaching the first argument.
- return Address(Assembler::FramePointerRegister, (index + 2) * sizeof(void*));
+ return Address(JITTargetPlatform::FramePointerRegister, (index + 2) * sizeof(void*));
}
#endif
@@ -192,61 +208,55 @@ private:
if (targetTemp->kind == IR::Temp::PhysicalRegister) {
if (IR::Temp *sourceTemp = source->asTemp()) {
if (sourceTemp->kind == IR::Temp::PhysicalRegister) {
- _as->convertInt32ToDouble((Assembler::RegisterID) sourceTemp->index,
- (Assembler::FPRegisterID) targetTemp->index);
+ _as->convertInt32ToDouble((RegisterID) sourceTemp->index,
+ (FPRegisterID) targetTemp->index);
} else {
- _as->convertInt32ToDouble(_as->loadAddress(Assembler::ReturnValueRegister, sourceTemp),
- (Assembler::FPRegisterID) targetTemp->index);
+ _as->convertInt32ToDouble(_as->loadAddress(JITTargetPlatform::ReturnValueRegister, sourceTemp),
+ (FPRegisterID) targetTemp->index);
}
} else {
- _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
- (Assembler::FPRegisterID) targetTemp->index);
+ _as->convertInt32ToDouble(_as->toInt32Register(source, JITTargetPlatform::ScratchRegister),
+ (FPRegisterID) targetTemp->index);
}
return;
}
}
- _as->convertInt32ToDouble(_as->toInt32Register(source, Assembler::ScratchRegister),
- Assembler::FPGpr0);
- _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(Assembler::ReturnValueRegister, target));
+ _as->convertInt32ToDouble(_as->toInt32Register(source, JITTargetPlatform::ScratchRegister),
+ JITTargetPlatform::FPGpr0);
+ _as->storeDouble(JITTargetPlatform::FPGpr0, _as->loadAddress(JITTargetPlatform::ReturnValueRegister, target));
}
void convertUIntToDouble(IR::Expr *source, IR::Expr *target)
{
- Assembler::RegisterID tmpReg = Assembler::ScratchRegister;
- Assembler::RegisterID reg = _as->toInt32Register(source, tmpReg);
+ RegisterID tmpReg = JITTargetPlatform::ScratchRegister;
+ RegisterID reg = _as->toInt32Register(source, tmpReg);
if (IR::Temp *targetTemp = target->asTemp()) {
if (targetTemp->kind == IR::Temp::PhysicalRegister) {
- _as->convertUInt32ToDouble(reg, (Assembler::FPRegisterID) targetTemp->index, tmpReg);
+ _as->convertUInt32ToDouble(reg, (FPRegisterID) targetTemp->index, tmpReg);
return;
}
}
_as->convertUInt32ToDouble(_as->toUInt32Register(source, tmpReg),
- Assembler::FPGpr0, tmpReg);
- _as->storeDouble(Assembler::FPGpr0, _as->loadAddress(tmpReg, target));
+ JITTargetPlatform::FPGpr0, tmpReg);
+ _as->storeDouble(JITTargetPlatform::FPGpr0, _as->loadAddress(tmpReg, target));
}
void convertIntToBool(IR::Expr *source, IR::Expr *target)
{
- Assembler::RegisterID reg = Assembler::ScratchRegister;
+ RegisterID reg = JITTargetPlatform::ScratchRegister;
if (IR::Temp *targetTemp = target->asTemp())
if (targetTemp->kind == IR::Temp::PhysicalRegister)
- reg = (Assembler::RegisterID) targetTemp->index;
+ reg = (RegisterID) targetTemp->index;
_as->move(_as->toInt32Register(source, reg), reg);
- _as->compare32(Assembler::NotEqual, reg, Assembler::TrustedImm32(0), reg);
+ _as->compare32(RelationalCondition::NotEqual, reg, TrustedImm32(0), reg);
_as->storeBool(reg, target);
}
- #define isel_stringIfyx(s) #s
- #define isel_stringIfy(s) isel_stringIfyx(s)
-
- #define generateRuntimeCall(t, function, ...) \
- _as->generateFunctionCallImp(Runtime::Method_##function##_NeedsExceptionCheck, t, "Runtime::" isel_stringIfy(function), RuntimeCall(qOffsetOf(QV4::Runtime, function)), __VA_ARGS__)
-
int prepareVariableArguments(IR::ExprList* args);
int prepareCallData(IR::ExprList* args, IR::Expr *thisObject);
@@ -259,22 +269,22 @@ private:
// goes into the same register as the return value (currently only ARM), the prepareCall
// will combine loading the looupAddr into the register and calculating the indirect call
// address.
- Assembler::Pointer lookupAddr(Assembler::ReturnValueRegister, index * sizeof(QV4::Lookup));
+ Pointer lookupAddr(JITTargetPlatform::ReturnValueRegister, index * sizeof(QV4::Lookup));
_as->generateFunctionCallImp(true, retval, "lookup getter/setter",
- LookupCall(lookupAddr, getterSetterOffset), lookupAddr,
+ typename JITAssembler::LookupCall(lookupAddr, getterSetterOffset), lookupAddr,
arg1, arg2, arg3);
}
template <typename Retval, typename Arg1, typename Arg2>
void generateLookupCall(Retval retval, uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2)
{
- generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, Assembler::VoidType());
+ generateLookupCall(retval, index, getterSetterOffset, arg1, arg2, typename JITAssembler::VoidType());
}
IR::BasicBlock *_block;
BitVector _removableJumps;
- Assembler* _as;
+ JITAssembler* _as;
QScopedPointer<CompilationUnit> compilationUnit;
QQmlEnginePrivate *qmlEngine;
@@ -282,13 +292,14 @@ private:
RegisterInformation fpRegistersToSave;
};
+template <typename JITAssembler = Assembler<DefaultAssemblerTargetConfiguration>>
class Q_QML_EXPORT ISelFactory: public EvalISelFactory
{
public:
ISelFactory() : EvalISelFactory(QStringLiteral("jit")) {}
virtual ~ISelFactory() {}
EvalInstructionSelection *create(QQmlEnginePrivate *qmlEngine, QV4::ExecutableAllocator *execAllocator, IR::Module *module, QV4::Compiler::JSUnitGenerator *jsGenerator) Q_DECL_OVERRIDE Q_DECL_FINAL
- { return new InstructionSelection(qmlEngine, execAllocator, module, jsGenerator, this); }
+ { return new InstructionSelection<JITAssembler>(qmlEngine, execAllocator, module, jsGenerator, this); }
bool jitCompileRegexps() const Q_DECL_OVERRIDE Q_DECL_FINAL
{ return true; }
QQmlRefPointer<CompiledData::CompilationUnit> createUnitForLoading() Q_DECL_OVERRIDE Q_DECL_FINAL;
diff --git a/src/qml/jit/qv4regalloc.cpp b/src/qml/jit/qv4regalloc.cpp
index 3fb0815299..d5da863ee0 100644
--- a/src/qml/jit/qv4regalloc.cpp
+++ b/src/qml/jit/qv4regalloc.cpp
@@ -973,7 +973,15 @@ private:
break;
Q_ASSERT(!i->isFixedInterval());
- _liveIntervals.push_back(i);
+ auto it = _liveIntervals.begin();
+ for (; it != _liveIntervals.end(); ++it) {
+ if ((*it)->temp() == i->temp()) {
+ *it = i;
+ break;
+ }
+ }
+ if (it == _liveIntervals.end())
+ _liveIntervals.push_back(i);
// qDebug() << "-- Activating interval for temp" << i->temp().index;
_unprocessedReverseOrder.removeLast();
@@ -1521,7 +1529,7 @@ static inline int indexOfRangeCoveringPosition(const LifeTimeInterval::Ranges &r
return -1;
}
-static inline int intersectionPosition(const LifeTimeInterval::Range &one, const LifeTimeInterval::Range &two)
+static inline int intersectionPosition(const LifeTimeIntervalRange &one, const LifeTimeIntervalRange &two)
{
if (one.covers(two.start))
return two.start;
@@ -1779,9 +1787,9 @@ int RegisterAllocator::nextIntersection(const LifeTimeInterval &current,
return -1;
for (int currentEnd = currentRanges.size(); currentIt < currentEnd; ++currentIt) {
- const LifeTimeInterval::Range currentRange = currentRanges.at(currentIt);
+ const LifeTimeIntervalRange currentRange = currentRanges.at(currentIt);
for (int anotherIt = anotherItStart, anotherEnd = anotherRanges.size(); anotherIt < anotherEnd; ++anotherIt) {
- const LifeTimeInterval::Range anotherRange = anotherRanges.at(anotherIt);
+ const LifeTimeIntervalRange anotherRange = anotherRanges.at(anotherIt);
if (anotherRange.start > currentRange.end)
break;
int intersectPos = intersectionPosition(currentRange, anotherRange);
diff --git a/src/qml/jit/qv4targetplatform_p.h b/src/qml/jit/qv4targetplatform_p.h
index 7e265258d5..1c29aa2a70 100644
--- a/src/qml/jit/qv4targetplatform_p.h
+++ b/src/qml/jit/qv4targetplatform_p.h
@@ -63,6 +63,11 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
+enum TargetOperatingSystemSpecialization {
+ NoOperatingSystemSpecialization,
+ WindowsSpecialization
+};
+
// The TargetPlatform class describes how the stack and the registers work on a CPU+ABI combination.
//
// All combinations have a separate definition, guarded by #ifdefs. The exceptions are:
@@ -79,25 +84,37 @@ namespace JIT {
// a call, we add a load it right before emitting the call instruction.
//
// NOTE: When adding new architecture, do not forget to whitelist it in qv4global_p.h!
+template <typename PlatformAssembler, TargetOperatingSystemSpecialization specialization = NoOperatingSystemSpecialization>
class TargetPlatform
{
-public:
+};
+
#if CPU(X86) && (OS(LINUX) || OS(WINDOWS) || OS(QNX) || OS(FREEBSD) || defined(Q_OS_IOS))
- enum { RegAllocIsSupported = 1 };
+template <>
+class TargetPlatform<JSC::MacroAssemblerX86, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerX86;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::X86Registers::ebp;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::edi;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::X86Registers::esi;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::ecx;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+ enum { RegAllocIsSupported = 1 };
- static RegisterInformation getPlatformRegisterInfo()
+ static const RegisterID FramePointerRegister = JSC::X86Registers::ebp;
+ static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const RegisterID LocalsRegister = JSC::X86Registers::edi;
+ static const RegisterID EngineRegister = JSC::X86Registers::esi;
+ static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID ScratchRegister = JSC::X86Registers::ecx;
+ static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+ static const RegisterID LowReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID HighReturnValueRegister = JSC::X86Registers::edx;
+
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
<< RI(JSC::X86Registers::edx, QStringLiteral("edx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::ebx, QStringLiteral("ebx"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::edi, QStringLiteral("edi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
@@ -109,6 +126,7 @@ public:
<< RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
;
+ return info;
}
# define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
@@ -117,19 +135,20 @@ public:
# undef ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 0;
- static JSC::MacroAssembler::RegisterID registerForArgument(int) { Q_UNREACHABLE(); }
+ static RegisterID registerForArgument(int) { Q_UNREACHABLE(); }
static const int StackAlignment = 16;
static const int StackShadowSpace = 0;
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(FramePointerRegister); }
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(FramePointerRegister); }
+ static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as) { as->pop(FramePointerRegister); }
#if OS(WINDOWS) || OS(QNX) || \
((OS(LINUX) || OS(FREEBSD)) && (defined(__PIC__) || defined(__PIE__)))
#define RESTORE_EBX_ON_CALL
- static JSC::MacroAssembler::Address ebxAddressOnStack()
+ using Address = PlatformAssembler::Address;
+ static Address ebxAddressOnStack()
{
static int ebxIdx = -1;
if (ebxIdx == -1) {
@@ -146,28 +165,36 @@ public:
Q_ASSERT(ebxIdx >= 0);
ebxIdx += 1;
}
- return JSC::MacroAssembler::Address(FramePointerRegister, ebxIdx * -int(sizeof(void*)));
+ return Address(FramePointerRegister, ebxIdx * -int(sizeof(void*)));
}
#endif
-
-#endif // Windows on x86
+};
+#endif // x86
#if CPU(X86_64) && (OS(LINUX) || OS(MAC_OS_X) || OS(FREEBSD) || OS(QNX) || defined(Q_OS_IOS))
+template <>
+class TargetPlatform<JSC::MacroAssemblerX86_64, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerX86_64;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
+
enum { RegAllocIsSupported = 1 };
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::X86Registers::ebp;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::r12;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::X86Registers::r14;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::r10;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+ static const RegisterID FramePointerRegister = JSC::X86Registers::ebp;
+ static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const RegisterID LocalsRegister = JSC::X86Registers::r12;
+ static const RegisterID EngineRegister = JSC::X86Registers::r14;
+ static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID ScratchRegister = JSC::X86Registers::r10;
+ static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
- static RegisterInformation getPlatformRegisterInfo()
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
<< RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
@@ -185,6 +212,7 @@ public:
<< RI(JSC::X86Registers::xmm6, QStringLiteral("xmm6"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::X86Registers::xmm7, QStringLiteral("xmm7"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
;
+ return info;
}
#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
@@ -193,9 +221,9 @@ public:
#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 6;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::X86Registers::edi,
JSC::X86Registers::esi,
JSC::X86Registers::edx,
@@ -210,29 +238,38 @@ public:
static const int StackAlignment = 16;
static const int StackShadowSpace = 0;
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(FramePointerRegister); }
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(FramePointerRegister); }
+ static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as) { as->pop(FramePointerRegister); }
+};
#endif // Linux/MacOS on x86_64
#if CPU(X86_64) && OS(WINDOWS)
+template <>
+class TargetPlatform<JSC::MacroAssemblerX86_64, WindowsSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerX86_64;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
+
// Register allocation is not (yet) supported on win64, because the ABI related stack handling
// is not completely implemented. Specifically, the saving of xmm registers, and the saving of
// incoming function parameters to the shadow space is missing.
enum { RegAllocIsSupported = 0 };
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::X86Registers::ebp;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::X86Registers::esp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::X86Registers::r12;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::X86Registers::r14;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::X86Registers::eax;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::X86Registers::r10;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
+ static const RegisterID FramePointerRegister = JSC::X86Registers::ebp;
+ static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const RegisterID LocalsRegister = JSC::X86Registers::r12;
+ static const RegisterID EngineRegister = JSC::X86Registers::r14;
+ static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID ScratchRegister = JSC::X86Registers::r10;
+ static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+ static const FPRegisterID FPGpr1 = JSC::X86Registers::xmm1;
- static RegisterInformation getPlatformRegisterInfo()
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
<< RI(JSC::X86Registers::ebx, QStringLiteral("rbx"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::X86Registers::edi, QStringLiteral("rdi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::X86Registers::esi, QStringLiteral("rsi"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
@@ -244,6 +281,7 @@ public:
<< RI(JSC::X86Registers::r14, QStringLiteral("r14"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
<< RI(JSC::X86Registers::r15, QStringLiteral("r15"), RI::RegularRegister, RI::CalleeSaved, RI::Predefined)
;
+ return info;
}
#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
@@ -252,9 +290,9 @@ public:
#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 4;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::X86Registers::ecx,
JSC::X86Registers::edx,
JSC::X86Registers::r8,
@@ -267,11 +305,20 @@ public:
static const int StackAlignment = 16;
static const int StackShadowSpace = 32;
static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize; // Return address is pushed onto stack by the CPU.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as) { as->push(FramePointerRegister); }
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as) { as->pop(FramePointerRegister); }
+ static void platformEnterStandardStackFrame(PlatformAssembler *as) { as->push(FramePointerRegister); }
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as) { as->pop(FramePointerRegister); }
+};
#endif // Windows on x86_64
-#if CPU(ARM)
+#if CPU(ARM) || defined(V4_BOOTSTRAP)
+template <>
+class TargetPlatform<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerARMv7;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
+
enum { RegAllocIsSupported = 1 };
// The AAPCS specifies that the platform ABI has to define the usage of r9. Known are:
@@ -287,23 +334,25 @@ public:
// is used for the subroutine: r7 for Thumb or Thumb2, and r11 for ARM. We assign the constants
// accordingly, and assign the locals-register to the "other" register.
#if CPU(ARM_THUMB2)
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::ARMRegisters::r7;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARMRegisters::r11;
+ static const RegisterID FramePointerRegister = JSC::ARMRegisters::r7;
+ static const RegisterID LocalsRegister = JSC::ARMRegisters::r11;
#else // Thumbs down
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::ARMRegisters::r11;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARMRegisters::r7;
+ static const RegisterID FramePointerRegister = JSC::ARMRegisters::r11;
+ static const RegisterID LocalsRegister = JSC::ARMRegisters::r7;
#endif
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::ARMRegisters::r13;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::ARMRegisters::r5;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::ARMRegisters::r10;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::ARMRegisters::r0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::ARMRegisters::d1;
-
- static RegisterInformation getPlatformRegisterInfo()
+ static const RegisterID StackPointerRegister = JSC::ARMRegisters::r13;
+ static const RegisterID ScratchRegister = JSC::ARMRegisters::r5;
+ static const RegisterID EngineRegister = JSC::ARMRegisters::r10;
+ static const RegisterID ReturnValueRegister = JSC::ARMRegisters::r0;
+ static const FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
+ static const FPRegisterID FPGpr1 = JSC::ARMRegisters::d1;
+ static const RegisterID LowReturnValueRegister = JSC::ARMRegisters::r0;
+ static const RegisterID HighReturnValueRegister = JSC::ARMRegisters::r1;
+
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
<< RI(JSC::ARMRegisters::r0, QStringLiteral("r0"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
<< RI(JSC::ARMRegisters::r1, QStringLiteral("r1"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::ARMRegisters::r2, QStringLiteral("r2"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
@@ -336,6 +385,7 @@ public:
<< RI(JSC::ARMRegisters::d14, QStringLiteral("d14"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::ARMRegisters::d15, QStringLiteral("d15"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
;
+ return info;
}
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
@@ -344,9 +394,9 @@ public:
#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 4;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::ARMRegisters::r0,
JSC::ARMRegisters::r1,
JSC::ARMRegisters::r2,
@@ -361,35 +411,44 @@ public:
static const int StackShadowSpace = 0;
static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformEnterStandardStackFrame(PlatformAssembler *as)
{
as->push(JSC::ARMRegisters::lr);
as->push(FramePointerRegister);
}
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as)
{
as->pop(FramePointerRegister);
as->pop(JSC::ARMRegisters::lr);
}
+};
#endif // ARM (32 bit)
#if CPU(ARM64)
+template <>
+class TargetPlatform<JSC::MacroAssemblerARM64, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerARM64;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
+
enum { RegAllocIsSupported = 1 };
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::ARM64Registers::fp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::ARM64Registers::x28;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::ARM64Registers::sp;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::ARM64Registers::x9;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::ARM64Registers::x27;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::ARM64Registers::x0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::ARM64Registers::q0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::ARM64Registers::q1;
+ static const RegisterID FramePointerRegister = JSC::ARM64Registers::fp;
+ static const RegisterID LocalsRegister = JSC::ARM64Registers::x28;
+ static const RegisterID StackPointerRegister = JSC::ARM64Registers::sp;
+ static const RegisterID ScratchRegister = JSC::ARM64Registers::x9;
+ static const RegisterID EngineRegister = JSC::ARM64Registers::x27;
+ static const RegisterID ReturnValueRegister = JSC::ARM64Registers::x0;
+ static const FPRegisterID FPGpr0 = JSC::ARM64Registers::q0;
+ static const FPRegisterID FPGpr1 = JSC::ARM64Registers::q1;
- static RegisterInformation getPlatformRegisterInfo()
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
<< RI(JSC::ARM64Registers::x0, QStringLiteral("x0"), RI::RegularRegister, RI::CallerSaved, RI::Predefined)
<< RI(JSC::ARM64Registers::x1, QStringLiteral("x1"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::ARM64Registers::x2, QStringLiteral("x2"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
@@ -447,6 +506,7 @@ public:
<< RI(JSC::ARM64Registers::q30, QStringLiteral("q30"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::ARM64Registers::q31, QStringLiteral("q31"), RI::FloatingPointRegister, RI::CallerSaved, RI::RegAlloc)
;
+ return info;
}
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
@@ -455,9 +515,9 @@ public:
#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 8;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::ARM64Registers::x0,
JSC::ARM64Registers::x1,
JSC::ARM64Registers::x2,
@@ -476,33 +536,43 @@ public:
static const int StackShadowSpace = 0;
static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformEnterStandardStackFrame(PlatformAssembler *as)
{
as->pushPair(FramePointerRegister, JSC::ARM64Registers::lr);
}
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as)
{
as->popPair(FramePointerRegister, JSC::ARM64Registers::lr);
}
+};
#endif // ARM64
#if defined(Q_PROCESSOR_MIPS_32) && defined(Q_OS_LINUX)
+template <>
+class TargetPlatform<JSC::MacroAssemblerMIPS, NoOperatingSystemSpecialization>
+{
+public:
+ using PlatformAssembler = JSC::MacroAssemblerMIPS;
+ using RegisterID = PlatformAssembler::RegisterID;
+ using FPRegisterID = PlatformAssembler::FPRegisterID;
enum { RegAllocIsSupported = 1 };
- static const JSC::MacroAssembler::RegisterID FramePointerRegister = JSC::MIPSRegisters::fp;
- static const JSC::MacroAssembler::RegisterID StackPointerRegister = JSC::MIPSRegisters::sp;
- static const JSC::MacroAssembler::RegisterID LocalsRegister = JSC::MIPSRegisters::s0;
- static const JSC::MacroAssembler::RegisterID EngineRegister = JSC::MIPSRegisters::s1;
- static const JSC::MacroAssembler::RegisterID ReturnValueRegister = JSC::MIPSRegisters::v0;
- static const JSC::MacroAssembler::RegisterID ScratchRegister = JSC::MIPSRegisters::s2;
- static const JSC::MacroAssembler::FPRegisterID FPGpr0 = JSC::MIPSRegisters::f0;
- static const JSC::MacroAssembler::FPRegisterID FPGpr1 = JSC::MIPSRegisters::f2;
-
- static RegisterInformation getPlatformRegisterInfo()
+ static const RegisterID FramePointerRegister = JSC::MIPSRegisters::fp;
+ static const RegisterID StackPointerRegister = JSC::MIPSRegisters::sp;
+ static const RegisterID LocalsRegister = JSC::MIPSRegisters::s0;
+ static const RegisterID EngineRegister = JSC::MIPSRegisters::s1;
+ static const RegisterID ReturnValueRegister = JSC::MIPSRegisters::v0;
+ static const RegisterID ScratchRegister = JSC::MIPSRegisters::s2;
+ static const FPRegisterID FPGpr0 = JSC::MIPSRegisters::f0;
+ static const FPRegisterID FPGpr1 = JSC::MIPSRegisters::f2;
+ static const RegisterID LowReturnValueRegister = JSC::MIPSRegisters::v0;
+ static const RegisterID HighReturnValueRegister = JSC::MIPSRegisters::v1;
+
+ static RegisterInformation getRegisterInfo()
{
typedef RegisterInfo RI;
- return RegisterInformation()
+ static RegisterInformation info = RegisterInformation()
// Note: t0, t1, t2, t3 and f16 are already used by MacroAssemblerMIPS.
<< RI(JSC::MIPSRegisters::t4, QStringLiteral("t4"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
<< RI(JSC::MIPSRegisters::t5, QStringLiteral("t5"), RI::RegularRegister, RI::CallerSaved, RI::RegAlloc)
@@ -524,6 +594,7 @@ public:
<< RI(JSC::MIPSRegisters::f26, QStringLiteral("f26"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
<< RI(JSC::MIPSRegisters::f28, QStringLiteral("f28"), RI::FloatingPointRegister, RI::CalleeSaved, RI::RegAlloc)
;
+ return info;
}
#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
@@ -532,9 +603,9 @@ public:
#define ARGUMENTS_IN_REGISTERS
static const int RegisterArgumentCount = 4;
- static JSC::MacroAssembler::RegisterID registerForArgument(int index)
+ static RegisterID registerForArgument(int index)
{
- static JSC::MacroAssembler::RegisterID regs[RegisterArgumentCount] = {
+ static RegisterID regs[RegisterArgumentCount] = {
JSC::MIPSRegisters::a0,
JSC::MIPSRegisters::a1,
JSC::MIPSRegisters::a2,
@@ -549,27 +620,19 @@ public:
static const int StackShadowSpace = 4 * RegisterSize; // Stack space for 4 argument registers.
static const int StackSpaceAllocatedUponFunctionEntry = 1 * RegisterSize; // Registers saved in platformEnterStandardStackFrame below.
- static void platformEnterStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformEnterStandardStackFrame(PlatformAssembler *as)
{
as->push(JSC::MIPSRegisters::ra);
as->push(FramePointerRegister);
}
- static void platformLeaveStandardStackFrame(JSC::MacroAssembler *as)
+ static void platformLeaveStandardStackFrame(PlatformAssembler *as)
{
as->pop(FramePointerRegister);
as->pop(JSC::MIPSRegisters::ra);
}
-#endif // Linux on MIPS (32 bit)
-
-public: // utility functions
- static const RegisterInformation getRegisterInfo()
- {
- static const RegisterInformation info = getPlatformRegisterInfo();
-
- return info;
- }
};
+#endif // Linux on MIPS (32 bit)
} // JIT namespace
} // QV4 namespace
diff --git a/src/qml/jit/qv4unop.cpp b/src/qml/jit/qv4unop.cpp
index 799103849b..31355e5dce 100644
--- a/src/qml/jit/qv4unop.cpp
+++ b/src/qml/jit/qv4unop.cpp
@@ -48,14 +48,15 @@ using namespace JIT;
#define stringIfy(s) stringIfyx(s)
#define setOp(operation) \
do { \
- call = RuntimeCall(qOffsetOf(QV4::Runtime, operation)); name = "Runtime::" stringIfy(operation); \
+ call = typename JITAssembler::RuntimeCall(qOffsetOf(QV4::Runtime, operation)); name = "Runtime::" stringIfy(operation); \
needsExceptionCheck = Runtime::Method_##operation##_NeedsExceptionCheck; \
} while (0)
-void Unop::generate(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void Unop<JITAssembler>::generate(IR::Expr *source, IR::Expr *target)
{
bool needsExceptionCheck;
- RuntimeCall call;
+ typename JITAssembler::RuntimeCall call;
const char *name = 0;
switch (op) {
case IR::OpNot:
@@ -75,17 +76,18 @@ void Unop::generate(IR::Expr *source, IR::Expr *target)
} // switch
Q_ASSERT(call.isValid());
- _as->generateFunctionCallImp(needsExceptionCheck, target, name, call, Assembler::PointerToValue(source));
+ _as->generateFunctionCallImp(needsExceptionCheck, target, name, call, PointerToValue(source));
}
-void Unop::generateUMinus(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void Unop<JITAssembler>::generateUMinus(IR::Expr *source, IR::Expr *target)
{
IR::Temp *targetTemp = target->asTemp();
if (source->type == IR::SInt32Type) {
- Assembler::RegisterID tReg = Assembler::ScratchRegister;
+ typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) targetTemp->index;
- Assembler::RegisterID sReg = _as->toInt32Register(source, tReg);
+ tReg = (typename JITAssembler::RegisterID) targetTemp->index;
+ typename JITAssembler::RegisterID sReg = _as->toInt32Register(source, tReg);
_as->move(sReg, tReg);
_as->neg32(tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
@@ -93,26 +95,27 @@ void Unop::generateUMinus(IR::Expr *source, IR::Expr *target)
return;
}
- generateRuntimeCall(target, uMinus, Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, target, uMinus, PointerToValue(source));
}
-void Unop::generateNot(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void Unop<JITAssembler>::generateNot(IR::Expr *source, IR::Expr *target)
{
IR::Temp *targetTemp = target->asTemp();
if (source->type == IR::BoolType) {
- Assembler::RegisterID tReg = Assembler::ScratchRegister;
+ typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) targetTemp->index;
- _as->xor32(Assembler::TrustedImm32(0x1), _as->toInt32Register(source, tReg), tReg);
+ tReg = (typename JITAssembler::RegisterID) targetTemp->index;
+ _as->xor32(TrustedImm32(0x1), _as->toInt32Register(source, tReg), tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
_as->storeBool(tReg, target);
return;
} else if (source->type == IR::SInt32Type) {
- Assembler::RegisterID tReg = Assembler::ScratchRegister;
+ typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) targetTemp->index;
- _as->compare32(Assembler::Equal,
- _as->toInt32Register(source, Assembler::ScratchRegister), Assembler::TrustedImm32(0),
+ tReg = (typename JITAssembler::RegisterID) targetTemp->index;
+ _as->compare32(RelationalCondition::Equal,
+ _as->toInt32Register(source, JITAssembler::ScratchRegister), TrustedImm32(0),
tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
_as->storeBool(tReg, target);
@@ -122,22 +125,28 @@ void Unop::generateNot(IR::Expr *source, IR::Expr *target)
}
// ## generic implementation testing for int/bool
- generateRuntimeCall(target, uNot, Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, target, uNot, PointerToValue(source));
}
-void Unop::generateCompl(IR::Expr *source, IR::Expr *target)
+template <typename JITAssembler>
+void Unop<JITAssembler>::generateCompl(IR::Expr *source, IR::Expr *target)
{
IR::Temp *targetTemp = target->asTemp();
if (source->type == IR::SInt32Type) {
- Assembler::RegisterID tReg = Assembler::ScratchRegister;
+ typename JITAssembler::RegisterID tReg = JITAssembler::ScratchRegister;
if (targetTemp && targetTemp->kind == IR::Temp::PhysicalRegister)
- tReg = (Assembler::RegisterID) targetTemp->index;
- _as->xor32(Assembler::TrustedImm32(0xffffffff), _as->toInt32Register(source, tReg), tReg);
+ tReg = (typename JITAssembler::RegisterID) targetTemp->index;
+ _as->xor32(TrustedImm32(0xffffffff), _as->toInt32Register(source, tReg), tReg);
if (!targetTemp || targetTemp->kind != IR::Temp::PhysicalRegister)
_as->storeInt32(tReg, target);
return;
}
- generateRuntimeCall(target, complement, Assembler::PointerToValue(source));
+ generateRuntimeCall(_as, target, complement, PointerToValue(source));
}
+template struct QV4::JIT::Unop<QV4::JIT::Assembler<DefaultAssemblerTargetConfiguration>>;
+#if defined(V4_BOOTSTRAP) && CPU(X86_64)
+template struct QV4::JIT::Unop<QV4::JIT::Assembler<AssemblerTargetConfiguration<JSC::MacroAssemblerARMv7, NoOperatingSystemSpecialization>>>;
+#endif
+
#endif
diff --git a/src/qml/jit/qv4unop_p.h b/src/qml/jit/qv4unop_p.h
index 1141a84913..fb68f80eec 100644
--- a/src/qml/jit/qv4unop_p.h
+++ b/src/qml/jit/qv4unop_p.h
@@ -60,21 +60,25 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
namespace JIT {
-class Assembler;
-
+template <typename JITAssembler>
struct Unop {
- Unop(Assembler *assembler, IR::AluOp operation)
+ Unop(JITAssembler *assembler, IR::AluOp operation)
: _as(assembler)
, op(operation)
{}
+ using RelationalCondition = typename JITAssembler::RelationalCondition;
+ using PointerToValue = typename JITAssembler::PointerToValue;
+ using RuntimeCall = typename JITAssembler::RuntimeCall;
+ using TrustedImm32 = typename JITAssembler::TrustedImm32;
+
void generate(IR::Expr *source, IR::Expr *target);
void generateUMinus(IR::Expr *source, IR::Expr *target);
void generateNot(IR::Expr *source, IR::Expr *target);
void generateCompl(IR::Expr *source, IR::Expr *target);
- Assembler *_as;
+ JITAssembler *_as;
IR::AluOp op;
};
diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri
index 919524d1ed..955cf585e4 100644
--- a/src/qml/jsruntime/jsruntime.pri
+++ b/src/qml/jsruntime/jsruntime.pri
@@ -35,7 +35,6 @@ SOURCES += \
$$PWD/qv4regexp.cpp \
$$PWD/qv4serialize.cpp \
$$PWD/qv4script.cpp \
- $$PWD/qv4executableallocator.cpp \
$$PWD/qv4sequenceobject.cpp \
$$PWD/qv4include.cpp \
$$PWD/qv4qobjectwrapper.cpp \
@@ -113,7 +112,8 @@ HEADERS += \
SOURCES += \
$$PWD/qv4runtime.cpp \
$$PWD/qv4string.cpp \
- $$PWD/qv4value.cpp
+ $$PWD/qv4value.cpp \
+ $$PWD/qv4executableallocator.cpp
valgrind {
DEFINES += V4_USE_VALGRIND
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 5a190d6690..9354bcb1a3 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -88,10 +88,12 @@ void ArgumentsObject::fullyCreate()
Scope scope(engine());
Scoped<MemberData> md(scope, d()->mappedArguments);
- d()->mappedArguments = md->allocate(engine(), numAccessors);
- for (uint i = 0; i < numAccessors; ++i) {
- d()->mappedArguments->data[i] = context()->callData->args[i];
- arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor);
+ if (numAccessors) {
+ d()->mappedArguments = md->allocate(engine(), numAccessors);
+ for (uint i = 0; i < numAccessors; ++i) {
+ d()->mappedArguments->data[i] = context()->callData->args[i];
+ arraySet(i, context()->engine->argumentsAccessors + i, Attr_Accessor);
+ }
}
arrayPut(numAccessors, context()->callData->args + numAccessors, argCount - numAccessors);
for (uint i = numAccessors; i < argCount; ++i)
diff --git a/src/qml/jsruntime/qv4arraybuffer.cpp b/src/qml/jsruntime/qv4arraybuffer.cpp
index 23075aa78c..ffe9aa846f 100644
--- a/src/qml/jsruntime/qv4arraybuffer.cpp
+++ b/src/qml/jsruntime/qv4arraybuffer.cpp
@@ -81,16 +81,19 @@ void ArrayBufferCtor::call(const Managed *that, Scope &scope, CallData *callData
construct(that, scope, callData);
}
-ReturnedValue ArrayBufferCtor::method_isView(CallContext *ctx)
+void ArrayBufferCtor::method_isView(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<TypedArray> a(scope, ctx->argument(0));
- if (!!a)
- return Encode(true);
- QV4::Scoped<DataView> v(scope, ctx->argument(0));
- if (!!v)
- return Encode(true);
- return Encode(false);
+ QV4::Scoped<TypedArray> a(scope, callData->argument(0));
+ if (!!a) {
+ scope.result = Encode(true);
+ return;
+ }
+ QV4::Scoped<DataView> v(scope, callData->argument(0));
+ if (!!v) {
+ scope.result = Encode(true);
+ return;
+ }
+ scope.result = Encode(false);
}
@@ -160,54 +163,48 @@ void ArrayBufferPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("toString"), method_toString, 0);
}
-ReturnedValue ArrayBufferPrototype::method_get_byteLength(CallContext *ctx)
+void ArrayBufferPrototype::method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<ArrayBuffer> v(scope, ctx->thisObject());
+ Scoped<ArrayBuffer> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->data->size);
+ scope.result = Encode(v->d()->data->size);
}
-ReturnedValue ArrayBufferPrototype::method_slice(CallContext *ctx)
+void ArrayBufferPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<ArrayBuffer> a(scope, ctx->thisObject());
+ Scoped<ArrayBuffer> a(scope, callData->thisObject);
if (!a)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- double start = ctx->argc() > 0 ? ctx->args()[0].toInteger() : 0;
- double end = (ctx->argc() < 2 || ctx->args()[1].isUndefined()) ?
- a->d()->data->size : ctx->args()[1].toInteger();
- if (scope.engine->hasException)
- return Encode::undefined();
+ double start = callData->argc > 0 ? callData->args[0].toInteger() : 0;
+ double end = (callData->argc < 2 || callData->args[1].isUndefined()) ?
+ a->d()->data->size : callData->args[1].toInteger();
+ CHECK_EXCEPTION();
double first = (start < 0) ? qMax(a->d()->data->size + start, 0.) : qMin(start, (double)a->d()->data->size);
double final = (end < 0) ? qMax(a->d()->data->size + end, 0.) : qMin(end, (double)a->d()->data->size);
ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor()));
if (!constructor)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope, 1);
+ ScopedCallData cData(scope, 1);
double newLen = qMax(final - first, 0.);
- callData->args[0] = QV4::Encode(newLen);
- constructor->construct(scope, callData);
- QV4::Scoped<ArrayBuffer> newBuffer(scope, scope.result.asReturnedValue());
+ cData->args[0] = QV4::Encode(newLen);
+ constructor->construct(scope, cData);
+ QV4::Scoped<ArrayBuffer> newBuffer(scope, scope.result);
if (!newBuffer || newBuffer->d()->data->size < (int)newLen)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
memcpy(newBuffer->d()->data->data(), a->d()->data->data() + (uint)first, newLen);
-
- return newBuffer.asReturnedValue();
}
-ReturnedValue ArrayBufferPrototype::method_toString(CallContext *ctx)
+void ArrayBufferPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<ArrayBuffer> a(scope, ctx->thisObject());
+ Scoped<ArrayBuffer> a(scope, callData->thisObject);
if (!a)
- return Encode::undefined();
- return Encode(ctx->engine()->newString(QString::fromUtf8(a->asByteArray())));
+ RETURN_UNDEFINED();
+ scope.result = scope.engine->newString(QString::fromUtf8(a->asByteArray()));
}
diff --git a/src/qml/jsruntime/qv4arraybuffer_p.h b/src/qml/jsruntime/qv4arraybuffer_p.h
index bc56d1ea31..4f7926d3dc 100644
--- a/src/qml/jsruntime/qv4arraybuffer_p.h
+++ b/src/qml/jsruntime/qv4arraybuffer_p.h
@@ -81,7 +81,7 @@ struct ArrayBufferCtor: FunctionObject
static void construct(const Managed *m, Scope &scope, CallData *callData);
static void call(const Managed *that, Scope &scope, CallData *callData);
- static ReturnedValue method_isView(CallContext *ctx);
+ static void method_isView(const BuiltinFunction *, Scope &scope, CallData *callData);
};
@@ -104,9 +104,9 @@ struct ArrayBufferPrototype: Object
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_get_byteLength(CallContext *ctx);
- static ReturnedValue method_slice(CallContext *ctx);
- static ReturnedValue method_toString(CallContext *ctx);
+ static void method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_slice(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4arraydata.cpp b/src/qml/jsruntime/qv4arraydata.cpp
index bfeb3d4699..d8a7de5466 100644
--- a/src/qml/jsruntime/qv4arraydata.cpp
+++ b/src/qml/jsruntime/qv4arraydata.cpp
@@ -237,8 +237,14 @@ void ArrayData::ensureAttributes(Object *o)
void SimpleArrayData::markObjects(Heap::Base *d, ExecutionEngine *e)
{
Heap::SimpleArrayData *dd = static_cast<Heap::SimpleArrayData *>(d);
- for (uint i = 0; i < dd->len; ++i)
- dd->arrayData[dd->mappedIndex(i)].mark(e);
+ uint end = dd->offset + dd->len;
+ if (end > dd->alloc) {
+ for (uint i = 0; i < end - dd->alloc; ++i)
+ dd->arrayData[i].mark(e);
+ end = dd->alloc;
+ }
+ for (uint i = dd->offset; i < end; ++i)
+ dd->arrayData[i].mark(e);
}
ReturnedValue SimpleArrayData::get(const Heap::ArrayData *d, uint index)
diff --git a/src/qml/jsruntime/qv4arrayobject.cpp b/src/qml/jsruntime/qv4arrayobject.cpp
index 20ba11fd75..759354f4e2 100644
--- a/src/qml/jsruntime/qv4arrayobject.cpp
+++ b/src/qml/jsruntime/qv4arrayobject.cpp
@@ -44,6 +44,7 @@
#include "qv4argumentsobject_p.h"
#include "qv4runtime_p.h"
#include "qv4string_p.h"
+#include <QtCore/qscopedvaluerollback.h>
using namespace QV4;
@@ -118,42 +119,40 @@ void ArrayPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("reduceRight"), method_reduceRight, 1);
}
-ReturnedValue ArrayPrototype::method_isArray(CallContext *ctx)
+void ArrayPrototype::method_isArray(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- bool isArray = ctx->argc() && ctx->args()[0].as<ArrayObject>();
- return Encode(isArray);
+ bool isArray = callData->argc && callData->args[0].as<ArrayObject>();
+ scope.result = Encode(isArray);
}
-ReturnedValue ArrayPrototype::method_toString(CallContext *ctx)
+void ArrayPrototype::method_toString(const BuiltinFunction *builtin, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->thisObject(), ScopedObject::Convert);
- if (ctx->d()->engine->hasException)
- return Encode::undefined();
- ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("join")));
+ ScopedObject o(scope, callData->thisObject, ScopedObject::Convert);
+ CHECK_EXCEPTION();
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("join")));
ScopedFunctionObject f(scope, o->get(s));
if (!!f) {
ScopedCallData d(scope, 0);
- d->thisObject = ctx->thisObject();
+ d->thisObject = callData->thisObject;
f->call(scope, d);
- return scope.result.asReturnedValue();
+ return;
}
- return ObjectPrototype::method_toString(ctx);
+ ObjectPrototype::method_toString(builtin, scope, callData);
}
-ReturnedValue ArrayPrototype::method_toLocaleString(CallContext *ctx)
+void ArrayPrototype::method_toLocaleString(const BuiltinFunction *builtin, Scope &scope, CallData *callData)
{
- return method_toString(ctx);
+ return method_toString(builtin, scope, callData);
}
-ReturnedValue ArrayPrototype::method_concat(CallContext *ctx)
+void ArrayPrototype::method_concat(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject result(scope, ctx->d()->engine->newArrayObject());
-
- ScopedObject thisObject(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject thisObject(scope, callData->thisObject.toObject(scope.engine));
if (!thisObject)
- return Encode::undefined();
+ RETURN_UNDEFINED();
+
+ ScopedArrayObject result(scope, scope.engine->newArrayObject());
+
if (thisObject->isArrayObject()) {
result->copyArrayData(thisObject);
} else {
@@ -163,9 +162,9 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx)
ScopedArrayObject elt(scope);
ScopedObject eltAsObj(scope);
ScopedValue entry(scope);
- for (int i = 0; i < ctx->argc(); ++i) {
- eltAsObj = ctx->args()[i];
- elt = ctx->args()[i];
+ for (int i = 0; i < callData->argc; ++i) {
+ eltAsObj = callData->args[i];
+ elt = callData->args[i];
if (elt) {
uint n = elt->getLength();
uint newLen = ArrayData::append(result, elt, n);
@@ -177,95 +176,90 @@ ReturnedValue ArrayPrototype::method_concat(CallContext *ctx)
result->putIndexed(startIndex + i, entry);
}
} else {
- result->arraySet(result->getLength(), ctx->args()[i]);
+ result->arraySet(result->getLength(), callData->args[i]);
}
}
- return result.asReturnedValue();
+ scope.result = result;
}
-ReturnedValue ArrayPrototype::method_find(CallContext *ctx)
+void ArrayPrototype::method_find(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope, 3);
- callData->thisObject = ctx->argument(1);
- callData->args[2] = instance;
+ ScopedCallData cData(scope, 3);
+ cData->thisObject = callData->argument(1);
+ cData->args[2] = instance;
ScopedValue v(scope);
for (uint k = 0; k < len; ++k) {
v = instance->getIndexed(k);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
- callData->args[0] = v;
- callData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, callData);
+ cData->args[0] = v;
+ cData->args[1] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
- if (scope.hasException())
- return Encode::undefined();
- else if (scope.result.toBoolean())
- return v->asReturnedValue();
+ CHECK_EXCEPTION();
+ if (scope.result.toBoolean())
+ RETURN_RESULT(v);
}
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue ArrayPrototype::method_findIndex(CallContext *ctx)
+void ArrayPrototype::method_findIndex(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope, 3);
- callData->thisObject = ctx->argument(1);
- callData->args[2] = instance;
+ ScopedCallData cData(scope, 3);
+ cData->thisObject = callData->argument(1);
+ cData->args[2] = instance;
ScopedValue v(scope);
for (uint k = 0; k < len; ++k) {
v = instance->getIndexed(k);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
- callData->args[0] = v;
- callData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, callData);
+ cData->args[0] = v;
+ cData->args[1] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
- if (scope.hasException())
- return Encode::undefined();
- else if (scope.result.toBoolean())
- return Encode(k);
+ CHECK_EXCEPTION();
+ if (scope.result.toBoolean())
+ RETURN_RESULT(Encode(k));
}
- return Encode(-1);
+ RETURN_RESULT(Encode(-1));
}
-ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
+void ArrayPrototype::method_join(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue arg(scope, ctx->argument(0));
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedValue arg(scope, callData->argument(0));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
- if (!instance)
- return ctx->d()->engine->newString()->asReturnedValue();
+ if (!instance) {
+ scope.result = scope.engine->newString();
+ return;
+ }
QString r4;
if (arg->isUndefined())
@@ -273,11 +267,13 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
else
r4 = arg->toQString();
- ScopedValue length(scope, instance->get(ctx->d()->engine->id_length()));
+ ScopedValue length(scope, instance->get(scope.engine->id_length()));
const quint32 r2 = length->isUndefined() ? 0 : length->toUInt32();
- if (!r2)
- return ctx->d()->engine->newString()->asReturnedValue();
+ if (!r2) {
+ scope.result = scope.engine->newString();
+ return;
+ }
QString R;
@@ -289,8 +285,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
R += r4;
e = a->getIndexed(i);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (!e->isNullOrUndefined())
R += e->toQString();
}
@@ -298,7 +293,7 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
//
// crazy!
//
- ScopedString name(scope, ctx->d()->engine->newString(QStringLiteral("0")));
+ ScopedString name(scope, scope.engine->newString(QStringLiteral("0")));
ScopedValue r6(scope, instance->get(name));
if (!r6->isNullOrUndefined())
R = r6->toQString();
@@ -309,99 +304,98 @@ ReturnedValue ArrayPrototype::method_join(CallContext *ctx)
name = Primitive::fromDouble(k).toString(scope.engine);
r12 = instance->get(name);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (!r12->isNullOrUndefined())
R += r12->toQString();
}
}
- return ctx->d()->engine->newString(R)->asReturnedValue();
+ scope.result = scope.engine->newString(R);
}
-ReturnedValue ArrayPrototype::method_pop(CallContext *ctx)
+void ArrayPrototype::method_pop(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
+
uint len = instance->getLength();
if (!len) {
if (!instance->isArrayObject())
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0)));
- return Encode::undefined();
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0)));
+ RETURN_UNDEFINED();
}
ScopedValue result(scope, instance->getIndexed(len - 1));
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
instance->deleteIndexedProperty(len - 1);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
+
if (instance->isArrayObject())
instance->setArrayLength(len - 1);
else
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1)));
- return result->asReturnedValue();
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1)));
+ scope.result = result;
}
-ReturnedValue ArrayPrototype::method_push(CallContext *ctx)
+void ArrayPrototype::method_push(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
instance->arrayCreate();
Q_ASSERT(instance->arrayData());
uint len = instance->getLength();
- if (len + ctx->argc() < len) {
+ if (len + callData->argc < len) {
// ughh...
double l = len;
ScopedString s(scope);
- for (int i = 0; i < ctx->argc(); ++i) {
+ for (int i = 0; i < callData->argc; ++i) {
s = Primitive::fromDouble(l + i).toString(scope.engine);
- instance->put(s, ctx->args()[i]);
+ instance->put(s, callData->args[i]);
}
- double newLen = l + ctx->argc();
+ double newLen = l + callData->argc;
if (!instance->isArrayObject())
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen)));
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen)));
else {
- ScopedString str(scope, ctx->d()->engine->newString(QStringLiteral("Array.prototype.push: Overflow")));
- return ctx->engine()->throwRangeError(str);
+ ScopedString str(scope, scope.engine->newString(QStringLiteral("Array.prototype.push: Overflow")));
+ scope.result = scope.engine->throwRangeError(str);
+ return;
}
- return Encode(newLen);
+ scope.result = Encode(newLen);
+ return;
}
- if (!ctx->argc())
+ if (!callData->argc)
;
else if (!instance->protoHasArray() && instance->arrayData()->length() <= len && instance->arrayData()->type == Heap::ArrayData::Simple) {
- instance->arrayData()->vtable()->putArray(instance, len, ctx->args(), ctx->argc());
+ instance->arrayData()->vtable()->putArray(instance, len, callData->args, callData->argc);
len = instance->arrayData()->length();
} else {
- for (int i = 0; i < ctx->argc(); ++i)
- instance->putIndexed(len + i, ctx->args()[i]);
- len += ctx->argc();
+ for (int i = 0; i < callData->argc; ++i)
+ instance->putIndexed(len + i, callData->args[i]);
+ len += callData->argc;
}
if (instance->isArrayObject())
instance->setArrayLengthUnchecked(len);
else
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len)));
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len)));
- return Encode(len);
+ scope.result = Encode(len);
}
-ReturnedValue ArrayPrototype::method_reverse(CallContext *ctx)
+void ArrayPrototype::method_reverse(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
+
uint length = instance->getLength();
int lo = 0, hi = length - 1;
@@ -412,28 +406,25 @@ ReturnedValue ArrayPrototype::method_reverse(CallContext *ctx)
bool loExists, hiExists;
lval = instance->getIndexed(lo, &loExists);
hval = instance->getIndexed(hi, &hiExists);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (hiExists)
instance->putIndexed(lo, hval);
else
instance->deleteIndexedProperty(lo);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (loExists)
instance->putIndexed(hi, lval);
else
instance->deleteIndexedProperty(hi);
}
- return instance.asReturnedValue();
+ scope.result = instance;
}
-ReturnedValue ArrayPrototype::method_shift(CallContext *ctx)
+void ArrayPrototype::method_shift(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
instance->arrayCreate();
Q_ASSERT(instance->arrayData());
@@ -442,54 +433,46 @@ ReturnedValue ArrayPrototype::method_shift(CallContext *ctx)
if (!len) {
if (!instance->isArrayObject())
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0)));
- return Encode::undefined();
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromInt32(0)));
+ RETURN_UNDEFINED();
}
- ScopedValue result(scope);
-
if (!instance->protoHasArray() && !instance->arrayData()->attrs && instance->arrayData()->length() <= len && instance->arrayData()->type != Heap::ArrayData::Custom) {
- result = instance->arrayData()->vtable()->pop_front(instance);
+ scope.result = instance->arrayData()->vtable()->pop_front(instance);
} else {
- result = instance->getIndexed(0);
- if (scope.hasException())
- return Encode::undefined();
+ scope.result = instance->getIndexed(0);
+ CHECK_EXCEPTION();
ScopedValue v(scope);
// do it the slow way
for (uint k = 1; k < len; ++k) {
bool exists;
v = instance->getIndexed(k, &exists);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (exists)
instance->putIndexed(k - 1, v);
else
instance->deleteIndexedProperty(k - 1);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
}
instance->deleteIndexedProperty(len - 1);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
}
if (instance->isArrayObject())
instance->setArrayLengthUnchecked(len - 1);
else
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1)));
- return result->asReturnedValue();
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - 1)));
}
-ReturnedValue ArrayPrototype::method_slice(CallContext *ctx)
+void ArrayPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject o(scope, callData->thisObject.toObject(scope.engine));
if (!o)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- ScopedArrayObject result(scope, ctx->d()->engine->newArrayObject());
+ ScopedArrayObject result(scope, scope.engine->newArrayObject());
uint len = o->getLength();
- double s = ScopedValue(scope, ctx->argument(0))->toInteger();
+ double s = ScopedValue(scope, callData->argument(0))->toInteger();
uint start;
if (s < 0)
start = (uint)qMax(len + s, 0.);
@@ -498,8 +481,8 @@ ReturnedValue ArrayPrototype::method_slice(CallContext *ctx)
else
start = (uint) s;
uint end = len;
- if (ctx->argc() > 1 && !ctx->args()[1].isUndefined()) {
- double e = ctx->args()[1].toInteger();
+ if (callData->argc > 1 && !callData->args[1].isUndefined()) {
+ double e = callData->args[1].toInteger();
if (e < 0)
end = (uint)qMax(len + e, 0.);
else if (e > len)
@@ -513,115 +496,107 @@ ReturnedValue ArrayPrototype::method_slice(CallContext *ctx)
for (uint i = start; i < end; ++i) {
bool exists;
v = o->getIndexed(i, &exists);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (exists)
result->arraySet(n, v);
++n;
}
- return result.asReturnedValue();
+ scope.result = result;
}
-ReturnedValue ArrayPrototype::method_sort(CallContext *ctx)
+void ArrayPrototype::method_sort(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedValue comparefn(scope, ctx->argument(0));
+ ScopedValue comparefn(scope, callData->argument(0));
ArrayData::sort(scope.engine, instance, comparefn, len);
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
}
-ReturnedValue ArrayPrototype::method_splice(CallContext *ctx)
+void ArrayPrototype::method_splice(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
+
uint len = instance->getLength();
- ScopedArrayObject newArray(scope, ctx->d()->engine->newArrayObject());
+ ScopedArrayObject newArray(scope, scope.engine->newArrayObject());
- double rs = ScopedValue(scope, ctx->argument(0))->toInteger();
+ double rs = ScopedValue(scope, callData->argument(0))->toInteger();
uint start;
if (rs < 0)
start = (uint) qMax(0., len + rs);
else
start = (uint) qMin(rs, (double)len);
- uint deleteCount = (uint)qMin(qMax(ScopedValue(scope, ctx->argument(1))->toInteger(), 0.), (double)(len - start));
+ uint deleteCount = (uint)qMin(qMax(ScopedValue(scope, callData->argument(1))->toInteger(), 0.), (double)(len - start));
newArray->arrayReserve(deleteCount);
ScopedValue v(scope);
for (uint i = 0; i < deleteCount; ++i) {
bool exists;
v = instance->getIndexed(start + i, &exists);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (exists)
newArray->arrayPut(i, v);
}
newArray->setArrayLengthUnchecked(deleteCount);
- uint itemCount = ctx->argc() < 2 ? 0 : ctx->argc() - 2;
+ uint itemCount = callData->argc < 2 ? 0 : callData->argc - 2;
if (itemCount < deleteCount) {
for (uint k = start; k < len - deleteCount; ++k) {
bool exists;
v = instance->getIndexed(k + deleteCount, &exists);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (exists)
instance->putIndexed(k + itemCount, v);
else
instance->deleteIndexedProperty(k + itemCount);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
}
for (uint k = len; k > len - deleteCount + itemCount; --k) {
instance->deleteIndexedProperty(k - 1);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
}
} else if (itemCount > deleteCount) {
uint k = len - deleteCount;
while (k > start) {
bool exists;
v = instance->getIndexed(k + deleteCount - 1, &exists);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (exists)
instance->putIndexed(k + itemCount - 1, v);
else
instance->deleteIndexedProperty(k + itemCount - 1);
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
--k;
}
}
for (uint i = 0; i < itemCount; ++i) {
- instance->putIndexed(start + i, ctx->args()[i + 2]);
- if (scope.hasException())
- return Encode::undefined();
+ instance->putIndexed(start + i, callData->args[i + 2]);
+ CHECK_EXCEPTION();
}
- ctx->d()->strictMode = true;
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount)));
+ bool wasStrict = scope.engine->current->strictMode;
+ scope.engine->current->strictMode = true;
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(len - deleteCount + itemCount)));
- return newArray.asReturnedValue();
+ scope.result = newArray;
+ scope.engine->current->strictMode = wasStrict;
}
-ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx)
+void ArrayPrototype::method_unshift(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
instance->arrayCreate();
Q_ASSERT(instance->arrayData());
@@ -630,50 +605,52 @@ ReturnedValue ArrayPrototype::method_unshift(CallContext *ctx)
if (!instance->protoHasArray() && !instance->arrayData()->attrs && instance->arrayData()->length() <= len &&
instance->arrayData()->type != Heap::ArrayData::Custom) {
- instance->arrayData()->vtable()->push_front(instance, ctx->args(), ctx->argc());
+ instance->arrayData()->vtable()->push_front(instance, callData->args, callData->argc);
} else {
ScopedValue v(scope);
for (uint k = len; k > 0; --k) {
bool exists;
v = instance->getIndexed(k - 1, &exists);
if (exists)
- instance->putIndexed(k + ctx->argc() - 1, v);
+ instance->putIndexed(k + callData->argc - 1, v);
else
- instance->deleteIndexedProperty(k + ctx->argc() - 1);
+ instance->deleteIndexedProperty(k + callData->argc - 1);
}
- for (int i = 0; i < ctx->argc(); ++i)
- instance->putIndexed(i, ctx->args()[i]);
+ for (int i = 0; i < callData->argc; ++i)
+ instance->putIndexed(i, callData->args[i]);
}
- uint newLen = len + ctx->argc();
+ uint newLen = len + callData->argc;
if (instance->isArrayObject())
instance->setArrayLengthUnchecked(newLen);
else
- instance->put(ctx->d()->engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen)));
+ instance->put(scope.engine->id_length(), ScopedValue(scope, Primitive::fromDouble(newLen)));
- return Encode(newLen);
+ scope.result = Encode(newLen);
}
-ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
+void ArrayPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
-
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
+
uint len = instance->getLength();
- if (!len)
- return Encode(-1);
+ if (!len) {
+ scope.result = Encode(-1);
+ return;
+ }
- ScopedValue searchValue(scope, ctx->argument(0));
+ ScopedValue searchValue(scope, callData->argument(0));
uint fromIndex = 0;
- if (ctx->argc() >= 2) {
- double f = ctx->args()[1].toInteger();
- if (scope.hasException())
- return Encode::undefined();
- if (f >= len)
- return Encode(-1);
+ if (callData->argc >= 2) {
+ double f = callData->args[1].toInteger();
+ CHECK_EXCEPTION();
+ if (f >= len) {
+ scope.result = Encode(-1);
+ return;
+ }
if (f < 0)
f = qMax(len + f, 0.);
fromIndex = (uint) f;
@@ -684,10 +661,13 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
for (uint k = fromIndex; k < len; ++k) {
bool exists;
v = instance->getIndexed(k, &exists);
- if (exists && RuntimeHelpers::strictEqual(v, searchValue))
- return Encode(k);
+ if (exists && RuntimeHelpers::strictEqual(v, searchValue)) {
+ scope.result = Encode(k);
+ return;
+ }
}
- return Encode(-1);
+ scope.result = Encode(-1);
+ return;
}
ScopedValue value(scope);
@@ -698,13 +678,15 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
for (uint i = fromIndex; i < len; ++i) {
bool exists;
value = instance->getIndexed(i, &exists);
- if (scope.hasException())
- return Encode::undefined();
- if (exists && RuntimeHelpers::strictEqual(value, searchValue))
- return Encode(i);
+ CHECK_EXCEPTION();
+ if (exists && RuntimeHelpers::strictEqual(value, searchValue)) {
+ scope.result = Encode(i);
+ return;
+ }
}
} else if (!instance->arrayData()) {
- return Encode(-1);
+ scope.result = Encode(-1);
+ return;
} else {
Q_ASSERT(instance->arrayType() == Heap::ArrayData::Simple || instance->arrayType() == Heap::ArrayData::Complex);
Heap::SimpleArrayData *sa = instance->d()->arrayData.cast<Heap::SimpleArrayData>();
@@ -713,45 +695,48 @@ ReturnedValue ArrayPrototype::method_indexOf(CallContext *ctx)
uint idx = fromIndex;
while (idx < len) {
value = sa->data(idx);
- if (scope.hasException())
- return Encode::undefined();
- if (RuntimeHelpers::strictEqual(value, searchValue))
- return Encode(idx);
+ CHECK_EXCEPTION();
+ if (RuntimeHelpers::strictEqual(value, searchValue)) {
+ scope.result = Encode(idx);
+ return;
+ }
++idx;
}
}
- return Encode(-1);
+ scope.result = Encode(-1);
}
-ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx)
+void ArrayPrototype::method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
-
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
+
uint len = instance->getLength();
- if (!len)
- return Encode(-1);
+ if (!len) {
+ scope.result = Encode(-1);
+ return;
+ }
ScopedValue searchValue(scope);
uint fromIndex = len;
- if (ctx->argc() >= 1)
- searchValue = ctx->argument(0);
+ if (callData->argc >= 1)
+ searchValue = callData->argument(0);
else
searchValue = Primitive::undefinedValue();
- if (ctx->argc() >= 2) {
- double f = ctx->args()[1].toInteger();
- if (scope.hasException())
- return Encode::undefined();
+ if (callData->argc >= 2) {
+ double f = callData->args[1].toInteger();
+ CHECK_EXCEPTION();
if (f > 0)
f = qMin(f, (double)(len - 1));
else if (f < 0) {
f = len + f;
- if (f < 0)
- return Encode(-1);
+ if (f < 0) {
+ scope.result = Encode(-1);
+ return;
+ }
}
fromIndex = (uint) f + 1;
}
@@ -761,30 +746,30 @@ ReturnedValue ArrayPrototype::method_lastIndexOf(CallContext *ctx)
--k;
bool exists;
v = instance->getIndexed(k, &exists);
- if (scope.hasException())
- return Encode::undefined();
- if (exists && RuntimeHelpers::strictEqual(v, searchValue))
- return Encode(k);
+ CHECK_EXCEPTION();
+ if (exists && RuntimeHelpers::strictEqual(v, searchValue)) {
+ scope.result = Encode(k);
+ return;
+ }
}
- return Encode(-1);
+ scope.result = Encode(-1);
}
-ReturnedValue ArrayPrototype::method_every(CallContext *ctx)
+void ArrayPrototype::method_every(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope, 3);
- callData->args[2] = instance;
- callData->thisObject = ctx->argument(1);
+ ScopedCallData cData(scope, 3);
+ cData->args[2] = instance;
+ cData->thisObject = callData->argument(1);
ScopedValue v(scope);
bool ok = true;
@@ -794,30 +779,29 @@ ReturnedValue ArrayPrototype::method_every(CallContext *ctx)
if (!exists)
continue;
- callData->args[0] = v;
- callData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, callData);
+ cData->args[0] = v;
+ cData->args[1] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
ok = scope.result.toBoolean();
}
- return Encode(ok);
+ scope.result = Encode(ok);
}
-ReturnedValue ArrayPrototype::method_some(CallContext *ctx)
+void ArrayPrototype::method_some(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope, 3);
- callData->thisObject = ctx->argument(1);
- callData->args[2] = instance;
+ ScopedCallData cData(scope, 3);
+ cData->thisObject = callData->argument(1);
+ cData->args[2] = instance;
ScopedValue v(scope);
for (uint k = 0; k < len; ++k) {
@@ -826,31 +810,32 @@ ReturnedValue ArrayPrototype::method_some(CallContext *ctx)
if (!exists)
continue;
- callData->args[0] = v;
- callData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, callData);
- if (scope.result.toBoolean())
- return Encode(true);
+ cData->args[0] = v;
+ cData->args[1] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
+ if (scope.result.toBoolean()) {
+ scope.result = Encode(true);
+ return;
+ }
}
- return Encode(false);
+ scope.result = Encode(false);
}
-ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx)
+void ArrayPrototype::method_forEach(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope, 3);
- callData->thisObject = ctx->argument(1);
- callData->args[2] = instance;
+ ScopedCallData cData(scope, 3);
+ cData->thisObject = callData->argument(1);
+ cData->args[2] = instance;
ScopedValue v(scope);
for (uint k = 0; k < len; ++k) {
@@ -859,33 +844,32 @@ ReturnedValue ArrayPrototype::method_forEach(CallContext *ctx)
if (!exists)
continue;
- callData->args[0] = v;
- callData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, callData);
+ cData->args[0] = v;
+ cData->args[1] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
}
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue ArrayPrototype::method_map(CallContext *ctx)
+void ArrayPrototype::method_map(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject());
+ ScopedArrayObject a(scope, scope.engine->newArrayObject());
a->arrayReserve(len);
a->setArrayLengthUnchecked(len);
- ScopedCallData callData(scope, 3);
- callData->thisObject = ctx->argument(1);
- callData->args[2] = instance;
+ ScopedCallData cData(scope, 3);
+ cData->thisObject = callData->argument(1);
+ cData->args[2] = instance;
ScopedValue v(scope);
for (uint k = 0; k < len; ++k) {
@@ -894,33 +878,32 @@ ReturnedValue ArrayPrototype::method_map(CallContext *ctx)
if (!exists)
continue;
- callData->args[0] = v;
- callData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, callData);
+ cData->args[0] = v;
+ cData->args[1] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
a->arraySet(k, scope.result);
}
- return a.asReturnedValue();
+ scope.result = a.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_filter(CallContext *ctx)
+void ArrayPrototype::method_filter(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject());
+ ScopedArrayObject a(scope, scope.engine->newArrayObject());
a->arrayReserve(len);
- ScopedCallData callData(scope, 3);
- callData->thisObject = ctx->argument(1);
- callData->args[2] = instance;
+ ScopedCallData cData(scope, 3);
+ cData->thisObject = callData->argument(1);
+ cData->args[2] = instance;
ScopedValue v(scope);
@@ -931,35 +914,34 @@ ReturnedValue ArrayPrototype::method_filter(CallContext *ctx)
if (!exists)
continue;
- callData->args[0] = v;
- callData->args[1] = Primitive::fromDouble(k);
- callback->call(scope, callData);
+ cData->args[0] = v;
+ cData->args[1] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
if (scope.result.toBoolean()) {
a->arraySet(to, v);
++to;
}
}
- return a.asReturnedValue();
+ scope.result = a.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx)
+void ArrayPrototype::method_reduce(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
uint k = 0;
ScopedValue v(scope);
- if (ctx->argc() > 1) {
- scope.result = ctx->argument(1);
+ if (callData->argc > 1) {
+ scope.result = callData->argument(1);
} else {
bool kPresent = false;
while (k < len && !kPresent) {
@@ -969,51 +951,50 @@ ReturnedValue ArrayPrototype::method_reduce(CallContext *ctx)
++k;
}
if (!kPresent)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
}
- ScopedCallData callData(scope, 4);
- callData->thisObject = Primitive::undefinedValue();
- callData->args[0] = scope.result;
- callData->args[3] = instance;
+ ScopedCallData cData(scope, 4);
+ cData->thisObject = Primitive::undefinedValue();
+ cData->args[0] = scope.result;
+ cData->args[3] = instance;
while (k < len) {
bool kPresent;
v = instance->getIndexed(k, &kPresent);
if (kPresent) {
- callData->args[0] = scope.result;
- callData->args[1] = v;
- callData->args[2] = Primitive::fromDouble(k);
- callback->call(scope, callData);
+ cData->args[0] = scope.result;
+ cData->args[1] = v;
+ cData->args[2] = Primitive::fromDouble(k);
+ callback->call(scope, cData);
}
++k;
}
- return scope.result.asReturnedValue();
}
-ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
+void ArrayPrototype::method_reduceRight(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject instance(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject instance(scope, callData->thisObject.toObject(scope.engine));
if (!instance)
- return Encode::undefined();
+ RETURN_UNDEFINED();
uint len = instance->getLength();
- ScopedFunctionObject callback(scope, ctx->argument(0));
+ ScopedFunctionObject callback(scope, callData->argument(0));
if (!callback)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (len == 0) {
- if (ctx->argc() == 1)
- return ctx->engine()->throwTypeError();
- return ctx->argument(1);
+ if (callData->argc == 1)
+ THROW_TYPE_ERROR();
+ scope.result = callData->argument(1);
+ return;
}
uint k = len;
ScopedValue v(scope);
- if (ctx->argc() > 1) {
- scope.result = ctx->argument(1);
+ if (callData->argc > 1) {
+ scope.result = callData->argument(1);
} else {
bool kPresent = false;
while (k > 0 && !kPresent) {
@@ -1023,24 +1004,24 @@ ReturnedValue ArrayPrototype::method_reduceRight(CallContext *ctx)
--k;
}
if (!kPresent)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
}
- ScopedCallData callData(scope, 4);
- callData->thisObject = Primitive::undefinedValue();
- callData->args[3] = instance;
+ ScopedCallData cData(scope, 4);
+ cData->thisObject = Primitive::undefinedValue();
+ cData->args[3] = instance;
while (k > 0) {
bool kPresent;
v = instance->getIndexed(k - 1, &kPresent);
if (kPresent) {
- callData->args[0] = scope.result;
- callData->args[1] = v;
- callData->args[2] = Primitive::fromDouble(k - 1);
- callback->call(scope, callData);
+ cData->args[0] = scope.result;
+ cData->args[1] = v;
+ cData->args[2] = Primitive::fromDouble(k - 1);
+ callback->call(scope, cData);
}
--k;
}
- return scope.result.asReturnedValue();
+ scope.result = scope.result.asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4arrayobject_p.h b/src/qml/jsruntime/qv4arrayobject_p.h
index f00c0c0249..689752433b 100644
--- a/src/qml/jsruntime/qv4arrayobject_p.h
+++ b/src/qml/jsruntime/qv4arrayobject_p.h
@@ -78,30 +78,30 @@ struct ArrayPrototype: ArrayObject
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_isArray(CallContext *ctx);
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_toLocaleString(CallContext *ctx);
- static ReturnedValue method_concat(CallContext *ctx);
- static ReturnedValue method_find(CallContext *ctx);
- static ReturnedValue method_findIndex(CallContext *ctx);
- static ReturnedValue method_join(CallContext *ctx);
- static ReturnedValue method_pop(CallContext *ctx);
- static ReturnedValue method_push(CallContext *ctx);
- static ReturnedValue method_reverse(CallContext *ctx);
- static ReturnedValue method_shift(CallContext *ctx);
- static ReturnedValue method_slice(CallContext *ctx);
- static ReturnedValue method_sort(CallContext *ctx);
- static ReturnedValue method_splice(CallContext *ctx);
- static ReturnedValue method_unshift(CallContext *ctx);
- static ReturnedValue method_indexOf(CallContext *ctx);
- static ReturnedValue method_lastIndexOf(CallContext *ctx);
- static ReturnedValue method_every(CallContext *ctx);
- static ReturnedValue method_some(CallContext *ctx);
- static ReturnedValue method_forEach(CallContext *ctx);
- static ReturnedValue method_map(CallContext *ctx);
- static ReturnedValue method_filter(CallContext *ctx);
- static ReturnedValue method_reduce(CallContext *ctx);
- static ReturnedValue method_reduceRight(CallContext *ctx);
+ static void method_isArray(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_toString(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_toLocaleString(const BuiltinFunction *builtin, Scope &, CallData *callData);
+ static void method_concat(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_find(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_findIndex(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_join(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_pop(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_push(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_reverse(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_shift(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_slice(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_sort(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_splice(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_unshift(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_indexOf(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_lastIndexOf(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_every(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_some(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_forEach(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_map(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_filter(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_reduce(const BuiltinFunction *, Scope &, CallData *callData);
+ static void method_reduceRight(const BuiltinFunction *, Scope &, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4booleanobject.cpp b/src/qml/jsruntime/qv4booleanobject.cpp
index 8047993266..601066110f 100644
--- a/src/qml/jsruntime/qv4booleanobject.cpp
+++ b/src/qml/jsruntime/qv4booleanobject.cpp
@@ -73,29 +73,31 @@ void BooleanPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(engine->id_valueOf(), method_valueOf);
}
-ReturnedValue BooleanPrototype::method_toString(CallContext *ctx)
+void BooleanPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
bool result;
- if (ctx->thisObject().isBoolean()) {
- result = ctx->thisObject().booleanValue();
+ if (callData->thisObject.isBoolean()) {
+ result = callData->thisObject.booleanValue();
} else {
- const BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>();
+ const BooleanObject *thisObject = callData->thisObject.as<BooleanObject>();
if (!thisObject)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
result = thisObject->value();
}
- return Encode(ctx->d()->engine->newString(QLatin1String(result ? "true" : "false")));
+ scope.result = scope.engine->newString(QLatin1String(result ? "true" : "false"));
}
-ReturnedValue BooleanPrototype::method_valueOf(CallContext *ctx)
+void BooleanPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->thisObject().isBoolean())
- return ctx->thisObject().asReturnedValue();
+ if (callData->thisObject.isBoolean()) {
+ scope.result = callData->thisObject.asReturnedValue();
+ return;
+ }
- const BooleanObject *thisObject = ctx->thisObject().as<BooleanObject>();
+ const BooleanObject *thisObject = callData->thisObject.as<BooleanObject>();
if (!thisObject)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(thisObject->value());
+ scope.result = Encode(thisObject->value());
}
diff --git a/src/qml/jsruntime/qv4booleanobject_p.h b/src/qml/jsruntime/qv4booleanobject_p.h
index 4c2f3c09e7..9c8b1d67f1 100644
--- a/src/qml/jsruntime/qv4booleanobject_p.h
+++ b/src/qml/jsruntime/qv4booleanobject_p.h
@@ -78,8 +78,8 @@ struct BooleanPrototype: BooleanObject
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_valueOf(CallContext *ctx);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 544d39339b..60b90e4bf0 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -95,6 +95,17 @@ Heap::CallContext *ExecutionContext::newCallContext(Function *function, CallData
return c;
}
+Heap::CallContext *Heap::CallContext::createSimpleContext(ExecutionEngine *v4)
+{
+ Heap::CallContext *ctxt = v4->memoryManager->allocSimpleCallContext(v4);
+ return ctxt;
+}
+
+void Heap::CallContext::freeSimpleCallContext()
+{
+ engine->memoryManager->freeSimpleCallContext();
+}
+
Heap::WithContext *ExecutionContext::newWithContext(Heap::Object *with)
{
return d()->engine->memoryManager->alloc<WithContext>(d(), with);
@@ -325,26 +336,27 @@ void QV4::ExecutionContext::simpleCall(Scope &scope, CallData *callData, Functio
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data ctx = CallContext::Data::createOnStack(scope.engine);
+ CallContext::Data *ctx = scope.engine->memoryManager->allocSimpleCallContext(scope.engine);
- ctx.strictMode = function->isStrict();
- ctx.callData = callData;
- ctx.v4Function = function;
- ctx.compilationUnit = function->compilationUnit;
- ctx.lookups = function->compilationUnit->runtimeLookups;
- ctx.constantTable = function->compilationUnit->constants;
- ctx.outer = this->d();
- ctx.locals = scope.alloc(function->compiledFunction->nLocals);
+ ctx->strictMode = function->isStrict();
+ ctx->callData = callData;
+ ctx->v4Function = function;
+ ctx->compilationUnit = function->compilationUnit;
+ ctx->lookups = function->compilationUnit->runtimeLookups;
+ ctx->constantTable = function->compilationUnit->constants;
+ ctx->outer = this->d();
+ ctx->locals = scope.alloc(function->compiledFunction->nLocals);
for (int i = callData->argc; i < (int)function->nFormals; ++i)
callData->args[i] = Encode::undefined();
- scope.engine->pushContext(&ctx);
- Q_ASSERT(scope.engine->current == &ctx);
+ scope.engine->pushContext(ctx);
+ Q_ASSERT(scope.engine->current == ctx);
scope.result = Q_V4_PROFILE(scope.engine, function);
if (function->hasQmlDependencies)
QQmlPropertyCapture::registerQmlDependencies(function->compiledFunction, scope);
+ scope.engine->memoryManager->freeSimpleCallContext();
}
void ExecutionContext::setProperty(String *name, const Value &value)
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index c985fdb24d..bcfee2e1f8 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -109,14 +109,8 @@ struct ExecutionContext : Base {
{
Base::init();
- callData = nullptr;
this->engine = engine;
- outer = nullptr;
- lookups = nullptr;
- constantTable = nullptr;
- compilationUnit = nullptr;
type = t;
- strictMode = false;
lineNumber = -1;
}
@@ -135,15 +129,12 @@ struct ExecutionContext : Base {
V4_ASSERT_IS_TRIVIAL(ExecutionContext)
struct CallContext : ExecutionContext {
- static CallContext createOnStack(ExecutionEngine *v4);
+ static CallContext *createSimpleContext(ExecutionEngine *v4);
+ void freeSimpleCallContext();
void init(ExecutionEngine *engine, ContextType t = Type_SimpleCallContext)
{
ExecutionContext::init(engine, t);
- function = 0;
- v4Function = 0;
- locals = 0;
- activation = 0;
}
inline unsigned int formalParameterCount() const;
@@ -247,6 +238,7 @@ struct Q_QML_EXPORT CallContext : public ExecutionContext
inline ReturnedValue argument(int i) const;
bool needsOwnArguments() const;
+
};
inline ReturnedValue CallContext::argument(int i) const {
@@ -289,16 +281,6 @@ inline const WithContext *ExecutionContext::asWithContext() const
return d()->type == Heap::ExecutionContext::Type_WithContext ? static_cast<const WithContext *>(this) : 0;
}
-inline Heap::CallContext Heap::CallContext::createOnStack(ExecutionEngine *v4)
-{
- Heap::CallContext ctxt;
- memset(&ctxt, 0, sizeof(Heap::CallContext));
- ctxt.mm_data = 0;
- ctxt.setVtable(QV4::CallContext::staticVTable());
- ctxt.init(v4);
- return ctxt;
-}
-
} // namespace QV4
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4dataview.cpp b/src/qml/jsruntime/qv4dataview.cpp
index db8376272d..a810b38f24 100644
--- a/src/qml/jsruntime/qv4dataview.cpp
+++ b/src/qml/jsruntime/qv4dataview.cpp
@@ -129,90 +129,84 @@ void DataViewPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("setUInt32"), method_set<unsigned int>, 0);
}
-ReturnedValue DataViewPrototype::method_get_buffer(CallContext *ctx)
+void DataViewPrototype::method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
+ Scoped<DataView> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->buffer->asReturnedValue());
+ scope.result = v->d()->buffer;
}
-ReturnedValue DataViewPrototype::method_get_byteLength(CallContext *ctx)
+void DataViewPrototype::method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
+ Scoped<DataView> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->byteLength);
+ scope.result = Encode(v->d()->byteLength);
}
-ReturnedValue DataViewPrototype::method_get_byteOffset(CallContext *ctx)
+void DataViewPrototype::method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
+ Scoped<DataView> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->byteOffset);
+ scope.result = Encode(v->d()->byteOffset);
}
template <typename T>
-ReturnedValue DataViewPrototype::method_getChar(CallContext *ctx)
+void DataViewPrototype::method_getChar(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
- if (!v || ctx->argc() < 1)
- return scope.engine->throwTypeError();
- double l = ctx->args()[0].toNumber();
+ Scoped<DataView> v(scope, callData->thisObject);
+ if (!v || callData->argc < 1)
+ THROW_TYPE_ERROR();
+ double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
idx += v->d()->byteOffset;
T t = T(v->d()->buffer->data->data()[idx]);
- return Encode((int)t);
+ scope.result = Encode((int)t);
}
template <typename T>
-ReturnedValue DataViewPrototype::method_get(CallContext *ctx)
+void DataViewPrototype::method_get(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
- if (!v || ctx->argc() < 1)
- return scope.engine->throwTypeError();
- double l = ctx->args()[0].toNumber();
+ Scoped<DataView> v(scope, callData->thisObject);
+ if (!v || callData->argc < 1)
+ THROW_TYPE_ERROR();
+ double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
idx += v->d()->byteOffset;
- bool littleEndian = ctx->argc() < 2 ? false : ctx->args()[1].toBoolean();
+ bool littleEndian = callData->argc < 2 ? false : callData->args[1].toBoolean();
T t = littleEndian
? qFromLittleEndian<T>((uchar *)v->d()->buffer->data->data() + idx)
: qFromBigEndian<T>((uchar *)v->d()->buffer->data->data() + idx);
- return Encode(t);
+ scope.result = Encode(t);
}
template <typename T>
-ReturnedValue DataViewPrototype::method_getFloat(CallContext *ctx)
+void DataViewPrototype::method_getFloat(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
- if (!v || ctx->argc() < 1)
- return scope.engine->throwTypeError();
- double l = ctx->args()[0].toNumber();
+ Scoped<DataView> v(scope, callData->thisObject);
+ if (!v || callData->argc < 1)
+ THROW_TYPE_ERROR();
+ double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
idx += v->d()->byteOffset;
- bool littleEndian = ctx->argc() < 2 ? false : ctx->args()[1].toBoolean();
+ bool littleEndian = callData->argc < 2 ? false : callData->args[1].toBoolean();
if (sizeof(T) == 4) {
// float
@@ -223,7 +217,7 @@ ReturnedValue DataViewPrototype::method_getFloat(CallContext *ctx)
u.i = littleEndian
? qFromLittleEndian<uint>((uchar *)v->d()->buffer->data->data() + idx)
: qFromBigEndian<uint>((uchar *)v->d()->buffer->data->data() + idx);
- return Encode(u.f);
+ scope.result = Encode(u.f);
} else {
Q_ASSERT(sizeof(T) == 8);
union {
@@ -233,69 +227,66 @@ ReturnedValue DataViewPrototype::method_getFloat(CallContext *ctx)
u.i = littleEndian
? qFromLittleEndian<quint64>((uchar *)v->d()->buffer->data->data() + idx)
: qFromBigEndian<quint64>((uchar *)v->d()->buffer->data->data() + idx);
- return Encode(u.d);
+ scope.result = Encode(u.d);
}
}
template <typename T>
-ReturnedValue DataViewPrototype::method_setChar(CallContext *ctx)
+void DataViewPrototype::method_setChar(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
- if (!v || ctx->argc() < 1)
- return scope.engine->throwTypeError();
- double l = ctx->args()[0].toNumber();
+ Scoped<DataView> v(scope, callData->thisObject);
+ if (!v || callData->argc < 1)
+ THROW_TYPE_ERROR();
+ double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
idx += v->d()->byteOffset;
- int val = ctx->argc() >= 2 ? ctx->args()[1].toInt32() : 0;
+ int val = callData->argc >= 2 ? callData->args[1].toInt32() : 0;
v->d()->buffer->data->data()[idx] = (char)val;
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
template <typename T>
-ReturnedValue DataViewPrototype::method_set(CallContext *ctx)
+void DataViewPrototype::method_set(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
- if (!v || ctx->argc() < 1)
- return scope.engine->throwTypeError();
- double l = ctx->args()[0].toNumber();
+ Scoped<DataView> v(scope, callData->thisObject);
+ if (!v || callData->argc < 1)
+ THROW_TYPE_ERROR();
+ double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
idx += v->d()->byteOffset;
- int val = ctx->argc() >= 2 ? ctx->args()[1].toInt32() : 0;
+ int val = callData->argc >= 2 ? callData->args[1].toInt32() : 0;
- bool littleEndian = ctx->argc() < 3 ? false : ctx->args()[2].toBoolean();
+ bool littleEndian = callData->argc < 3 ? false : callData->args[2].toBoolean();
if (littleEndian)
qToLittleEndian<T>(val, (uchar *)v->d()->buffer->data->data() + idx);
else
qToBigEndian<T>(val, (uchar *)v->d()->buffer->data->data() + idx);
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
template <typename T>
-ReturnedValue DataViewPrototype::method_setFloat(CallContext *ctx)
+void DataViewPrototype::method_setFloat(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DataView> v(scope, ctx->thisObject());
- if (!v || ctx->argc() < 1)
- return scope.engine->throwTypeError();
- double l = ctx->args()[0].toNumber();
+ Scoped<DataView> v(scope, callData->thisObject);
+ if (!v || callData->argc < 1)
+ THROW_TYPE_ERROR();
+ double l = callData->args[0].toNumber();
uint idx = (uint)l;
if (l != idx || idx + sizeof(T) > v->d()->byteLength)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
idx += v->d()->byteOffset;
- double val = ctx->argc() >= 2 ? ctx->args()[1].toNumber() : qt_qnan();
- bool littleEndian = ctx->argc() < 3 ? false : ctx->args()[2].toBoolean();
+ double val = callData->argc >= 2 ? callData->args[1].toNumber() : qt_qnan();
+ bool littleEndian = callData->argc < 3 ? false : callData->args[2].toBoolean();
if (sizeof(T) == 4) {
// float
@@ -320,5 +311,5 @@ ReturnedValue DataViewPrototype::method_setFloat(CallContext *ctx)
else
qToBigEndian(u.i, (uchar *)v->d()->buffer->data->data() + idx);
}
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
diff --git a/src/qml/jsruntime/qv4dataview_p.h b/src/qml/jsruntime/qv4dataview_p.h
index 246124394a..11cc0a6bd9 100644
--- a/src/qml/jsruntime/qv4dataview_p.h
+++ b/src/qml/jsruntime/qv4dataview_p.h
@@ -92,21 +92,21 @@ struct DataViewPrototype: Object
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_get_buffer(CallContext *ctx);
- static ReturnedValue method_get_byteLength(CallContext *ctx);
- static ReturnedValue method_get_byteOffset(CallContext *ctx);
+ static void method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData);
template <typename T>
- static ReturnedValue method_getChar(CallContext *ctx);
+ static void method_getChar(const BuiltinFunction *, Scope &scope, CallData *callData);
template <typename T>
- static ReturnedValue method_get(CallContext *ctx);
+ static void method_get(const BuiltinFunction *, Scope &scope, CallData *callData);
template <typename T>
- static ReturnedValue method_getFloat(CallContext *ctx);
+ static void method_getFloat(const BuiltinFunction *, Scope &scope, CallData *callData);
template <typename T>
- static ReturnedValue method_setChar(CallContext *ctx);
+ static void method_setChar(const BuiltinFunction *, Scope &scope, CallData *callData);
template <typename T>
- static ReturnedValue method_set(CallContext *ctx);
+ static void method_set(const BuiltinFunction *, Scope &scope, CallData *callData);
template <typename T>
- static ReturnedValue method_setFloat(CallContext *ctx);
+ static void method_setFloat(const BuiltinFunction *, Scope &scope, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4dateobject.cpp b/src/qml/jsruntime/qv4dateobject.cpp
index 8cc6a25fea..b90c335b1c 100644
--- a/src/qml/jsruntime/qv4dateobject.cpp
+++ b/src/qml/jsruntime/qv4dateobject.cpp
@@ -780,435 +780,435 @@ void DatePrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("toJSON"), method_toJSON, 1);
}
-double DatePrototype::getThisDate(ExecutionContext *ctx)
+double DatePrototype::getThisDate(Scope &scope, CallData *callData)
{
- if (DateObject *thisObject = ctx->thisObject().as<DateObject>())
+ if (DateObject *thisObject = callData->thisObject.as<DateObject>())
return thisObject->date();
else {
- ctx->engine()->throwTypeError();
+ scope.engine->throwTypeError();
return 0;
}
}
-ReturnedValue DatePrototype::method_parse(CallContext *ctx)
+void DatePrototype::method_parse(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!ctx->argc())
- return Encode(qt_qnan());
- return Encode(ParseString(ctx->args()[0].toQString()));
+ if (!callData->argc)
+ scope.result = Encode(qt_qnan());
+ else
+ scope.result = Encode(ParseString(callData->args[0].toQString()));
}
-ReturnedValue DatePrototype::method_UTC(CallContext *ctx)
+void DatePrototype::method_UTC(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- const int numArgs = ctx->argc();
+ const int numArgs = callData->argc;
if (numArgs >= 2) {
- double year = ctx->args()[0].toNumber();
- double month = ctx->args()[1].toNumber();
- double day = numArgs >= 3 ? ctx->args()[2].toNumber() : 1;
- double hours = numArgs >= 4 ? ctx->args()[3].toNumber() : 0;
- double mins = numArgs >= 5 ? ctx->args()[4].toNumber() : 0;
- double secs = numArgs >= 6 ? ctx->args()[5].toNumber() : 0;
- double ms = numArgs >= 7 ? ctx->args()[6].toNumber() : 0;
+ double year = callData->args[0].toNumber();
+ double month = callData->args[1].toNumber();
+ double day = numArgs >= 3 ? callData->args[2].toNumber() : 1;
+ double hours = numArgs >= 4 ? callData->args[3].toNumber() : 0;
+ double mins = numArgs >= 5 ? callData->args[4].toNumber() : 0;
+ double secs = numArgs >= 6 ? callData->args[5].toNumber() : 0;
+ double ms = numArgs >= 7 ? callData->args[6].toNumber() : 0;
if (year >= 0 && year <= 99)
year += 1900;
double t = MakeDate(MakeDay(year, month, day),
MakeTime(hours, mins, secs, ms));
- return Encode(TimeClip(t));
+ scope.result = Encode(TimeClip(t));
+ return;
}
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue DatePrototype::method_now(CallContext *ctx)
+void DatePrototype::method_now(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Q_UNUSED(ctx);
+ Q_UNUSED(callData);
double t = currentTime();
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_toString(CallContext *ctx)
+void DatePrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return ctx->d()->engine->newString(ToString(t))->asReturnedValue();
+ double t = getThisDate(scope, callData);
+ scope.result = scope.engine->newString(ToString(t));
}
-ReturnedValue DatePrototype::method_toDateString(CallContext *ctx)
+void DatePrototype::method_toDateString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return ctx->d()->engine->newString(ToDateString(t))->asReturnedValue();
+ double t = getThisDate(scope, callData);
+ scope.result = scope.engine->newString(ToDateString(t));
}
-ReturnedValue DatePrototype::method_toTimeString(CallContext *ctx)
+void DatePrototype::method_toTimeString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return ctx->d()->engine->newString(ToTimeString(t))->asReturnedValue();
+ double t = getThisDate(scope, callData);
+ scope.result = scope.engine->newString(ToTimeString(t));
}
-ReturnedValue DatePrototype::method_toLocaleString(CallContext *ctx)
+void DatePrototype::method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return ctx->d()->engine->newString(ToLocaleString(t))->asReturnedValue();
+ double t = getThisDate(scope, callData);
+ scope.result = scope.engine->newString(ToLocaleString(t));
}
-ReturnedValue DatePrototype::method_toLocaleDateString(CallContext *ctx)
+void DatePrototype::method_toLocaleDateString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return ctx->d()->engine->newString(ToLocaleDateString(t))->asReturnedValue();
+ double t = getThisDate(scope, callData);
+ scope.result = scope.engine->newString(ToLocaleDateString(t));
}
-ReturnedValue DatePrototype::method_toLocaleTimeString(CallContext *ctx)
+void DatePrototype::method_toLocaleTimeString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return ctx->d()->engine->newString(ToLocaleTimeString(t))->asReturnedValue();
+ double t = getThisDate(scope, callData);
+ scope.result = scope.engine->newString(ToLocaleTimeString(t));
}
-ReturnedValue DatePrototype::method_valueOf(CallContext *ctx)
+void DatePrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return Encode(t);
+ double t = getThisDate(scope, callData);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getTime(CallContext *ctx)
+void DatePrototype::method_getTime(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- return Encode(t);
+ double t = getThisDate(scope, callData);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getYear(CallContext *ctx)
+void DatePrototype::method_getYear(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = YearFromTime(LocalTime(t)) - 1900;
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getFullYear(CallContext *ctx)
+void DatePrototype::method_getFullYear(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = YearFromTime(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCFullYear(CallContext *ctx)
+void DatePrototype::method_getUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = YearFromTime(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getMonth(CallContext *ctx)
+void DatePrototype::method_getMonth(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = MonthFromTime(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCMonth(CallContext *ctx)
+void DatePrototype::method_getUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = MonthFromTime(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getDate(CallContext *ctx)
+void DatePrototype::method_getDate(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = DateFromTime(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCDate(CallContext *ctx)
+void DatePrototype::method_getUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = DateFromTime(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getDay(CallContext *ctx)
+void DatePrototype::method_getDay(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = WeekDay(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCDay(CallContext *ctx)
+void DatePrototype::method_getUTCDay(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = WeekDay(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getHours(CallContext *ctx)
+void DatePrototype::method_getHours(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = HourFromTime(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCHours(CallContext *ctx)
+void DatePrototype::method_getUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = HourFromTime(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getMinutes(CallContext *ctx)
+void DatePrototype::method_getMinutes(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = MinFromTime(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCMinutes(CallContext *ctx)
+void DatePrototype::method_getUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = MinFromTime(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getSeconds(CallContext *ctx)
+void DatePrototype::method_getSeconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = SecFromTime(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCSeconds(CallContext *ctx)
+void DatePrototype::method_getUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = SecFromTime(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getMilliseconds(CallContext *ctx)
+void DatePrototype::method_getMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = msFromTime(LocalTime(t));
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getUTCMilliseconds(CallContext *ctx)
+void DatePrototype::method_getUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = msFromTime(t);
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_getTimezoneOffset(CallContext *ctx)
+void DatePrototype::method_getTimezoneOffset(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double t = getThisDate(ctx);
- if (! std::isnan(t))
+ double t = getThisDate(scope, callData);
+ if (!std::isnan(t))
t = (t - LocalTime(t)) / msPerMinute;
- return Encode(t);
+ scope.result = Encode(t);
}
-ReturnedValue DatePrototype::method_setTime(CallContext *ctx)
+void DatePrototype::method_setTime(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DateObject> self(scope, ctx->thisObject());
+ Scoped<DateObject> self(scope, callData->thisObject);
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- double t = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ double t = callData->argc ? callData->args[0].toNumber() : qt_qnan();
self->setDate(TimeClip(t));
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setMilliseconds(CallContext *ctx)
+void DatePrototype::method_setMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<DateObject> self(scope, ctx->thisObject());
+ Scoped<DateObject> self(scope, callData->thisObject);
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = LocalTime(self->date());
- double ms = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan();
self->setDate(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setUTCMilliseconds(CallContext *ctx)
+void DatePrototype::method_setUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- double ms = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ double ms = callData->argc ? callData->args[0].toNumber() : qt_qnan();
self->setDate(TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms))));
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setSeconds(CallContext *ctx)
+void DatePrototype::method_setSeconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = LocalTime(self->date());
- double sec = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double ms = (ctx->argc() < 2) ? msFromTime(t) : ctx->args()[1].toNumber();
+ double sec = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double ms = (callData->argc < 2) ? msFromTime(t) : callData->args[1].toNumber();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setUTCSeconds(CallContext *ctx)
+void DatePrototype::method_setUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- double sec = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double ms = (ctx->argc() < 2) ? msFromTime(t) : ctx->args()[1].toNumber();
+ double sec = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double ms = (callData->argc < 2) ? msFromTime(t) : callData->args[1].toNumber();
t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms)));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setMinutes(CallContext *ctx)
+void DatePrototype::method_setMinutes(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = LocalTime(self->date());
- double min = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double sec = (ctx->argc() < 2) ? SecFromTime(t) : ctx->args()[1].toNumber();
- double ms = (ctx->argc() < 3) ? msFromTime(t) : ctx->args()[2].toNumber();
+ double min = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double sec = (callData->argc < 2) ? SecFromTime(t) : callData->args[1].toNumber();
+ double ms = (callData->argc < 3) ? msFromTime(t) : callData->args[2].toNumber();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setUTCMinutes(CallContext *ctx)
+void DatePrototype::method_setUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- double min = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double sec = (ctx->argc() < 2) ? SecFromTime(t) : ctx->args()[1].toNumber();
- double ms = (ctx->argc() < 3) ? msFromTime(t) : ctx->args()[2].toNumber();
+ double min = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double sec = (callData->argc < 2) ? SecFromTime(t) : callData->args[1].toNumber();
+ double ms = (callData->argc < 3) ? msFromTime(t) : callData->args[2].toNumber();
t = TimeClip(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms)));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setHours(CallContext *ctx)
+void DatePrototype::method_setHours(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = LocalTime(self->date());
- double hour = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double min = (ctx->argc() < 2) ? MinFromTime(t) : ctx->args()[1].toNumber();
- double sec = (ctx->argc() < 3) ? SecFromTime(t) : ctx->args()[2].toNumber();
- double ms = (ctx->argc() < 4) ? msFromTime(t) : ctx->args()[3].toNumber();
+ double hour = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double min = (callData->argc < 2) ? MinFromTime(t) : callData->args[1].toNumber();
+ double sec = (callData->argc < 3) ? SecFromTime(t) : callData->args[2].toNumber();
+ double ms = (callData->argc < 4) ? msFromTime(t) : callData->args[3].toNumber();
t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setUTCHours(CallContext *ctx)
+void DatePrototype::method_setUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- double hour = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double min = (ctx->argc() < 2) ? MinFromTime(t) : ctx->args()[1].toNumber();
- double sec = (ctx->argc() < 3) ? SecFromTime(t) : ctx->args()[2].toNumber();
- double ms = (ctx->argc() < 4) ? msFromTime(t) : ctx->args()[3].toNumber();
+ double hour = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double min = (callData->argc < 2) ? MinFromTime(t) : callData->args[1].toNumber();
+ double sec = (callData->argc < 3) ? SecFromTime(t) : callData->args[2].toNumber();
+ double ms = (callData->argc < 4) ? msFromTime(t) : callData->args[3].toNumber();
t = TimeClip(MakeDate(Day(t), MakeTime(hour, min, sec, ms)));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setDate(CallContext *ctx)
+void DatePrototype::method_setDate(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = LocalTime(self->date());
- double date = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ double date = callData->argc ? callData->args[0].toNumber() : qt_qnan();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setUTCDate(CallContext *ctx)
+void DatePrototype::method_setUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- double date = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ double date = callData->argc ? callData->args[0].toNumber() : qt_qnan();
t = TimeClip(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setMonth(CallContext *ctx)
+void DatePrototype::method_setMonth(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = LocalTime(self->date());
- double month = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double date = (ctx->argc() < 2) ? DateFromTime(t) : ctx->args()[1].toNumber();
+ double month = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double date = (callData->argc < 2) ? DateFromTime(t) : callData->args[1].toNumber();
t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setUTCMonth(CallContext *ctx)
+void DatePrototype::method_setUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- double month = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double date = (ctx->argc() < 2) ? DateFromTime(t) : ctx->args()[1].toNumber();
+ double month = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double date = (callData->argc < 2) ? DateFromTime(t) : callData->args[1].toNumber();
t = TimeClip(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t)));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setYear(CallContext *ctx)
+void DatePrototype::method_setYear(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
if (std::isnan(t))
t = 0;
else
t = LocalTime(t);
- double year = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ double year = callData->argc ? callData->args[0].toNumber() : qt_qnan();
double r;
if (std::isnan(year)) {
r = qt_qnan();
@@ -1220,49 +1220,49 @@ ReturnedValue DatePrototype::method_setYear(CallContext *ctx)
r = TimeClip(r);
}
self->setDate(r);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setUTCFullYear(CallContext *ctx)
+void DatePrototype::method_setUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- double year = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double month = (ctx->argc() < 2) ? MonthFromTime(t) : ctx->args()[1].toNumber();
- double date = (ctx->argc() < 3) ? DateFromTime(t) : ctx->args()[2].toNumber();
+ double year = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double month = (callData->argc < 2) ? MonthFromTime(t) : callData->args[1].toNumber();
+ double date = (callData->argc < 3) ? DateFromTime(t) : callData->args[2].toNumber();
t = TimeClip(MakeDate(MakeDay(year, month, date), TimeWithinDay(t)));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_setFullYear(CallContext *ctx)
+void DatePrototype::method_setFullYear(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = LocalTime(self->date());
if (std::isnan(t))
t = 0;
- double year = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
- double month = (ctx->argc() < 2) ? MonthFromTime(t) : ctx->args()[1].toNumber();
- double date = (ctx->argc() < 3) ? DateFromTime(t) : ctx->args()[2].toNumber();
+ double year = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double month = (callData->argc < 2) ? MonthFromTime(t) : callData->args[1].toNumber();
+ double date = (callData->argc < 3) ? DateFromTime(t) : callData->args[2].toNumber();
t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
self->setDate(t);
- return Encode(self->date());
+ scope.result = Encode(self->date());
}
-ReturnedValue DatePrototype::method_toUTCString(CallContext *ctx)
+void DatePrototype::method_toUTCString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
- return ctx->d()->engine->newString(ToUTCString(t))->asReturnedValue();
+ scope.result = scope.engine->newString(ToUTCString(t));
}
static void addZeroPrefixedInt(QString &str, int num, int nDigits)
@@ -1278,21 +1278,21 @@ static void addZeroPrefixedInt(QString &str, int num, int nDigits)
}
}
-ReturnedValue DatePrototype::method_toISOString(CallContext *ctx)
+void DatePrototype::method_toISOString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- DateObject *self = ctx->thisObject().as<DateObject>();
+ DateObject *self = callData->thisObject.as<DateObject>();
if (!self)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
double t = self->date();
if (!std::isfinite(t))
- return ctx->engine()->throwRangeError(ctx->thisObject());
+ RETURN_RESULT(scope.engine->throwRangeError(callData->thisObject));
QString result;
int year = (int)YearFromTime(t);
if (year < 0 || year > 9999) {
if (qAbs(year) >= 1000000)
- return ctx->d()->engine->newString(QStringLiteral("Invalid Date"))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("Invalid Date")));
result += year < 0 ? QLatin1Char('-') : QLatin1Char('+');
year = qAbs(year);
addZeroPrefixedInt(result, year, 6);
@@ -1313,32 +1313,29 @@ ReturnedValue DatePrototype::method_toISOString(CallContext *ctx)
addZeroPrefixedInt(result, msFromTime(t), 3);
result += QLatin1Char('Z');
- return ctx->d()->engine->newString(result)->asReturnedValue();
+ scope.result = scope.engine->newString(result);
}
-ReturnedValue DatePrototype::method_toJSON(CallContext *ctx)
+void DatePrototype::method_toJSON(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject O(scope, ctx->thisObject().toObject(scope.engine));
- if (scope.hasException())
- return Encode::undefined();
+ ScopedObject O(scope, callData->thisObject.toObject(scope.engine));
+ CHECK_EXCEPTION();
ScopedValue tv(scope, RuntimeHelpers::toPrimitive(O, NUMBER_HINT));
if (tv->isNumber() && !std::isfinite(tv->toNumber()))
- return Encode::null();
+ RETURN_RESULT(Encode::null());
- ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("toISOString")));
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("toISOString")));
ScopedValue v(scope, O->get(s));
FunctionObject *toIso = v->as<FunctionObject>();
if (!toIso)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope);
- callData->thisObject = ctx->thisObject();
- toIso->call(scope, callData);
- return scope.result.asReturnedValue();
+ ScopedCallData cData(scope);
+ cData->thisObject = callData->thisObject;
+ toIso->call(scope, cData);
}
void DatePrototype::timezoneUpdated()
diff --git a/src/qml/jsruntime/qv4dateobject_p.h b/src/qml/jsruntime/qv4dateobject_p.h
index 835f6adbe0..a56d17f9b1 100644
--- a/src/qml/jsruntime/qv4dateobject_p.h
+++ b/src/qml/jsruntime/qv4dateobject_p.h
@@ -116,57 +116,57 @@ struct DatePrototype: DateObject
{
void init(ExecutionEngine *engine, Object *ctor);
- static double getThisDate(ExecutionContext *ctx);
-
- static ReturnedValue method_parse(CallContext *ctx);
- static ReturnedValue method_UTC(CallContext *ctx);
- static ReturnedValue method_now(CallContext *ctx);
-
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_toDateString(CallContext *ctx);
- static ReturnedValue method_toTimeString(CallContext *ctx);
- static ReturnedValue method_toLocaleString(CallContext *ctx);
- static ReturnedValue method_toLocaleDateString(CallContext *ctx);
- static ReturnedValue method_toLocaleTimeString(CallContext *ctx);
- static ReturnedValue method_valueOf(CallContext *ctx);
- static ReturnedValue method_getTime(CallContext *ctx);
- static ReturnedValue method_getYear(CallContext *ctx);
- static ReturnedValue method_getFullYear(CallContext *ctx);
- static ReturnedValue method_getUTCFullYear(CallContext *ctx);
- static ReturnedValue method_getMonth(CallContext *ctx);
- static ReturnedValue method_getUTCMonth(CallContext *ctx);
- static ReturnedValue method_getDate(CallContext *ctx);
- static ReturnedValue method_getUTCDate(CallContext *ctx);
- static ReturnedValue method_getDay(CallContext *ctx);
- static ReturnedValue method_getUTCDay(CallContext *ctx);
- static ReturnedValue method_getHours(CallContext *ctx);
- static ReturnedValue method_getUTCHours(CallContext *ctx);
- static ReturnedValue method_getMinutes(CallContext *ctx);
- static ReturnedValue method_getUTCMinutes(CallContext *ctx);
- static ReturnedValue method_getSeconds(CallContext *ctx);
- static ReturnedValue method_getUTCSeconds(CallContext *ctx);
- static ReturnedValue method_getMilliseconds(CallContext *ctx);
- static ReturnedValue method_getUTCMilliseconds(CallContext *ctx);
- static ReturnedValue method_getTimezoneOffset(CallContext *ctx);
- static ReturnedValue method_setTime(CallContext *ctx);
- static ReturnedValue method_setMilliseconds(CallContext *ctx);
- static ReturnedValue method_setUTCMilliseconds(CallContext *ctx);
- static ReturnedValue method_setSeconds(CallContext *ctx);
- static ReturnedValue method_setUTCSeconds(CallContext *ctx);
- static ReturnedValue method_setMinutes(CallContext *ctx);
- static ReturnedValue method_setUTCMinutes(CallContext *ctx);
- static ReturnedValue method_setHours(CallContext *ctx);
- static ReturnedValue method_setUTCHours(CallContext *ctx);
- static ReturnedValue method_setDate(CallContext *ctx);
- static ReturnedValue method_setUTCDate(CallContext *ctx);
- static ReturnedValue method_setMonth(CallContext *ctx);
- static ReturnedValue method_setUTCMonth(CallContext *ctx);
- static ReturnedValue method_setYear(CallContext *ctx);
- static ReturnedValue method_setFullYear(CallContext *ctx);
- static ReturnedValue method_setUTCFullYear(CallContext *ctx);
- static ReturnedValue method_toUTCString(CallContext *ctx);
- static ReturnedValue method_toISOString(CallContext *ctx);
- static ReturnedValue method_toJSON(CallContext *ctx);
+ static double getThisDate(Scope &scope, CallData *callData);
+
+ static void method_parse(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_UTC(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_now(const BuiltinFunction *, Scope &scope, CallData *callData);
+
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toDateString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toTimeString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLocaleDateString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLocaleTimeString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getTime(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getYear(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getFullYear(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getMonth(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getDate(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getDay(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCDay(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getHours(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getMinutes(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getSeconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getTimezoneOffset(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setTime(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setUTCMilliseconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setSeconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setUTCSeconds(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setMinutes(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setUTCMinutes(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setHours(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setUTCHours(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setDate(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setUTCDate(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setMonth(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setUTCMonth(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setYear(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setFullYear(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_setUTCFullYear(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toUTCString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toISOString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toJSON(const BuiltinFunction *, Scope &scope, CallData *callData);
static void timezoneUpdated();
};
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index a11f7f0875..084ddc9010 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -91,7 +91,9 @@
#if USE(PTHREADS)
# include <pthread.h>
+#if !defined(Q_OS_INTEGRITY)
# include <sys/resource.h>
+#endif
#if HAVE(PTHREAD_NP_H)
# include <pthread_np.h>
#endif
@@ -168,7 +170,7 @@ ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
if (forceMoth) {
factory = new Moth::ISelFactory;
} else {
- factory = new JIT::ISelFactory;
+ factory = new JIT::ISelFactory<>;
jitDisabled = false;
}
#else // !V4_ENABLE_JIT
@@ -1109,7 +1111,7 @@ static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int
if (typeHint == qMetaTypeId<QJSValue>())
return QVariant::fromValue(QJSValue(e, value.asReturnedValue()));
- if (value.as<Object>()) {
+ if (value.as<QV4::Object>()) {
QV4::ScopedObject object(scope, value);
if (typeHint == QMetaType::QJsonObject
&& !value.as<ArrayObject>() && !value.as<FunctionObject>()) {
@@ -1755,7 +1757,7 @@ bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
return false;
}
-static bool convertToNativeQObject(QV4::ExecutionEngine *e, const Value &value, const QByteArray &targetType, void **result)
+static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value, const QByteArray &targetType, void **result)
{
if (!targetType.endsWith('*'))
return false;
@@ -1770,7 +1772,7 @@ static bool convertToNativeQObject(QV4::ExecutionEngine *e, const Value &value,
return false;
}
-static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const Value &value)
+static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value)
{
if (!value.isObject())
return 0;
diff --git a/src/qml/jsruntime/qv4errorobject.cpp b/src/qml/jsruntime/qv4errorobject.cpp
index 597ded6ae1..f290bc5136 100644
--- a/src/qml/jsruntime/qv4errorobject.cpp
+++ b/src/qml/jsruntime/qv4errorobject.cpp
@@ -153,12 +153,11 @@ const char *ErrorObject::className(Heap::ErrorObject::ErrorType t)
Q_UNREACHABLE();
}
-ReturnedValue ErrorObject::method_get_stack(CallContext *ctx)
+void ErrorObject::method_get_stack(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<ErrorObject> This(scope, ctx->thisObject());
+ Scoped<ErrorObject> This(scope, callData->thisObject);
if (!This)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (!This->d()->stack) {
QString trace;
for (int i = 0; i < This->d()->stackTrace->count(); ++i) {
@@ -169,9 +168,9 @@ ReturnedValue ErrorObject::method_get_stack(CallContext *ctx)
if (frame.line >= 0)
trace += QLatin1Char(':') + QString::number(frame.line);
}
- This->d()->stack = ctx->d()->engine->newString(trace);
+ This->d()->stack = scope.engine->newString(trace);
}
- return This->d()->stack->asReturnedValue();
+ scope.result = This->d()->stack;
}
void ErrorObject::markObjects(Heap::Base *that, ExecutionEngine *e)
@@ -335,22 +334,20 @@ void ErrorPrototype::init(ExecutionEngine *engine, Object *ctor, Object *obj, He
obj->defineDefaultProperty(engine->id_toString(), method_toString, 0);
}
-ReturnedValue ErrorPrototype::method_toString(CallContext *ctx)
+void ErrorPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
-
- Object *o = ctx->thisObject().as<Object>();
+ Object *o = callData->thisObject.as<Object>();
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedValue name(scope, o->get(ctx->d()->engine->id_name()));
+ ScopedValue name(scope, o->get(scope.engine->id_name()));
QString qname;
if (name->isUndefined())
qname = QStringLiteral("Error");
else
qname = name->toQString();
- ScopedString s(scope, ctx->d()->engine->newString(QStringLiteral("message")));
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("message")));
ScopedValue message(scope, o->get(s));
QString qmessage;
if (!message->isUndefined())
@@ -365,5 +362,5 @@ ReturnedValue ErrorPrototype::method_toString(CallContext *ctx)
str = qname + QLatin1String(": ") + qmessage;
}
- return ctx->d()->engine->newString(str)->asReturnedValue();
+ scope.result = scope.engine->newString(str)->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4errorobject_p.h b/src/qml/jsruntime/qv4errorobject_p.h
index 2b3ab25e2d..9ba9f05234 100644
--- a/src/qml/jsruntime/qv4errorobject_p.h
+++ b/src/qml/jsruntime/qv4errorobject_p.h
@@ -172,7 +172,7 @@ struct ErrorObject: Object {
static const char *className(Heap::ErrorObject::ErrorType t);
- static ReturnedValue method_get_stack(CallContext *ctx);
+ static void method_get_stack(const BuiltinFunction *, Scope &scope, CallData *callData);
static void markObjects(Heap::Base *that, ExecutionEngine *e);
};
@@ -282,7 +282,7 @@ struct ErrorPrototype : ErrorObject
void init(ExecutionEngine *engine, Object *ctor) { init(engine, ctor, this, Heap::ErrorObject::Error); }
static void init(ExecutionEngine *engine, Object *ctor, Object *obj, Heap::ErrorObject::ErrorType t);
- static ReturnedValue method_toString(CallContext *ctx);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
};
struct EvalErrorPrototype : ErrorObject
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 64f7b98618..b2d89220ea 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -270,23 +270,22 @@ void FunctionPrototype::init(ExecutionEngine *engine, Object *ctor)
}
-ReturnedValue FunctionPrototype::method_toString(CallContext *ctx)
+void FunctionPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- FunctionObject *fun = ctx->thisObject().as<FunctionObject>();
+ FunctionObject *fun = callData->thisObject.as<FunctionObject>();
if (!fun)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return ctx->d()->engine->newString(QStringLiteral("function() { [code] }"))->asReturnedValue();
+ scope.result = scope.engine->newString(QStringLiteral("function() { [code] }"));
}
-ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
+void FunctionPrototype::method_apply(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- FunctionObject *o = ctx->thisObject().as<FunctionObject>();
+ FunctionObject *o = callData->thisObject.as<FunctionObject>();
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- Scope scope(ctx);
- ScopedValue arg(scope, ctx->argument(1));
+ ScopedValue arg(scope, callData->argument(1));
ScopedObject arr(scope, arg);
@@ -294,75 +293,71 @@ ReturnedValue FunctionPrototype::method_apply(CallContext *ctx)
if (!arr) {
len = 0;
if (!arg->isNullOrUndefined())
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
} else {
len = arr->getLength();
}
- ScopedCallData callData(scope, len);
+ ScopedCallData cData(scope, len);
if (len) {
if (ArgumentsObject::isNonStrictArgumentsObject(arr) && !arr->cast<ArgumentsObject>()->fullyCreated()) {
QV4::ArgumentsObject *a = arr->cast<ArgumentsObject>();
int l = qMin(len, (uint)a->d()->context->callData->argc);
- memcpy(callData->args, a->d()->context->callData->args, l*sizeof(Value));
+ memcpy(cData->args, a->d()->context->callData->args, l*sizeof(Value));
for (quint32 i = l; i < len; ++i)
- callData->args[i] = Primitive::undefinedValue();
+ cData->args[i] = Primitive::undefinedValue();
} else if (arr->arrayType() == Heap::ArrayData::Simple && !arr->protoHasArray()) {
auto sad = static_cast<Heap::SimpleArrayData *>(arr->arrayData());
uint alen = sad ? sad->len : 0;
if (alen > len)
alen = len;
for (uint i = 0; i < alen; ++i)
- callData->args[i] = sad->data(i);
+ cData->args[i] = sad->data(i);
for (quint32 i = alen; i < len; ++i)
- callData->args[i] = Primitive::undefinedValue();
+ cData->args[i] = Primitive::undefinedValue();
} else {
for (quint32 i = 0; i < len; ++i)
- callData->args[i] = arr->getIndexed(i);
+ cData->args[i] = arr->getIndexed(i);
}
}
- callData->thisObject = ctx->argument(0);
- o->call(scope, callData);
- return scope.result.asReturnedValue();
+ cData->thisObject = callData->argument(0);
+ o->call(scope, cData);
}
-ReturnedValue FunctionPrototype::method_call(CallContext *ctx)
+void FunctionPrototype::method_call(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- FunctionObject *o = ctx->thisObject().as<FunctionObject>();
+ FunctionObject *o = callData->thisObject.as<FunctionObject>();
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- Scope scope(ctx);
- ScopedCallData callData(scope, ctx->argc() ? ctx->argc() - 1 : 0);
- if (ctx->argc()) {
- for (int i = 1; i < ctx->argc(); ++i)
- callData->args[i - 1] = ctx->args()[i];
+ ScopedCallData cData(scope, callData->argc ? callData->argc - 1 : 0);
+ if (callData->argc) {
+ for (int i = 1; i < callData->argc; ++i)
+ cData->args[i - 1] = callData->args[i];
}
- callData->thisObject = ctx->argument(0);
+ cData->thisObject = callData->argument(0);
- o->call(scope, callData);
- return scope.result.asReturnedValue();
+ o->call(scope, cData);
}
-ReturnedValue FunctionPrototype::method_bind(CallContext *ctx)
+void FunctionPrototype::method_bind(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- FunctionObject *target = ctx->thisObject().as<FunctionObject>();
+ FunctionObject *target = callData->thisObject.as<FunctionObject>();
if (!target)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- Scope scope(ctx);
- ScopedValue boundThis(scope, ctx->argument(0));
+ ScopedValue boundThis(scope, callData->argument(0));
Scoped<MemberData> boundArgs(scope, (Heap::MemberData *)0);
- if (ctx->argc() > 1) {
- boundArgs = MemberData::allocate(scope.engine, ctx->argc() - 1);
- boundArgs->d()->size = ctx->argc() - 1;
- memcpy(boundArgs->data(), ctx->args() + 1, (ctx->argc() - 1)*sizeof(Value));
+ if (callData->argc > 1) {
+ boundArgs = MemberData::allocate(scope.engine, callData->argc - 1);
+ boundArgs->d()->size = callData->argc - 1;
+ memcpy(boundArgs->data(), callData->args + 1, (callData->argc - 1)*sizeof(Value));
}
ExecutionContext *global = scope.engine->rootContext();
- return BoundFunction::create(global, target, boundThis, boundArgs)->asReturnedValue();
+ scope.result = BoundFunction::create(global, target, boundThis, boundArgs);
}
DEFINE_OBJECT_VTABLE(ScriptFunction);
@@ -459,22 +454,22 @@ Heap::Object *ScriptFunction::protoForConstructor() const
-DEFINE_OBJECT_VTABLE(BuiltinFunction);
+DEFINE_OBJECT_VTABLE(OldBuiltinFunction);
-void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *))
+void Heap::OldBuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *))
{
Heap::FunctionObject::init(scope, name);
this->code = code;
}
-void BuiltinFunction::construct(const Managed *f, Scope &scope, CallData *)
+void OldBuiltinFunction::construct(const Managed *f, Scope &scope, CallData *)
{
- scope.result = static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError();
+ scope.result = static_cast<const OldBuiltinFunction *>(f)->internalClass()->engine->throwTypeError();
}
-void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData)
+void OldBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
- const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that);
+ const OldBuiltinFunction *f = static_cast<const OldBuiltinFunction *>(that);
ExecutionEngine *v4 = scope.engine;
if (v4->hasException) {
scope.result = Encode::undefined();
@@ -484,15 +479,41 @@ void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data ctx = CallContext::Data::createOnStack(v4);
- ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
- ctx.callData = callData;
- v4->pushContext(&ctx);
- Q_ASSERT(v4->current == &ctx);
+ CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4);
+ ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
+ ctx->callData = callData;
+ v4->pushContext(ctx);
+ Q_ASSERT(v4->current == ctx);
scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext));
+ v4->memoryManager->freeSimpleCallContext();
+}
+
+DEFINE_OBJECT_VTABLE(BuiltinFunction);
+
+void Heap::BuiltinFunction::init(QV4::ExecutionContext *scope, QV4::String *name, void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *))
+{
+ Heap::FunctionObject::init(scope, name);
+ this->code = code;
+}
+
+void BuiltinFunction::construct(const Managed *f, Scope &scope, CallData *)
+{
+ scope.result = static_cast<const BuiltinFunction *>(f)->internalClass()->engine->throwTypeError();
+}
+
+void BuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData)
+{
+ const BuiltinFunction *f = static_cast<const BuiltinFunction *>(that);
+ ExecutionEngine *v4 = scope.engine;
+ if (v4->hasException) {
+ scope.result = Encode::undefined();
+ return;
+ }
+ f->d()->code(f, scope, callData);
}
+
void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *callData)
{
const IndexedBuiltinFunction *f = static_cast<const IndexedBuiltinFunction *>(that);
@@ -505,13 +526,14 @@ void IndexedBuiltinFunction::call(const Managed *that, Scope &scope, CallData *c
ExecutionContextSaver ctxSaver(scope);
- CallContext::Data ctx = CallContext::Data::createOnStack(v4);
- ctx.strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
- ctx.callData = callData;
- v4->pushContext(&ctx);
- Q_ASSERT(v4->current == &ctx);
+ CallContext::Data *ctx = v4->memoryManager->allocSimpleCallContext(v4);
+ ctx->strictMode = f->scope()->strictMode; // ### needed? scope or parent context?
+ ctx->callData = callData;
+ v4->pushContext(ctx);
+ Q_ASSERT(v4->current == ctx);
scope.result = f->d()->code(static_cast<QV4::CallContext *>(v4->currentContext), f->d()->index);
+ v4->memoryManager->freeSimpleCallContext();
}
DEFINE_OBJECT_VTABLE(IndexedBuiltinFunction);
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index a02e89e883..45d7485f1b 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -61,6 +61,8 @@ struct QQmlSourceLocation;
namespace QV4 {
+struct BuiltinFunction;
+
namespace Heap {
struct Q_QML_PRIVATE_EXPORT FunctionObject : Object {
@@ -93,11 +95,16 @@ struct FunctionPrototype : FunctionObject {
void init();
};
-struct Q_QML_EXPORT BuiltinFunction : FunctionObject {
+struct Q_QML_EXPORT OldBuiltinFunction : FunctionObject {
void init(QV4::ExecutionContext *scope, QV4::String *name, ReturnedValue (*code)(QV4::CallContext *));
ReturnedValue (*code)(QV4::CallContext *);
};
+struct Q_QML_EXPORT BuiltinFunction : FunctionObject {
+ void init(QV4::ExecutionContext *scope, QV4::String *name, void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *));
+ void (*code)(const QV4::BuiltinFunction *, Scope &, CallData *);
+};
+
struct IndexedBuiltinFunction : FunctionObject {
inline void init(QV4::ExecutionContext *scope, uint index, ReturnedValue (*code)(QV4::CallContext *ctx, uint index));
ReturnedValue (*code)(QV4::CallContext *, uint index);
@@ -177,16 +184,27 @@ struct FunctionPrototype: FunctionObject
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_apply(CallContext *ctx);
- static ReturnedValue method_call(CallContext *ctx);
- static ReturnedValue method_bind(CallContext *ctx);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_apply(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_call(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_bind(const BuiltinFunction *, Scope &scope, CallData *callData);
};
-struct Q_QML_EXPORT BuiltinFunction: FunctionObject {
+struct Q_QML_EXPORT OldBuiltinFunction : FunctionObject {
+ V4_OBJECT2(OldBuiltinFunction, FunctionObject)
+
+ static void construct(const Managed *, Scope &scope, CallData *);
+ static void call(const Managed *that, Scope &scope, CallData *callData);
+};
+
+struct Q_QML_EXPORT BuiltinFunction : FunctionObject {
V4_OBJECT2(BuiltinFunction, FunctionObject)
- static Heap::BuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *))
+ static Heap::OldBuiltinFunction *create(ExecutionContext *scope, String *name, ReturnedValue (*code)(CallContext *))
+ {
+ return scope->engine()->memoryManager->allocObject<OldBuiltinFunction>(scope, name, code);
+ }
+ static Heap::BuiltinFunction *create(ExecutionContext *scope, String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *))
{
return scope->engine()->memoryManager->allocObject<BuiltinFunction>(scope, name, code);
}
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 1dbc538be2..66861bf697 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -208,6 +208,7 @@ struct StringObject;
struct ArrayObject;
struct DateObject;
struct FunctionObject;
+struct BuiltinFunction;
struct ErrorObject;
struct ArgumentsObject;
struct Managed;
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index af92ce1ad8..1bc91f832b 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -423,18 +423,15 @@ static inline int toInt(const QChar &qc, int R)
}
// parseInt [15.1.2.2]
-ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx)
+void GlobalFunctions::method_parseInt(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue inputString(scope, ctx->argument(0));
- ScopedValue radix(scope, ctx->argument(1));
+ ScopedValue inputString(scope, callData->argument(0));
+ ScopedValue radix(scope, callData->argument(1));
int R = radix->isUndefined() ? 0 : radix->toInt32();
// [15.1.2.2] step by step:
QString trimmed = inputString->toQString().trimmed(); // 1 + 2
-
- if (ctx->d()->engine->hasException)
- return Encode::undefined();
+ CHECK_EXCEPTION();
const QChar *pos = trimmed.constData();
const QChar *end = pos + trimmed.length();
@@ -449,7 +446,7 @@ ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx)
bool stripPrefix = true; // 7
if (R) { // 8
if (R < 2 || R > 36)
- return Encode(std::numeric_limits<double>::quiet_NaN()); // 8a
+ RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN())); // 8a
if (R != 16)
stripPrefix = false; // 8b
} else { // 9
@@ -466,13 +463,13 @@ ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx)
// 11: Z is progressively built below
// 13: this is handled by the toInt function
if (pos == end) // 12
- return Encode(std::numeric_limits<double>::quiet_NaN());
+ RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN()));
bool overflow = false;
qint64 v_overflow = 0;
unsigned overflow_digit_count = 0;
int d = toInt(*pos++, R);
if (d == -1)
- return Encode(std::numeric_limits<double>::quiet_NaN());
+ RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN()));
qint64 v = d;
while (pos != end) {
d = toInt(*pos++, R);
@@ -499,155 +496,148 @@ ReturnedValue GlobalFunctions::method_parseInt(CallContext *ctx)
if (overflow) {
double result = (double) v_overflow * pow(static_cast<double>(R), static_cast<double>(overflow_digit_count));
result += v;
- return Encode(sign * result);
+ RETURN_RESULT(Encode(sign * result));
} else {
- return Encode(sign * (double) v); // 15
+ RETURN_RESULT(Encode(sign * (double) v)); // 15
}
}
// parseFloat [15.1.2.3]
-ReturnedValue GlobalFunctions::method_parseFloat(CallContext *ctx)
+void GlobalFunctions::method_parseFloat(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
-
// [15.1.2.3] step by step:
- ScopedString inputString(scope, ctx->argument(0), ScopedString::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedString inputString(scope, callData->argument(0), ScopedString::Convert);
+ CHECK_EXCEPTION();
QString trimmed = inputString->toQString().trimmed(); // 2
// 4:
if (trimmed.startsWith(QLatin1String("Infinity"))
|| trimmed.startsWith(QLatin1String("+Infinity")))
- return Encode(Q_INFINITY);
+ RETURN_RESULT(Encode(Q_INFINITY));
if (trimmed.startsWith(QLatin1String("-Infinity")))
- return Encode(-Q_INFINITY);
+ RETURN_RESULT(Encode(-Q_INFINITY));
QByteArray ba = trimmed.toLatin1();
bool ok;
const char *begin = ba.constData();
const char *end = 0;
double d = qstrtod(begin, &end, &ok);
if (end - begin == 0)
- return Encode(std::numeric_limits<double>::quiet_NaN()); // 3
+ RETURN_RESULT(Encode(std::numeric_limits<double>::quiet_NaN())); // 3
else
- return Encode(d);
+ RETURN_RESULT(Encode(d));
}
/// isNaN [15.1.2.4]
-ReturnedValue GlobalFunctions::method_isNaN(CallContext *ctx)
+void GlobalFunctions::method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!ctx->argc())
+ if (!callData->argc)
// undefined gets converted to NaN
- return Encode(true);
+ RETURN_RESULT(Encode(true));
- if (ctx->args()[0].integerCompatible())
- return Encode(false);
+ if (callData->args[0].integerCompatible())
+ RETURN_RESULT(Encode(false));
- double d = ctx->args()[0].toNumber();
- return Encode((bool)std::isnan(d));
+ double d = callData->args[0].toNumber();
+ RETURN_RESULT(Encode((bool)std::isnan(d)));
}
/// isFinite [15.1.2.5]
-ReturnedValue GlobalFunctions::method_isFinite(CallContext *ctx)
+void GlobalFunctions::method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!ctx->argc())
+ if (!callData->argc)
// undefined gets converted to NaN
- return Encode(false);
+ RETURN_RESULT(Encode(false));
- if (ctx->args()[0].integerCompatible())
- return Encode(true);
+ if (callData->args[0].integerCompatible())
+ RETURN_RESULT(Encode(true));
- double d = ctx->args()[0].toNumber();
- return Encode((bool)std::isfinite(d));
+ double d = callData->args[0].toNumber();
+ RETURN_RESULT(Encode((bool)std::isfinite(d)));
}
/// decodeURI [15.1.3.1]
-ReturnedValue GlobalFunctions::method_decodeURI(CallContext *context)
+void GlobalFunctions::method_decodeURI(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (context->argc() == 0)
- return Encode::undefined();
+ if (callData->argc == 0)
+ RETURN_UNDEFINED();
- QString uriString = context->args()[0].toQString();
+ QString uriString = callData->args[0].toQString();
bool ok;
QString out = decode(uriString, DecodeNonReserved, &ok);
if (!ok) {
- Scope scope(context);
- ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence")));
- return context->engine()->throwURIError(s);
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
+ RETURN_RESULT(scope.engine->throwURIError(s));
}
- return context->d()->engine->newString(out)->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(out));
}
/// decodeURIComponent [15.1.3.2]
-ReturnedValue GlobalFunctions::method_decodeURIComponent(CallContext *context)
+void GlobalFunctions::method_decodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (context->argc() == 0)
- return Encode::undefined();
+ if (callData->argc == 0)
+ RETURN_UNDEFINED();
- QString uriString = context->args()[0].toQString();
+ QString uriString = callData->args[0].toQString();
bool ok;
QString out = decode(uriString, DecodeAll, &ok);
if (!ok) {
- Scope scope(context);
- ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence")));
- return context->engine()->throwURIError(s);
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
+ RETURN_RESULT(scope.engine->throwURIError(s));
}
- return context->d()->engine->newString(out)->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(out));
}
/// encodeURI [15.1.3.3]
-ReturnedValue GlobalFunctions::method_encodeURI(CallContext *context)
+void GlobalFunctions::method_encodeURI(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (context->argc() == 0)
- return Encode::undefined();
+ if (callData->argc == 0)
+ RETURN_UNDEFINED();
- QString uriString = context->args()[0].toQString();
+ QString uriString = callData->args[0].toQString();
bool ok;
QString out = encode(uriString, uriUnescapedReserved, &ok);
if (!ok) {
- Scope scope(context);
- ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence")));
- return context->engine()->throwURIError(s);
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
+ RETURN_RESULT(scope.engine->throwURIError(s));
}
- return context->d()->engine->newString(out)->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(out));
}
/// encodeURIComponent [15.1.3.4]
-ReturnedValue GlobalFunctions::method_encodeURIComponent(CallContext *context)
+void GlobalFunctions::method_encodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (context->argc() == 0)
- return Encode::undefined();
+ if (callData->argc == 0)
+ RETURN_UNDEFINED();
- QString uriString = context->args()[0].toQString();
+ QString uriString = callData->args[0].toQString();
bool ok;
QString out = encode(uriString, uriUnescaped, &ok);
if (!ok) {
- Scope scope(context);
- ScopedString s(scope, context->d()->engine->newString(QStringLiteral("malformed URI sequence")));
- return context->engine()->throwURIError(s);
+ ScopedString s(scope, scope.engine->newString(QStringLiteral("malformed URI sequence")));
+ RETURN_RESULT(scope.engine->throwURIError(s));
}
- return context->d()->engine->newString(out)->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(out));
}
-ReturnedValue GlobalFunctions::method_escape(CallContext *context)
+void GlobalFunctions::method_escape(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!context->argc())
- return context->d()->engine->newString(QStringLiteral("undefined"))->asReturnedValue();
+ if (!callData->argc)
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("undefined")));
- QString str = context->args()[0].toQString();
- return context->d()->engine->newString(escape(str))->asReturnedValue();
+ QString str = callData->args[0].toQString();
+ RETURN_RESULT(scope.engine->newString(escape(str)));
}
-ReturnedValue GlobalFunctions::method_unescape(CallContext *context)
+void GlobalFunctions::method_unescape(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!context->argc())
- return context->d()->engine->newString(QStringLiteral("undefined"))->asReturnedValue();
+ if (!callData->argc)
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("undefined")));
- QString str = context->args()[0].toQString();
- return context->d()->engine->newString(unescape(str))->asReturnedValue();
+ QString str = callData->args[0].toQString();
+ RETURN_RESULT(scope.engine->newString(unescape(str)));
}
diff --git a/src/qml/jsruntime/qv4globalobject_p.h b/src/qml/jsruntime/qv4globalobject_p.h
index e8b3a92d34..273f1ba7ea 100644
--- a/src/qml/jsruntime/qv4globalobject_p.h
+++ b/src/qml/jsruntime/qv4globalobject_p.h
@@ -76,16 +76,16 @@ struct Q_QML_EXPORT EvalFunction : FunctionObject
struct GlobalFunctions
{
- static ReturnedValue method_parseInt(CallContext *context);
- static ReturnedValue method_parseFloat(CallContext *context);
- static ReturnedValue method_isNaN(CallContext *context);
- static ReturnedValue method_isFinite(CallContext *ctx);
- static ReturnedValue method_decodeURI(CallContext *context);
- static ReturnedValue method_decodeURIComponent(CallContext *context);
- static ReturnedValue method_encodeURI(CallContext *context);
- static ReturnedValue method_encodeURIComponent(CallContext *context);
- static ReturnedValue method_escape(CallContext *context);
- static ReturnedValue method_unescape(CallContext *context);
+ static void method_parseInt(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_parseFloat(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_decodeURI(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_decodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_encodeURI(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_encodeURIComponent(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_escape(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_unescape(const BuiltinFunction *, Scope &scope, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp
index 1d393cf0aa..f033eb2d2d 100644
--- a/src/qml/jsruntime/qv4include.cpp
+++ b/src/qml/jsruntime/qv4include.cpp
@@ -195,23 +195,22 @@ void QV4Include::finished()
/*
Documented in qv8engine.cpp
*/
-QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx)
+void QV4Include::method_include(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- if (!ctx->argc())
- return QV4::Encode::undefined();
+ if (!callData->argc)
+ RETURN_UNDEFINED();
- QV4::Scope scope(ctx->engine());
QQmlContextData *context = scope.engine->callingQmlContext();
if (!context || !context->isJSContext)
- V4THROW_ERROR("Qt.include(): Can only be called from JavaScript files");
+ RETURN_RESULT(scope.engine->throwError(QString::fromUtf8("Qt.include(): Can only be called from JavaScript files")));
QV4::ScopedValue callbackFunction(scope, QV4::Primitive::undefinedValue());
- if (ctx->argc() >= 2 && ctx->args()[1].as<QV4::FunctionObject>())
- callbackFunction = ctx->args()[1];
+ if (callData->argc >= 2 && callData->args[1].as<QV4::FunctionObject>())
+ callbackFunction = callData->args[1];
#if QT_CONFIG(qml_network)
- QUrl url(scope.engine->resolvedUrl(ctx->args()[0].toQStringNoThrow()));
+ QUrl url(scope.engine->resolvedUrl(callData->args[0].toQStringNoThrow()));
if (scope.engine->qmlEngine() && scope.engine->qmlEngine()->urlInterceptor())
url = scope.engine->qmlEngine()->urlInterceptor()->intercept(url, QQmlAbstractUrlInterceptor::JavaScriptFile);
@@ -261,12 +260,12 @@ QV4::ReturnedValue QV4Include::method_include(QV4::CallContext *ctx)
callback(callbackFunction, result);
}
- return result->asReturnedValue();
+ scope.result = result;
#else
QV4::ScopedValue result(scope);
result = resultValue(scope.engine, NetworkError);
callback(callbackFunction, result);
- return result->asReturnedValue();
+ scope.result = result;
#endif
}
diff --git a/src/qml/jsruntime/qv4include_p.h b/src/qml/jsruntime/qv4include_p.h
index 4c601a5e7b..5908d6bfde 100644
--- a/src/qml/jsruntime/qv4include_p.h
+++ b/src/qml/jsruntime/qv4include_p.h
@@ -77,7 +77,7 @@ public:
Exception = 3
};
- static QV4::ReturnedValue method_include(QV4::CallContext *ctx);
+ static void method_include(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
private Q_SLOTS:
void finished();
diff --git a/src/qml/jsruntime/qv4internalclass.cpp b/src/qml/jsruntime/qv4internalclass.cpp
index d17da9af0c..bac71b4537 100644
--- a/src/qml/jsruntime/qv4internalclass.cpp
+++ b/src/qml/jsruntime/qv4internalclass.cpp
@@ -128,48 +128,22 @@ InternalClass::InternalClass(const QV4::InternalClass &other)
static void insertHoleIntoPropertyData(Object *object, int idx)
{
- int inlineSize = object->d()->inlineMemberSize;
int icSize = object->internalClass()->size;
- int from = qMax(idx, inlineSize);
+ int from = idx;
int to = from + 1;
- if (from < icSize) {
+ if (from < icSize)
memmove(object->propertyData(to), object->propertyData(from),
(icSize - from - 1) * sizeof(Value));
- }
- if (from == idx)
- return;
- if (inlineSize < icSize)
- *object->propertyData(inlineSize) = *object->propertyData(inlineSize - 1);
- from = idx;
- to = from + 1;
- if (from < inlineSize - 1) {
- memmove(object->propertyData(to), object->propertyData(from),
- (inlineSize - from - 1) * sizeof(Value));
- }
}
static void removeFromPropertyData(Object *object, int idx, bool accessor = false)
{
- int inlineSize = object->d()->inlineMemberSize;
int delta = (accessor ? 2 : 1);
int oldSize = object->internalClass()->size + delta;
int to = idx;
int from = to + delta;
- if (from < inlineSize) {
- memmove(object->propertyData(to), object->d()->propertyData(from), (inlineSize - from)*sizeof(Value));
- to = inlineSize - delta;
- from = inlineSize;
- }
- if (to < inlineSize && from < oldSize) {
- Q_ASSERT(from >= inlineSize);
- memcpy(object->propertyData(to), object->d()->propertyData(from), (inlineSize - to)*sizeof(Value));
- to = inlineSize;
- from = inlineSize + delta;
- }
- if (from < oldSize) {
- Q_ASSERT(to >= inlineSize && from > to);
+ if (from < oldSize)
memmove(object->propertyData(to), object->d()->propertyData(from), (oldSize - to)*sizeof(Value));
- }
}
void InternalClass::changeMember(Object *object, String *string, PropertyAttributes data, uint *index)
diff --git a/src/qml/jsruntime/qv4internalclass_p.h b/src/qml/jsruntime/qv4internalclass_p.h
index dcda949c97..1d8ef4b0fb 100644
--- a/src/qml/jsruntime/qv4internalclass_p.h
+++ b/src/qml/jsruntime/qv4internalclass_p.h
@@ -234,7 +234,7 @@ struct InternalClassTransition
{ return id == other.id && flags == other.flags; }
bool operator<(const InternalClassTransition &other) const
- { return id < other.id; }
+ { return id < other.id || (id == other.id && flags < other.flags); }
};
struct InternalClass : public QQmlJS::Managed {
diff --git a/src/qml/jsruntime/qv4jsonobject.cpp b/src/qml/jsruntime/qv4jsonobject.cpp
index d79e6242ba..1d571f53f3 100644
--- a/src/qml/jsruntime/qv4jsonobject.cpp
+++ b/src/qml/jsruntime/qv4jsonobject.cpp
@@ -883,10 +883,9 @@ void Heap::JsonObject::init()
}
-ReturnedValue JsonObject::method_parse(CallContext *ctx)
+void JsonObject::method_parse(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue v(scope, ctx->argument(0));
+ ScopedValue v(scope, callData->argument(0));
QString jtext = v->toQString();
DEBUG << "parsing source = " << jtext;
@@ -895,19 +894,17 @@ ReturnedValue JsonObject::method_parse(CallContext *ctx)
ScopedValue result(scope, parser.parse(&error));
if (error.error != QJsonParseError::NoError) {
DEBUG << "parse error" << error.errorString();
- return ctx->engine()->throwSyntaxError(QStringLiteral("JSON.parse: Parse error"));
+ RETURN_RESULT(scope.engine->throwSyntaxError(QStringLiteral("JSON.parse: Parse error")));
}
- return result->asReturnedValue();
+ scope.result = result;
}
-ReturnedValue JsonObject::method_stringify(CallContext *ctx)
+void JsonObject::method_stringify(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
-
Stringify stringify(scope.engine);
- ScopedObject o(scope, ctx->argument(1));
+ ScopedObject o(scope, callData->argument(1));
if (o) {
stringify.replacerFunction = o->as<FunctionObject>();
if (o->isArrayObject()) {
@@ -932,7 +929,7 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx)
}
}
- ScopedValue s(scope, ctx->argument(2));
+ ScopedValue s(scope, callData->argument(2));
if (NumberObject *n = s->as<NumberObject>())
s = Encode(n->value());
else if (StringObject *so = s->as<StringObject>())
@@ -945,11 +942,11 @@ ReturnedValue JsonObject::method_stringify(CallContext *ctx)
}
- ScopedValue arg0(scope, ctx->argument(0));
+ ScopedValue arg0(scope, callData->argument(0));
QString result = stringify.Str(QString(), arg0);
if (result.isEmpty() || scope.engine->hasException)
- return Encode::undefined();
- return ctx->d()->engine->newString(result)->asReturnedValue();
+ RETURN_UNDEFINED();
+ scope.result = scope.engine->newString(result);
}
diff --git a/src/qml/jsruntime/qv4jsonobject_p.h b/src/qml/jsruntime/qv4jsonobject_p.h
index 43248a214d..a73ce1c74e 100644
--- a/src/qml/jsruntime/qv4jsonobject_p.h
+++ b/src/qml/jsruntime/qv4jsonobject_p.h
@@ -88,8 +88,8 @@ private:
typedef QSet<ObjectItem> V4ObjectSet;
public:
- static ReturnedValue method_parse(CallContext *ctx);
- static ReturnedValue method_stringify(CallContext *ctx);
+ static void method_parse(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_stringify(const BuiltinFunction *, Scope &scope, CallData *callData);
static ReturnedValue fromJsonValue(ExecutionEngine *engine, const QJsonValue &value);
static ReturnedValue fromJsonObject(ExecutionEngine *engine, const QJsonObject &object);
diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h
index 52f54e25f5..c5ee92fedd 100644
--- a/src/qml/jsruntime/qv4lookup_p.h
+++ b/src/qml/jsruntime/qv4lookup_p.h
@@ -54,8 +54,11 @@
#include "qv4runtime_p.h"
#include "qv4engine_p.h"
#include "qv4context_p.h"
+
+#if !defined(V4_BOOTSTRAP)
#include "qv4object_p.h"
#include "qv4internalclass_p.h"
+#endif
QT_BEGIN_NAMESPACE
diff --git a/src/qml/jsruntime/qv4mathobject.cpp b/src/qml/jsruntime/qv4mathobject.cpp
index e03b2762cc..2d9d81c64b 100644
--- a/src/qml/jsruntime/qv4mathobject.cpp
+++ b/src/qml/jsruntime/qv4mathobject.cpp
@@ -92,160 +92,160 @@ static Q_ALWAYS_INLINE double copySign(double x, double y)
return ::copysign(x, y);
}
-ReturnedValue MathObject::method_abs(CallContext *context)
+void MathObject::method_abs(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!context->argc())
- return Encode(qt_qnan());
+ if (!callData->argc)
+ RETURN_RESULT(Encode(qt_qnan()));
- if (context->args()[0].isInteger()) {
- int i = context->args()[0].integerValue();
- return Encode(i < 0 ? - i : i);
+ if (callData->args[0].isInteger()) {
+ int i = callData->args[0].integerValue();
+ RETURN_RESULT(Encode(i < 0 ? - i : i));
}
- double v = context->args()[0].toNumber();
+ double v = callData->args[0].toNumber();
if (v == 0) // 0 | -0
- return Encode(0);
+ RETURN_RESULT(Encode(0));
- return Encode(v < 0 ? -v : v);
+ RETURN_RESULT(Encode(v < 0 ? -v : v));
}
-ReturnedValue MathObject::method_acos(CallContext *context)
+void MathObject::method_acos(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : 2;
+ double v = callData->argc ? callData->args[0].toNumber() : 2;
if (v > 1)
- return Encode(qt_qnan());
+ RETURN_RESULT(Encode(qt_qnan()));
- return Encode(std::acos(v));
+ RETURN_RESULT(Encode(std::acos(v)));
}
-ReturnedValue MathObject::method_asin(CallContext *context)
+void MathObject::method_asin(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : 2;
+ double v = callData->argc ? callData->args[0].toNumber() : 2;
if (v > 1)
- return Encode(qt_qnan());
+ RETURN_RESULT(Encode(qt_qnan()));
else
- return Encode(std::asin(v));
+ RETURN_RESULT(Encode(std::asin(v)));
}
-ReturnedValue MathObject::method_atan(CallContext *context)
+void MathObject::method_atan(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
if (v == 0.0)
- return Encode(v);
+ RETURN_RESULT(Encode(v));
else
- return Encode(std::atan(v));
+ RETURN_RESULT(Encode(std::atan(v)));
}
-ReturnedValue MathObject::method_atan2(CallContext *context)
+void MathObject::method_atan2(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v1 = context->argc() ? context->args()[0].toNumber() : qt_qnan();
- double v2 = context->argc() > 1 ? context->args()[1].toNumber() : qt_qnan();
+ double v1 = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ double v2 = callData->argc > 1 ? callData->args[1].toNumber() : qt_qnan();
if ((v1 < 0) && qt_is_finite(v1) && qt_is_inf(v2) && (copySign(1.0, v2) == 1.0))
- return Encode(copySign(0, -1.0));
+ RETURN_RESULT(Encode(copySign(0, -1.0)));
if ((v1 == 0.0) && (v2 == 0.0)) {
if ((copySign(1.0, v1) == 1.0) && (copySign(1.0, v2) == -1.0)) {
- return Encode(M_PI);
+ RETURN_RESULT(Encode(M_PI));
} else if ((copySign(1.0, v1) == -1.0) && (copySign(1.0, v2) == -1.0)) {
- return Encode(-M_PI);
+ RETURN_RESULT(Encode(-M_PI));
}
}
- return Encode(std::atan2(v1, v2));
+ RETURN_RESULT(Encode(std::atan2(v1, v2)));
}
-ReturnedValue MathObject::method_ceil(CallContext *context)
+void MathObject::method_ceil(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
if (v < 0.0 && v > -1.0)
- return Encode(copySign(0, -1.0));
+ RETURN_RESULT(Encode(copySign(0, -1.0)));
else
- return Encode(std::ceil(v));
+ RETURN_RESULT(Encode(std::ceil(v)));
}
-ReturnedValue MathObject::method_cos(CallContext *context)
+void MathObject::method_cos(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
- return Encode(std::cos(v));
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ RETURN_RESULT(Encode(std::cos(v)));
}
-ReturnedValue MathObject::method_exp(CallContext *context)
+void MathObject::method_exp(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
if (qt_is_inf(v)) {
if (copySign(1.0, v) == -1.0)
- return Encode(0);
+ RETURN_RESULT(Encode(0));
else
- return Encode(qt_inf());
+ RETURN_RESULT(Encode(qt_inf()));
} else {
- return Encode(std::exp(v));
+ RETURN_RESULT(Encode(std::exp(v)));
}
}
-ReturnedValue MathObject::method_floor(CallContext *context)
+void MathObject::method_floor(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
- return Encode(std::floor(v));
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ RETURN_RESULT(Encode(std::floor(v)));
}
-ReturnedValue MathObject::method_log(CallContext *context)
+void MathObject::method_log(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
if (v < 0)
- return Encode(qt_qnan());
+ RETURN_RESULT(Encode(qt_qnan()));
else
- return Encode(std::log(v));
+ RETURN_RESULT(Encode(std::log(v)));
}
-ReturnedValue MathObject::method_max(CallContext *context)
+void MathObject::method_max(const BuiltinFunction *, Scope &scope, CallData *callData)
{
double mx = -qt_inf();
- for (int i = 0; i < context->argc(); ++i) {
- double x = context->args()[i].toNumber();
+ for (int i = 0; i < callData->argc; ++i) {
+ double x = callData->args[i].toNumber();
if (x > mx || std::isnan(x))
mx = x;
}
- return Encode(mx);
+ RETURN_RESULT(Encode(mx));
}
-ReturnedValue MathObject::method_min(CallContext *context)
+void MathObject::method_min(const BuiltinFunction *, Scope &scope, CallData *callData)
{
double mx = qt_inf();
- for (int i = 0; i < context->argc(); ++i) {
- double x = context->args()[i].toNumber();
+ for (int i = 0; i < callData->argc; ++i) {
+ double x = callData->args[i].toNumber();
if ((x == 0 && mx == x && copySign(1.0, x) == -1.0)
|| (x < mx) || std::isnan(x)) {
mx = x;
}
}
- return Encode(mx);
+ RETURN_RESULT(Encode(mx));
}
-ReturnedValue MathObject::method_pow(CallContext *context)
+void MathObject::method_pow(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double x = context->argc() > 0 ? context->args()[0].toNumber() : qt_qnan();
- double y = context->argc() > 1 ? context->args()[1].toNumber() : qt_qnan();
+ double x = callData->argc > 0 ? callData->args[0].toNumber() : qt_qnan();
+ double y = callData->argc > 1 ? callData->args[1].toNumber() : qt_qnan();
if (std::isnan(y))
- return Encode(qt_qnan());
+ RETURN_RESULT(Encode(qt_qnan()));
if (y == 0) {
- return Encode(1);
+ RETURN_RESULT(Encode(1));
} else if (((x == 1) || (x == -1)) && std::isinf(y)) {
- return Encode(qt_qnan());
+ RETURN_RESULT(Encode(qt_qnan()));
} else if (((x == 0) && copySign(1.0, x) == 1.0) && (y < 0)) {
- return Encode(qInf());
+ RETURN_RESULT(Encode(qInf()));
} else if ((x == 0) && copySign(1.0, x) == -1.0) {
if (y < 0) {
if (std::fmod(-y, 2.0) == 1.0)
- return Encode(-qt_inf());
+ RETURN_RESULT(Encode(-qt_inf()));
else
- return Encode(qt_inf());
+ RETURN_RESULT(Encode(qt_inf()));
} else if (y > 0) {
if (std::fmod(y, 2.0) == 1.0)
- return Encode(copySign(0, -1.0));
+ RETURN_RESULT(Encode(copySign(0, -1.0)));
else
- return Encode(0);
+ RETURN_RESULT(Encode(0));
}
}
@@ -253,78 +253,78 @@ ReturnedValue MathObject::method_pow(CallContext *context)
else if (qt_is_inf(x) && copySign(1.0, x) == -1.0) {
if (y > 0) {
if (std::fmod(y, 2.0) == 1.0)
- return Encode(-qt_inf());
+ RETURN_RESULT(Encode(-qt_inf()));
else
- return Encode(qt_inf());
+ RETURN_RESULT(Encode(qt_inf()));
} else if (y < 0) {
if (std::fmod(-y, 2.0) == 1.0)
- return Encode(copySign(0, -1.0));
+ RETURN_RESULT(Encode(copySign(0, -1.0)));
else
- return Encode(0);
+ RETURN_RESULT(Encode(0));
}
}
#endif
else {
- return Encode(std::pow(x, y));
+ RETURN_RESULT(Encode(std::pow(x, y)));
}
// ###
- return Encode(qt_qnan());
+ RETURN_RESULT(Encode(qt_qnan()));
}
Q_GLOBAL_STATIC(QThreadStorage<bool *>, seedCreatedStorage);
-ReturnedValue MathObject::method_random(CallContext *context)
+void MathObject::method_random(const BuiltinFunction *, Scope &scope, CallData *)
{
if (!seedCreatedStorage()->hasLocalData()) {
int msecs = QTime(0,0,0).msecsTo(QTime::currentTime());
Q_ASSERT(msecs >= 0);
- qsrand(uint(uint(msecs) ^ reinterpret_cast<quintptr>(context)));
+ qsrand(uint(uint(msecs) ^ reinterpret_cast<quintptr>(scope.engine)));
seedCreatedStorage()->setLocalData(new bool(true));
}
// rand()/qrand() return a value where the upperbound is RAND_MAX inclusive. So, instead of
// dividing by RAND_MAX (which would return 0..RAND_MAX inclusive), we divide by RAND_MAX + 1.
qint64 upperLimit = qint64(RAND_MAX) + 1;
- return Encode(qrand() / double(upperLimit));
+ RETURN_RESULT(Encode(qrand() / double(upperLimit)));
}
-ReturnedValue MathObject::method_round(CallContext *context)
+void MathObject::method_round(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
v = copySign(std::floor(v + 0.5), v);
- return Encode(v);
+ RETURN_RESULT(Encode(v));
}
-ReturnedValue MathObject::method_sign(CallContext *context)
+void MathObject::method_sign(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
if (std::isnan(v))
- return Encode(qt_qnan());
+ RETURN_RESULT(Encode(qt_qnan()));
if (qIsNull(v))
- return v;
+ RETURN_RESULT(Encode(v));
- return Encode(std::signbit(v) ? -1 : 1);
+ RETURN_RESULT(Encode(std::signbit(v) ? -1 : 1));
}
-ReturnedValue MathObject::method_sin(CallContext *context)
+void MathObject::method_sin(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
- return Encode(std::sin(v));
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ RETURN_RESULT(Encode(std::sin(v)));
}
-ReturnedValue MathObject::method_sqrt(CallContext *context)
+void MathObject::method_sqrt(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
- return Encode(std::sqrt(v));
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+ RETURN_RESULT(Encode(std::sqrt(v)));
}
-ReturnedValue MathObject::method_tan(CallContext *context)
+void MathObject::method_tan(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- double v = context->argc() ? context->args()[0].toNumber() : qt_qnan();
+ double v = callData->argc ? callData->args[0].toNumber() : qt_qnan();
if (v == 0.0)
- return Encode(v);
+ RETURN_RESULT(Encode(v));
else
- return Encode(std::tan(v));
+ RETURN_RESULT(Encode(std::tan(v)));
}
diff --git a/src/qml/jsruntime/qv4mathobject_p.h b/src/qml/jsruntime/qv4mathobject_p.h
index f6b1a4395f..e617712905 100644
--- a/src/qml/jsruntime/qv4mathobject_p.h
+++ b/src/qml/jsruntime/qv4mathobject_p.h
@@ -69,25 +69,25 @@ struct MathObject: Object
V4_OBJECT2(MathObject, Object)
Q_MANAGED_TYPE(MathObject)
- static ReturnedValue method_abs(CallContext *context);
- static ReturnedValue method_acos(CallContext *context);
- static ReturnedValue method_asin(CallContext *context);
- static ReturnedValue method_atan(CallContext *context);
- static ReturnedValue method_atan2(CallContext *context);
- static ReturnedValue method_ceil(CallContext *context);
- static ReturnedValue method_cos(CallContext *context);
- static ReturnedValue method_exp(CallContext *context);
- static ReturnedValue method_floor(CallContext *context);
- static ReturnedValue method_log(CallContext *context);
- static ReturnedValue method_max(CallContext *context);
- static ReturnedValue method_min(CallContext *context);
- static ReturnedValue method_pow(CallContext *context);
- static ReturnedValue method_random(CallContext *context);
- static ReturnedValue method_round(CallContext *context);
- static ReturnedValue method_sign(CallContext *context);
- static ReturnedValue method_sin(CallContext *context);
- static ReturnedValue method_sqrt(CallContext *context);
- static ReturnedValue method_tan(CallContext *context);
+ static void method_abs(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_acos(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_asin(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_atan(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_atan2(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_ceil(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_cos(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_exp(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_floor(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_log(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_max(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_min(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_pow(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_random(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_round(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_sign(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_sin(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_sqrt(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_tan(const BuiltinFunction *, Scope &scope, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp
index d5f75415cc..db45c77472 100644
--- a/src/qml/jsruntime/qv4memberdata.cpp
+++ b/src/qml/jsruntime/qv4memberdata.cpp
@@ -55,13 +55,14 @@ void MemberData::markObjects(Heap::Base *that, ExecutionEngine *e)
Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberData *old)
{
Q_ASSERT(!old || old->size < n);
+ Q_ASSERT(n);
- uint alloc = sizeof(Heap::MemberData) + (n)*sizeof(Value);
+ size_t alloc = MemoryManager::align(sizeof(Heap::MemberData) + (n - 1)*sizeof(Value));
Heap::MemberData *m = e->memoryManager->allocManaged<MemberData>(alloc);
if (old)
- memcpy(m, old, sizeof(Heap::MemberData) + old->size * sizeof(Value));
+ memcpy(m, old, sizeof(Heap::MemberData) + (old->size - 1)* sizeof(Value));
else
m->init();
- m->size = n;
+ m->size = static_cast<uint>((alloc - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
return m;
}
diff --git a/src/qml/jsruntime/qv4numberobject.cpp b/src/qml/jsruntime/qv4numberobject.cpp
index 3a6b9da763..09644c161d 100644
--- a/src/qml/jsruntime/qv4numberobject.cpp
+++ b/src/qml/jsruntime/qv4numberobject.cpp
@@ -120,61 +120,71 @@ QT_WARNING_POP
defineDefaultProperty(QStringLiteral("toPrecision"), method_toPrecision);
}
-inline ReturnedValue thisNumberValue(ExecutionContext *ctx)
+inline ReturnedValue thisNumberValue(Scope &scope, CallData *callData)
{
- if (ctx->thisObject().isNumber())
- return ctx->thisObject().asReturnedValue();
- NumberObject *n = ctx->thisObject().as<NumberObject>();
- if (!n)
- return ctx->engine()->throwTypeError();
+ if (callData->thisObject.isNumber())
+ return callData->thisObject.asReturnedValue();
+ NumberObject *n = callData->thisObject.as<NumberObject>();
+ if (!n) {
+ scope.engine->throwTypeError();
+ return Encode::undefined();
+ }
return Encode(n->value());
}
-inline double thisNumber(ExecutionContext *ctx)
+inline double thisNumber(Scope &scope, CallData *callData)
{
- if (ctx->thisObject().isNumber())
- return ctx->thisObject().asDouble();
- NumberObject *n = ctx->thisObject().as<NumberObject>();
- if (!n)
- return ctx->engine()->throwTypeError();
+ if (callData->thisObject.isNumber())
+ return callData->thisObject.asDouble();
+ NumberObject *n = callData->thisObject.as<NumberObject>();
+ if (!n) {
+ scope.engine->throwTypeError();
+ return 0;
+ }
return n->value();
}
-ReturnedValue NumberPrototype::method_isFinite(CallContext *ctx)
+void NumberPrototype::method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!ctx->argc())
- return Encode(false);
+ if (!callData->argc) {
+ scope.result = Encode(false);
+ return;
+ }
- double v = ctx->args()[0].toNumber();
- return Encode(!std::isnan(v) && !qt_is_inf(v));
+ double v = callData->args[0].toNumber();
+ scope.result = Encode(!std::isnan(v) && !qt_is_inf(v));
}
-ReturnedValue NumberPrototype::method_isNaN(CallContext *ctx)
+void NumberPrototype::method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (!ctx->argc())
- return Encode(false);
+ if (!callData->argc) {
+ scope.result = Encode(false);
+ return;
+ }
- double v = ctx->args()[0].toNumber();
- return Encode(std::isnan(v));
+ double v = callData->args[0].toNumber();
+ scope.result = Encode(std::isnan(v));
}
-ReturnedValue NumberPrototype::method_toString(CallContext *ctx)
+void NumberPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- double num = thisNumber(ctx);
- if (scope.engine->hasException)
- return Encode::undefined();
+ double num = thisNumber(scope, callData);
+ CHECK_EXCEPTION();
- if (ctx->argc() && !ctx->args()[0].isUndefined()) {
- int radix = ctx->args()[0].toInt32();
- if (radix < 2 || radix > 36)
- return ctx->engine()->throwError(QStringLiteral("Number.prototype.toString: %0 is not a valid radix")
+ if (callData->argc && !callData->args[0].isUndefined()) {
+ int radix = callData->args[0].toInt32();
+ if (radix < 2 || radix > 36) {
+ scope.result = scope.engine->throwError(QStringLiteral("Number.prototype.toString: %0 is not a valid radix")
.arg(radix));
+ return;
+ }
if (std::isnan(num)) {
- return scope.engine->newString(QStringLiteral("NaN"))->asReturnedValue();
+ scope.result = scope.engine->newString(QStringLiteral("NaN"));
+ return;
} else if (qt_is_inf(num)) {
- return scope.engine->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity"))->asReturnedValue();
+ scope.result = scope.engine->newString(QLatin1String(num < 0 ? "-Infinity" : "Infinity"));
+ return;
}
if (radix != 10) {
@@ -204,45 +214,43 @@ ReturnedValue NumberPrototype::method_toString(CallContext *ctx)
}
if (negative)
str.prepend(QLatin1Char('-'));
- return scope.engine->newString(str)->asReturnedValue();
+ scope.result = scope.engine->newString(str);
+ return;
}
}
- return Primitive::fromDouble(num).toString(scope.engine)->asReturnedValue();
+ scope.result = Primitive::fromDouble(num).toString(scope.engine);
}
-ReturnedValue NumberPrototype::method_toLocaleString(CallContext *ctx)
+void NumberPrototype::method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue v(scope, thisNumberValue(ctx));
- ScopedString str(scope, v->toString(scope.engine));
- if (scope.engine->hasException)
- return Encode::undefined();
- return str.asReturnedValue();
+ ScopedValue v(scope, thisNumberValue(scope, callData));
+ scope.result = v->toString(scope.engine);
+ CHECK_EXCEPTION();
}
-ReturnedValue NumberPrototype::method_valueOf(CallContext *ctx)
+void NumberPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- return thisNumberValue(ctx);
+ scope.result = thisNumberValue(scope, callData);
}
-ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx)
+void NumberPrototype::method_toFixed(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- double v = thisNumber(ctx);
- if (scope.engine->hasException)
- return Encode::undefined();
+ double v = thisNumber(scope, callData);
+ CHECK_EXCEPTION();
double fdigits = 0;
- if (ctx->argc() > 0)
- fdigits = ctx->args()[0].toInteger();
+ if (callData->argc > 0)
+ fdigits = callData->args[0].toInteger();
if (std::isnan(fdigits))
fdigits = 0;
- if (fdigits < 0 || fdigits > 20)
- return ctx->engine()->throwRangeError(ctx->thisObject());
+ if (fdigits < 0 || fdigits > 20) {
+ scope.result = scope.engine->throwRangeError(callData->thisObject);
+ return;
+ }
QString str;
if (std::isnan(v))
@@ -251,48 +259,50 @@ ReturnedValue NumberPrototype::method_toFixed(CallContext *ctx)
str = QString::fromLatin1(v < 0 ? "-Infinity" : "Infinity");
else if (v < 1.e21)
str = NumberLocale::instance()->toString(v, 'f', int(fdigits));
- else
- return RuntimeHelpers::stringFromNumber(ctx->engine(), v)->asReturnedValue();
- return scope.engine->newString(str)->asReturnedValue();
+ else {
+ scope.result = RuntimeHelpers::stringFromNumber(scope.engine, v);
+ return;
+ }
+ scope.result = scope.engine->newString(str);
}
-ReturnedValue NumberPrototype::method_toExponential(CallContext *ctx)
+void NumberPrototype::method_toExponential(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- double d = thisNumber(ctx);
- if (scope.engine->hasException)
- return Encode::undefined();
+ double d = thisNumber(scope, callData);
+ CHECK_EXCEPTION();
int fdigits = NumberLocale::instance()->defaultDoublePrecision;
- if (ctx->argc() && !ctx->args()[0].isUndefined()) {
- fdigits = ctx->args()[0].toInt32();
+ if (callData->argc && !callData->args[0].isUndefined()) {
+ fdigits = callData->args[0].toInt32();
if (fdigits < 0 || fdigits > 20) {
ScopedString error(scope, scope.engine->newString(QStringLiteral("Number.prototype.toExponential: fractionDigits out of range")));
- return ctx->engine()->throwRangeError(error);
+ scope.result = scope.engine->throwRangeError(error);
+ return;
}
}
QString result = NumberLocale::instance()->toString(d, 'e', fdigits);
- return scope.engine->newString(result)->asReturnedValue();
+ scope.result = scope.engine->newString(result);
}
-ReturnedValue NumberPrototype::method_toPrecision(CallContext *ctx)
+void NumberPrototype::method_toPrecision(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue v(scope, thisNumberValue(ctx));
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedValue v(scope, thisNumberValue(scope, callData));
+ CHECK_EXCEPTION();
- if (!ctx->argc() || ctx->args()[0].isUndefined())
- return Encode(v->toString(scope.engine));
+ if (!callData->argc || callData->args[0].isUndefined()) {
+ scope.result = v->toString(scope.engine);
+ return;
+ }
- int precision = ctx->args()[0].toInt32();
+ int precision = callData->args[0].toInt32();
if (precision < 1 || precision > 21) {
ScopedString error(scope, scope.engine->newString(QStringLiteral("Number.prototype.toPrecision: precision out of range")));
- return ctx->engine()->throwRangeError(error);
+ scope.result = scope.engine->throwRangeError(error);
+ return;
}
QString result = NumberLocale::instance()->toString(v->asDouble(), 'g', precision);
- return scope.engine->newString(result)->asReturnedValue();
+ scope.result = scope.engine->newString(result);
}
diff --git a/src/qml/jsruntime/qv4numberobject_p.h b/src/qml/jsruntime/qv4numberobject_p.h
index 6022b3a029..364b866a16 100644
--- a/src/qml/jsruntime/qv4numberobject_p.h
+++ b/src/qml/jsruntime/qv4numberobject_p.h
@@ -87,14 +87,14 @@ struct NumberPrototype: NumberObject
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_isFinite(CallContext *ctx);
- static ReturnedValue method_isNaN(CallContext *ctx);
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_toLocaleString(CallContext *ctx);
- static ReturnedValue method_valueOf(CallContext *ctx);
- static ReturnedValue method_toFixed(CallContext *ctx);
- static ReturnedValue method_toExponential(CallContext *ctx);
- static ReturnedValue method_toPrecision(CallContext *ctx);
+ static void method_isFinite(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isNaN(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toFixed(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toExponential(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toPrecision(const BuiltinFunction *, Scope &scope, CallData *callData);
};
diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp
index 8acca16dd0..2f664c6398 100644
--- a/src/qml/jsruntime/qv4object.cpp
+++ b/src/qml/jsruntime/qv4object.cpp
@@ -61,9 +61,8 @@ DEFINE_OBJECT_VTABLE(Object);
void Object::setInternalClass(InternalClass *ic)
{
d()->internalClass = ic;
- if ((ic->size > d()->inlineMemberSize && !d()->memberData) ||
- (d()->memberData && d()->memberData->size < ic->size - d()->inlineMemberSize))
- d()->memberData = MemberData::allocate(ic->engine, ic->size - d()->inlineMemberSize, d()->memberData);
+ if ((!d()->memberData && ic->size) || (d()->memberData->size < ic->size))
+ d()->memberData = MemberData::allocate(ic->engine, ic->size, d()->memberData);
}
void Object::getProperty(uint index, Property *p, PropertyAttributes *attrs) const
@@ -167,6 +166,17 @@ void Object::defineDefaultProperty(const QString &name, ReturnedValue (*code)(Ca
defineDefaultProperty(s, function);
}
+void Object::defineDefaultProperty(const QString &name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount)
+{
+ ExecutionEngine *e = engine();
+ Scope scope(e);
+ ScopedString s(scope, e->newIdentifier(name));
+ ExecutionContext *global = e->rootContext();
+ ScopedFunctionObject function(scope, BuiltinFunction::create(global, s, code));
+ function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ defineDefaultProperty(s, function);
+}
+
void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount)
{
ExecutionEngine *e = engine();
@@ -177,6 +187,16 @@ void Object::defineDefaultProperty(String *name, ReturnedValue (*code)(CallConte
defineDefaultProperty(name, function);
}
+void Object::defineDefaultProperty(String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount)
+{
+ ExecutionEngine *e = engine();
+ Scope scope(e);
+ ExecutionContext *global = e->rootContext();
+ ScopedFunctionObject function(scope, BuiltinFunction::create(global, name, code));
+ function->defineReadonlyProperty(e->id_length(), Primitive::fromInt32(argumentCount));
+ defineDefaultProperty(name, function);
+}
+
void Object::defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *))
{
ExecutionEngine *e = engine();
@@ -196,6 +216,27 @@ void Object::defineAccessorProperty(String *name, ReturnedValue (*getter)(CallCo
insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
}
+void Object::defineAccessorProperty(const QString &name, void (*getter)(const BuiltinFunction *, Scope &, CallData *),
+ void (*setter)(const BuiltinFunction *, Scope &, CallData *))
+{
+ ExecutionEngine *e = engine();
+ Scope scope(e);
+ ScopedString s(scope, e->newIdentifier(name));
+ defineAccessorProperty(s, getter, setter);
+}
+
+void Object::defineAccessorProperty(String *name, void (*getter)(const BuiltinFunction *, Scope &, CallData *),
+ void (*setter)(const BuiltinFunction *, Scope &, CallData *))
+{
+ ExecutionEngine *v4 = engine();
+ QV4::Scope scope(v4);
+ ScopedProperty p(scope);
+ ExecutionContext *global = v4->rootContext();
+ p->setGetter(ScopedFunctionObject(scope, (getter ? BuiltinFunction::create(global, name, getter) : 0)));
+ p->setSetter(ScopedFunctionObject(scope, (setter ? BuiltinFunction::create(global, name, setter) : 0)));
+ insertMember(name, p, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+}
+
void Object::defineReadonlyProperty(const QString &name, const Value &value)
{
QV4::ExecutionEngine *e = engine();
@@ -213,12 +254,6 @@ void Object::markObjects(Heap::Base *that, ExecutionEngine *e)
{
Heap::Object *o = static_cast<Heap::Object *>(that);
- if (o->inlineMemberSize) {
- Value *v = o->propertyData(0);
- for (uint i = 0; i < o->inlineMemberSize; ++i)
- v[i].mark(e);
- }
-
if (o->memberData)
o->memberData->mark(e);
if (o->arrayData)
@@ -1120,6 +1155,49 @@ uint Object::getLength(const Managed *m)
return v->toUInt32();
}
+// 'var' is 'V' in 15.3.5.3.
+ReturnedValue Object::instanceOf(const Object *typeObject, const Value &var)
+{
+ QV4::ExecutionEngine *engine = typeObject->internalClass()->engine;
+
+ // 15.3.5.3, Assume F is a Function object.
+ const FunctionObject *function = typeObject->as<FunctionObject>();
+ if (!function)
+ return engine->throwTypeError();
+
+ Heap::FunctionObject *f = function->d();
+ if (function->isBoundFunction())
+ f = function->cast<BoundFunction>()->target();
+
+ // 15.3.5.3, 1: HasInstance can only be used on an object
+ const Object *lhs = var.as<Object>();
+ if (!lhs)
+ return Encode(false);
+
+ // 15.3.5.3, 2
+ const Object *o = f->protoProperty();
+ if (!o) // 15.3.5.3, 3
+ return engine->throwTypeError();
+
+ Heap::Object *v = lhs->d();
+
+ // 15.3.5.3, 4
+ while (v) {
+ // 15.3.5.3, 4, a
+ v = v->prototype;
+
+ // 15.3.5.3, 4, b
+ if (!v)
+ break; // will return false
+
+ // 15.3.5.3, 4, c
+ else if (o->d() == v)
+ return Encode(true);
+ }
+
+ return Encode(false);
+}
+
bool Object::setArrayLength(uint newLen)
{
Q_ASSERT(isArrayObject());
diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h
index 6c679deb10..6a543ae1a8 100644
--- a/src/qml/jsruntime/qv4object_p.h
+++ b/src/qml/jsruntime/qv4object_p.h
@@ -63,17 +63,17 @@ QT_BEGIN_NAMESPACE
namespace QV4 {
+struct BuiltinFunction;
+
namespace Heap {
struct Object : Base {
void init() { Base::init(); }
void destroy() { Base::destroy(); }
- const Value *propertyData(uint index) const { if (index < inlineMemberSize) return reinterpret_cast<const Value *>(this) + inlineMemberOffset + index; return memberData->data + index - inlineMemberSize; }
- Value *propertyData(uint index) { if (index < inlineMemberSize) return reinterpret_cast<Value *>(this) + inlineMemberOffset + index; return memberData->data + index - inlineMemberSize; }
+ const Value *propertyData(uint index) const { return memberData->data + index; }
+ Value *propertyData(uint index) { return memberData->data + index; }
- uint inlineMemberOffset;
- uint inlineMemberSize;
InternalClass *internalClass;
Pointer<Object> prototype;
Pointer<MemberData> memberData;
@@ -140,6 +140,7 @@ struct ObjectVTable
void (*setLookup)(Managed *m, Lookup *l, const Value &v);
uint (*getLength)(const Managed *m);
void (*advanceIterator)(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
+ ReturnedValue (*instanceOf)(const Object *typeObject, const Value &var);
};
#define DEFINE_OBJECT_VTABLE_BASE(classname) \
@@ -159,7 +160,8 @@ const QV4::ObjectVTable classname::static_vtbl = \
getLookup, \
setLookup, \
getLength, \
- advanceIterator \
+ advanceIterator, \
+ instanceOf \
}
#define DEFINE_OBJECT_VTABLE(classname) \
@@ -238,9 +240,15 @@ struct Q_QML_EXPORT Object: Managed {
}
void defineDefaultProperty(const QString &name, const Value &value);
void defineDefaultProperty(const QString &name, ReturnedValue (*code)(CallContext *), int argumentCount = 0);
+ void defineDefaultProperty(const QString &name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount = 0);
void defineDefaultProperty(String *name, ReturnedValue (*code)(CallContext *), int argumentCount = 0);
+ void defineDefaultProperty(String *name, void (*code)(const BuiltinFunction *, Scope &, CallData *), int argumentCount = 0);
void defineAccessorProperty(const QString &name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *));
void defineAccessorProperty(String *name, ReturnedValue (*getter)(CallContext *), ReturnedValue (*setter)(CallContext *));
+ void defineAccessorProperty(const QString &name, void (*getter)(const BuiltinFunction *, Scope &, CallData *),
+ void (*setter)(const BuiltinFunction *, Scope &, CallData *));
+ void defineAccessorProperty(String *name, void (*getter)(const BuiltinFunction *, Scope &, CallData *),
+ void (*setter)(const BuiltinFunction *, Scope &, CallData *));
/* Fixed: Writable: false, Enumerable: false, Configurable: false */
void defineReadonlyProperty(const QString &name, const Value &value);
void defineReadonlyProperty(String *name, const Value &value);
@@ -345,6 +353,8 @@ public:
void advanceIterator(ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes)
{ vtable()->advanceIterator(this, it, name, index, p, attributes); }
uint getLength() const { return vtable()->getLength(this); }
+ ReturnedValue instanceOf(const Value &var) const
+ { return vtable()->instanceOf(this, var); }
inline void construct(Scope &scope, CallData *d) const
{ return vtable()->construct(this, scope, d); }
@@ -366,6 +376,7 @@ protected:
static void setLookup(Managed *m, Lookup *l, const Value &v);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static uint getLength(const Managed *m);
+ static ReturnedValue instanceOf(const Object *typeObject, const Value &var);
private:
ReturnedValue internalGet(String *name, bool *hasProperty) const;
diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp
index 8191083544..97dbe24339 100644
--- a/src/qml/jsruntime/qv4objectproto.cpp
+++ b/src/qml/jsruntime/qv4objectproto.cpp
@@ -121,100 +121,100 @@ void ObjectPrototype::init(ExecutionEngine *v4, Object *ctor)
insertMember(v4->id___proto__(), p, Attr_Accessor|Attr_NotEnumerable);
}
-ReturnedValue ObjectPrototype::method_getPrototypeOf(CallContext *ctx)
+void ObjectPrototype::method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
ScopedObject p(scope, o->prototype());
- return !!p ? p->asReturnedValue() : Encode::null();
+ scope.result = !!p ? p->asReturnedValue() : Encode::null();
}
-ReturnedValue ObjectPrototype::method_getOwnPropertyDescriptor(CallContext *ctx)
+void ObjectPrototype::method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject O(scope, ctx->argument(0));
- if (!O)
- return ctx->engine()->throwTypeError();
+ ScopedObject O(scope, callData->argument(0));
+ if (!O) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
if (ArgumentsObject::isNonStrictArgumentsObject(O))
static_cast<ArgumentsObject *>(O.getPointer())->fullyCreate();
- ScopedValue v(scope, ctx->argument(1));
+ ScopedValue v(scope, callData->argument(1));
ScopedString name(scope, v->toString(scope.engine));
- if (scope.hasException())
- return Encode::undefined();
+ CHECK_EXCEPTION();
+
PropertyAttributes attrs;
ScopedProperty desc(scope);
O->getOwnProperty(name, &attrs, desc);
- return fromPropertyDescriptor(scope.engine, desc, attrs);
+ scope.result = fromPropertyDescriptor(scope.engine, desc, attrs);
}
-ReturnedValue ObjectPrototype::method_getOwnPropertyNames(CallContext *context)
+void ObjectPrototype::method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(context);
- ScopedObject O(scope, context->argument(0));
- if (!O)
- return context->engine()->throwTypeError();
+ ScopedObject O(scope, callData->argument(0));
+ if (!O) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
- ScopedArrayObject array(scope, getOwnPropertyNames(context->d()->engine, context->args()[0]));
- return array.asReturnedValue();
+ scope.result = getOwnPropertyNames(scope.engine, callData->args[0]);
}
-ReturnedValue ObjectPrototype::method_create(CallContext *ctx)
+void ObjectPrototype::method_create(const BuiltinFunction *builtin, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue O(scope, ctx->argument(0));
- if (!O->isObject() && !O->isNull())
- return ctx->engine()->throwTypeError();
+ ScopedValue O(scope, callData->argument(0));
+ if (!O->isObject() && !O->isNull()) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
- ScopedObject newObject(scope, ctx->d()->engine->newObject());
+ ScopedObject newObject(scope, scope.engine->newObject());
newObject->setPrototype(O->as<Object>());
- if (ctx->argc() > 1 && !ctx->args()[1].isUndefined()) {
- ctx->d()->callData->args[0] = newObject.asReturnedValue();
- return method_defineProperties(ctx);
+ if (callData->argc > 1 && !callData->args[1].isUndefined()) {
+ callData->args[0] = newObject;
+ method_defineProperties(builtin, scope, callData);
+ return;
}
- return newObject.asReturnedValue();
+ scope.result = newObject;
}
-ReturnedValue ObjectPrototype::method_defineProperty(CallContext *ctx)
+void ObjectPrototype::method_defineProperty(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject O(scope, ctx->argument(0));
- if (!O)
- return ctx->engine()->throwTypeError();
+ ScopedObject O(scope, callData->argument(0));
+ if (!O) {
+ scope.result = scope.engine->throwTypeError();
+ return;
+ }
- ScopedString name(scope, ctx->argument(1), ScopedString::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedString name(scope, callData->argument(1), ScopedString::Convert);
+ CHECK_EXCEPTION();
- ScopedValue attributes(scope, ctx->argument(2));
+ ScopedValue attributes(scope, callData->argument(2));
ScopedProperty pd(scope);
PropertyAttributes attrs;
toPropertyDescriptor(scope.engine, attributes, pd, &attrs);
- if (scope.engine->hasException)
- return Encode::undefined();
+ CHECK_EXCEPTION();
if (!O->__defineOwnProperty__(scope.engine, name, pd, attrs))
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return O.asReturnedValue();
+ scope.result = O;
}
-ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx)
+void ObjectPrototype::method_defineProperties(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject O(scope, ctx->argument(0));
+ ScopedObject O(scope, callData->argument(0));
if (!O)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
+
+ ScopedObject o(scope, callData->argument(1), ScopedObject::Convert);
+ CHECK_EXCEPTION();
- ScopedObject o(scope, ctx->argument(1), ScopedObject::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
ScopedValue val(scope);
ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
@@ -230,26 +230,24 @@ ReturnedValue ObjectPrototype::method_defineProperties(CallContext *ctx)
PropertyAttributes nattrs;
val = o->getValue(pd->value, attrs);
toPropertyDescriptor(scope.engine, val, n, &nattrs);
- if (scope.engine->hasException)
- return Encode::undefined();
+ CHECK_EXCEPTION();
bool ok;
if (name)
ok = O->__defineOwnProperty__(scope.engine, name, n, nattrs);
else
ok = O->__defineOwnProperty__(scope.engine, index, n, nattrs);
if (!ok)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
}
- return O.asReturnedValue();
+ scope.result = O;
}
-ReturnedValue ObjectPrototype::method_seal(CallContext *ctx)
+void ObjectPrototype::method_seal(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
o->setInternalClass(o->internalClass()->sealed());
@@ -261,15 +259,14 @@ ReturnedValue ObjectPrototype::method_seal(CallContext *ctx)
}
}
- return o.asReturnedValue();
+ scope.result = o;
}
-ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx)
+void ObjectPrototype::method_freeze(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (ArgumentsObject::isNonStrictArgumentsObject(o))
static_cast<ArgumentsObject *>(o.getPointer())->fullyCreate();
@@ -285,96 +282,111 @@ ReturnedValue ObjectPrototype::method_freeze(CallContext *ctx)
o->arrayData()->attrs[i].setWritable(false);
}
}
- return o.asReturnedValue();
+ scope.result = o;
}
-ReturnedValue ObjectPrototype::method_preventExtensions(CallContext *ctx)
+void ObjectPrototype::method_preventExtensions(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
o->setInternalClass(o->internalClass()->nonExtensible());
- return o.asReturnedValue();
+ scope.result = o;
}
-ReturnedValue ObjectPrototype::method_isSealed(CallContext *ctx)
+void ObjectPrototype::method_isSealed(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- if (o->isExtensible())
- return Encode(false);
+ if (o->isExtensible()) {
+ scope.result = Encode(false);
+ return;
+ }
- if (o->internalClass() != o->internalClass()->sealed())
- return Encode(false);
+ if (o->internalClass() != o->internalClass()->sealed()) {
+ scope.result = Encode(false);
+ return;
+ }
- if (!o->arrayData() || !o->arrayData()->length())
- return Encode(true);
+ if (!o->arrayData() || !o->arrayData()->length()) {
+ scope.result = Encode(true);
+ return;
+ }
Q_ASSERT(o->arrayData() && o->arrayData()->length());
- if (!o->arrayData()->attrs)
- return Encode(false);
+ if (!o->arrayData()->attrs) {
+ scope.result = Encode(false);
+ return;
+ }
for (uint i = 0; i < o->arrayData()->alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
- if (o->arrayData()->attributes(i).isConfigurable())
- return Encode(false);
+ if (o->arrayData()->attributes(i).isConfigurable()) {
+ scope.result = Encode(false);
+ return;
+ }
}
- return Encode(true);
+ scope.result = Encode(true);
}
-ReturnedValue ObjectPrototype::method_isFrozen(CallContext *ctx)
+void ObjectPrototype::method_isFrozen(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- if (o->isExtensible())
- return Encode(false);
+ if (o->isExtensible()) {
+ scope.result = Encode(false);
+ return;
+ }
- if (o->internalClass() != o->internalClass()->frozen())
- return Encode(false);
+ if (o->internalClass() != o->internalClass()->frozen()) {
+ scope.result = Encode(false);
+ return;
+ }
- if (!o->arrayData() || !o->arrayData()->length())
- return Encode(true);
+ if (!o->arrayData() || !o->arrayData()->length()) {
+ scope.result = Encode(true);
+ return;
+ }
Q_ASSERT(o->arrayData() && o->arrayData()->length());
- if (!o->arrayData()->attrs)
- return Encode(false);
+ if (!o->arrayData()->attrs) {
+ scope.result = Encode(false);
+ return;
+ }
for (uint i = 0; i < o->arrayData()->alloc; ++i) {
if (!o->arrayData()->isEmpty(i))
- if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable())
- return Encode(false);
+ if (o->arrayData()->attributes(i).isConfigurable() || o->arrayData()->attributes(i).isWritable()) {
+ scope.result = Encode(false);
+ return;
+ }
}
- return Encode(true);
+ scope.result = Encode(true);
}
-ReturnedValue ObjectPrototype::method_isExtensible(CallContext *ctx)
+void ObjectPrototype::method_isExtensible(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode((bool)o->isExtensible());
+ scope.result = Encode((bool)o->isExtensible());
}
-ReturnedValue ObjectPrototype::method_keys(CallContext *ctx)
+void ObjectPrototype::method_keys(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->argument(0));
+ ScopedObject o(scope, callData->argument(0));
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedArrayObject a(scope, ctx->d()->engine->newArrayObject());
+ ScopedArrayObject a(scope, scope.engine->newArrayObject());
ObjectIterator it(scope, o, ObjectIterator::EnumerableOnly);
ScopedValue name(scope);
@@ -385,175 +397,159 @@ ReturnedValue ObjectPrototype::method_keys(CallContext *ctx)
a->push_back(name);
}
- return a.asReturnedValue();
+ scope.result = a;
}
-ReturnedValue ObjectPrototype::method_toString(CallContext *ctx)
+void ObjectPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- if (ctx->thisObject().isUndefined()) {
- return ctx->d()->engine->newString(QStringLiteral("[object Undefined]"))->asReturnedValue();
- } else if (ctx->thisObject().isNull()) {
- return ctx->d()->engine->newString(QStringLiteral("[object Null]"))->asReturnedValue();
+ if (callData->thisObject.isUndefined()) {
+ scope.result = scope.engine->newString(QStringLiteral("[object Undefined]"));
+ } else if (callData->thisObject.isNull()) {
+ scope.result = scope.engine->newString(QStringLiteral("[object Null]"));
} else {
- ScopedObject obj(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject obj(scope, callData->thisObject.toObject(scope.engine));
QString className = obj->className();
- return ctx->d()->engine->newString(QStringLiteral("[object %1]").arg(className))->asReturnedValue();
+ scope.result = scope.engine->newString(QStringLiteral("[object %1]").arg(className));
}
}
-ReturnedValue ObjectPrototype::method_toLocaleString(CallContext *ctx)
+void ObjectPrototype::method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->thisObject().toObject(scope.engine));
+ ScopedObject o(scope, callData->thisObject.toObject(scope.engine));
if (!o)
- return Encode::undefined();
- ScopedFunctionObject f(scope, o->get(ctx->d()->engine->id_toString()));
+ RETURN_UNDEFINED();
+
+ ScopedFunctionObject f(scope, o->get(scope.engine->id_toString()));
if (!f)
- return ctx->engine()->throwTypeError();
- ScopedCallData callData(scope);
- callData->thisObject = o;
+ THROW_TYPE_ERROR();
+ ScopedCallData cData(scope);
+ cData->thisObject = o;
f->call(scope, callData);
- return scope.result.asReturnedValue();
}
-ReturnedValue ObjectPrototype::method_valueOf(CallContext *ctx)
+void ObjectPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue v(scope, ctx->thisObject().toObject(scope.engine));
- if (ctx->d()->engine->hasException)
- return Encode::undefined();
- return v->asReturnedValue();
+ scope.result = callData->thisObject.toObject(scope.engine);
}
-ReturnedValue ObjectPrototype::method_hasOwnProperty(CallContext *ctx)
+void ObjectPrototype::method_hasOwnProperty(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedString P(scope, ctx->argument(0), ScopedString::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
- ScopedObject O(scope, ctx->thisObject(), ScopedObject::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedString P(scope, callData->argument(0), ScopedString::Convert);
+ CHECK_EXCEPTION();
+ ScopedObject O(scope, callData->thisObject, ScopedObject::Convert);
+ CHECK_EXCEPTION();
bool r = O->hasOwnProperty(P);
if (!r)
r = !O->query(P).isEmpty();
- return Encode(r);
+ scope.result = Encode(r);
}
-ReturnedValue ObjectPrototype::method_isPrototypeOf(CallContext *ctx)
+void ObjectPrototype::method_isPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject V(scope, ctx->argument(0));
- if (!V)
- return Encode(false);
+ ScopedObject V(scope, callData->argument(0));
+ if (!V) {
+ scope.result = Encode(false);
+ return;
+ }
- ScopedObject O(scope, ctx->thisObject(), ScopedObject::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedObject O(scope, callData->thisObject, ScopedObject::Convert);
+ CHECK_EXCEPTION();
ScopedObject proto(scope, V->prototype());
while (proto) {
- if (O->d() == proto->d())
- return Encode(true);
+ if (O->d() == proto->d()) {
+ scope.result = Encode(true);
+ return;
+ }
proto = proto->prototype();
}
- return Encode(false);
+ scope.result = Encode(false);
}
-ReturnedValue ObjectPrototype::method_propertyIsEnumerable(CallContext *ctx)
+void ObjectPrototype::method_propertyIsEnumerable(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedString p(scope, ctx->argument(0), ScopedString::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedString p(scope, callData->argument(0), ScopedString::Convert);
+ CHECK_EXCEPTION();
- ScopedObject o(scope, ctx->thisObject(), ScopedObject::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedObject o(scope, callData->thisObject, ScopedObject::Convert);
+ CHECK_EXCEPTION();
PropertyAttributes attrs;
o->getOwnProperty(p, &attrs);
- return Encode(attrs.isEnumerable());
+ scope.result = Encode(attrs.isEnumerable());
}
-ReturnedValue ObjectPrototype::method_defineGetter(CallContext *ctx)
+void ObjectPrototype::method_defineGetter(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 2)
- return ctx->engine()->throwTypeError();
+ if (callData->argc < 2)
+ THROW_TYPE_ERROR();
- Scope scope(ctx);
- ScopedFunctionObject f(scope, ctx->argument(1));
+ ScopedFunctionObject f(scope, callData->argument(1));
if (!f)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedString prop(scope, ctx->argument(0), ScopedString::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedString prop(scope, callData->argument(0), ScopedString::Convert);
+ CHECK_EXCEPTION();
- ScopedObject o(scope, ctx->thisObject());
+ ScopedObject o(scope, callData->thisObject);
if (!o) {
- if (!ctx->thisObject().isUndefined())
- return Encode::undefined();
- o = ctx->d()->engine->globalObject;
+ if (!callData->thisObject.isUndefined())
+ RETURN_UNDEFINED();
+ o = scope.engine->globalObject;
}
ScopedProperty pd(scope);
pd->value = f;
pd->set = Primitive::emptyValue();
o->__defineOwnProperty__(scope.engine, prop, pd, Attr_Accessor);
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue ObjectPrototype::method_defineSetter(CallContext *ctx)
+void ObjectPrototype::method_defineSetter(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 2)
- return ctx->engine()->throwTypeError();
+ if (callData->argc < 2)
+ THROW_TYPE_ERROR();
- Scope scope(ctx);
- ScopedFunctionObject f(scope, ctx->argument(1));
+ ScopedFunctionObject f(scope, callData->argument(1));
if (!f)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedString prop(scope, ctx->argument(0), ScopedString::Convert);
- if (scope.engine->hasException)
- return Encode::undefined();
+ ScopedString prop(scope, callData->argument(0), ScopedString::Convert);
+ CHECK_EXCEPTION();
- ScopedObject o(scope, ctx->thisObject());
+ ScopedObject o(scope, callData->thisObject);
if (!o) {
- if (!ctx->thisObject().isUndefined())
- return Encode::undefined();
- o = ctx->d()->engine->globalObject;
+ if (!callData->thisObject.isUndefined())
+ RETURN_UNDEFINED();
+ o = scope.engine->globalObject;
}
ScopedProperty pd(scope);
pd->value = Primitive::emptyValue();
pd->set = f;
o->__defineOwnProperty__(scope.engine, prop, pd, Attr_Accessor);
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue ObjectPrototype::method_get_proto(CallContext *ctx)
+void ObjectPrototype::method_get_proto(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->thisObject().as<Object>());
+ ScopedObject o(scope, callData->thisObject.as<Object>());
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return o->prototype()->asReturnedValue();
+ scope.result = o->prototype();
}
-ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx)
+void ObjectPrototype::method_set_proto(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedObject o(scope, ctx->thisObject());
- if (!o || !ctx->argc())
- return ctx->engine()->throwTypeError();
+ ScopedObject o(scope, callData->thisObject);
+ if (!o || !callData->argc)
+ THROW_TYPE_ERROR();
- if (ctx->args()[0].isNull()) {
+ if (callData->args[0].isNull()) {
o->setPrototype(0);
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
- ScopedObject p(scope, ctx->args()[0]);
+ ScopedObject p(scope, callData->args[0]);
bool ok = false;
if (!!p) {
if (o->prototype() == p->d()) {
@@ -562,9 +558,11 @@ ReturnedValue ObjectPrototype::method_set_proto(CallContext *ctx)
ok = o->setPrototype(p);
}
}
- if (!ok)
- return ctx->engine()->throwTypeError(QStringLiteral("Cyclic __proto__ value"));
- return Encode::undefined();
+ if (!ok) {
+ scope.result = scope.engine->throwTypeError(QStringLiteral("Cyclic __proto__ value"));
+ return;
+ }
+ RETURN_UNDEFINED();
}
void ObjectPrototype::toPropertyDescriptor(ExecutionEngine *engine, const Value &v, Property *desc, PropertyAttributes *attrs)
diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h
index e3d85782d5..1db8615511 100644
--- a/src/qml/jsruntime/qv4objectproto_p.h
+++ b/src/qml/jsruntime/qv4objectproto_p.h
@@ -78,32 +78,32 @@ struct ObjectPrototype: Object
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_getPrototypeOf(CallContext *ctx);
- static ReturnedValue method_getOwnPropertyDescriptor(CallContext *ctx);
- static ReturnedValue method_getOwnPropertyNames(CallContext *context);
- static ReturnedValue method_create(CallContext *ctx);
- static ReturnedValue method_defineProperty(CallContext *ctx);
- static ReturnedValue method_defineProperties(CallContext *ctx);
- static ReturnedValue method_seal(CallContext *ctx);
- static ReturnedValue method_freeze(CallContext *ctx);
- static ReturnedValue method_preventExtensions(CallContext *ctx);
- static ReturnedValue method_isSealed(CallContext *ctx);
- static ReturnedValue method_isFrozen(CallContext *ctx);
- static ReturnedValue method_isExtensible(CallContext *ctx);
- static ReturnedValue method_keys(CallContext *ctx);
-
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_toLocaleString(CallContext *ctx);
- static ReturnedValue method_valueOf(CallContext *ctx);
- static ReturnedValue method_hasOwnProperty(CallContext *ctx);
- static ReturnedValue method_isPrototypeOf(CallContext *ctx);
- static ReturnedValue method_propertyIsEnumerable(CallContext *ctx);
-
- static ReturnedValue method_defineGetter(CallContext *ctx);
- static ReturnedValue method_defineSetter(CallContext *ctx);
-
- static ReturnedValue method_get_proto(CallContext *ctx);
- static ReturnedValue method_set_proto(CallContext *ctx);
+ static void method_getPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getOwnPropertyDescriptor(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_getOwnPropertyNames(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_create(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_defineProperty(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_defineProperties(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_seal(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_freeze(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_preventExtensions(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isSealed(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isFrozen(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isExtensible(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_keys(const BuiltinFunction *, Scope &scope, CallData *callData);
+
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_hasOwnProperty(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_isPrototypeOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_propertyIsEnumerable(const BuiltinFunction *, Scope &scope, CallData *callData);
+
+ static void method_defineGetter(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_defineSetter(const BuiltinFunction *, Scope &scope, CallData *callData);
+
+ static void method_get_proto(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_set_proto(const BuiltinFunction *, Scope &scope, CallData *callData);
static void toPropertyDescriptor(ExecutionEngine *engine, const Value &v, Property *desc, PropertyAttributes *attrs);
static ReturnedValue fromPropertyDescriptor(ExecutionEngine *engine, const Property *desc, PropertyAttributes attrs);
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 77dbb18b50..7260e71fab 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -826,40 +826,39 @@ struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
} // namespace QV4
-ReturnedValue QObjectWrapper::method_connect(CallContext *ctx)
+void QObjectWrapper::method_connect(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() == 0)
- V4THROW_ERROR("Function.prototype.connect: no arguments given");
+ if (callData->argc == 0)
+ THROW_GENERIC_ERROR("Function.prototype.connect: no arguments given");
- QPair<QObject *, int> signalInfo = extractQtSignal(ctx->thisObject());
+ QPair<QObject *, int> signalInfo = extractQtSignal(callData->thisObject);
QObject *signalObject = signalInfo.first;
int signalIndex = signalInfo.second; // in method range, not signal range!
if (signalIndex < 0)
- V4THROW_ERROR("Function.prototype.connect: this object is not a signal");
+ THROW_GENERIC_ERROR("Function.prototype.connect: this object is not a signal");
if (!signalObject)
- V4THROW_ERROR("Function.prototype.connect: cannot connect to deleted QObject");
+ THROW_GENERIC_ERROR("Function.prototype.connect: cannot connect to deleted QObject");
if (signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
- V4THROW_ERROR("Function.prototype.connect: this object is not a signal");
+ THROW_GENERIC_ERROR("Function.prototype.connect: this object is not a signal");
- QV4::Scope scope(ctx);
QV4::ScopedFunctionObject f(scope);
QV4::ScopedValue thisObject (scope, QV4::Encode::undefined());
- if (ctx->argc() == 1) {
- f = ctx->args()[0];
- } else if (ctx->argc() >= 2) {
- thisObject = ctx->args()[0];
- f = ctx->args()[1];
+ if (callData->argc == 1) {
+ f = callData->args[0];
+ } else if (callData->argc >= 2) {
+ thisObject = callData->args[0];
+ f = callData->args[1];
}
if (!f)
- V4THROW_ERROR("Function.prototype.connect: target is not a function");
+ THROW_GENERIC_ERROR("Function.prototype.connect: target is not a function");
if (!thisObject->isUndefined() && !thisObject->isObject())
- V4THROW_ERROR("Function.prototype.connect: target this is not an object");
+ THROW_GENERIC_ERROR("Function.prototype.connect: target this is not an object");
QV4::QObjectSlotDispatcher *slot = new QV4::QObjectSlotDispatcher;
slot->signalIndex = signalIndex;
@@ -874,49 +873,47 @@ ReturnedValue QObjectWrapper::method_connect(CallContext *ctx)
}
QObjectPrivate::connect(signalObject, signalIndex, slot, Qt::AutoConnection);
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue QObjectWrapper::method_disconnect(CallContext *ctx)
+void QObjectWrapper::method_disconnect(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() == 0)
- V4THROW_ERROR("Function.prototype.disconnect: no arguments given");
-
- QV4::Scope scope(ctx);
+ if (callData->argc == 0)
+ THROW_GENERIC_ERROR("Function.prototype.disconnect: no arguments given");
- QPair<QObject *, int> signalInfo = extractQtSignal(ctx->thisObject());
+ QPair<QObject *, int> signalInfo = extractQtSignal(callData->thisObject);
QObject *signalObject = signalInfo.first;
int signalIndex = signalInfo.second;
if (signalIndex == -1)
- V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+ THROW_GENERIC_ERROR("Function.prototype.disconnect: this object is not a signal");
if (!signalObject)
- V4THROW_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject");
+ THROW_GENERIC_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject");
if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
- V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+ THROW_GENERIC_ERROR("Function.prototype.disconnect: this object is not a signal");
QV4::ScopedFunctionObject functionValue(scope);
QV4::ScopedValue functionThisValue(scope, QV4::Encode::undefined());
- if (ctx->argc() == 1) {
- functionValue = ctx->args()[0];
- } else if (ctx->argc() >= 2) {
- functionThisValue = ctx->args()[0];
- functionValue = ctx->args()[1];
+ if (callData->argc == 1) {
+ functionValue = callData->args[0];
+ } else if (callData->argc >= 2) {
+ functionThisValue = callData->args[0];
+ functionValue = callData->args[1];
}
if (!functionValue)
- V4THROW_ERROR("Function.prototype.disconnect: target is not a function");
+ THROW_GENERIC_ERROR("Function.prototype.disconnect: target is not a function");
if (!functionThisValue->isUndefined() && !functionThisValue->isObject())
- V4THROW_ERROR("Function.prototype.disconnect: target this is not an object");
+ THROW_GENERIC_ERROR("Function.prototype.disconnect: target this is not an object");
QPair<QObject *, int> functionData = QObjectMethod::extractQtMethod(functionValue);
void *a[] = {
- ctx->d()->engine,
+ scope.engine,
functionValue.ptr,
functionThisValue.ptr,
functionData.first,
@@ -925,7 +922,7 @@ ReturnedValue QObjectWrapper::method_disconnect(CallContext *ctx)
QObjectPrivate::disconnect(signalObject, signalIndex, reinterpret_cast<void**>(&a));
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
static void markChildQObjectsRecursively(QObject *parent, QV4::ExecutionEngine *e)
diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h
index c7c4f4dd77..b09e06cec5 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper_p.h
+++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h
@@ -197,8 +197,8 @@ protected:
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
static void markObjects(Heap::Base *that, QV4::ExecutionEngine *e);
- static ReturnedValue method_connect(CallContext *ctx);
- static ReturnedValue method_disconnect(CallContext *ctx);
+ static void method_connect(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_disconnect(const BuiltinFunction *, Scope &scope, CallData *callData);
private:
Q_NEVER_INLINE static ReturnedValue wrap_slowPath(ExecutionEngine *engine, QObject *object);
diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp
index 41d8010fef..40682aaa4b 100644
--- a/src/qml/jsruntime/qv4regexpobject.cpp
+++ b/src/qml/jsruntime/qv4regexpobject.cpp
@@ -349,34 +349,33 @@ void RegExpPrototype::init(ExecutionEngine *engine, Object *constructor)
defineDefaultProperty(QStringLiteral("compile"), method_compile, 2);
}
-ReturnedValue RegExpPrototype::method_exec(CallContext *ctx)
+void RegExpPrototype::method_exec(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<RegExpObject> r(scope, ctx->thisObject().as<RegExpObject>());
+ Scoped<RegExpObject> r(scope, callData->thisObject.as<RegExpObject>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedValue arg(scope, ctx->argument(0));
+ ScopedValue arg(scope, callData->argument(0));
ScopedString str(scope, arg->toString(scope.engine));
if (scope.hasException())
- return Encode::undefined();
+ RETURN_UNDEFINED();
QString s = str->toQString();
int offset = r->global() ? r->lastIndexProperty()->toInt32() : 0;
if (offset < 0 || offset > s.length()) {
*r->lastIndexProperty() = Primitive::fromInt32(0);
- return Encode::null();
+ RETURN_RESULT(Encode::null());
}
uint* matchOffsets = (uint*)alloca(r->value()->captureCount() * 2 * sizeof(uint));
const int result = Scoped<RegExp>(scope, r->value())->match(s, offset, matchOffsets);
- Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor());
+ Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor());
regExpCtor->d()->clearLastMatch();
if (result == -1) {
*r->lastIndexProperty() = Primitive::fromInt32(0);
- return Encode::null();
+ RETURN_RESULT(Encode::null());
}
// fill in result data
@@ -387,7 +386,7 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx)
for (int i = 0; i < len; ++i) {
int start = matchOffsets[i * 2];
int end = matchOffsets[i * 2 + 1];
- v = (start != -1) ? ctx->d()->engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined();
+ v = (start != -1) ? scope.engine->newString(s.mid(start, end - start))->asReturnedValue() : Encode::undefined();
array->arrayPut(i, v);
}
array->setArrayLengthUnchecked(len);
@@ -403,84 +402,75 @@ ReturnedValue RegExpPrototype::method_exec(CallContext *ctx)
if (r->global())
*r->lastIndexProperty() = Primitive::fromInt32(matchOffsets[1]);
- return array.asReturnedValue();
+ scope.result = array;
}
-ReturnedValue RegExpPrototype::method_test(CallContext *ctx)
+void RegExpPrototype::method_test(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue r(scope, method_exec(ctx));
- return Encode(!r->isNull());
+ method_exec(b, scope, callData);
+ scope.result = Encode(!scope.result.isNull());
}
-ReturnedValue RegExpPrototype::method_toString(CallContext *ctx)
+void RegExpPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<RegExpObject> r(scope, ctx->thisObject().as<RegExpObject>());
+ Scoped<RegExpObject> r(scope, callData->thisObject.as<RegExpObject>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return ctx->d()->engine->newString(r->toString())->asReturnedValue();
+ scope.result = scope.engine->newString(r->toString());
}
-ReturnedValue RegExpPrototype::method_compile(CallContext *ctx)
+void RegExpPrototype::method_compile(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<RegExpObject> r(scope, ctx->thisObject().as<RegExpObject>());
+ Scoped<RegExpObject> r(scope, callData->thisObject.as<RegExpObject>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- ScopedCallData callData(scope, ctx->argc());
- memcpy(callData->args, ctx->args(), ctx->argc()*sizeof(Value));
+ ScopedCallData cData(scope, callData->argc);
+ memcpy(cData->args, callData->args, callData->argc*sizeof(Value));
- ctx->d()->engine->regExpCtor()->as<FunctionObject>()->construct(scope, callData);
+ scope.engine->regExpCtor()->as<FunctionObject>()->construct(scope, cData);
Scoped<RegExpObject> re(scope, scope.result.asReturnedValue());
r->d()->value = re->value();
r->d()->global = re->global();
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
template <int index>
-ReturnedValue RegExpPrototype::method_get_lastMatch_n(CallContext *ctx)
+void RegExpPrototype::method_get_lastMatch_n(const BuiltinFunction *, Scope &scope, CallData *)
{
- Scope scope(ctx);
- ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastMatch());
- ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(index) : Encode::undefined());
- if (result->isUndefined())
- return ctx->d()->engine->newString()->asReturnedValue();
- return result->asReturnedValue();
+ ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(scope.engine->regExpCtor())->lastMatch());
+ scope.result = lastMatch ? lastMatch->getIndexed(index) : Encode::undefined();
+ if (scope.result.isUndefined())
+ scope.result = scope.engine->newString();
}
-ReturnedValue RegExpPrototype::method_get_lastParen(CallContext *ctx)
+void RegExpPrototype::method_get_lastParen(const BuiltinFunction *, Scope &scope, CallData *)
{
- Scope scope(ctx);
- ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastMatch());
- ScopedValue result(scope, lastMatch ? lastMatch->getIndexed(lastMatch->getLength() - 1) : Encode::undefined());
- if (result->isUndefined())
- return ctx->d()->engine->newString()->asReturnedValue();
- return result->asReturnedValue();
+ ScopedArrayObject lastMatch(scope, static_cast<RegExpCtor*>(scope.engine->regExpCtor())->lastMatch());
+ scope.result = lastMatch ? lastMatch->getIndexed(lastMatch->getLength() - 1) : Encode::undefined();
+ if (scope.result.isUndefined())
+ scope.result = scope.engine->newString();
}
-ReturnedValue RegExpPrototype::method_get_input(CallContext *ctx)
+void RegExpPrototype::method_get_input(const BuiltinFunction *, Scope &scope, CallData *)
{
- return static_cast<RegExpCtor*>(ctx->d()->engine->regExpCtor())->lastInput()->asReturnedValue();
+ scope.result = static_cast<RegExpCtor*>(scope.engine->regExpCtor())->lastInput();
}
-ReturnedValue RegExpPrototype::method_get_leftContext(CallContext *ctx)
+void RegExpPrototype::method_get_leftContext(const BuiltinFunction *, Scope &scope, CallData *)
{
- Scope scope(ctx);
- Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor());
+ Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor());
QString lastInput = regExpCtor->lastInput()->toQString();
- return ctx->d()->engine->newString(lastInput.left(regExpCtor->lastMatchStart()))->asReturnedValue();
+ scope.result = scope.engine->newString(lastInput.left(regExpCtor->lastMatchStart()));
}
-ReturnedValue RegExpPrototype::method_get_rightContext(CallContext *ctx)
+void RegExpPrototype::method_get_rightContext(const BuiltinFunction *, Scope &scope, CallData *)
{
- Scope scope(ctx);
- Scoped<RegExpCtor> regExpCtor(scope, ctx->d()->engine->regExpCtor());
+ Scoped<RegExpCtor> regExpCtor(scope, scope.engine->regExpCtor());
QString lastInput = regExpCtor->lastInput()->toQString();
- return ctx->d()->engine->newString(lastInput.mid(regExpCtor->lastMatchEnd()))->asReturnedValue();
+ scope.result = scope.engine->newString(lastInput.mid(regExpCtor->lastMatchEnd()));
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h
index 2c82cfdfd1..c0c7dfa78a 100644
--- a/src/qml/jsruntime/qv4regexpobject_p.h
+++ b/src/qml/jsruntime/qv4regexpobject_p.h
@@ -149,17 +149,17 @@ struct RegExpPrototype: RegExpObject
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_exec(CallContext *ctx);
- static ReturnedValue method_test(CallContext *ctx);
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_compile(CallContext *ctx);
+ static void method_exec(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_test(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_compile(const BuiltinFunction *, Scope &scope, CallData *callData);
template <int index>
- static ReturnedValue method_get_lastMatch_n(CallContext *ctx);
- static ReturnedValue method_get_lastParen(CallContext *ctx);
- static ReturnedValue method_get_input(CallContext *ctx);
- static ReturnedValue method_get_leftContext(CallContext *ctx);
- static ReturnedValue method_get_rightContext(CallContext *ctx);
+ static void method_get_lastMatch_n(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_lastParen(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_input(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_leftContext(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_rightContext(const BuiltinFunction *, Scope &scope, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 023a739e33..7f184f8221 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -343,35 +343,15 @@ ReturnedValue Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex)
return Encode(engine->currentContext->deleteProperty(name));
}
-QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &left, const Value &right)
+QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &lval, const Value &rval)
{
- const FunctionObject *function = right.as<FunctionObject>();
- if (!function)
- return engine->throwTypeError();
-
- Heap::FunctionObject *f = function->d();
- if (function->isBoundFunction())
- f = function->cast<BoundFunction>()->target();
-
- const Object *o = left.as<Object>();
- if (!o)
- return Encode(false);
- Heap::Object *v = o->d();
-
- o = f->protoProperty();
- if (!o)
- return engine->throwTypeError();
-
- while (v) {
- v = v->prototype;
-
- if (!v)
- break;
- else if (o->d() == v)
- return Encode(true);
- }
+ // 11.8.6, 5: rval must be an Object
+ const Object *rhs = rval.as<Object>();
+ if (!rhs)
+ return engine->throwTypeError();
- return Encode(false);
+ // 11.8.6, 7: call "HasInstance", which we term instanceOf, and return the result.
+ return rhs->instanceOf(lval);
}
QV4::ReturnedValue Runtime::method_in(ExecutionEngine *engine, const Value &left, const Value &right)
diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h
index 4e627e003f..6775028272 100644
--- a/src/qml/jsruntime/qv4scopedvalue_p.h
+++ b/src/qml/jsruntime/qv4scopedvalue_p.h
@@ -68,6 +68,38 @@ namespace QV4 {
struct ScopedValue;
+#define CHECK_EXCEPTION() \
+ do { \
+ if (scope.hasException()) { \
+ scope.result = QV4::Encode::undefined(); \
+ return; \
+ } \
+ } while (false)
+
+#define RETURN_UNDEFINED() \
+ do { \
+ scope.result = QV4::Encode::undefined(); \
+ return; \
+ } while (false)
+
+#define RETURN_RESULT(r) \
+ do { \
+ scope.result = r; \
+ return; \
+ } while (false)
+
+#define THROW_TYPE_ERROR() \
+ do { \
+ scope.result = scope.engine->throwTypeError(); \
+ return; \
+ } while (false)
+
+#define THROW_GENERIC_ERROR(str) \
+ do { \
+ scope.result = scope.engine->throwError(QString::fromUtf8(str)); \
+ return; \
+ } while (false)
+
struct Scope {
inline Scope(ExecutionContext *ctx)
: engine(ctx->d()->engine)
diff --git a/src/qml/jsruntime/qv4sequenceobject.cpp b/src/qml/jsruntime/qv4sequenceobject.cpp
index 58da7b9f68..8ce10e326d 100644
--- a/src/qml/jsruntime/qv4sequenceobject.cpp
+++ b/src/qml/jsruntime/qv4sequenceobject.cpp
@@ -404,28 +404,28 @@ public:
struct CompareFunctor
{
- CompareFunctor(QV4::ExecutionContext *ctx, const QV4::Value &compareFn)
- : m_ctx(ctx), m_compareFn(&compareFn)
+ CompareFunctor(QV4::ExecutionEngine *v4, const QV4::Value &compareFn)
+ : m_v4(v4), m_compareFn(&compareFn)
{}
bool operator()(typename Container::value_type lhs, typename Container::value_type rhs)
{
- QV4::Scope scope(m_ctx);
+ QV4::Scope scope(m_v4);
ScopedObject compare(scope, m_compareFn);
ScopedCallData callData(scope, 2);
- callData->args[0] = convertElementToValue(this->m_ctx->d()->engine, lhs);
- callData->args[1] = convertElementToValue(this->m_ctx->d()->engine, rhs);
- callData->thisObject = this->m_ctx->d()->engine->globalObject;
+ callData->args[0] = convertElementToValue(m_v4, lhs);
+ callData->args[1] = convertElementToValue(m_v4, rhs);
+ callData->thisObject = m_v4->globalObject;
compare->call(scope, callData);
return scope.result.toNumber() < 0;
}
private:
- QV4::ExecutionContext *m_ctx;
+ QV4::ExecutionEngine *m_v4;
const QV4::Value *m_compareFn;
};
- void sort(QV4::CallContext *ctx)
+ void sort(const BuiltinFunction *, Scope &scope, CallData *callData)
{
if (d()->isReference) {
if (!d()->object)
@@ -433,9 +433,8 @@ public:
loadReference();
}
- QV4::Scope scope(ctx);
- if (ctx->argc() == 1 && ctx->args()[0].as<FunctionObject>()) {
- CompareFunctor cf(ctx, ctx->args()[0]);
+ if (callData->argc == 1 && callData->args[0].as<FunctionObject>()) {
+ CompareFunctor cf(scope.engine, callData->args[0]);
std::sort(d()->container->begin(), d()->container->end(), cf);
} else {
DefaultCompareFunctor cf;
@@ -446,45 +445,43 @@ public:
storeReference();
}
- static QV4::ReturnedValue method_get_length(QV4::CallContext *ctx)
+ static void method_get_length(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->thisObject().as<QQmlSequence<Container> >());
+ QV4::Scoped<QQmlSequence<Container> > This(scope, callData->thisObject.as<QQmlSequence<Container> >());
if (!This)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (This->d()->isReference) {
if (!This->d()->object)
- return QV4::Encode(0);
+ RETURN_RESULT(Encode(0));
This->loadReference();
}
- return QV4::Encode(This->d()->container->count());
+ RETURN_RESULT(Encode(This->d()->container->count()));
}
- static QV4::ReturnedValue method_set_length(QV4::CallContext* ctx)
+ static void method_set_length(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlSequence<Container> > This(scope, ctx->thisObject().as<QQmlSequence<Container> >());
+ QV4::Scoped<QQmlSequence<Container> > This(scope, callData->thisObject.as<QQmlSequence<Container> >());
if (!This)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- quint32 newLength = ctx->args()[0].toUInt32();
+ quint32 newLength = callData->args[0].toUInt32();
/* Qt containers have int (rather than uint) allowable indexes. */
if (newLength > INT_MAX) {
generateWarning(scope.engine, QLatin1String("Index out of range during length set"));
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
/* Read the sequence from the QObject property if we're a reference */
if (This->d()->isReference) {
if (!This->d()->object)
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
This->loadReference();
}
/* Determine whether we need to modify the sequence */
qint32 newCount = static_cast<qint32>(newLength);
qint32 count = This->d()->container->count();
if (newCount == count) {
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
} else if (newCount > count) {
/* according to ECMA262r3 we need to insert */
/* undefined values increasing length to newLength. */
@@ -506,7 +503,7 @@ public:
/* write back. already checked that object is non-null, so skip that check here. */
This->storeReference();
}
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
QVariant toVariant() const
@@ -625,26 +622,25 @@ void SequencePrototype::init()
}
#undef REGISTER_QML_SEQUENCE_METATYPE
-QV4::ReturnedValue SequencePrototype::method_sort(QV4::CallContext *ctx)
+void SequencePrototype::method_sort(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::ScopedObject o(scope, ctx->thisObject());
+ QV4::ScopedObject o(scope, callData->thisObject);
if (!o || !o->isListType())
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- if (ctx->argc() >= 2)
- return o.asReturnedValue();
+ if (callData->argc >= 2)
+ RETURN_RESULT(o);
#define CALL_SORT(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue) \
if (QQml##SequenceElementTypeName##List *s = o->as<QQml##SequenceElementTypeName##List>()) { \
- s->sort(ctx); \
+ s->sort(b, scope, callData); \
} else
FOREACH_QML_SEQUENCE_TYPE(CALL_SORT)
#undef CALL_SORT
{}
- return o.asReturnedValue();
+ RETURN_RESULT(o);
}
#define IS_SEQUENCE(unused1, unused2, SequenceType, unused3) \
diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h
index c0416ad639..6f96b9f760 100644
--- a/src/qml/jsruntime/qv4sequenceobject_p.h
+++ b/src/qml/jsruntime/qv4sequenceobject_p.h
@@ -67,12 +67,12 @@ struct SequencePrototype : public QV4::Object
{
void init();
- static ReturnedValue method_valueOf(QV4::CallContext *ctx)
+ static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- return ctx->thisObject().toString(ctx->engine())->asReturnedValue();
+ scope.result = callData->thisObject.toString(scope.engine);
}
- static ReturnedValue method_sort(QV4::CallContext *ctx);
+ static void method_sort(const BuiltinFunction *, Scope &scope, CallData *callData);
static bool isSequenceType(int sequenceTypeId);
static ReturnedValue newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded);
diff --git a/src/qml/jsruntime/qv4stringobject.cpp b/src/qml/jsruntime/qv4stringobject.cpp
index 6fbf1c3c85..3c6a24e035 100644
--- a/src/qml/jsruntime/qv4stringobject.cpp
+++ b/src/qml/jsruntime/qv4stringobject.cpp
@@ -214,10 +214,9 @@ void StringPrototype::init(ExecutionEngine *engine, Object *ctor)
defineDefaultProperty(QStringLiteral("trim"), method_trim);
}
-static QString getThisString(ExecutionContext *ctx)
+static QString getThisString(Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- ScopedValue t(scope, ctx->thisObject());
+ ScopedValue t(scope, callData->thisObject);
if (String *s = t->stringValue())
return s->toQString();
if (StringObject *thisString = t->as<StringObject>())
@@ -229,158 +228,146 @@ static QString getThisString(ExecutionContext *ctx)
return t->toQString();
}
-ReturnedValue StringPrototype::method_toString(CallContext *context)
+void StringPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (context->thisObject().isString())
- return context->thisObject().asReturnedValue();
+ if (callData->thisObject.isString())
+ RETURN_RESULT(callData->thisObject);
- StringObject *o = context->thisObject().as<StringObject>();
+ StringObject *o = callData->thisObject.as<StringObject>();
if (!o)
- return context->engine()->throwTypeError();
- return Encode(o->d()->string);
+ THROW_TYPE_ERROR();
+ scope.result = o->d()->string;
}
-ReturnedValue StringPrototype::method_charAt(CallContext *context)
+void StringPrototype::method_charAt(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- const QString str = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ const QString str = getThisString(scope, callData);
+ CHECK_EXCEPTION();
int pos = 0;
- if (context->argc() > 0)
- pos = (int) context->args()[0].toInteger();
+ if (callData->argc > 0)
+ pos = (int) callData->args[0].toInteger();
QString result;
if (pos >= 0 && pos < str.length())
result += str.at(pos);
- return context->d()->engine->newString(result)->asReturnedValue();
+ scope.result = scope.engine->newString(result);
}
-ReturnedValue StringPrototype::method_charCodeAt(CallContext *context)
+void StringPrototype::method_charCodeAt(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- const QString str = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ const QString str = getThisString(scope, callData);
+ CHECK_EXCEPTION();
int pos = 0;
- if (context->argc() > 0)
- pos = (int) context->args()[0].toInteger();
+ if (callData->argc > 0)
+ pos = (int) callData->args[0].toInteger();
if (pos >= 0 && pos < str.length())
- return Encode(str.at(pos).unicode());
+ RETURN_RESULT(Encode(str.at(pos).unicode()));
- return Encode(qt_qnan());
+ scope.result = Encode(qt_qnan());
}
-ReturnedValue StringPrototype::method_concat(CallContext *context)
+void StringPrototype::method_concat(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(context);
-
- QString value = getThisString(context);
- if (scope.engine->hasException)
- return Encode::undefined();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
ScopedString s(scope);
- for (int i = 0; i < context->argc(); ++i) {
- s = context->args()[i].toString(scope.engine);
- if (scope.hasException())
- return Encode::undefined();
+ for (int i = 0; i < callData->argc; ++i) {
+ s = callData->args[i].toString(scope.engine);
+ CHECK_EXCEPTION();
+
Q_ASSERT(s->isString());
value += s->toQString();
}
- return context->d()->engine->newString(value)->asReturnedValue();
+ scope.result = scope.engine->newString(value);
}
-ReturnedValue StringPrototype::method_endsWith(CallContext *context)
+void StringPrototype::method_endsWith(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString value = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
QString searchString;
- if (context->argc()) {
- if (context->args()[0].as<RegExpObject>())
- return context->engine()->throwTypeError();
- searchString = context->args()[0].toQString();
+ if (callData->argc) {
+ if (callData->args[0].as<RegExpObject>())
+ THROW_TYPE_ERROR();
+ searchString = callData->args[0].toQString();
}
int pos = value.length();
- if (context->argc() > 1)
- pos = (int) context->args()[1].toInteger();
+ if (callData->argc > 1)
+ pos = (int) callData->args[1].toInteger();
if (pos == value.length())
- return Encode(value.endsWith(searchString));
+ RETURN_RESULT(Encode(value.endsWith(searchString)));
QStringRef stringToSearch = value.leftRef(pos);
- return Encode(stringToSearch.endsWith(searchString));
+ scope.result = Encode(stringToSearch.endsWith(searchString));
}
-ReturnedValue StringPrototype::method_indexOf(CallContext *context)
+void StringPrototype::method_indexOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString value = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
QString searchString;
- if (context->argc())
- searchString = context->args()[0].toQString();
+ if (callData->argc)
+ searchString = callData->args[0].toQString();
int pos = 0;
- if (context->argc() > 1)
- pos = (int) context->args()[1].toInteger();
+ if (callData->argc > 1)
+ pos = (int) callData->args[1].toInteger();
int index = -1;
if (! value.isEmpty())
index = value.indexOf(searchString, qMin(qMax(pos, 0), value.length()));
- return Encode(index);
+ scope.result = Encode(index);
}
-ReturnedValue StringPrototype::method_includes(CallContext *context)
+void StringPrototype::method_includes(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString value = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
QString searchString;
- if (context->argc()) {
- if (context->args()[0].as<RegExpObject>())
- return context->engine()->throwTypeError();
- searchString = context->args()[0].toQString();
+ if (callData->argc) {
+ if (callData->args[0].as<RegExpObject>())
+ THROW_TYPE_ERROR();
+ searchString = callData->args[0].toQString();
}
int pos = 0;
- if (context->argc() > 1) {
- Scope scope(context);
- ScopedValue posArg(scope, context->argument(1));
+ if (callData->argc > 1) {
+ ScopedValue posArg(scope, callData->argument(1));
pos = (int) posArg->toInteger();
if (!posArg->isInteger() && posArg->isNumber() && qIsInf(posArg->toNumber()))
pos = value.length();
}
if (pos == 0)
- return Encode(value.contains(searchString));
+ RETURN_RESULT(Encode(value.contains(searchString)));
QStringRef stringToSearch = value.midRef(pos);
- return Encode(stringToSearch.contains(searchString));
+ scope.result = Encode(stringToSearch.contains(searchString));
}
-ReturnedValue StringPrototype::method_lastIndexOf(CallContext *context)
+void StringPrototype::method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(context);
-
- const QString value = getThisString(context);
- if (scope.engine->hasException)
- return Encode::undefined();
+ const QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
QString searchString;
- if (context->argc())
- searchString = context->args()[0].toQString();
+ if (callData->argc)
+ searchString = callData->args[0].toQString();
- ScopedValue posArg(scope, context->argument(1));
+ ScopedValue posArg(scope, callData->argument(1));
double position = RuntimeHelpers::toNumber(posArg);
if (std::isnan(position))
position = +qInf();
@@ -391,43 +378,40 @@ ReturnedValue StringPrototype::method_lastIndexOf(CallContext *context)
if (!searchString.isEmpty() && pos == value.length())
--pos;
if (searchString.isNull() && pos == 0)
- return Encode(-1);
+ RETURN_RESULT(Encode(-1));
int index = value.lastIndexOf(searchString, pos);
- return Encode(index);
+ scope.result = Encode(index);
}
-ReturnedValue StringPrototype::method_localeCompare(CallContext *context)
+void StringPrototype::method_localeCompare(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(context);
- const QString value = getThisString(context);
- if (scope.engine->hasException)
- return Encode::undefined();
+ const QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
- ScopedValue v(scope, context->argument(0));
+ ScopedValue v(scope, callData->argument(0));
const QString that = v->toQString();
- return Encode(QString::localeAwareCompare(value, that));
+ scope.result = Encode(QString::localeAwareCompare(value, that));
}
-ReturnedValue StringPrototype::method_match(CallContext *context)
+void StringPrototype::method_match(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (context->thisObject().isUndefined() || context->thisObject().isNull())
- return context->engine()->throwTypeError();
+ if (callData->thisObject.isUndefined() || callData->thisObject.isNull())
+ THROW_TYPE_ERROR();
- Scope scope(context);
- ScopedString s(scope, context->thisObject().toString(scope.engine));
+ ScopedString s(scope, callData->thisObject.toString(scope.engine));
- ScopedValue regexp(scope, context->argument(0));
+ ScopedValue regexp(scope, callData->argument(0));
Scoped<RegExpObject> rx(scope, regexp);
if (!rx) {
ScopedCallData callData(scope, 1);
callData->args[0] = regexp;
- context->d()->engine->regExpCtor()->construct(scope, callData);
+ scope.engine->regExpCtor()->construct(scope, callData);
rx = scope.result.asReturnedValue();
}
if (!rx)
// ### CHECK
- return context->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
bool global = rx->global();
@@ -435,24 +419,24 @@ ReturnedValue StringPrototype::method_match(CallContext *context)
ScopedString execString(scope, scope.engine->newString(QStringLiteral("exec")));
ScopedFunctionObject exec(scope, scope.engine->regExpPrototype()->get(execString));
- ScopedCallData callData(scope, 1);
- callData->thisObject = rx;
- callData->args[0] = s;
+ ScopedCallData cData(scope, 1);
+ cData->thisObject = rx;
+ cData->args[0] = s;
if (!global) {
- exec->call(scope, callData);
- return scope.result.asReturnedValue();
+ exec->call(scope, cData);
+ return;
}
- ScopedString lastIndex(scope, context->d()->engine->newString(QStringLiteral("lastIndex")));
+ ScopedString lastIndex(scope, scope.engine->newString(QStringLiteral("lastIndex")));
rx->put(lastIndex, ScopedValue(scope, Primitive::fromInt32(0)));
- ScopedArrayObject a(scope, context->d()->engine->newArrayObject());
+ ScopedArrayObject a(scope, scope.engine->newArrayObject());
double previousLastIndex = 0;
uint n = 0;
ScopedValue matchStr(scope);
ScopedValue index(scope);
while (1) {
- exec->call(scope, callData);
+ exec->call(scope, cData);
if (scope.result.isNull())
break;
assert(scope.result.isObject());
@@ -469,10 +453,9 @@ ReturnedValue StringPrototype::method_match(CallContext *context)
++n;
}
if (!n)
- return Encode::null();
-
- return a.asReturnedValue();
-
+ scope.result = Encode::null();
+ else
+ scope.result = a;
}
static void appendReplacementString(QString *result, const QString &input, const QString& replaceValue, uint* matchOffsets, int captureCount)
@@ -521,14 +504,13 @@ static void appendReplacementString(QString *result, const QString &input, const
}
}
-ReturnedValue StringPrototype::method_replace(CallContext *ctx)
+void StringPrototype::method_replace(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
QString string;
- if (StringObject *thisString = ctx->thisObject().as<StringObject>())
+ if (StringObject *thisString = callData->thisObject.as<StringObject>())
string = thisString->d()->string->toQString();
else
- string = ctx->thisObject().toQString();
+ string = callData->thisObject.toQString();
int numCaptures = 0;
int numStringMatches = 0;
@@ -537,7 +519,7 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
uint _matchOffsets[64];
uint *matchOffsets = _matchOffsets;
- ScopedValue searchValue(scope, ctx->argument(0));
+ ScopedValue searchValue(scope, callData->argument(0));
Scoped<RegExpObject> regExp(scope, searchValue);
if (regExp) {
uint offset = 0;
@@ -580,7 +562,7 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
}
QString result;
- ScopedValue replaceValue(scope, ctx->argument(1));
+ ScopedValue replaceValue(scope, callData->argument(1));
ScopedFunctionObject searchCallback(scope, replaceValue);
if (!!searchCallback) {
result.reserve(string.length() + 10*numStringMatches);
@@ -595,14 +577,14 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
uint end = matchOffsets[idx + 1];
entry = Primitive::undefinedValue();
if (start != JSC::Yarr::offsetNoMatch && end != JSC::Yarr::offsetNoMatch)
- entry = ctx->d()->engine->newString(string.mid(start, end - start));
+ entry = scope.engine->newString(string.mid(start, end - start));
callData->args[k] = entry;
}
uint matchStart = matchOffsets[i * numCaptures * 2];
Q_ASSERT(matchStart >= static_cast<uint>(lastEnd));
uint matchEnd = matchOffsets[i * numCaptures * 2 + 1];
callData->args[numCaptures] = Primitive::fromUInt32(matchStart);
- callData->args[numCaptures + 1] = ctx->d()->engine->newString(string);
+ callData->args[numCaptures + 1] = scope.engine->newString(string);
searchCallback->call(scope, callData);
result += string.midRef(lastEnd, matchStart - lastEnd);
@@ -632,23 +614,22 @@ ReturnedValue StringPrototype::method_replace(CallContext *ctx)
if (matchOffsets != _matchOffsets)
free(matchOffsets);
- return ctx->d()->engine->newString(result)->asReturnedValue();
+ scope.result = scope.engine->newString(result);
}
-ReturnedValue StringPrototype::method_search(CallContext *ctx)
+void StringPrototype::method_search(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- QString string = getThisString(ctx);
- scope.result = ctx->argument(0);
- if (scope.engine->hasException)
- return Encode::undefined();
+ QString string = getThisString(scope, callData);
+ scope.result = callData->argument(0);
+ CHECK_EXCEPTION();
+
Scoped<RegExpObject> regExp(scope, scope.result.as<RegExpObject>());
if (!regExp) {
ScopedCallData callData(scope, 1);
callData->args[0] = scope.result;
- ctx->d()->engine->regExpCtor()->construct(scope, callData);
- if (scope.engine->hasException)
- return Encode::undefined();
+ scope.engine->regExpCtor()->construct(scope, callData);
+ CHECK_EXCEPTION();
+
regExp = scope.result.as<RegExpObject>();
Q_ASSERT(regExp);
}
@@ -656,21 +637,21 @@ ReturnedValue StringPrototype::method_search(CallContext *ctx)
uint* matchOffsets = (uint*)alloca(regExp->value()->captureCount() * 2 * sizeof(uint));
uint result = re->match(string, /*offset*/0, matchOffsets);
if (result == JSC::Yarr::offsetNoMatch)
- return Encode(-1);
- return Encode(result);
+ scope.result = Encode(-1);
+ else
+ scope.result = Encode(result);
}
-ReturnedValue StringPrototype::method_slice(CallContext *ctx)
+void StringPrototype::method_slice(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- const QString text = getThisString(ctx);
- if (ctx->d()->engine->hasException)
- return Encode::undefined();
+ const QString text = getThisString(scope, callData);
+ CHECK_EXCEPTION();
const double length = text.length();
- double start = ctx->argc() ? ctx->args()[0].toInteger() : 0;
- double end = (ctx->argc() < 2 || ctx->args()[1].isUndefined())
- ? length : ctx->args()[1].toInteger();
+ double start = callData->argc ? callData->args[0].toInteger() : 0;
+ double end = (callData->argc < 2 || callData->args[1].isUndefined())
+ ? length : callData->args[1].toInteger();
if (start < 0)
start = qMax(length + start, 0.);
@@ -686,40 +667,38 @@ ReturnedValue StringPrototype::method_slice(CallContext *ctx)
const int intEnd = int(end);
int count = qMax(0, intEnd - intStart);
- return ctx->d()->engine->newString(text.mid(intStart, count))->asReturnedValue();
+ scope.result = scope.engine->newString(text.mid(intStart, count));
}
-ReturnedValue StringPrototype::method_split(CallContext *ctx)
+void StringPrototype::method_split(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- QString text = getThisString(ctx);
- if (scope.engine->hasException)
- return Encode::undefined();
+ QString text = getThisString(scope, callData);
+ CHECK_EXCEPTION();
- ScopedValue separatorValue(scope, ctx->argument(0));
- ScopedValue limitValue(scope, ctx->argument(1));
+ ScopedValue separatorValue(scope, callData->argument(0));
+ ScopedValue limitValue(scope, callData->argument(1));
- ScopedArrayObject array(scope, ctx->d()->engine->newArrayObject());
+ ScopedArrayObject array(scope, scope.engine->newArrayObject());
if (separatorValue->isUndefined()) {
if (limitValue->isUndefined()) {
- ScopedString s(scope, ctx->d()->engine->newString(text));
+ ScopedString s(scope, scope.engine->newString(text));
array->push_back(s);
- return array.asReturnedValue();
+ RETURN_RESULT(array);
}
- return ctx->d()->engine->newString(text.left(limitValue->toInteger()))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(text.left(limitValue->toInteger())));
}
uint limit = limitValue->isUndefined() ? UINT_MAX : limitValue->toUInt32();
if (limit == 0)
- return array.asReturnedValue();
+ RETURN_RESULT(array);
Scoped<RegExpObject> re(scope, separatorValue);
if (re) {
if (re->value()->pattern->isEmpty()) {
re = (RegExpObject *)0;
- separatorValue = ctx->d()->engine->newString();
+ separatorValue = scope.engine->newString();
}
}
@@ -733,7 +712,7 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx)
if (result == JSC::Yarr::offsetNoMatch)
break;
- array->push_back((s = ctx->d()->engine->newString(text.mid(offset, matchOffsets[0] - offset))));
+ array->push_back((s = scope.engine->newString(text.mid(offset, matchOffsets[0] - offset))));
offset = qMax(offset + 1, matchOffsets[1]);
if (array->getLength() >= limit)
@@ -742,72 +721,70 @@ ReturnedValue StringPrototype::method_split(CallContext *ctx)
for (int i = 1; i < re->value()->captureCount(); ++i) {
uint start = matchOffsets[i * 2];
uint end = matchOffsets[i * 2 + 1];
- array->push_back((s = ctx->d()->engine->newString(text.mid(start, end - start))));
+ array->push_back((s = scope.engine->newString(text.mid(start, end - start))));
if (array->getLength() >= limit)
break;
}
}
if (array->getLength() < limit)
- array->push_back((s = ctx->d()->engine->newString(text.mid(offset))));
+ array->push_back((s = scope.engine->newString(text.mid(offset))));
} else {
QString separator = separatorValue->toQString();
if (separator.isEmpty()) {
for (uint i = 0; i < qMin(limit, uint(text.length())); ++i)
- array->push_back((s = ctx->d()->engine->newString(text.mid(i, 1))));
- return array.asReturnedValue();
+ array->push_back((s = scope.engine->newString(text.mid(i, 1))));
+ RETURN_RESULT(array);
}
int start = 0;
int end;
while ((end = text.indexOf(separator, start)) != -1) {
- array->push_back((s = ctx->d()->engine->newString(text.mid(start, end - start))));
+ array->push_back((s = scope.engine->newString(text.mid(start, end - start))));
start = end + separator.size();
if (array->getLength() >= limit)
break;
}
if (array->getLength() < limit && start != -1)
- array->push_back((s = ctx->d()->engine->newString(text.mid(start))));
+ array->push_back((s = scope.engine->newString(text.mid(start))));
}
- return array.asReturnedValue();
+ RETURN_RESULT(array);
}
-ReturnedValue StringPrototype::method_startsWith(CallContext *context)
+void StringPrototype::method_startsWith(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString value = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
QString searchString;
- if (context->argc()) {
- if (context->args()[0].as<RegExpObject>())
- return context->engine()->throwTypeError();
- searchString = context->args()[0].toQString();
+ if (callData->argc) {
+ if (callData->args[0].as<RegExpObject>())
+ THROW_TYPE_ERROR();
+ searchString = callData->args[0].toQString();
}
int pos = 0;
- if (context->argc() > 1)
- pos = (int) context->args()[1].toInteger();
+ if (callData->argc > 1)
+ pos = (int) callData->args[1].toInteger();
if (pos == 0)
- return Encode(value.startsWith(searchString));
+ RETURN_RESULT(Encode(value.startsWith(searchString)));
QStringRef stringToSearch = value.midRef(pos);
- return Encode(stringToSearch.startsWith(searchString));
+ RETURN_RESULT(Encode(stringToSearch.startsWith(searchString)));
}
-ReturnedValue StringPrototype::method_substr(CallContext *context)
+void StringPrototype::method_substr(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- const QString value = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ const QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
double start = 0;
- if (context->argc() > 0)
- start = context->args()[0].toInteger();
+ if (callData->argc > 0)
+ start = callData->args[0].toInteger();
double length = +qInf();
- if (context->argc() > 1)
- length = context->args()[1].toInteger();
+ if (callData->argc > 1)
+ length = callData->args[1].toInteger();
double count = value.length();
if (start < 0)
@@ -817,24 +794,23 @@ ReturnedValue StringPrototype::method_substr(CallContext *context)
qint32 x = Primitive::toInt32(start);
qint32 y = Primitive::toInt32(length);
- return context->d()->engine->newString(value.mid(x, y))->asReturnedValue();
+ scope.result = scope.engine->newString(value.mid(x, y));
}
-ReturnedValue StringPrototype::method_substring(CallContext *context)
+void StringPrototype::method_substring(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString value = getThisString(context);
- if (context->d()->engine->hasException)
- return Encode::undefined();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
+
int length = value.length();
double start = 0;
double end = length;
- if (context->argc() > 0)
- start = context->args()[0].toInteger();
+ if (callData->argc > 0)
+ start = callData->args[0].toInteger();
- Scope scope(context);
- ScopedValue endValue(scope, context->argument(1));
+ ScopedValue endValue(scope, callData->argument(1));
if (!endValue->isUndefined())
end = endValue->toInteger();
@@ -858,51 +834,50 @@ ReturnedValue StringPrototype::method_substring(CallContext *context)
qint32 x = (int)start;
qint32 y = (int)(end - start);
- return context->d()->engine->newString(value.mid(x, y))->asReturnedValue();
+ scope.result = scope.engine->newString(value.mid(x, y));
}
-ReturnedValue StringPrototype::method_toLowerCase(CallContext *ctx)
+void StringPrototype::method_toLowerCase(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString value = getThisString(ctx);
- if (ctx->d()->engine->hasException)
- return Encode::undefined();
- return ctx->d()->engine->newString(value.toLower())->asReturnedValue();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
+
+ scope.result = scope.engine->newString(value.toLower());
}
-ReturnedValue StringPrototype::method_toLocaleLowerCase(CallContext *ctx)
+void StringPrototype::method_toLocaleLowerCase(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- return method_toLowerCase(ctx);
+ method_toLowerCase(b, scope, callData);
}
-ReturnedValue StringPrototype::method_toUpperCase(CallContext *ctx)
+void StringPrototype::method_toUpperCase(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString value = getThisString(ctx);
- if (ctx->d()->engine->hasException)
- return Encode::undefined();
- return ctx->d()->engine->newString(value.toUpper())->asReturnedValue();
+ QString value = getThisString(scope, callData);
+ CHECK_EXCEPTION();
+
+ scope.result = scope.engine->newString(value.toUpper());
}
-ReturnedValue StringPrototype::method_toLocaleUpperCase(CallContext *ctx)
+void StringPrototype::method_toLocaleUpperCase(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- return method_toUpperCase(ctx);
+ return method_toUpperCase(b, scope, callData);
}
-ReturnedValue StringPrototype::method_fromCharCode(CallContext *context)
+void StringPrototype::method_fromCharCode(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString str(context->argc(), Qt::Uninitialized);
+ QString str(callData->argc, Qt::Uninitialized);
QChar *ch = str.data();
- for (int i = 0; i < context->argc(); ++i) {
- *ch = QChar(context->args()[i].toUInt16());
+ for (int i = 0; i < callData->argc; ++i) {
+ *ch = QChar(callData->args[i].toUInt16());
++ch;
}
- return context->d()->engine->newString(str)->asReturnedValue();
+ scope.result = scope.engine->newString(str);
}
-ReturnedValue StringPrototype::method_trim(CallContext *ctx)
+void StringPrototype::method_trim(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QString s = getThisString(ctx);
- if (ctx->d()->engine->hasException)
- return Encode::undefined();
+ QString s = getThisString(scope, callData);
+ CHECK_EXCEPTION();
const QChar *chars = s.constData();
int start, end;
@@ -915,5 +890,5 @@ ReturnedValue StringPrototype::method_trim(CallContext *ctx)
break;
}
- return ctx->d()->engine->newString(QString(chars + start, end - start + 1))->asReturnedValue();
+ scope.result = scope.engine->newString(QString(chars + start, end - start + 1));
}
diff --git a/src/qml/jsruntime/qv4stringobject_p.h b/src/qml/jsruntime/qv4stringobject_p.h
index b9f9d44fe8..0ee7a6ece9 100644
--- a/src/qml/jsruntime/qv4stringobject_p.h
+++ b/src/qml/jsruntime/qv4stringobject_p.h
@@ -111,29 +111,29 @@ struct StringPrototype: StringObject
{
void init(ExecutionEngine *engine, Object *ctor);
- static ReturnedValue method_toString(CallContext *context);
- static ReturnedValue method_charAt(CallContext *context);
- static ReturnedValue method_charCodeAt(CallContext *context);
- static ReturnedValue method_concat(CallContext *context);
- static ReturnedValue method_endsWith(CallContext *ctx);
- static ReturnedValue method_indexOf(CallContext *context);
- static ReturnedValue method_includes(CallContext *context);
- static ReturnedValue method_lastIndexOf(CallContext *context);
- static ReturnedValue method_localeCompare(CallContext *context);
- static ReturnedValue method_match(CallContext *context);
- static ReturnedValue method_replace(CallContext *ctx);
- static ReturnedValue method_search(CallContext *ctx);
- static ReturnedValue method_slice(CallContext *ctx);
- static ReturnedValue method_split(CallContext *ctx);
- static ReturnedValue method_startsWith(CallContext *ctx);
- static ReturnedValue method_substr(CallContext *context);
- static ReturnedValue method_substring(CallContext *context);
- static ReturnedValue method_toLowerCase(CallContext *ctx);
- static ReturnedValue method_toLocaleLowerCase(CallContext *ctx);
- static ReturnedValue method_toUpperCase(CallContext *ctx);
- static ReturnedValue method_toLocaleUpperCase(CallContext *ctx);
- static ReturnedValue method_fromCharCode(CallContext *context);
- static ReturnedValue method_trim(CallContext *ctx);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_charAt(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_charCodeAt(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_concat(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_endsWith(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_indexOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_includes(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_lastIndexOf(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_localeCompare(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_match(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_replace(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_search(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_slice(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_split(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_startsWith(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_substr(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_substring(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLowerCase(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLocaleLowerCase(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toUpperCase(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toLocaleUpperCase(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_fromCharCode(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_trim(const BuiltinFunction *, Scope &scope, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4typedarray.cpp b/src/qml/jsruntime/qv4typedarray.cpp
index 009c573bf8..cecd1e6958 100644
--- a/src/qml/jsruntime/qv4typedarray.cpp
+++ b/src/qml/jsruntime/qv4typedarray.cpp
@@ -438,79 +438,74 @@ void TypedArrayPrototype::init(ExecutionEngine *engine, TypedArrayCtor *ctor)
defineDefaultProperty(QStringLiteral("subarray"), method_subarray, 0);
}
-ReturnedValue TypedArrayPrototype::method_get_buffer(CallContext *ctx)
+void TypedArrayPrototype::method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<TypedArray> v(scope, ctx->thisObject());
+ Scoped<TypedArray> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->buffer->asReturnedValue());
+ scope.result = v->d()->buffer;
}
-ReturnedValue TypedArrayPrototype::method_get_byteLength(CallContext *ctx)
+void TypedArrayPrototype::method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<TypedArray> v(scope, ctx->thisObject());
+ Scoped<TypedArray> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->byteLength);
+ scope.result = Encode(v->d()->byteLength);
}
-ReturnedValue TypedArrayPrototype::method_get_byteOffset(CallContext *ctx)
+void TypedArrayPrototype::method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<TypedArray> v(scope, ctx->thisObject());
+ Scoped<TypedArray> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->byteOffset);
+ scope.result = Encode(v->d()->byteOffset);
}
-ReturnedValue TypedArrayPrototype::method_get_length(CallContext *ctx)
+void TypedArrayPrototype::method_get_length(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<TypedArray> v(scope, ctx->thisObject());
+ Scoped<TypedArray> v(scope, callData->thisObject);
if (!v)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(v->d()->byteLength/v->d()->type->bytesPerElement);
+ scope.result = Encode(v->d()->byteLength/v->d()->type->bytesPerElement);
}
-ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx)
+void TypedArrayPrototype::method_set(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<TypedArray> a(scope, ctx->thisObject());
+ Scoped<TypedArray> a(scope, callData->thisObject);
if (!a)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
Scoped<ArrayBuffer> buffer(scope, a->d()->buffer);
if (!buffer)
scope.engine->throwTypeError();
- double doffset = ctx->argc() >= 2 ? ctx->args()[1].toInteger() : 0;
+ double doffset = callData->argc >= 2 ? callData->args[1].toInteger() : 0;
if (scope.engine->hasException)
- return Encode::undefined();
+ RETURN_UNDEFINED();
if (doffset < 0 || doffset >= UINT_MAX)
- return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range"));
+ RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")));
uint offset = (uint)doffset;
uint elementSize = a->d()->type->bytesPerElement;
- Scoped<TypedArray> srcTypedArray(scope, ctx->args()[0]);
+ Scoped<TypedArray> srcTypedArray(scope, callData->args[0]);
if (!srcTypedArray) {
// src is a regular object
- ScopedObject o(scope, ctx->args()[0].toObject(scope.engine));
+ ScopedObject o(scope, callData->args[0].toObject(scope.engine));
if (scope.engine->hasException || !o)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
double len = ScopedValue(scope, o->get(scope.engine->id_length()))->toNumber();
uint l = (uint)len;
if (scope.engine->hasException || l != len)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
if (offset + l > a->length())
- return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range"));
+ RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")));
uint idx = 0;
char *b = buffer->d()->data->data() + a->d()->byteOffset + offset*elementSize;
@@ -519,28 +514,28 @@ ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx)
val = o->getIndexed(idx);
a->d()->type->write(scope.engine, b, 0, val);
if (scope.engine->hasException)
- return Encode::undefined();
+ RETURN_UNDEFINED();
++idx;
b += elementSize;
}
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
// src is a typed array
Scoped<ArrayBuffer> srcBuffer(scope, srcTypedArray->d()->buffer);
if (!srcBuffer)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
uint l = srcTypedArray->length();
if (offset + l > a->length())
- return scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range"));
+ RETURN_RESULT(scope.engine->throwRangeError(QStringLiteral("TypedArray.set: out of range")));
char *dest = buffer->d()->data->data() + a->d()->byteOffset + offset*elementSize;
const char *src = srcBuffer->d()->data->data() + srcTypedArray->d()->byteOffset;
if (srcTypedArray->d()->type == a->d()->type) {
// same type of typed arrays, use memmove (as srcbuffer and buffer could be the same)
memmove(dest, src, srcTypedArray->d()->byteLength);
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
char *srcCopy = 0;
@@ -564,28 +559,27 @@ ReturnedValue TypedArrayPrototype::method_set(CallContext *ctx)
if (srcCopy)
delete [] srcCopy;
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue TypedArrayPrototype::method_subarray(CallContext *ctx)
+void TypedArrayPrototype::method_subarray(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<TypedArray> a(scope, ctx->thisObject());
+ Scoped<TypedArray> a(scope, callData->thisObject);
if (!a)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
Scoped<ArrayBuffer> buffer(scope, a->d()->buffer);
if (!buffer)
- return scope.engine->throwTypeError();
+ THROW_TYPE_ERROR();
int len = a->length();
- double b = ctx->argc() > 0 ? ctx->args()[0].toInteger() : 0;
+ double b = callData->argc > 0 ? callData->args[0].toInteger() : 0;
if (b < 0)
b = len + b;
uint begin = (uint)qBound(0., b, (double)len);
- double e = ctx->argc() < 2 || ctx->args()[1].isUndefined() ? len : ctx->args()[1].toInteger();
+ double e = callData->argc < 2 || callData->args[1].isUndefined() ? len : callData->args[1].toInteger();
if (e < 0)
e = len + e;
uint end = (uint)qBound(0., e, (double)len);
@@ -593,18 +587,17 @@ ReturnedValue TypedArrayPrototype::method_subarray(CallContext *ctx)
end = begin;
if (scope.engine->hasException)
- return Encode::undefined();
+ RETURN_UNDEFINED();
int newLen = end - begin;
ScopedFunctionObject constructor(scope, a->get(scope.engine->id_constructor()));
if (!constructor)
- return scope.engine->throwTypeError();
-
- ScopedCallData callData(scope, 3);
- callData->args[0] = buffer;
- callData->args[1] = Encode(a->d()->byteOffset + begin*a->d()->type->bytesPerElement);
- callData->args[2] = Encode(newLen);
- constructor->construct(scope, callData);
- return scope.result.asReturnedValue();
+ THROW_TYPE_ERROR();
+
+ ScopedCallData cData(scope, 3);
+ cData->args[0] = buffer;
+ cData->args[1] = Encode(a->d()->byteOffset + begin*a->d()->type->bytesPerElement);
+ cData->args[2] = Encode(newLen);
+ constructor->construct(scope, cData);
}
diff --git a/src/qml/jsruntime/qv4typedarray_p.h b/src/qml/jsruntime/qv4typedarray_p.h
index 0112d2e4a1..eefed2db4b 100644
--- a/src/qml/jsruntime/qv4typedarray_p.h
+++ b/src/qml/jsruntime/qv4typedarray_p.h
@@ -151,13 +151,13 @@ struct TypedArrayPrototype : Object
void init(ExecutionEngine *engine, TypedArrayCtor *ctor);
- static ReturnedValue method_get_buffer(CallContext *ctx);
- static ReturnedValue method_get_byteLength(CallContext *ctx);
- static ReturnedValue method_get_byteOffset(CallContext *ctx);
- static ReturnedValue method_get_length(CallContext *ctx);
+ static void method_get_buffer(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_byteLength(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_byteOffset(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_length(const BuiltinFunction *, Scope &scope, CallData *callData);
- static ReturnedValue method_set(CallContext *ctx);
- static ReturnedValue method_subarray(CallContext *ctx);
+ static void method_set(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_subarray(const BuiltinFunction *, Scope &scope, CallData *callData);
};
inline void
diff --git a/src/qml/jsruntime/qv4value_p.h b/src/qml/jsruntime/qv4value_p.h
index 816b8fb11b..4ff0565f9b 100644
--- a/src/qml/jsruntime/qv4value_p.h
+++ b/src/qml/jsruntime/qv4value_p.h
@@ -254,34 +254,47 @@ public:
Q_ASSERT(isDouble()); return Double_Type;
}
-#ifndef QV4_USE_64_BIT_VALUE_ENCODING
+ // Shared between 32-bit and 64-bit encoding
+ enum {
+ Tag_Shift = 32
+ };
+
+ // Used only by 64-bit encoding
+ static const quint64 NaNEncodeMask = 0xfffc000000000000ll;
+ enum {
+ IsDouble_Shift = 64-14,
+ IsManagedOrUndefined_Shift = 64-15,
+ IsIntegerConvertible_Shift = 64-16,
+ IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift,
+ Managed_Type_Internal_64 = 0
+ };
+ static const quint64 Immediate_Mask_64 = 0x00020000u; // bit 49
+
+ // Used only by 32-bit encoding
enum Masks {
SilentNaNBit = 0x00040000,
- NaN_Mask = 0x7ff80000,
NotDouble_Mask = 0x7ffa0000,
- Immediate_Mask = NotDouble_Mask | 0x00020000u | SilentNaNBit,
- Tag_Shift = 32
};
+ static const quint64 Immediate_Mask_32 = NotDouble_Mask | 0x00020000u | SilentNaNBit;
enum {
- Managed_Type_Internal = NotDouble_Mask
+ Managed_Type_Internal_32 = NotDouble_Mask
};
-#else
- static const quint64 NaNEncodeMask = 0xfffc000000000000ll;
- static const quint64 Immediate_Mask = 0x00020000u; // bit 49
- enum Masks {
- NaN_Mask = 0x7ff80000,
+#ifdef QV4_USE_64_BIT_VALUE_ENCODING
+ enum {
+ Managed_Type_Internal = Managed_Type_Internal_64
};
+ static const quint64 Immediate_Mask = Immediate_Mask_64;
+#else
enum {
- IsDouble_Shift = 64-14,
- IsManagedOrUndefined_Shift = 64-15,
- IsIntegerConvertible_Shift = 64-16,
- Tag_Shift = 32,
- IsDoubleTag_Shift = IsDouble_Shift - Tag_Shift,
- Managed_Type_Internal = 0
+ Managed_Type_Internal = Managed_Type_Internal_32
};
+ static const quint64 Immediate_Mask = Immediate_Mask_32;
#endif
+ enum {
+ NaN_Mask = 0x7ff80000,
+ };
enum ValueTypeInternal {
Empty_Type_Internal = Immediate_Mask | 0,
ConvertibleToInt = Immediate_Mask | 0x10000u, // bit 48
@@ -544,7 +557,7 @@ inline bool Value::asArrayIndex(uint &idx) const
}
double d = doubleValue();
idx = (uint)d;
- return (idx == d);
+ return (idx == d && idx != UINT_MAX);
}
#endif
diff --git a/src/qml/jsruntime/qv4variantobject.cpp b/src/qml/jsruntime/qv4variantobject.cpp
index 455a7ccb65..5cab4c5386 100644
--- a/src/qml/jsruntime/qv4variantobject.cpp
+++ b/src/qml/jsruntime/qv4variantobject.cpp
@@ -113,67 +113,68 @@ void VariantPrototype::init()
defineDefaultProperty(engine()->id_toString(), method_toString, 0);
}
-QV4::ReturnedValue VariantPrototype::method_preserve(CallContext *ctx)
+void VariantPrototype::method_preserve(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>());
+ Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>());
if (o && o->d()->isScarce())
o->d()->addVmePropertyReference();
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-QV4::ReturnedValue VariantPrototype::method_destroy(CallContext *ctx)
+void VariantPrototype::method_destroy(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>());
+ Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>());
if (o) {
if (o->d()->isScarce())
o->d()->addVmePropertyReference();
o->d()->data() = QVariant();
}
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-QV4::ReturnedValue VariantPrototype::method_toString(CallContext *ctx)
+void VariantPrototype::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>());
+ Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>());
if (!o)
- return Encode::undefined();
+ RETURN_UNDEFINED();
QString result = o->d()->data().toString();
if (result.isEmpty() && !o->d()->data().canConvert(QVariant::String)) {
result = QLatin1String("QVariant(")
+ QLatin1String(o->d()->data().typeName())
+ QLatin1Char(')');
}
- return Encode(ctx->d()->engine->newString(result));
+ scope.result = scope.engine->newString(result);
}
-QV4::ReturnedValue VariantPrototype::method_valueOf(CallContext *ctx)
+void VariantPrototype::method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- Scoped<VariantObject> o(scope, ctx->thisObject().as<QV4::VariantObject>());
+ Scoped<VariantObject> o(scope, callData->thisObject.as<QV4::VariantObject>());
if (o) {
QVariant v = o->d()->data();
switch (v.type()) {
case QVariant::Invalid:
- return Encode::undefined();
+ scope.result = Encode::undefined();
+ return;
case QVariant::String:
- return Encode(ctx->d()->engine->newString(v.toString()));
+ scope.result = scope.engine->newString(v.toString());
+ return;
case QVariant::Int:
- return Encode(v.toInt());
+ scope.result = Encode(v.toInt());
+ return;
case QVariant::Double:
case QVariant::UInt:
- return Encode(v.toDouble());
+ scope.result = Encode(v.toDouble());
+ return;
case QVariant::Bool:
- return Encode(v.toBool());
+ scope.result = Encode(v.toBool());
+ return;
default:
if (QMetaType::typeFlags(v.userType()) & QMetaType::IsEnumeration)
- return Encode(v.toInt());
+ RETURN_RESULT(Encode(v.toInt()));
break;
}
}
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4variantobject_p.h b/src/qml/jsruntime/qv4variantobject_p.h
index 9a04069c12..ef51b6632d 100644
--- a/src/qml/jsruntime/qv4variantobject_p.h
+++ b/src/qml/jsruntime/qv4variantobject_p.h
@@ -107,10 +107,10 @@ struct VariantPrototype : VariantObject
public:
void init();
- static ReturnedValue method_preserve(CallContext *ctx);
- static ReturnedValue method_destroy(CallContext *ctx);
- static ReturnedValue method_toString(CallContext *ctx);
- static ReturnedValue method_valueOf(CallContext *ctx);
+ static void method_preserve(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_destroy(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_valueOf(const BuiltinFunction *, Scope &scope, CallData *callData);
};
}
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 622359a7d9..b9183313cd 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -347,6 +347,10 @@ Param traceParam(const Param &param)
goto catchException; \
VALUE(param) = tmp; \
}
+// qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro
+#ifdef CHECK_EXCEPTION
+#undef CHECK_EXCEPTION
+#endif
#define CHECK_EXCEPTION \
if (engine->hasException) \
goto catchException
diff --git a/src/qml/memory/memory.pri b/src/qml/memory/memory.pri
index 04b7566ccc..38fadbf23f 100644
--- a/src/qml/memory/memory.pri
+++ b/src/qml/memory/memory.pri
@@ -6,8 +6,8 @@ SOURCES += \
$$PWD/qv4mm.cpp \
HEADERS += \
- $$PWD/qv4mm_p.h
-
+ $$PWD/qv4mm_p.h \
+ $$PWD/qv4mmdefs_p.h
}
HEADERS += \
diff --git a/src/qml/memory/qv4heap_p.h b/src/qml/memory/qv4heap_p.h
index 5a3797f397..8285ef4de7 100644
--- a/src/qml/memory/qv4heap_p.h
+++ b/src/qml/memory/qv4heap_p.h
@@ -52,6 +52,7 @@
#include <QtCore/QString>
#include <private/qv4global_p.h>
+#include <private/qv4mmdefs_p.h>
#include <QSharedPointer>
// To check if Heap::Base::init is called (meaning, all subclasses did their init and called their
@@ -90,43 +91,31 @@ namespace Heap {
struct Q_QML_EXPORT Base {
void *operator new(size_t) = delete;
- quintptr mm_data; // vtable and markbit
+ const VTable *vt;
inline ReturnedValue asReturnedValue() const;
inline void mark(QV4::ExecutionEngine *engine);
- enum {
- MarkBit = 0x1,
- NotInUse = 0x2,
- PointerMask = ~0x3
- };
-
- void setVtable(const VTable *v) {
- Q_ASSERT(!(mm_data & MarkBit));
- mm_data = reinterpret_cast<quintptr>(v);
- }
- VTable *vtable() const {
- return reinterpret_cast<VTable *>(mm_data & PointerMask);
- }
+ void setVtable(const VTable *v) { vt = v; }
+ const VTable *vtable() const { return vt; }
inline bool isMarked() const {
- return mm_data & MarkBit;
+ const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
+ Chunk *c = h->chunk();
+ Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
+ return Chunk::testBit(c->blackBitmap, h - c->realBase());
}
inline void setMarkBit() {
- mm_data |= MarkBit;
- }
- inline void clearMarkBit() {
- mm_data &= ~MarkBit;
+ const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
+ Chunk *c = h->chunk();
+ Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
+ return Chunk::setBit(c->blackBitmap, h - c->realBase());
}
inline bool inUse() const {
- return !(mm_data & NotInUse);
- }
-
- Base *nextFree() {
- return reinterpret_cast<Base *>(mm_data & PointerMask);
- }
- void setNextFree(Base *m) {
- mm_data = (reinterpret_cast<quintptr>(m) | NotInUse);
+ const HeapItem *h = reinterpret_cast<const HeapItem *>(this);
+ Chunk *c = h->chunk();
+ Q_ASSERT(!Chunk::testBit(c->extendsBitmap, h - c->realBase()));
+ return Chunk::testBit(c->objectBitmap, h - c->realBase());
}
void *operator new(size_t, Managed *m) { return m; }
diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp
index 51eb82059a..6330ef6038 100644
--- a/src/qml/memory/qv4mm.cpp
+++ b/src/qml/memory/qv4mm.cpp
@@ -42,8 +42,12 @@
#include "qv4objectproto_p.h"
#include "qv4mm_p.h"
#include "qv4qobjectwrapper_p.h"
+#include <QtCore/qalgorithms.h>
+#include <QtCore/private/qnumeric_p.h>
#include <qqmlengine.h>
+#include "PageReservation.h"
#include "PageAllocation.h"
+#include "PageAllocationAligned.h"
#include "StdLibExtras.h"
#include <QElapsedTimer>
@@ -56,6 +60,14 @@
#include "qv4alloca_p.h"
#include "qv4profiling_p.h"
+#define MM_DEBUG 0
+
+#if MM_DEBUG
+#define DEBUG qDebug() << "MM:"
+#else
+#define DEBUG if (1) ; else qDebug() << "MM:"
+#endif
+
#ifdef V4_USE_VALGRIND
#include <valgrind/valgrind.h>
#include <valgrind/memcheck.h>
@@ -79,310 +91,616 @@ using namespace WTF;
QT_BEGIN_NAMESPACE
-static uint maxShiftValue()
-{
- static uint result = 0;
- if (!result) {
- result = 6;
- if (Q_UNLIKELY(qEnvironmentVariableIsSet(QV4_MM_MAXBLOCK_SHIFT))) {
- bool ok;
- const uint overrideValue = qgetenv(QV4_MM_MAXBLOCK_SHIFT).toUInt(&ok);
- if (ok && overrideValue <= 11 && overrideValue > 0)
- result = overrideValue;
+namespace QV4 {
+
+enum {
+ MinSlotsGCLimit = QV4::Chunk::AvailableSlots*16,
+ GCOverallocation = 200 /* Max overallocation by the GC in % */
+};
+
+struct MemorySegment {
+ enum {
+ NumChunks = 8*sizeof(quint64),
+ SegmentSize = NumChunks*Chunk::ChunkSize,
+ };
+
+ MemorySegment(size_t size)
+ {
+ size += Chunk::ChunkSize; // make sure we can get enough 64k aligment memory
+ if (size < SegmentSize)
+ size = SegmentSize;
+
+ pageReservation = PageReservation::reserve(size, OSAllocator::JSGCHeapPages);
+ base = reinterpret_cast<Chunk *>((reinterpret_cast<quintptr>(pageReservation.base()) + Chunk::ChunkSize - 1) & ~(Chunk::ChunkSize - 1));
+ nChunks = NumChunks;
+ if (base != pageReservation.base())
+ --nChunks;
+ }
+ MemorySegment(MemorySegment &&other) {
+ qSwap(pageReservation, other.pageReservation);
+ qSwap(base, other.base);
+ qSwap(nChunks, other.nChunks);
+ qSwap(allocatedMap, other.allocatedMap);
+ }
+
+ ~MemorySegment() {
+ if (base)
+ pageReservation.deallocate();
+ }
+
+ void setBit(size_t index) {
+ Q_ASSERT(index < nChunks);
+ quint64 bit = static_cast<quint64>(1) << index;
+// qDebug() << " setBit" << hex << index << (index & (Bits - 1)) << bit;
+ allocatedMap |= bit;
+ }
+ void clearBit(size_t index) {
+ Q_ASSERT(index < nChunks);
+ quint64 bit = static_cast<quint64>(1) << index;
+// qDebug() << " setBit" << hex << index << (index & (Bits - 1)) << bit;
+ allocatedMap &= ~bit;
+ }
+ bool testBit(size_t index) const {
+ Q_ASSERT(index < nChunks);
+ quint64 bit = static_cast<quint64>(1) << index;
+ return (allocatedMap & bit);
+ }
+
+ Chunk *allocate(size_t size);
+ void free(Chunk *chunk, size_t size) {
+ DEBUG << "freeing chunk" << chunk;
+ size_t index = static_cast<size_t>(chunk - base);
+ size_t end = index + (size - 1)/Chunk::ChunkSize + 1;
+ while (index < end) {
+ Q_ASSERT(testBit(index));
+ clearBit(index);
+ ++index;
}
+
+ size_t pageSize = WTF::pageSize();
+ size = (size + pageSize - 1) & ~(pageSize - 1);
+ pageReservation.decommit(chunk, size);
+ }
+
+ bool contains(Chunk *c) const {
+ return c >= base && c < base + nChunks;
}
- return result;
-}
-static std::size_t maxChunkSizeValue()
+ PageReservation pageReservation;
+ Chunk *base = 0;
+ quint64 allocatedMap = 0;
+ uint nChunks = 0;
+};
+
+Chunk *MemorySegment::allocate(size_t size)
{
- static std::size_t result = 0;
- if (!result) {
- result = 32 * 1024;
- if (Q_UNLIKELY(qEnvironmentVariableIsSet(QV4_MM_MAX_CHUNK_SIZE))) {
- bool ok;
- const std::size_t overrideValue = qgetenv(QV4_MM_MAX_CHUNK_SIZE).toUInt(&ok);
- if (ok)
- result = overrideValue;
+ size_t requiredChunks = (size + sizeof(Chunk) - 1)/sizeof(Chunk);
+ uint sequence = 0;
+ Chunk *candidate = 0;
+ for (uint i = 0; i < nChunks; ++i) {
+ if (!testBit(i)) {
+ if (!candidate)
+ candidate = base + i;
+ ++sequence;
+ } else {
+ candidate = 0;
+ sequence = 0;
+ }
+ if (sequence == requiredChunks) {
+ pageReservation.commit(candidate, size);
+ for (uint i = 0; i < requiredChunks; ++i)
+ setBit(candidate - base + i);
+ DEBUG << "allocated chunk " << candidate << hex << size;
+ return candidate;
}
}
- return result;
+ return 0;
}
-using namespace QV4;
-
-struct MemoryManager::Data
-{
- const size_t pageSize;
-
- struct ChunkHeader {
- Heap::Base freeItems;
- ChunkHeader *nextNonFull;
- char *itemStart;
- char *itemEnd;
- unsigned itemSize;
- };
+struct ChunkAllocator {
+ ChunkAllocator() {}
- ExecutionEngine *engine;
+ size_t requiredChunkSize(size_t size) {
+ size += Chunk::HeaderSize; // space required for the Chunk header
+ size_t pageSize = WTF::pageSize();
+ size = (size + pageSize - 1) & ~(pageSize - 1); // align to page sizes
+ if (size < Chunk::ChunkSize)
+ size = Chunk::ChunkSize;
+ return size;
+ }
- std::size_t maxChunkSize;
- std::vector<PageAllocation> heapChunks;
- std::size_t unmanagedHeapSize; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items.
- std::size_t unmanagedHeapSizeGCLimit;
+ Chunk *allocate(size_t size = 0);
+ void free(Chunk *chunk, size_t size = 0);
- struct LargeItem {
- LargeItem *next;
- size_t size;
- void *data;
+ std::vector<MemorySegment> memorySegments;
+};
- Heap::Base *heapObject() {
- return reinterpret_cast<Heap::Base *>(&data);
+Chunk *ChunkAllocator::allocate(size_t size)
+{
+ size = requiredChunkSize(size);
+ for (auto &m : memorySegments) {
+ if (~m.allocatedMap) {
+ Chunk *c = m.allocate(size);
+ if (c)
+ return c;
}
- };
-
- LargeItem *largeItems;
- std::size_t totalLargeItemsAllocated;
+ }
- enum { MaxItemSize = 512 };
- ChunkHeader *nonFullChunks[MaxItemSize/16];
- uint nChunks[MaxItemSize/16];
- uint availableItems[MaxItemSize/16];
- uint allocCount[MaxItemSize/16];
- int totalItems;
- int totalAlloc;
- uint maxShift;
+ // allocate a new segment
+ memorySegments.push_back(MemorySegment(size));
+ Chunk *c = memorySegments.back().allocate(size);
+ Q_ASSERT(c);
+ return c;
+}
- bool gcBlocked;
- bool aggressiveGC;
- bool gcStats;
- bool unused; // suppress padding warning
+void ChunkAllocator::free(Chunk *chunk, size_t size)
+{
+ size = requiredChunkSize(size);
+ for (auto &m : memorySegments) {
+ if (m.contains(chunk)) {
+ m.free(chunk, size);
+ return;
+ }
+ }
+ Q_ASSERT(false);
+}
- // statistics:
-#ifdef DETAILED_MM_STATS
- QVector<unsigned> allocSizeCounters;
-#endif // DETAILED_MM_STATS
- Data()
- : pageSize(WTF::pageSize())
- , engine(0)
- , maxChunkSize(maxChunkSizeValue())
- , unmanagedHeapSize(0)
- , unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT)
- , largeItems(0)
- , totalLargeItemsAllocated(0)
- , totalItems(0)
- , totalAlloc(0)
- , maxShift(maxShiftValue())
- , gcBlocked(false)
- , aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC"))
- , gcStats(!qEnvironmentVariableIsEmpty(QV4_MM_STATS))
- {
- memset(nonFullChunks, 0, sizeof(nonFullChunks));
- memset(nChunks, 0, sizeof(nChunks));
- memset(availableItems, 0, sizeof(availableItems));
- memset(allocCount, 0, sizeof(allocCount));
+void Chunk::sweep()
+{
+ // DEBUG << "sweeping chunk" << this << (*freeList);
+ HeapItem *o = realBase();
+ for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) {
+ Q_ASSERT((grayBitmap[i] | blackBitmap[i]) == blackBitmap[i]); // check that we don't have gray only objects
+ quintptr toFree = objectBitmap[i] ^ blackBitmap[i];
+ Q_ASSERT((toFree & objectBitmap[i]) == toFree); // check all black objects are marked as being used
+ quintptr e = extendsBitmap[i];
+ // DEBUG << hex << " index=" << i << toFree;
+ while (toFree) {
+ uint index = qCountTrailingZeroBits(toFree);
+ quintptr bit = (static_cast<quintptr>(1) << index);
+
+ toFree ^= bit; // mask out freed slot
+ // DEBUG << " index" << hex << index << toFree;
+
+ // remove all extends slots that have been freed
+ // this is a bit of bit trickery.
+ quintptr mask = (bit << 1) - 1; // create a mask of 1's to the right of and up to the current bit
+ quintptr objmask = e | mask; // or'ing mask with e gives all ones until the end of the current object
+ quintptr result = objmask + 1;
+ Q_ASSERT(qCountTrailingZeroBits(result) - index != 0); // ensure we freed something
+ result |= mask; // ensure we don't clear stuff to the right of the current object
+ e &= result;
+
+ HeapItem *itemToFree = o + index;
+ Heap::Base *b = *itemToFree;
+ if (b->vtable()->destroy) {
+ b->vtable()->destroy(b);
+ b->_checkIsDestroyed();
+ }
+ }
+ objectBitmap[i] = blackBitmap[i];
+ blackBitmap[i] = 0;
+ extendsBitmap[i] = e;
+ o += Chunk::Bits;
}
+ // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots.";
+}
- ~Data()
- {
- for (std::vector<PageAllocation>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i) {
- Q_V4_PROFILE_DEALLOC(engine, i->size(), Profiling::HeapPage);
- i->deallocate();
+void Chunk::freeAll()
+{
+ // DEBUG << "sweeping chunk" << this << (*freeList);
+ HeapItem *o = realBase();
+ for (uint i = 0; i < Chunk::EntriesInBitmap; ++i) {
+ quintptr toFree = objectBitmap[i];
+ quintptr e = extendsBitmap[i];
+ // DEBUG << hex << " index=" << i << toFree;
+ while (toFree) {
+ uint index = qCountTrailingZeroBits(toFree);
+ quintptr bit = (static_cast<quintptr>(1) << index);
+
+ toFree ^= bit; // mask out freed slot
+ // DEBUG << " index" << hex << index << toFree;
+
+ // remove all extends slots that have been freed
+ // this is a bit of bit trickery.
+ quintptr mask = (bit << 1) - 1; // create a mask of 1's to the right of and up to the current bit
+ quintptr objmask = e | mask; // or'ing mask with e gives all ones until the end of the current object
+ quintptr result = objmask + 1;
+ Q_ASSERT(qCountTrailingZeroBits(result) - index != 0); // ensure we freed something
+ result |= mask; // ensure we don't clear stuff to the right of the current object
+ e &= result;
+
+ HeapItem *itemToFree = o + index;
+ Heap::Base *b = *itemToFree;
+ if (b->vtable()->destroy) {
+ b->vtable()->destroy(b);
+ b->_checkIsDestroyed();
+ }
}
+ objectBitmap[i] = 0;
+ blackBitmap[i] = 0;
+ extendsBitmap[i] = e;
+ o += Chunk::Bits;
}
-};
-
-namespace {
+ // DEBUG << "swept chunk" << this << "freed" << slotsFreed << "slots.";
+}
-bool sweepChunk(MemoryManager::Data::ChunkHeader *header, uint *itemsInUse, ExecutionEngine *engine)
+void Chunk::sortIntoBins(HeapItem **bins, uint nBins)
{
- bool isEmpty = true;
- Heap::Base *tail = &header->freeItems;
-// qDebug("chunkStart @ %p, size=%x, pos=%x", header->itemStart, header->itemSize, header->itemSize>>4);
-#ifdef V4_USE_VALGRIND
- VALGRIND_DISABLE_ERROR_REPORTING;
+ HeapItem *base = realBase();
+#if QT_POINTER_SIZE == 8
+ const int start = 0;
+#else
+ const int start = 1;
#endif
- for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) {
- Heap::Base *m = reinterpret_cast<Heap::Base *>(item);
-// qDebug("chunk @ %p, in use: %s, mark bit: %s",
-// item, (m->inUse() ? "yes" : "no"), (m->isMarked() ? "true" : "false"));
-
- Q_ASSERT(qintptr(item) % 16 == 0);
-
- if (m->isMarked()) {
- Q_ASSERT(m->inUse());
- m->clearMarkBit();
- isEmpty = false;
- ++(*itemsInUse);
- } else {
- if (m->inUse()) {
-// qDebug() << "-- collecting it." << m << tail << m->nextFree();
-#ifdef V4_USE_VALGRIND
- VALGRIND_ENABLE_ERROR_REPORTING;
+ for (int i = start; i < EntriesInBitmap; ++i) {
+ quintptr usedSlots = (objectBitmap[i]|extendsBitmap[i]);
+#if QT_POINTER_SIZE == 8
+ if (!i)
+ usedSlots |= (static_cast<quintptr>(1) << (HeaderSize/SlotSize)) - 1;
#endif
- if (m->vtable()->destroy) {
- m->vtable()->destroy(m);
- m->_checkIsDestroyed();
- }
+ uint index = qCountTrailingZeroBits(usedSlots + 1);
+ if (index == Bits)
+ continue;
+ uint freeStart = i*Bits + index;
+ usedSlots &= ~((static_cast<quintptr>(1) << index) - 1);
+ while (i < EntriesInBitmap && !usedSlots) {
+ ++i;
+ usedSlots = (objectBitmap[i]|extendsBitmap[i]);
+ }
+ if (i == EntriesInBitmap)
+ usedSlots = 1;
+ HeapItem *freeItem = base + freeStart;
+
+ uint freeEnd = i*Bits + qCountTrailingZeroBits(usedSlots);
+ uint nSlots = freeEnd - freeStart;
+ Q_ASSERT(freeEnd > freeStart && freeEnd <= NumSlots);
+ freeItem->freeData.availableSlots = nSlots;
+ uint bin = qMin(nBins - 1, nSlots);
+ freeItem->freeData.next = bins[bin];
+ bins[bin] = freeItem;
+ // DEBUG << "binnig item" << freeItem << nSlots << bin << freeItem->freeData.availableSlots;
+ }
+}
- memset(m, 0, sizeof(Heap::Base));
-#ifdef V4_USE_VALGRIND
- VALGRIND_DISABLE_ERROR_REPORTING;
- VALGRIND_MEMPOOL_FREE(engine->memoryManager, m);
+
+template<typename T>
+StackAllocator<T>::StackAllocator(ChunkAllocator *chunkAlloc)
+ : chunkAllocator(chunkAlloc)
+{
+ chunks.push_back(chunkAllocator->allocate());
+ firstInChunk = chunks.back()->first();
+ nextFree = firstInChunk;
+ lastInChunk = firstInChunk + (Chunk::AvailableSlots - 1)/requiredSlots*requiredSlots;
+}
+
+template<typename T>
+void StackAllocator<T>::freeAll()
+{
+ for (auto c : chunks)
+ chunkAllocator->free(c);
+}
+
+template<typename T>
+void StackAllocator<T>::nextChunk() {
+ Q_ASSERT(nextFree == lastInChunk);
+ ++currentChunk;
+ if (currentChunk >= chunks.size()) {
+ Chunk *newChunk = chunkAllocator->allocate();
+ chunks.push_back(newChunk);
+ }
+ firstInChunk = chunks.at(currentChunk)->first();
+ nextFree = firstInChunk;
+ lastInChunk = firstInChunk + (Chunk::AvailableSlots - 1)/requiredSlots*requiredSlots;
+}
+
+template<typename T>
+void QV4::StackAllocator<T>::prevChunk() {
+ Q_ASSERT(nextFree == firstInChunk);
+ Q_ASSERT(chunks.at(currentChunk) == nextFree->chunk());
+ Q_ASSERT(currentChunk > 0);
+ --currentChunk;
+ firstInChunk = chunks.at(currentChunk)->first();
+ lastInChunk = firstInChunk + (Chunk::AvailableSlots - 1)/requiredSlots*requiredSlots;
+ nextFree = lastInChunk;
+}
+
+template struct StackAllocator<Heap::CallContext>;
+
+
+HeapItem *BlockAllocator::allocate(size_t size, bool forceAllocation) {
+ Q_ASSERT((size % Chunk::SlotSize) == 0);
+ size_t slotsRequired = size >> Chunk::SlotSizeShift;
+#if MM_DEBUG
+ ++allocations[bin];
#endif
-#ifdef V4_USE_HEAPTRACK
- heaptrack_report_free(m);
+
+ HeapItem **last;
+
+ HeapItem *m;
+
+ if (slotsRequired < NumBins - 1) {
+ m = freeBins[slotsRequired];
+ if (m) {
+ freeBins[slotsRequired] = m->freeData.next;
+ goto done;
+ }
+ }
+#if 0
+ for (uint b = bin + 1; b < NumBins - 1; ++b) {
+ if ((m = freeBins[b])) {
+ Q_ASSERT(binForSlots(m->freeData.availableSlots) == b);
+ freeBins[b] = m->freeData.next;
+ // DEBUG << "looking for empty bin" << bin << "size" << size << "found" << b;
+ uint remainingSlots = m->freeData.availableSlots - slotsRequired;
+ // DEBUG << "found free slots of size" << m->freeData.availableSlots << m << "remaining" << remainingSlots;
+ if (remainingSlots < 2) {
+ // avoid too much fragmentation and rather mark the memory as used
+ size += remainingSlots*Chunk::SlotSize;
+ goto done;
+ }
+ HeapItem *remainder = m + slotsRequired;
+ remainder->freeData.availableSlots = remainingSlots;
+ uint binForRemainder = binForSlots(remainingSlots);
+ remainder->freeData.next = freeBins[binForRemainder];
+ freeBins[binForRemainder] = remainder;
+ goto done;
+ }
+ }
#endif
- Q_V4_PROFILE_DEALLOC(engine, header->itemSize, Profiling::SmallItem);
- ++(*itemsInUse);
+ if (nFree >= slotsRequired) {
+ // use bump allocation
+ Q_ASSERT(nextFree);
+ m = nextFree;
+ nextFree += slotsRequired;
+ nFree -= slotsRequired;
+ goto done;
+ }
+
+ // DEBUG << "No matching bin found for item" << size << bin;
+ // search last bin for a large enough item
+ last = &freeBins[NumBins - 1];
+ while ((m = *last)) {
+ if (m->freeData.availableSlots >= slotsRequired) {
+ *last = m->freeData.next; // take it out of the list
+
+ size_t remainingSlots = m->freeData.availableSlots - slotsRequired;
+ // DEBUG << "found large free slots of size" << m->freeData.availableSlots << m << "remaining" << remainingSlots;
+ if (remainingSlots < 2) {
+ // avoid too much fragmentation and rather mark the memory as used
+ size += remainingSlots*Chunk::SlotSize;
+ goto done;
}
- // Relink all free blocks to rewrite references to any released chunk.
- tail->setNextFree(m);
- tail = m;
+ HeapItem *remainder = m + slotsRequired;
+ if (remainingSlots >= 2*NumBins) {
+ if (nFree) {
+ size_t bin = binForSlots(nFree);
+ nextFree->freeData.next = freeBins[bin];
+ nextFree->freeData.availableSlots = nFree;
+ freeBins[bin] = nextFree;
+ }
+ nextFree = remainder;
+ nFree = remainingSlots;
+ } else {
+ remainder->freeData.availableSlots = remainingSlots;
+ size_t binForRemainder = binForSlots(remainingSlots);
+ remainder->freeData.next = freeBins[binForRemainder];
+ freeBins[binForRemainder] = remainder;
+ }
+ goto done;
}
+ last = &m->freeData.next;
}
- tail->setNextFree(0);
-#ifdef V4_USE_VALGRIND
- VALGRIND_ENABLE_ERROR_REPORTING;
+
+ if (!m) {
+ if (!forceAllocation)
+ return 0;
+ Chunk *newChunk = chunkAllocator->allocate();
+ chunks.push_back(newChunk);
+ nextFree = newChunk->first();
+ nFree = Chunk::AvailableSlots;
+ m = nextFree;
+ nextFree += slotsRequired;
+ nFree -= slotsRequired;
+ }
+
+done:
+ m->setAllocatedSlots(slotsRequired);
+ // DEBUG << " " << hex << m->chunk() << m->chunk()->objectBitmap[0] << m->chunk()->extendsBitmap[0] << (m - m->chunk()->realBase());
+ return m;
+}
+
+void BlockAllocator::sweep()
+{
+ nextFree = 0;
+ nFree = 0;
+ memset(freeBins, 0, sizeof(freeBins));
+
+// qDebug() << "BlockAlloc: sweep";
+ usedSlotsAfterLastSweep = 0;
+ for (auto c : chunks) {
+ c->sweep();
+ c->sortIntoBins(freeBins, NumBins);
+// qDebug() << "used slots in chunk" << c << ":" << c->nUsedSlots();
+ usedSlotsAfterLastSweep += c->nUsedSlots();
+ }
+}
+
+void BlockAllocator::freeAll()
+{
+ for (auto c : chunks) {
+ c->freeAll();
+ chunkAllocator->free(c);
+ }
+}
+
+#if MM_DEBUG
+void BlockAllocator::stats() {
+ DEBUG << "MM stats:";
+ QString s;
+ for (int i = 0; i < 10; ++i) {
+ uint c = 0;
+ HeapItem *item = freeBins[i];
+ while (item) {
+ ++c;
+ item = item->freeData.next;
+ }
+ s += QString::number(c) + QLatin1String(", ");
+ }
+ HeapItem *item = freeBins[NumBins - 1];
+ uint c = 0;
+ while (item) {
+ ++c;
+ item = item->freeData.next;
+ }
+ s += QLatin1String("..., ") + QString::number(c);
+ DEBUG << "bins:" << s;
+ QString a;
+ for (int i = 0; i < 10; ++i)
+ a += QString::number(allocations[i]) + QLatin1String(", ");
+ a += QLatin1String("..., ") + QString::number(allocations[NumBins - 1]);
+ DEBUG << "allocs:" << a;
+ memset(allocations, 0, sizeof(allocations));
+}
#endif
- return isEmpty;
+
+
+HeapItem *HugeItemAllocator::allocate(size_t size) {
+ Chunk *c = chunkAllocator->allocate(size);
+ chunks.push_back(HugeChunk{c, size});
+ Chunk::setBit(c->objectBitmap, c->first() - c->realBase());
+ return c->first();
+}
+
+static void freeHugeChunk(ChunkAllocator *chunkAllocator, const HugeItemAllocator::HugeChunk &c)
+{
+ HeapItem *itemToFree = c.chunk->first();
+ Heap::Base *b = *itemToFree;
+ if (b->vtable()->destroy) {
+ b->vtable()->destroy(b);
+ b->_checkIsDestroyed();
+ }
+ chunkAllocator->free(c.chunk, c.size);
+}
+
+void HugeItemAllocator::sweep() {
+ auto isBlack = [this] (const HugeChunk &c) {
+ bool b = c.chunk->first()->isBlack();
+ Chunk::clearBit(c.chunk->blackBitmap, c.chunk->first() - c.chunk->realBase());
+ if (!b)
+ freeHugeChunk(chunkAllocator, c);
+ return !b;
+ };
+
+ auto newEnd = std::remove_if(chunks.begin(), chunks.end(), isBlack);
+ chunks.erase(newEnd, chunks.end());
+}
+
+void HugeItemAllocator::freeAll()
+{
+ for (auto &c : chunks) {
+ freeHugeChunk(chunkAllocator, c);
+ }
}
-} // namespace
MemoryManager::MemoryManager(ExecutionEngine *engine)
: engine(engine)
- , m_d(new Data)
+ , chunkAllocator(new ChunkAllocator)
+ , stackAllocator(chunkAllocator)
+ , blockAllocator(chunkAllocator)
+ , hugeItemAllocator(chunkAllocator)
, m_persistentValues(new PersistentValueStorage(engine))
, m_weakValues(new PersistentValueStorage(engine))
+ , unmanagedHeapSizeGCLimit(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT)
+ , aggressiveGC(!qEnvironmentVariableIsEmpty("QV4_MM_AGGRESSIVE_GC"))
+ , gcStats(!qEnvironmentVariableIsEmpty(QV4_MM_STATS))
{
#ifdef V4_USE_VALGRIND
VALGRIND_CREATE_MEMPOOL(this, 0, true);
#endif
- m_d->engine = engine;
}
-Heap::Base *MemoryManager::allocData(std::size_t size, std::size_t unmanagedSize)
+Heap::Base *MemoryManager::allocString(std::size_t unmanagedSize)
{
- if (m_d->aggressiveGC)
+ if (aggressiveGC)
runGC();
-#ifdef DETAILED_MM_STATS
- willAllocate(size);
-#endif // DETAILED_MM_STATS
- Q_ASSERT(size >= 16);
- Q_ASSERT(size % 16 == 0);
-
-// qDebug() << "unmanagedHeapSize:" << m_d->unmanagedHeapSize << "limit:" << m_d->unmanagedHeapSizeGCLimit << "unmanagedSize:" << unmanagedSize;
- m_d->unmanagedHeapSize += unmanagedSize;
+ const size_t stringSize = align(sizeof(Heap::String));
+ unmanagedHeapSize += unmanagedSize;
bool didGCRun = false;
- if (m_d->unmanagedHeapSize > m_d->unmanagedHeapSizeGCLimit) {
+ if (unmanagedHeapSize > unmanagedHeapSizeGCLimit) {
runGC();
- if (3*m_d->unmanagedHeapSizeGCLimit <= 4*m_d->unmanagedHeapSize)
+ if (3*unmanagedHeapSizeGCLimit <= 4*unmanagedHeapSize)
// more than 75% full, raise limit
- m_d->unmanagedHeapSizeGCLimit = std::max(m_d->unmanagedHeapSizeGCLimit, m_d->unmanagedHeapSize) * 2;
- else if (m_d->unmanagedHeapSize * 4 <= m_d->unmanagedHeapSizeGCLimit)
+ unmanagedHeapSizeGCLimit = std::max(unmanagedHeapSizeGCLimit, unmanagedHeapSize) * 2;
+ else if (unmanagedHeapSize * 4 <= unmanagedHeapSizeGCLimit)
// less than 25% full, lower limit
- m_d->unmanagedHeapSizeGCLimit = qMax(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT, m_d->unmanagedHeapSizeGCLimit/2);
+ unmanagedHeapSizeGCLimit = qMax(MIN_UNMANAGED_HEAPSIZE_GC_LIMIT, unmanagedHeapSizeGCLimit/2);
didGCRun = true;
}
- size_t pos = size >> 4;
-
- // doesn't fit into a small bucket
- if (size >= MemoryManager::Data::MaxItemSize) {
- if (!didGCRun && m_d->totalLargeItemsAllocated > 8 * 1024 * 1024)
+ HeapItem *m = blockAllocator.allocate(stringSize);
+ if (!m) {
+ if (!didGCRun && shouldRunGC())
runGC();
-
- // we use malloc for this
- const size_t totalSize = size + sizeof(MemoryManager::Data::LargeItem);
- Q_V4_PROFILE_ALLOC(engine, totalSize, Profiling::LargeItem);
- MemoryManager::Data::LargeItem *item =
- static_cast<MemoryManager::Data::LargeItem *>(malloc(totalSize));
- memset(item, 0, totalSize);
- item->next = m_d->largeItems;
- item->size = size;
- m_d->largeItems = item;
- m_d->totalLargeItemsAllocated += size;
- return item->heapObject();
+ m = blockAllocator.allocate(stringSize, true);
}
- Heap::Base *m = 0;
- Data::ChunkHeader *header = m_d->nonFullChunks[pos];
- if (header) {
- m = header->freeItems.nextFree();
- goto found;
- }
+ memset(m, 0, stringSize);
+ return *m;
+}
- // try to free up space, otherwise allocate
- if (!didGCRun && m_d->allocCount[pos] > (m_d->availableItems[pos] >> 1) && m_d->totalAlloc > (m_d->totalItems >> 1) && !m_d->aggressiveGC) {
+Heap::Base *MemoryManager::allocData(std::size_t size)
+{
+ if (aggressiveGC)
runGC();
- header = m_d->nonFullChunks[pos];
- if (header) {
- m = header->freeItems.nextFree();
- goto found;
- }
- }
+#ifdef DETAILED_MM_STATS
+ willAllocate(size);
+#endif // DETAILED_MM_STATS
- // no free item available, allocate a new chunk
- {
- // allocate larger chunks at a time to avoid excessive GC, but cap at maximum chunk size (2MB by default)
- uint shift = ++m_d->nChunks[pos];
- if (shift > m_d->maxShift)
- shift = m_d->maxShift;
- std::size_t allocSize = m_d->maxChunkSize*(size_t(1) << shift);
- allocSize = roundUpToMultipleOf(m_d->pageSize, allocSize);
- Q_V4_PROFILE_ALLOC(engine, allocSize, Profiling::HeapPage);
- PageAllocation allocation = PageAllocation::allocate(allocSize, OSAllocator::JSGCHeapPages);
- m_d->heapChunks.push_back(allocation);
-
- header = reinterpret_cast<Data::ChunkHeader *>(allocation.base());
- Q_ASSERT(size <= UINT_MAX);
- header->itemSize = unsigned(size);
- header->itemStart = reinterpret_cast<char *>(allocation.base()) + roundUpToMultipleOf(16, sizeof(Data::ChunkHeader));
- header->itemEnd = reinterpret_cast<char *>(allocation.base()) + allocation.size() - header->itemSize;
-
- header->nextNonFull = m_d->nonFullChunks[pos];
- m_d->nonFullChunks[pos] = header;
-
- Heap::Base *last = &header->freeItems;
- for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) {
- Heap::Base *o = reinterpret_cast<Heap::Base *>(item);
- last->setNextFree(o);
- last = o;
+ Q_ASSERT(size >= Chunk::SlotSize);
+ Q_ASSERT(size % Chunk::SlotSize == 0);
- }
- last->setNextFree(0);
- m = header->freeItems.nextFree();
- Q_ASSERT(header->itemEnd >= header->itemStart);
- const size_t increase = quintptr(header->itemEnd - header->itemStart) / header->itemSize;
- m_d->availableItems[pos] += uint(increase);
- m_d->totalItems += int(increase);
-#ifdef V4_USE_VALGRIND
- VALGRIND_MAKE_MEM_NOACCESS(allocation.base(), allocSize);
- VALGRIND_MEMPOOL_ALLOC(this, header, sizeof(Data::ChunkHeader));
-#endif
-#ifdef V4_USE_HEAPTRACK
- heaptrack_report_alloc(header, sizeof(Data::ChunkHeader));
-#endif
+// qDebug() << "unmanagedHeapSize:" << unmanagedHeapSize << "limit:" << unmanagedHeapSizeGCLimit << "unmanagedSize:" << unmanagedSize;
+
+ if (size > Chunk::DataSize)
+ return *hugeItemAllocator.allocate(size);
+
+ HeapItem *m = blockAllocator.allocate(size);
+ if (!m) {
+ if (shouldRunGC())
+ runGC();
+ m = blockAllocator.allocate(size, true);
}
- found:
-#ifdef V4_USE_VALGRIND
- VALGRIND_MEMPOOL_ALLOC(this, m, size);
-#endif
-#ifdef V4_USE_HEAPTRACK
- heaptrack_report_alloc(m, size);
-#endif
- Q_V4_PROFILE_ALLOC(engine, size, Profiling::SmallItem);
+ memset(m, 0, size);
+ return *m;
+}
- ++m_d->allocCount[pos];
- ++m_d->totalAlloc;
- header->freeItems.setNextFree(m->nextFree());
- if (!header->freeItems.nextFree())
- m_d->nonFullChunks[pos] = header->nextNonFull;
- return m;
+Heap::Object *MemoryManager::allocObjectWithMemberData(std::size_t size, uint nMembers)
+{
+ Heap::Object *o = static_cast<Heap::Object *>(allocData(size));
+
+ // ### Could optimize this and allocate both in one go through the block allocator
+ if (nMembers) {
+ std::size_t memberSize = align(sizeof(Heap::MemberData) + (nMembers - 1)*sizeof(Value));
+// qDebug() << "allocating member data for" << o << nMembers << memberSize;
+ Heap::Base *m;
+ if (memberSize > Chunk::DataSize)
+ m = *hugeItemAllocator.allocate(memberSize);
+ else
+ m = *blockAllocator.allocate(memberSize, true);
+ memset(m, 0, memberSize);
+ o->memberData = static_cast<Heap::MemberData *>(m);
+ o->memberData->setVtable(MemberData::staticVTable());
+ o->memberData->size = static_cast<uint>((memberSize - sizeof(Heap::MemberData) + sizeof(Value))/sizeof(Value));
+ o->memberData->init();
+// qDebug() << " got" << o->memberData << o->memberData->size;
+ }
+ return o;
}
static void drainMarkStack(QV4::ExecutionEngine *engine, Value *markBase)
@@ -486,88 +804,34 @@ void MemoryManager::sweep(bool lastSweep)
}
}
- bool *chunkIsEmpty = static_cast<bool *>(alloca(m_d->heapChunks.size() * sizeof(bool)));
- uint itemsInUse[MemoryManager::Data::MaxItemSize/16];
- memset(itemsInUse, 0, sizeof(itemsInUse));
- memset(m_d->nonFullChunks, 0, sizeof(m_d->nonFullChunks));
-
- for (size_t i = 0; i < m_d->heapChunks.size(); ++i) {
- Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(m_d->heapChunks[i].base());
- chunkIsEmpty[i] = sweepChunk(header, &itemsInUse[header->itemSize >> 4], engine);
- }
-
- std::vector<PageAllocation>::iterator chunkIter = m_d->heapChunks.begin();
- for (size_t i = 0; i < m_d->heapChunks.size(); ++i) {
- Q_ASSERT(chunkIter != m_d->heapChunks.end());
- Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(chunkIter->base());
- const size_t pos = header->itemSize >> 4;
- Q_ASSERT(header->itemEnd >= header->itemStart);
- const size_t decrease = quintptr(header->itemEnd - header->itemStart) / header->itemSize;
-
- // Release that chunk if it could have been spared since the last GC run without any difference.
- if (chunkIsEmpty[i] && m_d->availableItems[pos] - decrease >= itemsInUse[pos]) {
- Q_V4_PROFILE_DEALLOC(engine, chunkIter->size(), Profiling::HeapPage);
-#ifdef V4_USE_VALGRIND
- VALGRIND_MEMPOOL_FREE(this, header);
-#endif
-#ifdef V4_USE_HEAPTRACK
- heaptrack_report_free(header);
-#endif
- --m_d->nChunks[pos];
- m_d->availableItems[pos] -= uint(decrease);
- m_d->totalItems -= int(decrease);
- chunkIter->deallocate();
- chunkIter = m_d->heapChunks.erase(chunkIter);
- continue;
- } else if (header->freeItems.nextFree()) {
- header->nextNonFull = m_d->nonFullChunks[pos];
- m_d->nonFullChunks[pos] = header;
- }
- ++chunkIter;
- }
-
- Data::LargeItem *i = m_d->largeItems;
- Data::LargeItem **last = &m_d->largeItems;
- while (i) {
- Heap::Base *m = i->heapObject();
- Q_ASSERT(m->inUse());
- if (m->isMarked()) {
- m->clearMarkBit();
- last = &i->next;
- i = i->next;
- continue;
- }
- if (m->vtable()->destroy)
- m->vtable()->destroy(m);
-
- *last = i->next;
- Q_V4_PROFILE_DEALLOC(engine, i->size + sizeof(Data::LargeItem), Profiling::LargeItem);
- free(i);
- i = *last;
- }
+ blockAllocator.sweep();
+ hugeItemAllocator.sweep();
+}
- // some execution contexts are allocated on the stack, make sure we clear their markBit as well
- if (!lastSweep) {
- QV4::ExecutionContext *ctx = engine->currentContext;
- while (ctx) {
- ctx->d()->clearMarkBit();
- ctx = engine->parentContext(ctx);
- }
- }
+bool MemoryManager::shouldRunGC() const
+{
+ size_t total = blockAllocator.totalSlots();
+ size_t usedSlots = blockAllocator.usedSlotsAfterLastSweep;
+ if (total > MinSlotsGCLimit && usedSlots * GCOverallocation < total * 100)
+ return true;
+ return false;
}
+
void MemoryManager::runGC()
{
- if (m_d->gcBlocked) {
+ if (gcBlocked) {
// qDebug() << "Not running GC.";
return;
}
- QScopedValueRollback<bool> gcBlocker(m_d->gcBlocked, true);
+ QScopedValueRollback<bool> gcBlocker(gcBlocked, true);
- if (!m_d->gcStats) {
+ if (!gcStats) {
+// uint oldUsed = allocator.usedMem();
mark();
sweep();
+// DEBUG << "RUN GC: allocated:" << allocator.allocatedMem() << "used before" << oldUsed << "used now" << allocator.usedMem();
} else {
const size_t totalMem = getAllocatedMem();
@@ -577,7 +841,6 @@ void MemoryManager::runGC()
qint64 markTime = t.restart();
const size_t usedBefore = getUsedMem();
const size_t largeItemsBefore = getLargeItemsMem();
- size_t chunksBefore = m_d->heapChunks.size();
sweep();
const size_t usedAfter = getUsedMem();
const size_t largeItemsAfter = getLargeItemsMem();
@@ -586,56 +849,30 @@ void MemoryManager::runGC()
qDebug() << "========== GC ==========";
qDebug() << "Marked object in" << markTime << "ms.";
qDebug() << "Sweeped object in" << sweepTime << "ms.";
- qDebug() << "Allocated" << totalMem << "bytes in" << m_d->heapChunks.size() << "chunks.";
+ qDebug() << "Allocated" << totalMem << "bytes";
qDebug() << "Used memory before GC:" << usedBefore;
qDebug() << "Used memory after GC:" << usedAfter;
qDebug() << "Freed up bytes:" << (usedBefore - usedAfter);
- qDebug() << "Released chunks:" << (chunksBefore - m_d->heapChunks.size());
qDebug() << "Large item memory before GC:" << largeItemsBefore;
qDebug() << "Large item memory after GC:" << largeItemsAfter;
qDebug() << "Large item memory freed up:" << (largeItemsBefore - largeItemsAfter);
qDebug() << "======== End GC ========";
}
-
- memset(m_d->allocCount, 0, sizeof(m_d->allocCount));
- m_d->totalAlloc = 0;
- m_d->totalLargeItemsAllocated = 0;
}
size_t MemoryManager::getUsedMem() const
{
- size_t usedMem = 0;
- for (std::vector<PageAllocation>::const_iterator i = m_d->heapChunks.cbegin(), ei = m_d->heapChunks.cend(); i != ei; ++i) {
- Data::ChunkHeader *header = reinterpret_cast<Data::ChunkHeader *>(i->base());
- for (char *item = header->itemStart; item <= header->itemEnd; item += header->itemSize) {
- Heap::Base *m = reinterpret_cast<Heap::Base *>(item);
- Q_ASSERT(qintptr(item) % 16 == 0);
- if (m->inUse())
- usedMem += header->itemSize;
- }
- }
- return usedMem;
+ return blockAllocator.usedMem();
}
size_t MemoryManager::getAllocatedMem() const
{
- size_t total = 0;
- for (size_t i = 0; i < m_d->heapChunks.size(); ++i)
- total += m_d->heapChunks.at(i).size();
- return total;
+ return blockAllocator.allocatedMem() + hugeItemAllocator.usedMem();
}
size_t MemoryManager::getLargeItemsMem() const
{
- size_t total = 0;
- for (const Data::LargeItem *i = m_d->largeItems; i != 0; i = i->next)
- total += i->size;
- return total;
-}
-
-void MemoryManager::changeUnmanagedHeapSizeUsage(qptrdiff delta)
-{
- m_d->unmanagedHeapSize += delta;
+ return hugeItemAllocator.usedMem();
}
MemoryManager::~MemoryManager()
@@ -643,23 +880,26 @@ MemoryManager::~MemoryManager()
delete m_persistentValues;
sweep(/*lastSweep*/true);
+ blockAllocator.freeAll();
+ hugeItemAllocator.freeAll();
+ stackAllocator.freeAll();
delete m_weakValues;
#ifdef V4_USE_VALGRIND
VALGRIND_DESTROY_MEMPOOL(this);
#endif
+ delete chunkAllocator;
}
-
void MemoryManager::dumpStats() const
{
#ifdef DETAILED_MM_STATS
std::cerr << "=================" << std::endl;
std::cerr << "Allocation stats:" << std::endl;
std::cerr << "Requests for each chunk size:" << std::endl;
- for (int i = 0; i < m_d->allocSizeCounters.size(); ++i) {
- if (unsigned count = m_d->allocSizeCounters[i]) {
+ for (int i = 0; i < allocSizeCounters.size(); ++i) {
+ if (unsigned count = allocSizeCounters[i]) {
std::cerr << "\t" << (i << 4) << " bytes chunks: " << count << std::endl;
}
}
@@ -670,7 +910,7 @@ void MemoryManager::dumpStats() const
void MemoryManager::willAllocate(std::size_t size)
{
unsigned alignedSize = (size + 15) >> 4;
- QVector<unsigned> &counters = m_d->allocSizeCounters;
+ QVector<unsigned> &counters = allocSizeCounters;
if ((unsigned) counters.size() < alignedSize + 1)
counters.resize(alignedSize + 1);
counters[alignedSize]++;
@@ -690,4 +930,7 @@ void MemoryManager::collectFromJSStack() const
++v;
}
}
+
+} // namespace QV4
+
QT_END_NAMESPACE
diff --git a/src/qml/memory/qv4mm_p.h b/src/qml/memory/qv4mm_p.h
index e6417cb2e0..00daf8a622 100644
--- a/src/qml/memory/qv4mm_p.h
+++ b/src/qml/memory/qv4mm_p.h
@@ -55,6 +55,7 @@
#include <private/qv4value_p.h>
#include <private/qv4scopedvalue_p.h>
#include <private/qv4object_p.h>
+#include <private/qv4mmdefs_p.h>
#include <QVector>
//#define DETAILED_MM_STATS
@@ -63,35 +64,166 @@
#define QV4_MM_MAX_CHUNK_SIZE "QV4_MM_MAX_CHUNK_SIZE"
#define QV4_MM_STATS "QV4_MM_STATS"
+#define MM_DEBUG 0
+
QT_BEGIN_NAMESPACE
namespace QV4 {
-struct GCDeletable;
+struct ChunkAllocator;
+
+template<typename T>
+struct StackAllocator {
+ Q_STATIC_ASSERT(sizeof(T) < Chunk::DataSize);
+ static const uint requiredSlots = (sizeof(T) + sizeof(HeapItem) - 1)/sizeof(HeapItem);
+
+ StackAllocator(ChunkAllocator *chunkAlloc);
+
+ T *allocate() {
+ T *m = nextFree->as<T>();
+ if (Q_UNLIKELY(nextFree == lastInChunk)) {
+ nextChunk();
+ } else {
+ nextFree += requiredSlots;
+ }
+#if MM_DEBUG
+ Chunk *c = m->chunk();
+ Chunk::setBit(c->objectBitmap, m - c->realBase());
+#endif
+ return m;
+ }
+ void free() {
+#if MM_DEBUG
+ Chunk::clearBit(item->chunk()->objectBitmap, item - item->chunk()->realBase());
+#endif
+ if (Q_UNLIKELY(nextFree == firstInChunk)) {
+ prevChunk();
+ } else {
+ nextFree -= requiredSlots;
+ }
+ }
+
+ void nextChunk();
+ void prevChunk();
+
+ void freeAll();
+
+ ChunkAllocator *chunkAllocator;
+ HeapItem *nextFree = 0;
+ HeapItem *firstInChunk = 0;
+ HeapItem *lastInChunk = 0;
+ std::vector<Chunk *> chunks;
+ uint currentChunk = 0;
+};
+
+struct BlockAllocator {
+ BlockAllocator(ChunkAllocator *chunkAllocator)
+ : chunkAllocator(chunkAllocator)
+ {
+ memset(freeBins, 0, sizeof(freeBins));
+#if MM_DEBUG
+ memset(allocations, 0, sizeof(allocations));
+#endif
+ }
+
+ enum { NumBins = 8 };
+
+ static inline size_t binForSlots(size_t nSlots) {
+ return nSlots >= NumBins ? NumBins - 1 : nSlots;
+ }
+
+#if MM_DEBUG
+ void stats();
+#endif
+
+ HeapItem *allocate(size_t size, bool forceAllocation = false);
+
+ size_t totalSlots() const {
+ return Chunk::AvailableSlots*chunks.size();
+ }
+
+ size_t allocatedMem() const {
+ return chunks.size()*Chunk::DataSize;
+ }
+ size_t usedMem() const {
+ uint used = 0;
+ for (auto c : chunks)
+ used += c->nUsedSlots()*Chunk::SlotSize;
+ return used;
+ }
+
+ void sweep();
+ void freeAll();
+
+ // bump allocations
+ HeapItem *nextFree = 0;
+ size_t nFree = 0;
+ size_t usedSlotsAfterLastSweep = 0;
+ HeapItem *freeBins[NumBins];
+ ChunkAllocator *chunkAllocator;
+ std::vector<Chunk *> chunks;
+#if MM_DEBUG
+ uint allocations[NumBins];
+#endif
+};
+
+struct HugeItemAllocator {
+ HugeItemAllocator(ChunkAllocator *chunkAllocator)
+ : chunkAllocator(chunkAllocator)
+ {}
+
+ HeapItem *allocate(size_t size);
+ void sweep();
+ void freeAll();
+
+ size_t usedMem() const {
+ size_t used = 0;
+ for (const auto &c : chunks)
+ used += c.size;
+ return used;
+ }
+
+ ChunkAllocator *chunkAllocator;
+ struct HugeChunk {
+ Chunk *chunk;
+ size_t size;
+ };
+
+ std::vector<HugeChunk> chunks;
+};
+
class Q_QML_EXPORT MemoryManager
{
Q_DISABLE_COPY(MemoryManager);
public:
- struct Data;
-
-public:
MemoryManager(ExecutionEngine *engine);
~MemoryManager();
// TODO: this is only for 64bit (and x86 with SSE/AVX), so exend it for other architectures to be slightly more efficient (meaning, align on 8-byte boundaries).
// Note: all occurrences of "16" in alloc/dealloc are also due to the alignment.
- static inline std::size_t align(std::size_t size)
- { return (size + 15) & ~0xf; }
+ Q_DECL_CONSTEXPR static inline std::size_t align(std::size_t size)
+ { return (size + Chunk::SlotSize - 1) & ~(Chunk::SlotSize - 1); }
+
+ QV4::Heap::CallContext *allocSimpleCallContext(QV4::ExecutionEngine *v4)
+ {
+ Heap::CallContext *ctxt = stackAllocator.allocate();
+ memset(ctxt, 0, sizeof(Heap::CallContext));
+ ctxt->setVtable(QV4::CallContext::staticVTable());
+ ctxt->init(v4);
+ return ctxt;
+
+ }
+ void freeSimpleCallContext()
+ { stackAllocator.free(); }
template<typename ManagedType>
- inline typename ManagedType::Data *allocManaged(std::size_t size, std::size_t unmanagedSize = 0)
+ inline typename ManagedType::Data *allocManaged(std::size_t size)
{
V4_ASSERT_IS_TRIVIAL(typename ManagedType::Data)
size = align(size);
- Heap::Base *o = allocData(size, unmanagedSize);
- memset(o, 0, size);
+ Heap::Base *o = allocData(size);
o->setVtable(ManagedType::staticVTable());
return static_cast<typename ManagedType::Data *>(o);
}
@@ -99,35 +231,31 @@ public:
template <typename ObjectType>
typename ObjectType::Data *allocateObject(InternalClass *ic)
{
- const int size = (sizeof(typename ObjectType::Data) + (sizeof(Value) - 1)) & ~(sizeof(Value) - 1);
- typename ObjectType::Data *o = allocManaged<ObjectType>(size + ic->size*sizeof(Value));
+ Heap::Object *o = allocObjectWithMemberData(align(sizeof(typename ObjectType::Data)), ic->size);
+ o->setVtable(ObjectType::staticVTable());
o->internalClass = ic;
- o->inlineMemberSize = ic->size;
- o->inlineMemberOffset = size/sizeof(Value);
- return o;
+ return static_cast<typename ObjectType::Data *>(o);
}
template <typename ObjectType>
typename ObjectType::Data *allocateObject()
{
InternalClass *ic = ObjectType::defaultInternalClass(engine);
- const int size = (sizeof(typename ObjectType::Data) + (sizeof(Value) - 1)) & ~(sizeof(Value) - 1);
- typename ObjectType::Data *o = allocManaged<ObjectType>(size + ic->size*sizeof(Value));
+ Heap::Object *o = allocObjectWithMemberData(align(sizeof(typename ObjectType::Data)), ic->size);
+ o->setVtable(ObjectType::staticVTable());
Object *prototype = ObjectType::defaultPrototype(engine);
o->internalClass = ic;
o->prototype = prototype->d();
- o->inlineMemberSize = ic->size;
- o->inlineMemberOffset = size/sizeof(Value);
- return o;
+ return static_cast<typename ObjectType::Data *>(o);
}
template <typename ManagedType, typename Arg1>
typename ManagedType::Data *allocWithStringData(std::size_t unmanagedSize, Arg1 arg1)
{
- Scope scope(engine);
- Scoped<ManagedType> t(scope, allocManaged<ManagedType>(sizeof(typename ManagedType::Data), unmanagedSize));
- t->d_unchecked()->init(this, arg1);
- return t->d();
+ typename ManagedType::Data *o = reinterpret_cast<typename ManagedType::Data *>(allocString(unmanagedSize));
+ o->setVtable(ManagedType::staticVTable());
+ o->init(this, arg1);
+ return o;
}
template <typename ObjectType>
@@ -297,12 +425,15 @@ public:
size_t getAllocatedMem() const;
size_t getLargeItemsMem() const;
- void changeUnmanagedHeapSizeUsage(qptrdiff delta); // called when a JS object grows itself. Specifically: Heap::String::append
+ // called when a JS object grows itself. Specifically: Heap::String::append
+ void changeUnmanagedHeapSizeUsage(qptrdiff delta) { unmanagedHeapSize += delta; }
+
protected:
/// expects size to be aligned
- // TODO: try to inline
- Heap::Base *allocData(std::size_t size, std::size_t unmanagedSize);
+ Heap::Base *allocString(std::size_t unmanagedSize);
+ Heap::Base *allocData(std::size_t size);
+ Heap::Object *allocObjectWithMemberData(std::size_t size, uint nMembers);
#ifdef DETAILED_MM_STATS
void willAllocate(std::size_t size);
@@ -312,13 +443,24 @@ private:
void collectFromJSStack() const;
void mark();
void sweep(bool lastSweep = false);
+ bool shouldRunGC() const;
public:
QV4::ExecutionEngine *engine;
- QScopedPointer<Data> m_d;
+ ChunkAllocator *chunkAllocator;
+ StackAllocator<Heap::CallContext> stackAllocator;
+ BlockAllocator blockAllocator;
+ HugeItemAllocator hugeItemAllocator;
PersistentValueStorage *m_persistentValues;
PersistentValueStorage *m_weakValues;
QVector<Value *> m_pendingFreedObjectWrapperValue;
+
+ std::size_t unmanagedHeapSize = 0; // the amount of bytes of heap that is not managed by the memory manager, but which is held onto by managed items.
+ std::size_t unmanagedHeapSizeGCLimit;
+
+ bool gcBlocked = false;
+ bool aggressiveGC = false;
+ bool gcStats = false;
};
}
diff --git a/src/qml/memory/qv4mmdefs_p.h b/src/qml/memory/qv4mmdefs_p.h
new file mode 100644
index 0000000000..588ae21ee0
--- /dev/null
+++ b/src/qml/memory/qv4mmdefs_p.h
@@ -0,0 +1,262 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4MMDEFS_P_H
+#define QV4MMDEFS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <private/qv4global_p.h>
+#include <QtCore/qalgorithms.h>
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+/*
+ * Chunks are the basic structure containing GC managed objects.
+ *
+ * Chunks are 64k aligned in memory, so that retrieving the Chunk pointer from a Heap object
+ * is a simple masking operation. Each Chunk has 4 bitmaps for managing purposes,
+ * and 32byte wide slots for the objects following afterwards.
+ *
+ * The gray and black bitmaps are used for mark/sweep.
+ * The object bitmap has a bit set if this location represents the start of a Heap object.
+ * The extends bitmap denotes the extend of an object. It has a cleared bit at the start of the object
+ * and a set bit for all following slots used by the object.
+ *
+ * Free memory has both used and extends bits set to 0.
+ *
+ * This gives the following operations when allocating an object of size s:
+ * Find s/Alignment consecutive free slots in the chunk. Set the object bit for the first
+ * slot to 1. Set the extends bits for all following slots to 1.
+ *
+ * All used slots can be found by object|extents.
+ *
+ * When sweeping, simply copy the black bits over to the object bits.
+ *
+ */
+struct HeapItem;
+struct Chunk {
+ enum {
+ ChunkSize = 64*1024,
+ ChunkShift = 16,
+ SlotSize = 32,
+ SlotSizeShift = 5,
+ NumSlots = ChunkSize/SlotSize,
+ BitmapSize = NumSlots/8,
+ HeaderSize = 4*BitmapSize,
+ DataSize = ChunkSize - HeaderSize,
+ AvailableSlots = DataSize/SlotSize,
+#if QT_POINTER_SIZE == 8
+ Bits = 64,
+ BitShift = 6,
+#else
+ Bits = 32,
+ BitShift = 5,
+#endif
+ EntriesInBitmap = BitmapSize/sizeof(quintptr)
+ };
+ quintptr grayBitmap[BitmapSize/sizeof(quintptr)];
+ quintptr blackBitmap[BitmapSize/sizeof(quintptr)];
+ quintptr objectBitmap[BitmapSize/sizeof(quintptr)];
+ quintptr extendsBitmap[BitmapSize/sizeof(quintptr)];
+ char data[ChunkSize - HeaderSize];
+
+ HeapItem *realBase();
+ HeapItem *first();
+
+ static void setBit(quintptr *bitmap, size_t index) {
+// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
+ bitmap += index >> BitShift;
+ quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1));
+ *bitmap |= bit;
+ }
+ static void clearBit(quintptr *bitmap, size_t index) {
+// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
+ bitmap += index >> BitShift;
+ quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1));
+ *bitmap &= ~bit;
+ }
+ static bool testBit(quintptr *bitmap, size_t index) {
+// Q_ASSERT(index >= HeaderSize/SlotSize && index < ChunkSize/SlotSize);
+ bitmap += index >> BitShift;
+ quintptr bit = static_cast<quintptr>(1) << (index & (Bits - 1));
+ return (*bitmap & bit);
+ }
+ static void setBits(quintptr *bitmap, size_t index, size_t nBits) {
+// Q_ASSERT(index >= HeaderSize/SlotSize && index + nBits <= ChunkSize/SlotSize);
+ if (!nBits)
+ return;
+ bitmap += index >> BitShift;
+ index &= (Bits - 1);
+ while (1) {
+ size_t bitsToSet = qMin(nBits, Bits - index);
+ quintptr mask = static_cast<quintptr>(-1) >> (Bits - bitsToSet) << index;
+ *bitmap |= mask;
+ nBits -= bitsToSet;
+ if (!nBits)
+ return;
+ index = 0;
+ ++bitmap;
+ }
+ }
+ static bool hasNonZeroBit(quintptr *bitmap) {
+ for (uint i = 0; i < EntriesInBitmap; ++i)
+ if (bitmap[i])
+ return true;
+ return false;
+ }
+ static uint lowestNonZeroBit(quintptr *bitmap) {
+ for (uint i = 0; i < EntriesInBitmap; ++i) {
+ if (bitmap[i]) {
+ quintptr b = bitmap[i];
+ return i*Bits + qCountTrailingZeroBits(b);
+ }
+ }
+ return 0;
+ }
+
+ uint nFreeSlots() const {
+ return AvailableSlots - nUsedSlots();
+ }
+ uint nUsedSlots() const {
+ uint usedSlots = 0;
+ for (uint i = 0; i < EntriesInBitmap; ++i) {
+ quintptr used = objectBitmap[i] | extendsBitmap[i];
+ usedSlots += qPopulationCount(used);
+ }
+ return usedSlots;
+ }
+
+ void sweep();
+ void freeAll();
+
+ void sortIntoBins(HeapItem **bins, uint nBins);
+};
+
+struct HeapItem {
+ union {
+ struct {
+ HeapItem *next;
+ size_t availableSlots;
+ } freeData;
+ quint64 payload[Chunk::SlotSize/sizeof(quint64)];
+ };
+ operator Heap::Base *() { return reinterpret_cast<Heap::Base *>(this); }
+
+ template<typename T>
+ T *as() { return static_cast<T *>(reinterpret_cast<Heap::Base *>(this)); }
+
+ Chunk *chunk() const {
+ return reinterpret_cast<Chunk *>(reinterpret_cast<quintptr>(this) >> Chunk::ChunkShift << Chunk::ChunkShift);
+ }
+
+ bool isGray() const {
+ Chunk *c = chunk();
+ uint index = this - c->realBase();
+ return Chunk::testBit(c->grayBitmap, index);
+ }
+ bool isBlack() const {
+ Chunk *c = chunk();
+ uint index = this - c->realBase();
+ return Chunk::testBit(c->blackBitmap, index);
+ }
+ bool isInUse() const {
+ Chunk *c = chunk();
+ uint index = this - c->realBase();
+ return Chunk::testBit(c->objectBitmap, index);
+ }
+
+ void setAllocatedSlots(size_t nSlots) {
+// Q_ASSERT(size && !(size % sizeof(HeapItem)));
+ Chunk *c = chunk();
+ size_t index = this - c->realBase();
+// Q_ASSERT(!Chunk::testBit(c->objectBitmap, index));
+ Chunk::setBit(c->objectBitmap, index);
+ Chunk::setBits(c->extendsBitmap, index + 1, nSlots - 1);
+// for (uint i = index + 1; i < nBits - 1; ++i)
+// Q_ASSERT(Chunk::testBit(c->extendsBitmap, i));
+// Q_ASSERT(!Chunk::testBit(c->extendsBitmap, index));
+ }
+
+ // Doesn't report correctly for huge items
+ size_t size() const {
+ Chunk *c = chunk();
+ uint index = this - c->realBase();
+ Q_ASSERT(Chunk::testBit(c->objectBitmap, index));
+ // ### optimize me
+ uint end = index + 1;
+ while (end < Chunk::NumSlots && Chunk::testBit(c->extendsBitmap, end))
+ ++end;
+ return (end - index)*sizeof(HeapItem);
+ }
+};
+
+inline HeapItem *Chunk::realBase()
+{
+ return reinterpret_cast<HeapItem *>(this);
+}
+
+inline HeapItem *Chunk::first()
+{
+ return reinterpret_cast<HeapItem *>(data);
+}
+
+Q_STATIC_ASSERT(sizeof(Chunk) == Chunk::ChunkSize);
+Q_STATIC_ASSERT((1 << Chunk::ChunkShift) == Chunk::ChunkSize);
+Q_STATIC_ASSERT(1 << Chunk::SlotSizeShift == Chunk::SlotSize);
+Q_STATIC_ASSERT(sizeof(HeapItem) == Chunk::SlotSize);
+Q_STATIC_ASSERT(QT_POINTER_SIZE*8 == Chunk::Bits);
+Q_STATIC_ASSERT((1 << Chunk::BitShift) == Chunk::Bits);
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 4fbd828307..19ece44beb 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -199,7 +199,7 @@ void QQmlBoundSignalExpression::evaluate(void **a)
// for several cases (such as QVariant type and QObject-derived types)
//args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
if (type == qMetaTypeId<QJSValue>()) {
- if (QV4::Value *v4Value = QJSValuePrivate::getValue(reinterpret_cast<QJSValue *>(a[ii + 1])))
+ if (QV4::Value *v4Value = QJSValuePrivate::valueForData(reinterpret_cast<QJSValue *>(a[ii + 1]), &callData->args[ii]))
callData->args[ii] = *v4Value;
else
callData->args[ii] = QV4::Encode::undefined();
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index 50ed58e63d..a04f47e6a4 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -1063,11 +1063,11 @@ struct QmlIncubatorObject : public QV4::Object
V4_OBJECT2(QmlIncubatorObject, Object)
V4_NEEDS_DESTROY
- static QV4::ReturnedValue method_get_statusChanged(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_statusChanged(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_status(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_object(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_forceCompletion(QV4::CallContext *ctx);
+ static void method_get_statusChanged(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_set_statusChanged(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_status(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_object(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_forceCompletion(const BuiltinFunction *, Scope &scope, CallData *callData);
static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *e);
@@ -1415,58 +1415,53 @@ QQmlComponentExtension::QQmlComponentExtension(QV4::ExecutionEngine *v4)
incubationProto.set(v4, proto);
}
-QV4::ReturnedValue QV4::QmlIncubatorObject::method_get_object(QV4::CallContext *ctx)
+void QV4::QmlIncubatorObject::method_get_object(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>());
+ QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>());
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return QV4::QObjectWrapper::wrap(ctx->d()->engine, o->d()->incubator->object());
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, o->d()->incubator->object());
}
-QV4::ReturnedValue QV4::QmlIncubatorObject::method_forceCompletion(QV4::CallContext *ctx)
+void QV4::QmlIncubatorObject::method_forceCompletion(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>());
+ QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>());
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
o->d()->incubator->forceCompletion();
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
-QV4::ReturnedValue QV4::QmlIncubatorObject::method_get_status(QV4::CallContext *ctx)
+void QV4::QmlIncubatorObject::method_get_status(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>());
+ QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>());
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return QV4::Encode(o->d()->incubator->status());
+ scope.result = QV4::Encode(o->d()->incubator->status());
}
-QV4::ReturnedValue QV4::QmlIncubatorObject::method_get_statusChanged(QV4::CallContext *ctx)
+void QV4::QmlIncubatorObject::method_get_statusChanged(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>());
+ QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>());
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return o->d()->statusChanged.asReturnedValue();
+ scope.result = o->d()->statusChanged;
}
-QV4::ReturnedValue QV4::QmlIncubatorObject::method_set_statusChanged(QV4::CallContext *ctx)
+void QV4::QmlIncubatorObject::method_set_statusChanged(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QmlIncubatorObject> o(scope, ctx->thisObject().as<QmlIncubatorObject>());
- if (!o || ctx->argc() < 1)
- return ctx->engine()->throwTypeError();
+ QV4::Scoped<QmlIncubatorObject> o(scope, callData->thisObject.as<QmlIncubatorObject>());
+ if (!o || callData->argc < 1)
+ THROW_TYPE_ERROR();
+ o->d()->statusChanged = callData->args[0];
- o->d()->statusChanged = ctx->args()[0];
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
QQmlComponentExtension::~QQmlComponentExtension()
diff --git a/src/qml/qml/qqmldelayedcallqueue.cpp b/src/qml/qml/qqmldelayedcallqueue.cpp
index 7552e1e82b..d5d2c9a28d 100644
--- a/src/qml/qml/qqmldelayedcallqueue.cpp
+++ b/src/qml/qml/qqmldelayedcallqueue.cpp
@@ -105,17 +105,15 @@ void QQmlDelayedCallQueue::init(QV4::ExecutionEngine* engine)
m_tickedMethod = metaObject.method(methodIndex);
}
-QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(QV4::CallContext *ctx)
+void QQmlDelayedCallQueue::addUniquelyAndExecuteLater(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- const QV4::CallData *callData = ctx->d()->callData;
-
if (callData->argc == 0)
- V4THROW_ERROR("Qt.callLater: no arguments given");
+ THROW_GENERIC_ERROR("Qt.callLater: no arguments given");
const QV4::FunctionObject *func = callData->args[0].as<QV4::FunctionObject>();
if (!func)
- V4THROW_ERROR("Qt.callLater: first argument not a function or signal");
+ THROW_GENERIC_ERROR("Qt.callLater: first argument not a function or signal");
QPair<QObject *, int> functionData = QV4::QObjectMethod::extractQtMethod(func);
@@ -171,7 +169,7 @@ QV4::ReturnedValue QQmlDelayedCallQueue::addUniquelyAndExecuteLater(QV4::CallCon
m_tickedMethod.invoke(this, Qt::QueuedConnection);
m_callbackOutstanding = true;
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
void QQmlDelayedCallQueue::storeAnyArguments(DelayedFunctionCall &dfc, const QV4::CallData *callData, int offset, QV4::ExecutionEngine *engine)
diff --git a/src/qml/qml/qqmldelayedcallqueue_p.h b/src/qml/qml/qqmldelayedcallqueue_p.h
index ef899170a2..cffde4f0c0 100644
--- a/src/qml/qml/qqmldelayedcallqueue_p.h
+++ b/src/qml/qml/qqmldelayedcallqueue_p.h
@@ -70,7 +70,7 @@ public:
void init(QV4::ExecutionEngine *);
- QV4::ReturnedValue addUniquelyAndExecuteLater(QV4::CallContext *ctx);
+ void addUniquelyAndExecuteLater(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
public Q_SLOTS:
void ticked();
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 8712b638c5..c07d5c740a 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2017 Crimson AS <info@crimson.no>
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
@@ -130,42 +131,74 @@ bool isPathAbsolute(const QString &path)
#endif
}
-// If the type does not already exist as a file import, add the type and return the new type
-QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeName,
+/*
+ \internal
+
+ Fetches the QQmlType instance registered for \a urlString, creating a
+ registration for it if it is not already registered, using the associated
+ \a typeName, \a isCompositeSingleton, \a majorVersion and \a minorVersion
+ details.
+
+ Errors (if there are any) are placed into \a errors, if it is nonzero. Note
+ that errors are treated as fatal if \a errors is not set.
+*/
+QQmlType *fetchOrCreateTypeForUrl(const QString &urlString, const QHashedStringRef& typeName,
bool isCompositeSingleton, QList<QQmlError> *errors,
int majorVersion=-1, int minorVersion=-1)
{
- QUrl url(urlString);
+ QUrl url(urlString); // ### unfortunate (costly) conversion
QQmlType *ret = QQmlMetaType::qmlType(url);
- if (!ret) { //QQmlType not yet existing for composite or composite singleton type
- int dot = typeName.indexOf(QLatin1Char('.'));
- QHashedStringRef unqualifiedtype = dot < 0 ? typeName : QHashedStringRef(typeName.constData() + dot + 1, typeName.length() - dot - 1);
-
- //XXX: The constData of the string ref is pointing somewhere unsafe in qmlregister, so we need to create a temporary copy
- QByteArray buf(unqualifiedtype.toString().toUtf8());
-
- if (isCompositeSingleton) {
- QQmlPrivate::RegisterCompositeSingletonType reg = {
- url,
- "", //Empty URI indicates loaded via file imports
- majorVersion,
- minorVersion,
- buf.constData()
- };
- ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeSingletonRegistration, &reg));
- } else {
- QQmlPrivate::RegisterCompositeType reg = {
- url,
- "", //Empty URI indicates loaded via file imports
- majorVersion,
- minorVersion,
- buf.constData()
- };
- ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &reg));
- }
+ if (ret)
+ return ret;
+
+ int dot = typeName.indexOf(QLatin1Char('.'));
+ QHashedStringRef unqualifiedtype = dot < 0 ? typeName : QHashedStringRef(typeName.constData() + dot + 1, typeName.length() - dot - 1);
+
+ // We need a pointer, but we were passed a string. Take a copy so we
+ // can guarentee it will live long enough to reach qmlregister.
+ QByteArray buf(unqualifiedtype.toString().toUtf8());
+
+ // Register the type. Note that the URI parameters here are empty; for
+ // file type imports, we do not place them in a URI as we don't
+ // necessarily have a good and unique one (picture a library import,
+ // which may be found in multiple plugin locations on disk), but there
+ // are other reasons for this too.
+ //
+ // By not putting them in a URI, we prevent the types from being
+ // registered on a QQmlTypeModule; this is important, as once types are
+ // placed on there, they cannot be easily removed, meaning if the
+ // developer subsequently loads a different import (meaning different
+ // types) with the same URI (using, say, a different plugin path), it is
+ // very undesirable that we continue to associate the types from the
+ // "old" URI with that new module.
+ //
+ // Not having URIs also means that the types cannot be found by name
+ // etc, the only way to look them up is through QQmlImports -- for
+ // better or worse.
+ if (isCompositeSingleton) {
+ QQmlPrivate::RegisterCompositeSingletonType reg = {
+ url,
+ "", // uri
+ majorVersion,
+ minorVersion,
+ buf.constData()
+ };
+ ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeSingletonRegistration, &reg));
+ } else {
+ QQmlPrivate::RegisterCompositeType reg = {
+ url,
+ "", // uri
+ majorVersion,
+ minorVersion,
+ buf.constData()
+ };
+ ret = QQmlMetaType::qmlTypeFromIndex(QQmlPrivate::qmlregister(QQmlPrivate::CompositeRegistration, &reg));
}
- if (!ret) {//Usually when a type name is "found" but invalid
- //qDebug() << ret << urlString << QQmlMetaType::qmlType(url);
+
+ // This means that the type couldn't be found by URL, but could not be
+ // registered either, meaning we most likely were passed some kind of bad
+ // data.
+ if (!ret) {
if (!errors) // Cannot list errors properly, just quit
qFatal("%s", QQmlMetaType::typeRegistrationFailures().join('\n').toLatin1().constData());
QQmlError error;
@@ -204,44 +237,38 @@ void qmlClearEnginePlugins()
typedef QPair<QStaticPlugin, QJsonArray> StaticPluginPair;
#endif
-class QQmlImportNamespace
-{
-public:
- QQmlImportNamespace() : nextNamespace(0) {}
- ~QQmlImportNamespace() { qDeleteAll(imports); }
-
- struct Import {
- QString uri;
- QString url;
- int majversion;
- int minversion;
- bool isLibrary;
- QQmlDirComponents qmlDirComponents;
- QQmlDirScripts qmlDirScripts;
-
- bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoader::QmldirContent *qmldir,
- QQmlImportNamespace *nameSpace, QList<QQmlError> *errors);
-
- static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin);
-
- bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
- int *vmajor, int *vminor, QQmlType** type_return,
- QString *base = 0, bool *typeRecursionDetected = 0) const;
- };
- QList<Import *> imports;
+/*!
+ \internal
+ \class QQmlImportInstance
- Import *findImport(const QString &uri) const;
+ A QQmlImportType represents a single import of a document, held within a
+ namespace.
- bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
- int *vmajor, int *vminor, QQmlType** type_return,
- QString *base = 0, QList<QQmlError> *errors = 0);
+ \note The uri here may not necessarily be unique (e.g. for file imports).
- // Prefix when used as a qualified import. Otherwise empty.
- QHashedString prefix;
+ \note Version numbers may be -1 for file imports: this means that no
+ version was specified as part of the import. Type resolution will be
+ responsible for attempting to find the "best" possible version.
+*/
- // Used by QQmlImportsPrivate::qualifiedSets
- QQmlImportNamespace *nextNamespace;
-};
+/*!
+ \internal
+ \class QQmlImportNamespace
+
+ A QQmlImportNamespace is a way of seperating imports into a local namespace.
+
+ Within a QML document, there is at least one namespace (the
+ "unqualified set") where imports without a qualifier are placed, i.e:
+
+ import QtQuick 2.6
+
+ will have a single namespace (the unqualified set) containing a single import
+ for QtQuick 2.6. However, there may be others if an import statement gives
+ a qualifier, i.e the following will result in an additional new
+ QQmlImportNamespace in the qualified set:
+
+ import MyFoo 1.0 as Foo
+*/
class QQmlImportsPrivate
{
@@ -273,9 +300,12 @@ public:
QString base;
int ref;
+ // storage of data related to imports without a namespace
mutable QQmlImportNamespace unqualifiedset;
QQmlImportNamespace *findQualifiedNamespace(const QHashedStringRef &) const;
+
+ // storage of data related to imports with a namespace
mutable QFieldList<QQmlImportNamespace, &QQmlImportNamespace::nextNamespace> qualifiedSets;
QQmlTypeLoader *typeLoader;
@@ -284,21 +314,21 @@ public:
QQmlImportDatabase *database,
QString *outQmldirFilePath, QString *outUrl);
- static bool validateQmldirVersion(const QQmlTypeLoader::QmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
+ static bool validateQmldirVersion(const QQmlTypeLoaderQmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
QList<QQmlError> *errors);
bool importExtension(const QString &absoluteFilePath, const QString &uri,
int vmaj, int vmin,
QQmlImportDatabase *database,
- const QQmlTypeLoader::QmldirContent *qmldir,
+ const QQmlTypeLoaderQmldirContent *qmldir,
QList<QQmlError> *errors);
bool getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
- const QQmlTypeLoader::QmldirContent **qmldir, QList<QQmlError> *errors);
+ const QQmlTypeLoaderQmldirContent **qmldir, QList<QQmlError> *errors);
QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database);
- QQmlImportNamespace::Import *addImportToNamespace(QQmlImportNamespace *nameSpace,
+ QQmlImportInstance *addImportToNamespace(QQmlImportNamespace *nameSpace,
const QString &uri, const QString &url,
int vmaj, int vmin, QV4::CompiledData::Import::ImportType type,
QList<QQmlError> *errors, bool lowPrecedence = false);
@@ -363,12 +393,22 @@ QUrl QQmlImports::baseUrl() const
return d->baseUrl;
}
+/*
+ \internal
+
+ This method is responsible for populating data of all types visible in this
+ document's imports into the \a cache for resolution elsewhere (e.g. in JS,
+ or when loading additional types).
+
+ \note This is for C++ types only. Composite types are handled separately,
+ as they do not have a QQmlTypeModule.
+*/
void QQmlImports::populateCache(QQmlTypeNameCache *cache) const
{
const QQmlImportNamespace &set = d->unqualifiedset;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion);
if (module) {
cache->m_anonymousImports.append(QQmlTypeModuleVersion(module, import->minversion));
@@ -379,11 +419,14 @@ void QQmlImports::populateCache(QQmlTypeNameCache *cache) const
const QQmlImportNamespace &set = *ns;
+ // positioning is important; we must create the namespace even if there is no module.
+ QQmlTypeNameCache::Import &typeimport = cache->m_namedImports[set.prefix];
+ typeimport.m_qualifier = set.prefix;
+
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
QQmlTypeModule *module = QQmlMetaType::typeModule(import->uri, import->majversion);
if (module) {
- QQmlTypeNameCache::Import &typeimport = cache->m_namedImports[set.prefix];
typeimport.modules.append(QQmlTypeModuleVersion(module, import->minversion));
}
}
@@ -412,7 +455,7 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::
typedef QQmlDirComponents::const_iterator ConstIterator;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
const QQmlDirComponents &components = import->qmlDirComponents;
@@ -430,6 +473,15 @@ void findCompositeSingletons(const QQmlImportNamespace &set, QList<QQmlImports::
}
}
+/*
+ \internal
+
+ Returns a list of all composite singletons present in this document's
+ imports.
+
+ This information is used by QQmlTypeLoader to ensure that composite singletons
+ are marked as dependencies during type loading.
+*/
QList<QQmlImports::CompositeSingletonReference> QQmlImports::resolvedCompositeSingletons() const
{
QList<QQmlImports::CompositeSingletonReference> compositeSingletons;
@@ -445,6 +497,12 @@ QList<QQmlImports::CompositeSingletonReference> QQmlImports::resolvedCompositeSi
return compositeSingletons;
}
+/*
+ \internal
+
+ Returns a list of scripts imported by this document. This is used by
+ QQmlTypeLoader to properly handle dependencies on imported scripts.
+*/
QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
{
QList<QQmlImports::ScriptReference> scripts;
@@ -452,7 +510,7 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
const QQmlImportNamespace &set = d->unqualifiedset;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
for (const QQmlDirParser::Script &script : import->qmlDirScripts) {
ScriptReference ref;
@@ -466,7 +524,7 @@ QList<QQmlImports::ScriptReference> QQmlImports::resolvedScripts() const
const QQmlImportNamespace &set = *ns;
for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
- const QQmlImportNamespace::Import *import = set.imports.at(ii);
+ const QQmlImportInstance *import = set.imports.at(ii);
for (const QQmlDirParser::Script &script : import->qmlDirScripts) {
ScriptReference ref;
@@ -590,7 +648,7 @@ bool QQmlImports::resolveType(const QHashedStringRef &type,
return false;
}
-bool QQmlImportNamespace::Import::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoader::QmldirContent *qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
+bool QQmlImportInstance::setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent *qmldir, QQmlImportNamespace *nameSpace, QList<QQmlError> *errors)
{
Q_ASSERT(resolvedUrl.endsWith(Slash));
url = resolvedUrl;
@@ -600,7 +658,7 @@ bool QQmlImportNamespace::Import::setQmldirContent(const QString &resolvedUrl, c
const QQmlDirScripts &scripts = qmldir->scripts();
if (!scripts.isEmpty()) {
// Verify that we haven't imported these scripts already
- for (QList<QQmlImportNamespace::Import *>::const_iterator it = nameSpace->imports.constBegin();
+ for (QList<QQmlImportInstance *>::const_iterator it = nameSpace->imports.constBegin();
it != nameSpace->imports.constEnd(); ++it) {
if ((*it != this) && ((*it)->uri == uri)) {
QQmlError error;
@@ -616,7 +674,7 @@ bool QQmlImportNamespace::Import::setQmldirContent(const QString &resolvedUrl, c
return true;
}
-QQmlDirScripts QQmlImportNamespace::Import::getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin)
+QQmlDirScripts QQmlImportInstance::getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin)
{
QMap<QString, QQmlDirParser::Script> versioned;
@@ -652,7 +710,7 @@ bool QQmlImports::resolveType(QQmlImportNamespace* ns, const QHashedStringRef &t
return ns->resolveType(d->typeLoader,type,vmaj,vmin,type_return);
}
-bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
+bool QQmlImportInstance::resolveType(QQmlTypeLoader *typeLoader,
const QHashedStringRef& type, int *vmajor, int *vminor,
QQmlType** type_return, QString *base, bool *typeRecursionDetected) const
{
@@ -683,15 +741,17 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
if ((candidate == end) ||
(c.majorVersion > candidate->majorVersion) ||
((c.majorVersion == candidate->majorVersion) && (c.minorVersion > candidate->minorVersion))) {
- componentUrl = resolveLocalUrl(QString(url + c.typeName + dotqml_string), c.fileName);
- if (c.internal && base) {
- if (resolveLocalUrl(*base, c.fileName) != componentUrl)
- continue; // failed attempt to access an internal type
- }
- if (base && (*base == componentUrl)) {
- if (typeRecursionDetected)
- *typeRecursionDetected = true;
- continue; // no recursion
+ if (base) {
+ componentUrl = resolveLocalUrl(QString(url + c.typeName + dotqml_string), c.fileName);
+ if (c.internal) {
+ if (resolveLocalUrl(*base, c.fileName) != componentUrl)
+ continue; // failed attempt to access an internal type
+ }
+ if (*base == componentUrl) {
+ if (typeRecursionDetected)
+ *typeRecursionDetected = true;
+ continue; // no recursion
+ }
}
// This is our best candidate so far
@@ -702,9 +762,11 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
}
if (candidate != end) {
+ if (!base) // ensure we have a componentUrl
+ componentUrl = resolveLocalUrl(QString(url + candidate->typeName + dotqml_string), candidate->fileName);
int major = vmajor ? *vmajor : -1;
int minor = vminor ? *vminor : -1;
- QQmlType *returnType = getTypeForUrl(componentUrl, type, isCompositeSingleton, 0,
+ QQmlType *returnType = fetchOrCreateTypeForUrl(componentUrl, type, isCompositeSingleton, 0,
major, minor);
if (type_return)
*type_return = returnType;
@@ -732,7 +794,7 @@ bool QQmlImportNamespace::Import::resolveType(QQmlTypeLoader *typeLoader,
if (typeRecursionDetected)
*typeRecursionDetected = true;
} else {
- QQmlType *returnType = getTypeForUrl(qmlUrl, type, false, 0);
+ QQmlType *returnType = fetchOrCreateTypeForUrl(qmlUrl, type, false, 0);
if (type_return)
*type_return = returnType;
return returnType != 0;
@@ -777,7 +839,7 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
return true;
if (s->imports.count() == 1 && !s->imports.at(0)->isLibrary && type_return && s != &unqualifiedset) {
// qualified, and only 1 url
- *type_return = getTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, false, errors);
+ *type_return = fetchOrCreateTypeForUrl(resolveLocalUrl(s->imports.at(0)->url, unqualifiedtype.toString() + QLatin1String(".qml")), type, false, errors);
return (*type_return != 0);
}
}
@@ -785,9 +847,9 @@ bool QQmlImportsPrivate::resolveType(const QHashedStringRef& type, int *vmajor,
return false;
}
-QQmlImportNamespace::Import *QQmlImportNamespace::findImport(const QString &uri) const
+QQmlImportInstance *QQmlImportNamespace::findImport(const QString &uri) const
{
- for (Import *import : imports) {
+ for (QQmlImportInstance *import : imports) {
if (import->uri == uri)
return import;
}
@@ -800,13 +862,13 @@ bool QQmlImportNamespace::resolveType(QQmlTypeLoader *typeLoader, const QHashedS
{
bool typeRecursionDetected = false;
for (int i=0; i<imports.count(); ++i) {
- const Import *import = imports.at(i);
+ const QQmlImportInstance *import = imports.at(i);
if (import->resolveType(typeLoader, type, vmajor, vminor, type_return,
base, &typeRecursionDetected)) {
if (qmlCheckTypes()) {
// check for type clashes
for (int j = i+1; j<imports.count(); ++j) {
- const Import *import2 = imports.at(j);
+ const QQmlImportInstance *import2 = imports.at(j);
if (import2->resolveType(typeLoader, type, vmajor, vminor, 0, base)) {
if (errors) {
QString u1 = import->url;
@@ -949,10 +1011,12 @@ bool QQmlImportsPrivate::populatePluginPairVector(QVector<StaticPluginPair> &res
}
#endif
+#if defined(QT_SHARED) || !QT_CONFIG(library)
static inline QString msgCannotLoadPlugin(const QString &uri, const QString &why)
{
return QQmlImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri, why);
}
+#endif
/*!
Import an extension defined by a qmldir file.
@@ -963,7 +1027,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
const QString &uri,
int vmaj, int vmin,
QQmlImportDatabase *database,
- const QQmlTypeLoader::QmldirContent *qmldir,
+ const QQmlTypeLoaderQmldirContent *qmldir,
QList<QQmlError> *errors)
{
#if QT_CONFIG(library)
@@ -1099,7 +1163,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
}
bool QQmlImportsPrivate::getQmldirContent(const QString &qmldirIdentifier, const QString &uri,
- const QQmlTypeLoader::QmldirContent **qmldir, QList<QQmlError> *errors)
+ const QQmlTypeLoaderQmldirContent **qmldir, QList<QQmlError> *errors)
{
Q_ASSERT(errors);
Q_ASSERT(qmldir);
@@ -1224,7 +1288,7 @@ bool QQmlImportsPrivate::locateQmldir(const QString &uri, int vmaj, int vmin, QQ
return false;
}
-bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoader::QmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
+bool QQmlImportsPrivate::validateQmldirVersion(const QQmlTypeLoaderQmldirContent *qmldir, const QString &uri, int vmaj, int vmin,
QList<QQmlError> *errors)
{
int lowest_min = INT_MAX;
@@ -1307,7 +1371,7 @@ QQmlImportNamespace *QQmlImportsPrivate::importNamespace(const QString &prefix)
return nameSpace;
}
-QQmlImportNamespace::Import *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace *nameSpace,
+QQmlImportInstance *QQmlImportsPrivate::addImportToNamespace(QQmlImportNamespace *nameSpace,
const QString &uri, const QString &url, int vmaj, int vmin,
QV4::CompiledData::Import::ImportType type,
QList<QQmlError> *errors, bool lowPrecedence)
@@ -1317,7 +1381,7 @@ QQmlImportNamespace::Import *QQmlImportsPrivate::addImportToNamespace(QQmlImport
Q_UNUSED(errors);
Q_ASSERT(url.isEmpty() || url.endsWith(Slash));
- QQmlImportNamespace::Import *import = new QQmlImportNamespace::Import;
+ QQmlImportInstance *import = new QQmlImportInstance;
import->uri = uri;
import->url = url;
import->majversion = vmaj;
@@ -1343,11 +1407,11 @@ bool QQmlImportsPrivate::addLibraryImport(const QString& uri, const QString &pre
QQmlImportNamespace *nameSpace = importNamespace(prefix);
Q_ASSERT(nameSpace);
- QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, uri, qmldirUrl, vmaj, vmin, QV4::CompiledData::Import::ImportLibrary, errors);
+ QQmlImportInstance *inserted = addImportToNamespace(nameSpace, uri, qmldirUrl, vmaj, vmin, QV4::CompiledData::Import::ImportLibrary, errors);
Q_ASSERT(inserted);
if (!incomplete) {
- const QQmlTypeLoader::QmldirContent *qmldir = 0;
+ const QQmlTypeLoaderQmldirContent *qmldir = 0;
if (!qmldirIdentifier.isEmpty()) {
if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
@@ -1444,11 +1508,11 @@ bool QQmlImportsPrivate::addFileImport(const QString& uri, const QString &prefix
if (!url.endsWith(Slash) && !url.endsWith(Backslash))
url += Slash;
- QQmlImportNamespace::Import *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QV4::CompiledData::Import::ImportFile, errors, isImplicitImport);
+ QQmlImportInstance *inserted = addImportToNamespace(nameSpace, importUri, url, vmaj, vmin, QV4::CompiledData::Import::ImportFile, errors, isImplicitImport);
Q_ASSERT(inserted);
if (!incomplete && !qmldirIdentifier.isEmpty()) {
- const QQmlTypeLoader::QmldirContent *qmldir = 0;
+ const QQmlTypeLoaderQmldirContent *qmldir = 0;
if (!getQmldirContent(qmldirIdentifier, importUri, &qmldir, errors))
return false;
@@ -1471,8 +1535,8 @@ bool QQmlImportsPrivate::updateQmldirContent(const QString &uri, const QString &
QQmlImportNamespace *nameSpace = importNamespace(prefix);
Q_ASSERT(nameSpace);
- if (QQmlImportNamespace::Import *import = nameSpace->findImport(uri)) {
- const QQmlTypeLoader::QmldirContent *qmldir = 0;
+ if (QQmlImportInstance *import = nameSpace->findImport(uri)) {
+ const QQmlTypeLoaderQmldirContent *qmldir = 0;
if (!getQmldirContent(qmldirIdentifier, uri, &qmldir, errors))
return false;
diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h
index 0e7848730f..7c691a468c 100644
--- a/src/qml/qml/qqmlimport_p.h
+++ b/src/qml/qml/qqmlimport_p.h
@@ -68,6 +68,48 @@ class QQmlImportNamespace;
class QQmlImportsPrivate;
class QQmlImportDatabase;
class QQmlTypeLoader;
+class QQmlTypeLoaderQmldirContent;
+
+struct QQmlImportInstance
+{
+ QString uri; // e.g. QtQuick
+ QString url; // the base path of the import
+ int majversion; // the major version imported
+ int minversion; // the minor version imported
+ bool isLibrary; // true means that this is not a file import
+ QQmlDirComponents qmlDirComponents; // a copy of the components listed in the qmldir
+ QQmlDirScripts qmlDirScripts; // a copy of the scripts in the qmldir
+
+ bool setQmldirContent(const QString &resolvedUrl, const QQmlTypeLoaderQmldirContent *qmldir,
+ QQmlImportNamespace *nameSpace, QList<QQmlError> *errors);
+
+ static QQmlDirScripts getVersionedScripts(const QQmlDirScripts &qmldirscripts, int vmaj, int vmin);
+
+ bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef &type,
+ int *vmajor, int *vminor, QQmlType** type_return,
+ QString *base = 0, bool *typeRecursionDetected = 0) const;
+};
+
+class QQmlImportNamespace
+{
+public:
+ QQmlImportNamespace() : nextNamespace(0) {}
+ ~QQmlImportNamespace() { qDeleteAll(imports); }
+
+ QList<QQmlImportInstance *> imports;
+
+ QQmlImportInstance *findImport(const QString &uri) const;
+
+ bool resolveType(QQmlTypeLoader *typeLoader, const QHashedStringRef& type,
+ int *vmajor, int *vminor, QQmlType** type_return,
+ QString *base = 0, QList<QQmlError> *errors = 0);
+
+ // Prefix when used as a qualified import. Otherwise empty.
+ QHashedString prefix;
+
+ // Used by QQmlImportsPrivate::qualifiedSets
+ QQmlImportNamespace *nextNamespace;
+};
class Q_QML_PRIVATE_EXPORT QQmlImports
{
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index 3876e774c3..712da78807 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -56,10 +56,17 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(QQmlLocaleData);
+#define THROW_ERROR(string) \
+ do { \
+ scope.result = scope.engine->throwError(QString::fromUtf8(string)); \
+ return; \
+ } while (false)
+
+
#define GET_LOCALE_DATA_RESOURCE(OBJECT) \
QV4::Scoped<QQmlLocaleData> r(scope, OBJECT.as<QQmlLocaleData>()); \
if (!r) \
- V4THROW_ERROR("Not a valid Locale object")
+ THROW_ERROR("Not a valid Locale object")
static bool isLocaleObject(const QV4::Value &val)
{
@@ -80,215 +87,219 @@ void QQmlDateExtension::registerExtension(QV4::ExecutionEngine *engine)
engine->dateCtor()->defineDefaultProperty(QStringLiteral("timeZoneUpdated"), method_timeZoneUpdated);
}
-QV4::ReturnedValue QQmlDateExtension::method_toLocaleString(QV4::CallContext *ctx)
+void QQmlDateExtension::method_toLocaleString(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- if (ctx->argc() > 2)
- return QV4::DatePrototype::method_toLocaleString(ctx);
-
- QV4::Scope scope(ctx);
+ if (callData->argc > 2) {
+ QV4::DatePrototype::method_toLocaleString(b, scope, callData);
+ return;
+ }
- QV4::DateObject *date = ctx->thisObject().as<DateObject>();
- if (!date)
- return QV4::DatePrototype::method_toLocaleString(ctx);
+ QV4::DateObject *date = callData->thisObject.as<DateObject>();
+ if (!date) {
+ QV4::DatePrototype::method_toLocaleString(b, scope, callData);
+ return;
+ }
QDateTime dt = date->toQDateTime();
- if (ctx->argc() == 0) {
+ if (callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->d()->engine->newString(locale.toString(dt))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(locale.toString(dt)));
}
- if (!isLocaleObject(ctx->args()[0]))
- return QV4::DatePrototype::method_toLocaleString(ctx); // Use the default Date toLocaleString()
+ if (!isLocaleObject(callData->args[0])) {
+ QV4::DatePrototype::method_toLocaleString(b, scope, callData); // Use the default Date toLocaleString()
+ return;
+ }
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QString formattedDt;
- if (ctx->argc() == 2) {
- if (String *s = ctx->args()[1].stringValue()) {
+ if (callData->argc == 2) {
+ if (String *s = callData->args[1].stringValue()) {
QString format = s->toQString();
formattedDt = r->d()->locale->toString(dt, format);
- } else if (ctx->args()[1].isNumber()) {
- quint32 intFormat = ctx->args()[1].toNumber();
+ } else if (callData->args[1].isNumber()) {
+ quint32 intFormat = callData->args[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
formattedDt = r->d()->locale->toString(dt, format);
} else {
- V4THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format");
+ THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format");
}
} else {
formattedDt = r->d()->locale->toString(dt, enumFormat);
}
- return ctx->d()->engine->newString(formattedDt)->asReturnedValue();
+ scope.result = scope.engine->newString(formattedDt);
}
-QV4::ReturnedValue QQmlDateExtension::method_toLocaleTimeString(QV4::CallContext *ctx)
+void QQmlDateExtension::method_toLocaleTimeString(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- if (ctx->argc() > 2)
- return QV4::DatePrototype::method_toLocaleTimeString(ctx);
-
- QV4::Scope scope(ctx);
+ if (callData->argc > 2) {
+ QV4::DatePrototype::method_toLocaleTimeString(b, scope, callData);
+ return;
+ }
- QV4::DateObject *date = ctx->thisObject().as<DateObject>();
- if (!date)
- return QV4::DatePrototype::method_toLocaleTimeString(ctx);
+ QV4::DateObject *date = callData->thisObject.as<DateObject>();
+ if (!date) {
+ QV4::DatePrototype::method_toLocaleTimeString(b, scope, callData);
+ return;
+ }
QDateTime dt = date->toQDateTime();
QTime time = dt.time();
- if (ctx->argc() == 0) {
+ if (callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->d()->engine->newString(locale.toString(time))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(locale.toString(time)));
}
- if (!isLocaleObject(ctx->args()[0]))
- return QV4::DatePrototype::method_toLocaleTimeString(ctx); // Use the default Date toLocaleTimeString()
+ if (!isLocaleObject(callData->args[0]))
+ return QV4::DatePrototype::method_toLocaleTimeString(b, scope, callData); // Use the default Date toLocaleTimeString()
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QString formattedTime;
- if (ctx->argc() == 2) {
- if (String *s = ctx->args()[1].stringValue()) {
+ if (callData->argc == 2) {
+ if (String *s = callData->args[1].stringValue()) {
QString format = s->toQString();
formattedTime = r->d()->locale->toString(time, format);
- } else if (ctx->args()[1].isNumber()) {
- quint32 intFormat = ctx->args()[1].toNumber();
+ } else if (callData->args[1].isNumber()) {
+ quint32 intFormat = callData->args[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
formattedTime = r->d()->locale->toString(time, format);
} else {
- V4THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format");
+ THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format");
}
} else {
formattedTime = r->d()->locale->toString(time, enumFormat);
}
- return ctx->d()->engine->newString(formattedTime)->asReturnedValue();
+ scope.result = scope.engine->newString(formattedTime);
}
-QV4::ReturnedValue QQmlDateExtension::method_toLocaleDateString(QV4::CallContext *ctx)
+void QQmlDateExtension::method_toLocaleDateString(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- if (ctx->argc() > 2)
- return QV4::DatePrototype::method_toLocaleDateString(ctx);
-
- QV4::Scope scope(ctx);
+ if (callData->argc > 2) {
+ QV4::DatePrototype::method_toLocaleDateString(b, scope, callData);
+ return;
+ }
- QV4::DateObject *dateObj = ctx->thisObject().as<DateObject>();
- if (!dateObj)
- return QV4::DatePrototype::method_toLocaleDateString(ctx);
+ QV4::DateObject *dateObj = callData->thisObject.as<DateObject>();
+ if (!dateObj) {
+ QV4::DatePrototype::method_toLocaleDateString(b, scope, callData);
+ return;
+ }
QDateTime dt = dateObj->toQDateTime();
QDate date = dt.date();
- if (ctx->argc() == 0) {
+ if (callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->d()->engine->newString(locale.toString(date))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(locale.toString(date)));
}
- if (!isLocaleObject(ctx->args()[0]))
- return QV4::DatePrototype::method_toLocaleDateString(ctx); // Use the default Date toLocaleDateString()
+ if (!isLocaleObject(callData->args[0]))
+ return QV4::DatePrototype::method_toLocaleDateString(b, scope, callData); // Use the default Date toLocaleDateString()
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QString formattedDate;
- if (ctx->argc() == 2) {
- if (String *s = ctx->args()[1].stringValue()) {
+ if (callData->argc == 2) {
+ if (String *s = callData->args[1].stringValue()) {
QString format = s->toQString();
formattedDate = r->d()->locale->toString(date, format);
- } else if (ctx->args()[1].isNumber()) {
- quint32 intFormat = ctx->args()[1].toNumber();
+ } else if (callData->args[1].isNumber()) {
+ quint32 intFormat = callData->args[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
formattedDate = r->d()->locale->toString(date, format);
} else {
- V4THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format");
+ THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format");
}
} else {
formattedDate = r->d()->locale->toString(date, enumFormat);
}
- return ctx->d()->engine->newString(formattedDate)->asReturnedValue();
+ scope.result = scope.engine->newString(formattedDate);
}
-QV4::ReturnedValue QQmlDateExtension::method_fromLocaleString(QV4::CallContext *ctx)
+void QQmlDateExtension::method_fromLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::ExecutionEngine * const engine = ctx->d()->engine;
- if (ctx->argc() == 1) {
- if (String *s = ctx->args()[0].stringValue()) {
+ QV4::ExecutionEngine * const engine = scope.engine;
+ if (callData->argc == 1) {
+ if (String *s = callData->args[0].stringValue()) {
QLocale locale;
QString dateString = s->toQString();
QDateTime dt = locale.toDateTime(dateString);
- return QV4::Encode(engine->newDateObject(dt));
+ RETURN_RESULT(engine->newDateObject(dt));
}
}
- QV4::Scope scope(ctx);
-
- if (ctx->argc() < 1 || ctx->argc() > 3 || !isLocaleObject(ctx->args()[0]))
- V4THROW_ERROR("Locale: Date.fromLocaleString(): Invalid arguments");
+ if (callData->argc < 1 || callData->argc > 3 || !isLocaleObject(callData->args[0]))
+ THROW_ERROR("Locale: Date.fromLocaleString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QDateTime dt;
- QString dateString = ctx->args()[1].toQStringNoThrow();
- if (ctx->argc() == 3) {
- if (String *s = ctx->args()[2].stringValue()) {
+ QString dateString = callData->args[1].toQStringNoThrow();
+ if (callData->argc == 3) {
+ if (String *s = callData->args[2].stringValue()) {
QString format = s->toQString();
dt = r->d()->locale->toDateTime(dateString, format);
- } else if (ctx->args()[2].isNumber()) {
- quint32 intFormat = ctx->args()[2].toNumber();
+ } else if (callData->args[2].isNumber()) {
+ quint32 intFormat = callData->args[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
dt = r->d()->locale->toDateTime(dateString, format);
} else {
- V4THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format");
+ THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format");
}
} else {
dt = r->d()->locale->toDateTime(dateString, enumFormat);
}
- return QV4::Encode(engine->newDateObject(dt));
+ scope.result = engine->newDateObject(dt);
}
-QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallContext *ctx)
+void QQmlDateExtension::method_fromLocaleTimeString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::ExecutionEngine * const engine = ctx->d()->engine;
+ QV4::ExecutionEngine * const engine = scope.engine;
- if (ctx->argc() == 1) {
- if (String *s = ctx->args()[0].stringValue()) {
+ if (callData->argc == 1) {
+ if (String *s = callData->args[0].stringValue()) {
QLocale locale;
QString timeString = s->toQString();
QTime time = locale.toTime(timeString);
QDateTime dt = QDateTime::currentDateTime();
dt.setTime(time);
- return QV4::Encode(engine->newDateObject(dt));
+ RETURN_RESULT(engine->newDateObject(dt));
}
}
- if (ctx->argc() < 1 || ctx->argc() > 3 || !isLocaleObject(ctx->args()[0]))
- V4THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid arguments");
-
- QV4::Scope scope(ctx);
+ if (callData->argc < 1 || callData->argc > 3 || !isLocaleObject(callData->args[0]))
+ THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QTime tm;
- QString dateString = ctx->args()[1].toQStringNoThrow();
- if (ctx->argc() == 3) {
- if (String *s = ctx->args()[2].stringValue()) {
+ QString dateString = callData->args[1].toQStringNoThrow();
+ if (callData->argc == 3) {
+ if (String *s = callData->args[2].stringValue()) {
QString format = s->toQString();
tm = r->d()->locale->toTime(dateString, format);
- } else if (ctx->args()[2].isNumber()) {
- quint32 intFormat = ctx->args()[2].toNumber();
+ } else if (callData->args[2].isNumber()) {
+ quint32 intFormat = callData->args[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
tm = r->d()->locale->toTime(dateString, format);
} else {
- V4THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format");
+ THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format");
}
} else {
tm = r->d()->locale->toTime(dateString, enumFormat);
@@ -300,58 +311,56 @@ QV4::ReturnedValue QQmlDateExtension::method_fromLocaleTimeString(QV4::CallConte
dt.setTime(tm);
}
- return QV4::Encode(engine->newDateObject(dt));
+ RETURN_RESULT(engine->newDateObject(dt));
}
-QV4::ReturnedValue QQmlDateExtension::method_fromLocaleDateString(QV4::CallContext *ctx)
+void QQmlDateExtension::method_fromLocaleDateString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::ExecutionEngine * const engine = ctx->d()->engine;
+ QV4::ExecutionEngine * const engine = scope.engine;
- if (ctx->argc() == 1) {
- if (String *s = ctx->args()[0].stringValue()) {
+ if (callData->argc == 1) {
+ if (String *s = callData->args[0].stringValue()) {
QLocale locale;
QString dateString = s->toQString();
QDate date = locale.toDate(dateString);
- return QV4::Encode(engine->newDateObject(QDateTime(date)));
+ RETURN_RESULT(engine->newDateObject(QDateTime(date)));
}
}
- if (ctx->argc() < 1 || ctx->argc() > 3 || !isLocaleObject(ctx->args()[0]))
- V4THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid arguments");
+ if (callData->argc < 1 || callData->argc > 3 || !isLocaleObject(callData->args[0]))
+ THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid arguments");
- QV4::Scope scope(ctx);
-
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QDate dt;
- QString dateString = ctx->args()[1].toQStringNoThrow();
- if (ctx->argc() == 3) {
- if (String *s = ctx->args()[2].stringValue()) {
+ QString dateString = callData->args[1].toQStringNoThrow();
+ if (callData->argc == 3) {
+ if (String *s = callData->args[2].stringValue()) {
QString format = s->toQString();
dt = r->d()->locale->toDate(dateString, format);
- } else if (ctx->args()[2].isNumber()) {
- quint32 intFormat = ctx->args()[2].toNumber();
+ } else if (callData->args[2].isNumber()) {
+ quint32 intFormat = callData->args[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
dt = r->d()->locale->toDate(dateString, format);
} else {
- V4THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format");
+ THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format");
}
} else {
dt = r->d()->locale->toDate(dateString, enumFormat);
}
- return QV4::Encode(engine->newDateObject(QDateTime(dt)));
+ RETURN_RESULT(engine->newDateObject(QDateTime(dt)));
}
-QV4::ReturnedValue QQmlDateExtension::method_timeZoneUpdated(QV4::CallContext *ctx)
+void QQmlDateExtension::method_timeZoneUpdated(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 0)
- V4THROW_ERROR("Locale: Date.timeZoneUpdated(): Invalid arguments");
+ if (callData->argc != 0)
+ THROW_ERROR("Locale: Date.timeZoneUpdated(): Invalid arguments");
QV4::DatePrototype::timezoneUpdated();
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
//-----------------
@@ -364,148 +373,143 @@ void QQmlNumberExtension::registerExtension(QV4::ExecutionEngine *engine)
engine->numberCtor()->defineDefaultProperty(QStringLiteral("fromLocaleString"), method_fromLocaleString);
}
-QV4::ReturnedValue QQmlNumberExtension::method_toLocaleString(QV4::CallContext *ctx)
+void QQmlNumberExtension::method_toLocaleString(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- if (ctx->argc() > 3)
- V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ if (callData->argc > 3)
+ THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- double number = ctx->thisObject().toNumber();
+ double number = callData->thisObject.toNumber();
- if (ctx->argc() == 0) {
+ if (callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->d()->engine->newString(locale.toString(number))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(locale.toString(number)));
}
- if (!isLocaleObject(ctx->args()[0]))
- return QV4::NumberPrototype::method_toLocaleString(ctx); // Use the default Number toLocaleString()
-
- QV4::Scope scope(ctx);
+ if (!isLocaleObject(callData->args[0])) {
+ QV4::NumberPrototype::method_toLocaleString(b, scope, callData); // Use the default Number toLocaleString()
+ return;
+ }
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
quint16 format = 'f';
- if (ctx->argc() > 1) {
- if (!ctx->args()[1].isString())
- V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- QString fs = ctx->args()[1].toQString();
+ if (callData->argc > 1) {
+ if (!callData->args[1].isString())
+ THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ QString fs = callData->args[1].toQString();
if (fs.length())
format = fs.at(0).unicode();
}
int prec = 2;
- if (ctx->argc() > 2) {
- if (!ctx->args()[2].isNumber())
- V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- prec = ctx->args()[2].toInt32();
+ if (callData->argc > 2) {
+ if (!callData->args[2].isNumber())
+ THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ prec = callData->args[2].toInt32();
}
- return ctx->d()->engine->newString(r->d()->locale->toString(number, (char)format, prec))->asReturnedValue();
+ scope.result = scope.engine->newString(r->d()->locale->toString(number, (char)format, prec));
}
-QV4::ReturnedValue QQmlNumberExtension::method_toLocaleCurrencyString(QV4::CallContext *ctx)
+void QQmlNumberExtension::method_toLocaleCurrencyString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() > 2)
- V4THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
+ if (callData->argc > 2)
+ THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
- double number = ctx->thisObject().toNumber();
+ double number = callData->thisObject.toNumber();
- if (ctx->argc() == 0) {
+ if (callData->argc == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return ctx->d()->engine->newString(locale.toString(number))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(locale.toString(number)));
}
- if (!isLocaleObject(ctx->args()[0]))
- V4THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
-
- QV4::Scope scope(ctx);
+ if (!isLocaleObject(callData->args[0]))
+ THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
QString symbol;
- if (ctx->argc() > 1) {
- if (!ctx->args()[1].isString())
- V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- symbol = ctx->args()[1].toQStringNoThrow();
+ if (callData->argc > 1) {
+ if (!callData->args[1].isString())
+ THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ symbol = callData->args[1].toQStringNoThrow();
}
- return ctx->d()->engine->newString(r->d()->locale->toCurrencyString(number, symbol))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(r->d()->locale->toCurrencyString(number, symbol)));
}
-QV4::ReturnedValue QQmlNumberExtension::method_fromLocaleString(QV4::CallContext *ctx)
+void QQmlNumberExtension::method_fromLocaleString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1 || ctx->argc() > 2)
- V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
+ if (callData->argc < 1 || callData->argc > 2)
+ THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
int numberIdx = 0;
QLocale locale;
- QV4::Scope scope(ctx);
-
- if (ctx->argc() == 2) {
- if (!isLocaleObject(ctx->args()[0]))
- V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
+ if (callData->argc == 2) {
+ if (!isLocaleObject(callData->args[0]))
+ THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(ctx->args()[0]);
+ GET_LOCALE_DATA_RESOURCE(callData->args[0]);
locale = *r->d()->locale;
numberIdx = 1;
}
- QString ns = ctx->args()[numberIdx].toQString();
+ QString ns = callData->args[numberIdx].toQString();
if (!ns.length())
- return QV4::Encode(Q_QNAN);
+ RETURN_RESULT(QV4::Encode(Q_QNAN));
bool ok = false;
double val = locale.toDouble(ns, &ok);
if (!ok)
- V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid format")
+ THROW_ERROR("Locale: Number.fromLocaleString(): Invalid format");
- return QV4::Encode(val);
+ scope.result = QV4::Encode(val);
}
//--------------
// Locale object
-QV4::ReturnedValue QQmlLocaleData::method_get_firstDayOfWeek(QV4::CallContext *ctx)
+void QQmlLocaleData::method_get_firstDayOfWeek(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QLocale *locale = getThisLocale(ctx);
+ QLocale *locale = getThisLocale(scope, callData);
if (!locale)
- return QV4::Encode::undefined();
+ return;
int fdow = int(locale->firstDayOfWeek());
if (fdow == 7)
fdow = 0; // Qt::Sunday = 7, but Sunday is 0 in JS Date
- return QV4::Encode(fdow);
+ scope.result = QV4::Encode(fdow);
}
-QV4::ReturnedValue QQmlLocaleData::method_get_measurementSystem(QV4::CallContext *ctx)
+void QQmlLocaleData::method_get_measurementSystem(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QLocale *locale = getThisLocale(ctx);
+ QLocale *locale = getThisLocale(scope, callData);
if (!locale)
- return QV4::Encode::undefined();
- return QV4::Encode(locale->measurementSystem());
+ return;
+ scope.result = QV4::Encode(locale->measurementSystem());
}
-QV4::ReturnedValue QQmlLocaleData::method_get_textDirection(QV4::CallContext *ctx)
+void QQmlLocaleData::method_get_textDirection(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QLocale *locale = getThisLocale(ctx);
+ QLocale *locale = getThisLocale(scope, callData);
if (!locale)
- return QV4::Encode::undefined();
+ return;
- return QV4::Encode(locale->textDirection());
+ scope.result = QV4::Encode(locale->textDirection());
}
-QV4::ReturnedValue QQmlLocaleData::method_get_weekDays(QV4::CallContext *ctx)
+void QQmlLocaleData::method_get_weekDays(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QLocale *locale = getThisLocale(ctx);
+ QLocale *locale = getThisLocale(scope, callData);
if (!locale)
- return QV4::Encode::undefined();
+ return;
QList<Qt::DayOfWeek> days = locale->weekdays();
- QV4::ScopedArrayObject result(scope, ctx->d()->engine->newArrayObject());
+ QV4::ScopedArrayObject result(scope, scope.engine->newArrayObject());
result->arrayReserve(days.size());
for (int i = 0; i < days.size(); ++i) {
int day = days.at(i);
@@ -515,59 +519,58 @@ QV4::ReturnedValue QQmlLocaleData::method_get_weekDays(QV4::CallContext *ctx)
}
result->setArrayLengthUnchecked(days.size());
- return result.asReturnedValue();
+ scope.result = result.asReturnedValue();
}
-QV4::ReturnedValue QQmlLocaleData::method_get_uiLanguages(QV4::CallContext *ctx)
+void QQmlLocaleData::method_get_uiLanguages(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::Scope scope(ctx);
- QLocale *locale = getThisLocale(ctx);
+ QLocale *locale = getThisLocale(scope, callData);
if (!locale)
- return QV4::Encode::undefined();
+ return;
QStringList langs = locale->uiLanguages();
- QV4::ScopedArrayObject result(scope, ctx->d()->engine->newArrayObject());
+ QV4::ScopedArrayObject result(scope, scope.engine->newArrayObject());
result->arrayReserve(langs.size());
QV4::ScopedValue v(scope);
for (int i = 0; i < langs.size(); ++i)
- result->arrayPut(i, (v = ctx->d()->engine->newString(langs.at(i))));
+ result->arrayPut(i, (v = scope.engine->newString(langs.at(i))));
result->setArrayLengthUnchecked(langs.size());
- return result.asReturnedValue();
+ scope.result = result.asReturnedValue();
}
-QV4::ReturnedValue QQmlLocaleData::method_currencySymbol(QV4::CallContext *ctx)
+void QQmlLocaleData::method_currencySymbol(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QLocale *locale = getThisLocale(ctx);
+ QLocale *locale = getThisLocale(scope, callData);
if (!locale)
- return QV4::Encode::undefined();
+ return;
- if (ctx->argc() > 1)
- V4THROW_ERROR("Locale: currencySymbol(): Invalid arguments");
+ if (callData->argc > 1)
+ THROW_ERROR("Locale: currencySymbol(): Invalid arguments");
QLocale::CurrencySymbolFormat format = QLocale::CurrencySymbol;
- if (ctx->argc() == 1) {
- quint32 intFormat = ctx->args()[0].toNumber();
+ if (callData->argc == 1) {
+ quint32 intFormat = callData->args[0].toNumber();
format = QLocale::CurrencySymbolFormat(intFormat);
}
- return ctx->d()->engine->newString(locale->currencySymbol(format))->asReturnedValue();
+ scope.result = scope.engine->newString(locale->currencySymbol(format));
}
#define LOCALE_FORMAT(FUNC) \
-QV4::ReturnedValue QQmlLocaleData::method_ ##FUNC (QV4::CallContext *ctx) { \
- QLocale *locale = getThisLocale(ctx); \
+void QQmlLocaleData::method_ ##FUNC (const BuiltinFunction *, Scope &scope, CallData *callData) { \
+ QLocale *locale = getThisLocale(scope, callData); \
if (!locale) \
- return QV4::Encode::undefined(); \
- if (ctx->argc() > 1) \
- V4THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \
+ return; \
+ if (callData->argc > 1) \
+ THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \
QLocale::FormatType format = QLocale::LongFormat;\
- if (ctx->argc() == 1) { \
- quint32 intFormat = ctx->args()[0].toUInt32(); \
+ if (callData->argc == 1) { \
+ quint32 intFormat = callData->args[0].toUInt32(); \
format = QLocale::FormatType(intFormat); \
} \
- return ctx->engine()->newString(locale-> FUNC (format))->asReturnedValue(); \
+ scope.result = scope.engine->newString(locale-> FUNC (format)); \
}
LOCALE_FORMAT(dateTimeFormat)
@@ -576,57 +579,57 @@ LOCALE_FORMAT(dateFormat)
// +1 added to idx because JS is 0-based, whereas QLocale months begin at 1.
#define LOCALE_FORMATTED_MONTHNAME(VARIABLE) \
-QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) {\
- QLocale *locale = getThisLocale(ctx); \
+void QQmlLocaleData::method_ ## VARIABLE (const BuiltinFunction *, Scope &scope, CallData *callData) {\
+ QLocale *locale = getThisLocale(scope, callData); \
if (!locale) \
- return QV4::Encode::undefined(); \
- if (ctx->argc() < 1 || ctx->argc() > 2) \
- V4THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
+ return; \
+ if (callData->argc < 1 || callData->argc > 2) \
+ THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
QLocale::FormatType enumFormat = QLocale::LongFormat; \
- int idx = ctx->args()[0].toInt32() + 1; \
+ int idx = callData->args[0].toInt32() + 1; \
if (idx < 1 || idx > 12) \
- V4THROW_ERROR("Locale: Invalid month"); \
+ THROW_ERROR("Locale: Invalid month"); \
QString name; \
- if (ctx->argc() == 2) { \
- if (ctx->args()[1].isNumber()) { \
- quint32 intFormat = ctx->args()[1].toUInt32(); \
+ if (callData->argc == 2) { \
+ if (callData->args[1].isNumber()) { \
+ quint32 intFormat = callData->args[1].toUInt32(); \
QLocale::FormatType format = QLocale::FormatType(intFormat); \
name = locale-> VARIABLE(idx, format); \
} else { \
- V4THROW_ERROR("Locale: Invalid datetime format"); \
+ THROW_ERROR("Locale: Invalid datetime format"); \
} \
} else { \
name = locale-> VARIABLE(idx, enumFormat); \
} \
- return ctx->engine()->newString(name)->asReturnedValue(); \
+ scope.result = scope.engine->newString(name); \
}
// 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date
#define LOCALE_FORMATTED_DAYNAME(VARIABLE) \
-QV4::ReturnedValue QQmlLocaleData::method_ ## VARIABLE (QV4::CallContext *ctx) {\
- QLocale *locale = getThisLocale(ctx); \
+void QQmlLocaleData::method_ ## VARIABLE (const BuiltinFunction *, Scope &scope, CallData *callData) {\
+ QLocale *locale = getThisLocale(scope, callData); \
if (!locale) \
- return QV4::Encode::undefined(); \
- if (ctx->argc() < 1 || ctx->argc() > 2) \
- V4THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
+ return; \
+ if (callData->argc < 1 || callData->argc > 2) \
+ THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
QLocale::FormatType enumFormat = QLocale::LongFormat; \
- int idx = ctx->args()[0].toInt32(); \
+ int idx = callData->args[0].toInt32(); \
if (idx < 0 || idx > 7) \
- V4THROW_ERROR("Locale: Invalid day"); \
+ THROW_ERROR("Locale: Invalid day"); \
if (idx == 0) idx = 7; \
QString name; \
- if (ctx->argc() == 2) { \
- if (ctx->args()[1].isNumber()) { \
- quint32 intFormat = ctx->args()[1].toUInt32(); \
+ if (callData->argc == 2) { \
+ if (callData->args[1].isNumber()) { \
+ quint32 intFormat = callData->args[1].toUInt32(); \
QLocale::FormatType format = QLocale::FormatType(intFormat); \
name = locale-> VARIABLE(idx, format); \
} else { \
- V4THROW_ERROR("Locale: Invalid datetime format"); \
+ THROW_ERROR("Locale: Invalid datetime format"); \
} \
} else { \
name = locale-> VARIABLE(idx, enumFormat); \
} \
- return ctx->engine()->newString(name)->asReturnedValue(); \
+ scope.result = scope.engine->newString(name); \
}
LOCALE_FORMATTED_MONTHNAME(monthName)
@@ -634,12 +637,12 @@ LOCALE_FORMATTED_MONTHNAME(standaloneMonthName)
LOCALE_FORMATTED_DAYNAME(dayName)
LOCALE_FORMATTED_DAYNAME(standaloneDayName)
-#define LOCALE_STRING_PROPERTY(VARIABLE) QV4::ReturnedValue QQmlLocaleData::method_get_ ## VARIABLE (QV4::CallContext* ctx) \
+#define LOCALE_STRING_PROPERTY(VARIABLE) void QQmlLocaleData::method_get_ ## VARIABLE (const BuiltinFunction *, Scope &scope, CallData *callData) \
{ \
- QLocale *locale = getThisLocale(ctx); \
+ QLocale *locale = getThisLocale(scope, callData); \
if (!locale) \
- return QV4::Encode::undefined(); \
- return ctx->engine()->newString(locale-> VARIABLE())->asReturnedValue();\
+ return; \
+ scope.result = scope.engine->newString(locale-> VARIABLE());\
}
LOCALE_STRING_PROPERTY(name)
@@ -830,18 +833,22 @@ void QQmlLocale::registerStringLocaleCompare(QV4::ExecutionEngine *engine)
engine->stringPrototype()->defineDefaultProperty(QStringLiteral("localeCompare"), method_localeCompare);
}
-QV4::ReturnedValue QQmlLocale::method_localeCompare(QV4::CallContext *ctx)
+void QQmlLocale::method_localeCompare(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1 || (!ctx->args()[0].isString() && !ctx->args()[0].as<StringObject>()))
- return QV4::StringPrototype::method_localeCompare(ctx);
+ if (callData->argc != 1 || (!callData->args[0].isString() && !callData->args[0].as<StringObject>())) {
+ QV4::StringPrototype::method_localeCompare(b, scope, callData);
+ return;
+ }
- if (!ctx->thisObject().isString() && !ctx->thisObject().as<StringObject>())
- return QV4::StringPrototype::method_localeCompare(ctx);
+ if (!callData->thisObject.isString() && !callData->thisObject.as<StringObject>()) {
+ QV4::StringPrototype::method_localeCompare(b, scope, callData);
+ return;
+ }
- QString thisString = ctx->thisObject().toQStringNoThrow();
- QString thatString = ctx->args()[0].toQStringNoThrow();
+ QString thisString = callData->thisObject.toQStringNoThrow();
+ QString thatString = callData->args[0].toQStringNoThrow();
- return QV4::Encode(QString::localeAwareCompare(thisString, thatString));
+ scope.result = QV4::Encode(QString::localeAwareCompare(thisString, thatString));
}
/*!
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
index 275f58db7d..1a2ffc72b0 100644
--- a/src/qml/qml/qqmllocale_p.h
+++ b/src/qml/qml/qqmllocale_p.h
@@ -67,13 +67,13 @@ public:
static void registerExtension(QV4::ExecutionEngine *engine);
private:
- static QV4::ReturnedValue method_toLocaleString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_toLocaleTimeString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_toLocaleDateString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_fromLocaleString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_fromLocaleTimeString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_fromLocaleDateString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_timeZoneUpdated(QV4::CallContext *ctx);
+ static void method_toLocaleString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_toLocaleTimeString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_toLocaleDateString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_fromLocaleString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_fromLocaleTimeString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_fromLocaleDateString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_timeZoneUpdated(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
@@ -83,9 +83,9 @@ public:
static void registerExtension(QV4::ExecutionEngine *engine);
private:
- static QV4::ReturnedValue method_toLocaleString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_fromLocaleString(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_toLocaleCurrencyString(QV4::CallContext *ctx);
+ static void method_toLocaleString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_fromLocaleString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_toLocaleCurrencyString(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
@@ -135,7 +135,7 @@ public:
private:
QQmlLocale();
- static QV4::ReturnedValue method_localeCompare(QV4::CallContext *ctx);
+ static void method_localeCompare(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
namespace QV4 {
@@ -158,43 +158,43 @@ struct QQmlLocaleData : public QV4::Object
V4_OBJECT2(QQmlLocaleData, Object)
V4_NEEDS_DESTROY
- static QLocale *getThisLocale(QV4::CallContext *ctx) {
- QV4::Object *o = ctx->thisObject().as<Object>();
+ static QLocale *getThisLocale(QV4::Scope &scope, QV4::CallData *callData) {
+ QV4::Object *o = callData->thisObject.as<Object>();
QQmlLocaleData *thisObject = o ? o->as<QQmlLocaleData>() : 0;
if (!thisObject) {
- ctx->engine()->throwTypeError();
+ scope.engine->throwTypeError();
return 0;
}
return thisObject->d()->locale;
}
- static QV4::ReturnedValue method_currencySymbol(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_dateTimeFormat(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_timeFormat(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_dateFormat(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_monthName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_standaloneMonthName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_dayName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_standaloneDayName(QV4::CallContext *ctx);
-
- static QV4::ReturnedValue method_get_firstDayOfWeek(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_measurementSystem(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_textDirection(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_weekDays(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_uiLanguages(QV4::CallContext *ctx);
-
- static QV4::ReturnedValue method_get_name(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_nativeLanguageName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_nativeCountryName(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_decimalPoint(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_groupSeparator(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_percent(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_zeroDigit(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_negativeSign(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_positiveSign(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_exponential(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_amText(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_pmText(QV4::CallContext *ctx);
+ static void method_currencySymbol(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_dateTimeFormat(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_timeFormat(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_dateFormat(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_monthName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_standaloneMonthName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_dayName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_standaloneDayName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+
+ static void method_get_firstDayOfWeek(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_measurementSystem(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_textDirection(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_weekDays(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_uiLanguages(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+
+ static void method_get_name(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_nativeLanguageName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_nativeCountryName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_decimalPoint(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_groupSeparator(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_percent(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_zeroDigit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_negativeSign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_positiveSign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_exponential(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_amText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_pmText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
}
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index 520c44f4da..bd6b9a1599 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -79,7 +79,7 @@ struct QQmlMetaTypeData
Files urlToNonFileImportType; // For non-file imported composite and composite
// singleton types. This way we can locate any
// of them by url, even if it was registered as
- // a module via qmlRegisterCompositeType.
+ // a module via QQmlPrivate::RegisterCompositeType
typedef QHash<const QMetaObject *, QQmlType *> MetaObjects;
MetaObjects metaObjectToType;
typedef QHash<int, QQmlMetaType::StringConverter> StringConverters;
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 38a16b8cde..85fbd86dc4 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -170,7 +170,7 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI
context = new QQmlContextData;
context->isInternal = true;
- context->imports = compilationUnit->importCache;
+ context->imports = compilationUnit->typeNameCache;
context->initFromTypeCompilationUnit(compilationUnit, subComponentIndex);
context->setParent(parentContext);
@@ -1150,7 +1150,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
if (customParser && obj->flags & QV4::CompiledData::Object::HasCustomParserBindings) {
customParser->engine = QQmlEnginePrivate::get(engine);
- customParser->imports = compilationUnit->importCache;
+ customParser->imports = compilationUnit->typeNameCache;
QList<const QV4::CompiledData::Binding *> bindings;
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 562aa1c88a..88ce2fa1b9 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -76,7 +76,8 @@ public:
int argumentsValid:1;
QList<QByteArray> *names;
- int arguments[0];
+
+ int arguments[1];
};
// Flags that do *NOT* depend on the property's QMetaProperty::userType() and thus are quick
@@ -919,7 +920,7 @@ static int EnumType(const QMetaObject *metaobj, const QByteArray &str, int type)
QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(int argc, const QList<QByteArray> &names)
{
typedef QQmlPropertyCacheMethodArguments A;
- A *args = static_cast<A *>(malloc(sizeof(A) + (argc + 1) * sizeof(int)));
+ A *args = static_cast<A *>(malloc(sizeof(A) + (argc) * sizeof(int)));
args->arguments[0] = argc;
args->argumentsValid = false;
args->signalParameterStringForJS = 0;
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 5b1bba46dd..f4f04e12c0 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -1362,7 +1362,7 @@ bool QQmlTypeLoader::Blob::updateQmldir(QQmlQmldirData *data, const QV4::Compile
if (!importQualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
- const QmldirContent *qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
+ const QQmlTypeLoaderQmldirContent *qmldir = typeLoader()->qmldirContent(qmldirIdentifier);
const auto qmldirScripts = qmldir->scripts();
for (const QQmlDirParser::Script &script : qmldirScripts) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
@@ -1410,7 +1410,7 @@ bool QQmlTypeLoader::Blob::addImport(const QV4::CompiledData::Import *import, QL
if (!importQualifier.isEmpty()) {
// Does this library contain any qualified scripts?
QUrl libraryUrl(qmldirUrl);
- const QmldirContent *qmldir = typeLoader()->qmldirContent(qmldirFilePath);
+ const QQmlTypeLoaderQmldirContent *qmldir = typeLoader()->qmldirContent(qmldirFilePath);
const auto qmldirScripts = qmldir->scripts();
for (const QQmlDirParser::Script &script : qmldirScripts) {
QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName));
@@ -1539,57 +1539,57 @@ bool QQmlTypeLoader::Blob::qmldirDataAvailable(QQmlQmldirData *data, QList<QQmlE
}
-QQmlTypeLoader::QmldirContent::QmldirContent()
+QQmlTypeLoaderQmldirContent::QQmlTypeLoaderQmldirContent()
{
}
-bool QQmlTypeLoader::QmldirContent::hasError() const
+bool QQmlTypeLoaderQmldirContent::hasError() const
{
return m_parser.hasError();
}
-QList<QQmlError> QQmlTypeLoader::QmldirContent::errors(const QString &uri) const
+QList<QQmlError> QQmlTypeLoaderQmldirContent::errors(const QString &uri) const
{
return m_parser.errors(uri);
}
-QString QQmlTypeLoader::QmldirContent::typeNamespace() const
+QString QQmlTypeLoaderQmldirContent::typeNamespace() const
{
return m_parser.typeNamespace();
}
-void QQmlTypeLoader::QmldirContent::setContent(const QString &location, const QString &content)
+void QQmlTypeLoaderQmldirContent::setContent(const QString &location, const QString &content)
{
m_location = location;
m_parser.parse(content);
}
-void QQmlTypeLoader::QmldirContent::setError(const QQmlError &error)
+void QQmlTypeLoaderQmldirContent::setError(const QQmlError &error)
{
m_parser.setError(error);
}
-QQmlDirComponents QQmlTypeLoader::QmldirContent::components() const
+QQmlDirComponents QQmlTypeLoaderQmldirContent::components() const
{
return m_parser.components();
}
-QQmlDirScripts QQmlTypeLoader::QmldirContent::scripts() const
+QQmlDirScripts QQmlTypeLoaderQmldirContent::scripts() const
{
return m_parser.scripts();
}
-QQmlDirPlugins QQmlTypeLoader::QmldirContent::plugins() const
+QQmlDirPlugins QQmlTypeLoaderQmldirContent::plugins() const
{
return m_parser.plugins();
}
-QString QQmlTypeLoader::QmldirContent::pluginLocation() const
+QString QQmlTypeLoaderQmldirContent::pluginLocation() const
{
return m_location;
}
-bool QQmlTypeLoader::QmldirContent::designerSupported() const
+bool QQmlTypeLoaderQmldirContent::designerSupported() const
{
return m_parser.designerSupported();
}
@@ -1861,13 +1861,13 @@ bool QQmlTypeLoader::directoryExists(const QString &path)
/*!
-Return a QmldirContent for absoluteFilePath. The QmldirContent may be cached.
+Return a QQmlTypeLoaderQmldirContent for absoluteFilePath. The QQmlTypeLoaderQmldirContent may be cached.
\a filePath is a local file path.
It can also be a remote path for a remote directory import, but it will have been cached by now in this case.
*/
-const QQmlTypeLoader::QmldirContent *QQmlTypeLoader::qmldirContent(const QString &filePathIn)
+const QQmlTypeLoaderQmldirContent *QQmlTypeLoader::qmldirContent(const QString &filePathIn)
{
QUrl url(filePathIn); //May already contain http scheme
if (url.scheme() == QLatin1String("http") || url.scheme() == QLatin1String("https"))
@@ -1883,10 +1883,10 @@ const QQmlTypeLoader::QmldirContent *QQmlTypeLoader::qmldirContent(const QString
else
filePath = url.path();
- QmldirContent *qmldir;
- QmldirContent **val = m_importQmlDirCache.value(filePath);
+ QQmlTypeLoaderQmldirContent *qmldir;
+ QQmlTypeLoaderQmldirContent **val = m_importQmlDirCache.value(filePath);
if (!val) {
- qmldir = new QmldirContent;
+ qmldir = new QQmlTypeLoaderQmldirContent;
#define ERROR(description) { QQmlError e; e.setDescription(description); qmldir->setError(e); }
#define NOT_READABLE_ERROR QString(QLatin1String("module \"$$URI$$\" definition \"%1\" not readable"))
@@ -1916,12 +1916,12 @@ const QQmlTypeLoader::QmldirContent *QQmlTypeLoader::qmldirContent(const QString
void QQmlTypeLoader::setQmldirContent(const QString &url, const QString &content)
{
- QmldirContent *qmldir;
- QmldirContent **val = m_importQmlDirCache.value(url);
+ QQmlTypeLoaderQmldirContent *qmldir;
+ QQmlTypeLoaderQmldirContent **val = m_importQmlDirCache.value(url);
if (val) {
qmldir = *val;
} else {
- qmldir = new QmldirContent;
+ qmldir = new QQmlTypeLoaderQmldirContent;
m_importQmlDirCache.insert(url, qmldir);
}
@@ -2075,6 +2075,11 @@ bool QQmlTypeData::tryLoadFromDiskCache()
}
}
+ if (unit->data->flags & QV4::CompiledData::Unit::PendingTypeCompilation) {
+ restoreIR(unit);
+ return true;
+ }
+
m_compiledData = unit;
for (int i = 0, count = m_compiledData->objectCount(); i < count; ++i)
@@ -2127,11 +2132,11 @@ bool QQmlTypeData::tryLoadFromDiskCache()
return true;
}
-void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
{
Q_ASSERT(m_compiledData);
- m_compiledData->importCache = importCache;
+ m_compiledData->typeNameCache = typeNameCache;
m_compiledData->resolvedTypes = resolvedTypeCache;
QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
@@ -2217,10 +2222,10 @@ void QQmlTypeData::done()
}
}
- QQmlRefPointer<QQmlTypeNameCache> importCache;
+ QQmlRefPointer<QQmlTypeNameCache> typeNameCache;
QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache;
{
- QQmlCompileError error = buildTypeResolutionCaches(&importCache, &resolvedTypeCache);
+ QQmlCompileError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache);
if (error.isSet()) {
setError(error);
return;
@@ -2240,9 +2245,9 @@ void QQmlTypeData::done()
if (!m_document.isNull()) {
// Compile component
- compile(importCache, resolvedTypeCache);
+ compile(typeNameCache, resolvedTypeCache);
} else {
- createTypeAndPropertyCaches(importCache, resolvedTypeCache);
+ createTypeAndPropertyCaches(typeNameCache, resolvedTypeCache);
}
if (isError())
@@ -2303,7 +2308,7 @@ void QQmlTypeData::done()
qualifier = qualifier.mid(lastDotIndex+1);
}
- m_compiledData->importCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
+ m_compiledData->typeNameCache->add(qualifier.toString(), scriptIndex, enclosingNamespace);
QQmlScriptData *scriptData = script.script->scriptData();
scriptData->addref();
m_compiledData->dependentScripts << scriptData;
@@ -2397,6 +2402,15 @@ bool QQmlTypeData::loadFromSource()
return true;
}
+void QQmlTypeData::restoreIR(QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit)
+{
+ m_document.reset(new QmlIR::Document(isDebugging()));
+ QmlIR::IRLoader loader(unit->data, m_document.data());
+ loader.load();
+ m_document->javaScriptCompilationUnit = unit;
+ continueLoadFromIR();
+}
+
void QQmlTypeData::continueLoadFromIR()
{
m_typeReferences.collectFromObjects(m_document->objects.constBegin(), m_document->objects.constEnd());
@@ -2489,12 +2503,12 @@ QString QQmlTypeData::stringAt(int index) const
return m_document->jsGenerator.stringTable.stringForIndex(index);
}
-void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
+void QQmlTypeData::compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache, const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache)
{
Q_ASSERT(m_compiledData.isNull());
QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine());
- QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), importCache, resolvedTypeCache);
+ QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache);
m_compiledData = compiler.compile();
if (!m_compiledData) {
setError(compiler.compilationErrors());
@@ -2598,20 +2612,20 @@ void QQmlTypeData::resolveTypes()
}
QQmlCompileError QQmlTypeData::buildTypeResolutionCaches(
- QQmlRefPointer<QQmlTypeNameCache> *importCache,
+ QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
) const
{
- importCache->adopt(new QQmlTypeNameCache);
+ typeNameCache->adopt(new QQmlTypeNameCache(m_importCache));
for (const QString &ns: m_namespaces)
- (*importCache)->add(ns);
+ (*typeNameCache)->add(ns);
// Add any Composite Singletons that were used to the import cache
for (const QQmlTypeData::TypeReference &singleton: m_compositeSingletons)
- (*importCache)->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
+ (*typeNameCache)->add(singleton.type->qmlTypeName(), singleton.type->sourceUrl(), singleton.prefix);
- m_importCache.populateCache(*importCache);
+ m_importCache.populateCache(*typeNameCache);
QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine());
@@ -2710,7 +2724,7 @@ void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QV4::CompiledData:
}
QQmlScriptData::QQmlScriptData()
- : importCache(0)
+ : typeNameCache(0)
, m_loaded(false)
, m_program(0)
{
@@ -2767,8 +2781,8 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
// For backward compatibility, if there are no imports, we need to use the
// imports from the parent context. See QTBUG-17518.
- if (!importCache->isEmpty()) {
- ctxt->imports = importCache;
+ if (!typeNameCache->isEmpty()) {
+ ctxt->imports = typeNameCache;
} else if (effectiveCtxt) {
ctxt->imports = effectiveCtxt->imports;
ctxt->importedScripts = effectiveCtxt->importedScripts;
@@ -2823,9 +2837,9 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
void QQmlScriptData::clear()
{
- if (importCache) {
- importCache->release();
- importCache = 0;
+ if (typeNameCache) {
+ typeNameCache->release();
+ typeNameCache = 0;
}
for (int ii = 0; ii < scripts.count(); ++ii)
@@ -2946,7 +2960,7 @@ void QQmlScriptBlob::done()
}
}
- m_scriptData->importCache = new QQmlTypeNameCache();
+ m_scriptData->typeNameCache = new QQmlTypeNameCache(m_importCache);
QSet<QString> ns;
@@ -2958,13 +2972,13 @@ void QQmlScriptBlob::done()
if (!script.nameSpace.isNull()) {
if (!ns.contains(script.nameSpace)) {
ns.insert(script.nameSpace);
- m_scriptData->importCache->add(script.nameSpace);
+ m_scriptData->typeNameCache->add(script.nameSpace);
}
}
- m_scriptData->importCache->add(script.qualifier, scriptIndex, script.nameSpace);
+ m_scriptData->typeNameCache->add(script.qualifier, scriptIndex, script.nameSpace);
}
- m_importCache.populateCache(m_scriptData->importCache);
+ m_importCache.populateCache(m_scriptData->typeNameCache);
}
QString QQmlScriptBlob::stringAt(int index) const
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index c60435a2d6..915b1bcc4c 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -218,6 +218,34 @@ private:
class QQmlTypeLoaderThread;
+class QQmlTypeLoaderQmldirContent
+{
+private:
+ friend class QQmlTypeLoader;
+ QQmlTypeLoaderQmldirContent();
+
+ void setContent(const QString &location, const QString &content);
+ void setError(const QQmlError &);
+
+public:
+ bool hasError() const;
+ QList<QQmlError> errors(const QString &uri) const;
+
+ QString typeNamespace() const;
+
+ QQmlDirComponents components() const;
+ QQmlDirScripts scripts() const;
+ QQmlDirPlugins plugins() const;
+
+ QString pluginLocation() const;
+
+ bool designerSupported() const;
+
+private:
+ QQmlDirParser m_parser;
+ QString m_location;
+};
+
class Q_AUTOTEST_EXPORT QQmlTypeLoader
{
Q_DECLARE_TR_FUNCTIONS(QQmlTypeLoader)
@@ -256,34 +284,6 @@ public:
QList<QQmlQmldirData *> m_qmldirs;
};
- class QmldirContent
- {
- private:
- friend class QQmlTypeLoader;
- QmldirContent();
-
- void setContent(const QString &location, const QString &content);
- void setError(const QQmlError &);
-
- public:
- bool hasError() const;
- QList<QQmlError> errors(const QString &uri) const;
-
- QString typeNamespace() const;
-
- QQmlDirComponents components() const;
- QQmlDirScripts scripts() const;
- QQmlDirPlugins plugins() const;
-
- QString pluginLocation() const;
-
- bool designerSupported() const;
-
- private:
- QQmlDirParser m_parser;
- QString m_location;
- };
-
QQmlTypeLoader(QQmlEngine *);
~QQmlTypeLoader();
@@ -298,7 +298,7 @@ public:
QString absoluteFilePath(const QString &path);
bool directoryExists(const QString &path);
- const QmldirContent *qmldirContent(const QString &filePath);
+ const QQmlTypeLoaderQmldirContent *qmldirContent(const QString &filePath);
void setQmldirContent(const QString &filePath, const QString &content);
void clearCache();
@@ -363,7 +363,7 @@ private:
typedef QHash<QUrl, QQmlQmldirData *> QmldirCache;
typedef QStringHash<bool> StringSet;
typedef QStringHash<StringSet*> ImportDirCache;
- typedef QStringHash<QmldirContent *> ImportQmlDirCache;
+ typedef QStringHash<QQmlTypeLoaderQmldirContent *> ImportQmlDirCache;
QQmlEngine *m_engine;
QQmlTypeLoaderThread *m_thread;
@@ -446,15 +446,16 @@ protected:
private:
bool tryLoadFromDiskCache();
bool loadFromSource();
+ void restoreIR(QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit);
void continueLoadFromIR();
void resolveTypes();
QQmlCompileError buildTypeResolutionCaches(
- QQmlRefPointer<QQmlTypeNameCache> *importCache,
+ QQmlRefPointer<QQmlTypeNameCache> *typeNameCache,
QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache
) const;
- void compile(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ void compile(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
- void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &importCache,
+ void createTypeAndPropertyCaches(const QQmlRefPointer<QQmlTypeNameCache> &typeNameCache,
const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache);
bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref, int lineNumber = -1, int columnNumber = -1, bool reportErrors = true);
@@ -504,7 +505,7 @@ public:
QUrl url;
QString urlString;
- QQmlTypeNameCache *importCache;
+ QQmlTypeNameCache *typeNameCache;
QList<QQmlScriptBlob *> scripts;
QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt);
diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp
index c2098bc9a1..c8e2b92c29 100644
--- a/src/qml/qml/qqmltypenamecache.cpp
+++ b/src/qml/qml/qqmltypenamecache.cpp
@@ -43,7 +43,8 @@
QT_BEGIN_NAMESPACE
-QQmlTypeNameCache::QQmlTypeNameCache()
+QQmlTypeNameCache::QQmlTypeNameCache(const QQmlImports &importCache)
+ : m_imports(importCache)
{
}
@@ -70,6 +71,7 @@ void QQmlTypeNameCache::add(const QHashedString &name, int importedScriptIndex,
{
Import import;
import.scriptIndex = importedScriptIndex;
+ import.m_qualifier = name;
if (nameSpace.length() != 0) {
Import *i = m_namedImports.value(nameSpace);
@@ -94,6 +96,18 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name)
if (!result.isValid())
result = query(m_anonymousCompositeSingletons, name);
+ if (!result.isValid()) {
+ // Look up anonymous types from the imports of this document
+ QQmlImportNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+ QQmlType *t = 0;
+ bool typeFound = m_imports.resolveType(name, &t, 0, 0, &typeNamespace, &errors);
+ if (typeFound) {
+ return Result(t);
+ }
+
+ }
+
return result;
}
@@ -109,6 +123,20 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name,
if (!result.isValid())
result = query(i->compositeSingletons, name);
+ if (!result.isValid()) {
+ // Look up types from the imports of this document
+ // ### it would be nice if QQmlImports allowed us to resolve a namespace
+ // first, and then types on it.
+ QString qualifiedTypeName = i->m_qualifier + QLatin1Char('.') + name.toString();
+ QQmlImportNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+ QQmlType *t = 0;
+ bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, 0, 0, &typeNamespace, &errors);
+ if (typeFound) {
+ return Result(t);
+ }
+ }
+
return result;
}
@@ -122,6 +150,19 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name) cons
if (!result.isValid())
result = query(m_anonymousCompositeSingletons, name);
+ if (!result.isValid()) {
+ // Look up anonymous types from the imports of this document
+ QString typeName = name->toQStringNoThrow();
+ QQmlImportNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+ QQmlType *t = 0;
+ bool typeFound = m_imports.resolveType(typeName, &t, 0, 0, &typeNamespace, &errors);
+ if (typeFound) {
+ return Result(t);
+ }
+
+ }
+
return result;
}
@@ -143,6 +184,20 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, cons
if (!r.isValid())
r = query(i->compositeSingletons, name);
+ if (!r.isValid()) {
+ // Look up types from the imports of this document
+ // ### it would be nice if QQmlImports allowed us to resolve a namespace
+ // first, and then types on it.
+ QString qualifiedTypeName = i->m_qualifier + QLatin1Char('.') + name->toQStringNoThrow();
+ QQmlImportNamespace *typeNamespace = 0;
+ QList<QQmlError> errors;
+ QQmlType *t = 0;
+ bool typeFound = m_imports.resolveType(qualifiedTypeName, &t, 0, 0, &typeNamespace, &errors);
+ if (typeFound) {
+ return Result(t);
+ }
+ }
+
return r;
}
diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h
index 8a387bed5f..7cdcbe91b6 100644
--- a/src/qml/qml/qqmltypenamecache_p.h
+++ b/src/qml/qml/qqmltypenamecache_p.h
@@ -56,6 +56,7 @@
#include "qqmlmetatype_p.h"
#include <private/qhashedstring_p.h>
+#include <private/qqmlimport_p.h>
#include <QtCore/qvector.h>
@@ -66,7 +67,7 @@ class QQmlEngine;
class QQmlTypeNameCache : public QQmlRefCount
{
public:
- QQmlTypeNameCache();
+ QQmlTypeNameCache(const QQmlImports &imports);
virtual ~QQmlTypeNameCache();
inline bool isEmpty() const;
@@ -105,6 +106,9 @@ private:
// Or, imported compositeSingletons
QStringHash<QUrl> compositeSingletons;
+
+ // The qualifier of this import
+ QString m_qualifier;
};
template<typename Key>
@@ -112,6 +116,7 @@ private:
{
Import *i = imports.value(key);
if (i) {
+ Q_ASSERT(!i->m_qualifier.isEmpty());
if (i->scriptIndex != -1) {
return Result(i->scriptIndex);
} else {
@@ -151,6 +156,7 @@ private:
QMap<const Import *, QStringHash<Import> > m_namespacedImports;
QVector<QQmlTypeModuleVersion> m_anonymousImports;
QStringHash<QUrl> m_anonymousCompositeSingletons;
+ QQmlImports m_imports;
};
QQmlTypeNameCache::Result::Result()
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
index 6ce52bb9e5..44b612e7d2 100644
--- a/src/qml/qml/qqmlvaluetypewrapper.cpp
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -312,18 +312,18 @@ bool QQmlValueTypeWrapper::write(QObject *target, int propertyIndex) const
return true;
}
-ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx)
+void QQmlValueTypeWrapper::method_toString(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Object *o = ctx->thisObject().as<Object>();
+ Object *o = callData->thisObject.as<Object>();
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
QQmlValueTypeWrapper *w = o->as<QQmlValueTypeWrapper>();
if (!w)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (QQmlValueTypeReference *ref = w->as<QQmlValueTypeReference>())
if (!ref->readReferenceValue())
- return Encode::undefined();
+ RETURN_UNDEFINED();
QString result;
// Prepare a buffer to pass to QMetaType::convert()
@@ -346,7 +346,7 @@ ReturnedValue QQmlValueTypeWrapper::method_toString(CallContext *ctx)
}
result += QLatin1Char(')');
}
- return Encode(ctx->engine()->newString(result));
+ scope.result = scope.engine->newString(result);
}
ReturnedValue QQmlValueTypeWrapper::get(const Managed *m, String *name, bool *hasProperty)
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
index fec54df770..87f9116056 100644
--- a/src/qml/qml/qqmlvaluetypewrapper_p.h
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -111,7 +111,7 @@ public:
static PropertyAttributes query(const Managed *, String *name);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
- static QV4::ReturnedValue method_toString(CallContext *ctx);
+ static void method_toString(const BuiltinFunction *, Scope &scope, CallData *callData);
static void initProto(ExecutionEngine *v4);
};
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index 545daa96f8..490a4e19ab 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -325,9 +325,12 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
if (compiledObject->nProperties || compiledObject->nFunctions) {
Q_ASSERT(cache && cache->engine);
QV4::ExecutionEngine *v4 = cache->engine;
- QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, compiledObject->nProperties + compiledObject->nFunctions);
- propertyAndMethodStorage.set(v4, data);
- std::fill(data->data, data->data + data->size, QV4::Encode::undefined());
+ uint size = compiledObject->nProperties + compiledObject->nFunctions;
+ if (size) {
+ QV4::Heap::MemberData *data = QV4::MemberData::allocate(v4, size);
+ propertyAndMethodStorage.set(v4, data);
+ std::fill(data->data, data->data + data->size, QV4::Encode::undefined());
+ }
// Need JS wrapper to ensure properties/methods are marked.
ensureQObjectWrapper();
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 22c3c49c58..d0d9f080da 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -71,10 +71,12 @@ using namespace QV4;
#if QT_CONFIG(xmlstreamreader) && QT_CONFIG(qml_network)
-#define V4THROW_REFERENCE(string) { \
- ScopedObject error(scope, ctx->engine()->newReferenceErrorObject(QStringLiteral(string))); \
- return ctx->engine()->throwError(error); \
- }
+#define V4THROW_REFERENCE(string) \
+ do { \
+ ScopedObject error(scope, scope.engine->newReferenceErrorObject(QStringLiteral(string))); \
+ scope.result = scope.engine->throwError(error); \
+ return; \
+ } while (false)
QT_BEGIN_NAMESPACE
@@ -274,25 +276,25 @@ public:
static void initClass(ExecutionEngine *engine);
// JS API
- static ReturnedValue method_get_nodeName(CallContext *ctx);
- static ReturnedValue method_get_nodeValue(CallContext *ctx);
- static ReturnedValue method_get_nodeType(CallContext *ctx);
- static ReturnedValue method_get_namespaceUri(CallContext *ctx);
-
- static ReturnedValue method_get_parentNode(CallContext *ctx);
- static ReturnedValue method_get_childNodes(CallContext *ctx);
- static ReturnedValue method_get_firstChild(CallContext *ctx);
- static ReturnedValue method_get_lastChild(CallContext *ctx);
- static ReturnedValue method_get_previousSibling(CallContext *ctx);
- static ReturnedValue method_get_nextSibling(CallContext *ctx);
- static ReturnedValue method_get_attributes(CallContext *ctx);
-
- //static ReturnedValue ownerDocument(CallContext *ctx);
- //static ReturnedValue namespaceURI(CallContext *ctx);
- //static ReturnedValue prefix(CallContext *ctx);
- //static ReturnedValue localName(CallContext *ctx);
- //static ReturnedValue baseURI(CallContext *ctx);
- //static ReturnedValue textContent(CallContext *ctx);
+ static void method_get_nodeName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_nodeValue(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_nodeType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_namespaceUri(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+
+ static void method_get_parentNode(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_childNodes(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_firstChild(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_lastChild(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_previousSibling(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_nextSibling(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_attributes(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+
+ //static void ownerDocument(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ //static void namespaceURI(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ //static void prefix(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ //static void localName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ //static void baseURI(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ //static void textContent(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
static ReturnedValue getProto(ExecutionEngine *v4);
@@ -353,12 +355,12 @@ class Attr : public Node
{
public:
// JS API
- static ReturnedValue method_name(CallContext *ctx);
-// static ReturnedValue specified(CallContext *);
- static ReturnedValue method_value(CallContext *ctx);
- static ReturnedValue method_ownerElement(CallContext *ctx);
-// static ReturnedValue schemaTypeInfo(CallContext *);
-// static ReturnedValue isId(CallContext *c);
+ static void method_name(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+// static void specified(CallContext *);
+ static void method_value(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_ownerElement(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+// static void schemaTypeInfo(CallContext *);
+// static void isId(CallContext *c);
// C++ API
static ReturnedValue prototype(ExecutionEngine *);
@@ -368,7 +370,7 @@ class CharacterData : public Node
{
public:
// JS API
- static ReturnedValue method_length(CallContext *ctx);
+ static void method_length(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
// C++ API
static ReturnedValue prototype(ExecutionEngine *v4);
@@ -378,8 +380,8 @@ class Text : public CharacterData
{
public:
// JS API
- static ReturnedValue method_isElementContentWhitespace(CallContext *ctx);
- static ReturnedValue method_wholeText(CallContext *ctx);
+ static void method_isElementContentWhitespace(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_wholeText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
// C++ API
static ReturnedValue prototype(ExecutionEngine *);
@@ -396,10 +398,10 @@ class Document : public Node
{
public:
// JS API
- static ReturnedValue method_xmlVersion(CallContext *ctx);
- static ReturnedValue method_xmlEncoding(CallContext *ctx);
- static ReturnedValue method_xmlStandalone(CallContext *ctx);
- static ReturnedValue method_documentElement(CallContext *ctx);
+ static void method_xmlVersion(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_xmlEncoding(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_xmlStandalone(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_documentElement(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
// C++ API
static ReturnedValue prototype(ExecutionEngine *);
@@ -418,12 +420,11 @@ void NodeImpl::release()
document->release();
}
-ReturnedValue NodePrototype::method_get_nodeName(CallContext *ctx)
+void NodePrototype::method_get_nodeName(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
QString name;
switch (r->d()->d->type) {
@@ -440,15 +441,14 @@ ReturnedValue NodePrototype::method_get_nodeName(CallContext *ctx)
name = r->d()->d->name;
break;
}
- return Encode(ctx->d()->engine->newString(name));
+ scope.result = Encode(scope.engine->newString(name));
}
-ReturnedValue NodePrototype::method_get_nodeValue(CallContext *ctx)
+void NodePrototype::method_get_nodeValue(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (r->d()->d->type == NodeImpl::Document ||
r->d()->d->type == NodeImpl::DocumentFragment ||
@@ -457,135 +457,128 @@ ReturnedValue NodePrototype::method_get_nodeValue(CallContext *ctx)
r->d()->d->type == NodeImpl::Entity ||
r->d()->d->type == NodeImpl::EntityReference ||
r->d()->d->type == NodeImpl::Notation)
- return Encode::null();
+ RETURN_RESULT(Encode::null());
- return Encode(ctx->d()->engine->newString(r->d()->d->data));
+ scope.result = Encode(scope.engine->newString(r->d()->d->data));
}
-ReturnedValue NodePrototype::method_get_nodeType(CallContext *ctx)
+void NodePrototype::method_get_nodeType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(r->d()->d->type);
+ scope.result = Encode(r->d()->d->type);
}
-ReturnedValue NodePrototype::method_get_namespaceUri(CallContext *ctx)
+void NodePrototype::method_get_namespaceUri(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return Encode(ctx->d()->engine->newString(r->d()->d->namespaceUri));
+ scope.result = Encode(scope.engine->newString(r->d()->d->namespaceUri));
}
-ReturnedValue NodePrototype::method_get_parentNode(CallContext *ctx)
+void NodePrototype::method_get_parentNode(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (r->d()->d->parent)
- return Node::create(scope.engine, r->d()->d->parent);
+ scope.result = Node::create(scope.engine, r->d()->d->parent);
else
- return Encode::null();
+ scope.result = Encode::null();
}
-ReturnedValue NodePrototype::method_get_childNodes(CallContext *ctx)
+void NodePrototype::method_get_childNodes(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
- return NodeList::create(scope.engine, r->d()->d);
+ scope.result = NodeList::create(scope.engine, r->d()->d);
}
-ReturnedValue NodePrototype::method_get_firstChild(CallContext *ctx)
+void NodePrototype::method_get_firstChild(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (r->d()->d->children.isEmpty())
- return Encode::null();
+ scope.result = Encode::null();
else
- return Node::create(scope.engine, r->d()->d->children.constFirst());
+ scope.result = Node::create(scope.engine, r->d()->d->children.constFirst());
}
-ReturnedValue NodePrototype::method_get_lastChild(CallContext *ctx)
+void NodePrototype::method_get_lastChild(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (r->d()->d->children.isEmpty())
- return Encode::null();
+ scope.result = Encode::null();
else
- return Node::create(scope.engine, r->d()->d->children.constLast());
+ scope.result = Node::create(scope.engine, r->d()->d->children.constLast());
}
-ReturnedValue NodePrototype::method_get_previousSibling(CallContext *ctx)
+void NodePrototype::method_get_previousSibling(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (!r->d()->d->parent)
- return Encode::null();
+ RETURN_RESULT(Encode::null());
for (int ii = 0; ii < r->d()->d->parent->children.count(); ++ii) {
if (r->d()->d->parent->children.at(ii) == r->d()->d) {
if (ii == 0)
- return Encode::null();
+ scope.result = Encode::null();
else
- return Node::create(scope.engine, r->d()->d->parent->children.at(ii - 1));
+ scope.result = Node::create(scope.engine, r->d()->d->parent->children.at(ii - 1));
+ return;
}
}
- return Encode::null();
+ scope.result = Encode::null();
}
-ReturnedValue NodePrototype::method_get_nextSibling(CallContext *ctx)
+void NodePrototype::method_get_nextSibling(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (!r->d()->d->parent)
- return Encode::null();
+ RETURN_RESULT(Encode::null());
for (int ii = 0; ii < r->d()->d->parent->children.count(); ++ii) {
if (r->d()->d->parent->children.at(ii) == r->d()->d) {
if ((ii + 1) == r->d()->d->parent->children.count())
- return Encode::null();
+ scope.result = Encode::null();
else
- return Node::create(scope.engine, r->d()->d->parent->children.at(ii + 1));
+ scope.result = Node::create(scope.engine, r->d()->d->parent->children.at(ii + 1));
+ return;
}
}
- return Encode::null();
+ scope.result = Encode::null();
}
-ReturnedValue NodePrototype::method_get_attributes(CallContext *ctx)
+void NodePrototype::method_get_attributes(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (r->d()->d->type != NodeImpl::Element)
- return Encode::null();
+ scope.result = Encode::null();
else
- return NamedNodeMap::create(scope.engine, r->d()->d, r->d()->d->attributes);
+ scope.result = NamedNodeMap::create(scope.engine, r->d()->d, r->d()->d->attributes);
}
ReturnedValue NodePrototype::getProto(ExecutionEngine *v4)
@@ -666,44 +659,40 @@ ReturnedValue Attr::prototype(ExecutionEngine *engine)
return d->attrPrototype.value();
}
-ReturnedValue Attr::method_name(CallContext *ctx)
+void Attr::method_name(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return QV4::Encode(scope.engine->newString(r->d()->d->name));
+ scope.result = scope.engine->newString(r->d()->d->name);
}
-ReturnedValue Attr::method_value(CallContext *ctx)
+void Attr::method_value(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return QV4::Encode(scope.engine->newString(r->d()->d->data));
+ scope.result = scope.engine->newString(r->d()->d->data);
}
-ReturnedValue Attr::method_ownerElement(CallContext *ctx)
+void Attr::method_ownerElement(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return Node::create(scope.engine, r->d()->d->parent);
+ scope.result = Node::create(scope.engine, r->d()->d->parent);
}
-ReturnedValue CharacterData::method_length(CallContext *ctx)
+void CharacterData::method_length(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return Encode(r->d()->d->data.length());
+ scope.result = Encode(r->d()->d->data.length());
}
ReturnedValue CharacterData::prototype(ExecutionEngine *v4)
@@ -722,23 +711,22 @@ ReturnedValue CharacterData::prototype(ExecutionEngine *v4)
return d->characterDataPrototype.value();
}
-ReturnedValue Text::method_isElementContentWhitespace(CallContext *ctx)
+void Text::method_isElementContentWhitespace(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
- if (!r) return Encode::undefined();
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
+ if (!r)
+ RETURN_UNDEFINED();
- return Encode(QStringRef(&r->d()->d->data).trimmed().isEmpty());
+ scope.result = Encode(QStringRef(&r->d()->d->data).trimmed().isEmpty());
}
-ReturnedValue Text::method_wholeText(CallContext *ctx)
+void Text::method_wholeText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return QV4::Encode(scope.engine->newString(r->d()->d->data));
+ scope.result = scope.engine->newString(r->d()->d->data);
}
ReturnedValue Text::prototype(ExecutionEngine *v4)
@@ -964,44 +952,40 @@ ReturnedValue NodeList::create(ExecutionEngine *v4, NodeImpl *data)
return (v4->memoryManager->allocObject<NodeList>(data))->asReturnedValue();
}
-ReturnedValue Document::method_documentElement(CallContext *ctx)
+void Document::method_documentElement(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r || r->d()->d->type != NodeImpl::Document)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return Node::create(scope.engine, static_cast<DocumentImpl *>(r->d()->d)->root);
+ scope.result = Node::create(scope.engine, static_cast<DocumentImpl *>(r->d()->d)->root);
}
-ReturnedValue Document::method_xmlStandalone(CallContext *ctx)
+void Document::method_xmlStandalone(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r || r->d()->d->type != NodeImpl::Document)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return Encode(static_cast<DocumentImpl *>(r->d()->d)->isStandalone);
+ scope.result = Encode(static_cast<DocumentImpl *>(r->d()->d)->isStandalone);
}
-ReturnedValue Document::method_xmlVersion(CallContext *ctx)
+void Document::method_xmlVersion(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r || r->d()->d->type != NodeImpl::Document)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return QV4::Encode(scope.engine->newString(static_cast<DocumentImpl *>(r->d()->d)->version));
+ scope.result = scope.engine->newString(static_cast<DocumentImpl *>(r->d()->d)->version);
}
-ReturnedValue Document::method_xmlEncoding(CallContext *ctx)
+void Document::method_xmlEncoding(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<Node> r(scope, ctx->thisObject().as<Node>());
+ Scoped<Node> r(scope, callData->thisObject.as<Node>());
if (!r || r->d()->d->type != NodeImpl::Document)
- return Encode::undefined();
+ RETURN_UNDEFINED();
- return QV4::Encode(scope.engine->newString(static_cast<DocumentImpl *>(r->d()->d)->encoding));
+ scope.result = scope.engine->newString(static_cast<DocumentImpl *>(r->d()->d)->encoding);
}
class QQmlXMLHttpRequest : public QObject
@@ -1657,21 +1641,21 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject
void setupProto();
- static ReturnedValue method_open(CallContext *ctx);
- static ReturnedValue method_setRequestHeader(CallContext *ctx);
- static ReturnedValue method_send(CallContext *ctx);
- static ReturnedValue method_abort(CallContext *ctx);
- static ReturnedValue method_getResponseHeader(CallContext *ctx);
- static ReturnedValue method_getAllResponseHeaders(CallContext *ctx);
-
- static ReturnedValue method_get_readyState(CallContext *ctx);
- static ReturnedValue method_get_status(CallContext *ctx);
- static ReturnedValue method_get_statusText(CallContext *ctx);
- static ReturnedValue method_get_responseText(CallContext *ctx);
- static ReturnedValue method_get_responseXML(CallContext *ctx);
- static ReturnedValue method_get_response(CallContext *ctx);
- static ReturnedValue method_get_responseType(CallContext *ctx);
- static ReturnedValue method_set_responseType(CallContext *ctx);
+ static void method_open(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_setRequestHeader(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_send(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_abort(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_getResponseHeader(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_getAllResponseHeaders(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+
+ static void method_get_readyState(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_status(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_statusText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_responseText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_responseXML(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_response(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_responseType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_responseType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
}
@@ -1733,19 +1717,18 @@ void QQmlXMLHttpRequestCtor::setupProto()
// XMLHttpRequest methods
-ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_open(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- if (ctx->argc() < 2 || ctx->argc() > 5)
- V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+ if (callData->argc < 2 || callData->argc > 5)
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
// Argument 0 - Method
- QString method = ctx->args()[0].toQStringNoThrow().toUpper();
+ QString method = callData->args[0].toQStringNoThrow().toUpper();
if (method != QLatin1String("GET") &&
method != QLatin1String("PUT") &&
method != QLatin1String("HEAD") &&
@@ -1754,26 +1737,26 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx)
method != QLatin1String("OPTIONS") &&
method != QLatin1String("PROPFIND") &&
method != QLatin1String("PATCH"))
- V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type");
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type");
// Argument 1 - URL
- QUrl url = QUrl(ctx->args()[1].toQStringNoThrow());
+ QUrl url = QUrl(callData->args[1].toQStringNoThrow());
if (url.isRelative())
url = scope.engine->callingQmlContext()->resolvedUrl(url);
bool async = true;
// Argument 2 - async (optional)
- if (ctx->argc() > 2) {
- async = ctx->args()[2].booleanValue();
+ if (callData->argc > 2) {
+ async = callData->args[2].booleanValue();
}
// Argument 3/4 - user/pass (optional)
QString username, password;
- if (ctx->argc() > 3)
- username = ctx->args()[3].toQStringNoThrow();
- if (ctx->argc() > 4)
- password = ctx->args()[4].toQStringNoThrow();
+ if (callData->argc > 3)
+ username = callData->args[3].toQStringNoThrow();
+ if (callData->argc > 4)
+ password = callData->args[4].toQStringNoThrow();
// Clear the fragment (if any)
url.setFragment(QString());
@@ -1782,25 +1765,24 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx)
if (!username.isNull()) url.setUserName(username);
if (!password.isNull()) url.setPassword(password);
- return r->open(w, scope.engine->callingQmlContext(), method, url, async ? QQmlXMLHttpRequest::AsynchronousLoad : QQmlXMLHttpRequest::SynchronousLoad);
+ scope.result = r->open(w, scope.engine->callingQmlContext(), method, url, async ? QQmlXMLHttpRequest::AsynchronousLoad : QQmlXMLHttpRequest::SynchronousLoad);
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_setRequestHeader(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- if (ctx->argc() != 2)
- V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+ if (callData->argc != 2)
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
if (r->readyState() != QQmlXMLHttpRequest::Opened || r->sendFlag())
- V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
- QString name = ctx->args()[0].toQStringNoThrow();
- QString value = ctx->args()[1].toQStringNoThrow();
+ QString name = callData->args[0].toQStringNoThrow();
+ QString value = callData->args[1].toQStringNoThrow();
// ### Check that name and value are well formed
@@ -1825,148 +1807,139 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(CallContext *ctx)
nameUpper == QLatin1String("VIA") ||
nameUpper.startsWith(QLatin1String("PROXY-")) ||
nameUpper.startsWith(QLatin1String("SEC-")))
- return Encode::undefined();
+ RETURN_UNDEFINED();
r->addHeader(name, value);
- return Encode::undefined();
+ RETURN_UNDEFINED();
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_send(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_send(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
if (r->readyState() != QQmlXMLHttpRequest::Opened ||
r->sendFlag())
- V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
QByteArray data;
- if (ctx->argc() > 0)
- data = ctx->args()[0].toQStringNoThrow().toUtf8();
+ if (callData->argc > 0)
+ data = callData->args[0].toQStringNoThrow().toUtf8();
- return r->send(w, scope.engine->callingQmlContext(), data);
+ scope.result = r->send(w, scope.engine->callingQmlContext(), data);
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_abort(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_abort(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- return r->abort(w, scope.engine->callingQmlContext());
+ scope.result = r->abort(w, scope.engine->callingQmlContext());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_getResponseHeader(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_getResponseHeader(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- if (ctx->argc() != 1)
- V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+ if (callData->argc != 1)
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
if (r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done &&
r->readyState() != QQmlXMLHttpRequest::HeadersReceived)
- V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
- return QV4::Encode(scope.engine->newString(r->header(ctx->args()[0].toQStringNoThrow())));
+ scope.result = scope.engine->newString(r->header(callData->args[0].toQStringNoThrow()));
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- if (ctx->argc() != 0)
- V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+ if (callData->argc != 0)
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
if (r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done &&
r->readyState() != QQmlXMLHttpRequest::HeadersReceived)
- V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
- return QV4::Encode(scope.engine->newString(r->headers()));
+ scope.result = scope.engine->newString(r->headers());
}
// XMLHttpRequest properties
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_readyState(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_get_readyState(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- return Encode(r->readyState());
+ scope.result = Encode(r->readyState());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_status(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_get_status(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
if (r->readyState() == QQmlXMLHttpRequest::Unsent ||
r->readyState() == QQmlXMLHttpRequest::Opened)
- V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
if (r->errorFlag())
- return Encode(0);
+ scope.result = Encode(0);
else
- return Encode(r->replyStatus());
+ scope.result = Encode(r->replyStatus());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_statusText(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_get_statusText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
if (r->readyState() == QQmlXMLHttpRequest::Unsent ||
r->readyState() == QQmlXMLHttpRequest::Opened)
- V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
if (r->errorFlag())
- return QV4::Encode(scope.engine->newString(QString()));
+ scope.result = scope.engine->newString(QString());
else
- return QV4::Encode(scope.engine->newString(r->replyStatusText()));
+ scope.result = scope.engine->newString(r->replyStatusText());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseText(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_get_responseText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
if (r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done)
- return QV4::Encode(scope.engine->newString(QString()));
+ scope.result = scope.engine->newString(QString());
else
- return QV4::Encode(scope.engine->newString(r->responseBody()));
+ scope.result = scope.engine->newString(r->responseBody());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseXML(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_get_responseXML(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
@@ -1974,66 +1947,63 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseXML(CallContext *ctx)
if (!r->receivedXml() ||
(r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done)) {
- return Encode::null();
+ scope.result = Encode::null();
} else {
if (r->responseType().isEmpty())
r->setResponseType(QLatin1String("document"));
- return r->xmlResponseBody(scope.engine);
+ scope.result = r->xmlResponseBody(scope.engine);
}
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_response(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_get_response(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
if (r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done)
- return QV4::Encode(scope.engine->newString(QString()));
+ RETURN_RESULT(scope.engine->newString(QString()));
const QString& responseType = r->responseType();
if (responseType.compare(QLatin1String("text"), Qt::CaseInsensitive) == 0 || responseType.isEmpty()) {
- return QV4::Encode(scope.engine->newString(r->responseBody()));
+ RETURN_RESULT(scope.engine->newString(r->responseBody()));
} else if (responseType.compare(QLatin1String("arraybuffer"), Qt::CaseInsensitive) == 0) {
- return QV4::Encode(scope.engine->newArrayBuffer(r->rawResponseBody()));
+ RETURN_RESULT(scope.engine->newArrayBuffer(r->rawResponseBody()));
} else if (responseType.compare(QLatin1String("json"), Qt::CaseInsensitive) == 0) {
- return r->jsonResponseBody(scope.engine);
+ RETURN_RESULT(r->jsonResponseBody(scope.engine));
} else if (responseType.compare(QLatin1String("document"), Qt::CaseInsensitive) == 0) {
- return r->xmlResponseBody(scope.engine);
+ RETURN_RESULT(r->xmlResponseBody(scope.engine));
} else {
- return QV4::Encode(scope.engine->newString(QString()));
+ RETURN_RESULT(scope.engine->newString(QString()));
}
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_get_responseType(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_get_responseType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- return QV4::Encode(scope.engine->newString(r->responseType()));
+ scope.result = scope.engine->newString(r->responseType());
}
-ReturnedValue QQmlXMLHttpRequestCtor::method_set_responseType(CallContext *ctx)
+void QQmlXMLHttpRequestCtor::method_set_responseType(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- Scope scope(ctx);
- Scoped<QQmlXMLHttpRequestWrapper> w(scope, ctx->thisObject().as<QQmlXMLHttpRequestWrapper>());
+ Scoped<QQmlXMLHttpRequestWrapper> w(scope, callData->thisObject.as<QQmlXMLHttpRequestWrapper>());
if (!w)
V4THROW_REFERENCE("Not an XMLHttpRequest object");
QQmlXMLHttpRequest *r = w->d()->request;
- if (ctx->argc() < 1)
- V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+ if (callData->argc < 1)
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
// Argument 0 - response type
- r->setResponseType(ctx->args()[0].toQStringNoThrow());
+ r->setResponseType(callData->args[0].toQStringNoThrow());
- return Encode::undefined();
+ scope.result = Encode::undefined();
}
void qt_rem_qmlxmlhttprequest(ExecutionEngine * /* engine */, void *d)
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 19dc100f40..d359a0f62f 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -85,6 +85,12 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(QtObject);
+#define THROW_TYPE_ERROR_WITH_MESSAGE(msg) \
+ do { \
+ scope.result = scope.engine->throwTypeError(QString::fromUtf8(msg)); \
+ return; \
+ } while (false)
+
struct StaticQtMetaObject : public QObject
{
static const QMetaObject *get()
@@ -223,12 +229,12 @@ void QtObject::advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint
\qmlmethod bool Qt::isQtObject(object)
Returns true if \c object is a valid reference to a Qt or QML object, otherwise false.
*/
-ReturnedValue QtObject::method_isQtObject(QV4::CallContext *ctx)
+void QtObject::method_isQtObject(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() == 0)
- return QV4::Encode(false);
+ if (callData->argc == 0)
+ RETURN_RESULT(QV4::Encode(false));
- return QV4::Encode(ctx->args()[0].as<QV4::QObjectWrapper>() != 0);
+ scope.result = QV4::Encode(callData->args[0].as<QV4::QObjectWrapper>() != 0);
}
/*!
@@ -237,16 +243,16 @@ ReturnedValue QtObject::method_isQtObject(QV4::CallContext *ctx)
Returns a color with the specified \c red, \c green, \c blue and \c alpha components.
All components should be in the range 0-1 inclusive.
*/
-ReturnedValue QtObject::method_rgba(QV4::CallContext *ctx)
+void QtObject::method_rgba(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- int argCount = ctx->argc();
+ int argCount = callData->argc;
if (argCount < 3 || argCount > 4)
- V4THROW_ERROR("Qt.rgba(): Invalid arguments");
+ THROW_GENERIC_ERROR("Qt.rgba(): Invalid arguments");
- double r = ctx->args()[0].toNumber();
- double g = ctx->args()[1].toNumber();
- double b = ctx->args()[2].toNumber();
- double a = (argCount == 4) ? ctx->args()[3].toNumber() : 1;
+ double r = callData->args[0].toNumber();
+ double g = callData->args[1].toNumber();
+ double b = callData->args[2].toNumber();
+ double a = (argCount == 4) ? callData->args[3].toNumber() : 1;
if (r < 0.0) r=0.0;
if (r > 1.0) r=1.0;
@@ -257,7 +263,7 @@ ReturnedValue QtObject::method_rgba(QV4::CallContext *ctx)
if (a < 0.0) a=0.0;
if (a > 1.0) a=1.0;
- return ctx->engine()->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a));
+ scope.result = scope.engine->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a));
}
/*!
@@ -266,16 +272,16 @@ ReturnedValue QtObject::method_rgba(QV4::CallContext *ctx)
Returns a color with the specified \c hue, \c saturation, \c lightness and \c alpha components.
All components should be in the range 0-1 inclusive.
*/
-ReturnedValue QtObject::method_hsla(QV4::CallContext *ctx)
+void QtObject::method_hsla(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- int argCount = ctx->argc();
+ int argCount = callData->argc;
if (argCount < 3 || argCount > 4)
- V4THROW_ERROR("Qt.hsla(): Invalid arguments");
+ THROW_GENERIC_ERROR("Qt.hsla(): Invalid arguments");
- double h = ctx->args()[0].toNumber();
- double s = ctx->args()[1].toNumber();
- double l = ctx->args()[2].toNumber();
- double a = (argCount == 4) ? ctx->args()[3].toNumber() : 1;
+ double h = callData->args[0].toNumber();
+ double s = callData->args[1].toNumber();
+ double l = callData->args[2].toNumber();
+ double a = (argCount == 4) ? callData->args[3].toNumber() : 1;
if (h < 0.0) h=0.0;
if (h > 1.0) h=1.0;
@@ -286,7 +292,7 @@ ReturnedValue QtObject::method_hsla(QV4::CallContext *ctx)
if (a < 0.0) a=0.0;
if (a > 1.0) a=1.0;
- return ctx->engine()->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a));
+ scope.result = scope.engine->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a));
}
/*!
@@ -297,23 +303,23 @@ All components should be in the range 0-1 inclusive.
\since 5.5
*/
-ReturnedValue QtObject::method_hsva(QV4::CallContext *ctx)
+void QtObject::method_hsva(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- int argCount = ctx->argc();
+ int argCount = callData->argc;
if (argCount < 3 || argCount > 4)
- V4THROW_ERROR("Qt.hsva(): Invalid arguments");
+ THROW_GENERIC_ERROR("Qt.hsva(): Invalid arguments");
- double h = ctx->args()[0].toNumber();
- double s = ctx->args()[1].toNumber();
- double v = ctx->args()[2].toNumber();
- double a = (argCount == 4) ? ctx->args()[3].toNumber() : 1;
+ double h = callData->args[0].toNumber();
+ double s = callData->args[1].toNumber();
+ double v = callData->args[2].toNumber();
+ double a = (argCount == 4) ? callData->args[3].toNumber() : 1;
h = qBound(0.0, h, 1.0);
s = qBound(0.0, s, 1.0);
v = qBound(0.0, v, 1.0);
a = qBound(0.0, a, 1.0);
- return ctx->engine()->fromVariant(QQml_colorProvider()->fromHsvF(h, s, v, a));
+ scope.result = scope.engine->fromVariant(QQml_colorProvider()->fromHsvF(h, s, v, a));
}
/*!
@@ -324,35 +330,35 @@ may be either color values or string values. If a string value is supplied it
must be convertible to a color, as described for the \l{colorbasictypedocs}{color}
basic type.
*/
-ReturnedValue QtObject::method_colorEqual(QV4::CallContext *ctx)
+void QtObject::method_colorEqual(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 2)
- V4THROW_ERROR("Qt.colorEqual(): Invalid arguments");
+ if (callData->argc != 2)
+ THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments");
bool ok = false;
- QVariant lhs = ctx->d()->engine->toVariant(ctx->args()[0], -1);
+ QVariant lhs = scope.engine->toVariant(callData->args[0], -1);
if (lhs.userType() == QVariant::String) {
lhs = QQmlStringConverters::colorFromString(lhs.toString(), &ok);
if (!ok) {
- V4THROW_ERROR("Qt.colorEqual(): Invalid color name");
+ THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid color name");
}
} else if (lhs.userType() != QVariant::Color) {
- V4THROW_ERROR("Qt.colorEqual(): Invalid arguments");
+ THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments");
}
- QVariant rhs = ctx->engine()->toVariant(ctx->args()[1], -1);
+ QVariant rhs = scope.engine->toVariant(callData->args[1], -1);
if (rhs.userType() == QVariant::String) {
rhs = QQmlStringConverters::colorFromString(rhs.toString(), &ok);
if (!ok) {
- V4THROW_ERROR("Qt.colorEqual(): Invalid color name");
+ THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid color name");
}
} else if (rhs.userType() != QVariant::Color) {
- V4THROW_ERROR("Qt.colorEqual(): Invalid arguments");
+ THROW_GENERIC_ERROR("Qt.colorEqual(): Invalid arguments");
}
bool equal = (lhs == rhs);
- return QV4::Encode(equal);
+ scope.result = QV4::Encode(equal);
}
/*!
@@ -362,47 +368,47 @@ Returns a \c rect with the top-left corner at \c x, \c y and the specified \c wi
The returned object has \c x, \c y, \c width and \c height attributes with the given values.
*/
-ReturnedValue QtObject::method_rect(QV4::CallContext *ctx)
+void QtObject::method_rect(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 4)
- V4THROW_ERROR("Qt.rect(): Invalid arguments");
+ if (callData->argc != 4)
+ THROW_GENERIC_ERROR("Qt.rect(): Invalid arguments");
- double x = ctx->args()[0].toNumber();
- double y = ctx->args()[1].toNumber();
- double w = ctx->args()[2].toNumber();
- double h = ctx->args()[3].toNumber();
+ double x = callData->args[0].toNumber();
+ double y = callData->args[1].toNumber();
+ double w = callData->args[2].toNumber();
+ double h = callData->args[3].toNumber();
- return ctx->engine()->fromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
+ scope.result = scope.engine->fromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
}
/*!
\qmlmethod point Qt::point(int x, int y)
Returns a Point with the specified \c x and \c y coordinates.
*/
-ReturnedValue QtObject::method_point(QV4::CallContext *ctx)
+void QtObject::method_point(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 2)
- V4THROW_ERROR("Qt.point(): Invalid arguments");
+ if (callData->argc != 2)
+ THROW_GENERIC_ERROR("Qt.point(): Invalid arguments");
- double x = ctx->args()[0].toNumber();
- double y = ctx->args()[1].toNumber();
+ double x = callData->args[0].toNumber();
+ double y = callData->args[1].toNumber();
- return ctx->engine()->fromVariant(QVariant::fromValue(QPointF(x, y)));
+ scope.result = scope.engine->fromVariant(QVariant::fromValue(QPointF(x, y)));
}
/*!
\qmlmethod Qt::size(int width, int height)
Returns a Size with the specified \c width and \c height.
*/
-ReturnedValue QtObject::method_size(QV4::CallContext *ctx)
+void QtObject::method_size(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 2)
- V4THROW_ERROR("Qt.size(): Invalid arguments");
+ if (callData->argc != 2)
+ THROW_GENERIC_ERROR("Qt.size(): Invalid arguments");
- double w = ctx->args()[0].toNumber();
- double h = ctx->args()[1].toNumber();
+ double w = callData->args[0].toNumber();
+ double h = callData->args[1].toNumber();
- return ctx->engine()->fromVariant(QVariant::fromValue(QSizeF(w, h)));
+ scope.result = scope.engine->fromVariant(QVariant::fromValue(QSizeF(w, h)));
}
/*!
@@ -413,17 +419,17 @@ key-value pairs where valid keys are the \l{fontbasictypedocs}{font} type's
subproperty names, and the values are valid values for each subproperty.
Invalid keys will be ignored.
*/
-ReturnedValue QtObject::method_font(QV4::CallContext *ctx)
+void QtObject::method_font(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1 || !ctx->args()[0].isObject())
- V4THROW_ERROR("Qt.font(): Invalid arguments");
+ if (callData->argc != 1 || !callData->args[0].isObject())
+ THROW_GENERIC_ERROR("Qt.font(): Invalid arguments");
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
bool ok = false;
- QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, QQmlV4Handle(ctx->args()[0]), v4, &ok);
+ QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, QQmlV4Handle(callData->args[0]), v4, &ok);
if (!ok)
- V4THROW_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified");
- return ctx->engine()->fromVariant(v);
+ THROW_GENERIC_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified");
+ scope.result = scope.engine->fromVariant(v);
}
@@ -432,73 +438,73 @@ ReturnedValue QtObject::method_font(QV4::CallContext *ctx)
\qmlmethod Qt::vector2d(real x, real y)
Returns a Vector2D with the specified \c x and \c y.
*/
-ReturnedValue QtObject::method_vector2d(QV4::CallContext *ctx)
+void QtObject::method_vector2d(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 2)
- V4THROW_ERROR("Qt.vector2d(): Invalid arguments");
+ if (callData->argc != 2)
+ THROW_GENERIC_ERROR("Qt.vector2d(): Invalid arguments");
float xy[3]; // qvector2d uses float internally
- xy[0] = ctx->args()[0].toNumber();
- xy[1] = ctx->args()[1].toNumber();
+ xy[0] = callData->args[0].toNumber();
+ xy[1] = callData->args[1].toNumber();
const void *params[] = { xy };
- return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector2D, 1, params));
+ scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector2D, 1, params));
}
/*!
\qmlmethod Qt::vector3d(real x, real y, real z)
Returns a Vector3D with the specified \c x, \c y and \c z.
*/
-ReturnedValue QtObject::method_vector3d(QV4::CallContext *ctx)
+void QtObject::method_vector3d(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 3)
- V4THROW_ERROR("Qt.vector3d(): Invalid arguments");
+ if (callData->argc != 3)
+ THROW_GENERIC_ERROR("Qt.vector3d(): Invalid arguments");
float xyz[3]; // qvector3d uses float internally
- xyz[0] = ctx->args()[0].toNumber();
- xyz[1] = ctx->args()[1].toNumber();
- xyz[2] = ctx->args()[2].toNumber();
+ xyz[0] = callData->args[0].toNumber();
+ xyz[1] = callData->args[1].toNumber();
+ xyz[2] = callData->args[2].toNumber();
const void *params[] = { xyz };
- return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector3D, 1, params));
+ scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector3D, 1, params));
}
/*!
\qmlmethod Qt::vector4d(real x, real y, real z, real w)
Returns a Vector4D with the specified \c x, \c y, \c z and \c w.
*/
-ReturnedValue QtObject::method_vector4d(QV4::CallContext *ctx)
+void QtObject::method_vector4d(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 4)
- V4THROW_ERROR("Qt.vector4d(): Invalid arguments");
+ if (callData->argc != 4)
+ THROW_GENERIC_ERROR("Qt.vector4d(): Invalid arguments");
float xyzw[4]; // qvector4d uses float internally
- xyzw[0] = ctx->args()[0].toNumber();
- xyzw[1] = ctx->args()[1].toNumber();
- xyzw[2] = ctx->args()[2].toNumber();
- xyzw[3] = ctx->args()[3].toNumber();
+ xyzw[0] = callData->args[0].toNumber();
+ xyzw[1] = callData->args[1].toNumber();
+ xyzw[2] = callData->args[2].toNumber();
+ xyzw[3] = callData->args[3].toNumber();
const void *params[] = { xyzw };
- return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector4D, 1, params));
+ scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector4D, 1, params));
}
/*!
\qmlmethod Qt::quaternion(real scalar, real x, real y, real z)
Returns a Quaternion with the specified \c scalar, \c x, \c y, and \c z.
*/
-ReturnedValue QtObject::method_quaternion(QV4::CallContext *ctx)
+void QtObject::method_quaternion(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 4)
- V4THROW_ERROR("Qt.quaternion(): Invalid arguments");
+ if (callData->argc != 4)
+ THROW_GENERIC_ERROR("Qt.quaternion(): Invalid arguments");
qreal sxyz[4]; // qquaternion uses qreal internally
- sxyz[0] = ctx->args()[0].toNumber();
- sxyz[1] = ctx->args()[1].toNumber();
- sxyz[2] = ctx->args()[2].toNumber();
- sxyz[3] = ctx->args()[3].toNumber();
+ sxyz[0] = callData->args[0].toNumber();
+ sxyz[1] = callData->args[1].toNumber();
+ sxyz[2] = callData->args[2].toNumber();
+ sxyz[3] = callData->args[3].toNumber();
const void *params[] = { sxyz };
- return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QQuaternion, 1, params));
+ scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QQuaternion, 1, params));
}
/*!
@@ -510,44 +516,47 @@ matrix values.
Finally, the function may be called with no arguments and the resulting
matrix will be the identity matrix.
*/
-ReturnedValue QtObject::method_matrix4x4(QV4::CallContext *ctx)
+void QtObject::method_matrix4x4(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
- if (ctx->argc() == 0)
- return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 0, Q_NULLPTR));
+ if (callData->argc == 0) {
+ scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 0, Q_NULLPTR));
+ return;
+ }
- if (ctx->argc() == 1 && ctx->args()[0].isObject()) {
+ if (callData->argc == 1 && callData->args[0].isObject()) {
bool ok = false;
- QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, QQmlV4Handle(ctx->args()[0]), v4, &ok);
+ QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, QQmlV4Handle(callData->args[0]), v4, &ok);
if (!ok)
- V4THROW_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array");
- return ctx->engine()->fromVariant(v);
+ THROW_GENERIC_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array");
+ scope.result = scope.engine->fromVariant(v);
+ return;
}
- if (ctx->argc() != 16)
- V4THROW_ERROR("Qt.matrix4x4(): Invalid arguments");
+ if (callData->argc != 16)
+ THROW_GENERIC_ERROR("Qt.matrix4x4(): Invalid arguments");
qreal vals[16]; // qmatrix4x4 uses qreal internally
- vals[0] = ctx->args()[0].toNumber();
- vals[1] = ctx->args()[1].toNumber();
- vals[2] = ctx->args()[2].toNumber();
- vals[3] = ctx->args()[3].toNumber();
- vals[4] = ctx->args()[4].toNumber();
- vals[5] = ctx->args()[5].toNumber();
- vals[6] = ctx->args()[6].toNumber();
- vals[7] = ctx->args()[7].toNumber();
- vals[8] = ctx->args()[8].toNumber();
- vals[9] = ctx->args()[9].toNumber();
- vals[10] = ctx->args()[10].toNumber();
- vals[11] = ctx->args()[11].toNumber();
- vals[12] = ctx->args()[12].toNumber();
- vals[13] = ctx->args()[13].toNumber();
- vals[14] = ctx->args()[14].toNumber();
- vals[15] = ctx->args()[15].toNumber();
+ vals[0] = callData->args[0].toNumber();
+ vals[1] = callData->args[1].toNumber();
+ vals[2] = callData->args[2].toNumber();
+ vals[3] = callData->args[3].toNumber();
+ vals[4] = callData->args[4].toNumber();
+ vals[5] = callData->args[5].toNumber();
+ vals[6] = callData->args[6].toNumber();
+ vals[7] = callData->args[7].toNumber();
+ vals[8] = callData->args[8].toNumber();
+ vals[9] = callData->args[9].toNumber();
+ vals[10] = callData->args[10].toNumber();
+ vals[11] = callData->args[11].toNumber();
+ vals[12] = callData->args[12].toNumber();
+ vals[13] = callData->args[13].toNumber();
+ vals[14] = callData->args[14].toNumber();
+ vals[15] = callData->args[15].toNumber();
const void *params[] = { vals };
- return ctx->engine()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 1, params));
+ scope.result = scope.engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 1, params));
}
/*!
@@ -564,27 +573,29 @@ by factor and converts the color back to RGB.
If \c factor is not supplied, returns a color 50% lighter than \c baseColor (factor 1.5).
*/
-ReturnedValue QtObject::method_lighter(QV4::CallContext *ctx)
+void QtObject::method_lighter(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1 && ctx->argc() != 2)
- V4THROW_ERROR("Qt.lighter(): Invalid arguments");
+ if (callData->argc != 1 && callData->argc != 2)
+ THROW_GENERIC_ERROR("Qt.lighter(): Invalid arguments");
- QVariant v = ctx->engine()->toVariant(ctx->args()[0], -1);
+ QVariant v = scope.engine->toVariant(callData->args[0], -1);
if (v.userType() == QVariant::String) {
bool ok = false;
v = QQmlStringConverters::colorFromString(v.toString(), &ok);
if (!ok) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
} else if (v.userType() != QVariant::Color) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
qreal factor = 1.5;
- if (ctx->argc() == 2)
- factor = ctx->args()[1].toNumber();
+ if (callData->argc == 2)
+ factor = callData->args[1].toNumber();
- return ctx->engine()->fromVariant(QQml_colorProvider()->lighter(v, factor));
+ scope.result = scope.engine->fromVariant(QQml_colorProvider()->lighter(v, factor));
}
/*!
@@ -602,27 +613,29 @@ by factor and converts the color back to RGB.
If \c factor is not supplied, returns a color 50% darker than \c baseColor (factor 2.0).
*/
-ReturnedValue QtObject::method_darker(QV4::CallContext *ctx)
+void QtObject::method_darker(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1 && ctx->argc() != 2)
- V4THROW_ERROR("Qt.darker(): Invalid arguments");
+ if (callData->argc != 1 && callData->argc != 2)
+ THROW_GENERIC_ERROR("Qt.darker(): Invalid arguments");
- QVariant v = ctx->engine()->toVariant(ctx->args()[0], -1);
+ QVariant v = scope.engine->toVariant(callData->args[0], -1);
if (v.userType() == QVariant::String) {
bool ok = false;
v = QQmlStringConverters::colorFromString(v.toString(), &ok);
if (!ok) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
} else if (v.userType() != QVariant::Color) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
qreal factor = 2.0;
- if (ctx->argc() == 2)
- factor = ctx->args()[1].toNumber();
+ if (callData->argc == 2)
+ factor = callData->args[1].toNumber();
- return ctx->engine()->fromVariant(QQml_colorProvider()->darker(v, factor));
+ scope.result = scope.engine->fromVariant(QQml_colorProvider()->darker(v, factor));
}
/*!
@@ -649,36 +662,40 @@ ReturnedValue QtObject::method_darker(QV4::CallContext *ctx)
Tint is most useful when a subtle change is intended to be conveyed due to some event; you can then use tinting to more effectively tune the visible color.
*/
-ReturnedValue QtObject::method_tint(QV4::CallContext *ctx)
+void QtObject::method_tint(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 2)
- V4THROW_ERROR("Qt.tint(): Invalid arguments");
+ if (callData->argc != 2)
+ THROW_GENERIC_ERROR("Qt.tint(): Invalid arguments");
// base color
- QVariant v1 = ctx->engine()->toVariant(ctx->args()[0], -1);
+ QVariant v1 = scope.engine->toVariant(callData->args[0], -1);
if (v1.userType() == QVariant::String) {
bool ok = false;
v1 = QQmlStringConverters::colorFromString(v1.toString(), &ok);
if (!ok) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
} else if (v1.userType() != QVariant::Color) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
// tint color
- QVariant v2 = ctx->engine()->toVariant(ctx->args()[1], -1);
+ QVariant v2 = scope.engine->toVariant(callData->args[1], -1);
if (v2.userType() == QVariant::String) {
bool ok = false;
v2 = QQmlStringConverters::colorFromString(v2.toString(), &ok);
if (!ok) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
} else if (v2.userType() != QVariant::Color) {
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
+ return;
}
- return ctx->engine()->fromVariant(QQml_colorProvider()->tint(v1, v2));
+ scope.result = scope.engine->fromVariant(QQml_colorProvider()->tint(v1, v2));
}
/*!
@@ -697,32 +714,31 @@ If \a format is not specified, \a date is formatted using
\sa Locale
*/
-ReturnedValue QtObject::method_formatDate(QV4::CallContext *ctx)
+void QtObject::method_formatDate(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1 || ctx->argc() > 2)
- V4THROW_ERROR("Qt.formatDate(): Invalid arguments");
- QV4::Scope scope(ctx);
+ if (callData->argc < 1 || callData->argc > 2)
+ THROW_GENERIC_ERROR("Qt.formatDate(): Invalid arguments");
Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- QDate date = ctx->engine()->toVariant(ctx->args()[0], -1).toDateTime().date();
+ QDate date = scope.engine->toVariant(callData->args[0], -1).toDateTime().date();
QString formattedDate;
- if (ctx->argc() == 2) {
- QV4::ScopedString s(scope, ctx->args()[1]);
+ if (callData->argc == 2) {
+ QV4::ScopedString s(scope, callData->args[1]);
if (s) {
QString format = s->toQString();
formattedDate = date.toString(format);
- } else if (ctx->args()[1].isNumber()) {
- quint32 intFormat = ctx->args()[1].asDouble();
+ } else if (callData->args[1].isNumber()) {
+ quint32 intFormat = callData->args[1].asDouble();
Qt::DateFormat format = Qt::DateFormat(intFormat);
formattedDate = date.toString(format);
} else {
- V4THROW_ERROR("Qt.formatDate(): Invalid date format");
+ THROW_GENERIC_ERROR("Qt.formatDate(): Invalid date format");
}
} else {
formattedDate = date.toString(enumFormat);
}
- return ctx->d()->engine->newString(formattedDate)->asReturnedValue();
+ scope.result = scope.engine->newString(formattedDate);
}
/*!
@@ -740,38 +756,37 @@ If \a format is not specified, \a time is formatted using
\sa Locale
*/
-ReturnedValue QtObject::method_formatTime(QV4::CallContext *ctx)
+void QtObject::method_formatTime(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1 || ctx->argc() > 2)
- V4THROW_ERROR("Qt.formatTime(): Invalid arguments");
- QV4::Scope scope(ctx);
+ if (callData->argc < 1 || callData->argc > 2)
+ THROW_GENERIC_ERROR("Qt.formatTime(): Invalid arguments");
- QVariant argVariant = ctx->engine()->toVariant(ctx->args()[0], -1);
+ QVariant argVariant = scope.engine->toVariant(callData->args[0], -1);
QTime time;
- if (ctx->args()[0].as<DateObject>() || (argVariant.type() == QVariant::String))
+ if (callData->args[0].as<DateObject>() || (argVariant.type() == QVariant::String))
time = argVariant.toDateTime().time();
else // if (argVariant.type() == QVariant::Time), or invalid.
time = argVariant.toTime();
Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
QString formattedTime;
- if (ctx->argc() == 2) {
- QV4::ScopedString s(scope, ctx->args()[1]);
+ if (callData->argc == 2) {
+ QV4::ScopedString s(scope, callData->args[1]);
if (s) {
QString format = s->toQString();
formattedTime = time.toString(format);
- } else if (ctx->args()[1].isNumber()) {
- quint32 intFormat = ctx->args()[1].asDouble();
+ } else if (callData->args[1].isNumber()) {
+ quint32 intFormat = callData->args[1].asDouble();
Qt::DateFormat format = Qt::DateFormat(intFormat);
formattedTime = time.toString(format);
} else {
- V4THROW_ERROR("Qt.formatTime(): Invalid time format");
+ THROW_GENERIC_ERROR("Qt.formatTime(): Invalid time format");
}
} else {
formattedTime = time.toString(enumFormat);
}
- return ctx->d()->engine->newString(formattedTime)->asReturnedValue();
+ scope.result = scope.engine->newString(formattedTime);
}
/*!
@@ -864,32 +879,31 @@ with the \a format values below to produce the following results:
\sa Locale
*/
-ReturnedValue QtObject::method_formatDateTime(QV4::CallContext *ctx)
+void QtObject::method_formatDateTime(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1 || ctx->argc() > 2)
- V4THROW_ERROR("Qt.formatDateTime(): Invalid arguments");
- QV4::Scope scope(ctx);
+ if (callData->argc < 1 || callData->argc > 2)
+ THROW_GENERIC_ERROR("Qt.formatDateTime(): Invalid arguments");
Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- QDateTime dt = ctx->engine()->toVariant(ctx->args()[0], -1).toDateTime();
+ QDateTime dt = scope.engine->toVariant(callData->args[0], -1).toDateTime();
QString formattedDt;
- if (ctx->argc() == 2) {
- QV4::ScopedString s(scope, ctx->args()[1]);
+ if (callData->argc == 2) {
+ QV4::ScopedString s(scope, callData->args[1]);
if (s) {
QString format = s->toQString();
formattedDt = dt.toString(format);
- } else if (ctx->args()[1].isNumber()) {
- quint32 intFormat = ctx->args()[1].asDouble();
+ } else if (callData->args[1].isNumber()) {
+ quint32 intFormat = callData->args[1].asDouble();
Qt::DateFormat format = Qt::DateFormat(intFormat);
formattedDt = dt.toString(format);
} else {
- V4THROW_ERROR("Qt.formatDateTime(): Invalid datetime format");
+ THROW_GENERIC_ERROR("Qt.formatDateTime(): Invalid datetime format");
}
} else {
formattedDt = dt.toString(enumFormat);
}
- return ctx->d()->engine->newString(formattedDt)->asReturnedValue();
+ scope.result = scope.engine->newString(formattedDt);
}
/*!
@@ -903,90 +917,94 @@ ReturnedValue QtObject::method_formatDateTime(QV4::CallContext *ctx)
still fail to launch or fail to open the requested URL. This result will not be reported back
to the application.
*/
-ReturnedValue QtObject::method_openUrlExternally(QV4::CallContext *ctx)
+void QtObject::method_openUrlExternally(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- return QV4::Encode(false);
+ if (callData->argc != 1) {
+ scope.result = QV4::Encode(false);
+ return;
+ }
- QUrl url(Value::fromReturnedValue(method_resolvedUrl(ctx)).toQStringNoThrow());
- return ctx->engine()->fromVariant(QQml_guiProvider()->openUrlExternally(url));
+ method_resolvedUrl(b, scope, callData);
+ QUrl url(scope.result.toQStringNoThrow());
+ scope.result = scope.engine->fromVariant(QQml_guiProvider()->openUrlExternally(url));
}
/*!
\qmlmethod url Qt::resolvedUrl(url url)
Returns \a url resolved relative to the URL of the caller.
*/
-ReturnedValue QtObject::method_resolvedUrl(QV4::CallContext *ctx)
+void QtObject::method_resolvedUrl(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- ExecutionEngine *v4 = ctx->engine();
+ ExecutionEngine *v4 = scope.engine;
- QUrl url = v4->toVariant(ctx->args()[0], -1).toUrl();
+ QUrl url = v4->toVariant(callData->args[0], -1).toUrl();
QQmlEngine *e = v4->qmlEngine();
QQmlEnginePrivate *p = 0;
if (e) p = QQmlEnginePrivate::get(e);
if (p) {
QQmlContextData *ctxt = v4->callingQmlContext();
if (ctxt)
- return v4->newString(ctxt->resolvedUrl(url).toString())->asReturnedValue();
+ scope.result = v4->newString(ctxt->resolvedUrl(url).toString());
else
- return v4->newString(url.toString())->asReturnedValue();
+ scope.result = v4->newString(url.toString());
+ return;
}
- return v4->newString(e->baseUrl().resolved(url).toString())->asReturnedValue();
+ scope.result = v4->newString(e->baseUrl().resolved(url).toString());
}
/*!
\qmlmethod list<string> Qt::fontFamilies()
Returns a list of the font families available to the application.
*/
-ReturnedValue QtObject::method_fontFamilies(CallContext *ctx)
+void QtObject::method_fontFamilies(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 0)
- V4THROW_ERROR("Qt.fontFamilies(): Invalid arguments");
+ if (callData->argc != 0)
+ THROW_GENERIC_ERROR("Qt.fontFamilies(): Invalid arguments");
- return ctx->engine()->fromVariant(QVariant(QQml_guiProvider()->fontFamilies()));
+ scope.result = scope.engine->fromVariant(QVariant(QQml_guiProvider()->fontFamilies()));
}
/*!
\qmlmethod string Qt::md5(data)
Returns a hex string of the md5 hash of \c data.
*/
-ReturnedValue QtObject::method_md5(CallContext *ctx)
+void QtObject::method_md5(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("Qt.md5(): Invalid arguments");
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("Qt.md5(): Invalid arguments");
- QByteArray data = ctx->args()[0].toQStringNoThrow().toUtf8();
+ QByteArray data = callData->args[0].toQStringNoThrow().toUtf8();
QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5);
- return ctx->d()->engine->newString(QLatin1String(result.toHex()))->asReturnedValue();
+ scope.result = scope.engine->newString(QLatin1String(result.toHex()));
}
/*!
\qmlmethod string Qt::btoa(data)
Binary to ASCII - this function returns a base64 encoding of \c data.
*/
-ReturnedValue QtObject::method_btoa(CallContext *ctx)
+void QtObject::method_btoa(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("Qt.btoa(): Invalid arguments");
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("Qt.btoa(): Invalid arguments");
- QByteArray data = ctx->args()[0].toQStringNoThrow().toUtf8();
+ QByteArray data = callData->args[0].toQStringNoThrow().toUtf8();
- return ctx->d()->engine->newString(QLatin1String(data.toBase64()))->asReturnedValue();
+ scope.result = scope.engine->newString(QLatin1String(data.toBase64()));
}
/*!
\qmlmethod string Qt::atob(data)
ASCII to binary - this function decodes the base64 encoded \a data string and returns it.
*/
-ReturnedValue QtObject::method_atob(CallContext *ctx)
+void QtObject::method_atob(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("Qt.atob(): Invalid arguments");
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("Qt.atob(): Invalid arguments");
- QByteArray data = ctx->args()[0].toQStringNoThrow().toLatin1();
+ QByteArray data = callData->args[0].toQStringNoThrow().toLatin1();
- return ctx->d()->engine->newString(QString::fromUtf8(QByteArray::fromBase64(data)))->asReturnedValue();
+ scope.result = scope.engine->newString(QString::fromUtf8(QByteArray::fromBase64(data)));
}
/*!
@@ -998,10 +1016,10 @@ QQmlEngine::quit() signal to the QCoreApplication::quit() slot.
\sa exit()
*/
-ReturnedValue QtObject::method_quit(CallContext *ctx)
+void QtObject::method_quit(const BuiltinFunction *, Scope &scope, CallData *)
{
- QQmlEnginePrivate::get(ctx->engine()->qmlEngine())->sendQuit();
- return QV4::Encode::undefined();
+ QQmlEnginePrivate::get(scope.engine->qmlEngine())->sendQuit();
+ scope.result = Encode::undefined();
}
/*!
@@ -1015,15 +1033,15 @@ ReturnedValue QtObject::method_quit(CallContext *ctx)
\sa quit()
*/
-ReturnedValue QtObject::method_exit(CallContext *ctx)
+void QtObject::method_exit(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("Qt.exit(): Invalid arguments");
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("Qt.exit(): Invalid arguments");
- int retCode = ctx->args()[0].toNumber();
+ int retCode = callData->args[0].toNumber();
- QQmlEnginePrivate::get(ctx->engine()->qmlEngine())->sendExit(retCode);
- return QV4::Encode::undefined();
+ QQmlEnginePrivate::get(scope.engine->qmlEngine())->sendExit(retCode);
+ scope.result = QV4::Encode::undefined();
}
/*!
@@ -1050,11 +1068,10 @@ If this is the case, consider using \l{QtQml::Qt::createComponent()}{Qt.createCo
See \l {Dynamic QML Object Creation from JavaScript} for more information on using this function.
*/
-ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
+void QtObject::method_createQmlObject(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- Scope scope(ctx);
- if (ctx->argc() < 2 || ctx->argc() > 3)
- V4THROW_ERROR("Qt.createQmlObject(): Invalid arguments");
+ if (callData->argc < 2 || callData->argc > 3)
+ THROW_GENERIC_ERROR("Qt.createQmlObject(): Invalid arguments");
struct Error {
static ReturnedValue create(QV4::ExecutionEngine *v4, const QList<QQmlError> &errors) {
@@ -1085,7 +1102,7 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
}
};
- QV8Engine *v8engine = ctx->d()->engine->v8Engine;
+ QV8Engine *v8engine = scope.engine->v8Engine;
QQmlEngine *engine = v8engine->engine();
QQmlContextData *context = scope.engine->callingQmlContext();
@@ -1097,13 +1114,13 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
effectiveContext = context->asQQmlContext();
Q_ASSERT(effectiveContext);
- QString qml = ctx->args()[0].toQStringNoThrow();
+ QString qml = callData->args[0].toQStringNoThrow();
if (qml.isEmpty())
- return QV4::Encode::null();
+ RETURN_RESULT(Encode::null());
QUrl url;
- if (ctx->argc() > 2)
- url = QUrl(ctx->args()[2].toQStringNoThrow());
+ if (callData->argc > 2)
+ url = QUrl(callData->args[2].toQStringNoThrow());
else
url = QUrl(QLatin1String("inline"));
@@ -1111,11 +1128,11 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
url = context->resolvedUrl(url);
QObject *parentArg = 0;
- QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, ctx->args()[1]);
+ QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, callData->args[1]);
if (!!qobjectWrapper)
parentArg = qobjectWrapper->object();
if (!parentArg)
- V4THROW_ERROR("Qt.createQmlObject(): Missing parent object");
+ THROW_GENERIC_ERROR("Qt.createQmlObject(): Missing parent object");
QQmlTypeData *typeData = QQmlEnginePrivate::get(engine)->typeLoader.getType(
qml.toUtf8(), url, QQmlTypeLoader::Synchronous);
@@ -1126,12 +1143,12 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
componentPrivate->progress = 1.0;
if (component.isError()) {
- ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors()));
- return ctx->engine()->throwError(v);
+ ScopedValue v(scope, Error::create(scope.engine, component.errors()));
+ RETURN_RESULT(scope.engine->throwError(v));
}
if (!component.isReady())
- V4THROW_ERROR("Qt.createQmlObject(): Component is not ready");
+ THROW_GENERIC_ERROR("Qt.createQmlObject(): Component is not ready");
QObject *obj = component.beginCreate(effectiveContext);
if (obj) {
@@ -1150,13 +1167,14 @@ ReturnedValue QtObject::method_createQmlObject(CallContext *ctx)
component.completeCreate();
if (component.isError()) {
- ScopedValue v(scope, Error::create(ctx->d()->engine, component.errors()));
- return ctx->engine()->throwError(v);
+ ScopedValue v(scope, Error::create(scope.engine, component.errors()));
+ scope.result = scope.engine->throwError(v);
+ return;
}
Q_ASSERT(obj);
- return QV4::QObjectWrapper::wrap(ctx->d()->engine, obj);
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, obj);
}
/*!
@@ -1203,14 +1221,12 @@ See \l {Dynamic QML Object Creation from JavaScript} for more information on usi
To create a QML object from an arbitrary string of QML (instead of a file),
use \l{QtQml::Qt::createQmlObject()}{Qt.createQmlObject()}.
*/
-ReturnedValue QtObject::method_createComponent(CallContext *ctx)
+void QtObject::method_createComponent(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1 || ctx->argc() > 3)
- return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
+ if (callData->argc < 1 || callData->argc > 3)
+ THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments");
- Scope scope(ctx);
-
- QV8Engine *v8engine = ctx->d()->engine->v8Engine;
+ QV8Engine *v8engine = scope.engine->v8Engine;
QQmlEngine *engine = v8engine->engine();
QQmlContextData *context = scope.engine->callingQmlContext();
@@ -1219,41 +1235,41 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx)
if (context->isPragmaLibraryContext)
effectiveContext = 0;
- QString arg = ctx->args()[0].toQStringNoThrow();
+ QString arg = callData->args[0].toQStringNoThrow();
if (arg.isEmpty())
- return QV4::Encode::null();
+ RETURN_RESULT(QV4::Encode::null());
QQmlComponent::CompilationMode compileMode = QQmlComponent::PreferSynchronous;
QObject *parentArg = 0;
int consumedCount = 1;
- if (ctx->argc() > 1) {
- ScopedValue lastArg(scope, ctx->args()[ctx->argc()-1]);
+ if (callData->argc > 1) {
+ ScopedValue lastArg(scope, callData->args[callData->argc-1]);
// The second argument could be the mode enum
- if (ctx->args()[1].isInteger()) {
- int mode = ctx->args()[1].integerValue();
+ if (callData->args[1].isInteger()) {
+ int mode = callData->args[1].integerValue();
if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous))
- return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
+ THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments");
compileMode = QQmlComponent::CompilationMode(mode);
consumedCount += 1;
} else {
// The second argument could be the parent only if there are exactly two args
- if ((ctx->argc() != 2) || !(lastArg->isObject() || lastArg->isNull()))
- return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid arguments"));
+ if ((callData->argc != 2) || !(lastArg->isObject() || lastArg->isNull()))
+ THROW_GENERIC_ERROR("Qt.createComponent(): Invalid arguments");
}
- if (consumedCount < ctx->argc()) {
+ if (consumedCount < callData->argc) {
if (lastArg->isObject()) {
Scoped<QObjectWrapper> qobjectWrapper(scope, lastArg);
if (qobjectWrapper)
parentArg = qobjectWrapper->object();
if (!parentArg)
- return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object"));
+ THROW_GENERIC_ERROR("Qt.createComponent(): Invalid parent object");
} else if (lastArg->isNull()) {
parentArg = 0;
} else {
- return ctx->engine()->throwError(QStringLiteral("Qt.createComponent(): Invalid parent object"));
+ THROW_GENERIC_ERROR("Qt.createComponent(): Invalid parent object");
}
}
}
@@ -1264,7 +1280,7 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx)
QQmlData::get(c, true)->explicitIndestructibleSet = false;
QQmlData::get(c)->indestructible = false;
- return QV4::QObjectWrapper::wrap(ctx->d()->engine, c);
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, c);
}
/*!
@@ -1287,18 +1303,18 @@ ReturnedValue QtObject::method_createComponent(CallContext *ctx)
\sa Locale
*/
-ReturnedValue QtObject::method_locale(CallContext *ctx)
+void QtObject::method_locale(const BuiltinFunction *, Scope &scope, CallData *callData)
{
QString code;
- if (ctx->argc() > 1)
- V4THROW_ERROR("locale() requires 0 or 1 argument");
- if (ctx->argc() == 1 && !ctx->args()[0].isString())
- V4THROW_TYPE("locale(): argument (locale code) must be a string");
+ if (callData->argc > 1)
+ THROW_GENERIC_ERROR("locale() requires 0 or 1 argument");
+ if (callData->argc == 1 && !callData->args[0].isString())
+ THROW_TYPE_ERROR_WITH_MESSAGE("locale(): argument (locale code) must be a string");
- if (ctx->argc() == 1)
- code = ctx->args()[0].toQStringNoThrow();
+ if (callData->argc == 1)
+ code = callData->args[0].toQStringNoThrow();
- return QQmlLocale::locale(ctx->engine(), code);
+ scope.result = QQmlLocale::locale(scope.engine, code);
}
void Heap::QQmlBindingFunction::init(const QV4::FunctionObject *originalFunction)
@@ -1360,62 +1376,62 @@ DEFINE_OBJECT_VTABLE(QQmlBindingFunction);
\since 5.0
*/
-ReturnedValue QtObject::method_binding(CallContext *ctx)
+void QtObject::method_binding(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("binding() requires 1 argument");
- const QV4::FunctionObject *f = ctx->args()[0].as<FunctionObject>();
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("binding() requires 1 argument");
+ const QV4::FunctionObject *f = callData->args[0].as<FunctionObject>();
if (!f)
- V4THROW_TYPE("binding(): argument (binding expression) must be a function");
+ THROW_TYPE_ERROR_WITH_MESSAGE("binding(): argument (binding expression) must be a function");
- return (ctx->d()->engine->memoryManager->allocObject<QQmlBindingFunction>(f))->asReturnedValue();
+ scope.result = scope.engine->memoryManager->allocObject<QQmlBindingFunction>(f);
}
-ReturnedValue QtObject::method_get_platform(CallContext *ctx)
+void QtObject::method_get_platform(const BuiltinFunction *, Scope &scope, CallData *callData)
{
// ### inefficient. Should be just a value based getter
- Object *o = ctx->thisObject().as<Object>();
+ Object *o = callData->thisObject.as<Object>();
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
QtObject *qt = o->as<QtObject>();
if (!qt)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (!qt->d()->platform)
// Only allocate a platform object once
- qt->d()->platform = new QQmlPlatform(ctx->d()->engine->jsEngine());
+ qt->d()->platform = new QQmlPlatform(scope.engine->jsEngine());
- return QV4::QObjectWrapper::wrap(ctx->d()->engine, qt->d()->platform);
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, qt->d()->platform);
}
-ReturnedValue QtObject::method_get_application(CallContext *ctx)
+void QtObject::method_get_application(const BuiltinFunction *, Scope &scope, CallData *callData)
{
// ### inefficient. Should be just a value based getter
- Object *o = ctx->thisObject().as<Object>();
+ Object *o = callData->thisObject.as<Object>();
if (!o)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
QtObject *qt = o->as<QtObject>();
if (!qt)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (!qt->d()->application)
// Only allocate an application object once
- qt->d()->application = QQml_guiProvider()->application(ctx->d()->engine->jsEngine());
+ qt->d()->application = QQml_guiProvider()->application(scope.engine->jsEngine());
- return QV4::QObjectWrapper::wrap(ctx->d()->engine, qt->d()->application);
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, qt->d()->application);
}
-ReturnedValue QtObject::method_get_inputMethod(CallContext *ctx)
+void QtObject::method_get_inputMethod(const BuiltinFunction *, Scope &scope, CallData *)
{
QObject *o = QQml_guiProvider()->inputMethod();
- return QV4::QObjectWrapper::wrap(ctx->d()->engine, o);
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, o);
}
-ReturnedValue QtObject::method_get_styleHints(CallContext *ctx)
+void QtObject::method_get_styleHints(const BuiltinFunction *, Scope &scope, CallData *)
{
QObject *o = QQml_guiProvider()->styleHints();
- return QV4::QObjectWrapper::wrap(ctx->d()->engine, o);
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, o);
}
@@ -1475,35 +1491,35 @@ static QString jsStack(QV4::ExecutionEngine *engine) {
return stack;
}
-static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *ctx,
- bool printStack = false)
+static void writeToConsole(const BuiltinFunction *, Scope &scope, CallData *callData,
+ ConsoleLogTypes logType, bool printStack = false)
{
QLoggingCategory *loggingCategory = 0;
QString result;
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
int start = 0;
- if (ctx->argc() > 0) {
- if (const QObjectWrapper* wrapper = ctx->args()[0].as<QObjectWrapper>()) {
+ if (callData->argc > 0) {
+ if (const QObjectWrapper* wrapper = callData->args[0].as<QObjectWrapper>()) {
if (QQmlLoggingCategory* category = qobject_cast<QQmlLoggingCategory*>(wrapper->object())) {
if (category->category())
loggingCategory = category->category();
else
- V4THROW_ERROR("A QmlLoggingCatgory was provided without a valid name");
+ THROW_GENERIC_ERROR("A QmlLoggingCatgory was provided without a valid name");
start = 1;
}
}
}
- for (int i = start; i < ctx->argc(); ++i) {
+ for (int i = start; i < callData->argc; ++i) {
if (i != start)
result.append(QLatin1Char(' '));
- if (ctx->args()[i].as<ArrayObject>())
- result += QLatin1Char('[') + ctx->args()[i].toQStringNoThrow() + QLatin1Char(']');
+ if (callData->args[i].as<ArrayObject>())
+ result += QLatin1Char('[') + callData->args[i].toQStringNoThrow() + QLatin1Char(']');
else
- result.append(ctx->args()[i].toQStringNoThrow());
+ result.append(callData->args[i].toQStringNoThrow());
}
if (printStack)
@@ -1540,32 +1556,32 @@ static QV4::ReturnedValue writeToConsole(ConsoleLogTypes logType, CallContext *c
break;
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
DEFINE_OBJECT_VTABLE(ConsoleObject);
-QV4::ReturnedValue ConsoleObject::method_error(CallContext *ctx)
+void ConsoleObject::method_error(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- return writeToConsole(Error, ctx);
+ writeToConsole(b, scope, callData, Error);
}
-QV4::ReturnedValue ConsoleObject::method_log(CallContext *ctx)
+void ConsoleObject::method_log(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
//console.log
//console.debug
//print
- return writeToConsole(Log, ctx);
+ writeToConsole(b, scope, callData, Log);
}
-QV4::ReturnedValue ConsoleObject::method_info(CallContext *ctx)
+void ConsoleObject::method_info(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- return writeToConsole(Info, ctx);
+ writeToConsole(b, scope, callData, Info);
}
-QV4::ReturnedValue ConsoleObject::method_profile(CallContext *ctx)
+void ConsoleObject::method_profile(const BuiltinFunction *, Scope &scope, CallData *)
{
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
QV4::StackFrame frame = v4->currentStackFrame();
const QByteArray baSource = frame.source.toUtf8();
@@ -1579,12 +1595,12 @@ QV4::ReturnedValue ConsoleObject::method_profile(CallContext *ctx)
logger.debug("Profiling started.");
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_profileEnd(CallContext *ctx)
+void ConsoleObject::method_profileEnd(const BuiltinFunction *, Scope &scope, CallData *)
{
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
QV4::StackFrame frame = v4->currentStackFrame();
const QByteArray baSource = frame.source.toUtf8();
@@ -1599,46 +1615,46 @@ QV4::ReturnedValue ConsoleObject::method_profileEnd(CallContext *ctx)
logger.debug("Profiling ended.");
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_time(CallContext *ctx)
+void ConsoleObject::method_time(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("console.time(): Invalid arguments");
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("console.time(): Invalid arguments");
- QV8Engine *v8engine = ctx->d()->engine->v8Engine;
+ QV8Engine *v8engine = scope.engine->v8Engine;
- QString name = ctx->args()[0].toQStringNoThrow();
+ QString name = callData->args[0].toQStringNoThrow();
v8engine->startTimer(name);
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_timeEnd(CallContext *ctx)
+void ConsoleObject::method_timeEnd(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("console.timeEnd(): Invalid arguments");
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("console.timeEnd(): Invalid arguments");
- QV8Engine *v8engine = ctx->d()->engine->v8Engine;
+ QV8Engine *v8engine = scope.engine->v8Engine;
- QString name = ctx->args()[0].toQStringNoThrow();
+ QString name = callData->args[0].toQStringNoThrow();
bool wasRunning;
qint64 elapsed = v8engine->stopTimer(name, &wasRunning);
if (wasRunning) {
qDebug("%s: %llims", qPrintable(name), elapsed);
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_count(CallContext *ctx)
+void ConsoleObject::method_count(const BuiltinFunction *, Scope &scope, CallData *callData)
{
// first argument: name to print. Ignore any additional arguments
QString name;
- if (ctx->argc() > 0)
- name = ctx->args()[0].toQStringNoThrow();
+ if (callData->argc > 0)
+ name = callData->args[0].toQStringNoThrow();
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
- QV8Engine *v8engine = ctx->d()->engine->v8Engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
+ QV8Engine *v8engine = scope.engine->v8Engine;
QV4::StackFrame frame = v4->currentStackFrame();
@@ -1651,15 +1667,15 @@ QV4::ReturnedValue ConsoleObject::method_count(CallContext *ctx)
qPrintable(frame.function))
.debug("%s", qPrintable(message));
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_trace(CallContext *ctx)
+void ConsoleObject::method_trace(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 0)
- V4THROW_ERROR("console.trace(): Invalid arguments");
+ if (callData->argc != 0)
+ THROW_GENERIC_ERROR("console.trace(): Invalid arguments");
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
QString stack = jsStack(v4);
@@ -1668,28 +1684,28 @@ QV4::ReturnedValue ConsoleObject::method_trace(CallContext *ctx)
frame.function.toUtf8().constData())
.debug("%s", qPrintable(stack));
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_warn(CallContext *ctx)
+void ConsoleObject::method_warn(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- return writeToConsole(Warn, ctx);
+ return writeToConsole(b, scope, callData, Warn);
}
-QV4::ReturnedValue ConsoleObject::method_assert(CallContext *ctx)
+void ConsoleObject::method_assert(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() == 0)
- V4THROW_ERROR("console.assert(): Missing argument");
+ if (callData->argc == 0)
+ THROW_GENERIC_ERROR("console.assert(): Missing argument");
- QV4::ExecutionEngine *v4 = ctx->d()->engine;
+ QV4::ExecutionEngine *v4 = scope.engine;
- if (!ctx->args()[0].toBoolean()) {
+ if (!callData->args[0].toBoolean()) {
QString message;
- for (int i = 1; i < ctx->argc(); ++i) {
+ for (int i = 1; i < callData->argc; ++i) {
if (i != 1)
message.append(QLatin1Char(' '));
- message.append(ctx->args()[i].toQStringNoThrow());
+ message.append(callData->args[i].toQStringNoThrow());
}
QString stack = jsStack(v4);
@@ -1700,17 +1716,17 @@ QV4::ReturnedValue ConsoleObject::method_assert(CallContext *ctx)
.critical("%s\n%s",qPrintable(message), qPrintable(stack));
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-QV4::ReturnedValue ConsoleObject::method_exception(CallContext *ctx)
+void ConsoleObject::method_exception(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- if (ctx->argc() == 0)
- V4THROW_ERROR("console.exception(): Missing argument");
+ if (callData->argc == 0)
+ THROW_GENERIC_ERROR("console.exception(): Missing argument");
- writeToConsole(Error, ctx, true);
+ writeToConsole(b, scope, callData, Error, true);
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
@@ -1766,38 +1782,38 @@ void QV4::GlobalExtensions::init(Object *globalObject, QJSEngine::Extensions ext
\sa {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTranslate(CallContext *ctx)
-{
- if (ctx->argc() < 2)
- V4THROW_ERROR("qsTranslate() requires at least two arguments");
- if (!ctx->args()[0].isString())
- V4THROW_ERROR("qsTranslate(): first argument (context) must be a string");
- if (!ctx->args()[1].isString())
- V4THROW_ERROR("qsTranslate(): second argument (sourceText) must be a string");
- if ((ctx->argc() > 2) && !ctx->args()[2].isString())
- V4THROW_ERROR("qsTranslate(): third argument (disambiguation) must be a string");
-
- QString context = ctx->args()[0].toQStringNoThrow();
- QString text = ctx->args()[1].toQStringNoThrow();
+void GlobalExtensions::method_qsTranslate(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ if (callData->argc < 2)
+ THROW_GENERIC_ERROR("qsTranslate() requires at least two arguments");
+ if (!callData->args[0].isString())
+ THROW_GENERIC_ERROR("qsTranslate(): first argument (context) must be a string");
+ if (!callData->args[1].isString())
+ THROW_GENERIC_ERROR("qsTranslate(): second argument (sourceText) must be a string");
+ if ((callData->argc > 2) && !callData->args[2].isString())
+ THROW_GENERIC_ERROR("qsTranslate(): third argument (disambiguation) must be a string");
+
+ QString context = callData->args[0].toQStringNoThrow();
+ QString text = callData->args[1].toQStringNoThrow();
QString comment;
- if (ctx->argc() > 2) comment = ctx->args()[2].toQStringNoThrow();
+ if (callData->argc > 2) comment = callData->args[2].toQStringNoThrow();
int i = 3;
- if (ctx->argc() > i && ctx->args()[i].isString()) {
+ if (callData->argc > i && callData->args[i].isString()) {
qWarning("qsTranslate(): specifying the encoding as fourth argument is deprecated");
++i;
}
int n = -1;
- if (ctx->argc() > i)
- n = ctx->args()[i].toInt32();
+ if (callData->argc > i)
+ n = callData->args[i].toInt32();
QString result = QCoreApplication::translate(context.toUtf8().constData(),
text.toUtf8().constData(),
comment.toUtf8().constData(),
n);
- return ctx->d()->engine->newString(result)->asReturnedValue();
+ scope.result = scope.engine->newString(result);
}
/*!
@@ -1822,11 +1838,12 @@ ReturnedValue GlobalExtensions::method_qsTranslate(CallContext *ctx)
\sa {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTranslateNoOp(CallContext *ctx)
+void GlobalExtensions::method_qsTranslateNoOp(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 2)
- return QV4::Encode::undefined();
- return ctx->args()[1].asReturnedValue();
+ if (callData->argc < 2)
+ scope.result = QV4::Encode::undefined();
+ else
+ scope.result = callData->args[1];
}
/*!
@@ -1846,18 +1863,17 @@ ReturnedValue GlobalExtensions::method_qsTranslateNoOp(CallContext *ctx)
\sa {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx)
-{
- if (ctx->argc() < 1)
- V4THROW_ERROR("qsTr() requires at least one argument");
- if (!ctx->args()[0].isString())
- V4THROW_ERROR("qsTr(): first argument (sourceText) must be a string");
- if ((ctx->argc() > 1) && !ctx->args()[1].isString())
- V4THROW_ERROR("qsTr(): second argument (disambiguation) must be a string");
- if ((ctx->argc() > 2) && !ctx->args()[2].isNumber())
- V4THROW_ERROR("qsTr(): third argument (n) must be a number");
-
- Scope scope(ctx);
+void GlobalExtensions::method_qsTr(const BuiltinFunction *, Scope &scope, CallData *callData)
+{
+ if (callData->argc < 1)
+ THROW_GENERIC_ERROR("qsTr() requires at least one argument");
+ if (!callData->args[0].isString())
+ THROW_GENERIC_ERROR("qsTr(): first argument (sourceText) must be a string");
+ if ((callData->argc > 1) && !callData->args[1].isString())
+ THROW_GENERIC_ERROR("qsTr(): second argument (disambiguation) must be a string");
+ if ((callData->argc > 2) && !callData->args[2].isNumber())
+ THROW_GENERIC_ERROR("qsTr(): third argument (n) must be a number");
+
QString context;
if (QQmlContextData *ctxt = scope.engine->callingQmlContext()) {
QString path = ctxt->urlString();
@@ -1866,7 +1882,7 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx)
int length = lastDot - (lastSlash + 1);
context = (lastSlash > -1) ? path.mid(lastSlash + 1, (length > -1) ? length : -1) : QString();
} else {
- ExecutionContext *parentCtx = scope.engine->parentContext(ctx);
+ ExecutionContext *parentCtx = scope.engine->currentContext;
// The first non-empty source URL in the call stack determines the translation context.
while (!!parentCtx && context.isEmpty()) {
if (QV4::CompiledData::CompilationUnit *unit = parentCtx->d()->compilationUnit) {
@@ -1885,18 +1901,18 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx)
}
}
- QString text = ctx->args()[0].toQStringNoThrow();
+ QString text = callData->args[0].toQStringNoThrow();
QString comment;
- if (ctx->argc() > 1)
- comment = ctx->args()[1].toQStringNoThrow();
+ if (callData->argc > 1)
+ comment = callData->args[1].toQStringNoThrow();
int n = -1;
- if (ctx->argc() > 2)
- n = ctx->args()[2].toInt32();
+ if (callData->argc > 2)
+ n = callData->args[2].toInt32();
QString result = QCoreApplication::translate(context.toUtf8().constData(), text.toUtf8().constData(),
comment.toUtf8().constData(), n);
- return ctx->d()->engine->newString(result)->asReturnedValue();
+ scope.result = scope.engine->newString(result);
}
/*!
@@ -1921,11 +1937,12 @@ ReturnedValue GlobalExtensions::method_qsTr(CallContext *ctx)
\sa {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTrNoOp(CallContext *ctx)
+void GlobalExtensions::method_qsTrNoOp(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1)
- return QV4::Encode::undefined();
- return ctx->args()[0].asReturnedValue();
+ if (callData->argc < 1)
+ scope.result = QV4::Encode::undefined();
+ else
+ scope.result = callData->args[0];
}
/*!
@@ -1958,20 +1975,20 @@ ReturnedValue GlobalExtensions::method_qsTrNoOp(CallContext *ctx)
\sa QT_TRID_NOOP(), {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTrId(CallContext *ctx)
+void GlobalExtensions::method_qsTrId(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1)
- V4THROW_ERROR("qsTrId() requires at least one argument");
- if (!ctx->args()[0].isString())
- V4THROW_TYPE("qsTrId(): first argument (id) must be a string");
- if (ctx->argc() > 1 && !ctx->args()[1].isNumber())
- V4THROW_TYPE("qsTrId(): second argument (n) must be a number");
+ if (callData->argc < 1)
+ THROW_GENERIC_ERROR("qsTrId() requires at least one argument");
+ if (!callData->args[0].isString())
+ THROW_TYPE_ERROR_WITH_MESSAGE("qsTrId(): first argument (id) must be a string");
+ if (callData->argc > 1 && !callData->args[1].isNumber())
+ THROW_TYPE_ERROR_WITH_MESSAGE("qsTrId(): second argument (n) must be a number");
int n = -1;
- if (ctx->argc() > 1)
- n = ctx->args()[1].toInt32();
+ if (callData->argc > 1)
+ n = callData->args[1].toInt32();
- return ctx->d()->engine->newString(qtTrId(ctx->args()[0].toQStringNoThrow().toUtf8().constData(), n))->asReturnedValue();
+ scope.result = scope.engine->newString(qtTrId(callData->args[0].toQStringNoThrow().toUtf8().constData(), n));
}
/*!
@@ -1990,41 +2007,41 @@ ReturnedValue GlobalExtensions::method_qsTrId(CallContext *ctx)
\sa qsTrId(), {Internationalization and Localization with Qt Quick}
*/
-ReturnedValue GlobalExtensions::method_qsTrIdNoOp(CallContext *ctx)
+void GlobalExtensions::method_qsTrIdNoOp(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() < 1)
- return QV4::Encode::undefined();
- return ctx->args()[0].asReturnedValue();
+ if (callData->argc < 1)
+ scope.result = QV4::Encode::undefined();
+ else
+ scope.result = callData->args[0];
}
#endif // translation
-QV4::ReturnedValue GlobalExtensions::method_gc(CallContext *ctx)
+void GlobalExtensions::method_gc(const BuiltinFunction *, Scope &scope, CallData *)
{
- ctx->d()->engine->memoryManager->runGC();
+ scope.engine->memoryManager->runGC();
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
-ReturnedValue GlobalExtensions::method_string_arg(CallContext *ctx)
+void GlobalExtensions::method_string_arg(const BuiltinFunction *, Scope &scope, CallData *callData)
{
- if (ctx->argc() != 1)
- V4THROW_ERROR("String.arg(): Invalid arguments");
+ if (callData->argc != 1)
+ THROW_GENERIC_ERROR("String.arg(): Invalid arguments");
- QString value = ctx->thisObject().toQString();
+ QString value = callData->thisObject.toQString();
- QV4::Scope scope(ctx);
- QV4::ScopedValue arg(scope, ctx->args()[0]);
+ QV4::ScopedValue arg(scope, callData->args[0]);
if (arg->isInteger())
- return ctx->d()->engine->newString(value.arg(arg->integerValue()))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(value.arg(arg->integerValue())));
else if (arg->isDouble())
- return ctx->d()->engine->newString(value.arg(arg->doubleValue()))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(value.arg(arg->doubleValue())));
else if (arg->isBoolean())
- return ctx->d()->engine->newString(value.arg(arg->booleanValue()))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(value.arg(arg->booleanValue())));
- return ctx->d()->engine->newString(value.arg(arg->toQString()))->asReturnedValue();
+ RETURN_RESULT(scope.engine->newString(value.arg(arg->toQString())));
}
/*!
@@ -2047,10 +2064,10 @@ be passed on to the function invoked. Note that if redundant calls
are eliminated, then only the last set of arguments will be passed to the
function.
*/
-ReturnedValue QtObject::method_callLater(CallContext *ctx)
+void QtObject::method_callLater(const BuiltinFunction *b, Scope &scope, CallData *callData)
{
- QV8Engine *v8engine = ctx->engine()->v8Engine;
- return v8engine->delayedCallQueue()->addUniquelyAndExecuteLater(ctx);
+ QV8Engine *v8engine = scope.engine->v8Engine;
+ v8engine->delayedCallQueue()->addUniquelyAndExecuteLater(b, scope, callData);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
index fe43532647..21613b7c10 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -93,45 +93,45 @@ struct QtObject : Object
static ReturnedValue get(const Managed *m, String *name, bool *hasProperty);
static void advanceIterator(Managed *m, ObjectIterator *it, Value *name, uint *index, Property *p, PropertyAttributes *attributes);
- static ReturnedValue method_isQtObject(CallContext *ctx);
- static ReturnedValue method_rgba(CallContext *ctx);
- static ReturnedValue method_hsla(CallContext *ctx);
- static ReturnedValue method_hsva(CallContext *ctx);
- static ReturnedValue method_colorEqual(CallContext *ctx);
- static ReturnedValue method_font(CallContext *ctx);
- static ReturnedValue method_rect(CallContext *ctx);
- static ReturnedValue method_point(CallContext *ctx);
- static ReturnedValue method_size(CallContext *ctx);
- static ReturnedValue method_vector2d(CallContext *ctx);
- static ReturnedValue method_vector3d(CallContext *ctx);
- static ReturnedValue method_vector4d(CallContext *ctx);
- static ReturnedValue method_quaternion(CallContext *ctx);
- static ReturnedValue method_matrix4x4(CallContext *ctx);
- static ReturnedValue method_lighter(CallContext *ctx);
- static ReturnedValue method_darker(CallContext *ctx);
- static ReturnedValue method_tint(CallContext *ctx);
- static ReturnedValue method_formatDate(CallContext *ctx);
- static ReturnedValue method_formatTime(CallContext *ctx);
- static ReturnedValue method_formatDateTime(CallContext *ctx);
- static ReturnedValue method_openUrlExternally(CallContext *ctx);
- static ReturnedValue method_fontFamilies(CallContext *ctx);
- static ReturnedValue method_md5(CallContext *ctx);
- static ReturnedValue method_btoa(CallContext *ctx);
- static ReturnedValue method_atob(CallContext *ctx);
- static ReturnedValue method_quit(CallContext *ctx);
- static ReturnedValue method_exit(CallContext *ctx);
- static ReturnedValue method_resolvedUrl(CallContext *ctx);
- static ReturnedValue method_createQmlObject(CallContext *ctx);
- static ReturnedValue method_createComponent(CallContext *ctx);
- static ReturnedValue method_locale(CallContext *ctx);
- static ReturnedValue method_binding(CallContext *ctx);
-
- static ReturnedValue method_get_platform(CallContext *ctx);
- static ReturnedValue method_get_application(CallContext *ctx);
- static ReturnedValue method_get_inputMethod(CallContext *ctx);
- static ReturnedValue method_get_styleHints(CallContext *ctx);
-
- static ReturnedValue method_callLater(CallContext *ctx);
+ static void method_isQtObject(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_rgba(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_hsla(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_hsva(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_colorEqual(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_font(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_rect(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_point(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_size(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_vector2d(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_vector3d(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_vector4d(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_quaternion(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_matrix4x4(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_lighter(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_darker(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_tint(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_formatDate(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_formatTime(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_formatDateTime(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_openUrlExternally(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_fontFamilies(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_md5(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_btoa(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_atob(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_quit(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_exit(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_resolvedUrl(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_createQmlObject(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_createComponent(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_locale(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_binding(const BuiltinFunction *, Scope &scope, CallData *callData);
+
+ static void method_get_platform(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_application(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_inputMethod(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_get_styleHints(const BuiltinFunction *, Scope &scope, CallData *callData);
+
+ static void method_callLater(const BuiltinFunction *, Scope &scope, CallData *callData);
private:
void addAll();
@@ -142,18 +142,18 @@ struct ConsoleObject : Object
{
V4_OBJECT2(ConsoleObject, Object)
- static ReturnedValue method_error(CallContext *ctx);
- static ReturnedValue method_log(CallContext *ctx);
- static ReturnedValue method_info(CallContext *ctx);
- static ReturnedValue method_profile(CallContext *ctx);
- static ReturnedValue method_profileEnd(CallContext *ctx);
- static ReturnedValue method_time(CallContext *ctx);
- static ReturnedValue method_timeEnd(CallContext *ctx);
- static ReturnedValue method_count(CallContext *ctx);
- static ReturnedValue method_trace(CallContext *ctx);
- static ReturnedValue method_warn(CallContext *ctx);
- static ReturnedValue method_assert(CallContext *ctx);
- static ReturnedValue method_exception(CallContext *ctx);
+ static void method_error(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_log(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_info(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_profile(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_profileEnd(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_time(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_timeEnd(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_count(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_trace(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_warn(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_assert(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_exception(const BuiltinFunction *, Scope &scope, CallData *callData);
};
@@ -161,17 +161,17 @@ struct Q_QML_PRIVATE_EXPORT GlobalExtensions {
static void init(Object *globalObject, QJSEngine::Extensions extensions);
#if QT_CONFIG(translation)
- static ReturnedValue method_qsTranslate(CallContext *ctx);
- static ReturnedValue method_qsTranslateNoOp(CallContext *ctx);
- static ReturnedValue method_qsTr(CallContext *ctx);
- static ReturnedValue method_qsTrNoOp(CallContext *ctx);
- static ReturnedValue method_qsTrId(CallContext *ctx);
- static ReturnedValue method_qsTrIdNoOp(CallContext *ctx);
+ static void method_qsTranslate(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_qsTranslateNoOp(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_qsTr(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_qsTrNoOp(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_qsTrId(const BuiltinFunction *, Scope &scope, CallData *callData);
+ static void method_qsTrIdNoOp(const BuiltinFunction *, Scope &scope, CallData *callData);
#endif
- static ReturnedValue method_gc(CallContext *ctx);
+ static void method_gc(const BuiltinFunction *, Scope &scope, CallData *callData);
// on String:prototype
- static ReturnedValue method_string_arg(CallContext *ctx);
+ static void method_string_arg(const BuiltinFunction *, Scope &scope, CallData *callData);
};
diff --git a/src/qml/qml/v8/qv4domerrors_p.h b/src/qml/qml/v8/qv4domerrors_p.h
index faa9dd8bc7..a9bdbe01ae 100644
--- a/src/qml/qml/v8/qv4domerrors_p.h
+++ b/src/qml/qml/v8/qv4domerrors_p.h
@@ -74,11 +74,12 @@ QT_BEGIN_NAMESPACE
#define DOMEXCEPTION_VALIDATION_ERR 16
#define DOMEXCEPTION_TYPE_MISMATCH_ERR 17
-#define V4THROW_DOM(error, string) { \
+#define THROW_DOM(error, string) { \
QV4::ScopedValue v(scope, scope.engine->newString(QStringLiteral(string))); \
QV4::ScopedObject ex(scope, scope.engine->newErrorObject(v)); \
ex->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("code"))), QV4::ScopedValue(scope, QV4::Primitive::fromInt32(error))); \
- return ctx->engine()->throwError(ex); \
+ scope.result = scope.engine->throwError(ex); \
+ return; \
}
namespace QV4 {
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index c0d75cae33..a5878dcffd 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -1795,24 +1795,26 @@ int QQmlDelegateModelItemMetaType::parseGroups(const QV4::Value &groups) const
return groupFlags;
}
-QV4::ReturnedValue QQmlDelegateModelItem::get_model(QV4::CallContext *ctx)
+void QQmlDelegateModelItem::get_model(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->thisObject().as<QQmlDelegateModelItemObject>());
- if (!o)
- return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject.as<QQmlDelegateModelItemObject>());
+ if (!o) {
+ scope.result = scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return;
+ }
if (!o->d()->item->metaType->model)
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
- return o->d()->item->get();
+ scope.result = o->d()->item->get();
}
-QV4::ReturnedValue QQmlDelegateModelItem::get_groups(QV4::CallContext *ctx)
+void QQmlDelegateModelItem::get_groups(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->thisObject().as<QQmlDelegateModelItemObject>());
- if (!o)
- return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject.as<QQmlDelegateModelItemObject>());
+ if (!o) {
+ scope.result = scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return;
+ }
QStringList groups;
for (int i = 1; i < o->d()->item->metaType->groupCount; ++i) {
@@ -1820,27 +1822,29 @@ QV4::ReturnedValue QQmlDelegateModelItem::get_groups(QV4::CallContext *ctx)
groups.append(o->d()->item->metaType->groupNames.at(i - 1));
}
- return scope.engine->fromVariant(groups);
+ scope.result = scope.engine->fromVariant(groups);
}
-QV4::ReturnedValue QQmlDelegateModelItem::set_groups(QV4::CallContext *ctx)
+void QQmlDelegateModelItem::set_groups(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelItemObject> o(scope, ctx->thisObject().as<QQmlDelegateModelItemObject>());
- if (!o)
- return ctx->engine()->throwTypeError(QStringLiteral("Not a valid VisualData object"));
- if (!ctx->argc())
- return ctx->engine()->throwTypeError();
+ QV4::Scoped<QQmlDelegateModelItemObject> o(scope, callData->thisObject.as<QQmlDelegateModelItemObject>());
+ if (!o) {
+ scope.result = scope.engine->throwTypeError(QStringLiteral("Not a valid VisualData object"));
+ return;
+ }
+
+ if (!callData->argc)
+ THROW_TYPE_ERROR();
if (!o->d()->item->metaType->model)
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
QQmlDelegateModelPrivate *model = QQmlDelegateModelPrivate::get(o->d()->item->metaType->model);
- const int groupFlags = model->m_cacheMetaType->parseGroups(ctx->args()[0]);
+ const int groupFlags = model->m_cacheMetaType->parseGroups(callData->args[0]);
const int cacheIndex = model->m_cache.indexOf(o->d()->item);
Compositor::iterator it = model->m_compositor.find(Compositor::Cache, cacheIndex);
model->setGroups(it, 1, Compositor::Cache, groupFlags);
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
QV4::ReturnedValue QQmlDelegateModelItem::get_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &)
@@ -3234,28 +3238,25 @@ struct QQmlDelegateModelGroupChange : QV4::Object
return e->memoryManager->allocObject<QQmlDelegateModelGroupChange>();
}
- static QV4::ReturnedValue method_get_index(QV4::CallContext *ctx) {
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->thisObject().as<QQmlDelegateModelGroupChange>());
+ static void method_get_index(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) {
+ QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, callData->thisObject.as<QQmlDelegateModelGroupChange>());
if (!that)
- return ctx->engine()->throwTypeError();
- return QV4::Encode(that->d()->change.index);
+ THROW_TYPE_ERROR();
+ scope.result = QV4::Encode(that->d()->change.index);
}
- static QV4::ReturnedValue method_get_count(QV4::CallContext *ctx) {
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->thisObject().as<QQmlDelegateModelGroupChange>());
+ static void method_get_count(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) {
+ QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, callData->thisObject.as<QQmlDelegateModelGroupChange>());
if (!that)
- return ctx->engine()->throwTypeError();
- return QV4::Encode(that->d()->change.count);
+ THROW_TYPE_ERROR();
+ scope.result = QV4::Encode(that->d()->change.count);
}
- static QV4::ReturnedValue method_get_moveId(QV4::CallContext *ctx) {
- QV4::Scope scope(ctx);
- QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, ctx->thisObject().as<QQmlDelegateModelGroupChange>());
+ static void method_get_moveId(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData) {
+ QV4::Scoped<QQmlDelegateModelGroupChange> that(scope, callData->thisObject.as<QQmlDelegateModelGroupChange>());
if (!that)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
if (that->d()->change.moveId < 0)
- return QV4::Encode::undefined();
- return QV4::Encode(that->d()->change.moveId);
+ RETURN_UNDEFINED();
+ scope.result = QV4::Encode(that->d()->change.moveId);
}
};
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index 4c2841b8ba..cb4a1f79ba 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -131,9 +131,9 @@ public:
virtual void setValue(const QString &role, const QVariant &value) { Q_UNUSED(role); Q_UNUSED(value); }
virtual bool resolveIndex(const QQmlAdaptorModel &, int) { return false; }
- static QV4::ReturnedValue get_model(QV4::CallContext *ctx);
- static QV4::ReturnedValue get_groups(QV4::CallContext *ctx);
- static QV4::ReturnedValue set_groups(QV4::CallContext *ctx);
+ static void get_model(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void get_groups(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void set_groups(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
static QV4::ReturnedValue get_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &);
static QV4::ReturnedValue set_member(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg);
static QV4::ReturnedValue get_index(QQmlDelegateModelItem *thisItem, uint flag, const QV4::Value &arg);
diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp
index 5f716da17a..f35e17c34d 100644
--- a/src/qml/types/qquickworkerscript.cpp
+++ b/src/qml/types/qquickworkerscript.cpp
@@ -185,7 +185,7 @@ public:
int m_nextId;
- static QV4::ReturnedValue method_sendMessage(QV4::CallContext *ctx);
+ static void method_sendMessage(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
signals:
void stopThread();
@@ -292,14 +292,13 @@ QQuickWorkerScriptEnginePrivate::QQuickWorkerScriptEnginePrivate(QQmlEngine *eng
{
}
-QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::method_sendMessage(QV4::CallContext *ctx)
+void QQuickWorkerScriptEnginePrivate::method_sendMessage(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- WorkerEngine *engine = (WorkerEngine*)ctx->engine()->v8Engine;
+ WorkerEngine *engine = (WorkerEngine*)scope.engine->v8Engine;
- int id = ctx->argc() > 1 ? ctx->args()[1].toInt32() : 0;
+ int id = callData->argc > 1 ? callData->args[1].toInt32() : 0;
- QV4::Scope scope(ctx);
- QV4::ScopedValue v(scope, ctx->argument(2));
+ QV4::ScopedValue v(scope, callData->argument(2));
QByteArray data = QV4::Serialize::serialize(v, scope.engine);
QMutexLocker locker(&engine->p->m_lock);
@@ -307,7 +306,7 @@ QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::method_sendMessage(QV4::Call
if (script && script->owner)
QCoreApplication::postEvent(script->owner, new WorkerDataEvent(0, data));
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::getWorker(WorkerScript *script)
diff --git a/src/qmldevtools/qmldevtools.pro b/src/qmldevtools/qmldevtools.pro
index acd5c9729b..ec5d73044f 100644
--- a/src/qmldevtools/qmldevtools.pro
+++ b/src/qmldevtools/qmldevtools.pro
@@ -18,5 +18,6 @@ include(../qml/parser/parser.pri)
include(../qml/jsruntime/jsruntime.pri)
include(../qml/compiler/compiler.pri)
include(../qml/memory/memory.pri)
+include(../qml/jit/jit.pri)
load(qt_module)
diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp
index bcaedd67b4..b0c1d50907 100644
--- a/src/quick/items/context2d/qquickcontext2d.cpp
+++ b/src/quick/items/context2d/qquickcontext2d.cpp
@@ -129,10 +129,10 @@ Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok);
#define DEGREES(t) ((t) * 180.0 / M_PI)
#define CHECK_CONTEXT(r) if (!r || !r->d()->context || !r->d()->context->bufferValid()) \
- V4THROW_ERROR("Not a Context2D object");
+ THROW_GENERIC_ERROR("Not a Context2D object");
#define CHECK_CONTEXT_SETTER(r) if (!r || !r->d()->context || !r->d()->context->bufferValid()) \
- V4THROW_ERROR("Not a Context2D object");
+ THROW_GENERIC_ERROR("Not a Context2D object");
#define qClamp(val, min, max) qMin(qMax(val, min), max)
#define CHECK_RGBA(c) (c == '-' || c == '.' || (c >=0 && c <= 9))
QColor qt_color_from_string(const QV4::Value &name)
@@ -537,45 +537,45 @@ struct QQuickJSContext2D : public QV4::Object
{
V4_OBJECT2(QQuickJSContext2D, QV4::Object)
- static QV4::ReturnedValue method_get_globalAlpha(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_globalAlpha(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_globalCompositeOperation(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_globalCompositeOperation(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_fillStyle(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_fillStyle(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_fillRule(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_fillRule(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_strokeStyle(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_strokeStyle(QV4::CallContext *ctx);
-
- static QV4::ReturnedValue method_get_lineCap(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_lineCap(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_lineJoin(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_lineJoin(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_lineWidth(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_lineWidth(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_miterLimit(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_miterLimit(QV4::CallContext *ctx);
-
- static QV4::ReturnedValue method_get_shadowBlur(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_shadowBlur(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_shadowColor(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_shadowColor(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_shadowOffsetX(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_shadowOffsetX(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_shadowOffsetY(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_shadowOffsetY(QV4::CallContext *ctx);
+ static void method_get_globalAlpha(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_globalAlpha(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_globalCompositeOperation(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_globalCompositeOperation(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_fillStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_fillStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_fillRule(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_fillRule(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_strokeStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_strokeStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+
+ static void method_get_lineCap(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_lineCap(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_lineJoin(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_lineJoin(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_lineWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_lineWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+
+ static void method_get_shadowBlur(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_shadowBlur(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_shadowColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_shadowColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_shadowOffsetX(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_shadowOffsetX(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_shadowOffsetY(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_shadowOffsetY(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
// should these two be on the proto?
- static QV4::ReturnedValue method_get_path(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_path(QV4::CallContext *ctx);
-
- static QV4::ReturnedValue method_get_font(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_font(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_textAlign(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_textAlign(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_textBaseline(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_set_textBaseline(QV4::CallContext *ctx);
+ static void method_get_path(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_path(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+
+ static void method_get_font(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_font(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_textAlign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_textAlign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_textBaseline(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_set_textBaseline(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
DEFINE_OBJECT_VTABLE(QQuickJSContext2D);
@@ -638,50 +638,50 @@ public:
return o->d();
}
- static QV4::ReturnedValue method_get_canvas(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_restore(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_reset(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_save(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_rotate(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_scale(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_translate(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_setTransform(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_transform(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_resetTransform(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_shear(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_createLinearGradient(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_createRadialGradient(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_createConicalGradient(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_createPattern(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_clearRect(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_fillRect(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_strokeRect(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_arc(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_arcTo(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_beginPath(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_bezierCurveTo(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_clip(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_closePath(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_fill(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_lineTo(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_moveTo(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_quadraticCurveTo(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_rect(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_roundedRect(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_ellipse(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_text(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_stroke(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_isPointInPath(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_drawFocusRing(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_setCaretSelectionRect(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_caretBlinkRate(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_fillText(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_strokeText(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_measureText(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_drawImage(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_createImageData(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_getImageData(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_putImageData(QV4::CallContext *ctx);
+ static void method_get_canvas(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_restore(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_reset(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_save(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_rotate(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_scale(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_translate(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_setTransform(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_transform(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_resetTransform(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_shear(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_createLinearGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_createRadialGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_createConicalGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_createPattern(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_clearRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_fillRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_strokeRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_arc(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_arcTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_beginPath(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_bezierCurveTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_clip(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_closePath(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_fill(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_lineTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_moveTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_quadraticCurveTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_rect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_roundedRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_ellipse(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_text(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_stroke(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_isPointInPath(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_drawFocusRing(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_setCaretSelectionRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_caretBlinkRate(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_fillText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_strokeText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_measureText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_drawImage(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_createImageData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_getImageData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_putImageData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
@@ -693,7 +693,7 @@ struct QQuickContext2DStyle : public QV4::Object
V4_OBJECT2(QQuickContext2DStyle, QV4::Object)
V4_NEEDS_DESTROY
- static QV4::ReturnedValue gradient_proto_addColorStop(QV4::CallContext *ctx);
+ static void gradient_proto_addColorStop(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
@@ -903,7 +903,7 @@ struct QQuickJSContext2DPixelData : public QV4::Object
static QV4::ReturnedValue getIndexed(const QV4::Managed *m, uint index, bool *hasProperty);
static void putIndexed(QV4::Managed *m, uint index, const QV4::Value &value);
- static QV4::ReturnedValue proto_get_length(QV4::CallContext *ctx);
+ static void proto_get_length(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
};
void QV4::Heap::QQuickJSContext2DPixelData::init()
@@ -921,9 +921,9 @@ struct QQuickJSContext2DImageData : public QV4::Object
{
V4_OBJECT2(QQuickJSContext2DImageData, QV4::Object)
- static QV4::ReturnedValue method_get_width(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_height(QV4::CallContext *ctx);
- static QV4::ReturnedValue method_get_data(QV4::CallContext *ctx);
+ static void method_get_width(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_height(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
+ static void method_get_data(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData);
static void markObjects(QV4::Heap::Base *that, QV4::ExecutionEngine *engine) {
static_cast<QQuickJSContext2DImageData::Data *>(that)->pixelData.mark(engine);
@@ -975,13 +975,12 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE
This property is read only.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_get_canvas(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_get_canvas(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- return QV4::QObjectWrapper::wrap(scope.engine, r->d()->context->canvas());
+ scope.result = QV4::QObjectWrapper::wrap(scope.engine, r->d()->context->canvas());
}
/*!
@@ -990,29 +989,27 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_get_canvas(QV4::CallContex
\sa save()
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_restore(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_restore(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
r->d()->context->popState();
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject.asReturnedValue();
}
/*!
\qmlmethod object QtQuick::Context2D::reset()
Resets the context state and properties to the default values.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_reset(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_reset(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
r->d()->context->reset();
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject.asReturnedValue();
}
/*!
@@ -1045,15 +1042,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_reset(QV4::CallContext *ct
The current path is NOT part of the drawing state. The path can be reset by
invoking the beginPath() method.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_save(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_save(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
r->d()->context->pushState();
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
}
// transformations
@@ -1074,15 +1070,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_save(QV4::CallContext *ctx
where the \a angle of rotation is in radians.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_rotate(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_rotate(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->argc() >= 1)
- r->d()->context->rotate(ctx->args()[0].toNumber());
- return ctx->thisObject().asReturnedValue();
+ if (callData->argc >= 1)
+ r->d()->context->rotate(callData->args[0].toNumber());
+ scope.result = callData->thisObject;
}
/*!
@@ -1102,16 +1097,16 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_rotate(QV4::CallContext *c
\image qml-item-canvas-scale.png
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_scale(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_scale(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->argc() >= 2)
- r->d()->context->scale(ctx->args()[0].toNumber(), ctx->args()[1].toNumber());
- return ctx->thisObject().asReturnedValue();
+ if (callData->argc >= 2)
+ r->d()->context->scale(callData->args[0].toNumber(), callData->args[1].toNumber());
+ scope.result = callData->thisObject;
+
}
/*!
@@ -1148,22 +1143,22 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_scale(QV4::CallContext *ct
\sa transform()
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_setTransform(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_setTransform(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->argc() >= 6)
- r->d()->context->setTransform( ctx->args()[0].toNumber()
- , ctx->args()[1].toNumber()
- , ctx->args()[2].toNumber()
- , ctx->args()[3].toNumber()
- , ctx->args()[4].toNumber()
- , ctx->args()[5].toNumber());
+ if (callData->argc >= 6)
+ r->d()->context->setTransform( callData->args[0].toNumber()
+ , callData->args[1].toNumber()
+ , callData->args[2].toNumber()
+ , callData->args[3].toNumber()
+ , callData->args[4].toNumber()
+ , callData->args[5].toNumber());
+
+ scope.result = callData->thisObject;
- return ctx->thisObject().asReturnedValue();
}
/*!
@@ -1177,21 +1172,21 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_setTransform(QV4::CallCont
\sa setTransform()
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_transform(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_transform(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->argc() >= 6)
- r->d()->context->transform( ctx->args()[0].toNumber()
- , ctx->args()[1].toNumber()
- , ctx->args()[2].toNumber()
- , ctx->args()[3].toNumber()
- , ctx->args()[4].toNumber()
- , ctx->args()[5].toNumber());
+ if (callData->argc >= 6)
+ r->d()->context->transform( callData->args[0].toNumber()
+ , callData->args[1].toNumber()
+ , callData->args[2].toNumber()
+ , callData->args[3].toNumber()
+ , callData->args[4].toNumber()
+ , callData->args[5].toNumber());
+
+ scope.result = callData->thisObject;
- return ctx->thisObject().asReturnedValue();
}
/*!
@@ -1203,15 +1198,15 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_transform(QV4::CallContext
Translating the origin enables you to draw patterns of different objects on the canvas
without having to measure the coordinates manually for each shape.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_translate(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_translate(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->argc() >= 2)
- r->d()->context->translate(ctx->args()[0].toNumber(), ctx->args()[1].toNumber());
- return ctx->thisObject().asReturnedValue();
+ if (callData->argc >= 2)
+ r->d()->context->translate(callData->args[0].toNumber(), callData->args[1].toNumber());
+ scope.result = callData->thisObject;
+
}
@@ -1223,15 +1218,15 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_translate(QV4::CallContext
\sa transform(), setTransform(), reset()
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_resetTransform(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_resetTransform(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
r->d()->context->setTransform(1, 0, 0, 1, 0, 0);
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
+
}
@@ -1241,16 +1236,16 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_resetTransform(QV4::CallCo
Shears the transformation matrix by \a sh in the horizontal direction and
\a sv in the vertical direction.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_shear(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_shear(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->argc() >= 2)
- r->d()->context->shear(ctx->args()[0].toNumber(), ctx->args()[1].toNumber());
+ if (callData->argc >= 2)
+ r->d()->context->shear(callData->args[0].toNumber(), callData->args[1].toNumber());
+
+ scope.result = callData->thisObject;
- return ctx->thisObject().asReturnedValue();
}
// compositing
@@ -1261,31 +1256,30 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_shear(QV4::CallContext *ct
The value must be in the range from \c 0.0 (fully transparent) to \c 1.0 (fully opaque).
The default value is \c 1.0.
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_globalAlpha(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_globalAlpha(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- return QV4::Encode(r->d()->context->state.globalAlpha);
+ scope.result = QV4::Encode(r->d()->context->state.globalAlpha);
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_globalAlpha(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_globalAlpha(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
- double globalAlpha = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ double globalAlpha = callData->argc ? callData->args[0].toNumber() : qt_qnan();
+
+ scope.result = QV4::Encode::undefined();
if (!qt_is_finite(globalAlpha))
- return QV4::Encode::undefined();
+ return;
if (globalAlpha >= 0.0 && globalAlpha <= 1.0 && r->d()->context->state.globalAlpha != globalAlpha) {
r->d()->context->state.globalAlpha = globalAlpha;
r->d()->context->buffer()->setGlobalAlpha(r->d()->context->state.globalAlpha);
}
- return QV4::Encode::undefined();
}
/*!
@@ -1314,34 +1308,33 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_globalAlpha(QV4::CallContext *c
extension composition modes are provided as "vendorName-operationName" syntax, for example: QPainter::CompositionMode_Exclusion is provided as
"qt-exclusion".
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_globalCompositeOperation(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_globalCompositeOperation(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- return QV4::Encode(scope.engine->newString(qt_composite_mode_to_string(r->d()->context->state.globalCompositeOperation)));
+ scope.result = scope.engine->newString(qt_composite_mode_to_string(r->d()->context->state.globalCompositeOperation));
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_globalCompositeOperation(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_globalCompositeOperation(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
- if (!ctx->argc())
- return ctx->engine()->throwTypeError();
+ if (!callData->argc)
+ THROW_TYPE_ERROR();
- QString mode = ctx->args()[0].toQString();
+ scope.result = QV4::Encode::undefined();
+
+ QString mode = callData->args[0].toQString();
QPainter::CompositionMode cm = qt_composite_mode_from_string(mode);
if (cm == QPainter::CompositionMode_SourceOver && mode != QLatin1String("source-over"))
- return QV4::Encode::undefined();
+ return;
if (cm != r->d()->context->state.globalCompositeOperation) {
r->d()->context->state.globalCompositeOperation = cm;
r->d()->context->buffer()->setGlobalCompositeOperation(cm);
}
- return QV4::Encode::undefined();
}
// colors and styles
@@ -1367,34 +1360,32 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_globalCompositeOperation(QV4::C
\sa createPattern()
\sa strokeStyle
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_fillStyle(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_fillStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
QColor color = r->d()->context->state.fillStyle.color();
if (color.isValid()) {
if (color.alpha() == 255)
- return QV4::Encode(scope.engine->newString(color.name()));
+ RETURN_RESULT(scope.engine->newString(color.name()));
QString alphaString = QString::number(color.alphaF(), 'f');
while (alphaString.endsWith(QLatin1Char('0')))
alphaString.chop(1);
if (alphaString.endsWith(QLatin1Char('.')))
alphaString += QLatin1Char('0');
QString str = QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString);
- return QV4::Encode(scope.engine->newString(str));
+ RETURN_RESULT(scope.engine->newString(str));
}
- return r->d()->context->m_fillStyle.value();
+ scope.result = r->d()->context->m_fillStyle.value();
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_fillStyle(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_fillStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
- QV4::ScopedValue value(scope, ctx->argument(0));
+ QV4::ScopedValue value(scope, callData->argument(0));
if (value->as<Object>()) {
QColor color = scope.engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
@@ -1420,7 +1411,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillStyle(QV4::CallContext *ctx
r->d()->context->m_fillStyle.set(scope.engine, value);
}
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
/*!
\qmlproperty enumeration QtQuick::Context2D::fillRule
@@ -1434,22 +1425,20 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillStyle(QV4::CallContext *ctx
\sa fillStyle
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_fillRule(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_fillRule(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- return scope.engine->fromVariant(r->d()->context->state.fillRule);
+ scope.result = scope.engine->fromVariant(r->d()->context->state.fillRule);
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_fillRule(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_fillRule(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
- QV4::ScopedValue value(scope, ctx->argument(0));
+ QV4::ScopedValue value(scope, callData->argument(0));
if ((value->isString() && value->toQString() == QLatin1String("WindingFill"))
|| (value->isInt32() && value->integerValue() == Qt::WindingFill)) {
@@ -1461,7 +1450,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillRule(QV4::CallContext *ctx)
//error
}
r->d()->context->m_path.setFillRule(r->d()->context->state.fillRule);
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
/*!
\qmlproperty variant QtQuick::Context2D::strokeStyle
@@ -1476,34 +1465,32 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillRule(QV4::CallContext *ctx)
\sa createPattern()
\sa fillStyle
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_strokeStyle(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_strokeStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
QColor color = r->d()->context->state.strokeStyle.color();
if (color.isValid()) {
if (color.alpha() == 255)
- return QV4::Encode(scope.engine->newString(color.name()));
+ RETURN_RESULT(scope.engine->newString(color.name()));
QString alphaString = QString::number(color.alphaF(), 'f');
while (alphaString.endsWith(QLatin1Char('0')))
alphaString.chop(1);
if (alphaString.endsWith(QLatin1Char('.')))
alphaString += QLatin1Char('0');
QString str = QString::fromLatin1("rgba(%1, %2, %3, %4)").arg(color.red()).arg(color.green()).arg(color.blue()).arg(alphaString);
- return QV4::Encode(scope.engine->newString(str));
+ RETURN_RESULT(scope.engine->newString(str));
}
- return r->d()->context->m_strokeStyle.value();
+ scope.result = r->d()->context->m_strokeStyle.value();
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_strokeStyle(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_strokeStyle(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT_SETTER(r)
- QV4::ScopedValue value(scope, ctx->argument(0));
+ QV4::ScopedValue value(scope, callData->argument(0));
if (value->as<Object>()) {
QColor color = scope.engine->toVariant(value, qMetaTypeId<QColor>()).value<QColor>();
@@ -1530,7 +1517,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_strokeStyle(QV4::CallContext *c
r->d()->context->m_strokeStyle.set(scope.engine, value);
}
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
/*!
@@ -1550,23 +1537,22 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_strokeStyle(QV4::CallContext *c
\sa strokeStyle
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_createLinearGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->argc() >= 4) {
- qreal x0 = ctx->args()[0].toNumber();
- qreal y0 = ctx->args()[1].toNumber();
- qreal x1 = ctx->args()[2].toNumber();
- qreal y1 = ctx->args()[3].toNumber();
+ if (callData->argc >= 4) {
+ qreal x0 = callData->args[0].toNumber();
+ qreal y0 = callData->args[1].toNumber();
+ qreal x1 = callData->args[2].toNumber();
+ qreal y1 = callData->args[3].toNumber();
if (!qt_is_finite(x0)
|| !qt_is_finite(y0)
|| !qt_is_finite(x1)
|| !qt_is_finite(y1)) {
- V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createLinearGradient(): Incorrect arguments")
+ THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createLinearGradient(): Incorrect arguments")
}
QQuickContext2DEngineData *ed = engineData(scope.engine);
@@ -1574,10 +1560,11 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(QV4::
QV4::ScopedObject p(scope, ed->gradientProto.value());
gradient->setPrototype(p);
*gradient->d()->brush = QLinearGradient(x0, y0, x1, y1);
- return gradient.asReturnedValue();
+ RETURN_RESULT(gradient);
}
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
+
}
/*!
@@ -1593,19 +1580,18 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(QV4::
\sa strokeStyle
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_createRadialGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->argc() >= 6) {
- qreal x0 = ctx->args()[0].toNumber();
- qreal y0 = ctx->args()[1].toNumber();
- qreal r0 = ctx->args()[2].toNumber();
- qreal x1 = ctx->args()[3].toNumber();
- qreal y1 = ctx->args()[4].toNumber();
- qreal r1 = ctx->args()[5].toNumber();
+ if (callData->argc >= 6) {
+ qreal x0 = callData->args[0].toNumber();
+ qreal y0 = callData->args[1].toNumber();
+ qreal r0 = callData->args[2].toNumber();
+ qreal x1 = callData->args[3].toNumber();
+ qreal y1 = callData->args[4].toNumber();
+ qreal r1 = callData->args[5].toNumber();
if (!qt_is_finite(x0)
|| !qt_is_finite(y0)
@@ -1613,11 +1599,11 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(QV4::
|| !qt_is_finite(r0)
|| !qt_is_finite(r1)
|| !qt_is_finite(y1)) {
- V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createRadialGradient(): Incorrect arguments")
+ THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createRadialGradient(): Incorrect arguments")
}
if (r0 < 0 || r1 < 0)
- V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createRadialGradient(): Incorrect arguments")
+ THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createRadialGradient(): Incorrect arguments")
QQuickContext2DEngineData *ed = engineData(scope.engine);
@@ -1625,10 +1611,11 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(QV4::
QV4::ScopedObject p(scope, ed->gradientProto.value());
gradient->setPrototype(p);
*gradient->d()->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0));
- return gradient.asReturnedValue();
+ RETURN_RESULT(gradient);
}
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
+
}
/*!
@@ -1644,22 +1631,21 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(QV4::
\sa strokeStyle
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_createConicalGradient(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->argc() >= 3) {
- qreal x = ctx->args()[0].toNumber();
- qreal y = ctx->args()[1].toNumber();
- qreal angle = DEGREES(ctx->args()[2].toNumber());
+ if (callData->argc >= 3) {
+ qreal x = callData->args[0].toNumber();
+ qreal y = callData->args[1].toNumber();
+ qreal angle = DEGREES(callData->args[2].toNumber());
if (!qt_is_finite(x) || !qt_is_finite(y)) {
- V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments");
+ THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createConicalGradient(): Incorrect arguments");
}
if (!qt_is_finite(angle)) {
- V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createConicalGradient(): Incorrect arguments");
+ THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createConicalGradient(): Incorrect arguments");
}
QQuickContext2DEngineData *ed = engineData(scope.engine);
@@ -1668,10 +1654,11 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(QV4:
QV4::ScopedObject p(scope, ed->gradientProto.value());
gradient->setPrototype(p);
*gradient->d()->brush = QConicalGradient(x, y, angle);
- return gradient.asReturnedValue();
+ RETURN_RESULT(gradient);
}
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
+
}
/*!
\qmlmethod variant QtQuick::Context2D::createPattern(color color, enumeration patternMode)
@@ -1716,18 +1703,17 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(QV4:
\sa strokeStyle
\sa fillStyle
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_createPattern(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 2) {
+ if (callData->argc >= 2) {
QV4::Scoped<QQuickContext2DStyle> pattern(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>());
- QColor color = scope.engine->toVariant(ctx->args()[0], qMetaTypeId<QColor>()).value<QColor>();
+ QColor color = scope.engine->toVariant(callData->args[0], qMetaTypeId<QColor>()).value<QColor>();
if (color.isValid()) {
- int patternMode = ctx->args()[1].toInt32();
+ int patternMode = callData->args[1].toInt32();
Qt::BrushStyle style = Qt::SolidPattern;
if (patternMode >= 0 && patternMode < Qt::LinearGradientPattern) {
style = static_cast<Qt::BrushStyle>(patternMode);
@@ -1736,20 +1722,20 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(QV4::CallCon
} else {
QImage patternTexture;
- if (const QV4::Object *o = ctx->args()[0].as<Object>()) {
+ if (const QV4::Object *o = callData->args[0].as<Object>()) {
QV4::ScopedString s(scope, scope.engine->newString(QStringLiteral("data")));
QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, o->get(s));
if (!!pixelData) {
patternTexture = *pixelData->d()->image;
}
} else {
- patternTexture = r->d()->context->createPixmap(QUrl(ctx->args()[0].toQStringNoThrow()))->image();
+ patternTexture = r->d()->context->createPixmap(QUrl(callData->args[0].toQStringNoThrow()))->image();
}
if (!patternTexture.isNull()) {
pattern->d()->brush->setTextureImage(patternTexture);
- QString repetition = ctx->args()[1].toQStringNoThrow();
+ QString repetition = callData->args[1].toQStringNoThrow();
if (repetition == QLatin1String("repeat") || repetition.isEmpty()) {
pattern->d()->patternRepeatX = true;
pattern->d()->patternRepeatY = true;
@@ -1769,10 +1755,10 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(QV4::CallCon
}
}
- return pattern.asReturnedValue();
+ RETURN_RESULT(pattern);
}
- return QV4::Encode::undefined();
+ scope.result = QV4::Encode::undefined();
}
// line styles
@@ -1787,31 +1773,29 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(QV4::CallCon
\endlist
Other values are ignored.
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_lineCap(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_lineCap(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
switch (r->d()->context->state.lineCap) {
case Qt::RoundCap:
- return QV4::Encode(scope.engine->newString(QStringLiteral("round")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("round")));
case Qt::SquareCap:
- return QV4::Encode(scope.engine->newString(QStringLiteral("square")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("square")));
case Qt::FlatCap:
default:
break;
}
- return QV4::Encode(scope.engine->newString(QStringLiteral("butt")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("butt")));
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_lineCap(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_lineCap(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- QString lineCap = ctx->args()[0].toQString();
+ QString lineCap = callData->args[0].toQString();
Qt::PenCapStyle cap;
if (lineCap == QLatin1String("round"))
cap = Qt::RoundCap;
@@ -1820,13 +1804,13 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineCap(QV4::CallContext *ctx)
else if (lineCap == QLatin1String("square"))
cap = Qt::SquareCap;
else
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
if (cap != r->d()->context->state.lineCap) {
r->d()->context->state.lineCap = cap;
r->d()->context->buffer()->setLineCap(cap);
}
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
/*!
@@ -1843,34 +1827,32 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineCap(QV4::CallContext *ctx)
\endlist
Other values are ignored.
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_lineJoin(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_lineJoin(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
switch (r->d()->context->state.lineJoin) {
case Qt::RoundJoin:
- return QV4::Encode(scope.engine->newString(QStringLiteral("round")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("round")));
case Qt::BevelJoin:
- return QV4::Encode(scope.engine->newString(QStringLiteral("bevel")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("bevel")));
case Qt::MiterJoin:
default:
break;
}
- return QV4::Encode(scope.engine->newString(QStringLiteral("miter")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("miter")));
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_lineJoin(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_lineJoin(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- if (!ctx->argc())
- return ctx->engine()->throwTypeError();
+ if (!callData->argc)
+ THROW_TYPE_ERROR();
- QString lineJoin = ctx->args()[0].toQString();
+ QString lineJoin = callData->args[0].toQString();
Qt::PenJoinStyle join;
if (lineJoin == QLatin1String("round"))
join = Qt::RoundJoin;
@@ -1879,41 +1861,39 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineJoin(QV4::CallContext *ctx)
else if (lineJoin == QLatin1String("miter"))
join = Qt::SvgMiterJoin;
else
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
if (join != r->d()->context->state.lineJoin) {
r->d()->context->state.lineJoin = join;
r->d()->context->buffer()->setLineJoin(join);
}
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
/*!
\qmlproperty real QtQuick::Context2D::lineWidth
Holds the current line width. Values that are not finite values greater than zero are ignored.
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_lineWidth(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_lineWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- return QV4::Encode(r->d()->context->state.lineWidth);
+ RETURN_RESULT(r->d()->context->state.lineWidth);
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_lineWidth(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_lineWidth(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal w = ctx->argc() ? ctx->args()[0].toNumber() : -1;
+ qreal w = callData->argc ? callData->args[0].toNumber() : -1;
if (w > 0 && qt_is_finite(w) && w != r->d()->context->state.lineWidth) {
r->d()->context->state.lineWidth = w;
r->d()->context->buffer()->setLineWidth(w);
}
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
/*!
@@ -1921,28 +1901,26 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_lineWidth(QV4::CallContext *ctx
Holds the current miter limit ratio.
The default miter limit value is 10.0.
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_miterLimit(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- return QV4::Encode(r->d()->context->state.miterLimit);
+ RETURN_RESULT(r->d()->context->state.miterLimit);
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_miterLimit(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_miterLimit(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal ml = ctx->argc() ? ctx->args()[0].toNumber() : -1;
+ qreal ml = callData->argc ? callData->args[0].toNumber() : -1;
if (ml > 0 && qt_is_finite(ml) && ml != r->d()->context->state.miterLimit) {
r->d()->context->state.miterLimit = ml;
r->d()->context->buffer()->setMiterLimit(ml);
}
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
// shadows
@@ -1950,58 +1928,54 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_miterLimit(QV4::CallContext *ct
\qmlproperty real QtQuick::Context2D::shadowBlur
Holds the current level of blur applied to shadows
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_shadowBlur(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_shadowBlur(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- return QV4::Encode(r->d()->context->state.shadowBlur);
+ RETURN_RESULT(r->d()->context->state.shadowBlur);
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_shadowBlur(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_shadowBlur(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal blur = ctx->argc() ? ctx->args()[0].toNumber() : -1;
+ qreal blur = callData->argc ? callData->args[0].toNumber() : -1;
if (blur > 0 && qt_is_finite(blur) && blur != r->d()->context->state.shadowBlur) {
r->d()->context->state.shadowBlur = blur;
r->d()->context->buffer()->setShadowBlur(blur);
}
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
/*!
\qmlproperty string QtQuick::Context2D::shadowColor
Holds the current shadow color.
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_shadowColor(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_shadowColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- return QV4::Encode(scope.engine->newString(r->d()->context->state.shadowColor.name()));
+ RETURN_RESULT(scope.engine->newString(r->d()->context->state.shadowColor.name()));
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_shadowColor(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_shadowColor(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT_SETTER(r)
QColor color;
- if (ctx->argc())
- color = qt_color_from_string(ctx->args()[0]);
+ if (callData->argc)
+ color = qt_color_from_string(callData->args[0]);
if (color.isValid() && color != r->d()->context->state.shadowColor) {
r->d()->context->state.shadowColor = color;
r->d()->context->buffer()->setShadowColor(color);
}
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
@@ -2011,27 +1985,25 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowColor(QV4::CallContext *c
\sa shadowOffsetY
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_shadowOffsetX(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_shadowOffsetX(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- return QV4::Encode(r->d()->context->state.shadowOffsetX);
+ RETURN_RESULT(r->d()->context->state.shadowOffsetX);
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetX(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_shadowOffsetX(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal offsetX = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ qreal offsetX = callData->argc ? callData->args[0].toNumber() : qt_qnan();
if (qt_is_finite(offsetX) && offsetX != r->d()->context->state.shadowOffsetX) {
r->d()->context->state.shadowOffsetX = offsetX;
r->d()->context->buffer()->setShadowOffsetX(offsetX);
}
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
/*!
\qmlproperty qreal QtQuick::Context2D::shadowOffsetY
@@ -2039,45 +2011,41 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetX(QV4::CallContext
\sa shadowOffsetX
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_shadowOffsetY(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_shadowOffsetY(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- return QV4::Encode(r->d()->context->state.shadowOffsetY);
+ RETURN_RESULT(r->d()->context->state.shadowOffsetY);
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_shadowOffsetY(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_shadowOffsetY(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- qreal offsetY = ctx->argc() ? ctx->args()[0].toNumber() : qt_qnan();
+ qreal offsetY = callData->argc ? callData->args[0].toNumber() : qt_qnan();
if (qt_is_finite(offsetY) && offsetY != r->d()->context->state.shadowOffsetY) {
r->d()->context->state.shadowOffsetY = offsetY;
r->d()->context->buffer()->setShadowOffsetY(offsetY);
}
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
-QV4::ReturnedValue QQuickJSContext2D::method_get_path(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_path(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- return r->d()->context->m_v4path.value();
+ scope.result = r->d()->context->m_v4path.value();
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_path(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_path(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- QV4::ScopedValue value(scope, ctx->argument(0));
+ QV4::ScopedValue value(scope, callData->argument(0));
r->d()->context->beginPath();
QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope, value);
if (!!qobjectWrapper) {
@@ -2088,7 +2056,7 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_path(QV4::CallContext *ctx)
QQuickSvgParser::parsePathDataFast(path, r->d()->context->m_path);
}
r->d()->context->m_v4path.set(scope.engine, value);
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
//rects
@@ -2096,20 +2064,20 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_path(QV4::CallContext *ctx)
\qmlmethod object QtQuick::Context2D::clearRect(real x, real y, real w, real h)
Clears all pixels on the canvas in the given rectangle to transparent black.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_clearRect(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_clearRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 4)
- r->d()->context->clearRect(ctx->args()[0].toNumber(),
- ctx->args()[1].toNumber(),
- ctx->args()[2].toNumber(),
- ctx->args()[3].toNumber());
+ if (callData->argc >= 4)
+ r->d()->context->clearRect(callData->args[0].toNumber(),
+ callData->args[1].toNumber(),
+ callData->args[2].toNumber(),
+ callData->args[3].toNumber());
+
+ scope.result = callData->thisObject;
- return ctx->thisObject().asReturnedValue();
}
/*!
\qmlmethod object QtQuick::Context2D::fillRect(real x, real y, real w, real h)
@@ -2117,15 +2085,15 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_clearRect(QV4::CallContext
\sa fillStyle
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillRect(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_fillRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 4)
- r->d()->context->fillRect(ctx->args()[0].toNumber(), ctx->args()[1].toNumber(), ctx->args()[2].toNumber(), ctx->args()[3].toNumber());
- return ctx->thisObject().asReturnedValue();
+ if (callData->argc >= 4)
+ r->d()->context->fillRect(callData->args[0].toNumber(), callData->args[1].toNumber(), callData->args[2].toNumber(), callData->args[3].toNumber());
+ scope.result = callData->thisObject;
+
}
/*!
@@ -2138,16 +2106,16 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillRect(QV4::CallContext
\sa lineJoin
\sa miterLimit
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeRect(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_strokeRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 4)
- r->d()->context->strokeRect(ctx->args()[0].toNumber(), ctx->args()[1].toNumber(), ctx->args()[2].toNumber(), ctx->args()[3].toNumber());
+ if (callData->argc >= 4)
+ r->d()->context->strokeRect(callData->args[0].toNumber(), callData->args[1].toNumber(), callData->args[2].toNumber(), callData->args[3].toNumber());
+
+ scope.result = callData->thisObject;
- return ctx->thisObject().asReturnedValue();
}
// Complex shapes (paths) API
@@ -2171,32 +2139,32 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeRect(QV4::CallContex
\sa arcTo, {http://www.w3.org/TR/2dcontext/#dom-context-2d-arc}{W3C's 2D
Context Standard for arc()}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_arc(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_arc(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 5) {
+ if (callData->argc >= 5) {
bool antiClockwise = false;
- if (ctx->argc() == 6)
- antiClockwise = ctx->args()[5].toBoolean();
+ if (callData->argc == 6)
+ antiClockwise = callData->args[5].toBoolean();
- qreal radius = ctx->args()[2].toNumber();
+ qreal radius = callData->args[2].toNumber();
if (qt_is_finite(radius) && radius < 0)
- V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
+ THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
- r->d()->context->arc(ctx->args()[0].toNumber(),
- ctx->args()[1].toNumber(),
+ r->d()->context->arc(callData->args[0].toNumber(),
+ callData->args[1].toNumber(),
radius,
- ctx->args()[3].toNumber(),
- ctx->args()[4].toNumber(),
+ callData->args[3].toNumber(),
+ callData->args[4].toNumber(),
antiClockwise);
}
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
+
}
/*!
@@ -2222,26 +2190,26 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_arc(QV4::CallContext *ctx)
\sa arc, {http://www.w3.org/TR/2dcontext/#dom-context-2d-arcto}{W3C's 2D
Context Standard for arcTo()}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_arcTo(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_arcTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 5) {
- qreal radius = ctx->args()[4].toNumber();
+ if (callData->argc >= 5) {
+ qreal radius = callData->args[4].toNumber();
if (qt_is_finite(radius) && radius < 0)
- V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
+ THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "Incorrect argument radius");
- r->d()->context->arcTo(ctx->args()[0].toNumber(),
- ctx->args()[1].toNumber(),
- ctx->args()[2].toNumber(),
- ctx->args()[3].toNumber(),
+ r->d()->context->arcTo(callData->args[0].toNumber(),
+ callData->args[1].toNumber(),
+ callData->args[2].toNumber(),
+ callData->args[3].toNumber(),
radius);
}
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
+
}
/*!
@@ -2249,15 +2217,15 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_arcTo(QV4::CallContext *ct
Resets the current path to a new path.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_beginPath(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_beginPath(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
r->d()->context->beginPath();
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
+
}
/*!
@@ -2279,28 +2247,26 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_beginPath(QV4::CallContext
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-beziercurveto}{W3C 2d context standard for bezierCurveTo}
\sa {http://www.openrise.com/lab/FlowerPower/}{The beautiful flower demo by using bezierCurveTo}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_bezierCurveTo(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_bezierCurveTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
+ scope.result = callData->thisObject;
- if (ctx->argc() >= 6) {
- qreal cp1x = ctx->args()[0].toNumber();
- qreal cp1y = ctx->args()[1].toNumber();
- qreal cp2x = ctx->args()[2].toNumber();
- qreal cp2y = ctx->args()[3].toNumber();
- qreal x = ctx->args()[4].toNumber();
- qreal y = ctx->args()[5].toNumber();
+ if (callData->argc >= 6) {
+ qreal cp1x = callData->args[0].toNumber();
+ qreal cp1y = callData->args[1].toNumber();
+ qreal cp2x = callData->args[2].toNumber();
+ qreal cp2y = callData->args[3].toNumber();
+ qreal x = callData->args[4].toNumber();
+ qreal y = callData->args[5].toNumber();
if (!qt_is_finite(cp1x) || !qt_is_finite(cp1y) || !qt_is_finite(cp2x) || !qt_is_finite(cp2y) || !qt_is_finite(x) || !qt_is_finite(y))
- return ctx->thisObject().asReturnedValue();
+ return;
r->d()->context->bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
}
-
- return ctx->thisObject().asReturnedValue();
}
/*!
@@ -2327,14 +2293,13 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_bezierCurveTo(QV4::CallCon
\sa fill()
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-clip}{W3C 2d context standard for clip}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_clip(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_clip(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
r->d()->context->clip();
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
}
/*!
@@ -2344,16 +2309,15 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_clip(QV4::CallContext *ctx
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-closepath}{W3C 2d context standard for closePath}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_closePath(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_closePath(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
r->d()->context->closePath();
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
}
/*!
@@ -2365,13 +2329,12 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_closePath(QV4::CallContext
\sa fillStyle
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_fill(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_fill(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r);
r->d()->context->fill();
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
}
/*!
@@ -2379,24 +2342,22 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_fill(QV4::CallContext *ctx
Draws a line from the current position to the point (x, y).
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_lineTo(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_lineTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
+ scope.result = callData->thisObject;
- if (ctx->argc() >= 2) {
- qreal x = ctx->args()[0].toNumber();
- qreal y = ctx->args()[1].toNumber();
+ if (callData->argc >= 2) {
+ qreal x = callData->args[0].toNumber();
+ qreal y = callData->args[1].toNumber();
if (!qt_is_finite(x) || !qt_is_finite(y))
- return ctx->thisObject().asReturnedValue();
+ return;
r->d()->context->lineTo(x, y);
}
-
- return ctx->thisObject().asReturnedValue();
}
/*!
@@ -2404,21 +2365,21 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_lineTo(QV4::CallContext *c
Creates a new subpath with the given point.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_moveTo(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_moveTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 2) {
- qreal x = ctx->args()[0].toNumber();
- qreal y = ctx->args()[1].toNumber();
+ scope.result = callData->thisObject;
+
+ if (callData->argc >= 2) {
+ qreal x = callData->args[0].toNumber();
+ qreal y = callData->args[1].toNumber();
if (!qt_is_finite(x) || !qt_is_finite(y))
- return ctx->thisObject().asReturnedValue();
+ return;
r->d()->context->moveTo(x, y);
}
- return ctx->thisObject().asReturnedValue();
}
/*!
@@ -2428,25 +2389,24 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_moveTo(QV4::CallContext *c
See \l{http://www.w3.org/TR/2dcontext/#dom-context-2d-quadraticcurveto}{W3C 2d context standard for quadraticCurveTo}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_quadraticCurveTo(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_quadraticCurveTo(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 4) {
- qreal cpx = ctx->args()[0].toNumber();
- qreal cpy = ctx->args()[1].toNumber();
- qreal x = ctx->args()[2].toNumber();
- qreal y = ctx->args()[3].toNumber();
+ scope.result = callData->thisObject;
+
+ if (callData->argc >= 4) {
+ qreal cpx = callData->args[0].toNumber();
+ qreal cpy = callData->args[1].toNumber();
+ qreal x = callData->args[2].toNumber();
+ qreal y = callData->args[3].toNumber();
if (!qt_is_finite(cpx) || !qt_is_finite(cpy) || !qt_is_finite(x) || !qt_is_finite(y))
- return ctx->thisObject().asReturnedValue();
+ return;
r->d()->context->quadraticCurveTo(cpx, cpy, x, y);
}
-
- return ctx->thisObject().asReturnedValue();
}
/*!
@@ -2454,15 +2414,15 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_quadraticCurveTo(QV4::Call
Adds a rectangle at position (\c x, \c y), with the given width \c w and height \c h, as a closed subpath.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_rect(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_rect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 4)
- r->d()->context->rect(ctx->args()[0].toNumber(), ctx->args()[1].toNumber(), ctx->args()[2].toNumber(), ctx->args()[3].toNumber());
- return ctx->thisObject().asReturnedValue();
+ if (callData->argc >= 4)
+ r->d()->context->rect(callData->args[0].toNumber(), callData->args[1].toNumber(), callData->args[2].toNumber(), callData->args[3].toNumber());
+ scope.result = callData->thisObject;
+
}
/*!
@@ -2471,20 +2431,20 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_rect(QV4::CallContext *ctx
Adds the given rectangle rect with rounded corners to the path. The \c xRadius and \c yRadius arguments specify the radius of the
ellipses defining the corners of the rounded rectangle.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_roundedRect(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_roundedRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 6)
- r->d()->context->roundedRect(ctx->args()[0].toNumber()
- , ctx->args()[1].toNumber()
- , ctx->args()[2].toNumber()
- , ctx->args()[3].toNumber()
- , ctx->args()[4].toNumber()
- , ctx->args()[5].toNumber());
- return ctx->thisObject().asReturnedValue();
+ if (callData->argc >= 6)
+ r->d()->context->roundedRect(callData->args[0].toNumber()
+ , callData->args[1].toNumber()
+ , callData->args[2].toNumber()
+ , callData->args[3].toNumber()
+ , callData->args[4].toNumber()
+ , callData->args[5].toNumber());
+ scope.result = callData->thisObject;
+
}
/*!
@@ -2495,17 +2455,17 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_roundedRect(QV4::CallConte
The ellipse is composed of a clockwise curve, starting and finishing at zero degrees (the 3 o'clock position).
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_ellipse(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_ellipse(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 4)
- r->d()->context->ellipse(ctx->args()[0].toNumber(), ctx->args()[1].toNumber(), ctx->args()[2].toNumber(), ctx->args()[3].toNumber());
+ if (callData->argc >= 4)
+ r->d()->context->ellipse(callData->args[0].toNumber(), callData->args[1].toNumber(), callData->args[2].toNumber(), callData->args[3].toNumber());
+
+ scope.result = callData->thisObject;
- return ctx->thisObject().asReturnedValue();
}
/*!
@@ -2514,21 +2474,22 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_ellipse(QV4::CallContext *
Adds the given \c text to the path as a set of closed subpaths created from the current context font supplied.
The subpaths are positioned so that the left end of the text's baseline lies at the point specified by (\c x, \c y).
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_text(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_text(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 3) {
- qreal x = ctx->args()[1].toNumber();
- qreal y = ctx->args()[2].toNumber();
+ scope.result = callData->thisObject;
+
+ if (callData->argc >= 3) {
+ qreal x = callData->args[1].toNumber();
+ qreal y = callData->args[2].toNumber();
if (!qt_is_finite(x) || !qt_is_finite(y))
- return ctx->thisObject().asReturnedValue();
- r->d()->context->text(ctx->args()[0].toQStringNoThrow(), x, y);
+ return;
+ r->d()->context->text(callData->args[0].toQStringNoThrow(), x, y);
}
- return ctx->thisObject().asReturnedValue();
+
}
/*!
@@ -2540,14 +2501,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_text(QV4::CallContext *ctx
\sa strokeStyle
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_stroke(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_stroke(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
r->d()->context->stroke();
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
+
}
/*!
@@ -2557,37 +2518,30 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_stroke(QV4::CallContext *c
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-ispointinpath}{W3C 2d context standard for isPointInPath}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_isPointInPath(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_isPointInPath(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
bool pointInPath = false;
- if (ctx->argc() >= 2)
- pointInPath = r->d()->context->isPointInPath(ctx->args()[0].toNumber(), ctx->args()[1].toNumber());
- return QV4::Primitive::fromBoolean(pointInPath).asReturnedValue();
+ if (callData->argc >= 2)
+ pointInPath = r->d()->context->isPointInPath(callData->args[0].toNumber(), callData->args[1].toNumber());
+ scope.result = QV4::Primitive::fromBoolean(pointInPath).asReturnedValue();
}
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawFocusRing(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_drawFocusRing(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *)
{
- QV4::Scope scope(ctx);
-
- V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::drawFocusRing is not supported");
+ THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::drawFocusRing is not supported");
}
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_setCaretSelectionRect(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_setCaretSelectionRect(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *)
{
- QV4::Scope scope(ctx);
-
- V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::setCaretSelectionRect is not supported");
+ THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::setCaretSelectionRect is not supported");
}
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_caretBlinkRate(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_caretBlinkRate(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *)
{
- QV4::Scope scope(ctx);
-
- V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::caretBlinkRate is not supported");
+ THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Context2D::caretBlinkRate is not supported");
}
/*!
@@ -2613,29 +2567,27 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_caretBlinkRate(QV4::CallCo
The default font value is "10px sans-serif".
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_font(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_font(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- return QV4::Encode(scope.engine->newString(r->d()->context->state.font.toString()));
+ RETURN_RESULT(scope.engine->newString(r->d()->context->state.font.toString()));
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_font(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_font(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- QV4::ScopedString s(scope, ctx->argument(0), QV4::ScopedString::Convert);
+ QV4::ScopedString s(scope, callData->argument(0), QV4::ScopedString::Convert);
if (scope.engine->hasException)
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
QFont font = qt_font_from_string(s->toQString(), r->d()->context->state.font);
if (font != r->d()->context->state.font) {
r->d()->context->state.font = font;
}
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
/*!
@@ -2652,37 +2604,35 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_font(QV4::CallContext *ctx)
\endlist
Other values are ignored. The default value is "start".
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_textAlign(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_textAlign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
switch (r->d()->context->state.textAlign) {
case QQuickContext2D::End:
- return QV4::Encode(scope.engine->newString(QStringLiteral("end")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("end")));
case QQuickContext2D::Left:
- return QV4::Encode(scope.engine->newString(QStringLiteral("left")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("left")));
case QQuickContext2D::Right:
- return QV4::Encode(scope.engine->newString(QStringLiteral("right")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("right")));
case QQuickContext2D::Center:
- return QV4::Encode(scope.engine->newString(QStringLiteral("center")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("center")));
case QQuickContext2D::Start:
default:
break;
}
- return QV4::Encode(scope.engine->newString(QStringLiteral("start")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("start")));
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_textAlign(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_textAlign(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- QV4::ScopedString s(scope, ctx->argument(0), QV4::ScopedString::Convert);
+ QV4::ScopedString s(scope, callData->argument(0), QV4::ScopedString::Convert);
if (scope.engine->hasException)
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
QString textAlign = s->toQString();
QQuickContext2D::TextAlignType ta;
@@ -2697,12 +2647,12 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textAlign(QV4::CallContext *ctx
else if (textAlign == QLatin1String("center"))
ta = QQuickContext2D::Center;
else
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
if (ta != r->d()->context->state.textAlign)
r->d()->context->state.textAlign = ta;
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
/*!
@@ -2720,36 +2670,34 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textAlign(QV4::CallContext *ctx
\endlist
Other values are ignored. The default value is "alphabetic".
*/
-QV4::ReturnedValue QQuickJSContext2D::method_get_textBaseline(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_get_textBaseline(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
switch (r->d()->context->state.textBaseline) {
case QQuickContext2D::Hanging:
- return QV4::Encode(scope.engine->newString(QStringLiteral("hanging")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("hanging")));
case QQuickContext2D::Top:
- return QV4::Encode(scope.engine->newString(QStringLiteral("top")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("top")));
case QQuickContext2D::Bottom:
- return QV4::Encode(scope.engine->newString(QStringLiteral("bottom")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("bottom")));
case QQuickContext2D::Middle:
- return QV4::Encode(scope.engine->newString(QStringLiteral("middle")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("middle")));
case QQuickContext2D::Alphabetic:
default:
break;
}
- return QV4::Encode(scope.engine->newString(QStringLiteral("alphabetic")));
+ RETURN_RESULT(scope.engine->newString(QStringLiteral("alphabetic")));
}
-QV4::ReturnedValue QQuickJSContext2D::method_set_textBaseline(QV4::CallContext *ctx)
+void QQuickJSContext2D::method_set_textBaseline(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT_SETTER(r)
- QV4::ScopedString s(scope, ctx->argument(0), QV4::ScopedString::Convert);
+ QV4::ScopedString s(scope, callData->argument(0), QV4::ScopedString::Convert);
if (scope.engine->hasException)
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
QString textBaseline = s->toQString();
QQuickContext2D::TextBaseLineType tb;
@@ -2764,12 +2712,12 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textBaseline(QV4::CallContext *
else if (textBaseline == QLatin1String("middle"))
tb = QQuickContext2D::Middle;
else
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
if (tb != r->d()->context->state.textBaseline)
r->d()->context->state.textBaseline = tb;
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
/*!
@@ -2780,21 +2728,21 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textBaseline(QV4::CallContext *
\sa textBaseline
\sa strokeText
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillText(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_fillText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 3) {
- qreal x = ctx->args()[1].toNumber();
- qreal y = ctx->args()[2].toNumber();
+ scope.result = callData->thisObject;
+
+ if (callData->argc >= 3) {
+ qreal x = callData->args[1].toNumber();
+ qreal y = callData->args[2].toNumber();
if (!qt_is_finite(x) || !qt_is_finite(y))
- return ctx->thisObject().asReturnedValue();
- QPainterPath textPath = r->d()->context->createTextGlyphs(x, y, ctx->args()[0].toQStringNoThrow());
+ return;
+ QPainterPath textPath = r->d()->context->createTextGlyphs(x, y, callData->args[0].toQStringNoThrow());
r->d()->context->buffer()->fill(textPath);
}
- return ctx->thisObject().asReturnedValue();
}
/*!
\qmlmethod object QtQuick::Context2D::strokeText(text, x, y)
@@ -2804,15 +2752,15 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_fillText(QV4::CallContext
\sa textBaseline
\sa fillText
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeText(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_strokeText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 3)
- r->d()->context->drawText(ctx->args()[0].toQStringNoThrow(), ctx->args()[1].toNumber(), ctx->args()[2].toNumber(), false);
- return ctx->thisObject().asReturnedValue();
+ if (callData->argc >= 3)
+ r->d()->context->drawText(callData->args[0].toQStringNoThrow(), callData->args[1].toNumber(), callData->args[2].toNumber(), false);
+ scope.result = callData->thisObject;
+
}
/*!
@@ -2821,21 +2769,20 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_strokeText(QV4::CallContex
Returns an object with a \c width property, whose value is equivalent to
calling \l {QFontMetrics::width()} with the given \a text in the current font.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_measureText(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_measureText(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
- if (ctx->argc() >= 1) {
+ if (callData->argc >= 1) {
QFontMetrics fm(r->d()->context->state.font);
- uint width = fm.width(ctx->args()[0].toQStringNoThrow());
+ uint width = fm.width(callData->args[0].toQStringNoThrow());
QV4::ScopedObject tm(scope, scope.engine->newObject());
tm->put(QV4::ScopedString(scope, scope.engine->newIdentifier(QStringLiteral("width"))).getPointer(),
QV4::ScopedValue(scope, QV4::Primitive::fromDouble(width)));
- return tm.asReturnedValue();
+ RETURN_RESULT(tm);
}
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
// drawing images
@@ -2897,28 +2844,29 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_measureText(QV4::CallConte
\sa {http://www.w3.org/TR/2dcontext/#dom-context-2d-drawimage}{W3C 2d context standard for drawImage}
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_drawImage(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject);
CHECK_CONTEXT(r)
+ scope.result = callData->thisObject;
+
qreal sx, sy, sw, sh, dx, dy, dw, dh;
- if (!ctx->argc())
- return ctx->thisObject().asReturnedValue();
+ if (!callData->argc)
+ return;
//FIXME:This function should be moved to QQuickContext2D::drawImage(...)
if (!r->d()->context->state.invertibleCTM)
- return ctx->thisObject().asReturnedValue();
+ return;
QQmlRefPointer<QQuickCanvasPixmap> pixmap;
- QV4::ScopedValue arg(scope, ctx->args()[0]);
+ QV4::ScopedValue arg(scope, callData->args[0]);
if (arg->isString()) {
QUrl url(arg->toQString());
if (!url.isValid())
- V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
+ THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
pixmap = r->d()->context->createPixmap(url);
} else if (arg->isObject()) {
@@ -2931,7 +2879,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
if (!img.isNull())
pixmap.adopt(new QQuickCanvasPixmap(img));
} else {
- V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
+ THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
} else {
QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, arg);
@@ -2940,44 +2888,44 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
if (pix && !pix->d()->image->isNull()) {
pixmap.adopt(new QQuickCanvasPixmap(*pix->d()->image));
} else {
- V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
+ THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
} else {
QUrl url(arg->toQStringNoThrow());
if (url.isValid())
pixmap = r->d()->context->createPixmap(url);
else
- V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
+ THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
}
} else {
- V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
+ THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch");
}
if (pixmap.isNull() || !pixmap->isValid())
- return ctx->thisObject().asReturnedValue();
-
- if (ctx->argc() >= 9) {
- sx = ctx->args()[1].toNumber();
- sy = ctx->args()[2].toNumber();
- sw = ctx->args()[3].toNumber();
- sh = ctx->args()[4].toNumber();
- dx = ctx->args()[5].toNumber();
- dy = ctx->args()[6].toNumber();
- dw = ctx->args()[7].toNumber();
- dh = ctx->args()[8].toNumber();
- } else if (ctx->argc() >= 5) {
+ return;
+
+ if (callData->argc >= 9) {
+ sx = callData->args[1].toNumber();
+ sy = callData->args[2].toNumber();
+ sw = callData->args[3].toNumber();
+ sh = callData->args[4].toNumber();
+ dx = callData->args[5].toNumber();
+ dy = callData->args[6].toNumber();
+ dw = callData->args[7].toNumber();
+ dh = callData->args[8].toNumber();
+ } else if (callData->argc >= 5) {
sx = 0;
sy = 0;
sw = pixmap->width();
sh = pixmap->height();
- dx = ctx->args()[1].toNumber();
- dy = ctx->args()[2].toNumber();
- dw = ctx->args()[3].toNumber();
- dh = ctx->args()[4].toNumber();
- } else if (ctx->argc() >= 3) {
- dx = ctx->args()[1].toNumber();
- dy = ctx->args()[2].toNumber();
+ dx = callData->args[1].toNumber();
+ dy = callData->args[2].toNumber();
+ dw = callData->args[3].toNumber();
+ dh = callData->args[4].toNumber();
+ } else if (callData->argc >= 3) {
+ dx = callData->args[1].toNumber();
+ dy = callData->args[2].toNumber();
sx = 0;
sy = 0;
sw = pixmap->width();
@@ -2985,7 +2933,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
dw = sw;
dh = sh;
} else {
- return ctx->thisObject().asReturnedValue();
+ return;
}
if (!qt_is_finite(sx)
@@ -2996,7 +2944,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
|| !qt_is_finite(dy)
|| !qt_is_finite(dw)
|| !qt_is_finite(dh))
- return ctx->thisObject().asReturnedValue();
+ return;
if (sx < 0
|| sy < 0
@@ -3005,12 +2953,10 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
|| sx + sw > pixmap->width()
|| sy + sh > pixmap->height()
|| sx + sw < 0 || sy + sh < 0) {
- V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "drawImage(), index size error");
+ THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "drawImage(), index size error");
}
r->d()->context->buffer()->drawPixmap(pixmap, QRectF(sx, sy, sw, sh), QRectF(dx, dy, dw, dh));
-
- return ctx->thisObject().asReturnedValue();
}
// pixel manipulation
@@ -3037,45 +2983,40 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext
\qmlproperty int QtQuick::CanvasImageData::width
Holds the actual width dimension of the data in the ImageData object, in device pixels.
*/
-QV4::ReturnedValue QQuickJSContext2DImageData::method_get_width(QV4::CallContext *ctx)
+void QQuickJSContext2DImageData::method_get_width(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, callData->thisObject);
if (!imageData)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>());
- if (!r)
- return QV4::Encode(0);
- return QV4::Encode(r->d()->image->width());
+ int width = r ? r->d()->image->width() : 0;
+ scope.result = QV4::Encode(width);
}
/*!
\qmlproperty int QtQuick::CanvasImageData::height
Holds the actual height dimension of the data in the ImageData object, in device pixels.
*/
-QV4::ReturnedValue QQuickJSContext2DImageData::method_get_height(QV4::CallContext *ctx)
+void QQuickJSContext2DImageData::method_get_height(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, callData->thisObject);
if (!imageData)
- return ctx->engine()->throwTypeError();
+ THROW_TYPE_ERROR();
QV4::Scoped<QQuickJSContext2DPixelData> r(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>());
- if (!r)
- return QV4::Encode(0);
- return QV4::Encode(r->d()->image->height());
+ int height = r ? r->d()->image->height() : 0;
+ scope.result = QV4::Encode(height);
}
/*!
\qmlproperty object QtQuick::CanvasImageData::data
Holds the one-dimensional array containing the data in RGBA order, as integers in the range 0 to 255.
*/
-QV4::ReturnedValue QQuickJSContext2DImageData::method_get_data(QV4::CallContext *ctx)
+void QQuickJSContext2DImageData::method_get_data(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, ctx->thisObject());
+ QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, callData->thisObject);
if (!imageData)
- return ctx->engine()->throwTypeError();
- return imageData->d()->pixelData.asReturnedValue();
+ THROW_TYPE_ERROR();
+ scope.result = imageData->d()->pixelData;
}
/*!
@@ -3096,14 +3037,13 @@ QV4::ReturnedValue QQuickJSContext2DImageData::method_get_data(QV4::CallContext
The length attribute of a CanvasPixelArray object must return this h×w×4 number value.
This property is read only.
*/
-QV4::ReturnedValue QQuickJSContext2DPixelData::proto_get_length(QV4::CallContext *ctx)
+void QQuickJSContext2DPixelData::proto_get_length(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2DPixelData> r(scope, ctx->thisObject().as<QQuickJSContext2DPixelData>());
+ QV4::Scoped<QQuickJSContext2DPixelData> r(scope, callData->thisObject.as<QQuickJSContext2DPixelData>());
if (!r || r->d()->image->isNull())
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
- return QV4::Encode(r->d()->image->width() * r->d()->image->height() * 4);
+ RETURN_RESULT(r->d()->image->width() * r->d()->image->height() * 4);
}
QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(const QV4::Managed *m, uint index, bool *hasProperty)
@@ -3192,108 +3132,107 @@ void QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const Q
\sa Canvas::loadImage(), QtQuick::Canvas::unloadImage(),
QtQuick::Canvas::isImageLoaded
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_createImageData(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_createImageData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->argc() == 1) {
- QV4::ScopedValue arg0(scope, ctx->args()[0]);
+ if (callData->argc == 1) {
+ QV4::ScopedValue arg0(scope, callData->args[0]);
QV4::Scoped<QQuickJSContext2DImageData> imgData(scope, arg0);
if (!!imgData) {
QV4::Scoped<QQuickJSContext2DPixelData> pa(scope, imgData->d()->pixelData.as<QQuickJSContext2DPixelData>());
if (pa) {
qreal w = pa->d()->image->width();
qreal h = pa->d()->image->height();
- return qt_create_image_data(w, h, scope.engine, QImage());
+ RETURN_RESULT(qt_create_image_data(w, h, scope.engine, QImage()));
}
} else if (arg0->isString()) {
QImage image = r->d()->context->createPixmap(QUrl(arg0->toQStringNoThrow()))->image();
- return qt_create_image_data(image.width(), image.height(), scope.engine, image);
+ RETURN_RESULT(qt_create_image_data(image.width(), image.height(), scope.engine, image));
}
- } else if (ctx->argc() == 2) {
- qreal w = ctx->args()[0].toNumber();
- qreal h = ctx->args()[1].toNumber();
+ } else if (callData->argc == 2) {
+ qreal w = callData->args[0].toNumber();
+ qreal h = callData->args[1].toNumber();
if (!qt_is_finite(w) || !qt_is_finite(h))
- V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createImageData(): invalid arguments");
+ THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "createImageData(): invalid arguments");
if (w > 0 && h > 0)
- return qt_create_image_data(w, h, scope.engine, QImage());
+ RETURN_RESULT(qt_create_image_data(w, h, scope.engine, QImage()));
else
- V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createImageData(): invalid arguments");
+ THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "createImageData(): invalid arguments");
}
- return QV4::Encode::undefined();
+ RETURN_UNDEFINED();
}
/*!
\qmlmethod CanvasImageData QtQuick::Context2D::getImageData(real sx, real sy, real sw, real sh)
Returns an CanvasImageData object containing the image data for the given rectangle of the canvas.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_getImageData(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_getImageData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->argc() >= 4) {
- qreal x = ctx->args()[0].toNumber();
- qreal y = ctx->args()[1].toNumber();
- qreal w = ctx->args()[2].toNumber();
- qreal h = ctx->args()[3].toNumber();
+ if (callData->argc >= 4) {
+ qreal x = callData->args[0].toNumber();
+ qreal y = callData->args[1].toNumber();
+ qreal w = callData->args[2].toNumber();
+ qreal h = callData->args[3].toNumber();
if (!qt_is_finite(x) || !qt_is_finite(y) || !qt_is_finite(w) || !qt_is_finite(h))
- V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "getImageData(): Invalid arguments");
+ THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "getImageData(): Invalid arguments");
if (w <= 0 || h <= 0)
- V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "getImageData(): Invalid arguments");
+ THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "getImageData(): Invalid arguments");
QImage image = r->d()->context->canvas()->toImage(QRectF(x, y, w, h));
- return qt_create_image_data(w, h, scope.engine, image);
+ RETURN_RESULT(qt_create_image_data(w, h, scope.engine, image));
}
- return QV4::Encode::null();
+ scope.result = QV4::Encode::null();
}
/*!
\qmlmethod object QtQuick::Context2D::putImageData(CanvasImageData imageData, real dx, real dy, real dirtyX, real dirtyY, real dirtyWidth, real dirtyHeight)
Paints the data from the given ImageData object onto the canvas. If a dirty rectangle (\a dirtyX, \a dirtyY, \a dirtyWidth, \a dirtyHeight) is provided, only the pixels from that rectangle are painted.
*/
-QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallContext *ctx)
+void QQuickJSContext2DPrototype::method_putImageData(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickJSContext2D> r(scope, ctx->thisObject().as<QQuickJSContext2D>());
+ QV4::Scoped<QQuickJSContext2D> r(scope, callData->thisObject.as<QQuickJSContext2D>());
CHECK_CONTEXT(r)
- if (ctx->argc() < 7)
- return QV4::Encode::undefined();
+ if (callData->argc < 7)
+ RETURN_UNDEFINED();
- QV4::ScopedValue arg0(scope, ctx->args()[0]);
+ QV4::ScopedValue arg0(scope, callData->args[0]);
if (!arg0->isObject())
- V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "Context2D::putImageData, the image data type mismatch");
+ THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "Context2D::putImageData, the image data type mismatch");
- qreal dx = ctx->args()[1].toNumber();
- qreal dy = ctx->args()[2].toNumber();
+ qreal dx = callData->args[1].toNumber();
+ qreal dy = callData->args[2].toNumber();
qreal w, h, dirtyX, dirtyY, dirtyWidth, dirtyHeight;
if (!qt_is_finite(dx) || !qt_is_finite(dy))
- V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
+ THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
+
+ scope.result = callData->thisObject;
QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, arg0);
if (!imageData)
- return ctx->thisObject().asReturnedValue();
+ return;
QV4::Scoped<QQuickJSContext2DPixelData> pixelArray(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>());
if (pixelArray) {
w = pixelArray->d()->image->width();
h = pixelArray->d()->image->height();
- if (ctx->argc() == 7) {
- dirtyX = ctx->args()[3].toNumber();
- dirtyY = ctx->args()[4].toNumber();
- dirtyWidth = ctx->args()[5].toNumber();
- dirtyHeight = ctx->args()[6].toNumber();
+ if (callData->argc == 7) {
+ dirtyX = callData->args[3].toNumber();
+ dirtyY = callData->args[4].toNumber();
+ dirtyWidth = callData->args[5].toNumber();
+ dirtyHeight = callData->args[6].toNumber();
if (!qt_is_finite(dirtyX) || !qt_is_finite(dirtyY) || !qt_is_finite(dirtyWidth) || !qt_is_finite(dirtyHeight))
- V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
+ THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "putImageData() : Invalid arguments");
if (dirtyWidth < 0) {
@@ -3325,7 +3264,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallCont
}
if (dirtyWidth <=0 || dirtyHeight <= 0)
- return ctx->thisObject().asReturnedValue();
+ return;
} else {
dirtyX = 0;
dirtyY = 0;
@@ -3336,7 +3275,6 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallCont
QImage image = pixelArray->d()->image->copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight);
r->d()->context->buffer()->drawImage(image, QRectF(dirtyX, dirtyY, dirtyWidth, dirtyHeight), QRectF(dx, dy, dirtyWidth, dirtyHeight));
}
- return ctx->thisObject().asReturnedValue();
}
/*!
@@ -3359,39 +3297,38 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallCont
gradient.addColorStop(0.7, 'rgba(0, 255, 255, 1');
\endcode
*/
-QV4::ReturnedValue QQuickContext2DStyle::gradient_proto_addColorStop(QV4::CallContext *ctx)
+void QQuickContext2DStyle::gradient_proto_addColorStop(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData)
{
- QV4::Scope scope(ctx);
- QV4::Scoped<QQuickContext2DStyle> style(scope, ctx->thisObject().as<QQuickContext2DStyle>());
+ QV4::Scoped<QQuickContext2DStyle> style(scope, callData->thisObject.as<QQuickContext2DStyle>());
if (!style)
- V4THROW_ERROR("Not a CanvasGradient object");
+ THROW_GENERIC_ERROR("Not a CanvasGradient object");
- if (ctx->argc() == 2) {
+ if (callData->argc == 2) {
if (!style->d()->brush->gradient())
- V4THROW_ERROR("Not a valid CanvasGradient object, can't get the gradient information");
+ THROW_GENERIC_ERROR("Not a valid CanvasGradient object, can't get the gradient information");
QGradient gradient = *(style->d()->brush->gradient());
- qreal pos = ctx->args()[0].toNumber();
+ qreal pos = callData->args[0].toNumber();
QColor color;
- if (ctx->args()[1].as<Object>()) {
- color = scope.engine->toVariant(ctx->args()[1], qMetaTypeId<QColor>()).value<QColor>();
+ if (callData->args[1].as<Object>()) {
+ color = scope.engine->toVariant(callData->args[1], qMetaTypeId<QColor>()).value<QColor>();
} else {
- color = qt_color_from_string(ctx->args()[1]);
+ color = qt_color_from_string(callData->args[1]);
}
if (pos < 0.0 || pos > 1.0 || !qt_is_finite(pos)) {
- V4THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "CanvasGradient: parameter offset out of range");
+ THROW_DOM(DOMEXCEPTION_INDEX_SIZE_ERR, "CanvasGradient: parameter offset out of range");
}
if (color.isValid()) {
gradient.setColorAt(pos, color);
} else {
- V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "CanvasGradient: parameter color is not a valid color string");
+ THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "CanvasGradient: parameter color is not a valid color string");
}
*style->d()->brush = gradient;
}
- return ctx->thisObject().asReturnedValue();
+ scope.result = callData->thisObject;
}
void QQuickContext2D::scale(qreal x, qreal y)
diff --git a/src/quick/items/qquickevents_p_p.h b/src/quick/items/qquickevents_p_p.h
index 7b281623fe..cf6f83e5b1 100644
--- a/src/quick/items/qquickevents_p_p.h
+++ b/src/quick/items/qquickevents_p_p.h
@@ -108,7 +108,9 @@ public:
bool isAccepted() { return event.isAccepted(); }
void setAccepted(bool accepted) { event.setAccepted(accepted); }
+#if QT_CONFIG(shortcut)
Q_REVISION(2) Q_INVOKABLE bool matches(QKeySequence::StandardKey key) const { return event.matches(key); }
+#endif
private:
QKeyEvent event;
diff --git a/src/quick/items/qquickitemgrabresult.cpp b/src/quick/items/qquickitemgrabresult.cpp
index 07c2cb607c..12bcd43076 100644
--- a/src/quick/items/qquickitemgrabresult.cpp
+++ b/src/quick/items/qquickitemgrabresult.cpp
@@ -75,7 +75,7 @@ public:
void ensureImageInCache() const {
if (url.isEmpty() && !image.isNull()) {
- url.setScheme(QStringLiteral("ItemGrabber"));
+ url.setScheme(QQuickPixmap::itemGrabberScheme);
url.setPath(QVariant::fromValue(item.data()).toString());
static uint counter = 0;
url.setFragment(QString::number(++counter));
diff --git a/src/quick/items/qquicktext.cpp b/src/quick/items/qquicktext.cpp
index 965fb0102f..1720377046 100644
--- a/src/quick/items/qquicktext.cpp
+++ b/src/quick/items/qquicktext.cpp
@@ -74,7 +74,7 @@ Q_DECLARE_LOGGING_CATEGORY(DBG_HOVER_TRACE)
const QChar QQuickTextPrivate::elideChar = QChar(0x2026);
QQuickTextPrivate::QQuickTextPrivate()
- : elideLayout(0), textLine(0), lineWidth(0)
+ : fontInfo(font), elideLayout(0), textLine(0), lineWidth(0)
, color(0xFF000000), linkColor(0xFF0000FF), styleColor(0xFF000000)
, lineCount(1), multilengthEos(-1)
, elideMode(QQuickText::ElideNone), hAlign(QQuickText::AlignLeft), vAlign(QQuickText::AlignTop)
@@ -1018,6 +1018,17 @@ QRectF QQuickTextPrivate::setupTextLayout(qreal *const baseline)
implicitWidthValid = true;
implicitHeightValid = true;
+ QFontInfo scaledFontInfo(scaledFont);
+ if (fontInfo.weight() != scaledFontInfo.weight()
+ || fontInfo.pixelSize() != scaledFontInfo.pixelSize()
+ || fontInfo.italic() != scaledFontInfo.italic()
+ || !qFuzzyCompare(fontInfo.pointSizeF(), scaledFontInfo.pointSizeF())
+ || fontInfo.family() != scaledFontInfo.family()
+ || fontInfo.styleName() != scaledFontInfo.styleName()) {
+ fontInfo = scaledFontInfo;
+ emit q->fontInfoChanged();
+ }
+
if (eos != multilengthEos)
truncated = true;
@@ -2974,4 +2985,80 @@ void QQuickText::resetBottomPadding()
d->setBottomPadding(0, true);
}
+/*!
+ \qmlproperty string QtQuick::Text::fontInfo.family
+ \since 5.9
+
+ The family name of the font that has been resolved for the current font
+ and fontSizeMode.
+*/
+
+/*!
+ \qmlproperty string QtQuick::Text::fontInfo.styleName
+ \since 5.9
+
+ The style name of the font info that has been resolved for the current font
+ and fontSizeMode.
+*/
+
+/*!
+ \qmlproperty bool QtQuick::Text::fontInfo.bold
+ \since 5.9
+
+ The bold state of the font info that has been resolved for the current font
+ and fontSizeMode. This is true if the weight of the resolved font is bold or higher.
+*/
+
+/*!
+ \qmlproperty int QtQuick::Text::fontInfo.weight
+ \since 5.9
+
+ The weight of the font info that has been resolved for the current font
+ and fontSizeMode.
+*/
+
+/*!
+ \qmlproperty bool QtQuick::Text::fontInfo.italic
+ \since 5.9
+
+ The italic state of the font info that has been resolved for the current font
+ and fontSizeMode.
+*/
+
+/*!
+ \qmlproperty real QtQuick::Text::fontInfo.pointSize
+ \since 5.9
+
+ The pointSize of the font info that has been resolved for the current font
+ and fontSizeMode.
+*/
+
+/*!
+ \qmlproperty string QtQuick::Text::fontInfo.pixelSize
+ \since 5.9
+
+ The pixel size of the font info that has been resolved for the current font
+ and fontSizeMode.
+*/
+QJSValue QQuickText::fontInfo() const
+{
+ Q_D(const QQuickText);
+
+ QJSEngine *engine = qjsEngine(this);
+ if (!engine) {
+ qmlWarning(this) << "fontInfo: item has no JS engine";
+ return QJSValue();
+ }
+
+ QJSValue value = engine->newObject();
+ value.setProperty(QStringLiteral("family"), d->fontInfo.family());
+ value.setProperty(QStringLiteral("styleName"), d->fontInfo.styleName());
+ value.setProperty(QStringLiteral("bold"), d->fontInfo.bold());
+ value.setProperty(QStringLiteral("weight"), d->fontInfo.weight());
+ value.setProperty(QStringLiteral("italic"), d->fontInfo.italic());
+ value.setProperty(QStringLiteral("pointSize"), d->fontInfo.pointSizeF());
+ value.setProperty(QStringLiteral("pixelSize"), d->fontInfo.pixelSize());
+ return value;
+}
+
QT_END_NAMESPACE
diff --git a/src/quick/items/qquicktext_p.h b/src/quick/items/qquicktext_p.h
index c3d3906e7e..b190738cfb 100644
--- a/src/quick/items/qquicktext_p.h
+++ b/src/quick/items/qquicktext_p.h
@@ -98,6 +98,8 @@ class Q_QUICK_PRIVATE_EXPORT QQuickText : public QQuickImplicitSizeItem
Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged REVISION 6)
Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged REVISION 6)
+ Q_PROPERTY(QJSValue fontInfo READ fontInfo NOTIFY fontInfoChanged REVISION 9)
+
public:
QQuickText(QQuickItem *parent=0);
~QQuickText();
@@ -248,6 +250,8 @@ public:
void setBottomPadding(qreal padding);
void resetBottomPadding();
+ QJSValue fontInfo() const;
+
Q_SIGNALS:
void textChanged(const QString &text);
void linkActivated(const QString &link);
@@ -280,6 +284,7 @@ Q_SIGNALS:
Q_REVISION(6) void leftPaddingChanged();
Q_REVISION(6) void rightPaddingChanged();
Q_REVISION(6) void bottomPaddingChanged();
+ Q_REVISION(9) void fontInfoChanged();
protected:
QQuickText(QQuickTextPrivate &dd, QQuickItem *parent = 0);
diff --git a/src/quick/items/qquicktext_p_p.h b/src/quick/items/qquicktext_p_p.h
index 0669bcf115..6456750359 100644
--- a/src/quick/items/qquicktext_p_p.h
+++ b/src/quick/items/qquicktext_p_p.h
@@ -122,6 +122,7 @@ public:
QString text;
QFont font;
QFont sourceFont;
+ QFontInfo fontInfo;
QTextLayout layout;
QTextLayout *elideLayout;
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 660c5f8067..0e7c50ffcf 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -453,8 +453,13 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size)
fboId = renderTargetId;
renderer->setDeviceRect(rect);
renderer->setViewportRect(rect);
- renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), rect.size()));
- renderer->setDevicePixelRatio(1);
+ if (QQuickRenderControl::renderWindowFor(q)) {
+ renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), size));
+ renderer->setDevicePixelRatio(devicePixelRatio);
+ } else {
+ renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), rect.size()));
+ renderer->setDevicePixelRatio(1);
+ }
} else {
QRect rect(QPoint(0, 0), devicePixelRatio * size);
renderer->setDeviceRect(rect);
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index 322192944b..2c0f8667e8 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -440,9 +440,7 @@ struct Batch
mutable uint uploadedThisFrame : 1; // solely for debugging purposes
Buffer vbo;
-#ifdef QSG_SEPARATE_INDEX_BUFFER
Buffer ibo;
-#endif
QDataBuffer<DrawSet> drawSets;
};
@@ -744,9 +742,7 @@ private:
ClipType m_currentClipType;
QDataBuffer<char> m_vertexUploadPool;
-#ifdef QSG_SEPARATE_INDEX_BUFFER
QDataBuffer<char> m_indexUploadPool;
-#endif
// For minimal OpenGL core profile support
QOpenGLVertexArrayObject *m_vao;
@@ -766,10 +762,7 @@ Batch *Renderer::newBatch()
m_batchPool.resize(size - 1);
} else {
b = new Batch();
- memset(&b->vbo, 0, sizeof(Buffer));
-#ifdef QSG_SEPARATE_INDEX_BUFFER
- memset(&b->ibo, 0, sizeof(Buffer));
-#endif
+ memset(&b->vbo, 0, sizeof(Buffer) * 2); // Clear VBO & IBO
}
b->init();
return b;
diff --git a/src/quick/scenegraph/coreapi/qsgnode.cpp b/src/quick/scenegraph/coreapi/qsgnode.cpp
index a1e1ef8c27..7ef75d4b4c 100644
--- a/src/quick/scenegraph/coreapi/qsgnode.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnode.cpp
@@ -337,13 +337,6 @@ QSGNode::~QSGNode()
to the scene graph and will cause the preprocess() function to be called
for every frame the node is rendered.
- The preprocess function is called before the update pass that propagates
- opacity and transformations through the scene graph. That means that
- functions like QSGOpacityNode::combinedOpacity() and
- QSGTransformNode::combinedMatrix() will not contain up-to-date values.
- If such values are changed during the preprocess, these changes will be
- propagated through the scene graph before it is rendered.
-
\warning Beware of deleting nodes while they are being preprocessed. It is
possible, with a small performance hit, to delete a single node during its
own preprocess call. Deleting a subtree which has nodes that also use
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index 6b9db105e7..2f5d5790ee 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -88,6 +88,7 @@ class QSGRectangleNode;
class QSGImageNode;
class QSGNinePatchNode;
class QSGSpriteNode;
+class QSGRenderContext;
Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERLOOP)
Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_COMPILATION)
@@ -98,6 +99,54 @@ Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_TIME_RENDERER)
Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_INFO)
Q_DECLARE_LOGGING_CATEGORY(QSG_LOG_RENDERLOOP)
+class Q_QUICK_PRIVATE_EXPORT QSGContext : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum AntialiasingMethod {
+ UndecidedAntialiasing,
+ VertexAntialiasing,
+ MsaaAntialiasing
+ };
+
+ explicit QSGContext(QObject *parent = 0);
+ virtual ~QSGContext();
+
+ virtual void renderContextInitialized(QSGRenderContext *renderContext);
+ virtual void renderContextInvalidated(QSGRenderContext *renderContext);
+ virtual QSGRenderContext *createRenderContext() = 0;
+
+ QSGInternalRectangleNode *createInternalRectangleNode(const QRectF &rect, const QColor &c);
+ virtual QSGInternalRectangleNode *createInternalRectangleNode() = 0;
+ virtual QSGInternalImageNode *createInternalImageNode() = 0;
+ virtual QSGPainterNode *createPainterNode(QQuickPaintedItem *item) = 0;
+ virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) = 0;
+ virtual QSGLayer *createLayer(QSGRenderContext *renderContext) = 0;
+ virtual QSGGuiThreadShaderEffectManager *createGuiThreadShaderEffectManager();
+ virtual QSGShaderEffectNode *createShaderEffectNode(QSGRenderContext *renderContext,
+ QSGGuiThreadShaderEffectManager *mgr);
+#if QT_CONFIG(quick_sprite)
+ virtual QSGSpriteNode *createSpriteNode() = 0;
+#endif
+ virtual QAnimationDriver *createAnimationDriver(QObject *parent);
+
+ virtual QSize minimumFBOSize() const;
+ virtual QSurfaceFormat defaultSurfaceFormat() const = 0;
+
+ virtual QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext);
+
+ virtual QSGRectangleNode *createRectangleNode() = 0;
+ virtual QSGImageNode *createImageNode() = 0;
+ virtual QSGNinePatchNode *createNinePatchNode() = 0;
+
+ static QSGContext *createDefaultContext();
+ static QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image);
+ static QSGRenderLoop *createWindowManager();
+
+ static void setBackend(const QString &backend);
+};
+
class Q_QUICK_PRIVATE_EXPORT QSGRenderContext : public QObject
{
Q_OBJECT
@@ -150,55 +199,6 @@ protected:
QSet<QFontEngine *> m_fontEnginesToClean;
};
-
-class Q_QUICK_PRIVATE_EXPORT QSGContext : public QObject
-{
- Q_OBJECT
-
-public:
- enum AntialiasingMethod {
- UndecidedAntialiasing,
- VertexAntialiasing,
- MsaaAntialiasing
- };
-
- explicit QSGContext(QObject *parent = 0);
- virtual ~QSGContext();
-
- virtual void renderContextInitialized(QSGRenderContext *renderContext);
- virtual void renderContextInvalidated(QSGRenderContext *renderContext);
- virtual QSGRenderContext *createRenderContext() = 0;
-
- QSGInternalRectangleNode *createInternalRectangleNode(const QRectF &rect, const QColor &c);
- virtual QSGInternalRectangleNode *createInternalRectangleNode() = 0;
- virtual QSGInternalImageNode *createInternalImageNode() = 0;
- virtual QSGPainterNode *createPainterNode(QQuickPaintedItem *item) = 0;
- virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc, bool preferNativeGlyphNode) = 0;
- virtual QSGLayer *createLayer(QSGRenderContext *renderContext) = 0;
- virtual QSGGuiThreadShaderEffectManager *createGuiThreadShaderEffectManager();
- virtual QSGShaderEffectNode *createShaderEffectNode(QSGRenderContext *renderContext,
- QSGGuiThreadShaderEffectManager *mgr);
-#if QT_CONFIG(quick_sprite)
- virtual QSGSpriteNode *createSpriteNode() = 0;
-#endif
- virtual QAnimationDriver *createAnimationDriver(QObject *parent);
-
- virtual QSize minimumFBOSize() const;
- virtual QSurfaceFormat defaultSurfaceFormat() const = 0;
-
- virtual QSGRendererInterface *rendererInterface(QSGRenderContext *renderContext);
-
- virtual QSGRectangleNode *createRectangleNode() = 0;
- virtual QSGImageNode *createImageNode() = 0;
- virtual QSGNinePatchNode *createNinePatchNode() = 0;
-
- static QSGContext *createDefaultContext();
- static QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image);
- static QSGRenderLoop *createWindowManager();
-
- static void setBackend(const QString &backend);
-};
-
QT_END_NAMESPACE
#endif // QSGCONTEXT_H
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index edf4aa08c5..38c3b8dd85 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -1,4 +1,4 @@
-# DEFINES += QSG_SEPARATE_INDEX_BUFFER
+DEFINES += QSG_SEPARATE_INDEX_BUFFER
# DEFINES += QSG_DISTANCEFIELD_CACHE_DEBUG
# Core API
diff --git a/src/quick/scenegraph/util/qsgdefaultimagenode.cpp b/src/quick/scenegraph/util/qsgdefaultimagenode.cpp
index 63773887a0..7186ee4265 100644
--- a/src/quick/scenegraph/util/qsgdefaultimagenode.cpp
+++ b/src/quick/scenegraph/util/qsgdefaultimagenode.cpp
@@ -94,6 +94,21 @@ QSGTexture::Filtering QSGDefaultImageNode::mipmapFiltering() const
return m_material.mipmapFiltering();
}
+void QSGDefaultImageNode::setAnisotropyLevel(QSGTexture::AnisotropyLevel level)
+{
+ if (m_material.anisotropyLevel() == level)
+ return;
+
+ m_material.setAnisotropyLevel(level);
+ m_opaque_material.setAnisotropyLevel(level);
+ markDirty(DirtyMaterial);
+}
+
+QSGTexture::AnisotropyLevel QSGDefaultImageNode::anisotropyLevel() const
+{
+ return m_material.anisotropyLevel();
+}
+
void QSGDefaultImageNode::setRect(const QRectF &r)
{
if (m_rect == r)
diff --git a/src/quick/scenegraph/util/qsgdefaultimagenode_p.h b/src/quick/scenegraph/util/qsgdefaultimagenode_p.h
index bb9ebec885..cb23e759d3 100644
--- a/src/quick/scenegraph/util/qsgdefaultimagenode_p.h
+++ b/src/quick/scenegraph/util/qsgdefaultimagenode_p.h
@@ -85,6 +85,10 @@ public:
void setOwnsTexture(bool owns) override;
bool ownsTexture() const override;
+ // QSGImageNode now being a public class does not allow any additional virtual methods. Placing these here, non-virtual.
+ void setAnisotropyLevel(QSGTexture::AnisotropyLevel level);
+ QSGTexture::AnisotropyLevel anisotropyLevel() const;
+
private:
QSGGeometry m_geometry;
QSGOpaqueTextureMaterial m_opaque_material;
diff --git a/src/quick/scenegraph/util/qsgimagenode.h b/src/quick/scenegraph/util/qsgimagenode.h
index d25e732e4b..0e053c307f 100644
--- a/src/quick/scenegraph/util/qsgimagenode.h
+++ b/src/quick/scenegraph/util/qsgimagenode.h
@@ -67,6 +67,8 @@ public:
virtual void setMipmapFiltering(QSGTexture::Filtering filtering) = 0;
virtual QSGTexture::Filtering mipmapFiltering() const = 0;
+ // ### Qt6: Add anisotropy support here, and possibly a virtual hook or another mean to extend this class.
+
enum TextureCoordinatesTransformFlag {
NoTransform = 0x00,
MirrorHorizontally = 0x01,
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index 47248f2f37..bc59c49162 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -83,6 +83,9 @@ static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK"
#define GL_BGRA 0x80E1
#endif
+#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#endif
QT_BEGIN_NAMESPACE
@@ -97,10 +100,12 @@ inline static bool isPowerOfTwo(int x)
QSGTexturePrivate::QSGTexturePrivate()
: wrapChanged(false)
, filteringChanged(false)
+ , anisotropyChanged(false)
, horizontalWrap(QSGTexture::ClampToEdge)
, verticalWrap(QSGTexture::ClampToEdge)
, mipmapMode(QSGTexture::None)
, filterMode(QSGTexture::Nearest)
+ , anisotropyLevel(QSGTexture::AnisotropyNone)
{
}
@@ -274,6 +279,23 @@ static void qt_debug_remove_texture(QSGTexture* texture)
*/
/*!
+ \enum QSGTexture::AnisotropyLevel
+
+ Specifies the anisotropic filtering level to be used when
+ the texture is not screen aligned.
+
+ \value AnisotropyNone No anisotropic filtering.
+
+ \value Anisotropy2x 2x anisotropic filtering.
+
+ \value Anisotropy4x 4x anisotropic filtering.
+
+ \value Anisotropy8x 8x anisotropic filtering.
+
+ \value Anisotropy16x 16x anisotropic filtering.
+*/
+
+/*!
\fn QSGTexture::QSGTexture(QSGTexturePrivate &dd)
\internal
*/
@@ -472,6 +494,31 @@ QSGTexture::Filtering QSGTexture::filtering() const
return (QSGTexture::Filtering) d_func()->filterMode;
}
+/*!
+ Sets the level of anisotropic filtering to be used for the upcoming bind() call to \a level.
+ The default value is QSGTexture::AnisotropyNone, which means no anisotropic filtering is enabled.
+
+ \since 5.9
+ */
+void QSGTexture::setAnisotropyLevel(AnisotropyLevel level)
+{
+ Q_D(QSGTexture);
+ if (d->anisotropyLevel != (uint) level) {
+ d->anisotropyLevel = level;
+ d->anisotropyChanged = true;
+ }
+}
+
+/*!
+ Returns the anisotropy level in use for filtering this texture.
+
+ \since 5.9
+ */
+QSGTexture::AnisotropyLevel QSGTexture::anisotropyLevel() const
+{
+ return (QSGTexture::AnisotropyLevel) d_func()->anisotropyLevel;
+}
+
/*!
@@ -548,6 +595,12 @@ void QSGTexture::updateBindOptions(bool force)
d->filteringChanged = false;
}
+ if (force || d->anisotropyChanged) {
+ d->anisotropyChanged = false;
+ if (QOpenGLContext::currentContext()->hasExtension(QByteArrayLiteral("GL_EXT_texture_filter_anisotropic")))
+ funcs->glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, float(1 << (d->anisotropyLevel)));
+ }
+
if (force || d->wrapChanged) {
#ifndef QT_NO_DEBUG
if (d->horizontalWrap == Repeat || d->verticalWrap == Repeat) {
diff --git a/src/quick/scenegraph/util/qsgtexture.h b/src/quick/scenegraph/util/qsgtexture.h
index f0509b58ae..035acc02b1 100644
--- a/src/quick/scenegraph/util/qsgtexture.h
+++ b/src/quick/scenegraph/util/qsgtexture.h
@@ -67,6 +67,14 @@ public:
Linear
};
+ enum AnisotropyLevel {
+ AnisotropyNone,
+ Anisotropy2x,
+ Anisotropy4x,
+ Anisotropy8x,
+ Anisotropy16x
+ };
+
virtual int textureId() const = 0;
virtual QSize textureSize() const = 0;
virtual bool hasAlphaChannel() const = 0;
@@ -87,6 +95,9 @@ public:
void setFiltering(Filtering filter);
QSGTexture::Filtering filtering() const;
+ void setAnisotropyLevel(AnisotropyLevel level);
+ QSGTexture::AnisotropyLevel anisotropyLevel() const;
+
void setHorizontalWrapMode(WrapMode hwrap);
QSGTexture::WrapMode horizontalWrapMode() const;
diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgtexture_p.h
index b6fcfc31c4..36f9b802ba 100644
--- a/src/quick/scenegraph/util/qsgtexture_p.h
+++ b/src/quick/scenegraph/util/qsgtexture_p.h
@@ -69,11 +69,13 @@ public:
uint wrapChanged : 1;
uint filteringChanged : 1;
+ uint anisotropyChanged : 1;
uint horizontalWrap : 1;
uint verticalWrap : 1;
uint mipmapMode : 2;
uint filterMode : 2;
+ uint anisotropyLevel: 3;
};
class Q_QUICK_PRIVATE_EXPORT QSGPlainTexture : public QSGTexture
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp
index 9326ea640d..c536445e82 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.cpp
+++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp
@@ -110,6 +110,7 @@ void QSGOpaqueTextureMaterialShader::updateState(const RenderState &state, QSGMa
Q_UNUSED(state)
#endif
t->setMipmapFiltering(tx->mipmapFiltering());
+ t->setAnisotropyLevel(tx->anisotropyLevel());
if (oldTx == 0 || oldTx->texture()->textureId() != t->textureId())
t->bind();
@@ -173,6 +174,7 @@ QSGOpaqueTextureMaterial::QSGOpaqueTextureMaterial()
, m_mipmap_filtering(QSGTexture::None)
, m_horizontal_wrap(QSGTexture::ClampToEdge)
, m_vertical_wrap(QSGTexture::ClampToEdge)
+ , m_anisotropy_level(QSGTexture::AnisotropyNone)
{
}
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.h b/src/quick/scenegraph/util/qsgtexturematerial.h
index dc87131773..87d8e5fd49 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.h
+++ b/src/quick/scenegraph/util/qsgtexturematerial.h
@@ -69,6 +69,9 @@ public:
void setVerticalWrapMode(QSGTexture::WrapMode mode) { m_vertical_wrap = mode; }
QSGTexture::WrapMode verticalWrapMode() const { return QSGTexture::WrapMode(m_vertical_wrap); }
+ void setAnisotropyLevel(QSGTexture::AnisotropyLevel level) { m_anisotropy_level = level; }
+ QSGTexture::AnisotropyLevel anisotropyLevel() const { return QSGTexture::AnisotropyLevel(m_anisotropy_level); }
+
protected:
QSGTexture *m_texture;
@@ -76,8 +79,8 @@ protected:
uint m_mipmap_filtering: 2;
uint m_horizontal_wrap : 1;
uint m_vertical_wrap: 1;
-
- uint m_reserved : 26;
+ uint m_anisotropy_level : 3;
+ uint m_reserved : 23;
};
diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp
index 1c6b2afb54..be6d4d18bd 100644
--- a/src/quick/util/qquickpixmapcache.cpp
+++ b/src/quick/util/qquickpixmapcache.cpp
@@ -84,6 +84,7 @@
QT_BEGIN_NAMESPACE
+const QLatin1String QQuickPixmap::itemGrabberScheme = QLatin1String("itemgrabber");
#ifndef QT_NO_DEBUG
static const bool qsg_leak_check = !qEnvironmentVariableIsEmpty("QML_LEAK_CHECK");
@@ -1462,8 +1463,15 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques
QHash<QQuickPixmapKey, QQuickPixmapData *>::Iterator iter = store->m_cache.end();
// If Cache is disabled, the pixmap will always be loaded, even if there is an existing
- // cached version.
- if (options & QQuickPixmap::Cache)
+ // cached version. Unless it's an itemgrabber url, since the cache is used to pass
+ // the result between QQuickItemGrabResult and QQuickImage.
+ if (url.scheme() == itemGrabberScheme) {
+ QSize dummy;
+ if (requestSize != dummy)
+ qWarning() << "Ignoring sourceSize request for image url that came from grabToImage. Use the targetSize parameter of the grabToImage() function instead.";
+ const QQuickPixmapKey grabberKey = { &url, &dummy, QQuickImageProviderOptions() };
+ iter = store->m_cache.find(grabberKey);
+ } else if (options & QQuickPixmap::Cache)
iter = store->m_cache.find(key);
if (iter == store->m_cache.end()) {
diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h
index f7cdfa7d07..a867771755 100644
--- a/src/quick/util/qquickpixmapcache_p.h
+++ b/src/quick/util/qquickpixmapcache_p.h
@@ -177,6 +177,8 @@ public:
static void purgeCache();
static bool isCached(const QUrl &url, const QSize &requestSize);
+ static const QLatin1String itemGrabberScheme;
+
private:
Q_DISABLE_COPY(QQuickPixmap)
QQuickPixmapData *d;
diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp
index 77dae0d001..b2e5b84cf4 100644
--- a/src/quick/util/qquickutilmodule.cpp
+++ b/src/quick/util/qquickutilmodule.cpp
@@ -54,7 +54,9 @@
#include "qquicktextmetrics_p.h"
#include "qquicktransition_p.h"
#include "qquickanimator_p.h"
+#if QT_CONFIG(shortcut)
#include "qquickshortcut_p.h"
+#endif
#include "qquickvalidator_p.h"
#include <qqmlinfo.h>
#include <private/qqmltypenotavailable_p.h>
@@ -63,7 +65,9 @@
#include <QtGui/QInputMethod>
#include <QtGui/QKeySequence>
+#if QT_CONFIG(shortcut)
Q_DECLARE_METATYPE(QKeySequence::StandardKey)
+#endif
void QQuickUtilModule::defineModule()
{
@@ -114,15 +118,18 @@ void QQuickUtilModule::defineModule()
qmlRegisterCustomType<QQuickPropertyChanges>("QtQuick",2,0,"PropertyChanges", new QQuickPropertyChangesParser);
+#if QT_CONFIG(shortcut)
qRegisterMetaType<QKeySequence::StandardKey>();
qmlRegisterUncreatableType<QKeySequence, 2>("QtQuick", 2, 2, "StandardKey", QStringLiteral("Cannot create an instance of StandardKey."));
+#endif
qmlRegisterType<QQuickFontMetrics>("QtQuick", 2, 4, "FontMetrics");
qmlRegisterType<QQuickTextMetrics>("QtQuick", 2, 4, "TextMetrics");
+#if QT_CONFIG(shortcut)
qmlRegisterType<QQuickShortcut>("QtQuick", 2, 5, "Shortcut");
-
qmlRegisterType<QQuickShortcut,1>("QtQuick", 2, 6, "Shortcut");
qmlRegisterType<QQuickShortcut,9>("QtQuick", 2, 9, "Shortcut");
+#endif
}
diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri
index 1ef1018a31..b53b132cce 100644
--- a/src/quick/util/util.pri
+++ b/src/quick/util/util.pri
@@ -26,7 +26,6 @@ SOURCES += \
$$PWD/qquickanimatorcontroller.cpp \
$$PWD/qquickfontmetrics.cpp \
$$PWD/qquicktextmetrics.cpp \
- $$PWD/qquickshortcut.cpp \
$$PWD/qquickvalidator.cpp
!contains(QT_CONFIG, no-qml-debug): SOURCES += $$PWD/qquickprofiler.cpp
@@ -63,9 +62,15 @@ HEADERS += \
$$PWD/qquickprofiler_p.h \
$$PWD/qquickfontmetrics_p.h \
$$PWD/qquicktextmetrics_p.h \
- $$PWD/qquickshortcut_p.h \
$$PWD/qquickvalidator_p.h
+qtConfig(shortcut) {
+ SOURCES += \
+ $$PWD/qquickshortcut.cpp
+ HEADERS += \
+ $$PWD/qquickshortcut_p.h
+}
+
qtConfig(quick-path) {
SOURCES += \
$$PWD/qquickpath.cpp \
diff --git a/src/src.pro b/src/src.pro
index f585ef15ca..c2a58c3757 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -1,7 +1,7 @@
TEMPLATE = subdirs
CONFIG += ordered
include($$OUT_PWD/quick/qtquick-config.pri)
-QT_FOR_CONFIG += quick-private
+QT_FOR_CONFIG += network quick-private
SUBDIRS += \
qml
@@ -20,6 +20,4 @@ SUBDIRS += \
imports \
qmldevtools
-!contains(QT_CONFIG, no-qml-debug): SUBDIRS += qmldebug
-
-qmldevtools.CONFIG = host_build
+qtConfig(localserver):!contains(QT_CONFIG, no-qml-debug): SUBDIRS += qmldebug
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index f25742fb14..1e80f1bf65 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -18,6 +18,4 @@ qtHaveModule(gui):qtConfig(opengl(es1|es2)?) {
# console applications not supported
uikit: SUBDIRS -= qmltest
-qmldevtools.CONFIG = host_build
-
installed_cmake.depends = cmake
diff --git a/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp b/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
index 1791407934..ff295c5409 100644
--- a/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
+++ b/tests/auto/qml/animation/qpauseanimationjob/tst_qpauseanimationjob.cpp
@@ -392,8 +392,10 @@ void tst_QPauseAnimationJob::multipleSequentialGroups()
#ifdef Q_OS_WIN
if (group.state() != QAbstractAnimationJob::Stopped)
QEXPECT_FAIL("", winTimerError, Abort);
-#endif
+ QCOMPARE(group.state(), QAbstractAnimationJob::Stopped);
+#else
QTRY_COMPARE(group.state(), QAbstractAnimationJob::Stopped);
+#endif
#ifdef Q_OS_WIN
if (subgroup1.state() != QAbstractAnimationJob::Stopped)
diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro
index 68a2eace19..04e4b04114 100644
--- a/tests/auto/qml/qml.pro
+++ b/tests/auto/qml/qml.pro
@@ -73,7 +73,7 @@ qtHaveModule(widgets) {
SUBDIRS += $$PUBLICTESTS \
qqmlextensionplugin
SUBDIRS += $$METATYPETESTS
-!uikit:!winrt { # no QProcess on uikit/winrt
+!qtConfig(process) {
!contains(QT_CONFIG, no-qml-debug): SUBDIRS += debugger
SUBDIRS += qmllint qmlplugindump
}
diff --git a/tests/auto/qml/qqmlecmascript/data/signalParameterTypes.qml b/tests/auto/qml/qqmlecmascript/data/signalParameterTypes.qml
index 676593096c..54d29dfc94 100644
--- a/tests/auto/qml/qqmlecmascript/data/signalParameterTypes.qml
+++ b/tests/auto/qml/qqmlecmascript/data/signalParameterTypes.qml
@@ -16,5 +16,11 @@ MyQmlObject
onBasicSignal: root.mySignal(10, 19.2, Qt.rgba(1, 1, 0, 1), Qt.rgba(1, 0, 1, 1), MyQmlObject.EnumValue3, Qt.LeftButton)
- onQjsValueEmittingSignal: {}
+ property bool emittedQjsValueWasUndefined
+ property int emittedQjsValueAsInt
+
+ onQjsValueEmittingSignal: {
+ emittedQjsValueWasUndefined = value === undefined;
+ emittedQjsValueAsInt = value
+ }
}
diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
index 8c0b0601fc..89dac33671 100644
--- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
+++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp
@@ -1412,7 +1412,6 @@ void tst_qqmlecmascript::signalParameterTypes()
QVERIFY(object != 0);
emit object->basicSignal();
- emit object->qjsValueEmittingSignal(QJSValue());
QCOMPARE(object->property("intProperty").toInt(), 10);
QCOMPARE(object->property("realProperty").toReal(), 19.2);
@@ -1421,6 +1420,12 @@ void tst_qqmlecmascript::signalParameterTypes()
QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
+ emit object->qjsValueEmittingSignal(QJSValue());
+ QVERIFY(object->property("emittedQjsValueWasUndefined").toBool());
+ emit object->qjsValueEmittingSignal(QJSValue(42));
+ QVERIFY(!object->property("emittedQjsValueWasUndefined").toBool());
+ QCOMPARE(object->property("emittedQjsValueAsInt").value<int>(), 42);
+
delete object;
}
diff --git a/tests/auto/qml/qqmllanguage/data/compositeTypeByName_anon_qmldir.qml b/tests/auto/qml/qqmllanguage/data/compositeTypeByName_anon_qmldir.qml
new file mode 100644
index 0000000000..5ffdc26096
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/compositeTypeByName_anon_qmldir.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.6
+import "simpleimportByName"
+
+Item {
+ Component.onCompleted: {
+ console.warn(SimpleType)
+ }
+}
+
diff --git a/tests/auto/qml/qqmllanguage/data/compositeTypeByName_named_qmldir.qml b/tests/auto/qml/qqmllanguage/data/compositeTypeByName_named_qmldir.qml
new file mode 100644
index 0000000000..c446eae84c
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/compositeTypeByName_named_qmldir.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.6
+import "simpleimportByName" as ImportName
+
+Item {
+ Component.onCompleted: {
+ console.warn(ImportName.SimpleType)
+ }
+}
+
diff --git a/tests/auto/qml/qqmllanguage/data/quickTypeByName_anon.qml b/tests/auto/qml/qqmllanguage/data/quickTypeByName_anon.qml
new file mode 100644
index 0000000000..abe750db33
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/quickTypeByName_anon.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.6
+
+Item {
+ Component.onCompleted: {
+ console.warn(Item)
+ }
+}
+
diff --git a/tests/auto/qml/qqmllanguage/data/quickTypeByName_named.qml b/tests/auto/qml/qqmllanguage/data/quickTypeByName_named.qml
new file mode 100644
index 0000000000..397d4f42f0
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/quickTypeByName_named.qml
@@ -0,0 +1,8 @@
+import QtQuick 2.6 as Quick
+
+Quick.Item {
+ Quick.Component.onCompleted: {
+ console.warn(Quick.Item)
+ }
+}
+
diff --git a/tests/auto/qml/qqmllanguage/data/simpleimportByName/SimpleType.qml b/tests/auto/qml/qqmllanguage/data/simpleimportByName/SimpleType.qml
new file mode 100644
index 0000000000..4772dde8f0
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/simpleimportByName/SimpleType.qml
@@ -0,0 +1,4 @@
+import QtQuick 2.6
+
+MouseArea {
+}
diff --git a/tests/auto/qml/qqmllanguage/data/simpleimportByName/qmldir b/tests/auto/qml/qqmllanguage/data/simpleimportByName/qmldir
new file mode 100644
index 0000000000..80df37d0e6
--- /dev/null
+++ b/tests/auto/qml/qqmllanguage/data/simpleimportByName/qmldir
@@ -0,0 +1 @@
+SimpleType 1.0 SimpleType.qml
diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
index f586f7d429..c0500afddd 100644
--- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
+++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp
@@ -257,6 +257,9 @@ private slots:
void defaultListProperty();
void namespacedPropertyTypes();
+ void qmlTypeCanBeResolvedByName_data();
+ void qmlTypeCanBeResolvedByName();
+
private:
QQmlEngine engine;
QStringList defaultImportPathList;
@@ -4250,6 +4253,32 @@ void tst_qqmllanguage::namespacedPropertyTypes()
QVERIFY(!o.isNull());
}
+void tst_qqmllanguage::qmlTypeCanBeResolvedByName_data()
+{
+ QTest::addColumn<QUrl>("componentUrl");
+
+ // Built-in C++ types
+ QTest::newRow("C++ - Anonymous") << testFileUrl("quickTypeByName_anon.qml");
+ QTest::newRow("C++ - Named") << testFileUrl("quickTypeByName_named.qml");
+
+ // Composite types with a qmldir
+ QTest::newRow("QML - Anonymous - qmldir") << testFileUrl("compositeTypeByName_anon_qmldir.qml");
+ QTest::newRow("QML - Named - qmldir") << testFileUrl("compositeTypeByName_named_qmldir.qml");
+}
+
+void tst_qqmllanguage::qmlTypeCanBeResolvedByName()
+{
+ QFETCH(QUrl, componentUrl);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine, componentUrl);
+ VERIFY_ERRORS(0);
+ QTest::ignoreMessage(QtMsgType::QtWarningMsg, "[object Object]"); // a bit crude, but it will do
+
+ QScopedPointer<QObject> o(component.create());
+ QVERIFY(!o.isNull());
+}
+
QTEST_MAIN(tst_qqmllanguage)
#include "tst_qqmllanguage.moc"
diff --git a/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml b/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml
index 022e98a202..a80814d6de 100644
--- a/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml
+++ b/tests/auto/qmltest/itemgrabber/tst_itemgrabber.qml
@@ -37,8 +37,9 @@ Item {
TestCase {
id: testCase
name: "item-grabber"
- when: imageOnDisk.ready && imageOnDiskSmall.ready && imageInCache.ready && imageInCacheSmall.ready
- function test_endresult() {
+ when: imageOnDisk.ready && imageOnDiskSmall.ready
+
+ function test_endresult_disk() {
var image = grabImage(root);
// imageOnDisk at (0, 0) - (100x100)
@@ -52,6 +53,40 @@ Item {
compare(imageOnDiskSmall.height, 50);
verify(image.pixel(100, 0) === Qt.rgba(1, 0, 0, 1));
verify(image.pixel(149, 49) === Qt.rgba(0, 0, 1, 1));
+ }
+
+ function test_endresult_cache_data() {
+ return [
+ { cache: true, sourceSize: Qt.size(-1, -1), fillMode: Image.Stretch },
+ { cache: true, sourceSize: Qt.size(-1, -1), fillMode: Image.PreserveAspectFit },
+ { cache: true, sourceSize: Qt.size(-1, -1), fillMode: Image.PreserveAspectCrop },
+ { cache: true, sourceSize: Qt.size(10, 10), fillMode: Image.Stretch },
+ { cache: true, sourceSize: Qt.size(10, 10), fillMode: Image.PreserveAspectFit },
+ { cache: true, sourceSize: Qt.size(10, 10), fillMode: Image.PreserveAspectCrop },
+ { cache: false, sourceSize: Qt.size(-1, -1), fillMode: Image.Stretch },
+ { cache: false, sourceSize: Qt.size(-1, -1), fillMode: Image.PreserveAspectFit },
+ { cache: false, sourceSize: Qt.size(-1, -1), fillMode: Image.PreserveAspectCrop },
+ { cache: false, sourceSize: Qt.size(10, 10), fillMode: Image.Stretch },
+ { cache: false, sourceSize: Qt.size(10, 10), fillMode: Image.PreserveAspectFit },
+ { cache: false, sourceSize: Qt.size(10, 10), fillMode: Image.PreserveAspectCrop },
+ ];
+ }
+
+ function test_endresult_cache(data) {
+ imageInCache.cache = data.cache;
+ imageInCache.sourceSize = data.sourceSize;
+ imageInCache.fillMode = data.fillMode;
+ imageInCacheSmall.cache = data.cache;
+ imageInCacheSmall.sourceSize = data.sourceSize;
+ imageInCacheSmall.fillMode = data.fillMode;
+
+ box.grabToImage(imageInCache.handleGrab);
+ box.grabToImage(imageInCacheSmall.handleGrab, Qt.size(50, 50));
+
+ tryCompare(imageInCache, "ready", true);
+ tryCompare(imageInCacheSmall, "ready", true);
+
+ var image = grabImage(root);
// imageInCache at (0, 100) - 100x100
compare(imageInCache.width, 100);
@@ -72,8 +107,6 @@ Item {
onWindowShownChanged: {
box.grabToImage(imageOnDisk.handleGrab);
box.grabToImage(imageOnDiskSmall.handleGrab, Qt.size(50, 50));
- box.grabToImage(imageInCache.handleGrab);
- box.grabToImage(imageInCacheSmall.handleGrab, Qt.size(50, 50));
}
}
diff --git a/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml b/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml
new file mode 100644
index 0000000000..8234ac6ef7
--- /dev/null
+++ b/tests/auto/quick/qquicklayouts/data/tst_stacklayout.qml
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, 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 The Qt Company Ltd 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 QtTest 1.0
+import QtQuick.Layouts 1.3
+
+Item {
+ id: container
+ width: 200
+ height: 200
+ TestCase {
+ id: testCase
+ name: "Tests_StackLayout"
+ when: windowShown
+ width: 200
+ height: 200
+
+ Component {
+ id: layout_rearrange_Component
+
+ StackLayout {
+ width: 640
+ height: 480
+
+ property alias testRectangle: testRectangle
+
+ RowLayout {
+ spacing: 0
+
+ Rectangle {
+ Layout.preferredWidth: 100
+ Layout.preferredHeight: 100
+ }
+
+ Rectangle {
+ id: testRectangle
+ Layout.preferredWidth: 100
+ Layout.preferredHeight: 100
+ visible: false
+ }
+
+ Item {
+ Layout.fillWidth: true
+ }
+ }
+ }
+ }
+
+ function test_rearrange()
+ {
+ var layout = layout_rearrange_Component.createObject(container)
+ compare(layout.testRectangle.x, 0)
+ layout.testRectangle.visible = true
+ tryCompare(layout.testRectangle, "x", 100)
+
+ layout.destroy()
+ }
+ }
+}
diff --git a/tests/auto/quick/qquicklayouts/qquicklayouts.pro b/tests/auto/quick/qquicklayouts/qquicklayouts.pro
index 9ed3e076be..5079d0a182 100644
--- a/tests/auto/quick/qquicklayouts/qquicklayouts.pro
+++ b/tests/auto/quick/qquicklayouts/qquicklayouts.pro
@@ -9,5 +9,6 @@ TESTDATA = data/*
OTHER_FILES += \
data/tst_rowlayout.qml \
- data/tst_gridlayout.qml
+ data/tst_gridlayout.qml \
+ data/tst_stacklayout.qml
diff --git a/tests/auto/quick/qquickloader/tst_qquickloader.cpp b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
index 77af4796b6..3e7439f3e9 100644
--- a/tests/auto/quick/qquickloader/tst_qquickloader.cpp
+++ b/tests/auto/quick/qquickloader/tst_qquickloader.cpp
@@ -469,7 +469,7 @@ void tst_QQuickLoader::networkComponent()
// because in the synchronous case we're already done loading.
QTRY_COMPARE(component.status(), QQmlComponent::Ready);
- QQuickItem *item = qobject_cast<QQuickItem*>(component.create());
+ QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(component.create()));
QVERIFY(item);
QQuickLoader *loader = qobject_cast<QQuickLoader*>(item->children().at(1));
@@ -481,7 +481,6 @@ void tst_QQuickLoader::networkComponent()
QCOMPARE(loader->status(), QQuickLoader::Ready);
QCOMPARE(static_cast<QQuickItem*>(loader)->children().count(), 1);
- delete loader;
}
void tst_QQuickLoader::failNetworkRequest()
diff --git a/tests/auto/quick/qquicktext/data/fontInfo.qml b/tests/auto/quick/qquicktext/data/fontInfo.qml
new file mode 100644
index 0000000000..25f924029f
--- /dev/null
+++ b/tests/auto/quick/qquicktext/data/fontInfo.qml
@@ -0,0 +1,24 @@
+import QtQuick 2.9
+
+Item {
+ Text {
+ id: main
+ objectName: "main"
+ width: 500
+ height: 500
+ text: "Meaningless text"
+ font.pixelSize: 1000
+ fontSizeMode: Text.Fit
+ }
+
+ Text {
+ objectName: "copy"
+ text: main.text
+ width: main.width
+ height: main.height
+
+ font.family: main.fontInfo.family
+ font.pixelSize: main.fontInfo.pixelSize
+ }
+}
+
diff --git a/tests/auto/quick/qquicktext/tst_qquicktext.cpp b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
index 034ea4aec8..f741062d42 100644
--- a/tests/auto/quick/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/quick/qquicktext/tst_qquicktext.cpp
@@ -154,6 +154,8 @@ private slots:
void hAlignWidthDependsOnImplicitWidth_data();
void hAlignWidthDependsOnImplicitWidth();
+ void fontInfo();
+
private:
QStringList standard;
QStringList richText;
@@ -4253,6 +4255,23 @@ void tst_qquicktext::hAlignWidthDependsOnImplicitWidth()
QCOMPARE(numberOfNonWhitePixels(0, rectX - 1, image), 0);
}
+void tst_qquicktext::fontInfo()
+{
+ QQmlComponent component(&engine, testFile("fontInfo.qml"));
+
+ QScopedPointer<QObject> object(component.create());
+ QObject *root = object.data();
+
+ QQuickText *main = root->findChild<QQuickText *>("main");
+ QVERIFY(main);
+ QCOMPARE(main->font().pixelSize(), 1000);
+
+ QQuickText *copy = root->findChild<QQuickText *>("copy");
+ QVERIFY(copy);
+ QCOMPARE(copy->font().family(), QFontInfo(QFont()).family());
+ QVERIFY(copy->font().pixelSize() < 1000);
+}
+
QTEST_MAIN(tst_qquicktext)
#include "tst_qquicktext.moc"
diff --git a/tools/qmlcachegen/qmlcache.prf b/tools/qmlcachegen/qmlcache.prf
new file mode 100644
index 0000000000..fed9f0d2f3
--- /dev/null
+++ b/tools/qmlcachegen/qmlcache.prf
@@ -0,0 +1,12 @@
+qtPrepareTool(QML_CACHEGEN, qmlcachegen)
+
+!isEmpty(QT_TARGET_ARCH):QML_CACHEGEN_ARCH=$$QT_TARGET_ARCH
+else:QML_CACHEGEN_ARCH=$$QT_ARCH
+
+qmlcachegen.input = QML_FILES
+qmlcachegen.output = ${QMAKE_FILE_IN}c
+qmlcachegen.commands = $$QML_CACHEGEN --target-architecture=$$QML_CACHEGEN_ARCH ${QMAKE_FILE_IN}
+qmlcachegen.name = Generate QML Cache ${QMAKE_FILE_IN}
+qmlcachegen.variable_out = AUX_QML_FILES
+
+QMAKE_EXTRA_COMPILERS += qmlcachegen
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
new file mode 100644
index 0000000000..4b902eda0f
--- /dev/null
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -0,0 +1,309 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QCoreApplication>
+#include <QStringList>
+#include <QCommandLineParser>
+#include <QFile>
+#include <QFileInfo>
+#include <QDateTime>
+
+#include <private/qqmlirbuilder_p.h>
+#include <private/qv4isel_moth_p.h>
+#include <private/qqmljsparser_p.h>
+
+QT_BEGIN_NAMESPACE
+extern Q_CORE_EXPORT QBasicAtomicInt qt_qhash_seed;
+
+namespace QV4 { namespace JIT {
+Q_QML_EXPORT QV4::EvalISelFactory *createISelForArchitecture(const QString &architecture);
+} }
+
+QT_END_NAMESPACE
+
+struct Error
+{
+ QString message;
+ void print();
+ Error augment(const QString &contextErrorMessage) const;
+};
+
+void Error::print()
+{
+ fprintf(stderr, "%s\n", qPrintable(message));
+}
+
+Error Error::augment(const QString &contextErrorMessage) const
+{
+ Error augmented;
+ augmented.message = contextErrorMessage + message;
+ return augmented;
+}
+
+QString diagnosticErrorMessage(const QString &fileName, const QQmlJS::DiagnosticMessage &m)
+{
+ QString message;
+ message = fileName + QLatin1Char(':') + QString::number(m.loc.startLine) + QLatin1Char(':');
+ if (m.loc.startColumn > 0)
+ message += QString::number(m.loc.startColumn) + QLatin1Char(':');
+
+ if (m.isError())
+ message += QLatin1String(" error: ");
+ else
+ message += QLatin1String(" warning: ");
+ message += m.message;
+ return message;
+}
+
+static bool compileQmlFile(const QString &inputFileName, QV4::EvalISelFactory *iselFactory, Error *error)
+{
+ QmlIR::Document irDocument(/*debugMode*/false);
+
+ QString sourceCode;
+ {
+ QFile f(inputFileName);
+ if (!f.open(QIODevice::ReadOnly)) {
+ error->message = QLatin1String("Error opening ") + inputFileName + QLatin1Char(':') + f.errorString();
+ return false;
+ }
+ sourceCode = QString::fromUtf8(f.readAll());
+ if (f.error() != QFileDevice::NoError) {
+ error->message = QLatin1String("Error reading from ") + inputFileName + QLatin1Char(':') + f.errorString();
+ return false;
+ }
+ irDocument.jsModule.sourceTimeStamp = QFileInfo(f).lastModified().toMSecsSinceEpoch();
+ }
+
+ {
+ QSet<QString> illegalNames; // ####
+ QmlIR::IRBuilder irBuilder(illegalNames);
+ if (!irBuilder.generateFromQml(sourceCode, inputFileName, &irDocument)) {
+ for (const QQmlJS::DiagnosticMessage &parseError: qAsConst(irBuilder.errors)) {
+ if (!error->message.isEmpty())
+ error->message += QLatin1Char('\n');
+ error->message += diagnosticErrorMessage(inputFileName, parseError);
+ }
+ return false;
+ }
+ }
+
+ {
+ QmlIR::JSCodeGen v4CodeGen(inputFileName, irDocument.code, &irDocument.jsModule, &irDocument.jsParserEngine, irDocument.program, /*import cache*/0, &irDocument.jsGenerator.stringTable);
+ for (QmlIR::Object *object: qAsConst(irDocument.objects)) {
+ if (object->functionsAndExpressions->count == 0)
+ continue;
+ QList<QmlIR::CompiledFunctionOrExpression> functionsToCompile;
+ for (QmlIR::CompiledFunctionOrExpression *foe = object->functionsAndExpressions->first; foe; foe = foe->next) {
+ foe->disableAcceleratedLookups = true;
+ functionsToCompile << *foe;
+ }
+ const QVector<int> runtimeFunctionIndices = v4CodeGen.generateJSCodeForFunctionsAndBindings(functionsToCompile);
+ QList<QQmlJS::DiagnosticMessage> jsErrors = v4CodeGen.errors();
+ if (!jsErrors.isEmpty()) {
+ for (const QQmlJS::DiagnosticMessage &e: qAsConst(jsErrors)) {
+ if (!error->message.isEmpty())
+ error->message += QLatin1Char('\n');
+ error->message += diagnosticErrorMessage(inputFileName, e);
+ }
+ return false;
+ }
+
+ QQmlJS::MemoryPool *pool = irDocument.jsParserEngine.pool();
+ object->runtimeFunctionIndices.allocate(pool, runtimeFunctionIndices);
+ }
+
+ QmlIR::QmlUnitGenerator generator;
+
+ // ### translation binding simplification
+
+ QScopedPointer<QV4::EvalInstructionSelection> isel(iselFactory->create(/*engine*/nullptr, /*executable allocator*/nullptr, &irDocument.jsModule, &irDocument.jsGenerator));
+ // Disable lookups in non-standalone (aka QML) mode
+ isel->setUseFastLookups(false);
+ irDocument.javaScriptCompilationUnit = isel->compile(/*generate unit*/false);
+ // ###
+ QV4::CompiledData::ResolvedTypeReferenceMap dummyDependencies;
+ QV4::CompiledData::Unit *unit = generator.generate(irDocument, /*engine*/nullptr, dummyDependencies);
+ unit->flags |= QV4::CompiledData::Unit::StaticData;
+ unit->flags |= QV4::CompiledData::Unit::PendingTypeCompilation;
+ irDocument.javaScriptCompilationUnit->data = unit;
+
+ if (!irDocument.javaScriptCompilationUnit->saveToDisk(inputFileName, &error->message))
+ return false;
+
+ free(unit);
+ }
+ return true;
+}
+
+static bool compileJSFile(const QString &inputFileName, QV4::EvalISelFactory *iselFactory, Error *error)
+{
+ QmlIR::Document irDocument(/*debugMode*/false);
+
+ QString sourceCode;
+ {
+ QFile f(inputFileName);
+ if (!f.open(QIODevice::ReadOnly)) {
+ error->message = QLatin1String("Error opening ") + inputFileName + QLatin1Char(':') + f.errorString();
+ return false;
+ }
+ sourceCode = QString::fromUtf8(f.readAll());
+ if (f.error() != QFileDevice::NoError) {
+ error->message = QLatin1String("Error reading from ") + inputFileName + QLatin1Char(':') + f.errorString();
+ return false;
+ }
+ irDocument.jsModule.sourceTimeStamp = QFileInfo(f).lastModified().toMSecsSinceEpoch();
+ }
+
+ QQmlJS::Engine *engine = &irDocument.jsParserEngine;
+ QmlIR::ScriptDirectivesCollector directivesCollector(engine, &irDocument.jsGenerator);
+ QQmlJS::Directives *oldDirs = engine->directives();
+ engine->setDirectives(&directivesCollector);
+
+ QQmlJS::AST::Program *program = nullptr;
+
+ {
+ QQmlJS::Lexer lexer(engine);
+ lexer.setCode(sourceCode, /*line*/1, /*parseAsBinding*/false);
+ QQmlJS::Parser parser(engine);
+
+ bool parsed = parser.parseProgram();
+
+ for (const QQmlJS::DiagnosticMessage &parseError: parser.diagnosticMessages()) {
+ if (!error->message.isEmpty())
+ error->message += QLatin1Char('\n');
+ error->message += diagnosticErrorMessage(inputFileName, parseError);
+ }
+
+ if (!parsed) {
+ engine->setDirectives(oldDirs);
+ return false;
+ }
+
+ program = QQmlJS::AST::cast<QQmlJS::AST::Program*>(parser.rootNode());
+ if (!program) {
+ lexer.setCode(QStringLiteral("undefined;"), 1, false);
+ parsed = parser.parseProgram();
+ Q_ASSERT(parsed);
+ program = QQmlJS::AST::cast<QQmlJS::AST::Program*>(parser.rootNode());
+ Q_ASSERT(program);
+ }
+ }
+
+ {
+ QmlIR::JSCodeGen v4CodeGen(inputFileName, irDocument.code, &irDocument.jsModule, &irDocument.jsParserEngine, irDocument.program, /*import cache*/0, &irDocument.jsGenerator.stringTable);
+ v4CodeGen.generateFromProgram(inputFileName, sourceCode, program, &irDocument.jsModule, QQmlJS::Codegen::GlobalCode);
+ QList<QQmlJS::DiagnosticMessage> jsErrors = v4CodeGen.errors();
+ if (!jsErrors.isEmpty()) {
+ for (const QQmlJS::DiagnosticMessage &e: qAsConst(jsErrors)) {
+ if (!error->message.isEmpty())
+ error->message += QLatin1Char('\n');
+ error->message += diagnosticErrorMessage(inputFileName, e);
+ }
+ engine->setDirectives(oldDirs);
+ return false;
+ }
+
+ QmlIR::QmlUnitGenerator generator;
+
+ // ### translation binding simplification
+
+ QScopedPointer<QV4::EvalInstructionSelection> isel(iselFactory->create(/*engine*/nullptr, /*executable allocator*/nullptr, &irDocument.jsModule, &irDocument.jsGenerator));
+ // Disable lookups in non-standalone (aka QML) mode
+ isel->setUseFastLookups(false);
+ irDocument.javaScriptCompilationUnit = isel->compile(/*generate unit*/false);
+ // ###
+ QV4::CompiledData::ResolvedTypeReferenceMap dummyDependencies;
+ QV4::CompiledData::Unit *unit = generator.generate(irDocument, /*engine*/nullptr, dummyDependencies);
+ unit->flags |= QV4::CompiledData::Unit::StaticData;
+ irDocument.javaScriptCompilationUnit->data = unit;
+
+ if (!irDocument.javaScriptCompilationUnit->saveToDisk(inputFileName, &error->message)) {
+ engine->setDirectives(oldDirs);
+ return false;
+ }
+
+ free(unit);
+ }
+ engine->setDirectives(oldDirs);
+ return true;
+}
+
+int main(int argc, char **argv)
+{
+ // Produce reliably the same output for the same input by disabling QHash's random seeding.
+ qt_qhash_seed.testAndSetRelaxed(-1, 0);
+
+ QCoreApplication app(argc, argv);
+ QCoreApplication::setApplicationName(QStringLiteral("qmlcachegen"));
+ QCoreApplication::setApplicationVersion(QLatin1String(QT_VERSION_STR));
+
+ QCommandLineParser parser;
+ parser.addHelpOption();
+ parser.addVersionOption();
+
+ QCommandLineOption targetArchitectureOption(QStringLiteral("target-architecture"), QCoreApplication::translate("main", "Target architecture"), QCoreApplication::translate("main", "architecture"));
+ parser.addOption(targetArchitectureOption);
+
+ parser.addPositionalArgument(QStringLiteral("[qml file]"),
+ QStringLiteral("QML source file to generate cache for."));
+
+ parser.process(app);
+
+ const QStringList sources = parser.positionalArguments();
+ if (sources.count() > 1) {
+ fprintf(stderr, "%s\n", qPrintable(QStringLiteral("Too many input files specified: '") + sources.join(QStringLiteral("' '")) + QLatin1Char('\'')));
+ return EXIT_FAILURE;
+ }
+ const QString inputFile = sources.first();
+
+ QScopedPointer<QV4::EvalISelFactory> isel;
+ const QString targetArchitecture = parser.value(targetArchitectureOption);
+
+ isel.reset(QV4::JIT::createISelForArchitecture(targetArchitecture));
+
+ if (!isel)
+ isel.reset(new QV4::Moth::ISelFactory);
+
+ Error error;
+
+ if (inputFile.endsWith(QLatin1String(".qml"))) {
+ if (!compileQmlFile(inputFile, isel.data(), &error)) {
+ error.augment(QLatin1String("Error compiling qml file: ")).print();
+ return EXIT_FAILURE;
+ }
+ } else if (inputFile.endsWith(QLatin1String(".js"))) {
+ if (!compileJSFile(inputFile, isel.data(), &error)) {
+ error.augment(QLatin1String("Error compiling qml file: ")).print();
+ return EXIT_FAILURE;
+ }
+ } else {
+ fprintf(stderr, "Ignoring %s input file as it is not QML source code - maybe remove from QML_FILES?\n", qPrintable(inputFile)); }
+
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/qmlcachegen/qmlcachegen.pro b/tools/qmlcachegen/qmlcachegen.pro
new file mode 100644
index 0000000000..81783d0396
--- /dev/null
+++ b/tools/qmlcachegen/qmlcachegen.pro
@@ -0,0 +1,24 @@
+option(host_build)
+
+QT = qmldevtools-private
+DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII
+
+SOURCES = qmlcachegen.cpp
+TARGET = qmlcachegen
+
+BUILD_INTEGRATION = qmlcache.prf
+!force_independent {
+ qmake_integration.input = BUILD_INTEGRATION
+ qmake_integration.output = $$[QT_HOST_DATA]/mkspecs/features/${QMAKE_FILE_BASE}.prf
+ qmake_integration.commands = $$QMAKE_COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
+ qmake_integration.name = COPY ${QMAKE_FILE_IN} ${QMAKE_FILE_OUT}
+ qmake_integration.CONFIG = no_clean no_link
+ !contains(TEMPLATE, vc.*): qmake_integration.variable_out = GENERATED_FILES
+ QMAKE_EXTRA_COMPILERS += qmake_integration
+}
+
+qmake_integration_installs.files = $$BUILD_INTEGRATION
+qmake_integration_installs.path = $$[QT_HOST_DATA]/mkspecs/features
+INSTALLS += qmake_integration_installs
+
+load(qt_tool)
diff --git a/tools/qmljs/qmljs.cpp b/tools/qmljs/qmljs.cpp
index 54e1b6cea8..4d0f9d278f 100644
--- a/tools/qmljs/qmljs.cpp
+++ b/tools/qmljs/qmljs.cpp
@@ -141,7 +141,7 @@ int main(int argc, char *argv[])
#endif
#ifdef V4_ENABLE_JIT
} else {
- iSelFactory = new QV4::JIT::ISelFactory;
+ iSelFactory = new QV4::JIT::ISelFactory<>;
#endif // V4_ENABLE_JIT
}
diff --git a/tools/qmllint/main.cpp b/tools/qmllint/main.cpp
index 99a53110a8..791fb71685 100644
--- a/tools/qmllint/main.cpp
+++ b/tools/qmllint/main.cpp
@@ -29,7 +29,9 @@
#include <QDebug>
#include <QFile>
#include <QFileInfo>
+#if QT_CONFIG(commandlineparser)
#include <QCommandLineParser>
+#endif
#include <QCoreApplication>
#include <private/qv4value_p.h>
@@ -73,6 +75,7 @@ int main(int argv, char *argc[])
QCoreApplication app(argv, argc);
QCoreApplication::setApplicationName("qmllint");
QCoreApplication::setApplicationVersion("1.0");
+#if QT_CONFIG(commandlineparser)
QCommandLineParser parser;
parser.setApplicationDescription(QLatin1String("QML syntax verifier"));
parser.addHelpOption();
@@ -89,8 +92,16 @@ int main(int argv, char *argc[])
}
bool silent = parser.isSet(silentOption);
+#else
+ bool silent = false;
+#endif
bool success = true;
+#if QT_CONFIG(commandlineparser)
for (const QString &filename : positionalArguments)
+#else
+ const auto arguments = app.arguments();
+ for (const QString &filename : arguments)
+#endif
success &= lint_file(filename, silent);
return success ? 0 : -1;
diff --git a/tools/tools.pro b/tools/tools.pro
index 3952ec4b01..f3988a909a 100644
--- a/tools/tools.pro
+++ b/tools/tools.pro
@@ -4,9 +4,6 @@ SUBDIRS += \
qmlmin \
qmlimportscanner
-qmlmin.CONFIG = host_build
-qmlimportscanner.CONFIG = host_build
-
!android|android_app {
SUBDIRS += \
qml \