aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/ftw/qhashedstring.cpp44
-rw-r--r--src/qml/qml/ftw/qhashedstring_p.h199
-rw-r--r--src/qml/qml/parser/qqmljslexer.cpp5
-rw-r--r--src/qml/qml/qml.pri19
-rw-r--r--src/qml/qml/qqmlabstractbinding.cpp4
-rw-r--r--src/qml/qml/qqmlabstractbinding_p.h3
-rw-r--r--src/qml/qml/qqmlbinding.cpp61
-rw-r--r--src/qml/qml/qqmlbinding_p.h6
-rw-r--r--src/qml/qml/qqmlboundsignal.cpp179
-rw-r--r--src/qml/qml/qqmlboundsignal_p.h24
-rw-r--r--src/qml/qml/qqmlcompileddata.cpp5
-rw-r--r--src/qml/qml/qqmlcompiler.cpp286
-rw-r--r--src/qml/qml/qqmlcompiler_p.h26
-rw-r--r--src/qml/qml/qqmlcomponent.cpp368
-rw-r--r--src/qml/qml/qqmlcomponent.h6
-rw-r--r--src/qml/qml/qqmlcomponent_p.h3
-rw-r--r--src/qml/qml/qqmlcontext.cpp59
-rw-r--r--src/qml/qml/qqmlcontext_p.h23
-rw-r--r--src/qml/qml/qqmlcontextwrapper.cpp338
-rw-r--r--src/qml/qml/qqmlcontextwrapper_p.h104
-rw-r--r--src/qml/qml/qqmlcustomparser.cpp14
-rw-r--r--src/qml/qml/qqmlcustomparser_p.h3
-rw-r--r--src/qml/qml/qqmldata_p.h16
-rw-r--r--src/qml/qml/qqmldirparser.cpp2
-rw-r--r--src/qml/qml/qqmlengine.cpp23
-rw-r--r--src/qml/qml/qqmlengine_p.h29
-rw-r--r--src/qml/qml/qqmlerror.h1
-rw-r--r--src/qml/qml/qqmlexpression.cpp111
-rw-r--r--src/qml/qml/qqmlexpression.h8
-rw-r--r--src/qml/qml/qqmlexpression_p.h16
-rw-r--r--src/qml/qml/qqmlglobal.cpp4
-rw-r--r--src/qml/qml/qqmlglobal_p.h4
-rw-r--r--src/qml/qml/qqmlimport.cpp2
-rw-r--r--src/qml/qml/qqmlincubator_p.h2
-rw-r--r--src/qml/qml/qqmlinstruction.cpp9
-rw-r--r--src/qml/qml/qqmlinstruction_p.h26
-rw-r--r--src/qml/qml/qqmljavascriptexpression.cpp269
-rw-r--r--src/qml/qml/qqmljavascriptexpression_p.h48
-rw-r--r--src/qml/qml/qqmllist_p.h3
-rw-r--r--src/qml/qml/qqmllistwrapper.cpp164
-rw-r--r--src/qml/qml/qqmllistwrapper_p.h (renamed from src/qml/qml/v8/qv8objectresource_p.h)59
-rw-r--r--src/qml/qml/qqmllocale.cpp779
-rw-r--r--src/qml/qml/qqmllocale_p.h30
-rw-r--r--src/qml/qml/qqmlmetatype.cpp39
-rw-r--r--src/qml/qml/qqmlmetatype_p.h9
-rw-r--r--src/qml/qml/qqmlnotifier.cpp4
-rw-r--r--src/qml/qml/qqmlnotifier_p.h19
-rw-r--r--src/qml/qml/qqmlproperty.cpp68
-rw-r--r--src/qml/qml/qqmlproperty_p.h11
-rw-r--r--src/qml/qml/qqmlpropertycache.cpp93
-rw-r--r--src/qml/qml/qqmlpropertycache_p.h24
-rw-r--r--src/qml/qml/qqmlrewrite.cpp649
-rw-r--r--src/qml/qml/qqmlrewrite_p.h197
-rw-r--r--src/qml/qml/qqmlscript.cpp1
-rw-r--r--src/qml/qml/qqmltypeloader.cpp6
-rw-r--r--src/qml/qml/qqmltypeloader_p.h8
-rw-r--r--src/qml/qml/qqmltypenamecache.cpp4
-rw-r--r--src/qml/qml/qqmltypenamecache_p.h4
-rw-r--r--src/qml/qml/qqmltypewrapper.cpp268
-rw-r--r--src/qml/qml/qqmltypewrapper_p.h (renamed from src/qml/qml/v8/qv8typewrapper_p.h)52
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper.cpp399
-rw-r--r--src/qml/qml/qqmlvaluetypewrapper_p.h106
-rw-r--r--src/qml/qml/qqmlvme.cpp202
-rw-r--r--src/qml/qml/qqmlvme_p.h5
-rw-r--r--src/qml/qml/qqmlvmemetaobject.cpp219
-rw-r--r--src/qml/qml/qqmlvmemetaobject_p.h31
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp1403
-rw-r--r--src/qml/qml/v4/llvm_installation.pri23
-rw-r--r--src/qml/qml/v4/llvm_runtime.cpp513
-rw-r--r--src/qml/qml/v4/moth/moth.pri13
-rw-r--r--src/qml/qml/v4/moth/qv4instr_moth.cpp (renamed from src/qml/qml/v8/qscript_impl_p.h)29
-rw-r--r--src/qml/qml/v4/moth/qv4instr_moth_p.h612
-rw-r--r--src/qml/qml/v4/moth/qv4isel_moth.cpp1075
-rw-r--r--src/qml/qml/v4/moth/qv4isel_moth_p.h201
-rw-r--r--src/qml/qml/v4/moth/qv4vme_moth.cpp592
-rw-r--r--src/qml/qml/v4/moth/qv4vme_moth_p.h (renamed from src/qml/qml/v8/qv8stringwrapper_p.h)48
-rw-r--r--src/qml/qml/v4/qv4_llvm_p.h65
-rw-r--r--src/qml/qml/v4/qv4alloca_p.h (renamed from src/qml/qml/v8/qv8_p.h)14
-rw-r--r--src/qml/qml/v4/qv4argumentsobject.cpp171
-rw-r--r--src/qml/qml/v4/qv4argumentsobject_p.h97
-rw-r--r--src/qml/qml/v4/qv4arrayobject.cpp865
-rw-r--r--src/qml/qml/v4/qv4arrayobject_p.h (renamed from src/qml/qml/v4/qv4program_p.h)120
-rw-r--r--src/qml/qml/v4/qv4bindings.cpp2478
-rw-r--r--src/qml/qml/v4/qv4bindings_p.h172
-rw-r--r--src/qml/qml/v4/qv4booleanobject.cpp97
-rw-r--r--src/qml/qml/v4/qv4booleanobject_p.h77
-rw-r--r--src/qml/qml/v4/qv4codegen.cpp2605
-rw-r--r--src/qml/qml/v4/qv4codegen_p.h451
-rw-r--r--src/qml/qml/v4/qv4compiler.cpp1580
-rw-r--r--src/qml/qml/v4/qv4compiler_p_p.h245
-rw-r--r--src/qml/qml/v4/qv4context.cpp615
-rw-r--r--src/qml/qml/v4/qv4context_p.h227
-rw-r--r--src/qml/qml/v4/qv4dateobject.cpp1316
-rw-r--r--src/qml/qml/v4/qv4dateobject_p.h137
-rw-r--r--src/qml/qml/v4/qv4debugging.cpp372
-rw-r--r--src/qml/qml/v4/qv4debugging_p.h161
-rw-r--r--src/qml/qml/v4/qv4engine.cpp837
-rw-r--r--src/qml/qml/v4/qv4engine_p.h332
-rw-r--r--src/qml/qml/v4/qv4errorobject.cpp351
-rw-r--r--src/qml/qml/v4/qv4errorobject_p.h246
-rw-r--r--src/qml/qml/v4/qv4exception.cpp129
-rw-r--r--src/qml/qml/v4/qv4exception_gcc.cpp143
-rw-r--r--src/qml/qml/v4/qv4exception_p.h81
-rw-r--r--src/qml/qml/v4/qv4executableallocator.cpp220
-rw-r--r--src/qml/qml/v4/qv4executableallocator_p.h (renamed from src/qml/qml/v8/qv8jsonwrapper_p.h)122
-rw-r--r--src/qml/qml/v4/qv4function.cpp88
-rw-r--r--src/qml/qml/v4/qv4function_p.h142
-rw-r--r--src/qml/qml/v4/qv4functionobject.cpp558
-rw-r--r--src/qml/qml/v4/qv4functionobject_p.h223
-rw-r--r--src/qml/qml/v4/qv4global_p.h197
-rw-r--r--src/qml/qml/v4/qv4globalobject.cpp652
-rw-r--r--src/qml/qml/v4/qv4globalobject_p.h (renamed from src/qml/qml/v8/qscripttools_p.h)60
-rw-r--r--src/qml/qml/v4/qv4identifier.cpp172
-rw-r--r--src/qml/qml/v4/qv4identifier_p.h220
-rw-r--r--src/qml/qml/v4/qv4identifiertable.cpp184
-rw-r--r--src/qml/qml/v4/qv4identifiertable_p.h86
-rw-r--r--src/qml/qml/v4/qv4include.cpp232
-rw-r--r--src/qml/qml/v4/qv4include_p.h (renamed from src/qml/qml/v8/qv8include_p.h)36
-rw-r--r--src/qml/qml/v4/qv4instruction.cpp532
-rw-r--r--src/qml/qml/v4/qv4instruction_p.h483
-rw-r--r--src/qml/qml/v4/qv4internalclass.cpp296
-rw-r--r--src/qml/qml/v4/qv4internalclass_p.h154
-rw-r--r--src/qml/qml/v4/qv4ir.cpp919
-rw-r--r--src/qml/qml/v4/qv4ir_p.h615
-rw-r--r--src/qml/qml/v4/qv4irbuilder.cpp1394
-rw-r--r--src/qml/qml/v4/qv4irbuilder_p.h239
-rw-r--r--src/qml/qml/v4/qv4isel_llvm.cpp1388
-rw-r--r--src/qml/qml/v4/qv4isel_llvm_p.h178
-rw-r--r--src/qml/qml/v4/qv4isel_masm.cpp1450
-rw-r--r--src/qml/qml/v4/qv4isel_masm_p.h938
-rw-r--r--src/qml/qml/v4/qv4isel_p.cpp440
-rw-r--r--src/qml/qml/v4/qv4isel_p.h165
-rw-r--r--src/qml/qml/v4/qv4isel_util_p.h87
-rw-r--r--src/qml/qml/v4/qv4jsir.cpp1024
-rw-r--r--src/qml/qml/v4/qv4jsir_p.h890
-rw-r--r--src/qml/qml/v4/qv4jsonobject.cpp1040
-rw-r--r--src/qml/qml/v4/qv4jsonobject_p.h (renamed from src/qml/qml/v8/qscriptisolate_p.h)68
-rw-r--r--src/qml/qml/v4/qv4lookup.cpp365
-rw-r--r--src/qml/qml/v4/qv4lookup_p.h (renamed from src/qml/qml/v8/qv8sqlerrors.cpp)62
-rw-r--r--src/qml/qml/v4/qv4managed.cpp212
-rw-r--r--src/qml/qml/v4/qv4managed_p.h321
-rw-r--r--src/qml/qml/v4/qv4math_p.h147
-rw-r--r--src/qml/qml/v4/qv4mathobject.cpp311
-rw-r--r--src/qml/qml/v4/qv4mathobject_p.h78
-rw-r--r--src/qml/qml/v4/qv4mm.cpp605
-rw-r--r--src/qml/qml/v4/qv4mm_p.h157
-rw-r--r--src/qml/qml/v4/qv4numberobject.cpp257
-rw-r--r--src/qml/qml/v4/qv4numberobject_p.h81
-rw-r--r--src/qml/qml/v4/qv4object.cpp1383
-rw-r--r--src/qml/qml/v4/qv4object_p.h432
-rw-r--r--src/qml/qml/v4/qv4objectiterator.cpp129
-rw-r--r--src/qml/qml/v4/qv4objectiterator_p.h87
-rw-r--r--src/qml/qml/v4/qv4objectproto.cpp624
-rw-r--r--src/qml/qml/v4/qv4objectproto_p.h107
-rw-r--r--src/qml/qml/v4/qv4property_p.h150
-rw-r--r--src/qml/qml/v4/qv4qmlextensions.cpp51
-rw-r--r--src/qml/qml/v4/qv4qmlextensions_p.h66
-rw-r--r--src/qml/qml/v4/qv4qobjectwrapper.cpp1792
-rw-r--r--src/qml/qml/v4/qv4qobjectwrapper_p.h201
-rw-r--r--src/qml/qml/v4/qv4regexp.cpp180
-rw-r--r--src/qml/qml/v4/qv4regexp_p.h151
-rw-r--r--src/qml/qml/v4/qv4regexpobject.cpp359
-rw-r--r--src/qml/qml/v4/qv4regexpobject_p.h123
-rw-r--r--src/qml/qml/v4/qv4runtime.cpp1269
-rw-r--r--src/qml/qml/v4/qv4runtime_p.h717
-rw-r--r--src/qml/qml/v4/qv4script.cpp249
-rw-r--r--src/qml/qml/v4/qv4script_p.h88
-rw-r--r--src/qml/qml/v4/qv4sequenceobject.cpp651
-rw-r--r--src/qml/qml/v4/qv4sequenceobject_p.h (renamed from src/qml/qml/qqmlintegercache_p.h)54
-rw-r--r--src/qml/qml/v4/qv4serialize.cpp (renamed from src/qml/qml/v8/qv8worker.cpp)249
-rw-r--r--src/qml/qml/v4/qv4serialize_p.h (renamed from src/qml/qml/v8/qv8worker_p.h)25
-rw-r--r--src/qml/qml/v4/qv4sparsearray.cpp459
-rw-r--r--src/qml/qml/v4/qv4sparsearray_p.h367
-rw-r--r--src/qml/qml/v4/qv4ssa.cpp2122
-rw-r--r--src/qml/qml/v4/qv4ssa_p.h (renamed from src/qml/qml/v4/qv4compiler_p.h)112
-rw-r--r--src/qml/qml/v4/qv4stacktrace.cpp146
-rw-r--r--src/qml/qml/v4/qv4stacktrace_p.h75
-rw-r--r--src/qml/qml/v4/qv4string.cpp304
-rw-r--r--src/qml/qml/v4/qv4string_p.h144
-rw-r--r--src/qml/qml/v4/qv4stringobject.cpp761
-rw-r--r--src/qml/qml/v4/qv4stringobject_p.h110
-rw-r--r--src/qml/qml/v4/qv4syntaxchecker.cpp123
-rw-r--r--src/qml/qml/v4/qv4syntaxchecker_p.h77
-rw-r--r--src/qml/qml/v4/qv4unwindhelper.cpp82
-rw-r--r--src/qml/qml/v4/qv4unwindhelper_p-arm.h233
-rw-r--r--src/qml/qml/v4/qv4unwindhelper_p-dw2.h191
-rw-r--r--src/qml/qml/v4/qv4unwindhelper_p.h (renamed from src/qml/qml/qqmlintegercache.cpp)52
-rw-r--r--src/qml/qml/v4/qv4util_p.h (renamed from src/qml/qml/v8/qv8stringwrapper.cpp)52
-rw-r--r--src/qml/qml/v4/qv4value.cpp403
-rw-r--r--src/qml/qml/v4/qv4value_def_p.h280
-rw-r--r--src/qml/qml/v4/qv4value_p.h426
-rw-r--r--src/qml/qml/v4/qv4variantobject.cpp203
-rw-r--r--src/qml/qml/v4/qv4variantobject_p.h (renamed from src/qml/qml/v8/qv8variantresource_p.h)47
-rw-r--r--src/qml/qml/v4/v4.pri207
-rw-r--r--src/qml/qml/v8/qjsconverter_impl_p.h273
-rw-r--r--src/qml/qml/v8/qjsconverter_p.h111
-rw-r--r--src/qml/qml/v8/qjsengine.cpp120
-rw-r--r--src/qml/qml/v8/qjsvalue.cpp492
-rw-r--r--src/qml/qml/v8/qjsvalue.h17
-rw-r--r--src/qml/qml/v8/qjsvalue_impl_p.h950
-rw-r--r--src/qml/qml/v8/qjsvalue_p.h174
-rw-r--r--src/qml/qml/v8/qjsvalueiterator.cpp81
-rw-r--r--src/qml/qml/v8/qjsvalueiterator.h2
-rw-r--r--src/qml/qml/v8/qjsvalueiterator_impl_p.h143
-rw-r--r--src/qml/qml/v8/qjsvalueiterator_p.h40
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp1642
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions_p.h137
-rw-r--r--src/qml/qml/v8/qscriptoriginalglobalobject_p.h177
-rw-r--r--src/qml/qml/v8/qscriptshareddata_p.h169
-rw-r--r--src/qml/qml/v8/qv4domerrors.cpp72
-rw-r--r--src/qml/qml/v8/qv4domerrors_p.h (renamed from src/qml/qml/v8/qv8domerrors_p.h)19
-rw-r--r--src/qml/qml/v8/qv4sqlerrors.cpp64
-rw-r--r--src/qml/qml/v8/qv4sqlerrors_p.h (renamed from src/qml/qml/v8/qv8sqlerrors_p.h)7
-rw-r--r--src/qml/qml/v8/qv8bindings.cpp334
-rw-r--r--src/qml/qml/v8/qv8bindings_p.h161
-rw-r--r--src/qml/qml/v8/qv8contextwrapper.cpp430
-rw-r--r--src/qml/qml/v8/qv8contextwrapper_p.h116
-rw-r--r--src/qml/qml/v8/qv8debug_p.h2
-rw-r--r--src/qml/qml/v8/qv8domerrors.cpp73
-rw-r--r--src/qml/qml/v8/qv8engine.cpp1253
-rw-r--r--src/qml/qml/v8/qv8engine_impl_p.h172
-rw-r--r--src/qml/qml/v8/qv8engine_p.h508
-rw-r--r--src/qml/qml/v8/qv8include.cpp245
-rw-r--r--src/qml/qml/v8/qv8jsonwrapper.cpp181
-rw-r--r--src/qml/qml/v8/qv8listwrapper.cpp194
-rw-r--r--src/qml/qml/v8/qv8listwrapper_p.h97
-rw-r--r--src/qml/qml/v8/qv8profiler_p.h2
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper.cpp2283
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper_p.h186
-rw-r--r--src/qml/qml/v8/qv8sequencewrapper.cpp323
-rw-r--r--src/qml/qml/v8/qv8sequencewrapper_p.h114
-rw-r--r--src/qml/qml/v8/qv8sequencewrapper_p_p.h512
-rw-r--r--src/qml/qml/v8/qv8typewrapper.cpp307
-rw-r--r--src/qml/qml/v8/qv8valuetypewrapper.cpp452
-rw-r--r--src/qml/qml/v8/qv8valuetypewrapper_p.h108
-rw-r--r--src/qml/qml/v8/qv8variantwrapper.cpp279
-rw-r--r--src/qml/qml/v8/qv8variantwrapper_p.h110
-rw-r--r--src/qml/qml/v8/script.pri11
-rw-r--r--src/qml/qml/v8/v8.pri40
239 files changed, 47578 insertions, 24101 deletions
diff --git a/src/qml/qml/ftw/qhashedstring.cpp b/src/qml/qml/ftw/qhashedstring.cpp
index 1b7ad38ad1..7e6ea59ef9 100644
--- a/src/qml/qml/ftw/qhashedstring.cpp
+++ b/src/qml/qml/ftw/qhashedstring.cpp
@@ -40,20 +40,15 @@
****************************************************************************/
#include "qhashedstring_p.h"
-#include <private/qcalculatehash_p.h>
inline quint32 stringHash(const QChar* data, int length)
{
- quint32 rv = calculateHash<quint16>((quint16*)data, length) >> HashedString::kHashShift;
- Q_ASSERT(rv == v8::String::ComputeHash((uint16_t*)data, length));
- return rv;
+ return QV4::String::createHashValue(data, length);
}
inline quint32 stringHash(const char *data, int length)
{
- quint32 rv = calculateHash<quint8>((quint8*)data, length) >> HashedString::kHashShift;
- Q_ASSERT(rv == v8::String::ComputeHash((char *)data, length));
- return rv;
+ return QV4::String::createHashValue(data, length);
}
void QHashedString::computeHash() const
@@ -345,14 +340,6 @@ static void utf8FromUtf16(char *output, const QChar *uc, int len)
}
}
-void QHashedStringRef::computeUtf8Length() const
-{
- if (m_length)
- m_utf8length = utf8LengthFromUtf16(m_data, m_length);
- else
- m_utf8length = 0;
-}
-
QHashedStringRef QHashedStringRef::mid(int offset, int length) const
{
Q_ASSERT(offset < m_length);
@@ -400,33 +387,6 @@ QString QHashedStringRef::toString() const
return QString(m_data, m_length);
}
-QByteArray QHashedStringRef::toUtf8() const
-{
- if (m_length == 0)
- return QByteArray();
-
- QByteArray result;
- result.resize(utf8length());
- writeUtf8(result.data());
- return result;
-}
-
-void QHashedStringRef::writeUtf8(char *output) const
-{
- if (m_length) {
- int ulen = utf8length();
- if (ulen == m_length) {
- // Must be a latin1 string
- uchar *o = (uchar *)output;
- const QChar *c = m_data;
- while (ulen--)
- *o++ = (uchar)((*c++).unicode());
- } else {
- utf8FromUtf16(output, m_data, m_length);
- }
- }
-}
-
QString QHashedCStringRef::toUtf16() const
{
if (m_length == 0)
diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h
index cdf0717e3a..4815f787b6 100644
--- a/src/qml/qml/ftw/qhashedstring_p.h
+++ b/src/qml/qml/ftw/qhashedstring_p.h
@@ -55,7 +55,8 @@
#include <QtCore/qglobal.h>
#include <QtCore/qstring.h>
-#include <private/qv8_p.h>
+#include <private/qv4string_p.h>
+#include <private/qv4value_p.h>
#include <private/qflagpointer_p.h>
@@ -63,6 +64,8 @@
#include <stdlib.h>
#endif
+#include <stdint.h>
+
QT_BEGIN_NAMESPACE
// Enable this to debug hash linking assumptions.
@@ -84,8 +87,6 @@ public:
inline quint32 hash() const;
inline quint32 existingHash() const;
- static inline bool isUpper(const QChar &);
-
static bool compare(const QChar *lhs, const QChar *rhs, int length);
static inline bool compare(const QChar *lhs, const char *rhs, int length);
static inline bool compare(const char *lhs, const char *rhs, int length);
@@ -97,29 +98,6 @@ private:
mutable quint32 m_hash;
};
-class Q_AUTOTEST_EXPORT QHashedV8String
-{
-public:
- inline QHashedV8String();
- explicit inline QHashedV8String(v8::Handle<v8::String>);
- inline QHashedV8String(const QHashedV8String &string);
- inline QHashedV8String &operator=(const QHashedV8String &other);
-
- inline bool operator==(const QHashedV8String &string);
-
- inline quint32 hash() const;
- inline int length() const;
- inline quint32 symbolId() const;
-
- inline v8::Handle<v8::String> string() const;
-
- inline QString toString() const;
-
-private:
- v8::String::CompleteHashData m_hash;
- v8::Handle<v8::String> m_string;
-};
-
class QHashedCStringRef;
class Q_AUTOTEST_EXPORT QHashedStringRef
{
@@ -160,18 +138,13 @@ public:
inline bool isLatin1() const;
- inline int utf8length() const;
- QByteArray toUtf8() const;
- void writeUtf8(char *) const;
private:
friend class QHashedString;
void computeHash() const;
- void computeUtf8Length() const;
const QChar *m_data;
int m_length;
- mutable int m_utf8length;
mutable quint32 m_hash;
};
@@ -261,21 +234,29 @@ public:
inline char *cStrData() const { return (char *)ckey; }
inline uint16_t *utf16Data() const { return (uint16_t *)strData->data(); }
- inline bool equals(v8::Handle<v8::String> string) const {
- v8::Local<v8::String> data = isQString() ? v8::String::New(utf16Data(), length)
- : v8::String::New(cStrData(), length);
- return string->Equals(data);
- }
-
- inline bool symbolEquals(const QHashedV8String &string) const {
- Q_ASSERT(string.symbolId() != 0);
- return length == string.length() && hash == string.hash() &&
- (string.symbolId() == symbolId || equals(string.string()));
+ inline bool equals(const QV4::Value &string) const {
+ QString s = string.toQString();
+ if (isQString()) {
+ QStringDataPtr dd;
+ dd.ptr = strData;
+ strData->ref.ref();
+ return QString(dd) == s;
+ } else {
+ return QLatin1String(cStrData(), length) == s;
+ }
}
- inline bool equals(const QHashedV8String &string) const {
- return length == string.length() && hash == string.hash() &&
- equals(string.string());
+ inline bool equals(const QV4::String *string) const {
+ if (length != string->length() || hash != string->hashValue())
+ return false;
+ if (isQString()) {
+ QStringDataPtr dd;
+ dd.ptr = strData;
+ strData->ref.ref();
+ return QString(dd) == string->toQString();
+ } else {
+ return QLatin1String(cStrData(), length) == string->toQString();
+ }
}
inline bool equals(const QHashedStringRef &string) const {
@@ -332,7 +313,8 @@ struct HashedForm {};
template<> struct HashedForm<QString> { typedef QHashedString Type; };
template<> struct HashedForm<QStringRef> { typedef QHashedStringRef Type; };
template<> struct HashedForm<QHashedString> { typedef const QHashedString &Type; };
-template<> struct HashedForm<QHashedV8String> { typedef const QHashedV8String &Type; };
+template<> struct HashedForm<QV4::String *> { typedef const QV4::String *Type; };
+template<> struct HashedForm<const QV4::String *> { typedef const QV4::String *Type; };
template<> struct HashedForm<QHashedStringRef> { typedef const QHashedStringRef &Type; };
template<> struct HashedForm<QLatin1String> { typedef QHashedCStringRef Type; };
template<> struct HashedForm<QHashedCStringRef> { typedef const QHashedCStringRef &Type; };
@@ -343,7 +325,8 @@ public:
static HashedForm<QString>::Type hashedString(const QString &s) { return QHashedString(s);}
static HashedForm<QStringRef>::Type hashedString(const QStringRef &s) { return QHashedStringRef(s.constData(), s.size());}
static HashedForm<QHashedString>::Type hashedString(const QHashedString &s) { return s; }
- static HashedForm<QHashedV8String>::Type hashedString(const QHashedV8String &s) { return s; }
+ static HashedForm<QV4::String *>::Type hashedString(QV4::String *s) { return s; }
+ static HashedForm<const QV4::String *>::Type hashedString(const QV4::String *s) { return s; }
static HashedForm<QHashedStringRef>::Type hashedString(const QHashedStringRef &s) { return s; }
static HashedForm<QLatin1String>::Type hashedString(const QLatin1String &s) { return QHashedCStringRef(s.data(), s.size()); }
@@ -351,14 +334,15 @@ public:
static const QString &toQString(const QString &s) { return s; }
static const QString &toQString(const QHashedString &s) { return s; }
- static QString toQString(const QHashedV8String &s) { return s.toString(); }
+ static QString toQString(const QV4::String *s) { return s->toQString(); }
static QString toQString(const QHashedStringRef &s) { return s.toString(); }
static QString toQString(const QLatin1String &s) { return QString(s); }
static QString toQString(const QHashedCStringRef &s) { return s.toUtf16(); }
static inline quint32 hashOf(const QHashedStringRef &s) { return s.hash(); }
- static inline quint32 hashOf(const QHashedV8String &s) { return s.hash(); }
+ static inline quint32 hashOf(QV4::String *s) { return s->hashValue(); }
+ static inline quint32 hashOf(const QV4::String *s) { return s->hashValue(); }
template<typename K>
static inline quint32 hashOf(const K &key) { return hashedString(key).hash(); }
@@ -401,8 +385,6 @@ public:
template<typename K>
inline Node *findNode(const K &) const;
- inline Node *findSymbolNode(const QHashedV8String &) const;
-
inline Node *createNode(const Node &o);
template<typename K>
@@ -472,7 +454,7 @@ public:
template<typename K>
inline T *value(const K &) const;
- inline T *value(const QHashedV8String &string) const;
+ inline T *value(const QV4::String *string) const;
inline T *value(const ConstIterator &) const;
template<typename K>
@@ -866,21 +848,6 @@ typename QStringHash<T>::Node *QStringHash<T>::findNode(const K &key) const
}
template<class T>
-typename QStringHash<T>::Node *QStringHash<T>::findSymbolNode(const QHashedV8String &string) const
-{
- Q_ASSERT(string.symbolId() != 0);
-
- QStringHashNode *node = data.numBuckets?data.buckets[hashOf(string) % data.numBuckets]:0;
- while (node && !node->symbolEquals(string))
- node = (*node->next);
-
- if (node)
- node->symbolId = string.symbolId();
-
- return (Node *)node;
-}
-
-template<class T>
template<class K>
T *QStringHash<T>::value(const K &key) const
{
@@ -896,9 +863,9 @@ T *QStringHash<T>::value(const ConstIterator &iter) const
}
template<class T>
-T *QStringHash<T>::value(const QHashedV8String &string) const
+T *QStringHash<T>::value(const QV4::String *string) const
{
- Node *n = string.symbolId()?findSymbolNode(string):findNode(string);
+ Node *n = findNode(string);
return n?&n->value:0;
}
@@ -1122,110 +1089,38 @@ quint32 QHashedString::existingHash() const
return m_hash;
}
-bool QHashedString::isUpper(const QChar &qc)
-{
- ushort c = qc.unicode();
- // Optimize for _, a-z and A-Z.
- return ((c != '_' ) && (!(c >= 'a' && c <= 'z')) &&
- ((c >= 'A' && c <= 'Z') || QChar::category(c) == QChar::Letter_Uppercase));
-}
-
-QHashedV8String::QHashedV8String()
-{
-}
-
-QHashedV8String::QHashedV8String(v8::Handle<v8::String> string)
-: m_hash(string->CompleteHash()), m_string(string)
-{
- Q_ASSERT(!m_string.IsEmpty());
-}
-
-QHashedV8String::QHashedV8String(const QHashedV8String &string)
-: m_hash(string.m_hash), m_string(string.m_string)
-{
-}
-
-QHashedV8String &QHashedV8String::operator=(const QHashedV8String &other)
-{
- m_hash = other.m_hash;
- m_string = other.m_string;
- return *this;
-}
-
-bool QHashedV8String::operator==(const QHashedV8String &string)
-{
- return m_hash.hash == string.m_hash.hash && m_hash.length == string.m_hash.length &&
- m_string.IsEmpty() == m_string.IsEmpty() &&
- (m_string.IsEmpty() || m_string->StrictEquals(string.m_string));
-}
-
-quint32 QHashedV8String::hash() const
-{
- return m_hash.hash;
-}
-
-int QHashedV8String::length() const
-{
- return m_hash.length;
-}
-
-quint32 QHashedV8String::symbolId() const
-{
- return m_hash.symbol_id;
-}
-
-v8::Handle<v8::String> QHashedV8String::string() const
-{
- return m_string;
-}
-
-QString QHashedV8String::toString() const
-{
- QString result;
- result.reserve(m_hash.length);
-
- v8::String::Value value(m_string);
- Q_ASSERT(*value != NULL);
- uint16_t* string = *value;
- for (int i = 0; i < m_hash.length; ++i)
- result.append(string[i]);
-
- return result;
-}
-
QHashedStringRef::QHashedStringRef()
-: m_data(0), m_length(0), m_utf8length(-1), m_hash(0)
+: m_data(0), m_length(0), m_hash(0)
{
}
QHashedStringRef::QHashedStringRef(const QString &str)
-: m_data(str.constData()), m_length(str.length()), m_utf8length(0), m_hash(0)
+: m_data(str.constData()), m_length(str.length()), m_hash(0)
{
}
QHashedStringRef::QHashedStringRef(const QStringRef &str)
-: m_data(str.constData()), m_length(str.length()), m_utf8length(0), m_hash(0)
+: m_data(str.constData()), m_length(str.length()), m_hash(0)
{
}
QHashedStringRef::QHashedStringRef(const QChar *data, int length)
-: m_data(data), m_length(length), m_utf8length(0), m_hash(0)
+: m_data(data), m_length(length), m_hash(0)
{
}
QHashedStringRef::QHashedStringRef(const QChar *data, int length, quint32 hash)
-: m_data(data), m_length(length), m_utf8length(0), m_hash(hash)
+: m_data(data), m_length(length), m_hash(hash)
{
}
QHashedStringRef::QHashedStringRef(const QHashedString &string)
-: m_data(string.constData()), m_length(string.length()), m_utf8length(0), m_hash(string.m_hash)
+: m_data(string.constData()), m_length(string.length()), m_hash(string.m_hash)
{
}
QHashedStringRef::QHashedStringRef(const QHashedStringRef &string)
-: m_data(string.m_data), m_length(string.m_length), m_utf8length(string.m_utf8length),
- m_hash(string.m_hash)
+: m_data(string.m_data), m_length(string.m_length), m_hash(string.m_hash)
{
}
@@ -1233,7 +1128,6 @@ QHashedStringRef &QHashedStringRef::operator=(const QHashedStringRef &o)
{
m_data = o.m_data;
m_length = o.m_length;
- m_utf8length = o.m_utf8length;
m_hash = o.m_hash;
return *this;
}
@@ -1318,13 +1212,6 @@ int QHashedStringRef::length() const
return m_length;
}
-int QHashedStringRef::utf8length() const
-{
- if (m_utf8length < m_length)
- computeUtf8Length();
- return m_utf8length;
-}
-
bool QHashedStringRef::isLatin1() const
{
for (int ii = 0; ii < m_length; ++ii)
@@ -1335,7 +1222,7 @@ bool QHashedStringRef::isLatin1() const
bool QHashedStringRef::startsWithUpper() const
{
if (m_length < 1) return false;
- return QHashedString::isUpper(m_data[0]);
+ return m_data[0].isUpper();
}
quint32 QHashedStringRef::hash() const
diff --git a/src/qml/qml/parser/qqmljslexer.cpp b/src/qml/qml/parser/qqmljslexer.cpp
index cb78238f99..5d9ca1036f 100644
--- a/src/qml/qml/parser/qqmljslexer.cpp
+++ b/src/qml/qml/parser/qqmljslexer.cpp
@@ -287,7 +287,8 @@ int Lexer::lex()
break;
case BalancedParentheses:
- _parenthesesState = IgnoreParentheses;
+ if (_tokenKind != T_DO)
+ _parenthesesState = IgnoreParentheses;
break;
} // switch
@@ -1037,7 +1038,7 @@ bool Lexer::scanRegExp(RegExpBodyPrefix prefix)
_patternFlags = 0;
while (isIdentLetter(_char)) {
int flag = regExpFlagFromChar(_char);
- if (flag == 0) {
+ if (flag == 0 || _patternFlags & flag) {
_errorMessage = QCoreApplication::translate("QQmlParser", "Invalid regular expression flag '%0'")
.arg(QChar(_char));
return false;
diff --git a/src/qml/qml/qml.pri b/src/qml/qml/qml.pri
index 9b2926ec7e..3a18d02871 100644
--- a/src/qml/qml/qml.pri
+++ b/src/qml/qml/qml.pri
@@ -23,7 +23,6 @@ SOURCES += \
$$PWD/qqmlinfo.cpp \
$$PWD/qqmlerror.cpp \
$$PWD/qqmlscript.cpp \
- $$PWD/qqmlrewrite.cpp \
$$PWD/qqmlvaluetype.cpp \
$$PWD/qqmlaccessors.cpp \
$$PWD/qqmlxmlhttprequest.cpp \
@@ -31,7 +30,6 @@ SOURCES += \
$$PWD/qqmlcleanup.cpp \
$$PWD/qqmlpropertycache.cpp \
$$PWD/qqmlnotifier.cpp \
- $$PWD/qqmlintegercache.cpp \
$$PWD/qqmltypenotavailable.cpp \
$$PWD/qqmltypenamecache.cpp \
$$PWD/qqmlscriptstring.cpp \
@@ -52,7 +50,11 @@ SOURCES += \
$$PWD/qqmlplatform.cpp \
$$PWD/qqmlbinding.cpp \
$$PWD/qqmlabstracturlinterceptor.cpp \
- $$PWD/qqmlapplicationengine.cpp
+ $$PWD/qqmlapplicationengine.cpp \
+ $$PWD/qqmllistwrapper.cpp \
+ $$PWD/qqmlcontextwrapper.cpp \
+ $$PWD/qqmlvaluetypewrapper.cpp \
+ $$PWD/qqmltypewrapper.cpp
HEADERS += \
$$PWD/qqmlglobal_p.h \
@@ -92,7 +94,6 @@ HEADERS += \
$$PWD/qqmldata_p.h \
$$PWD/qqmlerror.h \
$$PWD/qqmlscript_p.h \
- $$PWD/qqmlrewrite_p.h \
$$PWD/qqmlvaluetype_p.h \
$$PWD/qqmlaccessors_p.h \
$$PWD/qqmlxmlhttprequest_p.h \
@@ -100,7 +101,6 @@ HEADERS += \
$$PWD/qqmlcleanup_p.h \
$$PWD/qqmlpropertycache_p.h \
$$PWD/qqmlnotifier_p.h \
- $$PWD/qqmlintegercache_p.h \
$$PWD/qqmltypenotavailable_p.h \
$$PWD/qqmltypenamecache_p.h \
$$PWD/qqmlscriptstring.h \
@@ -126,11 +126,14 @@ HEADERS += \
$$PWD/qqmlextensionplugin_p.h \
$$PWD/qqmlabstracturlinterceptor_p.h \
$$PWD/qqmlapplicationengine_p.h \
- $$PWD/qqmlapplicationengine.h
-
+ $$PWD/qqmlapplicationengine.h \
+ $$PWD/qqmllistwrapper_p.h \
+ $$PWD/qqmlcontextwrapper_p.h \
+ $$PWD/qqmlvaluetypewrapper_p.h \
+ $$PWD/qqmltypewrapper_p.h
include(parser/parser.pri)
include(rewriter/rewriter.pri)
include(ftw/ftw.pri)
-include(v4/v4.pri)
include(v8/v8.pri)
+include(v4/v4.pri)
diff --git a/src/qml/qml/qqmlabstractbinding.cpp b/src/qml/qml/qqmlabstractbinding.cpp
index 695dbfbf87..c01981b3d2 100644
--- a/src/qml/qml/qqmlabstractbinding.cpp
+++ b/src/qml/qml/qqmlabstractbinding.cpp
@@ -49,13 +49,9 @@ QT_BEGIN_NAMESPACE
extern QQmlAbstractBinding::VTable QQmlBinding_vtable;
extern QQmlAbstractBinding::VTable QQmlValueTypeProxyBinding_vtable;
-extern QQmlAbstractBinding::VTable QV4Bindings_Binding_vtable;
-extern QQmlAbstractBinding::VTable QV8Bindings_Binding_vtable;
QQmlAbstractBinding::VTable *QQmlAbstractBinding::vTables[] = {
&QQmlBinding_vtable,
- &QV4Bindings_Binding_vtable,
- &QV8Bindings_Binding_vtable,
&QQmlValueTypeProxyBinding_vtable
};
diff --git a/src/qml/qml/qqmlabstractbinding_p.h b/src/qml/qml/qqmlabstractbinding_p.h
index aa39e1cdfd..7ac10a6d63 100644
--- a/src/qml/qml/qqmlabstractbinding_p.h
+++ b/src/qml/qml/qqmlabstractbinding_p.h
@@ -91,7 +91,7 @@ public:
typedef QWeakPointer<QQmlAbstractBinding> Pointer;
- enum BindingType { Binding = 0, V4 = 1, V8 = 2, ValueTypeProxy = 3 };
+ enum BindingType { Binding = 0, ValueTypeProxy = 1 };
inline BindingType bindingType() const;
// Destroy the binding. Use this instead of calling delete.
@@ -149,7 +149,6 @@ private:
friend class QQmlPropertyPrivate;
friend class QQmlVME;
friend class QtSharedPointer::ExternalRefCount<QQmlAbstractBinding>;
- friend class QV8QObjectWrapper;
friend class QV4Bindings;
typedef QSharedPointer<QQmlAbstractBinding> SharedPointer;
diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp
index 12ab72e852..eff17ddd9a 100644
--- a/src/qml/qml/qqmlbinding.cpp
+++ b/src/qml/qml/qqmlbinding.cpp
@@ -49,7 +49,6 @@
#include <private/qqmlprofilerservice_p.h>
#include <private/qqmltrace_p.h>
#include <private/qqmlexpression_p.h>
-#include <private/qqmlrewrite_p.h>
#include <private/qqmlscriptstring_p.h>
#include <QVariant>
@@ -86,7 +85,7 @@ QQmlBinding::createBinding(Identifier id, QObject *obj, QQmlContext *ctxt,
Q_ASSERT(typeData);
if (QQmlCompiledData *cdata = typeData->compiledData()) {
- rv = new QQmlBinding(cdata->primitives.at(id), true, obj, ctxtdata, url, lineNumber, 0);
+ rv = new QQmlBinding(cdata->primitives.at(id), obj, ctxtdata, url, lineNumber, 0);
}
typeData->release();
@@ -108,11 +107,8 @@ QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContext *ctxt)
QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt));
setScopeObject(obj);
- QQmlRewrite::RewriteBinding rewriteBinding;
- QString code = rewriteBinding(str);
-
m_expression = str.toUtf8();
- v8function = evalFunction(context(), obj, code, QString(), 0);
+ v4function = qmlBinding(context(), obj, str, QString(), 0);
}
QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlContext *ctxt)
@@ -125,7 +121,6 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte
if (!ctxt && (!scriptPrivate->context || !scriptPrivate->context->isValid()))
return;
- bool needRewrite = true;
QString code;
int id = scriptPrivate->bindingId;
@@ -137,7 +132,6 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte
Q_ASSERT(typeData);
if (QQmlCompiledData *cdata = typeData->compiledData()) {
- needRewrite = false;
code = cdata->primitives.at(id);
m_url = cdata->name;
}
@@ -146,11 +140,6 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte
}
}
- if (needRewrite) {
- QQmlRewrite::RewriteBinding rewriteBinding;
- code = rewriteBinding(scriptPrivate->script);
- }
-
setNotifyOnValueChanged(true);
QQmlAbstractExpression::setContext(QQmlContextData::get(ctxt ? ctxt : scriptPrivate->context));
setScopeObject(obj ? obj : scriptPrivate->scope);
@@ -159,7 +148,7 @@ QQmlBinding::QQmlBinding(const QQmlScriptString &script, QObject *obj, QQmlConte
m_lineNumber = scriptPrivate->lineNumber;
m_columnNumber = scriptPrivate->columnNumber;
- v8function = evalFunction(context(), scopeObject(), code, QString(), m_lineNumber);
+ v4function = qmlBinding(context(), scopeObject(), code, QString(), m_lineNumber);
}
QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt)
@@ -170,14 +159,11 @@ QQmlBinding::QQmlBinding(const QString &str, QObject *obj, QQmlContextData *ctxt
QQmlAbstractExpression::setContext(ctxt);
setScopeObject(obj);
- QQmlRewrite::RewriteBinding rewriteBinding;
- QString code = rewriteBinding(str);
-
m_expression = str.toUtf8();
- v8function = evalFunction(ctxt, obj, code, QString(), 0);
+ v4function = qmlBinding(ctxt, obj, str, QString(), 0);
}
-QQmlBinding::QQmlBinding(const QString &str, bool isRewritten, QObject *obj,
+QQmlBinding::QQmlBinding(const QString &str, QObject *obj,
QQmlContextData *ctxt,
const QString &url, quint16 lineNumber, quint16 columnNumber)
: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding),
@@ -187,28 +173,12 @@ QQmlBinding::QQmlBinding(const QString &str, bool isRewritten, QObject *obj,
QQmlAbstractExpression::setContext(ctxt);
setScopeObject(obj);
- QString code;
- if (isRewritten) {
- code = str;
- } else {
- QQmlRewrite::RewriteBinding rewriteBinding;
- code = rewriteBinding(str);
- }
-
m_expression = str.toUtf8();
- v8function = evalFunction(ctxt, obj, code, url, m_lineNumber);
+ v4function = qmlBinding(ctxt, obj, str, url, m_lineNumber);
}
-/*!
- \internal
-
- To avoid exposing v8 in the public API, functionPtr must be a pointer to a v8::Handle<v8::Function>.
- For example:
- v8::Handle<v8::Function> function;
- new QQmlBinding(&function, scope, ctxt);
- */
-QQmlBinding::QQmlBinding(void *functionPtr, QObject *obj, QQmlContextData *ctxt,
+QQmlBinding::QQmlBinding(const QV4::Value &functionPtr, QObject *obj, QQmlContextData *ctxt,
const QString &url, quint16 lineNumber, quint16 columnNumber)
: QQmlJavaScriptExpression(&QQmlBinding_jsvtable), QQmlAbstractBinding(Binding),
m_url(url), m_lineNumber(lineNumber), m_columnNumber(columnNumber)
@@ -217,12 +187,11 @@ QQmlBinding::QQmlBinding(void *functionPtr, QObject *obj, QQmlContextData *ctxt,
QQmlAbstractExpression::setContext(ctxt);
setScopeObject(obj);
- v8function = qPersistentNew<v8::Function>(*(v8::Handle<v8::Function> *)functionPtr);
+ v4function = functionPtr;
}
QQmlBinding::~QQmlBinding()
{
- qPersistentDispose(v8function);
}
void QQmlBinding::setEvaluateFlags(EvaluateFlags flags)
@@ -279,10 +248,8 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags)
bool isUndefined = false;
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(ep->v8engine()->context());
- v8::Local<v8::Value> result =
- QQmlJavaScriptExpression::evaluate(context(), v8function, &isUndefined);
+ QV4::Value result =
+ QQmlJavaScriptExpression::evaluate(context(), v4function.value(), &isUndefined);
trace.event("writing binding result");
@@ -322,10 +289,8 @@ QVariant QQmlBinding::evaluate()
bool isUndefined = false;
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(ep->v8engine()->context());
- v8::Local<v8::Value> result =
- QQmlJavaScriptExpression::evaluate(context(), v8function, &isUndefined);
+ QV4::Value result =
+ QQmlJavaScriptExpression::evaluate(context(), v4function.value(), &isUndefined);
ep->dereferenceScarceResources();
@@ -336,7 +301,7 @@ QString QQmlBinding::expressionIdentifier(QQmlJavaScriptExpression *e)
{
QQmlBinding *This = static_cast<QQmlBinding *>(e);
- return QLatin1Char('"') + QString::fromUtf8(This->m_expression) + QLatin1Char('"');
+ return This->m_url + QLatin1Char(':') + QString::number(This->m_lineNumber) + QLatin1Char(':') + QString::number(This->m_columnNumber);
}
void QQmlBinding::expressionChanged(QQmlJavaScriptExpression *e)
diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h
index 5b547595e2..ea703e8d38 100644
--- a/src/qml/qml/qqmlbinding_p.h
+++ b/src/qml/qml/qqmlbinding_p.h
@@ -82,9 +82,9 @@ public:
QQmlBinding(const QString &, QObject *, QQmlContext *);
QQmlBinding(const QQmlScriptString &, QObject *, QQmlContext *);
QQmlBinding(const QString &, QObject *, QQmlContextData *);
- QQmlBinding(const QString &, bool isRewritten, QObject *, QQmlContextData *,
+ QQmlBinding(const QString &, QObject *, QQmlContextData *,
const QString &url, quint16 lineNumber, quint16 columnNumber);
- QQmlBinding(void *, QObject *, QQmlContextData *,
+ QQmlBinding(const QV4::Value &, QObject *, QQmlContextData *,
const QString &url, quint16 lineNumber, quint16 columnNumber);
void setTarget(const QQmlProperty &);
@@ -131,7 +131,7 @@ protected:
~QQmlBinding();
private:
- v8::Persistent<v8::Function> v8function;
+ QV4::PersistentValue v4function;
inline bool updatingFlag() const;
inline void setUpdatingFlag(bool);
diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp
index 49f6dec7fa..0c922294b4 100644
--- a/src/qml/qml/qqmlboundsignal.cpp
+++ b/src/qml/qml/qqmlboundsignal.cpp
@@ -50,11 +50,12 @@
#include "qqml.h"
#include "qqmlcontext.h"
#include "qqmlglobal_p.h"
-#include "qqmlrewrite_p.h"
#include <private/qqmlprofilerservice_p.h>
#include <private/qv8debugservice_p.h>
#include "qqmlinfo.h"
+#include <private/qv4value_p.h>
+
#include <QtCore/qstringbuilder.h>
#include <QtCore/qdebug.h>
@@ -66,45 +67,23 @@ static QQmlJavaScriptExpression::VTable QQmlBoundSignalExpression_jsvtable = {
};
QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
- QQmlContextData *ctxt, QObject *scope, const QByteArray &expression,
- bool isRewritten, const QString &fileName, quint16 line, quint16 column)
- : QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable),
- m_fileName(fileName),
- m_line(line),
- m_column(column),
- m_parameterCountForJS(-1),
- m_target(target),
- m_index(index),
- m_expressionFunctionValid(false),
- m_expressionFunctionRewritten(isRewritten),
- m_invalidParameterName(false)
-{
- init(ctxt, scope);
- if (isRewritten)
- m_expressionUtf8 = expression;
- else
- m_expression = QString::fromUtf8(expression);
-}
-
-QQmlBoundSignalExpression::QQmlBoundSignalExpression(QObject *target, int index,
QQmlContextData *ctxt, QObject *scope, const QString &expression,
- bool isRewritten, const QString &fileName, quint16 line, quint16 column)
+ const QString &fileName, quint16 line, quint16 column,
+ const QString &handlerName,
+ const QString &parameterString)
: QQmlJavaScriptExpression(&QQmlBoundSignalExpression_jsvtable),
m_fileName(fileName),
m_line(line),
m_column(column),
- m_parameterCountForJS(-1),
m_target(target),
m_index(index),
m_expressionFunctionValid(false),
- m_expressionFunctionRewritten(isRewritten),
m_invalidParameterName(false)
{
init(ctxt, scope);
- if (isRewritten)
- m_expressionUtf8 = expression.toUtf8();
- else
- m_expression = expression;
+ m_handlerName = handlerName;
+ m_parameterString = parameterString;
+ m_expression = expression;
}
void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope)
@@ -119,8 +98,6 @@ void QQmlBoundSignalExpression::init(QQmlContextData *ctxt, QObject *scope)
QQmlBoundSignalExpression::~QQmlBoundSignalExpression()
{
- qPersistentDispose(m_v8function);
- qPersistentDispose(m_v8qmlscope);
}
QString QQmlBoundSignalExpression::expressionIdentifier(QQmlJavaScriptExpression *e)
@@ -138,11 +115,7 @@ QString QQmlBoundSignalExpression::expression() const
{
if (m_expressionFunctionValid) {
Q_ASSERT (context() && engine());
- v8::HandleScope handle_scope;
- v8::Context::Scope context_scope(QQmlEnginePrivate::get(engine())->v8engine()->context());
- return QV8Engine::toStringStatic(m_v8function->ToString());
- } else if (!m_expressionUtf8.isEmpty()) {
- return QString::fromUtf8(m_expressionUtf8);
+ return m_v8function.value().toQString();
} else {
return m_expression;
}
@@ -161,100 +134,80 @@ void QQmlBoundSignalExpression::evaluate(void **a)
ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
{
- v8::HandleScope handle_scope;
- v8::Context::Scope context_scope(ep->v8engine()->context());
if (!m_expressionFunctionValid) {
-
- //TODO: look at using the property cache here (as in the compiler)
- // for further optimization
- QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index);
- QQmlRewrite::RewriteSignalHandler rewriter;
-
QString expression;
- bool ok = true;
-
- if (m_expressionFunctionRewritten) {
- expression = QString::fromUtf8(m_expressionUtf8);
-
- //if we need parameters, and the rewrite doesn't include them,
- //create and insert the parameter string now
- if (m_parameterCountForJS == -1 && signal.parameterCount()) {
- const QString &parameters = rewriter.createParameterString(signal.parameterNames(),
- ep->v8engine()->illegalNames());
- int index = expression.indexOf(QLatin1Char('('), 1);
- Q_ASSERT(index > -1);
- expression.insert(index + 1, parameters);
- setParameterCountForJS(rewriter.parameterCountForJS());
+ expression = QStringLiteral("(function ");
+ expression += m_handlerName;
+ expression += QLatin1Char('(');
+
+ if (m_parameterString.isEmpty()) {
+ QString error;
+ //TODO: look at using the property cache here (as in the compiler)
+ // for further optimization
+ QMetaMethod signal = QMetaObjectPrivate::signal(m_target->metaObject(), m_index);
+ expression += QQmlPropertyCache::signalParameterStringForJS(engine(), signal.parameterNames(), &error);
+
+ if (!error.isEmpty()) {
+ qmlInfo(scopeObject()) << error;
+ m_invalidParameterName = true;
+ ep->dereferenceScarceResources();
+ return;
}
+ } else
+ expression += m_parameterString;
- m_expressionUtf8.clear();
- } else {
- //expression is still in its original form, so perform a full rewrite
- expression = rewriter(m_expression, QString()/*no name hint available*/, &ok,
- signal.parameterNames(),
- ep->v8engine()->illegalNames());
- setParameterCountForJS(rewriter.parameterCountForJS());
- m_expression.clear();
- }
+ expression += QStringLiteral(") { ");
+ expression += m_expression;
+ expression += QStringLiteral(" })");
- if (rewriter.hasParameterError()) {
- qmlInfo(scopeObject()) << rewriter.parameterError();
- m_invalidParameterName = true;
- ep->dereferenceScarceResources();
- return;
- }
+ m_expression.clear();
+ m_handlerName.clear();
+ m_parameterString.clear();
- if (ok) {
- m_v8function = evalFunction(context(), scopeObject(), expression,
- m_fileName, m_line, &m_v8qmlscope);
- }
+ m_v8function = evalFunction(context(), scopeObject(), expression,
+ m_fileName, m_line, &m_v8qmlscope);
- if (m_v8function.IsEmpty() || m_v8function->IsNull()) {
+ if (m_v8function.isEmpty() || m_v8function.value().isNull()) {
ep->dereferenceScarceResources();
return; // could not evaluate function. Not valid.
}
- setUseSharedContext(false);
m_expressionFunctionValid = true;
}
- if (!hasParameterInfo()) {
- QQmlJavaScriptExpression::evaluate(context(), m_v8function, 0);
- } else {
- QV8Engine *engine = ep->v8engine();
- QVarLengthArray<int, 9> dummy;
- //TODO: lookup via signal index rather than method index as an optimization
- int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex();
- int *argsTypes = QQmlPropertyCache::methodParameterTypes(m_target, methodIndex, dummy, 0);
- int argCount = argsTypes ? m_parameterCountForJS : 0;
-
- QVarLengthArray<v8::Handle<v8::Value>, 9> args(argCount);
-
- for (int ii = 0; ii < argCount; ++ii) {
- int type = argsTypes[ii + 1];
- //### ideally we would use metaTypeToJS, however it currently gives different results
- // for several cases (such as QVariant type and QObject-derived types)
- //args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
- if (type == QMetaType::QVariant) {
- args[ii] = engine->fromVariant(*((QVariant *)a[ii + 1]));
- } else if (type == QMetaType::Int) {
- //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise
- args[ii] = v8::Integer::New(*reinterpret_cast<const int*>(a[ii + 1]));
- } else if (type == qMetaTypeId<QQmlV8Handle>()) {
- args[ii] = reinterpret_cast<QQmlV8Handle *>(a[ii + 1])->toHandle();
- } else if (ep->isQObject(type)) {
- if (!*reinterpret_cast<void* const *>(a[ii + 1]))
- args[ii] = v8::Null();
- else
- args[ii] = engine->newQObject(*reinterpret_cast<QObject* const *>(a[ii + 1]));
- } else {
- args[ii] = engine->fromVariant(QVariant(type, a[ii + 1]));
- }
+ QV8Engine *engine = ep->v8engine();
+ QVarLengthArray<int, 9> dummy;
+ //TODO: lookup via signal index rather than method index as an optimization
+ int methodIndex = QMetaObjectPrivate::signal(m_target->metaObject(), m_index).methodIndex();
+ int *argsTypes = QQmlPropertyCache::methodParameterTypes(m_target, methodIndex, dummy, 0);
+ int argCount = argsTypes ? *argsTypes : 0;
+
+ QVarLengthArray<QV4::Value, 9> args(argCount);
+
+ for (int ii = 0; ii < argCount; ++ii) {
+ int type = argsTypes[ii + 1];
+ //### ideally we would use metaTypeToJS, however it currently gives different results
+ // for several cases (such as QVariant type and QObject-derived types)
+ //args[ii] = engine->metaTypeToJS(type, a[ii + 1]);
+ if (type == QMetaType::QVariant) {
+ args[ii] = engine->fromVariant(*((QVariant *)a[ii + 1]));
+ } else if (type == QMetaType::Int) {
+ //### optimization. Can go away if we switch to metaTypeToJS, or be expanded otherwise
+ args[ii] = QV4::Value::fromInt32(*reinterpret_cast<const int*>(a[ii + 1]));
+ } else if (type == qMetaTypeId<QQmlV4Handle>()) {
+ args[ii] = reinterpret_cast<QQmlV4Handle *>(a[ii + 1])->toValue();
+ } else if (ep->isQObject(type)) {
+ if (!*reinterpret_cast<void* const *>(a[ii + 1]))
+ args[ii] = QV4::Value::nullValue();
+ else
+ args[ii] = QV4::QObjectWrapper::wrap(ep->v4engine(), *reinterpret_cast<QObject* const *>(a[ii + 1]));
+ } else {
+ args[ii] = engine->fromVariant(QVariant(type, a[ii + 1]));
}
-
- QQmlJavaScriptExpression::evaluate(context(), m_v8function, argCount, args.data(), 0);
}
+
+ QQmlJavaScriptExpression::evaluate(context(), m_v8function.value(), argCount, args.data(), 0);
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
}
diff --git a/src/qml/qml/qqmlboundsignal_p.h b/src/qml/qml/qqmlboundsignal_p.h
index 910e1e3f1e..ffb3d06770 100644
--- a/src/qml/qml/qqmlboundsignal_p.h
+++ b/src/qml/qml/qqmlboundsignal_p.h
@@ -70,18 +70,16 @@ class Q_QML_PRIVATE_EXPORT QQmlBoundSignalExpression : public QQmlAbstractExpres
{
public:
QQmlBoundSignalExpression(QObject *target, int index,
- QQmlContextData *ctxt, QObject *scope, const QByteArray &expression,
- bool isRewritten, const QString &fileName, quint16 line, quint16 column);
- QQmlBoundSignalExpression(QObject *target, int index,
QQmlContextData *ctxt, QObject *scope, const QString &expression,
- bool isRewritten, const QString &fileName, quint16 line, quint16 column);
+ const QString &fileName, quint16 line, quint16 column,
+ const QString &handlerName = QString(),
+ const QString &parameterString = QString());
+
// "inherited" from QQmlJavaScriptExpression.
static QString expressionIdentifier(QQmlJavaScriptExpression *);
static void expressionChanged(QQmlJavaScriptExpression *);
- void setParameterCountForJS(int count) { m_parameterCountForJS = count; }
-
// evaluation of a bound signal expression doesn't return any value
void evaluate(void **a);
@@ -97,27 +95,23 @@ private:
~QQmlBoundSignalExpression();
void init(QQmlContextData *ctxt, QObject *scope);
- bool hasParameterInfo() const { return m_parameterCountForJS > 0; }
- v8::Persistent<v8::Object> m_v8qmlscope;
- v8::Persistent<v8::Function> m_v8function;
+ QV4::PersistentValue m_v8qmlscope;
+ QV4::PersistentValue m_v8function;
- //either expressionUtf8 or expression will be used (but not both).
- //once m_v8function is valid, we clear both expressions, and
+ QString m_handlerName;
+ QString m_parameterString;
+ //once m_v8function is valid, we clear expression and
//extract it from m_v8function if needed.
- QByteArray m_expressionUtf8;
QString m_expression; //only used when expression needs to be rewritten
QString m_fileName;
quint16 m_line;
quint16 m_column;
- int m_parameterCountForJS;
-
QObject *m_target;
int m_index;
bool m_expressionFunctionValid:1;
- bool m_expressionFunctionRewritten:1;
bool m_invalidParameterName:1;
};
diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp
index cd527f6b1b..abe278f570 100644
--- a/src/qml/qml/qqmlcompileddata.cpp
+++ b/src/qml/qml/qqmlcompileddata.cpp
@@ -119,9 +119,6 @@ QQmlCompiledData::~QQmlCompiledData()
for (int ii = 0; ii < propertyCaches.count(); ++ii)
propertyCaches.at(ii)->release();
- for (int ii = 0; ii < contextCaches.count(); ++ii)
- contextCaches.at(ii)->release();
-
for (int ii = 0; ii < scripts.count(); ++ii)
scripts.at(ii)->release();
@@ -134,8 +131,6 @@ QQmlCompiledData::~QQmlCompiledData()
void QQmlCompiledData::clear()
{
- for (int ii = 0; ii < programs.count(); ++ii)
- qPersistentDispose(programs[ii].bindings);
}
/*!
diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp
index 7b27a4c314..ddefffe8e2 100644
--- a/src/qml/qml/qqmlcompiler.cpp
+++ b/src/qml/qml/qqmlcompiler.cpp
@@ -53,15 +53,15 @@
#include "qqmlcontext_p.h"
#include "qqmlcomponent_p.h"
#include <private/qqmljsast_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljsmemorypool_p.h>
#include "qqmlvmemetaobject_p.h"
#include "qqmlexpression_p.h"
#include "qqmlproperty_p.h"
-#include "qqmlrewrite_p.h"
#include "qqmlscriptstring.h"
#include "qqmlglobal_p.h"
#include "qqmlbinding_p.h"
#include "qqmlabstracturlinterceptor_p.h"
-#include <private/qv4compiler_p.h>
#include <QDebug>
#include <QPointF>
@@ -927,18 +927,6 @@ void QQmlCompiler::compileTree(QQmlScript::Object *tree)
output->addInstruction(import);
}
- if (!compileState->v8BindingProgram.isEmpty()) {
- Instruction::InitV8Bindings bindings;
- int index = output->programs.count();
-
- typedef QQmlCompiledData::V8Program V8Program;
- output->programs.append(V8Program(compileState->v8BindingProgram, output));
-
- bindings.programIndex = index;
- bindings.line = compileState->v8BindingProgramLine;
- output->addInstruction(bindings);
- }
-
genObject(tree);
Instruction::SetDefault def;
@@ -1265,8 +1253,7 @@ void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
ss.propertyIndex = prop->index;
ss.value = output->indexForString(script);
ss.scope = prop->scriptStringScope;
-// ss.bindingId = rewriteBinding(script, prop->name());
- ss.bindingId = rewriteBinding(prop->values.first()->value, QString()); // XXX
+ ss.bindingId = output->indexForString(prop->values.first()->value.asScript());
ss.line = prop->location.start.line;
ss.column = prop->location.start.column;
ss.isStringLiteral = prop->values.first()->value.isString();
@@ -1326,18 +1313,10 @@ void QQmlCompiler::genObjectBody(QQmlScript::Object *obj)
} else if (v->type == Value::SignalExpression) {
Instruction::StoreSignal store;
+ store.handlerName = output->indexForString(prop->name().toString());
+ store.parameters = output->indexForString(obj->metatype->signalParameterStringForJS(prop->index));
store.signalIndex = prop->index;
-
- const QList<QByteArray> &parameterNameList = obj->metatype->signalParameterNames(prop->index);
- QQmlRewrite::RewriteSignalHandler rewriter;
- int count = 0;
- const QString &rewrite = rewriter(v->value.asAST(), v->value.asScript(),
- prop->name().toString(),
- obj->metatype->signalParameterStringForJS(prop->index, &count),
- parameterNameList);
- store.value = output->indexForByteArray(rewrite.toUtf8());
- store.parameterCount =
- (rewriter.parameterAccess() == QQmlRewrite::RewriteSignalHandler::ParametersUnaccessed) ? 0 : count;
+ store.value = output->indexForString(v->value.asScript());
store.context = v->signalExpressionContextStack;
store.line = v->location.start.line;
store.column = v->location.start.column;
@@ -1461,18 +1440,6 @@ void QQmlCompiler::genComponent(QQmlScript::Object *obj)
init.compiledBinding = output->indexForByteArray(compileState->compiledBindingData);
output->addInstruction(init);
- if (!compileState->v8BindingProgram.isEmpty()) {
- Instruction::InitV8Bindings bindings;
- int index = output->programs.count();
-
- typedef QQmlCompiledData::V8Program V8Program;
- output->programs.append(V8Program(compileState->v8BindingProgram, output));
-
- bindings.programIndex = index;
- bindings.line = compileState->v8BindingProgramLine;
- output->addInstruction(bindings);
- }
-
genObject(root);
Instruction::SetDefault def;
@@ -1710,13 +1677,12 @@ bool QQmlCompiler::buildSignal(QQmlScript::Property *prop, QQmlScript::Object *o
//all handlers should be on the original, rather than cloned signals in order
//to ensure all parameters are available (see qqmlboundsignal constructor for more details)
prop->index = obj->metatype->originalClone(prop->index);
+ prop->values.first()->signalExpressionContextStack = ctxt.stack;
QString errorString;
- obj->metatype->signalParameterStringForJS(prop->index, 0, &errorString);
+ obj->metatype->signalParameterStringForJS(prop->index, &errorString);
if (!errorString.isEmpty())
COMPILE_EXCEPTION(prop, errorString);
-
- prop->values.first()->signalExpressionContextStack = ctxt.stack;
}
}
@@ -2310,7 +2276,6 @@ bool QQmlCompiler::buildListProperty(QQmlScript::Property *prop,
assignedBinding = true;
COMPILE_CHECK(buildBinding(v, prop, ctxt));
- v->type = Value::PropertyBinding;
} else {
COMPILE_EXCEPTION(v, tr("Cannot assign primitives to lists"));
}
@@ -2517,8 +2482,6 @@ bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop,
if (!buildLiteralBinding(v, prop, ctxt))
COMPILE_CHECK(buildBinding(v, prop, ctxt));
- v->type = Value::PropertyBinding;
-
} else {
COMPILE_CHECK(testLiteralAssignment(prop, v));
@@ -2650,22 +2613,9 @@ const QMetaObject *QQmlCompiler::resolveType(const QString& name) const
return qmltype->metaObject();
}
-// similar to logic of completeComponentBuild, but also sticks data
-// into primitives at the end
-int QQmlCompiler::rewriteBinding(const QQmlScript::Variant& value, const QString& name)
-{
- QQmlRewrite::RewriteBinding rewriteBinding;
- rewriteBinding.setName(QLatin1Char('$') + name.mid(name.lastIndexOf(QLatin1Char('.')) + 1));
-
- QString rewrite = rewriteBinding(value.asAST(), value.asScript(), 0);
-
- return output->indexForString(rewrite);
-}
-
-QString QQmlCompiler::rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name)
+int QQmlCompiler::bindingIdentifier(const Variant &value)
{
- QQmlRewrite::RewriteSignalHandler rewriteSignalHandler;
- return rewriteSignalHandler(value.asAST(), value.asScript(), name);
+ return output->indexForString(value.asScript());
}
// Ensures that the dynamic meta specification on obj is valid
@@ -2706,7 +2656,7 @@ bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
tr("Property names cannot begin with an upper case letter"));
}
- if (enginePrivate->v8engine()->illegalNames().contains(prop.name)) {
+ if (enginePrivate->v8engine()->illegalNames().contains(prop.name.toString())) {
COMPILE_EXCEPTION_LOCATION(prop.nameLocation.line,
prop.nameLocation.column,
tr("Illegal property name"));
@@ -2726,7 +2676,7 @@ bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
if (currSig.name.at(0).isUpper())
COMPILE_EXCEPTION(&currSig, tr("Signal names cannot begin with an upper case letter"));
- if (enginePrivate->v8engine()->illegalNames().contains(currSig.name))
+ if (enginePrivate->v8engine()->illegalNames().contains(currSig.name.toString()))
COMPILE_EXCEPTION(&currSig, tr("Illegal signal name"));
}
@@ -2748,7 +2698,7 @@ bool QQmlCompiler::checkDynamicMeta(QQmlScript::Object *obj)
if (currSlot.name.at(0).isUpper())
COMPILE_EXCEPTION(&currSlot, tr("Method names cannot begin with an upper case letter"));
- if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name))
+ if (enginePrivate->v8engine()->illegalNames().contains(currSlot.name.toString()))
COMPILE_EXCEPTION(&currSlot, tr("Illegal method name"));
}
@@ -2783,8 +2733,6 @@ bool QQmlCompiler::mergeDynamicMetaProperties(QQmlScript::Object *obj)
return true;
}
-#include <private/qqmljsparser_p.h>
-
static QStringList astNodeToStringList(QQmlJS::AST::Node *node)
{
if (node->kind == QQmlJS::AST::Node::Kind_IdentifierExpression) {
@@ -3443,6 +3391,7 @@ bool QQmlCompiler::buildBinding(QQmlScript::Value *value,
reference->value = value;
reference->bindingContext = ctxt;
addBindingReference(reference);
+ value->type = Value::PropertyBinding;
return true;
}
@@ -3480,6 +3429,7 @@ bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
reference->text = text;
reference->n = n;
v->bindingReference = reference;
+ v->type = Value::PropertyBinding;
return true;
}
@@ -3508,6 +3458,7 @@ bool QQmlCompiler::buildLiteralBinding(QQmlScript::Value *v,
reference->comment = comment;
reference->n = n;
v->bindingReference = reference;
+ v->type = Value::PropertyBinding;
return true;
}
@@ -3550,66 +3501,11 @@ void QQmlCompiler::genBindingAssignment(QQmlScript::Value *binding,
output->addInstruction(store);
} else
#endif
- if (ref.dataType == BindingReference::V4) {
- const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
-
- Instruction::StoreV4Binding store;
- store.value = js.compiledIndex;
- store.fallbackValue = js.sharedIndex;
- store.context = js.bindingContext.stack;
- store.owner = js.bindingContext.owner;
- store.isAlias = prop->isAlias;
- if (valueTypeProperty) {
- store.property = ((prop->index << 16) | valueTypeProperty->index);
- store.propType = valueTypeProperty->type;
- store.isRoot = (compileState->root == valueTypeProperty->parent);
- } else {
- store.property = prop->index;
- store.propType = 0;
- store.isRoot = (compileState->root == obj);
- }
- store.line = binding->location.start.line;
- store.column = binding->location.start.column;
- output->addInstruction(store);
-
- if (store.fallbackValue > -1) {
- //also create v8 instruction (needed to properly configure the fallback v8 binding)
- JSBindingReference &js = static_cast<JSBindingReference &>(*binding->bindingReference);
- js.dataType = BindingReference::V8;
- genBindingAssignment(binding, prop, obj, valueTypeProperty);
- }
- } else if (ref.dataType == BindingReference::V8) {
- const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
-
- Instruction::StoreV8Binding store;
- store.value = js.sharedIndex;
- store.context = js.bindingContext.stack;
- store.owner = js.bindingContext.owner;
- store.isAlias = prop->isAlias;
- store.isSafe = js.isSafe;
- if (valueTypeProperty) {
- store.isRoot = (compileState->root == valueTypeProperty->parent);
- } else {
- store.isRoot = (compileState->root == obj);
- }
- store.isFallback = js.compiledIndex > -1;
- store.line = binding->location.start.line;
- store.column = binding->location.start.column;
-
- Q_ASSERT(js.bindingContext.owner == 0 ||
- (js.bindingContext.owner != 0 && valueTypeProperty));
- if (js.bindingContext.owner) {
- store.property = genValueTypeData(prop, valueTypeProperty);
- } else {
- store.property = prop->core;
- }
-
- output->addInstruction(store);
- } else if (ref.dataType == BindingReference::QtScript) {
+ if (ref.dataType == BindingReference::QtScript) {
const JSBindingReference &js = static_cast<const JSBindingReference &>(ref);
Instruction::StoreBinding store;
- store.value = output->indexForString(js.rewrittenExpression);
+ store.value = output->indexForString(js.expression.asScript());
store.context = js.bindingContext.stack;
store.owner = js.bindingContext.owner;
store.line = binding->location.start.line;
@@ -3642,10 +3538,10 @@ int QQmlCompiler::genContextCache()
if (compileState->ids.count() == 0)
return -1;
- QQmlIntegerCache *cache = new QQmlIntegerCache();
- cache->reserve(compileState->ids.count());
- for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o))
- cache->add(o->id, o->idIndex);
+ QVector<QQmlContextData::ObjectIdMapping> cache(compileState->ids.count());
+ int i = 0;
+ for (Object *o = compileState->ids.first(); o; o = compileState->ids.next(o), ++i)
+ cache[i] = QQmlContextData::ObjectIdMapping(o->id, o->idIndex);
output->contextCaches.append(cache);
return output->contextCaches.count() - 1;
@@ -3669,109 +3565,15 @@ bool QQmlCompiler::completeComponentBuild()
aliasObject = compileState->aliasingObjects.next(aliasObject))
COMPILE_CHECK(buildDynamicMetaAliases(aliasObject));
- QV4Compiler::Expression expr(unit->imports());
- expr.component = compileState->root;
- expr.ids = &compileState->ids;
- expr.importCache = output->importCache;
-
- QV4Compiler bindingCompiler;
-
- QList<JSBindingReference*> sharedBindings;
-
for (JSBindingReference *b = compileState->bindings.first(); b; b = b->nextReference) {
JSBindingReference &binding = *b;
+ binding.dataType = BindingReference::QtScript;
- // First try v4
- expr.context = binding.bindingContext.object;
- expr.property = binding.property;
- expr.expression = binding.expression;
-
- bool needsFallback = false;
- int index = bindingCompiler.compile(expr, enginePrivate, &needsFallback);
- if (index != -1) {
- binding.dataType = BindingReference::V4;
- binding.compiledIndex = index;
- binding.sharedIndex = -1;
- if (componentStats)
- componentStats->componentStat.optimizedBindings.append(b->value->location);
-
- if (!needsFallback)
- continue;
-
- // Drop through. We need to create a V8 binding in case the V4 binding is invalidated
- }
-
- // Pre-rewrite the expression
- QString expression = binding.expression.asScript();
-
- QQmlRewrite::RewriteBinding rewriteBinding;
- rewriteBinding.setName(QLatin1Char('$')+binding.property->name().toString());
- bool isSharable = false;
- bool isSafe = false;
- binding.rewrittenExpression = rewriteBinding(binding.expression.asAST(), expression, &isSharable, &isSafe);
- binding.isSafe = isSafe;
-
- if (isSharable && binding.property->type != qMetaTypeId<QQmlBinding*>()) {
- sharedBindings.append(b);
-
- if (!needsFallback) {
- binding.dataType = BindingReference::V8;
- binding.compiledIndex = -1;
-
- if (componentStats)
- componentStats->componentStat.sharedBindings.append(b->value->location);
- }
- } else {
- Q_ASSERT(!needsFallback);
- binding.dataType = BindingReference::QtScript;
-
- if (componentStats)
- componentStats->componentStat.scriptBindings.append(b->value->location);
- }
- }
-
- if (!sharedBindings.isEmpty()) {
- struct Sort {
- static bool lt(const JSBindingReference *lhs, const JSBindingReference *rhs)
- {
- return lhs->value->location.start.line < rhs->value->location.start.line;
- }
- };
-
- qSort(sharedBindings.begin(), sharedBindings.end(), Sort::lt);
-
- int startLineNumber = sharedBindings.at(0)->value->location.start.line;
- int lineNumber = startLineNumber;
-
- QByteArray functionArray("[", 1);
- for (int ii = 0; ii < sharedBindings.count(); ++ii) {
-
- JSBindingReference *reference = sharedBindings.at(ii);
- QQmlScript::Value *value = reference->value;
- const QString &expression = reference->rewrittenExpression;
-
- if (ii != 0) functionArray.append(",", 1);
-
- while (lineNumber < value->location.start.line) {
- lineNumber++;
- functionArray.append("\n", 1);
- }
-
- functionArray += expression.toUtf8();
- lineNumber += expression.count(QLatin1Char('\n'));
-
- reference->sharedIndex = ii;
- }
- functionArray.append("]", 1);
-
- compileState->v8BindingProgram = functionArray;
- compileState->v8BindingProgramLine = startLineNumber;
+ if (componentStats)
+ componentStats->componentStat.scriptBindings.append(b->value->location);
}
- if (bindingCompiler.isValid())
- compileState->compiledBindingData = bindingCompiler.program();
-
// Check pop()'s matched push()'s
Q_ASSERT(compileState->objectDepth.depth() == 0);
Q_ASSERT(compileState->listDepth.depth() == 0);
@@ -3790,44 +3592,6 @@ void QQmlCompiler::dumpStats()
qWarning().nospace() << " Component Line " << stat.lineNumber;
qWarning().nospace() << " Total Objects: " << stat.objects;
qWarning().nospace() << " IDs Used: " << stat.ids;
- qWarning().nospace() << " Optimized Bindings: " << stat.optimizedBindings.count();
-
- {
- QByteArray output;
- for (int ii = 0; ii < stat.optimizedBindings.count(); ++ii) {
- if (0 == (ii % 10)) {
- if (ii) output.append("\n");
- output.append(" ");
- }
-
- output.append('(');
- output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.line));
- output.append(':');
- output.append(QByteArray::number(stat.optimizedBindings.at(ii).start.column));
- output.append(") ");
- }
- if (!output.isEmpty())
- qWarning().nospace() << output.constData();
- }
-
- qWarning().nospace() << " Shared Bindings: " << stat.sharedBindings.count();
- {
- QByteArray output;
- for (int ii = 0; ii < stat.sharedBindings.count(); ++ii) {
- if (0 == (ii % 10)) {
- if (ii) output.append('\n');
- output.append(" ");
- }
-
- output.append('(');
- output.append(QByteArray::number(stat.sharedBindings.at(ii).start.line));
- output.append(':');
- output.append(QByteArray::number(stat.sharedBindings.at(ii).start.column));
- output.append(") ");
- }
- if (!output.isEmpty())
- qWarning().nospace() << output.constData();
- }
qWarning().nospace() << " QScript Bindings: " << stat.scriptBindings.count();
{
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index 5ad2ee5c48..bc013358f5 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -55,15 +55,14 @@
#include "qqml.h"
#include "qqmlerror.h"
-#include <private/qv8_p.h>
#include "qqmlinstruction_p.h"
#include "qqmlscript_p.h"
#include "qqmlengine_p.h"
#include <private/qbitfield_p.h>
#include "qqmlpropertycache_p.h"
-#include "qqmlintegercache_p.h"
#include "qqmltypenamecache_p.h"
#include "qqmltypeloader_p.h"
+#include "private/qv4identifier_p.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qset.h>
@@ -111,7 +110,7 @@ public:
: program(p), cdata(c) {}
QByteArray program;
- v8::Persistent<v8::Array> bindings;
+ QV4::PersistentValue bindings;
QQmlCompiledData *cdata;
};
@@ -122,7 +121,7 @@ public:
QList<QByteArray> datas;
QByteArray bytecode;
QList<QQmlPropertyCache *> propertyCaches;
- QList<QQmlIntegerCache *> contextCaches;
+ QList<QVector<QQmlContextData::ObjectIdMapping> > contextCaches;
QList<QQmlScriptData *> scripts;
QList<QUrl> urls;
@@ -187,7 +186,7 @@ namespace QQmlCompilerTypes {
struct BindingReference
{
- enum DataType { QtScript, V4, V8,
+ enum DataType { QtScript,
Tr, TrId };
DataType dataType;
};
@@ -195,17 +194,15 @@ namespace QQmlCompilerTypes {
struct JSBindingReference : public QQmlPool::Class,
public BindingReference
{
- JSBindingReference() : isSafe(false), nextReference(0) {}
+ JSBindingReference() : nextReference(0) {}
QQmlScript::Variant expression;
QQmlScript::Property *property;
QQmlScript::Value *value;
- int compiledIndex:15;
- int sharedIndex:15;
- bool isSafe:1;
+ int compiledIndex : 16;
+ int sharedIndex : 16;
- QString rewrittenExpression;
BindingContext bindingContext;
JSBindingReference *nextReference;
@@ -255,7 +252,7 @@ namespace QQmlCompilerTypes {
{
ComponentCompileState()
: parserStatusCount(0), totalBindingsCount(0), pushedProperties(0), nested(false),
- v8BindingProgramLine(-1), root(0) {}
+ root(0) {}
IdList ids;
int parserStatusCount;
@@ -264,8 +261,6 @@ namespace QQmlCompilerTypes {
bool nested;
QByteArray compiledBindingData;
- QByteArray v8BindingProgram;
- int v8BindingProgramLine;
DepthStack objectDepth;
DepthStack listDepth;
@@ -299,8 +294,7 @@ public:
int evaluateEnum(const QHashedStringRef &scope, const QByteArray& enumValue, bool *ok) const; // for QQmlCustomParser::evaluateEnum
const QMetaObject *resolveType(const QString& name) const; // for QQmlCustomParser::resolveType
- int rewriteBinding(const QQmlScript::Variant& value, const QString& name); // for QQmlCustomParser::rewriteBinding
- QString rewriteSignalHandler(const QQmlScript::Variant& value, const QString &name); // for QQmlCustomParser::rewriteSignalHandler
+ int bindingIdentifier(const QQmlScript::Variant& value); // for QQmlCustomParser::bindingIndex
private:
typedef QQmlCompiledData::Instruction Instruction;
@@ -446,8 +440,6 @@ private:
int ids;
QList<QQmlScript::LocationSpan> scriptBindings;
- QList<QQmlScript::LocationSpan> sharedBindings;
- QList<QQmlScript::LocationSpan> optimizedBindings;
int objects;
};
struct ComponentStats : public QQmlPool::Class
diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp
index df1e7f420e..e59116a7c1 100644
--- a/src/qml/qml/qqmlcomponent.cpp
+++ b/src/qml/qml/qqmlcomponent.cpp
@@ -59,7 +59,9 @@
#include <private/qqmljavascriptexpression_p.h>
#include <private/qv8engine_p.h>
-#include <private/qv8include_p.h>
+
+#include <private/qv4functionobject_p.h>
+#include <private/qv4script_p.h>
#include <QStack>
#include <QStringList>
@@ -68,6 +70,23 @@
#include <qqmlinfo.h>
#include "qqmlmemoryprofiler_p.h"
+#define INITIALPROPERTIES_SOURCE \
+ "(function(object, values) {"\
+ "try {"\
+ "for (var property in values) {" \
+ "try {"\
+ "var properties = property.split(\".\");"\
+ "var o = object;"\
+ "for (var ii = 0; ii < properties.length - 1; ++ii) {"\
+ "o = o[properties[ii]];"\
+ "}"\
+ "o[properties[properties.length - 1]] = values[property];"\
+ "} catch(e) {}"\
+ "}"\
+ "} catch(e) {}"\
+ "})"
+
+
namespace {
QThreadStorage<int> creationDepth;
}
@@ -80,9 +99,7 @@ public:
QQmlComponentExtension(QV8Engine *);
virtual ~QQmlComponentExtension();
- v8::Persistent<v8::Function> incubationConstructor;
- v8::Persistent<v8::Script> initialProperties;
- v8::Persistent<v8::Function> forceCompletion;
+ QV4::PersistentValue incubationProto;
};
V8_DEFINE_EXTENSION(QQmlComponentExtension, componentExtension);
@@ -1067,37 +1084,33 @@ void QQmlComponent::create(QQmlIncubator &incubator, QQmlContext *context,
enginePriv->incubate(incubator, forContextData);
}
-class QV8IncubatorResource : public QV8ObjectResource,
- public QQmlIncubator
+class QmlIncubatorObject : public QV4::Object, public QQmlIncubator
{
-V8_RESOURCE_TYPE(IncubatorType)
+ Q_MANAGED
public:
- QV8IncubatorResource(QV8Engine *engine, IncubationMode = Asynchronous);
-
- static v8::Handle<v8::Value> StatusChangedGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info);
- static v8::Handle<v8::Value> StatusGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info);
- static v8::Handle<v8::Value> ObjectGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info);
- static v8::Handle<v8::Value> ForceCompletionGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info);
- static v8::Handle<v8::Value> ForceCompletion(const v8::Arguments &args);
-
- static void StatusChangedSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
- const v8::AccessorInfo& info);
-
- void dispose();
-
- v8::Persistent<v8::Object> me;
- QQmlGuard<QObject> parent;
- v8::Persistent<v8::Value> valuemap;
- v8::Persistent<v8::Object> qmlGlobal;
+ QmlIncubatorObject(QV8Engine *engine, IncubationMode = Asynchronous);
+
+ static QV4::Value method_get_statusChanged(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_set_statusChanged(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_status(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_object(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_forceCompletion(QV4::SimpleCallContext *ctx);
+
+ static void destroy(Managed *that);
+ static void markObjects(Managed *that);
+
+ QV8Engine *v8;
+ QPointer<QObject> parent;
+ QV4::Value valuemap;
+ QV4::Value qmlGlobal;
+ QV4::Value m_statusChanged;
protected:
virtual void statusChanged(Status);
virtual void setInitialState(QObject *);
};
+DEFINE_MANAGED_VTABLE(QmlIncubatorObject);
+
static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
{
if (parent) {
@@ -1165,29 +1178,32 @@ static void QQmlComponent_setQmlParent(QObject *me, QObject *parent)
/*!
\internal
*/
-void QQmlComponent::createObject(QQmlV8Function *args)
+void QQmlComponent::createObject(QQmlV4Function *args)
{
Q_D(QQmlComponent);
Q_ASSERT(d->engine);
Q_ASSERT(args);
QObject *parent = 0;
- v8::Local<v8::Object> valuemap;
+ QV4::Value valuemap = QV4::Value::emptyValue();
- if (args->Length() >= 1)
- parent = args->engine()->toQObject((*args)[0]);
+ if (args->length() >= 1) {
+ if (QV4::QObjectWrapper *qobjectWrapper = (*args)[0].as<QV4::QObjectWrapper>())
+ parent = qobjectWrapper->object();
+ }
- if (args->Length() >= 2) {
- v8::Local<v8::Value> v = (*args)[1];
- if (!v->IsObject() || v->IsArray()) {
+ if (args->length() >= 2) {
+ QV4::Value v = (*args)[1];
+ if (!v.asObject() || v.asArrayObject()) {
qmlInfo(this) << tr("createObject: value is not an object");
- args->returnValue(v8::Null());
+ args->setReturnValue(QV4::Value::nullValue());
return;
}
- valuemap = v8::Local<v8::Object>::Cast(v);
+ valuemap = v;
}
QV8Engine *v8engine = args->engine();
+ QV4::ExecutionEngine *v4engine = QV8Engine::getV4(v8engine);
QQmlContext *ctxt = creationContext();
if (!ctxt) ctxt = d->engine->rootContext();
@@ -1195,22 +1211,20 @@ void QQmlComponent::createObject(QQmlV8Function *args)
QObject *rv = beginCreate(ctxt);
if (!rv) {
- args->returnValue(v8::Null());
+ args->setReturnValue(QV4::Value::nullValue());
return;
}
QQmlComponent_setQmlParent(rv, parent);
- v8::Handle<v8::Value> ov = v8engine->newQObject(rv);
- Q_ASSERT(ov->IsObject());
- v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
+ QV4::Value object = QV4::QObjectWrapper::wrap(v4engine, rv);
+ Q_ASSERT(object.asObject());
- if (!valuemap.IsEmpty()) {
+ if (!valuemap.isEmpty()) {
QQmlComponentExtension *e = componentExtension(v8engine);
- // Try catch isn't needed as the function itself is loaded with try/catch
- v8::Handle<v8::Value> function = e->initialProperties->Run(args->qmlGlobal());
- v8::Handle<v8::Value> args[] = { object, valuemap };
- v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
+ QV4::Value f = QV4::Script::evaluate(QV8Engine::getV4(v8engine), QString::fromLatin1(INITIALPROPERTIES_SOURCE), args->qmlGlobal().asObject());
+ QV4::Value args[] = { object, valuemap };
+ f.asFunctionObject()->call(QV4::Value::fromObject(v4engine->globalObject), args, 2);
}
d->completeCreate();
@@ -1220,9 +1234,9 @@ void QQmlComponent::createObject(QQmlV8Function *args)
QQmlData::get(rv)->indestructible = false;
if (!rv)
- args->returnValue(v8::Null());
+ args->setReturnValue(QV4::Value::nullValue());
else
- args->returnValue(object);
+ args->setReturnValue(object);
}
/*!
@@ -1283,7 +1297,7 @@ void QQmlComponent::createObject(QQmlV8Function *args)
/*!
\internal
*/
-void QQmlComponent::incubateObject(QQmlV8Function *args)
+void QQmlComponent::incubateObject(QQmlV4Function *args)
{
Q_D(QQmlComponent);
Q_ASSERT(d->engine);
@@ -1291,26 +1305,28 @@ void QQmlComponent::incubateObject(QQmlV8Function *args)
Q_ASSERT(args);
QObject *parent = 0;
- v8::Local<v8::Object> valuemap;
+ QV4::Value valuemap = QV4::Value::emptyValue();
QQmlIncubator::IncubationMode mode = QQmlIncubator::Asynchronous;
- if (args->Length() >= 1)
- parent = args->engine()->toQObject((*args)[0]);
+ if (args->length() >= 1) {
+ if (QV4::QObjectWrapper *qobjectWrapper = (*args)[0].as<QV4::QObjectWrapper>())
+ parent = qobjectWrapper->object();
+ }
- if (args->Length() >= 2) {
- v8::Local<v8::Value> v = (*args)[1];
- if (v->IsNull()) {
- } else if (!v->IsObject() || v->IsArray()) {
+ if (args->length() >= 2) {
+ QV4::Value v = (*args)[1];
+ if (v.isNull()) {
+ } else if (!v.asObject() || v.asArrayObject()) {
qmlInfo(this) << tr("createObject: value is not an object");
- args->returnValue(v8::Null());
+ args->setReturnValue(QV4::Value::nullValue());
return;
} else {
- valuemap = v8::Local<v8::Object>::Cast(v);
+ valuemap = v;
}
}
- if (args->Length() >= 3) {
- quint32 v = (*args)[2]->Uint32Value();
+ if (args->length() >= 3) {
+ quint32 v = (*args)[2].toUInt32();
if (v == 0)
mode = QQmlIncubator::Asynchronous;
else if (v == 1)
@@ -1319,177 +1335,156 @@ void QQmlComponent::incubateObject(QQmlV8Function *args)
QQmlComponentExtension *e = componentExtension(args->engine());
- QV8IncubatorResource *r = new QV8IncubatorResource(args->engine(), mode);
- v8::Local<v8::Object> o = e->incubationConstructor->NewInstance();
- o->SetExternalResource(r);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(args->engine());
+ QmlIncubatorObject *r = new (v4->memoryManager) QmlIncubatorObject(args->engine(), mode);
+ r->prototype = e->incubationProto.value().asObject();
- if (!valuemap.IsEmpty()) {
- r->valuemap = qPersistentNew(valuemap);
- r->qmlGlobal = qPersistentNew(args->qmlGlobal());
+ if (!valuemap.isEmpty()) {
+ r->valuemap = valuemap;
+ r->qmlGlobal = args->qmlGlobal();
}
r->parent = parent;
- r->me = qPersistentNew(o);
create(*r, creationContext());
if (r->status() == QQmlIncubator::Null) {
- r->dispose();
- args->returnValue(v8::Null());
+ args->setReturnValue(QV4::Value::nullValue());
} else {
- args->returnValue(o);
+ args->setReturnValue(QV4::Value::fromObject(r));
}
}
// XXX used by QSGLoader
-void QQmlComponentPrivate::initializeObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate)
+void QQmlComponentPrivate::initializeObjectWithInitialProperties(const QV4::Value &qmlGlobal, const QV4::Value &valuemap, QObject *toCreate)
{
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
QV8Engine *v8engine = ep->v8engine();
+ QV4::ExecutionEngine *v4engine = QV8Engine::getV4(v8engine);
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(v8engine->context());
- v8::Handle<v8::Value> ov = v8engine->newQObject(toCreate);
- Q_ASSERT(ov->IsObject());
- v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(ov);
+ QV4::Value object = QV4::QObjectWrapper::wrap(v4engine, toCreate);
+ Q_ASSERT(object.asObject());
- if (!valuemap.IsEmpty()) {
+ if (!valuemap.isEmpty()) {
QQmlComponentExtension *e = componentExtension(v8engine);
- // Try catch isn't needed as the function itself is loaded with try/catch
- v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
- v8::Handle<v8::Value> args[] = { object, valuemap };
- v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args);
+ QV4::Value f = QV4::Script::evaluate(QV8Engine::getV4(v8engine), QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlGlobal.asObject());
+ QV4::Value args[] = { object, valuemap };
+ f.asFunctionObject()->call(QV4::Value::fromObject(v4engine->globalObject), args, 2);
}
}
+#define V4FUNCTION(function, engine) engine->newBuiltinFunction(engine->rootContext, engine->id_undefined, function)
+
QQmlComponentExtension::QQmlComponentExtension(QV8Engine *engine)
{
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(engine->context());
-
- forceCompletion = qPersistentNew(V8FUNCTION(QV8IncubatorResource::ForceCompletion, engine));
-
- {
- v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetHasExternalResource(true);
- ft->InstanceTemplate()->SetInternalFieldCount(1);
- ft->InstanceTemplate()->SetAccessor(v8::String::New("onStatusChanged"),
- QV8IncubatorResource::StatusChangedGetter,
- QV8IncubatorResource::StatusChangedSetter);
- ft->InstanceTemplate()->SetAccessor(v8::String::New("status"),
- QV8IncubatorResource::StatusGetter);
- ft->InstanceTemplate()->SetAccessor(v8::String::New("object"),
- QV8IncubatorResource::ObjectGetter);
- ft->InstanceTemplate()->SetAccessor(v8::String::New("forceCompletion"),
- QV8IncubatorResource::ForceCompletionGetter);
- incubationConstructor = qPersistentNew(ft->GetFunction());
- }
-
- {
-#define INITIALPROPERTIES_SOURCE \
- "(function(object, values) {"\
- "try {"\
- "for(var property in values) {" \
- "try {"\
- "var properties = property.split(\".\");"\
- "var o = object;"\
- "for (var ii = 0; ii < properties.length - 1; ++ii) {"\
- "o = o[properties[ii]];"\
- "}"\
- "o[properties[properties.length - 1]] = values[property];"\
- "} catch(e) {}"\
- "}"\
- "} catch(e) {}"\
- "})"
- initialProperties = qPersistentNew(engine->qmlModeCompile(QLatin1String(INITIALPROPERTIES_SOURCE)));
-#undef INITIALPROPERTIES_SOURCE
- }
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QV4::Object *proto = v4->newObject();
+ QV4::Property *s = proto->insertMember(v4->newString(QStringLiteral("onStatusChanged")),
+ QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ s->setGetter(V4FUNCTION(QmlIncubatorObject::method_get_statusChanged, v4));
+ s->setSetter(V4FUNCTION(QmlIncubatorObject::method_set_statusChanged, v4));
+ s = proto->insertMember(v4->newString(QStringLiteral("status")),
+ QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ s->setGetter(V4FUNCTION(QmlIncubatorObject::method_get_status, v4));
+ s = proto->insertMember(v4->newString(QStringLiteral("object")),
+ QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ s->setGetter(V4FUNCTION(QmlIncubatorObject::method_get_object, v4));
+ proto->defineDefaultProperty(v4, QStringLiteral("forceCompletion"), QmlIncubatorObject::method_forceCompletion);
+
+ incubationProto = QV4::Value::fromObject(proto);
}
-v8::Handle<v8::Value> QV8IncubatorResource::ObjectGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info)
+QV4::Value QmlIncubatorObject::method_get_object(QV4::SimpleCallContext *ctx)
{
- QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
- return r->engine->newQObject(r->object());
-}
+ QmlIncubatorObject *o = ctx->thisObject.as<QmlIncubatorObject>();
+ if (!o)
+ ctx->throwTypeError();
-v8::Handle<v8::Value> QV8IncubatorResource::ForceCompletionGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info)
-{
- QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
- return componentExtension(r->engine)->forceCompletion;
+ return QV4::QObjectWrapper::wrap(ctx->engine, o->object());
}
-v8::Handle<v8::Value> QV8IncubatorResource::ForceCompletion(const v8::Arguments &args)
+QV4::Value QmlIncubatorObject::method_forceCompletion(QV4::SimpleCallContext *ctx)
{
- QV8IncubatorResource *r = v8_resource_cast<QV8IncubatorResource>(args.This());
- if (!r)
- V8THROW_TYPE("Not an incubator object");
+ QmlIncubatorObject *o = ctx->thisObject.as<QmlIncubatorObject>();
+ if (!o)
+ ctx->throwTypeError();
- r->forceCompletion();
+ o->forceCompletion();
- return v8::Undefined();
+ return QV4::Value::undefinedValue();
}
-v8::Handle<v8::Value> QV8IncubatorResource::StatusGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info)
+QV4::Value QmlIncubatorObject::method_get_status(QV4::SimpleCallContext *ctx)
{
- QV8IncubatorResource *r = v8_resource_check<QV8IncubatorResource>(info.This());
- return v8::Integer::NewFromUnsigned(r->status());
+ QmlIncubatorObject *o = ctx->thisObject.as<QmlIncubatorObject>();
+ if (!o)
+ ctx->throwTypeError();
+
+ return QV4::Value::fromUInt32(o->status());
}
-v8::Handle<v8::Value> QV8IncubatorResource::StatusChangedGetter(v8::Local<v8::String>,
- const v8::AccessorInfo& info)
+QV4::Value QmlIncubatorObject::method_get_statusChanged(QV4::SimpleCallContext *ctx)
{
- return info.This()->GetInternalField(0);
+ QmlIncubatorObject *o = ctx->thisObject.as<QmlIncubatorObject>();
+ if (!o)
+ ctx->throwTypeError();
+
+ return o->m_statusChanged;
}
-void QV8IncubatorResource::StatusChangedSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
- const v8::AccessorInfo& info)
+QV4::Value QmlIncubatorObject::method_set_statusChanged(QV4::SimpleCallContext *ctx)
{
- info.This()->SetInternalField(0, value);
+ QmlIncubatorObject *o = ctx->thisObject.as<QmlIncubatorObject>();
+ if (!o || ctx->argumentCount < 1)
+ ctx->throwTypeError();
+
+ o->m_statusChanged = ctx->arguments[0];
+ return QV4::Value::undefinedValue();
}
QQmlComponentExtension::~QQmlComponentExtension()
{
- qPersistentDispose(incubationConstructor);
- qPersistentDispose(initialProperties);
- qPersistentDispose(forceCompletion);
}
-QV8IncubatorResource::QV8IncubatorResource(QV8Engine *engine, IncubationMode m)
-: QV8ObjectResource(engine), QQmlIncubator(m)
+QmlIncubatorObject::QmlIncubatorObject(QV8Engine *engine, IncubationMode m)
+ : Object(QV8Engine::getV4(engine)), QQmlIncubator(m)
{
+ v8 = engine;
+ vtbl = &static_vtbl;
}
-void QV8IncubatorResource::setInitialState(QObject *o)
+void QmlIncubatorObject::setInitialState(QObject *o)
{
QQmlComponent_setQmlParent(o, parent);
- if (!valuemap.IsEmpty()) {
- QQmlComponentExtension *e = componentExtension(engine);
-
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(engine->context());
+ if (!valuemap.isEmpty()) {
+ QQmlComponentExtension *e = componentExtension(v8);
- v8::Handle<v8::Value> function = e->initialProperties->Run(qmlGlobal);
- v8::Handle<v8::Value> args[] = { engine->newQObject(o), valuemap };
- v8::Handle<v8::Function>::Cast(function)->Call(engine->global(), 2, args);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8);
- qPersistentDispose(valuemap);
- qPersistentDispose(qmlGlobal);
+ QV4::Value f = QV4::Script::evaluate(v4, QString::fromLatin1(INITIALPROPERTIES_SOURCE), qmlGlobal.asObject());
+ QV4::Value args[] = { QV4::QObjectWrapper::wrap(v4, o), valuemap };
+ f.asFunctionObject()->call(QV4::Value::fromObject(v4->globalObject), args, 2);
}
}
-void QV8IncubatorResource::dispose()
+void QmlIncubatorObject::destroy(Managed *that)
+{
+ QmlIncubatorObject *o = that->as<QmlIncubatorObject>();
+ assert(o);
+ o->~QmlIncubatorObject();
+}
+
+void QmlIncubatorObject::markObjects(QV4::Managed *that)
{
- qPersistentDispose(valuemap);
- qPersistentDispose(qmlGlobal);
- // No further status changes are forthcoming, so we no long need a self reference
- qPersistentDispose(me);
+ QmlIncubatorObject *o = that->as<QmlIncubatorObject>();
+ assert(o);
+ o->valuemap.mark();
+ o->qmlGlobal.mark();
+ o->m_statusChanged.mark();
}
-void QV8IncubatorResource::statusChanged(Status s)
+void QmlIncubatorObject::statusChanged(Status s)
{
if (s == Ready) {
Q_ASSERT(QQmlData::get(object()));
@@ -1497,29 +1492,22 @@ void QV8IncubatorResource::statusChanged(Status s)
QQmlData::get(object())->indestructible = false;
}
- if (!me.IsEmpty()) { // Will be false in synchronous mode
- v8::HandleScope scope;
- v8::Local<v8::Value> callback = me->GetInternalField(0);
-
- if (!callback.IsEmpty() && !callback->IsUndefined()) {
-
- if (callback->IsFunction()) {
- v8::Context::Scope context_scope(engine->context());
- v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(callback);
- v8::Handle<v8::Value> args[] = { v8::Integer::NewFromUnsigned(s) };
- v8::TryCatch tc;
- f->Call(me, 1, args);
- if (tc.HasCaught()) {
- QQmlError error;
- QQmlJavaScriptExpression::exceptionToError(tc.Message(), error);
- QQmlEnginePrivate::warning(QQmlEnginePrivate::get(engine->engine()), error);
- }
- }
+ QV4::Value callback = m_statusChanged;
+
+ if (QV4::FunctionObject *f = callback.asFunctionObject()) {
+ QV4::ExecutionContext *ctx = f->engine()->current;
+ QV4::Value args[] = { QV4::Value::fromUInt32(s) };
+ try {
+ f->call(QV4::Value::fromObject(this), args, 1);
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ QQmlError error;
+ QQmlJavaScriptExpression::exceptionToError(e, error);
+ QQmlEnginePrivate::warning(QQmlEnginePrivate::get(v8->engine()), error);
}
}
-
- if (s == Ready || s == Error)
- dispose();
}
+#undef INITIALPROPERTIES_SOURCE
+
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index aefad475b4..9877f59fb6 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -56,7 +56,7 @@ class QByteArray;
class QQmlEngine;
class QQmlComponent;
class QQmlIncubator;
-class QQmlV8Function;
+class QQmlV4Function;
class QQmlCompiledData;
class QQmlComponentPrivate;
class QQmlComponentAttached;
@@ -120,8 +120,8 @@ Q_SIGNALS:
protected:
QQmlComponent(QQmlComponentPrivate &dd, QObject* parent);
- Q_INVOKABLE void createObject(QQmlV8Function *);
- Q_INVOKABLE void incubateObject(QQmlV8Function *);
+ Q_INVOKABLE void createObject(QQmlV4Function *);
+ Q_INVOKABLE void incubateObject(QQmlV4Function *);
private:
QQmlComponent(QQmlEngine *, QQmlCompiledData *, int, QObject *parent);
diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h
index 37cb234d42..439f1fcdd9 100644
--- a/src/qml/qml/qqmlcomponent_p.h
+++ b/src/qml/qml/qqmlcomponent_p.h
@@ -55,7 +55,6 @@
#include "qqmlcomponent.h"
-#include <private/qv8_p.h>
#include "qqmlengine_p.h"
#include "qqmltypeloader_p.h"
#include <private/qbitfield_p.h>
@@ -91,7 +90,7 @@ public:
QObject *beginCreate(QQmlContextData *);
void completeCreate();
- void initializeObjectWithInitialProperties(v8::Handle<v8::Object> qmlGlobal, v8::Handle<v8::Object> valuemap, QObject *toCreate);
+ void initializeObjectWithInitialProperties(const QV4::Value &qmlGlobal, const QV4::Value &valuemap, QObject *toCreate);
QQmlTypeData *typeData;
virtual void typeDataReady(QQmlTypeData *);
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 7fa2472335..7731935b75 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -49,8 +49,6 @@
#include "qqmlengine.h"
#include "qqmlinfo.h"
#include "qqmlabstracturlinterceptor_p.h"
-#include <private/qv4bindings_p.h>
-#include <private/qv8bindings_p.h>
#include <qjsengine.h>
#include <QtCore/qvarlengtharray.h>
@@ -314,11 +312,12 @@ void QQmlContext::setContextProperty(const QString &name, const QVariant &value)
}
}
- if (!data->propertyNames) data->propertyNames = new QQmlIntegerCache();
+ if (data->propertyNames.isEmpty())
+ data->propertyNames = QV4::IdentifierHash<int>(QV8Engine::getV4(engine()->handle()));
- int idx = data->propertyNames->value(name);
+ int idx = data->propertyNames.value(name);
if (idx == -1) {
- data->propertyNames->add(name, data->idValueCount + d->propertyValues.count());
+ data->propertyNames.add(name, data->idValueCount + d->propertyValues.count());
d->propertyValues.append(value);
data->refreshExpressions();
@@ -351,11 +350,12 @@ void QQmlContext::setContextProperty(const QString &name, QObject *value)
return;
}
- if (!data->propertyNames) data->propertyNames = new QQmlIntegerCache();
- int idx = data->propertyNames->value(name);
+ if (data->propertyNames.isEmpty())
+ data->propertyNames = QV4::IdentifierHash<int>(QV8Engine::getV4(engine()->handle()));
+ int idx = data->propertyNames.value(name);
if (idx == -1) {
- data->propertyNames->add(name, data->idValueCount + d->propertyValues.count());
+ data->propertyNames.add(name, data->idValueCount + d->propertyValues.count());
d->propertyValues.append(QVariant::fromValue(value));
data->refreshExpressions();
@@ -377,8 +377,8 @@ QVariant QQmlContext::contextProperty(const QString &name) const
QQmlContextData *data = d->data;
- if (data->propertyNames)
- idx = data->propertyNames->value(name);
+ if (data->propertyNames.count())
+ idx = data->propertyNames.value(name);
if (idx == -1) {
QByteArray utf8Name = name.toUtf8();
@@ -524,9 +524,9 @@ QQmlContextData::QQmlContextData()
: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
publicContext(0), activeVMEData(0),
- propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
+ contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
- componentAttached(0), v4bindings(0), v8bindings(0)
+ componentAttached(0)
{
}
@@ -534,9 +534,9 @@ QQmlContextData::QQmlContextData(QQmlContext *ctxt)
: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
publicContext(ctxt), activeVMEData(0),
- propertyNames(0), contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
+ contextObject(0), imports(0), childContexts(0), nextChild(0), prevChild(0),
expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
- componentAttached(0), v4bindings(0), v8bindings(0)
+ componentAttached(0)
{
}
@@ -638,22 +638,9 @@ void QQmlContextData::destroy()
}
contextGuards = 0;
- if (propertyNames)
- propertyNames->release();
-
if (imports)
imports->release();
- if (v4bindings)
- v4bindings->release();
-
- if (v8bindings)
- v8bindings->release();
-
- for (int ii = 0; ii < importedScripts.count(); ++ii) {
- qPersistentDispose(importedScripts[ii]);
- }
-
delete [] idValues;
if (isInternal)
@@ -783,31 +770,33 @@ void QQmlContextData::setIdProperty(int idx, QObject *obj)
idValues[idx].context = this;
}
-void QQmlContextData::setIdPropertyData(QQmlIntegerCache *data)
+void QQmlContextData::setIdPropertyData(const QVector<ObjectIdMapping> &data)
{
- Q_ASSERT(!propertyNames);
- propertyNames = data;
- propertyNames->addref();
+ Q_ASSERT(propertyNames.isEmpty());
+ propertyNames = QV4::IdentifierHash<int>(QV8Engine::getV4(engine->handle()));
+ for (QVector<ObjectIdMapping>::ConstIterator it = data.begin(), end = data.end();
+ it != end; ++it)
+ propertyNames.add(it->name, it->id);
- idValueCount = data->count();
+ idValueCount = data.count();
idValues = new ContextGuard[idValueCount];
}
QString QQmlContextData::findObjectId(const QObject *obj) const
{
- if (!propertyNames)
+ if (propertyNames.isEmpty())
return QString();
for (int ii = 0; ii < idValueCount; ii++) {
if (idValues[ii] == obj)
- return propertyNames->findId(ii);
+ return propertyNames.findId(ii);
}
if (publicContext) {
QQmlContextPrivate *p = QQmlContextPrivate::get(publicContext);
for (int ii = 0; ii < p->propertyValues.count(); ++ii)
if (p->propertyValues.at(ii) == QVariant::fromValue((QObject *)obj))
- return propertyNames->findId(ii);
+ return propertyNames.findId(ii);
}
if (linkedContext)
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index b19c64fe1c..a5c3886af1 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -56,7 +56,6 @@
#include "qqmlcontext.h"
#include "qqmldata_p.h"
-#include "qqmlintegercache_p.h"
#include "qqmltypenamecache_p.h"
#include "qqmlnotifier_p.h"
#include "qqmllist.h"
@@ -70,19 +69,16 @@
#include <private/qflagpointer_p.h>
#include <private/qqmlguard_p.h>
-#include <private/qv8_p.h>
-
+#include <private/qv4identifier_p.h>
QT_BEGIN_NAMESPACE
-class QV8Bindings;
class QQmlContext;
class QQmlExpression;
class QQmlEngine;
class QQmlExpression;
class QQmlExpressionPrivate;
class QQmlAbstractExpression;
-class QV4Bindings;
class QQmlContextData;
class QQmlContextPrivate : public QObjectPrivate
@@ -156,13 +152,13 @@ public:
void *activeVMEData;
// Property name cache
- QQmlIntegerCache *propertyNames;
+ QV4::IdentifierHash<int> propertyNames;
// Context object
QObject *contextObject;
// Any script blocks that exist on this context
- QList<v8::Persistent<v8::Object> > importedScripts;
+ QList<QV4::PersistentValue> importedScripts;
// Context base url
QUrl url;
@@ -199,10 +195,17 @@ public:
QFlagPointer<QQmlContextData> context;
QQmlNotifier bindings;
};
+ struct ObjectIdMapping {
+ ObjectIdMapping() : id(-1) {}
+ ObjectIdMapping(const QString &name, int id)
+ : name(name), id(id) {}
+ QString name;
+ int id;
+ };
ContextGuard *idValues;
int idValueCount;
void setIdProperty(int, QObject *);
- void setIdPropertyData(QQmlIntegerCache *);
+ void setIdPropertyData(const QVector<ObjectIdMapping> &);
// Linked contexts. this owns linkedContext.
QQmlContextData *linkedContext;
@@ -211,10 +214,6 @@ public:
// context
QQmlComponentAttached *componentAttached;
- // Optimized binding objects. Needed for deferred properties.
- QV4Bindings *v4bindings;
- QV8Bindings *v8bindings;
-
// Return the outermost id for obj, if any.
QString findObjectId(const QObject *obj) const;
diff --git a/src/qml/qml/qqmlcontextwrapper.cpp b/src/qml/qml/qqmlcontextwrapper.cpp
new file mode 100644
index 0000000000..4a66c7552d
--- /dev/null
+++ b/src/qml/qml/qqmlcontextwrapper.cpp
@@ -0,0 +1,338 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlcontextwrapper_p.h"
+#include <private/qv8engine_p.h>
+
+#include <private/qqmlengine_p.h>
+#include <private/qqmlcontext_p.h>
+
+#include <private/qv4engine_p.h>
+#include <private/qv4value_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4objectproto_p.h>
+#include <private/qv4mm_p.h>
+#include <private/qqmltypewrapper_p.h>
+#include <private/qqmllistwrapper_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+DEFINE_MANAGED_VTABLE(QmlContextWrapper);
+
+QmlContextWrapper::QmlContextWrapper(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext)
+ : Object(QV8Engine::getV4(engine)),
+ v8(engine), readOnly(true), ownsContext(ownsContext), isNullWrapper(false),
+ context(context), scopeObject(scopeObject)
+{
+ vtbl = &static_vtbl;
+}
+
+QmlContextWrapper::~QmlContextWrapper()
+{
+ if (context && ownsContext)
+ context->destroy();
+}
+
+QV4::Value QmlContextWrapper::qmlScope(QV8Engine *v8, QQmlContextData *ctxt, QObject *scope)
+{
+ ExecutionEngine *v4 = QV8Engine::getV4(v8);
+
+ QmlContextWrapper *w = new (v4->memoryManager) QmlContextWrapper(v8, ctxt, scope);
+ w->prototype = v4->objectPrototype;
+ return Value::fromObject(w);
+}
+
+QV4::Value QmlContextWrapper::urlScope(QV8Engine *v8, const QUrl &url)
+{
+ ExecutionEngine *v4 = QV8Engine::getV4(v8);
+
+ QQmlContextData *context = new QQmlContextData;
+ context->url = url;
+ context->isInternal = true;
+ context->isJSContext = true;
+
+ QmlContextWrapper *w = new (v4->memoryManager) QmlContextWrapper(v8, context, 0);
+ w->isNullWrapper = true;
+ w->prototype = v4->objectPrototype;
+ return Value::fromObject(w);
+}
+
+QQmlContextData *QmlContextWrapper::callingContext(ExecutionEngine *v4)
+{
+ QV4::Object *qmlglobal = v4->qmlContextObject();
+ if (!qmlglobal)
+ return 0;
+
+ QmlContextWrapper *c = qmlglobal->as<QmlContextWrapper>();
+ return c ? c->getContext() : 0;
+}
+
+QQmlContextData *QmlContextWrapper::getContext(const Value &value)
+{
+ Object *o = value.asObject();
+ QmlContextWrapper *c = o ? o->as<QmlContextWrapper>() : 0;
+ if (!c)
+ return 0;
+
+ return c ? c->getContext():0;
+}
+
+void QmlContextWrapper::takeContextOwnership(const Value &qmlglobal)
+{
+ Object *o = qmlglobal.asObject();
+ QmlContextWrapper *c = o ? o->as<QmlContextWrapper>() : 0;
+ assert(c);
+ c->ownsContext = true;
+}
+
+
+Value QmlContextWrapper::get(Managed *m, String *name, bool *hasProperty)
+{
+ QmlContextWrapper *resource = m->as<QmlContextWrapper>();
+ QV4::ExecutionEngine *v4 = m->engine();
+ if (!resource)
+ v4->current->throwTypeError();
+
+ if (resource->isNullWrapper)
+ return Object::get(m, name, hasProperty);
+
+ if (QV4::QmlContextWrapper::callingContext(v4) != resource->context)
+ return Object::get(m, name, hasProperty);
+
+ bool hasProp;
+ Value result = Object::get(m, name, &hasProp);
+ if (hasProp) {
+ if (hasProperty)
+ *hasProperty = hasProp;
+ return result;
+ }
+
+ // Its possible we could delay the calculation of the "actual" context (in the case
+ // of sub contexts) until it is definately needed.
+ QQmlContextData *context = resource->getContext();
+ QQmlContextData *expressionContext = context;
+
+ if (!context) {
+ if (hasProperty)
+ *hasProperty = true;
+ return result;
+ }
+
+ // Search type (attached property/enum/imported scripts) names
+ // while (context) {
+ // Search context properties
+ // Search scope object
+ // Search context object
+ // context = context->parent
+ // }
+
+ QV8Engine *engine = resource->v8;
+
+ QObject *scopeObject = resource->getScopeObject();
+
+ if (context->imports && name->startsWithUpper()) {
+ // Search for attached properties, enums and imported scripts
+ QQmlTypeNameCache::Result r = context->imports->query(name);
+
+ if (r.isValid()) {
+ if (hasProperty)
+ *hasProperty = true;
+ if (r.scriptIndex != -1) {
+ int index = r.scriptIndex;
+ if (index < context->importedScripts.count())
+ return context->importedScripts.at(index).value();
+ else
+ return QV4::Value::undefinedValue();
+ } else if (r.type) {
+ return QmlTypeWrapper::create(engine, scopeObject, r.type);
+ } else if (r.importNamespace) {
+ return QmlTypeWrapper::create(engine, scopeObject, context->imports, r.importNamespace);
+ }
+ Q_ASSERT(!"Unreachable");
+ }
+
+ // Fall through
+ }
+
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->engine());
+
+ while (context) {
+ // Search context properties
+ if (context->propertyNames.count()) {
+ int propertyIdx = context->propertyNames.value(name);
+
+ if (propertyIdx != -1) {
+
+ if (propertyIdx < context->idValueCount) {
+
+ ep->captureProperty(&context->idValues[propertyIdx].bindings);
+ if (hasProperty)
+ *hasProperty = true;
+ return QV4::QObjectWrapper::wrap(v4, context->idValues[propertyIdx]);
+ } else {
+
+ QQmlContextPrivate *cp = context->asQQmlContextPrivate();
+
+ ep->captureProperty(context->asQQmlContext(), -1,
+ propertyIdx + cp->notifyIndex);
+
+ const QVariant &value = cp->propertyValues.at(propertyIdx);
+ if (hasProperty)
+ *hasProperty = true;
+ if (value.userType() == qMetaTypeId<QList<QObject*> >()) {
+ QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*) qintptr(propertyIdx),
+ QQmlContextPrivate::context_count,
+ QQmlContextPrivate::context_at);
+ return QmlListWrapper::create(engine, prop, qMetaTypeId<QQmlListProperty<QObject> >());
+ } else {
+ return engine->fromVariant(cp->propertyValues.at(propertyIdx));
+ }
+ }
+ }
+ }
+
+ // Search scope object
+ if (scopeObject) {
+ bool hasProp = false;
+ QV4::Value result = QV4::QObjectWrapper::getQmlProperty(v4->current, context, scopeObject, name, QV4::QObjectWrapper::CheckRevision, &hasProp);
+ if (hasProp) {
+ if (hasProperty)
+ *hasProperty = true;
+ return result;
+ }
+ }
+ scopeObject = 0;
+
+
+ // Search context object
+ if (context->contextObject) {
+ bool hasProp = false;
+ QV4::Value result = QV4::QObjectWrapper::getQmlProperty(v4->current, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, &hasProp);
+ if (hasProp) {
+ if (hasProperty)
+ *hasProperty = true;
+ return result;
+ }
+ }
+
+ context = context->parent;
+ }
+
+ expressionContext->unresolvedNames = true;
+
+ return Value::undefinedValue();
+}
+
+void QmlContextWrapper::put(Managed *m, String *name, const Value &value)
+{
+ QmlContextWrapper *wrapper = m->as<QmlContextWrapper>();
+ ExecutionEngine *v4 = m->engine();
+ if (!wrapper)
+ v4->current->throwTypeError();
+
+ if (wrapper->isNullWrapper) {
+ if (wrapper && wrapper->readOnly) {
+ QString error = QLatin1String("Invalid write to global property \"") + name->toQString() +
+ QLatin1Char('"');
+ v4->current->throwError(Value::fromString(v4->current->engine->newString(error)));
+ }
+
+ Object::put(m, name, value);
+ return;
+ }
+
+ PropertyAttributes attrs;
+ Property *pd = wrapper->__getOwnProperty__(name, &attrs);
+ if (pd) {
+ wrapper->putValue(pd, attrs, value);
+ return;
+ }
+
+ // Its possible we could delay the calculation of the "actual" context (in the case
+ // of sub contexts) until it is definately needed.
+ QQmlContextData *context = wrapper->getContext();
+ QQmlContextData *expressionContext = context;
+
+ if (!context)
+ return;
+
+ // See QV8ContextWrapper::Getter for resolution order
+
+ QObject *scopeObject = wrapper->getScopeObject();
+
+ while (context) {
+ // Search context properties
+ if (context->propertyNames.count() && -1 != context->propertyNames.value(name))
+ return;
+
+ // Search scope object
+ if (scopeObject &&
+ QV4::QObjectWrapper::setQmlProperty(v4->current, context, scopeObject, name, QV4::QObjectWrapper::CheckRevision, value))
+ return;
+ scopeObject = 0;
+
+ // Search context object
+ if (context->contextObject &&
+ QV4::QObjectWrapper::setQmlProperty(v4->current, context, context->contextObject, name, QV4::QObjectWrapper::CheckRevision, value))
+ return;
+
+ context = context->parent;
+ }
+
+ expressionContext->unresolvedNames = true;
+
+ if (wrapper->readOnly) {
+ QString error = QLatin1String("Invalid write to global property \"") + name->toQString() +
+ QLatin1Char('"');
+ v4->current->throwError(error);
+ }
+
+ Object::put(m, name, value);
+}
+
+void QmlContextWrapper::destroy(Managed *that)
+{
+ static_cast<QmlContextWrapper *>(that)->~QmlContextWrapper();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcontextwrapper_p.h b/src/qml/qml/qqmlcontextwrapper_p.h
new file mode 100644
index 0000000000..0f44952567
--- /dev/null
+++ b/src/qml/qml/qqmlcontextwrapper_p.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLCONTEXTWRAPPER_P_H
+#define QQMLCONTEXTWRAPPER_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 <QtCore/qglobal.h>
+#include <private/qtqmlglobal_p.h>
+
+#include <private/qv4value_p.h>
+#include <private/qv4object_p.h>
+#include <private/qqmlcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct Q_QML_EXPORT QmlContextWrapper : Object
+{
+ Q_MANAGED
+ QmlContextWrapper(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext = false);
+ ~QmlContextWrapper();
+
+ static QV4::Value qmlScope(QV8Engine *e, QQmlContextData *ctxt, QObject *scope);
+ static QV4::Value urlScope(QV8Engine *e, const QUrl &);
+
+ static QQmlContextData *callingContext(ExecutionEngine *v4);
+ static void takeContextOwnership(const QV4::Value &qmlglobal);
+
+ inline QObject *getScopeObject() const { return scopeObject; }
+ inline QQmlContextData *getContext() const { return context; }
+ static QQmlContextData *getContext(const Value &value);
+
+ void setReadOnly(bool b) { readOnly = b; }
+
+ static Value get(Managed *m, String *name, bool *hasProperty);
+ static void put(Managed *m, String *name, const Value &value);
+ static void destroy(Managed *that);
+
+
+ QV8Engine *v8; // ### temporary, remove
+ bool readOnly;
+ bool ownsContext;
+ bool isNullWrapper;
+
+ QQmlGuardedContextData context;
+ QPointer<QObject> scopeObject;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV8CONTEXTWRAPPER_P_H
+
diff --git a/src/qml/qml/qqmlcustomparser.cpp b/src/qml/qml/qqmlcustomparser.cpp
index e2ec48f30d..eba2e14e51 100644
--- a/src/qml/qml/qqmlcustomparser.cpp
+++ b/src/qml/qml/qqmlcustomparser.cpp
@@ -311,18 +311,10 @@ const QMetaObject *QQmlCustomParser::resolveType(const QString& name) const
used to construct the binding later. \a name
is used as the name of the rewritten function.
*/
-QQmlBinding::Identifier QQmlCustomParser::rewriteBinding(const QQmlScript::Variant &value, const QString& name)
+QQmlBinding::Identifier QQmlCustomParser::bindingIdentifier(const QQmlScript::Variant &value, const QString& name)
{
- return compiler->rewriteBinding(value, name);
-}
-
-/*!
- Returns a rewritten \a handler. \a name
- is used as the name of the rewritten function.
-*/
-QString QQmlCustomParser::rewriteSignalHandler(const QQmlScript::Variant &value, const QString &name)
-{
- return compiler->rewriteSignalHandler(value , name);
+ Q_UNUSED(name);
+ return compiler->bindingIdentifier(value);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h
index 3eaf99191d..27f7e00b31 100644
--- a/src/qml/qml/qqmlcustomparser_p.h
+++ b/src/qml/qml/qqmlcustomparser_p.h
@@ -139,8 +139,7 @@ protected:
const QMetaObject *resolveType(const QString&) const;
- QQmlBinding::Identifier rewriteBinding(const QQmlScript::Variant&, const QString&);
- QString rewriteSignalHandler(const QQmlScript::Variant&, const QString&);
+ QQmlBinding::Identifier bindingIdentifier(const QQmlScript::Variant&, const QString&);
private:
QList<QQmlError> exceptions;
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index cedb2d688a..76d03f011e 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -55,7 +55,8 @@
#include <private/qtqmlglobal_p.h>
#include <private/qobject_p.h>
-#include <private/qv8_p.h>
+
+#include <private/qv4value_p.h>
QT_BEGIN_NAMESPACE
@@ -82,7 +83,7 @@ public:
hasTaintedV8Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
hasVMEMetaObject(false), parentFrozen(false), notifyList(0), context(0), outerContext(0),
bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0), bindingBitsSize(0), bindingBits(0),
- lineNumber(0), columnNumber(0), compiledData(0), deferredData(0), v8objectid(0),
+ lineNumber(0), columnNumber(0), compiledData(0), deferredData(0), jsEngineId(0),
propertyCache(0), guards(0), extendedData(0) {
init();
}
@@ -181,8 +182,8 @@ public:
QQmlCompiledData *compiledData;
DeferredData *deferredData;
- quint32 v8objectid;
- v8::Persistent<v8::Object> v8object;
+ quint32 jsEngineId; // id of the engine that cerated the jsWrapper
+ QV4::WeakValue jsWrapper;
QQmlPropertyCache *propertyCache;
@@ -203,6 +204,13 @@ public:
}
}
+ static bool keepAliveDuringGarbageCollection(const QObject *object) {
+ QQmlData *ddata = get(object);
+ if (!ddata || ddata->indestructible || ddata->rootObjectInCreation)
+ return true;
+ return false;
+ }
+
bool hasExtendedData() const { return extendedData != 0; }
QHash<int, QObject *> *attachedProperties() const;
diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp
index 6b6bee3406..8fcab2e570 100644
--- a/src/qml/qml/qqmldirparser.cpp
+++ b/src/qml/qml/qqmldirparser.cpp
@@ -160,7 +160,7 @@ bool QQmlDirParser::parse(const QString &source)
}
if (!firstLine) {
reportError(lineNumber, 0,
- QString::fromUtf8("module identifier directive must be the first command in a qmldir file"));
+ QString::fromUtf8("module identifier directive must be the first directive in a qmldir file"));
continue;
}
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 1c491ae492..dbf098e701 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -511,12 +511,12 @@ The \c status property will be updated as the operation progresses.
If provided, \a callback is invoked when the operation completes. The callback is passed
the same object as is returned from the Qt.include() call.
*/
-// Qt.include() is implemented in qv8include.cpp
+// Qt.include() is implemented in qv4include.cpp
QQmlEnginePrivate::QQmlEnginePrivate(QQmlEngine *e)
: propertyCapture(0), rootContext(0), isDebugging(false),
- outputWarningsToStdErr(true), sharedContext(0), sharedScope(0),
+ outputWarningsToStdErr(true),
cleanup(0), erroredBindings(0), inProgressCreations(0),
workerScriptEngine(0), activeVME(0),
networkAccessManager(0), networkAccessManagerFactory(0), urlInterceptor(0),
@@ -750,7 +750,7 @@ void QQmlEnginePrivate::init()
qRegisterMetaType<QQmlComponent::Status>();
qRegisterMetaType<QList<QObject*> >();
qRegisterMetaType<QList<int> >();
- qRegisterMetaType<QQmlV8Handle>();
+ qRegisterMetaType<QQmlV4Handle>();
v8engine()->setEngine(q);
@@ -991,7 +991,7 @@ QQmlNetworkAccessManagerFactory *QQmlEngine::networkAccessManagerFactory() const
void QQmlEnginePrivate::registerFinalizeCallback(QObject *obj, int index)
{
if (activeVME) {
- activeVME->finalizeCallbacks.append(qMakePair(QQmlGuard<QObject>(obj), index));
+ activeVME->finalizeCallbacks.append(qMakePair(QPointer<QObject>(obj), index));
} else {
void *args[] = { 0 };
QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, index, args);
@@ -1613,11 +1613,7 @@ void QQmlData::destroyed(QObject *object)
delete extendedData;
// Dispose the handle.
- // We don't simply clear it (and wait for next gc cycle to dispose
- // via the weak qobject reference callback) as this affects the
- // outcomes of v8's gc statistical analysis heuristics, which can
- // cause unnecessary growth of the old pointer space js heap area.
- qPersistentDispose(v8object);
+ jsWrapper = QV4::Value::undefinedValue();
if (ownMemory)
delete this;
@@ -1731,7 +1727,7 @@ void QQmlEnginePrivate::warning(const QList<QQmlError> &errors)
void QQmlEnginePrivate::warning(QQmlDelayedError *error)
{
Q_Q(QQmlEngine);
- warning(error->error(q));
+ warning(error->error());
}
void QQmlEnginePrivate::warning(QQmlEngine *engine, const QQmlError &error)
@@ -1755,7 +1751,7 @@ void QQmlEnginePrivate::warning(QQmlEngine *engine, QQmlDelayedError *error)
if (engine)
QQmlEnginePrivate::get(engine)->warning(error);
else
- dumpwarning(error->error(0));
+ dumpwarning(error->error());
}
void QQmlEnginePrivate::warning(QQmlEnginePrivate *engine, const QQmlError &error)
@@ -1801,9 +1797,10 @@ void QQmlEnginePrivate::dereferenceScarceResources()
// note that the actual SRD is owned by the JS engine,
// so we cannot delete the SRD; but we can free the
// memory used by the variant in the SRD.
- while (ScarceResourceData *sr = scarceResources.first()) {
+ QV4::ExecutionEngine *engine = QV8Engine::getV4(v8engine());
+ while (QV4::ExecutionEngine::ScarceResourceData *sr = engine->scarceResources.first()) {
sr->data = QVariant();
- scarceResources.remove(sr);
+ engine->scarceResources.remove(sr);
}
}
}
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 0d852c1c1b..c57c70fa40 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -147,9 +147,6 @@ public:
bool outputWarningsToStdErr;
- QQmlContextData *sharedContext;
- QObject *sharedScope;
-
// Registered cleanup handlers
QQmlCleanup *cleanup;
@@ -158,13 +155,14 @@ public:
int inProgressCreations;
QV8Engine *v8engine() const { return q_func()->handle(); }
+ QV4::ExecutionEngine *v4engine() const { return QV8Engine::getV4(q_func()->handle()); }
QQuickWorkerScriptEngine *getWorkerScriptEngine();
QQuickWorkerScriptEngine *workerScriptEngine;
QUrl baseUrl;
- typedef QPair<QQmlGuard<QObject>,int> FinalizeCallback;
+ typedef QPair<QPointer<QObject>,int> FinalizeCallback;
void registerFinalizeCallback(QObject *obj, int index);
QQmlVME *activeVME;
@@ -178,19 +176,6 @@ public:
QQmlAbstractUrlInterceptor* urlInterceptor;
- // Scarce resources are "exceptionally high cost" QVariant types where allowing the
- // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other
- // out-of-resource situations. When such a resource is passed into JavaScript we
- // add it to the scarceResources list and it is destroyed when we return from the
- // JavaScript execution that created it. The user can prevent this behavior by
- // calling preserve() on the object which removes it from this scarceResource list.
- class ScarceResourceData {
- public:
- ScarceResourceData(const QVariant &data) : data(data) {}
- QVariant data;
- QIntrusiveListNode node;
- };
- QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources;
int scarceResourcesRefCount;
void referenceScarceResources();
void dereferenceScarceResources();
@@ -260,6 +245,7 @@ public:
static void warning(QQmlEnginePrivate *, const QList<QQmlError> &);
inline static QV8Engine *getV8Engine(QQmlEngine *e);
+ inline static QV4::ExecutionEngine *getV4Engine(QQmlEngine *e);
inline static QQmlEnginePrivate *get(QQmlEngine *e);
inline static const QQmlEnginePrivate *get(const QQmlEngine *e);
inline static QQmlEnginePrivate *get(QQmlContext *c);
@@ -486,7 +472,14 @@ QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e)
{
Q_ASSERT(e);
- return e->d_func()->v8engine();
+ return e->d_func()->v8engine();
+}
+
+QV4::ExecutionEngine *QQmlEnginePrivate::getV4Engine(QQmlEngine *e)
+{
+ Q_ASSERT(e);
+
+ return e->d_func()->v4engine();
}
QQmlEnginePrivate *QQmlEnginePrivate::get(QQmlEngine *e)
diff --git a/src/qml/qml/qqmlerror.h b/src/qml/qml/qqmlerror.h
index cfa0dfcdbf..e69b3c15ba 100644
--- a/src/qml/qml/qqmlerror.h
+++ b/src/qml/qml/qqmlerror.h
@@ -49,7 +49,6 @@
QT_BEGIN_NAMESPACE
-
class QDebug;
class QQmlErrorPrivate;
class Q_QML_EXPORT QQmlError
diff --git a/src/qml/qml/qqmlexpression.cpp b/src/qml/qml/qqmlexpression.cpp
index accc645f1e..ddebf02c6c 100644
--- a/src/qml/qml/qqmlexpression.cpp
+++ b/src/qml/qml/qqmlexpression.cpp
@@ -45,9 +45,9 @@
#include "qqmlglobal_p.h"
#include "qqmlengine_p.h"
#include "qqmlcontext_p.h"
-#include "qqmlrewrite_p.h"
#include "qqmlscriptstring_p.h"
#include "qqmlcompiler_p.h"
+#include <private/qv8engine_p.h>
#include <QtCore/qdebug.h>
@@ -60,15 +60,13 @@ static QQmlJavaScriptExpression::VTable QQmlExpressionPrivate_jsvtable = {
QQmlExpressionPrivate::QQmlExpressionPrivate()
: QQmlJavaScriptExpression(&QQmlExpressionPrivate_jsvtable),
- expressionFunctionValid(true), expressionFunctionRewritten(false),
+ expressionFunctionValid(true),
line(0), column(0)
{
}
QQmlExpressionPrivate::~QQmlExpressionPrivate()
{
- qPersistentDispose(v8qmlscope);
- qPersistentDispose(v8function);
}
void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QObject *me)
@@ -78,11 +76,10 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr, QOb
QQmlAbstractExpression::setContext(ctxt);
setScopeObject(me);
expressionFunctionValid = false;
- expressionFunctionRewritten = false;
}
void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr,
- bool isRewritten, QObject *me, const QString &srcUrl,
+ QObject *me, const QString &srcUrl,
quint16 lineNumber, quint16 columnNumber)
{
url = srcUrl;
@@ -92,48 +89,11 @@ void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QString &expr,
expression = expr;
expressionFunctionValid = false;
- expressionFunctionRewritten = isRewritten;
QQmlAbstractExpression::setContext(ctxt);
setScopeObject(me);
}
-void QQmlExpressionPrivate::init(QQmlContextData *ctxt, const QByteArray &expr,
- bool isRewritten, QObject *me, const QString &srcUrl,
- quint16 lineNumber, quint16 columnNumber)
-{
- url = srcUrl;
- line = lineNumber;
- column = columnNumber;
-
- if (isRewritten) {
- expressionFunctionValid = true;
- expressionFunctionRewritten = true;
- v8function = evalFunction(ctxt, me, expr.constData(), expr.length(),
- srcUrl, lineNumber, &v8qmlscope);
- setUseSharedContext(false);
-
- expressionUtf8 = expr;
- } else {
- expression = QString::fromUtf8(expr);
-
- expressionFunctionValid = false;
- expressionFunctionRewritten = isRewritten;
- }
-
- QQmlAbstractExpression::setContext(ctxt);
- setScopeObject(me);
-}
-
-QQmlExpression *
-QQmlExpressionPrivate::create(QQmlContextData *ctxt, QObject *object,
- const QString &expr, bool isRewritten,
- const QString &url, quint16 lineNumber, quint16 columnNumber)
-{
- return new QQmlExpression(ctxt, object, expr, isRewritten, url, lineNumber, columnNumber,
- *new QQmlExpressionPrivate);
-}
-
/*!
\class QQmlExpression
\since 5.0
@@ -176,29 +136,6 @@ QQmlExpression::QQmlExpression()
{
}
-/*! \internal */
-QQmlExpression::QQmlExpression(QQmlContextData *ctxt,
- QObject *object, const QString &expr, bool isRewritten,
- const QString &url, int lineNumber, int columnNumber,
- QQmlExpressionPrivate &dd)
-: QObject(dd, 0)
-{
- Q_D(QQmlExpression);
- d->init(ctxt, expr, isRewritten, object, url, qmlSourceCoordinate(lineNumber), qmlSourceCoordinate(columnNumber));
-}
-
-/*! \internal */
-QQmlExpression::QQmlExpression(QQmlContextData *ctxt,
- QObject *object, const QByteArray &expr,
- bool isRewritten,
- const QString &url, int lineNumber, int columnNumber,
- QQmlExpressionPrivate &dd)
-: QObject(dd, 0)
-{
- Q_D(QQmlExpression);
- d->init(ctxt, expr, isRewritten, object, url, qmlSourceCoordinate(lineNumber), qmlSourceCoordinate(columnNumber));
-}
-
/*!
Create a QQmlExpression object that is a child of \a parent.
@@ -233,7 +170,7 @@ QQmlExpression::QQmlExpression(const QQmlScriptString &script, QQmlContext *ctxt
if (QQmlCompiledData *cdata = typeData->compiledData()) {
defaultConstruction = false;
- d->init(evalCtxtData, cdata->primitives.at(id), true, scopeObject,
+ d->init(evalCtxtData, cdata->primitives.at(id), scopeObject,
cdata->name, scriptPrivate->lineNumber, scriptPrivate->columnNumber);
}
@@ -273,15 +210,6 @@ QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
d->init(ctxt, expression, scope);
}
-/*! \internal */
-QQmlExpression::QQmlExpression(QQmlContextData *ctxt, QObject *scope,
- const QString &expression, QQmlExpressionPrivate &dd)
-: QObject(dd, 0)
-{
- Q_D(QQmlExpression);
- d->init(ctxt, expression, scope);
-}
-
/*!
Destroy the QQmlExpression instance.
*/
@@ -316,11 +244,7 @@ QQmlContext *QQmlExpression::context() const
QString QQmlExpression::expression() const
{
Q_D(const QQmlExpression);
- if (!d->expressionUtf8.isEmpty()) {
- return QString::fromUtf8(d->expressionUtf8);
- } else {
- return d->expression;
- }
+ return d->expression;
}
/*!
@@ -332,33 +256,18 @@ void QQmlExpression::setExpression(const QString &expression)
d->resetNotifyOnValueChanged();
d->expression = expression;
- d->expressionUtf8.clear();
d->expressionFunctionValid = false;
- d->expressionFunctionRewritten = false;
- qPersistentDispose(d->v8function);
- qPersistentDispose(d->v8qmlscope);
}
// Must be called with a valid handle scope
-v8::Local<v8::Value> QQmlExpressionPrivate::v8value(bool *isUndefined)
+QV4::Value QQmlExpressionPrivate::v4value(bool *isUndefined)
{
if (!expressionFunctionValid) {
- bool ok = true;
-
- QQmlRewrite::RewriteBinding rewriteBinding;
- rewriteBinding.setName(name);
- QString code;
- if (expressionFunctionRewritten)
- code = expression;
- else
- code = rewriteBinding(expression, &ok);
-
- if (ok) v8function = evalFunction(context(), scopeObject(), code, url, line, &v8qmlscope);
- setUseSharedContext(false);
+ function = qmlBinding(context(), scopeObject(), expression, url, line, &qmlscope);
expressionFunctionValid = true;
}
- return evaluate(context(), v8function, isUndefined);
+ return evaluate(context(), function.value(), isUndefined);
}
QVariant QQmlExpressionPrivate::value(bool *isUndefined)
@@ -376,9 +285,7 @@ QVariant QQmlExpressionPrivate::value(bool *isUndefined)
ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
{
- v8::HandleScope handle_scope;
- v8::Context::Scope context_scope(ep->v8engine()->context());
- v8::Local<v8::Value> result = v8value(isUndefined);
+ QV4::Value result = v4value(isUndefined);
rv = ep->v8engine()->toVariant(result, -1);
}
diff --git a/src/qml/qml/qqmlexpression.h b/src/qml/qml/qqmlexpression.h
index b04abc1b98..b702a37ee0 100644
--- a/src/qml/qml/qqmlexpression.h
+++ b/src/qml/qml/qqmlexpression.h
@@ -91,14 +91,6 @@ public:
Q_SIGNALS:
void valueChanged();
-protected:
- QQmlExpression(QQmlContextData *, QObject *, const QString &,
- QQmlExpressionPrivate &dd);
- QQmlExpression(QQmlContextData *, QObject *, const QString &, bool,
- const QString &, int, int, QQmlExpressionPrivate &dd);
- QQmlExpression(QQmlContextData *, QObject *, const QByteArray &, bool,
- const QString &, int, int, QQmlExpressionPrivate &dd);
-
private:
QQmlExpression(QQmlContextData *, QObject *, const QString &);
diff --git a/src/qml/qml/qqmlexpression_p.h b/src/qml/qml/qqmlexpression_p.h
index 5efb21b9ff..9cc5a326f8 100644
--- a/src/qml/qml/qqmlexpression_p.h
+++ b/src/qml/qml/qqmlexpression_p.h
@@ -55,8 +55,6 @@
#include "qqmlexpression.h"
-#include <private/qv8engine_p.h>
-#include <private/qqmlguard_p.h>
#include <private/qqmlengine_p.h>
#include <private/qfieldlist_p.h>
#include <private/qflagpointer_p.h>
@@ -79,23 +77,18 @@ public:
~QQmlExpressionPrivate();
void init(QQmlContextData *, const QString &, QObject *);
- void init(QQmlContextData *, const QString &, bool, QObject *, const QString &, quint16, quint16);
- void init(QQmlContextData *, const QByteArray &, bool, QObject *, const QString &, quint16, quint16);
+ void init(QQmlContextData *, const QString &, QObject *, const QString &, quint16, quint16);
QVariant value(bool *isUndefined = 0);
- v8::Local<v8::Value> v8value(bool *isUndefined = 0);
+ QV4::Value v4value(bool *isUndefined = 0);
static inline QQmlExpressionPrivate *get(QQmlExpression *expr);
static inline QQmlExpression *get(QQmlExpressionPrivate *expr);
void _q_notify();
- static QQmlExpression *create(QQmlContextData *, QObject *, const QString &, bool,
- const QString &, quint16, quint16);
-
bool expressionFunctionValid:1;
- bool expressionFunctionRewritten:1;
// "Inherited" from QQmlJavaScriptExpression
static QString expressionIdentifier(QQmlJavaScriptExpression *);
@@ -103,10 +96,9 @@ public:
virtual void expressionChanged();
QString expression;
- QByteArray expressionUtf8;
- v8::Persistent<v8::Object> v8qmlscope;
- v8::Persistent<v8::Function> v8function;
+ QV4::PersistentValue qmlscope;
+ QV4::PersistentValue function;
QString url; // This is a QString for a reason. QUrls are slooooooow...
quint16 line;
diff --git a/src/qml/qml/qqmlglobal.cpp b/src/qml/qml/qqmlglobal.cpp
index 25f836a16c..939b7e465a 100644
--- a/src/qml/qml/qqmlglobal.cpp
+++ b/src/qml/qml/qqmlglobal.cpp
@@ -181,7 +181,7 @@ QVariant QQmlValueTypeProvider::createVariantFromString(int type, const QString
return QVariant();
}
-QVariant QQmlValueTypeProvider::createVariantFromJsObject(int type, QQmlV8Handle obj, QV8Engine *e, bool *ok)
+QVariant QQmlValueTypeProvider::createVariantFromJsObject(int type, QQmlV4Handle obj, QV8Engine *e, bool *ok)
{
QVariant v;
@@ -262,7 +262,7 @@ bool QQmlValueTypeProvider::createFromString(int, const QString &, void *, size_
bool QQmlValueTypeProvider::createStringFrom(int, const void *, QString *) { return false; }
bool QQmlValueTypeProvider::variantFromString(const QString &, QVariant *) { return false; }
bool QQmlValueTypeProvider::variantFromString(int, const QString &, QVariant *) { return false; }
-bool QQmlValueTypeProvider::variantFromJsObject(int, QQmlV8Handle, QV8Engine *, QVariant *) { return false; }
+bool QQmlValueTypeProvider::variantFromJsObject(int, QQmlV4Handle, QV8Engine *, QVariant *) { return false; }
bool QQmlValueTypeProvider::equal(int, const void *, const void *, size_t) { return false; }
bool QQmlValueTypeProvider::store(int, const void *, void *, size_t) { return false; }
bool QQmlValueTypeProvider::read(int, const void *, size_t, int, void *) { return false; }
diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h
index d0f408d114..7b968a7e46 100644
--- a/src/qml/qml/qqmlglobal_p.h
+++ b/src/qml/qml/qqmlglobal_p.h
@@ -243,7 +243,7 @@ public:
QVariant createVariantFromString(const QString &);
QVariant createVariantFromString(int, const QString &, bool *);
- QVariant createVariantFromJsObject(int, QQmlV8Handle, QV8Engine *, bool*);
+ QVariant createVariantFromJsObject(int, QQmlV4Handle, QV8Engine *, bool*);
bool equalValueType(int, const void *, const void *, size_t);
bool storeValueType(int, const void *, void *, size_t);
@@ -263,7 +263,7 @@ private:
virtual bool variantFromString(const QString &, QVariant *);
virtual bool variantFromString(int, const QString &, QVariant *);
- virtual bool variantFromJsObject(int, QQmlV8Handle, QV8Engine *, QVariant *);
+ virtual bool variantFromJsObject(int, QQmlV4Handle, QV8Engine *, QVariant *);
virtual bool equal(int, const void *, const void *, size_t);
virtual bool store(int, const void *, void *, size_t);
diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp
index 50b2c8af0d..816f9cec0f 100644
--- a/src/qml/qml/qqmlimport.cpp
+++ b/src/qml/qml/qqmlimport.cpp
@@ -136,7 +136,7 @@ QQmlType *getTypeForUrl(const QString &urlString, const QHashedStringRef& typeNa
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.toUtf8().constData());
+ QByteArray buf(unqualifiedtype.toString().toUtf8());
QQmlPrivate::RegisterCompositeType reg = {
url,
diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h
index 54be20d68f..229919f37a 100644
--- a/src/qml/qml/qqmlincubator_p.h
+++ b/src/qml/qml/qqmlincubator_p.h
@@ -85,7 +85,7 @@ public:
enum Progress { Execute, Completing, Completed };
Progress progress;
- QQmlGuard<QObject> result;
+ QPointer<QObject> result;
QQmlGuardedContextData rootContext;
QQmlCompiledData *compiledData;
QQmlVME vme;
diff --git a/src/qml/qml/qqmlinstruction.cpp b/src/qml/qml/qqmlinstruction.cpp
index d58971b7a0..626140d99d 100644
--- a/src/qml/qml/qqmlinstruction.cpp
+++ b/src/qml/qml/qqmlinstruction.cpp
@@ -221,18 +221,9 @@ void QQmlCompiledData::dump(QQmlInstruction *instr, int idx)
case QQmlInstruction::AssignCustomType:
qWarning().nospace() << idx << "\t\t" << "ASSIGN_CUSTOMTYPE\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.primitive << "\t" << instr->assignCustomType.type;
break;
- case QQmlInstruction::InitV8Bindings:
- qWarning().nospace() << idx << "\t\t" << "INIT_V8_BINDING\t" << instr->initV8Bindings.programIndex << "\t" << instr->initV8Bindings.line;
- break;
case QQmlInstruction::StoreBinding:
qWarning().nospace() << idx << "\t\t" << "STORE_BINDING\t" << instr->assignBinding.property.coreIndex << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
break;
- case QQmlInstruction::StoreV4Binding:
- qWarning().nospace() << idx << "\t\t" << "STORE_COMPILED_BINDING\t" << instr->assignV4Binding.property << "\t" << instr->assignV4Binding.value << "\t" << instr->assignV4Binding.context;
- break;
- case QQmlInstruction::StoreV8Binding:
- qWarning().nospace() << idx << "\t\t" << "STORE_V8_BINDING\t" << instr->assignBinding.property.coreIndex << "\t" << instr->assignBinding.value << "\t" << instr->assignBinding.context;
- break;
case QQmlInstruction::StoreValueSource:
qWarning().nospace() << idx << "\t\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property.coreIndex << "\t" << instr->assignValueSource.castValue;
break;
diff --git a/src/qml/qml/qqmlinstruction_p.h b/src/qml/qml/qqmlinstruction_p.h
index 328b246b4f..be27f9069c 100644
--- a/src/qml/qml/qqmlinstruction_p.h
+++ b/src/qml/qml/qqmlinstruction_p.h
@@ -116,10 +116,7 @@ QT_BEGIN_NAMESPACE
F(StoreImportedScript, storeScript) \
F(StoreScriptString, storeScriptString) \
F(BeginObject, begin) \
- F(InitV8Bindings, initV8Bindings) \
F(StoreBinding, assignBinding) \
- F(StoreV8Binding, assignBinding) \
- F(StoreV4Binding, assignV4Binding) \
F(StoreValueSource, assignValueSource) \
F(StoreValueInterceptor, assignValueInterceptor) \
F(StoreObjectQList, common) \
@@ -237,24 +234,6 @@ union QQmlInstruction
QQmlPropertyRawData property;
int castValue;
};
- struct instr_initV8Bindings {
- QML_INSTR_HEADER
- ushort programIndex;
- ushort line;
- };
- struct instr_assignV4Binding {
- QML_INSTR_HEADER
- int property; // ((value type sub-property index << 16) | property index)
- int propType;
- int value;
- int fallbackValue;
- short context;
- short owner;
- bool isRoot:1;
- bool isAlias:1;
- ushort line;
- ushort column;
- };
struct instr_assignBinding {
QML_INSTR_HEADER
QQmlPropertyRawData property;
@@ -413,9 +392,10 @@ union QQmlInstruction
};
struct instr_storeSignal {
QML_INSTR_HEADER
+ int handlerName;
+ int parameters;
int signalIndex;
int value;
- int parameterCount;
short context;
ushort line;
ushort column;
@@ -510,8 +490,6 @@ union QQmlInstruction
instr_setId setId;
instr_assignValueSource assignValueSource;
instr_assignValueInterceptor assignValueInterceptor;
- instr_initV8Bindings initV8Bindings;
- instr_assignV4Binding assignV4Binding;
instr_assignBinding assignBinding;
instr_fetch fetch;
instr_fetchValue fetchValue;
diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp
index 2a1ed1406a..3b3227cbbb 100644
--- a/src/qml/qml/qqmljavascriptexpression.cpp
+++ b/src/qml/qml/qqmljavascriptexpression.cpp
@@ -42,6 +42,11 @@
#include "qqmljavascriptexpression_p.h"
#include <private/qqmlexpression_p.h>
+#include <private/qqmlcontextwrapper_p.h>
+#include <private/qv4value_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4script_p.h>
+#include <private/qv4errorobject_p.h>
QT_BEGIN_NAMESPACE
@@ -61,12 +66,6 @@ bool QQmlDelayedError::addError(QQmlEnginePrivate *e)
return true;
}
-void QQmlDelayedError::setMessage(v8::Handle<v8::Message> message)
-{
- qPersistentDispose(m_message);
- m_message = qPersistentNew<v8::Message>(message);
-}
-
void QQmlDelayedError::setErrorLocation(const QUrl &url, quint16 line, quint16 column)
{
m_error.setUrl(url);
@@ -84,24 +83,21 @@ void QQmlDelayedError::setErrorObject(QObject *object)
m_error.setObject(object);
}
-/*
- Converting from a message to an error is relatively expensive.
-
- We don't want to do this work for transient exceptions (exceptions
- that occur during startup because of the order of binding
- execution, but have gone away by the time startup has finished), so we
- delay conversion until it is required for displaying the error.
-*/
-void QQmlDelayedError::convertMessageToError(QQmlEngine *engine) const
+void QQmlDelayedError::setError(const QV4::Exception &e)
{
- if (!m_message.IsEmpty() && engine) {
- v8::HandleScope handle_scope;
- v8::Context::Scope context_scope(QQmlEnginePrivate::getV8Engine(engine)->context());
- QQmlExpressionPrivate::exceptionToError(m_message, m_error);
- qPersistentDispose(m_message);
+ m_error.setDescription(e.value().toQString());
+ QV4::ExecutionEngine::StackTrace trace = e.stackTrace();
+ if (!trace.isEmpty()) {
+ QV4::ExecutionEngine::StackFrame frame = trace.first();
+ m_error.setUrl(QUrl(frame.source));
+ m_error.setLine(frame.line);
+ m_error.setColumn(frame.column);
}
+
+ m_error.setColumn(-1);
}
+
QQmlJavaScriptExpression::QQmlJavaScriptExpression(VTable *v)
: m_vtable(v)
{
@@ -125,24 +121,25 @@ void QQmlJavaScriptExpression::resetNotifyOnValueChanged()
clearGuards();
}
-v8::Local<v8::Value>
+QV4::Value
QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
- v8::Handle<v8::Function> function, bool *isUndefined)
+ const QV4::Value &function, bool *isUndefined)
{
return evaluate(context, function, 0, 0, isUndefined);
}
-v8::Local<v8::Value>
+QV4::Value
QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
- v8::Handle<v8::Function> function,
- int argc, v8::Handle<v8::Value> args[],
+ const QV4::Value &function,
+ int argc, QV4::Value *args,
bool *isUndefined)
{
Q_ASSERT(context && context->engine);
- if (function.IsEmpty() || function->IsUndefined()) {
- if (isUndefined) *isUndefined = true;
- return v8::Local<v8::Value>();
+ if (function.isEmpty() || function.isUndefined()) {
+ if (isUndefined)
+ *isUndefined = true;
+ return QV4::Value::emptyValue();
}
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
@@ -160,52 +157,41 @@ QQmlJavaScriptExpression::evaluate(QQmlContextData *context,
QQmlContextData *lastSharedContext = 0;
QObject *lastSharedScope = 0;
- bool sharedContext = useSharedContext();
-
// All code that follows must check with watcher before it accesses data members
// incase we have been deleted.
DeleteWatcher watcher(this);
- if (sharedContext) {
- lastSharedContext = ep->sharedContext;
- lastSharedScope = ep->sharedScope;
- ep->sharedContext = context;
- ep->sharedScope = scopeObject();
- }
-
- v8::Local<v8::Value> result;
- {
- v8::TryCatch try_catch;
- v8::Handle<v8::Object> This = ep->v8engine()->global();
+ QV4::Value result = QV4::Value::undefinedValue();
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine());
+ QV4::ExecutionContext *ctx = v4->current;
+ try {
+ QV4::Value This = ep->v8engine()->global();
if (scopeObject() && requiresThisObject()) {
- v8::Handle<v8::Value> value = ep->v8engine()->newQObject(scopeObject());
- if (value->IsObject()) This = v8::Handle<v8::Object>::Cast(value);
+ QV4::Value value = QV4::QObjectWrapper::wrap(ctx->engine, scopeObject());
+ if (value.isObject())
+ This = value;
}
- result = function->Call(This, argc, args);
+ result = function.asFunctionObject()->call(This, args, argc);
if (isUndefined)
- *isUndefined = try_catch.HasCaught() || result->IsUndefined();
-
- if (watcher.wasDeleted()) {
- } else if (try_catch.HasCaught()) {
- v8::Context::Scope scope(ep->v8engine()->context());
- v8::Local<v8::Message> message = try_catch.Message();
- if (!message.IsEmpty()) {
- delayedError()->setMessage(message);
+ *isUndefined = result.isUndefined();
+
+ if (!watcher.wasDeleted() && hasDelayedError())
+ delayedError()->clearError();
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ if (isUndefined)
+ *isUndefined = true;
+ if (!watcher.wasDeleted()) {
+ if (!e.value().isEmpty()) {
+ delayedError()->setError(e);
} else {
if (hasDelayedError()) delayedError()->clearError();
}
- } else {
- if (hasDelayedError()) delayedError()->clearError();
}
}
- if (sharedContext) {
- ep->sharedContext = lastSharedContext;
- ep->sharedScope = lastSharedScope;
- }
-
if (capture.errorString) {
for (int ii = 0; ii < capture.errorString->count(); ++ii)
qWarning("%s", qPrintable(capture.errorString->at(ii)));
@@ -299,8 +285,10 @@ void QQmlJavaScriptExpression::clearError()
QQmlError QQmlJavaScriptExpression::error(QQmlEngine *engine) const
{
- if (m_vtable.hasValue()) return m_vtable.constValue()->error(engine);
- else return QQmlError();
+ if (m_vtable.hasValue())
+ return m_vtable.constValue()->error();
+ else
+ return QQmlError();
}
QQmlDelayedError *QQmlJavaScriptExpression::delayedError()
@@ -308,119 +296,100 @@ QQmlDelayedError *QQmlJavaScriptExpression::delayedError()
return &m_vtable.value();
}
-void QQmlJavaScriptExpression::exceptionToError(v8::Handle<v8::Message> message, QQmlError &error)
+void QQmlJavaScriptExpression::exceptionToError(const QV4::Exception &e, QQmlError &error)
{
- Q_ASSERT(!message.IsEmpty());
-
- v8::Handle<v8::Value> name = message->GetScriptResourceName();
- v8::Handle<v8::String> description = message->Get();
- int lineNumber = message->GetLineNumber();
-
- v8::Local<v8::String> file = name->IsString()?name->ToString():v8::Local<v8::String>();
- if (file.IsEmpty() || file->Length() == 0)
- error.setUrl(QUrl());
- else
- error.setUrl(QUrl(QV8Engine::toStringStatic(file)));
-
- error.setLine(lineNumber);
- error.setColumn(-1);
-
- QString qDescription = QV8Engine::toStringStatic(description);
- if (qDescription.startsWith(QLatin1String("Uncaught ")))
- qDescription = qDescription.mid(9 /* strlen("Uncaught ") */);
-
- error.setDescription(qDescription);
+ QV4::ErrorObject *errorObj = e.value().asErrorObject();
+ if (errorObj && errorObj->subtype == QV4::ErrorObject::SyntaxError) {
+ QV4::DiagnosticMessage *msg = static_cast<QV4::SyntaxErrorObject*>(errorObj)->message();
+ error.setUrl(QUrl(msg->fileName));
+ error.setLine(msg->startLine);
+ error.setColumn(msg->startColumn);
+ error.setDescription(msg->message);
+ // ### FIXME: support msg->next
+ } else {
+ QV4::ExecutionEngine::StackTrace trace = e.stackTrace();
+ if (!trace.isEmpty()) {
+ QV4::ExecutionEngine::StackFrame frame = trace.first();
+ error.setUrl(QUrl(frame.source));
+ error.setLine(frame.line);
+ error.setColumn(frame.column);
+ }
+ error.setDescription(e.value().toQString());
+ }
}
-// Callee owns the persistent handle
-v8::Persistent<v8::Function>
+QV4::PersistentValue
QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scope,
- const char *code, int codeLength,
- const QString &filename, quint16 line,
- v8::Persistent<v8::Object> *qmlscope)
+ const QString &code, const QString &filename, quint16 line,
+ QV4::PersistentValue *qmlscope)
{
QQmlEngine *engine = ctxt->engine;
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- v8::HandleScope handle_scope;
- v8::Context::Scope ctxtscope(ep->v8engine()->context());
-
- v8::TryCatch tc;
- v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
- v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, codeLength, filename, line);
- if (tc.HasCaught()) {
- QQmlError error;
- error.setDescription(QLatin1String("Exception occurred during function compilation"));
- error.setLine(line);
- error.setUrl(QUrl::fromLocalFile(filename));
- error.setObject(scope);
- v8::Local<v8::Message> message = tc.Message();
- if (!message.IsEmpty())
- QQmlExpressionPrivate::exceptionToError(message, error);
- ep->warning(error);
- return v8::Persistent<v8::Function>();
- }
- v8::Local<v8::Value> result = script->Run(scopeobject);
- if (tc.HasCaught()) {
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine());
+ QV4::ExecutionContext *ctx = v4->current;
+
+ QV4::Value scopeObject = QV4::QmlContextWrapper::qmlScope(ep->v8engine(), ctxt, scope);
+ QV4::Script script(v4, scopeObject.asObject(), code, filename, line);
+ QV4::Value result;
+ try {
+ script.parse();
+ result = script.run();
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
QQmlError error;
- error.setDescription(QLatin1String("Exception occurred during function evaluation"));
- error.setLine(line);
- error.setUrl(QUrl::fromLocalFile(filename));
+ QQmlExpressionPrivate::exceptionToError(e, error);
+ if (error.description().isEmpty())
+ error.setDescription(QLatin1String("Exception occurred during function evaluation"));
+ if (error.line() == -1)
+ error.setLine(line);
+ if (error.url().isEmpty())
+ error.setUrl(QUrl::fromLocalFile(filename));
error.setObject(scope);
- v8::Local<v8::Message> message = tc.Message();
- if (!message.IsEmpty())
- QQmlExpressionPrivate::exceptionToError(message, error);
ep->warning(error);
- return v8::Persistent<v8::Function>();
+ return QV4::PersistentValue();
}
- if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
- return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
+ if (qmlscope)
+ *qmlscope = scopeObject;
+ return result;
}
-// Callee owns the persistent handle
-v8::Persistent<v8::Function>
-QQmlJavaScriptExpression::evalFunction(QQmlContextData *ctxt, QObject *scope,
- const QString &code, const QString &filename, quint16 line,
- v8::Persistent<v8::Object> *qmlscope)
+QV4::PersistentValue QQmlJavaScriptExpression::qmlBinding(QQmlContextData *ctxt, QObject *scope,
+ const QString &code, const QString &filename, quint16 line,
+ QV4::PersistentValue *qmlscope)
{
QQmlEngine *engine = ctxt->engine;
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- v8::HandleScope handle_scope;
- v8::Context::Scope ctxtscope(ep->v8engine()->context());
-
- v8::TryCatch tc;
- v8::Local<v8::Object> scopeobject = ep->v8engine()->qmlScope(ctxt, scope);
- v8::Local<v8::Script> script = ep->v8engine()->qmlModeCompile(code, filename, line);
- if (tc.HasCaught()) {
- QQmlError error;
- error.setDescription(QLatin1String("Exception occurred during function compilation"));
- error.setLine(line);
- error.setUrl(QUrl::fromLocalFile(filename));
- error.setObject(scope);
- v8::Local<v8::Message> message = tc.Message();
- if (!message.IsEmpty())
- QQmlExpressionPrivate::exceptionToError(message, error);
- ep->warning(error);
- return v8::Persistent<v8::Function>();
- }
- v8::Local<v8::Value> result = script->Run(scopeobject);
- if (tc.HasCaught()) {
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine());
+ QV4::ExecutionContext *ctx = v4->current;
+
+ QV4::Value scopeObject = QV4::QmlContextWrapper::qmlScope(ep->v8engine(), ctxt, scope);
+ QV4::Script script(v4, scopeObject.asObject(), code, filename, line);
+ QV4::Value result;
+ try {
+ script.parse();
+ result = script.qmlBinding();
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
QQmlError error;
- error.setDescription(QLatin1String("Exception occurred during function evaluation"));
- error.setLine(line);
- error.setUrl(QUrl::fromLocalFile(filename));
+ QQmlExpressionPrivate::exceptionToError(e, error);
+ if (error.description().isEmpty())
+ error.setDescription(QLatin1String("Exception occurred during function evaluation"));
+ if (error.line() == -1)
+ error.setLine(line);
+ if (error.url().isEmpty())
+ error.setUrl(QUrl::fromLocalFile(filename));
error.setObject(scope);
- v8::Local<v8::Message> message = tc.Message();
- if (!message.IsEmpty())
- QQmlExpressionPrivate::exceptionToError(message, error);
ep->warning(error);
- return v8::Persistent<v8::Function>();
+ return QV4::PersistentValue();
}
- if (qmlscope) *qmlscope = qPersistentNew<v8::Object>(scopeobject);
- return qPersistentNew<v8::Function>(v8::Local<v8::Function>::Cast(result));
+ if (qmlscope)
+ *qmlscope = scopeObject;
+ return result;
}
+
void QQmlJavaScriptExpression::clearGuards()
{
while (Guard *g = activeGuards.takeFirst())
diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h
index b521ea3bee..ef36a2f91a 100644
--- a/src/qml/qml/qqmljavascriptexpression_p.h
+++ b/src/qml/qml/qqmljavascriptexpression_p.h
@@ -53,11 +53,11 @@
// We mean it.
//
-#include <private/qv8_p.h>
#include <QtCore/qglobal.h>
#include <QtQml/qqmlerror.h>
#include <private/qqmlengine_p.h>
#include <private/qpointervaluepair_p.h>
+#include <private/qv4exception_p.h>
QT_BEGIN_NAMESPACE
@@ -65,7 +65,7 @@ class QQmlDelayedError
{
public:
inline QQmlDelayedError() : nextError(0), prevError(0) {}
- inline ~QQmlDelayedError() { qPersistentDispose(m_message); removeError(); }
+ inline ~QQmlDelayedError() { removeError(); }
bool addError(QQmlEnginePrivate *);
@@ -77,20 +77,19 @@ public:
prevError = 0;
}
- inline bool isValid() const { return !m_message.IsEmpty() || m_error.isValid(); }
- inline const QQmlError &error(QQmlEngine *engine) const { convertMessageToError(engine); return m_error; }
- inline void clearError() { qPersistentDispose(m_message); m_error = QQmlError(); }
+ inline bool isValid() const { return m_error.isValid(); }
+ inline const QQmlError &error() const { return m_error; }
+ inline void clearError() { m_error = QQmlError(); }
- void setMessage(v8::Handle<v8::Message> message);
void setErrorLocation(const QUrl &url, quint16 line, quint16 column);
void setErrorDescription(const QString &description);
void setErrorObject(QObject *object);
+ void setError(const QV4::Exception &e);
+
private:
- void convertMessageToError(QQmlEngine *engine) const;
mutable QQmlError m_error;
- mutable v8::Persistent<v8::Message> m_message;
QQmlDelayedError *nextError;
QQmlDelayedError **prevError;
@@ -111,16 +110,14 @@ public:
QQmlJavaScriptExpression(VTable *vtable);
- v8::Local<v8::Value> evaluate(QQmlContextData *, v8::Handle<v8::Function>,
+ QV4::Value evaluate(QQmlContextData *, const QV4::Value &function,
bool *isUndefined);
- v8::Local<v8::Value> evaluate(QQmlContextData *, v8::Handle<v8::Function>,
- int argc, v8::Handle<v8::Value> args[],
+ QV4::Value evaluate(QQmlContextData *, const QV4::Value &function,
+ int argc, QV4::Value *args,
bool *isUndefined);
inline bool requiresThisObject() const;
inline void setRequiresThisObject(bool v);
- inline bool useSharedContext() const;
- inline void setUseSharedContext(bool v);
inline bool notifyOnValueChanged() const;
void setNotifyOnValueChanged(bool v);
@@ -148,15 +145,16 @@ public:
void clearGuards();
QQmlDelayedError *delayedError();
- static void exceptionToError(v8::Handle<v8::Message>, QQmlError &);
- static v8::Persistent<v8::Function> evalFunction(QQmlContextData *ctxt, QObject *scope,
+ static void exceptionToError(const QV4::Exception &e, QQmlError &);
+ static QV4::PersistentValue evalFunction(QQmlContextData *ctxt, QObject *scope,
const QString &code, const QString &filename,
quint16 line,
- v8::Persistent<v8::Object> *qmlscope = 0);
- static v8::Persistent<v8::Function> evalFunction(QQmlContextData *ctxt, QObject *scope,
- const char *code, int codeLength,
- const QString &filename, quint16 line,
- v8::Persistent<v8::Object> *qmlscope = 0);
+ QV4::PersistentValue *qmlscope = 0);
+ // doesn't require rewriting the expression
+ static QV4::PersistentValue qmlBinding(QQmlContextData *ctxt, QObject *scope,
+ const QString &code,
+ const QString &filename, quint16 line,
+ QV4::PersistentValue *qmlscope = 0);
protected:
~QQmlJavaScriptExpression();
@@ -227,16 +225,6 @@ void QQmlJavaScriptExpression::setRequiresThisObject(bool v)
m_scopeObject.setFlagValue(v);
}
-bool QQmlJavaScriptExpression::useSharedContext() const
-{
- return activeGuards.flag2();
-}
-
-void QQmlJavaScriptExpression::setUseSharedContext(bool v)
-{
- activeGuards.setFlag2Value(v);
-}
-
bool QQmlJavaScriptExpression::notifyOnValueChanged() const
{
return activeGuards.flag();
diff --git a/src/qml/qml/qqmllist_p.h b/src/qml/qml/qqmllist_p.h
index a39730049d..48732223dd 100644
--- a/src/qml/qml/qqmllist_p.h
+++ b/src/qml/qml/qqmllist_p.h
@@ -54,7 +54,6 @@
//
#include "qqmllist.h"
-#include "qqmlguard_p.h"
#include "qqmlpropertycache_p.h"
QT_BEGIN_NAMESPACE
@@ -66,7 +65,7 @@ public:
static QQmlListReference init(const QQmlListProperty<QObject> &, int, QQmlEngine *);
- QQmlGuard<QObject> object;
+ QPointer<QObject> object;
QQmlMetaObject elementType;
QQmlListProperty<QObject> property;
int propertyType;
diff --git a/src/qml/qml/qqmllistwrapper.cpp b/src/qml/qml/qqmllistwrapper.cpp
new file mode 100644
index 0000000000..e396f700af
--- /dev/null
+++ b/src/qml/qml/qqmllistwrapper.cpp
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmllistwrapper_p.h"
+#include <private/qv8engine_p.h>
+#include <private/qqmllist_p.h>
+
+#include <private/qv4functionobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+DEFINE_MANAGED_VTABLE(QmlListWrapper);
+
+QmlListWrapper::QmlListWrapper(QV8Engine *engine)
+ : Object(QV8Engine::getV4(engine)),
+ v8(engine)
+{
+ vtbl = &static_vtbl;
+}
+
+QmlListWrapper::~QmlListWrapper()
+{
+}
+
+Value QmlListWrapper::create(QV8Engine *v8, QObject *object, int propId, int propType)
+{
+ if (!object || propId == -1)
+ return Value::nullValue();
+
+ ExecutionEngine *v4 = QV8Engine::getV4(v8);
+
+ QmlListWrapper *r = new (v4->memoryManager) QmlListWrapper(v8);
+ r->object = object;
+ r->propertyType = propType;
+ void *args[] = { &r->property, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args);
+ return Value::fromObject(r);
+}
+
+Value QmlListWrapper::create(QV8Engine *v8, const QQmlListProperty<QObject> &prop, int propType)
+{
+ ExecutionEngine *v4 = QV8Engine::getV4(v8);
+
+ QmlListWrapper *r = new (v4->memoryManager) QmlListWrapper(v8);
+ r->object = prop.object;
+ r->property = prop;
+ r->propertyType = propType;
+ return Value::fromObject(r);
+}
+
+QVariant QmlListWrapper::toVariant() const
+{
+ if (!object)
+ return QVariant();
+
+ return QVariant::fromValue(QQmlListReferencePrivate::init(property, propertyType, v8->engine()));
+}
+
+
+Value QmlListWrapper::get(Managed *m, String *name, bool *hasProperty)
+{
+ QV4::ExecutionEngine *v4 = m->engine();
+ QmlListWrapper *w = m->as<QmlListWrapper>();
+ if (!w)
+ v4->current->throwTypeError();
+
+ if (name == v4->id_length && !w->object.isNull()) {
+ quint32 count = w->property.count ? w->property.count(&w->property) : 0;
+ return Value::fromUInt32(count);
+ }
+
+ uint idx = name->asArrayIndex();
+ if (idx != UINT_MAX)
+ return getIndexed(m, idx, hasProperty);
+
+ return Value::undefinedValue();
+}
+
+Value QmlListWrapper::getIndexed(Managed *m, uint index, bool *hasProperty)
+{
+ QV4::ExecutionEngine *e = m->engine();
+ QmlListWrapper *w = m->as<QmlListWrapper>();
+ if (!w)
+ e->current->throwTypeError();
+
+ quint32 count = w->property.count ? w->property.count(&w->property) : 0;
+ if (index < count && w->property.at)
+ return QV4::QObjectWrapper::wrap(e, w->property.at(&w->property, index));
+
+ return Value::undefinedValue();
+}
+
+void QmlListWrapper::put(Managed *m, String *name, const Value &value)
+{
+ // doesn't do anything. Should we throw?
+ Q_UNUSED(m);
+ Q_UNUSED(name);
+ Q_UNUSED(value);
+}
+
+void QmlListWrapper::destroy(Managed *that)
+{
+ QmlListWrapper *w = that->as<QmlListWrapper>();
+ w->~QmlListWrapper();
+}
+
+Property *QmlListWrapper::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs)
+{
+ *name = 0;
+ *index = UINT_MAX;
+ QmlListWrapper *w = m->as<QmlListWrapper>();
+ quint32 count = w->property.count ? w->property.count(&w->property) : 0;
+ if (it->arrayIndex < count) {
+ if (attrs)
+ *attrs = QV4::Attr_Data;
+ *index = it->arrayIndex;
+ ++it->arrayIndex;
+ it->tmpDynamicProperty.value = QV4::QObjectWrapper::wrap(w->engine(), w->property.at(&w->property, *index));
+ return &it->tmpDynamicProperty;
+ }
+ return QV4::Object::advanceIterator(m, it, name, index, attrs);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8objectresource_p.h b/src/qml/qml/qqmllistwrapper_p.h
index 78fd835431..c87b9b22d5 100644
--- a/src/qml/qml/v8/qv8objectresource_p.h
+++ b/src/qml/qml/qqmllistwrapper_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QV8OBJECTRESOURCE_P_H
-#define QV8OBJECTRESOURCE_P_H
+#ifndef QQMLLISTWRAPPER_P_H
+#define QQMLLISTWRAPPER_P_H
//
// W A R N I N G
@@ -54,31 +54,50 @@
//
#include <QtCore/qglobal.h>
-#include <private/qv8_p.h>
+#include <QtCore/qpointer.h>
-QT_BEGIN_NAMESPACE
+#include <QtQml/qqmllist.h>
-#define V8_RESOURCE_TYPE(resourcetype) \
-public: \
- enum { V8ResourceType = QV8ObjectResource:: resourcetype }; \
- virtual QV8ObjectResource::ResourceType resourceType() const { return QV8ObjectResource:: resourcetype; } \
-private:
+#include <private/qv4value_p.h>
+#include <private/qv4object_p.h>
+
+QT_BEGIN_NAMESPACE
class QV8Engine;
-class QV8ObjectResource : public v8::Object::ExternalResource
+
+namespace QV4 {
+
+struct Q_QML_EXPORT QmlListWrapper : Object
{
+ Q_MANAGED
+protected:
+ QmlListWrapper(QV8Engine *engine);
+ ~QmlListWrapper();
+
public:
- QV8ObjectResource(QV8Engine *engine) : engine(engine) { Q_ASSERT(engine); }
- enum ResourceType { ContextType, QObjectType, TypeType, ListType, VariantType,
- ValueTypeType, XMLHttpRequestType, DOMNodeType, SQLDatabaseType,
- ListModelType, Context2DType, Context2DStyleType, Context2DPixelArrayType,
- ParticleDataType, SignalHandlerType, IncubatorType, VisualDataItemType,
- SequenceType, LocaleDataType, ChangeSetArrayType };
- virtual ResourceType resourceType() const = 0;
-
- QV8Engine *engine;
+
+ static Value create(QV8Engine *v8, QObject *object, int propId, int propType);
+ static Value create(QV8Engine *v8, const QQmlListProperty<QObject> &prop, int propType);
+
+ QVariant toVariant() const;
+
+ static Value get(Managed *m, String *name, bool *hasProperty);
+ static Value getIndexed(Managed *m, uint index, bool *hasProperty);
+ static void put(Managed *m, String *name, const Value &value);
+ static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes);
+ static void destroy(Managed *that);
+
+private:
+ QV8Engine *v8;
+ QPointer<QObject> object;
+ QQmlListProperty<QObject> property;
+ int propertyType;
+
};
+}
+
QT_END_NAMESPACE
-#endif // QV8OBJECTRESOURCE_P_H
+#endif
+
diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp
index 194a5ca7e7..c07144a66c 100644
--- a/src/qml/qml/qqmllocale.cpp
+++ b/src/qml/qml/qqmllocale.cpp
@@ -42,313 +42,294 @@
#include "qqmllocale_p.h"
#include "qqmlengine_p.h"
#include <private/qqmlcontext_p.h>
-#include <private/qjsconverter_impl_p.h>
#include <QtCore/qnumeric.h>
#include <QtCore/qdatetime.h>
#include <private/qlocale_p.h>
#include <private/qlocale_data_p.h>
+#include <private/qv4dateobject_p.h>
+#include <private/qv4numberobject_p.h>
+#include <private/qv4stringobject_p.h>
+
QT_BEGIN_NAMESPACE
-class QV8LocaleDataResource : public QV8ObjectResource
+class QQmlLocaleData : public QV4::Object
{
- V8_RESOURCE_TYPE(LocaleDataType)
+ Q_MANAGED
public:
- QV8LocaleDataResource(QV8Engine *e) : QV8ObjectResource(e) {}
+ QQmlLocaleData(QV4::ExecutionEngine *engine)
+ : QV4::Object(engine)
+ {
+ vtbl = &static_vtbl;
+ type = Type_Object;
+ }
+
QLocale locale;
+
+ static QLocale &getThisLocale(QV4::SimpleCallContext *ctx) {
+ QQmlLocaleData *thisObject = ctx->thisObject.asObject()->as<QQmlLocaleData>();
+ if (!thisObject)
+ ctx->throwTypeError();
+ return thisObject->locale;
+ }
+
+ static QV4::Value method_currencySymbol(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_dateTimeFormat(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_timeFormat(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_dateFormat(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_monthName(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_standaloneMonthName(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_dayName(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_standaloneDayName(QV4::SimpleCallContext *ctx);
+
+ static QV4::Value method_get_firstDayOfWeek(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_measurementSystem(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_textDirection(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_weekDays(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_uiLanguages(QV4::SimpleCallContext *ctx);
+
+ static QV4::Value method_get_name(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_nativeLanguageName(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_nativeCountryName(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_decimalPoint(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_groupSeparator(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_percent(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_zeroDigit(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_negativeSign(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_positiveSign(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_exponential(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_amText(QV4::SimpleCallContext *ctx);
+ static QV4::Value method_get_pmText(QV4::SimpleCallContext *ctx);
+
+private:
+ static void destroy(Managed *that)
+ {
+ static_cast<QQmlLocaleData *>(that)->~QQmlLocaleData();
+ }
};
+DEFINE_MANAGED_VTABLE(QQmlLocaleData);
+
#define GET_LOCALE_DATA_RESOURCE(OBJECT) \
-QV8LocaleDataResource *r = v8_resource_cast<QV8LocaleDataResource>(OBJECT); \
-if (!r) \
- V8THROW_ERROR("Not a valid Locale object")
+ QQmlLocaleData *r = OBJECT.as<QQmlLocaleData>(); \
+ if (!r) \
+ V4THROW_ERROR("Not a valid Locale object")
-static bool isLocaleObject(v8::Handle<v8::Value> val)
+static bool isLocaleObject(const QV4::Value &val)
{
- if (!val->IsObject())
- return false;
-
- v8::Handle<v8::Object> localeObj = val->ToObject();
- return localeObj->Has(v8::String::New("nativeLanguageName")); //XXX detect locale object properly
+ return val.as<QQmlLocaleData>();
}
//--------------
// Date extension
-static const char dateToLocaleStringFunction[] =
- "(function(toLocaleStringFunc) { "
- " var orig_toLocaleString;"
- " orig_toLocaleString = Date.prototype.toLocaleString;"
- " Date.prototype.toLocaleString = (function() {"
- " var val = toLocaleStringFunc.apply(this, arguments);"
- " if (val == undefined) val = orig_toLocaleString.call(this);"
- " return val;"
- " })"
- "})";
-
-static const char dateToLocaleTimeStringFunction[] =
- "(function(toLocaleTimeStringFunc) { "
- " var orig_toLocaleTimeString;"
- " orig_toLocaleTimeString = Date.prototype.toLocaleTimeString;"
- " Date.prototype.toLocaleTimeString = (function() {"
- " var val = toLocaleTimeStringFunc.apply(this, arguments);"
- " if (val == undefined) val = orig_toLocaleTimeString.call(this);"
- " return val;"
- " })"
- "})";
-
-static const char dateToLocaleDateStringFunction[] =
- "(function(toLocaleDateStringFunc) { "
- " var orig_toLocaleDateString;"
- " orig_toLocaleDateString = Date.prototype.toLocaleDateString;"
- " Date.prototype.toLocaleDateString = (function() {"
- " var val = toLocaleDateStringFunc.apply(this, arguments);"
- " if (val == undefined) val = orig_toLocaleDateString.call(this);"
- " return val;"
- " })"
- "})";
-
-
-static const char dateFromLocaleStringFunction[] =
- "(function(fromLocaleStringFunc) { "
- " Date.fromLocaleString = (function() {"
- " return fromLocaleStringFunc.apply(null, arguments);"
- " })"
- "})";
-
-static const char dateFromLocaleTimeStringFunction[] =
- "(function(fromLocaleTimeStringFunc) { "
- " Date.fromLocaleTimeString = (function() {"
- " return fromLocaleTimeStringFunc.apply(null, arguments);"
- " })"
- "})";
-
-static const char dateFromLocaleDateStringFunction[] =
- "(function(fromLocaleDateStringFunc) { "
- " Date.fromLocaleDateString = (function() {"
- " return fromLocaleDateStringFunc.apply(null, arguments);"
- " })"
- "})";
-
-static const char dateTimeZoneUpdatedFunction[] =
- "(function(timeZoneUpdatedFunc) { "
- " Date.timeZoneUpdated = (function() {"
- " return timeZoneUpdatedFunc.apply(null, arguments);"
- " })"
- "})";
-
-
-static void registerFunction(QV8Engine *engine, const char *script, v8::InvocationCallback func)
-{
- v8::Local<v8::Script> registerScript = v8::Script::New(v8::String::New(script), 0, 0, v8::Handle<v8::String>(), v8::Script::NativeMode);
- v8::Local<v8::Value> result = registerScript->Run();
- Q_ASSERT(result->IsFunction());
- v8::Local<v8::Function> registerFunc = v8::Local<v8::Function>::Cast(result);
- v8::Handle<v8::Value> args = V8FUNCTION(func, engine);
- registerFunc->Call(v8::Local<v8::Object>::Cast(registerFunc), 1, &args);
-}
-
-void QQmlDateExtension::registerExtension(QV8Engine *engine)
+void QQmlDateExtension::registerExtension(QV4::ExecutionEngine *engine)
{
- registerFunction(engine, dateToLocaleStringFunction, toLocaleString);
- registerFunction(engine, dateToLocaleTimeStringFunction, toLocaleTimeString);
- registerFunction(engine, dateToLocaleDateStringFunction, toLocaleDateString);
- registerFunction(engine, dateFromLocaleStringFunction, fromLocaleString);
- registerFunction(engine, dateFromLocaleTimeStringFunction, fromLocaleTimeString);
- registerFunction(engine, dateFromLocaleDateStringFunction, fromLocaleDateString);
- registerFunction(engine, dateTimeZoneUpdatedFunction, timeZoneUpdated);
+ engine->datePrototype->defineDefaultProperty(engine, QStringLiteral("toLocaleString"), toLocaleString);
+ engine->datePrototype->defineDefaultProperty(engine, QStringLiteral("toLocaleTimeString"), toLocaleTimeString);
+ engine->datePrototype->defineDefaultProperty(engine, QStringLiteral("toLocaleDateString"), toLocaleDateString);
+ engine->dateCtor.objectValue()->defineDefaultProperty(engine, QStringLiteral("fromLocaleString"), fromLocaleString);
+ engine->dateCtor.objectValue()->defineDefaultProperty(engine, QStringLiteral("fromLocaleTimeString"), fromLocaleTimeString);
+ engine->dateCtor.objectValue()->defineDefaultProperty(engine, QStringLiteral("fromLocaleDateString"), fromLocaleDateString);
+ engine->dateCtor.objectValue()->defineDefaultProperty(engine, QStringLiteral("timeZoneUpdated"), timeZoneUpdated);
}
-v8::Handle<v8::Value> QQmlDateExtension::toLocaleString(const v8::Arguments& args)
+QV4::Value QQmlDateExtension::toLocaleString(QV4::SimpleCallContext *ctx)
{
- if (args.Length() > 2)
- return v8::Undefined();
+ if (ctx->argumentCount > 2)
+ return QV4::DatePrototype::method_toLocaleString(ctx);
- if (!args.This()->IsDate())
- return v8::Undefined();
+ QV4::DateObject *date = ctx->thisObject.asDateObject();
+ if (!date)
+ return QV4::DatePrototype::method_toLocaleString(ctx);
- QDateTime dt = QV8Engine::qtDateTimeFromJsDate(v8::Handle<v8::Date>::Cast(args.This())->NumberValue());
+ QDateTime dt = date->toQDateTime();
- if (args.Length() == 0) {
+ if (ctx->argumentCount == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return QJSConverter::toString(locale.toString(dt));
+ return QV4::Value::fromString(ctx, locale.toString(dt));
}
- if (!isLocaleObject(args[0]))
- return v8::Undefined(); // Use the default Date toLocaleString()
+ if (!isLocaleObject(ctx->arguments[0]))
+ return QV4::DatePrototype::method_toLocaleString(ctx); // Use the default Date toLocaleString()
- GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+ GET_LOCALE_DATA_RESOURCE(ctx->arguments[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QString formattedDt;
- if (args.Length() == 2) {
- if (args[1]->IsString()) {
- QString format = r->engine->toVariant(args[1], -1).toString();
+ if (ctx->argumentCount == 2) {
+ if (ctx->arguments[1].isString()) {
+ QString format = ctx->arguments[1].stringValue()->toQString();
formattedDt = r->locale.toString(dt, format);
- } else if (args[1]->IsNumber()) {
- quint32 intFormat = args[1]->ToNumber()->Value();
+ } else if (ctx->arguments[1].isNumber()) {
+ quint32 intFormat = ctx->arguments[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
formattedDt = r->locale.toString(dt, format);
} else {
- V8THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format");
+ V4THROW_ERROR("Locale: Date.toLocaleString(): Invalid datetime format");
}
} else {
formattedDt = r->locale.toString(dt, enumFormat);
}
- return r->engine->toString(formattedDt);
+ return QV4::Value::fromString(ctx, formattedDt);
}
-v8::Handle<v8::Value> QQmlDateExtension::toLocaleTimeString(const v8::Arguments& args)
+QV4::Value QQmlDateExtension::toLocaleTimeString(QV4::SimpleCallContext *ctx)
{
- if (args.Length() > 2)
- return v8::Undefined();
+ if (ctx->argumentCount > 2)
+ return QV4::DatePrototype::method_toLocaleTimeString(ctx);
- if (!args.This()->IsDate())
- return v8::Undefined();
+ QV4::DateObject *date = ctx->thisObject.asDateObject();
+ if (!date)
+ return QV4::DatePrototype::method_toLocaleTimeString(ctx);
- QDateTime dt = QV8Engine::qtDateTimeFromJsDate(v8::Handle<v8::Date>::Cast(args.This())->NumberValue());
+ QDateTime dt = date->toQDateTime();
QTime time = dt.time();
- if (args.Length() == 0) {
+ if (ctx->argumentCount == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return QJSConverter::toString(locale.toString(time));
+ return QV4::Value::fromString(ctx, locale.toString(time));
}
- if (!isLocaleObject(args[0]))
- return v8::Undefined(); // Use the default Date toLocaleTimeString()
+ if (!isLocaleObject(ctx->arguments[0]))
+ return QV4::DatePrototype::method_toLocaleTimeString(ctx); // Use the default Date toLocaleTimeString()
- GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+ GET_LOCALE_DATA_RESOURCE(ctx->arguments[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QString formattedTime;
- if (args.Length() == 2) {
- if (args[1]->IsString()) {
- QString format = r->engine->toVariant(args[1], -1).toString();
+ if (ctx->argumentCount == 2) {
+ if (ctx->arguments[1].isString()) {
+ QString format = ctx->arguments[1].stringValue()->toQString();
formattedTime = r->locale.toString(time, format);
- } else if (args[1]->IsNumber()) {
- quint32 intFormat = args[1]->ToNumber()->Value();
+ } else if (ctx->arguments[1].isNumber()) {
+ quint32 intFormat = ctx->arguments[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
formattedTime = r->locale.toString(time, format);
} else {
- V8THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format");
+ V4THROW_ERROR("Locale: Date.toLocaleTimeString(): Invalid time format");
}
} else {
formattedTime = r->locale.toString(time, enumFormat);
}
- return r->engine->toString(formattedTime);
+ return QV4::Value::fromString(ctx, formattedTime);
}
-v8::Handle<v8::Value> QQmlDateExtension::toLocaleDateString(const v8::Arguments& args)
+QV4::Value QQmlDateExtension::toLocaleDateString(QV4::SimpleCallContext *ctx)
{
- if (args.Length() > 2)
- return v8::Undefined();
+ if (ctx->argumentCount > 2)
+ return QV4::DatePrototype::method_toLocaleDateString(ctx);
- if (!args.This()->IsDate())
- return v8::Undefined();
+ QV4::DateObject *dateObj = ctx->thisObject.asDateObject();
+ if (!dateObj)
+ return QV4::DatePrototype::method_toLocaleDateString(ctx);
- QDateTime dt = QV8Engine::qtDateTimeFromJsDate(v8::Handle<v8::Date>::Cast(args.This())->NumberValue());
+ QDateTime dt = dateObj->toQDateTime();
QDate date = dt.date();
- if (args.Length() == 0) {
+ if (ctx->argumentCount == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return QJSConverter::toString(locale.toString(date));
+ return QV4::Value::fromString(ctx, locale.toString(date));
}
- if (!isLocaleObject(args[0]))
- return v8::Undefined(); // Use the default Date toLocaleDateString()
+ if (!isLocaleObject(ctx->arguments[0]))
+ return QV4::DatePrototype::method_toLocaleDateString(ctx); // Use the default Date toLocaleDateString()
- GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+ GET_LOCALE_DATA_RESOURCE(ctx->arguments[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QString formattedDate;
- if (args.Length() == 2) {
- if (args[1]->IsString()) {
- QString format = r->engine->toVariant(args[1], -1).toString();
+ if (ctx->argumentCount == 2) {
+ if (ctx->arguments[1].isString()) {
+ QString format = ctx->arguments[1].stringValue()->toQString();
formattedDate = r->locale.toString(date, format);
- } else if (args[1]->IsNumber()) {
- quint32 intFormat = args[1]->ToNumber()->Value();
+ } else if (ctx->arguments[1].isNumber()) {
+ quint32 intFormat = ctx->arguments[1].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
formattedDate = r->locale.toString(date, format);
} else {
- V8THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format");
+ V4THROW_ERROR("Locale: Date.loLocaleDateString(): Invalid date format");
}
} else {
formattedDate = r->locale.toString(date, enumFormat);
}
- return r->engine->toString(formattedDate);
+ return QV4::Value::fromString(ctx, formattedDate);
}
-v8::Handle<v8::Value> QQmlDateExtension::fromLocaleString(const v8::Arguments& args)
+QV4::Value QQmlDateExtension::fromLocaleString(QV4::SimpleCallContext *ctx)
{
- if (args.Length() == 1 && args[0]->IsString()) {
+ QV4::ExecutionEngine * const engine = ctx->engine;
+ if (ctx->argumentCount == 1 && ctx->arguments[0].isString()) {
QLocale locale;
- QString dateString = QJSConverter::toString(args[0]->ToString());
+ QString dateString = ctx->arguments[0].stringValue()->toQString();
QDateTime dt = locale.toDateTime(dateString);
- return QJSConverter::toDateTime(dt);
+ return QV4::Value::fromObject(engine->newDateObject(dt));
}
- if (args.Length() < 1 || args.Length() > 3 || !isLocaleObject(args[0]))
- V8THROW_ERROR("Locale: Date.fromLocaleString(): Invalid arguments");
+ if (ctx->argumentCount < 1 || ctx->argumentCount > 3 || !isLocaleObject(ctx->arguments[0]))
+ V4THROW_ERROR("Locale: Date.fromLocaleString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+ GET_LOCALE_DATA_RESOURCE(ctx->arguments[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QDateTime dt;
- QString dateString = r->engine->toString(args[1]->ToString());
- if (args.Length() == 3) {
- if (args[2]->IsString()) {
- QString format = r->engine->toString(args[2]->ToString());
+ QString dateString = ctx->arguments[1].toQString();
+ if (ctx->argumentCount == 3) {
+ if (ctx->arguments[2].isString()) {
+ QString format = ctx->arguments[2].stringValue()->toQString();
dt = r->locale.toDateTime(dateString, format);
- } else if (args[2]->IsNumber()) {
- quint32 intFormat = args[2]->ToNumber()->Value();
+ } else if (ctx->arguments[2].isNumber()) {
+ quint32 intFormat = ctx->arguments[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
dt = r->locale.toDateTime(dateString, format);
} else {
- V8THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format");
+ V4THROW_ERROR("Locale: Date.fromLocaleString(): Invalid datetime format");
}
} else {
dt = r->locale.toDateTime(dateString, enumFormat);
}
- return QJSConverter::toDateTime(dt);
+ return QV4::Value::fromObject(engine->newDateObject(dt));
}
-v8::Handle<v8::Value> QQmlDateExtension::fromLocaleTimeString(const v8::Arguments& args)
+QV4::Value QQmlDateExtension::fromLocaleTimeString(QV4::SimpleCallContext *ctx)
{
- if (args.Length() == 1 && args[0]->IsString()) {
+ QV4::ExecutionEngine * const engine = ctx->engine;
+
+ if (ctx->argumentCount == 1 && ctx->arguments[0].isString()) {
QLocale locale;
- QString timeString = QJSConverter::toString(args[0]->ToString());
+ QString timeString = ctx->arguments[0].stringValue()->toQString();
QTime time = locale.toTime(timeString);
QDateTime dt = QDateTime::currentDateTime();
dt.setTime(time);
- return QJSConverter::toDateTime(dt);
+ return QV4::Value::fromObject(engine->newDateObject(dt));
}
- if (args.Length() < 1 || args.Length() > 3 || !isLocaleObject(args[0]))
- V8THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid arguments");
+ if (ctx->argumentCount < 1 || ctx->argumentCount > 3 || !isLocaleObject(ctx->arguments[0]))
+ V4THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+ GET_LOCALE_DATA_RESOURCE(ctx->arguments[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QTime tm;
- QString dateString = r->engine->toString(args[1]->ToString());
- if (args.Length() == 3) {
- if (args[2]->IsString()) {
- QString format = r->engine->toString(args[2]->ToString());
+ QString dateString = ctx->arguments[1].toQString();
+ if (ctx->argumentCount == 3) {
+ if (ctx->arguments[2].isString()) {
+ QString format = ctx->arguments[2].stringValue()->toQString();
tm = r->locale.toTime(dateString, format);
- } else if (args[2]->IsNumber()) {
- quint32 intFormat = args[2]->ToNumber()->Value();
+ } else if (ctx->arguments[2].isNumber()) {
+ quint32 intFormat = ctx->arguments[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
tm = r->locale.toTime(dateString, format);
} else {
- V8THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format");
+ V4THROW_ERROR("Locale: Date.fromLocaleTimeString(): Invalid datetime format");
}
} else {
tm = r->locale.toTime(dateString, enumFormat);
@@ -357,269 +338,244 @@ v8::Handle<v8::Value> QQmlDateExtension::fromLocaleTimeString(const v8::Argument
QDateTime dt = QDateTime::currentDateTime();
dt.setTime(tm);
- return QJSConverter::toDateTime(dt);
+ return QV4::Value::fromObject(engine->newDateObject(dt));
}
-v8::Handle<v8::Value> QQmlDateExtension::fromLocaleDateString(const v8::Arguments& args)
+QV4::Value QQmlDateExtension::fromLocaleDateString(QV4::SimpleCallContext *ctx)
{
- if (args.Length() == 1 && args[0]->IsString()) {
+ QV4::ExecutionEngine * const engine = ctx->engine;
+
+ if (ctx->argumentCount == 1 && ctx->arguments[0].isString()) {
QLocale locale;
- QString dateString = QJSConverter::toString(args[0]->ToString());
+ QString dateString = ctx->arguments[0].stringValue()->toQString();
QDate date = locale.toDate(dateString);
- return QJSConverter::toDateTime(QDateTime(date));
+ return QV4::Value::fromObject(engine->newDateObject(QDateTime(date)));
}
- if (args.Length() < 1 || args.Length() > 3 || !isLocaleObject(args[0]))
- V8THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid arguments");
+ if (ctx->argumentCount < 1 || ctx->argumentCount > 3 || !isLocaleObject(ctx->arguments[0]))
+ V4THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+ GET_LOCALE_DATA_RESOURCE(ctx->arguments[0]);
QLocale::FormatType enumFormat = QLocale::LongFormat;
QDate dt;
- QString dateString = r->engine->toString(args[1]->ToString());
- if (args.Length() == 3) {
- if (args[2]->IsString()) {
- QString format = r->engine->toString(args[2]->ToString());
+ QString dateString = ctx->arguments[1].toQString();
+ if (ctx->argumentCount == 3) {
+ if (ctx->arguments[2].isString()) {
+ QString format = ctx->arguments[2].stringValue()->toQString();
dt = r->locale.toDate(dateString, format);
- } else if (args[2]->IsNumber()) {
- quint32 intFormat = args[2]->ToNumber()->Value();
+ } else if (ctx->arguments[2].isNumber()) {
+ quint32 intFormat = ctx->arguments[2].toNumber();
QLocale::FormatType format = QLocale::FormatType(intFormat);
dt = r->locale.toDate(dateString, format);
} else {
- V8THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format");
+ V4THROW_ERROR("Locale: Date.fromLocaleDateString(): Invalid datetime format");
}
} else {
dt = r->locale.toDate(dateString, enumFormat);
}
- return QJSConverter::toDateTime(QDateTime(dt));
+ return QV4::Value::fromObject(engine->newDateObject(QDateTime(dt)));
}
-v8::Handle<v8::Value> QQmlDateExtension::timeZoneUpdated(const v8::Arguments& args)
+QV4::Value QQmlDateExtension::timeZoneUpdated(QV4::SimpleCallContext *ctx)
{
- if (args.Length() != 0)
- V8THROW_ERROR("Locale: Date.timeZoneUpdated(): Invalid arguments");
+ if (ctx->argumentCount != 0)
+ V4THROW_ERROR("Locale: Date.timeZoneUpdated(): Invalid arguments");
- v8::Date::DateTimeConfigurationChangeNotification();
+ QV4::DatePrototype::timezoneUpdated();
- return v8::Undefined();
+ return QV4::Value::undefinedValue();
}
//-----------------
// Number extension
-static const char numberToLocaleStringFunction[] =
- "(function(toLocaleStringFunc) { "
- " var orig_toLocaleString;"
- " orig_toLocaleString = Number.prototype.toLocaleString;"
- " Number.prototype.toLocaleString = (function() {"
- " var val = toLocaleStringFunc.apply(this, arguments);"
- " if (val == undefined) val = orig_toLocaleString.call(this);"
- " return val;"
- " })"
- "})";
-
-static const char numberToLocaleCurrencyStringFunction[] =
- "(function(toLocaleCurrencyStringFunc) { "
- " Number.prototype.toLocaleCurrencyString = (function() {"
- " return toLocaleCurrencyStringFunc.apply(this, arguments);"
- " })"
- "})";
-
-static const char numberFromLocaleStringFunction[] =
- "(function(fromLocaleStringFunc) { "
- " Number.fromLocaleString = (function() {"
- " return fromLocaleStringFunc.apply(null, arguments);"
- " })"
- "})";
-
-
-void QQmlNumberExtension::registerExtension(QV8Engine *engine)
+void QQmlNumberExtension::registerExtension(QV4::ExecutionEngine *engine)
{
- registerFunction(engine, numberToLocaleStringFunction, toLocaleString);
- registerFunction(engine, numberToLocaleCurrencyStringFunction, toLocaleCurrencyString);
- registerFunction(engine, numberFromLocaleStringFunction, fromLocaleString);
+ engine->numberPrototype->defineDefaultProperty(engine, QStringLiteral("toLocaleString"), toLocaleString);
+ engine->numberPrototype->defineDefaultProperty(engine, QStringLiteral("toLocaleCurrencyString"), toLocaleCurrencyString);
+ engine->numberCtor.objectValue()->defineDefaultProperty(engine, QStringLiteral("fromLocaleString"), fromLocaleString);
}
-v8::Handle<v8::Value> QQmlNumberExtension::toLocaleString(const v8::Arguments& args)
+QV4::Value QQmlNumberExtension::toLocaleString(QV4::SimpleCallContext *ctx)
{
- if (args.Length() > 3)
- V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ if (ctx->argumentCount > 3)
+ V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- double number = args.This()->ToNumber()->Value();
+ double number = ctx->thisObject.toNumber();
- if (args.Length() == 0) {
+ if (ctx->argumentCount == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return QJSConverter::toString(locale.toString(number));
+ return QV4::Value::fromString(ctx, locale.toString(number));
}
- if (!isLocaleObject(args[0]))
- return v8::Undefined(); // Use the default Number toLocaleString()
+ if (!isLocaleObject(ctx->arguments[0]))
+ return QV4::NumberPrototype::method_toLocaleString(ctx); // Use the default Number toLocaleString()
- GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+ GET_LOCALE_DATA_RESOURCE(ctx->arguments[0]);
uint16_t format = 'f';
- if (args.Length() > 1) {
- if (!args[1]->IsString())
- V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- v8::Local<v8::String> fs = args[1]->ToString();
- if (!fs.IsEmpty() && fs->Length()) {
- v8::String::Value value(fs);
- Q_ASSERT(*value != NULL);
- format = **value;
- }
+ if (ctx->argumentCount > 1) {
+ if (!ctx->arguments[1].isString())
+ V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ QV4::String *fs = ctx->arguments[1].toString(ctx);
+ if (!fs->isEmpty())
+ format = fs->toQString().at(0).unicode();
}
int prec = 2;
- if (args.Length() > 2) {
- if (!args[2]->IsNumber())
- V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- prec = args[2]->IntegerValue();
+ if (ctx->argumentCount > 2) {
+ if (!ctx->arguments[2].isNumber())
+ V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ prec = ctx->arguments[2].toInt32();
}
- return r->engine->toString(r->locale.toString(number, (char)format, prec));
+ return QV4::Value::fromString(ctx, r->locale.toString(number, (char)format, prec));
}
-v8::Handle<v8::Value> QQmlNumberExtension::toLocaleCurrencyString(const v8::Arguments& args)
+QV4::Value QQmlNumberExtension::toLocaleCurrencyString(QV4::SimpleCallContext *ctx)
{
- if (args.Length() > 2)
- V8THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
+ if (ctx->argumentCount > 2)
+ V4THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
- double number = args.This()->ToNumber()->Value();
+ double number = ctx->thisObject.toNumber();
- if (args.Length() == 0) {
+ if (ctx->argumentCount == 0) {
// Use QLocale for standard toLocaleString() function
QLocale locale;
- return QJSConverter::toString(locale.toString(number));
+ return QV4::Value::fromString(ctx, locale.toString(number));
}
- if (!isLocaleObject(args[0]))
- V8THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
+ if (!isLocaleObject(ctx->arguments[0]))
+ V4THROW_ERROR("Locale: Number.toLocaleCurrencyString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+ GET_LOCALE_DATA_RESOURCE(ctx->arguments[0]);
QString symbol;
- if (args.Length() > 1) {
- if (!args[1]->IsString())
- V8THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
- symbol = r->engine->toString(args[1]->ToString());
+ if (ctx->argumentCount > 1) {
+ if (!ctx->arguments[1].isString())
+ V4THROW_ERROR("Locale: Number.toLocaleString(): Invalid arguments");
+ symbol = ctx->arguments[1].toQString();
}
- return r->engine->toString(r->locale.toCurrencyString(number, symbol));
+ return QV4::Value::fromString(ctx, r->locale.toCurrencyString(number, symbol));
}
-v8::Handle<v8::Value> QQmlNumberExtension::fromLocaleString(const v8::Arguments& args)
+QV4::Value QQmlNumberExtension::fromLocaleString(QV4::SimpleCallContext *ctx)
{
- if (args.Length() < 1 || args.Length() > 2)
- V8THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
+ if (ctx->argumentCount < 1 || ctx->argumentCount > 2)
+ V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
int numberIdx = 0;
QLocale locale;
- if (args.Length() == 2) {
- if (!isLocaleObject(args[0]))
- V8THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
+ if (ctx->argumentCount == 2) {
+ if (!isLocaleObject(ctx->arguments[0]))
+ V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid arguments");
- GET_LOCALE_DATA_RESOURCE(args[0]->ToObject());
+ GET_LOCALE_DATA_RESOURCE(ctx->arguments[0]);
locale = r->locale;
numberIdx = 1;
}
- v8::Local<v8::String> ns = args[numberIdx]->ToString();
- if (ns.IsEmpty() || ns->Length() == 0)
- return v8::Number::New(Q_QNAN);
+ QV4::String *ns = ctx->arguments[numberIdx].toString(ctx);
+ if (ns->isEmpty())
+ return QV4::Value::fromDouble(Q_QNAN);
bool ok = false;
- double val = locale.toDouble(QJSConverter::toString(ns), &ok);
+ double val = locale.toDouble(ns->toQString(), &ok);
if (!ok)
- V8THROW_ERROR("Locale: Number.fromLocaleString(): Invalid format")
+ V4THROW_ERROR("Locale: Number.fromLocaleString(): Invalid format")
- return v8::Number::New(val);
+ return QV4::Value::fromDouble(val);
}
//--------------
// Locale object
-static v8::Handle<v8::Value> locale_get_firstDayOfWeek(v8::Local<v8::String>, const v8::AccessorInfo &info)
+QV4::Value QQmlLocaleData::method_get_firstDayOfWeek(QV4::SimpleCallContext *ctx)
{
- GET_LOCALE_DATA_RESOURCE(info.This());
- int fdow = int(r->locale.firstDayOfWeek());
+ QLocale locale = getThisLocale(ctx);
+ int fdow = int(locale.firstDayOfWeek());
if (fdow == 7)
fdow = 0; // Qt::Sunday = 7, but Sunday is 0 in JS Date
- return v8::Integer::New(fdow);
+ return QV4::Value::fromInt32(fdow);
}
-static v8::Handle<v8::Value> locale_get_measurementSystem(v8::Local<v8::String>, const v8::AccessorInfo &info)
+QV4::Value QQmlLocaleData::method_get_measurementSystem(QV4::SimpleCallContext *ctx)
{
- GET_LOCALE_DATA_RESOURCE(info.This());
- return v8::Integer::New(r->locale.measurementSystem());
+ QLocale locale = getThisLocale(ctx);
+ return QV4::Value::fromInt32(locale.measurementSystem());
}
-static v8::Handle<v8::Value> locale_get_textDirection(v8::Local<v8::String>, const v8::AccessorInfo &info)
+QV4::Value QQmlLocaleData::method_get_textDirection(QV4::SimpleCallContext *ctx)
{
- GET_LOCALE_DATA_RESOURCE(info.This());
- return v8::Integer::New(r->locale.textDirection());
+ QLocale locale = getThisLocale(ctx);
+ return QV4::Value::fromInt32(locale.textDirection());
}
-static v8::Handle<v8::Value> locale_get_weekDays(v8::Local<v8::String>, const v8::AccessorInfo &info)
+QV4::Value QQmlLocaleData::method_get_weekDays(QV4::SimpleCallContext *ctx)
{
- GET_LOCALE_DATA_RESOURCE(info.This());
+ QLocale locale = getThisLocale(ctx);
+ QList<Qt::DayOfWeek> days = locale.weekdays();
- QList<Qt::DayOfWeek> days = r->locale.weekdays();
-
- v8::Handle<v8::Array> result = v8::Array::New(days.size());
+ QV4::ArrayObject *result = ctx->engine->newArrayObject();
+ result->arrayReserve(days.size());
+ result->arrayDataLen = days.size();
for (int i = 0; i < days.size(); ++i) {
int day = days.at(i);
if (day == 7) // JS Date days in range 0(Sunday) to 6(Saturday)
day = 0;
- result->Set(i, v8::Integer::New(day));
+ result->arrayData[i].value = QV4::Value::fromInt32(day);
}
+ result->setArrayLengthUnchecked(days.size());
- return result;
+ return QV4::Value::fromObject(result);
}
-static v8::Handle<v8::Value> locale_get_uiLanguages(v8::Local<v8::String>, const v8::AccessorInfo &info)
+QV4::Value QQmlLocaleData::method_get_uiLanguages(QV4::SimpleCallContext *ctx)
{
- GET_LOCALE_DATA_RESOURCE(info.This());
-
- QStringList langs = r->locale.uiLanguages();
- v8::Handle<v8::Array> result = v8::Array::New(langs.size());
- for (int i = 0; i < langs.size(); ++i) {
- result->Set(i, r->engine->toString(langs.at(i)));
- }
-
- return result;
+ QLocale locale = getThisLocale(ctx);
+ QStringList langs = locale.uiLanguages();
+ QV4::ArrayObject *result = ctx->engine->newArrayObject();
+ result->arrayReserve(langs.size());
+ result->arrayDataLen = langs.size();
+ for (int i = 0; i < langs.size(); ++i)
+ result->arrayData[i].value = QV4::Value::fromString(ctx, langs.at(i));
+ result->setArrayLengthUnchecked(langs.size());
+
+ return QV4::Value::fromObject(result);
}
-static v8::Handle<v8::Value> locale_currencySymbol(const v8::Arguments &args)
+QV4::Value QQmlLocaleData::method_currencySymbol(QV4::SimpleCallContext *ctx)
{
- GET_LOCALE_DATA_RESOURCE(args.This());
-
- if (args.Length() > 1)
- V8THROW_ERROR("Locale: currencySymbol(): Invalid arguments");
+ QLocale locale = getThisLocale(ctx);
+ if (ctx->argumentCount > 1)
+ V4THROW_ERROR("Locale: currencySymbol(): Invalid arguments");
QLocale::CurrencySymbolFormat format = QLocale::CurrencySymbol;
- if (args.Length() == 1) {
- quint32 intFormat = args[0]->ToNumber()->Value();
+ if (ctx->argumentCount == 1) {
+ quint32 intFormat = ctx->arguments[0].toNumber();
format = QLocale::CurrencySymbolFormat(intFormat);
}
- return r->engine->toString(r->locale.currencySymbol(format));
+ return QV4::Value::fromString(ctx, locale.currencySymbol(format));
}
#define LOCALE_FORMAT(FUNC) \
-static v8::Handle<v8::Value> locale_ ##FUNC (const v8::Arguments &args) { \
- GET_LOCALE_DATA_RESOURCE(args.This());\
- if (args.Length() > 1) \
- V8THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \
+QV4::Value QQmlLocaleData::method_ ##FUNC (QV4::SimpleCallContext *ctx) { \
+ QLocale locale = getThisLocale(ctx); \
+ if (ctx->argumentCount > 1) \
+ V4THROW_ERROR("Locale: " #FUNC "(): Invalid arguments"); \
QLocale::FormatType format = QLocale::LongFormat;\
- if (args.Length() == 1) { \
- quint32 intFormat = args[0]->Uint32Value(); \
+ if (ctx->argumentCount == 1) { \
+ quint32 intFormat = ctx->arguments[0].toUInt32(); \
format = QLocale::FormatType(intFormat); \
} \
- return r->engine->toString(r->locale. FUNC (format)); \
+ return QV4::Value::fromString(ctx, locale. FUNC (format)); \
}
LOCALE_FORMAT(dateTimeFormat)
@@ -628,74 +584,66 @@ LOCALE_FORMAT(dateFormat)
// +1 added to idx because JS is 0-based, whereas QLocale months begin at 1.
#define LOCALE_FORMATTED_MONTHNAME(VARIABLE) \
-static v8::Handle<v8::Value> locale_ ## VARIABLE (const v8::Arguments &args) {\
- GET_LOCALE_DATA_RESOURCE(args.This()); \
- if (args.Length() < 1 || args.Length() > 2) \
- V8THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
+QV4::Value QQmlLocaleData::method_ ## VARIABLE (QV4::SimpleCallContext *ctx) {\
+ QLocale locale = getThisLocale(ctx); \
+ if (ctx->argumentCount < 1 || ctx->argumentCount > 2) \
+ V4THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
QLocale::FormatType enumFormat = QLocale::LongFormat; \
- int idx = args[0]->IntegerValue() + 1; \
+ int idx = ctx->arguments[0].toInt32() + 1; \
if (idx < 1 || idx > 12) \
- V8THROW_ERROR("Locale: Invalid month"); \
+ V4THROW_ERROR("Locale: Invalid month"); \
QString name; \
- if (args.Length() == 2) { \
- if (args[1]->IsNumber()) { \
- quint32 intFormat = args[1]->IntegerValue(); \
+ if (ctx->argumentCount == 2) { \
+ if (ctx->arguments[1].isNumber()) { \
+ quint32 intFormat = ctx->arguments[1].toUInt32(); \
QLocale::FormatType format = QLocale::FormatType(intFormat); \
- name = r->locale. VARIABLE(idx, format); \
+ name = locale. VARIABLE(idx, format); \
} else { \
- V8THROW_ERROR("Locale: Invalid datetime format"); \
+ V4THROW_ERROR("Locale: Invalid datetime format"); \
} \
} else { \
- name = r->locale. VARIABLE(idx, enumFormat); \
+ name = locale. VARIABLE(idx, enumFormat); \
} \
- return r->engine->toString(name); \
+ return QV4::Value::fromString(ctx, name); \
}
// 0 -> 7 as Qt::Sunday is 7, but Sunday is 0 in JS Date
#define LOCALE_FORMATTED_DAYNAME(VARIABLE) \
-static v8::Handle<v8::Value> locale_ ## VARIABLE (const v8::Arguments &args) {\
- GET_LOCALE_DATA_RESOURCE(args.This()); \
- if (args.Length() < 1 || args.Length() > 2) \
- V8THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
+QV4::Value QQmlLocaleData::method_ ## VARIABLE (QV4::SimpleCallContext *ctx) {\
+ QLocale locale = getThisLocale(ctx); \
+ if (ctx->argumentCount < 1 || ctx->argumentCount > 2) \
+ V4THROW_ERROR("Locale: " #VARIABLE "(): Invalid arguments"); \
QLocale::FormatType enumFormat = QLocale::LongFormat; \
- int idx = args[0]->IntegerValue(); \
+ int idx = ctx->arguments[0].toInt32(); \
if (idx < 0 || idx > 7) \
- V8THROW_ERROR("Locale: Invalid day"); \
+ V4THROW_ERROR("Locale: Invalid day"); \
if (idx == 0) idx = 7; \
QString name; \
- if (args.Length() == 2) { \
- if (args[1]->IsNumber()) { \
- quint32 intFormat = args[1]->ToNumber()->Value(); \
+ if (ctx->argumentCount == 2) { \
+ if (ctx->arguments[1].isNumber()) { \
+ quint32 intFormat = ctx->arguments[1].toUInt32(); \
QLocale::FormatType format = QLocale::FormatType(intFormat); \
- name = r->locale. VARIABLE(idx, format); \
+ name = locale. VARIABLE(idx, format); \
} else { \
- V8THROW_ERROR("Locale: Invalid datetime format"); \
+ V4THROW_ERROR("Locale: Invalid datetime format"); \
} \
} else { \
- name = r->locale. VARIABLE(idx, enumFormat); \
+ name = locale. VARIABLE(idx, enumFormat); \
} \
- return r->engine->toString(name); \
+ return QV4::Value::fromString(ctx, name); \
}
-
-#define LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(FT, VARIABLE, ENGINE) \
- FT->PrototypeTemplate()->Set(v8::String::New( #VARIABLE ), V8FUNCTION(locale_ ## VARIABLE, ENGINE));
-
LOCALE_FORMATTED_MONTHNAME(monthName)
LOCALE_FORMATTED_MONTHNAME(standaloneMonthName)
LOCALE_FORMATTED_DAYNAME(dayName)
LOCALE_FORMATTED_DAYNAME(standaloneDayName)
-#define LOCALE_STRING_PROPERTY(VARIABLE) static v8::Handle<v8::Value> locale_get_ ## VARIABLE (v8::Local<v8::String>, const v8::AccessorInfo &info) \
+#define LOCALE_STRING_PROPERTY(VARIABLE) QV4::Value QQmlLocaleData::method_get_ ## VARIABLE (QV4::SimpleCallContext* ctx) \
{ \
- GET_LOCALE_DATA_RESOURCE(info.This()); \
- return r->engine->toString(r->locale. VARIABLE());\
+ QLocale locale = getThisLocale(ctx); \
+ return QV4::Value::fromString(ctx, locale. VARIABLE());\
}
-#define LOCALE_REGISTER_STRING_ACCESSOR(FT, VARIABLE) \
- FT ->PrototypeTemplate()->SetAccessor( v8::String::New( #VARIABLE ), locale_get_ ## VARIABLE )
-
-
LOCALE_STRING_PROPERTY(name)
LOCALE_STRING_PROPERTY(nativeLanguageName)
LOCALE_STRING_PROPERTY(nativeCountryName)
@@ -715,53 +663,44 @@ public:
QV8LocaleDataDeletable(QV8Engine *engine);
~QV8LocaleDataDeletable();
- v8::Persistent<v8::Function> constructor;
+ QV4::PersistentValue prototype;
};
QV8LocaleDataDeletable::QV8LocaleDataDeletable(QV8Engine *engine)
{
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(engine->context());
-
- v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetHasExternalResource(true);
-
- LOCALE_REGISTER_STRING_ACCESSOR(ft, name);
- LOCALE_REGISTER_STRING_ACCESSOR(ft, nativeLanguageName);
- LOCALE_REGISTER_STRING_ACCESSOR(ft, nativeCountryName);
- LOCALE_REGISTER_STRING_ACCESSOR(ft, decimalPoint);
- LOCALE_REGISTER_STRING_ACCESSOR(ft, groupSeparator);
- LOCALE_REGISTER_STRING_ACCESSOR(ft, percent);
- LOCALE_REGISTER_STRING_ACCESSOR(ft, zeroDigit);
- LOCALE_REGISTER_STRING_ACCESSOR(ft, negativeSign);
- LOCALE_REGISTER_STRING_ACCESSOR(ft, positiveSign);
- LOCALE_REGISTER_STRING_ACCESSOR(ft, exponential);
- LOCALE_REGISTER_STRING_ACCESSOR(ft, amText);
- LOCALE_REGISTER_STRING_ACCESSOR(ft, pmText);
-
- ft->PrototypeTemplate()->Set(v8::String::New("currencySymbol"), V8FUNCTION(locale_currencySymbol, engine));
-
- ft->PrototypeTemplate()->Set(v8::String::New("dateTimeFormat"), V8FUNCTION(locale_dateTimeFormat, engine));
- ft->PrototypeTemplate()->Set(v8::String::New("dateFormat"), V8FUNCTION(locale_dateFormat, engine));
- ft->PrototypeTemplate()->Set(v8::String::New("timeFormat"), V8FUNCTION(locale_timeFormat, engine));
-
- LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, monthName, engine);
- LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, standaloneMonthName, engine);
- LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, dayName, engine);
- LOCALE_REGISTER_FORMATTED_NAME_FUNCTION(ft, standaloneDayName, engine);
-
- ft->PrototypeTemplate()->SetAccessor(v8::String::New("firstDayOfWeek"), locale_get_firstDayOfWeek);
- ft->PrototypeTemplate()->SetAccessor(v8::String::New("weekDays"), locale_get_weekDays);
- ft->PrototypeTemplate()->SetAccessor(v8::String::New("measurementSystem"), locale_get_measurementSystem);
- ft->PrototypeTemplate()->SetAccessor(v8::String::New("textDirection"), locale_get_textDirection);
- ft->PrototypeTemplate()->SetAccessor(v8::String::New("uiLanguages"), locale_get_uiLanguages);
-
- constructor = qPersistentNew(ft->GetFunction());
+ QV4::ExecutionEngine *eng = QV8Engine::getV4(engine);
+ QV4::Object *o = eng->newObject();
+ prototype = QV4::Value::fromObject(o);
+
+ o->defineDefaultProperty(eng, QStringLiteral("dateFormat"), QQmlLocaleData::method_dateFormat, 0);
+ o->defineDefaultProperty(eng, QStringLiteral("standaloneDayName"), QQmlLocaleData::method_standaloneDayName, 0);
+ o->defineDefaultProperty(eng, QStringLiteral("standaloneMonthName"), QQmlLocaleData::method_standaloneMonthName, 0);
+ o->defineDefaultProperty(eng, QStringLiteral("dayName"), QQmlLocaleData::method_dayName, 0);
+ o->defineDefaultProperty(eng, QStringLiteral("timeFormat"), QQmlLocaleData::method_timeFormat, 0);
+ o->defineDefaultProperty(eng, QStringLiteral("monthName"), QQmlLocaleData::method_monthName, 0);
+ o->defineDefaultProperty(eng, QStringLiteral("currencySymbol"), QQmlLocaleData::method_currencySymbol, 0);
+ o->defineDefaultProperty(eng, QStringLiteral("dateTimeFormat"), QQmlLocaleData::method_dateTimeFormat, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("name"), QQmlLocaleData::method_get_name, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("positiveSign"), QQmlLocaleData::method_get_positiveSign, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("uiLanguages"), QQmlLocaleData::method_get_uiLanguages, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("firstDayOfWeek"), QQmlLocaleData::method_get_firstDayOfWeek, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("pmText"), QQmlLocaleData::method_get_pmText, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("percent"), QQmlLocaleData::method_get_percent, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("textDirection"), QQmlLocaleData::method_get_textDirection, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("weekDays"), QQmlLocaleData::method_get_weekDays, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("negativeSign"), QQmlLocaleData::method_get_negativeSign, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("groupSeparator"), QQmlLocaleData::method_get_groupSeparator, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("decimalPoint"), QQmlLocaleData::method_get_decimalPoint, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("nativeLanguageName"), QQmlLocaleData::method_get_nativeLanguageName, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("nativeCountryName"), QQmlLocaleData::method_get_nativeCountryName, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("zeroDigit"), QQmlLocaleData::method_get_zeroDigit, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("amText"), QQmlLocaleData::method_get_amText, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("measurementSystem"), QQmlLocaleData::method_get_measurementSystem, 0);
+ o->defineAccessorProperty(eng, QStringLiteral("exponential"), QQmlLocaleData::method_get_exponential, 0);
}
QV8LocaleDataDeletable::~QV8LocaleDataDeletable()
{
- qPersistentDispose(constructor);
}
V8_DEFINE_EXTENSION(QV8LocaleDataDeletable, localeV8Data);
@@ -868,48 +807,34 @@ QQmlLocale::~QQmlLocale()
{
}
-v8::Handle<v8::Value> QQmlLocale::locale(QV8Engine *v8engine, const QString &locale)
+QV4::Value QQmlLocale::locale(QV8Engine *v8engine, const QString &locale)
{
QV8LocaleDataDeletable *d = localeV8Data(v8engine);
- v8::Local<v8::Object> v8Value = d->constructor->NewInstance();
- QV8LocaleDataResource *r = new QV8LocaleDataResource(v8engine);
- if (locale.isEmpty())
- r->locale = QLocale();
- else
- r->locale = QLocale(locale);
- v8Value->SetExternalResource(r);
-
- return v8Value;
+ QV4::ExecutionEngine *engine = QV8Engine::getV4(v8engine);
+ QQmlLocaleData *wrapper = new (engine->memoryManager) QQmlLocaleData(engine);
+ if (!locale.isEmpty())
+ wrapper->locale = QLocale(locale);
+ wrapper->prototype = d->prototype.value().asObject();
+ return QV4::Value::fromObject(wrapper);
}
-static const char localeCompareFunction[] =
- "(function(localeCompareFunc) { "
- " var orig_localeCompare;"
- " orig_localeCompare = String.prototype.localeCompare;"
- " String.prototype.localeCompare = (function() {"
- " var val = localeCompareFunc.apply(this, arguments);"
- " if (val == undefined) val = orig_localeCompare.call(this);"
- " return val;"
- " })"
- "})";
-
-void QQmlLocale::registerStringLocaleCompare(QV8Engine *engine)
+void QQmlLocale::registerStringLocaleCompare(QV4::ExecutionEngine *engine)
{
- registerFunction(engine, localeCompareFunction, localeCompare);
+ engine->stringPrototype->defineDefaultProperty(engine, QStringLiteral("localeCompare"), localeCompare);
}
-v8::Handle<v8::Value> QQmlLocale::localeCompare(const v8::Arguments &args)
+QV4::Value QQmlLocale::localeCompare(QV4::SimpleCallContext *ctx)
{
- if (args.Length() != 1 || (!args[0]->IsString() && !args[0]->IsStringObject()))
- return v8::Undefined();
+ if (ctx->argumentCount != 1 || (!ctx->arguments[0].isString() && !ctx->arguments[0].asStringObject()))
+ return QV4::StringPrototype::method_localeCompare(ctx);
- if (!args.This()->IsString() && !args.This()->IsStringObject())
- return v8::Undefined();
+ if (!ctx->thisObject.isString() && !ctx->thisObject.asStringObject())
+ return QV4::StringPrototype::method_localeCompare(ctx);
- QString thisString = QJSConverter::toString(args.This()->ToString());
- QString thatString = QJSConverter::toString(args[0]->ToString());
+ QString thisString = ctx->thisObject.toQString();
+ QString thatString = ctx->arguments[0].toQString();
- return v8::Integer::New(QString::localeAwareCompare(thisString, thatString));
+ return QV4::Value::fromInt32(QString::localeAwareCompare(thisString, thatString));
}
/*!
diff --git a/src/qml/qml/qqmllocale_p.h b/src/qml/qml/qqmllocale_p.h
index 25f98d9168..3bc8b6096e 100644
--- a/src/qml/qml/qqmllocale_p.h
+++ b/src/qml/qml/qqmllocale_p.h
@@ -55,28 +55,28 @@ QT_BEGIN_NAMESPACE
class QQmlDateExtension
{
public:
- static void registerExtension(QV8Engine *engine);
+ static void registerExtension(QV4::ExecutionEngine *engine);
private:
- static v8::Handle<v8::Value> toLocaleString(const v8::Arguments& args);
- static v8::Handle<v8::Value> toLocaleTimeString(const v8::Arguments& args);
- static v8::Handle<v8::Value> toLocaleDateString(const v8::Arguments& args);
- static v8::Handle<v8::Value> fromLocaleString(const v8::Arguments& args);
- static v8::Handle<v8::Value> fromLocaleTimeString(const v8::Arguments& args);
- static v8::Handle<v8::Value> fromLocaleDateString(const v8::Arguments& args);
- static v8::Handle<v8::Value> timeZoneUpdated(const v8::Arguments& args);
+ static QV4::Value toLocaleString(QV4::SimpleCallContext *ctx);
+ static QV4::Value toLocaleTimeString(QV4::SimpleCallContext *ctx);
+ static QV4::Value toLocaleDateString(QV4::SimpleCallContext *ctx);
+ static QV4::Value fromLocaleString(QV4::SimpleCallContext *ctx);
+ static QV4::Value fromLocaleTimeString(QV4::SimpleCallContext *ctx);
+ static QV4::Value fromLocaleDateString(QV4::SimpleCallContext *ctx);
+ static QV4::Value timeZoneUpdated(QV4::SimpleCallContext *ctx);
};
class QQmlNumberExtension
{
public:
- static void registerExtension(QV8Engine *engine);
+ static void registerExtension(QV4::ExecutionEngine *engine);
private:
- static v8::Handle<v8::Value> toLocaleString(const v8::Arguments& args);
- static v8::Handle<v8::Value> fromLocaleString(const v8::Arguments& args);
- static v8::Handle<v8::Value> toLocaleCurrencyString(const v8::Arguments& args);
+ static QV4::Value toLocaleString(QV4::SimpleCallContext *ctx);
+ static QV4::Value fromLocaleString(QV4::SimpleCallContext *ctx);
+ static QV4::Value toLocaleCurrencyString(QV4::SimpleCallContext *ctx);
};
@@ -118,14 +118,14 @@ public:
Saturday = Qt::Saturday
};
- static v8::Handle<v8::Value> locale(QV8Engine *v8engine, const QString &lang);
+ static QV4::Value locale(QV8Engine *v8engine, const QString &lang);
- static void registerStringLocaleCompare(QV8Engine *engine);
+ static void registerStringLocaleCompare(QV4::ExecutionEngine *engine);
private:
QQmlLocale();
- static v8::Handle<v8::Value> localeCompare(const v8::Arguments &args);
+ static QV4::Value localeCompare(QV4::SimpleCallContext *ctx);
};
diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp
index b29df4d252..f3b4d6b1e5 100644
--- a/src/qml/qml/qqmlmetatype.cpp
+++ b/src/qml/qml/qqmlmetatype.cpp
@@ -44,7 +44,6 @@
#include <private/qqmlproxymetaobject_p.h>
#include <private/qqmlcustomparser_p.h>
-#include <private/qqmlguard_p.h>
#include <private/qhashedstring_p.h>
#include <private/qqmlimport_p.h>
@@ -215,34 +214,16 @@ public:
static QHash<const QMetaObject *, int> attachedPropertyIds;
};
-// Avoid multiple fromUtf8(), copies and hashing of the module name.
-// This is only called when metaTypeDataLock is locked.
-static QHashedString moduleFromUtf8(const char *module)
-{
- if (!module)
- return QHashedString();
-
- static const char *lastModule = 0;
- static QHashedString lastModuleStr;
-
- // Separate plugins may have different strings at the same address
- QHashedCStringRef currentModule(module, ::strlen(module));
- if ((lastModule != module) || (lastModuleStr.hash() != currentModule.hash())) {
- lastModuleStr = QString::fromUtf8(module);
- lastModuleStr.hash();
- lastModule = module;
- }
-
- return lastModuleStr;
-}
-
void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e)
{
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(e->handle());
+ v4->pushGlobalContext();
if (scriptCallback && scriptApi(e).isUndefined()) {
setScriptApi(e, scriptCallback(e, e));
} else if (qobjectCallback && !qobjectApi(e)) {
setQObjectApi(e, qobjectCallback(e, e));
}
+ v4->popContext();
}
void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e)
@@ -343,7 +324,7 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg
: d(new QQmlTypePrivate(SingletonType))
{
d->elementName = elementName;
- d->module = moduleFromUtf8(type.uri);
+ d->module = QString::fromUtf8(type.uri);
d->version_maj = type.versionMajor;
d->version_min = type.versionMinor;
@@ -371,7 +352,7 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg
: d(new QQmlTypePrivate(CppType))
{
d->elementName = elementName;
- d->module = moduleFromUtf8(type.uri);
+ d->module = QString::fromUtf8(type.uri);
d->version_maj = type.versionMajor;
d->version_min = type.versionMinor;
@@ -410,7 +391,7 @@ QQmlType::QQmlType(int index, const QString &elementName, const QQmlPrivate::Reg
d->index = index;
d->elementName = elementName;
- d->module = moduleFromUtf8(type.uri);
+ d->module = QString::fromUtf8(type.uri);
d->version_maj = type.versionMajor;
d->version_min = type.versionMinor;
@@ -920,7 +901,7 @@ int QQmlType::enumValue(const QHashedCStringRef &name, bool *ok) const
return -1;
}
-int QQmlType::enumValue(const QHashedV8String &name, bool *ok) const
+int QQmlType::enumValue(const QV4::String *name, bool *ok) const
{
Q_ASSERT(ok);
*ok = true;
@@ -994,7 +975,7 @@ QQmlType *QQmlTypeModule::type(const QHashedStringRef &name, int minor)
return 0;
}
-QQmlType *QQmlTypeModule::type(const QHashedV8String &name, int minor)
+QQmlType *QQmlTypeModule::type(const QV4::String *name, int minor)
{
QReadLocker lock(metaTypeDataLock());
@@ -1063,7 +1044,7 @@ QQmlType *QQmlTypeModuleVersion::type(const QHashedStringRef &name) const
else return 0;
}
-QQmlType *QQmlTypeModuleVersion::type(const QHashedV8String &name) const
+QQmlType *QQmlTypeModuleVersion::type(const QV4::String *name) const
{
if (m_module) return m_module->type(name, m_minor);
else return 0;
@@ -1159,7 +1140,7 @@ bool checkRegistration(QQmlType::RegistrationType typeType, QQmlMetaTypeData *da
}
if (uri && !typeName.isEmpty()) {
- QString nameSpace = moduleFromUtf8(uri);
+ QString nameSpace = QString::fromUtf8(uri);
if (!data->typeRegistrationNamespace.isEmpty()) {
// We can only install types into the registered namespace
diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h
index f522812398..e44eade902 100644
--- a/src/qml/qml/qqmlmetatype_p.h
+++ b/src/qml/qml/qqmlmetatype_p.h
@@ -61,6 +61,8 @@
#include <QtCore/qbitarray.h>
#include <QtQml/qjsvalue.h>
+#include <private/qv4string_p.h>
+
QT_BEGIN_NAMESPACE
class QQmlType;
@@ -136,7 +138,6 @@ private:
struct QQmlMetaTypeData;
class QHashedCStringRef;
-class QHashedV8String;
class Q_QML_PRIVATE_EXPORT QQmlType
{
public:
@@ -213,7 +214,7 @@ public:
int enumValue(const QHashedStringRef &, bool *ok) const;
int enumValue(const QHashedCStringRef &, bool *ok) const;
- int enumValue(const QHashedV8String &, bool *ok) const;
+ int enumValue(const QV4::String *, bool *ok) const;
private:
QQmlType *superType() const;
friend class QQmlTypePrivate;
@@ -252,7 +253,7 @@ public:
int maximumMinorVersion() const;
QQmlType *type(const QHashedStringRef &, int);
- QQmlType *type(const QHashedV8String &, int);
+ QQmlType *type(const QV4::String *, int);
QList<QQmlType*> singletonTypes(int) const;
@@ -279,7 +280,7 @@ public:
int minorVersion() const;
QQmlType *type(const QHashedStringRef &) const;
- QQmlType *type(const QHashedV8String &) const;
+ QQmlType *type(const QV4::String *) const;
private:
QQmlTypeModule *m_module;
diff --git a/src/qml/qml/qqmlnotifier.cpp b/src/qml/qml/qqmlnotifier.cpp
index 3253a5f0e8..da016c90a5 100644
--- a/src/qml/qml/qqmlnotifier.cpp
+++ b/src/qml/qml/qqmlnotifier.cpp
@@ -51,14 +51,12 @@ typedef void (*Callback)(QQmlNotifierEndpoint *, void **);
void QQmlBoundSignal_callback(QQmlNotifierEndpoint *, void **);
void QQmlJavaScriptExpressionGuard_callback(QQmlNotifierEndpoint *, void **);
void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *, void **);
-void QV4BindingsSubscription_callback(QQmlNotifierEndpoint *, void **);
static Callback QQmlNotifier_callbacks[] = {
0,
QQmlBoundSignal_callback,
QQmlJavaScriptExpressionGuard_callback,
- QQmlVMEMetaObjectEndpoint_callback,
- QV4BindingsSubscription_callback
+ QQmlVMEMetaObjectEndpoint_callback
};
void QQmlNotifier::emitNotify(QQmlNotifierEndpoint *endpoint, void **a)
diff --git a/src/qml/qml/qqmlnotifier_p.h b/src/qml/qml/qqmlnotifier_p.h
index a19007511c..93f2cd68da 100644
--- a/src/qml/qml/qqmlnotifier_p.h
+++ b/src/qml/qml/qqmlnotifier_p.h
@@ -43,7 +43,6 @@
#define QQMLNOTIFIER_P_H
#include "qqmldata_p.h"
-#include "qqmlguard_p.h"
#include <QtCore/qmetaobject.h>
#include <private/qmetaobject_p.h>
@@ -104,8 +103,8 @@ private:
// Contains either the QObject*, or the QQmlNotifier* that this
// endpoint is connected to. While the endpoint is notifying, the
- // senderPtr points to another intptr_t that contains this value.
- intptr_t senderPtr;
+ // senderPtr points to another qintptr that contains this value.
+ qintptr senderPtr;
inline QObject *senderAsObject() const;
inline QQmlNotifier *senderAsNotifier() const;
@@ -130,7 +129,7 @@ QQmlNotifier::~QQmlNotifier()
QQmlNotifierEndpoint *n = endpoint;
endpoint = n->next;
- if (n->isNotifying()) *((intptr_t *)(n->senderPtr & ~0x1)) = 0;
+ if (n->isNotifying()) *((qintptr *)(n->senderPtr & ~0x1)) = 0;
n->next = 0;
n->prev = 0;
@@ -184,7 +183,7 @@ void QQmlNotifierEndpoint::connect(QQmlNotifier *notifier)
if (next) { next->prev = &next; }
notifier->endpoints = this;
prev = &notifier->endpoints;
- senderPtr = intptr_t(notifier);
+ senderPtr = qintptr(notifier);
}
void QQmlNotifierEndpoint::disconnect()
@@ -200,7 +199,7 @@ void QQmlNotifierEndpoint::disconnect()
priv->disconnectNotify(QMetaObjectPrivate::signal(obj->metaObject(), sourceSignal));
}
- if (isNotifying()) *((intptr_t *)(senderPtr & ~0x1)) = 0;
+ if (isNotifying()) *((qintptr *)(senderPtr & ~0x1)) = 0;
next = 0;
prev = 0;
senderPtr = 0;
@@ -225,20 +224,20 @@ Cancel any notifies that are in progress.
void QQmlNotifierEndpoint::cancelNotify()
{
if (isNotifying()) {
- intptr_t sp = *((intptr_t *)(senderPtr & ~0x1));
- *((intptr_t *)(senderPtr & ~0x1)) = 0;
+ qintptr sp = *((qintptr *)(senderPtr & ~0x1));
+ *((qintptr *)(senderPtr & ~0x1)) = 0;
senderPtr = sp;
}
}
QObject *QQmlNotifierEndpoint::senderAsObject() const
{
- return isNotifying()?((QObject *)(*((intptr_t *)(senderPtr & ~0x1)))):((QObject *)senderPtr);
+ return isNotifying()?((QObject *)(*((qintptr *)(senderPtr & ~0x1)))):((QObject *)senderPtr);
}
QQmlNotifier *QQmlNotifierEndpoint::senderAsNotifier() const
{
- return isNotifying()?((QQmlNotifier *)(*((intptr_t *)(senderPtr & ~0x1)))):((QQmlNotifier *)senderPtr);
+ return isNotifying()?((QQmlNotifier *)(*((qintptr *)(senderPtr & ~0x1)))):((QQmlNotifier *)senderPtr);
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlproperty.cpp b/src/qml/qml/qqmlproperty.cpp
index 0936df59c4..d1ecfdc52d 100644
--- a/src/qml/qml/qqmlproperty.cpp
+++ b/src/qml/qml/qqmlproperty.cpp
@@ -56,7 +56,8 @@
#include "qqmlvmemetaobject_p.h"
#include "qqmlexpression_p.h"
#include "qqmlvaluetypeproxybinding_p.h"
-#include <private/qv8bindings_p.h>
+#include <private/qjsvalue_p.h>
+#include <private/qv4functionobject_p.h>
#include <QStringList>
#include <private/qmetaobject_p.h>
@@ -941,31 +942,6 @@ QQmlPropertyPrivate::setBindingNoEnable(QObject *object, int coreIndex, int valu
}
/*!
- Activates a shared binding which was previously created but not added to the
- object. This is needed when an optimized binding is invalidated.
-*/
-QQmlAbstractBinding *QQmlPropertyPrivate::activateSharedBinding(QQmlContextData *context,
- int sharedIdx, WriteFlags flags)
-{
- QQmlAbstractBinding *newBinding = 0;
- newBinding = context->v8bindings->binding(sharedIdx);
-
- if (!newBinding)
- return newBinding;
-
- // This binding now references the bindings object
- context->v8bindings->addref();
-
- QObject *object = newBinding->object();
- int pi = newBinding->propertyIndex();
-
- int core = pi & 0x0000FFFF;
- int vt = (pi & 0xFFFF0000)?(pi >> 16):-1;
-
- return setBinding(object, core, vt, newBinding, flags);
-}
-
-/*!
Returns the expression associated with this signal property, or 0 if no
signal expression exists.
*/
@@ -1484,7 +1460,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
const QQmlPropertyData &core,
QQmlContextData *context,
QQmlJavaScriptExpression *expression,
- v8::Handle<v8::Value> result, bool isUndefined,
+ const QV4::Value &result, bool isUndefined,
WriteFlags flags)
{
Q_ASSERT(object);
@@ -1506,22 +1482,22 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
if (!isUndefined && !core.isValueTypeVirtual()) {
switch (core.propType) {
case QMetaType::Int:
- if (result->IsInt32())
- QUICK_STORE(int, result->Int32Value())
- else if (result->IsNumber())
- QUICK_STORE(int, qRound(result->NumberValue()))
+ if (result.isInteger())
+ QUICK_STORE(int, result.integerValue())
+ else if (result.isNumber())
+ QUICK_STORE(int, qRound(result.doubleValue()))
break;
case QMetaType::Double:
- if (result->IsNumber())
- QUICK_STORE(double, result->NumberValue())
+ if (result.isNumber())
+ QUICK_STORE(double, result.asDouble())
break;
case QMetaType::Float:
- if (result->IsNumber())
- QUICK_STORE(float, result->NumberValue())
+ if (result.isNumber())
+ QUICK_STORE(float, result.asDouble())
break;
case QMetaType::QString:
- if (result->IsString())
- QUICK_STORE(QString, v8engine->toString(result))
+ if (result.isString())
+ QUICK_STORE(QString, result.toQString())
break;
default:
break;
@@ -1539,7 +1515,7 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
if (isUndefined) {
} else if (core.isQList()) {
value = v8engine->toVariant(result, qMetaTypeId<QList<QObject *> >());
- } else if (result->IsNull() && core.isQObject()) {
+ } else if (result.isNull() && core.isQObject()) {
value = QVariant::fromValue((QObject *)0);
} else if (core.propType == qMetaTypeId<QList<QUrl> >()) {
value = resolvedUrlSequence(v8engine->toVariant(result, qMetaTypeId<QList<QUrl> >()), context);
@@ -1550,8 +1526,8 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
if (expression->hasError()) {
return false;
} else if (isVarProperty) {
- if (!result.IsEmpty() && result->IsFunction()
- && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
+ QV4::FunctionObject *f = result.asFunctionObject();
+ if (f && f->bindingKeyFlag) {
// we explicitly disallow this case to avoid confusion. Users can still store one
// in an array in a var property if they need to, but the common case is user error.
expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
@@ -1568,13 +1544,15 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
} else if (isUndefined && type == qMetaTypeId<QVariant>()) {
writeValueProperty(object, core, QVariant(), context, flags);
} else if (type == qMetaTypeId<QJSValue>()) {
- if (!result.IsEmpty() && result->IsFunction()
- && !result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty()) {
+ QV4::FunctionObject *f = result.asFunctionObject();
+ if (f && f->bindingKeyFlag) {
expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
expression->delayedError()->setErrorObject(object);
return false;
}
- writeValueProperty(object, core, QVariant::fromValue(v8engine->scriptValueFromInternal(result)), context, flags);
+ writeValueProperty(object, core, QVariant::fromValue(
+ QJSValue(new QJSValuePrivate(QV8Engine::getV4(v8engine), result))),
+ context, flags);
} else if (isUndefined) {
QString errorStr = QLatin1String("Unable to assign [undefined] to ");
if (!QMetaType::typeName(type))
@@ -1584,8 +1562,8 @@ bool QQmlPropertyPrivate::writeBinding(QObject *object,
expression->delayedError()->setErrorDescription(errorStr);
expression->delayedError()->setErrorObject(object);
return false;
- } else if (result->IsFunction()) {
- if (!result->ToObject()->GetHiddenValue(v8engine->bindingFlagKey()).IsEmpty())
+ } else if (QV4::FunctionObject *f = result.asFunctionObject()) {
+ if (f->bindingKeyFlag)
expression->delayedError()->setErrorDescription(QLatin1String("Invalid use of Qt.binding() in a binding declaration."));
else
expression->delayedError()->setErrorDescription(QLatin1String("Unable to assign a function to a property of any type other than var."));
diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h
index 108b98f3ca..9af091ad46 100644
--- a/src/qml/qml/qqmlproperty_p.h
+++ b/src/qml/qml/qqmlproperty_p.h
@@ -59,7 +59,6 @@
#include <private/qobject_p.h>
#include <private/qtqmlglobal_p.h>
#include <private/qqmlpropertycache_p.h>
-#include <private/qqmlguard_p.h>
#include <private/qqmlboundsignalexpressionpointer_p.h>
QT_BEGIN_NAMESPACE
@@ -78,8 +77,8 @@ public:
Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
QQmlContextData *context;
- QQmlGuard<QQmlEngine> engine;
- QQmlGuard<QObject> object;
+ QPointer<QQmlEngine> engine;
+ QPointer<QObject> object;
QQmlPropertyData core;
@@ -119,8 +118,6 @@ public:
static QQmlAbstractBinding *setBindingNoEnable(QObject *, int coreIndex,
int valueTypeIndex /* -1 */,
QQmlAbstractBinding *);
- static QQmlAbstractBinding *activateSharedBinding(QQmlContextData *context,
- int sharedIdx, WriteFlags flags);
static QQmlAbstractBinding *binding(QObject *, int coreIndex,
int valueTypeIndex /* -1 */);
@@ -150,8 +147,8 @@ public:
static bool write(const QQmlProperty &that, const QVariant &, WriteFlags);
static bool writeBinding(QObject *, const QQmlPropertyData &,
QQmlContextData *context,
- QQmlJavaScriptExpression *expression,
- v8::Handle<v8::Value> result, bool isUndefined,
+ QQmlJavaScriptExpression *expression,
+ const QV4::Value &result, bool isUndefined,
WriteFlags flags);
static int valueTypeCoreIndex(const QQmlProperty &that);
static int bindingIndex(const QQmlProperty &that);
diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp
index 4712fbd614..d10af391f5 100644
--- a/src/qml/qml/qqmlpropertycache.cpp
+++ b/src/qml/qml/qqmlpropertycache.cpp
@@ -49,7 +49,8 @@
#include <private/qmetaobject_p.h>
#include <private/qqmlaccessors_p.h>
#include <private/qmetaobjectbuilder_p.h>
-#include <private/qqmlrewrite_p.h>
+
+#include <private/qv4value_p.h>
#include <QtCore/qdebug.h>
@@ -72,7 +73,6 @@ public:
//for signal handler rewrites
QString *signalParameterStringForJS;
- int signalParameterCountForJS:30;
int parameterError:1;
int argumentsValid:1;
@@ -117,8 +117,8 @@ static QQmlPropertyData::Flags flagsForPropertyType(int propType, QQmlEngine *en
flags |= QQmlPropertyData::IsQmlBinding;
} else if (propType == qMetaTypeId<QJSValue>()) {
flags |= QQmlPropertyData::IsQJSValue;
- } else if (propType == qMetaTypeId<QQmlV8Handle>()) {
- flags |= QQmlPropertyData::IsV8Handle;
+ } else if (propType == qMetaTypeId<QQmlV4Handle>()) {
+ flags |= QQmlPropertyData::IsV4Handle;
} else {
QQmlMetaType::TypeCategory cat =
engine ? QQmlEnginePrivate::get(engine)->typeCategory(propType)
@@ -194,8 +194,8 @@ void QQmlPropertyData::load(const QMetaMethod &m)
if (m.parameterCount()) {
flags |= HasArguments;
- if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) {
- flags |= IsV8Function;
+ if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) {
+ flags |= IsV4Function;
}
}
@@ -225,8 +225,8 @@ void QQmlPropertyData::lazyLoad(const QMetaMethod &m)
if (m.parameterCount()) {
flags |= HasArguments;
- if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV8Function*")) {
- flags |= IsV8Function;
+ if ((m.parameterCount() == 1) && (m.parameterTypes().first() == "QQmlV4Function*")) {
+ flags |= IsV4Function;
}
}
@@ -288,18 +288,14 @@ QQmlPropertyCache::~QQmlPropertyCache()
void QQmlPropertyCache::destroy()
{
- Q_ASSERT(engine || constructor.IsEmpty());
- if (constructor.IsEmpty())
- delete this;
- else
- QQmlEnginePrivate::deleteInEngineThread(engine, this);
+ Q_ASSERT(engine);
+ delete this;
}
// This is inherited from QQmlCleanup, so it should only clear the things
// that are tied to the specific QQmlEngine.
void QQmlPropertyCache::clear()
{
- qPersistentDispose(constructor);
engine = 0;
}
@@ -316,8 +312,6 @@ QQmlPropertyCache *QQmlPropertyCache::copy(int reserve)
cache->_metaObject = _metaObject;
cache->_defaultPropertyName = _defaultPropertyName;
- // We specifically do *NOT* copy the constructor
-
return cache;
}
@@ -597,7 +591,6 @@ void QQmlPropertyCache::append(QQmlEngine *engine, const QMetaObject *metaObject
QQmlPropertyData::Flag signalFlags)
{
Q_UNUSED(revision);
- Q_ASSERT(constructor.IsEmpty()); // We should not be appending to an in-use property cache
_metaObject = metaObject;
@@ -1089,7 +1082,6 @@ QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(int a
args->arguments[0] = argc;
args->argumentsValid = false;
args->signalParameterStringForJS = 0;
- args->signalParameterCountForJS = 0;
args->parameterError = false;
args->names = argc ? new QList<QByteArray>(names) : 0;
args->next = argumentsCache;
@@ -1101,7 +1093,7 @@ QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(int a
\a index MUST be in the signal index range (see QObjectPrivate::signalIndex()).
This is different from QMetaMethod::methodIndex().
*/
-QString QQmlPropertyCache::signalParameterStringForJS(int index, int *count, QString *errorString)
+QString QQmlPropertyCache::signalParameterStringForJS(int index, QString *errorString)
{
QQmlPropertyCache *c = 0;
QQmlPropertyData *signalData = signal(index, &c);
@@ -1113,8 +1105,6 @@ QString QQmlPropertyCache::signalParameterStringForJS(int index, int *count, QSt
if (signalData->arguments) {
A *arguments = static_cast<A *>(signalData->arguments);
if (arguments->signalParameterStringForJS) {
- if (count)
- *count = arguments->signalParameterCountForJS;
if (arguments->parameterError) {
if (errorString)
*errorString = *arguments->signalParameterStringForJS;
@@ -1131,18 +1121,12 @@ QString QQmlPropertyCache::signalParameterStringForJS(int index, int *count, QSt
signalData->arguments = args;
}
- QQmlRewrite::RewriteSignalHandler rewriter;
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- const QString &parameters = rewriter.createParameterString(parameterNameList,
- ep->v8engine()->illegalNames());
+ QString error;
+ QString parameters = signalParameterStringForJS(engine, parameterNameList, &error);
- bool error = rewriter.hasParameterError();
A *arguments = static_cast<A *>(signalData->arguments);
- arguments->signalParameterStringForJS = new QString(error ? rewriter.parameterError() : parameters);
- arguments->signalParameterCountForJS = rewriter.parameterCountForJS();
- if (count)
- *count = arguments->signalParameterCountForJS;
- if (error) {
+ arguments->signalParameterStringForJS = new QString(!error.isEmpty() ? error : parameters);
+ if (!error.isEmpty()) {
arguments->parameterError = true;
if (errorString)
*errorString = *arguments->signalParameterStringForJS;
@@ -1151,6 +1135,35 @@ QString QQmlPropertyCache::signalParameterStringForJS(int index, int *count, QSt
return *arguments->signalParameterStringForJS;
}
+QString QQmlPropertyCache::signalParameterStringForJS(QQmlEngine *engine, const QList<QByteArray> &parameterNameList, QString *errorString)
+{
+ QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
+ bool unnamedParameter = false;
+ const QV4::IdentifierHash<bool> &illegalNames = ep->v8engine()->illegalNames();
+ QString error;
+ QString parameters;
+
+ for (int i = 0; i < parameterNameList.count(); ++i) {
+ if (i > 0)
+ parameters += QLatin1Char(',');
+ const QByteArray &param = parameterNameList.at(i);
+ if (param.isEmpty())
+ unnamedParameter = true;
+ else if (unnamedParameter) {
+ if (errorString)
+ *errorString = QCoreApplication::translate("QQmlRewrite", "Signal uses unnamed parameter followed by named parameter.");
+ return QString();
+ } else if (illegalNames.contains(param)) {
+ if (errorString)
+ *errorString = QCoreApplication::translate("QQmlRewrite", "Signal parameter \"%1\" hides global variable.").arg(QString::fromUtf8(param));
+ return QString();
+ }
+ parameters += QString::fromUtf8(param);
+ }
+
+ return parameters;
+}
+
// Returns an array of the arguments for method \a index. The first entry in the array
// is the number of arguments.
int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index,
@@ -1327,6 +1340,8 @@ QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QS
static const int destroyedIdx2 = QObject::staticMetaObject.indexOfSignal("destroyed()");
static const int deleteLaterIdx = QObject::staticMetaObject.indexOfSlot("deleteLater()");
+ const QByteArray propertyName = property.toUtf8();
+
int methodCount = metaObject->methodCount();
for (int ii = methodCount - 1; ii >= 0; --ii) {
if (ii == destroyedIdx1 || ii == destroyedIdx2 || ii == deleteLaterIdx)
@@ -1334,9 +1349,8 @@ QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QS
QMetaMethod m = metaObject->method(ii);
if (m.access() == QMetaMethod::Private)
continue;
- QString methodName = QString::fromUtf8(m.name().constData());
- if (methodName == property) {
+ if (m.name() == propertyName) {
rv.load(m);
return rv;
}
@@ -1344,7 +1358,6 @@ QQmlPropertyData qQmlPropertyCacheCreate(const QMetaObject *metaObject, const QS
{
const QMetaObject *cmo = metaObject;
- const QByteArray propertyName = property.toUtf8();
while (cmo) {
int idx = cmo->indexOfProperty(propertyName);
if (idx != -1) {
@@ -1375,14 +1388,14 @@ inline const QString &qQmlPropertyCacheToString(const QString &string)
return string;
}
-inline QString qQmlPropertyCacheToString(const QHashedV8String &string)
+inline QString qQmlPropertyCacheToString(const QV4::String *string)
{
- return QV8Engine::toStringStatic(string.string());
+ return string->toQString();
}
template<typename T>
QQmlPropertyData *
-qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name,
+qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, T name,
QQmlContextData *context, QQmlPropertyData &local)
{
QQmlPropertyCache *cache = 0;
@@ -1416,17 +1429,17 @@ qQmlPropertyCacheProperty(QQmlEngine *engine, QObject *obj, const T &name,
}
QQmlPropertyData *
-QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, const QHashedV8String &name,
+QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj, const QV4::String *name,
QQmlContextData *context, QQmlPropertyData &local)
{
- return qQmlPropertyCacheProperty<QHashedV8String>(engine, obj, name, context, local);
+ return qQmlPropertyCacheProperty<const QV4::String *>(engine, obj, name, context, local);
}
QQmlPropertyData *
QQmlPropertyCache::property(QQmlEngine *engine, QObject *obj,
const QString &name, QQmlContextData *context, QQmlPropertyData &local)
{
- return qQmlPropertyCacheProperty<QString>(engine, obj, name, context, local);
+ return qQmlPropertyCacheProperty<const QString &>(engine, obj, name, context, local);
}
static inline const QMetaObjectPrivate *priv(const uint* data)
diff --git a/src/qml/qml/qqmlpropertycache_p.h b/src/qml/qml/qqmlpropertycache_p.h
index e9fc584a53..daba6e856d 100644
--- a/src/qml/qml/qqmlpropertycache_p.h
+++ b/src/qml/qml/qqmlpropertycache_p.h
@@ -62,11 +62,12 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qvector.h>
+#include <private/qv4value_p.h>
+
QT_BEGIN_NAMESPACE
class QV8Engine;
class QMetaProperty;
-class QV8QObjectWrapper;
class QQmlEngine;
class QQmlPropertyData;
class QQmlAccessors;
@@ -101,7 +102,7 @@ public:
IsQList = 0x00000800, // Property type is a QML list
IsQmlBinding = 0x00001000, // Property type is a QQmlBinding*
IsQJSValue = 0x00002000, // Property type is a QScriptValue
- IsV8Handle = 0x00004000, // Property type is a QQmlV8Handle
+ IsV4Handle = 0x00004000, // Property type is a QQmlV4Handle
IsVarProperty = 0x00008000, // Property type is a "var" property of VMEMO
IsValueTypeVirtual = 0x00010000, // Property is a value type "virtual" property
IsQVariant = 0x00020000, // Property is a QVariant
@@ -111,7 +112,7 @@ public:
HasArguments = 0x00080000, // Function takes arguments
IsSignal = 0x00100000, // Function is a signal
IsVMESignal = 0x00200000, // Signal was added by QML
- IsV8Function = 0x00400000, // Function takes QQmlV8Function* args
+ IsV4Function = 0x00400000, // Function takes QQmlV4Function* args
IsSignalHandler = 0x00800000, // Function is a signal handler
IsOverload = 0x01000000, // Function is an overload of another function
IsCloned = 0x02000000, // The function was marked as cloned
@@ -121,7 +122,7 @@ public:
// Flags that are set based on the propType field
PropTypeFlagMask = IsQObjectDerived | IsEnumType | IsQList | IsQmlBinding | IsQJSValue |
- IsV8Handle | IsQVariant,
+ IsV4Handle | IsQVariant,
};
Q_DECLARE_FLAGS(Flags, Flag)
@@ -144,7 +145,7 @@ public:
bool isQList() const { return flags & IsQList; }
bool isQmlBinding() const { return flags & IsQmlBinding; }
bool isQJSValue() const { return flags & IsQJSValue; }
- bool isV8Handle() const { return flags & IsV8Handle; }
+ bool isV4Handle() const { return flags & IsV4Handle; }
bool isVarProperty() const { return flags & IsVarProperty; }
bool isValueTypeVirtual() const { return flags & IsValueTypeVirtual; }
bool isQVariant() const { return flags & IsQVariant; }
@@ -152,7 +153,7 @@ public:
bool hasArguments() const { return flags & HasArguments; }
bool isSignal() const { return flags & IsSignal; }
bool isVMESignal() const { return flags & IsVMESignal; }
- bool isV8Function() const { return flags & IsV8Function; }
+ bool isV4Function() const { return flags & IsV4Function; }
bool isSignalHandler() const { return flags & IsSignalHandler; }
bool isOverload() const { return flags & IsOverload; }
bool isCloned() const { return flags & IsCloned; }
@@ -294,6 +295,7 @@ public:
QString defaultPropertyName() const;
QQmlPropertyData *defaultProperty() const;
QQmlPropertyCache *parent() const;
+ // is used by the Qml Designer
void setParent(QQmlPropertyCache *newParent);
inline QQmlPropertyData *overrideData(QQmlPropertyData *) const;
@@ -302,7 +304,7 @@ public:
inline QQmlEngine *qmlEngine() const;
static QQmlPropertyData *property(QQmlEngine *, QObject *, const QString &,
QQmlContextData *, QQmlPropertyData &);
- static QQmlPropertyData *property(QQmlEngine *, QObject *, const QHashedV8String &,
+ static QQmlPropertyData *property(QQmlEngine *, QObject *, const QV4::String *,
QQmlContextData *, QQmlPropertyData &);
static int *methodParameterTypes(QObject *, int index, QVarLengthArray<int, 9> &dummy,
QByteArray *unknownTypeError);
@@ -314,7 +316,8 @@ public:
static int originalClone(QObject *, int index);
QList<QByteArray> signalParameterNames(int index) const;
- QString signalParameterStringForJS(int index, int *count = 0, QString *errorString = 0);
+ QString signalParameterStringForJS(int index, QString *errorString = 0);
+ static QString signalParameterStringForJS(QQmlEngine *engine, const QList<QByteArray> &parameterNameList, QString *errorString = 0);
const char *className() const;
@@ -335,7 +338,6 @@ protected:
private:
friend class QQmlEnginePrivate;
- friend class QV8QObjectWrapper;
friend class QQmlCompiler;
inline QQmlPropertyCache *copy(int reserve);
@@ -345,9 +347,6 @@ private:
QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
- // Implemented in v8/qv8qobjectwrapper.cpp
- v8::Local<v8::Object> newQObject(QObject *, QV8Engine *);
-
QQmlPropertyCacheMethodArguments *createArgumentsObject(int count,
const QList<QByteArray> &names = QList<QByteArray>());
QQmlPropertyData *signal(int, QQmlPropertyCache **) const;
@@ -390,7 +389,6 @@ private:
IndexCache signalHandlerIndexCache;
StringCache stringCache;
AllowedRevisionCache allowedRevisionCache;
- v8::Persistent<v8::Function> constructor;
bool _hasPropertyOverrides : 1;
bool _ownMetaObject : 1;
diff --git a/src/qml/qml/qqmlrewrite.cpp b/src/qml/qml/qqmlrewrite.cpp
deleted file mode 100644
index 0e281428ed..0000000000
--- a/src/qml/qml/qqmlrewrite.cpp
+++ /dev/null
@@ -1,649 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qqmlrewrite_p.h"
-
-#include <private/qqmlglobal_p.h>
-
-#include <QtCore/qdebug.h>
-#include <QtCore/qcoreapplication.h>
-
-QT_BEGIN_NAMESPACE
-
-DEFINE_BOOL_CONFIG_OPTION(rewriteDump, QML_REWRITE_DUMP)
-
-namespace QQmlRewrite {
-
-static void rewriteStringLiteral(AST::StringLiteral *ast, const QString *code, int startPosition, TextWriter *writer)
-{
- const unsigned position = ast->firstSourceLocation().begin() - startPosition + 1;
- const unsigned length = ast->literalToken.length - 2;
- const QStringRef spell = code->midRef(position, length);
- const int end = spell.size();
- int index = 0;
-
- while (index < end) {
- const QChar ch = spell.at(index++);
-
- if (index < end && ch == QLatin1Char('\\')) {
- int pos = index;
-
- // skip a possibly empty sequence of \r characters
- while (pos < end && spell.at(pos) == QLatin1Char('\r'))
- ++pos;
-
- if (pos < end && spell.at(pos) == QLatin1Char('\n')) {
- // This is a `\' followed by a newline terminator.
- // In this case there's nothing to replace. We keep the code
- // as it is and we resume the searching.
- index = pos + 1; // refresh the index
- }
- } else if (ch == QLatin1Char('\r') || ch == QLatin1Char('\n')) {
- const QString sep = ch == QLatin1Char('\r') ? QLatin1String("\\r") : QLatin1String("\\n");
- const int pos = index - 1;
- QString s = sep;
-
- while (index < end && spell.at(index) == ch) {
- s += sep;
- ++index;
- }
-
- writer->replace(position + pos, index - pos, s);
- }
- }
-}
-
-SharedBindingTester::SharedBindingTester()
-: _sharable(false), _safe(false)
-{
-}
-
-void SharedBindingTester::parse(const QString &code)
-{
- _sharable = _safe = false;
-
- Engine engine;
- Lexer lexer(&engine);
- Parser parser(&engine);
- lexer.setCode(code, 0);
- parser.parseStatement();
- if (!parser.statement())
- return;
-
- return parse(parser.statement());
-}
-
-void SharedBindingTester::parse(AST::Node *node)
-{
- _sharable = true;
- _safe = true;
-
- AST::Node::acceptChild(node, this);
-}
-
-bool SharedBindingTester::visit(AST::FunctionDeclaration *)
-{
- _sharable = false;
- return false;
-}
-
-bool SharedBindingTester::visit(AST::FunctionExpression *)
-{
- _sharable = false;
- return false;
-}
-
-bool SharedBindingTester::visit(AST::CallExpression *e)
-{
- static const QString mathString = QStringLiteral("Math");
-
- if (AST::IdentifierExpression *ie = AST::cast<AST::IdentifierExpression *>(e->base)) {
- if (ie->name == mathString)
- return true;
- }
-
- _safe = false;
- return true;
-}
-
-bool SharedBindingTester::visit(AST::IdentifierExpression *e)
-{
- static const QString evalString = QStringLiteral("eval");
- if (e->name == evalString)
- _sharable = false;
-
- return false; // IdentifierExpression is a leaf node anyway
-}
-
-bool SharedBindingTester::visit(AST::PostDecrementExpression *)
-{
- _safe = false;
- return true;
-}
-
-bool SharedBindingTester::visit(AST::PostIncrementExpression *)
-{
- _safe = false;
- return true;
-}
-
-bool SharedBindingTester::visit(AST::PreDecrementExpression *)
-{
- _safe = false;
- return true;
-}
-
-bool SharedBindingTester::visit(AST::PreIncrementExpression *)
-{
- _safe = false;
- return true;
-}
-
-bool SharedBindingTester::visit(AST::BinaryExpression *e)
-{
- if (e->op == QSOperator::InplaceAnd ||
- e->op == QSOperator::Assign ||
- e->op == QSOperator::InplaceSub ||
- e->op == QSOperator::InplaceDiv ||
- e->op == QSOperator::InplaceAdd ||
- e->op == QSOperator::InplaceLeftShift ||
- e->op == QSOperator::InplaceMod ||
- e->op == QSOperator::InplaceMul ||
- e->op == QSOperator::InplaceOr ||
- e->op == QSOperator::InplaceRightShift ||
- e->op == QSOperator::InplaceURightShift ||
- e->op == QSOperator::InplaceXor)
- _safe = false;
-
- return true;
-}
-
-QString RewriteBinding::operator()(const QString &code, bool *ok, bool *sharable, bool *safe)
-{
- Engine engine;
- Lexer lexer(&engine);
- Parser parser(&engine);
- lexer.setCode(code, 0);
- parser.parseStatement();
- if (!parser.statement()) {
- if (ok) *ok = false;
- return QString();
- } else {
- if (ok) *ok = true;
- if (sharable || safe) {
- SharedBindingTester tester;
- tester.parse(parser.statement());
- if (sharable) *sharable = tester.isSharable();
- if (safe) *safe = tester.isSafe();
- }
- }
- return rewrite(code, 0, parser.statement());
-}
-
-QString RewriteBinding::operator()(QQmlJS::AST::Node *node, const QString &code, bool *sharable, bool *safe)
-{
- if (!node)
- return code;
-
- if (sharable || safe) {
- SharedBindingTester tester;
- tester.parse(node);
- if (sharable) *sharable = tester.isSharable();
- if (safe) *safe = tester.isSafe();
- }
-
- QQmlJS::AST::ExpressionNode *expression = node->expressionCast();
- QQmlJS::AST::Statement *statement = node->statementCast();
- if(!expression && !statement)
- return code;
-
- TextWriter w;
- _writer = &w;
- _position = expression ? expression->firstSourceLocation().begin() : statement->firstSourceLocation().begin();
- _inLoop = 0;
- _code = &code;
-
- accept(node);
-
- unsigned startOfStatement = 0;
- unsigned endOfStatement = (expression ? expression->lastSourceLocation().end() : statement->lastSourceLocation().end()) - _position;
-
- QString startString = QLatin1String("(function ") + _name + QLatin1String("() { ");
- if (expression)
- startString += QLatin1String("return ");
- _writer->replace(startOfStatement, 0, startString);
- _writer->replace(endOfStatement, 0, QLatin1String(" })"));
-
- if (rewriteDump()) {
- qWarning() << "=============================================================";
- qWarning() << "Rewrote:";
- qWarning() << qPrintable(code);
- }
-
- QString codeCopy = code;
- w.write(&codeCopy);
-
- if (rewriteDump()) {
- qWarning() << "To:";
- qWarning() << qPrintable(codeCopy);
- qWarning() << "=============================================================";
- }
-
- return codeCopy;
-}
-
-void RewriteBinding::accept(AST::Node *node)
-{
- AST::Node::acceptChild(node, this);
-}
-
-QString RewriteBinding::rewrite(QString code, unsigned position,
- AST::Statement *node)
-{
- TextWriter w;
- _writer = &w;
- _position = position;
- _inLoop = 0;
- _code = &code;
-
- accept(node);
-
- unsigned startOfStatement = node->firstSourceLocation().begin() - _position;
- unsigned endOfStatement = node->lastSourceLocation().end() - _position;
-
- _writer->replace(startOfStatement, 0, QLatin1String("(function ") + _name + QLatin1String("() { "));
- _writer->replace(endOfStatement, 0, QLatin1String(" })"));
-
- if (rewriteDump()) {
- qWarning() << "=============================================================";
- qWarning() << "Rewrote:";
- qWarning() << qPrintable(code);
- }
-
- w.write(&code);
-
- if (rewriteDump()) {
- qWarning() << "To:";
- qWarning() << qPrintable(code);
- qWarning() << "=============================================================";
- }
-
- return code;
-}
-
-bool RewriteBinding::visit(AST::Block *ast)
-{
- for (AST::StatementList *it = ast->statements; it; it = it->next) {
- if (! it->next) {
- // we need to rewrite only the last statement of a block.
- accept(it->statement);
- }
- }
-
- return false;
-}
-
-bool RewriteBinding::visit(AST::ExpressionStatement *ast)
-{
- if (! _inLoop) {
- unsigned startOfExpressionStatement = ast->firstSourceLocation().begin() - _position;
- _writer->replace(startOfExpressionStatement, 0, QLatin1String("return "));
- }
-
- return false;
-}
-
-bool RewriteBinding::visit(AST::StringLiteral *ast)
-{
- rewriteStringLiteral(ast, _code, _position, _writer);
- return false;
-}
-
-bool RewriteBinding::visit(AST::DoWhileStatement *)
-{
- ++_inLoop;
- return true;
-}
-
-void RewriteBinding::endVisit(AST::DoWhileStatement *)
-{
- --_inLoop;
-}
-
-bool RewriteBinding::visit(AST::WhileStatement *)
-{
- ++_inLoop;
- return true;
-}
-
-void RewriteBinding::endVisit(AST::WhileStatement *)
-{
- --_inLoop;
-}
-
-bool RewriteBinding::visit(AST::ForStatement *)
-{
- ++_inLoop;
- return true;
-}
-
-void RewriteBinding::endVisit(AST::ForStatement *)
-{
- --_inLoop;
-}
-
-bool RewriteBinding::visit(AST::LocalForStatement *)
-{
- ++_inLoop;
- return true;
-}
-
-void RewriteBinding::endVisit(AST::LocalForStatement *)
-{
- --_inLoop;
-}
-
-bool RewriteBinding::visit(AST::ForEachStatement *)
-{
- ++_inLoop;
- return true;
-}
-
-void RewriteBinding::endVisit(AST::ForEachStatement *)
-{
- --_inLoop;
-}
-
-bool RewriteBinding::visit(AST::LocalForEachStatement *)
-{
- ++_inLoop;
- return true;
-}
-
-void RewriteBinding::endVisit(AST::LocalForEachStatement *)
-{
- --_inLoop;
-}
-
-bool RewriteBinding::visit(AST::FunctionExpression *)
-{
- return false;
-}
-
-bool RewriteBinding::visit(AST::FunctionDeclaration *)
-{
- return false;
-}
-
-bool RewriteBinding::visit(AST::CaseBlock *ast)
-{
- // Process the initial sequence of the case clauses.
- for (AST::CaseClauses *it = ast->clauses; it; it = it->next) {
- // Return the value of the last statement in the block, if this is the last `case clause'
- // of the switch statement.
- bool returnTheValueOfLastStatement = (it->next == 0) && (ast->defaultClause == 0) && (ast->moreClauses == 0);
-
- if (AST::CaseClause *clause = it->clause) {
- accept(clause->expression);
- rewriteCaseStatements(clause->statements, returnTheValueOfLastStatement);
- }
- }
-
- // Process the default case clause
- if (ast->defaultClause) {
- // Return the value of the last statement in the block, if this is the last `case clause'
- // of the switch statement.
- bool rewriteTheLastStatement = (ast->moreClauses == 0);
-
- rewriteCaseStatements(ast->defaultClause->statements, rewriteTheLastStatement);
- }
-
- // Process trailing `case clauses'
- for (AST::CaseClauses *it = ast->moreClauses; it; it = it->next) {
- // Return the value of the last statement in the block, if this is the last `case clause'
- // of the switch statement.
- bool returnTheValueOfLastStatement = (it->next == 0);
-
- if (AST::CaseClause *clause = it->clause) {
- accept(clause->expression);
- rewriteCaseStatements(clause->statements, returnTheValueOfLastStatement);
- }
- }
-
- return false;
-}
-
-void RewriteBinding::rewriteCaseStatements(AST::StatementList *statements, bool rewriteTheLastStatement)
-{
- for (AST::StatementList *it = statements; it; it = it->next) {
- if (it->next && AST::cast<AST::BreakStatement *>(it->next->statement) != 0) {
- // The value of the first statement followed by a `break'.
- accept(it->statement);
- break;
- } else if (!it->next) {
- if (rewriteTheLastStatement)
- accept(it->statement);
- else if (AST::Block *block = AST::cast<AST::Block *>(it->statement))
- rewriteCaseStatements(block->statements, rewriteTheLastStatement);
- }
- }
-}
-
-
-/*
- RewriteSignalHandler performs two different types of rewrites, depending on what information
- is available.
-
- When the target object is known, the rewriter can be provided a list of parameter names (and an
- optional preconstructed parameter string), which allows us to:
- 1. Check whether the parameters are used
- 2. Rewrite with the parameters included in the rewrite
- When this information is not available, we do a more generic rewrite, and rely on the expression
- to perform a second rewrite with the parameter information (using createParameterString)
- once the target object is known.
-*/
-RewriteSignalHandler::RewriteSignalHandler()
- : _writer(0)
- , _code(0)
- , _position(0)
- , _parameterAccess(UnknownAccess)
- , _parameterCountForJS(0)
-{
-}
-
-void RewriteSignalHandler::accept(AST::Node *node)
-{
- AST::Node::acceptChild(node, this);
-}
-
-bool RewriteSignalHandler::visit(AST::StringLiteral *ast)
-{
- rewriteStringLiteral(ast, _code, _position, _writer);
- return false;
-}
-
-//if we never make use of the signal parameters in our expression,
-//there is no need to provide them
-bool RewriteSignalHandler::visit(AST::IdentifierExpression *e)
-{
- //optimization: don't need to compare strings if a parameter has already been marked as used.
- if (_parameterAccess == ParametersAccessed)
- return false;
-
- static const QString argumentsString = QStringLiteral("arguments");
- if (_parameterNames.contains(e->name) || e->name == argumentsString)
- _parameterAccess = ParametersAccessed;
- return false;
-}
-
-static inline QString msgUnnamedErrorString()
-{
- return QCoreApplication::translate("QQmlRewrite", "Signal uses unnamed parameter followed by named parameter.");
-}
-
-static inline QString msgGlobalErrorString(const QString &p)
-{
- return QCoreApplication::translate("QQmlRewrite", "Signal parameter \"%1\" hides global variable.").arg(p);
-}
-
-#define EXIT_ON_ERROR(error) \
-{ \
- _error = error; \
- return QString(); \
-}
-
-//create a parameter string which can be inserted into a generic rewrite
-QString RewriteSignalHandler::createParameterString(const QList<QByteArray> &parameterNameList,
- const QStringHash<bool> &illegalNames)
-{
- QList<QHashedString> hashedParameterNameList;
- for (int i = 0; i < parameterNameList.count(); ++i)
- hashedParameterNameList.append(QString::fromUtf8(parameterNameList.at(i).constData()));
-
- return createParameterString(hashedParameterNameList, illegalNames);
-}
-
-QString RewriteSignalHandler::createParameterString(const QList<QHashedString> &parameterNameList,
- const QStringHash<bool> &illegalNames)
-{
- QString parameters;
- bool unnamedParam = false;
- for (int i = 0; i < parameterNameList.count(); ++i) {
- const QHashedString &param = parameterNameList.at(i);
- if (param.isEmpty())
- unnamedParam = true;
- else if (unnamedParam)
- EXIT_ON_ERROR(msgUnnamedErrorString())
- else if (illegalNames.contains(param))
- EXIT_ON_ERROR(msgGlobalErrorString(param))
- ++_parameterCountForJS;
- parameters += param;
- if (i < parameterNameList.count()-1)
- parameters += QStringLiteral(",");
- }
- if (parameters.endsWith(QLatin1Char(',')))
- parameters.resize(parameters.length() - 1);
- return parameters;
-}
-
-/*
- If \a parameterString is provided, use \a parameterNameList to test whether the
- parameters are used in the body of the function
- * if unused, the rewrite will not include parameters, else
- * if used, the rewrite will use \a parameterString
- If \a parameterString is not provided, it is constructed from \a parameterNameList
- as needed.
-*/
-QString RewriteSignalHandler::operator()(QQmlJS::AST::Node *node, const QString &code, const QString &name,
- const QString &parameterString,
- const QList<QByteArray> &parameterNameList,
- const QStringHash<bool> &illegalNames)
-{
- if (rewriteDump()) {
- qWarning() << "=============================================================";
- qWarning() << "Rewrote:";
- qWarning() << qPrintable(code);
- }
-
- bool hasParameterString = !parameterString.isEmpty();
-
- QQmlJS::AST::ExpressionNode *expression = node->expressionCast();
- QQmlJS::AST::Statement *statement = node->statementCast();
- if (!expression && !statement)
- return code;
-
- if (!parameterNameList.isEmpty()) {
- for (int i = 0; i < parameterNameList.count(); ++i) {
- QHashedString param(QString::fromUtf8(parameterNameList.at(i).constData()));
- _parameterNames.insert(param, i);
- if (!hasParameterString)
- _parameterNameList.append(param);
- }
-
- //this is set to Unaccessed here, and will be set to Accessed
- //if we detect that a parameter has been used
- _parameterAccess = ParametersUnaccessed;
- }
-
- TextWriter w;
- _writer = &w;
- _code = &code;
-
- _position = expression ? expression->firstSourceLocation().begin() : statement->firstSourceLocation().begin();
- accept(node);
-
- QString rewritten = code;
- w.write(&rewritten);
-
- QString parameters = (_parameterAccess == ParametersUnaccessed) ? QString()
- : hasParameterString ? parameterString
- : createParameterString(_parameterNameList, illegalNames);
- rewritten = QStringLiteral("(function ") + name + QStringLiteral("(") + parameters + QStringLiteral(") { ") + rewritten + QStringLiteral(" })");
-
- if (rewriteDump()) {
- qWarning() << "To:";
- qWarning() << qPrintable(rewritten);
- qWarning() << "=============================================================";
- }
-
- return rewritten;
-}
-
-QString RewriteSignalHandler::operator()(const QString &code, const QString &name, bool *ok,
- const QList<QByteArray> &parameterNameList,
- const QStringHash<bool> &illegalNames)
-{
- Engine engine;
- Lexer lexer(&engine);
- Parser parser(&engine);
- lexer.setCode(code, 0);
- parser.parseStatement();
- if (!parser.statement()) {
- if (ok) *ok = false;
- return QString();
- }
- if (ok) *ok = true;
- return operator()(parser.statement(), code, name, QString(), parameterNameList, illegalNames);
-}
-
-} // namespace QQmlRewrite
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlrewrite_p.h b/src/qml/qml/qqmlrewrite_p.h
deleted file mode 100644
index c3139c6a2f..0000000000
--- a/src/qml/qml/qqmlrewrite_p.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QQMLREWRITE_P_H
-#define QQMLREWRITE_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/textwriter_p.h>
-#include <private/qqmljslexer_p.h>
-#include <private/qqmljsparser_p.h>
-#include <private/qqmljsmemorypool_p.h>
-#include <private/qhashedstring_p.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QQmlRewrite {
-using namespace QQmlJS;
-
-class SharedBindingTester : protected AST::Visitor
-{
- bool _sharable;
- bool _safe;
-public:
- SharedBindingTester();
-
- bool isSharable() const { return _sharable; }
- bool isSafe() const { return isSharable() && _safe; }
-
- void parse(const QString &code);
- void parse(AST::Node *Node);
-
- virtual bool visit(AST::FunctionDeclaration *);
- virtual bool visit(AST::FunctionExpression *);
- virtual bool visit(AST::IdentifierExpression *);
- virtual bool visit(AST::CallExpression *);
- virtual bool visit(AST::PostDecrementExpression *);
- virtual bool visit(AST::PostIncrementExpression *);
- virtual bool visit(AST::PreDecrementExpression *);
- virtual bool visit(AST::PreIncrementExpression *);
- virtual bool visit(AST::BinaryExpression *);
-};
-
-class RewriteBinding: protected AST::Visitor
-{
- unsigned _position;
- TextWriter *_writer;
- QString _name;
- const QString *_code;
-
-public:
- QString operator()(const QString &code, bool *ok = 0, bool *sharable = 0, bool *safe = 0);
- QString operator()(QQmlJS::AST::Node *node, const QString &code, bool *sharable = 0, bool *safe = 0);
-
- //name of the function: used for the debugger
- void setName(const QString &name) { _name = name; }
-
-protected:
- using AST::Visitor::visit;
-
- void accept(AST::Node *node);
- QString rewrite(QString code, unsigned position, AST::Statement *node);
- void rewriteCaseStatements(AST::StatementList *statements, bool rewriteTheLastStatement);
-
- virtual bool visit(AST::StringLiteral *ast);
- virtual bool visit(AST::Block *ast);
- virtual bool visit(AST::ExpressionStatement *ast);
-
- virtual bool visit(AST::DoWhileStatement *ast);
- virtual void endVisit(AST::DoWhileStatement *ast);
-
- virtual bool visit(AST::WhileStatement *ast);
- virtual void endVisit(AST::WhileStatement *ast);
-
- virtual bool visit(AST::ForStatement *ast);
- virtual void endVisit(AST::ForStatement *ast);
-
- virtual bool visit(AST::LocalForStatement *ast);
- virtual void endVisit(AST::LocalForStatement *ast);
-
- virtual bool visit(AST::ForEachStatement *ast);
- virtual void endVisit(AST::ForEachStatement *ast);
-
- virtual bool visit(AST::LocalForEachStatement *ast);
- virtual void endVisit(AST::LocalForEachStatement *ast);
-
- virtual bool visit(AST::CaseBlock *ast);
-
- virtual bool visit(AST::FunctionExpression *ast);
- virtual bool visit(AST::FunctionDeclaration *ast);
-
-private:
- int _inLoop;
-};
-
-class RewriteSignalHandler: protected AST::Visitor
-{
-public:
- RewriteSignalHandler();
- QString operator()(QQmlJS::AST::Node *node, const QString &code, const QString &name,
- const QString &parameterString = QString(),
- const QList<QByteArray> &parameterNameList = QList<QByteArray>(),
- const QStringHash<bool> &illegalNames = QStringHash<bool>());
- QString operator()(const QString &code, const QString &name, bool *ok = 0,
- const QList<QByteArray> &parameterNameList = QList<QByteArray>(),
- const QStringHash<bool> &illegalNames = QStringHash<bool>());
-
- enum ParameterAccess {
- ParametersAccessed,
- ParametersUnaccessed,
- UnknownAccess
- };
-
- //returns the first n signal parameters that are used in the expression
- int parameterCountForJS() const { return _parameterCountForJS; }
- ParameterAccess parameterAccess() const { return _parameterAccess; }
- QString createParameterString(const QList<QByteArray> &parameterNameList,
- const QStringHash<bool> &illegalNames);
-
- bool hasParameterError() { return !_error.isEmpty(); }
- QString parameterError() const { return _error; }
-
-protected:
- void rewriteMultilineStrings(QString &code);
-
- using AST::Visitor::visit;
- void accept(AST::Node *node);
- virtual bool visit(AST::StringLiteral *ast);
- virtual bool visit(AST::IdentifierExpression *);
-
-private:
- QString createParameterString(const QList<QHashedString> &parameterNameList,
- const QStringHash<bool> &illegalNames);
-
- TextWriter *_writer;
- const QString *_code;
- int _position;
- QStringHash<int> _parameterNames;
- QList<QHashedString> _parameterNameList;
- ParameterAccess _parameterAccess;
- int _parameterCountForJS;
- QString _error;
-};
-
-} // namespace QQmlRewrite
-
-QT_END_NAMESPACE
-
-#endif // QQMLREWRITE_P_H
-
diff --git a/src/qml/qml/qqmlscript.cpp b/src/qml/qml/qqmlscript.cpp
index ba2882f3e7..7e3a23b489 100644
--- a/src/qml/qml/qqmlscript.cpp
+++ b/src/qml/qml/qqmlscript.cpp
@@ -47,7 +47,6 @@
#include "parser/qqmljsmemorypool_p.h"
#include "parser/qqmljsastvisitor_p.h"
#include "parser/qqmljsast_p.h"
-#include <private/qqmlrewrite_p.h>
#include <QStack>
#include <QStringList>
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index 8d8503f344..022083c596 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2260,12 +2260,13 @@ void QQmlTypeData::scriptImported(QQmlScriptBlob *blob, const QQmlScript::Locati
}
QQmlScriptData::QQmlScriptData()
-: importCache(0), pragmas(QQmlScript::Object::ScriptBlock::None), m_loaded(false)
+: importCache(0), pragmas(QQmlScript::Object::ScriptBlock::None), m_loaded(false), m_program(0)
{
}
QQmlScriptData::~QQmlScriptData()
{
+ delete m_program;
}
void QQmlScriptData::clear()
@@ -2279,9 +2280,6 @@ void QQmlScriptData::clear()
scripts.at(ii)->release();
scripts.clear();
- qPersistentDispose(m_program);
- qPersistentDispose(m_value);
-
// An addref() was made when the QQmlCleanup was added to the engine.
release();
}
diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h
index 1bd07661f7..88bca702db 100644
--- a/src/qml/qml/qqmltypeloader_p.h
+++ b/src/qml/qml/qqmltypeloader_p.h
@@ -60,7 +60,6 @@
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlfile.h>
-#include <private/qv8_p.h>
#include <private/qhashedstring_p.h>
#include <private/qqmlscript_p.h>
#include <private/qqmlimport_p.h>
@@ -70,6 +69,9 @@
#include <private/qflagpointer_p.h>
#include <private/qqmlabstracturlinterceptor_p.h>
+#include <private/qv4value_p.h>
+#include <private/qv4script_p.h>
+
QT_BEGIN_NAMESPACE
class QQmlScriptData;
@@ -511,8 +513,8 @@ private:
bool m_loaded;
QByteArray m_programSource;
- v8::Persistent<v8::Script> m_program;
- v8::Persistent<v8::Object> m_value;
+ QV4::Script *m_program;
+ QV4::PersistentValue m_value;
QQmlError m_error;
};
diff --git a/src/qml/qml/qqmltypenamecache.cpp b/src/qml/qml/qqmltypenamecache.cpp
index 180c620558..38466aa20d 100644
--- a/src/qml/qml/qqmltypenamecache.cpp
+++ b/src/qml/qml/qqmltypenamecache.cpp
@@ -91,7 +91,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedStringRef &name,
return typeSearch(i->modules, name);
}
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedV8String &name)
+QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name)
{
Result result = query(m_namedImports, name);
@@ -101,7 +101,7 @@ QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedV8String &name)
return result;
}
-QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QHashedV8String &name, const void *importNamespace)
+QQmlTypeNameCache::Result QQmlTypeNameCache::query(const QV4::String *name, const void *importNamespace)
{
Q_ASSERT(importNamespace);
const Import *i = static_cast<const Import *>(importNamespace);
diff --git a/src/qml/qml/qqmltypenamecache_p.h b/src/qml/qml/qqmltypenamecache_p.h
index 4484adffc6..094bd5c777 100644
--- a/src/qml/qml/qqmltypenamecache_p.h
+++ b/src/qml/qml/qqmltypenamecache_p.h
@@ -90,8 +90,8 @@ public:
};
Result query(const QHashedStringRef &);
Result query(const QHashedStringRef &, const void *importNamespace);
- Result query(const QHashedV8String &);
- Result query(const QHashedV8String &, const void *importNamespace);
+ Result query(const QV4::String *);
+ Result query(const QV4::String *, const void *importNamespace);
private:
friend class QQmlImports;
diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp
new file mode 100644
index 0000000000..f4e9d9b406
--- /dev/null
+++ b/src/qml/qml/qqmltypewrapper.cpp
@@ -0,0 +1,268 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmltypewrapper_p.h"
+#include <private/qqmlcontextwrapper_p.h>
+#include <private/qv8engine_p.h>
+
+#include <private/qqmlengine_p.h>
+#include <private/qqmlcontext_p.h>
+
+#include <private/qjsvalue_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4objectproto_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+DEFINE_MANAGED_VTABLE(QmlTypeWrapper);
+
+QmlTypeWrapper::QmlTypeWrapper(QV8Engine *engine)
+ : Object(QV8Engine::getV4(engine)),
+ v8(engine), mode(IncludeEnums), type(0), typeNamespace(0), importNamespace(0)
+{
+ vtbl = &static_vtbl;
+}
+
+QmlTypeWrapper::~QmlTypeWrapper()
+{
+ if (typeNamespace)
+ typeNamespace->release();
+}
+
+QVariant QmlTypeWrapper::toVariant() const
+{
+ if (type && type->isSingleton()) {
+ QQmlEngine *e = v8->engine();
+ QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
+ siinfo->init(e); // note: this will also create QJSValue singleton which isn't strictly required.
+ QObject *qobjectSingleton = siinfo->qobjectApi(e);
+ if (qobjectSingleton) {
+ return QVariant::fromValue<QObject*>(qobjectSingleton);
+ }
+ }
+
+ // only QObject Singleton Type can be converted to a variant.
+ return QVariant();
+}
+
+
+// Returns a type wrapper for type t on o. This allows access of enums, and attached properties.
+Value QmlTypeWrapper::create(QV8Engine *v8, QObject *o, QQmlType *t, TypeNameMode mode)
+{
+ Q_ASSERT(t);
+ ExecutionEngine *v4 = QV8Engine::getV4(v8);
+
+ QmlTypeWrapper *w = new (v4->memoryManager) QmlTypeWrapper(v8);
+ w->prototype = v4->objectPrototype;
+ w->mode = mode; w->object = o; w->type = t;
+ return Value::fromObject(w);
+}
+
+// Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
+// namespace.
+Value QmlTypeWrapper::create(QV8Engine *v8, QObject *o, QQmlTypeNameCache *t, const void *importNamespace, TypeNameMode mode)
+{
+ Q_ASSERT(t);
+ Q_ASSERT(importNamespace);
+ ExecutionEngine *v4 = QV8Engine::getV4(v8);
+
+ QmlTypeWrapper *w = new (v4->memoryManager) QmlTypeWrapper(v8);
+ w->prototype = v4->objectPrototype;
+ w->mode = mode; w->object = o; w->typeNamespace = t; w->importNamespace = importNamespace;
+ t->addref();
+ return Value::fromObject(w);
+}
+
+
+Value QmlTypeWrapper::get(Managed *m, String *name, bool *hasProperty)
+{
+ QmlTypeWrapper *w = m->as<QmlTypeWrapper>();
+ QV4::ExecutionEngine *v4 = m->engine();
+ if (!w)
+ v4->current->throwTypeError();
+
+ if (hasProperty)
+ *hasProperty = true;
+
+ QV8Engine *v8engine = w->v8;
+ QQmlContextData *context = v8engine->callingContext();
+
+ QObject *object = w->object;
+
+ if (w->type) {
+ QQmlType *type = w->type;
+
+ // singleton types are handled differently to other types.
+ if (type->isSingleton()) {
+ QQmlEngine *e = v8engine->engine();
+ QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
+ siinfo->init(e);
+
+ QObject *qobjectSingleton = siinfo->qobjectApi(e);
+ if (qobjectSingleton) {
+ // check for enum value
+ if (name->startsWithUpper()) {
+ if (w->mode == IncludeEnums) {
+ // ### Optimize
+ QByteArray enumName = name->toQString().toUtf8();
+ const QMetaObject *metaObject = qobjectSingleton->metaObject();
+ for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
+ QMetaEnum e = metaObject->enumerator(ii);
+ bool ok;
+ int value = e.keyToValue(enumName.constData(), &ok);
+ if (ok)
+ return QV4::Value::fromInt32(value);
+ }
+ }
+ }
+
+ // check for property.
+ return QV4::QObjectWrapper::getQmlProperty(v4->current, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision);
+ } else if (!siinfo->scriptApi(e).isUndefined()) {
+ QV4::ExecutionEngine *engine = QV8Engine::getV4(v8engine);
+ // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
+ QV4::Object *o = QJSValuePrivate::get(siinfo->scriptApi(e))->getValue(engine).asObject();
+ if (o)
+ return o->get(name);
+ }
+
+ // Fall through to base implementation
+
+ } else {
+
+ if (name->startsWithUpper()) {
+ bool ok = false;
+ int value = type->enumValue(name, &ok);
+ if (ok)
+ return QV4::Value::fromInt32(value);
+
+ // Fall through to base implementation
+
+ } else if (w->object) {
+ QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
+ if (ao)
+ return QV4::QObjectWrapper::getQmlProperty(v4->current, context, ao, name, QV4::QObjectWrapper::IgnoreRevision);
+
+ // Fall through to base implementation
+ }
+
+ // Fall through to base implementation
+ }
+
+ // Fall through to base implementation
+
+ } else if (w->typeNamespace) {
+ Q_ASSERT(w->importNamespace);
+ QQmlTypeNameCache::Result r = w->typeNamespace->query(name,
+ w->importNamespace);
+
+ if (r.isValid()) {
+ QQmlContextData *context = v8engine->callingContext();
+ if (r.type) {
+ return create(w->v8, object, r.type, w->mode);
+ } else if (r.scriptIndex != -1) {
+ int index = r.scriptIndex;
+ if (index < context->importedScripts.count())
+ return context->importedScripts.at(index).value();
+ } else if (r.importNamespace) {
+ return create(w->v8, object, context->imports, r.importNamespace);
+ }
+
+ return QV4::Value::undefinedValue();
+
+ }
+
+ // Fall through to base implementation
+
+ } else {
+ Q_ASSERT(!"Unreachable");
+ }
+
+ if (hasProperty)
+ *hasProperty = false;
+ return Object::get(m, name, hasProperty);
+}
+
+
+void QmlTypeWrapper::put(Managed *m, String *name, const Value &value)
+{
+ QmlTypeWrapper *w = m->as<QmlTypeWrapper>();
+ QV4::ExecutionEngine *v4 = m->engine();
+ if (!w)
+ v4->current->throwTypeError();
+
+ QV8Engine *v8engine = v4->v8Engine;
+ QQmlContextData *context = v8engine->callingContext();
+
+ QQmlType *type = w->type;
+ if (type && !type->isSingleton() && w->object) {
+ QObject *object = w->object;
+ QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
+ if (ao)
+ QV4::QObjectWrapper::setQmlProperty(v4->current, context, ao, name, QV4::QObjectWrapper::IgnoreRevision, value);
+ } else if (type && type->isSingleton()) {
+ QQmlEngine *e = v8engine->engine();
+ QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
+ siinfo->init(e);
+
+ QObject *qobjectSingleton = siinfo->qobjectApi(e);
+ if (qobjectSingleton) {
+ QV4::QObjectWrapper::setQmlProperty(v4->current, context, qobjectSingleton, name, QV4::QObjectWrapper::IgnoreRevision, value);
+ } else if (!siinfo->scriptApi(e).isUndefined()) {
+ QV4::Object *apiprivate = QJSValuePrivate::get(siinfo->scriptApi(e))->value.asObject();
+ if (!apiprivate) {
+ QString error = QLatin1String("Cannot assign to read-only property \"") + name->toQString() + QLatin1Char('\"');
+ v4->current->throwError(error);
+ } else {
+ apiprivate->put(name, value);
+ }
+ }
+ }
+}
+
+void QmlTypeWrapper::destroy(Managed *that)
+{
+ static_cast<QmlTypeWrapper *>(that)->~QmlTypeWrapper();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8typewrapper_p.h b/src/qml/qml/qqmltypewrapper_p.h
index 852f49770b..ae70367dc4 100644
--- a/src/qml/qml/v8/qv8typewrapper_p.h
+++ b/src/qml/qml/qqmltypewrapper_p.h
@@ -54,40 +54,50 @@
//
#include <QtCore/qglobal.h>
-#include <private/qv8_p.h>
+#include <QtCore/qpointer.h>
+
+#include <private/qv4value_p.h>
+#include <private/qv4object_p.h>
QT_BEGIN_NAMESPACE
-class QObject;
class QV8Engine;
-class QQmlType;
class QQmlTypeNameCache;
-class QV8TypeWrapper
+
+namespace QV4 {
+
+struct Q_QML_EXPORT QmlTypeWrapper : Object
{
+ Q_MANAGED
+private:
+ QmlTypeWrapper(QV8Engine *engine);
+ ~QmlTypeWrapper();
+
public:
- QV8TypeWrapper();
- ~QV8TypeWrapper();
+ enum TypeNameMode { IncludeEnums, ExcludeEnums };
- void init(QV8Engine *);
- void destroy();
+ QVariant toVariant() const;
- enum TypeNameMode { IncludeEnums, ExcludeEnums };
- v8::Local<v8::Object> newObject(QObject *, QQmlType *, TypeNameMode = IncludeEnums);
- v8::Local<v8::Object> newObject(QObject *, QQmlTypeNameCache *, const void *,
- TypeNameMode = IncludeEnums);
- QVariant toVariant(QV8ObjectResource *);
+ static QV4::Value create(QV8Engine *, QObject *, QQmlType *, TypeNameMode = IncludeEnums);
+ static QV4::Value create(QV8Engine *, QObject *, QQmlTypeNameCache *, const void *, TypeNameMode = IncludeEnums);
+
+
+ static Value get(Managed *m, String *name, bool *hasProperty);
+ static void put(Managed *m, String *name, const Value &value);
+ static void destroy(Managed *that);
private:
- static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
- v8::Local<v8::Value> value,
- const v8::AccessorInfo &info);
-
- QV8Engine *m_engine;
- v8::Persistent<v8::Function> m_constructor;
+ QV8Engine *v8;
+ TypeNameMode mode;
+ QPointer<QObject> object;
+
+ QQmlType *type;
+ QQmlTypeNameCache *typeNamespace;
+ const void *importNamespace;
};
+}
+
QT_END_NAMESPACE
#endif // QV8TYPEWRAPPER_P_H
diff --git a/src/qml/qml/qqmlvaluetypewrapper.cpp b/src/qml/qml/qqmlvaluetypewrapper.cpp
new file mode 100644
index 0000000000..05412e99a7
--- /dev/null
+++ b/src/qml/qml/qqmlvaluetypewrapper.cpp
@@ -0,0 +1,399 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qqmlvaluetypewrapper_p.h"
+#include <private/qv8engine_p.h>
+
+#include <private/qqmlvaluetype_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qqmlglobal_p.h>
+#include <private/qqmlcontextwrapper_p.h>
+
+#include <private/qv4engine_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4variantobject_p.h>
+#include <private/qv4qmlextensions_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+DEFINE_MANAGED_VTABLE(QmlValueTypeWrapper);
+
+class QmlValueTypeReference : public QmlValueTypeWrapper
+{
+public:
+ QmlValueTypeReference(QV8Engine *engine);
+
+ QPointer<QObject> object;
+ int property;
+};
+
+class QmlValueTypeCopy : public QmlValueTypeWrapper
+{
+public:
+ QmlValueTypeCopy(QV8Engine *engine);
+
+ QVariant value;
+};
+
+QmlValueTypeWrapper::QmlValueTypeWrapper(QV8Engine *engine, ObjectType objectType)
+ : Object(QV8Engine::getV4(engine)), objectType(objectType)
+{
+ v8 = engine;
+ vtbl = &static_vtbl;
+}
+
+QmlValueTypeWrapper::~QmlValueTypeWrapper()
+{
+}
+
+QmlValueTypeReference::QmlValueTypeReference(QV8Engine *engine)
+: QmlValueTypeWrapper(engine, Reference)
+{
+}
+
+QmlValueTypeCopy::QmlValueTypeCopy(QV8Engine *engine)
+: QmlValueTypeWrapper(engine, Copy)
+{
+}
+
+
+static bool readReferenceValue(const QmlValueTypeReference *reference)
+{
+ // A reference resource may be either a "true" reference (eg, to a QVector3D property)
+ // or a "variant" reference (eg, to a QVariant property which happens to contain a value-type).
+ QMetaProperty writebackProperty = reference->object->metaObject()->property(reference->property);
+ if (writebackProperty.userType() == QMetaType::QVariant) {
+ // variant-containing-value-type reference
+ QVariant variantReferenceValue;
+ reference->type->readVariantValue(reference->object, reference->property, &variantReferenceValue);
+ int variantReferenceType = variantReferenceValue.userType();
+ if (variantReferenceType != reference->type->userType()) {
+ // This is a stale VariantReference. That is, the variant has been
+ // overwritten with a different type in the meantime.
+ // We need to modify this reference to the updated value type, if
+ // possible, or return false if it is not a value type.
+ if (QQmlValueTypeFactory::isValueType(variantReferenceType)) {
+ reference->type = QQmlValueTypeFactory::valueType(variantReferenceType);
+ if (!reference->type) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ reference->type->setValue(variantReferenceValue);
+ } else {
+ // value-type reference
+ reference->type->read(reference->object, reference->property);
+ }
+ return true;
+}
+
+void QmlValueTypeWrapper::initProto(ExecutionEngine *v4)
+{
+ if (v4->qmlExtensions()->valueTypeWrapperPrototype)
+ return;
+
+ Object *o = v4->newObject();
+ o->defineDefaultProperty(v4, QStringLiteral("toString"), method_toString, 1);
+ v4->qmlExtensions()->valueTypeWrapperPrototype = o;
+}
+
+Value QmlValueTypeWrapper::create(QV8Engine *v8, QObject *object, int property, QQmlValueType *type)
+{
+ ExecutionEngine *v4 = QV8Engine::getV4(v8);
+ initProto(v4);
+
+ QmlValueTypeReference *r = new (v4->memoryManager) QmlValueTypeReference(v8);
+ r->prototype = v4->qmlExtensions()->valueTypeWrapperPrototype;
+ r->type = type; r->object = object; r->property = property;
+ return Value::fromObject(r);
+}
+
+Value QmlValueTypeWrapper::create(QV8Engine *v8, const QVariant &value, QQmlValueType *type)
+{
+ ExecutionEngine *v4 = QV8Engine::getV4(v8);
+ initProto(v4);
+
+ QmlValueTypeCopy *r = new (v4->memoryManager) QmlValueTypeCopy(v8);
+ r->prototype = v4->qmlExtensions()->valueTypeWrapperPrototype;
+ r->type = type; r->value = value;
+ return Value::fromObject(r);
+}
+
+QVariant QmlValueTypeWrapper::toVariant() const
+{
+ if (objectType == QmlValueTypeWrapper::Reference) {
+ const QmlValueTypeReference *reference = static_cast<const QmlValueTypeReference *>(this);
+
+ if (reference->object && readReferenceValue(reference)) {
+ return reference->type->value();
+ } else {
+ return QVariant();
+ }
+ } else {
+ Q_ASSERT(objectType == QmlValueTypeWrapper::Copy);
+ return static_cast<const QmlValueTypeCopy *>(this)->value;
+ }
+}
+
+void QmlValueTypeWrapper::destroy(Managed *that)
+{
+ QmlValueTypeWrapper *w = that->as<QmlValueTypeWrapper>();
+ assert(w);
+ if (w->objectType == Reference)
+ static_cast<QmlValueTypeReference *>(w)->~QmlValueTypeReference();
+ else
+ static_cast<QmlValueTypeCopy *>(w)->~QmlValueTypeCopy();
+}
+
+bool QmlValueTypeWrapper::isEqualTo(Managed *m, Managed *other)
+{
+ QV4::QmlValueTypeWrapper *lv = m->as<QmlValueTypeWrapper>();
+ assert(lv);
+
+ if (QV4::VariantObject *rv = other->as<VariantObject>())
+ return lv->isEqual(rv->data);
+
+ if (QV4::QmlValueTypeWrapper *v = other->as<QmlValueTypeWrapper>())
+ return lv->isEqual(v->toVariant());
+
+ return false;
+}
+
+bool QmlValueTypeWrapper::isEqual(const QVariant& value)
+{
+ if (objectType == QmlValueTypeWrapper::Reference) {
+ QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(this);
+ if (reference->object && readReferenceValue(reference)) {
+ return reference->type->isEqual(value);
+ } else {
+ return false;
+ }
+ } else {
+ Q_ASSERT(objectType == QmlValueTypeWrapper::Copy);
+ QmlValueTypeCopy *copy = static_cast<QmlValueTypeCopy *>(this);
+ type->setValue(copy->value);
+ if (type->isEqual(value))
+ return true;
+ return (value == copy->value);
+ }
+}
+
+Value QmlValueTypeWrapper::method_toString(SimpleCallContext *ctx)
+{
+ Object *o = ctx->thisObject.asObject();
+ if (!o)
+ ctx->throwTypeError();
+ QmlValueTypeWrapper *w = o->as<QmlValueTypeWrapper>();
+ if (!w)
+ ctx->throwTypeError();
+
+ if (w->objectType == QmlValueTypeWrapper::Reference) {
+ QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(w);
+ if (reference->object && readReferenceValue(reference)) {
+ return w->v8->toString(w->type->toString());
+ } else {
+ return QV4::Value::undefinedValue();
+ }
+ } else {
+ Q_ASSERT(w->objectType == QmlValueTypeWrapper::Copy);
+ QmlValueTypeCopy *copy = static_cast<QmlValueTypeCopy *>(w);
+ w->type->setValue(copy->value);
+ return w->v8->toString(w->type->toString());
+ }
+}
+
+Value QmlValueTypeWrapper::get(Managed *m, String *name, bool *hasProperty)
+{
+ QmlValueTypeWrapper *r = m->as<QmlValueTypeWrapper>();
+ QV4::ExecutionEngine *v4 = m->engine();
+ if (!r)
+ v4->current->throwTypeError();
+
+ // Note: readReferenceValue() can change the reference->type.
+ if (r->objectType == QmlValueTypeWrapper::Reference) {
+ QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(r);
+
+ if (!reference->object || !readReferenceValue(reference))
+ return Value::undefinedValue();
+
+ } else {
+ Q_ASSERT(r->objectType == QmlValueTypeWrapper::Copy);
+
+ QmlValueTypeCopy *copy = static_cast<QmlValueTypeCopy *>(r);
+
+ r->type->setValue(copy->value);
+ }
+
+ QQmlPropertyData local;
+ QQmlPropertyData *result = 0;
+ {
+ QQmlData *ddata = QQmlData::get(r->type, false);
+ if (ddata && ddata->propertyCache)
+ result = ddata->propertyCache->property(name, 0, 0);
+ else
+ result = QQmlPropertyCache::property(r->v8->engine(), r->type, name, 0, local);
+ }
+
+ if (!result)
+ return Object::get(m, name, hasProperty);
+
+ if (result->isFunction()) {
+ // calling a Q_INVOKABLE function of a value type
+ QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4);
+ return QV4::QObjectWrapper::getQmlProperty(v4->current, qmlContext, r->type, name, QV4::QObjectWrapper::IgnoreRevision);
+ }
+
+#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
+ if (result->propType == metatype) { \
+ cpptype v; \
+ void *args[] = { &v, 0 }; \
+ r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args); \
+ return constructor(v); \
+ }
+
+ // These four types are the most common used by the value type wrappers
+ VALUE_TYPE_LOAD(QMetaType::QReal, qreal, QV4::Value::fromDouble);
+ VALUE_TYPE_LOAD(QMetaType::Int, int, QV4::Value::fromInt32);
+ VALUE_TYPE_LOAD(QMetaType::QString, QString, r->v8->toString);
+ VALUE_TYPE_LOAD(QMetaType::Bool, bool, QV4::Value::fromBoolean);
+
+ QVariant v(result->propType, (void *)0);
+ void *args[] = { v.data(), 0 };
+ r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args);
+ return r->v8->fromVariant(v);
+#undef VALUE_TYPE_ACCESSOR
+}
+
+void QmlValueTypeWrapper::put(Managed *m, String *name, const Value &value)
+{
+ QmlValueTypeWrapper *r = m->as<QmlValueTypeWrapper>();
+ ExecutionEngine *v4 = m->engine();
+ if (!r)
+ v4->current->throwTypeError();
+
+ QByteArray propName = name->toQString().toUtf8();
+ if (r->objectType == QmlValueTypeWrapper::Reference) {
+ QmlValueTypeReference *reference = static_cast<QmlValueTypeReference *>(r);
+ QMetaProperty writebackProperty = reference->object->metaObject()->property(reference->property);
+
+ if (!reference->object || !writebackProperty.isWritable() || !readReferenceValue(reference))
+ return;
+
+ // we lookup the index after readReferenceValue() since it can change the reference->type.
+ int index = r->type->metaObject()->indexOfProperty(propName.constData());
+ if (index == -1)
+ return;
+ QMetaProperty p = r->type->metaObject()->property(index);
+
+ QQmlBinding *newBinding = 0;
+
+ QV4::FunctionObject *f = value.asFunctionObject();
+ if (f) {
+ if (!f->bindingKeyFlag) {
+ // assigning a JS function to a non-var-property is not allowed.
+ QString error = QLatin1String("Cannot assign JavaScript function to value-type property");
+ v4->current->throwError(r->v8->toString(error));
+ }
+
+ QQmlContextData *context = r->v8->callingContext();
+
+ QQmlPropertyData cacheData;
+ cacheData.setFlags(QQmlPropertyData::IsWritable |
+ QQmlPropertyData::IsValueTypeVirtual);
+ cacheData.propType = reference->object->metaObject()->property(reference->property).userType();
+ cacheData.coreIndex = reference->property;
+ cacheData.valueTypeFlags = 0;
+ cacheData.valueTypeCoreIndex = index;
+ cacheData.valueTypePropType = p.userType();
+
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
+
+ newBinding = new QQmlBinding(value, reference->object, context,
+ frame.source, qmlSourceCoordinate(frame.line), qmlSourceCoordinate(frame.column));
+ newBinding->setTarget(reference->object, cacheData, context);
+ newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
+ QQmlBinding::RequiresThisObject);
+ }
+
+ QQmlAbstractBinding *oldBinding =
+ QQmlPropertyPrivate::setBinding(reference->object, reference->property, index, newBinding);
+ if (oldBinding)
+ oldBinding->destroy();
+
+ if (!f) {
+ QVariant v = r->v8->toVariant(value, -1);
+
+ if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
+ v = v.toInt();
+
+ p.write(reference->type, v);
+
+ if (writebackProperty.userType() == QMetaType::QVariant) {
+ QVariant variantReferenceValue = r->type->value();
+ reference->type->writeVariantValue(reference->object, reference->property, 0, &variantReferenceValue);
+ } else {
+ reference->type->write(reference->object, reference->property, 0);
+ }
+ }
+
+ } else {
+ Q_ASSERT(r->objectType == QmlValueTypeWrapper::Copy);
+
+ QmlValueTypeCopy *copy = static_cast<QmlValueTypeCopy *>(r);
+
+ int index = r->type->metaObject()->indexOfProperty(propName.constData());
+ if (index == -1)
+ return;
+
+ QVariant v = r->v8->toVariant(value, -1);
+
+ r->type->setValue(copy->value);
+ QMetaProperty p = r->type->metaObject()->property(index);
+ p.write(r->type, v);
+ copy->value = r->type->value();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlvaluetypewrapper_p.h b/src/qml/qml/qqmlvaluetypewrapper_p.h
new file mode 100644
index 0000000000..18dca0a4c9
--- /dev/null
+++ b/src/qml/qml/qqmlvaluetypewrapper_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQMLVALUETYPEWRAPPER_P_H
+#define QQMLVALUETYPEWRAPPER_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 <QtCore/qglobal.h>
+#include <private/qtqmlglobal_p.h>
+
+#include <private/qv4value_p.h>
+#include <private/qv4object_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlValueType;
+class QV8Engine;
+
+namespace QV4 {
+
+struct Q_QML_EXPORT QmlValueTypeWrapper : Object
+{
+ Q_MANAGED
+protected:
+ enum ObjectType { Reference, Copy };
+ QmlValueTypeWrapper(QV8Engine *engine, ObjectType type);
+ ~QmlValueTypeWrapper();
+
+public:
+
+ static Value create(QV8Engine *v8, QObject *, int, QQmlValueType *);
+ static Value create(QV8Engine *v8, const QVariant &, QQmlValueType *);
+
+ QVariant toVariant() const;
+ bool isEqual(const QVariant& value);
+
+
+ static Value get(Managed *m, String *name, bool *hasProperty);
+ static void put(Managed *m, String *name, const Value &value);
+ static void destroy(Managed *that);
+ static bool isEqualTo(Managed *m, Managed *other);
+
+ static QV4::Value method_toString(SimpleCallContext *ctx);
+
+ QV8Engine *v8;
+ ObjectType objectType;
+ mutable QQmlValueType *type;
+
+ static void initProto(ExecutionEngine *v4);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV8VALUETYPEWRAPPER_P_H
+
+
diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp
index 736ed5f8bc..e32193e6f6 100644
--- a/src/qml/qml/qqmlvme.cpp
+++ b/src/qml/qml/qqmlvme.cpp
@@ -58,14 +58,14 @@
#include "qqmlcomponent_p.h"
#include "qqmlvmemetaobject_p.h"
#include "qqmlcontext_p.h"
-#include <private/qv4bindings_p.h>
-#include <private/qv8bindings_p.h>
#include "qqmlglobal_p.h"
#include <private/qfinitestack_p.h>
#include "qqmlscriptstring.h"
#include "qqmlscriptstring_p.h"
#include "qqmlpropertyvalueinterceptor_p.h"
#include "qqmlvaluetypeproxybinding_p.h"
+#include "qqmlexpression_p.h"
+#include "qqmlcontextwrapper_p.h"
#include <QStack>
#include <QPointF>
@@ -296,12 +296,12 @@ static QVariant variantFromString(const QString &string)
#define QML_STORE_VAR(name, value) \
QML_BEGIN_INSTR(name) \
- v8::Handle<v8::Value> v8value = value; \
+ QV4::Value v4value = value; \
QObject *target = objects.top(); \
CLEAN_PROPERTY(target, instr.propertyIndex); \
QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(target); \
Q_ASSERT(vmemo); \
- vmemo->setVMEProperty(instr.propertyIndex, v8value); \
+ vmemo->setVMEProperty(instr.propertyIndex, v4value); \
QML_END_INSTR(name)
#define QML_STORE_POINTER(name, value) \
@@ -340,10 +340,6 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QQmlEngine *engine = states.at(0).context->engine;
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
- // Need a v8 handle scope and execution context for StoreVar instructions.
- v8::HandleScope handleScope;
- v8::Context::Scope contextScope(ep->v8engine()->context());
-
int status = -1; // needed for dbus
QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::BypassInterceptor |
QQmlPropertyPrivate::RemoveBindingOnAliasWrite;
@@ -376,7 +372,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
// Store a created object in a property. These all pop from the objects stack.
QML_STORE_VALUE(StoreObject, QObject *, objects.pop());
QML_STORE_VALUE(StoreVariantObject, QVariant, QVariant::fromValue(objects.pop()));
- QML_STORE_VAR(StoreVarObject, ep->v8engine()->newQObject(objects.pop()));
+ QML_STORE_VAR(StoreVarObject, QV4::QObjectWrapper::wrap(ep->v4engine(), objects.pop()));
// Store a literal value in a corresponding property
QML_STORE_VALUE(StoreFloat, float, instr.value);
@@ -425,9 +421,9 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
// Store a literal value in a var property.
// We deliberately do not use string converters here
QML_STORE_VAR(StoreVar, ep->v8engine()->fromVariant(PRIMITIVES.at(instr.value)));
- QML_STORE_VAR(StoreVarInteger, v8::Integer::New(instr.value));
- QML_STORE_VAR(StoreVarDouble, v8::Number::New(instr.value));
- QML_STORE_VAR(StoreVarBool, v8::Boolean::New(instr.value));
+ QML_STORE_VAR(StoreVarInteger, QV4::Value::fromInt32(instr.value));
+ QML_STORE_VAR(StoreVarDouble, QV4::Value::fromDouble(instr.value));
+ QML_STORE_VAR(StoreVarBool, QV4::Value::fromBoolean(instr.value));
// Store a literal value in a QJSValue property.
QML_STORE_VALUE(StoreJSValueString, QJSValue, QJSValue(PRIMITIVES.at(instr.value)));
@@ -449,10 +445,6 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
CTXT->setParent(parentCtxt);
if (instr.contextCache != -1)
CTXT->setIdPropertyData(COMP->contextCaches.at(instr.contextCache));
- if (instr.compiledBinding != -1) {
- const char *v4data = DATAS.at(instr.compiledBinding).constData();
- CTXT->v4bindings = new QV4Bindings(v4data, CTXT);
- }
if (states.count() == 1) {
rootContext = CTXT;
rootContext->activeVMEData = data;
@@ -476,8 +468,6 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
// double dispose. It is possible we could do this more efficiently using some form of
// referencing instead.
CTXT->importedScripts = creationContext->importedScripts;
- for (int ii = 0; ii < CTXT->importedScripts.count(); ++ii)
- CTXT->importedScripts[ii] = qPersistentNew<v8::Object>(CTXT->importedScripts[ii]);
}
QML_END_INSTR(Init)
@@ -767,9 +757,10 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
QQmlBoundSignal *bs = new QQmlBoundSignal(target, instr.signalIndex, target, engine);
QQmlBoundSignalExpression *expr =
new QQmlBoundSignalExpression(target, instr.signalIndex,
- CTXT, context, DATAS.at(instr.value),
- true, COMP->name, instr.line, instr.column);
- expr->setParameterCountForJS(instr.parameterCount);
+ CTXT, context, PRIMITIVES.at(instr.value),
+ COMP->name, instr.line, instr.column,
+ PRIMITIVES.at(instr.handlerName),
+ PRIMITIVES.at(instr.parameters));
bs->takeExpression(expr);
QML_END_INSTR(StoreSignal)
@@ -806,10 +797,6 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
status->classBegin();
QML_END_INSTR(BeginObject)
- QML_BEGIN_INSTR(InitV8Bindings)
- CTXT->v8bindings = new QV8Bindings(&PROGRAMS[instr.programIndex], instr.line, CTXT);
- QML_END_INSTR(InitV8Bindings)
-
QML_BEGIN_INSTR(StoreBinding)
QObject *target =
objects.at(objects.count() - 1 - instr.owner);
@@ -819,7 +806,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
if (instr.isRoot && BINDINGSKIPLIST.testBit(instr.property.coreIndex))
QML_NEXT_INSTR(StoreBinding);
- QQmlBinding *bind = new QQmlBinding(PRIMITIVES.at(instr.value), true,
+ QQmlBinding *bind = new QQmlBinding(PRIMITIVES.at(instr.value),
context, CTXT, COMP->name, instr.line,
instr.column);
bindValues.push(bind);
@@ -844,86 +831,6 @@ QObject *QQmlVME::run(QList<QQmlError> *errors,
}
QML_END_INSTR(StoreBinding)
- QML_BEGIN_INSTR(StoreV4Binding)
- QObject *target =
- objects.at(objects.count() - 1 - instr.owner);
- QObject *scope =
- objects.at(objects.count() - 1 - instr.context);
-
- int propertyIdx = (instr.property & 0x0000FFFF);
-
- if (instr.isRoot && BINDINGSKIPLIST.testBit(propertyIdx))
- QML_NEXT_INSTR(StoreV4Binding);
-
- QQmlAbstractBinding *binding = CTXT->v4bindings->configBinding(target, scope, &instr);
- bindValues.push(binding);
- binding->m_mePtr = &bindValues.top();
-
- if (instr.isAlias) {
- QQmlAbstractBinding *old =
- QQmlPropertyPrivate::setBindingNoEnable(target,
- propertyIdx,
- instr.propType ? (instr.property >> 16) : -1,
- binding);
- if (old) { old->destroy(); }
- } else {
- Q_ASSERT(binding->propertyIndex() == instr.property);
- Q_ASSERT(binding->object() == target);
-
- CLEAN_PROPERTY(target, instr.property);
-
- binding->addToObject();
-
- if (instr.propType == 0) {
- // All non-valuetype V4 bindings are safe bindings
- QQmlData *data = QQmlData::get(target);
- Q_ASSERT(data);
- data->setPendingBindingBit(target, propertyIdx);
- }
- }
- QML_END_INSTR(StoreV4Binding)
-
- QML_BEGIN_INSTR(StoreV8Binding)
- QObject *target =
- objects.at(objects.count() - 1 - instr.owner);
- QObject *scope =
- objects.at(objects.count() - 1 - instr.context);
-
- int coreIndex = instr.property.coreIndex;
-
- if (instr.isRoot && BINDINGSKIPLIST.testBit(coreIndex))
- QML_NEXT_INSTR(StoreV8Binding);
-
- QQmlAbstractBinding *binding = CTXT->v8bindings->configBinding(target, scope,
- &instr);
- if (binding && !instr.isFallback) {
- bindValues.push(binding);
- binding->m_mePtr = &bindValues.top();
-
- if (instr.isAlias) {
- QQmlAbstractBinding *old =
- QQmlPropertyPrivate::setBindingNoEnable(target, coreIndex,
- instr.property.getValueTypeCoreIndex(),
- binding);
- if (old) { old->destroy(); }
- } else {
- typedef QQmlPropertyPrivate QDPP;
- Q_ASSERT(binding->propertyIndex() == QDPP::bindingIndex(instr.property));
- Q_ASSERT(binding->object() == target);
-
- CLEAN_PROPERTY(target, QDPP::bindingIndex(instr.property));
-
- binding->addToObject();
-
- if (instr.isSafe && !instr.property.isValueTypeVirtual()) {
- QQmlData *data = QQmlData::get(target);
- Q_ASSERT(data);
- data->setPendingBindingBit(target, coreIndex);
- }
- }
- }
- QML_END_INSTR(StoreV8Binding)
-
QML_BEGIN_INSTR(StoreValueSource)
QObject *obj = objects.pop();
QQmlPropertyValueSource *vs = reinterpret_cast<QQmlPropertyValueSource *>(reinterpret_cast<char *>(obj) + instr.castValue);
@@ -1170,20 +1077,25 @@ void QQmlVME::reset()
// Must be called with a handle scope and context
void QQmlScriptData::initialize(QQmlEngine *engine)
{
- Q_ASSERT(m_program.IsEmpty());
+ Q_ASSERT(!m_program);
Q_ASSERT(engine);
Q_ASSERT(!hasEngine());
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine);
QV8Engine *v8engine = ep->v8engine();
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(v8engine);
+
+ // If compilation throws an error, a surrounding catch will record it.
+ // pass 0 as the QML object, we set it later before calling run()
+ QV4::Script *program = new QV4::Script(v4, 0, m_programSource, urlString, 1);
+ try {
+ program->parse();
+ } catch (QV4::Exception &) {
+ delete program;
+ throw;
+ }
- // If compilation throws an error, a surrounding v8::TryCatch will record it.
- v8::Local<v8::Script> program = v8engine->qmlModeCompile(m_programSource.constData(),
- m_programSource.length(), urlString, 1);
- if (program.IsEmpty())
- return;
-
- m_program = qPersistentNew<v8::Script>(program);
+ m_program = program;
m_programSource.clear(); // We don't need this anymore
addToEngine(engine);
@@ -1191,12 +1103,12 @@ void QQmlScriptData::initialize(QQmlEngine *engine)
addref();
}
-v8::Persistent<v8::Object> QQmlVME::run(QQmlContextData *parentCtxt, QQmlScriptData *script)
+QV4::PersistentValue QQmlVME::run(QQmlContextData *parentCtxt, QQmlScriptData *script)
{
if (script->m_loaded)
- return qPersistentNew<v8::Object>(script->m_value);
+ return script->m_value;
- v8::Persistent<v8::Object> rv;
+ QV4::PersistentValue rv;
Q_ASSERT(parentCtxt && parentCtxt->engine);
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(parentCtxt->engine);
@@ -1231,8 +1143,6 @@ v8::Persistent<v8::Object> QQmlVME::run(QQmlContextData *parentCtxt, QQmlScriptD
} else if (effectiveCtxt) {
ctxt->imports = effectiveCtxt->imports;
ctxt->importedScripts = effectiveCtxt->importedScripts;
- for (int ii = 0; ii < ctxt->importedScripts.count(); ++ii)
- ctxt->importedScripts[ii] = qPersistentNew<v8::Object>(ctxt->importedScripts[ii]);
}
if (ctxt->imports) {
@@ -1249,35 +1159,43 @@ v8::Persistent<v8::Object> QQmlVME::run(QQmlContextData *parentCtxt, QQmlScriptD
ctxt->importedScripts << run(ctxt, script->scripts.at(ii)->scriptData());
}
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(v8engine->context());
-
- v8::TryCatch try_catch;
- if (!script->isInitialized())
- script->initialize(parentCtxt->engine);
-
- v8::Local<v8::Object> qmlglobal = v8engine->qmlScope(ctxt, 0);
- v8engine->contextWrapper()->takeContextOwnership(qmlglobal);
+ if (!script->isInitialized()) {
+ QV4::ExecutionContext *ctx = QV8Engine::getV4(parentCtxt->engine)->current;
+ try {
+ script->initialize(parentCtxt->engine);
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ QQmlError error;
+ QQmlExpressionPrivate::exceptionToError(e, error);
+ if (error.isValid())
+ ep->warning(error);
+ }
+ }
- if (!script->m_program.IsEmpty()) {
- script->m_program->Run(qmlglobal);
- } else {
- // Compilation failed.
- Q_ASSERT(try_catch.HasCaught());
+ if (!script->m_program) {
+ if (shared)
+ script->m_loaded = true;
+ return QV4::PersistentValue();
}
- if (try_catch.HasCaught()) {
- v8::Local<v8::Message> message = try_catch.Message();
- if (!message.IsEmpty()) {
- QQmlError error;
- QQmlExpressionPrivate::exceptionToError(message, error);
+ QV4::Value qmlglobal = QV4::QmlContextWrapper::qmlScope(v8engine, ctxt, 0);
+ QV4::QmlContextWrapper::takeContextOwnership(qmlglobal);
+
+ QV4::ExecutionContext *ctx = QV8Engine::getV4(v8engine)->current;
+ try {
+ script->m_program->qml = qmlglobal;
+ script->m_program->run();
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ QQmlError error;
+ QQmlExpressionPrivate::exceptionToError(e, error);
+ if (error.isValid())
ep->warning(error);
- }
}
- rv = qPersistentNew<v8::Object>(qmlglobal);
+ rv = qmlglobal;
if (shared) {
- script->m_value = qPersistentNew<v8::Object>(qmlglobal);
+ script->m_value = rv;
script->m_loaded = true;
}
@@ -1449,7 +1367,7 @@ void QQmlVMEGuard::guard(QQmlVME *vme)
clear();
m_objectCount = vme->objects.count();
- m_objects = new QQmlGuard<QObject>[m_objectCount];
+ m_objects = new QPointer<QObject>[m_objectCount];
for (int ii = 0; ii < m_objectCount; ++ii)
m_objects[ii] = vme->objects[ii];
diff --git a/src/qml/qml/qqmlvme_p.h b/src/qml/qml/qqmlvme_p.h
index 405a83c4fe..09e3237aee 100644
--- a/src/qml/qml/qqmlvme_p.h
+++ b/src/qml/qml/qqmlvme_p.h
@@ -64,7 +64,6 @@
#include <QtCore/qcoreapplication.h>
#include <QtCore/qtypeinfo.h>
-#include <private/qv8_p.h>
#include <private/qqmlengine_p.h>
#include <private/qfinitestack_p.h>
@@ -152,7 +151,7 @@ private:
, void *const**storeJumpTable = 0
#endif
);
- v8::Persistent<v8::Object> run(QQmlContextData *, QQmlScriptData *);
+ QV4::PersistentValue run(QQmlContextData *, QQmlScriptData *);
#ifdef QML_THREADED_VME_INTERPRETER
static void *const*instructionJumpTable();
@@ -203,7 +202,7 @@ public:
private:
int m_objectCount;
- QQmlGuard<QObject> *m_objects;
+ QPointer<QObject> *m_objects;
int m_contextCount;
QQmlGuardedContextData *m_contexts;
};
diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp
index a80cba2c5e..327b638068 100644
--- a/src/qml/qml/qqmlvmemetaobject.cpp
+++ b/src/qml/qml/qqmlvmemetaobject.cpp
@@ -50,9 +50,12 @@
#include "qqmlbinding_p.h"
#include "qqmlpropertyvalueinterceptor_p.h"
-#include <private/qv8variantresource_p.h>
#include <private/qqmlglobal_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4variantobject_p.h>
+#include <private/qv4functionobject_p.h>
+
QT_BEGIN_NAMESPACE
QQmlVMEVariantQObjectPtr::QQmlVMEVariantQObjectPtr(bool isVar)
@@ -67,9 +70,11 @@ QQmlVMEVariantQObjectPtr::~QQmlVMEVariantQObjectPtr()
void QQmlVMEVariantQObjectPtr::objectDestroyed(QObject *)
{
if (m_target && m_index >= 0) {
- if (m_isVar && m_target->varPropertiesInitialized && !m_target->varProperties.IsEmpty()) {
+ if (m_isVar && m_target->varPropertiesInitialized && !m_target->varProperties.isEmpty()) {
// Set the var property to NULL
- m_target->varProperties->Set(m_index - m_target->firstVarPropertyIndex, v8::Null());
+ QV4::ArrayObject *a = m_target->varProperties.value().asArrayObject();
+ if (a)
+ a->putIndexed(m_index - m_target->firstVarPropertyIndex, QV4::Value::nullValue());
}
m_target->activate(m_target->object, m_target->methodOffset() + m_index, 0);
@@ -550,7 +555,7 @@ QAbstractDynamicMetaObject *QQmlVMEMetaObject::toDynamicMetaObject(QObject *o)
QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
QQmlPropertyCache *cache,
const QQmlVMEMetaData *meta)
-: QV8GCCallback::Node(GcPrologueCallback), object(obj),
+: object(obj),
ctxt(QQmlData::get(obj, true)->outerContext), cache(cache), metaData(meta),
hasAssignedMetaObjectData(false), data(0), aliasEndpoints(0), firstVarPropertyIndex(-1),
varPropertiesInitialized(false), interceptors(0), v8methods(0)
@@ -573,7 +578,10 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
int list_type = qMetaTypeId<QQmlListProperty<QObject> >();
int qobject_type = qMetaTypeId<QObject*>();
int variant_type = qMetaTypeId<QVariant>();
- bool needsGcCallback = (metaData->varPropertyCount > 0);
+ // Need JS wrapper to ensure variant and var properties are marked.
+ // ### FIXME: I hope that this can be removed once we have the proper scope chain
+ // set up and the JS wrappers always exist.
+ bool needsJSWrapper = (metaData->varPropertyCount > 0);
// ### Optimize
for (int ii = 0; ii < metaData->propertyCount - metaData->varPropertyCount; ++ii) {
@@ -581,20 +589,15 @@ QQmlVMEMetaObject::QQmlVMEMetaObject(QObject *obj,
if (t == list_type) {
listProperties.append(List(methodOffset() + ii, this));
data[ii].setValue(listProperties.count() - 1);
- } else if (!needsGcCallback && (t == qobject_type || t == variant_type)) {
- needsGcCallback = true;
+ } else if (!needsJSWrapper && (t == qobject_type || t == variant_type)) {
+ needsJSWrapper = true;
}
}
firstVarPropertyIndex = metaData->propertyCount - metaData->varPropertyCount;
- // both var properties and variant properties can keep references to
- // other QObjects, and var properties can also keep references to
- // JavaScript objects. If we have any properties, we need to hook
- // the gc() to ensure that references keep objects alive as needed.
- if (needsGcCallback) {
- QV8GCCallback::addGcCallbackNode(this);
- }
+ if (needsJSWrapper)
+ ensureQObjectWrapper();
}
QQmlVMEMetaObject::~QQmlVMEMetaObject()
@@ -602,15 +605,8 @@ QQmlVMEMetaObject::~QQmlVMEMetaObject()
if (parent.isT1()) parent.asT1()->objectDestroyed(object);
delete [] data;
delete [] aliasEndpoints;
-
- for (int ii = 0; v8methods && ii < metaData->methodCount; ++ii) {
- qPersistentDispose(v8methods[ii]);
- }
delete [] v8methods;
- if (metaData->varPropertyCount)
- qPersistentDispose(varProperties); // if not weak, will not have been cleaned up by the callback.
-
qDeleteAll(varObjectGuards);
}
@@ -705,8 +701,6 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine);
QV8Engine *v8e = (ep == 0) ? 0 : ep->v8engine();
if (v8e) {
- v8::HandleScope handleScope;
- v8::Context::Scope contextScope(v8e->context());
if (c == QMetaObject::ReadProperty) {
*reinterpret_cast<QVariant *>(a[0]) = readPropertyAsVariant(id);
} else if (c == QMetaObject::WriteProperty) {
@@ -917,8 +911,8 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
QQmlEnginePrivate *ep = QQmlEnginePrivate::get(ctxt->engine);
ep->referenceScarceResources(); // "hold" scarce resources in memory during evaluation.
- v8::Handle<v8::Function> function = method(id);
- if (function.IsEmpty()) {
+ QV4::FunctionObject *function = method(id).asFunctionObject();
+ if (!function) {
// The function was not compiled. There are some exceptional cases which the
// expression rewriter does not rewrite properly (e.g., \r-terminated lines
// are not rewritten correctly but this bug is deemed out-of-scope to fix for
@@ -932,29 +926,23 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
QQmlVMEMetaData::MethodData *data = metaData->methodData() + id;
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(ep->v8engine()->context());
- v8::Handle<v8::Value> *args = 0;
-
- if (data->parameterCount) {
- args = new v8::Handle<v8::Value>[data->parameterCount];
- for (int ii = 0; ii < data->parameterCount; ++ii)
- args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]);
- }
-
- v8::TryCatch try_catch;
+ QVarLengthArray<QV4::Value, 9> args(data->parameterCount);
- v8::Local<v8::Value> result = function->Call(ep->v8engine()->global(), data->parameterCount, args);
+ for (int ii = 0; ii < data->parameterCount; ++ii)
+ args[ii] = ep->v8engine()->fromVariant(*(QVariant *)a[ii + 1]);
- QVariant rv;
- if (try_catch.HasCaught()) {
+ QV4::Value result = QV4::Value::undefinedValue();
+ QV4::ExecutionContext *ctx = function->engine()->current;
+ try {
+ result = function->call(ep->v8engine()->global(), args.data(), data->parameterCount);
+ if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result, 0);
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
QQmlError error;
- QQmlExpressionPrivate::exceptionToError(try_catch.Message(), error);
+ QQmlExpressionPrivate::exceptionToError(e, error);
if (error.isValid())
ep->warning(error);
if (a[0]) *(QVariant *)a[0] = QVariant();
- } else {
- if (a[0]) *(QVariant *)a[0] = ep->v8engine()->toVariant(result, 0);
}
ep->dereferenceScarceResources(); // "release" scarce resources if top-level expression evaluation is complete.
@@ -970,17 +958,17 @@ int QQmlVMEMetaObject::metaCall(QMetaObject::Call c, int _id, void **a)
return object->qt_metacall(c, _id, a);
}
-v8::Handle<v8::Function> QQmlVMEMetaObject::method(int index)
+QV4::Value QQmlVMEMetaObject::method(int index)
{
if (!ctxt || !ctxt->isValid()) {
qWarning("QQmlVMEMetaObject: Internal error - attempted to evaluate a function in an invalid context");
- return v8::Handle<v8::Function>();
+ return QV4::Value::emptyValue();
}
if (!v8methods)
- v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
+ v8methods = new QV4::PersistentValue[metaData->methodCount];
- if (v8methods[index].IsEmpty()) {
+ if (v8methods[index].isEmpty()) {
QQmlVMEMetaData::MethodData *data = metaData->methodData() + index;
const char *body = ((const char*)metaData) + data->bodyOffset;
@@ -989,29 +977,28 @@ v8::Handle<v8::Function> QQmlVMEMetaObject::method(int index)
// XXX We should evaluate all methods in a single big script block to
// improve the call time between dynamic methods defined on the same
// object
- v8methods[index] = QQmlExpressionPrivate::evalFunction(ctxt, object, body,
- bodyLength,
- ctxt->urlString,
- data->lineNumber);
+ v8methods[index] = QQmlExpressionPrivate::evalFunction(ctxt, object, QString::fromUtf8(body, bodyLength),
+ ctxt->urlString, data->lineNumber);
}
return v8methods[index];
}
-v8::Handle<v8::Value> QQmlVMEMetaObject::readVarProperty(int id)
+QV4::Value QQmlVMEMetaObject::readVarProperty(int id)
{
Q_ASSERT(id >= firstVarPropertyIndex);
if (ensureVarPropertiesAllocated())
- return varProperties->Get(id - firstVarPropertyIndex);
- return v8::Handle<v8::Value>();
+ return varProperties.value().asObject()->getIndexed(id - firstVarPropertyIndex);
+ return QV4::Value::emptyValue();
}
QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id)
{
if (id >= firstVarPropertyIndex) {
if (ensureVarPropertiesAllocated())
- return QQmlEnginePrivate::get(ctxt->engine)->v8engine()->toVariant(varProperties->Get(id - firstVarPropertyIndex), -1);
+ return QQmlEnginePrivate::get(ctxt->engine)->v8engine()->toVariant(
+ varProperties.value().asObject()->getIndexed(id - firstVarPropertyIndex), -1);
return QVariant();
} else {
if (data[id].dataType() == QMetaType::QObjectStar) {
@@ -1022,7 +1009,7 @@ QVariant QQmlVMEMetaObject::readPropertyAsVariant(int id)
}
}
-void QQmlVMEMetaObject::writeVarProperty(int id, v8::Handle<v8::Value> value)
+void QQmlVMEMetaObject::writeVarProperty(int id, const QV4::Value &value)
{
Q_ASSERT(id >= firstVarPropertyIndex);
if (!ensureVarPropertiesAllocated())
@@ -1030,25 +1017,21 @@ void QQmlVMEMetaObject::writeVarProperty(int id, v8::Handle<v8::Value> value)
// Importantly, if the current value is a scarce resource, we need to ensure that it
// gets automatically released by the engine if no other references to it exist.
- v8::Local<v8::Value> oldv = varProperties->Get(id - firstVarPropertyIndex);
- if (oldv->IsObject()) {
- QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(oldv));
- if (r) {
- r->removeVmePropertyReference();
- }
- }
+ QV4::Value oldv = varProperties.value().asObject()->getIndexed(id - firstVarPropertyIndex);
+ if (QV4::VariantObject *v = oldv.as<QV4::VariantObject>())
+ v->removeVmePropertyReference();
QObject *valueObject = 0;
QQmlVMEVariantQObjectPtr *guard = getQObjectGuardForProperty(id);
- if (value->IsObject()) {
+ if (QV4::Object *o = value.asObject()) {
// And, if the new value is a scarce resource, we need to ensure that it does not get
// automatically released by the engine until no other references to it exist.
- if (QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(value))) {
- r->addVmePropertyReference();
- } else if (QV8QObjectResource *r = v8_resource_cast<QV8QObjectResource>(v8::Handle<v8::Object>::Cast(value))) {
+ if (QV4::VariantObject *v = o->as<QV4::VariantObject>()) {
+ v->addVmePropertyReference();
+ } else if (QV4::QObjectWrapper *wrapper = o->as<QV4::QObjectWrapper>()) {
// We need to track this QObject to signal its deletion
- valueObject = r->object;
+ valueObject = wrapper->object();
// Do we already have a QObject guard for this property?
if (valueObject && !guard) {
@@ -1063,7 +1046,7 @@ void QQmlVMEMetaObject::writeVarProperty(int id, v8::Handle<v8::Value> value)
}
// Write the value and emit change signal as appropriate.
- varProperties->Set(id - firstVarPropertyIndex, value);
+ varProperties.value().asObject()->putIndexed(id - firstVarPropertyIndex, value);
activate(object, methodOffset() + id, 0);
}
@@ -1075,27 +1058,19 @@ void QQmlVMEMetaObject::writeProperty(int id, const QVariant &value)
// Importantly, if the current value is a scarce resource, we need to ensure that it
// gets automatically released by the engine if no other references to it exist.
- v8::Local<v8::Value> oldv = varProperties->Get(id - firstVarPropertyIndex);
- if (oldv->IsObject()) {
- QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(oldv));
- if (r) {
- r->removeVmePropertyReference();
- }
- }
+ QV4::Value oldv = varProperties.value().asObject()->getIndexed(id - firstVarPropertyIndex);
+ if (QV4::VariantObject *v = oldv.as<QV4::VariantObject>())
+ v->removeVmePropertyReference();
// And, if the new value is a scarce resource, we need to ensure that it does not get
// automatically released by the engine until no other references to it exist.
- v8::Handle<v8::Value> newv = QQmlEnginePrivate::get(ctxt->engine)->v8engine()->fromVariant(value);
- if (newv->IsObject()) {
- QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(v8::Handle<v8::Object>::Cast(newv));
- if (r) {
- r->addVmePropertyReference();
- }
- }
+ QV4::Value newv = QQmlEnginePrivate::get(ctxt->engine)->v8engine()->fromVariant(value);
+ if (QV4::VariantObject *v = newv.as<QV4::VariantObject>())
+ v->addVmePropertyReference();
// Write the value and emit change signal as appropriate.
QVariant currentValue = readPropertyAsVariant(id);
- varProperties->Set(id - firstVarPropertyIndex, newv);
+ varProperties.value().asObject()->putIndexed(id - firstVarPropertyIndex, newv);
if ((currentValue.userType() != value.userType() || currentValue != value))
activate(object, methodOffset() + id, 0);
} else {
@@ -1169,7 +1144,7 @@ quint16 QQmlVMEMetaObject::vmeMethodLineNumber(int index)
return data->lineNumber;
}
-v8::Handle<v8::Function> QQmlVMEMetaObject::vmeMethod(int index)
+QV4::Value QQmlVMEMetaObject::vmeMethod(int index)
{
if (index < methodOffset()) {
Q_ASSERT(parentVMEMetaObject());
@@ -1181,25 +1156,23 @@ v8::Handle<v8::Function> QQmlVMEMetaObject::vmeMethod(int index)
}
// Used by debugger
-void QQmlVMEMetaObject::setVmeMethod(int index, v8::Persistent<v8::Function> value)
+void QQmlVMEMetaObject::setVmeMethod(int index, QV4::PersistentValue function)
{
if (index < methodOffset()) {
Q_ASSERT(parentVMEMetaObject());
- return parentVMEMetaObject()->setVmeMethod(index, value);
+ return parentVMEMetaObject()->setVmeMethod(index, function);
}
int plainSignals = metaData->signalCount + metaData->propertyCount + metaData->aliasCount;
Q_ASSERT(index >= (methodOffset() + plainSignals) && index < (methodOffset() + plainSignals + metaData->methodCount));
if (!v8methods)
- v8methods = new v8::Persistent<v8::Function>[metaData->methodCount];
+ v8methods = new QV4::PersistentValue[metaData->methodCount];
int methodIndex = index - methodOffset() - plainSignals;
- if (!v8methods[methodIndex].IsEmpty())
- qPersistentDispose(v8methods[methodIndex]);
- v8methods[methodIndex] = value;
+ v8methods[methodIndex] = function;
}
-v8::Handle<v8::Value> QQmlVMEMetaObject::vmeProperty(int index)
+QV4::Value QQmlVMEMetaObject::vmeProperty(int index)
{
if (index < propOffset()) {
Q_ASSERT(parentVMEMetaObject());
@@ -1208,7 +1181,7 @@ v8::Handle<v8::Value> QQmlVMEMetaObject::vmeProperty(int index)
return readVarProperty(index - propOffset());
}
-void QQmlVMEMetaObject::setVMEProperty(int index, v8::Handle<v8::Value> v)
+void QQmlVMEMetaObject::setVMEProperty(int index, const QV4::Value &v)
{
if (index < propOffset()) {
Q_ASSERT(parentVMEMetaObject());
@@ -1228,59 +1201,45 @@ bool QQmlVMEMetaObject::ensureVarPropertiesAllocated()
// QObject ptr will not yet have been deleted (eg, waiting on deleteLater).
// In this situation, the varProperties handle will be (and should remain)
// empty.
- return !varProperties.IsEmpty();
-}
-
-// see also: QV8GCCallback::garbageCollectorPrologueCallback()
-void QQmlVMEMetaObject::allocateVarPropertiesArray()
-{
- v8::HandleScope handleScope;
- v8::Context::Scope cs(QQmlEnginePrivate::get(ctxt->engine)->v8engine()->context());
- varProperties = qPersistentNew(v8::Array::New(metaData->varPropertyCount));
- varProperties.MakeWeak(static_cast<void*>(this), VarPropertiesWeakReferenceCallback);
- varPropertiesInitialized = true;
+ return !varProperties.isEmpty();
}
-/*
- The "var" properties are stored in a v8::Array which will be strong persistent if the object has cpp-ownership
- and the root QObject in the parent chain does not have JS-ownership. In the weak persistent handle case,
- this callback will dispose the handle when the v8object which owns the lifetime of the var properties array
- is cleared as a result of all other handles to that v8object being released.
- See QV8GCCallback::garbageCollectorPrologueCallback() for more information.
- */
-void QQmlVMEMetaObject::VarPropertiesWeakReferenceCallback(v8::Persistent<v8::Value> object, void* parameter)
+void QQmlVMEMetaObject::ensureQObjectWrapper()
{
- QQmlVMEMetaObject *vmemo = static_cast<QQmlVMEMetaObject*>(parameter);
- Q_ASSERT(vmemo);
- qPersistentDispose(object);
- vmemo->varProperties.Clear();
+ QQmlEnginePrivate *ep = (ctxt == 0 || ctxt->engine == 0) ? 0 : QQmlEnginePrivate::get(ctxt->engine);
+ QV4::ExecutionEngine *v4 = (ep == 0) ? 0 : ep->v4engine();
+ QV4::QObjectWrapper::wrap(v4, object);
}
-void QQmlVMEMetaObject::GcPrologueCallback(QV8GCCallback::Node *node)
+void QQmlVMEMetaObject::mark()
{
- QQmlVMEMetaObject *vmemo = static_cast<QQmlVMEMetaObject*>(node);
- Q_ASSERT(vmemo);
-
- if (!vmemo->ctxt || !vmemo->ctxt->engine)
- return;
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(vmemo->ctxt->engine);
+ varProperties.markOnce();
// add references created by VMEVariant properties
- int maxDataIdx = vmemo->metaData->propertyCount - vmemo->metaData->varPropertyCount;
+ int maxDataIdx = metaData->propertyCount - metaData->varPropertyCount;
for (int ii = 0; ii < maxDataIdx; ++ii) { // XXX TODO: optimize?
- if (vmemo->data[ii].dataType() == QMetaType::QObjectStar) {
+ if (data[ii].dataType() == QMetaType::QObjectStar) {
// possible QObject reference.
- QObject *ref = vmemo->data[ii].asQObject();
+ QObject *ref = data[ii].asQObject();
if (ref) {
- ep->v8engine()->addRelationshipForGC(vmemo->object, ref);
+ QQmlData *ddata = QQmlData::get(ref);
+ if (ddata)
+ ddata->jsWrapper.markOnce();
}
}
}
- // add references created by var properties
- if (!vmemo->varPropertiesInitialized || vmemo->varProperties.IsEmpty())
- return;
- ep->v8engine()->addRelationshipForGC(vmemo->object, vmemo->varProperties);
+ if (QQmlVMEMetaObject *parent = parentVMEMetaObject())
+ parent->mark();
+}
+
+void QQmlVMEMetaObject::allocateVarPropertiesArray()
+{
+ QQmlEngine *qml = qmlEngine(object);
+ assert(qml);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(qml->handle());
+ varProperties = QV4::Value::fromObject(v4->newArrayObject(metaData->varPropertyCount));
+ varPropertiesInitialized = true;
}
bool QQmlVMEMetaObject::aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const
diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h
index 8b80d7f176..9824e0d54b 100644
--- a/src/qml/qml/qqmlvmemetaobject_p.h
+++ b/src/qml/qml/qqmlvmemetaobject_p.h
@@ -71,7 +71,7 @@
#include <private/qv8engine_p.h>
#include <private/qflagpointer_p.h>
-#include <private/qv8_p.h>
+#include <private/qv4value_p.h>
QT_BEGIN_NAMESPACE
@@ -153,12 +153,10 @@ public:
int m_index : 31;
};
-class QV8QObjectWrapper;
class QQmlVMEVariant;
class QQmlRefCount;
class QQmlVMEMetaObjectEndpoint;
-class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QAbstractDynamicMetaObject,
- public QV8GCCallback::Node
+class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QAbstractDynamicMetaObject
{
public:
QQmlVMEMetaObject(QObject *obj, QQmlPropertyCache *cache, const QQmlVMEMetaData *data);
@@ -166,11 +164,11 @@ public:
bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const;
void registerInterceptor(int index, int valueIndex, QQmlPropertyValueInterceptor *interceptor);
- v8::Handle<v8::Function> vmeMethod(int index);
+ QV4::Value vmeMethod(int index);
quint16 vmeMethodLineNumber(int index);
- void setVmeMethod(int index, v8::Persistent<v8::Function>);
- v8::Handle<v8::Value> vmeProperty(int index);
- void setVMEProperty(int index, v8::Handle<v8::Value> v);
+ void setVmeMethod(int index, QV4::PersistentValue function);
+ QV4::Value vmeProperty(int index);
+ void setVMEProperty(int index, const QV4::Value &v);
void connectAliasSignal(int index, bool indexInSignalRange);
@@ -203,24 +201,26 @@ public:
QQmlVMEVariant *data;
QQmlVMEMetaObjectEndpoint *aliasEndpoints;
- v8::Persistent<v8::Array> varProperties;
+ QV4::WeakValue varProperties;
int firstVarPropertyIndex;
bool varPropertiesInitialized;
- static void VarPropertiesWeakReferenceCallback(v8::Persistent<v8::Value> object, void* parameter);
- static void GcPrologueCallback(QV8GCCallback::Node *node);
inline void allocateVarPropertiesArray();
inline bool ensureVarPropertiesAllocated();
+ void ensureQObjectWrapper();
+
+ void mark();
+
void connectAlias(int aliasId);
QBitArray aConnected;
QQmlPropertyValueInterceptor *interceptors;
- v8::Persistent<v8::Function> *v8methods;
- v8::Handle<v8::Function> method(int);
+ QV4::PersistentValue *v8methods;
+ QV4::Value method(int);
- v8::Handle<v8::Value> readVarProperty(int);
- void writeVarProperty(int, v8::Handle<v8::Value>);
+ QV4::Value readVarProperty(int);
+ void writeVarProperty(int, const QV4::Value &);
QVariant readPropertyAsVariant(int);
void writeProperty(int, const QVariant &);
@@ -250,7 +250,6 @@ public:
QQmlVMEVariantQObjectPtr *getQObjectGuardForProperty(int) const;
friend class QV8GCCallback;
- friend class QV8QObjectWrapper;
};
QQmlVMEMetaObject *QQmlVMEMetaObject::get(QObject *obj)
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 7ec92a8171..fb6733ee58 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -49,7 +49,10 @@
#include "qqmlengine_p.h"
#include "qqmlexpression_p.h"
#include "qqmlglobal_p.h"
-#include <private/qv8domerrors_p.h>
+#include <private/qv4domerrors_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qqmlcontextwrapper_p.h>
#include <QtCore/qobject.h>
#include <QtQml/qjsvalue.h>
@@ -60,15 +63,14 @@
#include <QtCore/qstack.h>
#include <QtCore/qdebug.h>
-#ifndef QT_NO_XMLSTREAMREADER
+#include <private/qv4objectproto_p.h>
-#define V8THROW_REFERENCE(string) { \
- v8::ThrowException(v8::Exception::ReferenceError(v8::String::New(string))); \
- return v8::Handle<v8::Value>(); \
-}
+using namespace QV4;
+
+#ifndef QT_NO_XMLSTREAMREADER
-#define D(arg) (arg)->release()
-#define A(arg) (arg)->addref()
+#define V4THROW_REFERENCE(string) \
+ ctx->throwError(Value::fromObject(ctx->engine->newReferenceErrorObject(QStringLiteral(string))))
QT_BEGIN_NAMESPACE
@@ -78,19 +80,15 @@ struct QQmlXMLHttpRequestData {
QQmlXMLHttpRequestData();
~QQmlXMLHttpRequestData();
- v8::Persistent<v8::Function> nodeFunction;
+ PersistentValue nodeFunction;
- v8::Persistent<v8::Object> namedNodeMapPrototype;
- v8::Persistent<v8::Object> nodeListPrototype;
- v8::Persistent<v8::Object> nodePrototype;
- v8::Persistent<v8::Object> elementPrototype;
- v8::Persistent<v8::Object> attrPrototype;
- v8::Persistent<v8::Object> characterDataPrototype;
- v8::Persistent<v8::Object> textPrototype;
- v8::Persistent<v8::Object> cdataPrototype;
- v8::Persistent<v8::Object> documentPrototype;
-
- v8::Local<v8::Object> newNode();
+ PersistentValue nodePrototype;
+ PersistentValue elementPrototype;
+ PersistentValue attrPrototype;
+ PersistentValue characterDataPrototype;
+ PersistentValue textPrototype;
+ PersistentValue cdataPrototype;
+ PersistentValue documentPrototype;
};
static inline QQmlXMLHttpRequestData *xhrdata(QV8Engine *engine)
@@ -98,12 +96,13 @@ static inline QQmlXMLHttpRequestData *xhrdata(QV8Engine *engine)
return (QQmlXMLHttpRequestData *)engine->xmlHttpRequestData();
}
-static v8::Local<v8::Object> constructMeObject(v8::Handle<v8::Object> thisObj, QV8Engine *e)
+static Value constructMeObject(const Value &thisObj, QV8Engine *e)
{
- v8::Local<v8::Object> meObj = v8::Object::New();
- meObj->Set(v8::String::New("ThisObject"), thisObj);
- meObj->Set(v8::String::New("ActivationObject"), e->qmlScope(e->callingContext(), 0));
- return meObj;
+ ExecutionEngine *v4 = QV8Engine::getV4(e);
+ Object *meObj = v4->newObject();
+ meObj->put(v4->newString(QStringLiteral("ThisObject")), thisObj);
+ meObj->put(v4->newString(QStringLiteral("ActivationObject")), QmlContextWrapper::qmlScope(e, e->callingContext(), 0));
+ return Value::fromObject(meObj);
}
QQmlXMLHttpRequestData::QQmlXMLHttpRequestData()
@@ -112,27 +111,6 @@ QQmlXMLHttpRequestData::QQmlXMLHttpRequestData()
QQmlXMLHttpRequestData::~QQmlXMLHttpRequestData()
{
- qPersistentDispose(nodeFunction);
- qPersistentDispose(namedNodeMapPrototype);
- qPersistentDispose(nodeListPrototype);
- qPersistentDispose(nodePrototype);
- qPersistentDispose(elementPrototype);
- qPersistentDispose(attrPrototype);
- qPersistentDispose(characterDataPrototype);
- qPersistentDispose(textPrototype);
- qPersistentDispose(cdataPrototype);
- qPersistentDispose(documentPrototype);
-}
-
-v8::Local<v8::Object> QQmlXMLHttpRequestData::newNode()
-{
- if (nodeFunction.IsEmpty()) {
- v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetHasExternalResource(true);
- nodeFunction = qPersistentNew<v8::Function>(ft->GetFunction());
- }
-
- return nodeFunction->NewInstance();
}
namespace {
@@ -199,61 +177,150 @@ public:
void release() { QQmlRefCount::release(); }
};
-class NamedNodeMap
+class NamedNodeMap : public Object
{
+ Q_MANAGED
public:
- // JS API
- static v8::Handle<v8::Value> length(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> indexed(uint32_t index, const v8::AccessorInfo& info);
- static v8::Handle<v8::Value> named(v8::Local<v8::String> property, const v8::AccessorInfo& args);
+ NamedNodeMap(ExecutionEngine *engine, NodeImpl *data, const QList<NodeImpl *> &list)
+ : Object(engine)
+ , d(data)
+ , list(list)
+ {
+ vtbl = &static_vtbl;
+
+ if (d)
+ d->addref();
+ }
+ ~NamedNodeMap() {
+ if (d)
+ d->release();
+ }
// C++ API
- static v8::Handle<v8::Object> prototype(QV8Engine *);
- static v8::Handle<v8::Value> create(QV8Engine *, NodeImpl *, QList<NodeImpl *> *);
+ static Value create(QV8Engine *, NodeImpl *, const QList<NodeImpl *> &);
+
+ // JS API
+ static void destroy(Managed *that) {
+ that->as<NamedNodeMap>()->~NamedNodeMap();
+ }
+ static Value get(Managed *m, String *name, bool *hasProperty);
+ static Value getIndexed(Managed *m, uint index, bool *hasProperty);
+
+ QList<NodeImpl *> list; // Only used in NamedNodeMap
+ NodeImpl *d;
};
-class NodeList
+DEFINE_MANAGED_VTABLE(NamedNodeMap);
+
+class NodeList : public Object
{
+ Q_MANAGED
public:
+ NodeList(ExecutionEngine *engine, NodeImpl *data)
+ : Object(engine)
+ , d(data)
+ {
+ vtbl = &static_vtbl;
+
+ if (d)
+ d->addref();
+ }
+ ~NodeList() {
+ if (d)
+ d->release();
+ }
+
// JS API
- static v8::Handle<v8::Value> length(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> indexed(uint32_t index, const v8::AccessorInfo& info);
+ static void destroy(Managed *that) {
+ that->as<NodeList>()->~NodeList();
+ }
+ static Value get(Managed *m, String *name, bool *hasProperty);
+ static Value getIndexed(Managed *m, uint index, bool *hasProperty);
// C++ API
- static v8::Handle<v8::Object> prototype(QV8Engine *);
- static v8::Handle<v8::Value> create(QV8Engine *, NodeImpl *);
+ static Value create(QV8Engine *, NodeImpl *);
+
+ NodeImpl *d;
};
-class Node
+DEFINE_MANAGED_VTABLE(NodeList);
+
+class NodePrototype : public Object
{
+ Q_MANAGED
public:
+ NodePrototype(ExecutionEngine *engine)
+ : Object(engine)
+ {
+ vtbl = &static_vtbl;
+ defineAccessorProperty(engine, QStringLiteral("nodeName"), method_get_nodeName, 0);
+ defineAccessorProperty(engine, QStringLiteral("nodeValue"), method_get_nodeValue, 0);
+ defineAccessorProperty(engine, QStringLiteral("nodeType"), method_get_nodeType, 0);
+
+ defineAccessorProperty(engine, QStringLiteral("parentNode"), method_get_parentNode, 0);
+ defineAccessorProperty(engine, QStringLiteral("childNodes"), method_get_childNodes, 0);
+ defineAccessorProperty(engine, QStringLiteral("firstChild"), method_get_firstChild, 0);
+ defineAccessorProperty(engine, QStringLiteral("lastChild"), method_get_lastChild, 0);
+ defineAccessorProperty(engine, QStringLiteral("previousSibling"), method_get_previousSibling, 0);
+ defineAccessorProperty(engine, QStringLiteral("nextSibling"), method_get_nextSibling, 0);
+ defineAccessorProperty(engine, QStringLiteral("attributes"), method_get_attributes, 0);
+ }
+
+ static void initClass(ExecutionEngine *engine);
+
// JS API
- static v8::Handle<v8::Value> nodeName(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> nodeValue(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> nodeType(v8::Local<v8::String>, const v8::AccessorInfo& args);
-
- static v8::Handle<v8::Value> parentNode(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> childNodes(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> firstChild(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> lastChild(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> previousSibling(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> nextSibling(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> attributes(v8::Local<v8::String>, const v8::AccessorInfo& args);
-
- //static v8::Handle<v8::Value> ownerDocument(v8::Local<v8::String>, const v8::AccessorInfo& args);
- //static v8::Handle<v8::Value> namespaceURI(v8::Local<v8::String>, const v8::AccessorInfo& args);
- //static v8::Handle<v8::Value> prefix(v8::Local<v8::String>, const v8::AccessorInfo& args);
- //static v8::Handle<v8::Value> localName(v8::Local<v8::String>, const v8::AccessorInfo& args);
- //static v8::Handle<v8::Value> baseURI(v8::Local<v8::String>, const v8::AccessorInfo& args);
- //static v8::Handle<v8::Value> textContent(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static Value method_get_nodeName(SimpleCallContext *ctx);
+ static Value method_get_nodeValue(SimpleCallContext *ctx);
+ static Value method_get_nodeType(SimpleCallContext *ctx);
+
+ static Value method_get_parentNode(SimpleCallContext *ctx);
+ static Value method_get_childNodes(SimpleCallContext *ctx);
+ static Value method_get_firstChild(SimpleCallContext *ctx);
+ static Value method_get_lastChild(SimpleCallContext *ctx);
+ static Value method_get_previousSibling(SimpleCallContext *ctx);
+ static Value method_get_nextSibling(SimpleCallContext *ctx);
+ static Value method_get_attributes(SimpleCallContext *ctx);
+
+ //static Value ownerDocument(SimpleCallContext *ctx);
+ //static Value namespaceURI(SimpleCallContext *ctx);
+ //static Value prefix(SimpleCallContext *ctx);
+ //static Value localName(SimpleCallContext *ctx);
+ //static Value baseURI(SimpleCallContext *ctx);
+ //static Value textContent(SimpleCallContext *ctx);
+
+ static Value getProto(ExecutionEngine *v4);
+
+};
+
+DEFINE_MANAGED_VTABLE(NodePrototype);
+
+class Node : public Object
+{
+ Q_MANAGED
+
+ Node(ExecutionEngine *engine, NodeImpl *data)
+ : Object(engine)
+ , d(data)
+ {
+ vtbl = &static_vtbl;
+
+ if (d)
+ d->addref();
+ }
+ ~Node() {
+ if (d)
+ d->release();
+ }
+
+ // JS API
+ static void destroy(Managed *that) {
+ that->as<Node>()->~Node();
+ }
// C++ API
- static v8::Handle<v8::Object> prototype(QV8Engine *);
- static v8::Handle<v8::Value> create(QV8Engine *, NodeImpl *);
+ static Value create(QV8Engine *, NodeImpl *);
- Node();
Node(const Node &o);
- ~Node();
bool isNull() const;
NodeImpl *d;
@@ -262,127 +329,113 @@ private:
Node &operator=(const Node &);
};
+DEFINE_MANAGED_VTABLE(Node);
+
class Element : public Node
{
public:
// C++ API
- static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static Value prototype(ExecutionEngine *);
};
class Attr : public Node
{
public:
// JS API
- static v8::Handle<v8::Value> name(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> specified(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> value(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> ownerElement(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> schemaTypeInfo(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> isId(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static Value name(SimpleCallContext *ctx);
+// static Value specified(SimpleCallContext *);
+ static Value value(SimpleCallContext *ctx);
+ static Value ownerElement(SimpleCallContext *ctx);
+// static Value schemaTypeInfo(SimpleCallContext *);
+// static Value isId(SimpleCallContext *c);
// C++ API
- static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static Value prototype(ExecutionEngine *);
};
class CharacterData : public Node
{
public:
// JS API
- static v8::Handle<v8::Value> length(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static Value length(SimpleCallContext *ctx);
// C++ API
- static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static Value prototype(ExecutionEngine *v4);
};
class Text : public CharacterData
{
public:
// JS API
- static v8::Handle<v8::Value> isElementContentWhitespace(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> wholeText(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static Value isElementContentWhitespace(SimpleCallContext *ctx);
+ static Value wholeText(SimpleCallContext *ctx);
// C++ API
- static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static Value prototype(ExecutionEngine *);
};
class CDATA : public Text
{
public:
// C++ API
- static v8::Handle<v8::Object> prototype(QV8Engine *);
+ static Value prototype(ExecutionEngine *v4);
};
class Document : public Node
{
public:
// JS API
- static v8::Handle<v8::Value> xmlVersion(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> xmlEncoding(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> xmlStandalone(v8::Local<v8::String>, const v8::AccessorInfo& args);
- static v8::Handle<v8::Value> documentElement(v8::Local<v8::String>, const v8::AccessorInfo& args);
+ static Value xmlVersion(SimpleCallContext *ctx);
+ static Value xmlEncoding(SimpleCallContext *ctx);
+ static Value xmlStandalone(SimpleCallContext *ctx);
+ static Value documentElement(SimpleCallContext *ctx);
// C++ API
- static v8::Handle<v8::Object> prototype(QV8Engine *);
- static v8::Handle<v8::Value> load(QV8Engine *engine, const QByteArray &data);
-};
-
-}
-
-class QQmlDOMNodeResource : public QV8ObjectResource, public Node
-{
- V8_RESOURCE_TYPE(DOMNodeType)
-public:
- QQmlDOMNodeResource(QV8Engine *e);
-
- QList<NodeImpl *> *list; // Only used in NamedNodeMap
+ static Value prototype(ExecutionEngine *);
+ static Value load(QV8Engine *engine, const QByteArray &data);
};
-QQmlDOMNodeResource::QQmlDOMNodeResource(QV8Engine *e)
-: QV8ObjectResource(e), list(0)
-{
}
-QT_END_NAMESPACE
-
-Q_DECLARE_METATYPE(Node)
-Q_DECLARE_METATYPE(NodeList)
-Q_DECLARE_METATYPE(NamedNodeMap)
-
-QT_BEGIN_NAMESPACE
-
void NodeImpl::addref()
{
- A(document);
+ document->addref();
}
void NodeImpl::release()
{
- D(document);
+ document->release();
}
-v8::Handle<v8::Value> Node::nodeName(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value NodePrototype::method_get_nodeName(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r)
+ ctx->throwTypeError();
+ QString name;
switch (r->d->type) {
case NodeImpl::Document:
- return v8::String::New("#document");
+ name = QStringLiteral("#document");
+ break;
case NodeImpl::CDATA:
- return v8::String::New("#cdata-section");
+ name = QStringLiteral("#cdata-section");
+ break;
case NodeImpl::Text:
- return v8::String::New("#text");
+ name = QStringLiteral("#text");
+ break;
default:
- return engine->toString(r->d->name);
+ name = r->d->name;
+ break;
}
+ return Value::fromString(ctx->engine->newString(name));
}
-v8::Handle<v8::Value> Node::nodeValue(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value NodePrototype::method_get_nodeValue(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r)
+ ctx->throwTypeError();
if (r->d->type == NodeImpl::Document ||
r->d->type == NodeImpl::DocumentFragment ||
@@ -391,143 +444,142 @@ v8::Handle<v8::Value> Node::nodeValue(v8::Local<v8::String>, const v8::AccessorI
r->d->type == NodeImpl::Entity ||
r->d->type == NodeImpl::EntityReference ||
r->d->type == NodeImpl::Notation)
- return v8::Null();
+ return Value::nullValue();
- return engine->toString(r->d->data);
+ return Value::fromString(ctx->engine->newString(r->d->data));
}
-v8::Handle<v8::Value> Node::nodeType(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value NodePrototype::method_get_nodeType(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- return v8::Integer::New(r->d->type);
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r)
+ ctx->throwTypeError();
+
+ return Value::fromInt32(r->d->type);
}
-v8::Handle<v8::Value> Node::parentNode(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value NodePrototype::method_get_parentNode(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r)
+ ctx->throwTypeError();
+
+ QV8Engine *engine = ctx->engine->v8Engine;
if (r->d->parent) return Node::create(engine, r->d->parent);
- else return v8::Null();
+ else return Value::nullValue();
}
-v8::Handle<v8::Value> Node::childNodes(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value NodePrototype::method_get_childNodes(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r)
+ ctx->throwTypeError();
+
+ QV8Engine *engine = ctx->engine->v8Engine;
return NodeList::create(engine, r->d);
}
-v8::Handle<v8::Value> Node::firstChild(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value NodePrototype::method_get_firstChild(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r)
+ ctx->throwTypeError();
+
+ QV8Engine *engine = ctx->engine->v8Engine;
- if (r->d->children.isEmpty()) return v8::Null();
+ if (r->d->children.isEmpty()) return Value::nullValue();
else return Node::create(engine, r->d->children.first());
}
-v8::Handle<v8::Value> Node::lastChild(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value NodePrototype::method_get_lastChild(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r)
+ ctx->throwTypeError();
- if (r->d->children.isEmpty()) return v8::Null();
+ QV8Engine *engine = ctx->engine->v8Engine;
+
+ if (r->d->children.isEmpty()) return Value::nullValue();
else return Node::create(engine, r->d->children.last());
}
-v8::Handle<v8::Value> Node::previousSibling(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value NodePrototype::method_get_previousSibling(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r)
+ ctx->throwTypeError();
+
+ QV8Engine *engine = ctx->engine->v8Engine;
- if (!r->d->parent) return v8::Null();
+ if (!r->d->parent) return Value::nullValue();
for (int ii = 0; ii < r->d->parent->children.count(); ++ii) {
if (r->d->parent->children.at(ii) == r->d) {
- if (ii == 0) return v8::Null();
+ if (ii == 0) return Value::nullValue();
else return Node::create(engine, r->d->parent->children.at(ii - 1));
}
}
- return v8::Null();
+ return Value::nullValue();
}
-v8::Handle<v8::Value> Node::nextSibling(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value NodePrototype::method_get_nextSibling(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r)
+ ctx->throwTypeError();
+
+ QV8Engine *engine = ctx->engine->v8Engine;
- if (!r->d->parent) return v8::Null();
+ if (!r->d->parent) return Value::nullValue();
for (int ii = 0; ii < r->d->parent->children.count(); ++ii) {
if (r->d->parent->children.at(ii) == r->d) {
- if ((ii + 1) == r->d->parent->children.count()) return v8::Null();
+ if ((ii + 1) == r->d->parent->children.count()) return Value::nullValue();
else return Node::create(engine, r->d->parent->children.at(ii + 1));
}
}
- return v8::Null();
+ return Value::nullValue();
}
-v8::Handle<v8::Value> Node::attributes(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value NodePrototype::method_get_attributes(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r)
+ ctx->throwTypeError();
+
+ QV8Engine *engine = ctx->engine->v8Engine;
if (r->d->type != NodeImpl::Element)
- return v8::Null();
+ return Value::nullValue();
else
- return NamedNodeMap::create(engine, r->d, &r->d->attributes);
+ return NamedNodeMap::create(engine, r->d, r->d->attributes);
}
-v8::Handle<v8::Object> Node::prototype(QV8Engine *engine)
+Value NodePrototype::getProto(ExecutionEngine *v4)
{
- QQmlXMLHttpRequestData *d = xhrdata(engine);
- if (d->nodePrototype.IsEmpty()) {
- d->nodePrototype = qPersistentNew<v8::Object>(v8::Object::New());
- d->nodePrototype->SetAccessor(v8::String::New("nodeName"), nodeName,
- 0, v8::External::New(engine));
- d->nodePrototype->SetAccessor(v8::String::New("nodeValue"), nodeValue,
- 0, v8::External::New(engine));
- d->nodePrototype->SetAccessor(v8::String::New("nodeType"), nodeType,
- 0, v8::External::New(engine));
- d->nodePrototype->SetAccessor(v8::String::New("parentNode"), parentNode,
- 0, v8::External::New(engine));
- d->nodePrototype->SetAccessor(v8::String::New("childNodes"), childNodes,
- 0, v8::External::New(engine));
- d->nodePrototype->SetAccessor(v8::String::New("firstChild"), firstChild,
- 0, v8::External::New(engine));
- d->nodePrototype->SetAccessor(v8::String::New("lastChild"), lastChild,
- 0, v8::External::New(engine));
- d->nodePrototype->SetAccessor(v8::String::New("previousSibling"), previousSibling,
- 0, v8::External::New(engine));
- d->nodePrototype->SetAccessor(v8::String::New("nextSibling"), nextSibling,
- 0, v8::External::New(engine));
- d->nodePrototype->SetAccessor(v8::String::New("attributes"), attributes,
- 0, v8::External::New(engine));
- engine->freezeObject(d->nodePrototype);
+ QQmlXMLHttpRequestData *d = xhrdata(v4->v8Engine);
+ if (d->nodePrototype.isEmpty()) {
+ Object *p = new (v4->memoryManager) NodePrototype(v4);
+ d->nodePrototype = Value::fromObject(p);
+ v4->v8Engine->freezeObject(d->nodePrototype.value());
}
- return d->nodePrototype;
+ return d->nodePrototype.value();
}
-v8::Handle<v8::Value> Node::create(QV8Engine *engine, NodeImpl *data)
+Value Node::create(QV8Engine *engine, NodeImpl *data)
{
+ ExecutionEngine *v4 = QV8Engine::getV4(engine);
+
QQmlXMLHttpRequestData *d = xhrdata(engine);
- v8::Local<v8::Object> instance = d->newNode();
+ Node *instance = new (v4->memoryManager) Node(v4, data);
switch (data->type) {
case NodeImpl::Attr:
- instance->SetPrototype(Attr::prototype(engine));
+ instance->prototype = Attr::prototype(v4).asObject();
break;
case NodeImpl::Comment:
case NodeImpl::Document:
@@ -537,173 +589,163 @@ v8::Handle<v8::Value> Node::create(QV8Engine *engine, NodeImpl *data)
case NodeImpl::EntityReference:
case NodeImpl::Notation:
case NodeImpl::ProcessingInstruction:
- return v8::Undefined();
+ return Value::undefinedValue();
case NodeImpl::CDATA:
- instance->SetPrototype(CDATA::prototype(engine));
+ instance->prototype = CDATA::prototype(v4).asObject();
break;
case NodeImpl::Text:
- instance->SetPrototype(Text::prototype(engine));
+ instance->prototype = Text::prototype(v4).asObject();
break;
case NodeImpl::Element:
- instance->SetPrototype(Element::prototype(engine));
+ instance->prototype = Element::prototype(v4).asObject();
break;
}
- QQmlDOMNodeResource *r = new QQmlDOMNodeResource(engine);
- r->d = data;
- if (data) A(data);
- instance->SetExternalResource(r);
-
- return instance;
+ return Value::fromObject(instance);
}
-v8::Handle<v8::Object> Element::prototype(QV8Engine *engine)
+Value Element::prototype(ExecutionEngine *engine)
{
- QQmlXMLHttpRequestData *d = xhrdata(engine);
- if (d->elementPrototype.IsEmpty()) {
- d->elementPrototype = qPersistentNew<v8::Object>(v8::Object::New());
- d->elementPrototype->SetPrototype(Node::prototype(engine));
- d->elementPrototype->SetAccessor(v8::String::New("tagName"), nodeName,
- 0, v8::External::New(engine));
- engine->freezeObject(d->elementPrototype);
+ QQmlXMLHttpRequestData *d = xhrdata(engine->v8Engine);
+ if (d->elementPrototype.isEmpty()) {
+ Object *p = engine->newObject();
+ p->prototype = NodePrototype::getProto(engine).asObject();
+ p->defineAccessorProperty(engine, QStringLiteral("tagName"), NodePrototype::method_get_nodeName, 0);
+ d->elementPrototype = Value::fromObject(p);
+ engine->v8Engine->freezeObject(d->elementPrototype.value());
}
- return d->elementPrototype;
+ return d->elementPrototype.value();
}
-v8::Handle<v8::Object> Attr::prototype(QV8Engine *engine)
+Value Attr::prototype(ExecutionEngine *engine)
{
- QQmlXMLHttpRequestData *d = xhrdata(engine);
- if (d->attrPrototype.IsEmpty()) {
- d->attrPrototype = qPersistentNew<v8::Object>(v8::Object::New());
- d->attrPrototype->SetPrototype(Node::prototype(engine));
- d->attrPrototype->SetAccessor(v8::String::New("name"), name,
- 0, v8::External::New(engine));
- d->attrPrototype->SetAccessor(v8::String::New("value"), value,
- 0, v8::External::New(engine));
- d->attrPrototype->SetAccessor(v8::String::New("ownerElement"), ownerElement,
- 0, v8::External::New(engine));
- engine->freezeObject(d->attrPrototype);
+ QQmlXMLHttpRequestData *d = xhrdata(engine->v8Engine);
+ if (d->attrPrototype.isEmpty()) {
+ Object *p = engine->newObject();
+ p->prototype = NodePrototype::getProto(engine).asObject();
+ p->defineAccessorProperty(engine, QStringLiteral("name"), name, 0);
+ p->defineAccessorProperty(engine, QStringLiteral("value"), value, 0);
+ p->defineAccessorProperty(engine, QStringLiteral("ownerElement"), ownerElement, 0);
+ d->attrPrototype = Value::fromObject(p);
+ engine->v8Engine->freezeObject(d->attrPrototype.value());
}
- return d->attrPrototype;
+ return d->attrPrototype.value();
}
-v8::Handle<v8::Value> Attr::name(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value Attr::name(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r) return Value::undefinedValue();
+ QV8Engine *engine = ctx->engine->v8Engine;
return engine->toString(r->d->name);
}
-v8::Handle<v8::Value> Attr::value(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value Attr::value(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r) return Value::undefinedValue();
+ QV8Engine *engine = ctx->engine->v8Engine;
return engine->toString(r->d->data);
}
-v8::Handle<v8::Value> Attr::ownerElement(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value Attr::ownerElement(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r) return Value::undefinedValue();
+ QV8Engine *engine = ctx->engine->v8Engine;
return Node::create(engine, r->d->parent);
}
-v8::Handle<v8::Value> CharacterData::length(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value CharacterData::length(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r) return Value::undefinedValue();
+ QV8Engine *engine = ctx->engine->v8Engine;
Q_UNUSED(engine)
- return v8::Integer::New(r->d->data.length());
+ return Value::fromInt32(r->d->data.length());
}
-v8::Handle<v8::Object> CharacterData::prototype(QV8Engine *engine)
+Value CharacterData::prototype(ExecutionEngine *v4)
{
- QQmlXMLHttpRequestData *d = xhrdata(engine);
- if (d->characterDataPrototype.IsEmpty()) {
- d->characterDataPrototype = qPersistentNew<v8::Object>(v8::Object::New());
- d->characterDataPrototype->SetPrototype(Node::prototype(engine));
- d->characterDataPrototype->SetAccessor(v8::String::New("data"), nodeValue,
- 0, v8::External::New(engine));
- d->characterDataPrototype->SetAccessor(v8::String::New("length"), length,
- 0, v8::External::New(engine));
- engine->freezeObject(d->characterDataPrototype);
+ QQmlXMLHttpRequestData *d = xhrdata(v4->v8Engine);
+ if (d->characterDataPrototype.isEmpty()) {
+ Object *p = v4->newObject();
+ p->prototype = NodePrototype::getProto(v4).asObject();
+ p->defineAccessorProperty(v4, QStringLiteral("data"), NodePrototype::method_get_nodeValue, 0);
+ p->defineAccessorProperty(v4, QStringLiteral("length"), length, 0);
+ d->characterDataPrototype = Value::fromObject(p);
+ v4->v8Engine->freezeObject(d->characterDataPrototype);
}
- return d->characterDataPrototype;
+ return d->characterDataPrototype.value();
}
-v8::Handle<v8::Value> Text::isElementContentWhitespace(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value Text::isElementContentWhitespace(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
- Q_UNUSED(engine)
- return v8::Boolean::New(r->d->data.trimmed().isEmpty());
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r) return Value::undefinedValue();
+
+ return Value::fromBoolean(r->d->data.trimmed().isEmpty());
}
-v8::Handle<v8::Value> Text::wholeText(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value Text::wholeText(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r) return Value::undefinedValue();
+ QV8Engine *engine = ctx->engine->v8Engine;
return engine->toString(r->d->data);
}
-v8::Handle<v8::Object> Text::prototype(QV8Engine *engine)
+Value Text::prototype(ExecutionEngine *v4)
{
- QQmlXMLHttpRequestData *d = xhrdata(engine);
- if (d->textPrototype.IsEmpty()) {
- d->textPrototype = qPersistentNew<v8::Object>(v8::Object::New());
- d->textPrototype->SetPrototype(CharacterData::prototype(engine));
- d->textPrototype->SetAccessor(v8::String::New("isElementContentWhitespace"), isElementContentWhitespace,
- 0, v8::External::New(engine));
- d->textPrototype->SetAccessor(v8::String::New("wholeText"), wholeText,
- 0, v8::External::New(engine));
- engine->freezeObject(d->textPrototype);
+ QQmlXMLHttpRequestData *d = xhrdata(v4->v8Engine);
+ if (d->textPrototype.isEmpty()) {
+ Object *p = v4->newObject();
+ p->prototype = CharacterData::prototype(v4).asObject();
+ p->defineAccessorProperty(v4, QStringLiteral("isElementContentWhitespace"), isElementContentWhitespace, 0);
+ p->defineAccessorProperty(v4, QStringLiteral("wholeText"), wholeText, 0);
+ d->textPrototype = Value::fromObject(p);
+ v4->v8Engine->freezeObject(d->textPrototype);
}
- return d->textPrototype;
+ return d->textPrototype.value();
}
-v8::Handle<v8::Object> CDATA::prototype(QV8Engine *engine)
+Value CDATA::prototype(ExecutionEngine *v4)
{
- QQmlXMLHttpRequestData *d = xhrdata(engine);
- if (d->cdataPrototype.IsEmpty()) {
- d->cdataPrototype = qPersistentNew<v8::Object>(v8::Object::New());
- d->cdataPrototype->SetPrototype(Text::prototype(engine));
- engine->freezeObject(d->cdataPrototype);
+ // ### why not just use TextProto???
+ QQmlXMLHttpRequestData *d = xhrdata(v4->v8Engine);
+ if (d->cdataPrototype.isEmpty()) {
+ Object *p = v4->newObject();
+ p->prototype = Text::prototype(v4).asObject();
+ d->cdataPrototype = Value::fromObject(p);
+ v4->v8Engine->freezeObject(d->cdataPrototype);
}
- return d->cdataPrototype;
+ return d->cdataPrototype.value();
}
-v8::Handle<v8::Object> Document::prototype(QV8Engine *engine)
+Value Document::prototype(ExecutionEngine *v4)
{
- QQmlXMLHttpRequestData *d = xhrdata(engine);
- if (d->documentPrototype.IsEmpty()) {
- d->documentPrototype = qPersistentNew<v8::Object>(v8::Object::New());
- d->documentPrototype->SetPrototype(Node::prototype(engine));
- d->documentPrototype->SetAccessor(v8::String::New("xmlVersion"), xmlVersion,
- 0, v8::External::New(engine));
- d->documentPrototype->SetAccessor(v8::String::New("xmlEncoding"), xmlEncoding,
- 0, v8::External::New(engine));
- d->documentPrototype->SetAccessor(v8::String::New("xmlStandalone"), xmlStandalone,
- 0, v8::External::New(engine));
- d->documentPrototype->SetAccessor(v8::String::New("documentElement"), documentElement,
- 0, v8::External::New(engine));
- engine->freezeObject(d->documentPrototype);
+ QQmlXMLHttpRequestData *d = xhrdata(v4->v8Engine);
+ if (d->documentPrototype.isEmpty()) {
+ Object *p = v4->newObject();
+ p->prototype = NodePrototype::getProto(v4).asObject();
+ p->defineAccessorProperty(v4, QStringLiteral("xmlVersion"), xmlVersion, 0);
+ p->defineAccessorProperty(v4, QStringLiteral("xmlEncoding"), xmlEncoding, 0);
+ p->defineAccessorProperty(v4, QStringLiteral("xmlStandalone"), xmlStandalone, 0);
+ p->defineAccessorProperty(v4, QStringLiteral("documentElement"), documentElement, 0);
+ d->documentPrototype = Value::fromObject(p);
+ v4->v8Engine->freezeObject(d->documentPrototype);
}
- return d->documentPrototype;
+ return d->documentPrototype.value();
}
-v8::Handle<v8::Value> Document::load(QV8Engine *engine, const QByteArray &data)
+Value Document::load(QV8Engine *engine, const QByteArray &data)
{
Q_ASSERT(engine);
+ ExecutionEngine *v4 = QV8Engine::getV4(engine);
DocumentImpl *document = 0;
QStack<NodeImpl *> nodeStack;
@@ -778,32 +820,21 @@ v8::Handle<v8::Value> Document::load(QV8Engine *engine, const QByteArray &data)
}
if (!document || reader.hasError()) {
- if (document) D(document);
- return v8::Null();
+ if (document)
+ document->release();
+ return Value::nullValue();
}
- v8::Local<v8::Object> instance = xhrdata(engine)->newNode();
- QQmlDOMNodeResource *r = new QQmlDOMNodeResource(engine);
- r->d = document;
- instance->SetExternalResource(r);
- instance->SetPrototype(Document::prototype(engine));
- return instance;
-}
-
-Node::Node()
-: d(0)
-{
+ Object *instance = new (v4->memoryManager) Node(v4, document);
+ instance->prototype = Document::prototype(v4).asObject();
+ return Value::fromObject(instance);
}
Node::Node(const Node &o)
-: d(o.d)
+ : Object(o.engine()), d(o.d)
{
- if (d) A(d);
-}
-
-Node::~Node()
-{
- if (d) D(d);
+ if (d)
+ d->addref();
}
bool Node::isNull() const
@@ -811,158 +842,142 @@ bool Node::isNull() const
return d == 0;
}
-v8::Handle<v8::Value> NamedNodeMap::length(v8::Local<v8::String>, const v8::AccessorInfo &args)
+Value NamedNodeMap::getIndexed(Managed *m, uint index, bool *hasProperty)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
- Q_UNUSED(engine)
- return v8::Integer::New(r->list->count());
-}
+ QV4::ExecutionEngine *v4 = m->engine();
+ NamedNodeMap *r = m->as<NamedNodeMap>();
+ if (!r)
+ v4->current->throwTypeError();
-v8::Handle<v8::Value> NamedNodeMap::indexed(uint32_t index, const v8::AccessorInfo& args)
-{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r || !r->list) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ QV8Engine *engine = v4->v8Engine;
- if ((int)index < r->list->count()) {
- return Node::create(engine, r->list->at(index));
- } else {
- return v8::Undefined();
+ if ((int)index < r->list.count()) {
+ if (hasProperty)
+ *hasProperty = true;
+ return Node::create(engine, r->list.at(index));
}
+ if (hasProperty)
+ *hasProperty = false;
+ return Value::undefinedValue();
}
-v8::Handle<v8::Value> NamedNodeMap::named(v8::Local<v8::String> property, const v8::AccessorInfo& args)
+Value NamedNodeMap::get(Managed *m, String *name, bool *hasProperty)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r || !r->list) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ NamedNodeMap *r = m->as<NamedNodeMap>();
+ QV4::ExecutionEngine *v4 = m->engine();
+ if (!r)
+ v4->current->throwTypeError();
+
+ name->makeIdentifier();
+ if (name->isEqualTo(v4->id_length))
+ return Value::fromInt32(r->list.count());
- QString str = engine->toString(property);
- for (int ii = 0; ii < r->list->count(); ++ii) {
- if (r->list->at(ii)->name == str) {
- return Node::create(engine, r->list->at(ii));
+ QV8Engine *engine = v4->v8Engine;
+
+ QString str = name->toQString();
+ for (int ii = 0; ii < r->list.count(); ++ii) {
+ if (r->list.at(ii)->name == str) {
+ if (hasProperty)
+ *hasProperty = true;
+ return Node::create(engine, r->list.at(ii));
}
}
- return v8::Undefined();
+ if (hasProperty)
+ *hasProperty = false;
+ return Value::undefinedValue();
}
-v8::Handle<v8::Object> NamedNodeMap::prototype(QV8Engine *engine)
+Value NamedNodeMap::create(QV8Engine *engine, NodeImpl *data, const QList<NodeImpl *> &list)
{
- QQmlXMLHttpRequestData *d = xhrdata(engine);
- if (d->namedNodeMapPrototype.IsEmpty()) {
- v8::Local<v8::ObjectTemplate> ot = v8::ObjectTemplate::New();
- ot->SetAccessor(v8::String::New("length"), length, 0, v8::External::New(engine));
- ot->SetIndexedPropertyHandler(indexed, 0, 0, 0, 0, v8::External::New(engine));
- ot->SetFallbackPropertyHandler(named, 0, 0, 0, 0, v8::External::New(engine));
- d->namedNodeMapPrototype = qPersistentNew<v8::Object>(ot->NewInstance());
- engine->freezeObject(d->namedNodeMapPrototype);
- }
- return d->namedNodeMapPrototype;
-}
+ ExecutionEngine *v4 = QV8Engine::getV4(engine);
-v8::Handle<v8::Value> NamedNodeMap::create(QV8Engine *engine, NodeImpl *data, QList<NodeImpl *> *list)
-{
- QQmlXMLHttpRequestData *d = xhrdata(engine);
- v8::Local<v8::Object> instance = d->newNode();
- instance->SetPrototype(NamedNodeMap::prototype(engine));
- QQmlDOMNodeResource *r = new QQmlDOMNodeResource(engine);
- r->d = data;
- r->list = list;
- if (data) A(data);
- instance->SetExternalResource(r);
- return instance;
+ NamedNodeMap *instance = new (v4->memoryManager) NamedNodeMap(v4, data, list);
+ instance->prototype = v4->objectPrototype;
+ return Value::fromObject(instance);
}
-v8::Handle<v8::Value> NodeList::indexed(uint32_t index, const v8::AccessorInfo& args)
+Value NodeList::getIndexed(Managed *m, uint index, bool *hasProperty)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ QV4::ExecutionEngine *v4 = m->engine();
+ NodeList *r = m->as<NodeList>();
+ if (!r)
+ v4->current->throwTypeError();
+
+ QV8Engine *engine = v4->v8Engine;
if ((int)index < r->d->children.count()) {
+ if (hasProperty)
+ *hasProperty = true;
return Node::create(engine, r->d->children.at(index));
- } else {
- return v8::Undefined();
}
+ if (hasProperty)
+ *hasProperty = false;
+ return Value::undefinedValue();
}
-v8::Handle<v8::Value> NodeList::length(v8::Local<v8::String>, const v8::AccessorInfo& args)
+Value NodeList::get(Managed *m, String *name, bool *hasProperty)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
- Q_UNUSED(engine)
- return v8::Integer::New(r->d->children.count());
-}
+ QV4::ExecutionEngine *v4 = m->engine();
+ NodeList *r = m->as<NodeList>();
+ if (!r)
+ v4->current->throwTypeError();
-v8::Handle<v8::Object> NodeList::prototype(QV8Engine *engine)
-{
- QQmlXMLHttpRequestData *d = xhrdata(engine);
- if (d->nodeListPrototype.IsEmpty()) {
- v8::Local<v8::ObjectTemplate> ot = v8::ObjectTemplate::New();
- ot->SetAccessor(v8::String::New("length"), length, 0, v8::External::New(engine));
- ot->SetIndexedPropertyHandler(indexed, 0, 0, 0, 0, v8::External::New(engine));
- d->nodeListPrototype = qPersistentNew<v8::Object>(ot->NewInstance());
- engine->freezeObject(d->nodeListPrototype);
- }
- return d->nodeListPrototype;
+ name->makeIdentifier();
+
+ if (name->isEqualTo(v4->id_length))
+ return Value::fromInt32(r->d->children.count());
+ return Object::get(m, name, hasProperty);
}
-v8::Handle<v8::Value> NodeList::create(QV8Engine *engine, NodeImpl *data)
+Value NodeList::create(QV8Engine *engine, NodeImpl *data)
{
QQmlXMLHttpRequestData *d = xhrdata(engine);
- v8::Local<v8::Object> instance = d->newNode();
- instance->SetPrototype(NodeList::prototype(engine));
- QQmlDOMNodeResource *r = new QQmlDOMNodeResource(engine);
- r->d = data;
- if (data) A(data);
- instance->SetExternalResource(r);
- return instance;
+ ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ NodeList *instance = new (v4->memoryManager) NodeList(v4, data);
+ instance->prototype = v4->objectPrototype;
+ return Value::fromObject(instance);
}
-v8::Handle<v8::Value> Document::documentElement(v8::Local<v8::String>, const v8::AccessorInfo& args)
+Value Document::documentElement(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r || r->d->type != NodeImpl::Document) return Value::undefinedValue();
+ QV8Engine *engine = ctx->engine->v8Engine;
return Node::create(engine, static_cast<DocumentImpl *>(r->d)->root);
}
-v8::Handle<v8::Value> Document::xmlStandalone(v8::Local<v8::String>, const v8::AccessorInfo& args)
+Value Document::xmlStandalone(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r || r->d->type != NodeImpl::Document) return Value::undefinedValue();
+ QV8Engine *engine = ctx->engine->v8Engine;
Q_UNUSED(engine)
- return v8::Boolean::New(static_cast<DocumentImpl *>(r->d)->isStandalone);
+ return Value::fromBoolean(static_cast<DocumentImpl *>(r->d)->isStandalone);
}
-v8::Handle<v8::Value> Document::xmlVersion(v8::Local<v8::String>, const v8::AccessorInfo& args)
+Value Document::xmlVersion(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r || r->d->type != NodeImpl::Document) return Value::undefinedValue();
+ QV8Engine *engine = ctx->engine->v8Engine;
return engine->toString(static_cast<DocumentImpl *>(r->d)->version);
}
-v8::Handle<v8::Value> Document::xmlEncoding(v8::Local<v8::String>, const v8::AccessorInfo& args)
+Value Document::xmlEncoding(SimpleCallContext *ctx)
{
- QQmlDOMNodeResource *r = v8_resource_cast<QQmlDOMNodeResource>(args.This());
- if (!r || r->d->type != NodeImpl::Document) return v8::Undefined();
- QV8Engine *engine = V8ENGINE();
+ Node *r = ctx->thisObject.as<Node>();
+ if (!r || r->d->type != NodeImpl::Document) return Value::undefinedValue();
+ QV8Engine *engine = ctx->engine->v8Engine;
return engine->toString(static_cast<DocumentImpl *>(r->d)->encoding);
}
-class QQmlXMLHttpRequest : public QObject, public QV8ObjectResource
+class QQmlXMLHttpRequest : public QObject
{
-Q_OBJECT
-V8_RESOURCE_TYPE(XMLHttpRequestType)
+ Q_OBJECT
public:
enum State { Unsent = 0,
Opened = 1, HeadersReceived = 2,
@@ -977,9 +992,9 @@ public:
int replyStatus() const;
QString replyStatusText() const;
- v8::Handle<v8::Value> open(v8::Handle<v8::Object> me, const QString &, const QUrl &);
- v8::Handle<v8::Value> send(v8::Handle<v8::Object> me, const QByteArray &);
- v8::Handle<v8::Value> abort(v8::Handle<v8::Object> me);
+ Value open(const Value &me, const QString &, const QUrl &);
+ Value send(const Value &me, const QByteArray &);
+ Value abort(const Value &me);
void addHeader(const QString &, const QString &);
QString header(const QString &name);
@@ -997,6 +1012,7 @@ private slots:
private:
void requestFromUrl(const QUrl &url);
+ ExecutionEngine *v4;
State m_state;
bool m_errorFlag;
bool m_sendFlag;
@@ -1020,18 +1036,18 @@ private:
#endif
void readEncoding();
- v8::Handle<v8::Object> getMe() const;
- void setMe(v8::Handle<v8::Object> me);
- v8::Persistent<v8::Object> m_me;
+ Value getMe() const;
+ void setMe(const Value &me);
+ PersistentValue m_me;
- void dispatchCallback(v8::Handle<v8::Object> me);
- void printError(v8::Handle<v8::Message>);
+ void dispatchCallback(const Value &me);
+ void printError(const Exception &e);
int m_status;
QString m_statusText;
QNetworkRequest m_request;
QStringList m_addedHeaders;
- QQmlGuard<QNetworkReply> m_network;
+ QPointer<QNetworkReply> m_network;
void destroyNetwork();
QNetworkAccessManager *m_nam;
@@ -1039,8 +1055,9 @@ private:
};
QQmlXMLHttpRequest::QQmlXMLHttpRequest(QV8Engine *engine, QNetworkAccessManager *manager)
-: QV8ObjectResource(engine), m_state(Unsent), m_errorFlag(false), m_sendFlag(false),
- m_redirectCount(0), m_gotXml(false), m_textCodec(0), m_network(0), m_nam(manager)
+ : v4(QV8Engine::getV4(engine))
+ , m_state(Unsent), m_errorFlag(false), m_sendFlag(false)
+ , m_redirectCount(0), m_gotXml(false), m_textCodec(0), m_network(0), m_nam(manager)
{
}
@@ -1074,7 +1091,7 @@ QString QQmlXMLHttpRequest::replyStatusText() const
return m_statusText;
}
-v8::Handle<v8::Value> QQmlXMLHttpRequest::open(v8::Handle<v8::Object> me, const QString &method,
+Value QQmlXMLHttpRequest::open(const Value &me, const QString &method,
const QUrl &url)
{
destroyNetwork();
@@ -1085,10 +1102,8 @@ v8::Handle<v8::Value> QQmlXMLHttpRequest::open(v8::Handle<v8::Object> me, const
m_url = url;
m_state = Opened;
m_addedHeaders.clear();
- v8::TryCatch tc;
dispatchCallback(me);
- if (tc.HasCaught()) printError(tc.Message());
- return v8::Undefined();
+ return Value::undefinedValue();
}
void QQmlXMLHttpRequest::addHeader(const QString &name, const QString &value)
@@ -1202,7 +1217,7 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url)
this, SLOT(finished()));
}
-v8::Handle<v8::Value> QQmlXMLHttpRequest::send(v8::Handle<v8::Object> me, const QByteArray &data)
+Value QQmlXMLHttpRequest::send(const Value &me, const QByteArray &data)
{
m_errorFlag = false;
m_sendFlag = true;
@@ -1213,10 +1228,10 @@ v8::Handle<v8::Value> QQmlXMLHttpRequest::send(v8::Handle<v8::Object> me, const
requestFromUrl(m_url);
- return v8::Undefined();
+ return Value::undefinedValue();
}
-v8::Handle<v8::Value> QQmlXMLHttpRequest::abort(v8::Handle<v8::Object> me)
+Value QQmlXMLHttpRequest::abort(const Value &me)
{
destroyNetwork();
m_responseEntityBody = QByteArray();
@@ -1229,33 +1244,26 @@ v8::Handle<v8::Value> QQmlXMLHttpRequest::abort(v8::Handle<v8::Object> me)
m_state = Done;
m_sendFlag = false;
- v8::TryCatch tc;
dispatchCallback(me);
- if (tc.HasCaught()) printError(tc.Message());
}
m_state = Unsent;
- return v8::Undefined();
+ return Value::undefinedValue();
}
-v8::Handle<v8::Object> QQmlXMLHttpRequest::getMe() const
+Value QQmlXMLHttpRequest::getMe() const
{
- return m_me;
+ return m_me.value();
}
-void QQmlXMLHttpRequest::setMe(v8::Handle<v8::Object> me)
+void QQmlXMLHttpRequest::setMe(const Value &me)
{
- qPersistentDispose(m_me);
-
- if (!me.IsEmpty())
- m_me = qPersistentNew<v8::Object>(me);
+ m_me = me;
}
void QQmlXMLHttpRequest::readyRead()
{
- v8::HandleScope handle_scope;
-
m_status =
m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
m_statusText =
@@ -1265,18 +1273,14 @@ void QQmlXMLHttpRequest::readyRead()
if (m_state < HeadersReceived) {
m_state = HeadersReceived;
fillHeadersList ();
- v8::TryCatch tc;
- dispatchCallback(m_me);
- if (tc.HasCaught()) printError(tc.Message());
+ dispatchCallback(m_me.value());
}
bool wasEmpty = m_responseEntityBody.isEmpty();
m_responseEntityBody.append(m_network->readAll());
if (wasEmpty && !m_responseEntityBody.isEmpty())
m_state = Loading;
- v8::TryCatch tc;
- dispatchCallback(m_me);
- if (tc.HasCaught()) printError(tc.Message());
+ dispatchCallback(m_me.value());
}
static const char *errorToString(QNetworkReply::NetworkError error)
@@ -1293,8 +1297,6 @@ static const char *errorToString(QNetworkReply::NetworkError error)
void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error)
{
- v8::HandleScope handle_scope;
-
m_status =
m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
m_statusText =
@@ -1316,9 +1318,7 @@ void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error)
error == QNetworkReply::ContentReSendError ||
error == QNetworkReply::UnknownContentError) {
m_state = Loading;
- v8::TryCatch tc;
- dispatchCallback(m_me);
- if (tc.HasCaught()) printError(tc.Message());
+ dispatchCallback(m_me.value());
} else {
m_errorFlag = true;
m_responseEntityBody = QByteArray();
@@ -1326,16 +1326,12 @@ void QQmlXMLHttpRequest::error(QNetworkReply::NetworkError error)
m_state = Done;
- v8::TryCatch tc;
- dispatchCallback(m_me);
- if (tc.HasCaught()) printError(tc.Message());
+ dispatchCallback(m_me.value());
}
#define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15
void QQmlXMLHttpRequest::finished()
{
- v8::HandleScope handle_scope;
-
m_redirectCount++;
if (m_redirectCount < XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION) {
QVariant redirect = m_network->attribute(QNetworkRequest::RedirectionTargetAttribute);
@@ -1362,9 +1358,7 @@ void QQmlXMLHttpRequest::finished()
if (m_state < HeadersReceived) {
m_state = HeadersReceived;
fillHeadersList ();
- v8::TryCatch tc;
dispatchCallback(m_me);
- if (tc.HasCaught()) printError(tc.Message());
}
m_responseEntityBody.append(m_network->readAll());
readEncoding();
@@ -1381,17 +1375,13 @@ void QQmlXMLHttpRequest::finished()
destroyNetwork();
if (m_state < Loading) {
m_state = Loading;
- v8::TryCatch tc;
dispatchCallback(m_me);
- if (tc.HasCaught()) printError(tc.Message());
}
m_state = Done;
- v8::TryCatch tc;
dispatchCallback(m_me);
- if (tc.HasCaught()) printError(tc.Message());
- setMe(v8::Handle<v8::Object>());
+ setMe(Value::emptyValue());
}
@@ -1469,55 +1459,48 @@ const QByteArray &QQmlXMLHttpRequest::rawResponseBody() const
return m_responseEntityBody;
}
-// Requires a TryCatch scope
-void QQmlXMLHttpRequest::dispatchCallback(v8::Handle<v8::Object> me)
+void QQmlXMLHttpRequest::dispatchCallback(const Value &me)
{
- v8::HandleScope hs;
- v8::Context::Scope scope(engine->context());
+ ExecutionContext *ctx = v4->current;
+ try {
+ Object *o = me.asObject();
+ if (!o)
+ ctx->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject"));
- if (me.IsEmpty() || me->IsNull()) {
- v8::ThrowException(v8::Exception::Error(v8::String::New("Unable to dispatch QQmlXmlHttpRequest callback: invalid object")));
- return;
- }
+ Object *thisObj = o->get(v4->newString(QStringLiteral("ThisObject"))).asObject();
+ if (!thisObj)
+ ctx->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ThisObject"));
- if (me->Get(v8::String::New("ThisObject")).IsEmpty()) {
- v8::ThrowException(v8::Exception::Error(v8::String::New("QQmlXMLHttpRequest: internal error: empty ThisObject")));
- return;
- }
-
- v8::Local<v8::Object> thisObj = me->Get(v8::String::New("ThisObject"))->ToObject();
- v8::Local<v8::Value> callback = thisObj->Get(v8::String::New("onreadystatechange"));
- if (!callback->IsFunction()) {
- // not an error, but no onreadystatechange function to call.
- return;
- }
-
- if (me->Get(v8::String::New("ActivationObject")).IsEmpty()) {
- v8::ThrowException(v8::Exception::Error(v8::String::New("QQmlXMLHttpRequest: internal error: empty ActivationObject")));
- return;
- }
+ FunctionObject *callback = thisObj->get(v4->newString(QStringLiteral("onreadystatechange"))).asFunctionObject();
+ if (!callback) {
+ // not an error, but no onreadystatechange function to call.
+ return;
+ }
- v8::Local<v8::Object> activationObject = me->Get(v8::String::New("ActivationObject"))->ToObject();
- QQmlContextData *callingContext = engine->contextWrapper()->context(activationObject);
- if (callingContext) {
- v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(callback);
- f->Call(activationObject, 0, 0); // valid activation object.
+ Value activationObject = o->get(v4->newString(QStringLiteral("ActivationObject")));
+ if (!activationObject.asObject())
+ v4->current->throwError(QStringLiteral("QQmlXMLHttpRequest: internal error: empty ActivationObject"));
+
+ QQmlContextData *callingContext = QmlContextWrapper::getContext(activationObject);
+ if (callingContext)
+ callback->call(activationObject, 0, 0);
+
+ // if the callingContext object is no longer valid, then it has been
+ // deleted explicitly (e.g., by a Loader deleting the itemContext when
+ // the source is changed). We do nothing in this case, as the evaluation
+ // cannot succeed.
+ } catch(Exception &e) {
+ e.accept(ctx);
+ printError(e);
}
-
- // if the callingContext object is no longer valid, then it has been
- // deleted explicitly (e.g., by a Loader deleting the itemContext when
- // the source is changed). We do nothing in this case, as the evaluation
- // cannot succeed.
}
// Must have a handle scope
-void QQmlXMLHttpRequest::printError(v8::Handle<v8::Message> message)
+void QQmlXMLHttpRequest::printError(const Exception &e)
{
- v8::Context::Scope scope(engine->context());
-
QQmlError error;
- QQmlExpressionPrivate::exceptionToError(message, error);
- QQmlEnginePrivate::warning(QQmlEnginePrivate::get(engine->engine()), error);
+ QQmlExpressionPrivate::exceptionToError(e, error);
+ QQmlEnginePrivate::warning(QQmlEnginePrivate::get(v4->v8Engine->engine()), error);
}
void QQmlXMLHttpRequest::destroyNetwork()
@@ -1529,43 +1512,161 @@ void QQmlXMLHttpRequest::destroyNetwork()
}
}
+
+struct QQmlXMLHttpRequestWrapper : public Object
+{
+ Q_MANAGED
+ QQmlXMLHttpRequestWrapper(ExecutionEngine *engine, QQmlXMLHttpRequest *request)
+ : Object(engine)
+ , request(request)
+ {
+ vtbl = &static_vtbl;
+ }
+ ~QQmlXMLHttpRequestWrapper() {
+ delete request;
+ }
+
+ static void destroy(Managed *that) {
+ that->as<QQmlXMLHttpRequestWrapper>()->~QQmlXMLHttpRequestWrapper();
+ }
+
+ QQmlXMLHttpRequest *request;
+};
+
+DEFINE_MANAGED_VTABLE(QQmlXMLHttpRequestWrapper);
+
+struct QQmlXMLHttpRequestCtor : public FunctionObject
+{
+ Q_MANAGED
+ QQmlXMLHttpRequestCtor(ExecutionEngine *engine)
+ : FunctionObject(engine->rootContext, engine->newString(QStringLiteral("XMLHttpRequest")))
+ {
+ vtbl = &static_vtbl;
+ defineReadonlyProperty(engine, QStringLiteral("UNSENT"), Value::fromInt32(0));
+ defineReadonlyProperty(engine, QStringLiteral("OPENED"), Value::fromInt32(1));
+ defineReadonlyProperty(engine, QStringLiteral("HEADERS_RECEIVED"), Value::fromInt32(2));
+ defineReadonlyProperty(engine, QStringLiteral("LOADING"), Value::fromInt32(3));
+ defineReadonlyProperty(engine, QStringLiteral("DONE"), Value::fromInt32(4));
+ if (!proto)
+ setupProto();
+ defineDefaultProperty(engine->id_prototype, Value::fromObject(proto));
+ }
+ ~QQmlXMLHttpRequestCtor()
+ {}
+
+ static void destroy(Managed *that) {
+ that->as<QQmlXMLHttpRequestCtor>()->~QQmlXMLHttpRequestCtor();
+ }
+ static void markObjects(Managed *that) {
+ QQmlXMLHttpRequestCtor *c = that->as<QQmlXMLHttpRequestCtor>();
+ if (c->proto)
+ c->proto->mark();
+ }
+ static Value construct(Managed *that, Value *, int)
+ {
+ QQmlXMLHttpRequestCtor *ctor = that->as<QQmlXMLHttpRequestCtor>();
+ if (!ctor)
+ that->engine()->current->throwTypeError();
+
+ QV8Engine *engine = that->engine()->v8Engine;
+ QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(engine, engine->networkAccessManager());
+ QQmlXMLHttpRequestWrapper *w = new (that->engine()->memoryManager) QQmlXMLHttpRequestWrapper(that->engine(), r);
+ w->prototype = ctor->proto;
+ return Value::fromObject(w);
+ }
+
+ static Value call(Managed *, const Value &, Value *, int) {
+ return Value::undefinedValue();
+ }
+
+ void setupProto();
+
+ static Value method_open(SimpleCallContext *ctx);
+ static Value method_setRequestHeader(SimpleCallContext *ctx);
+ static Value method_send(SimpleCallContext *ctx);
+ static Value method_abort(SimpleCallContext *ctx);
+ static Value method_getResponseHeader(SimpleCallContext *ctx);
+ static Value method_getAllResponseHeaders(SimpleCallContext *ctx);
+
+ static Value method_get_readyState(SimpleCallContext *ctx);
+ static Value method_get_status(SimpleCallContext *ctx);
+ static Value method_get_statusText(SimpleCallContext *ctx);
+ static Value method_get_responseText(SimpleCallContext *ctx);
+ static Value method_get_responseXML(SimpleCallContext *ctx);
+
+
+ Object *proto;
+};
+
+DEFINE_MANAGED_VTABLE(QQmlXMLHttpRequestCtor);
+
+void QQmlXMLHttpRequestCtor::setupProto()
+{
+ ExecutionEngine *v4 = engine();
+ proto = v4->newObject();
+
+ // Methods
+ proto->defineDefaultProperty(v4, QStringLiteral("open"), method_open);
+ proto->defineDefaultProperty(v4, QStringLiteral("setRequestHeader"), method_setRequestHeader);
+ proto->defineDefaultProperty(v4, QStringLiteral("send"), method_send);
+ proto->defineDefaultProperty(v4, QStringLiteral("abort"), method_abort);
+ proto->defineDefaultProperty(v4, QStringLiteral("getResponseHeader"), method_getResponseHeader);
+ proto->defineDefaultProperty(v4, QStringLiteral("getAllResponseHeaders"), method_getAllResponseHeaders);
+
+ // Read-only properties
+ proto->defineAccessorProperty(v4, QStringLiteral("readyState"), method_get_readyState, 0);
+ proto->defineAccessorProperty(v4, QStringLiteral("status"),method_get_status, 0);
+ proto->defineAccessorProperty(v4, QStringLiteral("statusText"),method_get_statusText, 0);
+ proto->defineAccessorProperty(v4, QStringLiteral("responseText"),method_get_responseText, 0);
+ proto->defineAccessorProperty(v4, QStringLiteral("responseXML"),method_get_responseXML, 0);
+
+ // State values
+ proto->defineReadonlyProperty(v4, QStringLiteral("UNSENT"), Value::fromInt32(0));
+ proto->defineReadonlyProperty(v4, QStringLiteral("OPENED"), Value::fromInt32(1));
+ proto->defineReadonlyProperty(v4, QStringLiteral("HEADERS_RECEIVED"), Value::fromInt32(2));
+ proto->defineReadonlyProperty(v4, QStringLiteral("LOADING"), Value::fromInt32(3));
+ proto->defineReadonlyProperty(v4, QStringLiteral("DONE"), Value::fromInt32(4));
+}
+
+
// XMLHttpRequest methods
-static v8::Handle<v8::Value> qmlxmlhttprequest_open(const v8::Arguments &args)
+Value QQmlXMLHttpRequestCtor::method_open(SimpleCallContext *ctx)
{
- QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(args.This());
- if (!r)
- V8THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequestWrapper *w = ctx->thisObject.as<QQmlXMLHttpRequestWrapper>();
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->request;
- if (args.Length() < 2 || args.Length() > 5)
- V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+ if (ctx->argumentCount < 2 || ctx->argumentCount > 5)
+ V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
- QV8Engine *engine = r->engine;
+ QV8Engine *engine = ctx->engine->v8Engine;
// Argument 0 - Method
- QString method = engine->toString(args[0]).toUpper();
+ QString method = ctx->arguments[0].toQString().toUpper();
if (method != QLatin1String("GET") &&
method != QLatin1String("PUT") &&
method != QLatin1String("HEAD") &&
method != QLatin1String("POST") &&
method != QLatin1String("DELETE"))
- V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type");
+ V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Unsupported HTTP method type");
// Argument 1 - URL
- QUrl url = QUrl(engine->toString(args[1]));
+ QUrl url = QUrl(ctx->arguments[1].toQString());
if (url.isRelative())
url = engine->callingContext()->resolvedUrl(url);
// Argument 2 - async (optional)
- if (args.Length() > 2 && !args[2]->BooleanValue())
- V8THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported");
+ if (ctx->argumentCount > 2 && !ctx->arguments[2].booleanValue())
+ V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported");
// Argument 3/4 - user/pass (optional)
QString username, password;
- if (args.Length() > 3)
- username = engine->toString(args[3]);
- if (args.Length() > 4)
- password = engine->toString(args[4]);
+ if (ctx->argumentCount > 3)
+ username = ctx->arguments[3].toQString();
+ if (ctx->argumentCount > 4)
+ password = ctx->arguments[4].toQString();
// Clear the fragment (if any)
url.setFragment(QString());
@@ -1574,25 +1675,24 @@ static v8::Handle<v8::Value> qmlxmlhttprequest_open(const v8::Arguments &args)
if (!username.isNull()) url.setUserName(username);
if (!password.isNull()) url.setPassword(password);
- return r->open(constructMeObject(args.This(), engine), method, url);
+ return r->open(constructMeObject(ctx->thisObject, engine), method, url);
}
-static v8::Handle<v8::Value> qmlxmlhttprequest_setRequestHeader(const v8::Arguments &args)
+Value QQmlXMLHttpRequestCtor::method_setRequestHeader(SimpleCallContext *ctx)
{
- QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(args.This());
- if (!r)
- V8THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequestWrapper *w = ctx->thisObject.as<QQmlXMLHttpRequestWrapper>();
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->request;
- if (args.Length() != 2)
- V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+ if (ctx->argumentCount != 2)
+ V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
if (r->readyState() != QQmlXMLHttpRequest::Opened || r->sendFlag())
- V8THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
- QV8Engine *engine = r->engine;
-
- QString name = engine->toString(args[0]);
- QString value = engine->toString(args[1]);
+ QString name = ctx->arguments[0].toQString();
+ QString value = ctx->arguments[1].toQString();
// ### Check that name and value are well formed
@@ -1617,119 +1717,123 @@ static v8::Handle<v8::Value> qmlxmlhttprequest_setRequestHeader(const v8::Argume
nameUpper == QLatin1String("VIA") ||
nameUpper.startsWith(QLatin1String("PROXY-")) ||
nameUpper.startsWith(QLatin1String("SEC-")))
- return v8::Undefined();
+ return Value::undefinedValue();
r->addHeader(name, value);
- return v8::Undefined();
+ return Value::undefinedValue();
}
-static v8::Handle<v8::Value> qmlxmlhttprequest_send(const v8::Arguments &args)
+Value QQmlXMLHttpRequestCtor::method_send(SimpleCallContext *ctx)
{
- QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(args.This());
- if (!r)
- V8THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequestWrapper *w = ctx->thisObject.as<QQmlXMLHttpRequestWrapper>();
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->request;
- QV8Engine *engine = r->engine;
+ QV8Engine *engine = ctx->engine->v8Engine;
if (r->readyState() != QQmlXMLHttpRequest::Opened ||
r->sendFlag())
- V8THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
QByteArray data;
- if (args.Length() > 0)
- data = engine->toString(args[0]).toUtf8();
+ if (ctx->argumentCount > 0)
+ data = ctx->arguments[0].toQString().toUtf8();
- return r->send(constructMeObject(args.This(), engine), data);
+ return r->send(constructMeObject(ctx->thisObject, engine), data);
}
-static v8::Handle<v8::Value> qmlxmlhttprequest_abort(const v8::Arguments &args)
+Value QQmlXMLHttpRequestCtor::method_abort(SimpleCallContext *ctx)
{
- QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(args.This());
- if (!r)
- V8THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequestWrapper *w = ctx->thisObject.as<QQmlXMLHttpRequestWrapper>();
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->request;
- return r->abort(constructMeObject(args.This(), r->engine));
+ return r->abort(constructMeObject(ctx->thisObject, ctx->engine->v8Engine));
}
-static v8::Handle<v8::Value> qmlxmlhttprequest_getResponseHeader(const v8::Arguments &args)
+Value QQmlXMLHttpRequestCtor::method_getResponseHeader(SimpleCallContext *ctx)
{
- QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(args.This());
- if (!r)
- V8THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequestWrapper *w = ctx->thisObject.as<QQmlXMLHttpRequestWrapper>();
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->request;
- QV8Engine *engine = r->engine;
+ QV8Engine *engine = ctx->engine->v8Engine;
- if (args.Length() != 1)
- V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+ if (ctx->argumentCount != 1)
+ V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
if (r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done &&
r->readyState() != QQmlXMLHttpRequest::HeadersReceived)
- V8THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
- return engine->toString(r->header(engine->toString(args[0])));
+ return engine->toString(r->header(ctx->arguments[0].toQString()));
}
-static v8::Handle<v8::Value> qmlxmlhttprequest_getAllResponseHeaders(const v8::Arguments &args)
+Value QQmlXMLHttpRequestCtor::method_getAllResponseHeaders(SimpleCallContext *ctx)
{
- QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(args.This());
- if (!r)
- V8THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequestWrapper *w = ctx->thisObject.as<QQmlXMLHttpRequestWrapper>();
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->request;
- QV8Engine *engine = r->engine;
+ QV8Engine *engine = ctx->engine->v8Engine;
- if (args.Length() != 0)
- V8THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
+ if (ctx->argumentCount != 0)
+ V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "Incorrect argument count");
if (r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done &&
r->readyState() != QQmlXMLHttpRequest::HeadersReceived)
- V8THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
return engine->toString(r->headers());
}
// XMLHttpRequest properties
-static v8::Handle<v8::Value> qmlxmlhttprequest_readyState(v8::Local<v8::String> /* property */,
- const v8::AccessorInfo& info)
+Value QQmlXMLHttpRequestCtor::method_get_readyState(SimpleCallContext *ctx)
{
- QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(info.This());
- if (!r)
- V8THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequestWrapper *w = ctx->thisObject.as<QQmlXMLHttpRequestWrapper>();
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->request;
- return v8::Integer::NewFromUnsigned(r->readyState());
+ return Value::fromUInt32(r->readyState());
}
-static v8::Handle<v8::Value> qmlxmlhttprequest_status(v8::Local<v8::String> /* property */,
- const v8::AccessorInfo& info)
+Value QQmlXMLHttpRequestCtor::method_get_status(SimpleCallContext *ctx)
{
- QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(info.This());
- if (!r)
- V8THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequestWrapper *w = ctx->thisObject.as<QQmlXMLHttpRequestWrapper>();
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->request;
if (r->readyState() == QQmlXMLHttpRequest::Unsent ||
r->readyState() == QQmlXMLHttpRequest::Opened)
- V8THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
if (r->errorFlag())
- return v8::Integer::New(0);
+ return Value::fromInt32(0);
else
- return v8::Integer::New(r->replyStatus());
+ return Value::fromInt32(r->replyStatus());
}
-static v8::Handle<v8::Value> qmlxmlhttprequest_statusText(v8::Local<v8::String> /* property */,
- const v8::AccessorInfo& info)
+Value QQmlXMLHttpRequestCtor::method_get_statusText(SimpleCallContext *ctx)
{
- QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(info.This());
- if (!r)
- V8THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequestWrapper *w = ctx->thisObject.as<QQmlXMLHttpRequestWrapper>();
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->request;
- QV8Engine *engine = r->engine;
+ QV8Engine *engine = ctx->engine->v8Engine;
if (r->readyState() == QQmlXMLHttpRequest::Unsent ||
r->readyState() == QQmlXMLHttpRequest::Opened)
- V8THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
+ V4THROW_DOM(DOMEXCEPTION_INVALID_STATE_ERR, "Invalid state");
if (r->errorFlag())
return engine->toString(QString());
@@ -1737,14 +1841,14 @@ static v8::Handle<v8::Value> qmlxmlhttprequest_statusText(v8::Local<v8::String>
return engine->toString(r->replyStatusText());
}
-static v8::Handle<v8::Value> qmlxmlhttprequest_responseText(v8::Local<v8::String> /* property */,
- const v8::AccessorInfo& info)
+Value QQmlXMLHttpRequestCtor::method_get_responseText(SimpleCallContext *ctx)
{
- QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(info.This());
- if (!r)
- V8THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequestWrapper *w = ctx->thisObject.as<QQmlXMLHttpRequestWrapper>();
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->request;
- QV8Engine *engine = r->engine;
+ QV8Engine *engine = ctx->engine->v8Engine;
if (r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done)
@@ -1753,39 +1857,22 @@ static v8::Handle<v8::Value> qmlxmlhttprequest_responseText(v8::Local<v8::String
return engine->toString(r->responseBody());
}
-static v8::Handle<v8::Value> qmlxmlhttprequest_responseXML(v8::Local<v8::String> /* property */,
- const v8::AccessorInfo& info)
+Value QQmlXMLHttpRequestCtor::method_get_responseXML(SimpleCallContext *ctx)
{
- QQmlXMLHttpRequest *r = v8_resource_cast<QQmlXMLHttpRequest>(info.This());
- if (!r)
- V8THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequestWrapper *w = ctx->thisObject.as<QQmlXMLHttpRequestWrapper>();
+ if (!w)
+ V4THROW_REFERENCE("Not an XMLHttpRequest object");
+ QQmlXMLHttpRequest *r = w->request;
if (!r->receivedXml() ||
(r->readyState() != QQmlXMLHttpRequest::Loading &&
r->readyState() != QQmlXMLHttpRequest::Done)) {
- return v8::Null();
- } else {
- return Document::load(r->engine, r->rawResponseBody());
- }
-}
-
-static v8::Handle<v8::Value> qmlxmlhttprequest_new(const v8::Arguments &args)
-{
- if (args.IsConstructCall()) {
- QV8Engine *engine = V8ENGINE();
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->engine());
- Q_UNUSED(ep)
- QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(engine, engine->networkAccessManager());
- args.This()->SetExternalResource(r);
-
- return args.This();
+ return Value::nullValue();
} else {
- return v8::Undefined();
+ return Document::load(ctx->engine->v8Engine, r->rawResponseBody());
}
}
-#define NEWFUNCTION(function) v8::FunctionTemplate::New(function)->GetFunction()
-
void qt_rem_qmlxmlhttprequest(QV8Engine * /* engine */, void *d)
{
QQmlXMLHttpRequestData *data = (QQmlXMLHttpRequestData *)d;
@@ -1794,42 +1881,10 @@ void qt_rem_qmlxmlhttprequest(QV8Engine * /* engine */, void *d)
void *qt_add_qmlxmlhttprequest(QV8Engine *engine)
{
- v8::PropertyAttribute attributes = (v8::PropertyAttribute)(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
+ ExecutionEngine *v4 = QV8Engine::getV4(engine);
- // XMLHttpRequest
- v8::Local<v8::FunctionTemplate> xmlhttprequest = v8::FunctionTemplate::New(qmlxmlhttprequest_new,
- v8::External::New(engine));
- xmlhttprequest->InstanceTemplate()->SetHasExternalResource(true);
-
- // Methods
- xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("open"), NEWFUNCTION(qmlxmlhttprequest_open), attributes);
- xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("setRequestHeader"), NEWFUNCTION(qmlxmlhttprequest_setRequestHeader), attributes);
- xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("send"), NEWFUNCTION(qmlxmlhttprequest_send), attributes);
- xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("abort"), NEWFUNCTION(qmlxmlhttprequest_abort), attributes);
- xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("getResponseHeader"), NEWFUNCTION(qmlxmlhttprequest_getResponseHeader), attributes);
- xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("getAllResponseHeaders"), NEWFUNCTION(qmlxmlhttprequest_getAllResponseHeaders), attributes);
-
- // Read-only properties
- xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("readyState"), qmlxmlhttprequest_readyState, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
- xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("status"),qmlxmlhttprequest_status, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
- xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("statusText"),qmlxmlhttprequest_statusText, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
- xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("responseText"),qmlxmlhttprequest_responseText, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
- xmlhttprequest->PrototypeTemplate()->SetAccessor(v8::String::New("responseXML"),qmlxmlhttprequest_responseXML, 0, v8::Handle<v8::Value>(), v8::DEFAULT, attributes);
-
- // State values
- xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("UNSENT"), v8::Integer::New(0), attributes);
- xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("OPENED"), v8::Integer::New(1), attributes);
- xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("HEADERS_RECEIVED"), v8::Integer::New(2), attributes);
- xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("LOADING"), v8::Integer::New(3), attributes);
- xmlhttprequest->PrototypeTemplate()->Set(v8::String::New("DONE"), v8::Integer::New(4), attributes);
-
- // Constructor
- xmlhttprequest->Set(v8::String::New("UNSENT"), v8::Integer::New(0), attributes);
- xmlhttprequest->Set(v8::String::New("OPENED"), v8::Integer::New(1), attributes);
- xmlhttprequest->Set(v8::String::New("HEADERS_RECEIVED"), v8::Integer::New(2), attributes);
- xmlhttprequest->Set(v8::String::New("LOADING"), v8::Integer::New(3), attributes);
- xmlhttprequest->Set(v8::String::New("DONE"), v8::Integer::New(4), attributes);
- engine->global()->Set(v8::String::New("XMLHttpRequest"), xmlhttprequest->GetFunction());
+ QQmlXMLHttpRequestCtor *ctor = new (v4->memoryManager) QQmlXMLHttpRequestCtor(v4);
+ v4->globalObject->defineReadonlyProperty(v4->newString(QStringLiteral("XMLHttpRequest")), Value::fromObject(ctor));
QQmlXMLHttpRequestData *data = new QQmlXMLHttpRequestData;
return data;
diff --git a/src/qml/qml/v4/llvm_installation.pri b/src/qml/qml/v4/llvm_installation.pri
new file mode 100644
index 0000000000..99e955fd2b
--- /dev/null
+++ b/src/qml/qml/v4/llvm_installation.pri
@@ -0,0 +1,23 @@
+LLVM_CONFIG=llvm-config
+# Pick up the qmake variable or environment variable for LLVM_INSTALL_DIR. If either was set, change the LLVM_CONFIG to use that.
+isEmpty(LLVM_INSTALL_DIR):LLVM_INSTALL_DIR=$$(LLVM_INSTALL_DIR)
+!isEmpty(LLVM_INSTALL_DIR):LLVM_CONFIG=$$LLVM_INSTALL_DIR/bin/llvm-config
+exists ($${LLVM_CONFIG}) {
+ CONFIG += llvm-libs
+ message("Found LLVM in $$LLVM_INSTALL_DIR")
+}
+
+llvm-libs {
+ win32 {
+ LLVM_INCLUDEPATH = $$LLVM_INSTALL_DIR/include
+# TODO: check if the next line is needed somehow for the llvm_runtime target.
+ LLVM_LIBS += -ladvapi32 -lshell32
+ }
+
+ unix {
+ LLVM_INCLUDEPATH = $$system($$LLVM_CONFIG --includedir)
+ LLVM_LIBDIR = $$system($$LLVM_CONFIG --libdir)
+ }
+
+ LLVM_DEFINES += __STDC_LIMIT_MACROS __STDC_CONSTANT_MACROS
+}
diff --git a/src/qml/qml/v4/llvm_runtime.cpp b/src/qml/qml/v4/llvm_runtime.cpp
new file mode 100644
index 0000000000..0498bab44f
--- /dev/null
+++ b/src/qml/qml/v4/llvm_runtime.cpp
@@ -0,0 +1,513 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4runtime_p.h"
+#include "qv4context_p.h"
+#include "qv4engine_p.h"
+#include <stdio.h>
+#include <setjmp.h>
+
+using namespace QV4;
+
+extern "C" {
+
+Value __qmljs_llvm_return(ExecutionContext */*ctx*/, Value *result)
+{
+ return *result;
+}
+
+Value *__qmljs_llvm_get_argument(ExecutionContext *ctx, int index)
+{
+ assert(ctx->type == ExecutionContext::Type_CallContext);
+ return &static_cast<CallContext *>(ctx)->arguments[index];
+}
+
+void __qmljs_llvm_init_undefined(Value *result)
+{
+ *result = Value::undefinedValue();
+}
+
+void __qmljs_llvm_init_null(Value *result)
+{
+ *result = Value::nullValue();
+}
+
+void __qmljs_llvm_init_boolean(Value *result, bool value)
+{
+ *result = Value::fromBoolean(value);
+}
+
+void __qmljs_llvm_init_number(Value *result, double value)
+{
+ *result = Value::fromDouble(value);
+}
+
+void __qmljs_llvm_init_string(ExecutionContext *ctx, Value *result, const char *str)
+{
+ *result = Value::fromString(ctx->engine->newString(QString::fromUtf8(str)));
+}
+
+void __qmljs_llvm_init_closure(ExecutionContext *ctx, Value *result,
+ String *name, bool hasDirectEval,
+ bool usesArgumentsObject, bool isStrict,
+ bool hasNestedFunctions,
+ String **formals, unsigned formalCount,
+ String **locals, unsigned localCount)
+{
+ Function *clos = __qmljs_register_function(ctx, name, hasDirectEval,
+ usesArgumentsObject, isStrict,
+ hasNestedFunctions,
+ formals, formalCount,
+ locals, localCount);
+ __qmljs_init_closure(ctx, result, clos);
+}
+
+bool __qmljs_llvm_to_boolean(ExecutionContext *ctx, const Value *value)
+{
+ return __qmljs_to_boolean(*value);
+}
+
+void __qmljs_llvm_bit_and(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_bit_and(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_bit_or(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_bit_or(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_bit_xor(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_bit_xor(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_add(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_add(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_sub(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_sub(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_mul(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_mul(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_div(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_div(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_mod(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_mod(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_shl(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_shl(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_shr(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_shr(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_ushr(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_ushr(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_gt(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_gt(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_lt(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_lt(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_ge(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_ge(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_le(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_le(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_eq(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_eq(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_ne(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_ne(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_se(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_se(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_sne(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_sne(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_instanceof(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_instanceof(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_in(ExecutionContext *ctx, Value *result, Value *left, Value *right)
+{
+ __qmljs_in(ctx, result, *left, *right);
+}
+
+void __qmljs_llvm_uplus(ExecutionContext *ctx, Value *result, const Value *value)
+{
+ __qmljs_uplus(result, *value);
+}
+
+void __qmljs_llvm_uminus(ExecutionContext *ctx, Value *result, const Value *value)
+{
+ __qmljs_uminus(result, *value);
+}
+
+void __qmljs_llvm_compl(ExecutionContext *ctx, Value *result, const Value *value)
+{
+ __qmljs_compl(result, *value);
+}
+
+void __qmljs_llvm_not(ExecutionContext *ctx, Value *result, const Value *value)
+{
+ __qmljs_not(result, *value);
+}
+
+void __qmljs_llvm_inplace_bit_and_name(ExecutionContext *ctx, String *dest, Value *src)
+{
+ __qmljs_inplace_bit_and_name(ctx, dest, *src);
+}
+
+void __qmljs_llvm_inplace_bit_or_name(ExecutionContext *ctx, String *dest, Value *src)
+{
+ __qmljs_inplace_bit_or_name(ctx, dest, *src);
+}
+
+void __qmljs_llvm_inplace_bit_xor_name(ExecutionContext *ctx, String *dest, Value *src)
+{
+ __qmljs_inplace_bit_xor_name(ctx, dest, *src);
+}
+
+void __qmljs_llvm_inplace_add_name(ExecutionContext *ctx, String *dest, Value *src)
+{
+ __qmljs_inplace_add_name(ctx, dest, *src);
+}
+
+void __qmljs_llvm_inplace_sub_name(ExecutionContext *ctx, String *dest, Value *src)
+{
+ __qmljs_inplace_sub_name(ctx, dest, *src);
+}
+
+void __qmljs_llvm_inplace_mul_name(ExecutionContext *ctx, String *dest, Value *src)
+{
+ __qmljs_inplace_mul_name(ctx, dest, *src);
+}
+
+void __qmljs_llvm_inplace_div_name(ExecutionContext *ctx, String *dest, Value *src)
+{
+ __qmljs_inplace_div_name(ctx, dest, *src);
+}
+
+void __qmljs_llvm_inplace_mod_name(ExecutionContext *ctx, String *dest, Value *src)
+{
+ __qmljs_inplace_mod_name(ctx, dest, *src);
+}
+
+void __qmljs_llvm_inplace_shl_name(ExecutionContext *ctx, String *dest, Value *src)
+{
+ __qmljs_inplace_shl_name(ctx, dest, *src);
+}
+
+void __qmljs_llvm_inplace_shr_name(ExecutionContext *ctx, String *dest, Value *src)
+{
+ __qmljs_inplace_shr_name(ctx, dest, *src);
+}
+
+void __qmljs_llvm_inplace_ushr_name(ExecutionContext *ctx, String *dest, Value *src)
+{
+ __qmljs_inplace_ushr_name(ctx, dest, *src);
+}
+
+void __qmljs_llvm_inplace_bit_and_element(ExecutionContext *ctx, Value *base, Value *index, Value *value)
+{
+ __qmljs_inplace_bit_and_element(ctx, *base, *index, *value);
+}
+
+void __qmljs_llvm_inplace_bit_or_element(ExecutionContext *ctx, Value *base, Value *index, Value *value)
+{
+ __qmljs_inplace_bit_or_element(ctx, *base, *index, *value);
+}
+
+void __qmljs_llvm_inplace_bit_xor_element(ExecutionContext *ctx, Value *base, Value *index, Value *value)
+{
+ __qmljs_inplace_bit_xor_element(ctx, *base, *index, *value);
+}
+
+void __qmljs_llvm_inplace_add_element(ExecutionContext *ctx, Value *base, Value *index, Value *value)
+{
+ __qmljs_inplace_add_element(ctx, *base, *index, *value);
+}
+
+void __qmljs_llvm_inplace_sub_element(ExecutionContext *ctx, Value *base, Value *index, Value *value)
+{
+ __qmljs_inplace_sub_element(ctx, *base, *index, *value);
+}
+
+void __qmljs_llvm_inplace_mul_element(ExecutionContext *ctx, Value *base, Value *index, Value *value)
+{
+ __qmljs_inplace_mul_element(ctx, *base, *index, *value);
+}
+
+void __qmljs_llvm_inplace_div_element(ExecutionContext *ctx, Value *base, Value *index, Value *value)
+{
+ __qmljs_inplace_div_element(ctx, *base, *index, *value);
+}
+
+void __qmljs_llvm_inplace_mod_element(ExecutionContext *ctx, Value *base, Value *index, Value *value)
+{
+ __qmljs_inplace_mod_element(ctx, *base, *index, *value);
+}
+
+void __qmljs_llvm_inplace_shl_element(ExecutionContext *ctx, Value *base, Value *index, Value *value)
+{
+ __qmljs_inplace_shl_element(ctx, *base, *index, *value);
+}
+
+void __qmljs_llvm_inplace_shr_element(ExecutionContext *ctx, Value *base, Value *index, Value *value)
+{
+ __qmljs_inplace_shr_element(ctx, *base, *index, *value);
+}
+
+void __qmljs_llvm_inplace_ushr_element(ExecutionContext *ctx, Value *base, Value *index, Value *value)
+{
+ __qmljs_inplace_ushr_element(ctx, *base, *index, *value);
+}
+
+void __qmljs_llvm_inplace_bit_and_member(ExecutionContext *ctx, Value *value, Value *base, String *member)
+{
+ __qmljs_inplace_bit_and_member(ctx, *base, member, *value);
+}
+
+void __qmljs_llvm_inplace_bit_or_member(ExecutionContext *ctx, Value *value, Value *base, String *member)
+{
+ __qmljs_inplace_bit_or_member(ctx, *base, member, *value);
+}
+
+void __qmljs_llvm_inplace_bit_xor_member(ExecutionContext *ctx, Value *value, Value *base, String *member)
+{
+ __qmljs_inplace_bit_xor_member(ctx, *base, member, *value);
+}
+
+void __qmljs_llvm_inplace_add_member(ExecutionContext *ctx, Value *value, Value *base, String *member)
+{
+ __qmljs_inplace_add_member(ctx, *base, member, *value);
+}
+
+void __qmljs_llvm_inplace_sub_member(ExecutionContext *ctx, Value *value, Value *base, String *member)
+{
+ __qmljs_inplace_sub_member(ctx, *base, member, *value);
+}
+
+void __qmljs_llvm_inplace_mul_member(ExecutionContext *ctx, Value *value, Value *base, String *member)
+{
+ __qmljs_inplace_mul_member(ctx, *base, member, *value);
+}
+
+void __qmljs_llvm_inplace_div_member(ExecutionContext *ctx, Value *value, Value *base, String *member)
+{
+ __qmljs_inplace_div_member(ctx, *base, member, *value);
+}
+
+void __qmljs_llvm_inplace_mod_member(ExecutionContext *ctx, Value *value, Value *base, String *member)
+{
+ __qmljs_inplace_mod_member(ctx, *base, member, *value);
+}
+
+void __qmljs_llvm_inplace_shl_member(ExecutionContext *ctx, Value *value, Value *base, String *member)
+{
+ __qmljs_inplace_shl_member(ctx, *base, member, *value);
+}
+
+void __qmljs_llvm_inplace_shr_member(ExecutionContext *ctx, Value *value, Value *base, String *member)
+{
+ __qmljs_inplace_shr_member(ctx, *base, member, *value);
+}
+
+void __qmljs_llvm_inplace_ushr_member(ExecutionContext *ctx, Value *value, Value *base, String *member)
+{
+ __qmljs_inplace_ushr_member(ctx, *base, member, *value);
+}
+
+String *__qmljs_llvm_identifier_from_utf8(ExecutionContext *ctx, const char *str)
+{
+ return ctx->engine->newIdentifier(QString::fromUtf8(str));
+}
+
+void __qmljs_llvm_call_activation_property(ExecutionContext *context, Value *result, String *name, Value *args, int argc)
+{
+ __qmljs_call_activation_property(context, result, name, args, argc);
+}
+
+void __qmljs_llvm_call_value(ExecutionContext *context, Value *result, const Value *thisObject, const Value *func, Value *args, int argc)
+{
+ __qmljs_call_value(context, result, thisObject, *func, args, argc);
+}
+
+void __qmljs_llvm_construct_activation_property(ExecutionContext *context, Value *result, String *name, Value *args, int argc)
+{
+ __qmljs_construct_activation_property(context, result, name, args, argc);
+}
+
+void __qmljs_llvm_construct_value(ExecutionContext *context, Value *result, const Value *func, Value *args, int argc)
+{
+ __qmljs_construct_value(context, result, *func, args, argc);
+}
+
+void __qmljs_llvm_get_activation_property(ExecutionContext *ctx, Value *result, String *name)
+{
+ __qmljs_get_activation_property(ctx, result, name);
+}
+
+void __qmljs_llvm_set_activation_property(ExecutionContext *ctx, String *name, Value *value)
+{
+ __qmljs_set_activation_property(ctx, name, *value);
+}
+
+void __qmljs_llvm_get_property(ExecutionContext *ctx, Value *result, Value *object, String *name)
+{
+ __qmljs_get_property(ctx, result, *object, name);
+}
+
+void __qmljs_llvm_call_property(ExecutionContext *context, Value *result, const Value *base, String *name, Value *args, int argc)
+{
+ __qmljs_call_property(context, result, *base, name, args, argc);
+}
+
+void __qmljs_llvm_construct_property(ExecutionContext *context, Value *result, const Value *base, String *name, Value *args, int argc)
+{
+ __qmljs_construct_property(context, result, *base, name, args, argc);
+}
+
+void __qmljs_llvm_get_element(ExecutionContext *ctx, Value *result, Value *object, Value *index)
+{
+ __qmljs_get_element(ctx, result, *object, *index);
+}
+
+void __qmljs_llvm_set_element(ExecutionContext *ctx, Value *object, Value *index, Value *value)
+{
+ __qmljs_set_element(ctx, *object, *index, *value);
+}
+
+void __qmljs_llvm_set_property(ExecutionContext *ctx, Value *object, String *name, Value *value)
+{
+ __qmljs_set_property(ctx, *object, name, *value);
+}
+
+void __qmljs_llvm_builtin_declare_var(ExecutionContext *ctx, bool deletable, String *name)
+{
+ __qmljs_builtin_declare_var(ctx, deletable, name);
+}
+
+void __qmljs_llvm_typeof(ExecutionContext *ctx, Value *result, const Value *value)
+{
+ __qmljs_builtin_typeof(ctx, result, *value);
+}
+
+void __qmljs_llvm_throw(ExecutionContext *context, Value *value)
+{
+ __qmljs_throw(context, *value);
+}
+
+void __qmljs_llvm_delete_exception_handler(ExecutionContext *context)
+{
+ // ### FIXME.
+}
+
+void __qmljs_llvm_foreach_iterator_object(ExecutionContext *context, Value *result, Value *in)
+{
+ __qmljs_foreach_iterator_object(context, result, *in);
+}
+
+void __qmljs_llvm_foreach_next_property_name(Value *result, Value *it)
+{
+ __qmljs_foreach_next_property_name(result, *it);
+}
+
+void __qmljs_llvm_get_this_object(ExecutionContext *ctx, Value *result)
+{
+ *result = ctx->thisObject;
+}
+
+void __qmljs_llvm_delete_subscript(ExecutionContext *ctx, Value *result, Value *base, Value *index)
+{
+ __qmljs_delete_subscript(ctx, result, *base, *index);
+}
+
+void __qmljs_llvm_delete_member(ExecutionContext *ctx, Value *result, Value *base, String *name)
+{
+ __qmljs_delete_member(ctx, result, *base, name);
+}
+
+void __qmljs_llvm_delete_name(ExecutionContext *ctx, Value *result, String *name)
+{
+ __qmljs_delete_name(ctx, result, name);
+}
+
+} // extern "C"
diff --git a/src/qml/qml/v4/moth/moth.pri b/src/qml/qml/v4/moth/moth.pri
new file mode 100644
index 0000000000..73bd893286
--- /dev/null
+++ b/src/qml/qml/v4/moth/moth.pri
@@ -0,0 +1,13 @@
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/qv4isel_moth_p.h \
+ $$PWD/qv4instr_moth_p.h \
+ $$PWD/qv4vme_moth_p.h
+
+SOURCES += \
+ $$PWD/qv4isel_moth.cpp \
+ $$PWD/qv4instr_moth.cpp \
+ $$PWD/qv4vme_moth.cpp
+
+#DEFINES += DO_TRACE_INSTR
diff --git a/src/qml/qml/v8/qscript_impl_p.h b/src/qml/qml/v4/moth/qv4instr_moth.cpp
index 41791189a7..ec68ede72d 100644
--- a/src/qml/qml/v8/qscript_impl_p.h
+++ b/src/qml/qml/v4/moth/qv4instr_moth.cpp
@@ -39,23 +39,18 @@
**
****************************************************************************/
-//
-// 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 "qv4instr_moth_p.h"
-#ifndef QSCRIPT_IMPL_P_H
-#define QSCRIPT_IMPL_P_H
+using namespace QQmlJS;
+using namespace QQmlJS::Moth;
-#include "qv8engine_impl_p.h"
-#include "qjsvalue_impl_p.h"
-#include "qjsvalueiterator_impl_p.h"
-#include "qjsconverter_impl_p.h"
+int Instr::size(Type type)
+{
+#define MOTH_RETURN_INSTR_SIZE(I, FMT) case I: return InstrMeta<(int)I>::Size;
+ switch (type) {
+ FOR_EACH_MOTH_INSTR(MOTH_RETURN_INSTR_SIZE)
+ default: return 0;
+ }
+#undef MOTH_RETURN_INSTR_SIZE
+}
-#endif //QSCRIPT_IMPL_P_H
diff --git a/src/qml/qml/v4/moth/qv4instr_moth_p.h b/src/qml/qml/v4/moth/qv4instr_moth_p.h
new file mode 100644
index 0000000000..7397a1811d
--- /dev/null
+++ b/src/qml/qml/v4/moth/qv4instr_moth_p.h
@@ -0,0 +1,612 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4INSTR_MOTH_P_H
+#define QV4INSTR_MOTH_P_H
+
+#include <QtCore/qglobal.h>
+#include <private/qv4object_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#define FOR_EACH_MOTH_INSTR(F) \
+ F(Ret, ret) \
+ F(LoadValue, loadValue) \
+ F(LoadClosure, loadClosure) \
+ F(MoveTemp, moveTemp) \
+ F(LoadName, loadName) \
+ F(StoreName, storeName) \
+ F(LoadElement, loadElement) \
+ F(StoreElement, storeElement) \
+ F(LoadProperty, loadProperty) \
+ F(StoreProperty, storeProperty) \
+ F(Push, push) \
+ F(EnterTry, enterTry) \
+ F(CallValue, callValue) \
+ F(CallProperty, callProperty) \
+ F(CallElement, callElement) \
+ F(CallActivationProperty, callActivationProperty) \
+ F(CallBuiltinThrow, callBuiltinThrow) \
+ F(CallBuiltinFinishTry, callBuiltinFinishTry) \
+ F(CallBuiltinPushScope, callBuiltinPushScope) \
+ F(CallBuiltinPopScope, callBuiltinPopScope) \
+ F(CallBuiltinForeachIteratorObject, callBuiltinForeachIteratorObject) \
+ F(CallBuiltinForeachNextPropertyName, callBuiltinForeachNextPropertyName) \
+ F(CallBuiltinDeleteMember, callBuiltinDeleteMember) \
+ F(CallBuiltinDeleteSubscript, callBuiltinDeleteSubscript) \
+ F(CallBuiltinDeleteName, callBuiltinDeleteName) \
+ F(CallBuiltinTypeofMember, callBuiltinTypeofMember) \
+ F(CallBuiltinTypeofSubscript, callBuiltinTypeofSubscript) \
+ F(CallBuiltinTypeofName, callBuiltinTypeofName) \
+ F(CallBuiltinTypeofValue, callBuiltinTypeofValue) \
+ F(CallBuiltinPostIncMember, callBuiltinPostIncMember) \
+ F(CallBuiltinPostIncSubscript, callBuiltinPostIncSubscript) \
+ F(CallBuiltinPostIncName, callBuiltinPostIncName) \
+ F(CallBuiltinPostIncValue, callBuiltinPostIncValue) \
+ F(CallBuiltinPostDecMember, callBuiltinPostDecMember) \
+ F(CallBuiltinPostDecSubscript, callBuiltinPostDecSubscript) \
+ F(CallBuiltinPostDecName, callBuiltinPostDecName) \
+ F(CallBuiltinPostDecValue, callBuiltinPostDecValue) \
+ F(CallBuiltinDeclareVar, callBuiltinDeclareVar) \
+ F(CallBuiltinDefineGetterSetter, callBuiltinDefineGetterSetter) \
+ F(CallBuiltinDefineProperty, callBuiltinDefineProperty) \
+ F(CallBuiltinDefineArray, callBuiltinDefineArray) \
+ F(CallBuiltinDefineObjectLiteral, callBuiltinDefineObjectLiteral) \
+ F(CreateValue, createValue) \
+ F(CreateProperty, createProperty) \
+ F(CreateActivationProperty, createActivationProperty) \
+ F(Jump, jump) \
+ F(CJump, cjump) \
+ F(Unop, unop) \
+ F(Binop, binop) \
+ F(AddNumberParams, addNumberParams) \
+ F(MulNumberParams, mulNumberParams) \
+ F(SubNumberParams, subNumberParams) \
+ F(LoadThis, loadThis) \
+ F(InplaceElementOp, inplaceElementOp) \
+ F(InplaceMemberOp, inplaceMemberOp) \
+ F(InplaceNameOp, inplaceNameOp)
+
+#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
+# define MOTH_THREADED_INTERPRETER
+#endif
+
+#define MOTH_INSTR_ALIGN_MASK (Q_ALIGNOF(QQmlJS::Moth::Instr) - 1)
+
+#ifdef MOTH_THREADED_INTERPRETER
+# define MOTH_INSTR_HEADER void *code; \
+ unsigned int breakPoint : 1;
+#else
+# define MOTH_INSTR_HEADER quint8 instructionType; \
+ unsigned int breakPoint : 1;
+#endif
+
+#define MOTH_INSTR_ENUM(I, FMT) I,
+#define MOTH_INSTR_SIZE(I, FMT) ((sizeof(QQmlJS::Moth::Instr::instr_##FMT) + MOTH_INSTR_ALIGN_MASK) & ~MOTH_INSTR_ALIGN_MASK)
+
+
+namespace QQmlJS {
+namespace Moth {
+
+union Instr
+{
+ struct Param {
+ enum {
+ ValueType = 0,
+ ArgumentType = 1,
+ LocalType = 2,
+ TempType = 3,
+ ScopedLocalType = 4
+ };
+ QV4::Value value;
+ unsigned type : 3;
+ unsigned scope : 29;
+ unsigned index;
+
+ bool isValue() const { return type == ValueType; }
+ bool isArgument() const { return type == ArgumentType; }
+ bool isLocal() const { return type == LocalType; }
+ bool isTemp() const { return type == TempType; }
+ bool isScopedLocal() const { return type == ScopedLocalType; }
+
+ static Param createValue(const QV4::Value &v)
+ {
+ Param p;
+ p.type = ValueType;
+ p.scope = 0;
+ p.value = v;
+ return p;
+ }
+
+ static Param createArgument(unsigned idx, uint scope)
+ {
+ Param p;
+ p.type = ArgumentType;
+ p.scope = scope;
+ p.index = idx;
+ return p;
+ }
+
+ static Param createLocal(unsigned idx)
+ {
+ Param p;
+ p.type = LocalType;
+ p.scope = 0;
+ p.index = idx;
+ return p;
+ }
+
+ static Param createTemp(unsigned idx)
+ {
+ Param p;
+ p.type = TempType;
+ p.scope = 0;
+ p.index = idx;
+ return p;
+ }
+
+ static Param createScopedLocal(unsigned idx, uint scope)
+ {
+ Param p;
+ p.type = ScopedLocalType;
+ p.scope = scope;
+ p.index = idx;
+ return p;
+ }
+
+ inline bool operator==(const Param &other) const
+ { return type == other.type && scope == other.scope && index == other.index; }
+
+ inline bool operator!=(const Param &other) const
+ { return !(*this == other); }
+ };
+
+ enum Type {
+ FOR_EACH_MOTH_INSTR(MOTH_INSTR_ENUM)
+ };
+
+ struct instr_common {
+ MOTH_INSTR_HEADER
+ };
+ struct instr_ret {
+ MOTH_INSTR_HEADER
+ Param result;
+ };
+ struct instr_loadValue {
+ MOTH_INSTR_HEADER
+ Param value;
+ Param result;
+ };
+ struct instr_moveTemp {
+ MOTH_INSTR_HEADER
+ Param source;
+ Param result;
+ };
+ struct instr_loadClosure {
+ MOTH_INSTR_HEADER
+ QV4::Function *value;
+ Param result;
+ };
+ struct instr_loadName {
+ MOTH_INSTR_HEADER
+ QV4::String *name;
+ Param result;
+ };
+ struct instr_storeName {
+ MOTH_INSTR_HEADER
+ QV4::String *name;
+ Param source;
+ };
+ struct instr_loadProperty {
+ MOTH_INSTR_HEADER
+ QV4::String *name;
+ Param base;
+ Param result;
+ };
+ struct instr_storeProperty {
+ MOTH_INSTR_HEADER
+ QV4::String *name;
+ Param base;
+ Param source;
+ };
+ struct instr_loadElement {
+ MOTH_INSTR_HEADER
+ Param base;
+ Param index;
+ Param result;
+ };
+ struct instr_storeElement {
+ MOTH_INSTR_HEADER
+ Param base;
+ Param index;
+ Param source;
+ };
+ struct instr_push {
+ MOTH_INSTR_HEADER
+ quint32 value;
+ };
+ struct instr_enterTry {
+ MOTH_INSTR_HEADER
+ ptrdiff_t tryOffset;
+ ptrdiff_t catchOffset;
+ QV4::String *exceptionVarName;
+ Param exceptionVar;
+ };
+ struct instr_callValue {
+ MOTH_INSTR_HEADER
+ quint32 argc;
+ quint32 args;
+ Param dest;
+ Param result;
+ };
+ struct instr_callProperty {
+ MOTH_INSTR_HEADER
+ QV4::String *name;
+ quint32 argc;
+ quint32 args;
+ Param base;
+ Param result;
+ };
+ struct instr_callElement {
+ MOTH_INSTR_HEADER
+ Param base;
+ Param index;
+ quint32 argc;
+ quint32 args;
+ Param result;
+ };
+ struct instr_callActivationProperty {
+ MOTH_INSTR_HEADER
+ QV4::String *name;
+ quint32 argc;
+ quint32 args;
+ Param result;
+ };
+ struct instr_callBuiltinThrow {
+ MOTH_INSTR_HEADER
+ Param arg;
+ };
+ struct instr_callBuiltinFinishTry {
+ MOTH_INSTR_HEADER
+ };
+ struct instr_callBuiltinPushScope {
+ MOTH_INSTR_HEADER
+ Param arg;
+ };
+ struct instr_callBuiltinPopScope {
+ MOTH_INSTR_HEADER
+ };
+ struct instr_callBuiltinForeachIteratorObject {
+ MOTH_INSTR_HEADER
+ Param arg;
+ Param result;
+ };
+ struct instr_callBuiltinForeachNextPropertyName {
+ MOTH_INSTR_HEADER
+ Param arg;
+ Param result;
+ };
+ struct instr_callBuiltinDeleteMember {
+ MOTH_INSTR_HEADER
+ QV4::String *member;
+ Param base;
+ Param result;
+ };
+ struct instr_callBuiltinDeleteSubscript {
+ MOTH_INSTR_HEADER
+ Param base;
+ Param index;
+ Param result;
+ };
+ struct instr_callBuiltinDeleteName {
+ MOTH_INSTR_HEADER
+ QV4::String *name;
+ Param result;
+ };
+ struct instr_callBuiltinTypeofMember {
+ MOTH_INSTR_HEADER
+ QV4::String *member;
+ Param base;
+ Param result;
+ };
+ struct instr_callBuiltinTypeofSubscript {
+ MOTH_INSTR_HEADER
+ Param base;
+ Param index;
+ Param result;
+ };
+ struct instr_callBuiltinTypeofName {
+ MOTH_INSTR_HEADER
+ QV4::String *name;
+ Param result;
+ };
+ struct instr_callBuiltinTypeofValue {
+ MOTH_INSTR_HEADER
+ Param value;
+ Param result;
+ };
+ struct instr_callBuiltinPostIncMember {
+ MOTH_INSTR_HEADER
+ Param base;
+ QV4::String *member;
+ Param result;
+ };
+ struct instr_callBuiltinPostIncSubscript {
+ MOTH_INSTR_HEADER
+ Param base;
+ Param index;
+ Param result;
+ };
+ struct instr_callBuiltinPostIncName {
+ MOTH_INSTR_HEADER
+ QV4::String *name;
+ Param result;
+ };
+ struct instr_callBuiltinPostIncValue {
+ MOTH_INSTR_HEADER
+ Param value;
+ Param result;
+ };
+ struct instr_callBuiltinPostDecMember {
+ MOTH_INSTR_HEADER
+ Param base;
+ QV4::String *member;
+ Param result;
+ };
+ struct instr_callBuiltinPostDecSubscript {
+ MOTH_INSTR_HEADER
+ Param base;
+ Param index;
+ Param result;
+ };
+ struct instr_callBuiltinPostDecName {
+ MOTH_INSTR_HEADER
+ QV4::String *name;
+ Param result;
+ };
+ struct instr_callBuiltinPostDecValue {
+ MOTH_INSTR_HEADER
+ Param value;
+ Param result;
+ };
+ struct instr_callBuiltinDeclareVar {
+ MOTH_INSTR_HEADER
+ QV4::String *varName;
+ bool isDeletable;
+ };
+ struct instr_callBuiltinDefineGetterSetter {
+ MOTH_INSTR_HEADER
+ QV4::String *name;
+ Param object;
+ Param getter;
+ Param setter;
+ };
+ struct instr_callBuiltinDefineProperty {
+ MOTH_INSTR_HEADER
+ QV4::String *name;
+ Param object;
+ Param value;
+ };
+ struct instr_callBuiltinDefineArray {
+ MOTH_INSTR_HEADER
+ quint32 argc;
+ quint32 args;
+ Param result;
+ };
+ struct instr_callBuiltinDefineObjectLiteral {
+ MOTH_INSTR_HEADER
+ QV4::InternalClass *internalClass;
+ quint32 args;
+ Param result;
+ };
+ struct instr_createValue {
+ MOTH_INSTR_HEADER
+ quint32 argc;
+ quint32 args;
+ Param func;
+ Param result;
+ };
+ struct instr_createProperty {
+ MOTH_INSTR_HEADER
+ QV4::String *name;
+ quint32 argc;
+ quint32 args;
+ Param base;
+ Param result;
+ };
+ struct instr_createActivationProperty {
+ MOTH_INSTR_HEADER
+ QV4::String *name;
+ quint32 argc;
+ quint32 args;
+ Param result;
+ };
+ struct instr_jump {
+ MOTH_INSTR_HEADER
+ ptrdiff_t offset;
+ };
+ struct instr_cjump {
+ MOTH_INSTR_HEADER
+ ptrdiff_t offset;
+ Param condition;
+ };
+ struct instr_unop {
+ MOTH_INSTR_HEADER
+ QV4::UnaryOpName alu;
+ Param source;
+ Param result;
+ };
+ struct instr_binop {
+ MOTH_INSTR_HEADER
+ QV4::BinOp alu;
+ Param lhs;
+ Param rhs;
+ Param result;
+ };
+ struct instr_addNumberParams {
+ MOTH_INSTR_HEADER
+ Param lhs;
+ Param rhs;
+ Param result;
+ };
+ struct instr_mulNumberParams {
+ MOTH_INSTR_HEADER
+ Param lhs;
+ Param rhs;
+ Param result;
+ };
+ struct instr_subNumberParams {
+ MOTH_INSTR_HEADER
+ Param lhs;
+ Param rhs;
+ Param result;
+ };
+ struct instr_loadThis {
+ MOTH_INSTR_HEADER
+ Param result;
+ };
+ struct instr_inplaceElementOp {
+ MOTH_INSTR_HEADER
+ QV4::InplaceBinOpElement alu;
+ Param base;
+ Param index;
+ Param source;
+ };
+ struct instr_inplaceMemberOp {
+ MOTH_INSTR_HEADER
+ QV4::InplaceBinOpMember alu;
+ QV4::String *member;
+ Param base;
+ Param source;
+ };
+ struct instr_inplaceNameOp {
+ MOTH_INSTR_HEADER
+ QV4::InplaceBinOpName alu;
+ QV4::String *name;
+ Param source;
+ };
+
+ instr_common common;
+ instr_ret ret;
+ instr_loadValue loadValue;
+ instr_moveTemp moveTemp;
+ instr_loadClosure loadClosure;
+ instr_loadName loadName;
+ instr_storeName storeName;
+ instr_loadElement loadElement;
+ instr_storeElement storeElement;
+ instr_loadProperty loadProperty;
+ instr_storeProperty storeProperty;
+ instr_push push;
+ instr_enterTry enterTry;
+ instr_callValue callValue;
+ instr_callProperty callProperty;
+ instr_callElement callElement;
+ instr_callActivationProperty callActivationProperty;
+ instr_callBuiltinThrow callBuiltinThrow;
+ instr_callBuiltinFinishTry callBuiltinFinishTry;
+ instr_callBuiltinPushScope callBuiltinPushScope;
+ instr_callBuiltinPopScope callBuiltinPopScope;
+ instr_callBuiltinForeachIteratorObject callBuiltinForeachIteratorObject;
+ instr_callBuiltinForeachNextPropertyName callBuiltinForeachNextPropertyName;
+ instr_callBuiltinDeleteMember callBuiltinDeleteMember;
+ instr_callBuiltinDeleteSubscript callBuiltinDeleteSubscript;
+ instr_callBuiltinDeleteName callBuiltinDeleteName;
+ instr_callBuiltinTypeofMember callBuiltinTypeofMember;
+ instr_callBuiltinTypeofSubscript callBuiltinTypeofSubscript;
+ instr_callBuiltinTypeofName callBuiltinTypeofName;
+ instr_callBuiltinTypeofValue callBuiltinTypeofValue;
+ instr_callBuiltinPostIncMember callBuiltinPostIncMember;
+ instr_callBuiltinPostIncSubscript callBuiltinPostIncSubscript;
+ instr_callBuiltinPostIncName callBuiltinPostIncName;
+ instr_callBuiltinPostIncValue callBuiltinPostIncValue;
+ instr_callBuiltinPostDecMember callBuiltinPostDecMember;
+ instr_callBuiltinPostDecSubscript callBuiltinPostDecSubscript;
+ instr_callBuiltinPostDecName callBuiltinPostDecName;
+ instr_callBuiltinPostDecValue callBuiltinPostDecValue;
+ instr_callBuiltinDeclareVar callBuiltinDeclareVar;
+ instr_callBuiltinDefineGetterSetter callBuiltinDefineGetterSetter;
+ instr_callBuiltinDefineProperty callBuiltinDefineProperty;
+ instr_callBuiltinDefineArray callBuiltinDefineArray;
+ instr_callBuiltinDefineObjectLiteral callBuiltinDefineObjectLiteral;
+ instr_createValue createValue;
+ instr_createProperty createProperty;
+ instr_createActivationProperty createActivationProperty;
+ instr_jump jump;
+ instr_cjump cjump;
+ instr_unop unop;
+ instr_binop binop;
+ instr_addNumberParams addNumberParams;
+ instr_mulNumberParams mulNumberParams;
+ instr_subNumberParams subNumberParams;
+ instr_loadThis loadThis;
+ instr_inplaceElementOp inplaceElementOp;
+ instr_inplaceMemberOp inplaceMemberOp;
+ instr_inplaceNameOp inplaceNameOp;
+
+ static int size(Type type);
+};
+
+template<int N>
+struct InstrMeta {
+};
+
+#define MOTH_INSTR_META_TEMPLATE(I, FMT) \
+ template<> struct InstrMeta<(int)Instr::I> { \
+ enum { Size = MOTH_INSTR_SIZE(I, FMT) }; \
+ typedef Instr::instr_##FMT DataType; \
+ static const DataType &data(const Instr &instr) { return instr.FMT; } \
+ static void setData(Instr &instr, const DataType &v) { instr.FMT = v; } \
+ };
+FOR_EACH_MOTH_INSTR(MOTH_INSTR_META_TEMPLATE);
+#undef MOTH_INSTR_META_TEMPLATE
+
+template<int InstrType>
+class InstrData : public InstrMeta<InstrType>::DataType
+{
+};
+
+} // namespace Moth
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif // QV4INSTR_MOTH_P_H
diff --git a/src/qml/qml/v4/moth/qv4isel_moth.cpp b/src/qml/qml/v4/moth/qv4isel_moth.cpp
new file mode 100644
index 0000000000..04d759ed8d
--- /dev/null
+++ b/src/qml/qml/v4/moth/qv4isel_moth.cpp
@@ -0,0 +1,1075 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4isel_util_p.h"
+#include "qv4isel_moth_p.h"
+#include "qv4vme_moth_p.h"
+#include "qv4ssa_p.h"
+#include <private/qv4functionobject_p.h>
+#include <private/qv4regexpobject_p.h>
+#include <private/qv4debugging_p.h>
+#include <private/qv4function_p.h>
+
+#undef USE_TYPE_INFO
+
+using namespace QQmlJS;
+using namespace QQmlJS::Moth;
+
+namespace {
+
+inline QV4::BinOp aluOpFunction(V4IR::AluOp op)
+{
+ switch (op) {
+ case V4IR::OpInvalid:
+ return 0;
+ case V4IR::OpIfTrue:
+ return 0;
+ case V4IR::OpNot:
+ return 0;
+ case V4IR::OpUMinus:
+ return 0;
+ case V4IR::OpUPlus:
+ return 0;
+ case V4IR::OpCompl:
+ return 0;
+ case V4IR::OpBitAnd:
+ return QV4::__qmljs_bit_and;
+ case V4IR::OpBitOr:
+ return QV4::__qmljs_bit_or;
+ case V4IR::OpBitXor:
+ return QV4::__qmljs_bit_xor;
+ case V4IR::OpAdd:
+ return QV4::__qmljs_add;
+ case V4IR::OpSub:
+ return QV4::__qmljs_sub;
+ case V4IR::OpMul:
+ return QV4::__qmljs_mul;
+ case V4IR::OpDiv:
+ return QV4::__qmljs_div;
+ case V4IR::OpMod:
+ return QV4::__qmljs_mod;
+ case V4IR::OpLShift:
+ return QV4::__qmljs_shl;
+ case V4IR::OpRShift:
+ return QV4::__qmljs_shr;
+ case V4IR::OpURShift:
+ return QV4::__qmljs_ushr;
+ case V4IR::OpGt:
+ return QV4::__qmljs_gt;
+ case V4IR::OpLt:
+ return QV4::__qmljs_lt;
+ case V4IR::OpGe:
+ return QV4::__qmljs_ge;
+ case V4IR::OpLe:
+ return QV4::__qmljs_le;
+ case V4IR::OpEqual:
+ return QV4::__qmljs_eq;
+ case V4IR::OpNotEqual:
+ return QV4::__qmljs_ne;
+ case V4IR::OpStrictEqual:
+ return QV4::__qmljs_se;
+ case V4IR::OpStrictNotEqual:
+ return QV4::__qmljs_sne;
+ case V4IR::OpInstanceof:
+ return QV4::__qmljs_instanceof;
+ case V4IR::OpIn:
+ return QV4::__qmljs_in;
+ case V4IR::OpAnd:
+ return 0;
+ case V4IR::OpOr:
+ return 0;
+ default:
+ assert(!"Unknown AluOp");
+ return 0;
+ }
+};
+} // anonymous namespace
+
+// TODO: extend to optimize out temp-to-temp moves, where the lifetime of one temp ends at that statement.
+// To handle that, add a hint when such a move will occur, and add a stmt for the hint.
+// Then when asked for a register, check if the active statement is the terminating statement, and if so, apply the hint.
+// This generalises the hint usage for Phi removal too, when the phi is passed in there as the current statement.
+class QQmlJS::Moth::StackSlotAllocator
+{
+ QHash<V4IR::Temp, int> _slotForTemp;
+ QHash<V4IR::Temp, int> _hints;
+ QVector<int> _activeSlots;
+
+ QHash<V4IR::Temp, V4IR::LifeTimeInterval> _intervals;
+
+public:
+ StackSlotAllocator(const QList<V4IR::LifeTimeInterval> &ranges, int maxTempCount)
+ : _activeSlots(maxTempCount)
+ {
+ _intervals.reserve(ranges.size());
+ foreach (const V4IR::LifeTimeInterval &r, ranges)
+ _intervals[r.temp()] = r;
+ }
+
+ void addHint(const V4IR::Temp &hintedSlotOfTemp, const V4IR::Temp &newTemp)
+ {
+ if (hintedSlotOfTemp.kind != V4IR::Temp::VirtualRegister
+ || newTemp.kind != V4IR::Temp::VirtualRegister)
+ return;
+
+ if (_slotForTemp.contains(newTemp) || _hints.contains(newTemp))
+ return;
+
+ int hintedSlot = _slotForTemp.value(hintedSlotOfTemp, -1);
+ Q_ASSERT(hintedSlot >= 0);
+ _hints[newTemp] = hintedSlot;
+ }
+
+ int stackSlotFor(V4IR::Temp *t, V4IR::Stmt *currentStmt) {
+ int idx = _slotForTemp.value(*t, -1);
+ if (idx == -1)
+ idx = allocateSlot(t, currentStmt);
+ Q_ASSERT(idx >= 0);
+ return idx;
+ }
+
+private:
+ int allocateSlot(V4IR::Temp *t, V4IR::Stmt *currentStmt) {
+ const V4IR::LifeTimeInterval &interval = _intervals[*t];
+ int idx = _hints.value(*t, -1);
+ if (idx != -1 && _activeSlots[idx] <= currentStmt->id) {
+ _slotForTemp[*t] = idx;
+ _activeSlots[idx] = interval.end();
+ return idx;
+ }
+
+ for (int i = 0, ei = _activeSlots.size(); i != ei; ++i) {
+ if (_activeSlots[i] < currentStmt->id) {
+ _slotForTemp[*t] = i;
+ _activeSlots[i] = interval.end();
+ return i;
+ }
+ }
+
+ return -1;
+ }
+};
+
+InstructionSelection::InstructionSelection(QV4::ExecutionEngine *engine, V4IR::Module *module)
+ : EvalInstructionSelection(engine, module)
+ , _function(0)
+ , _vmFunction(0)
+ , _block(0)
+ , _codeStart(0)
+ , _codeNext(0)
+ , _codeEnd(0)
+ , _stackSlotAllocator(0)
+ , _currentStatement(0)
+{
+}
+
+InstructionSelection::~InstructionSelection()
+{
+}
+
+void InstructionSelection::run(QV4::Function *vmFunction, V4IR::Function *function)
+{
+ V4IR::BasicBlock *block = 0, *nextBlock = 0;
+
+ QHash<V4IR::BasicBlock *, QVector<ptrdiff_t> > patches;
+ QHash<V4IR::BasicBlock *, ptrdiff_t> addrs;
+
+ int codeSize = 4096;
+ uchar *codeStart = new uchar[codeSize];
+ memset(codeStart, 0, codeSize);
+ uchar *codeNext = codeStart;
+ uchar *codeEnd = codeStart + codeSize;
+
+ qSwap(_function, function);
+ qSwap(_vmFunction, vmFunction);
+ qSwap(block, _block);
+ qSwap(nextBlock, _nextBlock);
+ qSwap(patches, _patches);
+ qSwap(addrs, _addrs);
+ qSwap(codeStart, _codeStart);
+ qSwap(codeNext, _codeNext);
+ qSwap(codeEnd, _codeEnd);
+
+ V4IR::Optimizer opt(_function);
+ opt.run();
+ StackSlotAllocator *stackSlotAllocator = 0;
+ if (opt.isInSSA())
+ stackSlotAllocator = new StackSlotAllocator(opt.lifeRanges(), _function->tempCount);
+ qSwap(_stackSlotAllocator, stackSlotAllocator);
+ V4IR::Stmt *cs = 0;
+ qSwap(_currentStatement, cs);
+
+ int locals = frameSize();
+ assert(locals >= 0);
+
+ Instruction::Push push;
+ push.value = quint32(locals);
+ addInstruction(push);
+
+ for (int i = 0, ei = _function->basicBlocks.size(); i != ei; ++i) {
+ _block = _function->basicBlocks[i];
+ _nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0;
+ _addrs.insert(_block, _codeNext - _codeStart);
+
+ foreach (V4IR::Stmt *s, _block->statements) {
+ if (s->location.isValid()) {
+ QV4::LineNumberMapping mapping;
+ mapping.codeOffset = _codeNext - _codeStart;
+ mapping.lineNumber = s->location.startLine;
+ _vmFunction->lineNumberMappings.append(mapping);
+ }
+
+ if (opt.isInSSA() && s->asTerminator()) {
+ foreach (const V4IR::Optimizer::SSADeconstructionMove &move,
+ opt.ssaDeconstructionMoves(_block)) {
+ Q_ASSERT(move.source->asTemp()); // FIXME: support Const exprs in Phi nodes.
+ if (move.needsConversion())
+ convertType(move.source->asTemp(), move.target);
+ else
+ copyValue(move.source->asTemp(), move.target);
+ }
+ }
+
+ _currentStatement = s;
+ s->accept(this);
+ }
+ }
+
+ // TODO: patch stack size (the push instruction)
+ patchJumpAddresses();
+
+ _vmFunction->code = VME::exec;
+ _vmFunction->codeData = squeezeCode();
+
+ if (QV4::Debugging::Debugger *debugger = engine()->debugger)
+ debugger->setPendingBreakpoints(_vmFunction);
+
+ qSwap(_currentStatement, cs);
+ qSwap(_stackSlotAllocator, stackSlotAllocator);
+ delete stackSlotAllocator;
+ qSwap(_function, function);
+ qSwap(_vmFunction, vmFunction);
+ qSwap(block, _block);
+ qSwap(nextBlock, _nextBlock);
+ qSwap(patches, _patches);
+ qSwap(addrs, _addrs);
+ qSwap(codeStart, _codeStart);
+ qSwap(codeNext, _codeNext);
+ qSwap(codeEnd, _codeEnd);
+
+ delete[] codeStart;
+}
+
+void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ Instruction::CallValue call;
+ prepareCallArgs(args, call.argc, call.args);
+ call.dest = getParam(value);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ // call the property on the loaded base
+ Instruction::CallProperty call;
+ call.base = getParam(base);
+ call.name = identifier(name);
+ prepareCallArgs(args, call.argc, call.args);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ // call the property on the loaded base
+ Instruction::CallElement call;
+ call.base = getParam(base);
+ call.index = getParam(index);
+ prepareCallArgs(args, call.argc, call.args);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::convertType(V4IR::Temp *source, V4IR::Temp *target)
+{
+ if (_stackSlotAllocator)
+ _stackSlotAllocator->addHint(*source, *target);
+
+ // FIXME: do something more useful with this info
+ copyValue(source, target);
+}
+
+void InstructionSelection::constructActivationProperty(V4IR::Name *func,
+ V4IR::ExprList *args,
+ V4IR::Temp *result)
+{
+ Instruction::CreateActivationProperty create;
+ create.name = identifier(*func->id);
+ prepareCallArgs(args, create.argc, create.args);
+ create.result = getResultParam(result);
+ addInstruction(create);
+}
+
+void InstructionSelection::constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ Instruction::CreateProperty create;
+ create.base = getParam(base);
+ create.name = identifier(name);
+ prepareCallArgs(args, create.argc, create.args);
+ create.result = getResultParam(result);
+ addInstruction(create);
+}
+
+void InstructionSelection::constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ Instruction::CreateValue create;
+ create.func = getParam(value);
+ prepareCallArgs(args, create.argc, create.args);
+ create.result = getResultParam(result);
+ addInstruction(create);
+}
+
+void InstructionSelection::loadThisObject(V4IR::Temp *temp)
+{
+ Instruction::LoadThis load;
+ load.result = getResultParam(temp);
+ addInstruction(load);
+}
+
+void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
+{
+ assert(sourceConst);
+
+ Instruction::LoadValue load;
+ load.value = getParam(sourceConst);
+ load.result = getResultParam(targetTemp);
+ addInstruction(load);
+}
+
+void InstructionSelection::loadString(const QString &str, V4IR::Temp *targetTemp)
+{
+ Instruction::LoadValue load;
+ load.value = Instr::Param::createValue(QV4::Value::fromString(identifier(str)));
+ load.result = getResultParam(targetTemp);
+ addInstruction(load);
+}
+
+void InstructionSelection::loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp)
+{
+ QV4::Value v = QV4::Value::fromObject(engine()->newRegExpObject(
+ *sourceRegexp->value,
+ sourceRegexp->flags));
+ _vmFunction->generatedValues.append(v);
+
+ Instruction::LoadValue load;
+ load.value = Instr::Param::createValue(v);
+ load.result = getResultParam(targetTemp);
+ addInstruction(load);
+}
+
+void InstructionSelection::getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp)
+{
+ Instruction::LoadName load;
+ load.name = identifier(*name->id);
+ load.result = getResultParam(temp);
+ addInstruction(load);
+}
+
+void InstructionSelection::setActivationProperty(V4IR::Temp *source, const QString &targetName)
+{
+ Instruction::StoreName store;
+ store.source = getParam(source);
+ store.name = identifier(targetName);
+ addInstruction(store);
+}
+
+void InstructionSelection::initClosure(V4IR::Closure *closure, V4IR::Temp *target)
+{
+ QV4::Function *vmFunc = vmFunction(closure->value);
+ assert(vmFunc);
+ Instruction::LoadClosure load;
+ load.value = vmFunc;
+ load.result = getResultParam(target);
+ addInstruction(load);
+}
+
+void InstructionSelection::getProperty(V4IR::Temp *base, const QString &name, V4IR::Temp *target)
+{
+ Instruction::LoadProperty load;
+ load.base = getParam(base);
+ load.name = identifier(name);
+ load.result = getResultParam(target);
+ addInstruction(load);
+}
+
+void InstructionSelection::setProperty(V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName)
+{
+ Instruction::StoreProperty store;
+ store.base = getParam(targetBase);
+ store.name = identifier(targetName);
+ store.source = getParam(source);
+ addInstruction(store);
+}
+
+void InstructionSelection::getElement(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *target)
+{
+ Instruction::LoadElement load;
+ load.base = getParam(base);
+ load.index = getParam(index);
+ load.result = getResultParam(target);
+ addInstruction(load);
+}
+
+void InstructionSelection::setElement(V4IR::Temp *source, V4IR::Temp *targetBase, V4IR::Temp *targetIndex)
+{
+ Instruction::StoreElement store;
+ store.base = getParam(targetBase);
+ store.index = getParam(targetIndex);
+ store.source = getParam(source);
+ addInstruction(store);
+}
+
+void InstructionSelection::copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp)
+{
+ if (_stackSlotAllocator)
+ _stackSlotAllocator->addHint(*sourceTemp, *targetTemp);
+
+ Instruction::MoveTemp move;
+ move.source = getParam(sourceTemp);
+ move.result = getResultParam(targetTemp);
+ if (move.source != move.result)
+ addInstruction(move);
+}
+
+void InstructionSelection::unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp)
+{
+ QV4::UnaryOpName op = 0;
+ switch (oper) {
+ case V4IR::OpIfTrue: assert(!"unreachable"); break;
+ case V4IR::OpNot: op = QV4::__qmljs_not; break;
+ case V4IR::OpUMinus: op = QV4::__qmljs_uminus; break;
+ case V4IR::OpUPlus: op = QV4::__qmljs_uplus; break;
+ case V4IR::OpCompl: op = QV4::__qmljs_compl; break;
+ case V4IR::OpIncrement: op = QV4::__qmljs_increment; break;
+ case V4IR::OpDecrement: op = QV4::__qmljs_decrement; break;
+ default: assert(!"unreachable"); break;
+ } // switch
+
+ if (op) {
+ Instruction::Unop unop;
+ unop.alu = op;
+ unop.source = getParam(sourceTemp);
+ unop.result = getResultParam(targetTemp);
+ addInstruction(unop);
+ } else {
+ qWarning(" UNOP1");
+ }
+}
+
+void InstructionSelection::binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target)
+{
+#ifdef USE_TYPE_INFO
+ if (leftSource->type & V4IR::NumberType && rightSource->type & V4IR::NumberType) {
+ // TODO: add Temp+Const variation on the topic.
+ switch (oper) {
+ case V4IR::OpAdd: {
+ Instruction::AddNumberParams instr;
+ instr.lhs = getParam(leftSource);
+ instr.rhs = getParam(rightSource);
+ instr.result = getResultParam(target);
+ addInstruction(instr);
+ } return;
+ case V4IR::OpMul: {
+ Instruction::MulNumberParams instr;
+ instr.lhs = getParam(leftSource);
+ instr.rhs = getParam(rightSource);
+ instr.result = getResultParam(target);
+ addInstruction(instr);
+ } return;
+ case V4IR::OpSub: {
+ Instruction::SubNumberParams instr;
+ instr.lhs = getParam(leftSource);
+ instr.rhs = getParam(rightSource);
+ instr.result = getResultParam(target);
+ addInstruction(instr);
+ } return;
+ default:
+ break;
+ }
+ }
+#else // !USE_TYPE_INFO
+ Q_ASSERT(leftSource->asTemp() && rightSource->asTemp());
+#endif // USE_TYPE_INFO
+
+ Instruction::Binop binop;
+ binop.alu = aluOpFunction(oper);
+ binop.lhs = getParam(leftSource);
+ binop.rhs = getParam(rightSource);
+ binop.result = getResultParam(target);
+ addInstruction(binop);
+}
+
+void InstructionSelection::inplaceNameOp(V4IR::AluOp oper, V4IR::Temp *rightSource, const QString &targetName)
+{
+ QV4::InplaceBinOpName op = 0;
+ switch (oper) {
+ case V4IR::OpBitAnd: op = QV4::__qmljs_inplace_bit_and_name; break;
+ case V4IR::OpBitOr: op = QV4::__qmljs_inplace_bit_or_name; break;
+ case V4IR::OpBitXor: op = QV4::__qmljs_inplace_bit_xor_name; break;
+ case V4IR::OpAdd: op = QV4::__qmljs_inplace_add_name; break;
+ case V4IR::OpSub: op = QV4::__qmljs_inplace_sub_name; break;
+ case V4IR::OpMul: op = QV4::__qmljs_inplace_mul_name; break;
+ case V4IR::OpDiv: op = QV4::__qmljs_inplace_div_name; break;
+ case V4IR::OpMod: op = QV4::__qmljs_inplace_mod_name; break;
+ case V4IR::OpLShift: op = QV4::__qmljs_inplace_shl_name; break;
+ case V4IR::OpRShift: op = QV4::__qmljs_inplace_shr_name; break;
+ case V4IR::OpURShift: op = QV4::__qmljs_inplace_ushr_name; break;
+ default: break;
+ }
+
+ if (op) {
+ Instruction::InplaceNameOp ieo;
+ ieo.alu = op;
+ ieo.name = identifier(targetName);
+ ieo.source = getParam(rightSource);
+ addInstruction(ieo);
+ }
+}
+
+void InstructionSelection::inplaceElementOp(V4IR::AluOp oper, V4IR::Temp *source, V4IR::Temp *targetBaseTemp, V4IR::Temp *targetIndexTemp)
+{
+ QV4::InplaceBinOpElement op = 0;
+ switch (oper) {
+ case V4IR::OpBitAnd: op = QV4::__qmljs_inplace_bit_and_element; break;
+ case V4IR::OpBitOr: op = QV4::__qmljs_inplace_bit_or_element; break;
+ case V4IR::OpBitXor: op = QV4::__qmljs_inplace_bit_xor_element; break;
+ case V4IR::OpAdd: op = QV4::__qmljs_inplace_add_element; break;
+ case V4IR::OpSub: op = QV4::__qmljs_inplace_sub_element; break;
+ case V4IR::OpMul: op = QV4::__qmljs_inplace_mul_element; break;
+ case V4IR::OpDiv: op = QV4::__qmljs_inplace_div_element; break;
+ case V4IR::OpMod: op = QV4::__qmljs_inplace_mod_element; break;
+ case V4IR::OpLShift: op = QV4::__qmljs_inplace_shl_element; break;
+ case V4IR::OpRShift: op = QV4::__qmljs_inplace_shr_element; break;
+ case V4IR::OpURShift: op = QV4::__qmljs_inplace_ushr_element; break;
+ default: break;
+ }
+
+ Instruction::InplaceElementOp ieo;
+ ieo.alu = op;
+ ieo.base = getParam(targetBaseTemp);
+ ieo.index = getParam(targetIndexTemp);
+ ieo.source = getParam(source);
+ addInstruction(ieo);
+}
+
+void InstructionSelection::inplaceMemberOp(V4IR::AluOp oper, V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName)
+{
+ QV4::InplaceBinOpMember op = 0;
+ switch (oper) {
+ case V4IR::OpBitAnd: op = QV4::__qmljs_inplace_bit_and_member; break;
+ case V4IR::OpBitOr: op = QV4::__qmljs_inplace_bit_or_member; break;
+ case V4IR::OpBitXor: op = QV4::__qmljs_inplace_bit_xor_member; break;
+ case V4IR::OpAdd: op = QV4::__qmljs_inplace_add_member; break;
+ case V4IR::OpSub: op = QV4::__qmljs_inplace_sub_member; break;
+ case V4IR::OpMul: op = QV4::__qmljs_inplace_mul_member; break;
+ case V4IR::OpDiv: op = QV4::__qmljs_inplace_div_member; break;
+ case V4IR::OpMod: op = QV4::__qmljs_inplace_mod_member; break;
+ case V4IR::OpLShift: op = QV4::__qmljs_inplace_shl_member; break;
+ case V4IR::OpRShift: op = QV4::__qmljs_inplace_shr_member; break;
+ case V4IR::OpURShift: op = QV4::__qmljs_inplace_ushr_member; break;
+ default: break;
+ }
+
+ Instruction::InplaceMemberOp imo;
+ imo.alu = op;
+ imo.base = getParam(targetBase);
+ imo.member = identifier(targetName);
+ imo.source = getParam(source);
+ addInstruction(imo);
+}
+
+void InstructionSelection::prepareCallArgs(V4IR::ExprList *e, quint32 &argc, quint32 &args)
+{
+ bool singleArgIsTemp = false;
+ if (e && e->next == 0 && e->expr->asTemp()) {
+ singleArgIsTemp = e->expr->asTemp()->kind == V4IR::Temp::VirtualRegister;
+ }
+
+ if (singleArgIsTemp) {
+ // We pass single arguments as references to the stack, but only if it's not a local or an argument.
+ argc = 1;
+ args = getParam(e->expr).index;
+ } else if (e) {
+ // We need to move all the temps into the function arg array
+ int argLocation = outgoingArgumentTempStart();
+ assert(argLocation >= 0);
+ argc = 0;
+ args = argLocation;
+ while (e) {
+ Instruction::MoveTemp move;
+ move.source = getParam(e->expr);
+ move.result = Instr::Param::createTemp(argLocation);
+ addInstruction(move);
+ ++argLocation;
+ ++argc;
+ e = e->next;
+ }
+ } else {
+ argc = 0;
+ args = 0;
+ }
+}
+
+void InstructionSelection::visitJump(V4IR::Jump *s)
+{
+ if (s->target == _nextBlock)
+ return;
+
+ Instruction::Jump jump;
+ jump.offset = 0;
+ ptrdiff_t loc = addInstruction(jump) + (((const char *)&jump.offset) - ((const char *)&jump));
+
+ _patches[s->target].append(loc);
+}
+
+void InstructionSelection::visitCJump(V4IR::CJump *s)
+{
+ Instr::Param condition;
+ if (V4IR::Temp *t = s->cond->asTemp()) {
+ condition = getResultParam(t);
+ } else if (V4IR::Binop *b = s->cond->asBinop()) {
+ condition = getResultParam(0);
+ Instruction::Binop binop;
+ binop.alu = aluOpFunction(b->op);
+ binop.lhs = getParam(b->left);
+ binop.rhs = getParam(b->right);
+ binop.result = condition;
+ addInstruction(binop);
+ } else {
+ Q_UNIMPLEMENTED();
+ }
+
+ Instruction::CJump jump;
+ jump.offset = 0;
+ jump.condition = condition;
+ ptrdiff_t trueLoc = addInstruction(jump) + (((const char *)&jump.offset) - ((const char *)&jump));
+ _patches[s->iftrue].append(trueLoc);
+
+ if (s->iffalse != _nextBlock) {
+ Instruction::Jump jump;
+ jump.offset = 0;
+ ptrdiff_t falseLoc = addInstruction(jump) + (((const char *)&jump.offset) - ((const char *)&jump));
+ _patches[s->iffalse].append(falseLoc);
+ }
+}
+
+void InstructionSelection::visitRet(V4IR::Ret *s)
+{
+ Instruction::Ret ret;
+ ret.result = getParam(s->expr);
+ addInstruction(ret);
+}
+
+void InstructionSelection::visitTry(V4IR::Try *t)
+{
+ Instruction::EnterTry enterTry;
+ enterTry.tryOffset = 0;
+ enterTry.catchOffset = 0;
+ enterTry.exceptionVarName = identifier(t->exceptionVarName);
+ enterTry.exceptionVar = getParam(t->exceptionVar);
+ ptrdiff_t enterTryLoc = addInstruction(enterTry);
+
+ ptrdiff_t tryLoc = enterTryLoc + (((const char *)&enterTry.tryOffset) - ((const char *)&enterTry));
+ _patches[t->tryBlock].append(tryLoc);
+
+ ptrdiff_t catchLoc = enterTryLoc + (((const char *)&enterTry.catchOffset) - ((const char *)&enterTry));
+ _patches[t->catchBlock].append(catchLoc);
+}
+
+void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ Instruction::CallActivationProperty call;
+ call.name = identifier(*func->id);
+ prepareCallArgs(args, call.argc, call.args);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinTypeofMember call;
+ call.base = getParam(base);
+ call.member = identifier(name);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinTypeofSubscript call;
+ call.base = getParam(base);
+ call.index = getParam(index);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinTypeofName(const QString &name, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinTypeofName call;
+ call.name = identifier(name);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinTypeofValue(V4IR::Temp *value, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinTypeofValue call;
+ call.value = getParam(value);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinDeleteMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinDeleteMember call;
+ call.base = getParam(base);
+ call.member = identifier(name);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinDeleteSubscript call;
+ call.base = getParam(base);
+ call.index = getParam(index);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinDeleteName(const QString &name, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinDeleteName call;
+ call.name = identifier(name);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinDeleteValue(V4IR::Temp *result)
+{
+ Instruction::LoadValue load;
+ load.value = Instr::Param::createValue(QV4::Value::fromBoolean(false));
+ load.result = getResultParam(result);
+ addInstruction(load);
+}
+
+void InstructionSelection::callBuiltinPostDecrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinPostDecMember call;
+ call.base = getParam(base);
+ call.member = identifier(name);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinPostDecrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinPostDecSubscript call;
+ call.base = getParam(base);
+ call.index = getParam(index);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinPostDecrementName(const QString &name, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinPostDecName call;
+ call.name = identifier(name);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinPostDecrementValue(V4IR::Temp *value, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinPostDecValue call;
+ call.value = getParam(value);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinPostIncrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinPostIncMember call;
+ call.base = getParam(base);
+ call.member = identifier(name);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinPostIncSubscript call;
+ call.base = getParam(base);
+ call.index = getParam(index);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinPostIncName call;
+ call.name = identifier(name);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinPostIncValue call;
+ call.value = getParam(value);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinThrow(V4IR::Temp *arg)
+{
+ Instruction::CallBuiltinThrow call;
+ call.arg = getParam(arg);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinFinishTry()
+{
+ Instruction::CallBuiltinFinishTry call;
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinForeachIteratorObject call;
+ call.arg = getParam(arg);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result)
+{
+ Instruction::CallBuiltinForeachNextPropertyName call;
+ call.arg = getParam(arg);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinPushWithScope(V4IR::Temp *arg)
+{
+ Instruction::CallBuiltinPushScope call;
+ call.arg = getParam(arg);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinPopScope()
+{
+ Instruction::CallBuiltinPopScope call;
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &name)
+{
+ Instruction::CallBuiltinDeclareVar call;
+ call.isDeletable = deletable;
+ call.varName = identifier(name);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter)
+{
+ Instruction::CallBuiltinDefineGetterSetter call;
+ call.object = getParam(object);
+ call.name = identifier(name);
+ call.getter = getParam(getter);
+ call.setter = getParam(setter);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value)
+{
+ Instruction::CallBuiltinDefineProperty call;
+ call.object = getParam(object);
+ call.name = identifier(name);
+ call.value = getParam(value);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args)
+{
+ Instruction::CallBuiltinDefineArray call;
+ prepareCallArgs(args, call.argc, call.args);
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args)
+{
+ int argLocation = outgoingArgumentTempStart();
+
+ QV4::InternalClass *klass = engine()->emptyClass;
+ V4IR::ExprList *it = args;
+ while (it) {
+ V4IR::Name *name = it->expr->asName();
+ it = it->next;
+
+ bool isData = it->expr->asConst()->value;
+ it = it->next;
+ klass = klass->addMember(identifier(*name->id), isData ? QV4::Attr_Data : QV4::Attr_Accessor);
+
+ Instruction::MoveTemp move;
+ move.source = getParam(it->expr);
+ move.result = Instr::Param::createTemp(argLocation);
+ addInstruction(move);
+ ++argLocation;
+
+ if (!isData) {
+ it = it->next;
+
+ Instruction::MoveTemp move;
+ move.source = getParam(it->expr);
+ move.result = Instr::Param::createTemp(argLocation);
+ addInstruction(move);
+ ++argLocation;
+ }
+
+ it = it->next;
+ }
+
+ Instruction::CallBuiltinDefineObjectLiteral call;
+ call.internalClass = klass;
+ call.args = outgoingArgumentTempStart();
+ call.result = getResultParam(result);
+ addInstruction(call);
+}
+
+ptrdiff_t InstructionSelection::addInstructionHelper(Instr::Type type, Instr &instr)
+{
+#ifdef MOTH_THREADED_INTERPRETER
+ instr.common.code = VME::instructionJumpTable()[static_cast<int>(type)];
+#else
+ instr.common.instructionType = type;
+#endif
+ instr.common.breakPoint = 0;
+
+ int instructionSize = Instr::size(type);
+ if (_codeEnd - _codeNext < instructionSize) {
+ int currSize = _codeEnd - _codeStart;
+ uchar *newCode = new uchar[currSize * 2];
+ ::memset(newCode + currSize, 0, currSize);
+ ::memcpy(newCode, _codeStart, currSize);
+ _codeNext = _codeNext - _codeStart + newCode;
+ delete[] _codeStart;
+ _codeStart = newCode;
+ _codeEnd = _codeStart + currSize * 2;
+ }
+
+ ::memcpy(_codeNext, reinterpret_cast<const char *>(&instr), instructionSize);
+ ptrdiff_t ptrOffset = _codeNext - _codeStart;
+ _codeNext += instructionSize;
+
+ return ptrOffset;
+}
+
+void InstructionSelection::patchJumpAddresses()
+{
+ typedef QHash<V4IR::BasicBlock *, QVector<ptrdiff_t> >::ConstIterator PatchIt;
+ for (PatchIt i = _patches.begin(), ei = _patches.end(); i != ei; ++i) {
+ Q_ASSERT(_addrs.contains(i.key()));
+ ptrdiff_t target = _addrs.value(i.key());
+
+ const QVector<ptrdiff_t> &patchList = i.value();
+ for (int ii = 0, eii = patchList.count(); ii < eii; ++ii) {
+ ptrdiff_t patch = patchList.at(ii);
+
+ *((ptrdiff_t *)(_codeStart + patch)) = target - patch;
+ }
+ }
+
+ _patches.clear();
+ _addrs.clear();
+}
+
+uchar *InstructionSelection::squeezeCode() const
+{
+ int codeSize = _codeNext - _codeStart;
+ uchar *squeezed = new uchar[codeSize];
+ ::memcpy(squeezed, _codeStart, codeSize);
+ return squeezed;
+}
+
+QV4::String *InstructionSelection::identifier(const QString &s)
+{
+ QV4::String *str = engine()->newIdentifier(s);
+ _vmFunction->identifiers.append(str);
+ return str;
+}
+
+Instr::Param InstructionSelection::getParam(V4IR::Expr *e) {
+ typedef Instr::Param Param;
+ assert(e);
+
+ if (V4IR::Const *c = e->asConst()) {
+ return Param::createValue(convertToValue(c));
+ } else if (V4IR::Temp *t = e->asTemp()) {
+ switch (t->kind) {
+ case V4IR::Temp::Formal:
+ case V4IR::Temp::ScopedFormal: return Param::createArgument(t->index, t->scope);
+ case V4IR::Temp::Local: return Param::createLocal(t->index);
+ case V4IR::Temp::ScopedLocal: return Param::createScopedLocal(t->index, t->scope);
+ case V4IR::Temp::VirtualRegister:
+ return Param::createTemp(_stackSlotAllocator ?
+ _stackSlotAllocator->stackSlotFor(t, _currentStatement) : t->index);
+ default:
+ Q_UNIMPLEMENTED();
+ return Param();
+ }
+ } else {
+ Q_UNIMPLEMENTED();
+ return Param();
+ }
+}
diff --git a/src/qml/qml/v4/moth/qv4isel_moth_p.h b/src/qml/qml/v4/moth/qv4isel_moth_p.h
new file mode 100644
index 0000000000..9c17245f67
--- /dev/null
+++ b/src/qml/qml/v4/moth/qv4isel_moth_p.h
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4ISEL_MOTH_P_H
+#define QV4ISEL_MOTH_P_H
+
+#include <private/qv4global_p.h>
+#include <private/qv4isel_p.h>
+#include <private/qv4isel_util_p.h>
+#include <private/qv4jsir_p.h>
+#include <private/qv4object_p.h>
+#include "qv4instr_moth_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+namespace Moth {
+
+class StackSlotAllocator;
+
+class Q_QML_EXPORT InstructionSelection:
+ public V4IR::IRDecoder,
+ public EvalInstructionSelection
+{
+public:
+ InstructionSelection(QV4::ExecutionEngine *engine, V4IR::Module *module);
+ ~InstructionSelection();
+
+ virtual void run(QV4::Function *vmFunction, V4IR::Function *function);
+
+protected:
+ virtual void visitJump(V4IR::Jump *);
+ virtual void visitCJump(V4IR::CJump *);
+ virtual void visitRet(V4IR::Ret *);
+ virtual void visitTry(V4IR::Try *);
+
+ virtual void callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinTypeofName(const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinTypeofValue(V4IR::Temp *value, V4IR::Temp *result);
+ virtual void callBuiltinDeleteMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinDeleteName(const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinDeleteValue(V4IR::Temp *result);
+ virtual void callBuiltinPostDecrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinPostDecrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinPostDecrementName(const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinPostDecrementValue(V4IR::Temp *value, V4IR::Temp *result);
+ virtual void callBuiltinPostIncrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR::Temp *result);
+ virtual void callBuiltinThrow(V4IR::Temp *arg);
+ virtual void callBuiltinFinishTry();
+ virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result);
+ virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result);
+ virtual void callBuiltinPushWithScope(V4IR::Temp *arg);
+ virtual void callBuiltinPopScope();
+ virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
+ virtual void callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter);
+ virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value);
+ virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args);
+ virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args);
+ virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void convertType(V4IR::Temp *source, V4IR::Temp *target);
+ virtual void constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void loadThisObject(V4IR::Temp *temp);
+ virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp);
+ virtual void loadString(const QString &str, V4IR::Temp *targetTemp);
+ virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp);
+ virtual void getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp);
+ virtual void setActivationProperty(V4IR::Temp *source, const QString &targetName);
+ virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target);
+ virtual void getProperty(V4IR::Temp *base, const QString &name, V4IR::Temp *target);
+ virtual void setProperty(V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName);
+ virtual void getElement(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *target);
+ virtual void setElement(V4IR::Temp *source, V4IR::Temp *targetBase, V4IR::Temp *targetIndex);
+ virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
+ virtual void unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
+ virtual void binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target);
+ virtual void inplaceNameOp(V4IR::AluOp oper, V4IR::Temp *rightSource, const QString &targetName);
+ virtual void inplaceElementOp(V4IR::AluOp oper, V4IR::Temp *source, V4IR::Temp *targetBaseTemp, V4IR::Temp *targetIndexTemp);
+ virtual void inplaceMemberOp(V4IR::AluOp oper, V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName);
+
+private:
+ struct Instruction {
+#define MOTH_INSTR_DATA_TYPEDEF(I, FMT) typedef InstrData<Instr::I> I;
+ FOR_EACH_MOTH_INSTR(MOTH_INSTR_DATA_TYPEDEF)
+#undef MOTH_INSTR_DATA_TYPEDEF
+ private:
+ Instruction();
+ };
+
+ Instr::Param getParam(V4IR::Expr *e);
+
+ Instr::Param getResultParam(V4IR::Temp *result)
+ {
+ if (result)
+ return getParam(result);
+ else
+ return Instr::Param::createTemp(scratchTempIndex());
+ }
+
+ void simpleMove(V4IR::Move *);
+ void prepareCallArgs(V4IR::ExprList *, quint32 &, quint32 &);
+
+ int outgoingArgumentTempStart() const { return _function->tempCount; }
+ int scratchTempIndex() const { return outgoingArgumentTempStart() + _function->maxNumberOfArguments; }
+ int frameSize() const { return scratchTempIndex() + 1; }
+
+ template <int Instr>
+ inline ptrdiff_t addInstruction(const InstrData<Instr> &data);
+ ptrdiff_t addInstructionHelper(Instr::Type type, Instr &instr);
+ void patchJumpAddresses();
+ uchar *squeezeCode() const;
+
+ QV4::String *identifier(const QString &s);
+
+ V4IR::Function *_function;
+ QV4::Function *_vmFunction;
+ V4IR::BasicBlock *_block;
+ V4IR::BasicBlock *_nextBlock;
+
+ QHash<V4IR::BasicBlock *, QVector<ptrdiff_t> > _patches;
+ QHash<V4IR::BasicBlock *, ptrdiff_t> _addrs;
+
+ uchar *_codeStart;
+ uchar *_codeNext;
+ uchar *_codeEnd;
+
+ StackSlotAllocator *_stackSlotAllocator;
+ V4IR::Stmt *_currentStatement;
+};
+
+class Q_QML_EXPORT ISelFactory: public EvalISelFactory
+{
+public:
+ virtual ~ISelFactory() {}
+ virtual EvalInstructionSelection *create(QV4::ExecutionEngine *engine, V4IR::Module *module)
+ { return new InstructionSelection(engine, module); }
+ virtual bool jitCompileRegexps() const
+ { return false; }
+};
+
+template<int InstrT>
+ptrdiff_t InstructionSelection::addInstruction(const InstrData<InstrT> &data)
+{
+ Instr genericInstr;
+ InstrMeta<InstrT>::setData(genericInstr, data);
+ return addInstructionHelper(static_cast<Instr::Type>(InstrT), genericInstr);
+}
+
+} // namespace Moth
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif // QV4ISEL_MOTH_P_H
diff --git a/src/qml/qml/v4/moth/qv4vme_moth.cpp b/src/qml/qml/v4/moth/qv4vme_moth.cpp
new file mode 100644
index 0000000000..678d0edc4f
--- /dev/null
+++ b/src/qml/qml/v4/moth/qv4vme_moth.cpp
@@ -0,0 +1,592 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4vme_moth_p.h"
+#include "qv4instr_moth_p.h"
+#include <private/qv4value_p.h>
+#include <private/qv4debugging_p.h>
+#include <private/qv4exception_p.h>
+#include <private/qv4math_p.h>
+
+#include <iostream>
+
+#include "qv4alloca_p.h"
+
+#ifdef DO_TRACE_INSTR
+# define TRACE_INSTR(I) fprintf(stderr, "executing a %s\n", #I);
+# define TRACE(n, str, ...) { char buf[4096]; snprintf(buf, 4096, str, __VA_ARGS__); fprintf(stderr, " %s : %s\n", #n, buf); }
+#else
+# define TRACE_INSTR(I)
+# define TRACE(n, str, ...)
+#endif // DO_TRACE_INSTR
+
+using namespace QQmlJS;
+using namespace QQmlJS::Moth;
+
+#define MOTH_BEGIN_INSTR_COMMON(I) { \
+ const InstrMeta<(int)Instr::I>::DataType &instr = InstrMeta<(int)Instr::I>::data(*genericInstr); \
+ code += InstrMeta<(int)Instr::I>::Size; \
+ if (context->engine->debugger && (instr.breakPoint || context->engine->debugger->pauseAtNextOpportunity())) \
+ context->engine->debugger->maybeBreakAtInstruction(code, instr.breakPoint); \
+ Q_UNUSED(instr); \
+ TRACE_INSTR(I)
+
+#ifdef MOTH_THREADED_INTERPRETER
+
+# define MOTH_BEGIN_INSTR(I) op_##I: \
+ MOTH_BEGIN_INSTR_COMMON(I)
+
+# define MOTH_NEXT_INSTR(I) { \
+ genericInstr = reinterpret_cast<const Instr *>(code); \
+ goto *genericInstr->common.code; \
+ }
+
+# define MOTH_END_INSTR(I) } \
+ genericInstr = reinterpret_cast<const Instr *>(code); \
+ goto *genericInstr->common.code; \
+
+#else
+
+# define MOTH_BEGIN_INSTR(I) \
+ case Instr::I: \
+ MOTH_BEGIN_INSTR_COMMON(I)
+
+# define MOTH_NEXT_INSTR(I) { \
+ break; \
+ }
+
+# define MOTH_END_INSTR(I) } \
+ break;
+
+#endif
+
+#ifdef WITH_STATS
+namespace {
+struct VMStats {
+ quint64 paramIsValue;
+ quint64 paramIsArg;
+ quint64 paramIsLocal;
+ quint64 paramIsTemp;
+ quint64 paramIsScopedLocal;
+
+ VMStats()
+ : paramIsValue(0)
+ , paramIsArg(0)
+ , paramIsLocal(0)
+ , paramIsTemp(0)
+ , paramIsScopedLocal(0)
+ {}
+
+ ~VMStats()
+ { show(); }
+
+ void show() {
+ fprintf(stderr, "VM stats:\n");
+ fprintf(stderr, " value: %lu\n", paramIsValue);
+ fprintf(stderr, " arg: %lu\n", paramIsArg);
+ fprintf(stderr, " local: %lu\n", paramIsLocal);
+ fprintf(stderr, " temp: %lu\n", paramIsTemp);
+ fprintf(stderr, " scoped local: %lu\n", paramIsScopedLocal);
+ }
+};
+static VMStats vmStats;
+#define VMSTATS(what) ++vmStats.what
+}
+#else // !WITH_STATS
+#define VMSTATS(what) {}
+#endif // WITH_STATS
+
+static inline QV4::Value *getValueRef(QV4::ExecutionContext *context,
+ QV4::Value* stack,
+ const Instr::Param &param
+#if !defined(QT_NO_DEBUG)
+ , unsigned stackSize
+#endif
+ )
+{
+#ifdef DO_TRACE_INSTR
+ if (param.isValue()) {
+ fprintf(stderr, " value %s\n", param.value.toString(context)->toQString().toUtf8().constData());
+ } else if (param.isArgument()) {
+ fprintf(stderr, " argument %d@%d\n", param.index, param.scope);
+ } else if (param.isLocal()) {
+ fprintf(stderr, " local %d\n", param.index);
+ } else if (param.isTemp()) {
+ fprintf(stderr, " temp %d\n", param.index);
+ } else if (param.isScopedLocal()) {
+ fprintf(stderr, " temp %d@%d\n", param.index, param.scope);
+ } else {
+ Q_ASSERT(!"INVALID");
+ }
+#endif // DO_TRACE_INSTR
+
+ if (param.isValue()) {
+ VMSTATS(paramIsValue);
+ return const_cast<QV4::Value *>(&param.value);
+ } else if (param.isArgument()) {
+ VMSTATS(paramIsArg);
+ QV4::ExecutionContext *c = context;
+ uint scope = param.scope;
+ while (scope--)
+ c = c->outer;
+ QV4::CallContext *cc = static_cast<QV4::CallContext *>(c);
+ const unsigned arg = param.index;
+ Q_ASSERT(arg >= 0);
+ Q_ASSERT((unsigned) arg < cc->argumentCount);
+ Q_ASSERT(cc->arguments);
+ return cc->arguments + arg;
+ } else if (param.isLocal()) {
+ VMSTATS(paramIsLocal);
+ const unsigned index = param.index;
+ QV4::CallContext *c = static_cast<QV4::CallContext *>(context);
+ Q_ASSERT(index >= 0);
+ Q_ASSERT(index < context->variableCount());
+ Q_ASSERT(c->locals);
+ return c->locals + index;
+ } else if (param.isTemp()) {
+ VMSTATS(paramIsTemp);
+ Q_ASSERT(param.index < stackSize);
+ return stack + param.index;
+ } else if (param.isScopedLocal()) {
+ VMSTATS(paramIsScopedLocal);
+ QV4::ExecutionContext *c = context;
+ uint scope = param.scope;
+ while (scope--)
+ c = c->outer;
+ const unsigned index = param.index;
+ QV4::CallContext *cc = static_cast<QV4::CallContext *>(c);
+ Q_ASSERT(index >= 0);
+ Q_ASSERT(index < cc->variableCount());
+ Q_ASSERT(cc->locals);
+ return cc->locals + index;
+ } else {
+ Q_UNIMPLEMENTED();
+ return 0;
+ }
+}
+
+#if defined(QT_NO_DEBUG)
+# define VALUE(param) (*VALUEPTR(param))
+
+// The non-temp case might need some tweaking for QML: there it would probably be a value instead of a local.
+# define VALUEPTR(param) \
+ (param.isTemp() ? stack + param.index \
+ : (param.isLocal() ? static_cast<QV4::CallContext *>(context)->locals + param.index \
+ : getValueRef(context, stack, param)))
+#else
+# define VALUE(param) *getValueRef(context, stack, param, stackSize)
+# define VALUEPTR(param) getValueRef(context, stack, param, stackSize)
+#endif
+
+QV4::Value VME::run(QV4::ExecutionContext *context, const uchar *&code,
+ QV4::Value *stack, unsigned stackSize
+#ifdef MOTH_THREADED_INTERPRETER
+ , void ***storeJumpTable
+#endif
+ )
+{
+#ifdef DO_TRACE_INSTR
+ qDebug("Starting VME with context=%p and code=%p", context, code);
+#endif // DO_TRACE_INSTR
+
+#ifdef MOTH_THREADED_INTERPRETER
+ if (storeJumpTable) {
+#define MOTH_INSTR_ADDR(I, FMT) &&op_##I,
+ static void *jumpTable[] = {
+ FOR_EACH_MOTH_INSTR(MOTH_INSTR_ADDR)
+ };
+#undef MOTH_INSTR_ADDR
+ *storeJumpTable = jumpTable;
+ return QV4::Value::undefinedValue();
+ }
+#endif
+
+ context->interpreterInstructionPointer = &code;
+
+#ifdef MOTH_THREADED_INTERPRETER
+ const Instr *genericInstr = reinterpret_cast<const Instr *>(code);
+ goto *genericInstr->common.code;
+#else
+ for (;;) {
+ const Instr *genericInstr = reinterpret_cast<const Instr *>(code);
+ switch (genericInstr->common.instructionType) {
+#endif
+
+ MOTH_BEGIN_INSTR(MoveTemp)
+ VALUE(instr.result) = VALUE(instr.source);
+ MOTH_END_INSTR(MoveTemp)
+
+ MOTH_BEGIN_INSTR(LoadValue)
+// TRACE(value, "%s", instr.value.toString(context)->toQString().toUtf8().constData());
+ VALUE(instr.result) = VALUE(instr.value);
+ MOTH_END_INSTR(LoadValue)
+
+ MOTH_BEGIN_INSTR(LoadClosure)
+ __qmljs_init_closure(context, VALUEPTR(instr.result), instr.value);
+ MOTH_END_INSTR(LoadClosure)
+
+ MOTH_BEGIN_INSTR(LoadName)
+ TRACE(inline, "property name = %s", instr.name->toQString().toUtf8().constData());
+ __qmljs_get_activation_property(context, VALUEPTR(instr.result), instr.name);
+ MOTH_END_INSTR(LoadName)
+
+ MOTH_BEGIN_INSTR(StoreName)
+ TRACE(inline, "property name = %s", instr.name->toQString().toUtf8().constData());
+ __qmljs_set_activation_property(context, instr.name, VALUE(instr.source));
+ MOTH_END_INSTR(StoreName)
+
+ MOTH_BEGIN_INSTR(LoadElement)
+ __qmljs_get_element(context, VALUEPTR(instr.result), VALUE(instr.base), VALUE(instr.index));
+ MOTH_END_INSTR(LoadElement)
+
+ MOTH_BEGIN_INSTR(StoreElement)
+ __qmljs_set_element(context, VALUE(instr.base), VALUE(instr.index), VALUE(instr.source));
+ MOTH_END_INSTR(StoreElement)
+
+ MOTH_BEGIN_INSTR(LoadProperty)
+ __qmljs_get_property(context, VALUEPTR(instr.result), VALUE(instr.base), instr.name);
+ MOTH_END_INSTR(LoadProperty)
+
+ MOTH_BEGIN_INSTR(StoreProperty)
+ __qmljs_set_property(context, VALUE(instr.base), instr.name, VALUE(instr.source));
+ MOTH_END_INSTR(StoreProperty)
+
+ MOTH_BEGIN_INSTR(Push)
+ TRACE(inline, "stack size: %u", instr.value);
+ stackSize = instr.value;
+ stack = static_cast<QV4::Value *>(alloca(stackSize * sizeof(QV4::Value)));
+ memset(stack, 0, stackSize * sizeof(QV4::Value));
+ MOTH_END_INSTR(Push)
+
+ MOTH_BEGIN_INSTR(CallValue)
+#ifdef DO_TRACE_INSTR
+ if (Debugging::Debugger *debugger = context->engine->debugger) {
+ if (QV4::FunctionObject *o = (VALUE(instr.dest)).asFunctionObject()) {
+ if (Debugging::FunctionDebugInfo *info = debugger->debugInfo(o)) {
+ QString n = debugger->name(o);
+ std::cerr << "*** Call to \"" << (n.isNull() ? "<no name>" : qPrintable(n)) << "\" defined @" << info->startLine << ":" << info->startColumn << std::endl;
+ }
+ }
+ }
+#endif // DO_TRACE_INSTR
+ Q_ASSERT(instr.args + instr.argc <= stackSize);
+ QV4::Value *args = stack + instr.args;
+ __qmljs_call_value(context, VALUEPTR(instr.result), /*thisObject*/0, VALUE(instr.dest), args, instr.argc);
+ MOTH_END_INSTR(CallValue)
+
+ MOTH_BEGIN_INSTR(CallProperty)
+ TRACE(property name, "%s, args=%u, argc=%u, this=%s", qPrintable(instr.name->toQString()), instr.args, instr.argc, (VALUE(instr.base)).toString(context)->toQString().toUtf8().constData());
+ Q_ASSERT(instr.args + instr.argc <= stackSize);
+ QV4::Value *args = stack + instr.args;
+ __qmljs_call_property(context, VALUEPTR(instr.result), VALUE(instr.base), instr.name, args, instr.argc);
+ MOTH_END_INSTR(CallProperty)
+
+ MOTH_BEGIN_INSTR(CallElement)
+ Q_ASSERT(instr.args + instr.argc <= stackSize);
+ QV4::Value *args = stack + instr.args;
+ __qmljs_call_element(context, VALUEPTR(instr.result), VALUE(instr.base), VALUE(instr.index), args, instr.argc);
+ MOTH_END_INSTR(CallElement)
+
+ MOTH_BEGIN_INSTR(CallActivationProperty)
+ Q_ASSERT(instr.args + instr.argc <= stackSize);
+ TRACE(args, "starting at %d, length %d", instr.args, instr.argc);
+ QV4::Value *args = stack + instr.args;
+ __qmljs_call_activation_property(context, VALUEPTR(instr.result), instr.name, args, instr.argc);
+ MOTH_END_INSTR(CallActivationProperty)
+
+ MOTH_BEGIN_INSTR(CallBuiltinThrow)
+ __qmljs_throw(context, VALUE(instr.arg));
+ MOTH_END_INSTR(CallBuiltinThrow)
+
+ MOTH_BEGIN_INSTR(EnterTry)
+ VALUE(instr.exceptionVar) = QV4::Value::undefinedValue();
+ try {
+ const uchar *tryCode = ((uchar *)&instr.tryOffset) + instr.tryOffset;
+ run(context, tryCode, stack, stackSize);
+ code = tryCode;
+ context->interpreterInstructionPointer = &code;
+ } catch (QV4::Exception &ex) {
+ ex.accept(context);
+ VALUE(instr.exceptionVar) = ex.value();
+ try {
+ QV4::ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(instr.exceptionVarName, ex.value(), context);
+ const uchar *catchCode = ((uchar *)&instr.catchOffset) + instr.catchOffset;
+ run(catchContext, catchCode, stack, stackSize);
+ code = catchCode;
+ context->interpreterInstructionPointer = &code;
+ context = __qmljs_builtin_pop_scope(catchContext);
+ } catch (QV4::Exception &ex) {
+ ex.accept(context);
+ VALUE(instr.exceptionVar) = ex.value();
+ const uchar *catchCode = ((uchar *)&instr.catchOffset) + instr.catchOffset;
+ run(context, catchCode, stack, stackSize);
+ code = catchCode;
+ context->interpreterInstructionPointer = &code;
+ }
+ }
+ MOTH_END_INSTR(EnterTry)
+
+ MOTH_BEGIN_INSTR(CallBuiltinFinishTry)
+ return QV4::Value();
+ MOTH_END_INSTR(CallBuiltinFinishTry)
+
+ MOTH_BEGIN_INSTR(CallBuiltinPushScope)
+ context = __qmljs_builtin_push_with_scope(VALUE(instr.arg), context);
+ MOTH_END_INSTR(CallBuiltinPushScope)
+
+ MOTH_BEGIN_INSTR(CallBuiltinPopScope)
+ context = __qmljs_builtin_pop_scope(context);
+ MOTH_END_INSTR(CallBuiltinPopScope)
+
+ MOTH_BEGIN_INSTR(CallBuiltinForeachIteratorObject)
+ __qmljs_foreach_iterator_object(context, VALUEPTR(instr.result), VALUE(instr.arg));
+ MOTH_END_INSTR(CallBuiltinForeachIteratorObject)
+
+ MOTH_BEGIN_INSTR(CallBuiltinForeachNextPropertyName)
+ __qmljs_foreach_next_property_name(VALUEPTR(instr.result), VALUE(instr.arg));
+ MOTH_END_INSTR(CallBuiltinForeachNextPropertyName)
+
+ MOTH_BEGIN_INSTR(CallBuiltinDeleteMember)
+ __qmljs_delete_member(context, VALUEPTR(instr.result), VALUE(instr.base), instr.member);
+ MOTH_END_INSTR(CallBuiltinDeleteMember)
+
+ MOTH_BEGIN_INSTR(CallBuiltinDeleteSubscript)
+ __qmljs_delete_subscript(context, VALUEPTR(instr.result), VALUE(instr.base), VALUE(instr.index));
+ MOTH_END_INSTR(CallBuiltinDeleteSubscript)
+
+ MOTH_BEGIN_INSTR(CallBuiltinDeleteName)
+ __qmljs_delete_name(context, VALUEPTR(instr.result), instr.name);
+ MOTH_END_INSTR(CallBuiltinDeleteName)
+
+ MOTH_BEGIN_INSTR(CallBuiltinTypeofMember)
+ __qmljs_builtin_typeof_member(context, VALUEPTR(instr.result), VALUE(instr.base), instr.member);
+ MOTH_END_INSTR(CallBuiltinTypeofMember)
+
+ MOTH_BEGIN_INSTR(CallBuiltinTypeofSubscript)
+ __qmljs_builtin_typeof_element(context, VALUEPTR(instr.result), VALUE(instr.base), VALUE(instr.index));
+ MOTH_END_INSTR(CallBuiltinTypeofSubscript)
+
+ MOTH_BEGIN_INSTR(CallBuiltinTypeofName)
+ __qmljs_builtin_typeof_name(context, VALUEPTR(instr.result), instr.name);
+ MOTH_END_INSTR(CallBuiltinTypeofName)
+
+ MOTH_BEGIN_INSTR(CallBuiltinTypeofValue)
+ __qmljs_builtin_typeof(context, VALUEPTR(instr.result), VALUE(instr.value));
+ MOTH_END_INSTR(CallBuiltinTypeofValue)
+
+ MOTH_BEGIN_INSTR(CallBuiltinPostIncMember)
+ __qmljs_builtin_post_increment_member(context, VALUEPTR(instr.result), VALUE(instr.base), instr.member);
+ MOTH_END_INSTR(CallBuiltinTypeofMember)
+
+ MOTH_BEGIN_INSTR(CallBuiltinPostIncSubscript)
+ __qmljs_builtin_post_increment_element(context, VALUEPTR(instr.result), VALUE(instr.base), VALUEPTR(instr.index));
+ MOTH_END_INSTR(CallBuiltinTypeofSubscript)
+
+ MOTH_BEGIN_INSTR(CallBuiltinPostIncName)
+ __qmljs_builtin_post_increment_name(context, VALUEPTR(instr.result), instr.name);
+ MOTH_END_INSTR(CallBuiltinTypeofName)
+
+ MOTH_BEGIN_INSTR(CallBuiltinPostIncValue)
+ __qmljs_builtin_post_increment(VALUEPTR(instr.result), VALUEPTR(instr.value));
+ MOTH_END_INSTR(CallBuiltinTypeofValue)
+
+ MOTH_BEGIN_INSTR(CallBuiltinPostDecMember)
+ __qmljs_builtin_post_decrement_member(context, VALUEPTR(instr.result), VALUE(instr.base), instr.member);
+ MOTH_END_INSTR(CallBuiltinTypeofMember)
+
+ MOTH_BEGIN_INSTR(CallBuiltinPostDecSubscript)
+ __qmljs_builtin_post_decrement_element(context, VALUEPTR(instr.result), VALUE(instr.base), VALUE(instr.index));
+ MOTH_END_INSTR(CallBuiltinTypeofSubscript)
+
+ MOTH_BEGIN_INSTR(CallBuiltinPostDecName)
+ __qmljs_builtin_post_decrement_name(context, VALUEPTR(instr.result), instr.name);
+ MOTH_END_INSTR(CallBuiltinTypeofName)
+
+ MOTH_BEGIN_INSTR(CallBuiltinPostDecValue)
+ __qmljs_builtin_post_decrement(VALUEPTR(instr.result), VALUEPTR(instr.value));
+ MOTH_END_INSTR(CallBuiltinTypeofValue)
+
+ MOTH_BEGIN_INSTR(CallBuiltinDeclareVar)
+ __qmljs_builtin_declare_var(context, instr.isDeletable, instr.varName);
+ MOTH_END_INSTR(CallBuiltinDeclareVar)
+
+ MOTH_BEGIN_INSTR(CallBuiltinDefineGetterSetter)
+ __qmljs_builtin_define_getter_setter(context, VALUE(instr.object), instr.name, VALUEPTR(instr.getter), VALUEPTR(instr.setter));
+ MOTH_END_INSTR(CallBuiltinDefineGetterSetter)
+
+ MOTH_BEGIN_INSTR(CallBuiltinDefineProperty)
+ __qmljs_builtin_define_property(context, VALUE(instr.object), instr.name, VALUEPTR(instr.value));
+ MOTH_END_INSTR(CallBuiltinDefineProperty)
+
+ MOTH_BEGIN_INSTR(CallBuiltinDefineArray)
+ Q_ASSERT(instr.args + instr.argc <= stackSize);
+ QV4::Value *args = stack + instr.args;
+ __qmljs_builtin_define_array(context, VALUEPTR(instr.result), args, instr.argc);
+ MOTH_END_INSTR(CallBuiltinDefineArray)
+
+ MOTH_BEGIN_INSTR(CallBuiltinDefineObjectLiteral)
+ QV4::Value *args = stack + instr.args;
+ __qmljs_builtin_define_object_literal(context, VALUEPTR(instr.result), args, instr.internalClass);
+ MOTH_END_INSTR(CallBuiltinDefineObjectLiteral)
+
+ MOTH_BEGIN_INSTR(CreateValue)
+ Q_ASSERT(instr.args + instr.argc <= stackSize);
+ QV4::Value *args = stack + instr.args;
+ __qmljs_construct_value(context, VALUEPTR(instr.result), VALUE(instr.func), args, instr.argc);
+ MOTH_END_INSTR(CreateValue)
+
+ MOTH_BEGIN_INSTR(CreateProperty)
+ Q_ASSERT(instr.args + instr.argc <= stackSize);
+ QV4::Value *args = stack + instr.args;
+ __qmljs_construct_property(context, VALUEPTR(instr.result), VALUE(instr.base), instr.name, args, instr.argc);
+ MOTH_END_INSTR(CreateProperty)
+
+ MOTH_BEGIN_INSTR(CreateActivationProperty)
+ TRACE(inline, "property name = %s, args = %d, argc = %d", instr.name->toQString().toUtf8().constData(), instr.args, instr.argc);
+ Q_ASSERT(instr.args + instr.argc <= stackSize);
+ QV4::Value *args = stack + instr.args;
+ __qmljs_construct_activation_property(context, VALUEPTR(instr.result), instr.name, args, instr.argc);
+ MOTH_END_INSTR(CreateActivationProperty)
+
+ MOTH_BEGIN_INSTR(Jump)
+ code = ((uchar *)&instr.offset) + instr.offset;
+ MOTH_END_INSTR(Jump)
+
+ MOTH_BEGIN_INSTR(CJump)
+ uint cond = __qmljs_to_boolean(VALUE(instr.condition));
+ TRACE(condition, "%s", cond ? "TRUE" : "FALSE");
+ if (cond)
+ code = ((uchar *)&instr.offset) + instr.offset;
+ MOTH_END_INSTR(CJump)
+
+ MOTH_BEGIN_INSTR(Unop)
+ instr.alu(VALUEPTR(instr.result), VALUE(instr.source));
+ MOTH_END_INSTR(Unop)
+
+ MOTH_BEGIN_INSTR(Binop)
+ instr.alu(context, VALUEPTR(instr.result), VALUE(instr.lhs), VALUE(instr.rhs));
+ MOTH_END_INSTR(Binop)
+
+ MOTH_BEGIN_INSTR(AddNumberParams)
+ QV4::Value lhs = VALUE(instr.lhs);
+ QV4::Value rhs = VALUE(instr.rhs);
+ if (lhs.isInteger() && rhs.isInteger())
+ VALUE(instr.result) = QV4::add_int32(lhs.integerValue(), rhs.integerValue());
+ else
+ VALUEPTR(instr.result)->setDouble(lhs.asDouble() + rhs.asDouble());
+ MOTH_END_INSTR(AddNumberParams)
+
+ MOTH_BEGIN_INSTR(MulNumberParams)
+ QV4::Value lhs = VALUE(instr.lhs);
+ QV4::Value rhs = VALUE(instr.rhs);
+ if (lhs.isInteger() && rhs.isInteger())
+ VALUE(instr.result) = QV4::mul_int32(lhs.integerValue(), rhs.integerValue());
+ else
+ VALUEPTR(instr.result)->setDouble(lhs.asDouble() * rhs.asDouble());
+ MOTH_END_INSTR(MulNumberParams)
+
+ MOTH_BEGIN_INSTR(SubNumberParams)
+ QV4::Value lhs = VALUE(instr.lhs);
+ QV4::Value rhs = VALUE(instr.rhs);
+ if (lhs.isInteger() && rhs.isInteger())
+ VALUE(instr.result) = QV4::sub_int32(lhs.integerValue(), rhs.integerValue());
+ else
+ VALUEPTR(instr.result)->setDouble(lhs.asDouble() - rhs.asDouble());
+ MOTH_END_INSTR(SubNumberParams)
+
+ MOTH_BEGIN_INSTR(Ret)
+ QV4::Value &result = VALUE(instr.result);
+// TRACE(Ret, "returning value %s", result.toString(context)->toQString().toUtf8().constData());
+ return result;
+ MOTH_END_INSTR(Ret)
+
+ MOTH_BEGIN_INSTR(LoadThis)
+ VALUE(instr.result) = context->thisObject;
+ MOTH_END_INSTR(LoadThis)
+
+ MOTH_BEGIN_INSTR(InplaceElementOp)
+ instr.alu(context,
+ VALUE(instr.base),
+ VALUE(instr.index),
+ VALUE(instr.source));
+ MOTH_END_INSTR(InplaceElementOp)
+
+ MOTH_BEGIN_INSTR(InplaceMemberOp)
+ instr.alu(context,
+ VALUE(instr.base),
+ instr.member,
+ VALUE(instr.source));
+ MOTH_END_INSTR(InplaceMemberOp)
+
+ MOTH_BEGIN_INSTR(InplaceNameOp)
+ TRACE(name, "%s", instr.name->toQString().toUtf8().constData());
+ instr.alu(context, instr.name, VALUE(instr.source));
+ MOTH_END_INSTR(InplaceNameOp)
+
+#ifdef MOTH_THREADED_INTERPRETER
+ // nothing to do
+#else
+ default:
+ qFatal("QQmlJS::Moth::VME: Internal error - unknown instruction %d", genericInstr->common.instructionType);
+ break;
+ }
+ }
+#endif
+
+}
+
+#ifdef MOTH_THREADED_INTERPRETER
+void **VME::instructionJumpTable()
+{
+ static void **jumpTable = 0;
+ if (!jumpTable) {
+ const uchar *code = 0;
+ VME().run(0, code, 0, 0, &jumpTable);
+ }
+ return jumpTable;
+}
+#endif
+
+QV4::Value VME::exec(QV4::ExecutionContext *ctxt, const uchar *code)
+{
+ VME vme;
+ return vme.run(ctxt, code);
+}
diff --git a/src/qml/qml/v8/qv8stringwrapper_p.h b/src/qml/qml/v4/moth/qv4vme_moth_p.h
index 6720e06199..59692500ba 100644
--- a/src/qml/qml/v8/qv8stringwrapper_p.h
+++ b/src/qml/qml/v4/moth/qv4vme_moth_p.h
@@ -39,40 +39,38 @@
**
****************************************************************************/
-#ifndef QQMLV8STRINGWRAPPER_P_H
-#define QQMLV8STRINGWRAPPER_P_H
+#ifndef QV4VME_MOTH_P_H
+#define QV4VME_MOTH_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/qtqmlglobal_p.h>
-
-#include <QtCore/qstring.h>
-#include <private/qv8_p.h>
+#include <private/qv4runtime_p.h>
+#include "qv4instr_moth_p.h"
QT_BEGIN_NAMESPACE
-class Q_QML_PRIVATE_EXPORT QV8StringWrapper
+namespace QQmlJS {
+namespace Moth {
+
+class VME
{
public:
- QV8StringWrapper();
- ~QV8StringWrapper();
+ static QV4::Value exec(QV4::ExecutionContext *, const uchar *);
- void init();
- void destroy();
+#ifdef MOTH_THREADED_INTERPRETER
+ static void **instructionJumpTable();
+#endif
- v8::Local<v8::String> toString(const QString &);
- QString toString(v8::Handle<v8::String>);
+private:
+ QV4::Value run(QV4::ExecutionContext *, const uchar *&code,
+ QV4::Value *stack = 0, unsigned stackSize = 0
+#ifdef MOTH_THREADED_INTERPRETER
+ , void ***storeJumpTable = 0
+#endif
+ );
};
+} // namespace Moth
+} // namespace QQmlJS
+
QT_END_NAMESPACE
-#endif // QQMLV8STRINGWRAPPER_P_H
+#endif // QV4VME_MOTH_P_H
diff --git a/src/qml/qml/v4/qv4_llvm_p.h b/src/qml/qml/v4/qv4_llvm_p.h
new file mode 100644
index 0000000000..50bd7d3831
--- /dev/null
+++ b/src/qml/qml/v4/qv4_llvm_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4_LLVM_P_H
+#define QV4_LLVM_P_H
+
+#include "qv4global_p.h"
+#include "qv4jsir_p.h"
+
+#include <QtCore/QString>
+
+namespace QQmlJS {
+
+// Note: keep this enum in sync with the command-line option!
+enum LLVMOutputType {
+ LLVMOutputJit = -1,
+ LLVMOutputIR = 0, // .ll
+ LLVMOutputBitcode = 1, // .bc
+ LLVMOutputAssembler = 2, // .s
+ LLVMOutputObject = 3 // .o
+};
+
+Q_QML_EXPORT int compileWithLLVM(V4IR::Module *module, const QString &fileName, LLVMOutputType outputType, int (*)(void *));
+
+} // QQmlJS
+
+#endif // QV4_LLVM_P_H
diff --git a/src/qml/qml/v8/qv8_p.h b/src/qml/qml/v4/qv4alloca_p.h
index dc5ecc31bc..e4580da3d8 100644
--- a/src/qml/qml/v8/qv8_p.h
+++ b/src/qml/qml/v4/qv4alloca_p.h
@@ -39,4 +39,16 @@
**
****************************************************************************/
-#include <private/v8.h>
+#ifndef QV4_ALLOCA_H
+#define QV4_ALLOCA_H
+
+#include <qglobal.h>
+
+#if defined(Q_OS_WIN)
+#include <malloc.h>
+#define alloca _alloca
+#else
+#include <alloca.h>
+#endif
+
+#endif
diff --git a/src/qml/qml/v4/qv4argumentsobject.cpp b/src/qml/qml/v4/qv4argumentsobject.cpp
new file mode 100644
index 0000000000..6247ef1504
--- /dev/null
+++ b/src/qml/qml/v4/qv4argumentsobject.cpp
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qv4argumentsobject_p.h>
+
+using namespace QV4;
+
+static Value throwTypeError(SimpleCallContext *ctx)
+{
+ ctx->throwTypeError();
+ return Value::undefinedValue();
+}
+
+DEFINE_MANAGED_VTABLE(ArgumentsObject);
+
+ArgumentsObject::ArgumentsObject(CallContext *context, int formalParameterCount, int actualParameterCount)
+ : Object(context->engine), context(context)
+{
+ vtbl = &static_vtbl;
+ type = Type_ArgumentsObject;
+
+ defineDefaultProperty(context->engine->id_length, Value::fromInt32(actualParameterCount));
+ if (context->strictMode) {
+ for (uint i = 0; i < context->argumentCount; ++i)
+ Object::put(context, QString::number(i), context->arguments[i]);
+ FunctionObject *thrower = context->engine->newBuiltinFunction(context, 0, throwTypeError);
+ Property pd = Property::fromAccessor(thrower, thrower);
+ __defineOwnProperty__(context, QStringLiteral("callee"), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ __defineOwnProperty__(context, QStringLiteral("caller"), pd, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
+ } else {
+ uint numAccessors = qMin(formalParameterCount, actualParameterCount);
+ context->engine->requireArgumentsAccessors(numAccessors);
+ for (uint i = 0; i < (uint)numAccessors; ++i) {
+ mappedArguments.append(context->argument(i));
+ __defineOwnProperty__(context, i, context->engine->argumentsAccessors.at(i), Attr_Accessor);
+ }
+ for (uint i = numAccessors; i < qMin((uint)actualParameterCount, context->argumentCount); ++i) {
+ Property pd = Property::fromValue(context->argument(i));
+ __defineOwnProperty__(context, i, pd, Attr_Data);
+ }
+ defineDefaultProperty(context, QStringLiteral("callee"), Value::fromObject(context->function));
+ isNonStrictArgumentsObject = true;
+ }
+}
+
+void ArgumentsObject::destroy(Managed *that)
+{
+ static_cast<ArgumentsObject *>(that)->~ArgumentsObject();
+}
+
+bool ArgumentsObject::defineOwnProperty(ExecutionContext *ctx, uint index, const Property &desc, PropertyAttributes attrs)
+{
+ uint pidx = propertyIndexFromArrayIndex(index);
+ Property *pd = arrayData + pidx;
+ Property map;
+ PropertyAttributes mapAttrs;
+ bool isMapped = false;
+ if (pd && index < (uint)mappedArguments.size())
+ isMapped = arrayAttributes && arrayAttributes[pidx].isAccessor() && pd->getter() == context->engine->argumentsAccessors.at(index).getter();
+
+ if (isMapped) {
+ map = *pd;
+ mapAttrs = arrayAttributes[pidx];
+ arrayAttributes[pidx] = Attr_Data;
+ pd->value = mappedArguments.at(index);
+ }
+
+ isNonStrictArgumentsObject = false;
+ bool strict = ctx->strictMode;
+ ctx->strictMode = false;
+ bool result = Object::__defineOwnProperty__(ctx, index, desc, attrs);
+ ctx->strictMode = strict;
+ isNonStrictArgumentsObject = true;
+
+ if (isMapped && attrs.isData()) {
+ if (!attrs.isGeneric()) {
+ Value arg = desc.value;
+ map.setter()->call(Value::fromObject(this), &arg, 1);
+ }
+ if (attrs.isWritable()) {
+ *pd = map;
+ arrayAttributes[pidx] = mapAttrs;
+ }
+ }
+
+ if (ctx->strictMode && !result)
+ ctx->throwTypeError();
+ return result;
+}
+
+DEFINE_MANAGED_VTABLE(ArgumentsGetterFunction);
+
+Value ArgumentsGetterFunction::call(Managed *getter, const Value &thisObject, Value *, int)
+{
+ ArgumentsGetterFunction *g = static_cast<ArgumentsGetterFunction *>(getter);
+ Object *that = thisObject.asObject();
+ if (!that)
+ getter->engine()->current->throwTypeError();
+ ArgumentsObject *o = that->asArgumentsObject();
+ if (!o)
+ getter->engine()->current->throwTypeError();
+
+ assert(g->index < o->context->argumentCount);
+ return o->context->argument(g->index);
+}
+
+DEFINE_MANAGED_VTABLE(ArgumentsSetterFunction);
+
+Value ArgumentsSetterFunction::call(Managed *setter, const Value &thisObject, Value *args, int argc)
+{
+ ArgumentsSetterFunction *s = static_cast<ArgumentsSetterFunction *>(setter);
+ Object *that = thisObject.asObject();
+ if (!that)
+ setter->engine()->current->throwTypeError();
+ ArgumentsObject *o = that->asArgumentsObject();
+ if (!o)
+ setter->engine()->current->throwTypeError();
+
+ assert(s->index < o->context->argumentCount);
+ o->context->arguments[s->index] = argc ? args[0] : Value::undefinedValue();
+ return Value::undefinedValue();
+}
+
+void ArgumentsObject::markObjects(Managed *that)
+{
+ ArgumentsObject *o = static_cast<ArgumentsObject *>(that);
+ o->context->mark();
+ for (int i = 0; i < o->mappedArguments.size(); ++i) {
+ Managed *m = o->mappedArguments.at(i).asManaged();
+ if (m)
+ m->mark();
+ }
+ Object::markObjects(that);
+}
diff --git a/src/qml/qml/v4/qv4argumentsobject_p.h b/src/qml/qml/v4/qv4argumentsobject_p.h
new file mode 100644
index 0000000000..3d760b8937
--- /dev/null
+++ b/src/qml/qml/v4/qv4argumentsobject_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4ARGUMENTSOBJECTS_H
+#define QV4ARGUMENTSOBJECTS_H
+
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct ArgumentsGetterFunction: FunctionObject
+{
+ uint index;
+
+ ArgumentsGetterFunction(ExecutionContext *scope, uint index)
+ : FunctionObject(scope), index(index) { vtbl = &static_vtbl; }
+
+ static Value call(Managed *that, const Value &, Value *, int);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct ArgumentsSetterFunction: FunctionObject
+{
+ uint index;
+
+ ArgumentsSetterFunction(ExecutionContext *scope, uint index)
+ : FunctionObject(scope), index(index) { vtbl = &static_vtbl; }
+
+ static Value call(Managed *that, const Value &, Value *, int);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+
+struct ArgumentsObject: Object {
+ CallContext *context;
+ QVector<Value> mappedArguments;
+ ArgumentsObject(CallContext *context, int formalParameterCount, int actualParameterCount);
+ ~ArgumentsObject() {}
+
+ bool defineOwnProperty(ExecutionContext *ctx, uint index, const Property &desc, PropertyAttributes attrs);
+
+ static void markObjects(Managed *that);
+protected:
+ static const ManagedVTable static_vtbl;
+ static void destroy(Managed *);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/src/qml/qml/v4/qv4arrayobject.cpp b/src/qml/qml/v4/qv4arrayobject.cpp
new file mode 100644
index 0000000000..b1f25177dd
--- /dev/null
+++ b/src/qml/qml/v4/qv4arrayobject.cpp
@@ -0,0 +1,865 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4arrayobject_p.h"
+#include "qv4sparsearray_p.h"
+
+using namespace QV4;
+
+DEFINE_MANAGED_VTABLE(ArrayCtor);
+
+ArrayCtor::ArrayCtor(ExecutionContext *scope)
+ : FunctionObject(scope, scope->engine->newIdentifier(QStringLiteral("Array")))
+{
+ vtbl = &static_vtbl;
+}
+
+Value ArrayCtor::construct(Managed *m, Value *argv, int argc)
+{
+ ExecutionEngine *v4 = m->engine();
+ ArrayObject *a = v4->newArrayObject();
+ uint len;
+ if (argc == 1 && argv[0].isNumber()) {
+ bool ok;
+ len = argv[0].asArrayLength(&ok);
+
+ if (!ok)
+ v4->current->throwRangeError(argv[0]);
+
+ if (len < 0x1000)
+ a->arrayReserve(len);
+ } else {
+ len = argc;
+ a->arrayReserve(len);
+ for (unsigned int i = 0; i < len; ++i)
+ a->arrayData[i].value = argv[i];
+ a->arrayDataLen = len;
+ }
+ a->setArrayLengthUnchecked(len);
+
+ return Value::fromObject(a);
+}
+
+Value ArrayCtor::call(Managed *that, const Value &, Value *argv, int argc)
+{
+ return construct(that, argv, argc);
+}
+
+ArrayPrototype::ArrayPrototype(ExecutionContext *context)
+ : ArrayObject(context->engine)
+{
+}
+
+void ArrayPrototype::init(ExecutionContext *ctx, const Value &ctor)
+{
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(1));
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this));
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("isArray"), method_isArray, 1);
+ defineDefaultProperty(ctx, QStringLiteral("constructor"), ctor);
+ defineDefaultProperty(ctx, QStringLiteral("toString"), method_toString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("toLocaleString"), method_toLocaleString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("concat"), method_concat, 1);
+ defineDefaultProperty(ctx, QStringLiteral("join"), method_join, 1);
+ defineDefaultProperty(ctx, QStringLiteral("pop"), method_pop, 0);
+ defineDefaultProperty(ctx, QStringLiteral("push"), method_push, 1);
+ defineDefaultProperty(ctx, QStringLiteral("reverse"), method_reverse, 0);
+ defineDefaultProperty(ctx, QStringLiteral("shift"), method_shift, 0);
+ defineDefaultProperty(ctx, QStringLiteral("slice"), method_slice, 2);
+ defineDefaultProperty(ctx, QStringLiteral("sort"), method_sort, 1);
+ defineDefaultProperty(ctx, QStringLiteral("splice"), method_splice, 2);
+ defineDefaultProperty(ctx, QStringLiteral("unshift"), method_unshift, 1);
+ defineDefaultProperty(ctx, QStringLiteral("indexOf"), method_indexOf, 1);
+ defineDefaultProperty(ctx, QStringLiteral("lastIndexOf"), method_lastIndexOf, 1);
+ defineDefaultProperty(ctx, QStringLiteral("every"), method_every, 1);
+ defineDefaultProperty(ctx, QStringLiteral("some"), method_some, 1);
+ defineDefaultProperty(ctx, QStringLiteral("forEach"), method_forEach, 1);
+ defineDefaultProperty(ctx, QStringLiteral("map"), method_map, 1);
+ defineDefaultProperty(ctx, QStringLiteral("filter"), method_filter, 1);
+ defineDefaultProperty(ctx, QStringLiteral("reduce"), method_reduce, 1);
+ defineDefaultProperty(ctx, QStringLiteral("reduceRight"), method_reduceRight, 1);
+}
+
+uint ArrayPrototype::getLength(ExecutionContext *ctx, Object *o)
+{
+ if (o->isArrayObject())
+ return o->arrayLength();
+ return o->get(ctx->engine->id_length).toUInt32();
+}
+
+Value ArrayPrototype::method_isArray(SimpleCallContext *ctx)
+{
+ Value arg = ctx->argument(0);
+ bool isArray = arg.asArrayObject();
+ return Value::fromBoolean(isArray);
+}
+
+Value ArrayPrototype::method_toString(SimpleCallContext *ctx)
+{
+ return method_join(ctx);
+}
+
+Value ArrayPrototype::method_toLocaleString(SimpleCallContext *ctx)
+{
+ return method_toString(ctx);
+}
+
+Value ArrayPrototype::method_concat(SimpleCallContext *ctx)
+{
+ ArrayObject *result = ctx->engine->newArrayObject();
+
+ if (ArrayObject *instance = ctx->thisObject.asArrayObject()) {
+ result->copyArrayData(instance);
+ } else {
+ QString v = ctx->thisObject.toString(ctx)->toQString();
+ result->arraySet(0, Value::fromString(ctx, v));
+ }
+
+ for (uint i = 0; i < ctx->argumentCount; ++i) {
+ Value arg = ctx->argument(i);
+
+ if (ArrayObject *elt = arg.asArrayObject())
+ result->arrayConcat(elt);
+
+ else
+ result->arraySet(getLength(ctx, result), arg);
+ }
+
+ return Value::fromObject(result);
+}
+
+Value ArrayPrototype::method_join(SimpleCallContext *ctx)
+{
+ Value arg = ctx->argument(0);
+
+ QString r4;
+ if (arg.isUndefined())
+ r4 = QStringLiteral(",");
+ else
+ r4 = arg.toString(ctx)->toQString();
+
+ Value self = ctx->thisObject;
+ const Value length = self.property(ctx, ctx->engine->id_length);
+ const quint32 r2 = Value::toUInt32(length.isUndefined() ? 0 : length.toNumber());
+
+ static QSet<Object *> visitedArrayElements;
+
+ if (! r2 || visitedArrayElements.contains(self.objectValue()))
+ return Value::fromString(ctx, QString());
+
+ // avoid infinite recursion
+ visitedArrayElements.insert(self.objectValue());
+
+ QString R;
+
+ // ### FIXME
+ if (ArrayObject *a = self.asArrayObject()) {
+ for (uint i = 0; i < a->arrayLength(); ++i) {
+ if (i)
+ R += r4;
+
+ Value e = a->getIndexed(i);
+ if (! (e.isUndefined() || e.isNull()))
+ R += e.toString(ctx)->toQString();
+ }
+ } else {
+ //
+ // crazy!
+ //
+ Value r6 = self.property(ctx, ctx->engine->newString(QStringLiteral("0")));
+ if (!(r6.isUndefined() || r6.isNull()))
+ R = r6.toString(ctx)->toQString();
+
+ for (quint32 k = 1; k < r2; ++k) {
+ R += r4;
+
+ String *name = Value::fromDouble(k).toString(ctx);
+ Value r12 = self.property(ctx, name);
+
+ if (! (r12.isUndefined() || r12.isNull()))
+ R += r12.toString(ctx)->toQString();
+ }
+ }
+
+ visitedArrayElements.remove(self.objectValue());
+ return Value::fromString(ctx, R);
+}
+
+Value ArrayPrototype::method_pop(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+ uint len = getLength(ctx, instance);
+
+ if (!len) {
+ if (!instance->isArrayObject())
+ instance->put(ctx->engine->id_length, Value::fromInt32(0));
+ return Value::undefinedValue();
+ }
+
+ Value result = instance->getIndexed(len - 1);
+
+ instance->deleteIndexedProperty(len - 1);
+ if (instance->isArrayObject())
+ instance->setArrayLengthUnchecked(len - 1);
+ else
+ instance->put(ctx->engine->id_length, Value::fromDouble(len - 1));
+ return result;
+}
+
+Value ArrayPrototype::method_push(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+ uint len = getLength(ctx, instance);
+
+ if (len + ctx->argumentCount < len) {
+ // ughh...
+ double l = len;
+ for (double i = 0; i < ctx->argumentCount; ++i) {
+ Value idx = Value::fromDouble(l + i);
+ instance->put(idx.toString(ctx), ctx->argument(i));
+ }
+ double newLen = l + ctx->argumentCount;
+ if (!instance->isArrayObject())
+ instance->put(ctx->engine->id_length, Value::fromDouble(newLen));
+ else
+ ctx->throwRangeError(Value::fromString(ctx, QStringLiteral("Array.prototype.push: Overflow")));
+ return Value::fromDouble(newLen);
+ }
+
+ bool protoHasArray = false;
+ Object *p = instance;
+ while ((p = p->prototype))
+ if (p->arrayDataLen)
+ protoHasArray = true;
+
+ if (!protoHasArray && instance->arrayDataLen <= len) {
+ for (uint i = 0; i < ctx->argumentCount; ++i) {
+ Value v = ctx->argument(i);
+
+ if (!instance->sparseArray) {
+ if (len >= instance->arrayAlloc)
+ instance->arrayReserve(len + 1);
+ instance->arrayData[len].value = v;
+ if (instance->arrayAttributes)
+ instance->arrayAttributes[len] = Attr_Data;
+ instance->arrayDataLen = len + 1;
+ } else {
+ uint i = instance->allocArrayValue(v);
+ instance->sparseArray->push_back(i, len);
+ }
+ ++len;
+ }
+ } else {
+ for (uint i = 0; i < ctx->argumentCount; ++i)
+ instance->putIndexed(len + i, ctx->argument(i));
+ len += ctx->argumentCount;
+ }
+ if (instance->isArrayObject())
+ instance->setArrayLengthUnchecked(len);
+ else
+ instance->put(ctx->engine->id_length, Value::fromDouble(len));
+
+ if (len < INT_MAX)
+ return Value::fromInt32(len);
+ return Value::fromDouble((double)len);
+
+}
+
+Value ArrayPrototype::method_reverse(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+ uint length = getLength(ctx, instance);
+
+ int lo = 0, hi = length - 1;
+
+ for (; lo < hi; ++lo, --hi) {
+ bool loExists, hiExists;
+ Value lval = instance->getIndexed(lo, &loExists);
+ Value hval = instance->getIndexed(hi, &hiExists);
+ if (hiExists)
+ instance->putIndexed(lo, hval);
+ else
+ instance->deleteIndexedProperty(lo);
+ if (loExists)
+ instance->putIndexed(hi, lval);
+ else
+ instance->deleteIndexedProperty(hi);
+ }
+ return Value::fromObject(instance);
+}
+
+Value ArrayPrototype::method_shift(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+ uint len = getLength(ctx, instance);
+
+ if (!len) {
+ if (!instance->isArrayObject())
+ instance->put(ctx->engine->id_length, Value::fromInt32(0));
+ return Value::undefinedValue();
+ }
+
+ Property *front = 0;
+ uint pidx = instance->propertyIndexFromArrayIndex(0);
+ if (pidx < UINT_MAX && (!instance->arrayAttributes || !instance->arrayAttributes[0].isGeneric()))
+ front = instance->arrayData + pidx;
+
+ Value result = front ? instance->getValue(front, instance->arrayAttributes ? instance->arrayAttributes[pidx] : Attr_Data) : Value::undefinedValue();
+
+ bool protoHasArray = false;
+ Object *p = instance;
+ while ((p = p->prototype))
+ if (p->arrayDataLen)
+ protoHasArray = true;
+
+ if (!protoHasArray && instance->arrayDataLen <= len) {
+ if (!instance->sparseArray) {
+ if (instance->arrayDataLen) {
+ ++instance->arrayOffset;
+ ++instance->arrayData;
+ --instance->arrayDataLen;
+ --instance->arrayAlloc;
+ if (instance->arrayAttributes)
+ ++instance->arrayAttributes;
+ }
+ } else {
+ uint idx = instance->sparseArray->pop_front();
+ instance->freeArrayValue(idx);
+ }
+ } else {
+ // do it the slow way
+ for (uint k = 1; k < len; ++k) {
+ bool exists;
+ Value v = instance->getIndexed(k, &exists);
+ if (exists)
+ instance->putIndexed(k - 1, v);
+ else
+ instance->deleteIndexedProperty(k - 1);
+ }
+ instance->deleteIndexedProperty(len - 1);
+ }
+
+ if (instance->isArrayObject())
+ instance->setArrayLengthUnchecked(len - 1);
+ else
+ instance->put(ctx->engine->id_length, Value::fromDouble(len - 1));
+ return result;
+}
+
+Value ArrayPrototype::method_slice(SimpleCallContext *ctx)
+{
+ Object *o = ctx->thisObject.toObject(ctx);
+
+ ArrayObject *result = ctx->engine->newArrayObject();
+ uint len = o->get(ctx->engine->id_length).toUInt32();
+ double s = ctx->argument(0).toInteger();
+ uint start;
+ if (s < 0)
+ start = (uint)qMax(len + s, 0.);
+ else if (s > len)
+ start = len;
+ else
+ start = (uint) s;
+ uint end = len;
+ if (!ctx->argument(1).isUndefined()) {
+ double e = ctx->argument(1).toInteger();
+ if (e < 0)
+ end = (uint)qMax(len + e, 0.);
+ else if (e > len)
+ end = len;
+ else
+ end = (uint) e;
+ }
+
+ uint n = 0;
+ for (uint i = start; i < end; ++i) {
+ bool exists;
+ Value v = o->getIndexed(i, &exists);
+ if (exists) {
+ result->arraySet(n, v);
+ }
+ ++n;
+ }
+ return Value::fromObject(result);
+}
+
+Value ArrayPrototype::method_sort(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+
+ uint len = getLength(ctx, instance);
+
+ Value comparefn = ctx->argument(0);
+ instance->arraySort(ctx, instance, comparefn, len);
+ return ctx->thisObject;
+}
+
+Value ArrayPrototype::method_splice(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+ uint len = getLength(ctx, instance);
+
+ ArrayObject *newArray = ctx->engine->newArrayObject();
+
+ double rs = ctx->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(ctx->argument(1).toInteger(), 0.), (double)(len - start));
+
+ newArray->arrayReserve(deleteCount);
+ Property *pd = newArray->arrayData;
+ for (uint i = 0; i < deleteCount; ++i) {
+ pd->value = instance->getIndexed(start + i);
+ ++pd;
+ }
+ newArray->arrayDataLen = deleteCount;
+ newArray->setArrayLengthUnchecked(deleteCount);
+
+ uint itemCount = ctx->argumentCount < 2 ? 0 : ctx->argumentCount - 2;
+
+ if (itemCount < deleteCount) {
+ for (uint k = start; k < len - deleteCount; ++k) {
+ bool exists;
+ Value v = instance->getIndexed(k + deleteCount, &exists);
+ if (exists)
+ instance->putIndexed(k + itemCount, v);
+ else
+ instance->deleteIndexedProperty(k + itemCount);
+ }
+ for (uint k = len; k > len - deleteCount + itemCount; --k)
+ instance->deleteIndexedProperty(k - 1);
+ } else if (itemCount > deleteCount) {
+ uint k = len - deleteCount;
+ while (k > start) {
+ bool exists;
+ Value v = instance->getIndexed(k + deleteCount - 1, &exists);
+ if (exists)
+ instance->putIndexed(k + itemCount - 1, v);
+ else
+ instance->deleteIndexedProperty(k + itemCount - 1);
+ --k;
+ }
+ }
+
+ for (uint i = 0; i < itemCount; ++i)
+ instance->putIndexed(start + i, ctx->argument(i + 2));
+
+ ctx->strictMode = true;
+ instance->put(ctx->engine->id_length, Value::fromDouble(len - deleteCount + itemCount));
+
+ return Value::fromObject(newArray);
+}
+
+Value ArrayPrototype::method_unshift(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+ uint len = getLength(ctx, instance);
+
+ bool protoHasArray = false;
+ Object *p = instance;
+ while ((p = p->prototype))
+ if (p->arrayDataLen)
+ protoHasArray = true;
+
+ if (!protoHasArray && instance->arrayDataLen <= len) {
+ for (int i = ctx->argumentCount - 1; i >= 0; --i) {
+ Value v = ctx->argument(i);
+
+ if (!instance->sparseArray) {
+ if (!instance->arrayOffset)
+ instance->getArrayHeadRoom();
+
+ --instance->arrayOffset;
+ --instance->arrayData;
+ ++instance->arrayDataLen;
+ if (instance->arrayAttributes) {
+ --instance->arrayAttributes;
+ *instance->arrayAttributes = Attr_Data;
+ }
+ instance->arrayData->value = v;
+ } else {
+ uint idx = instance->allocArrayValue(v);
+ instance->sparseArray->push_front(idx);
+ }
+ }
+ } else {
+ for (uint k = len; k > 0; --k) {
+ bool exists;
+ Value v = instance->getIndexed(k - 1, &exists);
+ if (exists)
+ instance->putIndexed(k + ctx->argumentCount - 1, v);
+ else
+ instance->deleteIndexedProperty(k + ctx->argumentCount - 1);
+ }
+ for (uint i = 0; i < ctx->argumentCount; ++i)
+ instance->putIndexed(i, ctx->argument(i));
+ }
+
+ uint newLen = len + ctx->argumentCount;
+ if (instance->isArrayObject())
+ instance->setArrayLengthUnchecked(newLen);
+ else
+ instance->put(ctx->engine->id_length, Value::fromDouble(newLen));
+
+ if (newLen < INT_MAX)
+ return Value::fromInt32(newLen);
+ return Value::fromDouble((double)newLen);
+}
+
+Value ArrayPrototype::method_indexOf(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+ uint len = getLength(ctx, instance);
+ if (!len)
+ return Value::fromInt32(-1);
+
+ Value searchValue;
+ uint fromIndex = 0;
+
+ if (ctx->argumentCount >= 1)
+ searchValue = ctx->argument(0);
+ else
+ searchValue = Value::undefinedValue();
+
+ if (ctx->argumentCount >= 2) {
+ double f = ctx->argument(1).toInteger();
+ if (f >= len)
+ return Value::fromInt32(-1);
+ if (f < 0)
+ f = qMax(len + f, 0.);
+ fromIndex = (uint) f;
+ }
+
+ if (instance->isStringObject()) {
+ for (uint k = fromIndex; k < len; ++k) {
+ bool exists;
+ Value v = instance->getIndexed(k, &exists);
+ if (exists && __qmljs_strict_equal(v, searchValue))
+ return Value::fromDouble(k);
+ }
+ return Value::fromInt32(-1);
+ }
+
+ return instance->arrayIndexOf(searchValue, fromIndex, len, ctx, instance);
+}
+
+Value ArrayPrototype::method_lastIndexOf(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+ uint len = getLength(ctx, instance);
+ if (!len)
+ return Value::fromInt32(-1);
+
+ Value searchValue;
+ uint fromIndex = len;
+
+ if (ctx->argumentCount >= 1)
+ searchValue = ctx->argument(0);
+ else
+ searchValue = Value::undefinedValue();
+
+ if (ctx->argumentCount >= 2) {
+ double f = ctx->argument(1).toInteger();
+ if (f > 0)
+ f = qMin(f, (double)(len - 1));
+ else if (f < 0) {
+ f = len + f;
+ if (f < 0)
+ return Value::fromInt32(-1);
+ }
+ fromIndex = (uint) f + 1;
+ }
+
+ for (uint k = fromIndex; k > 0;) {
+ --k;
+ bool exists;
+ Value v = instance->getIndexed(k, &exists);
+ if (exists && __qmljs_strict_equal(v, searchValue))
+ return Value::fromDouble(k);
+ }
+ return Value::fromInt32(-1);
+}
+
+Value ArrayPrototype::method_every(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+
+ uint len = getLength(ctx, instance);
+
+ FunctionObject *callback = ctx->argument(0).asFunctionObject();
+ if (!callback)
+ ctx->throwTypeError();
+
+ Value thisArg = ctx->argument(1);
+
+ bool ok = true;
+ for (uint k = 0; ok && k < len; ++k) {
+ bool exists;
+ Value v = instance->getIndexed(k, &exists);
+ if (!exists)
+ continue;
+
+ Value args[3];
+ args[0] = v;
+ args[1] = Value::fromDouble(k);
+ args[2] = ctx->thisObject;
+ Value r = callback->call(thisArg, args, 3);
+ ok = r.toBoolean();
+ }
+ return Value::fromBoolean(ok);
+}
+
+Value ArrayPrototype::method_some(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+
+ uint len = getLength(ctx, instance);
+
+ FunctionObject *callback = ctx->argument(0).asFunctionObject();
+ if (!callback)
+ ctx->throwTypeError();
+
+ Value thisArg = ctx->argument(1);
+
+ for (uint k = 0; k < len; ++k) {
+ bool exists;
+ Value v = instance->getIndexed(k, &exists);
+ if (!exists)
+ continue;
+
+ Value args[3];
+ args[0] = v;
+ args[1] = Value::fromDouble(k);
+ args[2] = ctx->thisObject;
+ Value r = callback->call(thisArg, args, 3);
+ if (r.toBoolean())
+ return Value::fromBoolean(true);
+ }
+ return Value::fromBoolean(false);
+}
+
+Value ArrayPrototype::method_forEach(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+
+ uint len = getLength(ctx, instance);
+
+ FunctionObject *callback = ctx->argument(0).asFunctionObject();
+ if (!callback)
+ ctx->throwTypeError();
+
+ Value thisArg = ctx->argument(1);
+
+ for (uint k = 0; k < len; ++k) {
+ bool exists;
+ Value v = instance->getIndexed(k, &exists);
+ if (!exists)
+ continue;
+
+ Value args[3];
+ args[0] = v;
+ args[1] = Value::fromDouble(k);
+ args[2] = ctx->thisObject;
+ callback->call(thisArg, args, 3);
+ }
+ return Value::undefinedValue();
+}
+
+Value ArrayPrototype::method_map(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+
+ uint len = getLength(ctx, instance);
+
+ FunctionObject *callback = ctx->argument(0).asFunctionObject();
+ if (!callback)
+ ctx->throwTypeError();
+
+ Value thisArg = ctx->argument(1);
+
+ ArrayObject *a = ctx->engine->newArrayObject();
+ a->arrayReserve(len);
+ a->setArrayLengthUnchecked(len);
+
+ for (uint k = 0; k < len; ++k) {
+ bool exists;
+ Value v = instance->getIndexed(k, &exists);
+ if (!exists)
+ continue;
+
+ Value args[3];
+ args[0] = v;
+ args[1] = Value::fromDouble(k);
+ args[2] = ctx->thisObject;
+ Value mapped = callback->call(thisArg, args, 3);
+ a->arraySet(k, mapped);
+ }
+ return Value::fromObject(a);
+}
+
+Value ArrayPrototype::method_filter(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+
+ uint len = getLength(ctx, instance);
+
+ FunctionObject *callback = ctx->argument(0).asFunctionObject();
+ if (!callback)
+ ctx->throwTypeError();
+
+ Value thisArg = ctx->argument(1);
+
+ ArrayObject *a = ctx->engine->newArrayObject();
+ a->arrayReserve(len);
+
+ uint to = 0;
+ for (uint k = 0; k < len; ++k) {
+ bool exists;
+ Value v = instance->getIndexed(k, &exists);
+ if (!exists)
+ continue;
+
+ Value args[3];
+ args[0] = v;
+ args[1] = Value::fromDouble(k);
+ args[2] = ctx->thisObject;
+ Value selected = callback->call(thisArg, args, 3);
+ if (selected.toBoolean()) {
+ a->arraySet(to, v);
+ ++to;
+ }
+ }
+ return Value::fromObject(a);
+}
+
+Value ArrayPrototype::method_reduce(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+
+ uint len = getLength(ctx, instance);
+
+ FunctionObject *callback = ctx->argument(0).asFunctionObject();
+ if (!callback)
+ ctx->throwTypeError();
+
+ uint k = 0;
+ Value acc;
+ if (ctx->argumentCount > 1) {
+ acc = ctx->argument(1);
+ } else {
+ bool kPresent = false;
+ while (k < len && !kPresent) {
+ Value v = instance->getIndexed(k, &kPresent);
+ if (kPresent)
+ acc = v;
+ ++k;
+ }
+ if (!kPresent)
+ ctx->throwTypeError();
+ }
+
+ while (k < len) {
+ bool kPresent;
+ Value v = instance->getIndexed(k, &kPresent);
+ if (kPresent) {
+ Value args[4];
+ args[0] = acc;
+ args[1] = v;
+ args[2] = Value::fromDouble(k);
+ args[3] = ctx->thisObject;
+ acc = callback->call(Value::undefinedValue(), args, 4);
+ }
+ ++k;
+ }
+ return acc;
+}
+
+Value ArrayPrototype::method_reduceRight(SimpleCallContext *ctx)
+{
+ Object *instance = ctx->thisObject.toObject(ctx);
+
+ uint len = getLength(ctx, instance);
+
+ FunctionObject *callback = ctx->argument(0).asFunctionObject();
+ if (!callback)
+ ctx->throwTypeError();
+
+ if (len == 0) {
+ if (ctx->argumentCount == 1)
+ ctx->throwTypeError();
+ return ctx->argument(1);
+ }
+
+ uint k = len;
+ Value acc;
+ if (ctx->argumentCount > 1) {
+ acc = ctx->argument(1);
+ } else {
+ bool kPresent = false;
+ while (k > 0 && !kPresent) {
+ Value v = instance->getIndexed(k - 1, &kPresent);
+ if (kPresent)
+ acc = v;
+ --k;
+ }
+ if (!kPresent)
+ ctx->throwTypeError();
+ }
+
+ while (k > 0) {
+ bool kPresent;
+ Value v = instance->getIndexed(k - 1, &kPresent);
+ if (kPresent) {
+ Value args[4];
+ args[0] = acc;
+ args[1] = v;
+ args[2] = Value::fromDouble(k - 1);
+ args[3] = ctx->thisObject;
+ acc = callback->call(Value::undefinedValue(), args, 4);
+ }
+ --k;
+ }
+ return acc;
+}
+
diff --git a/src/qml/qml/v4/qv4program_p.h b/src/qml/qml/v4/qv4arrayobject_p.h
index fb23e863af..13c3882f4f 100644
--- a/src/qml/qml/v4/qv4program_p.h
+++ b/src/qml/qml/v4/qv4arrayobject_p.h
@@ -38,91 +38,63 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+#ifndef QV4ARRAYOBJECT_H
+#define QV4ARRAYOBJECT_H
-#ifndef QV4PROGRAM_P_H
-#define QV4PROGRAM_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 "qv4instruction_p.h"
-
-#ifdef Q_CC_MSVC
-// nonstandard extension used : zero-sized array in struct/union.
-# pragma warning( disable : 4200 )
-#endif
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+#include <QtCore/qnumeric.h>
QT_BEGIN_NAMESPACE
-struct QV4Program {
- quint32 bindings;
- quint32 dataLength;
- quint32 signalTableOffset;
- quint32 exceptionDataOffset;
- quint16 subscriptions;
- quint16 instructionCount;
-
- struct BindingReference {
- quint32 binding;
- quint32 blockMask;
- };
-
- struct BindingReferenceList {
- quint32 count;
- BindingReference bindings[];
- };
+namespace QV4 {
- inline const char *data() const;
- inline const char *instructions() const;
- inline BindingReferenceList *signalTable(int signalIndex) const;
-};
-
-enum QQmlRegisterType {
- UndefinedType,
- NullType,
- QObjectStarType,
- NumberType,
- FloatType,
- IntType,
- BoolType,
- SpecialNumericType,
+struct ArrayCtor: FunctionObject
+{
+ ArrayCtor(ExecutionContext *scope);
- PODValueType,
+ static Value construct(Managed *m, Value *args, int argc);
+ static Value call(Managed *that, const Value &, Value *, int);
- FirstCleanupType,
- QStringType = FirstCleanupType,
- QUrlType,
- QVariantType,
- QColorType,
- V8HandleType,
- QJSValueType
+protected:
+ static const ManagedVTable static_vtbl;
};
-const char *QV4Program::data() const
-{
- return ((const char *)this) + sizeof(QV4Program);
-}
+struct ArrayPrototype: ArrayObject
+{
+ ArrayPrototype(ExecutionContext *context);
+
+ void init(ExecutionContext *ctx, const Value &ctor);
+
+ static uint getLength(ExecutionContext *ctx, Object *o);
+
+ static Value method_isArray(SimpleCallContext *ctx);
+ static Value method_toString(SimpleCallContext *ctx);
+ static Value method_toLocaleString(SimpleCallContext *ctx);
+ static Value method_concat(SimpleCallContext *ctx);
+ static Value method_join(SimpleCallContext *ctx);
+ static Value method_pop(SimpleCallContext *ctx);
+ static Value method_push(SimpleCallContext *ctx);
+ static Value method_reverse(SimpleCallContext *ctx);
+ static Value method_shift(SimpleCallContext *ctx);
+ static Value method_slice(SimpleCallContext *ctx);
+ static Value method_sort(SimpleCallContext *ctx);
+ static Value method_splice(SimpleCallContext *ctx);
+ static Value method_unshift(SimpleCallContext *ctx);
+ static Value method_indexOf(SimpleCallContext *ctx);
+ static Value method_lastIndexOf(SimpleCallContext *ctx);
+ static Value method_every(SimpleCallContext *ctx);
+ static Value method_some(SimpleCallContext *ctx);
+ static Value method_forEach(SimpleCallContext *ctx);
+ static Value method_map(SimpleCallContext *ctx);
+ static Value method_filter(SimpleCallContext *ctx);
+ static Value method_reduce(SimpleCallContext *ctx);
+ static Value method_reduceRight(SimpleCallContext *ctx);
+};
-const char *QV4Program::instructions() const
-{
- return (const char *)(data() + dataLength);
-}
-QV4Program::BindingReferenceList *QV4Program::signalTable(int signalIndex) const
-{
- quint32 *signalTable = (quint32 *)(data() + signalTableOffset);
- return (BindingReferenceList *)(signalTable + signalTable[signalIndex]);
-}
+} // namespace QV4
QT_END_NAMESPACE
-#endif // QV4PROGRAM_P_H
-
+#endif // QV4ECMAOBJECTS_P_H
diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp
deleted file mode 100644
index 668f7b4d05..0000000000
--- a/src/qml/qml/v4/qv4bindings.cpp
+++ /dev/null
@@ -1,2478 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-// #define REGISTER_CLEANUP_DEBUG
-
-#include "qv4bindings_p.h"
-#include "qv4program_p.h"
-#include "qv4compiler_p.h"
-#include "qv4compiler_p_p.h"
-
-#include <private/qqmlglobal_p.h>
-
-#include <private/qv8_p.h>
-#include <private/qjsconverter_p.h>
-#include <private/qjsconverter_impl_p.h>
-#include <private/qjsvalue_impl_p.h>
-#include <private/qjsvalueiterator_impl_p.h>
-#include <private/qv8engine_impl_p.h>
-
-#include <private/qqmlaccessors_p.h>
-#include <private/qqmlprofilerservice_p.h>
-#include <private/qqmlmetatype_p.h>
-#include <private/qqmltrace_p.h>
-#include <private/qqmlstringconverters_p.h>
-#include <private/qqmlproperty_p.h>
-#include <private/qqmlvmemetaobject_p.h>
-
-#include <QtQml/qqmlinfo.h>
-#include <QtCore/qnumeric.h>
-#include <QtCore/qmath.h>
-#include <math.h> // ::fmod
-
-#ifdef Q_CC_MSVC
-// MSVC2010 warns about 'unreferenced formal parameter', even if it's used in p->~T()
-# pragma warning( disable : 4100 )
-#endif
-
-QT_BEGIN_NAMESPACE
-
-using namespace QQmlJS;
-
-QQmlAbstractBinding::VTable QV4Bindings_Binding_vtable = {
- QV4Bindings::Binding::destroy,
- QQmlAbstractBinding::default_expression,
- QV4Bindings::Binding::propertyIndex,
- QV4Bindings::Binding::object,
- QV4Bindings::Binding::setEnabled,
- QV4Bindings::Binding::update,
- QV4Bindings::Binding::retargetBinding
-};
-
-namespace {
-
-// The highest bit is the sign bit, in any endianness
-static const quint64 doubleSignMask = (quint64(0x1) << 63);
-
-inline bool signBitSet(const double &v)
-{
- union { double d; quint64 u; } u;
- u.d = v;
- return (u.u & doubleSignMask);
-}
-
-inline double setSignBit(const double &v, bool b = true)
-{
- union { double d; quint64 u; } u;
-
- u.d = v;
- if (b) {
- u.u |= doubleSignMask;
- } else {
- u.u &= ~doubleSignMask;
- }
- return u.d;
-}
-
-inline double clearSignBit(const double &v, bool b = true)
-{
- return setSignBit(v, !b);
-}
-
-struct Register {
- typedef QQmlRegisterType Type;
-
- enum SpecialNumericValue {
- NegativeZero = 1,
- PositiveInfinity = 2,
- NegativeInfinity = 3,
- NotANumber = 4
- };
-
- inline void setUndefined() { dataType = UndefinedType; }
- inline bool isUndefined() const { return dataType == UndefinedType; }
-
- inline void setNull() { dataType = NullType; }
-
- inline void setNaN() { setnumber(qSNaN()); }
- inline void setNaNType() { dataType = SpecialNumericType; intValue = NotANumber; } // non-numeric representation of NaN
- inline bool isNaN() const { return (((dataType == SpecialNumericType) && (intValue == NotANumber)) ||
- ((dataType == NumberType) && qIsNaN(numberValue))); }
-
- inline void setInf(bool negative) { setnumber(setSignBit(qInf(), negative)); }
- inline void setInfType(bool negative) { dataType = SpecialNumericType; intValue = (negative ? NegativeInfinity : PositiveInfinity); } // non-numeric representation of Inf
- inline bool isInf() const { return (((dataType == SpecialNumericType) && ((intValue == NegativeInfinity) || (intValue == PositiveInfinity))) ||
- ((dataType == NumberType) && qIsInf(numberValue))); }
-
- inline void setNegativeZero() { setnumber(setSignBit(0)); }
- inline void setNegativeZeroType() { dataType = SpecialNumericType; intValue = NegativeZero; } // non-numeric representation of -0
- inline bool isNegativeZero() const { return (((dataType == SpecialNumericType) && (intValue == NegativeZero)) ||
- ((dataType == NumberType) && (numberValue == 0) && signBitSet(numberValue))); }
-
- inline void setQObject(QObject *o) { qobjectValue = o; dataType = QObjectStarType; }
- inline QObject *getQObject() const { return qobjectValue; }
-
- inline void setnumber(double v) { numberValue = v; dataType = NumberType; }
- inline double getnumber() const { return numberValue; }
- inline double &getnumberref() { return numberValue; }
-
- inline void setfloat(float v) { floatValue = v; dataType = FloatType; }
- inline float getfloat() const { return floatValue; }
- inline float &getfloatref() { return floatValue; }
-
- inline void setint(int v) { intValue = v; dataType = IntType; }
- inline int getint() const { return intValue; }
- inline int &getintref() { return intValue; }
-
- inline void setbool(bool v) { boolValue = v; dataType = BoolType; }
- inline bool getbool() const { return boolValue; }
- inline bool &getboolref() { return boolValue; }
-
- inline QVariant *getvariantptr() { return reinterpret_cast<QVariant *>(typeDataPtr()); }
- inline QString *getstringptr() { return reinterpret_cast<QString *>(typeDataPtr()); }
- inline QUrl *geturlptr() { return reinterpret_cast<QUrl *>(typeDataPtr()); }
- inline v8::Handle<v8::Value> *gethandleptr() { return reinterpret_cast<v8::Handle<v8::Value> *>(typeDataPtr()); }
- inline QJSValue *getjsvalueptr() { return reinterpret_cast<QJSValue *>(typeDataPtr()); }
-
- inline const QVariant *getvariantptr() const { return reinterpret_cast<const QVariant *>(typeDataPtr()); }
- inline const QString *getstringptr() const { return reinterpret_cast<const QString *>(typeDataPtr()); }
- inline const QUrl *geturlptr() const { return reinterpret_cast<const QUrl *>(typeDataPtr()); }
- inline const v8::Handle<v8::Value> *gethandleptr() const { return reinterpret_cast<const v8::Handle<v8::Value> *>(typeDataPtr()); }
- inline const QJSValue *getjsvalueptr() const { return reinterpret_cast<const QJSValue *>(typeDataPtr()); }
-
- size_t dataSize() { return sizeof(data); }
- inline void *typeDataPtr() { return (void *)&data; }
- inline void *typeMemory() { return (void *)data; }
- inline const void *typeDataPtr() const { return (void *)&data; }
- inline const void *typeMemory() const { return (void *)data; }
-
- inline Type gettype() const { return dataType; }
- inline void settype(Type t) { dataType = t; }
-
- Type dataType; // Type of data
- union {
- QObject *qobjectValue;
- double numberValue;
- float floatValue;
- int intValue;
- bool boolValue;
- void *data[sizeof(QVariant)];
- qint64 q_for_alignment_1;
- double q_for_alignment_2;
- };
-
- inline void cleanup();
- inline void cleanupString();
- inline void cleanupUrl();
- inline void cleanupColor();
- inline void cleanupVariant();
- inline void cleanupHandle();
- inline void cleanupJSValue();
-
- inline void copy(const Register &other);
- inline void init(Type type);
-#ifdef REGISTER_CLEANUP_DEBUG
- Register() {
- type = 0;
- }
-
- ~Register() {
- if (dataType >= FirstCleanupType)
- qWarning("Register leaked of type %d", dataType);
- }
-#endif
-
- template <typename T>
- inline static void copyConstructPointee(T *p, const T *other)
- {
- new (p) T(*other);
- }
-
- template <typename T>
- inline static void defaultConstructPointee(T *p)
- {
- new (p) T();
- }
-
- template <typename T>
- inline static void destroyPointee(T *p)
- {
- p->~T();
- }
-};
-
-void Register::cleanup()
-{
- if (dataType >= FirstCleanupType) {
- if (dataType == QStringType) {
- destroyPointee(getstringptr());
- } else if (dataType == QUrlType) {
- destroyPointee(geturlptr());
- } else if (dataType == QColorType) {
- QQml_valueTypeProvider()->destroyValueType(QMetaType::QColor, typeDataPtr(), dataSize());
- } else if (dataType == QVariantType) {
- destroyPointee(getvariantptr());
- } else if (dataType == qMetaTypeId<v8::Handle<v8::Value> >()) {
- destroyPointee(gethandleptr());
- } else if (dataType == qMetaTypeId<QJSValue>()) {
- destroyPointee(getjsvalueptr());
- }
- }
- setUndefined();
-}
-
-void Register::cleanupString()
-{
- destroyPointee(getstringptr());
- setUndefined();
-}
-
-void Register::cleanupUrl()
-{
- destroyPointee(geturlptr());
- setUndefined();
-}
-
-void Register::cleanupColor()
-{
- QQml_valueTypeProvider()->destroyValueType(QMetaType::QColor, typeDataPtr(), dataSize());
- setUndefined();
-}
-
-void Register::cleanupVariant()
-{
- destroyPointee(getvariantptr());
- setUndefined();
-}
-
-void Register::cleanupHandle()
-{
- destroyPointee(gethandleptr());
- setUndefined();
-}
-
-void Register::cleanupJSValue()
-{
- destroyPointee(getjsvalueptr());
- setUndefined();
-}
-
-void Register::copy(const Register &other)
-{
- *this = other;
- if (other.dataType >= FirstCleanupType) {
- if (other.dataType == QStringType)
- copyConstructPointee(getstringptr(), other.getstringptr());
- else if (other.dataType == QUrlType)
- copyConstructPointee(geturlptr(), other.geturlptr());
- else if (other.dataType == QColorType)
- QQml_valueTypeProvider()->copyValueType(QMetaType::QColor, other.typeDataPtr(), typeDataPtr(), dataSize());
- else if (other.dataType == QVariantType)
- copyConstructPointee(getvariantptr(), other.getvariantptr());
- else if (other.dataType == qMetaTypeId<v8::Handle<v8::Value> >())
- copyConstructPointee(gethandleptr(), other.gethandleptr());
- else if (other.dataType == qMetaTypeId<QJSValue>())
- copyConstructPointee(getjsvalueptr(), other.getjsvalueptr());
- }
-}
-
-void Register::init(Type type)
-{
- dataType = type;
- if (dataType >= FirstCleanupType) {
- if (dataType == QStringType)
- defaultConstructPointee(getstringptr());
- else if (dataType == QUrlType)
- defaultConstructPointee(geturlptr());
- else if (dataType == QColorType)
- QQml_valueTypeProvider()->initValueType(QMetaType::QColor, typeDataPtr(), dataSize());
- else if (dataType == QVariantType)
- defaultConstructPointee(getvariantptr());
- else if (dataType == qMetaTypeId<v8::Handle<v8::Value> >())
- defaultConstructPointee(gethandleptr());
- else if (dataType == qMetaTypeId<QJSValue>())
- defaultConstructPointee(getjsvalueptr());
- }
-}
-
-} // end of anonymous namespace
-
-QV4Bindings::QV4Bindings(const char *programData, QQmlContextData *context)
-: subscriptions(0), program(0), bindings(0)
-{
- program = (QV4Program *)programData;
- if (program) {
- subscriptions = new Subscription[program->subscriptions];
- bindings = new Binding[program->bindings];
-
- QQmlAbstractExpression::setContext(context);
- }
-}
-
-QV4Bindings::~QV4Bindings()
-{
- delete [] bindings; bindings = 0;
- delete [] subscriptions; subscriptions = 0;
-}
-
-QQmlAbstractBinding *QV4Bindings::configBinding(QObject *target, QObject *scope,
- const QQmlInstruction::instr_assignV4Binding *i)
-{
- Binding *rv = bindings + i->value;
-
- rv->instruction = i;
- rv->target = target;
- rv->scope = scope;
- rv->parent = this;
-
- addref(); // This is decremented in Binding::destroy()
-
- return rv;
-}
-
-void QV4Bindings::Binding::setEnabled(QQmlAbstractBinding *_This,
- bool e, QQmlPropertyPrivate::WriteFlags flags)
-{
- QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
-
- if (This->enabledFlag() != e) {
- This->setEnabledFlag(e);
-
- if (e) update(_This, flags);
- }
-}
-
-void QV4Bindings::Binding::update(QQmlAbstractBinding *_This, QQmlPropertyPrivate::WriteFlags flags)
-{
- QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
- This->parent->run(This, flags);
-}
-
-void QV4Bindings::Binding::destroy(QQmlAbstractBinding *_This, QQmlAbstractBinding::DestroyMode mode)
-{
- QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
-
- if (mode == QQmlAbstractBinding::DisconnectBinding)
- This->disconnect();
-
- This->setEnabledFlag(false);
- This->removeFromObject();
- This->clear();
- This->removeError();
- This->parent->release();
-}
-
-int QV4Bindings::Binding::propertyIndex(const QQmlAbstractBinding *_This)
-{
- const QV4Bindings::Binding *This = static_cast<const QV4Bindings::Binding *>(_This);
-
- if (This->target.hasValue()) return This->target.constValue()->targetProperty;
- else return This->instruction->property;
-}
-
-QObject *QV4Bindings::Binding::object(const QQmlAbstractBinding *_This)
-{
- const QV4Bindings::Binding *This = static_cast<const QV4Bindings::Binding *>(_This);
-
- if (This->target.hasValue()) return This->target.constValue()->target;
- return *This->target;
-}
-
-void QV4Bindings::Binding::retargetBinding(QQmlAbstractBinding *_This, QObject *t, int i)
-{
- QV4Bindings::Binding *This = static_cast<QV4Bindings::Binding *>(_This);
-
- This->target.value().target = t;
- This->target.value().targetProperty = i;
-}
-
-void QV4Bindings::Binding::disconnect()
-{
- // We iterate over the signal table to find all subscriptions associated with this binding.
- // This is slow, but disconnect() is not called in the common case, only in special cases
- // like when the binding is overwritten.
- QV4Program * const program = parent->program;
- for (quint16 subIndex = 0; subIndex < program->subscriptions; subIndex++) {
- QV4Program::BindingReferenceList * const list = program->signalTable(subIndex);
- for (quint32 bindingIndex = 0; bindingIndex < list->count; ++bindingIndex) {
- QV4Program::BindingReference * const bindingRef = list->bindings + bindingIndex;
- Binding * const binding = parent->bindings + bindingRef->binding;
- if (binding == this) {
- Subscription * const sub = parent->subscriptions + subIndex;
- if (sub->active()) {
- sub->setActive(false);
- sub->disconnect();
- }
- }
- }
- }
-}
-
-void QV4Bindings::Binding::dump()
-{
- qWarning() << parent->context()->url << instruction->line << instruction->column;
-}
-
-QV4Bindings::Subscription::Subscription()
- : m_bindings(0)
-{
- setCallback(QQmlNotifierEndpoint::QV4BindingsSubscription);
-}
-
-int QV4Bindings::Subscription::method() const
-{
- Q_ASSERT(bindings() != 0);
- return (this - bindings()->subscriptions);
-}
-
-void QV4Bindings::Subscription::setBindings(QV4Bindings *bindings)
-{
- m_bindings = bindings;
-}
-
-QV4Bindings *QV4Bindings::Subscription::bindings() const
-{
- return *m_bindings;
-}
-
-bool QV4Bindings::Subscription::active() const
-{
- return m_bindings.flag();
-}
-
-void QV4Bindings::Subscription::setActive(bool active)
-{
- m_bindings.setFlagValue(active);
-}
-
-void QV4BindingsSubscription_callback(QQmlNotifierEndpoint *e, void **)
-{
- QV4Bindings::Subscription *s = static_cast<QV4Bindings::Subscription *>(e);
- Q_ASSERT(s->bindings());
- s->bindings()->subscriptionNotify(s->method());
-}
-
-void QV4Bindings::subscriptionNotify(int id)
-{
- QV4Program::BindingReferenceList *list = program->signalTable(id);
-
- for (quint32 ii = 0; ii < list->count; ++ii) {
- QV4Program::BindingReference *bindingRef = list->bindings + ii;
-
- Binding *binding = bindings + bindingRef->binding;
-
- if (binding->executedBlocks & bindingRef->blockMask) {
- run(binding, QQmlPropertyPrivate::DontRemoveBinding);
- }
- }
-}
-
-void QV4Bindings::run(Binding *binding, QQmlPropertyPrivate::WriteFlags flags)
-{
- if (!binding->enabledFlag())
- return;
-
- QQmlContextData *context = QQmlAbstractExpression::context();
- if (!context || !context->isValid())
- return;
-
- // Check that the target has not been deleted
- if (QQmlData::wasDeleted(*binding->target))
- return;
-
- QQmlTrace trace("V4 Binding Update");
- trace.addDetail("URL", context->url);
- trace.addDetail("Line", binding->instruction->line);
- trace.addDetail("Column", binding->instruction->column);
-
- QQmlBindingProfiler prof(context->urlString, binding->instruction->line, binding->instruction->column, QQmlProfilerService::V4Binding);
-
- const int propType = binding->instruction->propType;
- const int property = binding->instruction->property;
-
- if (binding->updatingFlag()) {
- QString name;
- if (propType) {
- QQmlValueType *vt = QQmlValueTypeFactory::valueType(propType);
- Q_ASSERT(vt);
-
- name = QLatin1String(binding->target->metaObject()->property(property & 0x0000FFFF).name());
- name.append(QLatin1Char('.'));
- name.append(QLatin1String(vt->metaObject()->property(property >> 16).name()));
- } else {
- name = QLatin1String(binding->target->metaObject()->property(property).name());
- }
- qmlInfo(*binding->target) << tr("Binding loop detected for property \"%1\"").arg(name);
- return;
- }
-
- int index = binding->instruction->value;
- int fallbackIndex = binding->instruction->fallbackValue;
-
- bool invalidated = false;
- bool *inv = (fallbackIndex != -1) ? &invalidated : 0;
-
- binding->setUpdatingFlag(true);
- if (propType) {
- QQmlValueType *vt = QQmlValueTypeFactory::valueType(propType);
- Q_ASSERT(vt);
- vt->read(*binding->target, property & 0x0000FFFF);
-
- QObject *target = vt;
- run(index, binding->executedBlocks, context, binding, binding->scope, target, flags, inv);
-
- if (!invalidated) {
- vt->write(*binding->target, property & 0x0000FFFF, flags);
- }
- } else {
- QQmlData *data = QQmlData::get(*binding->target);
- QQmlPropertyData *propertyData = (data && data->propertyCache ? data->propertyCache->property(property) : 0);
-
- if (propertyData && propertyData->isVarProperty()) {
- // We will allocate a V8 handle in this conversion/store
- v8::HandleScope handle_scope;
- v8::Context::Scope context_scope(QQmlEnginePrivate::get(context->engine)->v8engine()->context());
-
- run(index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags, inv);
- } else {
- run(index, binding->executedBlocks, context, binding, binding->scope, *binding->target, flags, inv);
- }
- }
- binding->setUpdatingFlag(false);
-
- if (invalidated) {
- // This binding is no longer valid - fallback to V8
- Q_ASSERT(fallbackIndex > -1);
- QQmlAbstractBinding *b = QQmlPropertyPrivate::activateSharedBinding(context, fallbackIndex, flags);
- Q_ASSERT(b == binding);
- b->destroy();
- }
-}
-
-void QV4Bindings::subscribeId(QQmlContextData *p, int idIndex, int subIndex)
-{
- Subscription *sub = (subscriptions + subIndex);
- sub->disconnect();
-
- if (p->idValues[idIndex]) {
- sub->setBindings(this);
- sub->connect(&p->idValues[idIndex].bindings);
- sub->setActive(true);
- } else {
- sub->setActive(false);
- }
-}
-
-void QV4Bindings::subscribe(QObject *o, int notifyIndex, int subIndex, QQmlEngine *e)
-{
- Subscription *sub = (subscriptions + subIndex);
- if (sub->isConnected(o, notifyIndex))
- return;
- sub->setBindings(this);
- if (o) {
- sub->connect(o, notifyIndex, e);
- sub->setActive(true);
- } else {
- sub->disconnect();
- sub->setActive(false);
- }
-}
-
-static bool testCompareVariants(const QVariant &qtscriptRaw, const QVariant &v4)
-{
- QVariant qtscript = qtscriptRaw;
-
- if (qtscript.userType() == v4.userType()) {
- } else if (qtscript.canConvert(v4.userType())) {
- qtscript.convert(v4.userType());
- } else if (qtscript.userType() == QVariant::Invalid && v4.userType() == QMetaType::QObjectStar) {
- qtscript = qVariantFromValue<QObject *>(0);
- } else {
- return false;
- }
-
- int type = qtscript.userType();
-
- if (type == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
- return QQmlMetaType::QQuickAnchorLineCompare(qtscript.constData(), v4.constData());
- } else if (type == QMetaType::Double) {
-
- double la = qvariant_cast<double>(qtscript);
- double lr = qvariant_cast<double>(v4);
-
- return la == lr || (qIsNaN(la) && qIsNaN(lr));
-
- } else if (type == QMetaType::Float) {
-
- float la = qvariant_cast<float>(qtscript);
- float lr = qvariant_cast<float>(v4);
-
- return la == lr || (qIsNaN(la) && qIsNaN(lr));
-
- } else {
- return qtscript == v4;
- }
-}
-
-QByteArray testResultToString(const QVariant &result, bool undefined)
-{
- if (undefined) {
- return "undefined";
- } else {
- QString rv;
- QDebug d(&rv);
- d << result;
- return rv.toUtf8();
- }
-}
-
-static void testBindingResult(const QString &binding, quint16 line, quint16 column,
- QQmlContextData *context, QObject *scope,
- const Register &result, int resultType)
-{
- QQmlExpression expression(context->asQQmlContext(), scope, binding);
- bool isUndefined = false;
- QVariant value = expression.evaluate(&isUndefined);
-
- bool iserror = false;
- QByteArray qtscriptResult;
- QByteArray v4Result;
-
- const int handleType = qMetaTypeId<v8::Handle<v8::Value> >();
-
- if (expression.hasError()) {
- iserror = true;
- qtscriptResult = "exception";
- } else if ((value.userType() != resultType) &&
- (resultType != QMetaType::QVariant) &&
- (resultType != qMetaTypeId<QJSValue>()) &&
- (resultType != handleType)) {
- // Override the QMetaType conversions to make them more JS friendly.
- if (value.userType() == QMetaType::Double && (resultType == QMetaType::QString ||
- resultType == QMetaType::QUrl)) {
- // number to string-like conversion.
- value = QVariant::fromValue<QString>(QString::number(value.toDouble(), 'g', 16));
- } else if (value.userType() == QMetaType::QUrl && resultType == QMetaType::Bool) {
- // url to bool conversion
- value = QVariant::fromValue<bool>(!value.toUrl().isEmpty());
- }
-
- if (!value.isNull() && !value.convert(resultType)) {
- iserror = true;
- qtscriptResult = "exception";
- } else if (resultType == QMetaType::QUrl) {
- // a V8 value was converted to QUrl.
- value = QVariant::fromValue<QUrl>(context->resolvedUrl(value.toUrl()));
- }
- }
-
- if (! iserror)
- qtscriptResult = testResultToString(value, isUndefined);
-
- if (isUndefined && result.isUndefined()) {
- return;
- } else if(isUndefined != result.isUndefined()) {
- iserror = true;
- }
-
- QVariant v4value;
- if (!result.isUndefined()) {
- switch (resultType) {
- case QMetaType::QString:
- v4value = *result.getstringptr();
- break;
- case QMetaType::QUrl:
- v4value = *result.geturlptr();
- break;
- case QMetaType::QObjectStar:
- v4value = qVariantFromValue<QObject *>(result.getQObject());
- break;
- case QMetaType::Bool:
- v4value = result.getbool();
- break;
- case QMetaType::Int:
- v4value = result.getint();
- break;
- case QMetaType::Double:
- v4value = result.getnumber();
- break;
- case QMetaType::QColor:
- v4value = QVariant(QMetaType::QColor, result.typeDataPtr());
- break;
- case QMetaType::QVariant:
- v4value = *result.getvariantptr();
- break;
- default:
- if (resultType == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
- v4value = QVariant(QQmlMetaType::QQuickAnchorLineMetaTypeId(), result.typeDataPtr());
- } else if (resultType == qMetaTypeId<QJSValue>()) {
- v4value = result.getjsvalueptr()->toVariant();
- } else if (resultType == handleType) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
- v4value = ep->v8engine()->toVariant(*result.gethandleptr(), resultType);
- } else {
- iserror = true;
- v4Result = "Unknown V4 type";
- }
- }
- }
- if (v4Result.isEmpty())
- v4Result = testResultToString(v4value, result.isUndefined());
-
- if (!testCompareVariants(value, v4value))
- iserror = true;
-
- if (iserror) {
- qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ':' << line << ':' << column;
-
- qWarning().nospace() << " Binding: " << binding;
- qWarning().nospace() << " QtScript: " << qtscriptResult.constData();
- qWarning().nospace() << " V4: " << v4Result.constData();
- }
-}
-
-static void testBindingException(const QString &binding, quint16 line, quint16 column,
- QQmlContextData *context, QObject *scope)
-{
- QQmlExpression expression(context->asQQmlContext(), scope, binding);
- bool isUndefined = false;
- QVariant value = expression.evaluate(&isUndefined);
-
- if (!expression.hasError()) {
- QByteArray qtscriptResult = testResultToString(value, isUndefined);
- qWarning().nospace() << "QV4: Optimization error @" << context->url.toString().toUtf8().constData() << ':' << line << ':' << column;
- qWarning().nospace() << " Binding: " << binding;
- qWarning().nospace() << " QtScript: " << qtscriptResult.constData();
- qWarning().nospace() << " V4: exception";
- }
-}
-
-static void throwException(int id, QQmlDelayedError *error,
- QV4Program *program, QQmlContextData *context,
- const QString &description = QString())
-{
- if (description.isEmpty())
- error->setErrorDescription(QLatin1String("TypeError: Result of expression is not an object"));
- else
- error->setErrorDescription(description);
- error->setErrorObject(context->contextObject);
- if (id != 0xFF) {
- quint32 e = *((quint32 *)(program->data() + program->exceptionDataOffset) + id);
- error->setErrorLocation(context->url, (e >> 16), (e & 0xFFFF));
- } else {
- error->setErrorLocation(context->url, -1, -1);
- }
- if (!context->engine || !error->addError(QQmlEnginePrivate::get(context->engine)))
- QQmlEnginePrivate::warning(context->engine, error);
-}
-
-const double QV4Bindings::D32 = 4294967296.0;
-
-qint32 QV4Bindings::toInt32(double n)
-{
- if (qIsNaN(n) || qIsInf(n) || (n == 0))
- return 0;
-
- double sign = (n < 0) ? -1.0 : 1.0;
- double abs_n = fabs(n);
-
- n = ::fmod(sign * ::floor(abs_n), D32);
- const double D31 = D32 / 2.0;
-
- if (sign == -1 && n < -D31)
- n += D32;
-
- else if (sign != -1 && n >= D31)
- n -= D32;
-
- return qint32 (n);
-}
-
-inline quint32 QV4Bindings::toUint32(double n)
-{
- if (qIsNaN(n) || qIsInf(n) || (n == 0))
- return 0;
-
- double sign = (n < 0) ? -1.0 : 1.0;
- double abs_n = fabs(n);
-
- n = ::fmod(sign * ::floor(abs_n), D32);
-
- if (n < 0)
- n += D32;
-
- return quint32 (n);
-}
-
-#define THROW_EXCEPTION_STR(id, str) { \
- if (testBinding) testBindingException(*testBindingSource, bindingLine, bindingColumn, context, scope); \
- throwException((id), error, program, context, (str)); \
- goto exceptionExit; \
-}
-
-#define THROW_VALUE_EXCEPTION_STR(id, str) { \
- throwException((id), error, program, context, (str)); \
- goto exceptionExit; \
-}
-
-#define THROW_EXCEPTION(id) THROW_EXCEPTION_STR(id, QString())
-
-#define MARK_REGISTER(reg) cleanupRegisterMask |= (1 << (reg))
-#define MARK_CLEAN_REGISTER(reg) cleanupRegisterMask &= ~(1 << (reg))
-
-#define STRING_REGISTER(reg) { \
- registers[(reg)].settype(QStringType); \
- MARK_REGISTER(reg); \
-}
-
-#define URL_REGISTER(reg) { \
- registers[(reg)].settype(QUrlType); \
- MARK_REGISTER(reg); \
-}
-
-#define COLOR_REGISTER(reg) { \
- registers[(reg)].settype(QColorType); \
- MARK_REGISTER(reg); \
-}
-
-#define VARIANT_REGISTER(reg) { \
- registers[(reg)].settype(QVariantType); \
- MARK_REGISTER(reg); \
-}
-
-#define V8HANDLE_REGISTER(reg) { \
- registers[(reg)].settype(V8HandleType); \
- MARK_REGISTER(reg); \
-}
-
-#define JSVALUE_REGISTER(reg) { \
- registers[(reg)].settype(QJSValueType); \
- MARK_REGISTER(reg); \
-}
-
-namespace {
-
-bool bindingInvalidated(bool *invalidated, QObject *obj, QQmlContextData *context, int index)
-{
- if (invalidated != 0) {
- if (QQmlData *data = QQmlData::get(obj, true)) {
- if (!data->propertyCache) {
- data->propertyCache = QQmlEnginePrivate::get(context->engine)->cache(obj);
- if (data->propertyCache) data->propertyCache->addref();
- }
-
- if (QQmlPropertyData *prop = data->propertyCache ? data->propertyCache->property(index) : 0) {
- if (prop->isOverridden()) {
- // TODO: avoid construction of name and name-based lookup
- int resolvedIndex = data->propertyCache->property(prop->name(obj), obj, context)->coreIndex;
- if (index < resolvedIndex) {
- *invalidated = true;
- return true;
- }
- }
- }
- }
- }
-
- return false;
-}
-
-}
-
-#ifdef QML_THREADED_INTERPRETER
-void **QV4Bindings::getDecodeInstrTable()
-{
- static void **decode_instr;
- if (!decode_instr) {
- QV4Bindings *dummy = new QV4Bindings(0, 0);
- quint32 executedBlocks = 0;
- dummy->run(0, executedBlocks, 0, 0, 0, 0,
- QQmlPropertyPrivate::BypassInterceptor,
- 0, &decode_instr);
- dummy->release();
- }
- return decode_instr;
-}
-#endif
-
-void QV4Bindings::run(int instrIndex, quint32 &executedBlocks,
- QQmlContextData *context, QQmlDelayedError *error,
- QObject *scope, QObject *output,
- QQmlPropertyPrivate::WriteFlags storeFlags,
- bool *invalidated
-#ifdef QML_THREADED_INTERPRETER
- ,void ***table
-#endif
- )
-{
-#ifdef QML_THREADED_INTERPRETER
- if (table) {
- static void *decode_instr[] = {
- FOR_EACH_V4_INSTR(QML_V4_INSTR_ADDR)
- };
-
- *table = decode_instr;
- return;
- }
-#endif
-
-
- error->removeError();
-
- Register registers[32];
- quint32 cleanupRegisterMask = 0;
-
- executedBlocks = 0;
-
- const char *code = program->instructions();
- code += instrIndex * QML_V4_INSTR_SIZE(Jump, jump);
- const V4Instr *instr = reinterpret_cast<const V4Instr *>(code);
-
- const char *data = program->data();
-
- QString *testBindingSource = 0;
- bool testBinding = false;
- int bindingLine = 0;
- int bindingColumn = 0;
-
-#ifdef QML_THREADED_INTERPRETER
- goto *instr->common.code;
-#else
- for (;;) {
- switch (instr->common.type) {
-#endif
-
- QML_V4_BEGIN_INSTR(Noop, common)
- QML_V4_END_INSTR(Noop, common)
-
- QML_V4_BEGIN_INSTR(BindingId, id)
- bindingLine = instr->id.line;
- bindingColumn = instr->id.column;
- QML_V4_END_INSTR(BindingId, id)
-
- QML_V4_BEGIN_INSTR(SubscribeId, subscribeop)
- subscribeId(context, instr->subscribeop.index, instr->subscribeop.offset);
- QML_V4_END_INSTR(SubscribeId, subscribeop)
-
- QML_V4_BEGIN_INSTR(FetchAndSubscribe, fetchAndSubscribe)
- {
- Register &reg = registers[instr->fetchAndSubscribe.reg];
-
- if (reg.isUndefined())
- THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
-
- QObject *object = reg.getQObject();
- if (!object) {
- THROW_EXCEPTION(instr->fetchAndSubscribe.exceptionId);
- } else {
- if (bindingInvalidated(invalidated, object, context, instr->fetchAndSubscribe.property.coreIndex))
- goto programExit;
-
- const Register::Type valueType = (Register::Type)instr->fetchAndSubscribe.valueType;
- reg.init(valueType);
- if (instr->fetchAndSubscribe.valueType >= FirstCleanupType)
- MARK_REGISTER(instr->fetchAndSubscribe.reg);
-
- QQmlData::flushPendingBinding(object, instr->fetchAndSubscribe.property.coreIndex);
-
- QQmlAccessors *accessors = instr->fetchAndSubscribe.property.accessors;
- accessors->read(object, instr->fetchAndSubscribe.property.accessorData,
- reg.typeDataPtr());
-
- if (valueType == FloatType) {
- // promote floats
- const double v = reg.getfloat();
- reg.setnumber(v);
- }
-
- if (accessors->notifier) {
- QQmlNotifier *notifier = 0;
- accessors->notifier(object, instr->fetchAndSubscribe.property.accessorData, &notifier);
- if (notifier) {
- int subIdx = instr->fetchAndSubscribe.subscription;
- Subscription *sub = 0;
- if (subIdx != -1) {
- sub = (subscriptions + subIdx);
- sub->setBindings(this);
- }
- sub->connect(notifier);
- }
- } else {
- const int notifyIndex = instr->fetchAndSubscribe.property.notifyIndex;
- if (notifyIndex != -1) {
- const int subIdx = instr->fetchAndSubscribe.subscription;
- subscribe(object, notifyIndex, subIdx, context->engine);
- }
- }
- }
- }
- QML_V4_END_INSTR(FetchAndSubscribe, fetchAndSubscribe)
-
- QML_V4_BEGIN_INSTR(LoadId, load)
- registers[instr->load.reg].setQObject(context->idValues[instr->load.index].data());
- QML_V4_END_INSTR(LoadId, load)
-
- QML_V4_BEGIN_INSTR(LoadScope, load)
- registers[instr->load.reg].setQObject(scope);
- QML_V4_END_INSTR(LoadScope, load)
-
- QML_V4_BEGIN_INSTR(LoadRoot, load)
- registers[instr->load.reg].setQObject(context->contextObject);
- QML_V4_END_INSTR(LoadRoot, load)
-
- QML_V4_BEGIN_INSTR(LoadSingletonObject, load)
- {
- Register &reg = registers[instr->load.reg];
-
- const QString *name = reg.getstringptr();
- QQmlTypeNameCache::Result r = context->imports->query(*name);
- reg.cleanupString();
-
- if (r.isValid() && r.type) {
- if (r.type->isSingleton()) {
- QQmlEngine *e = context->engine;
- QQmlType::SingletonInstanceInfo *siinfo = r.type->singletonInstanceInfo();
- siinfo->init(e); // note: this will also create QJSValue singleton, which is not strictly required here.
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- if (qobjectSingleton)
- reg.setQObject(qobjectSingleton);
- }
- }
- }
- QML_V4_END_INSTR(LoadSingletonObject, load)
-
- QML_V4_BEGIN_INSTR(LoadAttached, attached)
- {
- const Register &input = registers[instr->attached.reg];
- Register &output = registers[instr->attached.output];
- if (input.isUndefined())
- THROW_EXCEPTION(instr->attached.exceptionId);
-
- QObject *object = registers[instr->attached.reg].getQObject();
- if (!object) {
- output.setUndefined();
- } else {
- QObject *attached = qmlAttachedPropertiesObjectById(instr->attached.id, input.getQObject(), true);
- Q_ASSERT(attached);
- output.setQObject(attached);
- }
- }
- QML_V4_END_INSTR(LoadAttached, attached)
-
- QML_V4_BEGIN_INSTR(UnaryNot, unaryop)
- {
- registers[instr->unaryop.output].setbool(!registers[instr->unaryop.src].getbool());
- }
- QML_V4_END_INSTR(UnaryNot, unaryop)
-
- QML_V4_BEGIN_INSTR(UnaryMinusNumber, unaryop)
- {
- registers[instr->unaryop.output].setnumber(-registers[instr->unaryop.src].getnumber());
- }
- QML_V4_END_INSTR(UnaryMinusNumber, unaryop)
-
- QML_V4_BEGIN_INSTR(UnaryMinusInt, unaryop)
- {
- registers[instr->unaryop.output].setint(-registers[instr->unaryop.src].getint());
- }
- QML_V4_END_INSTR(UnaryMinusInt, unaryop)
-
- QML_V4_BEGIN_INSTR(UnaryPlusNumber, unaryop)
- {
- registers[instr->unaryop.output].setnumber(+registers[instr->unaryop.src].getnumber());
- }
- QML_V4_END_INSTR(UnaryPlusNumber, unaryop)
-
- QML_V4_BEGIN_INSTR(UnaryPlusInt, unaryop)
- {
- registers[instr->unaryop.output].setint(+registers[instr->unaryop.src].getint());
- }
- QML_V4_END_INSTR(UnaryPlusInt, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertBoolToInt, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) output.setUndefined();
- else output.setint(src.getbool());
- }
- QML_V4_END_INSTR(ConvertBoolToInt, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertBoolToJSValue, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- new (output.getjsvalueptr()) QJSValue(src.getbool());
- JSVALUE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertBoolToJSValue, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertBoolToNumber, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) output.setUndefined();
- else output.setnumber(src.getbool());
- }
- QML_V4_END_INSTR(ConvertBoolToNumber, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertBoolToString, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- new (output.getstringptr()) QString(QLatin1String(src.getbool() ? "true" : "false"));
- STRING_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertBoolToString, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertBoolToVariant, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- new (output.getvariantptr()) QVariant(src.getbool());
- VARIANT_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertBoolToVariant, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertBoolToVar, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Boolean::New(src.getbool()));
- V8HANDLE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertBoolToVar, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertIntToBool, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) output.setUndefined();
- else output.setbool(src.getint());
- }
- QML_V4_END_INSTR(ConvertIntToBool, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertIntToJSValue, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- new (output.getjsvalueptr()) QJSValue(src.getint());
- JSVALUE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertIntToJSValue, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertIntToNumber, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) output.setUndefined();
- else if (src.isNaN()) output.setNaN();
- else if (src.isInf()) output.setInf(src.getint() == Register::NegativeInfinity);
- else if (src.isNegativeZero()) output.setNegativeZero();
- else output.setnumber(double(src.getint()));
- }
- QML_V4_END_INSTR(ConvertIntToNumber, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertIntToString, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- new (output.getstringptr()) QString(QString::number(src.getint()));
- STRING_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertIntToString, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertIntToVariant, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- new (output.getvariantptr()) QVariant(src.getint());
- VARIANT_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertIntToVariant, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertIntToVar, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Integer::New(src.getint()));
- V8HANDLE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertIntToVar, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertJSValueToVar, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- QJSValue tmp(*src.getjsvalueptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupJSValue();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- if (tmp.isUndefined()) {
- output.setUndefined();
- } else {
- QV8Engine *v8engine = QQmlEnginePrivate::get(context->engine)->v8engine();
- new (output.gethandleptr()) v8::Handle<v8::Value>(
- QJSValuePrivate::get(tmp)->asV8Value(v8engine));
- V8HANDLE_REGISTER(instr->unaryop.output);
- }
- }
- }
- QML_V4_END_INSTR(ConvertJSValueToVar, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertNumberToBool, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) output.setUndefined();
- else output.setbool(src.getnumber() != 0);
- }
- QML_V4_END_INSTR(ConvertNumberToBool, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertNumberToInt, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) output.setUndefined();
- else output.setint(toInt32(src.getnumber()));
- }
- QML_V4_END_INSTR(ConvertNumberToInt, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertNumberToJSValue, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- new (output.getjsvalueptr()) QJSValue(src.getnumber());
- JSVALUE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertNumberToJSValue, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertNumberToString, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- new (output.getstringptr()) QString(QString::number(src.getnumber(), 'g', 16));
- STRING_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertNumberToString, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertNumberToVariant, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- new (output.getvariantptr()) QVariant(src.getnumber());
- VARIANT_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertNumberToVariant, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertNumberToVar, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Number::New(src.getnumber()));
- V8HANDLE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertNumberToVar, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertStringToBool, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
- // Ideally we should just call the methods in the QScript namespace directly.
- QJSValue tmp(*src.getstringptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupString();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- output.setbool(tmp.toBool());
- }
- }
- QML_V4_END_INSTR(ConvertStringToBool, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertStringToInt, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
- // Ideally we should just call the methods in the QScript namespace directly.
- QJSValue tmp(*src.getstringptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupString();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- output.setint(tmp.toInt());
- }
- }
- QML_V4_END_INSTR(ConvertStringToInt, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertStringToJSValue, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- QString tmp(*src.getstringptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupString();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- new (output.getjsvalueptr()) QJSValue(tmp);
- JSVALUE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertStringToJSValue, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertStringToNumber, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- // Delegate the conversion. This is pretty fast and it doesn't require a QScriptEngine.
- // Ideally we should just call the methods in the QScript namespace directly.
- QJSValue tmp(*src.getstringptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupString();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- output.setnumber(tmp.toNumber());
- }
- }
- QML_V4_END_INSTR(ConvertStringToNumber, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertStringToUrl, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- QString tmp(*src.getstringptr());
- // Encoded dir-separators defeat QUrl processing - decode them first
- tmp.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive);
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupString();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- new (output.geturlptr()) QUrl(tmp);
-
- URL_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertStringToUrl, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertStringToColor, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- const QString tmp(*src.getstringptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupString();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- QQml_valueTypeProvider()->createValueFromString(QMetaType::QColor, tmp, output.typeDataPtr(), output.dataSize());
-
- COLOR_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertStringToColor, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertStringToVariant, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- const QString tmp(*src.getstringptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupString();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- new (output.getvariantptr()) QVariant(tmp);
-
- VARIANT_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertStringToVariant, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertStringToVar, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- const QString tmp(*src.getstringptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupString();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- new (output.gethandleptr()) v8::Handle<v8::Value>(QJSConverter::toString(tmp));
- V8HANDLE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertStringToVar, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertUrlToBool, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- const QUrl tmp(*src.geturlptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupUrl();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- output.setbool(!tmp.isEmpty());
- }
- }
- QML_V4_END_INSTR(ConvertUrlToBool, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertUrlToJSValue, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- const QUrl tmp(*src.geturlptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupUrl();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- new (output.getjsvalueptr()) QJSValue(tmp.toString());
- JSVALUE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertUrlToJSValue, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertUrlToString, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- const QUrl tmp(*src.geturlptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupUrl();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- new (output.getstringptr()) QString(tmp.toString());
- STRING_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertUrlToString, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertUrlToVariant, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- const QUrl tmp(*src.geturlptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupUrl();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- new (output.getvariantptr()) QVariant(tmp);
- VARIANT_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertUrlToVariant, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertUrlToVar, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- const QUrl tmp(*src.geturlptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupUrl();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- new (output.gethandleptr()) v8::Handle<v8::Value>(QJSConverter::toString(tmp.toString()));
- V8HANDLE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertUrlToVar, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertColorToBool, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- // for compatibility with color behavior in v8, always true
- output.setbool(true);
- }
- }
- QML_V4_END_INSTR(ConvertColorToBool, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertColorToJSValue, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- const QVariant tmp(QMetaType::QColor, src.typeDataPtr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupColor();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
-
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
- QV8Engine *v8engine = ep->v8engine();
- QQmlValueType *vt = QQmlValueTypeFactory::valueType(QMetaType::QColor);
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(v8engine->context());
- new (output.getjsvalueptr()) QJSValue(v8engine->scriptValueFromInternal(
- v8engine->valueTypeWrapper()->newValueType(tmp, vt)));
- JSVALUE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertColorToJSValue, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertColorToString, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- QQml_valueTypeProvider()->createStringFromValue(QMetaType::QColor, src.typeDataPtr(), output.getstringptr());
- STRING_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertColorToString, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertColorToVariant, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- QVariant tmp(QMetaType::QColor, src.typeDataPtr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupColor();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- new (output.getvariantptr()) QVariant(tmp);
- VARIANT_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertColorToVariant, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertColorToVar, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- const QVariant tmp(QMetaType::QColor, src.typeDataPtr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupColor();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
-
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
- QQmlValueType *vt = QQmlValueTypeFactory::valueType(QMetaType::QColor);
- new (output.gethandleptr()) v8::Handle<v8::Value>(ep->v8engine()->valueTypeWrapper()->newValueType(tmp, vt));
- V8HANDLE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertColorToVar, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertObjectToBool, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined())
- output.setUndefined();
- else
- output.setbool(src.getQObject() != 0);
- }
- QML_V4_END_INSTR(ConvertObjectToBool, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertObjectToJSValue, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(ep->v8engine()->context());
- new (output.getjsvalueptr()) QJSValue(context->engine->newQObject(src.getQObject()));
- JSVALUE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertObjectToJSValue, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertObjectToVariant, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined())
- output.setUndefined();
- else {
- new (output.getvariantptr()) QVariant(qVariantFromValue<QObject *>(src.getQObject()));
- VARIANT_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertObjectToVariant, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertObjectToVar, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- // ### NaN
- if (src.isUndefined())
- output.setUndefined();
- else {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
- new (output.gethandleptr()) v8::Handle<v8::Value>(ep->v8engine()->newQObject(src.getQObject()));
- V8HANDLE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertObjectToVar, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertVarToJSValue, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- v8::Handle<v8::Value> tmp(*src.gethandleptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- output.cleanupHandle();
- MARK_CLEAN_REGISTER(instr->unaryop.output);
- }
- QV8Engine *v8engine = QQmlEnginePrivate::get(context->engine)->v8engine();
- new (output.getjsvalueptr()) QJSValue(v8engine->scriptValueFromInternal(tmp));
- JSVALUE_REGISTER(instr->unaryop.output);
- }
- }
- QML_V4_END_INSTR(ConvertVarToJSValue, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertNullToJSValue, unaryop)
- {
- Register &output = registers[instr->unaryop.output];
- new (output.getjsvalueptr()) QJSValue(QJSValue::NullValue);
- JSVALUE_REGISTER(instr->unaryop.output);
- }
- QML_V4_END_INSTR(ConvertNullToJSValue, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertNullToObject, unaryop)
- {
- Register &output = registers[instr->unaryop.output];
- output.setQObject(0);
- }
- QML_V4_END_INSTR(ConvertNullToObject, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertNullToVariant, unaryop)
- {
- Register &output = registers[instr->unaryop.output];
- new (output.getvariantptr()) QVariant();
- VARIANT_REGISTER(instr->unaryop.output);
- }
- QML_V4_END_INSTR(ConvertNullToVariant, unaryop)
-
- QML_V4_BEGIN_INSTR(ConvertNullToVar, unaryop)
- {
- Register &output = registers[instr->unaryop.output];
- new (output.gethandleptr()) v8::Handle<v8::Value>(v8::Null());
- V8HANDLE_REGISTER(instr->unaryop.output);
- }
- QML_V4_END_INSTR(ConvertNullToVar, unaryop)
-
- QML_V4_BEGIN_INSTR(ResolveUrl, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) {
- output.setUndefined();
- } else {
- const QUrl tmp(*src.geturlptr());
- if (instr->unaryop.src == instr->unaryop.output) {
- *output.geturlptr() = context->resolvedUrl(tmp);
- } else {
- new (output.geturlptr()) QUrl(context->resolvedUrl(tmp));
- URL_REGISTER(instr->unaryop.output);
- }
- }
- }
- QML_V4_END_INSTR(ResolveUrl, unaryop)
-
- QML_V4_BEGIN_INSTR(MathSinNumber, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) output.setUndefined();
- else output.setnumber(qSin(src.getnumber()));
- }
- QML_V4_END_INSTR(MathSinNumber, unaryop)
-
- QML_V4_BEGIN_INSTR(MathCosNumber, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) output.setUndefined();
- else output.setnumber(qCos(src.getnumber()));
- }
- QML_V4_END_INSTR(MathCosNumber, unaryop)
-
- QML_V4_BEGIN_INSTR(MathAbsNumber, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) output.setUndefined();
- else output.setnumber(clearSignBit(qAbs(src.getnumber())));
- }
- QML_V4_END_INSTR(MathAbsNumber, unaryop)
-
- QML_V4_BEGIN_INSTR(MathRoundNumber, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined()) output.setUndefined();
- else output.setint(qRound(src.getnumber()));
- }
- QML_V4_END_INSTR(MathRoundNumber, unaryop)
-
- QML_V4_BEGIN_INSTR(MathFloorNumber, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined())
- output.setUndefined();
- else if (src.isNaN())
- // output should be an int, but still NaN
- output.setNaNType();
- else if (src.isInf())
- // output should be an int, but still Inf
- output.setInfType(signBitSet(src.getnumber()));
- else if (src.isNegativeZero())
- // output should be an int, but still -0
- output.setNegativeZeroType();
- else
- output.setint(qFloor(src.getnumber()));
- }
- QML_V4_END_INSTR(MathFloorNumber, unaryop)
-
- QML_V4_BEGIN_INSTR(MathCeilNumber, unaryop)
- {
- const Register &src = registers[instr->unaryop.src];
- Register &output = registers[instr->unaryop.output];
- if (src.isUndefined())
- output.setUndefined();
- else if (src.isNaN())
- // output should be an int, but still NaN
- output.setNaNType();
- else if (src.isInf())
- // output should be an int, but still Inf
- output.setInfType(signBitSet(src.getnumber()));
- else if (src.isNegativeZero())
- // output should be an int, but still -0
- output.setNegativeZeroType();
- else {
- // Ensure that we preserve the sign bit (Math.ceil(-0) -> -0)
- const double input = src.getnumber();
- const int ceiled = qCeil(input);
- if (ceiled == 0 && signBitSet(input)) {
- output.setNegativeZeroType();
- } else {
- output.setint(ceiled);
- }
- }
- }
- QML_V4_END_INSTR(MathCeilNumber, unaryop)
-
- QML_V4_BEGIN_INSTR(MathPINumber, unaryop)
- {
- static const double qmlPI = 2.0 * qAsin(1.0);
- Register &output = registers[instr->unaryop.output];
- output.setnumber(qmlPI);
- }
- QML_V4_END_INSTR(MathPINumber, unaryop)
-
- QML_V4_BEGIN_INSTR(LoadNull, null_value)
- registers[instr->null_value.reg].setNull();
- QML_V4_END_INSTR(LoadNull, null_value)
-
- QML_V4_BEGIN_INSTR(LoadNumber, number_value)
- registers[instr->number_value.reg].setnumber(instr->number_value.value);
- QML_V4_END_INSTR(LoadNumber, number_value)
-
- QML_V4_BEGIN_INSTR(LoadInt, int_value)
- registers[instr->int_value.reg].setint(instr->int_value.value);
- QML_V4_END_INSTR(LoadInt, int_value)
-
- QML_V4_BEGIN_INSTR(LoadBool, bool_value)
- registers[instr->bool_value.reg].setbool(instr->bool_value.value);
- QML_V4_END_INSTR(LoadBool, bool_value)
-
- QML_V4_BEGIN_INSTR(LoadString, string_value)
- {
- Register &output = registers[instr->string_value.reg];
- QChar *string = (QChar *)(data + instr->string_value.offset);
- new (output.getstringptr()) QString(string, instr->string_value.length);
- STRING_REGISTER(instr->string_value.reg);
- }
- QML_V4_END_INSTR(LoadString, string_value)
-
- QML_V4_BEGIN_INSTR(EnableV4Test, string_value)
- {
- testBindingSource = new QString((QChar *)(data + instr->string_value.offset), instr->string_value.length);
- testBinding = true;
- }
- QML_V4_END_INSTR(String, string_value)
-
- QML_V4_BEGIN_INSTR(BitAndInt, binaryop)
- {
- registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() &
- registers[instr->binaryop.right].getint());
- }
- QML_V4_END_INSTR(BitAndInt, binaryop)
-
- QML_V4_BEGIN_INSTR(BitOrInt, binaryop)
- {
- registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() |
- registers[instr->binaryop.right].getint());
- }
- QML_V4_END_INSTR(BitAndInt, binaryop)
-
- QML_V4_BEGIN_INSTR(BitXorInt, binaryop)
- {
- registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() ^
- registers[instr->binaryop.right].getint());
- }
- QML_V4_END_INSTR(BitXorInt, binaryop)
-
- QML_V4_BEGIN_INSTR(AddNumber, binaryop)
- {
- registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() +
- registers[instr->binaryop.right].getnumber());
- }
- QML_V4_END_INSTR(AddNumber, binaryop)
-
- QML_V4_BEGIN_INSTR(AddString, binaryop)
- {
- QString &string = *registers[instr->binaryop.output].getstringptr();
- if (instr->binaryop.output == instr->binaryop.left) {
- string += registers[instr->binaryop.right].getstringptr();
- } else {
- string = *registers[instr->binaryop.left].getstringptr() +
- *registers[instr->binaryop.right].getstringptr();
- }
- }
- QML_V4_END_INSTR(AddString, binaryop)
-
- QML_V4_BEGIN_INSTR(SubNumber, binaryop)
- {
- registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() -
- registers[instr->binaryop.right].getnumber());
- }
- QML_V4_END_INSTR(SubNumber, binaryop)
-
- QML_V4_BEGIN_INSTR(MulNumber, binaryop)
- {
- registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() *
- registers[instr->binaryop.right].getnumber());
- }
- QML_V4_END_INSTR(MulNumber, binaryop)
-
- QML_V4_BEGIN_INSTR(DivNumber, binaryop)
- {
- registers[instr->binaryop.output].setnumber(registers[instr->binaryop.left].getnumber() /
- registers[instr->binaryop.right].getnumber());
- }
- QML_V4_END_INSTR(DivNumber, binaryop)
-
- QML_V4_BEGIN_INSTR(ModNumber, binaryop)
- {
- Register &target = registers[instr->binaryop.output];
- const Register &left = registers[instr->binaryop.left];
- const Register &right = registers[instr->binaryop.right];
- target.setnumber(::fmod(left.getnumber(), right.getnumber()));
- }
- QML_V4_END_INSTR(ModInt, binaryop)
-
- QML_V4_BEGIN_INSTR(LShiftInt, binaryop)
- {
- registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() <<
- registers[instr->binaryop.right].getint());
- }
- QML_V4_END_INSTR(LShiftInt, binaryop)
-
- QML_V4_BEGIN_INSTR(RShiftInt, binaryop)
- {
- registers[instr->binaryop.output].setint(registers[instr->binaryop.left].getint() >>
- registers[instr->binaryop.right].getint());
- }
- QML_V4_END_INSTR(RShiftInt, binaryop)
-
- QML_V4_BEGIN_INSTR(URShiftInt, binaryop)
- {
- registers[instr->binaryop.output].setint((unsigned)registers[instr->binaryop.left].getint() >>
- registers[instr->binaryop.right].getint());
- }
- QML_V4_END_INSTR(URShiftInt, binaryop)
-
- QML_V4_BEGIN_INSTR(GtNumber, binaryop)
- {
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() >
- registers[instr->binaryop.right].getnumber());
- }
- QML_V4_END_INSTR(GtNumber, binaryop)
-
- QML_V4_BEGIN_INSTR(LtNumber, binaryop)
- {
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() <
- registers[instr->binaryop.right].getnumber());
- }
- QML_V4_END_INSTR(LtNumber, binaryop)
-
- QML_V4_BEGIN_INSTR(GeNumber, binaryop)
- {
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() >=
- registers[instr->binaryop.right].getnumber());
- }
- QML_V4_END_INSTR(GeNumber, binaryop)
-
- QML_V4_BEGIN_INSTR(LeNumber, binaryop)
- {
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() <=
- registers[instr->binaryop.right].getnumber());
- }
- QML_V4_END_INSTR(LeNumber, binaryop)
-
- QML_V4_BEGIN_INSTR(EqualNumber, binaryop)
- {
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() ==
- registers[instr->binaryop.right].getnumber());
- }
- QML_V4_END_INSTR(EqualNumber, binaryop)
-
- QML_V4_BEGIN_INSTR(NotEqualNumber, binaryop)
- {
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() !=
- registers[instr->binaryop.right].getnumber());
- }
- QML_V4_END_INSTR(NotEqualNumber, binaryop)
-
- QML_V4_BEGIN_INSTR(StrictEqualNumber, binaryop)
- {
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() ==
- registers[instr->binaryop.right].getnumber());
- }
- QML_V4_END_INSTR(StrictEqualNumber, binaryop)
-
- QML_V4_BEGIN_INSTR(StrictNotEqualNumber, binaryop)
- {
- registers[instr->binaryop.output].setbool(registers[instr->binaryop.left].getnumber() !=
- registers[instr->binaryop.right].getnumber());
- }
- QML_V4_END_INSTR(StrictNotEqualNumber, binaryop)
-
- QML_V4_BEGIN_INSTR(GtString, binaryop)
- {
- const QString &a = *registers[instr->binaryop.left].getstringptr();
- const QString &b = *registers[instr->binaryop.right].getstringptr();
- bool result = a > b;
- if (instr->binaryop.left == instr->binaryop.output) {
- registers[instr->binaryop.output].cleanupString();
- MARK_CLEAN_REGISTER(instr->binaryop.output);
- }
- registers[instr->binaryop.output].setbool(result);
- }
- QML_V4_END_INSTR(GtString, binaryop)
-
- QML_V4_BEGIN_INSTR(LtString, binaryop)
- {
- const QString &a = *registers[instr->binaryop.left].getstringptr();
- const QString &b = *registers[instr->binaryop.right].getstringptr();
- bool result = a < b;
- if (instr->binaryop.left == instr->binaryop.output) {
- registers[instr->binaryop.output].cleanupString();
- MARK_CLEAN_REGISTER(instr->binaryop.output);
- }
- registers[instr->binaryop.output].setbool(result);
- }
- QML_V4_END_INSTR(LtString, binaryop)
-
- QML_V4_BEGIN_INSTR(GeString, binaryop)
- {
- const QString &a = *registers[instr->binaryop.left].getstringptr();
- const QString &b = *registers[instr->binaryop.right].getstringptr();
- bool result = a >= b;
- if (instr->binaryop.left == instr->binaryop.output) {
- registers[instr->binaryop.output].cleanupString();
- MARK_CLEAN_REGISTER(instr->binaryop.output);
- }
- registers[instr->binaryop.output].setbool(result);
- }
- QML_V4_END_INSTR(GeString, binaryop)
-
- QML_V4_BEGIN_INSTR(LeString, binaryop)
- {
- const QString &a = *registers[instr->binaryop.left].getstringptr();
- const QString &b = *registers[instr->binaryop.right].getstringptr();
- bool result = a <= b;
- if (instr->binaryop.left == instr->binaryop.output) {
- registers[instr->binaryop.output].cleanupString();
- MARK_CLEAN_REGISTER(instr->binaryop.output);
- }
- registers[instr->binaryop.output].setbool(result);
- }
- QML_V4_END_INSTR(LeString, binaryop)
-
- QML_V4_BEGIN_INSTR(EqualString, binaryop)
- {
- const QString &a = *registers[instr->binaryop.left].getstringptr();
- const QString &b = *registers[instr->binaryop.right].getstringptr();
- bool result = a == b;
- if (instr->binaryop.left == instr->binaryop.output) {
- registers[instr->binaryop.output].cleanupString();
- MARK_CLEAN_REGISTER(instr->binaryop.output);
- }
- registers[instr->binaryop.output].setbool(result);
- }
- QML_V4_END_INSTR(EqualString, binaryop)
-
- QML_V4_BEGIN_INSTR(NotEqualString, binaryop)
- {
- const QString &a = *registers[instr->binaryop.left].getstringptr();
- const QString &b = *registers[instr->binaryop.right].getstringptr();
- bool result = a != b;
- if (instr->binaryop.left == instr->binaryop.output) {
- registers[instr->binaryop.output].cleanupString();
- MARK_CLEAN_REGISTER(instr->binaryop.output);
- }
- registers[instr->binaryop.output].setbool(result);
- }
- QML_V4_END_INSTR(NotEqualString, binaryop)
-
- QML_V4_BEGIN_INSTR(StrictEqualString, binaryop)
- {
- const QString &a = *registers[instr->binaryop.left].getstringptr();
- const QString &b = *registers[instr->binaryop.right].getstringptr();
- bool result = a == b;
- if (instr->binaryop.left == instr->binaryop.output) {
- registers[instr->binaryop.output].cleanupString();
- MARK_CLEAN_REGISTER(instr->binaryop.output);
- }
- registers[instr->binaryop.output].setbool(result);
- }
- QML_V4_END_INSTR(StrictEqualString, binaryop)
-
- QML_V4_BEGIN_INSTR(StrictNotEqualString, binaryop)
- {
- const QString &a = *registers[instr->binaryop.left].getstringptr();
- const QString &b = *registers[instr->binaryop.right].getstringptr();
- bool result = a != b;
- if (instr->binaryop.left == instr->binaryop.output) {
- registers[instr->binaryop.output].cleanupString();
- MARK_CLEAN_REGISTER(instr->binaryop.output);
- }
- registers[instr->binaryop.output].setbool(result);
- }
- QML_V4_END_INSTR(StrictNotEqualString, binaryop)
-
- QML_V4_BEGIN_INSTR(EqualObject, binaryop)
- {
- const Register &left = registers[instr->binaryop.left];
- const Register &right = registers[instr->binaryop.right];
- QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
- QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
- registers[instr->binaryop.output].setbool(leftobj == rightobj);
- }
- QML_V4_END_INSTR(EqualObject, binaryop)
-
- QML_V4_BEGIN_INSTR(NotEqualObject, binaryop)
- {
- const Register &left = registers[instr->binaryop.left];
- const Register &right = registers[instr->binaryop.right];
- QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
- QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
- registers[instr->binaryop.output].setbool(leftobj != rightobj);
- }
- QML_V4_END_INSTR(NotEqualObject, binaryop)
-
- QML_V4_BEGIN_INSTR(StrictEqualObject, binaryop)
- {
- const Register &left = registers[instr->binaryop.left];
- const Register &right = registers[instr->binaryop.right];
- QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
- QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
- registers[instr->binaryop.output].setbool(leftobj == rightobj);
- }
- QML_V4_END_INSTR(StrictEqualObject, binaryop)
-
- QML_V4_BEGIN_INSTR(StrictNotEqualObject, binaryop)
- {
- const Register &left = registers[instr->binaryop.left];
- const Register &right = registers[instr->binaryop.right];
- QObject *leftobj = (left.gettype() == NullType) ? 0 : left.getQObject();
- QObject *rightobj = (right.gettype() == NullType) ? 0 : right.getQObject();
- registers[instr->binaryop.output].setbool(leftobj != rightobj);
- }
- QML_V4_END_INSTR(StrictNotEqualObject, binaryop)
-
- QML_V4_BEGIN_INSTR(MathMaxNumber, binaryop)
- {
- const Register &left = registers[instr->binaryop.left];
- const Register &right = registers[instr->binaryop.right];
- Register &output = registers[instr->binaryop.output];
- if (left.isUndefined() || right.isUndefined()) {
- output.setUndefined();
- } else {
- const double lhs = left.getnumber();
- const double rhs = right.getnumber();
- double result(lhs);
- if (lhs == rhs) {
- // If these are both zero, +0 is greater than -0
- if (signBitSet(lhs) && !signBitSet(rhs))
- result = rhs;
- } else {
- result = qMax(lhs, rhs);
- }
- output.setnumber(result);
- }
- }
- QML_V4_END_INSTR(MathMaxNumber, binaryop)
-
- QML_V4_BEGIN_INSTR(MathMinNumber, binaryop)
- {
- const Register &left = registers[instr->binaryop.left];
- const Register &right = registers[instr->binaryop.right];
- Register &output = registers[instr->binaryop.output];
- if (left.isUndefined() || right.isUndefined()) {
- output.setUndefined();
- } else {
- const double lhs = left.getnumber();
- const double rhs = right.getnumber();
- double result(lhs);
- if (lhs == rhs) {
- // If these are both zero, -0 is lesser than +0
- if (!signBitSet(lhs) && signBitSet(rhs))
- result = rhs;
- } else {
- result = qMin(lhs, rhs);
- }
- output.setnumber(result);
- }
- }
- QML_V4_END_INSTR(MathMinNumber, binaryop)
-
- QML_V4_BEGIN_INSTR(NewString, construct)
- {
- Register &output = registers[instr->construct.reg];
- new (output.getstringptr()) QString;
- STRING_REGISTER(instr->construct.reg);
- }
- QML_V4_END_INSTR(NewString, construct)
-
- QML_V4_BEGIN_INSTR(NewUrl, construct)
- {
- Register &output = registers[instr->construct.reg];
- new (output.geturlptr()) QUrl;
- URL_REGISTER(instr->construct.reg);
- }
- QML_V4_END_INSTR(NewUrl, construct)
-
- QML_V4_BEGIN_INSTR(Fetch, fetch)
- {
- Register &reg = registers[instr->fetch.reg];
-
- if (reg.isUndefined())
- THROW_EXCEPTION(instr->fetch.exceptionId);
-
- QObject *object = reg.getQObject();
- if (!object) {
- THROW_EXCEPTION(instr->fetch.exceptionId);
- } else {
- if (bindingInvalidated(invalidated, object, context, instr->fetch.index))
- goto programExit;
-
- const Register::Type valueType = (Register::Type)instr->fetch.valueType;
- reg.init(valueType);
- if (instr->fetch.valueType >= FirstCleanupType)
- MARK_REGISTER(instr->fetch.reg);
-
- QQmlData::flushPendingBinding(object, instr->fetch.index);
-
- void *argv[] = { reg.typeDataPtr(), 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, instr->fetch.index, argv);
- if (valueType == FloatType) {
- // promote floats
- const double v = reg.getfloat();
- reg.setnumber(v);
- }
-
- if (instr->fetch.subIndex != static_cast<quint32>(-1))
- subscribe(object, instr->fetch.subIndex, instr->fetch.subOffset, context->engine);
-
- }
- }
- QML_V4_END_INSTR(Fetch, fetch)
-
- QML_V4_BEGIN_INSTR(TestV4Store, storetest)
- {
- Register &data = registers[instr->storetest.reg];
- testBindingResult(*testBindingSource, bindingLine, bindingColumn, context,
- scope, data, instr->storetest.regType);
- }
- QML_V4_END_INSTR(TestV4Store, storetest)
-
- QML_V4_BEGIN_INSTR(Store, store)
- {
- Register &data = registers[instr->store.reg];
-
- if (data.isUndefined())
- THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign undefined value"));
-
- if (data.gettype() == QObjectStarType) {
- if (QObject *dataObject = data.getQObject()) {
- QQmlMetaObject dataMo(dataObject);
-
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
-
- QQmlMetaObject receiverMo;
-
- if (QQmlData::get(output, false) && QQmlData::get(output, false)->propertyCache) {
- QQmlPropertyData *receiver =
- QQmlData::get(output, false)->propertyCache->property(instr->store.index);
- receiverMo = ep->rawMetaObjectForType(receiver->propType);
- } else {
- QMetaProperty receiver = output->metaObject()->property(instr->store.index);
- receiverMo = ep->rawMetaObjectForType(receiver.userType());
- }
-
- // Verify that these types are compatible
- if (!QQmlMetaObject::canConvert(dataMo, receiverMo)) {
- THROW_EXCEPTION_STR(instr->store.exceptionId, QLatin1String("Unable to assign ") +
- QLatin1String(dataMo.className()) +
- QLatin1String(" to ") +
- QLatin1String(receiverMo.className()));
- }
- }
- }
-
- if (instr->store.valueType == FloatType) {
- // cast numbers to floats
- const float v = (float) data.getnumber();
- data.setfloat(v);
- }
-
- if (data.gettype() == V8HandleType) {
- // This property must be a VME var property
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(output);
- Q_ASSERT(vmemo);
- vmemo->setVMEProperty(instr->store.index, *data.gethandleptr());
- } else {
- int status = -1;
- void *argv[] = { data.typeDataPtr(), 0, &status, &storeFlags };
- QMetaObject::metacall(output, QMetaObject::WriteProperty,
- instr->store.index, argv);
- }
-
- goto programExit;
- }
- QML_V4_END_INSTR(Store, store)
-
- QML_V4_BEGIN_INSTR(Copy, copy)
- registers[instr->copy.reg].copy(registers[instr->copy.src]);
- if (registers[instr->copy.reg].gettype() >= FirstCleanupType)
- MARK_REGISTER(instr->copy.reg);
- QML_V4_END_INSTR(Copy, copy)
-
- QML_V4_BEGIN_INSTR(Jump, jump)
- if (instr->jump.reg == -1 || !registers[instr->jump.reg].getbool())
- code += instr->jump.count;
- QML_V4_END_INSTR(Jump, jump)
-
- QML_V4_BEGIN_INSTR(BranchTrue, branchop)
- if (registers[instr->branchop.reg].getbool())
- code += instr->branchop.offset;
- QML_V4_END_INSTR(BranchTrue, branchop)
-
- QML_V4_BEGIN_INSTR(BranchFalse, branchop)
- if (! registers[instr->branchop.reg].getbool())
- code += instr->branchop.offset;
- QML_V4_END_INSTR(BranchFalse, branchop)
-
- QML_V4_BEGIN_INSTR(Branch, branchop)
- code += instr->branchop.offset;
- QML_V4_END_INSTR(Branch, branchop)
-
- QML_V4_BEGIN_INSTR(Block, blockop)
- executedBlocks |= instr->blockop.block;
- QML_V4_END_INSTR(Block, blockop)
-
- QML_V4_BEGIN_INSTR(CleanupRegister, cleanup)
- registers[instr->cleanup.reg].cleanup();
- QML_V4_END_INSTR(CleanupRegister, cleanup)
-
- QML_V4_BEGIN_INSTR(Throw, throwop)
- THROW_VALUE_EXCEPTION_STR(instr->throwop.exceptionId, *registers[instr->throwop.message].getstringptr());
- QML_V4_END_INSTR(Throw, throwop)
-
-#ifdef QML_THREADED_INTERPRETER
- // nothing to do
-#else
- default:
- qFatal("QV4: Unknown instruction %d encountered.", instr->common.type);
- break;
- } // switch
-
- } // while
-#endif
-
- Q_ASSERT(!"Unreachable code reached");
-
-programExit:
-exceptionExit:
- delete testBindingSource;
-
- int reg = 0;
- while (cleanupRegisterMask) {
- if (cleanupRegisterMask & 0x1)
- registers[reg].cleanup();
-
- reg++;
- cleanupRegisterMask >>= 1;
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4bindings_p.h b/src/qml/qml/v4/qv4bindings_p.h
deleted file mode 100644
index adb05ba1f4..0000000000
--- a/src/qml/qml/v4/qv4bindings_p.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4BINDINGS_P_H
-#define QV4BINDINGS_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/qqmlexpression_p.h"
-#include "private/qqmlbinding_p.h"
-#include "private/qqmlinstruction_p.h"
-#include "private/qv4instruction_p.h"
-#include "private/qpointervaluepair_p.h"
-
-QT_BEGIN_NAMESPACE
-
-struct QV4Program;
-class QV4Bindings : public QQmlAbstractExpression,
- public QQmlRefCount
-{
- Q_DECLARE_TR_FUNCTIONS(QV4Bindings)
-public:
- QV4Bindings(const char *program, QQmlContextData *context);
- virtual ~QV4Bindings();
-
- QQmlAbstractBinding *configBinding(QObject *target, QObject *scope,
- const QQmlInstruction::instr_assignV4Binding *);
-
-#ifdef QML_THREADED_INTERPRETER
- static void **getDecodeInstrTable();
-#endif
-
- struct Binding : public QQmlAbstractBinding, public QQmlDelayedError {
- Binding()
- : QQmlAbstractBinding(V4), target(0), scope(0), instruction(0), executedBlocks(0), parent(0) {}
-
- // Inherited from QQmlAbstractBinding
- static void destroy(QQmlAbstractBinding *, QQmlAbstractBinding::DestroyMode mode);
- static int propertyIndex(const QQmlAbstractBinding *);
- static QObject *object(const QQmlAbstractBinding *);
- static void setEnabled(QQmlAbstractBinding *, bool, QQmlPropertyPrivate::WriteFlags);
- static void update(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags);
- static void retargetBinding(QQmlAbstractBinding *, QObject *, int);
-
- void disconnect();
-
- void dump();
-
- struct Retarget {
- QObject *target;
- int targetProperty;
- };
-
- QPointerValuePair<QObject, Retarget> target;
- QObject *scope;
-
- // To save memory, we store flags inside the instruction pointer.
- // instruction.flag1: enabled
- // instruction.flag2: updating
- QFlagPointer<const QQmlInstruction::instr_assignV4Binding> instruction;
-
- quint32 executedBlocks;
- QV4Bindings *parent;
-
- inline bool enabledFlag() const { return instruction.flag(); }
- inline void setEnabledFlag(bool v) { instruction.setFlagValue(v); }
- inline bool updatingFlag() const { return instruction.flag2(); }
- inline void setUpdatingFlag(bool v) { instruction.setFlag2Value(v); }
- };
-
-private:
- Q_DISABLE_COPY(QV4Bindings)
-
- class Subscription : public QQmlNotifierEndpoint
- {
- public:
- inline Subscription();
-
- // Index of this Subscription into the QV4Bindings::subscriptions array.
- // This may not be used before setBindings() was called.
- inline int method() const;
-
- inline void setBindings(QV4Bindings *bindings);
- inline QV4Bindings *bindings() const;
-
- inline bool active() const;
- inline void setActive(bool active);
-
- // Pointer to the parent QV4Bindings. The flag is used as the 'active' value.
- QFlagPointer<QV4Bindings> m_bindings;
- };
- friend void QV4BindingsSubscription_callback(QQmlNotifierEndpoint *e, void **);
-
- Subscription *subscriptions;
-
- void subscriptionNotify(int);
- void run(Binding *, QQmlPropertyPrivate::WriteFlags flags);
-
- QV4Program *program;
- Binding *bindings;
-
- void init();
- void run(int instr, quint32 &executedBlocks, QQmlContextData *context,
- QQmlDelayedError *error, QObject *scope, QObject *output,
- QQmlPropertyPrivate::WriteFlags storeFlags,
- bool *invalidated
-#ifdef QML_THREADED_INTERPRETER
- , void ***decode_instr = 0
-#endif
- );
-
-
- inline void subscribeId(QQmlContextData *p, int idIndex, int subIndex);
- inline void subscribe(QObject *o, int notifyIndex, int subIndex, QQmlEngine *);
-
- inline static qint32 toInt32(double n);
- static const double D32;
- static quint32 toUint32(double n);
-
-};
-
-QT_END_NAMESPACE
-
-#endif // QV4BINDINGS_P_H
-
diff --git a/src/qml/qml/v4/qv4booleanobject.cpp b/src/qml/qml/v4/qv4booleanobject.cpp
new file mode 100644
index 0000000000..24678d23dc
--- /dev/null
+++ b/src/qml/qml/v4/qv4booleanobject.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4booleanobject_p.h"
+
+using namespace QV4;
+
+DEFINE_MANAGED_VTABLE(BooleanCtor);
+
+BooleanCtor::BooleanCtor(ExecutionContext *scope)
+ : FunctionObject(scope, scope->engine->newIdentifier("Boolean"))
+{
+ vtbl = &static_vtbl;
+}
+
+Value BooleanCtor::construct(Managed *m, Value *args, int argc)
+{
+ bool n = argc ? args[0].toBoolean() : false;
+ return Value::fromObject(m->engine()->newBooleanObject(Value::fromBoolean(n)));
+}
+
+Value BooleanCtor::call(Managed *, const Value &, Value *argv, int argc)
+{
+ bool value = argc ? argv[0].toBoolean() : 0;
+ return Value::fromBoolean(value);
+}
+
+void BooleanPrototype::init(ExecutionContext *ctx, const Value &ctor)
+{
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(1));
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this));
+ defineDefaultProperty(ctx, QStringLiteral("constructor"), ctor);
+ defineDefaultProperty(ctx, QStringLiteral("toString"), method_toString);
+ defineDefaultProperty(ctx, QStringLiteral("valueOf"), method_valueOf);
+}
+
+Value BooleanPrototype::method_toString(SimpleCallContext *ctx)
+{
+ bool result;
+ if (ctx->thisObject.isBoolean()) {
+ result = ctx->thisObject.booleanValue();
+ } else {
+ BooleanObject *thisObject = ctx->thisObject.asBooleanObject();
+ if (!thisObject)
+ ctx->throwTypeError();
+ result = thisObject->value.booleanValue();
+ }
+
+ return Value::fromString(ctx, QLatin1String(result ? "true" : "false"));
+}
+
+Value BooleanPrototype::method_valueOf(SimpleCallContext *ctx)
+{
+ BooleanObject *thisObject = ctx->thisObject.asBooleanObject();
+ if (!thisObject)
+ ctx->throwTypeError();
+
+ return thisObject->value;
+}
diff --git a/src/qml/qml/v4/qv4booleanobject_p.h b/src/qml/qml/v4/qv4booleanobject_p.h
new file mode 100644
index 0000000000..3e5e7663f2
--- /dev/null
+++ b/src/qml/qml/v4/qv4booleanobject_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4BOOLEANOBJECT_H
+#define QBOOLEANOBJECT_H
+
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+#include <QtCore/qnumeric.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct BooleanCtor: FunctionObject
+{
+ BooleanCtor(ExecutionContext *scope);
+
+ static Value construct(Managed *, Value *args, int argc);
+ static Value call(Managed *that, const Value &, Value *, int);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct BooleanPrototype: BooleanObject
+{
+ BooleanPrototype(ExecutionEngine *engine): BooleanObject(engine, Value::fromBoolean(false)) {}
+ void init(ExecutionContext *ctx, const Value &ctor);
+
+ static Value method_toString(SimpleCallContext *ctx);
+ static Value method_valueOf(SimpleCallContext *ctx);
+};
+
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4ECMAOBJECTS_P_H
diff --git a/src/qml/qml/v4/qv4codegen.cpp b/src/qml/qml/v4/qv4codegen.cpp
new file mode 100644
index 0000000000..d0c43c8f56
--- /dev/null
+++ b/src/qml/qml/v4/qv4codegen.cpp
@@ -0,0 +1,2605 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4codegen_p.h"
+#include "qv4util_p.h"
+#include "qv4debugging_p.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QStringList>
+#include <QtCore/QSet>
+#include <QtCore/QBuffer>
+#include <QtCore/QBitArray>
+#include <QtCore/QLinkedList>
+#include <QtCore/QStack>
+#include <private/qqmljsast_p.h>
+#include <qv4runtime_p.h>
+#include <qv4context_p.h>
+#include <cmath>
+#include <iostream>
+#include <cassert>
+
+#ifdef CONST
+#undef CONST
+#endif
+
+#define QV4_NO_LIVENESS
+#undef SHOW_SSA
+
+using namespace QQmlJS;
+using namespace AST;
+
+class Codegen::ScanFunctions: Visitor
+{
+ typedef QV4::TemporaryAssignment<bool> TemporaryBoolAssignment;
+public:
+ ScanFunctions(Codegen *cg, const QString &sourceCode)
+ : _cg(cg)
+ , _sourceCode(sourceCode)
+ , _env(0)
+ , _inFuncBody(false)
+ , _allowFuncDecls(true)
+ {
+ }
+
+ void operator()(Node *node)
+ {
+ if (node)
+ node->accept(this);
+ }
+
+ inline void enterEnvironment(Node *node)
+ {
+ Environment *e = _cg->newEnvironment(node, _env);
+ if (!e->isStrict)
+ e->isStrict = _cg->_strictMode;
+ _envStack.append(e);
+ _env = e;
+ }
+
+ inline void leaveEnvironment()
+ {
+ _envStack.pop();
+ _env = _envStack.isEmpty() ? 0 : _envStack.top();
+ }
+
+protected:
+ using Visitor::visit;
+ using Visitor::endVisit;
+
+ void checkDirectivePrologue(SourceElements *ast)
+ {
+ for (SourceElements *it = ast; it; it = it->next) {
+ if (StatementSourceElement *stmt = cast<StatementSourceElement *>(it->element)) {
+ if (ExpressionStatement *expr = cast<ExpressionStatement *>(stmt->statement)) {
+ if (StringLiteral *strLit = cast<StringLiteral *>(expr->expression)) {
+ // Use the source code, because the StringLiteral's
+ // value might have escape sequences in it, which is not
+ // allowed.
+ if (strLit->literalToken.length < 2)
+ continue;
+ QStringRef str = _sourceCode.midRef(strLit->literalToken.offset + 1, strLit->literalToken.length - 2);
+ if (str == QStringLiteral("use strict")) {
+ _env->isStrict = true;
+ } else {
+ // TODO: give a warning.
+ }
+ continue;
+ }
+ }
+ }
+
+ break;
+ }
+ }
+
+ void checkName(const QStringRef &name, const SourceLocation &loc)
+ {
+ if (_env->isStrict) {
+ if (name == QLatin1String("implements")
+ || name == QLatin1String("interface")
+ || name == QLatin1String("let")
+ || name == QLatin1String("package")
+ || name == QLatin1String("private")
+ || name == QLatin1String("protected")
+ || name == QLatin1String("public")
+ || name == QLatin1String("static")
+ || name == QLatin1String("yield")) {
+ _cg->throwSyntaxError(loc, QCoreApplication::translate("qv4codegen", "Unexpected strict mode reserved word"));
+ }
+ }
+ }
+ void checkForArguments(AST::FormalParameterList *parameters)
+ {
+ while (parameters) {
+ if (parameters->name == QStringLiteral("arguments"))
+ _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
+ parameters = parameters->next;
+ }
+ }
+
+ virtual bool visit(Program *ast)
+ {
+ enterEnvironment(ast);
+ checkDirectivePrologue(ast->elements);
+ return true;
+ }
+
+ virtual void endVisit(Program *)
+ {
+ leaveEnvironment();
+ }
+
+ virtual bool visit(CallExpression *ast)
+ {
+ if (! _env->hasDirectEval) {
+ if (IdentifierExpression *id = cast<IdentifierExpression *>(ast->base)) {
+ if (id->name == QStringLiteral("eval")) {
+ if (_env->usesArgumentsObject == Environment::ArgumentsObjectUnknown)
+ _env->usesArgumentsObject = Environment::ArgumentsObjectUsed;
+ _env->hasDirectEval = true;
+ }
+ }
+ }
+ int argc = 0;
+ for (ArgumentList *it = ast->arguments; it; it = it->next)
+ ++argc;
+ _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc);
+ return true;
+ }
+
+ virtual bool visit(NewMemberExpression *ast)
+ {
+ int argc = 0;
+ for (ArgumentList *it = ast->arguments; it; it = it->next)
+ ++argc;
+ _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc);
+ return true;
+ }
+
+ virtual bool visit(ArrayLiteral *ast)
+ {
+ int index = 0;
+ for (ElementList *it = ast->elements; it; it = it->next) {
+ for (Elision *elision = it->elision; elision; elision = elision->next)
+ ++index;
+ ++index;
+ }
+ if (ast->elision) {
+ for (Elision *elision = ast->elision->next; elision; elision = elision->next)
+ ++index;
+ }
+ _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, index);
+ return true;
+ }
+
+ virtual bool visit(VariableDeclaration *ast)
+ {
+ if (_env->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
+ _cg->throwSyntaxError(ast->identifierToken, QCoreApplication::translate("qv4codegen", "Variable name may not be eval or arguments in strict mode"));
+ checkName(ast->name, ast->identifierToken);
+ if (ast->name == QLatin1String("arguments"))
+ _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
+ _env->enter(ast->name.toString(), ast->expression ? Environment::VariableDefinition : Environment::VariableDeclaration);
+ return true;
+ }
+
+ virtual bool visit(IdentifierExpression *ast)
+ {
+ checkName(ast->name, ast->identifierToken);
+ if (_env->usesArgumentsObject == Environment::ArgumentsObjectUnknown && ast->name == QLatin1String("arguments"))
+ _env->usesArgumentsObject = Environment::ArgumentsObjectUsed;
+ return true;
+ }
+
+ virtual bool visit(ExpressionStatement *ast)
+ {
+ if (FunctionExpression* expr = AST::cast<AST::FunctionExpression*>(ast->expression)) {
+ if (!_allowFuncDecls)
+ _cg->throwSyntaxError(expr->functionToken, QCoreApplication::translate("qv4codegen", "conditional function or closure declaration"));
+
+ enterFunction(expr, /*enterName*/ true);
+ Node::accept(expr->formals, this);
+ Node::accept(expr->body, this);
+ leaveEnvironment();
+ return false;
+ } else {
+ SourceLocation firstToken = ast->firstSourceLocation();
+ if (_sourceCode.midRef(firstToken.offset, firstToken.length) == QStringLiteral("function")) {
+ _cg->throwSyntaxError(firstToken, QCoreApplication::translate("qv4codegen", "unexpected token"));
+ }
+ }
+ return true;
+ }
+
+ virtual bool visit(FunctionExpression *ast)
+ {
+ enterFunction(ast, /*enterName*/ false);
+ return true;
+ }
+
+ void enterFunction(FunctionExpression *ast, bool enterName, bool isExpression = true)
+ {
+ if (_env->isStrict && (ast->name == QLatin1String("eval") || ast->name == QLatin1String("arguments")))
+ _cg->throwSyntaxError(ast->identifierToken, QCoreApplication::translate("qv4codegen", "Function name may not be eval or arguments in strict mode"));
+ enterFunction(ast, ast->name.toString(), ast->formals, ast->body, enterName ? ast : 0, isExpression);
+ }
+
+ virtual void endVisit(FunctionExpression *)
+ {
+ leaveEnvironment();
+ }
+
+ virtual bool visit(ObjectLiteral *ast)
+ {
+ int argc = 0;
+ for (PropertyAssignmentList *it = ast->properties; it; it = it->next) {
+ ++argc;
+ if (AST::cast<AST::PropertyGetterSetter *>(it->assignment))
+ ++argc;
+ }
+ _env->maxNumberOfArguments = qMax(_env->maxNumberOfArguments, argc);
+
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, true);
+ Node::accept(ast->properties, this);
+ return false;
+ }
+
+ virtual bool visit(PropertyGetterSetter *ast)
+ {
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, true);
+ enterFunction(ast, QString(), ast->formals, ast->functionBody, /*FunctionExpression*/0, /*isExpression*/false);
+ return true;
+ }
+
+ virtual void endVisit(PropertyGetterSetter *)
+ {
+ leaveEnvironment();
+ }
+
+ virtual bool visit(FunctionDeclaration *ast)
+ {
+ enterFunction(ast, /*enterName*/ true, /*isExpression */false);
+ return true;
+ }
+
+ virtual void endVisit(FunctionDeclaration *)
+ {
+ leaveEnvironment();
+ }
+
+ virtual bool visit(FunctionBody *ast)
+ {
+ TemporaryBoolAssignment inFuncBody(_inFuncBody, true);
+ Node::accept(ast->elements, this);
+ return false;
+ }
+
+ virtual bool visit(WithStatement *ast)
+ {
+ if (_env->isStrict) {
+ _cg->throwSyntaxError(ast->withToken, QCoreApplication::translate("qv4codegen", "'with' statement is not allowed in strict mode"));
+ return false;
+ }
+
+ return true;
+ }
+
+ virtual bool visit(IfStatement *ast) {
+ Node::accept(ast->expression, this);
+
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_inFuncBody);
+ Node::accept(ast->ok, this);
+ Node::accept(ast->ko, this);
+
+ return false;
+ }
+
+ virtual bool visit(WhileStatement *ast) {
+ Node::accept(ast->expression, this);
+
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_inFuncBody);
+ Node::accept(ast->statement, this);
+
+ return false;
+ }
+
+ virtual bool visit(DoWhileStatement *ast) {
+ {
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ Node::accept(ast->statement, this);
+ }
+ Node::accept(ast->expression, this);
+ return false;
+ }
+
+ virtual bool visit(ForStatement *ast) {
+ Node::accept(ast->initialiser, this);
+ Node::accept(ast->condition, this);
+ Node::accept(ast->expression, this);
+
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ Node::accept(ast->statement, this);
+
+ return false;
+ }
+
+ virtual bool visit(LocalForStatement *ast) {
+ Node::accept(ast->declarations, this);
+ Node::accept(ast->condition, this);
+ Node::accept(ast->expression, this);
+
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ Node::accept(ast->statement, this);
+
+ return false;
+ }
+
+ virtual bool visit(ForEachStatement *ast) {
+ Node::accept(ast->initialiser, this);
+ Node::accept(ast->expression, this);
+
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ Node::accept(ast->statement, this);
+
+ return false;
+ }
+
+ virtual bool visit(LocalForEachStatement *ast) {
+ Node::accept(ast->declaration, this);
+ Node::accept(ast->expression, this);
+
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, !_env->isStrict);
+ Node::accept(ast->statement, this);
+
+ return false;
+ }
+
+ virtual bool visit(Block *ast) {
+ TemporaryBoolAssignment allowFuncDecls(_allowFuncDecls, _env->isStrict ? false : _allowFuncDecls);
+ Node::accept(ast->statements, this);
+ return false;
+ }
+
+private:
+ void enterFunction(Node *ast, const QString &name, FormalParameterList *formals, FunctionBody *body, FunctionExpression *expr, bool isExpression)
+ {
+ bool wasStrict = false;
+ if (_env) {
+ _env->hasNestedFunctions = true;
+ // The identifier of a function expression cannot be referenced from the enclosing environment.
+ if (expr)
+ _env->enter(name, Environment::FunctionDefinition, expr);
+ if (name == QLatin1String("arguments"))
+ _env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
+ wasStrict = _env->isStrict;
+ }
+
+ enterEnvironment(ast);
+ checkForArguments(formals);
+
+ _env->isNamedFunctionExpression = isExpression && !name.isEmpty();
+ _env->formals = formals;
+
+ if (body)
+ checkDirectivePrologue(body->elements);
+
+ if (wasStrict || _env->isStrict) {
+ QStringList args;
+ for (FormalParameterList *it = formals; it; it = it->next) {
+ QString arg = it->name.toString();
+ if (args.contains(arg))
+ _cg->throwSyntaxError(it->identifierToken, QCoreApplication::translate("qv4codegen", "Duplicate parameter name '%1' is not allowed in strict mode").arg(arg));
+ if (arg == QLatin1String("eval") || arg == QLatin1String("arguments"))
+ _cg->throwSyntaxError(it->identifierToken, QCoreApplication::translate("qv4codegen", "'%1' cannot be used as parameter name in strict mode").arg(arg));
+ args += arg;
+ }
+ }
+ }
+
+private: // fields:
+ Codegen *_cg;
+ const QString _sourceCode;
+ Environment *_env;
+ QStack<Environment *> _envStack;
+
+ bool _inFuncBody;
+ bool _allowFuncDecls;
+};
+
+Codegen::Codegen(QV4::ExecutionContext *context, bool strict)
+ : _module(0)
+ , _function(0)
+ , _block(0)
+ , _exitBlock(0)
+ , _throwBlock(0)
+ , _returnAddress(0)
+ , _mode(GlobalCode)
+ , _env(0)
+ , _loop(0)
+ , _labelledStatement(0)
+ , _scopeAndFinally(0)
+ , _context(context)
+ , _strictMode(strict)
+ , _errorHandler(0)
+{
+}
+
+Codegen::Codegen(ErrorHandler *errorHandler, bool strictMode)
+ : _module(0)
+ , _function(0)
+ , _block(0)
+ , _exitBlock(0)
+ , _throwBlock(0)
+ , _returnAddress(0)
+ , _mode(GlobalCode)
+ , _env(0)
+ , _loop(0)
+ , _labelledStatement(0)
+ , _scopeAndFinally(0)
+ , _context(0)
+ , _strictMode(strictMode)
+ , _errorHandler(errorHandler)
+{
+}
+
+V4IR::Function *Codegen::operator()(const QString &fileName,
+ const QString &sourceCode,
+ Program *node,
+ V4IR::Module *module,
+ Mode mode,
+ const QStringList &inheritedLocals)
+{
+ assert(node);
+
+ _fileName = fileName;
+ _module = module;
+ _env = 0;
+
+ ScanFunctions scan(this, sourceCode);
+ scan(node);
+
+ V4IR::Function *globalCode = defineFunction(QStringLiteral("%entry"), node, 0,
+ node->elements, mode, inheritedLocals);
+ qDeleteAll(_envMap);
+ _envMap.clear();
+
+ return globalCode;
+}
+
+V4IR::Function *Codegen::operator()(const QString &fileName,
+ const QString &sourceCode,
+ AST::FunctionExpression *ast,
+ V4IR::Module *module)
+{
+ _fileName = fileName;
+ _module = module;
+ _env = 0;
+
+ ScanFunctions scan(this, sourceCode);
+ // fake a global environment
+ scan.enterEnvironment(0);
+ scan(ast);
+ scan.leaveEnvironment();
+
+ V4IR::Function *function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0);
+
+ qDeleteAll(_envMap);
+ _envMap.clear();
+
+ return function;
+}
+
+
+void Codegen::enterEnvironment(Node *node)
+{
+ _env = _envMap.value(node);
+ assert(_env);
+}
+
+void Codegen::leaveEnvironment()
+{
+ assert(_env);
+ _env = _env->parent;
+}
+
+void Codegen::enterLoop(Statement *node, V4IR::BasicBlock *startBlock, V4IR::BasicBlock *breakBlock, V4IR::BasicBlock *continueBlock)
+{
+ if (startBlock)
+ startBlock->markAsGroupStart();
+ _loop = new Loop(node, startBlock, breakBlock, continueBlock, _loop);
+ _loop->labelledStatement = _labelledStatement; // consume the enclosing labelled statement
+ _loop->scopeAndFinally = _scopeAndFinally;
+ _labelledStatement = 0;
+}
+
+void Codegen::leaveLoop()
+{
+ Loop *current = _loop;
+ _loop = _loop->parent;
+ delete current;
+}
+
+V4IR::Expr *Codegen::member(V4IR::Expr *base, const QString *name)
+{
+ if (base->asTemp() /*|| base->asName()*/)
+ return _block->MEMBER(base->asTemp(), name);
+ else {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), base);
+ return _block->MEMBER(_block->TEMP(t), name);
+ }
+}
+
+V4IR::Expr *Codegen::subscript(V4IR::Expr *base, V4IR::Expr *index)
+{
+ if (! base->asTemp()) {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), base);
+ base = _block->TEMP(t);
+ }
+
+ if (! index->asTemp()) {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), index);
+ index = _block->TEMP(t);
+ }
+
+ assert(base->asTemp() && index->asTemp());
+ return _block->SUBSCRIPT(base->asTemp(), index->asTemp());
+}
+
+V4IR::Expr *Codegen::argument(V4IR::Expr *expr)
+{
+ if (expr && ! expr->asTemp()) {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), expr);
+ expr = _block->TEMP(t);
+ }
+ return expr;
+}
+
+// keeps references alive, converts other expressions to temps
+V4IR::Expr *Codegen::reference(V4IR::Expr *expr)
+{
+ if (expr && !expr->asTemp() && !expr->asName() && !expr->asMember() && !expr->asSubscript()) {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), expr);
+ expr = _block->TEMP(t);
+ }
+ return expr;
+}
+
+V4IR::Expr *Codegen::unop(V4IR::AluOp op, V4IR::Expr *expr)
+{
+ Q_ASSERT(op != V4IR::OpIncrement);
+ Q_ASSERT(op != V4IR::OpDecrement);
+
+ if (V4IR::Const *c = expr->asConst()) {
+ if (c->type == V4IR::NumberType) {
+ switch (op) {
+ case V4IR::OpNot:
+ return _block->CONST(V4IR::BoolType, !c->value);
+ case V4IR::OpUMinus:
+ return _block->CONST(V4IR::NumberType, -c->value);
+ case V4IR::OpUPlus:
+ return expr;
+ case V4IR::OpCompl:
+ return _block->CONST(V4IR::NumberType, ~QV4::Value::toInt32(c->value));
+ case V4IR::OpIncrement:
+ return _block->CONST(V4IR::NumberType, c->value + 1);
+ case V4IR::OpDecrement:
+ return _block->CONST(V4IR::NumberType, c->value - 1);
+ default:
+ break;
+ }
+ }
+ }
+ if (! expr->asTemp()) {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), expr);
+ expr = _block->TEMP(t);
+ }
+ assert(expr->asTemp());
+ return _block->UNOP(op, expr->asTemp());
+}
+
+V4IR::Expr *Codegen::binop(V4IR::AluOp op, V4IR::Expr *left, V4IR::Expr *right)
+{
+ if (V4IR::Const *c1 = left->asConst()) {
+ if (V4IR::Const *c2 = right->asConst()) {
+ if (c1->type == V4IR::NumberType && c2->type == V4IR::NumberType) {
+ switch (op) {
+ case V4IR::OpAdd: return _block->CONST(V4IR::NumberType, c1->value + c2->value);
+ case V4IR::OpAnd: return _block->CONST(V4IR::BoolType, c1->value ? c2->value : 0);
+ case V4IR::OpBitAnd: return _block->CONST(V4IR::NumberType, int(c1->value) & int(c2->value));
+ case V4IR::OpBitOr: return _block->CONST(V4IR::NumberType, int(c1->value) | int(c2->value));
+ case V4IR::OpBitXor: return _block->CONST(V4IR::NumberType, int(c1->value) ^ int(c2->value));
+ case V4IR::OpDiv: return _block->CONST(V4IR::NumberType, c1->value / c2->value);
+ case V4IR::OpEqual: return _block->CONST(V4IR::BoolType, c1->value == c2->value);
+ case V4IR::OpNotEqual: return _block->CONST(V4IR::BoolType, c1->value != c2->value);
+ case V4IR::OpStrictEqual: return _block->CONST(V4IR::BoolType, c1->value == c2->value);
+ case V4IR::OpStrictNotEqual: return _block->CONST(V4IR::BoolType, c1->value != c2->value);
+ case V4IR::OpGe: return _block->CONST(V4IR::BoolType, c1->value >= c2->value);
+ case V4IR::OpGt: return _block->CONST(V4IR::BoolType, c1->value > c2->value);
+ case V4IR::OpLe: return _block->CONST(V4IR::BoolType, c1->value <= c2->value);
+ case V4IR::OpLt: return _block->CONST(V4IR::BoolType, c1->value < c2->value);
+ case V4IR::OpLShift: return _block->CONST(V4IR::NumberType, QV4::Value::toInt32(c1->value) << (QV4::Value::toUInt32(c2->value) & 0x1f));
+ case V4IR::OpMod: return _block->CONST(V4IR::NumberType, std::fmod(c1->value, c2->value));
+ case V4IR::OpMul: return _block->CONST(V4IR::NumberType, c1->value * c2->value);
+ case V4IR::OpOr: return _block->CONST(V4IR::NumberType, c1->value ? c1->value : c2->value);
+ case V4IR::OpRShift: return _block->CONST(V4IR::NumberType, QV4::Value::toInt32(c1->value) >> (QV4::Value::toUInt32(c2->value) & 0x1f));
+ case V4IR::OpSub: return _block->CONST(V4IR::NumberType, c1->value - c2->value);
+ case V4IR::OpURShift: return _block->CONST(V4IR::NumberType,QV4::Value::toUInt32(c1->value) >> (QV4::Value::toUInt32(c2->value) & 0x1f));
+
+ case V4IR::OpInstanceof:
+ case V4IR::OpIn:
+ break;
+
+ case V4IR::OpIfTrue: // unary ops
+ case V4IR::OpNot:
+ case V4IR::OpUMinus:
+ case V4IR::OpUPlus:
+ case V4IR::OpCompl:
+ case V4IR::OpIncrement:
+ case V4IR::OpDecrement:
+ case V4IR::OpInvalid:
+ break;
+ }
+ }
+ }
+ } else if (op == V4IR::OpAdd) {
+ if (V4IR::String *s1 = left->asString()) {
+ if (V4IR::String *s2 = right->asString()) {
+ return _block->STRING(_function->newString(*s1->value + *s2->value));
+ }
+ }
+ }
+
+ if (!left->asTemp()) {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), left);
+ left = _block->TEMP(t);
+ }
+
+ if (!right->asTemp()) {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), right);
+ right = _block->TEMP(t);
+ }
+
+ assert(left->asTemp());
+ assert(right->asTemp());
+
+ return _block->BINOP(op, left, right);
+}
+
+V4IR::Expr *Codegen::call(V4IR::Expr *base, V4IR::ExprList *args)
+{
+ base = reference(base);
+ return _block->CALL(base, args);
+}
+
+void Codegen::move(V4IR::Expr *target, V4IR::Expr *source, V4IR::AluOp op)
+{
+ assert(target->isLValue());
+
+ // TODO: verify the rest of the function for when op == OpInvalid
+ if (op != V4IR::OpInvalid) {
+ move(target, binop(op, target, source), V4IR::OpInvalid);
+ return;
+ }
+
+ if (!source->asTemp() && !source->asConst() && (op != V4IR::OpInvalid || ! target->asTemp())) {
+ unsigned t = _block->newTemp();
+ _block->MOVE(_block->TEMP(t), source);
+ source = _block->TEMP(t);
+ }
+ if (source->asConst() && (!target->asTemp() || op != V4IR::OpInvalid)) {
+ unsigned t = _block->newTemp();
+ _block->MOVE(_block->TEMP(t), source);
+ source = _block->TEMP(t);
+ }
+
+ _block->MOVE(target, source, op);
+}
+
+void Codegen::cjump(V4IR::Expr *cond, V4IR::BasicBlock *iftrue, V4IR::BasicBlock *iffalse)
+{
+ if (! (cond->asTemp() || cond->asBinop())) {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), cond);
+ cond = _block->TEMP(t);
+ }
+ _block->CJUMP(cond, iftrue, iffalse);
+}
+
+void Codegen::accept(Node *node)
+{
+ if (node)
+ node->accept(this);
+}
+
+void Codegen::statement(Statement *ast)
+{
+ _block->nextLocation = ast->firstSourceLocation();
+ accept(ast);
+}
+
+void Codegen::statement(ExpressionNode *ast)
+{
+ if (! ast) {
+ return;
+ } else {
+ Result r(nx);
+ qSwap(_expr, r);
+ accept(ast);
+ qSwap(_expr, r);
+ if (r.format == ex) {
+ if (r->asCall()) {
+ _block->EXP(*r); // the nest nx representation for calls is EXP(CALL(c..))
+ } else if (r->asTemp()) {
+ // there is nothing to do
+ } else {
+ unsigned t = _block->newTemp();
+ move(_block->TEMP(t), *r);
+ }
+ }
+ }
+}
+
+void Codegen::condition(ExpressionNode *ast, V4IR::BasicBlock *iftrue, V4IR::BasicBlock *iffalse)
+{
+ if (ast) {
+ Result r(iftrue, iffalse);
+ qSwap(_expr, r);
+ accept(ast);
+ qSwap(_expr, r);
+ if (r.format == ex) {
+ cjump(*r, r.iftrue, r.iffalse);
+ }
+ }
+}
+
+Codegen::Result Codegen::expression(ExpressionNode *ast)
+{
+ Result r;
+ if (ast) {
+ qSwap(_expr, r);
+ accept(ast);
+ qSwap(_expr, r);
+ }
+ return r;
+}
+
+QString Codegen::propertyName(PropertyName *ast)
+{
+ QString p;
+ if (ast) {
+ qSwap(_property, p);
+ accept(ast);
+ qSwap(_property, p);
+ }
+ return p;
+}
+
+Codegen::Result Codegen::sourceElement(SourceElement *ast)
+{
+ Result r(nx);
+ if (ast) {
+ qSwap(_expr, r);
+ accept(ast);
+ qSwap(_expr, r);
+ }
+ return r;
+}
+
+Codegen::UiMember Codegen::uiObjectMember(UiObjectMember *ast)
+{
+ UiMember m;
+ if (ast) {
+ qSwap(_uiMember, m);
+ accept(ast);
+ qSwap(_uiMember, m);
+ }
+ return m;
+}
+
+void Codegen::functionBody(FunctionBody *ast)
+{
+ if (ast)
+ sourceElements(ast->elements);
+}
+
+void Codegen::program(Program *ast)
+{
+ if (ast) {
+ sourceElements(ast->elements);
+ }
+}
+
+void Codegen::sourceElements(SourceElements *ast)
+{
+ for (SourceElements *it = ast; it; it = it->next) {
+ sourceElement(it->element);
+ }
+}
+
+void Codegen::variableDeclaration(VariableDeclaration *ast)
+{
+ V4IR::Expr *initializer = 0;
+ if (!ast->expression)
+ return;
+ Result expr = expression(ast->expression);
+ assert(expr.code);
+ initializer = *expr;
+
+ if (! _env->parent || _function->insideWithOrCatch) {
+ // it's global code.
+ move(_block->NAME(ast->name.toString(), ast->identifierToken.startLine, ast->identifierToken.startColumn), initializer);
+ } else {
+ const int index = _env->findMember(ast->name.toString());
+ assert(index != -1);
+ move(_block->LOCAL(index, 0), initializer);
+ }
+}
+
+void Codegen::variableDeclarationList(VariableDeclarationList *ast)
+{
+ for (VariableDeclarationList *it = ast; it; it = it->next) {
+ variableDeclaration(it->declaration);
+ }
+}
+
+
+bool Codegen::visit(ArgumentList *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(CaseBlock *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(CaseClause *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(CaseClauses *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(Catch *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(DefaultClause *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(ElementList *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(Elision *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(Finally *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(FormalParameterList *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(FunctionBody *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(Program *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(PropertyAssignmentList *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(PropertyNameAndValue *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(PropertyGetterSetter *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(SourceElements *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(StatementList *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(UiArrayMemberList *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(UiImport *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(UiImportList *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(UiObjectInitializer *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(UiObjectMemberList *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(UiParameterList *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(UiProgram *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(UiQualifiedId *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(VariableDeclaration *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(VariableDeclarationList *)
+{
+ assert(!"unreachable");
+ return false;
+}
+
+bool Codegen::visit(Expression *ast)
+{
+ statement(ast->left);
+ accept(ast->right);
+ return false;
+}
+
+bool Codegen::visit(ArrayLiteral *ast)
+{
+ V4IR::ExprList *args = 0;
+ V4IR::ExprList *current = 0;
+ for (ElementList *it = ast->elements; it; it = it->next) {
+ for (Elision *elision = it->elision; elision; elision = elision->next) {
+ V4IR::ExprList *arg = _function->New<V4IR::ExprList>();
+ if (!current) {
+ args = arg;
+ } else {
+ current->next = arg;
+ }
+ current = arg;
+ current->expr = _block->CONST(V4IR::MissingType, 0);
+ }
+ Result expr = expression(it->expression);
+
+ V4IR::ExprList *arg = _function->New<V4IR::ExprList>();
+ if (!current) {
+ args = arg;
+ } else {
+ current->next = arg;
+ }
+ current = arg;
+
+ V4IR::Expr *exp = *expr;
+ if (exp->asTemp() || exp->asConst()) {
+ current->expr = exp;
+ } else {
+ unsigned value = _block->newTemp();
+ move(_block->TEMP(value), exp);
+ current->expr = _block->TEMP(value);
+ }
+ }
+ for (Elision *elision = ast->elision; elision; elision = elision->next) {
+ V4IR::ExprList *arg = _function->New<V4IR::ExprList>();
+ if (!current) {
+ args = arg;
+ } else {
+ current->next = arg;
+ }
+ current = arg;
+ current->expr = _block->CONST(V4IR::MissingType, 0);
+ }
+
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), _block->CALL(_block->NAME(V4IR::Name::builtin_define_array, 0, 0), args));
+ _expr.code = _block->TEMP(t);
+ return false;
+}
+
+bool Codegen::visit(ArrayMemberExpression *ast)
+{
+ Result base = expression(ast->base);
+ Result index = expression(ast->expression);
+ _expr.code = subscript(*base, *index);
+ return false;
+}
+
+static V4IR::AluOp baseOp(int op)
+{
+ switch ((QSOperator::Op) op) {
+ case QSOperator::InplaceAnd: return V4IR::OpBitAnd;
+ case QSOperator::InplaceSub: return V4IR::OpSub;
+ case QSOperator::InplaceDiv: return V4IR::OpDiv;
+ case QSOperator::InplaceAdd: return V4IR::OpAdd;
+ case QSOperator::InplaceLeftShift: return V4IR::OpLShift;
+ case QSOperator::InplaceMod: return V4IR::OpMod;
+ case QSOperator::InplaceMul: return V4IR::OpMul;
+ case QSOperator::InplaceOr: return V4IR::OpBitOr;
+ case QSOperator::InplaceRightShift: return V4IR::OpRShift;
+ case QSOperator::InplaceURightShift: return V4IR::OpURShift;
+ case QSOperator::InplaceXor: return V4IR::OpBitXor;
+ default: return V4IR::OpInvalid;
+ }
+}
+
+bool Codegen::visit(BinaryExpression *ast)
+{
+ if (ast->op == QSOperator::And) {
+ if (_expr.accept(cx)) {
+ V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock());
+ condition(ast->left, iftrue, _expr.iffalse);
+ _block = iftrue;
+ condition(ast->right, _expr.iftrue, _expr.iffalse);
+ } else {
+ V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock());
+
+ const unsigned r = _block->newTemp();
+
+ move(_block->TEMP(r), *expression(ast->left));
+ cjump(_block->TEMP(r), iftrue, endif);
+ _block = iftrue;
+ move(_block->TEMP(r), *expression(ast->right));
+ _block->JUMP(endif);
+
+ _expr.code = _block->TEMP(r);
+ _block = endif;
+ }
+ return false;
+ } else if (ast->op == QSOperator::Or) {
+ if (_expr.accept(cx)) {
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
+ condition(ast->left, _expr.iftrue, iffalse);
+ _block = iffalse;
+ condition(ast->right, _expr.iftrue, _expr.iffalse);
+ } else {
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock());
+
+ const unsigned r = _block->newTemp();
+ move(_block->TEMP(r), *expression(ast->left));
+ cjump(_block->TEMP(r), endif, iffalse);
+ _block = iffalse;
+ move(_block->TEMP(r), *expression(ast->right));
+ _block->JUMP(endif);
+
+ _block = endif;
+ _expr.code = _block->TEMP(r);
+ }
+ return false;
+ }
+
+ V4IR::Expr* left = *expression(ast->left);
+ throwSyntaxErrorOnEvalOrArgumentsInStrictMode(left, ast->left->lastSourceLocation());
+
+ switch (ast->op) {
+ case QSOperator::Or:
+ case QSOperator::And:
+ break;
+
+ case QSOperator::Assign: {
+ V4IR::Expr* right = *expression(ast->right);
+ if (! (left->asTemp() || left->asName() || left->asSubscript() || left->asMember()))
+ throwReferenceError(ast->operatorToken, QCoreApplication::translate("qv4codegen", "left-hand side of assignment operator is not an lvalue"));
+
+ if (_expr.accept(nx)) {
+ move(left, right);
+ } else {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), right);
+ move(left, _block->TEMP(t));
+ _expr.code = _block->TEMP(t);
+ }
+ break;
+ }
+
+ case QSOperator::InplaceAnd:
+ case QSOperator::InplaceSub:
+ case QSOperator::InplaceDiv:
+ case QSOperator::InplaceAdd:
+ case QSOperator::InplaceLeftShift:
+ case QSOperator::InplaceMod:
+ case QSOperator::InplaceMul:
+ case QSOperator::InplaceOr:
+ case QSOperator::InplaceRightShift:
+ case QSOperator::InplaceURightShift:
+ case QSOperator::InplaceXor: {
+ V4IR::Expr* right = *expression(ast->right);
+ if (!left->isLValue())
+ throwSyntaxError(ast->operatorToken, QCoreApplication::translate("qv4codegen", "left-hand side of inplace operator is not an lvalue"));
+
+ if (_expr.accept(nx)) {
+ move(left, right, baseOp(ast->op));
+ } else {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), right);
+ move(left, _block->TEMP(t), baseOp(ast->op));
+ _expr.code = left;
+ }
+ break;
+ }
+
+ case QSOperator::In:
+ case QSOperator::InstanceOf:
+ case QSOperator::Equal:
+ case QSOperator::NotEqual:
+ case QSOperator::Ge:
+ case QSOperator::Gt:
+ case QSOperator::Le:
+ case QSOperator::Lt:
+ case QSOperator::StrictEqual:
+ case QSOperator::StrictNotEqual: {
+ if (!left->asTemp() && !left->asConst()) {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), left);
+ left = _block->TEMP(t);
+ }
+
+ V4IR::Expr* right = *expression(ast->right);
+
+ if (_expr.accept(cx)) {
+ cjump(binop(V4IR::binaryOperator(ast->op), left, right), _expr.iftrue, _expr.iffalse);
+ } else {
+ V4IR::Expr *e = binop(V4IR::binaryOperator(ast->op), left, right);
+ if (e->asConst() || e->asString())
+ _expr.code = e;
+ else {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), e);
+ _expr.code = _block->TEMP(t);
+ }
+ }
+ break;
+ }
+
+ case QSOperator::Add:
+ case QSOperator::BitAnd:
+ case QSOperator::BitOr:
+ case QSOperator::BitXor:
+ case QSOperator::Div:
+ case QSOperator::LShift:
+ case QSOperator::Mod:
+ case QSOperator::Mul:
+ case QSOperator::RShift:
+ case QSOperator::Sub:
+ case QSOperator::URShift: {
+ if (!left->asTemp() && !left->asConst()) {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), left);
+ left = _block->TEMP(t);
+ }
+
+ V4IR::Expr* right = *expression(ast->right);
+
+ V4IR::Expr *e = binop(V4IR::binaryOperator(ast->op), left, right);
+ if (e->asConst() || e->asString())
+ _expr.code = e;
+ else {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), e);
+ _expr.code = _block->TEMP(t);
+ }
+ break;
+ }
+
+ } // switch
+
+ return false;
+}
+
+bool Codegen::visit(CallExpression *ast)
+{
+ Result base = expression(ast->base);
+ V4IR::ExprList *args = 0, **args_it = &args;
+ for (ArgumentList *it = ast->arguments; it; it = it->next) {
+ Result arg = expression(it->expression);
+ V4IR::Expr *actual = argument(*arg);
+ *args_it = _function->New<V4IR::ExprList>();
+ (*args_it)->init(actual);
+ args_it = &(*args_it)->next;
+ }
+ _expr.code = call(*base, args);
+ return false;
+}
+
+bool Codegen::visit(ConditionalExpression *ast)
+{
+ V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock());
+
+ const unsigned t = _block->newTemp();
+
+ condition(ast->expression, iftrue, iffalse);
+
+ _block = iftrue;
+ move(_block->TEMP(t), *expression(ast->ok));
+ _block->JUMP(endif);
+
+ _block = iffalse;
+ move(_block->TEMP(t), *expression(ast->ko));
+ _block->JUMP(endif);
+
+ _block = endif;
+
+ _expr.code = _block->TEMP(t);
+
+ return false;
+}
+
+bool Codegen::visit(DeleteExpression *ast)
+{
+ V4IR::Expr* expr = *expression(ast->expression);
+ // Temporaries cannot be deleted
+ if (expr->asTemp() && expr->asTemp()->index < _env->members.size()) {
+ // Trying to delete a function argument might throw.
+ if (_function->isStrict && expr->asTemp()->index < 0)
+ throwSyntaxError(ast->deleteToken, "Delete of an unqualified identifier in strict mode.");
+ _expr.code = _block->CONST(V4IR::BoolType, 0);
+ return false;
+ }
+ if (_function->isStrict && expr->asName())
+ throwSyntaxError(ast->deleteToken, "Delete of an unqualified identifier in strict mode.");
+
+ // [[11.4.1]] Return true if it's not a reference
+ if (expr->asConst() || expr->asString()) {
+ _expr.code = _block->CONST(V4IR::BoolType, 1);
+ return false;
+ }
+
+ // Return values from calls are also not a reference, but we have to
+ // perform the call to allow for side effects.
+ if (expr->asCall()) {
+ _block->EXP(expr);
+ _expr.code = _block->CONST(V4IR::BoolType, 1);
+ return false;
+ }
+ if (expr->asTemp() && expr->asTemp()->index >= _env->members.size()) {
+ _expr.code = _block->CONST(V4IR::BoolType, 1);
+ return false;
+ }
+
+ V4IR::ExprList *args = _function->New<V4IR::ExprList>();
+ args->init(reference(expr));
+ _expr.code = call(_block->NAME(V4IR::Name::builtin_delete, ast->deleteToken.startLine, ast->deleteToken.startColumn), args);
+ return false;
+}
+
+bool Codegen::visit(FalseLiteral *)
+{
+ if (_expr.accept(cx)) {
+ _block->JUMP(_expr.iffalse);
+ } else {
+ _expr.code = _block->CONST(V4IR::BoolType, 0);
+ }
+ return false;
+}
+
+bool Codegen::visit(FieldMemberExpression *ast)
+{
+ Result base = expression(ast->base);
+ _expr.code = member(*base, _function->newString(ast->name.toString()));
+ return false;
+}
+
+bool Codegen::visit(FunctionExpression *ast)
+{
+ V4IR::Function *function = defineFunction(ast->name.toString(), ast, ast->formals, ast->body ? ast->body->elements : 0);
+ _expr.code = _block->CLOSURE(function);
+ return false;
+}
+
+V4IR::Expr *Codegen::identifier(const QString &name, int line, int col)
+{
+ uint scope = 0;
+ Environment *e = _env;
+ V4IR::Function *f = _function;
+
+ while (f && e->parent) {
+ if ((f->usesArgumentsObject && name == "arguments") || (!f->isStrict && f->hasDirectEval) || f->insideWithOrCatch || (f->isNamedExpression && f->name == name))
+ break;
+ int index = e->findMember(name);
+ assert (index < e->members.size());
+ if (index != -1) {
+ return _block->LOCAL(index, scope);
+ }
+ const int argIdx = f->indexOfArgument(&name);
+ if (argIdx != -1)
+ return _block->ARG(argIdx, scope);
+ ++scope;
+ e = e->parent;
+ f = f->outer;
+ }
+
+ if (!e->parent && (!f || !f->insideWithOrCatch) && _mode != EvalCode && _mode != QmlBinding && (!f || f->name != name))
+ return _block->GLOBALNAME(name, line, col);
+
+ // global context or with. Lookup by name
+ return _block->NAME(name, line, col);
+
+}
+
+bool Codegen::visit(IdentifierExpression *ast)
+{
+ _expr.code = identifier(ast->name.toString(), ast->identifierToken.startLine, ast->identifierToken.startColumn);
+ return false;
+}
+
+bool Codegen::visit(NestedExpression *ast)
+{
+ accept(ast->expression);
+ return false;
+}
+
+bool Codegen::visit(NewExpression *ast)
+{
+ Result base = expression(ast->expression);
+ V4IR::Expr *expr = *base;
+ if (expr && !expr->asTemp() && !expr->asName() && !expr->asMember()) {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), expr);
+ expr = _block->TEMP(t);
+ }
+ _expr.code = _block->NEW(expr, 0);
+ return false;
+}
+
+bool Codegen::visit(NewMemberExpression *ast)
+{
+ Result base = expression(ast->base);
+ V4IR::Expr *expr = *base;
+ if (expr && !expr->asTemp() && !expr->asName() && !expr->asMember()) {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), expr);
+ expr = _block->TEMP(t);
+ }
+
+ V4IR::ExprList *args = 0, **args_it = &args;
+ for (ArgumentList *it = ast->arguments; it; it = it->next) {
+ Result arg = expression(it->expression);
+ V4IR::Expr *actual = argument(*arg);
+ *args_it = _function->New<V4IR::ExprList>();
+ (*args_it)->init(actual);
+ args_it = &(*args_it)->next;
+ }
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), _block->NEW(expr, args));
+ _expr.code = _block->TEMP(t);
+ return false;
+}
+
+bool Codegen::visit(NotExpression *ast)
+{
+ Result expr = expression(ast->expression);
+ const unsigned r = _block->newTemp();
+ move(_block->TEMP(r), unop(V4IR::OpNot, *expr));
+ _expr.code = _block->TEMP(r);
+ return false;
+}
+
+bool Codegen::visit(NullExpression *)
+{
+ if (_expr.accept(cx)) _block->JUMP(_expr.iffalse);
+ else _expr.code = _block->CONST(V4IR::NullType, 0);
+
+ return false;
+}
+
+bool Codegen::visit(NumericLiteral *ast)
+{
+ if (_expr.accept(cx)) {
+ if (ast->value) _block->JUMP(_expr.iftrue);
+ else _block->JUMP(_expr.iffalse);
+ } else {
+ _expr.code = _block->CONST(V4IR::NumberType, ast->value);
+ }
+ return false;
+}
+
+struct ObjectPropertyValue {
+ V4IR::Expr *value;
+ V4IR::Function *getter;
+ V4IR::Function *setter;
+};
+
+bool Codegen::visit(ObjectLiteral *ast)
+{
+ QMap<QString, ObjectPropertyValue> valueMap;
+
+ for (PropertyAssignmentList *it = ast->properties; it; it = it->next) {
+ if (PropertyNameAndValue *nv = AST::cast<AST::PropertyNameAndValue *>(it->assignment)) {
+ QString name = propertyName(nv->name);
+ Result value = expression(nv->value);
+ ObjectPropertyValue &v = valueMap[name];
+ if (v.getter || v.setter || (_function->isStrict && v.value))
+ throwSyntaxError(nv->lastSourceLocation(),
+ QCoreApplication::translate("qv4codegen", "Illegal duplicate key '%1' in object literal").arg(name));
+
+ valueMap[name].value = *value;
+ } else if (PropertyGetterSetter *gs = AST::cast<AST::PropertyGetterSetter *>(it->assignment)) {
+ QString name = propertyName(gs->name);
+ V4IR::Function *function = defineFunction(name, gs, gs->formals, gs->functionBody ? gs->functionBody->elements : 0);
+ ObjectPropertyValue &v = valueMap[name];
+ if (v.value ||
+ (gs->type == PropertyGetterSetter::Getter && v.getter) ||
+ (gs->type == PropertyGetterSetter::Setter && v.setter))
+ throwSyntaxError(gs->lastSourceLocation(),
+ QCoreApplication::translate("qv4codegen", "Illegal duplicate key '%1' in object literal").arg(name));
+ if (gs->type == PropertyGetterSetter::Getter)
+ v.getter = function;
+ else
+ v.setter = function;
+ } else {
+ Q_UNREACHABLE();
+ }
+ }
+
+ V4IR::ExprList *args = 0;
+
+ if (!valueMap.isEmpty()) {
+ V4IR::ExprList *current;
+ for (QMap<QString, ObjectPropertyValue>::iterator it = valueMap.begin(); it != valueMap.end(); ) {
+ if (QV4::String(0, it.key()).asArrayIndex() != UINT_MAX) {
+ ++it;
+ continue;
+ }
+
+ if (!args) {
+ args = _function->New<V4IR::ExprList>();
+ current = args;
+ } else {
+ current->next = _function->New<V4IR::ExprList>();
+ current = current->next;
+ }
+
+ current->expr = _block->NAME(it.key(), 0, 0);
+
+ if (it->value) {
+ current->next = _function->New<V4IR::ExprList>();
+ current = current->next;
+ current->expr = _block->CONST(V4IR::BoolType, true);
+
+ unsigned value = _block->newTemp();
+ move(_block->TEMP(value), it->value);
+
+ current->next = _function->New<V4IR::ExprList>();
+ current = current->next;
+ current->expr = _block->TEMP(value);
+ } else {
+ current->next = _function->New<V4IR::ExprList>();
+ current = current->next;
+ current->expr = _block->CONST(V4IR::BoolType, false);
+
+ unsigned getter = _block->newTemp();
+ unsigned setter = _block->newTemp();
+ move(_block->TEMP(getter), it->getter ? _block->CLOSURE(it->getter) : _block->CONST(V4IR::UndefinedType, 0));
+ move(_block->TEMP(setter), it->setter ? _block->CLOSURE(it->setter) : _block->CONST(V4IR::UndefinedType, 0));
+
+ current->next = _function->New<V4IR::ExprList>();
+ current = current->next;
+ current->expr = _block->TEMP(getter);
+ current->next = _function->New<V4IR::ExprList>();
+ current = current->next;
+ current->expr = _block->TEMP(setter);
+ }
+
+ it = valueMap.erase(it);
+ }
+ }
+
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), _block->CALL(_block->NAME(V4IR::Name::builtin_define_object_literal,
+ ast->firstSourceLocation().startLine, ast->firstSourceLocation().startColumn), args));
+
+ // What's left are array entries
+ if (!valueMap.isEmpty()) {
+ unsigned value = 0;
+ unsigned getter = 0;
+ unsigned setter = 0;
+ for (QMap<QString, ObjectPropertyValue>::const_iterator it = valueMap.constBegin(); it != valueMap.constEnd(); ++it) {
+ V4IR::ExprList *args = _function->New<V4IR::ExprList>();
+ V4IR::ExprList *current = args;
+ current->expr = _block->TEMP(t);
+ current->next = _function->New<V4IR::ExprList>();
+ current = current->next;
+ current->expr = _block->NAME(it.key(), 0, 0);
+ current->next = _function->New<V4IR::ExprList>();
+ current = current->next;
+
+ if (it->value) {
+ if (!value)
+ value = _block->newTemp();
+ move(_block->TEMP(value), it->value);
+ // __qmljs_builtin_define_property(Value object, String *name, Value val, ExecutionContext *ctx)
+ current->expr = _block->TEMP(value);
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_define_property, 0, 0), args));
+ } else {
+ if (!getter) {
+ getter = _block->newTemp();
+ setter = _block->newTemp();
+ }
+ move(_block->TEMP(getter), it->getter ? _block->CLOSURE(it->getter) : _block->CONST(V4IR::UndefinedType, 0));
+ move(_block->TEMP(setter), it->setter ? _block->CLOSURE(it->setter) : _block->CONST(V4IR::UndefinedType, 0));
+
+
+ // __qmljs_builtin_define_getter_setter(Value object, String *name, Value getter, Value setter, ExecutionContext *ctx);
+ current->expr = _block->TEMP(getter);
+ current->next = _function->New<V4IR::ExprList>();
+ current = current->next;
+ current->expr = _block->TEMP(setter);
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_define_getter_setter, 0, 0), args));
+ }
+ }
+ }
+
+ _expr.code = _block->TEMP(t);
+ return false;
+}
+
+bool Codegen::visit(PostDecrementExpression *ast)
+{
+ Result expr = expression(ast->base);
+ if (!expr->isLValue())
+ throwReferenceError(ast->base->lastSourceLocation(), "Invalid left-hand side expression in postfix operation");
+ throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->decrementToken);
+
+ if (_expr.accept(nx)) {
+ move(*expr, binop(V4IR::OpSub, *expr, _block->CONST(V4IR::NumberType, 1)));
+ } else {
+ V4IR::ExprList *args = _function->New<V4IR::ExprList>();
+ args->init(*expr);
+ _expr.code = call(_block->NAME(V4IR::Name::builtin_postdecrement, ast->lastSourceLocation().startLine, ast->lastSourceLocation().startColumn), args);
+ }
+ return false;
+}
+
+bool Codegen::visit(PostIncrementExpression *ast)
+{
+ Result expr = expression(ast->base);
+ if (!expr->isLValue())
+ throwReferenceError(ast->base->lastSourceLocation(), "Invalid left-hand side expression in postfix operation");
+ throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->incrementToken);
+
+ if (_expr.accept(nx)) {
+ move(*expr, binop(V4IR::OpAdd, unop(V4IR::OpUPlus, *expr), _block->CONST(V4IR::NumberType, 1)));
+ } else {
+ V4IR::ExprList *args = _function->New<V4IR::ExprList>();
+ args->init(*expr);
+ _expr.code = call(_block->NAME(V4IR::Name::builtin_postincrement, ast->lastSourceLocation().startLine, ast->lastSourceLocation().startColumn), args);
+ }
+ return false;
+}
+
+bool Codegen::visit(PreDecrementExpression *ast)
+{
+ Result expr = expression(ast->expression);
+ throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->decrementToken);
+ V4IR::Expr *op = binop(V4IR::OpSub, *expr, _block->CONST(V4IR::NumberType, 1));
+ if (_expr.accept(nx)) {
+ move(*expr, op);
+ } else {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), op);
+ move(*expr, _block->TEMP(t));
+ _expr.code = _block->TEMP(t);
+ }
+ return false;
+}
+
+bool Codegen::visit(PreIncrementExpression *ast)
+{
+ Result expr = expression(ast->expression);
+ throwSyntaxErrorOnEvalOrArgumentsInStrictMode(*expr, ast->incrementToken);
+ V4IR::Expr *op = binop(V4IR::OpAdd, unop(V4IR::OpUPlus, *expr), _block->CONST(V4IR::NumberType, 1));
+ if (_expr.accept(nx)) {
+ move(*expr, op);
+ } else {
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), op);
+ move(*expr, _block->TEMP(t));
+ _expr.code = _block->TEMP(t);
+ }
+ return false;
+}
+
+bool Codegen::visit(RegExpLiteral *ast)
+{
+ _expr.code = _block->REGEXP(_function->newString(ast->pattern.toString()), ast->flags);
+ return false;
+}
+
+bool Codegen::visit(StringLiteral *ast)
+{
+ _expr.code = _block->STRING(_function->newString(ast->value.toString()));
+ return false;
+}
+
+bool Codegen::visit(ThisExpression *ast)
+{
+ _expr.code = _block->NAME(QStringLiteral("this"), ast->thisToken.startLine, ast->thisToken.startColumn);
+ return false;
+}
+
+bool Codegen::visit(TildeExpression *ast)
+{
+ Result expr = expression(ast->expression);
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), unop(V4IR::OpCompl, *expr));
+ _expr.code = _block->TEMP(t);
+ return false;
+}
+
+bool Codegen::visit(TrueLiteral *)
+{
+ if (_expr.accept(cx)) {
+ _block->JUMP(_expr.iftrue);
+ } else {
+ _expr.code = _block->CONST(V4IR::BoolType, 1);
+ }
+ return false;
+}
+
+bool Codegen::visit(TypeOfExpression *ast)
+{
+ Result expr = expression(ast->expression);
+ V4IR::ExprList *args = _function->New<V4IR::ExprList>();
+ args->init(reference(*expr));
+ _expr.code = call(_block->NAME(V4IR::Name::builtin_typeof, ast->typeofToken.startLine, ast->typeofToken.startColumn), args);
+ return false;
+}
+
+bool Codegen::visit(UnaryMinusExpression *ast)
+{
+ Result expr = expression(ast->expression);
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), unop(V4IR::OpUMinus, *expr));
+ _expr.code = _block->TEMP(t);
+ return false;
+}
+
+bool Codegen::visit(UnaryPlusExpression *ast)
+{
+ Result expr = expression(ast->expression);
+ const unsigned t = _block->newTemp();
+ move(_block->TEMP(t), unop(V4IR::OpUPlus, *expr));
+ _expr.code = _block->TEMP(t);
+ return false;
+}
+
+bool Codegen::visit(VoidExpression *ast)
+{
+ statement(ast->expression);
+ _expr.code = _block->CONST(V4IR::UndefinedType, 0);
+ return false;
+}
+
+bool Codegen::visit(FunctionDeclaration * ast)
+{
+ if (_mode == QmlBinding)
+ move(_block->TEMP(_returnAddress), _block->NAME(ast->name.toString(), 0, 0));
+ _expr.accept(nx);
+ return false;
+}
+
+V4IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
+ AST::FormalParameterList *formals,
+ AST::SourceElements *body, Mode mode,
+ const QStringList &inheritedLocals)
+{
+ qSwap(_mode, mode); // enter function code.
+ Loop *loop = 0;
+ qSwap(_loop, loop);
+
+ ScopeAndFinally *scopeAndFinally = 0;
+
+ enterEnvironment(ast);
+ V4IR::Function *function = _module->newFunction(name, _function);
+ function->sourceFile = _fileName;
+
+ V4IR::BasicBlock *entryBlock = function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *exitBlock = function->newBasicBlock(groupStartBlock(), V4IR::Function::DontInsertBlock);
+ V4IR::BasicBlock *throwBlock = function->newBasicBlock(groupStartBlock());
+ function->hasDirectEval = _env->hasDirectEval;
+ function->usesArgumentsObject = (_env->usesArgumentsObject == Environment::ArgumentsObjectUsed);
+ function->maxNumberOfArguments = _env->maxNumberOfArguments;
+ function->isStrict = _env->isStrict;
+ function->isNamedExpression = _env->isNamedFunctionExpression;
+
+ // variables in global code are properties of the global context object, not locals as with other functions.
+ if (_mode == FunctionCode) {
+ unsigned t = 0;
+ for (Environment::MemberMap::iterator it = _env->members.begin(); it != _env->members.end(); ++it) {
+ const QString &local = it.key();
+ function->LOCAL(local);
+ (*it).index = t;
+ entryBlock->MOVE(entryBlock->LOCAL(t, 0), entryBlock->CONST(V4IR::UndefinedType, 0));
+ ++t;
+ }
+ } else {
+ if (!_env->isStrict) {
+ foreach (const QString &inheritedLocal, inheritedLocals) {
+ function->LOCAL(inheritedLocal);
+ unsigned tempIndex = entryBlock->newTemp();
+ Environment::Member member = { Environment::UndefinedMember,
+ static_cast<int>(tempIndex), 0 };
+ _env->members.insert(inheritedLocal, member);
+ }
+ }
+
+ V4IR::ExprList *args = 0;
+ for (Environment::MemberMap::const_iterator it = _env->members.constBegin(); it != _env->members.constEnd(); ++it) {
+ const QString &local = it.key();
+ V4IR::ExprList *next = function->New<V4IR::ExprList>();
+ next->expr = entryBlock->NAME(local, 0, 0);
+ next->next = args;
+ args = next;
+ }
+ if (args) {
+ V4IR::ExprList *next = function->New<V4IR::ExprList>();
+ next->expr = entryBlock->CONST(V4IR::BoolType, (mode == EvalCode || mode == QmlBinding));
+ next->next = args;
+ args = next;
+
+ entryBlock->EXP(entryBlock->CALL(entryBlock->NAME(V4IR::Name::builtin_declare_vars, 0, 0), args));
+ }
+ }
+
+ unsigned returnAddress = entryBlock->newTemp();
+
+ entryBlock->MOVE(entryBlock->TEMP(returnAddress), entryBlock->CONST(V4IR::UndefinedType, 0));
+ exitBlock->RET(exitBlock->TEMP(returnAddress));
+ V4IR::ExprList *throwArgs = function->New<V4IR::ExprList>();
+ throwArgs->expr = throwBlock->TEMP(returnAddress);
+ throwBlock->EXP(throwBlock->CALL(throwBlock->NAME(V4IR::Name::builtin_throw, /*line*/0, /*column*/0), throwArgs));
+ throwBlock->JUMP(exitBlock);
+
+ qSwap(_function, function);
+ qSwap(_block, entryBlock);
+ qSwap(_exitBlock, exitBlock);
+ qSwap(_throwBlock, throwBlock);
+ qSwap(_returnAddress, returnAddress);
+ qSwap(_scopeAndFinally, scopeAndFinally);
+
+ for (FormalParameterList *it = formals; it; it = it->next) {
+ _function->RECEIVE(it->name.toString());
+ }
+
+ foreach (const Environment::Member &member, _env->members) {
+ if (member.function) {
+ V4IR::Function *function = defineFunction(member.function->name.toString(), member.function, member.function->formals,
+ member.function->body ? member.function->body->elements : 0);
+ if (! _env->parent) {
+ move(_block->NAME(member.function->name.toString(), member.function->identifierToken.startLine, member.function->identifierToken.startColumn),
+ _block->CLOSURE(function));
+ } else {
+ assert(member.index >= 0);
+ move(_block->LOCAL(member.index, 0), _block->CLOSURE(function));
+ }
+ }
+ }
+
+ sourceElements(body);
+
+ _function->insertBasicBlock(_exitBlock);
+
+ _block->JUMP(_exitBlock);
+
+ qSwap(_function, function);
+ qSwap(_block, entryBlock);
+ qSwap(_exitBlock, exitBlock);
+ qSwap(_throwBlock, throwBlock);
+ qSwap(_returnAddress, returnAddress);
+ qSwap(_scopeAndFinally, scopeAndFinally);
+ qSwap(_loop, loop);
+
+ leaveEnvironment();
+
+ qSwap(_mode, mode);
+
+ return function;
+}
+
+bool Codegen::visit(IdentifierPropertyName *ast)
+{
+ _property = ast->id.toString();
+ return false;
+}
+
+bool Codegen::visit(NumericLiteralPropertyName *ast)
+{
+ _property = QString::number(ast->id, 'g', 16);
+ return false;
+}
+
+bool Codegen::visit(StringLiteralPropertyName *ast)
+{
+ _property = ast->id.toString();
+ return false;
+}
+
+bool Codegen::visit(FunctionSourceElement *ast)
+{
+ statement(ast->declaration);
+ return false;
+}
+
+bool Codegen::visit(StatementSourceElement *ast)
+{
+ statement(ast->statement);
+ return false;
+}
+
+bool Codegen::visit(Block *ast)
+{
+ for (StatementList *it = ast->statements; it; it = it->next) {
+ statement(it->statement);
+ }
+ return false;
+}
+
+bool Codegen::visit(BreakStatement *ast)
+{
+ if (!_loop)
+ throwSyntaxError(ast->lastSourceLocation(), QCoreApplication::translate("qv4codegen", "Break outside of loop"));
+ Loop *loop = 0;
+ if (ast->label.isEmpty())
+ loop = _loop;
+ else {
+ for (loop = _loop; loop; loop = loop->parent) {
+ if (loop->labelledStatement && loop->labelledStatement->label == ast->label)
+ break;
+ }
+ if (!loop)
+ throwSyntaxError(ast->lastSourceLocation(), QCoreApplication::translate("qv4codegen", "Undefined label '%1'").arg(ast->label.toString()));
+ }
+ unwindException(loop->scopeAndFinally);
+ _block->JUMP(loop->breakBlock);
+ return false;
+}
+
+bool Codegen::visit(ContinueStatement *ast)
+{
+ Loop *loop = 0;
+ if (ast->label.isEmpty()) {
+ for (loop = _loop; loop; loop = loop->parent) {
+ if (loop->continueBlock)
+ break;
+ }
+ } else {
+ for (loop = _loop; loop; loop = loop->parent) {
+ if (loop->labelledStatement && loop->labelledStatement->label == ast->label) {
+ if (!loop->continueBlock)
+ loop = 0;
+ break;
+ }
+ }
+ if (!loop)
+ throwSyntaxError(ast->lastSourceLocation(), QCoreApplication::translate("qv4codegen", "Undefined label '%1'").arg(ast->label.toString()));
+ }
+ if (!loop)
+ throwSyntaxError(ast->lastSourceLocation(), QCoreApplication::translate("qv4codegen", "continue outside of loop"));
+ unwindException(loop->scopeAndFinally);
+ _block->JUMP(loop->continueBlock);
+ return false;
+}
+
+bool Codegen::visit(DebuggerStatement *)
+{
+ Q_UNIMPLEMENTED();
+ return false;
+}
+
+bool Codegen::visit(DoWhileStatement *ast)
+{
+ V4IR::BasicBlock *loopbody = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *loopcond = _function->newBasicBlock(loopbody);
+ V4IR::BasicBlock *loopend = _function->newBasicBlock(groupStartBlock());
+
+ enterLoop(ast, loopbody, loopend, loopcond);
+
+ _block->JUMP(loopbody);
+
+ _block = loopbody;
+ statement(ast->statement);
+ _block->JUMP(loopcond);
+
+ _block = loopcond;
+ condition(ast->expression, loopbody, loopend);
+
+ _block = loopend;
+
+ leaveLoop();
+
+ return false;
+}
+
+bool Codegen::visit(EmptyStatement *)
+{
+ return false;
+}
+
+bool Codegen::visit(ExpressionStatement *ast)
+{
+ if (_mode == EvalCode || _mode == QmlBinding) {
+ Result e = expression(ast->expression);
+ if (*e)
+ move(_block->TEMP(_returnAddress), *e);
+ } else {
+ statement(ast->expression);
+ }
+ return false;
+}
+
+bool Codegen::visit(ForEachStatement *ast)
+{
+ V4IR::BasicBlock *foreachin = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin);
+ V4IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock());
+
+ enterLoop(ast, foreachin, foreachend, foreachin);
+
+ int objectToIterateOn = _block->newTemp();
+ move(_block->TEMP(objectToIterateOn), *expression(ast->expression));
+ V4IR::ExprList *args = _function->New<V4IR::ExprList>();
+ args->init(_block->TEMP(objectToIterateOn));
+
+ int iterator = _block->newTemp();
+ move(_block->TEMP(iterator), _block->CALL(_block->NAME(V4IR::Name::builtin_foreach_iterator_object, 0, 0), args));
+
+ _block->JUMP(foreachin);
+
+ _block = foreachbody;
+ int temp = _block->newTemp();
+ move(*expression(ast->initialiser), _block->TEMP(temp));
+ statement(ast->statement);
+ _block->JUMP(foreachin);
+
+ _block = foreachin;
+
+ args = _function->New<V4IR::ExprList>();
+ args->init(_block->TEMP(iterator));
+ move(_block->TEMP(temp), _block->CALL(_block->NAME(V4IR::Name::builtin_foreach_next_property_name, 0, 0), args));
+ int null = _block->newTemp();
+ move(_block->TEMP(null), _block->CONST(V4IR::NullType, 0));
+ cjump(_block->BINOP(V4IR::OpStrictNotEqual, _block->TEMP(temp), _block->TEMP(null)), foreachbody, foreachend);
+ _block = foreachend;
+
+ leaveLoop();
+ return false;
+}
+
+bool Codegen::visit(ForStatement *ast)
+{
+ V4IR::BasicBlock *forcond = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *forbody = _function->newBasicBlock(forcond);
+ V4IR::BasicBlock *forstep = _function->newBasicBlock(forcond);
+ V4IR::BasicBlock *forend = _function->newBasicBlock(groupStartBlock());
+
+ enterLoop(ast, forcond, forend, forstep);
+
+ statement(ast->initialiser);
+ _block->JUMP(forcond);
+
+ _block = forcond;
+ if (ast->condition)
+ condition(ast->condition, forbody, forend);
+ else
+ _block->JUMP(forbody);
+
+ _block = forbody;
+ statement(ast->statement);
+ _block->JUMP(forstep);
+
+ _block = forstep;
+ statement(ast->expression);
+ _block->JUMP(forcond);
+
+ _block = forend;
+
+ leaveLoop();
+
+ return false;
+}
+
+bool Codegen::visit(IfStatement *ast)
+{
+ V4IR::BasicBlock *iftrue = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *iffalse = ast->ko ? _function->newBasicBlock(groupStartBlock()) : 0;
+ V4IR::BasicBlock *endif = _function->newBasicBlock(groupStartBlock());
+ condition(ast->expression, iftrue, ast->ko ? iffalse : endif);
+
+ _block = iftrue;
+ statement(ast->ok);
+ _block->JUMP(endif);
+
+ if (ast->ko) {
+ _block = iffalse;
+ statement(ast->ko);
+ _block->JUMP(endif);
+ }
+
+ _block = endif;
+
+ return false;
+}
+
+bool Codegen::visit(LabelledStatement *ast)
+{
+ // check that no outer loop contains the label
+ Loop *l = _loop;
+ while (l) {
+ if (l->labelledStatement->label == ast->label) {
+ QString error = QString(QStringLiteral("Label '%1' has already been declared")).arg(ast->label.toString());
+ throwSyntaxError(ast->firstSourceLocation(), error);
+ }
+ l = l->parent;
+ }
+ _labelledStatement = ast;
+
+ if (AST::cast<AST::SwitchStatement *>(ast->statement) ||
+ AST::cast<AST::WhileStatement *>(ast->statement) ||
+ AST::cast<AST::DoWhileStatement *>(ast->statement) ||
+ AST::cast<AST::ForStatement *>(ast->statement) ||
+ AST::cast<AST::ForEachStatement *>(ast->statement) ||
+ AST::cast<AST::LocalForStatement *>(ast->statement) ||
+ AST::cast<AST::LocalForEachStatement *>(ast->statement)) {
+ statement(ast->statement); // labelledStatement will be associated with the ast->statement's loop.
+ } else {
+ V4IR::BasicBlock *breakBlock = _function->newBasicBlock(groupStartBlock());
+ enterLoop(ast->statement, 0, breakBlock, /*continueBlock*/ 0);
+ statement(ast->statement);
+ _block->JUMP(breakBlock);
+ _block = breakBlock;
+ leaveLoop();
+ }
+
+ return false;
+}
+
+bool Codegen::visit(LocalForEachStatement *ast)
+{
+ V4IR::BasicBlock *foreachin = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *foreachbody = _function->newBasicBlock(foreachin);
+ V4IR::BasicBlock *foreachend = _function->newBasicBlock(groupStartBlock());
+
+ enterLoop(ast, foreachin, foreachend, foreachin);
+
+ variableDeclaration(ast->declaration);
+
+ int iterator = _block->newTemp();
+ move(_block->TEMP(iterator), *expression(ast->expression));
+ V4IR::ExprList *args = _function->New<V4IR::ExprList>();
+ args->init(_block->TEMP(iterator));
+ move(_block->TEMP(iterator), _block->CALL(_block->NAME(V4IR::Name::builtin_foreach_iterator_object, 0, 0), args));
+
+ _block->JUMP(foreachin);
+
+ _block = foreachbody;
+ int temp = _block->newTemp();
+ move(identifier(ast->declaration->name.toString()), _block->TEMP(temp));
+ statement(ast->statement);
+ _block->JUMP(foreachin);
+
+ _block = foreachin;
+
+ args = _function->New<V4IR::ExprList>();
+ args->init(_block->TEMP(iterator));
+ move(_block->TEMP(temp), _block->CALL(_block->NAME(V4IR::Name::builtin_foreach_next_property_name, 0, 0), args));
+ int null = _block->newTemp();
+ move(_block->TEMP(null), _block->CONST(V4IR::NullType, 0));
+ cjump(_block->BINOP(V4IR::OpStrictNotEqual, _block->TEMP(temp), _block->TEMP(null)), foreachbody, foreachend);
+ _block = foreachend;
+
+ leaveLoop();
+ return false;
+}
+
+bool Codegen::visit(LocalForStatement *ast)
+{
+ V4IR::BasicBlock *forcond = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *forbody = _function->newBasicBlock(forcond);
+ V4IR::BasicBlock *forstep = _function->newBasicBlock(forcond);
+ V4IR::BasicBlock *forend = _function->newBasicBlock(groupStartBlock());
+
+ enterLoop(ast, forcond, forend, forstep);
+
+ variableDeclarationList(ast->declarations);
+ _block->JUMP(forcond);
+
+ _block = forcond;
+ if (ast->condition)
+ condition(ast->condition, forbody, forend);
+ else
+ _block->JUMP(forbody);
+
+ _block = forbody;
+ statement(ast->statement);
+ _block->JUMP(forstep);
+
+ _block = forstep;
+ statement(ast->expression);
+ _block->JUMP(forcond);
+
+ _block = forend;
+
+ leaveLoop();
+
+ return false;
+}
+
+bool Codegen::visit(ReturnStatement *ast)
+{
+ if (_mode != FunctionCode && _mode != QmlBinding)
+ throwSyntaxError(ast->returnToken, QCoreApplication::translate("qv4codegen", "Return statement outside of function"));
+ if (ast->expression) {
+ Result expr = expression(ast->expression);
+ move(_block->TEMP(_returnAddress), *expr);
+ }
+ unwindException(0);
+
+ _block->JUMP(_exitBlock);
+ return false;
+}
+
+bool Codegen::visit(SwitchStatement *ast)
+{
+ V4IR::BasicBlock *switchend = _function->newBasicBlock(groupStartBlock());
+
+ if (ast->block) {
+ Result lhs = expression(ast->expression);
+ V4IR::BasicBlock *switchcond = _function->newBasicBlock(groupStartBlock());
+ _block->JUMP(switchcond);
+ V4IR::BasicBlock *previousBlock = 0;
+
+ QHash<Node *, V4IR::BasicBlock *> blockMap;
+
+ enterLoop(ast, 0, switchend, 0);
+
+ for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
+ CaseClause *clause = it->clause;
+
+ _block = _function->newBasicBlock(groupStartBlock());
+ blockMap[clause] = _block;
+
+ if (previousBlock && !previousBlock->isTerminated())
+ previousBlock->JUMP(_block);
+
+ for (StatementList *it2 = clause->statements; it2; it2 = it2->next)
+ statement(it2->statement);
+
+ previousBlock = _block;
+ }
+
+ if (ast->block->defaultClause) {
+ _block = _function->newBasicBlock(groupStartBlock());
+ blockMap[ast->block->defaultClause] = _block;
+
+ if (previousBlock && !previousBlock->isTerminated())
+ previousBlock->JUMP(_block);
+
+ for (StatementList *it2 = ast->block->defaultClause->statements; it2; it2 = it2->next)
+ statement(it2->statement);
+
+ previousBlock = _block;
+ }
+
+ for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
+ CaseClause *clause = it->clause;
+
+ _block = _function->newBasicBlock(groupStartBlock());
+ blockMap[clause] = _block;
+
+ if (previousBlock && !previousBlock->isTerminated())
+ previousBlock->JUMP(_block);
+
+ for (StatementList *it2 = clause->statements; it2; it2 = it2->next)
+ statement(it2->statement);
+
+ previousBlock = _block;
+ }
+
+ leaveLoop();
+
+ _block->JUMP(switchend);
+
+ _block = switchcond;
+ for (CaseClauses *it = ast->block->clauses; it; it = it->next) {
+ CaseClause *clause = it->clause;
+ Result rhs = expression(clause->expression);
+ V4IR::BasicBlock *iftrue = blockMap[clause];
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
+ cjump(binop(V4IR::OpStrictEqual, *lhs, *rhs), iftrue, iffalse);
+ _block = iffalse;
+ }
+
+ for (CaseClauses *it = ast->block->moreClauses; it; it = it->next) {
+ CaseClause *clause = it->clause;
+ Result rhs = expression(clause->expression);
+ V4IR::BasicBlock *iftrue = blockMap[clause];
+ V4IR::BasicBlock *iffalse = _function->newBasicBlock(groupStartBlock());
+ cjump(binop(V4IR::OpStrictEqual, *lhs, *rhs), iftrue, iffalse);
+ _block = iffalse;
+ }
+
+ if (ast->block->defaultClause) {
+ _block->JUMP(blockMap[ast->block->defaultClause]);
+ }
+ }
+
+ _block->JUMP(switchend);
+
+ _block = switchend;
+ return false;
+}
+
+bool Codegen::visit(ThrowStatement *ast)
+{
+ Result expr = expression(ast->expression);
+ move(_block->TEMP(_returnAddress), *expr);
+ _block->JUMP(_throwBlock);
+ return false;
+}
+
+bool Codegen::visit(TryStatement *ast)
+{
+ _function->hasTry = true;
+
+ if (_function->isStrict && ast->catchExpression &&
+ (ast->catchExpression->name == QLatin1String("eval") || ast->catchExpression->name == QLatin1String("arguments")))
+ throwSyntaxError(ast->catchExpression->identifierToken, QCoreApplication::translate("qv4codegen", "Catch variable name may not be eval or arguments in strict mode"));
+
+ V4IR::BasicBlock *tryBody = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *catchBody = _function->newBasicBlock(groupStartBlock());
+ // We always need a finally body to clean up the exception handler
+ V4IR::BasicBlock *finallyBody = _function->newBasicBlock(groupStartBlock());
+
+ V4IR::BasicBlock *throwBlock = _function->newBasicBlock(groupStartBlock());
+ V4IR::ExprList *throwArgs = _function->New<V4IR::ExprList>();
+ throwArgs->expr = throwBlock->TEMP(_returnAddress);
+ throwBlock->EXP(throwBlock->CALL(throwBlock->NAME(V4IR::Name::builtin_throw, /*line*/0, /*column*/0), throwArgs));
+ throwBlock->JUMP(catchBody);
+ qSwap(_throwBlock, throwBlock);
+
+ int hasException = _block->newTemp();
+ move(_block->TEMP(hasException), _block->CONST(V4IR::BoolType, false));
+
+ // Pass the hidden "needRethrow" TEMP to the
+ // builtin_delete_exception_handler, in order to have those TEMPs alive for
+ // the duration of the exception handling block.
+ V4IR::ExprList *finishTryArgs = _function->New<V4IR::ExprList>();
+ finishTryArgs->init(_block->TEMP(hasException));
+
+ ScopeAndFinally tcf(_scopeAndFinally, ast->finallyExpression, finishTryArgs);
+ _scopeAndFinally = &tcf;
+
+ int exception_to_rethrow = _block->newTemp();
+
+ _block->TRY(tryBody, catchBody,
+ ast->catchExpression ? ast->catchExpression->name.toString() : QString(),
+ _block->TEMP(exception_to_rethrow));
+
+ _block = tryBody;
+ statement(ast->statement);
+ _block->JUMP(finallyBody);
+
+ _block = catchBody;
+
+ if (ast->catchExpression) {
+ // check if an exception got thrown within catch. Go to finally
+ // and then rethrow
+ V4IR::BasicBlock *b = _function->newBasicBlock(groupStartBlock());
+ _block->CJUMP(_block->TEMP(hasException), finallyBody, b);
+ _block = b;
+ }
+
+ move(_block->TEMP(hasException), _block->CONST(V4IR::BoolType, true));
+
+ if (ast->catchExpression) {
+ ++_function->insideWithOrCatch;
+ {
+ ScopeAndFinally scope(_scopeAndFinally, ScopeAndFinally::CatchScope);
+ _scopeAndFinally = &scope;
+ statement(ast->catchExpression->statement);
+ _scopeAndFinally = scope.parent;
+ }
+ --_function->insideWithOrCatch;
+ move(_block->TEMP(hasException), _block->CONST(V4IR::BoolType, false));
+ }
+ _block->JUMP(finallyBody);
+
+ _scopeAndFinally = tcf.parent;
+
+ qSwap(_throwBlock, throwBlock);
+
+ V4IR::BasicBlock *after = _function->newBasicBlock(groupStartBlock());
+ _block = finallyBody;
+
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_finish_try, 0, 0), finishTryArgs));
+
+ if (ast->finallyExpression && ast->finallyExpression->statement)
+ statement(ast->finallyExpression->statement);
+
+ V4IR::BasicBlock *rethrowBlock = _function->newBasicBlock(groupStartBlock());
+ _block->CJUMP(_block->TEMP(hasException), rethrowBlock, after);
+ _block = rethrowBlock;
+ move(_block->TEMP(_returnAddress), _block->TEMP(exception_to_rethrow));
+ _block->JUMP(_throwBlock);
+
+ _block = after;
+
+ return false;
+}
+
+void Codegen::unwindException(Codegen::ScopeAndFinally *outest)
+{
+ int savedDepthForWidthOrCatch = _function->insideWithOrCatch;
+ ScopeAndFinally *scopeAndFinally = _scopeAndFinally;
+ qSwap(_scopeAndFinally, scopeAndFinally);
+ while (_scopeAndFinally != outest) {
+ switch (_scopeAndFinally->type) {
+ case ScopeAndFinally::WithScope:
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_pop_scope, 0, 0)));
+ // fall through
+ case ScopeAndFinally::CatchScope:
+ _scopeAndFinally = _scopeAndFinally->parent;
+ --_function->insideWithOrCatch;
+ break;
+ case ScopeAndFinally::TryScope: {
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_finish_try, 0, 0), _scopeAndFinally->finishTryArgs));
+ ScopeAndFinally *tc = _scopeAndFinally;
+ _scopeAndFinally = tc->parent;
+ if (tc->finally && tc->finally->statement)
+ statement(tc->finally->statement);
+ break;
+ }
+ }
+ }
+ qSwap(_scopeAndFinally, scopeAndFinally);
+ _function->insideWithOrCatch = savedDepthForWidthOrCatch;
+}
+
+bool Codegen::visit(VariableStatement *ast)
+{
+ variableDeclarationList(ast->declarations);
+ return false;
+}
+
+bool Codegen::visit(WhileStatement *ast)
+{
+ V4IR::BasicBlock *whilecond = _function->newBasicBlock(groupStartBlock());
+ V4IR::BasicBlock *whilebody = _function->newBasicBlock(whilecond);
+ V4IR::BasicBlock *whileend = _function->newBasicBlock(groupStartBlock());
+
+ enterLoop(ast, whilecond, whileend, whilecond);
+
+ _block->JUMP(whilecond);
+ _block = whilecond;
+ condition(ast->expression, whilebody, whileend);
+
+ _block = whilebody;
+ statement(ast->statement);
+ _block->JUMP(whilecond);
+
+ _block = whileend;
+ leaveLoop();
+
+ return false;
+}
+
+bool Codegen::visit(WithStatement *ast)
+{
+ _function->hasWith = true;
+
+ V4IR::BasicBlock *withBlock = _function->newBasicBlock(groupStartBlock());
+
+ _block->JUMP(withBlock);
+ _block = withBlock;
+ int withObject = _block->newTemp();
+ _block->MOVE(_block->TEMP(withObject), *expression(ast->expression));
+ V4IR::ExprList *args = _function->New<V4IR::ExprList>();
+ args->init(_block->TEMP(withObject));
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_push_with_scope, 0, 0), args));
+
+ ++_function->insideWithOrCatch;
+ {
+ ScopeAndFinally scope(_scopeAndFinally);
+ _scopeAndFinally = &scope;
+ statement(ast->statement);
+ _scopeAndFinally = scope.parent;
+ }
+ --_function->insideWithOrCatch;
+ _block->EXP(_block->CALL(_block->NAME(V4IR::Name::builtin_pop_scope, 0, 0), 0));
+
+ V4IR::BasicBlock *next = _function->newBasicBlock(groupStartBlock());
+ _block->JUMP(next);
+ _block = next;
+
+ return false;
+}
+
+bool Codegen::visit(UiArrayBinding *)
+{
+ assert(!"not implemented");
+ return false;
+}
+
+bool Codegen::visit(UiObjectBinding *)
+{
+ assert(!"not implemented");
+ return false;
+}
+
+bool Codegen::visit(UiObjectDefinition *)
+{
+ assert(!"not implemented");
+ return false;
+}
+
+bool Codegen::visit(UiPublicMember *)
+{
+ assert(!"not implemented");
+ return false;
+}
+
+bool Codegen::visit(UiScriptBinding *)
+{
+ assert(!"not implemented");
+ return false;
+}
+
+bool Codegen::visit(UiSourceElement *)
+{
+ assert(!"not implemented");
+ return false;
+}
+
+void Codegen::throwSyntaxErrorOnEvalOrArgumentsInStrictMode(V4IR::Expr *expr, const SourceLocation& loc)
+{
+ if (!_env->isStrict)
+ return;
+ V4IR::Name *n = expr->asName();
+ if (!n)
+ return;
+ if (*n->id == QLatin1String("eval") || *n->id == QLatin1String("arguments"))
+ throwSyntaxError(loc, QCoreApplication::translate("qv4codegen", "Variable name may not be eval or arguments in strict mode"));
+}
+
+void Codegen::throwSyntaxError(const SourceLocation &loc, const QString &detail)
+{
+ QV4::DiagnosticMessage *msg = new QV4::DiagnosticMessage;
+ msg->fileName = _fileName;
+ msg->offset = loc.begin();
+ msg->startLine = loc.startLine;
+ msg->startColumn = loc.startColumn;
+ msg->message = detail;
+ if (_context)
+ _context->throwSyntaxError(msg);
+ else if (_errorHandler)
+ _errorHandler->syntaxError(msg);
+ else
+ Q_ASSERT(!"No error handler available.");
+}
+
+void Codegen::throwReferenceError(const SourceLocation &loc, const QString &detail)
+{
+ if (_context)
+ _context->throwReferenceError(QV4::Value::fromString(_context, detail), _fileName, loc.startLine);
+ else if (_errorHandler)
+ throwSyntaxError(loc, detail);
+ else
+ Q_ASSERT(!"No error handler available.");
+}
diff --git a/src/qml/qml/v4/qv4codegen_p.h b/src/qml/qml/v4/qv4codegen_p.h
new file mode 100644
index 0000000000..fe00d87852
--- /dev/null
+++ b/src/qml/qml/v4/qv4codegen_p.h
@@ -0,0 +1,451 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4CODEGEN_P_H
+#define QV4CODEGEN_P_H
+
+#include "qv4global_p.h"
+#include "qv4jsir_p.h"
+#include <private/qqmljsastvisitor_p.h>
+#include <private/qqmljsast_p.h>
+#include <QtCore/QStringList>
+#include <assert.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+struct DiagnosticMessage;
+struct ExecutionContext;
+}
+
+namespace QQmlJS {
+namespace AST {
+class UiParameterList;
+}
+
+
+
+class ErrorHandler
+{
+public:
+ virtual void syntaxError(QV4::DiagnosticMessage *message) = 0;
+};
+
+class Q_QML_EXPORT Codegen: protected AST::Visitor
+{
+public:
+ Codegen(QV4::ExecutionContext *ctx, bool strict);
+ Codegen(ErrorHandler *errorHandler, bool strictMode);
+
+ enum Mode {
+ GlobalCode,
+ EvalCode,
+ FunctionCode,
+ QmlBinding
+ };
+
+ V4IR::Function *operator()(const QString &fileName,
+ const QString &sourceCode,
+ AST::Program *ast,
+ V4IR::Module *module,
+ Mode mode = GlobalCode,
+ const QStringList &inheritedLocals = QStringList());
+ V4IR::Function *operator()(const QString &fileName,
+ const QString &sourceCode,
+ AST::FunctionExpression *ast,
+ V4IR::Module *module);
+
+protected:
+ enum Format { ex, cx, nx };
+ struct Result {
+ V4IR::Expr *code;
+ V4IR::BasicBlock *iftrue;
+ V4IR::BasicBlock *iffalse;
+ Format format;
+ Format requested;
+
+ explicit Result(Format requested = ex)
+ : code(0)
+ , iftrue(0)
+ , iffalse(0)
+ , format(ex)
+ , requested(requested) {}
+
+ explicit Result(V4IR::BasicBlock *iftrue, V4IR::BasicBlock *iffalse)
+ : code(0)
+ , iftrue(iftrue)
+ , iffalse(iffalse)
+ , format(ex)
+ , requested(cx) {}
+
+ inline V4IR::Expr *operator*() const { Q_ASSERT(format == ex); return code; }
+ inline V4IR::Expr *operator->() const { Q_ASSERT(format == ex); return code; }
+
+ bool accept(Format f)
+ {
+ if (requested == f) {
+ format = f;
+ return true;
+ }
+ return false;
+ }
+ };
+
+ struct Environment {
+ Environment *parent;
+
+ enum MemberType {
+ UndefinedMember,
+ VariableDefinition,
+ VariableDeclaration,
+ FunctionDefinition
+ };
+ struct Member {
+ MemberType type;
+ int index;
+ AST::FunctionExpression *function;
+ };
+ typedef QMap<QString, Member> MemberMap;
+
+ MemberMap members;
+ AST::FormalParameterList *formals;
+ int maxNumberOfArguments;
+ bool hasDirectEval;
+ bool hasNestedFunctions;
+ bool isStrict;
+ bool isNamedFunctionExpression;
+ enum UsesArgumentsObject {
+ ArgumentsObjectUnknown,
+ ArgumentsObjectNotUsed,
+ ArgumentsObjectUsed
+ };
+
+ UsesArgumentsObject usesArgumentsObject;
+
+ Environment(Environment *parent)
+ : parent(parent)
+ , formals(0)
+ , maxNumberOfArguments(0)
+ , hasDirectEval(false)
+ , hasNestedFunctions(false)
+ , isStrict(false)
+ , isNamedFunctionExpression(false)
+ , usesArgumentsObject(ArgumentsObjectUnknown)
+ {
+ if (parent && parent->isStrict)
+ isStrict = true;
+ }
+
+ int findMember(const QString &name) const
+ {
+ MemberMap::const_iterator it = members.find(name);
+ if (it == members.end())
+ return -1;
+ assert((*it).index != -1 || !parent);
+ return (*it).index;
+ }
+
+ bool lookupMember(const QString &name, Environment **scope, int *index, int *distance)
+ {
+ Environment *it = this;
+ *distance = 0;
+ for (; it; it = it->parent, ++(*distance)) {
+ int idx = it->findMember(name);
+ if (idx != -1) {
+ *scope = it;
+ *index = idx;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void enter(const QString &name, MemberType type, AST::FunctionExpression *function = 0)
+ {
+ if (! name.isEmpty()) {
+ if (type != FunctionDefinition) {
+ for (AST::FormalParameterList *it = formals; it; it = it->next)
+ if (it->name == name)
+ return;
+ }
+ MemberMap::iterator it = members.find(name);
+ if (it == members.end()) {
+ Member m;
+ m.index = -1;
+ m.type = type;
+ m.function = function;
+ members.insert(name, m);
+ } else {
+ if ((*it).type <= type) {
+ (*it).type = type;
+ (*it).function = function;
+ }
+ }
+ }
+ }
+ };
+
+ Environment *newEnvironment(AST::Node *node, Environment *parent)
+ {
+ Environment *env = new Environment(parent);
+ _envMap.insert(node, env);
+ return env;
+ }
+
+ struct UiMember {
+ };
+
+ struct ScopeAndFinally {
+ enum ScopeType {
+ WithScope,
+ TryScope,
+ CatchScope
+ };
+
+ ScopeAndFinally *parent;
+ AST::Finally *finally;
+ V4IR::ExprList *finishTryArgs;
+ ScopeType type;
+
+ ScopeAndFinally(ScopeAndFinally *parent, ScopeType t = WithScope) : parent(parent), finally(0), finishTryArgs(0), type(t) {}
+ ScopeAndFinally(ScopeAndFinally *parent, AST::Finally *finally, V4IR::ExprList *finishTryArgs)
+ : parent(parent), finally(finally), finishTryArgs(finishTryArgs), type(TryScope)
+ {}
+ };
+
+ struct Loop {
+ AST::LabelledStatement *labelledStatement;
+ AST::Statement *node;
+ V4IR::BasicBlock *groupStartBlock;
+ V4IR::BasicBlock *breakBlock;
+ V4IR::BasicBlock *continueBlock;
+ Loop *parent;
+ ScopeAndFinally *scopeAndFinally;
+
+ Loop(AST::Statement *node, V4IR::BasicBlock *groupStartBlock, V4IR::BasicBlock *breakBlock, V4IR::BasicBlock *continueBlock, Loop *parent)
+ : labelledStatement(0), node(node), groupStartBlock(groupStartBlock), breakBlock(breakBlock), continueBlock(continueBlock), parent(parent) {}
+ };
+
+ void enterEnvironment(AST::Node *node);
+ void leaveEnvironment();
+
+ void enterLoop(AST::Statement *node, V4IR::BasicBlock *startBlock, V4IR::BasicBlock *breakBlock, V4IR::BasicBlock *continueBlock);
+ void leaveLoop();
+ V4IR::BasicBlock *groupStartBlock() const
+ {
+ for (Loop *it = _loop; it; it = it->parent)
+ if (it->groupStartBlock)
+ return it->groupStartBlock;
+ return 0;
+ }
+
+ V4IR::Expr *member(V4IR::Expr *base, const QString *name);
+ V4IR::Expr *subscript(V4IR::Expr *base, V4IR::Expr *index);
+ V4IR::Expr *argument(V4IR::Expr *expr);
+ V4IR::Expr *reference(V4IR::Expr *expr);
+ V4IR::Expr *unop(V4IR::AluOp op, V4IR::Expr *expr);
+ V4IR::Expr *binop(V4IR::AluOp op, V4IR::Expr *left, V4IR::Expr *right);
+ V4IR::Expr *call(V4IR::Expr *base, V4IR::ExprList *args);
+ void move(V4IR::Expr *target, V4IR::Expr *source, V4IR::AluOp op = V4IR::OpInvalid);
+ void cjump(V4IR::Expr *cond, V4IR::BasicBlock *iftrue, V4IR::BasicBlock *iffalse);
+
+ V4IR::Function *defineFunction(const QString &name, AST::Node *ast,
+ AST::FormalParameterList *formals,
+ AST::SourceElements *body,
+ Mode mode = FunctionCode,
+ const QStringList &inheritedLocals = QStringList());
+
+ void unwindException(ScopeAndFinally *outest);
+
+ void statement(AST::Statement *ast);
+ void statement(AST::ExpressionNode *ast);
+ void condition(AST::ExpressionNode *ast, V4IR::BasicBlock *iftrue, V4IR::BasicBlock *iffalse);
+ Result expression(AST::ExpressionNode *ast);
+ QString propertyName(AST::PropertyName *ast);
+ Result sourceElement(AST::SourceElement *ast);
+ UiMember uiObjectMember(AST::UiObjectMember *ast);
+
+ void accept(AST::Node *node);
+
+ void functionBody(AST::FunctionBody *ast);
+ void program(AST::Program *ast);
+ void sourceElements(AST::SourceElements *ast);
+ void variableDeclaration(AST::VariableDeclaration *ast);
+ void variableDeclarationList(AST::VariableDeclarationList *ast);
+
+ V4IR::Expr *identifier(const QString &name, int line = 0, int col = 0);
+
+ // nodes
+ virtual bool visit(AST::ArgumentList *ast);
+ virtual bool visit(AST::CaseBlock *ast);
+ virtual bool visit(AST::CaseClause *ast);
+ virtual bool visit(AST::CaseClauses *ast);
+ virtual bool visit(AST::Catch *ast);
+ virtual bool visit(AST::DefaultClause *ast);
+ virtual bool visit(AST::ElementList *ast);
+ virtual bool visit(AST::Elision *ast);
+ virtual bool visit(AST::Finally *ast);
+ virtual bool visit(AST::FormalParameterList *ast);
+ virtual bool visit(AST::FunctionBody *ast);
+ virtual bool visit(AST::Program *ast);
+ virtual bool visit(AST::PropertyNameAndValue *ast);
+ virtual bool visit(AST::PropertyAssignmentList *ast);
+ virtual bool visit(AST::PropertyGetterSetter *ast);
+ virtual bool visit(AST::SourceElements *ast);
+ virtual bool visit(AST::StatementList *ast);
+ virtual bool visit(AST::UiArrayMemberList *ast);
+ virtual bool visit(AST::UiImport *ast);
+ virtual bool visit(AST::UiImportList *ast);
+ virtual bool visit(AST::UiObjectInitializer *ast);
+ virtual bool visit(AST::UiObjectMemberList *ast);
+ virtual bool visit(AST::UiParameterList *ast);
+ virtual bool visit(AST::UiProgram *ast);
+ virtual bool visit(AST::UiQualifiedId *ast);
+ virtual bool visit(AST::VariableDeclaration *ast);
+ virtual bool visit(AST::VariableDeclarationList *ast);
+
+ // expressions
+ virtual bool visit(AST::Expression *ast);
+ virtual bool visit(AST::ArrayLiteral *ast);
+ virtual bool visit(AST::ArrayMemberExpression *ast);
+ virtual bool visit(AST::BinaryExpression *ast);
+ virtual bool visit(AST::CallExpression *ast);
+ virtual bool visit(AST::ConditionalExpression *ast);
+ virtual bool visit(AST::DeleteExpression *ast);
+ virtual bool visit(AST::FalseLiteral *ast);
+ virtual bool visit(AST::FieldMemberExpression *ast);
+ virtual bool visit(AST::FunctionExpression *ast);
+ virtual bool visit(AST::IdentifierExpression *ast);
+ virtual bool visit(AST::NestedExpression *ast);
+ virtual bool visit(AST::NewExpression *ast);
+ virtual bool visit(AST::NewMemberExpression *ast);
+ virtual bool visit(AST::NotExpression *ast);
+ virtual bool visit(AST::NullExpression *ast);
+ virtual bool visit(AST::NumericLiteral *ast);
+ virtual bool visit(AST::ObjectLiteral *ast);
+ virtual bool visit(AST::PostDecrementExpression *ast);
+ virtual bool visit(AST::PostIncrementExpression *ast);
+ virtual bool visit(AST::PreDecrementExpression *ast);
+ virtual bool visit(AST::PreIncrementExpression *ast);
+ virtual bool visit(AST::RegExpLiteral *ast);
+ virtual bool visit(AST::StringLiteral *ast);
+ virtual bool visit(AST::ThisExpression *ast);
+ virtual bool visit(AST::TildeExpression *ast);
+ virtual bool visit(AST::TrueLiteral *ast);
+ virtual bool visit(AST::TypeOfExpression *ast);
+ virtual bool visit(AST::UnaryMinusExpression *ast);
+ virtual bool visit(AST::UnaryPlusExpression *ast);
+ virtual bool visit(AST::VoidExpression *ast);
+ virtual bool visit(AST::FunctionDeclaration *ast);
+
+ // property names
+ virtual bool visit(AST::IdentifierPropertyName *ast);
+ virtual bool visit(AST::NumericLiteralPropertyName *ast);
+ virtual bool visit(AST::StringLiteralPropertyName *ast);
+
+ // source elements
+ virtual bool visit(AST::FunctionSourceElement *ast);
+ virtual bool visit(AST::StatementSourceElement *ast);
+
+ // statements
+ virtual bool visit(AST::Block *ast);
+ virtual bool visit(AST::BreakStatement *ast);
+ virtual bool visit(AST::ContinueStatement *ast);
+ virtual bool visit(AST::DebuggerStatement *ast);
+ virtual bool visit(AST::DoWhileStatement *ast);
+ virtual bool visit(AST::EmptyStatement *ast);
+ virtual bool visit(AST::ExpressionStatement *ast);
+ virtual bool visit(AST::ForEachStatement *ast);
+ virtual bool visit(AST::ForStatement *ast);
+ virtual bool visit(AST::IfStatement *ast);
+ virtual bool visit(AST::LabelledStatement *ast);
+ virtual bool visit(AST::LocalForEachStatement *ast);
+ virtual bool visit(AST::LocalForStatement *ast);
+ virtual bool visit(AST::ReturnStatement *ast);
+ virtual bool visit(AST::SwitchStatement *ast);
+ virtual bool visit(AST::ThrowStatement *ast);
+ virtual bool visit(AST::TryStatement *ast);
+ virtual bool visit(AST::VariableStatement *ast);
+ virtual bool visit(AST::WhileStatement *ast);
+ virtual bool visit(AST::WithStatement *ast);
+
+ // ui object members
+ virtual bool visit(AST::UiArrayBinding *ast);
+ virtual bool visit(AST::UiObjectBinding *ast);
+ virtual bool visit(AST::UiObjectDefinition *ast);
+ virtual bool visit(AST::UiPublicMember *ast);
+ virtual bool visit(AST::UiScriptBinding *ast);
+ virtual bool visit(AST::UiSourceElement *ast);
+
+ void throwSyntaxErrorOnEvalOrArgumentsInStrictMode(V4IR::Expr* expr, const AST::SourceLocation &loc);
+
+ void throwSyntaxError(const AST::SourceLocation &loc, const QString &detail);
+ void throwReferenceError(const AST::SourceLocation &loc, const QString &detail);
+
+private:
+ QString _fileName;
+ Result _expr;
+ QString _property;
+ UiMember _uiMember;
+ V4IR::Module *_module;
+ V4IR::Function *_function;
+ V4IR::BasicBlock *_block;
+ V4IR::BasicBlock *_exitBlock;
+ V4IR::BasicBlock *_throwBlock;
+ unsigned _returnAddress;
+ Mode _mode;
+ Environment *_env;
+ Loop *_loop;
+ AST::LabelledStatement *_labelledStatement;
+ ScopeAndFinally *_scopeAndFinally;
+ QHash<AST::Node *, Environment *> _envMap;
+ QHash<AST::FunctionExpression *, int> _functionMap;
+ QV4::ExecutionContext *_context;
+ bool _strictMode;
+ ErrorHandler *_errorHandler;
+
+ class ScanFunctions;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4CODEGEN_P_H
diff --git a/src/qml/qml/v4/qv4compiler.cpp b/src/qml/qml/v4/qv4compiler.cpp
deleted file mode 100644
index d6ab73acc2..0000000000
--- a/src/qml/qml/v4/qv4compiler.cpp
+++ /dev/null
@@ -1,1580 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4compiler_p.h"
-#include "qv4compiler_p_p.h"
-#include "qv4program_p.h"
-#include "qv4ir_p.h"
-#include "qv4irbuilder_p.h"
-
-#include <private/qqmlglobal_p.h>
-#include <private/qqmljsast_p.h>
-#include <private/qqmlaccessors_p.h>
-#include <private/qqmljsengine_p.h>
-
-QT_BEGIN_NAMESPACE
-
-DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP)
-DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER)
-DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
-DEFINE_BOOL_CONFIG_OPTION(qmlBindingsTestEnv, QML_BINDINGS_TEST)
-
-static bool qmlBindingsTest = false;
-static bool qmlEnableV4 = true;
-
-using namespace QQmlJS;
-QV4CompilerPrivate::QV4CompilerPrivate()
- : subscriptionOffset(0)
- , _function(0) , _block(0) , _discarded(false), registerCount(0)
- , bindingLine(0), bindingColumn(0), invalidatable(false)
-{
-}
-
-//
-// tracing
-//
-void QV4CompilerPrivate::trace(quint16 line, quint16 column)
-{
- bytecode.clear();
-
- this->bindingLine = line;
- this->bindingColumn = column;
- this->currentReg = _function->tempCount;
- this->registerCount = qMax(this->registerCount, this->currentReg);
-
- foreach (IR::BasicBlock *bb, _function->basicBlocks) {
- if (! bb->isTerminated() && (bb->index + 1) < _function->basicBlocks.size())
- bb->JUMP(_function->basicBlocks.at(bb->index + 1));
- }
-
- QVector<IR::BasicBlock *> blocks;
- trace(&blocks);
- currentBlockMask = 0x00000001;
-
-
- for (int i = 0; !_discarded && i < blocks.size(); ++i) {
- IR::BasicBlock *block = blocks.at(i);
- IR::BasicBlock *next = i + 1 < blocks.size() ? blocks.at(i + 1) : 0;
- if (IR::Stmt *terminator = block->terminator()) {
- if (IR::CJump *cj = terminator->asCJump()) {
- if (cj->iffalse != next) {
- IR::Jump *jump = _function->pool->New<IR::Jump>();
- jump->init(cj->iffalse);
- block->statements.append(jump);
- }
- } else if (IR::Jump *j = terminator->asJump()) {
- if (j->target == next) {
- block->statements.resize(block->statements.size() - 1);
- }
- }
- }
-
- block->offset = bytecode.size();
-
- if (bytecode.isEmpty()) {
- if (qmlBindingsTest || bindingsDump()) {
- Instr::BindingId id;
- id.column = column;
- id.line = line;
- gen(id);
- }
-
- if (qmlBindingsTest) {
- QString str = expression->expression.asScript();
- QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
- int offset = data.count();
- data += strdata;
-
- Instr::EnableV4Test test;
- test.reg = 0;
- test.offset = offset;
- test.length = str.length();
- gen(test);
- }
- }
-
- bool usic = false;
- int patchesCount = patches.count();
- qSwap(usedSubscriptionIdsChanged, usic);
-
- int blockopIndex = bytecode.size();
- Instr::Block blockop;
- blockop.block = currentBlockMask;
- gen(blockop);
-
- foreach (IR::Stmt *s, block->statements) {
- if (! _discarded)
- s->accept(this);
- }
-
- qSwap(usedSubscriptionIdsChanged, usic);
-
- if (usic) {
- if (currentBlockMask == 0x80000000) {
- discard();
- return;
- }
- currentBlockMask <<= 1;
- } else if (! _discarded) {
- const int adjust = bytecode.remove(blockopIndex);
- // Correct patches
- for (int ii = patchesCount; ii < patches.count(); ++ii)
- patches[ii].offset -= adjust;
- }
- }
-
-#ifdef DEBUG_IR_STRUCTURE
- IR::IRDump dump;
- for (int i = 0; i < blocks.size(); ++i) {
- dump.basicblock(blocks.at(i));
- }
-#endif
-
-
- if (! _discarded) {
- // back patching
- foreach (const Patch &patch, patches) {
- V4Instr &instr = bytecode[patch.offset];
- int size = V4Instr::size(instructionType(&instr));
- instr.branchop.offset = patch.block->offset - patch.offset - size;
- }
-
- patches.clear();
- }
-}
-
-void QV4CompilerPrivate::trace(QVector<IR::BasicBlock *> *blocks)
-{
- for (int i = 0; i < _function->basicBlocks.size(); ++i) {
- IR::BasicBlock *block = _function->basicBlocks.at(i);
-
- while (! blocks->contains(block)) {
- blocks->append(block);
-
- if (IR::Stmt *terminator = block->terminator()) {
- if (IR::CJump *cj = terminator->asCJump())
- block = cj->iffalse;
- else if (IR::Jump *j = terminator->asJump())
- block = j->target;
- }
- }
- }
-}
-
-void QV4CompilerPrivate::traceExpression(IR::Expr *e, quint8 r)
-{
- if (!e) {
- discard();
- } else {
- qSwap(currentReg, r);
- e->accept(this);
- qSwap(currentReg, r);
- }
-}
-
-//
-// expressions
-//
-void QV4CompilerPrivate::visitConst(IR::Const *e)
-{
- switch (e->type) {
- case IR::BoolType: {
- Instr::LoadBool i;
- i.reg = currentReg;
- i.value = e->value;
- gen(i);
- } break;
-
- case IR::IntType: {
- Instr::LoadInt i;
- i.reg = currentReg;
- i.value = e->value;
- gen(i);
- } break;
-
- case IR::FloatType:
- case IR::NumberType: {
- Instr::LoadNumber i;
- i.reg = currentReg;
- i.value = e->value;
- gen(i);
- } break;
-
- case IR::NullType: {
- Instr::LoadNull i;
- i.reg = currentReg;
- gen(i);
- } break;
-
- default:
- if (qmlVerboseCompiler())
- qWarning() << Q_FUNC_INFO << "unexpected type";
- discard();
- }
-}
-
-void QV4CompilerPrivate::visitString(IR::String *e)
-{
- registerLiteralString(currentReg, e->value);
-}
-
-void QV4CompilerPrivate::visitName(IR::Name *e)
-{
- if (e->base) {
- // fetch the object and store it in reg.
- traceExpression(e->base, currentReg);
- } else {
- _subscribeName.clear();
- }
-
- if (e->storage == IR::Name::RootStorage) {
-
- Instr::LoadRoot instr;
- instr.reg = currentReg;
- gen(instr);
-
- if (e->symbol == IR::Name::IdObject) {
- // The ID is a reference to the root object
- return;
- }
-
- } else if (e->storage == IR::Name::ScopeStorage) {
-
- Instr::LoadScope instr;
- instr.reg = currentReg;
- gen(instr);
-
- _subscribeName << contextName();
-
- } else if (e->storage == IR::Name::IdStorage) {
-
- Instr::LoadId instr;
- instr.reg = currentReg;
- instr.index = e->idObject->idIndex;
- gen(instr);
-
- _subscribeName << QLatin1String("$$$ID_") + *e->id;
-
- if (blockNeedsSubscription(_subscribeName)) {
- Instr::SubscribeId sub;
- sub.reg = currentReg;
- sub.offset = subscriptionIndex(_subscribeName);
- sub.index = instr.index;
- gen(sub);
- }
-
- return;
- } else {
- // No action needed
- }
-
- switch (e->symbol) {
- case IR::Name::Unbound:
- case IR::Name::IdObject:
- case IR::Name::Slot:
- case IR::Name::Object: {
- Q_ASSERT(!"Unreachable");
- discard();
- } break;
-
- case IR::Name::AttachType: {
- _subscribeName << *e->id;
-
- Instr::LoadAttached attached;
- attached.output = currentReg;
- attached.reg = currentReg;
- attached.exceptionId = exceptionId(bindingLine, bindingColumn);
- if (e->declarativeType->attachedPropertiesId() == -1)
- discard();
- attached.id = e->declarativeType->attachedPropertiesId();
- gen(attached);
- } break;
-
- case IR::Name::SingletonObject: {
- /*
- Existing singleton type object lookup methods include:
- 1. string -> singleton object (search via importCache->query(name))
- 2. typeid -> singleton object QQmlType (search via ???)
- We currently use 1, which is not ideal for performance
- */
- _subscribeName << *e->id;
-
- registerLiteralString(currentReg, e->id);
-
- Instr::LoadSingletonObject module;
- module.reg = currentReg;
- gen(module);
- } break;
-
- case IR::Name::Property: {
- _subscribeName << *e->id;
-
- if (e->property->coreIndex == -1) {
- QMetaProperty prop;
- e->property->load(prop, QQmlEnginePrivate::get(engine));
- }
-
- const int propTy = e->property->propType;
- QQmlRegisterType regType;
-
- switch (propTy) {
- case QMetaType::Float:
- regType = FloatType;
- break;
- case QMetaType::Double:
- regType = NumberType;
- break;
- case QMetaType::Bool:
- regType = BoolType;
- break;
- case QMetaType::Int:
- regType = IntType;
- break;
- case QMetaType::QString:
- regType = QStringType;
- break;
- case QMetaType::QUrl:
- regType = QUrlType;
- break;
- case QMetaType::QColor:
- regType = QColorType;
- break;
- case QMetaType::QVariant:
- regType = QVariantType;
- break;
-
- default:
- if (propTy == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
- regType = PODValueType;
- } else if (!engine->metaObjectForType(propTy).isNull()) {
- regType = QObjectStarType;
- } else {
- if (qmlVerboseCompiler())
- qWarning() << "Discard unsupported property type:" << QMetaType::typeName(propTy);
- discard(); // Unsupported type
- return;
- }
-
- break;
- } // switch
-
- if (e->property->hasAccessors()) {
- Instr::FetchAndSubscribe fetch;
- fetch.reg = currentReg;
- fetch.subscription = subscriptionIndex(_subscribeName);
- fetch.exceptionId = exceptionId(e->line, e->column);
- fetch.valueType = regType;
- fetch.property = *e->property;
- gen(fetch);
- } else {
- Instr::Fetch fetch;
- fetch.reg = currentReg;
- fetch.index = e->property->coreIndex;
- fetch.exceptionId = exceptionId(e->line, e->column);
- fetch.valueType = regType;
-
- if (blockNeedsSubscription(_subscribeName) && e->property->notifyIndex != -1) {
- fetch.subOffset = subscriptionIndex(_subscribeName);
- fetch.subIndex = e->property->notifyIndex;
- } else {
- fetch.subOffset = static_cast<quint16>(-1);
- fetch.subIndex = static_cast<quint32>(-1);
- }
-
- gen(fetch);
- }
-
- } break;
- } // switch
-}
-
-void QV4CompilerPrivate::visitTemp(IR::Temp *e)
-{
- if (currentReg != e->index) {
- Instr::Copy i;
- i.reg = currentReg;
- i.src = e->index;
- gen(i);
- }
-}
-
-void QV4CompilerPrivate::visitUnop(IR::Unop *e)
-{
- quint8 src = currentReg;
-
- if (IR::Temp *temp = e->expr->asTemp()) {
- src = temp->index;
- } else {
- traceExpression(e->expr, src);
- }
-
- switch (e->op) {
- case IR::OpInvalid:
- Q_ASSERT(!"unreachable");
- break;
-
- case IR::OpIfTrue:
- convertToBool(e->expr, src);
- if (src != currentReg) {
- Instr::Copy i;
- i.reg = currentReg;
- i.src = src;
- gen(i);
- }
- break;
-
- case IR::OpNot: {
- Instr::UnaryNot i;
- convertToBool(e->expr, src);
- i.output = currentReg;
- i.src = src;
- gen(i);
- } break;
-
- case IR::OpUMinus:
- if (IR::isRealType(e->expr->type)) {
- Instr::UnaryMinusNumber i;
- i.output = currentReg;
- i.src = src;
- gen(i);
- } else if (e->expr->type == IR::IntType) {
- convertToNumber(e->expr, currentReg);
- Instr::UnaryMinusNumber i;
- i.output = currentReg;
- i.src = src;
- gen(i);
- } else {
- discard();
- }
- break;
-
- case IR::OpUPlus:
- if (IR::isRealType(e->expr->type)) {
- Instr::UnaryPlusNumber i;
- i.output = currentReg;
- i.src = src;
- gen(i);
- } else if (e->expr->type == IR::IntType) {
- convertToNumber(e->expr, currentReg);
- Instr::UnaryPlusNumber i;
- i.output = currentReg;
- i.src = src;
- gen(i);
- } else {
- discard();
- }
- break;
-
- case IR::OpCompl:
- // TODO
- discard();
- break;
-
- case IR::OpBitAnd:
- case IR::OpBitOr:
- case IR::OpBitXor:
- case IR::OpAdd:
- case IR::OpSub:
- case IR::OpMul:
- case IR::OpDiv:
- case IR::OpMod:
- case IR::OpLShift:
- case IR::OpRShift:
- case IR::OpURShift:
- case IR::OpGt:
- case IR::OpLt:
- case IR::OpGe:
- case IR::OpLe:
- case IR::OpEqual:
- case IR::OpNotEqual:
- case IR::OpStrictEqual:
- case IR::OpStrictNotEqual:
- case IR::OpAnd:
- case IR::OpOr:
- Q_ASSERT(!"unreachable");
- break;
- } // switch
-}
-
-void QV4CompilerPrivate::convertToNumber(IR::Expr *expr, int reg)
-{
- if (expr->type == IR::NumberType)
- return;
-
- switch (expr->type) {
- case IR::BoolType: {
- Instr::ConvertBoolToNumber i;
- i.output = i.src = reg;
- gen(i);
- } break;
-
- case IR::IntType: {
- Instr::ConvertIntToNumber i;
- i.output = i.src = reg;
- gen(i);
- } break;
-
- case IR::FloatType:
- case IR::NumberType:
- // nothing to do
- return;
-
- default:
- discard();
- break;
- } // switch
-}
-
-void QV4CompilerPrivate::convertToInt(IR::Expr *expr, int reg)
-{
- if (expr->type == IR::IntType)
- return;
-
- switch (expr->type) {
- case IR::BoolType: {
- Instr::ConvertBoolToInt i;
- i.output = i.src = reg;
- gen(i);
- } break;
-
- case IR::IntType:
- // nothing to do
- return;
-
- case IR::FloatType:
- case IR::NumberType: {
- Instr::ConvertNumberToInt i;
- i.output = i.src = reg;
- gen(i);
- } break;
-
- default:
- discard();
- break;
- } // switch
-}
-
-void QV4CompilerPrivate::convertToBool(IR::Expr *expr, int reg)
-{
- if (expr->type == IR::BoolType)
- return;
-
- switch (expr->type) {
- case IR::BoolType:
- // nothing to do
- break;
-
- case IR::IntType: {
- Instr::ConvertIntToBool i;
- i.output = i.src = reg;
- gen(i);
- } break;
-
- case IR::FloatType:
- case IR::NumberType: {
- Instr::ConvertNumberToBool i;
- i.output = i.src = reg;
- gen(i);
- } return;
-
- case IR::StringType: {
- Instr::ConvertStringToBool i;
- i.output = i.src = reg;
- gen(i);
- } return;
-
- case IR::ColorType: {
- Instr::ConvertColorToBool i;
- i.output = i.src = reg;
- gen(i);
- } return;
-
- default:
- discard();
- break;
- } // switch
-}
-
-quint8 QV4CompilerPrivate::instructionOpcode(IR::Binop *e)
-{
- switch (e->op) {
- case IR::OpInvalid:
- return V4Instr::Noop;
-
- case IR::OpIfTrue:
- case IR::OpNot:
- case IR::OpUMinus:
- case IR::OpUPlus:
- case IR::OpCompl:
- return V4Instr::Noop;
-
- case IR::OpBitAnd:
- return V4Instr::BitAndInt;
-
- case IR::OpBitOr:
- return V4Instr::BitOrInt;
-
- case IR::OpBitXor:
- return V4Instr::BitXorInt;
-
- case IR::OpAdd:
- if (e->type == IR::StringType)
- return V4Instr::AddString;
- return V4Instr::AddNumber;
-
- case IR::OpSub:
- return V4Instr::SubNumber;
-
- case IR::OpMul:
- return V4Instr::MulNumber;
-
- case IR::OpDiv:
- return V4Instr::DivNumber;
-
- case IR::OpMod:
- return V4Instr::ModNumber;
-
- case IR::OpLShift:
- return V4Instr::LShiftInt;
-
- case IR::OpRShift:
- return V4Instr::RShiftInt;
-
- case IR::OpURShift:
- return V4Instr::URShiftInt;
-
- case IR::OpGt:
- if (e->left->type == IR::StringType)
- return V4Instr::GtString;
- return V4Instr::GtNumber;
-
- case IR::OpLt:
- if (e->left->type == IR::StringType)
- return V4Instr::LtString;
- return V4Instr::LtNumber;
-
- case IR::OpGe:
- if (e->left->type == IR::StringType)
- return V4Instr::GeString;
- return V4Instr::GeNumber;
-
- case IR::OpLe:
- if (e->left->type == IR::StringType)
- return V4Instr::LeString;
- return V4Instr::LeNumber;
-
- case IR::OpEqual:
- if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
- return V4Instr::EqualObject;
- if (e->left->type == IR::StringType)
- return V4Instr::EqualString;
- return V4Instr::EqualNumber;
-
- case IR::OpNotEqual:
- if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
- return V4Instr::NotEqualObject;
- if (e->left->type == IR::StringType)
- return V4Instr::NotEqualString;
- return V4Instr::NotEqualNumber;
-
- case IR::OpStrictEqual:
- if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
- return V4Instr::StrictEqualObject;
- if (e->left->type == IR::StringType)
- return V4Instr::StrictEqualString;
- return V4Instr::StrictEqualNumber;
-
- case IR::OpStrictNotEqual:
- if (e->left->type == IR::ObjectType || e->right->type == IR::ObjectType)
- return V4Instr::StrictNotEqualObject;
- if (e->left->type == IR::StringType)
- return V4Instr::StrictNotEqualString;
- return V4Instr::StrictNotEqualNumber;
-
- case IR::OpAnd:
- case IR::OpOr:
- return V4Instr::Noop;
-
- } // switch
-
- return V4Instr::Noop;
-}
-
-void QV4CompilerPrivate::visitBinop(IR::Binop *e)
-{
- if (e->type == IR::InvalidType) {
- discard();
- return;
- }
-
- int left = currentReg;
- int right = currentReg + 1;
-
- if (e->left->asTemp() && e->type != IR::StringType)
- left = e->left->asTemp()->index;
- else
- traceExpression(e->left, left);
-
- if (IR::Temp *t = e->right->asTemp())
- right = t->index;
- else
- traceExpression(e->right, right);
-
- if (e->left->type != e->right->type) {
- if (qmlVerboseCompiler())
- qWarning().nospace() << "invalid operands to binary operator " << IR::binaryOperator(e->op)
- << "(`" << IR::binaryOperator(e->left->type)
- << "' and `"
- << IR::binaryOperator(e->right->type)
- << '\'';
- discard();
- return;
- }
-
- switch (e->op) {
- case IR::OpInvalid:
- discard();
- break;
-
- // unary
- case IR::OpIfTrue:
- case IR::OpNot:
- case IR::OpUMinus:
- case IR::OpUPlus:
- case IR::OpCompl:
- discard();
- break;
-
- case IR::OpBitAnd:
- case IR::OpBitOr:
- case IR::OpBitXor:
- case IR::OpLShift:
- case IR::OpRShift:
- case IR::OpURShift:
- convertToInt(e->left, left);
- convertToInt(e->right, right);
- break;
-
- case IR::OpAdd:
- if (e->type != IR::StringType) {
- convertToNumber(e->left, left);
- convertToNumber(e->right, right);
- }
- break;
-
- case IR::OpSub:
- case IR::OpMul:
- case IR::OpDiv:
- case IR::OpMod:
- convertToNumber(e->left, left);
- convertToNumber(e->right, right);
- break;
-
- case IR::OpGt:
- case IR::OpLt:
- case IR::OpGe:
- case IR::OpLe:
- case IR::OpEqual:
- case IR::OpNotEqual:
- case IR::OpStrictEqual:
- case IR::OpStrictNotEqual:
- if (e->left->type >= IR::FirstNumberType) {
- convertToNumber(e->left, left);
- convertToNumber(e->right, right);
- }
- break;
-
- case IR::OpAnd:
- case IR::OpOr:
- discard(); // ### unreachable
- break;
- } // switch
-
- const quint8 opcode = instructionOpcode(e);
- if (opcode != V4Instr::Noop) {
- V4Instr instr;
- instr.binaryop.output = currentReg;
- instr.binaryop.left = left;
- instr.binaryop.right = right;
- gen(static_cast<V4Instr::Type>(opcode), instr);
- }
-}
-
-void QV4CompilerPrivate::visitCall(IR::Call *call)
-{
- if (IR::Name *name = call->base->asName()) {
- IR::Expr *arg = call->onlyArgument();
- if (arg != 0 && IR::isRealType(arg->type)) {
- traceExpression(arg, currentReg);
-
- switch (name->builtin) {
- case IR::NoBuiltinSymbol:
- break;
-
- case IR::MathSinBultinFunction: {
- Instr::MathSinNumber i;
- i.output = i.src = currentReg;
- gen(i);
- } return;
-
- case IR::MathCosBultinFunction: {
- Instr::MathCosNumber i;
- i.output = i.src = currentReg;
- gen(i);
- } return;
-
- case IR::MathAbsBuiltinFunction: {
- Instr::MathAbsNumber i;
- i.output = i.src = currentReg;
- gen(i);
- } return;
-
- case IR::MathRoundBultinFunction: {
- Instr::MathRoundNumber i;
- i.output = i.src = currentReg;
- gen(i);
- } return;
-
- case IR::MathFloorBultinFunction: {
- Instr::MathFloorNumber i;
- i.output = i.src = currentReg;
- gen(i);
- } return;
-
- case IR::MathCeilBuiltinFunction: {
- Instr::MathCeilNumber i;
- i.output = i.src = currentReg;
- gen(i);
- } return;
-
- case IR::MathPIBuiltinConstant:
- default:
- break;
- } // switch
- } else {
- if (name->builtin == IR::MathMaxBuiltinFunction ||
- name->builtin == IR::MathMinBuiltinFunction) {
-
- //only handles the most common case of exactly two arguments
- if (call->args && call->args->next && !call->args->next->next) {
- IR::Expr *arg1 = call->args->expr;
- IR::Expr *arg2 = call->args->next->expr;
-
- if (arg1 != 0 && IR::isRealType(arg1->type) &&
- arg2 != 0 && IR::isRealType(arg2->type)) {
-
- traceExpression(arg1, currentReg);
- traceExpression(arg2, currentReg + 1);
-
- if (name->builtin == IR::MathMaxBuiltinFunction) {
- Instr::MathMaxNumber i;
- i.left = currentReg;
- i.right = currentReg + 1;
- i.output = currentReg;
- gen(i);
- return;
- } else if (name->builtin == IR::MathMinBuiltinFunction) {
- Instr::MathMinNumber i;
- i.left = currentReg;
- i.right = currentReg + 1;
- i.output = currentReg;
- gen(i);
- return;
- }
- }
- }
- }
- }
- }
-
- if (qmlVerboseCompiler())
- qWarning() << "TODO:" << Q_FUNC_INFO << __LINE__;
- discard();
-}
-
-
-//
-// statements
-//
-void QV4CompilerPrivate::visitExp(IR::Exp *s)
-{
- traceExpression(s->expr, currentReg);
-}
-
-void QV4CompilerPrivate::visitMove(IR::Move *s)
-{
- IR::Temp *target = s->target->asTemp();
- Q_ASSERT(target != 0);
-
- quint8 dest = target->index;
-
- IR::Type targetTy = s->target->type;
- IR::Type sourceTy = s->source->type;
-
- // promote the floats
- if (sourceTy == IR::FloatType)
- sourceTy = IR::NumberType;
-
- if (targetTy == IR::FloatType)
- targetTy = IR::NumberType;
-
- if (sourceTy != targetTy) {
- quint8 src = dest;
-
- if (IR::Temp *t = s->source->asTemp())
- src = t->index;
- else
- traceExpression(s->source, dest);
-
- V4Instr::Type opcode = V4Instr::Noop;
-
- if (sourceTy == IR::UrlType) {
- switch (targetTy) {
- case IR::BoolType:
- case IR::StringType:
- case IR::VariantType:
- case IR::VarType:
- case IR::JSValueType:
- // nothing to do. V4 will generate optimized
- // url-to-xxx conversions.
- break;
- default: {
- if (s->isMoveForReturn) {
- V4Instr instr;
- instr.throwop.exceptionId = exceptionId(bindingLine, bindingColumn);
- registerLiteralString(dest, _function->newString(QString::fromUtf8("Unable to assign %1 to %2")
- .arg(QLatin1String(IR::typeName(sourceTy)))
- .arg(QLatin1String(IR::typeName(targetTy)))));
- instr.throwop.message = dest;
- gen(V4Instr::Throw, instr);
- return;
- }
- // generate a UrlToString conversion and fix
- // the type of the source expression.
- V4Instr conv;
- conv.unaryop.output = src;
- conv.unaryop.src = src;
- gen(V4Instr::ConvertUrlToString, conv);
- sourceTy = IR::StringType;
- break;
- }
- } // switch
- }
-
- if (targetTy == IR::BoolType) {
- switch (sourceTy) {
- case IR::IntType: opcode = V4Instr::ConvertIntToBool; break;
- case IR::NumberType: opcode = V4Instr::ConvertNumberToBool; break;
- case IR::StringType: opcode = V4Instr::ConvertStringToBool; break;
- case IR::UrlType: opcode = V4Instr::ConvertUrlToBool; break;
- case IR::ColorType: opcode = V4Instr::ConvertColorToBool; break;
- case IR::ObjectType: opcode = V4Instr::ConvertObjectToBool; break;
- default: break;
- } // switch
- } else if (targetTy == IR::IntType) {
- switch (sourceTy) {
- case IR::BoolType: opcode = V4Instr::ConvertBoolToInt; break;
- case IR::NumberType: {
- if (s->isMoveForReturn)
- opcode = V4Instr::MathRoundNumber;
- else
- opcode = V4Instr::ConvertNumberToInt;
- break;
- }
- case IR::StringType: opcode = V4Instr::ConvertStringToInt; break;
- default: break;
- } // switch
- } else if (IR::isRealType(targetTy)) {
- switch (sourceTy) {
- case IR::BoolType: opcode = V4Instr::ConvertBoolToNumber; break;
- case IR::IntType: opcode = V4Instr::ConvertIntToNumber; break;
- case IR::StringType: opcode = V4Instr::ConvertStringToNumber; break;
- default: break;
- } // switch
- } else if (targetTy == IR::StringType) {
- switch (sourceTy) {
- case IR::BoolType: opcode = V4Instr::ConvertBoolToString; break;
- case IR::IntType: opcode = V4Instr::ConvertIntToString; break;
- case IR::NumberType: opcode = V4Instr::ConvertNumberToString; break;
- case IR::UrlType: opcode = V4Instr::ConvertUrlToString; break;
- case IR::ColorType: opcode = V4Instr::ConvertColorToString; break;
- default: break;
- } // switch
- } else if (targetTy == IR::UrlType) {
- if (s->isMoveForReturn && sourceTy != IR::StringType) {
- V4Instr instr;
- instr.throwop.exceptionId = exceptionId(bindingLine, bindingColumn);
- registerLiteralString(dest, _function->newString(QString::fromUtf8("Unable to assign %1 to %2")
- .arg(QLatin1String(IR::typeName(sourceTy)))
- .arg(QLatin1String(IR::typeName(targetTy)))));
- instr.throwop.message = dest;
- gen(V4Instr::Throw, instr);
- return;
- }
-
- V4Instr convToString;
- convToString.unaryop.output = dest;
- convToString.unaryop.src = src;
-
- // try to convert the source expression to a string.
- switch (sourceTy) {
- case IR::BoolType: gen(V4Instr::ConvertBoolToString, convToString); sourceTy = IR::StringType; break;
- case IR::IntType: gen(V4Instr::ConvertIntToString, convToString); sourceTy = IR::StringType; break;
- case IR::NumberType: gen(V4Instr::ConvertNumberToString, convToString); sourceTy = IR::StringType; break;
- case IR::ColorType: gen(V4Instr::ConvertColorToString, convToString); sourceTy = IR::StringType; break;
- default: break;
- } // switch
-
- if (sourceTy == IR::StringType)
- opcode = V4Instr::ConvertStringToUrl;
- } else if (targetTy == IR::ColorType) {
- switch (sourceTy) {
- case IR::StringType: opcode = V4Instr::ConvertStringToColor; break;
- default: break;
- } // switch
- } else if (targetTy == IR::ObjectType) {
- switch (sourceTy) {
- case IR::NullType: opcode = V4Instr::ConvertNullToObject; break;
- default: break;
- } // switch
- } else if (targetTy == IR::VariantType) {
- if (s->isMoveForReturn) {
- switch (sourceTy) {
- case IR::BoolType: opcode = V4Instr::ConvertBoolToVariant; break;
- case IR::IntType: opcode = V4Instr::ConvertIntToVariant; break;
- case IR::NumberType: opcode = V4Instr::ConvertNumberToVariant; break;
- case IR::UrlType: opcode = V4Instr::ConvertUrlToVariant; break;
- case IR::ColorType: opcode = V4Instr::ConvertColorToVariant; break;
- case IR::StringType: opcode = V4Instr::ConvertStringToVariant; break;
- case IR::ObjectType: opcode = V4Instr::ConvertObjectToVariant; break;
- case IR::NullType: opcode = V4Instr::ConvertNullToVariant; break;
- default: break;
- } // switch
- }
- } else if (targetTy == IR::VarType) {
- if (s->isMoveForReturn) {
- switch (sourceTy) {
- case IR::BoolType: opcode = V4Instr::ConvertBoolToVar; break;
- case IR::IntType: opcode = V4Instr::ConvertIntToVar; break;
- case IR::NumberType: opcode = V4Instr::ConvertNumberToVar; break;
- case IR::UrlType: opcode = V4Instr::ConvertUrlToVar; break;
- case IR::ColorType: opcode = V4Instr::ConvertColorToVar; break;
- case IR::StringType: opcode = V4Instr::ConvertStringToVar; break;
- case IR::ObjectType: opcode = V4Instr::ConvertObjectToVar; break;
- case IR::NullType: opcode = V4Instr::ConvertNullToVar; break;
- case IR::JSValueType: opcode = V4Instr::ConvertJSValueToVar; break;
- default: break;
- } // switch
- }
- } else if (targetTy == IR::JSValueType) {
- if (s->isMoveForReturn) {
- switch (sourceTy) {
- case IR::BoolType: opcode = V4Instr::ConvertBoolToJSValue; break;
- case IR::IntType: opcode = V4Instr::ConvertIntToJSValue; break;
- case IR::NumberType: opcode = V4Instr::ConvertNumberToJSValue; break;
- case IR::UrlType: opcode = V4Instr::ConvertUrlToJSValue; break;
- case IR::ColorType: opcode = V4Instr::ConvertColorToJSValue; break;
- case IR::StringType: opcode = V4Instr::ConvertStringToJSValue; break;
- case IR::ObjectType: opcode = V4Instr::ConvertObjectToJSValue; break;
- case IR::VarType: opcode = V4Instr::ConvertVarToJSValue; break;
- case IR::NullType: opcode = V4Instr::ConvertNullToJSValue; break;
- default: break;
- }
- }
- }
- if (opcode != V4Instr::Noop) {
- V4Instr conv;
- conv.unaryop.output = dest;
- conv.unaryop.src = src;
- gen(opcode, conv);
-
- if (s->isMoveForReturn && opcode == V4Instr::ConvertStringToUrl) {
- V4Instr resolveUrl;
- resolveUrl.unaryop.output = dest;
- resolveUrl.unaryop.src = dest;
- gen(V4Instr::ResolveUrl, resolveUrl);
- }
- } else {
- discard();
- }
- } else {
- traceExpression(s->source, dest);
- }
-}
-
-void QV4CompilerPrivate::visitJump(IR::Jump *s)
-{
- patches.append(Patch(s->target, bytecode.size()));
-
- Instr::Branch i;
- i.offset = 0; // ### backpatch
- gen(i);
-}
-
-void QV4CompilerPrivate::visitCJump(IR::CJump *s)
-{
- traceExpression(s->cond, currentReg);
-
- patches.append(Patch(s->iftrue, bytecode.size()));
-
- Instr::BranchTrue i;
- i.reg = currentReg;
- i.offset = 0; // ### backpatch
- gen(i);
-}
-
-void QV4CompilerPrivate::visitRet(IR::Ret *s)
-{
- Q_ASSERT(s->expr != 0);
-
- int storeReg = currentReg;
-
- if (IR::Temp *temp = s->expr->asTemp()) {
- storeReg = temp->index;
- } else {
- traceExpression(s->expr, storeReg);
- }
-
- if (qmlBindingsTest) {
- Instr::TestV4Store test;
- test.reg = storeReg;
- switch (s->type) {
- case IR::StringType:
- test.regType = QMetaType::QString;
- break;
- case IR::UrlType:
- test.regType = QMetaType::QUrl;
- break;
- case IR::ColorType:
- test.regType = QMetaType::QColor;
- break;
- case IR::SGAnchorLineType:
- test.regType = QQmlMetaType::QQuickAnchorLineMetaTypeId();
- break;
- case IR::ObjectType:
- test.regType = QMetaType::QObjectStar;
- break;
- case IR::VariantType:
- test.regType = QMetaType::QVariant;
- break;
- case IR::VarType:
- test.regType = qMetaTypeId<v8::Handle<v8::Value> >();
- break;
- case IR::JSValueType:
- test.regType = qMetaTypeId<QJSValue>();
- break;
- case IR::BoolType:
- test.regType = QMetaType::Bool;
- break;
- case IR::IntType:
- test.regType = QMetaType::Int;
- break;
- case IR::FloatType:
- case IR::NumberType:
- test.regType = QMetaType::Double;
- break;
- default:
- discard();
- return;
- }
- gen(test);
- }
-
- Instr::Store store;
- store.output = 0;
- store.index = expression->property->index;
- store.reg = storeReg;
- store.valueType = s->type == IR::FloatType ? FloatType : 0;
- store.exceptionId = exceptionId(s->line, s->column);
- gen(store);
-}
-
-void QV4Compiler::dump(const QByteArray &programData)
-{
- const QV4Program *program = (const QV4Program *)programData.constData();
-
- qWarning() << "Program.bindings:" << program->bindings;
- qWarning() << "Program.dataLength:" << program->dataLength;
- qWarning() << "Program.subscriptions:" << program->subscriptions;
-
- const int programSize = program->instructionCount;
- const char *start = program->instructions();
- const char *end = start + programSize;
- Bytecode bc;
- bc.dump(start, end);
-}
-
-/*!
-Clear the state associated with attempting to compile a specific binding.
-This does not clear the global "committed binding" states.
-*/
-void QV4CompilerPrivate::resetInstanceState()
-{
- data = committed.data;
- exceptions = committed.exceptions;
- usedSubscriptionIds.clear();
- subscriptionIds.clear();
- subscriptionOffset = committed.subscriptionCount;
- bytecode.clear();
- patches.clear();
- pool.clear();
- currentReg = 0;
- invalidatable = false;
-}
-
-/*!
-Mark the last compile as successful, and add it to the "committed data"
-section.
-
-Returns the index for the committed binding.
-*/
-int QV4CompilerPrivate::commitCompile()
-{
- int rv = committed.count();
- committed.offsets << committed.bytecode.count();
- committed.dependencies << usedSubscriptionIds;
- committed.bytecode.append(bytecode.constData(), bytecode.size());
- committed.data = data;
- committed.exceptions = exceptions;
- committed.subscriptionCount = subscriptionOffset + subscriptionIds.count();
- if (bindingsDump())
- committed.subscriptions.append(subscriptionIds);
- return rv;
-}
-
-bool QV4CompilerPrivate::compile(QQmlJS::AST::Node *node)
-{
- resetInstanceState();
-
- if (expression->property->type == -1)
- return false;
-
- AST::SourceLocation location;
- if (AST::ExpressionNode *astExpression = node->expressionCast()) {
- location = astExpression->firstSourceLocation();
- } else if (AST::Statement *astStatement = node->statementCast()) {
- if (AST::Block *block = AST::cast<AST::Block *>(astStatement))
- location = block->lbraceToken;
- else if (AST::IfStatement *ifStmt = AST::cast<AST::IfStatement *>(astStatement))
- location = ifStmt->ifToken;
- else
- return false;
- } else {
- return false;
- }
-
- IR::Function thisFunction(&pool), *function = &thisFunction;
-
- QV4IRBuilder irBuilder(expression, engine);
- if (!irBuilder(function, node, &invalidatable))
- return false;
-
- bool discarded = false;
- qSwap(_discarded, discarded);
- qSwap(_function, function);
- trace(location.startLine, location.startColumn);
- qSwap(_function, function);
- qSwap(_discarded, discarded);
-
- if (qmlVerboseCompiler()) {
- QTextStream qerr(stderr, QIODevice::WriteOnly);
- if (discarded)
- qerr << "======== TODO ====== " << endl;
- else
- qerr << "==================== " << endl;
- qerr << "\tline: " << location.startLine
- << "\tcolumn: " << location.startColumn
- << endl;
- foreach (IR::BasicBlock *bb, function->basicBlocks)
- bb->dump(qerr);
- qerr << endl;
- }
-
- if (discarded || subscriptionIds.count() > 0xFFFF || registerCount > 31)
- return false;
-
- return true;
-}
-
-// Returns a reg
-int QV4CompilerPrivate::registerLiteralString(quint8 reg, const QStringRef &str)
-{
- // ### string cleanup
-
- QByteArray strdata((const char *)str.constData(), str.length() * sizeof(QChar));
- int offset = data.count();
- data += strdata;
-
- Instr::LoadString string;
- string.reg = reg;
- string.offset = offset;
- string.length = str.length();
- gen(string);
-
- return reg;
-}
-
-/*!
-Returns true if the current expression has not already subscribed to \a sub in currentBlockMask.
-*/
-bool QV4CompilerPrivate::blockNeedsSubscription(const QStringList &sub)
-{
- QString str = sub.join(QLatin1String("."));
-
- int *iter = subscriptionIds.value(str);
- if (!iter)
- return true;
-
- quint32 *uiter = usedSubscriptionIds.value(*iter);
- if (!uiter)
- return true;
- else
- return !(*uiter & currentBlockMask);
-}
-
-int QV4CompilerPrivate::subscriptionIndex(const QStringList &sub)
-{
- QString str = sub.join(QLatin1String("."));
- int *iter = subscriptionIds.value(str);
- if (!iter) {
- int count = subscriptionOffset + subscriptionIds.count();
- iter = &subscriptionIds[str];
- *iter = count;
- }
- quint32 &u = usedSubscriptionIds[*iter];
- if (!(u & currentBlockMask)) {
- u |= currentBlockMask;
- usedSubscriptionIdsChanged = true;
- }
- return *iter;
-}
-
-quint32 QV4CompilerPrivate::subscriptionBlockMask(const QStringList &sub)
-{
- QString str = sub.join(QLatin1String("."));
-
- int *iter = subscriptionIds.value(str);
- Q_ASSERT(iter != 0);
-
- quint32 *uiter = usedSubscriptionIds.value(*iter);
- Q_ASSERT(uiter != 0);
-
- return *uiter;
-}
-
-quint8 QV4CompilerPrivate::exceptionId(quint16 line, quint16 column)
-{
- quint8 rv = 0xFF;
- if (exceptions.count() < 0xFF) {
- rv = (quint8)exceptions.count();
- quint32 e = line;
- e <<= 16;
- e |= column;
- exceptions.append(e);
- }
- return rv;
-}
-
-quint8 QV4CompilerPrivate::exceptionId(QQmlJS::AST::ExpressionNode *n)
-{
- quint8 rv = 0xFF;
- if (n && exceptions.count() < 0xFF) {
- QQmlJS::AST::SourceLocation l = n->firstSourceLocation();
- rv = exceptionId(l.startLine, l.startColumn);
- }
- return rv;
-}
-
-QV4Compiler::QV4Compiler()
-: d(new QV4CompilerPrivate)
-{
- qmlBindingsTest |= qmlBindingsTestEnv();
-}
-
-QV4Compiler::~QV4Compiler()
-{
- delete d; d = 0;
-}
-
-/*
-Returns true if any bindings were compiled.
-*/
-bool QV4Compiler::isValid() const
-{
- return !d->committed.bytecode.isEmpty();
-}
-
-/*
--1 on failure, otherwise the binding index to use.
-*/
-int QV4Compiler::compile(const Expression &expression, QQmlEnginePrivate *engine, bool *invalidatable)
-{
- if (!expression.expression.asAST()) return false;
-
- if (qmlDisableOptimizer() || !qmlEnableV4)
- return -1;
-
- d->expression = &expression;
- d->engine = engine;
-
- if (d->compile(expression.expression.asAST())) {
- *invalidatable = d->isInvalidatable();
- return d->commitCompile();
- } else {
- return -1;
- }
-}
-
-QByteArray QV4CompilerPrivate::buildSignalTable() const
-{
- QHash<int, QList<QPair<int, quint32> > > table;
-
- for (int ii = 0; ii < committed.count(); ++ii) {
- const QQmlAssociationList<int, quint32> &deps = committed.dependencies.at(ii);
- for (QQmlAssociationList<int, quint32>::const_iterator iter = deps.begin(); iter != deps.end(); ++iter)
- table[iter->first].append(qMakePair(ii, iter->second));
- }
-
- QVector<quint32> header;
- QVector<quint32> data;
- for (int ii = 0; ii < committed.subscriptionCount; ++ii) {
- header.append(committed.subscriptionCount + data.count());
- const QList<QPair<int, quint32> > &bindings = table[ii];
- data.append(bindings.count());
- for (int jj = 0; jj < bindings.count(); ++jj) {
- data.append(bindings.at(jj).first);
- data.append(bindings.at(jj).second);
- }
- }
- header << data;
-
- return QByteArray((const char *)header.constData(), header.count() * sizeof(quint32));
-}
-
-QByteArray QV4CompilerPrivate::buildExceptionData() const
-{
- QByteArray rv;
- rv.resize(committed.exceptions.count() * sizeof(quint32));
- ::memcpy(rv.data(), committed.exceptions.constData(), rv.size());
- return rv;
-}
-
-/*
-Returns the compiled program.
-*/
-QByteArray QV4Compiler::program() const
-{
- QByteArray programData;
-
- if (isValid()) {
- QV4Program prog;
- prog.bindings = d->committed.count();
-
- Bytecode bc;
- QV4CompilerPrivate::Instr::Jump jump;
- jump.reg = -1;
-
- for (int ii = 0; ii < d->committed.count(); ++ii) {
- jump.count = d->committed.count() - ii - 1;
- jump.count*= V4InstrMeta<V4Instr::Jump>::Size;
- jump.count+= d->committed.offsets.at(ii);
- bc.append(jump);
- }
-
-
- QByteArray bytecode;
- bytecode.reserve(bc.size() + d->committed.bytecode.size());
- bytecode.append(bc.constData(), bc.size());
- bytecode.append(d->committed.bytecode.constData(), d->committed.bytecode.size());
-
- QByteArray data = d->committed.data;
- while (data.count() % 4) data.append('\0');
- prog.signalTableOffset = data.count();
- data += d->buildSignalTable();
- while (data.count() % 4) data.append('\0');
- prog.exceptionDataOffset = data.count();
- data += d->buildExceptionData();
-
- prog.dataLength = 4 * ((data.size() + 3) / 4);
- prog.subscriptions = d->committed.subscriptionCount;
- prog.instructionCount = bytecode.count();
- int size = sizeof(QV4Program) + bytecode.count();
- size += prog.dataLength;
-
- programData.resize(size);
- memcpy(programData.data(), &prog, sizeof(QV4Program));
- if (prog.dataLength)
- memcpy((char *)((QV4Program *)programData.data())->data(), data.constData(),
- data.size());
- memcpy((char *)((QV4Program *)programData.data())->instructions(), bytecode.constData(),
- bytecode.count());
- }
-
- if (bindingsDump()) {
- qWarning().nospace() << "Subscription slots:";
-
- QQmlAssociationList<QString, int> subscriptionIds;
- foreach (subscriptionIds, d->committed.subscriptions) {
- for (QQmlAssociationList<QString, int>::ConstIterator iter = subscriptionIds.begin();
- iter != subscriptionIds.end(); ++iter) {
- qWarning().nospace() << " " << iter->first << "\t-> " << iter->second;
- }
- }
- QV4Compiler::dump(programData);
- }
-
- return programData;
-}
-
-void QV4Compiler::enableBindingsTest(bool e)
-{
- if (e)
- qmlBindingsTest = true;
- else
- qmlBindingsTest = qmlBindingsTestEnv();
-}
-
-void QV4Compiler::enableV4(bool e)
-{
- qmlEnableV4 = e;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4compiler_p_p.h b/src/qml/qml/v4/qv4compiler_p_p.h
deleted file mode 100644
index 58ec521a97..0000000000
--- a/src/qml/qml/v4/qv4compiler_p_p.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4COMPILER_P_P_H
-#define QV4COMPILER_P_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 "qv4instruction_p.h"
-#include "qv4ir_p.h"
-#include <private/qqmlscript_p.h>
-#include <private/qqmlimport_p.h>
-#include <private/qqmlengine_p.h>
-
-QT_BEGIN_NAMESPACE
-
-template <typename _Key, typename _Value>
-class QQmlAssociationList
-{
-public:
- typedef QVarLengthArray<QPair<_Key, _Value>, 8> Container;
- typedef typename Container::const_iterator const_iterator;
- typedef typename Container::const_iterator ConstIterator;
-
- const_iterator begin() const { return _container.begin(); }
- const_iterator end() const { return _container.end(); }
- int count() const { return _container.count(); }
- void clear() { _container.clear(); }
-
- _Value *value(const _Key &key) {
- for (int i = 0; i < _container.size(); ++i) {
- QPair<_Key, _Value> &p = _container[i];
- if (p.first == key)
- return &p.second;
- }
- return 0;
- }
-
- _Value &operator[](const _Key &key) {
- for (int i = 0; i < _container.size(); ++i) {
- QPair<_Key, _Value> &p = _container[i];
- if (p.first == key)
- return p.second;
- }
- int index = _container.size();
- _container.append(qMakePair(key, _Value()));
- return _container[index].second;
- }
-
- void insert(const _Key &key, _Value &value) {
- for (int i = 0; i < _container.size(); ++i) {
- QPair<_Key, _Value> &p = _container[i];
- if (p.first == key) {
- p.second = value;
- return;
- }
- }
- _container.append(qMakePair(key, value));
- }
-
-private:
- Container _container;
-};
-
-class QV4CompilerPrivate: protected QQmlJS::IR::ExprVisitor,
- protected QQmlJS::IR::StmtVisitor
-{
-public:
- QV4CompilerPrivate();
-
- void resetInstanceState();
- int commitCompile();
-
- const QV4Compiler::Expression *expression;
- QQmlEnginePrivate *engine;
-
- QString contextName() const { return QLatin1String("$$$SCOPE_") + QString::number((quintptr)expression->context, 16); }
-
- bool compile(QQmlJS::AST::Node *);
-
- bool isInvalidatable() const { return invalidatable; }
-
- int registerLiteralString(quint8 reg, const QStringRef &);
- QByteArray data;
-
- bool blockNeedsSubscription(const QStringList &);
- int subscriptionIndex(const QStringList &);
- quint32 subscriptionBlockMask(const QStringList &);
-
- quint8 exceptionId(quint16 line, quint16 column);
- quint8 exceptionId(QQmlJS::AST::ExpressionNode *);
- QVector<quint32> exceptions;
-
- QQmlAssociationList<int, quint32> usedSubscriptionIds;
- int subscriptionOffset;
- QQmlAssociationList<QString, int> subscriptionIds;
- QQmlJS::Bytecode bytecode;
-
- // back patching
- struct Patch {
- QQmlJS::IR::BasicBlock *block; // the basic block
- int offset; // the index of the instruction to patch
- Patch(QQmlJS::IR::BasicBlock *block = 0, int index = -1)
- : block(block), offset(index) {}
- };
- QVector<Patch> patches;
- QQmlPool pool;
-
- // Committed binding data
- struct Committed {
- Committed(): subscriptionCount(0) {}
- QList<int> offsets;
- QList<QQmlAssociationList<int, quint32> > dependencies;
-
- //QQmlJS::Bytecode bytecode;
- QByteArray bytecode;
- QByteArray data;
- QVector<quint32> exceptions;
- int subscriptionCount;
- QList<QQmlAssociationList<QString, int> > subscriptions;
-
- int count() const { return offsets.count(); }
- } committed;
-
- QByteArray buildSignalTable() const;
- QByteArray buildExceptionData() const;
-
- void convertToNumber(QQmlJS::IR::Expr *expr, int reg);
- void convertToInt(QQmlJS::IR::Expr *expr, int reg);
- void convertToBool(QQmlJS::IR::Expr *expr, int reg);
- quint8 instructionOpcode(QQmlJS::IR::Binop *e);
-
- struct Instr {
-#define QML_V4_INSTR_DATA_TYPEDEF(I, FMT) typedef QQmlJS::V4InstrData<QQmlJS::V4Instr::I> I;
- FOR_EACH_V4_INSTR(QML_V4_INSTR_DATA_TYPEDEF)
-#undef QML_v4_INSTR_DATA_TYPEDEF
- private:
- Instr();
- };
-
-protected:
- //
- // tracing
- //
- void trace(quint16 line, quint16 column);
- void trace(QVector<QQmlJS::IR::BasicBlock *> *blocks);
- void traceExpression(QQmlJS::IR::Expr *e, quint8 r);
-
- template <int Instr>
- inline void gen(const QQmlJS::V4InstrData<Instr> &i)
- { bytecode.append(i); }
- inline void gen(QQmlJS::V4Instr::Type type, QQmlJS::V4Instr &instr)
- { bytecode.append(type, instr); }
-
- inline QQmlJS::V4Instr::Type instructionType(const QQmlJS::V4Instr *i) const
- { return bytecode.instructionType(i); }
-
- //
- // expressions
- //
- virtual void visitConst(QQmlJS::IR::Const *e);
- virtual void visitString(QQmlJS::IR::String *e);
- virtual void visitName(QQmlJS::IR::Name *e);
- virtual void visitTemp(QQmlJS::IR::Temp *e);
- virtual void visitUnop(QQmlJS::IR::Unop *e);
- virtual void visitBinop(QQmlJS::IR::Binop *e);
- virtual void visitCall(QQmlJS::IR::Call *e);
-
- //
- // statements
- //
- virtual void visitExp(QQmlJS::IR::Exp *s);
- virtual void visitMove(QQmlJS::IR::Move *s);
- virtual void visitJump(QQmlJS::IR::Jump *s);
- virtual void visitCJump(QQmlJS::IR::CJump *s);
- virtual void visitRet(QQmlJS::IR::Ret *s);
-
-private:
- QStringList _subscribeName;
- QQmlJS::IR::Function *_function;
- QQmlJS::IR::BasicBlock *_block;
- void discard() { _discarded = true; }
- bool _discarded;
- quint8 currentReg;
- quint8 registerCount;
-
- bool usedSubscriptionIdsChanged;
- quint32 currentBlockMask;
- quint16 bindingLine;
- quint16 bindingColumn;
- bool invalidatable;
-};
-
-
-QT_END_NAMESPACE
-
-#endif // QV4COMPILER_P_P_H
-
diff --git a/src/qml/qml/v4/qv4context.cpp b/src/qml/qml/v4/qv4context.cpp
new file mode 100644
index 0000000000..ed01548410
--- /dev/null
+++ b/src/qml/qml/v4/qv4context.cpp
@@ -0,0 +1,615 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QString>
+#include "qv4debugging_p.h"
+#include <qv4context_p.h>
+#include <qv4object_p.h>
+#include <qv4objectproto_p.h>
+#include "qv4mm_p.h"
+#include <qv4argumentsobject_p.h>
+#include "qv4function_p.h"
+
+using namespace QV4;
+
+DiagnosticMessage::DiagnosticMessage()
+ : offset(0)
+ , length(0)
+ , startLine(0)
+ , startColumn(0)
+ , type(0)
+ , next(0)
+{}
+
+DiagnosticMessage::~DiagnosticMessage()
+{
+ delete next;
+}
+
+String *DiagnosticMessage::buildFullMessage(ExecutionContext *ctx) const
+{
+ QString msg;
+ if (!fileName.isEmpty())
+ msg = fileName + QLatin1Char(':');
+ msg += QString::number(startLine) + QLatin1Char(':') + QString::number(startColumn) + QLatin1String(": ");
+ if (type == QV4::DiagnosticMessage::Error)
+ msg += QLatin1String("error");
+ else
+ msg += QLatin1String("warning");
+ msg += ": " + message;
+
+ return ctx->engine->newString(msg);
+}
+
+void ExecutionContext::createMutableBinding(String *name, bool deletable)
+{
+
+ // find the right context to create the binding on
+ Object *activation = engine->globalObject;
+ ExecutionContext *ctx = this;
+ while (ctx) {
+ if (ctx->type >= Type_CallContext) {
+ CallContext *c = static_cast<CallContext *>(ctx);
+ if (!c->activation)
+ c->activation = engine->newObject();
+ activation = c->activation;
+ break;
+ }
+ ctx = ctx->outer;
+ }
+
+ if (activation->__hasProperty__(name))
+ return;
+ Property desc = Property::fromValue(Value::undefinedValue());
+ PropertyAttributes attrs(Attr_Data);
+ attrs.setConfigurable(deletable);
+ activation->__defineOwnProperty__(this, name, desc, attrs);
+}
+
+String * const *ExecutionContext::formals() const
+{
+ return type >= Type_CallContext ? static_cast<const CallContext *>(this)->function->formalParameterList : 0;
+}
+
+unsigned int ExecutionContext::formalCount() const
+{
+ return type >= Type_CallContext ? static_cast<const CallContext *>(this)->function->formalParameterCount : 0;
+}
+
+String * const *ExecutionContext::variables() const
+{
+ return type >= Type_CallContext ? static_cast<const CallContext *>(this)->function->varList : 0;
+}
+
+unsigned int ExecutionContext::variableCount() const
+{
+ return type >= Type_CallContext ? static_cast<const CallContext *>(this)->function->varCount : 0;
+}
+
+
+void GlobalContext::initGlobalContext(ExecutionEngine *eng)
+{
+ initBaseContext(Type_GlobalContext, eng, /*parentContext*/0);
+ thisObject = Value::fromObject(eng->globalObject);
+ global = 0;
+}
+
+void WithContext::initWithContext(ExecutionContext *p, Object *with)
+{
+ initBaseContext(Type_WithContext, p->engine, p);
+ thisObject = p->thisObject;
+ outer = p;
+ lookups = p->lookups;
+
+ withObject = with;
+}
+
+void CatchContext::initCatchContext(ExecutionContext *p, String *exceptionVarName, const Value &exceptionValue)
+{
+ initBaseContext(Type_CatchContext, p->engine, p);
+ strictMode = p->strictMode;
+ thisObject = p->thisObject;
+ outer = p;
+ lookups = p->lookups;
+
+ this->exceptionVarName = exceptionVarName;
+ this->exceptionValue = exceptionValue;
+}
+
+void CallContext::initCallContext(ExecutionContext *parentContext, FunctionObject *function, Value *_arguments, int _argumentCount, const Value &_thisObject)
+{
+ initBaseContext(Type_CallContext, parentContext->engine, parentContext);
+
+ this->function = function;
+ this->arguments = _arguments;
+ this->argumentCount = _argumentCount;
+ this->thisObject = _thisObject;
+
+ strictMode = function->strictMode;
+ marked = false;
+ outer = function->scope;
+#ifndef QT_NO_DEBUG
+ assert(outer->next != (ExecutionContext *)0x1);
+#endif
+
+ activation = 0;
+
+ if (function->function)
+ lookups = function->function->lookups;
+
+ uint argc = argumentCount;
+
+ locals = (Value *)(this + 1);
+ if (function->varCount)
+ std::fill(locals, locals + function->varCount, Value::undefinedValue());
+
+ if (needsOwnArguments()) {
+ Value *args = arguments;
+ argumentCount = qMax(argc, function->formalParameterCount);
+ arguments = locals + function->varCount;
+ if (argc)
+ ::memcpy(arguments, args, argc * sizeof(Value));
+ if (argc < function->formalParameterCount)
+ std::fill(arguments + argc, arguments + function->formalParameterCount, Value::undefinedValue());
+
+ }
+
+ if (function->usesArgumentsObject) {
+ ArgumentsObject *args = new (engine->memoryManager) ArgumentsObject(this, function->formalParameterCount, argc);
+ args->prototype = engine->objectPrototype;
+ activation = engine->newObject();
+ Property desc = Property::fromValue(Value::fromObject(args));
+ activation->__defineOwnProperty__(this, engine->id_arguments, desc, Attr_NotConfigurable);
+ }
+}
+
+void CallContext::initQmlContext(ExecutionContext *parentContext, Object *qml, FunctionObject *function)
+{
+ initBaseContext(Type_QmlContext, parentContext->engine, parentContext);
+
+ this->function = function;
+ this->arguments = 0;
+ this->argumentCount = 0;
+ this->thisObject = Value::undefinedValue();
+
+ strictMode = true;
+ marked = false;
+ this->outer = function->scope;
+#ifndef QT_NO_DEBUG
+ assert(outer->next != (ExecutionContext *)0x1);
+#endif
+
+ activation = qml;
+
+ lookups = function->function->lookups;
+
+ locals = (Value *)(this + 1);
+ if (function->varCount)
+ std::fill(locals, locals + function->varCount, Value::undefinedValue());
+}
+
+
+bool ExecutionContext::deleteProperty(String *name)
+{
+ bool hasWith = false;
+ for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) {
+ if (ctx->type == Type_WithContext) {
+ hasWith = true;
+ WithContext *w = static_cast<WithContext *>(ctx);
+ if (w->withObject->__hasProperty__(name))
+ return w->withObject->deleteProperty(name);
+ } else if (ctx->type == Type_CatchContext) {
+ CatchContext *c = static_cast<CatchContext *>(ctx);
+ if (c->exceptionVarName->isEqualTo(name))
+ return false;
+ } else if (ctx->type >= Type_CallContext) {
+ CallContext *c = static_cast<CallContext *>(ctx);
+ FunctionObject *f = c->function;
+ if (f->needsActivation || hasWith) {
+ for (unsigned int i = 0; i < f->varCount; ++i)
+ if (f->varList[i]->isEqualTo(name))
+ return false;
+ for (int i = (int)f->formalParameterCount - 1; i >= 0; --i)
+ if (f->formalParameterList[i]->isEqualTo(name))
+ return false;
+ }
+ if (c->activation && c->activation->__hasProperty__(name))
+ return c->activation->deleteProperty(name);
+ } else if (ctx->type == Type_GlobalContext) {
+ GlobalContext *g = static_cast<GlobalContext *>(ctx);
+ if (g->global->__hasProperty__(name))
+ return g->global->deleteProperty(name);
+ }
+ }
+
+ if (strictMode)
+ throwSyntaxError(0);
+ return true;
+}
+
+bool CallContext::needsOwnArguments() const
+{
+ return function->needsActivation || argumentCount < function->formalParameterCount;
+}
+
+void ExecutionContext::mark()
+{
+ if (marked)
+ return;
+ marked = true;
+
+ if (type != Type_SimpleCallContext && outer)
+ outer->mark();
+
+ thisObject.mark();
+
+ if (type >= Type_SimpleCallContext) {
+ QV4::CallContext *c = static_cast<CallContext *>(this);
+ for (unsigned arg = 0, lastArg = c->argumentCount; arg < lastArg; ++arg)
+ c->arguments[arg].mark();
+ if (type >= Type_CallContext) {
+ for (unsigned local = 0, lastLocal = c->variableCount(); local < lastLocal; ++local)
+ c->locals[local].mark();
+ if (c->activation)
+ c->activation->mark();
+ c->function->mark();
+ }
+ } else if (type == Type_WithContext) {
+ WithContext *w = static_cast<WithContext *>(this);
+ w->withObject->mark();
+ } else if (type == Type_CatchContext) {
+ CatchContext *c = static_cast<CatchContext *>(this);
+ if (c->exceptionVarName)
+ c->exceptionVarName->mark();
+ c->exceptionValue.mark();
+ } else if (type == Type_GlobalContext) {
+ GlobalContext *g = static_cast<GlobalContext *>(this);
+ g->global->mark();
+ }
+}
+
+void ExecutionContext::setProperty(String *name, const Value& value)
+{
+ for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) {
+ if (ctx->type == Type_WithContext) {
+ Object *w = static_cast<WithContext *>(ctx)->withObject;
+ if (w->__hasProperty__(name)) {
+ w->put(name, value);
+ return;
+ }
+ } else if (ctx->type == Type_CatchContext && static_cast<CatchContext *>(ctx)->exceptionVarName->isEqualTo(name)) {
+ static_cast<CatchContext *>(ctx)->exceptionValue = value;
+ return;
+ } else {
+ Object *activation = 0;
+ if (ctx->type >= Type_CallContext) {
+ CallContext *c = static_cast<CallContext *>(ctx);
+ for (unsigned int i = 0; i < c->function->varCount; ++i)
+ if (c->function->varList[i]->isEqualTo(name)) {
+ c->locals[i] = value;
+ return;
+ }
+ for (int i = (int)c->function->formalParameterCount - 1; i >= 0; --i)
+ if (c->function->formalParameterList[i]->isEqualTo(name)) {
+ c->arguments[i] = value;
+ return;
+ }
+ activation = c->activation;
+ } else if (ctx->type == Type_GlobalContext) {
+ activation = static_cast<GlobalContext *>(ctx)->global;
+ }
+
+ if (activation && (ctx->type == Type_QmlContext || activation->__hasProperty__(name))) {
+ activation->put(name, value);
+ return;
+ }
+ }
+ }
+ if (strictMode || name->isEqualTo(engine->id_this))
+ throwReferenceError(Value::fromString(name));
+ engine->globalObject->put(name, value);
+}
+
+Value ExecutionContext::getProperty(String *name)
+{
+ name->makeIdentifier();
+
+ if (name->isEqualTo(engine->id_this))
+ return thisObject;
+
+ bool hasWith = false;
+ bool hasCatchScope = false;
+ for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) {
+ if (ctx->type == Type_WithContext) {
+ Object *w = static_cast<WithContext *>(ctx)->withObject;
+ hasWith = true;
+ bool hasProperty = false;
+ Value v = w->get(name, &hasProperty);
+ if (hasProperty) {
+ return v;
+ }
+ continue;
+ }
+
+ else if (ctx->type == Type_CatchContext) {
+ hasCatchScope = true;
+ CatchContext *c = static_cast<CatchContext *>(ctx);
+ if (c->exceptionVarName->isEqualTo(name))
+ return c->exceptionValue;
+ }
+
+ else if (ctx->type >= Type_CallContext) {
+ QV4::CallContext *c = static_cast<CallContext *>(ctx);
+ FunctionObject *f = c->function;
+ if (f->needsActivation || hasWith || hasCatchScope) {
+ for (unsigned int i = 0; i < f->varCount; ++i)
+ if (f->varList[i]->isEqualTo(name))
+ return c->locals[i];
+ for (int i = (int)f->formalParameterCount - 1; i >= 0; --i)
+ if (f->formalParameterList[i]->isEqualTo(name))
+ return c->arguments[i];
+ }
+ if (c->activation) {
+ bool hasProperty = false;
+ Value v = c->activation->get(name, &hasProperty);
+ if (hasProperty)
+ return v;
+ }
+ if (f->function && f->function->isNamedExpression
+ && name->isEqualTo(f->function->name))
+ return Value::fromObject(c->function);
+ }
+
+ else if (ctx->type == Type_GlobalContext) {
+ GlobalContext *g = static_cast<GlobalContext *>(ctx);
+ bool hasProperty = false;
+ Value v = g->global->get(name, &hasProperty);
+ if (hasProperty)
+ return v;
+ }
+ }
+ throwReferenceError(Value::fromString(name));
+ return Value::undefinedValue();
+}
+
+Value ExecutionContext::getPropertyNoThrow(String *name)
+{
+ name->makeIdentifier();
+
+ if (name->isEqualTo(engine->id_this))
+ return thisObject;
+
+ bool hasWith = false;
+ bool hasCatchScope = false;
+ for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) {
+ if (ctx->type == Type_WithContext) {
+ Object *w = static_cast<WithContext *>(ctx)->withObject;
+ hasWith = true;
+ bool hasProperty = false;
+ Value v = w->get(name, &hasProperty);
+ if (hasProperty) {
+ return v;
+ }
+ continue;
+ }
+
+ else if (ctx->type == Type_CatchContext) {
+ hasCatchScope = true;
+ CatchContext *c = static_cast<CatchContext *>(ctx);
+ if (c->exceptionVarName->isEqualTo(name))
+ return c->exceptionValue;
+ }
+
+ else if (ctx->type >= Type_CallContext) {
+ QV4::CallContext *c = static_cast<CallContext *>(ctx);
+ FunctionObject *f = c->function;
+ if (f->needsActivation || hasWith || hasCatchScope) {
+ for (unsigned int i = 0; i < f->varCount; ++i)
+ if (f->varList[i]->isEqualTo(name))
+ return c->locals[i];
+ for (int i = (int)f->formalParameterCount - 1; i >= 0; --i)
+ if (f->formalParameterList[i]->isEqualTo(name))
+ return c->arguments[i];
+ }
+ if (c->activation) {
+ bool hasProperty = false;
+ Value v = c->activation->get(name, &hasProperty);
+ if (hasProperty)
+ return v;
+ }
+ if (f->function && f->function->isNamedExpression
+ && name->isEqualTo(f->function->name))
+ return Value::fromObject(c->function);
+ }
+
+ else if (ctx->type == Type_GlobalContext) {
+ GlobalContext *g = static_cast<GlobalContext *>(ctx);
+ bool hasProperty = false;
+ Value v = g->global->get(name, &hasProperty);
+ if (hasProperty)
+ return v;
+ }
+ }
+ return Value::undefinedValue();
+}
+
+Value ExecutionContext::getPropertyAndBase(String *name, Object **base)
+{
+ *base = 0;
+ name->makeIdentifier();
+
+ if (name->isEqualTo(engine->id_this))
+ return thisObject;
+
+ bool hasWith = false;
+ bool hasCatchScope = false;
+ for (ExecutionContext *ctx = this; ctx; ctx = ctx->outer) {
+ if (ctx->type == Type_WithContext) {
+ Object *w = static_cast<WithContext *>(ctx)->withObject;
+ hasWith = true;
+ bool hasProperty = false;
+ Value v = w->get(name, &hasProperty);
+ if (hasProperty) {
+ *base = w;
+ return v;
+ }
+ continue;
+ }
+
+ else if (ctx->type == Type_CatchContext) {
+ hasCatchScope = true;
+ CatchContext *c = static_cast<CatchContext *>(ctx);
+ if (c->exceptionVarName->isEqualTo(name))
+ return c->exceptionValue;
+ }
+
+ else if (ctx->type >= Type_CallContext) {
+ QV4::CallContext *c = static_cast<CallContext *>(ctx);
+ FunctionObject *f = c->function;
+ if (f->needsActivation || hasWith || hasCatchScope) {
+ for (unsigned int i = 0; i < f->varCount; ++i)
+ if (f->varList[i]->isEqualTo(name))
+ return c->locals[i];
+ for (int i = (int)f->formalParameterCount - 1; i >= 0; --i)
+ if (f->formalParameterList[i]->isEqualTo(name))
+ return c->arguments[i];
+ }
+ if (c->activation) {
+ bool hasProperty = false;
+ Value v = c->activation->get(name, &hasProperty);
+ if (hasProperty) {
+ *base = c->activation;
+ return v;
+ }
+ }
+ if (f->function && f->function->isNamedExpression
+ && name->isEqualTo(f->function->name))
+ return Value::fromObject(c->function);
+ }
+
+ else if (ctx->type == Type_GlobalContext) {
+ GlobalContext *g = static_cast<GlobalContext *>(ctx);
+ bool hasProperty = false;
+ Value v = g->global->get(name, &hasProperty);
+ if (hasProperty)
+ return v;
+ }
+ }
+ throwReferenceError(Value::fromString(name));
+ return Value::undefinedValue();
+}
+
+
+
+void ExecutionContext::inplaceBitOp(String *name, const Value &value, BinOp op)
+{
+ Value lhs = getProperty(name);
+ Value result;
+ op(this, &result, lhs, value);
+ setProperty(name, result);
+}
+
+void ExecutionContext::throwError(const Value &value)
+{
+ __qmljs_throw(this, value);
+}
+
+void ExecutionContext::throwError(const QString &message)
+{
+ Value v = Value::fromString(this, message);
+ throwError(Value::fromObject(engine->newErrorObject(v)));
+}
+
+void ExecutionContext::throwSyntaxError(DiagnosticMessage *message)
+{
+ throwError(Value::fromObject(engine->newSyntaxErrorObject(this, message)));
+}
+
+void ExecutionContext::throwTypeError()
+{
+ throwError(Value::fromObject(engine->newTypeErrorObject(QStringLiteral("Type error"))));
+}
+
+void ExecutionContext::throwTypeError(const QString &message)
+{
+ throwError(Value::fromObject(engine->newTypeErrorObject(message)));
+}
+
+void ExecutionContext::throwUnimplemented(const QString &message)
+{
+ Value v = Value::fromString(this, QStringLiteral("Unimplemented ") + message);
+ throwError(Value::fromObject(engine->newErrorObject(v)));
+}
+
+void ExecutionContext::throwReferenceError(Value value)
+{
+ String *s = value.toString(this);
+ QString msg = s->toQString() + QStringLiteral(" is not defined");
+ throwError(Value::fromObject(engine->newReferenceErrorObject(msg)));
+}
+
+void ExecutionContext::throwReferenceError(Value value, const QString &fileName, int line)
+{
+ String *s = value.toString(this);
+ QString msg = s->toQString() + QStringLiteral(" is not defined");
+ throwError(Value::fromObject(engine->newReferenceErrorObject(msg, fileName, line)));
+}
+
+void ExecutionContext::throwRangeError(Value value)
+{
+ String *s = value.toString(this);
+ QString msg = s->toQString() + QStringLiteral(" out of range");
+ throwError(Value::fromObject(engine->newRangeErrorObject(msg)));
+}
+
+void ExecutionContext::throwURIError(Value msg)
+{
+ throwError(Value::fromObject(engine->newURIErrorObject(msg)));
+}
+
+
+void SimpleCallContext::initSimpleCallContext(ExecutionEngine *engine)
+{
+ initBaseContext(Type_SimpleCallContext, engine, engine->current);
+ function = 0;
+ arguments = 0;
+ argumentCount = 0;
+}
diff --git a/src/qml/qml/v4/qv4context_p.h b/src/qml/qml/v4/qv4context_p.h
new file mode 100644
index 0000000000..dfe02bdcc8
--- /dev/null
+++ b/src/qml/qml/v4/qv4context_p.h
@@ -0,0 +1,227 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QMLJS_ENVIRONMENT_H
+#define QMLJS_ENVIRONMENT_H
+
+#include "qv4global_p.h"
+#include "qv4runtime_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct Object;
+struct ExecutionEngine;
+struct DeclarativeEnvironment;
+struct Lookup;
+
+struct Q_QML_EXPORT DiagnosticMessage
+{
+ enum { Error, Warning };
+
+ QString fileName;
+ quint32 offset;
+ quint32 length;
+ quint32 startLine;
+ unsigned startColumn: 31;
+ unsigned type: 1;
+ QString message;
+ DiagnosticMessage *next;
+
+ DiagnosticMessage();
+ ~DiagnosticMessage();
+ String *buildFullMessage(ExecutionContext *ctx) const;
+};
+
+struct CallContext;
+
+struct Q_QML_EXPORT ExecutionContext
+{
+ enum Type {
+ Type_GlobalContext = 0x1,
+ Type_CatchContext = 0x2,
+ Type_WithContext = 0x3,
+ Type_SimpleCallContext = 0x4,
+ Type_CallContext = 0x5,
+ Type_QmlContext = 0x6
+ };
+
+ Type type;
+ bool strictMode;
+ bool marked;
+
+ Value thisObject;
+
+ ExecutionEngine *engine;
+ ExecutionContext *parent;
+ ExecutionContext *outer;
+ Lookup *lookups;
+ ExecutionContext *next; // used in the GC
+
+ struct EvalCode
+ {
+ Function *function;
+ EvalCode *next;
+ };
+ EvalCode *currentEvalCode;
+
+ const uchar **interpreterInstructionPointer;
+
+ void initBaseContext(Type type, ExecutionEngine *engine, ExecutionContext *parentContext)
+ {
+ this->type = type;
+ strictMode = false;
+ marked = false;
+ thisObject = Value::undefinedValue();
+ this->engine = engine;
+ parent = parentContext;
+ outer = 0;
+ lookups = 0;
+ currentEvalCode = 0;
+ interpreterInstructionPointer = 0;
+ }
+
+ String * const *formals() const;
+ unsigned int formalCount() const;
+ String * const *variables() const;
+ unsigned int variableCount() const;
+
+ void createMutableBinding(String *name, bool deletable);
+
+ void Q_NORETURN throwError(const Value &value);
+ void Q_NORETURN throwError(const QString &message);
+ void Q_NORETURN throwSyntaxError(DiagnosticMessage *message);
+ void Q_NORETURN throwTypeError();
+ void Q_NORETURN throwTypeError(const QString &message);
+ void Q_NORETURN throwReferenceError(Value value);
+ void Q_NORETURN throwReferenceError(Value value, const QString &fileName, int line);
+ void Q_NORETURN throwRangeError(Value value);
+ void Q_NORETURN throwURIError(Value msg);
+ void Q_NORETURN throwUnimplemented(const QString &message);
+
+ void setProperty(String *name, const Value &value);
+ Value getProperty(String *name);
+ Value getPropertyNoThrow(String *name);
+ Value getPropertyAndBase(String *name, Object **base);
+ void inplaceBitOp(String *name, const QV4::Value &value, BinOp op);
+ bool deleteProperty(String *name);
+
+ inline Value argument(unsigned int index = 0);
+
+ void mark();
+
+ inline CallContext *asCallContext();
+ inline const CallContext *asCallContext() const;
+};
+
+struct SimpleCallContext : public ExecutionContext
+{
+ void initSimpleCallContext(ExecutionEngine *engine);
+ FunctionObject *function;
+ Value *arguments;
+ unsigned int argumentCount;
+};
+
+struct CallContext : public SimpleCallContext
+{
+ void initCallContext(ExecutionContext *parentContext, FunctionObject *function, Value *args, int argc,
+ const Value &thisObject);
+ void initQmlContext(ExecutionContext *parentContext, Object *qml, QV4::FunctionObject *function);
+ bool needsOwnArguments() const;
+
+ Value *locals;
+ Object *activation;
+};
+
+struct GlobalContext : public ExecutionContext
+{
+ void initGlobalContext(ExecutionEngine *e);
+
+ Object *global;
+};
+
+struct CatchContext : public ExecutionContext
+{
+ void initCatchContext(ExecutionContext *p, String *exceptionVarName, const QV4::Value &exceptionValue);
+
+ String *exceptionVarName;
+ Value exceptionValue;
+};
+
+struct WithContext : public ExecutionContext
+{
+ Object *withObject;
+
+ void initWithContext(ExecutionContext *p, Object *with);
+};
+
+inline Value ExecutionContext::argument(unsigned int index)
+{
+ if (type >= Type_SimpleCallContext) {
+ CallContext *ctx = static_cast<CallContext *>(this);
+ if (index < ctx->argumentCount)
+ return ctx->arguments[index];
+ }
+ return Value::undefinedValue();
+}
+
+inline CallContext *ExecutionContext::asCallContext()
+{
+ return type >= Type_CallContext ? static_cast<CallContext *>(this) : 0;
+}
+
+inline const CallContext *ExecutionContext::asCallContext() const
+{
+ return type >= Type_CallContext ? static_cast<const CallContext *>(this) : 0;
+}
+
+/* Function *f, int argc */
+#define requiredMemoryForExecutionContect(f, argc) \
+ sizeof(CallContext) + sizeof(Value) * (f->varCount + qMax((uint)argc, f->formalParameterCount))
+#define requiredMemoryForQmlExecutionContect(f) \
+ sizeof(CallContext) + sizeof(Value) * (f->locals.size())
+#define stackContextSize (sizeof(CallContext) + 32*sizeof(Value))
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v4/qv4dateobject.cpp b/src/qml/qml/v4/qv4dateobject.cpp
new file mode 100644
index 0000000000..3cf6cb1aeb
--- /dev/null
+++ b/src/qml/qml/v4/qv4dateobject.cpp
@@ -0,0 +1,1316 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qv4dateobject_p.h"
+#include "qv4objectproto_p.h"
+#include "qv4mm_p.h"
+#include <QtCore/qnumeric.h>
+#include <QtCore/qmath.h>
+#include <QtCore/QDateTime>
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+#include <cmath>
+#include <qmath.h>
+#include <qnumeric.h>
+#include <cassert>
+#include <time.h>
+
+#include <private/qqmljsengine_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljsast_p.h>
+#include <qv4jsir_p.h>
+#include <qv4codegen_p.h>
+#include <qv4isel_masm_p.h>
+
+#include <wtf/MathExtras.h>
+
+#ifdef Q_OS_WIN
+# include <windows.h>
+#else
+# ifndef Q_OS_VXWORKS
+# include <sys/time.h>
+# else
+# include "qplatformdefs.h"
+# endif
+#endif
+
+using namespace QV4;
+
+static const double HoursPerDay = 24.0;
+static const double MinutesPerHour = 60.0;
+static const double SecondsPerMinute = 60.0;
+static const double msPerSecond = 1000.0;
+static const double msPerMinute = 60000.0;
+static const double msPerHour = 3600000.0;
+static const double msPerDay = 86400000.0;
+
+static double LocalTZA = 0.0; // initialized at startup
+
+static inline double TimeWithinDay(double t)
+{
+ double r = ::fmod(t, msPerDay);
+ return (r >= 0) ? r : r + msPerDay;
+}
+
+static inline int HourFromTime(double t)
+{
+ int r = int(::fmod(::floor(t / msPerHour), HoursPerDay));
+ return (r >= 0) ? r : r + int(HoursPerDay);
+}
+
+static inline int MinFromTime(double t)
+{
+ int r = int(::fmod(::floor(t / msPerMinute), MinutesPerHour));
+ return (r >= 0) ? r : r + int(MinutesPerHour);
+}
+
+static inline int SecFromTime(double t)
+{
+ int r = int(::fmod(::floor(t / msPerSecond), SecondsPerMinute));
+ return (r >= 0) ? r : r + int(SecondsPerMinute);
+}
+
+static inline int msFromTime(double t)
+{
+ int r = int(::fmod(t, msPerSecond));
+ return (r >= 0) ? r : r + int(msPerSecond);
+}
+
+static inline double Day(double t)
+{
+ return ::floor(t / msPerDay);
+}
+
+static inline double DaysInYear(double y)
+{
+ if (::fmod(y, 4))
+ return 365;
+
+ else if (::fmod(y, 100))
+ return 366;
+
+ else if (::fmod(y, 400))
+ return 365;
+
+ return 366;
+}
+
+static inline double DayFromYear(double y)
+{
+ return 365 * (y - 1970)
+ + ::floor((y - 1969) / 4)
+ - ::floor((y - 1901) / 100)
+ + ::floor((y - 1601) / 400);
+}
+
+static inline double TimeFromYear(double y)
+{
+ return msPerDay * DayFromYear(y);
+}
+
+static inline double YearFromTime(double t)
+{
+ int y = 1970;
+ y += (int) ::floor(t / (msPerDay * 365.2425));
+
+ double t2 = TimeFromYear(y);
+ return (t2 > t) ? y - 1 : ((t2 + msPerDay * DaysInYear(y)) <= t) ? y + 1 : y;
+}
+
+static inline bool InLeapYear(double t)
+{
+ double x = DaysInYear(YearFromTime(t));
+ if (x == 365)
+ return 0;
+
+ assert(x == 366);
+ return 1;
+}
+
+static inline double DayWithinYear(double t)
+{
+ return Day(t) - DayFromYear(YearFromTime(t));
+}
+
+static inline double MonthFromTime(double t)
+{
+ double d = DayWithinYear(t);
+ double l = InLeapYear(t);
+
+ if (d < 31.0)
+ return 0;
+
+ else if (d < 59.0 + l)
+ return 1;
+
+ else if (d < 90.0 + l)
+ return 2;
+
+ else if (d < 120.0 + l)
+ return 3;
+
+ else if (d < 151.0 + l)
+ return 4;
+
+ else if (d < 181.0 + l)
+ return 5;
+
+ else if (d < 212.0 + l)
+ return 6;
+
+ else if (d < 243.0 + l)
+ return 7;
+
+ else if (d < 273.0 + l)
+ return 8;
+
+ else if (d < 304.0 + l)
+ return 9;
+
+ else if (d < 334.0 + l)
+ return 10;
+
+ else if (d < 365.0 + l)
+ return 11;
+
+ return qSNaN(); // ### assert?
+}
+
+static inline double DateFromTime(double t)
+{
+ int m = (int) Value::toInteger(MonthFromTime(t));
+ double d = DayWithinYear(t);
+ double l = InLeapYear(t);
+
+ switch (m) {
+ case 0: return d + 1.0;
+ case 1: return d - 30.0;
+ case 2: return d - 58.0 - l;
+ case 3: return d - 89.0 - l;
+ case 4: return d - 119.0 - l;
+ case 5: return d - 150.0 - l;
+ case 6: return d - 180.0 - l;
+ case 7: return d - 211.0 - l;
+ case 8: return d - 242.0 - l;
+ case 9: return d - 272.0 - l;
+ case 10: return d - 303.0 - l;
+ case 11: return d - 333.0 - l;
+ }
+
+ return qSNaN(); // ### assert
+}
+
+static inline double WeekDay(double t)
+{
+ double r = ::fmod (Day(t) + 4.0, 7.0);
+ return (r >= 0) ? r : r + 7.0;
+}
+
+
+static inline double MakeTime(double hour, double min, double sec, double ms)
+{
+ return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec) * msPerSecond + ms;
+}
+
+static inline double DayFromMonth(double month, double leap)
+{
+ switch ((int) month) {
+ case 0: return 0;
+ case 1: return 31.0;
+ case 2: return 59.0 + leap;
+ case 3: return 90.0 + leap;
+ case 4: return 120.0 + leap;
+ case 5: return 151.0 + leap;
+ case 6: return 181.0 + leap;
+ case 7: return 212.0 + leap;
+ case 8: return 243.0 + leap;
+ case 9: return 273.0 + leap;
+ case 10: return 304.0 + leap;
+ case 11: return 334.0 + leap;
+ }
+
+ return qSNaN(); // ### assert?
+}
+
+static double MakeDay(double year, double month, double day)
+{
+ year += ::floor(month / 12.0);
+
+ month = ::fmod(month, 12.0);
+ if (month < 0)
+ month += 12.0;
+
+ double d = DayFromYear(year);
+ bool leap = InLeapYear(d*msPerDay);
+
+ d += DayFromMonth(month, leap);
+ d += day - 1;
+
+ return d;
+}
+
+static inline double MakeDate(double day, double time)
+{
+ return day * msPerDay + time;
+}
+
+static inline double DaylightSavingTA(double t)
+{
+ struct tm tmtm;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ __time64_t tt = (__time64_t)(t / msPerSecond);
+ // _localtime_64_s returns non-zero on failure
+ if (_localtime64_s(&tmtm, &tt) != 0)
+#else
+ long int tt = (long int)(t / msPerSecond);
+ if (!localtime_r((const time_t*) &tt, &tmtm))
+#endif
+ return 0;
+ return (tmtm.tm_isdst > 0) ? msPerHour : 0;
+}
+
+static inline double LocalTime(double t)
+{
+ return t + LocalTZA + DaylightSavingTA(t);
+}
+
+static inline double UTC(double t)
+{
+ return t - LocalTZA - DaylightSavingTA(t - LocalTZA);
+}
+
+static inline double currentTime()
+{
+#ifndef Q_OS_WIN
+ struct timeval tv;
+
+ gettimeofday(&tv, 0);
+ return ::floor(tv.tv_sec * msPerSecond + (tv.tv_usec / 1000.0));
+#else
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+ FILETIME ft;
+ SystemTimeToFileTime(&st, &ft);
+ LARGE_INTEGER li;
+ li.LowPart = ft.dwLowDateTime;
+ li.HighPart = ft.dwHighDateTime;
+ return double(li.QuadPart - Q_INT64_C(116444736000000000)) / 10000.0;
+#endif
+}
+
+static inline double TimeClip(double t)
+{
+ if (! qIsFinite(t) || fabs(t) > 8.64e15)
+ return qSNaN();
+ return Value::toInteger(t);
+}
+
+static inline double ParseString(const QString &s)
+{
+ // first try the format defined in 15.9.1.15, only if that fails fall back to
+ // QDateTime for parsing
+
+ // the define string format is YYYY-MM-DDTHH:mm:ss.sssZ
+ // It can be date or time only, and the second and later components
+ // of both fields are optional
+ // and extended syntax for negative and large positive years exists: +/-YYYYYY
+
+ enum Format {
+ Year,
+ Month,
+ Day,
+ Hour,
+ Minute,
+ Second,
+ MilliSecond,
+ TimezoneHour,
+ TimezoneMinute,
+ Done
+ };
+
+ const QChar *ch = s.constData();
+ const QChar *end = ch + s.length();
+
+ uint format = Year;
+ int current = 0;
+ int currentSize = 0;
+ bool extendedYear = false;
+
+ int yearSign = 1;
+ int year = 0;
+ int month = 0;
+ int day = 1;
+ int hour = 0;
+ int minute = 0;
+ int second = 0;
+ int msec = 0;
+ int offsetSign = 1;
+ int offset = 0;
+
+ bool error = false;
+ if (*ch == '+' || *ch == '-') {
+ extendedYear = true;
+ if (*ch == '-')
+ yearSign = -1;
+ ++ch;
+ }
+ while (ch <= end) {
+ if (*ch >= '0' && *ch <= '9') {
+ current *= 10;
+ current += ch->unicode() - '0';
+ ++currentSize;
+ } else { // other char, delimits field
+ switch (format) {
+ case Year:
+ year = current;
+ if (extendedYear)
+ error = (currentSize != 6);
+ else
+ error = (currentSize != 4);
+ break;
+ case Month:
+ month = current - 1;
+ error = (currentSize != 2) || month > 11;
+ break;
+ case Day:
+ day = current;
+ error = (currentSize != 2) || day > 31;
+ break;
+ case Hour:
+ hour = current;
+ error = (currentSize != 2) || hour > 24;
+ break;
+ case Minute:
+ minute = current;
+ error = (currentSize != 2) || minute > 60;
+ break;
+ case Second:
+ second = current;
+ error = (currentSize != 2) || second > 60;
+ break;
+ case MilliSecond:
+ msec = current;
+ error = (currentSize != 3);
+ break;
+ case TimezoneHour:
+ offset = current*60;
+ error = (currentSize != 2) || offset > 23*60;
+ break;
+ case TimezoneMinute:
+ offset += current;
+ error = (currentSize != 2) || current >= 60;
+ break;
+ }
+ if (*ch == 'T') {
+ if (format >= Hour)
+ error = true;
+ format = Hour;
+ } else if (*ch == '-') {
+ if (format < Day)
+ ++format;
+ else if (format < Minute)
+ error = true;
+ else if (format >= TimezoneHour)
+ error = true;
+ else {
+ offsetSign = -1;
+ format = TimezoneHour;
+ }
+ } else if (*ch == ':') {
+ if (format != Hour && format != Minute && format != TimezoneHour)
+ error = true;
+ ++format;
+ } else if (*ch == '.') {
+ if (format != Second)
+ error = true;
+ ++format;
+ } else if (*ch == '+') {
+ if (format < Minute || format >= TimezoneHour)
+ error = true;
+ format = TimezoneHour;
+ } else if (*ch == 'Z' || *ch == 0) {
+ format = Done;
+ }
+ current = 0;
+ currentSize = 0;
+ }
+ if (error || format == Done)
+ break;
+ ++ch;
+ }
+
+ if (!error) {
+ double t = MakeDate(MakeDay(year * yearSign, month, day), MakeTime(hour, minute, second, msec));
+ t -= offset * offsetSign * 60 * 1000;
+ return t;
+ }
+
+ QDateTime dt = QDateTime::fromString(s, Qt::TextDate);
+ if (!dt.isValid())
+ dt = QDateTime::fromString(s, Qt::ISODate);
+ if (!dt.isValid()) {
+ QStringList formats;
+ formats << QStringLiteral("M/d/yyyy")
+ << QStringLiteral("M/d/yyyy hh:mm")
+ << QStringLiteral("M/d/yyyy hh:mm A")
+
+ << QStringLiteral("M/d/yyyy, hh:mm")
+ << QStringLiteral("M/d/yyyy, hh:mm A")
+
+ << QStringLiteral("MMM d yyyy")
+ << QStringLiteral("MMM d yyyy hh:mm")
+ << QStringLiteral("MMM d yyyy hh:mm:ss")
+ << QStringLiteral("MMM d yyyy, hh:mm")
+ << QStringLiteral("MMM d yyyy, hh:mm:ss")
+
+ << QStringLiteral("MMMM d yyyy")
+ << QStringLiteral("MMMM d yyyy hh:mm")
+ << QStringLiteral("MMMM d yyyy hh:mm:ss")
+ << QStringLiteral("MMMM d yyyy, hh:mm")
+ << QStringLiteral("MMMM d yyyy, hh:mm:ss")
+
+ << QStringLiteral("MMM d, yyyy")
+ << QStringLiteral("MMM d, yyyy hh:mm")
+ << QStringLiteral("MMM d, yyyy hh:mm:ss")
+
+ << QStringLiteral("MMMM d, yyyy")
+ << QStringLiteral("MMMM d, yyyy hh:mm")
+ << QStringLiteral("MMMM d, yyyy hh:mm:ss")
+
+ << QStringLiteral("d MMM yyyy")
+ << QStringLiteral("d MMM yyyy hh:mm")
+ << QStringLiteral("d MMM yyyy hh:mm:ss")
+ << QStringLiteral("d MMM yyyy, hh:mm")
+ << QStringLiteral("d MMM yyyy, hh:mm:ss")
+
+ << QStringLiteral("d MMMM yyyy")
+ << QStringLiteral("d MMMM yyyy hh:mm")
+ << QStringLiteral("d MMMM yyyy hh:mm:ss")
+ << QStringLiteral("d MMMM yyyy, hh:mm")
+ << QStringLiteral("d MMMM yyyy, hh:mm:ss")
+
+ << QStringLiteral("d MMM, yyyy")
+ << QStringLiteral("d MMM, yyyy hh:mm")
+ << QStringLiteral("d MMM, yyyy hh:mm:ss")
+
+ << QStringLiteral("d MMMM, yyyy")
+ << QStringLiteral("d MMMM, yyyy hh:mm")
+ << QStringLiteral("d MMMM, yyyy hh:mm:ss");
+
+ for (int i = 0; i < formats.size(); ++i) {
+ dt = QDateTime::fromString(s, formats.at(i));
+ if (dt.isValid())
+ break;
+ }
+ }
+ if (!dt.isValid())
+ return qSNaN();
+ return dt.toMSecsSinceEpoch();
+}
+
+/*!
+ \internal
+
+ Converts the ECMA Date value \tt (in UTC form) to QDateTime
+ according to \a spec.
+*/
+static inline QDateTime ToDateTime(double t, Qt::TimeSpec spec)
+{
+ if (std::isnan(t))
+ return QDateTime();
+ if (spec == Qt::LocalTime)
+ t = LocalTime(t);
+ int year = int(YearFromTime(t));
+ int month = int(MonthFromTime(t) + 1);
+ int day = int(DateFromTime(t));
+ int hours = HourFromTime(t);
+ int mins = MinFromTime(t);
+ int secs = SecFromTime(t);
+ int ms = msFromTime(t);
+ return QDateTime(QDate(year, month, day), QTime(hours, mins, secs, ms), spec);
+}
+
+static inline QString ToString(double t)
+{
+ if (std::isnan(t))
+ return QStringLiteral("Invalid Date");
+ QString str = ToDateTime(t, Qt::LocalTime).toString() + QStringLiteral(" GMT");
+ double tzoffset = LocalTZA + DaylightSavingTA(t);
+ if (tzoffset) {
+ int hours = static_cast<int>(::fabs(tzoffset) / 1000 / 60 / 60);
+ int mins = int(::fabs(tzoffset) / 1000 / 60) % 60;
+ str.append(QLatin1Char((tzoffset > 0) ? '+' : '-'));
+ if (hours < 10)
+ str.append(QLatin1Char('0'));
+ str.append(QString::number(hours));
+ if (mins < 10)
+ str.append(QLatin1Char('0'));
+ str.append(QString::number(mins));
+ }
+ return str;
+}
+
+static inline QString ToUTCString(double t)
+{
+ if (std::isnan(t))
+ return QStringLiteral("Invalid Date");
+ return ToDateTime(t, Qt::UTC).toString() + QStringLiteral(" GMT");
+}
+
+static inline QString ToDateString(double t)
+{
+ return ToDateTime(t, Qt::LocalTime).date().toString();
+}
+
+static inline QString ToTimeString(double t)
+{
+ return ToDateTime(t, Qt::LocalTime).time().toString();
+}
+
+static inline QString ToLocaleString(double t)
+{
+ return ToDateTime(t, Qt::LocalTime).toString(Qt::LocaleDate);
+}
+
+static inline QString ToLocaleDateString(double t)
+{
+ return ToDateTime(t, Qt::LocalTime).date().toString(Qt::LocaleDate);
+}
+
+static inline QString ToLocaleTimeString(double t)
+{
+ return ToDateTime(t, Qt::LocalTime).time().toString(Qt::LocaleDate);
+}
+
+static double getLocalTZA()
+{
+#ifndef Q_OS_WIN
+ struct tm t;
+ time_t curr;
+ time(&curr);
+ localtime_r(&curr, &t);
+ time_t locl = mktime(&t);
+ gmtime_r(&curr, &t);
+ time_t globl = mktime(&t);
+ return double(locl - globl) * 1000.0;
+#else
+ TIME_ZONE_INFORMATION tzInfo;
+ GetTimeZoneInformation(&tzInfo);
+ return -tzInfo.Bias * 60.0 * 1000.0;
+#endif
+}
+
+DateObject::DateObject(ExecutionEngine *engine, const QDateTime &date)
+ : Object(engine)
+{
+ type = Type_DateObject;
+ value = Value::fromDouble(date.toMSecsSinceEpoch());
+}
+
+QDateTime DateObject::toQDateTime() const
+{
+ return ToDateTime(value.asDouble(), Qt::LocalTime);
+}
+
+DEFINE_MANAGED_VTABLE(DateCtor);
+
+DateCtor::DateCtor(ExecutionContext *scope)
+ : FunctionObject(scope, scope->engine->newIdentifier(QStringLiteral("Date")))
+{
+ vtbl = &static_vtbl;
+}
+
+Value DateCtor::construct(Managed *m, Value *args, int argc)
+{
+ double t = 0;
+
+ if (argc == 0)
+ t = currentTime();
+
+ else if (argc == 1) {
+ Value arg = args[0];
+ if (DateObject *d = arg.asDateObject())
+ arg = d->value;
+ else
+ arg = __qmljs_to_primitive(arg, PREFERREDTYPE_HINT);
+
+ if (arg.isString())
+ t = ParseString(arg.stringValue()->toQString());
+ else
+ t = TimeClip(arg.toNumber());
+ }
+
+ else { // argc > 1
+ double year = args[0].toNumber();
+ double month = args[1].toNumber();
+ double day = argc >= 3 ? args[2].toNumber() : 1;
+ double hours = argc >= 4 ? args[3].toNumber() : 0;
+ double mins = argc >= 5 ? args[4].toNumber() : 0;
+ double secs = argc >= 6 ? args[5].toNumber() : 0;
+ double ms = argc >= 7 ? args[6].toNumber() : 0;
+ if (year >= 0 && year <= 99)
+ year += 1900;
+ t = MakeDate(MakeDay(year, month, day), MakeTime(hours, mins, secs, ms));
+ t = TimeClip(UTC(t));
+ }
+
+ Object *d = m->engine()->newDateObject(Value::fromDouble(t));
+ return Value::fromObject(d);
+}
+
+Value DateCtor::call(Managed *m, const Value &, Value *, int)
+{
+ double t = currentTime();
+ return Value::fromString(m->engine()->current, ToString(t));
+}
+
+void DatePrototype::init(ExecutionContext *ctx, const Value &ctor)
+{
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this));
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(7));
+ LocalTZA = getLocalTZA();
+
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("parse"), method_parse, 1);
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("UTC"), method_UTC, 7);
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("now"), method_now, 0);
+
+ defineDefaultProperty(ctx, QStringLiteral("constructor"), ctor);
+ defineDefaultProperty(ctx, QStringLiteral("toString"), method_toString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("toDateString"), method_toDateString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("toTimeString"), method_toTimeString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("toLocaleString"), method_toLocaleString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("toLocaleDateString"), method_toLocaleDateString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("toLocaleTimeString"), method_toLocaleTimeString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("valueOf"), method_valueOf, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getTime"), method_getTime, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getYear"), method_getYear, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getFullYear"), method_getFullYear, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getUTCFullYear"), method_getUTCFullYear, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getMonth"), method_getMonth, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getUTCMonth"), method_getUTCMonth, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getDate"), method_getDate, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getUTCDate"), method_getUTCDate, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getDay"), method_getDay, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getUTCDay"), method_getUTCDay, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getHours"), method_getHours, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getUTCHours"), method_getUTCHours, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getMinutes"), method_getMinutes, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getUTCMinutes"), method_getUTCMinutes, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getSeconds"), method_getSeconds, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getUTCSeconds"), method_getUTCSeconds, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getMilliseconds"), method_getMilliseconds, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getUTCMilliseconds"), method_getUTCMilliseconds, 0);
+ defineDefaultProperty(ctx, QStringLiteral("getTimezoneOffset"), method_getTimezoneOffset, 0);
+ defineDefaultProperty(ctx, QStringLiteral("setTime"), method_setTime, 1);
+ defineDefaultProperty(ctx, QStringLiteral("setMilliseconds"), method_setMilliseconds, 1);
+ defineDefaultProperty(ctx, QStringLiteral("setUTCMilliseconds"), method_setUTCMilliseconds, 1);
+ defineDefaultProperty(ctx, QStringLiteral("setSeconds"), method_setSeconds, 2);
+ defineDefaultProperty(ctx, QStringLiteral("setUTCSeconds"), method_setUTCSeconds, 2);
+ defineDefaultProperty(ctx, QStringLiteral("setMinutes"), method_setMinutes, 3);
+ defineDefaultProperty(ctx, QStringLiteral("setUTCMinutes"), method_setUTCMinutes, 3);
+ defineDefaultProperty(ctx, QStringLiteral("setHours"), method_setHours, 4);
+ defineDefaultProperty(ctx, QStringLiteral("setUTCHours"), method_setUTCHours, 4);
+ defineDefaultProperty(ctx, QStringLiteral("setDate"), method_setDate, 1);
+ defineDefaultProperty(ctx, QStringLiteral("setUTCDate"), method_setUTCDate, 1);
+ defineDefaultProperty(ctx, QStringLiteral("setMonth"), method_setMonth, 2);
+ defineDefaultProperty(ctx, QStringLiteral("setUTCMonth"), method_setUTCMonth, 2);
+ defineDefaultProperty(ctx, QStringLiteral("setYear"), method_setYear, 1);
+ defineDefaultProperty(ctx, QStringLiteral("setFullYear"), method_setFullYear, 3);
+ defineDefaultProperty(ctx, QStringLiteral("setUTCFullYear"), method_setUTCFullYear, 3);
+ defineDefaultProperty(ctx, QStringLiteral("toUTCString"), method_toUTCString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("toGMTString"), method_toUTCString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("toISOString"), method_toISOString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("toJSON"), method_toJSON, 1);
+}
+
+double DatePrototype::getThisDate(ExecutionContext *ctx)
+{
+ if (DateObject *thisObject = ctx->thisObject.asDateObject())
+ return thisObject->value.asDouble();
+ else {
+ ctx->throwTypeError();
+ return 0;
+ }
+}
+
+Value DatePrototype::method_parse(SimpleCallContext *ctx)
+{
+ return Value::fromDouble(ParseString(ctx->argument(0).toString(ctx)->toQString()));
+}
+
+Value DatePrototype::method_UTC(SimpleCallContext *ctx)
+{
+ const int numArgs = ctx->argumentCount;
+ if (numArgs >= 2) {
+ double year = ctx->argument(0).toNumber();
+ double month = ctx->argument(1).toNumber();
+ double day = numArgs >= 3 ? ctx->argument(2).toNumber() : 1;
+ double hours = numArgs >= 4 ? ctx->argument(3).toNumber() : 0;
+ double mins = numArgs >= 5 ? ctx->argument(4).toNumber() : 0;
+ double secs = numArgs >= 6 ? ctx->argument(5).toNumber() : 0;
+ double ms = numArgs >= 7 ? ctx->argument(6).toNumber() : 0;
+ if (year >= 0 && year <= 99)
+ year += 1900;
+ double t = MakeDate(MakeDay(year, month, day),
+ MakeTime(hours, mins, secs, ms));
+ return Value::fromDouble(TimeClip(t));
+ }
+ return Value::undefinedValue();
+}
+
+Value DatePrototype::method_now(SimpleCallContext *ctx)
+{
+ Q_UNUSED(ctx);
+ double t = currentTime();
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_toString(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ return Value::fromString(ctx, ToString(t));
+}
+
+Value DatePrototype::method_toDateString(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ return Value::fromString(ctx, ToDateString(t));
+}
+
+Value DatePrototype::method_toTimeString(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ return Value::fromString(ctx, ToTimeString(t));
+}
+
+Value DatePrototype::method_toLocaleString(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ return Value::fromString(ctx, ToLocaleString(t));
+}
+
+Value DatePrototype::method_toLocaleDateString(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ return Value::fromString(ctx, ToLocaleDateString(t));
+}
+
+Value DatePrototype::method_toLocaleTimeString(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ return Value::fromString(ctx, ToLocaleTimeString(t));
+}
+
+Value DatePrototype::method_valueOf(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getTime(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getYear(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = YearFromTime(LocalTime(t)) - 1900;
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getFullYear(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = YearFromTime(LocalTime(t));
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getUTCFullYear(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = YearFromTime(t);
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getMonth(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = MonthFromTime(LocalTime(t));
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getUTCMonth(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = MonthFromTime(t);
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getDate(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = DateFromTime(LocalTime(t));
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getUTCDate(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = DateFromTime(t);
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getDay(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = WeekDay(LocalTime(t));
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getUTCDay(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = WeekDay(t);
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getHours(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = HourFromTime(LocalTime(t));
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getUTCHours(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = HourFromTime(t);
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getMinutes(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = MinFromTime(LocalTime(t));
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getUTCMinutes(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = MinFromTime(t);
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getSeconds(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = SecFromTime(LocalTime(t));
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getUTCSeconds(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = SecFromTime(t);
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getMilliseconds(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = msFromTime(LocalTime(t));
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getUTCMilliseconds(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = msFromTime(t);
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_getTimezoneOffset(SimpleCallContext *ctx)
+{
+ double t = getThisDate(ctx);
+ if (! std::isnan(t))
+ t = (t - LocalTime(t)) / msPerMinute;
+ return Value::fromDouble(t);
+}
+
+Value DatePrototype::method_setTime(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ self->value.setDouble(TimeClip(ctx->argument(0).toNumber()));
+ return self->value;
+}
+
+Value DatePrototype::method_setMilliseconds(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = LocalTime(self->value.asDouble());
+ double ms = ctx->argument(0).toNumber();
+ self->value.setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
+ return self->value;
+}
+
+Value DatePrototype::method_setUTCMilliseconds(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = self->value.asDouble();
+ double ms = ctx->argument(0).toNumber();
+ self->value.setDouble(TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms)))));
+ return self->value;
+}
+
+Value DatePrototype::method_setSeconds(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = LocalTime(self->value.asDouble());
+ double sec = ctx->argument(0).toNumber();
+ double ms = (ctx->argumentCount < 2) ? msFromTime(t) : ctx->argument(1).toNumber();
+ t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
+ self->value.setDouble(t);
+ return self->value;
+}
+
+Value DatePrototype::method_setUTCSeconds(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = self->value.asDouble();
+ double sec = ctx->argument(0).toNumber();
+ double ms = (ctx->argumentCount < 2) ? msFromTime(t) : ctx->argument(1).toNumber();
+ t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), sec, ms))));
+ self->value.setDouble(t);
+ return self->value;
+}
+
+Value DatePrototype::method_setMinutes(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = LocalTime(self->value.asDouble());
+ double min = ctx->argument(0).toNumber();
+ double sec = (ctx->argumentCount < 2) ? SecFromTime(t) : ctx->argument(1).toNumber();
+ double ms = (ctx->argumentCount < 3) ? msFromTime(t) : ctx->argument(2).toNumber();
+ t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
+ self->value.setDouble(t);
+ return self->value;
+}
+
+Value DatePrototype::method_setUTCMinutes(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = self->value.asDouble();
+ double min = ctx->argument(0).toNumber();
+ double sec = (ctx->argumentCount < 2) ? SecFromTime(t) : ctx->argument(1).toNumber();
+ double ms = (ctx->argumentCount < 3) ? msFromTime(t) : ctx->argument(2).toNumber();
+ t = TimeClip(UTC(MakeDate(Day(t), MakeTime(HourFromTime(t), min, sec, ms))));
+ self->value.setDouble(t);
+ return self->value;
+}
+
+Value DatePrototype::method_setHours(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = LocalTime(self->value.asDouble());
+ double hour = ctx->argument(0).toNumber();
+ double min = (ctx->argumentCount < 2) ? MinFromTime(t) : ctx->argument(1).toNumber();
+ double sec = (ctx->argumentCount < 3) ? SecFromTime(t) : ctx->argument(2).toNumber();
+ double ms = (ctx->argumentCount < 4) ? msFromTime(t) : ctx->argument(3).toNumber();
+ t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
+ self->value.setDouble(t);
+ return self->value;
+}
+
+Value DatePrototype::method_setUTCHours(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = self->value.asDouble();
+ double hour = ctx->argument(0).toNumber();
+ double min = (ctx->argumentCount < 2) ? MinFromTime(t) : ctx->argument(1).toNumber();
+ double sec = (ctx->argumentCount < 3) ? SecFromTime(t) : ctx->argument(2).toNumber();
+ double ms = (ctx->argumentCount < 4) ? msFromTime(t) : ctx->argument(3).toNumber();
+ t = TimeClip(UTC(MakeDate(Day(t), MakeTime(hour, min, sec, ms))));
+ self->value.setDouble(t);
+ return self->value;
+}
+
+Value DatePrototype::method_setDate(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = LocalTime(self->value.asDouble());
+ double date = ctx->argument(0).toNumber();
+ t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
+ self->value.setDouble(t);
+ return self->value;
+}
+
+Value DatePrototype::method_setUTCDate(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = self->value.asDouble();
+ double date = ctx->argument(0).toNumber();
+ t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t))));
+ self->value.setDouble(t);
+ return self->value;
+}
+
+Value DatePrototype::method_setMonth(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = LocalTime(self->value.asDouble());
+ double month = ctx->argument(0).toNumber();
+ double date = (ctx->argumentCount < 2) ? DateFromTime(t) : ctx->argument(1).toNumber();
+ t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
+ self->value.setDouble(t);
+ return self->value;
+}
+
+Value DatePrototype::method_setUTCMonth(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = self->value.asDouble();
+ double month = ctx->argument(0).toNumber();
+ double date = (ctx->argumentCount < 2) ? DateFromTime(t) : ctx->argument(1).toNumber();
+ t = TimeClip(UTC(MakeDate(MakeDay(YearFromTime(t), month, date), TimeWithinDay(t))));
+ self->value.setDouble(t);
+ return self->value;
+}
+
+Value DatePrototype::method_setYear(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = self->value.asDouble();
+ if (std::isnan(t))
+ t = 0;
+ else
+ t = LocalTime(t);
+ double year = ctx->argument(0).toNumber();
+ double r;
+ if (std::isnan(year)) {
+ r = qSNaN();
+ } else {
+ if ((Value::toInteger(year) >= 0) && (Value::toInteger(year) <= 99))
+ year += 1900;
+ r = MakeDay(year, MonthFromTime(t), DateFromTime(t));
+ r = UTC(MakeDate(r, TimeWithinDay(t)));
+ r = TimeClip(r);
+ }
+ self->value.setDouble(r);
+ return self->value;
+}
+
+Value DatePrototype::method_setUTCFullYear(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = self->value.asDouble();
+ double year = ctx->argument(0).toNumber();
+ double month = (ctx->argumentCount < 2) ? MonthFromTime(t) : ctx->argument(1).toNumber();
+ double date = (ctx->argumentCount < 3) ? DateFromTime(t) : ctx->argument(2).toNumber();
+ t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
+ self->value.setDouble(t);
+ return self->value;
+}
+
+Value DatePrototype::method_setFullYear(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = LocalTime(self->value.asDouble());
+ if (std::isnan(t))
+ t = 0;
+ double year = ctx->argument(0).toNumber();
+ double month = (ctx->argumentCount < 2) ? MonthFromTime(t) : ctx->argument(1).toNumber();
+ double date = (ctx->argumentCount < 3) ? DateFromTime(t) : ctx->argument(2).toNumber();
+ t = TimeClip(UTC(MakeDate(MakeDay(year, month, date), TimeWithinDay(t))));
+ self->value.setDouble(t);
+ return self->value;
+}
+
+Value DatePrototype::method_toUTCString(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = self->value.asDouble();
+ return Value::fromString(ctx, ToUTCString(t));
+}
+
+static void addZeroPrefixedInt(QString &str, int num, int nDigits)
+{
+ str.resize(str.size() + nDigits);
+
+ QChar *c = str.data() + str.size() - 1;
+ while (nDigits) {
+ *c = QChar(num % 10 + '0');
+ num /= 10;
+ --c;
+ --nDigits;
+ }
+}
+
+Value DatePrototype::method_toISOString(SimpleCallContext *ctx)
+{
+ DateObject *self = ctx->thisObject.asDateObject();
+ if (!self)
+ ctx->throwTypeError();
+
+ double t = self->value.asDouble();
+ if (!std::isfinite(t))
+ ctx->throwRangeError(ctx->thisObject);
+
+ QString result;
+ int year = (int)YearFromTime(t);
+ if (year < 0 || year > 9999) {
+ if (qAbs(year) >= 1000000)
+ return Value::fromString(ctx, QStringLiteral("Invalid Date"));
+ result += year < 0 ? '-' : '+';
+ year = qAbs(year);
+ addZeroPrefixedInt(result, year, 6);
+ } else {
+ addZeroPrefixedInt(result, year, 4);
+ }
+ result += '-';
+ addZeroPrefixedInt(result, (int)MonthFromTime(t) + 1, 2);
+ result += '-';
+ addZeroPrefixedInt(result, (int)DateFromTime(t), 2);
+ result += 'T';
+ addZeroPrefixedInt(result, HourFromTime(t), 2);
+ result += ':';
+ addZeroPrefixedInt(result, MinFromTime(t), 2);
+ result += ':';
+ addZeroPrefixedInt(result, SecFromTime(t), 2);
+ result += '.';
+ addZeroPrefixedInt(result, msFromTime(t), 3);
+ result += 'Z';
+
+ return Value::fromString(ctx, result);
+}
+
+Value DatePrototype::method_toJSON(SimpleCallContext *ctx)
+{
+ Value O = __qmljs_to_object(ctx, ctx->thisObject);
+ Value tv = __qmljs_to_primitive(O, NUMBER_HINT);
+
+ if (tv.isNumber() && !std::isfinite(tv.toNumber()))
+ return Value::nullValue();
+
+ FunctionObject *toIso = O.objectValue()->get(ctx->engine->newString(QStringLiteral("toISOString"))).asFunctionObject();
+
+ if (!toIso)
+ ctx->throwTypeError();
+
+ return toIso->call(ctx->thisObject, 0, 0);
+}
+
+void DatePrototype::timezoneUpdated()
+{
+ LocalTZA = getLocalTZA();
+}
diff --git a/src/qml/qml/v4/qv4dateobject_p.h b/src/qml/qml/v4/qv4dateobject_p.h
new file mode 100644
index 0000000000..4e833e143f
--- /dev/null
+++ b/src/qml/qml/v4/qv4dateobject_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4DATEOBJECT_P_H
+#define QV4DATEOBJECT_P_H
+
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+#include <QtCore/qnumeric.h>
+
+QT_BEGIN_NAMESPACE
+
+class QDateTime;
+
+namespace QV4 {
+
+struct DateObject: Object {
+ Value value;
+ DateObject(ExecutionEngine *engine, const Value &value): Object(engine), value(value) { type = Type_DateObject; }
+ DateObject(ExecutionEngine *engine, const QDateTime &value);
+
+ QDateTime toQDateTime() const;
+};
+
+struct DateCtor: FunctionObject
+{
+ DateCtor(ExecutionContext *scope);
+
+ static Value construct(Managed *, Value *args, int argc);
+ static Value call(Managed *that, const Value &, Value *, int);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct DatePrototype: DateObject
+{
+ DatePrototype(ExecutionEngine *engine): DateObject(engine, Value::fromDouble(qSNaN())) {}
+ void init(ExecutionContext *ctx, const Value &ctor);
+
+ static double getThisDate(ExecutionContext *ctx);
+
+ static Value method_parse(SimpleCallContext *ctx);
+ static Value method_UTC(SimpleCallContext *ctx);
+ static Value method_now(SimpleCallContext *ctx);
+
+ static Value method_toString(SimpleCallContext *ctx);
+ static Value method_toDateString(SimpleCallContext *ctx);
+ static Value method_toTimeString(SimpleCallContext *ctx);
+ static Value method_toLocaleString(SimpleCallContext *ctx);
+ static Value method_toLocaleDateString(SimpleCallContext *ctx);
+ static Value method_toLocaleTimeString(SimpleCallContext *ctx);
+ static Value method_valueOf(SimpleCallContext *ctx);
+ static Value method_getTime(SimpleCallContext *ctx);
+ static Value method_getYear(SimpleCallContext *ctx);
+ static Value method_getFullYear(SimpleCallContext *ctx);
+ static Value method_getUTCFullYear(SimpleCallContext *ctx);
+ static Value method_getMonth(SimpleCallContext *ctx);
+ static Value method_getUTCMonth(SimpleCallContext *ctx);
+ static Value method_getDate(SimpleCallContext *ctx);
+ static Value method_getUTCDate(SimpleCallContext *ctx);
+ static Value method_getDay(SimpleCallContext *ctx);
+ static Value method_getUTCDay(SimpleCallContext *ctx);
+ static Value method_getHours(SimpleCallContext *ctx);
+ static Value method_getUTCHours(SimpleCallContext *ctx);
+ static Value method_getMinutes(SimpleCallContext *ctx);
+ static Value method_getUTCMinutes(SimpleCallContext *ctx);
+ static Value method_getSeconds(SimpleCallContext *ctx);
+ static Value method_getUTCSeconds(SimpleCallContext *ctx);
+ static Value method_getMilliseconds(SimpleCallContext *ctx);
+ static Value method_getUTCMilliseconds(SimpleCallContext *ctx);
+ static Value method_getTimezoneOffset(SimpleCallContext *ctx);
+ static Value method_setTime(SimpleCallContext *ctx);
+ static Value method_setMilliseconds(SimpleCallContext *ctx);
+ static Value method_setUTCMilliseconds(SimpleCallContext *ctx);
+ static Value method_setSeconds(SimpleCallContext *ctx);
+ static Value method_setUTCSeconds(SimpleCallContext *ctx);
+ static Value method_setMinutes(SimpleCallContext *ctx);
+ static Value method_setUTCMinutes(SimpleCallContext *ctx);
+ static Value method_setHours(SimpleCallContext *ctx);
+ static Value method_setUTCHours(SimpleCallContext *ctx);
+ static Value method_setDate(SimpleCallContext *ctx);
+ static Value method_setUTCDate(SimpleCallContext *ctx);
+ static Value method_setMonth(SimpleCallContext *ctx);
+ static Value method_setUTCMonth(SimpleCallContext *ctx);
+ static Value method_setYear(SimpleCallContext *ctx);
+ static Value method_setFullYear(SimpleCallContext *ctx);
+ static Value method_setUTCFullYear(SimpleCallContext *ctx);
+ static Value method_toUTCString(SimpleCallContext *ctx);
+ static Value method_toISOString(SimpleCallContext *ctx);
+ static Value method_toJSON(SimpleCallContext *ctx);
+
+ static void timezoneUpdated();
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4ECMAOBJECTS_P_H
diff --git a/src/qml/qml/v4/qv4debugging.cpp b/src/qml/qml/v4/qv4debugging.cpp
new file mode 100644
index 0000000000..624390d8f2
--- /dev/null
+++ b/src/qml/qml/v4/qv4debugging.cpp
@@ -0,0 +1,372 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4debugging_p.h"
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+#include "qv4function_p.h"
+#include "moth/qv4instr_moth_p.h"
+#include <iostream>
+
+using namespace QV4;
+using namespace QV4::Debugging;
+
+Debugger::Debugger(QV4::ExecutionEngine *engine)
+ : _engine(engine)
+ , m_agent(0)
+ , m_state(Running)
+ , m_pauseRequested(false)
+ , m_currentInstructionPointer(0)
+{
+ qMetaTypeId<Debugger*>();
+}
+
+Debugger::~Debugger()
+{
+ detachFromAgent();
+}
+
+void Debugger::attachToAgent(DebuggerAgent *agent)
+{
+ Q_ASSERT(!m_agent);
+ m_agent = agent;
+}
+
+void Debugger::detachFromAgent()
+{
+ DebuggerAgent *agent = 0;
+ {
+ QMutexLocker locker(&m_lock);
+ agent = m_agent;
+ m_agent = 0;
+ }
+ if (agent)
+ agent->removeDebugger(this);
+}
+
+void Debugger::pause()
+{
+ QMutexLocker locker(&m_lock);
+ if (m_state == Paused)
+ return;
+ m_pauseRequested = true;
+}
+
+void Debugger::resume()
+{
+ QMutexLocker locker(&m_lock);
+ Q_ASSERT(m_state == Paused);
+ m_runningCondition.wakeAll();
+}
+
+void Debugger::addBreakPoint(const QString &fileName, int lineNumber)
+{
+ QMutexLocker locker(&m_lock);
+ if (!m_pendingBreakPointsToRemove.remove(fileName, lineNumber))
+ m_pendingBreakPointsToAdd.add(fileName, lineNumber);
+ m_havePendingBreakPoints = !m_pendingBreakPointsToAdd.isEmpty() || !m_pendingBreakPointsToRemove.isEmpty();
+}
+
+void Debugger::removeBreakPoint(const QString &fileName, int lineNumber)
+{
+ QMutexLocker locker(&m_lock);
+ if (!m_pendingBreakPointsToAdd.remove(fileName, lineNumber))
+ m_pendingBreakPointsToRemove.add(fileName, lineNumber);
+ m_havePendingBreakPoints = !m_pendingBreakPointsToAdd.isEmpty() || !m_pendingBreakPointsToRemove.isEmpty();
+}
+
+Debugger::ExecutionState Debugger::currentExecutionState(const uchar *code) const
+{
+ if (!code)
+ code = m_currentInstructionPointer;
+ // ### Locking
+ ExecutionState state;
+
+ QV4::ExecutionContext *context = _engine->current;
+ QV4::Function *function = 0;
+ if (CallContext *callCtx = context->asCallContext())
+ function = callCtx->function->function;
+ else {
+ Q_ASSERT(context->type == QV4::ExecutionContext::Type_GlobalContext);
+ function = context->engine->globalCode;
+ }
+
+ state.function = function;
+ state.fileName = function->sourceFile;
+
+ qptrdiff relativeProgramCounter = code - function->codeData;
+ state.lineNumber = function->lineNumberForProgramCounter(relativeProgramCounter);
+
+ return state;
+}
+
+void Debugger::setPendingBreakpoints(Function *function)
+{
+ m_pendingBreakPointsToAddToFutureCode.applyToFunction(function, /*removeBreakPoints*/ false);
+}
+
+void Debugger::maybeBreakAtInstruction(const uchar *code, bool breakPointHit)
+{
+ QMutexLocker locker(&m_lock);
+ m_currentInstructionPointer = code;
+
+ // Do debugger internal work
+ if (m_havePendingBreakPoints) {
+
+ if (breakPointHit) {
+ ExecutionState state = currentExecutionState();
+ breakPointHit = !m_pendingBreakPointsToRemove.contains(state.fileName, state.lineNumber);
+ }
+
+ applyPendingBreakPoints();
+ }
+
+ // Serve debugging requests from the agent
+ if (m_pauseRequested) {
+ m_pauseRequested = false;
+ pauseAndWait();
+ } else if (breakPointHit)
+ pauseAndWait();
+
+ if (!m_pendingBreakPointsToAdd.isEmpty() || !m_pendingBreakPointsToRemove.isEmpty())
+ applyPendingBreakPoints();
+}
+
+void Debugger::aboutToThrow(const QV4::Value &value)
+{
+ qDebug() << "*** We are about to throw...";
+}
+
+void Debugger::pauseAndWait()
+{
+ m_state = Paused;
+ QMetaObject::invokeMethod(m_agent, "debuggerPaused", Qt::QueuedConnection, Q_ARG(QV4::Debugging::Debugger*, this));
+ m_runningCondition.wait(&m_lock);
+ m_state = Running;
+}
+
+void Debugger::applyPendingBreakPoints()
+{
+ foreach (Function *function, _engine->functions) {
+ m_pendingBreakPointsToAdd.applyToFunction(function, /*removeBreakPoints*/false);
+ m_pendingBreakPointsToRemove.applyToFunction(function, /*removeBreakPoints*/true);
+ }
+
+ for (BreakPoints::ConstIterator it = m_pendingBreakPointsToAdd.constBegin(),
+ end = m_pendingBreakPointsToAdd.constEnd(); it != end; ++it) {
+ foreach (int lineNumber, it.value())
+ m_pendingBreakPointsToAddToFutureCode.add(it.key(), lineNumber);
+ }
+
+ m_pendingBreakPointsToAdd.clear();
+ m_pendingBreakPointsToRemove.clear();
+ m_havePendingBreakPoints = false;
+}
+
+static void realDumpValue(QV4::Value v, QV4::ExecutionContext *ctx, std::string prefix)
+{
+ using namespace QV4;
+ using namespace std;
+ cout << prefix << "tag: " << hex << v.tag << dec << endl << prefix << "\t-> ";
+ switch (v.type()) {
+ case Value::Undefined_Type: cout << "Undefined" << endl; return;
+ case Value::Null_Type: cout << "Null" << endl; return;
+ case Value::Boolean_Type: cout << "Boolean"; break;
+ case Value::Integer_Type: cout << "Integer"; break;
+ case Value::Object_Type: cout << "Object"; break;
+ case Value::String_Type: cout << "String"; break;
+ default: cout << "UNKNOWN" << endl; return;
+ }
+ cout << endl;
+
+ if (v.isBoolean()) {
+ cout << prefix << "\t-> " << (v.booleanValue() ? "TRUE" : "FALSE") << endl;
+ return;
+ }
+
+ if (v.isInteger()) {
+ cout << prefix << "\t-> " << v.integerValue() << endl;
+ return;
+ }
+
+ if (v.isDouble()) {
+ cout << prefix << "\t-> " << v.doubleValue() << endl;
+ return;
+ }
+
+ if (v.isString()) {
+ // maybe check something on the Managed object?
+ cout << prefix << "\t-> @" << hex << v.stringValue() << endl;
+ cout << prefix << "\t-> \"" << qPrintable(v.stringValue()->toQString()) << "\"" << endl;
+ return;
+ }
+
+ Object *o = v.objectValue();
+ if (!o)
+ return;
+
+ cout << prefix << "\t-> @" << hex << o << endl;
+ cout << prefix << "object type: " << o->internalType() << endl << prefix << "\t-> ";
+ switch (o->internalType()) {
+ case QV4::Managed::Type_Invalid: cout << "Invalid"; break;
+ case QV4::Managed::Type_String: cout << "String"; break;
+ case QV4::Managed::Type_Object: cout << "Object"; break;
+ case QV4::Managed::Type_ArrayObject: cout << "ArrayObject"; break;
+ case QV4::Managed::Type_FunctionObject: cout << "FunctionObject"; break;
+ case QV4::Managed::Type_BooleanObject: cout << "BooleanObject"; break;
+ case QV4::Managed::Type_NumberObject: cout << "NumberObject"; break;
+ case QV4::Managed::Type_StringObject: cout << "StringObject"; break;
+ case QV4::Managed::Type_DateObject: cout << "DateObject"; break;
+ case QV4::Managed::Type_RegExpObject: cout << "RegExpObject"; break;
+ case QV4::Managed::Type_ErrorObject: cout << "ErrorObject"; break;
+ case QV4::Managed::Type_ArgumentsObject: cout << "ArgumentsObject"; break;
+ case QV4::Managed::Type_JSONObject: cout << "JSONObject"; break;
+ case QV4::Managed::Type_MathObject: cout << "MathObject"; break;
+ case QV4::Managed::Type_ForeachIteratorObject: cout << "ForeachIteratorObject"; break;
+ default: cout << "UNKNOWN" << endl; return;
+ }
+ cout << endl;
+
+ cout << prefix << "properties:" << endl;
+ ForEachIteratorObject it(ctx, o);
+ for (Value name = it.nextPropertyName(); !name.isNull(); name = it.nextPropertyName()) {
+ cout << prefix << "\t\"" << qPrintable(name.stringValue()->toQString()) << "\"" << endl;
+ PropertyAttributes attrs;
+ Property *d = o->__getOwnProperty__(name.stringValue(), &attrs);
+ Value pval = o->getValue(d, attrs);
+ cout << prefix << "\tvalue:" << endl;
+ realDumpValue(pval, ctx, prefix + "\t");
+ }
+}
+
+void dumpValue(QV4::Value v, QV4::ExecutionContext *ctx)
+{
+ realDumpValue(v, ctx, std::string(""));
+}
+
+
+void DebuggerAgent::addDebugger(Debugger *debugger)
+{
+ Q_ASSERT(!m_debuggers.contains(debugger));
+ m_debuggers << debugger;
+ debugger->attachToAgent(this);
+}
+
+void DebuggerAgent::removeDebugger(Debugger *debugger)
+{
+ m_debuggers.removeAll(debugger);
+ debugger->detachFromAgent();
+}
+
+void DebuggerAgent::pause(Debugger *debugger)
+{
+ debugger->pause();
+}
+
+void DebuggerAgent::addBreakPoint(Debugger *debugger, const QString &fileName, int lineNumber)
+{
+ debugger->addBreakPoint(fileName, lineNumber);
+}
+
+void DebuggerAgent::removeBreakPoint(Debugger *debugger, const QString &fileName, int lineNumber)
+{
+ debugger->removeBreakPoint(fileName, lineNumber);
+}
+
+DebuggerAgent::~DebuggerAgent()
+{
+ Q_ASSERT(m_debuggers.isEmpty());
+}
+
+void Debugger::BreakPoints::add(const QString &fileName, int lineNumber)
+{
+ QList<int> &lines = (*this)[fileName];
+ if (!lines.contains(lineNumber)) {
+ lines.append(lineNumber);
+ qSort(lines);
+ }
+}
+
+bool Debugger::BreakPoints::remove(const QString &fileName, int lineNumber)
+{
+ Iterator breakPoints = find(fileName);
+ if (breakPoints == constEnd())
+ return false;
+ return breakPoints->removeAll(lineNumber) > 0;
+}
+
+bool Debugger::BreakPoints::contains(const QString &fileName, int lineNumber) const
+{
+ ConstIterator breakPoints = find(fileName);
+ if (breakPoints == constEnd())
+ return false;
+ return breakPoints->contains(lineNumber);
+}
+
+void Debugger::BreakPoints::applyToFunction(Function *function, bool removeBreakPoints)
+{
+ Iterator breakPointsForFile = find(function->sourceFile);
+ if (breakPointsForFile == end())
+ return;
+
+ QList<int>::Iterator breakPoint = breakPointsForFile->begin();
+ while (breakPoint != breakPointsForFile->end()) {
+ bool breakPointFound = false;
+ for (QVector<LineNumberMapping>::ConstIterator mapping = function->lineNumberMappings.constBegin(),
+ end = function->lineNumberMappings.constEnd(); mapping != end; ++mapping) {
+ if (mapping->lineNumber == *breakPoint) {
+ uchar *codePtr = const_cast<uchar *>(function->codeData) + mapping->codeOffset;
+ QQmlJS::Moth::Instr *instruction = reinterpret_cast<QQmlJS::Moth::Instr*>(codePtr);
+ instruction->common.breakPoint = !removeBreakPoints;
+ // Continue setting the next break point.
+ breakPointFound = true;
+ break;
+ }
+ }
+ if (breakPointFound)
+ breakPoint = breakPointsForFile->erase(breakPoint);
+ else
+ ++breakPoint;
+ }
+
+ if (breakPointsForFile->isEmpty())
+ erase(breakPointsForFile);
+}
diff --git a/src/qml/qml/v4/qv4debugging_p.h b/src/qml/qml/v4/qv4debugging_p.h
new file mode 100644
index 0000000000..4a273be732
--- /dev/null
+++ b/src/qml/qml/v4/qv4debugging_p.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef DEBUGGING_H
+#define DEBUGGING_H
+
+#include "qv4global_p.h"
+#include "qv4engine_p.h"
+#include "qv4context_p.h"
+#include "qv4jsir_p.h"
+
+#include <QHash>
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct Function;
+
+namespace Debugging {
+
+class DebuggerAgent;
+
+class Q_QML_EXPORT Debugger
+{
+public:
+ enum State {
+ Running,
+ Paused
+ };
+
+ Debugger(ExecutionEngine *_engine);
+ ~Debugger();
+
+ void attachToAgent(DebuggerAgent *agent);
+ void detachFromAgent();
+
+ void pause();
+ void resume();
+
+ State state() const { return m_state; }
+
+ void addBreakPoint(const QString &fileName, int lineNumber);
+ void removeBreakPoint(const QString &fileName, int lineNumber);
+
+ struct ExecutionState
+ {
+ ExecutionState() : lineNumber(-1), function(0) {}
+ QString fileName;
+ int lineNumber;
+ Function *function;
+ };
+
+ ExecutionState currentExecutionState(const uchar *code = 0) const;
+
+ bool pauseAtNextOpportunity() const {
+ return m_pauseRequested || m_havePendingBreakPoints;
+ }
+ void setPendingBreakpoints(Function *function);
+
+public: // compile-time interface
+ void maybeBreakAtInstruction(const uchar *code, bool breakPointHit);
+
+public: // execution hooks
+ void aboutToThrow(const Value &value);
+
+private:
+ // requires lock to be held
+ void pauseAndWait();
+
+ void applyPendingBreakPoints();
+
+ struct BreakPoints : public QHash<QString, QList<int> >
+ {
+ void add(const QString &fileName, int lineNumber);
+ bool remove(const QString &fileName, int lineNumber);
+ bool contains(const QString &fileName, int lineNumber) const;
+ void applyToFunction(Function *function, bool removeBreakPoints);
+ };
+
+ QV4::ExecutionEngine *_engine;
+ DebuggerAgent *m_agent;
+ QMutex m_lock;
+ QWaitCondition m_runningCondition;
+ State m_state;
+ bool m_pauseRequested;
+ bool m_havePendingBreakPoints;
+ BreakPoints m_pendingBreakPointsToAdd;
+ BreakPoints m_pendingBreakPointsToAddToFutureCode;
+ BreakPoints m_pendingBreakPointsToRemove;
+ const uchar *m_currentInstructionPointer;
+};
+
+class Q_QML_EXPORT DebuggerAgent : public QObject
+{
+ Q_OBJECT
+public:
+ ~DebuggerAgent();
+
+ void addDebugger(Debugger *debugger);
+ void removeDebugger(Debugger *debugger);
+
+ void pause(Debugger *debugger);
+ void addBreakPoint(Debugger *debugger, const QString &fileName, int lineNumber);
+ void removeBreakPoint(Debugger *debugger, const QString &fileName, int lineNumber);
+
+ Q_INVOKABLE virtual void debuggerPaused(QV4::Debugging::Debugger *debugger) = 0;
+
+protected:
+ QList<Debugger *> m_debuggers;
+};
+
+} // namespace Debugging
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QV4::Debugging::Debugger*)
+
+#endif // DEBUGGING_H
diff --git a/src/qml/qml/v4/qv4engine.cpp b/src/qml/qml/v4/qv4engine.cpp
new file mode 100644
index 0000000000..0b7c850aa6
--- /dev/null
+++ b/src/qml/qml/v4/qv4engine.cpp
@@ -0,0 +1,837 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qv4engine_p.h>
+#include <qv4value_p.h>
+#include <qv4object_p.h>
+#include <qv4objectproto_p.h>
+#include <qv4arrayobject_p.h>
+#include <qv4booleanobject_p.h>
+#include <qv4globalobject_p.h>
+#include <qv4errorobject_p.h>
+#include <qv4functionobject_p.h>
+#include "qv4function_p.h"
+#include <qv4mathobject_p.h>
+#include <qv4numberobject_p.h>
+#include <qv4regexpobject_p.h>
+#include <qv4variantobject_p.h>
+#include <qv4runtime_p.h>
+#include "qv4mm_p.h"
+#include <qv4argumentsobject_p.h>
+#include <qv4dateobject_p.h>
+#include <qv4jsonobject_p.h>
+#include <qv4stringobject_p.h>
+#include <qv4identifiertable_p.h>
+#include <qv4unwindhelper_p.h>
+#include "qv4debugging_p.h"
+#include "qv4executableallocator_p.h"
+#include "qv4sequenceobject_p.h"
+#include "qv4qobjectwrapper_p.h"
+#include "qv4qmlextensions_p.h"
+#include "qv4stacktrace_p.h"
+
+#ifdef V4_ENABLE_JIT
+#include "qv4isel_masm_p.h"
+#endif // V4_ENABLE_JIT
+
+#include "qv4isel_moth_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1);
+
+ExecutionEngine::ExecutionEngine(QQmlJS::EvalISelFactory *factory)
+ : memoryManager(new QV4::MemoryManager)
+ , executableAllocator(new QV4::ExecutableAllocator)
+ , regExpAllocator(new QV4::ExecutableAllocator)
+ , bumperPointerAllocator(new WTF::BumpPointerAllocator)
+ , debugger(0)
+ , globalObject(0)
+ , globalCode(0)
+ , functionsNeedSort(false)
+ , m_engineId(engineSerial.fetchAndAddOrdered(1))
+ , regExpCache(0)
+ , m_multiplyWrappedQObjects(0)
+ , m_qmlExtensions(0)
+{
+ MemoryManager::GCBlocker gcBlocker(memoryManager);
+
+ if (!factory) {
+#ifdef V4_ENABLE_JIT
+ factory = new QQmlJS::MASM::ISelFactory;
+#else // !V4_ENABLE_JIT
+ factory = new QQmlJS::Moth::ISelFactory;
+#endif // V4_ENABLE_JIT
+ }
+ iselFactory.reset(factory);
+
+ memoryManager->setExecutionEngine(this);
+
+ identifierTable = new IdentifierTable(this);
+
+ emptyClass = new (classPool.allocate(sizeof(InternalClass))) InternalClass(this);
+
+ id_undefined = newIdentifier(QStringLiteral("undefined"));
+ id_null = newIdentifier(QStringLiteral("null"));
+ id_true = newIdentifier(QStringLiteral("true"));
+ id_false = newIdentifier(QStringLiteral("false"));
+ id_boolean = newIdentifier(QStringLiteral("boolean"));
+ id_number = newIdentifier(QStringLiteral("number"));
+ id_string = newIdentifier(QStringLiteral("string"));
+ id_object = newIdentifier(QStringLiteral("object"));
+ id_function = newIdentifier(QStringLiteral("function"));
+ id_length = newIdentifier(QStringLiteral("length"));
+ id_prototype = newIdentifier(QStringLiteral("prototype"));
+ id_constructor = newIdentifier(QStringLiteral("constructor"));
+ id_arguments = newIdentifier(QStringLiteral("arguments"));
+ id_caller = newIdentifier(QStringLiteral("caller"));
+ id_this = newIdentifier(QStringLiteral("this"));
+ id___proto__ = newIdentifier(QStringLiteral("__proto__"));
+ id_enumerable = newIdentifier(QStringLiteral("enumerable"));
+ id_configurable = newIdentifier(QStringLiteral("configurable"));
+ id_writable = newIdentifier(QStringLiteral("writable"));
+ id_value = newIdentifier(QStringLiteral("value"));
+ id_get = newIdentifier(QStringLiteral("get"));
+ id_set = newIdentifier(QStringLiteral("set"));
+ id_eval = newIdentifier(QStringLiteral("eval"));
+ id_uintMax = newIdentifier(QStringLiteral("4294967295"));
+ id_name = newIdentifier(QStringLiteral("name"));
+
+ arrayClass = emptyClass->addMember(id_length, Attr_NotConfigurable|Attr_NotEnumerable);
+ initRootContext();
+
+ objectPrototype = new (memoryManager) ObjectPrototype(this);
+ stringPrototype = new (memoryManager) StringPrototype(this);
+ numberPrototype = new (memoryManager) NumberPrototype(this);
+ booleanPrototype = new (memoryManager) BooleanPrototype(this);
+ arrayPrototype = new (memoryManager) ArrayPrototype(rootContext);
+ datePrototype = new (memoryManager) DatePrototype(this);
+ functionPrototype = new (memoryManager) FunctionPrototype(rootContext);
+ regExpPrototype = new (memoryManager) RegExpPrototype(this);
+ errorPrototype = new (memoryManager) ErrorPrototype(this);
+ evalErrorPrototype = new (memoryManager) EvalErrorPrototype(this);
+ rangeErrorPrototype = new (memoryManager) RangeErrorPrototype(this);
+ referenceErrorPrototype = new (memoryManager) ReferenceErrorPrototype(this);
+ syntaxErrorPrototype = new (memoryManager) SyntaxErrorPrototype(this);
+ typeErrorPrototype = new (memoryManager) TypeErrorPrototype(this);
+ uRIErrorPrototype = new (memoryManager) URIErrorPrototype(this);
+
+ variantPrototype = new (memoryManager) VariantPrototype(this);
+ sequencePrototype = new (memoryManager) SequencePrototype(this);
+
+ stringPrototype->prototype = objectPrototype;
+ numberPrototype->prototype = objectPrototype;
+ booleanPrototype->prototype = objectPrototype;
+ arrayPrototype->prototype = objectPrototype;
+ datePrototype->prototype = objectPrototype;
+ functionPrototype->prototype = objectPrototype;
+ regExpPrototype->prototype = objectPrototype;
+ errorPrototype->prototype = objectPrototype;
+ evalErrorPrototype->prototype = objectPrototype;
+ rangeErrorPrototype->prototype = objectPrototype;
+ referenceErrorPrototype->prototype = objectPrototype;
+ syntaxErrorPrototype->prototype = objectPrototype;
+ typeErrorPrototype->prototype = objectPrototype;
+ uRIErrorPrototype->prototype = objectPrototype;
+
+ objectCtor = Value::fromObject(new (memoryManager) ObjectCtor(rootContext));
+ stringCtor = Value::fromObject(new (memoryManager) StringCtor(rootContext));
+ numberCtor = Value::fromObject(new (memoryManager) NumberCtor(rootContext));
+ booleanCtor = Value::fromObject(new (memoryManager) BooleanCtor(rootContext));
+ arrayCtor = Value::fromObject(new (memoryManager) ArrayCtor(rootContext));
+ functionCtor = Value::fromObject(new (memoryManager) FunctionCtor(rootContext));
+ dateCtor = Value::fromObject(new (memoryManager) DateCtor(rootContext));
+ regExpCtor = Value::fromObject(new (memoryManager) RegExpCtor(rootContext));
+ errorCtor = Value::fromObject(new (memoryManager) ErrorCtor(rootContext));
+ evalErrorCtor = Value::fromObject(new (memoryManager) EvalErrorCtor(rootContext));
+ rangeErrorCtor = Value::fromObject(new (memoryManager) RangeErrorCtor(rootContext));
+ referenceErrorCtor = Value::fromObject(new (memoryManager) ReferenceErrorCtor(rootContext));
+ syntaxErrorCtor = Value::fromObject(new (memoryManager) SyntaxErrorCtor(rootContext));
+ typeErrorCtor = Value::fromObject(new (memoryManager) TypeErrorCtor(rootContext));
+ uRIErrorCtor = Value::fromObject(new (memoryManager) URIErrorCtor(rootContext));
+
+ objectCtor.objectValue()->prototype = functionPrototype;
+ stringCtor.objectValue()->prototype = functionPrototype;
+ numberCtor.objectValue()->prototype = functionPrototype;
+ booleanCtor.objectValue()->prototype = functionPrototype;
+ arrayCtor.objectValue()->prototype = functionPrototype;
+ functionCtor.objectValue()->prototype = functionPrototype;
+ dateCtor.objectValue()->prototype = functionPrototype;
+ regExpCtor.objectValue()->prototype = functionPrototype;
+ errorCtor.objectValue()->prototype = functionPrototype;
+ evalErrorCtor.objectValue()->prototype = functionPrototype;
+ rangeErrorCtor.objectValue()->prototype = functionPrototype;
+ referenceErrorCtor.objectValue()->prototype = functionPrototype;
+ syntaxErrorCtor.objectValue()->prototype = functionPrototype;
+ typeErrorCtor.objectValue()->prototype = functionPrototype;
+ uRIErrorCtor.objectValue()->prototype = functionPrototype;
+
+ objectPrototype->init(rootContext, objectCtor);
+ stringPrototype->init(this, stringCtor);
+ numberPrototype->init(rootContext, numberCtor);
+ booleanPrototype->init(rootContext, booleanCtor);
+ arrayPrototype->init(rootContext, arrayCtor);
+ datePrototype->init(rootContext, dateCtor);
+ functionPrototype->init(rootContext, functionCtor);
+ regExpPrototype->init(rootContext, regExpCtor);
+ errorPrototype->init(this, errorCtor);
+ evalErrorPrototype->init(this, evalErrorCtor);
+ rangeErrorPrototype->init(this, rangeErrorCtor);
+ referenceErrorPrototype->init(this, referenceErrorCtor);
+ syntaxErrorPrototype->init(this, syntaxErrorCtor);
+ typeErrorPrototype->init(this, typeErrorCtor);
+ uRIErrorPrototype->init(this, uRIErrorCtor);
+
+ variantPrototype->init(this);
+ sequencePrototype->init(this);
+
+ //
+ // set up the global object
+ //
+ globalObject = newObject(/*rootContext*/);
+ rootContext->global = globalObject;
+ rootContext->thisObject = Value::fromObject(globalObject);
+
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("Object"), objectCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("String"), stringCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("Number"), numberCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("Boolean"), booleanCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("Array"), arrayCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("Function"), functionCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("Date"), dateCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("RegExp"), regExpCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("Error"), errorCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("EvalError"), evalErrorCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("RangeError"), rangeErrorCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("ReferenceError"), referenceErrorCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("SyntaxError"), syntaxErrorCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("TypeError"), typeErrorCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("URIError"), uRIErrorCtor);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("Math"), Value::fromObject(new (memoryManager) MathObject(rootContext)));
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("JSON"), Value::fromObject(new (memoryManager) JsonObject(rootContext)));
+
+ globalObject->defineReadonlyProperty(this, QStringLiteral("undefined"), Value::undefinedValue());
+ globalObject->defineReadonlyProperty(this, QStringLiteral("NaN"), Value::fromDouble(std::numeric_limits<double>::quiet_NaN()));
+ globalObject->defineReadonlyProperty(this, QStringLiteral("Infinity"), Value::fromDouble(Q_INFINITY));
+
+ evalFunction = new (memoryManager) EvalFunction(rootContext);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("eval"), Value::fromObject(evalFunction));
+
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("parseFloat"), GlobalFunctions::method_parseFloat, 1);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("decodeURIComponent"), GlobalFunctions::method_decodeURIComponent, 1);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("encodeURI"), GlobalFunctions::method_encodeURI, 1);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("encodeURIComponent"), GlobalFunctions::method_encodeURIComponent, 1);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("escape"), GlobalFunctions::method_escape, 1);
+ globalObject->defineDefaultProperty(rootContext, QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1);
+}
+
+ExecutionEngine::~ExecutionEngine()
+{
+ delete debugger;
+ delete m_multiplyWrappedQObjects;
+ m_multiplyWrappedQObjects = 0;
+ delete memoryManager;
+ delete m_qmlExtensions;
+ emptyClass->destroy();
+ delete identifierTable;
+ delete bumperPointerAllocator;
+ delete regExpCache;
+ UnwindHelper::deregisterFunctions(functions);
+ qDeleteAll(functions);
+ delete regExpAllocator;
+ delete executableAllocator;
+}
+
+void ExecutionEngine::enableDebugger()
+{
+ Q_ASSERT(!debugger);
+ debugger = new Debugging::Debugger(this);
+ iselFactory.reset(new QQmlJS::Moth::ISelFactory);
+}
+
+void ExecutionEngine::initRootContext()
+{
+ rootContext = static_cast<GlobalContext *>(memoryManager->allocContext(sizeof(GlobalContext)));
+ current = rootContext;
+ current->parent = 0;
+ rootContext->initGlobalContext(this);
+}
+
+InternalClass *ExecutionEngine::newClass(const InternalClass &other)
+{
+ return new (classPool.allocate(sizeof(InternalClass))) InternalClass(other);
+}
+
+WithContext *ExecutionEngine::newWithContext(Object *with)
+{
+ WithContext *w = static_cast<WithContext *>(memoryManager->allocContext(sizeof(WithContext)));
+ ExecutionContext *p = current;
+ current = w;
+ w->initWithContext(p, with);
+ return w;
+}
+
+CatchContext *ExecutionEngine::newCatchContext(String *exceptionVarName, const Value &exceptionValue)
+{
+ CatchContext *c = static_cast<CatchContext *>(memoryManager->allocContext(sizeof(CatchContext)));
+ ExecutionContext *p = current;
+ current = c;
+ c->initCatchContext(p, exceptionVarName, exceptionValue);
+ return c;
+}
+
+CallContext *ExecutionEngine::newCallContext(FunctionObject *f, const Value &thisObject, Value *args, int argc)
+{
+ CallContext *c = static_cast<CallContext *>(memoryManager->allocContext(requiredMemoryForExecutionContect(f, argc)));
+ ExecutionContext *p = current;
+ current = c;
+ c->initCallContext(p, f, args, argc, thisObject);
+
+ return c;
+}
+
+CallContext *ExecutionEngine::newQmlContext(FunctionObject *f, Object *qml)
+{
+ CallContext *c = static_cast<CallContext *>(memoryManager->allocContext(requiredMemoryForExecutionContect(f, 0)));
+
+ ExecutionContext *p = current;
+ current = c;
+ c->initQmlContext(p, qml, f);
+
+ return c;
+}
+
+CallContext *ExecutionEngine::newCallContext(void *stackSpace, FunctionObject *f, const Value &thisObject, Value *args, int argc)
+{
+ CallContext *c;
+ uint memory = requiredMemoryForExecutionContect(f, argc);
+ if (f->needsActivation || memory > stackContextSize) {
+ c = static_cast<CallContext *>(memoryManager->allocContext(memory));
+ } else {
+ c = (CallContext *)stackSpace;
+#ifndef QT_NO_DEBUG
+ c->next = (CallContext *)0x1;
+#endif
+ }
+
+ ExecutionContext *p = current;
+ current = c;
+ c->initCallContext(p, f, args, argc, thisObject);
+
+ return c;
+}
+
+
+ExecutionContext *ExecutionEngine::pushGlobalContext()
+{
+ GlobalContext *g = static_cast<GlobalContext *>(memoryManager->allocContext(sizeof(GlobalContext)));
+ ExecutionContext *oldNext = g->next;
+ *g = *rootContext;
+ g->next = oldNext;
+ g->parent = current;
+ current = g;
+
+ return current;
+}
+
+Function *ExecutionEngine::newFunction(const QString &name)
+{
+ Function *f = new Function(newIdentifier(name));
+ functions.append(f);
+ functionsNeedSort = true;
+ return f;
+}
+
+FunctionObject *ExecutionEngine::newBuiltinFunction(ExecutionContext *scope, String *name, Value (*code)(SimpleCallContext *))
+{
+ BuiltinFunctionOld *f = new (memoryManager) BuiltinFunctionOld(scope, name, code);
+ return f;
+}
+
+FunctionObject *ExecutionEngine::newScriptFunction(ExecutionContext *scope, Function *function)
+{
+ assert(function);
+
+ ScriptFunction *f = new (memoryManager) ScriptFunction(scope, function);
+ return f;
+}
+
+BoundFunction *ExecutionEngine::newBoundFunction(ExecutionContext *scope, FunctionObject *target, Value boundThis, const QVector<Value> &boundArgs)
+{
+ assert(target);
+
+ BoundFunction *f = new (memoryManager) BoundFunction(scope, target, boundThis, boundArgs);
+ return f;
+}
+
+
+Object *ExecutionEngine::newObject()
+{
+ Object *object = new (memoryManager) Object(this);
+ object->prototype = objectPrototype;
+ return object;
+}
+
+Object *ExecutionEngine::newObject(InternalClass *internalClass)
+{
+ Object *object = new (memoryManager) Object(this, internalClass);
+ object->prototype = objectPrototype;
+ return object;
+}
+
+String *ExecutionEngine::newString(const QString &s)
+{
+ return new (memoryManager) String(this, s);
+}
+
+String *ExecutionEngine::newIdentifier(const QString &text)
+{
+ return identifierTable->insertString(text);
+}
+
+Object *ExecutionEngine::newStringObject(const Value &value)
+{
+ StringObject *object = new (memoryManager) StringObject(this, value);
+ object->prototype = stringPrototype;
+ return object;
+}
+
+Object *ExecutionEngine::newNumberObject(const Value &value)
+{
+ NumberObject *object = new (memoryManager) NumberObject(this, value);
+ object->prototype = numberPrototype;
+ return object;
+}
+
+Object *ExecutionEngine::newBooleanObject(const Value &value)
+{
+ Object *object = new (memoryManager) BooleanObject(this, value);
+ object->prototype = booleanPrototype;
+ return object;
+}
+
+ArrayObject *ExecutionEngine::newArrayObject(int count)
+{
+ ArrayObject *object = new (memoryManager) ArrayObject(this);
+ object->prototype = arrayPrototype;
+
+ if (count) {
+ if (count < 0x1000)
+ object->arrayReserve(count);
+ object->setArrayLengthUnchecked(count);
+ }
+ return object;
+}
+
+ArrayObject *ExecutionEngine::newArrayObject(const QStringList &list)
+{
+ ArrayObject *object = new (memoryManager) ArrayObject(this, list);
+ object->prototype = arrayPrototype;
+ return object;
+}
+
+DateObject *ExecutionEngine::newDateObject(const Value &value)
+{
+ DateObject *object = new (memoryManager) DateObject(this, value);
+ object->prototype = datePrototype;
+ return object;
+}
+
+DateObject *ExecutionEngine::newDateObject(const QDateTime &dt)
+{
+ DateObject *object = new (memoryManager) DateObject(this, dt);
+ object->prototype = datePrototype;
+ return object;
+}
+
+RegExpObject *ExecutionEngine::newRegExpObject(const QString &pattern, int flags)
+{
+ bool global = (flags & QQmlJS::V4IR::RegExp::RegExp_Global);
+ bool ignoreCase = false;
+ bool multiline = false;
+ if (flags & QQmlJS::V4IR::RegExp::RegExp_IgnoreCase)
+ ignoreCase = true;
+ if (flags & QQmlJS::V4IR::RegExp::RegExp_Multiline)
+ multiline = true;
+
+ return newRegExpObject(RegExp::create(this, pattern, ignoreCase, multiline), global);
+}
+
+RegExpObject *ExecutionEngine::newRegExpObject(RegExp* re, bool global)
+{
+ RegExpObject *object = new (memoryManager) RegExpObject(this, re, global);
+ object->prototype = regExpPrototype;
+ return object;
+}
+
+RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re)
+{
+ RegExpObject *object = new (memoryManager) RegExpObject(this, re);
+ object->prototype = regExpPrototype;
+ return object;
+}
+
+Object *ExecutionEngine::newErrorObject(const Value &value)
+{
+ ErrorObject *object = new (memoryManager) ErrorObject(this, value);
+ object->prototype = errorPrototype;
+ return object;
+}
+
+Object *ExecutionEngine::newSyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *message)
+{
+ return new (memoryManager) SyntaxErrorObject(ctx, message);
+}
+
+Object *ExecutionEngine::newSyntaxErrorObject(const QString &message)
+{
+ return new (memoryManager) SyntaxErrorObject(this, message);
+}
+
+
+Object *ExecutionEngine::newReferenceErrorObject(const QString &message)
+{
+ return new (memoryManager) ReferenceErrorObject(this, message);
+}
+
+Object *ExecutionEngine::newReferenceErrorObject(const QString &message, const QString &fileName, int lineNumber)
+{
+ return new (memoryManager) ReferenceErrorObject(this, message, fileName, lineNumber);
+}
+
+
+Object *ExecutionEngine::newTypeErrorObject(const QString &message)
+{
+ return new (memoryManager) TypeErrorObject(this, message);
+}
+
+Object *ExecutionEngine::newRangeErrorObject(const QString &message)
+{
+ return new (memoryManager) RangeErrorObject(this, message);
+}
+
+Object *ExecutionEngine::newURIErrorObject(Value message)
+{
+ return new (memoryManager) URIErrorObject(this, message);
+}
+
+Object *ExecutionEngine::newVariantObject(const QVariant &v)
+{
+ return new (memoryManager) VariantObject(this, v);
+}
+
+Object *ExecutionEngine::newForEachIteratorObject(ExecutionContext *ctx, Object *o)
+{
+ return new (memoryManager) ForEachIteratorObject(ctx, o);
+}
+
+Object *ExecutionEngine::qmlContextObject() const
+{
+ ExecutionContext *ctx = current;
+
+ if (ctx->type == QV4::ExecutionContext::Type_SimpleCallContext)
+ ctx = ctx->parent;
+
+ if (!ctx->outer)
+ return 0;
+
+ while (ctx->outer && ctx->outer->type != ExecutionContext::Type_GlobalContext)
+ ctx = ctx->outer;
+
+ assert(ctx);
+ if (ctx->type != ExecutionContext::Type_QmlContext)
+ return 0;
+
+ return static_cast<CallContext *>(ctx)->activation;
+}
+
+namespace {
+ struct LineNumberResolver {
+ const ExecutionEngine* engine;
+ QScopedPointer<QV4::NativeStackTrace> nativeTrace;
+
+ LineNumberResolver(const ExecutionEngine *engine)
+ : engine(engine)
+ {
+ }
+
+ void resolve(ExecutionEngine::StackFrame *frame, ExecutionContext *context, Function *function)
+ {
+ if (context->interpreterInstructionPointer) {
+ qptrdiff offset = *context->interpreterInstructionPointer - 1 - function->codeData;
+ frame->line = function->lineNumberForProgramCounter(offset);
+ } else {
+ if (!nativeTrace)
+ nativeTrace.reset(new QV4::NativeStackTrace(engine->current));
+
+ NativeFrame nativeFrame = nativeTrace->nextFrame();
+ if (nativeFrame.function == function)
+ frame->line = nativeFrame.line;
+ }
+ }
+ };
+}
+
+QVector<ExecutionEngine::StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
+{
+ LineNumberResolver lineNumbers(this);
+
+ QVector<StackFrame> stack;
+
+ QV4::ExecutionContext *c = current;
+ while (c && frameLimit) {
+ if (CallContext *callCtx = c->asCallContext()) {
+ StackFrame frame;
+ if (callCtx->function->function)
+ frame.source = callCtx->function->function->sourceFile;
+ frame.function = callCtx->function->name->toQString();
+ frame.line = -1;
+ frame.column = -1;
+
+ if (callCtx->function->function)
+ lineNumbers.resolve(&frame, callCtx, callCtx->function->function);
+
+ stack.append(frame);
+ --frameLimit;
+ }
+ c = c->parent;
+ }
+
+ if (frameLimit && globalCode) {
+ StackFrame frame;
+ frame.source = globalCode->sourceFile;
+ frame.function = globalCode->name->toQString();
+ frame.line = -1;
+ frame.column = -1;
+
+ lineNumbers.resolve(&frame, rootContext, globalCode);
+
+ stack.append(frame);
+ }
+ return stack;
+}
+
+ExecutionEngine::StackFrame ExecutionEngine::currentStackFrame() const
+{
+ StackFrame frame;
+ frame.line = -1;
+ frame.column = -1;
+
+ QVector<StackFrame> trace = stackTrace(/*limit*/ 1);
+ if (!trace.isEmpty())
+ frame = trace.first();
+
+ return frame;
+}
+
+QUrl ExecutionEngine::resolvedUrl(const QString &file)
+{
+ QUrl src(file);
+ if (!src.isRelative())
+ return src;
+
+ QUrl base;
+ QV4::ExecutionContext *c = current;
+ while (c) {
+ if (CallContext *callCtx = c->asCallContext()) {
+ if (callCtx->function->function)
+ base.setUrl(callCtx->function->function->sourceFile);
+ break;
+ }
+ c = c->parent;
+ }
+
+ if (base.isEmpty() && globalCode)
+ base.setUrl(globalCode->sourceFile);
+
+ if (base.isEmpty())
+ return src;
+
+ return base.resolved(src);
+}
+
+void ExecutionEngine::requireArgumentsAccessors(int n)
+{
+ if (n <= argumentsAccessors.size())
+ return;
+
+ uint oldSize = argumentsAccessors.size();
+ argumentsAccessors.resize(n);
+ for (int i = oldSize; i < n; ++i) {
+ FunctionObject *get = new (memoryManager) ArgumentsGetterFunction(rootContext, i);
+ get->prototype = functionPrototype;
+ FunctionObject *set = new (memoryManager) ArgumentsSetterFunction(rootContext, i);
+ set->prototype = functionPrototype;
+ Property pd = Property::fromAccessor(get, set);
+ argumentsAccessors[i] = pd;
+ }
+}
+
+void ExecutionEngine::markObjects()
+{
+ identifierTable->mark();
+
+ globalObject->mark();
+
+ if (globalCode)
+ globalCode->mark();
+
+ for (int i = 0; i < argumentsAccessors.size(); ++i) {
+ const Property &pd = argumentsAccessors.at(i);
+ if (FunctionObject *getter = pd.getter())
+ getter->mark();
+ if (FunctionObject *setter = pd.setter())
+ setter->mark();
+ }
+
+ ExecutionContext *c = current;
+ while (c) {
+ c->mark();
+ c = c->parent;
+ }
+
+ for (int i = 0; i < functions.size(); ++i)
+ functions.at(i)->mark();
+
+ id_length->mark();
+ id_prototype->mark();
+ id_constructor->mark();
+ id_arguments->mark();
+ id_caller->mark();
+ id_this->mark();
+ id___proto__->mark();
+ id_enumerable->mark();
+ id_configurable->mark();
+ id_writable->mark();
+ id_value->mark();
+ id_get->mark();
+ id_set->mark();
+ id_eval->mark();
+ id_uintMax->mark();
+ id_name->mark();
+
+ objectCtor.mark();
+ stringCtor.mark();
+ numberCtor.mark();
+ booleanCtor.mark();
+ arrayCtor.mark();
+ functionCtor.mark();
+ dateCtor.mark();
+ regExpCtor.mark();
+ errorCtor.mark();
+ evalErrorCtor.mark();
+ rangeErrorCtor.mark();
+ referenceErrorCtor.mark();
+ syntaxErrorCtor.mark();
+ typeErrorCtor.mark();
+ uRIErrorCtor.mark();
+
+ objectPrototype->mark();
+ stringPrototype->mark();
+ numberPrototype->mark();
+ booleanPrototype->mark();
+ arrayPrototype->mark();
+ functionPrototype->mark();
+ datePrototype->mark();
+ regExpPrototype->mark();
+ errorPrototype->mark();
+ evalErrorPrototype->mark();
+ rangeErrorPrototype->mark();
+ referenceErrorPrototype->mark();
+ syntaxErrorPrototype->mark();
+ typeErrorPrototype->mark();
+ uRIErrorPrototype->mark();
+
+ variantPrototype->mark();
+ sequencePrototype->mark();
+
+ if (m_qmlExtensions)
+ m_qmlExtensions->markObjects();
+}
+
+namespace {
+ bool functionSortHelper(Function *lhs, Function *rhs)
+ {
+ return reinterpret_cast<quintptr>(lhs->code) < reinterpret_cast<quintptr>(rhs->code);
+ }
+
+ struct FindHelper
+ {
+ bool operator()(Function *function, quintptr pc)
+ {
+ return reinterpret_cast<quintptr>(function->code) < pc
+ && (reinterpret_cast<quintptr>(function->code) + function->codeSize) < pc;
+ }
+
+ bool operator()(quintptr pc, Function *function)
+ {
+ return pc < reinterpret_cast<quintptr>(function->code);
+ }
+ };
+}
+
+Function *ExecutionEngine::functionForProgramCounter(quintptr pc) const
+{
+ if (functionsNeedSort) {
+ qSort(functions.begin(), functions.end(), functionSortHelper);
+ functionsNeedSort = false;
+ }
+
+ QVector<Function*>::ConstIterator it = qBinaryFind(functions.constBegin(), functions.constEnd(),
+ pc, FindHelper());
+ if (it != functions.constEnd())
+ return *it;
+ return 0;
+}
+
+QmlExtensions *ExecutionEngine::qmlExtensions()
+{
+ if (!m_qmlExtensions)
+ m_qmlExtensions = new QmlExtensions;
+ return m_qmlExtensions;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4engine_p.h b/src/qml/qml/v4/qv4engine_p.h
new file mode 100644
index 0000000000..20fbf03ae2
--- /dev/null
+++ b/src/qml/qml/v4/qv4engine_p.h
@@ -0,0 +1,332 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4ENGINE_H
+#define QV4ENGINE_H
+
+#include "qv4global_p.h"
+#include "qv4isel_p.h"
+#include "qv4util_p.h"
+#include "qv4context_p.h"
+#include "qv4property_p.h"
+#include <private/qintrusivelist_p.h>
+
+namespace WTF {
+class BumpPointerAllocator;
+}
+
+QT_BEGIN_NAMESPACE
+
+class QV8Engine;
+
+namespace QV4 {
+namespace Debugging {
+class Debugger;
+} // namespace Debugging
+}
+
+namespace QV4 {
+
+struct Function;
+struct Object;
+struct BooleanObject;
+struct NumberObject;
+struct StringObject;
+struct ArrayObject;
+struct DateObject;
+struct FunctionObject;
+struct BoundFunction;
+struct RegExpObject;
+struct ErrorObject;
+struct ArgumentsObject;
+struct ExecutionContext;
+struct ExecutionEngine;
+class MemoryManager;
+class UnwindHelper;
+class ExecutableAllocator;
+
+struct ObjectPrototype;
+struct StringPrototype;
+struct NumberPrototype;
+struct BooleanPrototype;
+struct ArrayPrototype;
+struct FunctionPrototype;
+struct DatePrototype;
+struct RegExpPrototype;
+struct ErrorPrototype;
+struct EvalErrorPrototype;
+struct RangeErrorPrototype;
+struct ReferenceErrorPrototype;
+struct SyntaxErrorPrototype;
+struct TypeErrorPrototype;
+struct URIErrorPrototype;
+struct VariantPrototype;
+struct SequencePrototype;
+struct EvalFunction;
+struct IdentifierTable;
+struct InternalClass;
+class MultiplyWrappedQObjectMap;
+class RegExp;
+class RegExpCache;
+struct QmlExtensions;
+
+struct Q_QML_EXPORT ExecutionEngine
+{
+ MemoryManager *memoryManager;
+ ExecutableAllocator *executableAllocator;
+ ExecutableAllocator *regExpAllocator;
+ QScopedPointer<QQmlJS::EvalISelFactory> iselFactory;
+
+ ExecutionContext *current;
+ GlobalContext *rootContext;
+
+ WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
+
+ IdentifierTable *identifierTable;
+
+ QV4::Debugging::Debugger *debugger;
+
+ Object *globalObject;
+
+ Function *globalCode;
+
+ QV8Engine *v8Engine;
+
+ Value objectCtor;
+ Value stringCtor;
+ Value numberCtor;
+ Value booleanCtor;
+ Value arrayCtor;
+ Value functionCtor;
+ Value dateCtor;
+ Value regExpCtor;
+ Value errorCtor;
+ Value evalErrorCtor;
+ Value rangeErrorCtor;
+ Value referenceErrorCtor;
+ Value syntaxErrorCtor;
+ Value typeErrorCtor;
+ Value uRIErrorCtor;
+
+ ObjectPrototype *objectPrototype;
+ StringPrototype *stringPrototype;
+ NumberPrototype *numberPrototype;
+ BooleanPrototype *booleanPrototype;
+ ArrayPrototype *arrayPrototype;
+ FunctionPrototype *functionPrototype;
+ DatePrototype *datePrototype;
+ RegExpPrototype *regExpPrototype;
+ ErrorPrototype *errorPrototype;
+ EvalErrorPrototype *evalErrorPrototype;
+ RangeErrorPrototype *rangeErrorPrototype;
+ ReferenceErrorPrototype *referenceErrorPrototype;
+ SyntaxErrorPrototype *syntaxErrorPrototype;
+ TypeErrorPrototype *typeErrorPrototype;
+ URIErrorPrototype *uRIErrorPrototype;
+
+ VariantPrototype *variantPrototype;
+ SequencePrototype *sequencePrototype;
+
+ QQmlJS::MemoryPool classPool;
+ InternalClass *emptyClass;
+ InternalClass *arrayClass;
+
+ EvalFunction *evalFunction;
+
+ QVector<Property> argumentsAccessors;
+
+ String *id_undefined;
+ String *id_null;
+ String *id_true;
+ String *id_false;
+ String *id_boolean;
+ String *id_number;
+ String *id_string;
+ String *id_object;
+ String *id_function;
+ String *id_length;
+ String *id_prototype;
+ String *id_constructor;
+ String *id_arguments;
+ String *id_caller;
+ String *id_this;
+ String *id___proto__;
+ String *id_enumerable;
+ String *id_configurable;
+ String *id_writable;
+ String *id_value;
+ String *id_get;
+ String *id_set;
+ String *id_eval;
+ String *id_uintMax;
+ String *id_name;
+
+ mutable QVector<Function *> functions;
+ mutable bool functionsNeedSort;
+
+ quint32 m_engineId;
+
+ RegExpCache *regExpCache;
+
+ // Scarce resources are "exceptionally high cost" QVariant types where allowing the
+ // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other
+ // out-of-resource situations. When such a resource is passed into JavaScript we
+ // add it to the scarceResources list and it is destroyed when we return from the
+ // JavaScript execution that created it. The user can prevent this behavior by
+ // calling preserve() on the object which removes it from this scarceResource list.
+ class ScarceResourceData {
+ public:
+ ScarceResourceData(const QVariant &data) : data(data) {}
+ QVariant data;
+ QIntrusiveListNode node;
+ };
+ QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources;
+
+ // Normally the JS wrappers for QObjects are stored in the QQmlData/QObjectPrivate,
+ // but any time a QObject is wrapped a second time in another engine, we have to do
+ // bookkeeping.
+ MultiplyWrappedQObjectMap *m_multiplyWrappedQObjects;
+
+ ExecutionEngine(QQmlJS::EvalISelFactory *iselFactory = 0);
+ ~ExecutionEngine();
+
+ void enableDebugger();
+
+ WithContext *newWithContext(Object *with);
+ CatchContext *newCatchContext(String* exceptionVarName, const QV4::Value &exceptionValue);
+ CallContext *newCallContext(FunctionObject *f, const QV4::Value &thisObject, QV4::Value *args, int argc);
+ CallContext *newCallContext(void *stackSpace, FunctionObject *f, const QV4::Value &thisObject, QV4::Value *args, int argc);
+ CallContext *newQmlContext(FunctionObject *f, Object *qml);
+ ExecutionContext *pushGlobalContext();
+ void pushContext(SimpleCallContext *context);
+ ExecutionContext *popContext();
+
+ Function *newFunction(const QString &name);
+
+ FunctionObject *newBuiltinFunction(ExecutionContext *scope, String *name, Value (*code)(SimpleCallContext *));
+ FunctionObject *newScriptFunction(ExecutionContext *scope, Function *function);
+ BoundFunction *newBoundFunction(ExecutionContext *scope, FunctionObject *target, Value boundThis, const QVector<Value> &boundArgs);
+
+ Object *newObject();
+ Object *newObject(InternalClass *internalClass);
+
+ String *newString(const QString &s);
+ String *newIdentifier(const QString &text);
+
+ Object *newStringObject(const Value &value);
+ Object *newNumberObject(const Value &value);
+ Object *newBooleanObject(const Value &value);
+
+ ArrayObject *newArrayObject(int count = 0);
+ ArrayObject *newArrayObject(const QStringList &list);
+
+ DateObject *newDateObject(const Value &value);
+ DateObject *newDateObject(const QDateTime &dt);
+
+ RegExpObject *newRegExpObject(const QString &pattern, int flags);
+ RegExpObject *newRegExpObject(RegExp* re, bool global);
+ RegExpObject *newRegExpObject(const QRegExp &re);
+
+ Object *newErrorObject(const Value &value);
+ Object *newSyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *message);
+ Object *newSyntaxErrorObject(const QString &message);
+ Object *newReferenceErrorObject(const QString &message);
+ Object *newReferenceErrorObject(const QString &message, const QString &fileName, int lineNumber);
+ Object *newTypeErrorObject(const QString &message);
+ Object *newRangeErrorObject(const QString &message);
+ Object *newURIErrorObject(Value message);
+
+ Object *newVariantObject(const QVariant &v);
+
+ Object *newForEachIteratorObject(ExecutionContext *ctx, Object *o);
+
+ Object *qmlContextObject() const;
+
+ struct StackFrame {
+ QString source;
+ QString function;
+ int line;
+ int column;
+ };
+ typedef QVector<StackFrame> StackTrace;
+ StackTrace stackTrace(int frameLimit = -1) const;
+ StackFrame currentStackFrame() const;
+ QUrl resolvedUrl(const QString &file);
+
+ void requireArgumentsAccessors(int n);
+
+ void markObjects();
+
+ void initRootContext();
+
+ InternalClass *newClass(const InternalClass &other);
+
+ Function *functionForProgramCounter(quintptr pc) const;
+
+ QmlExtensions *qmlExtensions();
+
+private:
+ QmlExtensions *m_qmlExtensions;
+};
+
+inline void ExecutionEngine::pushContext(SimpleCallContext *context)
+{
+ context->parent = current;
+ current = context;
+ current->currentEvalCode = 0;
+}
+
+inline ExecutionContext *ExecutionEngine::popContext()
+{
+ CallContext *c = current->asCallContext();
+ if (c && !c->needsOwnArguments()) {
+ c->arguments = 0;
+ c->argumentCount = 0;
+ }
+
+ current = current->parent;
+ return current;
+}
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4ENGINE_H
diff --git a/src/qml/qml/v4/qv4errorobject.cpp b/src/qml/qml/v4/qv4errorobject.cpp
new file mode 100644
index 0000000000..516a4d37f8
--- /dev/null
+++ b/src/qml/qml/v4/qv4errorobject.cpp
@@ -0,0 +1,351 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qv4errorobject_p.h"
+#include "qv4mm_p.h"
+#include <QtCore/qnumeric.h>
+#include <QtCore/qmath.h>
+#include <QtCore/QDateTime>
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+#include <cmath>
+#include <qmath.h>
+#include <qnumeric.h>
+#include <cassert>
+
+#include <private/qqmljsengine_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljsast_p.h>
+#include <qv4jsir_p.h>
+#include <qv4codegen_p.h>
+#include <qv4isel_masm_p.h>
+
+#ifndef Q_OS_WIN
+# include <time.h>
+# ifndef Q_OS_VXWORKS
+# include <sys/time.h>
+# else
+# include "qplatformdefs.h"
+# endif
+#else
+# include <windows.h>
+#endif
+
+using namespace QV4;
+
+ErrorObject::ErrorObject(ExecutionEngine *engine, const Value &message, ErrorType t)
+ : Object(engine)
+ , stack(0)
+{
+ type = Type_ErrorObject;
+ vtbl = &static_vtbl;
+ subtype = t;
+ defineAccessorProperty(engine, QStringLiteral("stack"), ErrorObject::method_get_stack, 0);
+
+ if (!message.isUndefined())
+ defineDefaultProperty(engine->newString(QStringLiteral("message")), message);
+ defineDefaultProperty(engine, QStringLiteral("name"), Value::fromString(engine, className()));
+
+ stackTrace = engine->stackTrace();
+ if (!stackTrace.isEmpty()) {
+ defineDefaultProperty(engine, QStringLiteral("fileName"), Value::fromString(engine, stackTrace.at(0).source));
+ defineDefaultProperty(engine, QStringLiteral("lineNumber"), Value::fromInt32(stackTrace.at(0).line));
+ }
+}
+
+Value ErrorObject::method_get_stack(SimpleCallContext *ctx)
+{
+ ErrorObject *This = ctx->thisObject.asErrorObject();
+ if (!This)
+ ctx->throwTypeError();
+ if (!This->stack) {
+ QString trace;
+ for (int i = 0; i < This->stackTrace.count(); ++i) {
+ if (i > 0)
+ trace += QLatin1Char('\n');
+ const ExecutionEngine::StackFrame &frame = This->stackTrace[i];
+ trace += frame.function;
+ trace += QLatin1Char('@');
+ trace += frame.source;
+ if (frame.line >= 0) {
+ trace += QLatin1Char(':');
+ trace += QString::number(frame.line);
+ }
+ }
+ This->stack = ctx->engine->newString(trace);
+ }
+ return Value::fromString(This->stack);
+}
+
+void ErrorObject::markObjects(Managed *that)
+{
+ ErrorObject *This = that->asErrorObject();
+ if (This->stack)
+ This->stack->mark();
+ Object::markObjects(that);
+}
+
+DEFINE_MANAGED_VTABLE(ErrorObject);
+
+DEFINE_MANAGED_VTABLE(SyntaxErrorObject);
+
+SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const Value &msg)
+ : ErrorObject(engine, msg, SyntaxError)
+ , msg(0)
+{
+ vtbl = &static_vtbl;
+ prototype = engine->syntaxErrorPrototype;
+}
+
+SyntaxErrorObject::SyntaxErrorObject(ExecutionEngine *engine, const QString &msg)
+ : ErrorObject(engine, Value::fromString(engine, msg), SyntaxError)
+ , msg(0)
+{
+ vtbl = &static_vtbl;
+ prototype = engine->syntaxErrorPrototype;
+}
+
+SyntaxErrorObject::SyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *message)
+ : ErrorObject(ctx->engine, message ? Value::fromString(message->buildFullMessage(ctx)) : ctx->argument(0), SyntaxError)
+ , msg(message)
+{
+ vtbl = &static_vtbl;
+ prototype = ctx->engine->syntaxErrorPrototype;
+ if (message) {
+ defineDefaultProperty(ctx->engine, QStringLiteral("fileName"), Value::fromString(ctx, message->fileName));
+ defineDefaultProperty(ctx->engine, QStringLiteral("lineNumber"), Value::fromInt32(message->startLine));
+ }
+}
+
+
+
+EvalErrorObject::EvalErrorObject(ExecutionEngine *engine, const Value &message)
+ : ErrorObject(engine, message, EvalError)
+{
+ prototype = engine->evalErrorPrototype;
+}
+
+RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const Value &message)
+ : ErrorObject(engine, message, RangeError)
+{
+ prototype = engine->rangeErrorPrototype;
+}
+
+RangeErrorObject::RangeErrorObject(ExecutionEngine *engine, const QString &message)
+ : ErrorObject(engine, Value::fromString(engine, message), RangeError)
+{
+ prototype = engine->rangeErrorPrototype;
+}
+
+ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const Value &message)
+ : ErrorObject(engine, message, ReferenceError)
+{
+ prototype = engine->referenceErrorPrototype;
+}
+
+ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &message)
+ : ErrorObject(engine, Value::fromString(engine, message), ReferenceError)
+{
+ prototype = engine->referenceErrorPrototype;
+}
+
+ReferenceErrorObject::ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber)
+ : ErrorObject(engine, Value::fromString(engine, msg), ReferenceError)
+{
+ prototype = engine->referenceErrorPrototype;
+ defineDefaultProperty(engine, QStringLiteral("fileName"), Value::fromString(engine->rootContext, fileName));
+ defineDefaultProperty(engine, QStringLiteral("lineNumber"), Value::fromInt32(lineNumber));
+}
+
+TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const Value &message)
+ : ErrorObject(engine, message, TypeError)
+{
+ prototype = engine->typeErrorPrototype;
+}
+
+TypeErrorObject::TypeErrorObject(ExecutionEngine *engine, const QString &message)
+ : ErrorObject(engine, Value::fromString(engine, message), TypeError)
+{
+ prototype = engine->typeErrorPrototype;
+}
+
+URIErrorObject::URIErrorObject(ExecutionEngine *engine, const Value &message)
+ : ErrorObject(engine, message, URIError)
+{
+ prototype = engine->uRIErrorPrototype;
+}
+
+DEFINE_MANAGED_VTABLE(ErrorCtor);
+DEFINE_MANAGED_VTABLE(EvalErrorCtor);
+DEFINE_MANAGED_VTABLE(RangeErrorCtor);
+DEFINE_MANAGED_VTABLE(ReferenceErrorCtor);
+DEFINE_MANAGED_VTABLE(SyntaxErrorCtor);
+DEFINE_MANAGED_VTABLE(TypeErrorCtor);
+DEFINE_MANAGED_VTABLE(URIErrorCtor);
+
+ErrorCtor::ErrorCtor(ExecutionContext *scope)
+ : FunctionObject(scope, scope->engine->newIdentifier(QStringLiteral("Error")))
+{
+ vtbl = &static_vtbl;
+}
+
+ErrorCtor::ErrorCtor(ExecutionContext *scope, String *name)
+ : FunctionObject(scope, name)
+{
+ vtbl = &static_vtbl;
+}
+
+Value ErrorCtor::construct(Managed *m, Value *args, int argc)
+{
+ return Value::fromObject(m->engine()->newErrorObject(argc ? args[0] : Value::undefinedValue()));
+}
+
+Value ErrorCtor::call(Managed *that, const Value &, Value *args, int argc)
+{
+ return that->construct(args, argc);
+}
+
+EvalErrorCtor::EvalErrorCtor(ExecutionContext *scope)
+ : ErrorCtor(scope, scope->engine->newIdentifier("EvalError"))
+{
+ vtbl = &static_vtbl;
+}
+
+Value EvalErrorCtor::construct(Managed *m, Value *args, int argc)
+{
+ return Value::fromObject(new (m->engine()->memoryManager) EvalErrorObject(m->engine(), argc ? args[0] : Value::undefinedValue()));
+}
+
+RangeErrorCtor::RangeErrorCtor(ExecutionContext *scope)
+ : ErrorCtor(scope, scope->engine->newIdentifier("RangeError"))
+{
+ vtbl = &static_vtbl;
+}
+
+Value RangeErrorCtor::construct(Managed *m, Value *args, int argc)
+{
+ return Value::fromObject(new (m->engine()->memoryManager) RangeErrorObject(m->engine(), argc ? args[0] : Value::undefinedValue()));
+}
+
+ReferenceErrorCtor::ReferenceErrorCtor(ExecutionContext *scope)
+ : ErrorCtor(scope, scope->engine->newIdentifier("ReferenceError"))
+{
+ vtbl = &static_vtbl;
+}
+
+Value ReferenceErrorCtor::construct(Managed *m, Value *args, int argc)
+{
+ return Value::fromObject(new (m->engine()->memoryManager) ReferenceErrorObject(m->engine(), argc ? args[0] : Value::undefinedValue()));
+}
+
+SyntaxErrorCtor::SyntaxErrorCtor(ExecutionContext *scope)
+ : ErrorCtor(scope, scope->engine->newIdentifier("SyntaxError"))
+{
+ vtbl = &static_vtbl;
+}
+
+Value SyntaxErrorCtor::construct(Managed *m, Value *args, int argc)
+{
+ return Value::fromObject(new (m->engine()->memoryManager) SyntaxErrorObject(m->engine(), argc ? args[0] : Value::undefinedValue()));
+}
+
+TypeErrorCtor::TypeErrorCtor(ExecutionContext *scope)
+ : ErrorCtor(scope, scope->engine->newIdentifier("TypeError"))
+{
+ vtbl = &static_vtbl;
+}
+
+Value TypeErrorCtor::construct(Managed *m, Value *args, int argc)
+{
+ return Value::fromObject(new (m->engine()->memoryManager) TypeErrorObject(m->engine(), argc ? args[0] : Value::undefinedValue()));
+}
+
+URIErrorCtor::URIErrorCtor(ExecutionContext *scope)
+ : ErrorCtor(scope, scope->engine->newIdentifier("URIError"))
+{
+ vtbl = &static_vtbl;
+}
+
+Value URIErrorCtor::construct(Managed *m, Value *args, int argc)
+{
+ return Value::fromObject(new (m->engine()->memoryManager) URIErrorObject(m->engine(), argc ? args[0] : Value::undefinedValue()));
+}
+
+void ErrorPrototype::init(ExecutionEngine *engine, const Value &ctor, Object *obj)
+{
+ ctor.objectValue()->defineReadonlyProperty(engine->id_prototype, Value::fromObject(obj));
+ ctor.objectValue()->defineReadonlyProperty(engine->id_length, Value::fromInt32(1));
+ obj->defineDefaultProperty(engine, QStringLiteral("constructor"), ctor);
+ obj->defineDefaultProperty(engine, QStringLiteral("toString"), method_toString, 0);
+ obj->defineDefaultProperty(engine, QStringLiteral("message"), Value::fromString(engine, QString()));
+}
+
+Value ErrorPrototype::method_toString(SimpleCallContext *ctx)
+{
+ Object *o = ctx->thisObject.asObject();
+ if (!o)
+ ctx->throwTypeError();
+
+ Value name = o->get(ctx->engine->newString(QString::fromLatin1("name")));
+ QString qname;
+ if (name.isUndefined())
+ qname = QString::fromLatin1("Error");
+ else
+ qname = __qmljs_to_string(name, ctx).stringValue()->toQString();
+
+ Value message = o->get(ctx->engine->newString(QString::fromLatin1("message")));
+ QString qmessage;
+ if (!message.isUndefined())
+ qmessage = __qmljs_to_string(message, ctx).stringValue()->toQString();
+
+ QString str;
+ if (qname.isEmpty()) {
+ str = qmessage;
+ } else if (qmessage.isEmpty()) {
+ str = qname;
+ } else {
+ str = qname + QLatin1String(": ") + qmessage;
+ }
+
+ return Value::fromString(ctx, str);
+}
diff --git a/src/qml/qml/v4/qv4errorobject_p.h b/src/qml/qml/v4/qv4errorobject_p.h
new file mode 100644
index 0000000000..d3e0f107bc
--- /dev/null
+++ b/src/qml/qml/v4/qv4errorobject_p.h
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4ERROROBJECT_H
+#define QV4ERROROBJECT_H
+
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct SyntaxErrorObject;
+
+struct ErrorObject: Object {
+ Q_MANAGED
+
+ enum ErrorType {
+ Error,
+ EvalError,
+ RangeError,
+ ReferenceError,
+ SyntaxError,
+ TypeError,
+ URIError
+ };
+
+ ErrorObject(ExecutionEngine *engine, const Value &message, ErrorType t = Error);
+
+ SyntaxErrorObject *asSyntaxError();
+
+ ExecutionEngine::StackTrace stackTrace;
+ String *stack;
+
+ static Value method_get_stack(SimpleCallContext *ctx);
+ static void markObjects(Managed *that);
+ static void destroy(Managed *that) { static_cast<ErrorObject *>(that)->~ErrorObject(); }
+};
+
+struct EvalErrorObject: ErrorObject {
+ EvalErrorObject(ExecutionEngine *engine, const Value &message);
+};
+
+struct RangeErrorObject: ErrorObject {
+ RangeErrorObject(ExecutionEngine *engine, const Value &message);
+ RangeErrorObject(ExecutionEngine *engine, const QString &msg);
+};
+
+struct ReferenceErrorObject: ErrorObject {
+ ReferenceErrorObject(ExecutionEngine *engine, const Value &message);
+ ReferenceErrorObject(ExecutionEngine *engine, const QString &msg);
+ ReferenceErrorObject(ExecutionEngine *engine, const QString &msg, const QString &fileName, int lineNumber);
+};
+
+struct SyntaxErrorObject: ErrorObject {
+ SyntaxErrorObject(ExecutionEngine *engine, const Value &msg);
+ SyntaxErrorObject(ExecutionEngine *engine, const QString &msg);
+ SyntaxErrorObject(ExecutionContext *ctx, DiagnosticMessage *msg);
+ ~SyntaxErrorObject() { delete msg; }
+ static void destroy(Managed *that) { static_cast<SyntaxErrorObject *>(that)->~SyntaxErrorObject(); }
+
+ DiagnosticMessage *message() { return msg; }
+
+private:
+ DiagnosticMessage *msg;
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct TypeErrorObject: ErrorObject {
+ TypeErrorObject(ExecutionEngine *engine, const Value &message);
+ TypeErrorObject(ExecutionEngine *engine, const QString &msg);
+};
+
+struct URIErrorObject: ErrorObject {
+ URIErrorObject(ExecutionEngine *engine, const Value &message);
+};
+
+struct ErrorCtor: FunctionObject
+{
+ ErrorCtor(ExecutionContext *scope);
+ ErrorCtor(ExecutionContext *scope, String *name);
+
+ static Value construct(Managed *, Value *args, int argc);
+ static Value call(Managed *that, const Value &, Value *, int);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct EvalErrorCtor: ErrorCtor
+{
+ EvalErrorCtor(ExecutionContext *scope);
+
+ static Value construct(Managed *m, Value *args, int argc);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct RangeErrorCtor: ErrorCtor
+{
+ RangeErrorCtor(ExecutionContext *scope);
+
+ static Value construct(Managed *m, Value *args, int argc);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct ReferenceErrorCtor: ErrorCtor
+{
+ ReferenceErrorCtor(ExecutionContext *scope);
+
+ static Value construct(Managed *m, Value *args, int argc);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct SyntaxErrorCtor: ErrorCtor
+{
+ SyntaxErrorCtor(ExecutionContext *scope);
+
+ static Value construct(Managed *m, Value *args, int argc);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct TypeErrorCtor: ErrorCtor
+{
+ TypeErrorCtor(ExecutionContext *scope);
+
+ static Value construct(Managed *m, Value *args, int argc);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct URIErrorCtor: ErrorCtor
+{
+ URIErrorCtor(ExecutionContext *scope);
+
+ static Value construct(Managed *m, Value *args, int argc);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+
+struct ErrorPrototype: ErrorObject
+{
+ // ### shouldn't be undefined
+ ErrorPrototype(ExecutionEngine *engine): ErrorObject(engine, Value::undefinedValue()) {}
+ void init(ExecutionEngine *engine, const Value &ctor) { init(engine, ctor, this); }
+
+ static void init(ExecutionEngine *engine, const Value &ctor, Object *obj);
+ static Value method_toString(SimpleCallContext *ctx);
+};
+
+struct EvalErrorPrototype: EvalErrorObject
+{
+ EvalErrorPrototype(ExecutionEngine *engine): EvalErrorObject(engine, Value::undefinedValue()) { vtbl = &static_vtbl; }
+ void init(ExecutionEngine *engine, const Value &ctor) { ErrorPrototype::init(engine, ctor, this); }
+};
+
+struct RangeErrorPrototype: RangeErrorObject
+{
+ RangeErrorPrototype(ExecutionEngine *engine): RangeErrorObject(engine, Value::undefinedValue()) { vtbl = &static_vtbl; }
+ void init(ExecutionEngine *engine, const Value &ctor) { ErrorPrototype::init(engine, ctor, this); }
+};
+
+struct ReferenceErrorPrototype: ReferenceErrorObject
+{
+ ReferenceErrorPrototype(ExecutionEngine *engine): ReferenceErrorObject(engine, Value::undefinedValue()) { vtbl = &static_vtbl; }
+ void init(ExecutionEngine *engine, const Value &ctor) { ErrorPrototype::init(engine, ctor, this); }
+};
+
+struct SyntaxErrorPrototype: SyntaxErrorObject
+{
+ SyntaxErrorPrototype(ExecutionEngine *engine): SyntaxErrorObject(engine, 0) { vtbl = &static_vtbl; }
+ void init(ExecutionEngine *engine, const Value &ctor) { ErrorPrototype::init(engine, ctor, this); }
+};
+
+struct TypeErrorPrototype: TypeErrorObject
+{
+ TypeErrorPrototype(ExecutionEngine *engine): TypeErrorObject(engine, Value::undefinedValue()) { vtbl = &static_vtbl; }
+ void init(ExecutionEngine *engine, const Value &ctor) { ErrorPrototype::init(engine, ctor, this); }
+};
+
+struct URIErrorPrototype: URIErrorObject
+{
+ URIErrorPrototype(ExecutionEngine *engine): URIErrorObject(engine, Value::undefinedValue()) { vtbl = &static_vtbl; }
+ void init(ExecutionEngine *engine, const Value &ctor) { ErrorPrototype::init(engine, ctor, this); }
+};
+
+
+inline SyntaxErrorObject *ErrorObject::asSyntaxError()
+{
+ return subtype == SyntaxError ? static_cast<SyntaxErrorObject *>(this) : 0;
+}
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4ECMAOBJECTS_P_H
diff --git a/src/qml/qml/v4/qv4exception.cpp b/src/qml/qml/v4/qv4exception.cpp
new file mode 100644
index 0000000000..9f15c27ffc
--- /dev/null
+++ b/src/qml/qml/v4/qv4exception.cpp
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4exception_p.h"
+#include "qv4errorobject_p.h"
+#include "qv4debugging_p.h"
+#include "qv4unwindhelper_p.h"
+
+#include <wtf/Platform.h>
+
+#if USE(LIBUNWIND_DEBUG)
+#include <libunwind.h>
+#include <execinfo.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+
+void Exception::throwException(ExecutionContext *context, const Value &value)
+{
+ if (context->engine->debugger)
+ context->engine->debugger->aboutToThrow(value);
+
+ UnwindHelper::prepareForUnwind(context);
+
+#if USE(LIBUNWIND_DEBUG)
+ printf("about to throw exception. walking stack first with libunwind:\n");
+ unw_cursor_t cursor; unw_context_t uc;
+ unw_word_t ip, sp;
+
+ unw_getcontext(&uc);
+ unw_init_local(&cursor, &uc);
+ while (unw_step(&cursor) > 0) {
+ unw_get_reg(&cursor, UNW_REG_IP, &ip);
+ unw_get_reg(&cursor, UNW_REG_SP, &sp);
+ printf("ip = %lx, sp = %lx ", (long) ip, (long) sp);
+ void * const addr = (void*)ip;
+ char **symbol = backtrace_symbols(&addr, 1);
+ printf("%s", symbol[0]);
+ free(symbol);
+ printf("\n");
+ }
+ printf("stack walked. throwing exception now...\n");
+#endif
+
+ throwInternal(context, value);
+}
+
+Exception::Exception(ExecutionContext *throwingContext, const Value &exceptionValue)
+ : exception(exceptionValue)
+{
+ this->throwingContext = throwingContext->engine->current;
+ accepted = false;
+ if (ErrorObject *error = exceptionValue.asErrorObject())
+ m_stackTrace = error->stackTrace;
+ else
+ m_stackTrace = throwingContext->engine->stackTrace();
+}
+
+Exception::~Exception()
+{
+ assert(accepted);
+}
+
+void Exception::accept(ExecutionContext *catchingContext)
+{
+ assert(!accepted);
+ accepted = true;
+ partiallyUnwindContext(catchingContext);
+}
+
+void Exception::partiallyUnwindContext(ExecutionContext *catchingContext)
+{
+ if (!throwingContext)
+ return;
+ ExecutionContext *context = throwingContext;
+ while (context != catchingContext)
+ context = context->engine->popContext();
+ throwingContext = context;
+}
+
+#if !defined(V4_CXX_ABI_EXCEPTION)
+void Exception::throwInternal(ExecutionContext *throwingContext, const Value &exceptionValue)
+{
+ throw Exception(throwingContext, exceptionValue);
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4exception_gcc.cpp b/src/qml/qml/v4/qv4exception_gcc.cpp
new file mode 100644
index 0000000000..0324a06e0b
--- /dev/null
+++ b/src/qml/qml/v4/qv4exception_gcc.cpp
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4exception_p.h"
+
+#include <unwind.h>
+#include <cxxabi.h>
+#include <bits/atomic_word.h>
+#include <typeinfo>
+#include <exception>
+
+/*
+ * This is a little bit hacky as it relies on the fact that exceptions are
+ * reference counted in libstdc++ and that affects the layout of the standardized
+ * cxa_exception, making it bigger. LLVM's libcxxabi stores the reference count
+ * differently, so this here is entirely GNU libstdc++ specific.
+ *
+ * Eliminating this dependency is doable but requires replacing the use of C++ exceptions
+ * with foreign exceptions (a different exception class) and then using __cxa_get_globals
+ * to get hold of the exception inside the catch (...). AFAICS that would be portable.
+ */
+
+namespace {
+
+// 2.1.1 from http://mentorembedded.github.io/cxx-abi/abi-eh.html
+struct cxa_exception {
+ std::type_info *typeInfo;
+ void (*exceptionDestructor)(void*);
+ std::unexpected_handler unexpectedHandler;
+ std::terminate_handler terminateHandler;
+ cxa_exception *nextException;
+ int handlerCount;
+#ifdef __ARM_EABI_UNWINDER__
+ cxa_exception *nextPropagatingException;
+ int propagationCount;
+#else
+ int handlerSwitchValue;
+ const char *actionRecord;
+ const char *languageSpecificData;
+ void *catchTemp;
+ void *adjustedPtr;
+#endif
+ _Unwind_Exception unwindHeader;
+};
+
+// This is what libstdc++ actually allocates
+struct gcc_refcounted_compatible_exception {
+ _Atomic_word refCount;
+ cxa_exception x;
+};
+
+}
+
+static void exception_cleanup(_Unwind_Reason_Code, _Unwind_Exception *ex)
+{
+ gcc_refcounted_compatible_exception *exception = reinterpret_cast<gcc_refcounted_compatible_exception *>(ex + 1) - 1;
+ if (!--exception->refCount) {
+ if (exception->x.exceptionDestructor)
+ exception->x.exceptionDestructor(ex + 1);
+ abi::__cxa_free_exception(ex + 1);
+ }
+}
+
+static void exception_destructor(void *ex)
+{
+ reinterpret_cast<QV4::Exception *>(ex)->~Exception();
+}
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+void Exception::throwInternal(ExecutionContext *throwingContext, const Value &exceptionValue)
+{
+ void *rawException = abi::__cxa_allocate_exception(sizeof(QV4::Exception));
+ gcc_refcounted_compatible_exception *refCountedException = reinterpret_cast<gcc_refcounted_compatible_exception *>(rawException) - 1;
+ cxa_exception *exception = &refCountedException->x;
+
+ (void)new (rawException) Exception(throwingContext, exceptionValue);
+
+ refCountedException->refCount = 1;
+ exception->typeInfo = const_cast<std::type_info*>(&typeid(Exception));
+ exception->exceptionDestructor = &exception_destructor;
+ exception->unexpectedHandler = std::unexpected;
+ exception->terminateHandler = std::terminate;
+ exception->unwindHeader.exception_cleanup = &exception_cleanup;
+#ifdef __ARM_EABI_UNWINDER__
+ exception->unwindHeader.exception_class[0] = 'G';
+ exception->unwindHeader.exception_class[1] = 'N';
+ exception->unwindHeader.exception_class[2] = 'U';
+ exception->unwindHeader.exception_class[3] = 'C';
+ exception->unwindHeader.exception_class[4] = 'C';
+ exception->unwindHeader.exception_class[5] = '+';
+ exception->unwindHeader.exception_class[6] = '+';
+ exception->unwindHeader.exception_class[7] = 0;
+#else
+ exception->unwindHeader.exception_class = 0x474e5543432b2b00; // GNUCC++0
+#endif
+
+ _Unwind_RaiseException(&exception->unwindHeader);
+ abi::__cxa_begin_catch(rawException);
+ std::terminate();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4exception_p.h b/src/qml/qml/v4/qv4exception_p.h
new file mode 100644
index 0000000000..8ba06f57f4
--- /dev/null
+++ b/src/qml/qml/v4/qv4exception_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4EXCEPTION_GNU_P
+#define QV4EXCEPTION_GNU_P
+
+#include <qglobal.h>
+#include "qv4value_p.h"
+#include "qv4engine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct Q_QML_EXPORT Exception {
+ static void throwException(ExecutionContext *throwingContext, const Value &exceptionValue);
+
+ ~Exception();
+
+ void accept(ExecutionContext *catchingContext);
+
+ void partiallyUnwindContext(ExecutionContext *catchingContext);
+
+ Value value() const { return exception; }
+
+ ExecutionEngine::StackTrace stackTrace() const { return m_stackTrace; }
+
+private:
+ void *operator new(size_t, void *p) { return p; }
+
+ explicit Exception(ExecutionContext *throwingContext, const Value &exceptionValue);
+
+ ExecutionContext *throwingContext;
+ bool accepted;
+ PersistentValue exception;
+ ExecutionEngine::StackTrace m_stackTrace;
+ static void throwInternal(ExecutionContext *throwingContext, const Value &exceptionValue);
+};
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4EXCEPTION_GNU_P
diff --git a/src/qml/qml/v4/qv4executableallocator.cpp b/src/qml/qml/v4/qv4executableallocator.cpp
new file mode 100644
index 0000000000..a754663556
--- /dev/null
+++ b/src/qml/qml/v4/qv4executableallocator.cpp
@@ -0,0 +1,220 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4executableallocator_p.h"
+
+#include <assert.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/PageAllocation.h>
+
+using namespace QV4;
+
+void *ExecutableAllocator::Allocation::start() const
+{
+ return reinterpret_cast<void*>(addr);
+}
+
+ExecutableAllocator::Allocation *ExecutableAllocator::Allocation::split(size_t dividingSize)
+{
+ Allocation *remainder = new Allocation;
+ if (next)
+ next->prev = remainder;
+
+ remainder->next = next;
+ next = remainder;
+
+ remainder->prev = this;
+
+ remainder->size = size - dividingSize;
+ remainder->free = free;
+ remainder->addr = addr + dividingSize;
+ size = dividingSize;
+
+ return remainder;
+}
+
+bool ExecutableAllocator::Allocation::mergeNext(ExecutableAllocator *allocator)
+{
+ assert(free);
+ if (!next || !next->free)
+ return false;
+
+ allocator->freeAllocations.remove(size, this);
+ allocator->freeAllocations.remove(next->size, next);
+
+ size += next->size;
+ Allocation *newNext = next->next;
+ delete next;
+ next = newNext;
+ if (next)
+ next->prev = this;
+
+ allocator->freeAllocations.insert(size, this);
+ return true;
+}
+
+bool ExecutableAllocator::Allocation::mergePrevious(ExecutableAllocator *allocator)
+{
+ assert(free);
+ if (!prev || !prev->free)
+ return false;
+
+ allocator->freeAllocations.remove(size, this);
+ allocator->freeAllocations.remove(prev->size, prev);
+
+ prev->size += size;
+ if (next)
+ next->prev = prev;
+ prev->next = next;
+
+ allocator->freeAllocations.insert(prev->size, prev);
+
+ delete this;
+ return true;
+}
+
+ExecutableAllocator::ChunkOfPages::~ChunkOfPages()
+{
+ delete unwindInfo;
+ Allocation *alloc = firstAllocation;
+ while (alloc) {
+ Allocation *next = alloc->next;
+ delete alloc;
+ alloc = next;
+ }
+ pages->deallocate();
+ delete pages;
+}
+
+bool ExecutableAllocator::ChunkOfPages::contains(Allocation *alloc) const
+{
+ Allocation *it = firstAllocation;
+ while (it) {
+ if (it == alloc)
+ return true;
+ it = it->next;
+ }
+ return false;
+}
+
+ExecutableAllocator::~ExecutableAllocator()
+{
+ qDeleteAll(chunks);
+}
+
+ExecutableAllocator::Allocation *ExecutableAllocator::allocate(size_t size)
+{
+ Allocation *allocation = 0;
+
+ // Code is best aligned to 16-byte boundaries.
+ size = WTF::roundUpToMultipleOf(16, size);
+
+ QMultiMap<size_t, Allocation*>::Iterator it = freeAllocations.lowerBound(size);
+ if (it != freeAllocations.end()) {
+ allocation = *it;
+ freeAllocations.erase(it);
+ }
+
+ if (!allocation) {
+ ChunkOfPages *chunk = new ChunkOfPages;
+ size_t allocSize = WTF::roundUpToMultipleOf(WTF::pageSize(), size);
+ chunk->pages = new WTF::PageAllocation(WTF::PageAllocation::allocate(allocSize, OSAllocator::JSJITCodePages));
+ chunks.insert(reinterpret_cast<quintptr>(chunk->pages->base()) - 1, chunk);
+ allocation = new Allocation;
+ allocation->addr = reinterpret_cast<quintptr>(chunk->pages->base());
+ allocation->size = allocSize;
+ allocation->free = true;
+ chunk->firstAllocation = allocation;
+ }
+
+ assert(allocation);
+ assert(allocation->free);
+
+ allocation->free = false;
+
+ if (allocation->size > size) {
+ Allocation *remainder = allocation->split(size);
+ remainder->free = true;
+ if (!remainder->mergeNext(this))
+ freeAllocations.insert(remainder->size, remainder);
+ }
+
+ return allocation;
+}
+
+void ExecutableAllocator::free(Allocation *allocation)
+{
+ assert(allocation);
+
+ allocation->free = true;
+
+ QMap<quintptr, ChunkOfPages*>::Iterator it = chunks.lowerBound(allocation->addr);
+ if (it != chunks.begin())
+ --it;
+ assert(it != chunks.end());
+ ChunkOfPages *chunk = *it;
+ assert(chunk->contains(allocation));
+
+ bool merged = allocation->mergeNext(this);
+ merged |= allocation->mergePrevious(this);
+ if (!merged)
+ freeAllocations.insert(allocation->size, allocation);
+
+ allocation = 0;
+
+ if (!chunk->firstAllocation->next) {
+ freeAllocations.remove(chunk->firstAllocation->size, chunk->firstAllocation);
+ chunks.erase(it);
+ delete chunk;
+ return;
+ }
+}
+
+ExecutableAllocator::ChunkOfPages *ExecutableAllocator::chunkForAllocation(Allocation *allocation) const
+{
+ QMap<quintptr, ChunkOfPages*>::ConstIterator it = chunks.lowerBound(allocation->addr);
+ if (it != chunks.begin())
+ --it;
+ if (it == chunks.end())
+ return 0;
+ return *it;
+}
+
diff --git a/src/qml/qml/v8/qv8jsonwrapper_p.h b/src/qml/qml/v4/qv4executableallocator_p.h
index eb4a197819..2a304baf9c 100644
--- a/src/qml/qml/v8/qv8jsonwrapper_p.h
+++ b/src/qml/qml/v4/qv4executableallocator_p.h
@@ -39,62 +39,96 @@
**
****************************************************************************/
-#ifndef QV8JSONWRAPPER_P_H
-#define QV8JSONWRAPPER_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 <QtCore/qglobal.h>
-#include <QtCore/qset.h>
-#include <private/qv8_p.h>
-
-#include <QtCore/qjsonarray.h>
-#include <QtCore/qjsonobject.h>
-#include <QtCore/qjsonvalue.h>
+#ifndef QV4EXECUTABLEALLOCATOR_H
+#define QV4EXECUTABLEALLOCATOR_H
+
+#include "qv4global_p.h"
+
+#include <QMultiMap>
+#include <QHash>
+#include <QVector>
+#include <QByteArray>
+
+namespace WTF {
+class PageAllocation;
+};
QT_BEGIN_NAMESPACE
-class QV8Engine;
-class QV8JsonWrapper
+namespace QV4 {
+
+class Q_AUTOTEST_EXPORT ExecutableAllocator
{
- typedef QSet<v8::Handle<v8::Object> > V8ObjectSet;
public:
- QV8JsonWrapper();
- ~QV8JsonWrapper();
+ struct ChunkOfPages;
+ struct Allocation;
- void init(QV8Engine *);
- void destroy();
+ ~ExecutableAllocator();
- v8::Handle<v8::Value> fromJsonValue(const QJsonValue &value);
- inline QJsonValue toJsonValue(v8::Handle<v8::Value> value)
- { V8ObjectSet visitedObjects; return toJsonValue(value, visitedObjects); }
+ Allocation *allocate(size_t size);
+ void free(Allocation *allocation);
- v8::Local<v8::Object> fromJsonObject(const QJsonObject &object);
- inline QJsonObject toJsonObject(v8::Handle<v8::Value> value)
- { V8ObjectSet visitedObjects; return toJsonObject(value, visitedObjects); }
+ struct Allocation
+ {
+ Allocation()
+ : addr(0)
+ , size(0)
+ , free(true)
+ , next(0)
+ , prev(0)
+ {}
- v8::Local<v8::Array> fromJsonArray(const QJsonArray &array);
- inline QJsonArray toJsonArray(v8::Handle<v8::Value> value)
- { V8ObjectSet visitedObjects; return toJsonArray(value, visitedObjects); }
+ void *start() const;
-private:
- QJsonValue toJsonValue(v8::Handle<v8::Value> value, V8ObjectSet &visitedObjects);
- QJsonObject toJsonObject(v8::Handle<v8::Value> value, V8ObjectSet &visitedObjects);
- QJsonArray toJsonArray(v8::Handle<v8::Value> value, V8ObjectSet &visitedObjects);
+ private:
+ friend class ExecutableAllocator;
+
+ Allocation *split(size_t dividingSize);
+ bool mergeNext(ExecutableAllocator *allocator);
+ bool mergePrevious(ExecutableAllocator *allocator);
+
+ quintptr addr;
+ uint size : 31; // More than 2GB of function code? nah :)
+ uint free : 1;
+ Allocation *next;
+ Allocation *prev;
+ };
+
+ // for debugging / unit-testing
+ int freeAllocationCount() const { return freeAllocations.count(); }
+ int chunkCount() const { return chunks.count(); }
- QV8Engine *m_engine;
+ // Used to store CIE+FDE on x86/x86-64.
+ struct PlatformUnwindInfo
+ {
+ virtual ~PlatformUnwindInfo() {}
+ };
+
+ struct ChunkOfPages
+ {
+ ChunkOfPages()
+ : pages(0)
+ , firstAllocation(0)
+ , unwindInfo(0)
+ {}
+ ~ChunkOfPages();
+
+ WTF::PageAllocation *pages;
+ Allocation *firstAllocation;
+ PlatformUnwindInfo *unwindInfo;
+
+ bool contains(Allocation *alloc) const;
+ };
+
+ ChunkOfPages *chunkForAllocation(Allocation *allocation) const;
+
+private:
+ QMultiMap<size_t, Allocation*> freeAllocations;
+ QMap<quintptr, ChunkOfPages*> chunks;
};
-QT_END_NAMESPACE
+}
-#endif // QV8JSONWRAPPER_P_H
+QT_END_NAMESPACE
+#endif // QV4EXECUTABLEALLOCATOR_H
diff --git a/src/qml/qml/v4/qv4function.cpp b/src/qml/qml/v4/qv4function.cpp
new file mode 100644
index 0000000000..bf633a9b41
--- /dev/null
+++ b/src/qml/qml/v4/qv4function.cpp
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4function_p.h"
+#include "qv4managed_p.h"
+#include "qv4string_p.h"
+#include "qv4value_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+Function::~Function()
+{
+ delete[] codeData;
+}
+
+void Function::mark()
+{
+ if (name)
+ name->mark();
+ for (int i = 0; i < formals.size(); ++i)
+ formals.at(i)->mark();
+ for (int i = 0; i < locals.size(); ++i)
+ locals.at(i)->mark();
+ for (int i = 0; i < generatedValues.size(); ++i)
+ if (Managed *m = generatedValues.at(i).asManaged())
+ m->mark();
+ for (int i = 0; i < identifiers.size(); ++i)
+ identifiers.at(i)->mark();
+}
+
+namespace QV4 {
+bool operator<(const LineNumberMapping &mapping, qptrdiff pc)
+{
+ return mapping.codeOffset < pc;
+}
+}
+
+int Function::lineNumberForProgramCounter(qptrdiff offset) const
+{
+ QVector<LineNumberMapping>::ConstIterator it = qLowerBound(lineNumberMappings.begin(), lineNumberMappings.end(), offset);
+ if (it != lineNumberMappings.constBegin() && lineNumberMappings.count() > 0)
+ --it;
+ if (it == lineNumberMappings.constEnd())
+ return -1;
+ return it->lineNumber;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4function_p.h b/src/qml/qml/v4/qv4function_p.h
new file mode 100644
index 0000000000..4dd0533d51
--- /dev/null
+++ b/src/qml/qml/v4/qv4function_p.h
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4FUNCTION_H
+#define QV4FUNCTION_H
+
+#include "qv4global_p.h"
+
+#include <QtCore/QVector>
+#include <QtCore/QByteArray>
+#include <QtCore/qurl.h>
+
+#include <config.h>
+#include <assembler/MacroAssemblerCodeRef.h>
+#include "qv4value_def_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct String;
+struct Function;
+struct Object;
+struct FunctionObject;
+struct ExecutionContext;
+struct ExecutionEngine;
+class MemoryManager;
+
+struct ObjectPrototype;
+struct StringPrototype;
+struct NumberPrototype;
+struct BooleanPrototype;
+struct ArrayPrototype;
+struct FunctionPrototype;
+struct DatePrototype;
+struct ErrorPrototype;
+struct EvalErrorPrototype;
+struct RangeErrorPrototype;
+struct ReferenceErrorPrototype;
+struct SyntaxErrorPrototype;
+struct TypeErrorPrototype;
+struct URIErrorPrototype;
+struct InternalClass;
+struct Lookup;
+
+struct LineNumberMapping
+{
+ quint32 codeOffset;
+ int lineNumber;
+};
+
+struct Function {
+ String *name;
+
+ Value (*code)(ExecutionContext *, const uchar *);
+ const uchar *codeData;
+ JSC::MacroAssemblerCodeRef codeRef;
+ quint32 codeSize;
+
+ QVector<String *> formals;
+ QVector<String *> locals;
+ QVector<Value> generatedValues;
+ QVector<String *> identifiers;
+ QVector<Function *> nestedFunctions;
+ Function *outer;
+
+ Lookup *lookups;
+
+ bool hasNestedFunctions;
+ bool hasDirectEval;
+ bool usesArgumentsObject;
+ bool isStrict;
+ bool isNamedExpression;
+
+ QString sourceFile;
+ QVector<LineNumberMapping> lineNumberMappings;
+
+ Function(String *name)
+ : name(name)
+ , code(0)
+ , codeData(0)
+ , codeSize(0)
+ , outer(0)
+ , lookups(0)
+ , hasNestedFunctions(0)
+ , hasDirectEval(false)
+ , usesArgumentsObject(false)
+ , isStrict(false)
+ , isNamedExpression(false)
+ {}
+ ~Function();
+
+ inline bool needsActivation() const { return hasNestedFunctions || hasDirectEval || usesArgumentsObject; }
+
+ void mark();
+
+ int lineNumberForProgramCounter(qptrdiff offset) const;
+};
+
+}
+Q_DECLARE_TYPEINFO(QV4::LineNumberMapping, Q_PRIMITIVE_TYPE);
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v4/qv4functionobject.cpp b/src/qml/qml/v4/qv4functionobject.cpp
new file mode 100644
index 0000000000..ffdd08ed0a
--- /dev/null
+++ b/src/qml/qml/v4/qv4functionobject.cpp
@@ -0,0 +1,558 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4object_p.h"
+#include "qv4jsir_p.h"
+#include "qv4isel_p.h"
+#include "qv4objectproto_p.h"
+#include "qv4stringobject_p.h"
+#include "qv4function_p.h"
+#include "qv4mm_p.h"
+#include "qv4exception_p.h"
+
+#include <private/qqmljsengine_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljsast_p.h>
+#include <qv4jsir_p.h>
+#include <qv4codegen_p.h>
+#include "private/qlocale_tools_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtCore/QDebug>
+#include <cassert>
+#include <typeinfo>
+#include <iostream>
+#include "qv4alloca_p.h"
+
+using namespace QV4;
+
+
+DEFINE_MANAGED_VTABLE(FunctionObject);
+
+FunctionObject::FunctionObject(ExecutionContext *scope, String *name)
+ : Object(scope->engine)
+ , scope(scope)
+ , name(name)
+ , formalParameterList(0)
+ , varList(0)
+ , formalParameterCount(0)
+ , varCount(0)
+ , function(0)
+{
+ vtbl = &static_vtbl;
+ prototype = scope->engine->functionPrototype;
+
+ type = Type_FunctionObject;
+ needsActivation = true;
+ usesArgumentsObject = false;
+ strictMode = false;
+#ifndef QT_NO_DEBUG
+ assert(scope->next != (ExecutionContext *)0x1);
+#endif
+
+ if (name)
+ defineReadonlyProperty(scope->engine->id_name, Value::fromString(name));
+}
+
+Value FunctionObject::newInstance()
+{
+ return construct(0, 0);
+}
+
+bool FunctionObject::hasInstance(Managed *that, const Value &value)
+{
+ FunctionObject *f = static_cast<FunctionObject *>(that);
+
+ Object *v = value.asObject();
+ if (!v)
+ return false;
+
+ ExecutionContext *ctx = f->engine()->current;
+ Object *o = f->get(ctx->engine->id_prototype).asObject();
+ if (!o)
+ ctx->throwTypeError();
+
+ while (v) {
+ v = v->prototype;
+
+ if (! v)
+ break;
+ else if (o == v)
+ return true;
+ }
+
+ return false;
+}
+
+Value FunctionObject::construct(Managed *that, Value *, int)
+{
+ FunctionObject *f = static_cast<FunctionObject *>(that);
+ ExecutionEngine *v4 = f->engine();
+
+ Object *obj = v4->newObject();
+ Value proto = f->get(v4->id_prototype);
+ if (proto.isObject())
+ obj->prototype = proto.objectValue();
+ return Value::fromObject(obj);
+}
+
+Value FunctionObject::call(Managed *, const Value &, Value *, int)
+{
+ return Value::undefinedValue();
+}
+
+void FunctionObject::markObjects(Managed *that)
+{
+ FunctionObject *o = static_cast<FunctionObject *>(that);
+ if (o->name)
+ o->name->mark();
+ // these are marked in VM::Function:
+// for (uint i = 0; i < formalParameterCount; ++i)
+// formalParameterList[i]->mark();
+// for (uint i = 0; i < varCount; ++i)
+// varList[i]->mark();
+ o->scope->mark();
+ if (o->function)
+ o->function->mark();
+
+ Object::markObjects(that);
+}
+
+
+DEFINE_MANAGED_VTABLE(FunctionCtor);
+
+FunctionCtor::FunctionCtor(ExecutionContext *scope)
+ : FunctionObject(scope, scope->engine->newIdentifier(QStringLiteral("Function")))
+{
+ vtbl = &static_vtbl;
+}
+
+// 15.3.2
+Value FunctionCtor::construct(Managed *that, Value *args, int argc)
+{
+ FunctionCtor *f = static_cast<FunctionCtor *>(that);
+ MemoryManager::GCBlocker gcBlocker(f->engine()->memoryManager);
+
+ ExecutionContext *ctx = f->engine()->current;
+ QString arguments;
+ QString body;
+ if (argc > 0) {
+ for (uint i = 0; i < argc - 1; ++i) {
+ if (i)
+ arguments += QLatin1String(", ");
+ arguments += args[i].toString(ctx)->toQString();
+ }
+ body = args[argc - 1].toString(ctx)->toQString();
+ }
+
+ QString function = QLatin1String("function(") + arguments + QLatin1String("){") + body + QLatin1String("}");
+
+ QQmlJS::Engine ee, *engine = &ee;
+ QQmlJS::Lexer lexer(engine);
+ lexer.setCode(function, 1, false);
+ QQmlJS::Parser parser(engine);
+
+ const bool parsed = parser.parseExpression();
+
+ if (!parsed)
+ f->engine()->current->throwSyntaxError(0);
+
+ using namespace QQmlJS::AST;
+ FunctionExpression *fe = QQmlJS::AST::cast<FunctionExpression *>(parser.rootNode());
+ ExecutionEngine *v4 = f->engine();
+ if (!fe)
+ v4->current->throwSyntaxError(0);
+
+ QQmlJS::V4IR::Module module;
+
+ QQmlJS::Codegen cg(v4->current, f->strictMode);
+ QQmlJS::V4IR::Function *irf = cg(QString(), function, fe, &module);
+
+ QScopedPointer<QQmlJS::EvalInstructionSelection> isel(v4->iselFactory->create(v4, &module));
+ QV4::Function *vmf = isel->vmFunction(irf);
+
+ return Value::fromObject(v4->newScriptFunction(v4->rootContext, vmf));
+}
+
+// 15.3.1: This is equivalent to new Function(...)
+Value FunctionCtor::call(Managed *that, const Value &, Value *args, int argc)
+{
+ return construct(that, args, argc);
+}
+
+FunctionPrototype::FunctionPrototype(ExecutionContext *ctx)
+ : FunctionObject(ctx)
+{
+}
+
+void FunctionPrototype::init(ExecutionContext *ctx, const Value &ctor)
+{
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(1));
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this));
+
+ defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(0));
+ defineDefaultProperty(ctx, QStringLiteral("constructor"), ctor);
+ defineDefaultProperty(ctx, QStringLiteral("toString"), method_toString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("apply"), method_apply, 2);
+ defineDefaultProperty(ctx, QStringLiteral("call"), method_call, 1);
+ defineDefaultProperty(ctx, QStringLiteral("bind"), method_bind, 1);
+
+}
+
+Value FunctionPrototype::method_toString(SimpleCallContext *ctx)
+{
+ FunctionObject *fun = ctx->thisObject.asFunctionObject();
+ if (!fun)
+ ctx->throwTypeError();
+
+ return Value::fromString(ctx, QStringLiteral("function() { [code] }"));
+}
+
+Value FunctionPrototype::method_apply(SimpleCallContext *ctx)
+{
+ Value thisArg = ctx->argument(0);
+
+ Value arg = ctx->argument(1);
+ QVector<Value> args;
+
+ if (Object *arr = arg.asObject()) {
+ quint32 len = arr->get(ctx->engine->id_length).toUInt32();
+ for (quint32 i = 0; i < len; ++i) {
+ Value a = arr->getIndexed(i);
+ args.append(a);
+ }
+ } else if (!(arg.isUndefined() || arg.isNull())) {
+ ctx->throwTypeError();
+ return Value::undefinedValue();
+ }
+
+ FunctionObject *o = ctx->thisObject.asFunctionObject();
+ if (!o)
+ ctx->throwTypeError();
+
+ return o->call(thisArg, args.data(), args.size());
+}
+
+Value FunctionPrototype::method_call(SimpleCallContext *ctx)
+{
+ Value thisArg = ctx->argument(0);
+
+ QVector<Value> args(ctx->argumentCount ? ctx->argumentCount - 1 : 0);
+ if (ctx->argumentCount)
+ qCopy(ctx->arguments + 1,
+ ctx->arguments + ctx->argumentCount, args.begin());
+
+ FunctionObject *o = ctx->thisObject.asFunctionObject();
+ if (!o)
+ ctx->throwTypeError();
+
+ return o->call(thisArg, args.data(), args.size());
+}
+
+Value FunctionPrototype::method_bind(SimpleCallContext *ctx)
+{
+ FunctionObject *target = ctx->thisObject.asFunctionObject();
+ if (!target)
+ ctx->throwTypeError();
+
+ Value boundThis = ctx->argument(0);
+ QVector<Value> boundArgs;
+ for (uint i = 1; i < ctx->argumentCount; ++i)
+ boundArgs += ctx->argument(i);
+
+
+ BoundFunction *f = ctx->engine->newBoundFunction(ctx->engine->rootContext, target, boundThis, boundArgs);
+ return Value::fromObject(f);
+}
+
+
+static Value throwTypeError(SimpleCallContext *ctx)
+{
+ ctx->throwTypeError();
+ return Value::undefinedValue();
+}
+
+DEFINE_MANAGED_VTABLE(ScriptFunction);
+
+ScriptFunction::ScriptFunction(ExecutionContext *scope, Function *function)
+ : FunctionObject(scope, function->name)
+{
+ vtbl = &static_vtbl;
+ this->function = function;
+ assert(function);
+ assert(function->code);
+
+ // global function
+ if (!scope)
+ return;
+
+ MemoryManager::GCBlocker gcBlocker(scope->engine->memoryManager);
+
+ needsActivation = function->needsActivation();
+ usesArgumentsObject = function->usesArgumentsObject;
+ strictMode = function->isStrict;
+ formalParameterCount = function->formals.size();
+ formalParameterList = function->formals.constData();
+ defineReadonlyProperty(scope->engine->id_length, Value::fromInt32(formalParameterCount));
+
+ varCount = function->locals.size();
+ varList = function->locals.constData();
+
+ Object *proto = scope->engine->newObject();
+ proto->defineDefaultProperty(scope->engine->id_constructor, Value::fromObject(this));
+ Property *pd = insertMember(scope->engine->id_prototype, Attr_NotEnumerable|Attr_NotConfigurable);
+ pd->value = Value::fromObject(proto);
+
+ if (scope->strictMode) {
+ FunctionObject *thrower = scope->engine->newBuiltinFunction(scope, 0, throwTypeError);
+ Property pd = Property::fromAccessor(thrower, thrower);
+ __defineOwnProperty__(scope, QStringLiteral("caller"), pd, Attr_Accessor|Attr_NotEnumerable|Attr_NotConfigurable);
+ __defineOwnProperty__(scope, QStringLiteral("arguments"), pd, Attr_Accessor|Attr_NotEnumerable|Attr_NotConfigurable);
+ }
+}
+
+Value ScriptFunction::construct(Managed *that, Value *args, int argc)
+{
+ ScriptFunction *f = static_cast<ScriptFunction *>(that);
+ assert(f->function->code);
+ ExecutionEngine *v4 = f->engine();
+ Object *obj = v4->newObject();
+ Value proto = f->get(v4->id_prototype);
+ if (proto.isObject())
+ obj->prototype = proto.objectValue();
+
+ ExecutionContext *context = v4->current;
+ quintptr stackSpace[stackContextSize/sizeof(quintptr)];
+ ExecutionContext *ctx = v4->newCallContext(stackSpace, f, Value::fromObject(obj), args, argc);
+
+ Value result;
+ try {
+ result = f->function->code(ctx, f->function->codeData);
+ } catch (Exception &ex) {
+ ex.partiallyUnwindContext(context);
+ throw;
+ }
+ ctx->engine->popContext();
+
+ if (result.isObject())
+ return result;
+ return Value::fromObject(obj);
+}
+
+Value ScriptFunction::call(Managed *that, const Value &thisObject, Value *args, int argc)
+{
+ ScriptFunction *f = static_cast<ScriptFunction *>(that);
+ assert(f->function->code);
+ quintptr stackSpace[stackContextSize/sizeof(quintptr)];
+ ExecutionContext *context = f->engine()->current;
+ ExecutionContext *ctx = f->engine()->newCallContext(stackSpace, f, thisObject, args, argc);
+
+ if (!f->strictMode && !thisObject.isObject()) {
+ if (thisObject.isUndefined() || thisObject.isNull()) {
+ ctx->thisObject = Value::fromObject(f->engine()->globalObject);
+ } else {
+ ctx->thisObject = Value::fromObject(thisObject.toObject(context));
+ }
+ }
+
+ Value result;
+ try {
+ result = f->function->code(ctx, f->function->codeData);
+ } catch (Exception &ex) {
+ ex.partiallyUnwindContext(context);
+ throw;
+ }
+ ctx->engine->popContext();
+ return result;
+}
+
+
+
+DEFINE_MANAGED_VTABLE(BuiltinFunctionOld);
+
+BuiltinFunctionOld::BuiltinFunctionOld(ExecutionContext *scope, String *name, Value (*code)(SimpleCallContext *))
+ : FunctionObject(scope, name)
+ , code(code)
+{
+ vtbl = &static_vtbl;
+ isBuiltinFunction = true;
+}
+
+Value BuiltinFunctionOld::construct(Managed *f, Value *, int)
+{
+ f->engine()->current->throwTypeError();
+ return Value::undefinedValue();
+}
+
+Value BuiltinFunctionOld::call(Managed *that, const Value &thisObject, Value *args, int argc)
+{
+ BuiltinFunctionOld *f = static_cast<BuiltinFunctionOld *>(that);
+ ExecutionEngine *v4 = f->engine();
+ ExecutionContext *context = v4->current;
+
+ SimpleCallContext ctx;
+ ctx.initSimpleCallContext(f->scope->engine);
+ ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context?
+ ctx.thisObject = thisObject;
+ ctx.arguments = args;
+ ctx.argumentCount = argc;
+ v4->pushContext(&ctx);
+
+ if (!f->strictMode && !thisObject.isObject()) {
+ // Built-in functions allow for the this object to be null or undefined. This overrides
+ // the behaviour of changing thisObject to the global object if null/undefined and allows
+ // the built-in functions for example to throw a type error if null is passed.
+ if (!thisObject.isUndefined() && !thisObject.isNull())
+ ctx.thisObject = Value::fromObject(thisObject.toObject(context));
+ }
+
+ Value result = Value::undefinedValue();
+ try {
+ result = f->code(&ctx);
+ } catch (Exception &ex) {
+ ex.partiallyUnwindContext(context);
+ throw;
+ }
+
+ context->engine->popContext();
+ return result;
+}
+
+Value IndexedBuiltinFunction::call(Managed *that, const Value &thisObject, Value *args, int argc)
+{
+ IndexedBuiltinFunction *f = static_cast<IndexedBuiltinFunction *>(that);
+ ExecutionEngine *v4 = f->engine();
+ ExecutionContext *context = v4->current;
+
+ SimpleCallContext ctx;
+ ctx.initSimpleCallContext(f->scope->engine);
+ ctx.strictMode = f->scope->strictMode; // ### needed? scope or parent context?
+ ctx.thisObject = thisObject;
+ ctx.arguments = args;
+ ctx.argumentCount = argc;
+ v4->pushContext(&ctx);
+
+ if (!f->strictMode && !thisObject.isObject()) {
+ // Built-in functions allow for the this object to be null or undefined. This overrides
+ // the behaviour of changing thisObject to the global object if null/undefined and allows
+ // the built-in functions for example to throw a type error if null is passed.
+ if (!thisObject.isUndefined() && !thisObject.isNull())
+ ctx.thisObject = Value::fromObject(thisObject.toObject(context));
+ }
+
+ Value result = Value::undefinedValue();
+ try {
+ result = f->code(&ctx, f->index);
+ } catch (Exception &ex) {
+ ex.partiallyUnwindContext(context);
+ throw;
+ }
+
+ context->engine->popContext();
+ return result;
+}
+
+DEFINE_MANAGED_VTABLE(IndexedBuiltinFunction);
+
+DEFINE_MANAGED_VTABLE(BoundFunction);
+
+BoundFunction::BoundFunction(ExecutionContext *scope, FunctionObject *target, Value boundThis, const QVector<Value> &boundArgs)
+ : FunctionObject(scope, 0)
+ , target(target)
+ , boundThis(boundThis)
+ , boundArgs(boundArgs)
+{
+ vtbl = &static_vtbl;
+ int len = target->get(scope->engine->id_length).toUInt32();
+ len -= boundArgs.size();
+ if (len < 0)
+ len = 0;
+ defineReadonlyProperty(scope->engine->id_length, Value::fromInt32(len));
+
+ FunctionObject *thrower = scope->engine->newBuiltinFunction(scope, 0, throwTypeError);
+ Property pd = Property::fromAccessor(thrower, thrower);
+ *insertMember(scope->engine->id_arguments, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable) = pd;
+ *insertMember(scope->engine->id_caller, Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable) = pd;
+}
+
+void BoundFunction::destroy(Managed *that)
+{
+ static_cast<BoundFunction *>(that)->~BoundFunction();
+}
+
+Value BoundFunction::call(Managed *that, const Value &, Value *args, int argc)
+{
+ BoundFunction *f = static_cast<BoundFunction *>(that);
+ Value *newArgs = static_cast<Value *>(alloca(sizeof(Value)*(f->boundArgs.size() + argc)));
+ memcpy(newArgs, f->boundArgs.constData(), f->boundArgs.size()*sizeof(Value));
+ memcpy(newArgs + f->boundArgs.size(), args, argc*sizeof(Value));
+
+ return f->target->call(f->boundThis, newArgs, f->boundArgs.size() + argc);
+}
+
+Value BoundFunction::construct(Managed *that, Value *args, int argc)
+{
+ BoundFunction *f = static_cast<BoundFunction *>(that);
+ Value *newArgs = static_cast<Value *>(alloca(sizeof(Value)*(f->boundArgs.size() + argc)));
+ memcpy(newArgs, f->boundArgs.constData(), f->boundArgs.size()*sizeof(Value));
+ memcpy(newArgs + f->boundArgs.size(), args, argc*sizeof(Value));
+
+ return f->target->construct(newArgs, f->boundArgs.size() + argc);
+}
+
+bool BoundFunction::hasInstance(Managed *that, const Value &value)
+{
+ BoundFunction *f = static_cast<BoundFunction *>(that);
+ return FunctionObject::hasInstance(f->target, value);
+}
+
+void BoundFunction::markObjects(Managed *that)
+{
+ BoundFunction *o = static_cast<BoundFunction *>(that);
+ o->target->mark();
+ if (Managed *m = o->boundThis.asManaged())
+ m->mark();
+ for (int i = 0; i < o->boundArgs.size(); ++i)
+ if (Managed *m = o->boundArgs.at(i).asManaged())
+ m->mark();
+ FunctionObject::markObjects(that);
+}
diff --git a/src/qml/qml/v4/qv4functionobject_p.h b/src/qml/qml/v4/qv4functionobject_p.h
new file mode 100644
index 0000000000..39e07a2b8d
--- /dev/null
+++ b/src/qml/qml/v4/qv4functionobject_p.h
@@ -0,0 +1,223 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4FUNCTIONOBJECT_H
+#define QV4FUNCTIONOBJECT_H
+
+#include "qv4global_p.h"
+#include "qv4runtime_p.h"
+#include "qv4engine_p.h"
+#include "qv4context_p.h"
+#include "qv4object_p.h"
+#include "qv4string_p.h"
+#include "qv4codegen_p.h"
+#include "qv4isel_p.h"
+#include "qv4managed_p.h"
+#include "qv4property_p.h"
+#include "qv4objectiterator_p.h"
+
+#include <QtCore/QString>
+#include <QtCore/QHash>
+#include <QtCore/QScopedPointer>
+#include <cstdio>
+#include <cassert>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct Function;
+struct Object;
+struct BooleanObject;
+struct NumberObject;
+struct StringObject;
+struct ArrayObject;
+struct DateObject;
+struct FunctionObject;
+struct ErrorObject;
+struct ArgumentsObject;
+struct ExecutionContext;
+struct ExecutionEngine;
+class MemoryManager;
+
+struct ObjectPrototype;
+struct StringPrototype;
+struct NumberPrototype;
+struct BooleanPrototype;
+struct ArrayPrototype;
+struct FunctionPrototype;
+struct DatePrototype;
+struct ErrorPrototype;
+struct EvalErrorPrototype;
+struct RangeErrorPrototype;
+struct ReferenceErrorPrototype;
+struct SyntaxErrorPrototype;
+struct TypeErrorPrototype;
+struct URIErrorPrototype;
+struct InternalClass;
+struct Lookup;
+
+struct Q_QML_EXPORT FunctionObject: Object {
+ // Used with Managed::subType
+ enum FunctionType {
+ RegularFunction = 0,
+ WrappedQtMethod = 1
+ };
+
+ ExecutionContext *scope;
+ String *name;
+ String * const *formalParameterList;
+ String * const *varList;
+ unsigned int formalParameterCount;
+ unsigned int varCount;
+ Function *function;
+
+ FunctionObject(ExecutionContext *scope, String *name = 0);
+
+ Value newInstance();
+
+ static Value construct(Managed *that, Value *args, int argc);
+ static Value call(Managed *that, const Value &, Value *, int);
+ inline Value construct(Value *args, int argc) {
+ return vtbl->construct(this, args, argc);
+ }
+ inline Value call(const Value &thisObject, Value *args, int argc) {
+ return vtbl->call(this, thisObject, args, argc);
+ }
+
+protected:
+ static const ManagedVTable static_vtbl;
+ static void markObjects(Managed *that);
+ static bool hasInstance(Managed *that, const Value &value);
+};
+
+struct FunctionCtor: FunctionObject
+{
+ FunctionCtor(ExecutionContext *scope);
+
+ static Value construct(Managed *that, Value *args, int argc);
+ static Value call(Managed *that, const Value &, Value *, int);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct FunctionPrototype: FunctionObject
+{
+ FunctionPrototype(ExecutionContext *ctx);
+ void init(ExecutionContext *ctx, const Value &ctor);
+
+ static Value method_toString(SimpleCallContext *ctx);
+ static Value method_apply(SimpleCallContext *ctx);
+ static Value method_call(SimpleCallContext *ctx);
+ static Value method_bind(SimpleCallContext *ctx);
+};
+
+struct BuiltinFunctionOld: FunctionObject {
+ Value (*code)(SimpleCallContext *);
+
+ BuiltinFunctionOld(ExecutionContext *scope, String *name, Value (*code)(SimpleCallContext *));
+
+ static Value construct(Managed *, Value *args, int argc);
+ static Value call(Managed *that, const Value &, Value *, int);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct IndexedBuiltinFunction: FunctionObject
+{
+ Q_MANAGED
+
+ Value (*code)(SimpleCallContext *ctx, uint index);
+ uint index;
+
+ IndexedBuiltinFunction(ExecutionContext *scope, uint index, Value (*code)(SimpleCallContext *ctx, uint index))
+ : FunctionObject(scope, /*name*/0)
+ , code(code)
+ , index(index)
+ {
+ vtbl = &static_vtbl;
+ isBuiltinFunction = true;
+ }
+
+ static Value construct(Managed *m, Value *, int)
+ {
+ m->engine()->current->throwTypeError();
+ return Value::undefinedValue();
+ }
+
+ static Value call(Managed *that, const Value &thisObject, Value *args, int argc);
+};
+
+
+struct ScriptFunction: FunctionObject {
+ ScriptFunction(ExecutionContext *scope, Function *function);
+
+ static Value construct(Managed *, Value *args, int argc);
+ static Value call(Managed *that, const Value &, Value *, int);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct BoundFunction: FunctionObject {
+ FunctionObject *target;
+ Value boundThis;
+ QVector<Value> boundArgs;
+
+ BoundFunction(ExecutionContext *scope, FunctionObject *target, Value boundThis, const QVector<Value> &boundArgs);
+ ~BoundFunction() {}
+
+
+ static Value construct(Managed *, Value *args, int argc);
+ static Value call(Managed *that, const Value &, Value *, int);
+
+ static const ManagedVTable static_vtbl;
+ static void destroy(Managed *);
+ static void markObjects(Managed *that);
+ static bool hasInstance(Managed *that, const Value &value);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QMLJS_OBJECTS_H
diff --git a/src/qml/qml/v4/qv4global_p.h b/src/qml/qml/v4/qv4global_p.h
new file mode 100644
index 0000000000..8e47f3c88a
--- /dev/null
+++ b/src/qml/qml/v4/qv4global_p.h
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4GLOBAL_H
+#define QV4GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#include <qtqmlglobal.h>
+
+#if defined(Q_CC_MSVC)
+namespace std {
+
+inline bool isinf(double d) { return !_finite(d) && !_isnan(d); }
+inline bool isnan(double d) { return !!_isnan(d); }
+inline bool isfinite(double d) { return _finite(d); }
+inline bool signbit(double d) { return _copysign(1.0, d) < 0; }
+
+} // namespace std
+
+inline double trunc(double d) { return d > 0 ? floor(d) : ceil(d); }
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+class MemoryManager;
+struct String;
+struct Object;
+struct ObjectPrototype;
+struct ObjectIterator;
+struct ExecutionContext;
+struct ScriptFunction;
+struct InternalClass;
+struct Property;
+
+struct BooleanObject;
+struct NumberObject;
+struct StringObject;
+struct ArrayObject;
+struct DateObject;
+struct FunctionObject;
+struct ErrorObject;
+struct ArgumentsObject;
+struct Managed;
+struct Lookup;
+struct ExecutionEngine;
+struct QObjectWrapper;
+
+
+enum PropertyFlag {
+ Attr_Data = 0,
+ Attr_Accessor = 0x1,
+ Attr_NotWritable = 0x2,
+ Attr_NotEnumerable = 0x4,
+ Attr_NotConfigurable = 0x8,
+ Attr_ReadOnly = Attr_NotWritable|Attr_NotEnumerable|Attr_NotConfigurable,
+ Attr_Invalid = 0xff
+};
+
+Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag);
+Q_DECLARE_OPERATORS_FOR_FLAGS(PropertyFlags);
+
+struct PropertyAttributes
+{
+ union {
+ uchar m_all;
+ struct {
+ uchar m_flags : 4;
+ uchar m_mask : 4;
+ };
+ struct {
+ uchar m_type : 1;
+ uchar m_writable : 1;
+ uchar m_enumerable : 1;
+ uchar m_configurable : 1;
+ uchar type_set : 1;
+ uchar writable_set : 1;
+ uchar enumerable_set : 1;
+ uchar configurable_set : 1;
+ };
+ };
+
+ enum Type {
+ Data = 0,
+ Accessor = 1,
+ Generic = 2
+ };
+
+ PropertyAttributes() : m_all(0) {}
+ PropertyAttributes(PropertyFlag f) : m_all(0) {
+ if (f != Attr_Invalid) {
+ setType(f & Attr_Accessor ? Accessor : Data);
+ if (!(f & Attr_Accessor))
+ setWritable(!(f & Attr_NotWritable));
+ setEnumerable(!(f & Attr_NotEnumerable));
+ setConfigurable(!(f & Attr_NotConfigurable));
+ }
+ }
+ PropertyAttributes(PropertyFlags f) : m_all(0) {
+ if (f != Attr_Invalid) {
+ setType(f & Attr_Accessor ? Accessor : Data);
+ if (!(f & Attr_Accessor))
+ setWritable(!(f & Attr_NotWritable));
+ setEnumerable(!(f & Attr_NotEnumerable));
+ setConfigurable(!(f & Attr_NotConfigurable));
+ }
+ }
+ PropertyAttributes(const PropertyAttributes &other) : m_all(other.m_all) {}
+ PropertyAttributes & operator=(const PropertyAttributes &other) { m_all = other.m_all; return *this; }
+
+ void setType(Type t) { m_type = t; type_set = true; }
+ Type type() const { return type_set ? (Type)m_type : Generic; }
+
+ bool isData() const { return type() == PropertyAttributes::Data || writable_set; }
+ bool isAccessor() const { return type() == PropertyAttributes::Accessor; }
+ bool isGeneric() const { return type() == PropertyAttributes::Generic && !writable_set; }
+
+ bool hasType() const { return type_set; }
+ bool hasWritable() const { return writable_set; }
+ bool hasConfigurable() const { return configurable_set; }
+ bool hasEnumerable() const { return enumerable_set; }
+
+ void setWritable(bool b) { m_writable = b; writable_set = true; }
+ void setConfigurable(bool b) { m_configurable = b; configurable_set = true; }
+ void setEnumerable(bool b) { m_enumerable = b; enumerable_set = true; }
+
+ void resolve() { m_mask = 0xf; if (m_type == Accessor) { m_writable = false; writable_set = false; } }
+
+ bool isWritable() const { return m_type != Data || m_writable; }
+ bool isEnumerable() const { return m_enumerable; }
+ bool isConfigurable() const { return m_configurable; }
+
+ void clearType() { m_type = Data; type_set = false; }
+ void clearWritable() { m_writable = false; writable_set = false; }
+ void clearEnumerable() { m_enumerable = false; enumerable_set = false; }
+ void clearConfigurable() { m_configurable = false; configurable_set = false; }
+
+ void clear() { m_all = 0; }
+ bool isEmpty() const { return !m_all; }
+
+ uint flags() const { return m_flags; }
+
+ bool operator==(PropertyAttributes other) {
+ return m_all == other.m_all;
+ }
+ bool operator!=(PropertyAttributes other) {
+ return m_all != other.m_all;
+ }
+};
+
+}
+
+Q_DECLARE_TYPEINFO(QV4::PropertyAttributes, Q_PRIMITIVE_TYPE);
+
+QT_END_NAMESPACE
+
+#endif // QV4GLOBAL_H
diff --git a/src/qml/qml/v4/qv4globalobject.cpp b/src/qml/qml/v4/qv4globalobject.cpp
new file mode 100644
index 0000000000..6b279416a3
--- /dev/null
+++ b/src/qml/qml/v4/qv4globalobject.cpp
@@ -0,0 +1,652 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4globalobject_p.h"
+#include "qv4mm_p.h"
+#include "qv4value_p.h"
+#include "qv4context_p.h"
+#include "qv4function_p.h"
+#include "qv4debugging_p.h"
+#include "qv4script_p.h"
+#include "qv4exception_p.h"
+
+#include <private/qqmljsengine_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljsast_p.h>
+#include <qv4jsir_p.h>
+#include <qv4codegen_p.h>
+#include "private/qlocale_tools_p.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QString>
+#include <iostream>
+#include "qv4alloca_p.h"
+
+#include <wtf/MathExtras.h>
+
+using namespace QV4;
+
+
+static inline char toHex(char c)
+{
+ static const char hexnumbers[] = "0123456789ABCDEF";
+ return hexnumbers[c & 0xf];
+}
+
+static int fromHex(QChar ch)
+{
+ ushort c = ch.unicode();
+ if ((c >= '0') && (c <= '9'))
+ return c - '0';
+ if ((c >= 'A') && (c <= 'F'))
+ return c - 'A' + 10;
+ if ((c >= 'a') && (c <= 'f'))
+ return c - 'a' + 10;
+ return -1;
+}
+
+static QString escape(const QString &input)
+{
+ QString output;
+ output.reserve(input.size() * 3);
+ const int length = input.length();
+ for (int i = 0; i < length; ++i) {
+ ushort uc = input.at(i).unicode();
+ if (uc < 0x100) {
+ if ( (uc > 0x60 && uc < 0x7B)
+ || (uc > 0x3F && uc < 0x5B)
+ || (uc > 0x2C && uc < 0x3A)
+ || (uc == 0x2A)
+ || (uc == 0x2B)
+ || (uc == 0x5F)) {
+ output.append(QChar(uc));
+ } else {
+ output.append('%');
+ output.append(QChar(toHex(uc >> 4)));
+ output.append(QChar(toHex(uc)));
+ }
+ } else {
+ output.append('%');
+ output.append('u');
+ output.append(QChar(toHex(uc >> 12)));
+ output.append(QChar(toHex(uc >> 8)));
+ output.append(QChar(toHex(uc >> 4)));
+ output.append(QChar(toHex(uc)));
+ }
+ }
+ return output;
+}
+
+static QString unescape(const QString &input)
+{
+ QString result;
+ result.reserve(input.length());
+ int i = 0;
+ const int length = input.length();
+ while (i < length) {
+ QChar c = input.at(i++);
+ if ((c == '%') && (i + 1 < length)) {
+ QChar a = input.at(i);
+ if ((a == 'u') && (i + 4 < length)) {
+ int d3 = fromHex(input.at(i+1));
+ int d2 = fromHex(input.at(i+2));
+ int d1 = fromHex(input.at(i+3));
+ int d0 = fromHex(input.at(i+4));
+ if ((d3 != -1) && (d2 != -1) && (d1 != -1) && (d0 != -1)) {
+ ushort uc = ushort((d3 << 12) | (d2 << 8) | (d1 << 4) | d0);
+ result.append(QChar(uc));
+ i += 5;
+ } else {
+ result.append(c);
+ }
+ } else {
+ int d1 = fromHex(a);
+ int d0 = fromHex(input.at(i+1));
+ if ((d1 != -1) && (d0 != -1)) {
+ c = (d1 << 4) | d0;
+ i += 2;
+ }
+ result.append(c);
+ }
+ } else {
+ result.append(c);
+ }
+ }
+ return result;
+}
+
+static const char uriReserved[] = ";/?:@&=+$,#";
+static const char uriUnescaped[] = "-_.!~*'()";
+static const char uriUnescapedReserved[] = "-_.!~*'();/?:@&=+$,#";
+
+static void addEscapeSequence(QString &output, uchar ch)
+{
+ output.append(QLatin1Char('%'));
+ output.append(QLatin1Char(toHex(ch >> 4)));
+ output.append(QLatin1Char(toHex(ch & 0xf)));
+}
+
+static QString encode(const QString &input, const char *unescapedSet, bool *ok)
+{
+ *ok = true;
+ QString output;
+ const int length = input.length();
+ int i = 0;
+ while (i < length) {
+ const QChar c = input.at(i);
+ bool escape = true;
+ if ((c.unicode() >= 'a' && c.unicode() <= 'z') ||
+ (c.unicode() >= 'A' && c.unicode() <= 'Z') ||
+ (c.unicode() >= '0' && c.unicode() <= '9')) {
+ escape = false;
+ } else {
+ const char *r = unescapedSet;
+ while (*r) {
+ if (*r == c.unicode()) {
+ escape = false;
+ break;
+ }
+ ++r;
+ }
+ }
+ if (escape) {
+ uint uc = c.unicode();
+ if ((uc >= 0xDC00) && (uc <= 0xDFFF)) {
+ *ok = false;
+ break;
+ }
+ if (!((uc < 0xD800) || (uc > 0xDBFF))) {
+ ++i;
+ if (i == length) {
+ *ok = false;
+ break;
+ }
+ const uint uc2 = input.at(i).unicode();
+ if ((uc2 < 0xDC00) || (uc2 > 0xDFFF)) {
+ *ok = false;
+ break;
+ }
+ uc = ((uc - 0xD800) * 0x400) + (uc2 - 0xDC00) + 0x10000;
+ }
+ if (uc < 0x80) {
+ addEscapeSequence(output, (uchar)uc);
+ } else {
+ if (uc < 0x0800) {
+ addEscapeSequence(output, 0xc0 | ((uchar) (uc >> 6)));
+ } else {
+
+ if (QChar::requiresSurrogates(uc)) {
+ addEscapeSequence(output, 0xf0 | ((uchar) (uc >> 18)));
+ addEscapeSequence(output, 0x80 | (((uchar) (uc >> 12)) & 0x3f));
+ } else {
+ addEscapeSequence(output, 0xe0 | (((uchar) (uc >> 12)) & 0x3f));
+ }
+ addEscapeSequence(output, 0x80 | (((uchar) (uc >> 6)) & 0x3f));
+ }
+ addEscapeSequence(output, 0x80 | ((uchar) (uc&0x3f)));
+ }
+ } else {
+ output.append(c);
+ }
+ ++i;
+ }
+ if (i != length)
+ *ok = false;
+ return output;
+}
+
+enum DecodeMode {
+ DecodeAll,
+ DecodeNonReserved
+};
+
+static QString decode(const QString &input, DecodeMode decodeMode, bool *ok)
+{
+ *ok = true;
+ QString output;
+ output.reserve(input.length());
+ const int length = input.length();
+ int i = 0;
+ const QChar percent = QLatin1Char('%');
+ while (i < length) {
+ const QChar ch = input.at(i);
+ if (ch == percent) {
+ int start = i;
+ if (i + 2 >= length)
+ goto error;
+
+ int d1 = fromHex(input.at(i+1));
+ int d0 = fromHex(input.at(i+2));
+ if ((d1 == -1) || (d0 == -1))
+ goto error;
+
+ int b = (d1 << 4) | d0;
+ i += 2;
+ if (b & 0x80) {
+ int uc;
+ int min_uc;
+ int need;
+ if ((b & 0xe0) == 0xc0) {
+ uc = b & 0x1f;
+ need = 1;
+ min_uc = 0x80;
+ } else if ((b & 0xf0) == 0xe0) {
+ uc = b & 0x0f;
+ need = 2;
+ min_uc = 0x800;
+ } else if ((b & 0xf8) == 0xf0) {
+ uc = b & 0x07;
+ need = 3;
+ min_uc = 0x10000;
+ } else {
+ goto error;
+ }
+
+ if (i + (3 * need) >= length)
+ goto error;
+
+ for (int j = 0; j < need; ++j) {
+ ++i;
+ if (input.at(i) != percent)
+ goto error;
+
+ d1 = fromHex(input.at(i+1));
+ d0 = fromHex(input.at(i+2));
+ if ((d1 == -1) || (d0 == -1))
+ goto error;
+
+ b = (d1 << 4) | d0;
+ if ((b & 0xC0) != 0x80)
+ goto error;
+
+ i += 2;
+ uc = (uc << 6) + (b & 0x3f);
+ }
+ if (uc < min_uc)
+ goto error;
+
+ if (uc < 0x10000) {
+ output.append(QChar(uc));
+ } else {
+ if (uc > 0x10FFFF)
+ goto error;
+
+ ushort l = ushort(((uc - 0x10000) & 0x3FF) + 0xDC00);
+ ushort h = ushort((((uc - 0x10000) >> 10) & 0x3FF) + 0xD800);
+ output.append(QChar(h));
+ output.append(QChar(l));
+ }
+ } else {
+ if (decodeMode == DecodeNonReserved && b <= 0x40) {
+ const char *r = uriReserved;
+ while (*r) {
+ if (*r == b)
+ break;
+ ++r;
+ }
+ if (*r)
+ output.append(input.mid(start, i - start + 1));
+ else
+ output.append(QChar(b));
+ } else {
+ output.append(QChar(b));
+ }
+ }
+ } else {
+ output.append(ch);
+ }
+ ++i;
+ }
+ if (i != length)
+ *ok = false;
+ return output;
+ error:
+ *ok = false;
+ return QString();
+}
+
+DEFINE_MANAGED_VTABLE(EvalFunction);
+
+EvalFunction::EvalFunction(ExecutionContext *scope)
+ : FunctionObject(scope, scope->engine->id_eval)
+{
+ vtbl = &static_vtbl;
+ defineReadonlyProperty(scope->engine->id_length, Value::fromInt32(1));
+}
+
+Value EvalFunction::evalCall(Value /*thisObject*/, Value *args, int argc, bool directCall)
+{
+ if (argc < 1)
+ return Value::undefinedValue();
+
+ ExecutionContext *parentContext = engine()->current;
+ ExecutionEngine *engine = parentContext->engine;
+ ExecutionContext *ctx = parentContext;
+
+ if (!directCall) {
+ // the context for eval should be the global scope, so we fake a root
+ // context
+ ctx = engine->pushGlobalContext();
+ }
+
+ if (!args[0].isString())
+ return args[0];
+
+ const QString code = args[0].stringValue()->toQString();
+ bool inheritContext = !ctx->strictMode;
+
+ Script script(ctx, code, QString("eval code"));
+ script.strictMode = (directCall && parentContext->strictMode);
+ script.inheritContext = inheritContext;
+ script.parse();
+
+ Function *function = script.function();
+ if (!function)
+ return Value::undefinedValue();
+
+ strictMode = function->isStrict || (ctx->strictMode);
+
+ usesArgumentsObject = function->usesArgumentsObject;
+ needsActivation = function->needsActivation();
+
+ if (strictMode) {
+ FunctionObject *e = engine->newScriptFunction(ctx, function);
+ return e->call(ctx->thisObject, 0, 0);
+ }
+
+ ExecutionContext::EvalCode evalCode;
+ evalCode.function = function;
+ evalCode.next = ctx->currentEvalCode;
+ ctx->currentEvalCode = &evalCode;
+
+ // set the correct strict mode flag on the context
+ bool cstrict = ctx->strictMode;
+ ctx->strictMode = strictMode;
+
+ Value result = Value::undefinedValue();
+ try {
+ result = function->code(ctx, function->codeData);
+ } catch (Exception &ex) {
+ ctx->strictMode = cstrict;
+ ctx->currentEvalCode = evalCode.next;
+ if (strictMode)
+ ex.partiallyUnwindContext(parentContext);
+ throw;
+ }
+
+ ctx->strictMode = cstrict;
+ ctx->currentEvalCode = evalCode.next;
+
+ while (engine->current != parentContext)
+ engine->popContext();
+
+ return result;
+}
+
+
+Value EvalFunction::call(Managed *that, const Value &thisObject, Value *args, int argc)
+{
+ // indirect call
+ return static_cast<EvalFunction *>(that)->evalCall(thisObject, args, argc, false);
+}
+
+
+static inline int toInt(const QChar &qc, int R)
+{
+ ushort c = qc.unicode();
+ int v = -1;
+ if (c >= '0' && c <= '9')
+ v = c - '0';
+ else if (c >= 'A' && c <= 'Z')
+ v = c - 'A' + 10;
+ else if (c >= 'a' && c <= 'z')
+ v = c - 'a' + 10;
+ if (v >= 0 && v < R)
+ return v;
+ else
+ return -1;
+}
+
+// parseInt [15.1.2.2]
+Value GlobalFunctions::method_parseInt(SimpleCallContext *context)
+{
+ Value string = context->argument(0);
+ Value radix = context->argument(1);
+ int R = radix.isUndefined() ? 0 : radix.toInt32();
+
+ // [15.1.2.2] step by step:
+ String *inputString = string.toString(context); // 1
+ QString trimmed = inputString->toQString().trimmed(); // 2
+ const QChar *pos = trimmed.constData();
+ const QChar *end = pos + trimmed.length();
+
+ int sign = 1; // 3
+ if (pos != end) {
+ if (*pos == QLatin1Char('-'))
+ sign = -1; // 4
+ if (*pos == QLatin1Char('-') || *pos == QLatin1Char('+'))
+ ++pos; // 5
+ }
+ bool stripPrefix = true; // 7
+ if (R) { // 8
+ if (R < 2 || R > 36)
+ return Value::fromDouble(std::numeric_limits<double>::quiet_NaN()); // 8a
+ if (R != 16)
+ stripPrefix = false; // 8b
+ } else { // 9
+ R = 10; // 9a
+ }
+ if (stripPrefix) { // 10
+ if ((end - pos >= 2)
+ && (pos[0] == QLatin1Char('0'))
+ && (pos[1] == QLatin1Char('x') || pos[1] == QLatin1Char('X'))) { // 10a
+ pos += 2;
+ R = 16;
+ }
+ }
+ // 11: Z is progressively built below
+ // 13: this is handled by the toInt function
+ if (pos == end) // 12
+ return Value::fromDouble(std::numeric_limits<double>::quiet_NaN());
+ bool overflow = false;
+ qint64 v_overflow;
+ unsigned overflow_digit_count = 0;
+ int d = toInt(*pos++, R);
+ if (d == -1)
+ return Value::fromDouble(std::numeric_limits<double>::quiet_NaN());
+ qint64 v = d;
+ while (pos != end) {
+ d = toInt(*pos++, R);
+ if (d == -1)
+ break;
+ if (overflow) {
+ if (overflow_digit_count == 0) {
+ v_overflow = v;
+ v = 0;
+ }
+ ++overflow_digit_count;
+ v = v * R + d;
+ } else {
+ qint64 vNew = v * R + d;
+ if (vNew < v) {
+ overflow = true;
+ --pos;
+ } else {
+ v = vNew;
+ }
+ }
+ }
+
+ if (overflow) {
+ double result = (double) v_overflow * pow(R, overflow_digit_count);
+ result += v;
+ return Value::fromDouble(sign * result);
+ } else {
+ return Value::fromDouble(sign * (double) v); // 15
+ }
+}
+
+// parseFloat [15.1.2.3]
+Value GlobalFunctions::method_parseFloat(SimpleCallContext *context)
+{
+ Value string = context->argument(0);
+
+ // [15.1.2.3] step by step:
+ String *inputString = string.toString(context); // 1
+ QString trimmed = inputString->toQString().trimmed(); // 2
+
+ // 4:
+ if (trimmed.startsWith(QLatin1String("Infinity"))
+ || trimmed.startsWith(QLatin1String("+Infinity")))
+ return Value::fromDouble(Q_INFINITY);
+ if (trimmed.startsWith("-Infinity"))
+ return Value::fromDouble(-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 Value::fromDouble(std::numeric_limits<double>::quiet_NaN()); // 3
+ else
+ return Value::fromDouble(d);
+}
+
+/// isNaN [15.1.2.4]
+Value GlobalFunctions::method_isNaN(SimpleCallContext *context)
+{
+ const Value &v = context->argument(0);
+ if (v.integerCompatible())
+ return Value::fromBoolean(false);
+
+ double d = v.toNumber();
+ return Value::fromBoolean(std::isnan(d));
+}
+
+/// isFinite [15.1.2.5]
+Value GlobalFunctions::method_isFinite(SimpleCallContext *context)
+{
+ const Value &v = context->argument(0);
+ if (v.integerCompatible())
+ return Value::fromBoolean(true);
+
+ double d = v.toNumber();
+ return Value::fromBoolean(std::isfinite(d));
+}
+
+/// decodeURI [15.1.3.1]
+Value GlobalFunctions::method_decodeURI(SimpleCallContext *context)
+{
+ if (context->argumentCount == 0)
+ return Value::undefinedValue();
+
+ QString uriString = context->arguments[0].toString(context)->toQString();
+ bool ok;
+ QString out = decode(uriString, DecodeNonReserved, &ok);
+ if (!ok)
+ context->throwURIError(Value::fromString(context, QStringLiteral("malformed URI sequence")));
+
+ return Value::fromString(context, out);
+}
+
+/// decodeURIComponent [15.1.3.2]
+Value GlobalFunctions::method_decodeURIComponent(SimpleCallContext *context)
+{
+ if (context->argumentCount == 0)
+ return Value::undefinedValue();
+
+ QString uriString = context->arguments[0].toString(context)->toQString();
+ bool ok;
+ QString out = decode(uriString, DecodeAll, &ok);
+ if (!ok)
+ context->throwURIError(Value::fromString(context, QStringLiteral("malformed URI sequence")));
+
+ return Value::fromString(context, out);
+}
+
+/// encodeURI [15.1.3.3]
+Value GlobalFunctions::method_encodeURI(SimpleCallContext *context)
+{
+ if (context->argumentCount == 0)
+ return Value::undefinedValue();
+
+ QString uriString = context->arguments[0].toString(context)->toQString();
+ bool ok;
+ QString out = encode(uriString, uriUnescapedReserved, &ok);
+ if (!ok)
+ context->throwURIError(Value::fromString(context, QStringLiteral("malformed URI sequence")));
+
+ return Value::fromString(context, out);
+}
+
+/// encodeURIComponent [15.1.3.4]
+Value GlobalFunctions::method_encodeURIComponent(SimpleCallContext *context)
+{
+ if (context->argumentCount == 0)
+ return Value::undefinedValue();
+
+ QString uriString = context->arguments[0].toString(context)->toQString();
+ bool ok;
+ QString out = encode(uriString, uriUnescaped, &ok);
+ if (!ok)
+ context->throwURIError(Value::fromString(context, QStringLiteral("malformed URI sequence")));
+
+ return Value::fromString(context, out);
+}
+
+Value GlobalFunctions::method_escape(SimpleCallContext *context)
+{
+ if (!context->argumentCount)
+ return Value::fromString(context, QStringLiteral("undefined"));
+
+ QString str = context->argument(0).toString(context)->toQString();
+ return Value::fromString(context, escape(str));
+}
+
+Value GlobalFunctions::method_unescape(SimpleCallContext *context)
+{
+ if (!context->argumentCount)
+ return Value::fromString(context, QStringLiteral("undefined"));
+
+ QString str = context->argument(0).toString(context)->toQString();
+ return Value::fromString(context, unescape(str));
+}
diff --git a/src/qml/qml/v8/qscripttools_p.h b/src/qml/qml/v4/qv4globalobject_p.h
index 29adfa4ef9..11d034b5b4 100644
--- a/src/qml/qml/v8/qscripttools_p.h
+++ b/src/qml/qml/v4/qv4globalobject_p.h
@@ -38,49 +38,45 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+#ifndef QV4GLOBALOBJECT_H
+#define QV4GLOBALOBJECT_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 "qv4global_p.h"
+#include "qv4functionobject_p.h"
+QT_BEGIN_NAMESPACE
-#ifndef QSCRIPTTOOLS_P_H
-#define QSCRIPTTOOLS_P_H
+namespace QV4 {
-#include <private/qintrusivelist_p.h>
+struct Q_QML_EXPORT EvalFunction : FunctionObject
+{
+ EvalFunction(ExecutionContext *scope);
-QT_BEGIN_NAMESPACE
+ Value evalCall(Value thisObject, Value *args, int argc, bool directCall);
-template<class N, QIntrusiveListNode N::*member>
-class QScriptIntrusiveList : public QIntrusiveList<N, member>
-{
-public:
- inline void insert(N *n);
- inline void remove(N *n);
+ using Managed::construct;
+ static Value call(Managed *that, const Value &, Value *, int);
+
+protected:
+ static const ManagedVTable static_vtbl;
};
-template<class N, QIntrusiveListNode N::*member>
-void QScriptIntrusiveList<N, member>::insert(N *n)
+struct GlobalFunctions
{
- Q_ASSERT_X(!this->contains(n), Q_FUNC_INFO, "Can't insert a value which is in the list already");
- Q_ASSERT_X(!(n->*member).isInList(), Q_FUNC_INFO, "Can't insert a value which is in another list");
- QIntrusiveList<N, member>::insert(n);
-}
+ static Value method_parseInt(SimpleCallContext *context);
+ static Value method_parseFloat(SimpleCallContext *context);
+ static Value method_isNaN(SimpleCallContext *context);
+ static Value method_isFinite(SimpleCallContext *context);
+ static Value method_decodeURI(SimpleCallContext *context);
+ static Value method_decodeURIComponent(SimpleCallContext *context);
+ static Value method_encodeURI(SimpleCallContext *context);
+ static Value method_encodeURIComponent(SimpleCallContext *context);
+ static Value method_escape(SimpleCallContext *context);
+ static Value method_unescape(SimpleCallContext *context);
+};
-template<class N, QIntrusiveListNode N::*member>
-void QScriptIntrusiveList<N, member>::remove(N *n)
-{
- Q_ASSERT_X(this->contains(n), Q_FUNC_INFO, "Can't remove a value which is not in the list");
- QIntrusiveList<N, member>::remove(n);
}
QT_END_NAMESPACE
-#endif //QSCRIPTTOOLS_P_H
+#endif // QMLJS_OBJECTS_H
diff --git a/src/qml/qml/v4/qv4identifier.cpp b/src/qml/qml/v4/qv4identifier.cpp
new file mode 100644
index 0000000000..5d8077bfdc
--- /dev/null
+++ b/src/qml/qml/v4/qv4identifier.cpp
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qv4identifier_p.h"
+#include "qv4identifiertable_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+static const uchar prime_deltas[] = {
+ 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
+ 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
+};
+
+static inline int primeForNumBits(int numBits)
+{
+ return (1 << numBits) + prime_deltas[numBits];
+}
+
+
+IdentifierHashData::IdentifierHashData(int numBits)
+ : numBits(numBits)
+ , size(0)
+{
+ refCount.store(1);
+ alloc = primeForNumBits(numBits);
+ entries = (IdentifierHashEntry *)malloc(alloc*sizeof(IdentifierHashEntry));
+ memset(entries, 0, alloc*sizeof(IdentifierHashEntry));
+}
+
+IdentifierHashBase::IdentifierHashBase(ExecutionEngine *engine)
+{
+ d = new IdentifierHashData(3);
+ d->identifierTable = engine->identifierTable;
+}
+
+
+IdentifierHashEntry *IdentifierHashBase::addEntry(const Identifier *identifier)
+{
+ // fill up to max 50%
+ bool grow = (d->alloc <= d->size*2);
+
+ if (grow) {
+ ++d->numBits;
+ int newAlloc = primeForNumBits(d->numBits);
+ IdentifierHashEntry *newEntries = (IdentifierHashEntry *)malloc(newAlloc * sizeof(IdentifierHashEntry));
+ memset(newEntries, 0, newAlloc*sizeof(IdentifierHashEntry));
+ for (uint i = 0; i < d->alloc; ++i) {
+ const IdentifierHashEntry &e = d->entries[i];
+ if (!e.identifier)
+ continue;
+ uint idx = e.identifier->hashValue % newAlloc;
+ while (newEntries[idx].identifier) {
+ ++idx;
+ idx %= newAlloc;
+ }
+ newEntries[idx] = e;
+ }
+ free(d->entries);
+ d->entries = newEntries;
+ d->alloc = newAlloc;
+ }
+
+ uint idx = identifier->hashValue % d->alloc;
+ while (d->entries[idx].identifier) {
+ Q_ASSERT(d->entries[idx].identifier != identifier);
+ ++idx;
+ idx %= d->alloc;
+ }
+ d->entries[idx].identifier = identifier;
+ ++d->size;
+ return d->entries + idx;
+}
+
+const IdentifierHashEntry *IdentifierHashBase::lookup(const Identifier *identifier) const
+{
+ if (!d)
+ return 0;
+ assert(d->entries);
+
+ uint idx = identifier->hashValue % d->alloc;
+ while (1) {
+ if (!d->entries[idx].identifier)
+ return 0;
+ if (d->entries[idx].identifier == identifier)
+ return d->entries + idx;
+ ++idx;
+ idx %= d->alloc;
+ }
+}
+
+const IdentifierHashEntry *IdentifierHashBase::lookup(const QString &str) const
+{
+ if (!d)
+ return 0;
+ assert(d->entries);
+
+ uint hash = String::createHashValue(str.constData(), str.length());
+ uint idx = hash % d->alloc;
+ while (1) {
+ if (!d->entries[idx].identifier)
+ return 0;
+ if (d->entries[idx].identifier->string == str)
+ return d->entries + idx;
+ ++idx;
+ idx %= d->alloc;
+ }
+}
+
+const IdentifierHashEntry *IdentifierHashBase::lookup(String *str) const
+{
+ if (!d)
+ return 0;
+ if (str->identifier)
+ return lookup(str->identifier);
+ return lookup(str->toQString());
+}
+
+const Identifier *IdentifierHashBase::toIdentifier(const QString &str) const
+{
+ Q_ASSERT(d);
+ return d->identifierTable->identifier(str);
+}
+
+const Identifier *IdentifierHashBase::toIdentifier(String *str) const
+{
+ Q_ASSERT(d);
+ return d->identifierTable->identifier(str);
+}
+
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4identifier_p.h b/src/qml/qml/v4/qv4identifier_p.h
new file mode 100644
index 0000000000..7c69e1d8c4
--- /dev/null
+++ b/src/qml/qml/v4/qv4identifier_p.h
@@ -0,0 +1,220 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4IDENTIFIER_H
+#define QV4IDENTIFIER_H
+
+#include <qstring.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct String;
+struct IdentifierTable;
+struct ExecutionEngine;
+
+struct Identifier
+{
+ QString string;
+ uint hashValue;
+};
+
+
+struct IdentifierHashEntry {
+ const Identifier *identifier;
+ union {
+ int value;
+ void *pointer;
+ };
+ int get(int *) const { return this ? value : -1; }
+ bool get(bool *) const { return this != 0; }
+ void *get(void **) const { return this ? pointer : 0; }
+};
+
+struct IdentifierHashData
+{
+ IdentifierHashData(int numBits);
+ ~IdentifierHashData() {
+ free(entries);
+ }
+
+ QBasicAtomicInt refCount;
+ int alloc;
+ int size;
+ int numBits;
+ IdentifierTable *identifierTable;
+ IdentifierHashEntry *entries;
+};
+
+struct IdentifierHashBase
+{
+
+ IdentifierHashData *d;
+
+ IdentifierHashBase() : d(0) {}
+ IdentifierHashBase(ExecutionEngine *engine);
+ inline IdentifierHashBase(const IdentifierHashBase &other);
+ inline ~IdentifierHashBase();
+ inline IdentifierHashBase &operator=(const IdentifierHashBase &other);
+
+ bool isEmpty() const { return !d; }
+ // ###
+ void reserve(int) {}
+
+ inline int count() const;
+ bool contains(const Identifier *i) const;
+ bool contains(const QString &str) const;
+ bool contains(String *str) const;
+
+protected:
+ IdentifierHashEntry *addEntry(const Identifier *i);
+ const IdentifierHashEntry *lookup(const Identifier *identifier) const;
+ const IdentifierHashEntry *lookup(const QString &str) const;
+ const IdentifierHashEntry *lookup(String *str) const;
+ const Identifier *toIdentifier(const QString &str) const;
+ const Identifier *toIdentifier(String *str) const;
+};
+
+
+template<typename T>
+struct IdentifierHash : public IdentifierHashBase
+{
+ IdentifierHash()
+ : IdentifierHashBase() {}
+ IdentifierHash(ExecutionEngine *engine)
+ : IdentifierHashBase(engine) {}
+ inline IdentifierHash(const IdentifierHash<T> &other)
+ : IdentifierHashBase(other) {}
+ inline ~IdentifierHash() {}
+ inline IdentifierHash &operator=(const IdentifierHash<T> &other) {
+ IdentifierHashBase::operator =(other);
+ return *this;
+ }
+
+ void add(const QString &str, const T &value);
+
+ inline T value(const QString &str) const;
+ inline T value(String *str) const;
+ QString findId(T value) const;
+};
+
+inline IdentifierHashBase::IdentifierHashBase(const IdentifierHashBase &other)
+{
+ d = other.d;
+ if (d)
+ d->refCount.ref();
+}
+
+inline IdentifierHashBase::~IdentifierHashBase()
+{
+ if (d && !d->refCount.deref())
+ delete d;
+}
+
+IdentifierHashBase &IdentifierHashBase::operator=(const IdentifierHashBase &other)
+{
+ if (other.d)
+ other.d->refCount.ref();
+ if (d && !d->refCount.deref())
+ delete d;
+ d = other.d;
+ return *this;
+}
+
+inline int IdentifierHashBase::count() const
+{
+ return d ? d->size : 0;
+}
+
+inline bool IdentifierHashBase::contains(const Identifier *i) const
+{
+ return lookup(i) != 0;
+}
+
+inline bool IdentifierHashBase::contains(const QString &str) const
+{
+ return lookup(str) != 0;
+}
+
+inline bool IdentifierHashBase::contains(String *str) const
+{
+ return lookup(str) != 0;
+}
+
+template<typename T>
+void IdentifierHash<T>::add(const QString &str, const T &value)
+{
+ IdentifierHashEntry *e = addEntry(toIdentifier(str));
+ e->value = value;
+}
+
+template<typename T>
+inline T IdentifierHash<T>::value(const QString &str) const
+{
+ return lookup(str)->get((T*)0);
+}
+
+template<typename T>
+inline T IdentifierHash<T>::value(String *str) const
+{
+ return lookup(str)->get((T*)0);
+}
+
+
+template<typename T>
+QString IdentifierHash<T>::findId(T value) const
+{
+ IdentifierHashEntry *e = d->entries;
+ IdentifierHashEntry *end = e + d->alloc;
+ while (e < end) {
+ if (e->identifier && e->get((T*)0) == value)
+ return e->identifier->string;
+ ++e;
+ }
+ return QString();
+}
+
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v4/qv4identifiertable.cpp b/src/qml/qml/v4/qv4identifiertable.cpp
new file mode 100644
index 0000000000..5de2f893ef
--- /dev/null
+++ b/src/qml/qml/v4/qv4identifiertable.cpp
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qv4identifiertable_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+static const uchar prime_deltas[] = {
+ 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
+ 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
+};
+
+static inline int primeForNumBits(int numBits)
+{
+ return (1 << numBits) + prime_deltas[numBits];
+}
+
+
+IdentifierTable::IdentifierTable(ExecutionEngine *engine)
+ : engine(engine)
+ , size(0)
+ , numBits(8)
+{
+ alloc = primeForNumBits(numBits);
+ entries = (String **)malloc(alloc*sizeof(String *));
+ memset(entries, 0, alloc*sizeof(String *));
+}
+
+IdentifierTable::~IdentifierTable()
+{
+ free(entries);
+}
+
+void IdentifierTable::addEntry(String *str)
+{
+ uint hash = str->hashValue();
+
+ if (str->subtype == String::StringType_ArrayIndex)
+ return;
+
+ str->identifier = new Identifier;
+ str->identifier->string = str->toQString();
+ str->identifier->hashValue = hash;
+
+ bool grow = (alloc <= size*2);
+
+ if (grow) {
+ ++numBits;
+ int newAlloc = primeForNumBits(numBits);
+ String **newEntries = (String **)malloc(newAlloc*sizeof(String *));
+ memset(newEntries, 0, newAlloc*sizeof(String *));
+ for (uint i = 0; i < alloc; ++i) {
+ String *e = entries[i];
+ if (!e)
+ continue;
+ uint idx = e->stringHash % newAlloc;
+ while (newEntries[idx]) {
+ ++idx;
+ idx %= newAlloc;
+ }
+ newEntries[idx] = e;
+ }
+ free(entries);
+ entries = newEntries;
+ alloc = newAlloc;
+ }
+
+ uint idx = hash % alloc;
+ while (entries[idx]) {
+ ++idx;
+ idx %= alloc;
+ }
+ entries[idx] = str;
+ ++size;
+}
+
+
+
+String *IdentifierTable::insertString(const QString &s)
+{
+ uint hash = String::createHashValue(s.constData(), s.length());
+ uint idx = hash % alloc;
+ while (String *e = entries[idx]) {
+ if (e->stringHash == hash && e->toQString() == s)
+ return e;
+ ++idx;
+ idx %= alloc;
+ }
+
+ String *str = engine->newString(s);
+ addEntry(str);
+ return str;
+}
+
+
+Identifier *IdentifierTable::identifier(String *str)
+{
+ if (str->identifier)
+ return str->identifier;
+ uint hash = str->hashValue();
+ if (str->subtype == String::StringType_ArrayIndex)
+ return 0;
+
+ uint idx = hash % alloc;
+ while (String *e = entries[idx]) {
+ if (e->stringHash == hash && e->isEqualTo(str)) {
+ str->identifier = e->identifier;
+ return e->identifier;
+ }
+ ++idx;
+ idx %= alloc;
+ }
+
+ addEntry(str);
+ return str->identifier;
+}
+
+Identifier *IdentifierTable::identifier(const QString &s)
+{
+ return insertString(s)->identifier;
+}
+
+Identifier *IdentifierTable::identifier(const char *s, int len)
+{
+ uint hash = String::createHashValue(s, len);
+ if (hash == UINT_MAX)
+ return identifier(QString::fromUtf8(s, len));
+
+ QLatin1String latin(s, len);
+ uint idx = hash % alloc;
+ while (String *e = entries[idx]) {
+ if (e->stringHash == hash && e->toQString() == latin)
+ return e->identifier;
+ ++idx;
+ idx %= alloc;
+ }
+
+ String *str = engine->newString(QString::fromLatin1(s, len));
+ addEntry(str);
+ return str->identifier;
+}
+
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4identifiertable_p.h b/src/qml/qml/v4/qv4identifiertable_p.h
new file mode 100644
index 0000000000..0f9a5921f9
--- /dev/null
+++ b/src/qml/qml/v4/qv4identifiertable_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4IDENTIFIERTABLE_H
+#define QV4IDENTIFIERTABLE_H
+
+#include "qv4identifier_p.h"
+#include "qv4string_p.h"
+#include "qv4engine_p.h"
+#include <limits.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct IdentifierTable
+{
+ ExecutionEngine *engine;
+
+ int alloc;
+ int size;
+ int numBits;
+ String **entries;
+
+ void addEntry(String *str);
+
+public:
+
+ IdentifierTable(ExecutionEngine *engine);
+ ~IdentifierTable();
+
+ String *insertString(const QString &s);
+
+ Identifier *identifier(String *str);
+ Identifier *identifier(const QString &s);
+ Identifier *identifier(const char *s, int len);
+
+ void mark() {
+ for (int i = 0; i < alloc; ++i)
+ if (entries[i])
+ entries[i]->mark();
+ }
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v4/qv4include.cpp b/src/qml/qml/v4/qv4include.cpp
new file mode 100644
index 0000000000..4fd7bb14c7
--- /dev/null
+++ b/src/qml/qml/v4/qv4include.cpp
@@ -0,0 +1,232 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4include_p.h"
+
+#include <QtQml/qjsengine.h>
+#include <QtNetwork/qnetworkrequest.h>
+#include <QtNetwork/qnetworkreply.h>
+#include <QtCore/qfile.h>
+#include <QtQml/qqmlfile.h>
+
+#include <private/qqmlengine_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4script_p.h>
+#include <private/qv4context_p.h>
+#include <private/qv4exception_p.h>
+#include <private/qqmlcontextwrapper_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QV4Include::QV4Include(const QUrl &url, QV8Engine *engine, QQmlContextData *context,
+ const QV4::Value &qmlglobal, const QV4::Value &callback)
+ : v4(QV8Engine::getV4(engine)), m_network(0), m_reply(0), m_url(url), m_redirectCount(0), m_context(context)
+{
+ m_qmlglobal = qmlglobal;
+ if (callback.asFunctionObject())
+ m_callbackFunction = callback;
+
+ m_resultObject = resultValue(v4);
+
+ m_network = engine->networkAccessManager();
+
+ QNetworkRequest request;
+ request.setUrl(url);
+
+ m_reply = m_network->get(request);
+ QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+}
+
+QV4Include::~QV4Include()
+{
+ delete m_reply; m_reply = 0;
+}
+
+QV4::Value QV4Include::resultValue(QV4::ExecutionEngine *v4, Status status)
+{
+
+ // XXX It seems inefficient to create this object from scratch each time.
+ QV4::Object *o = v4->newObject();
+ o->put(v4->newString("OK"), QV4::Value::fromInt32(Ok));
+ o->put(v4->newString("LOADING"), QV4::Value::fromInt32(Loading));
+ o->put(v4->newString("NETWORK_ERROR"), QV4::Value::fromInt32(NetworkError));
+ o->put(v4->newString("EXCEPTION"), QV4::Value::fromInt32(Exception));
+
+ o->put(v4->newString("status"), QV4::Value::fromInt32(status));
+
+ return QV4::Value::fromObject(o);
+}
+
+void QV4Include::callback(const QV4::Value &callback, const QV4::Value &status)
+{
+ QV4::FunctionObject *f = callback.asFunctionObject();
+ if (!f)
+ return;
+
+ QV4::Value args[] = { status };
+ QV4::ExecutionContext *ctx = f->engine()->current;
+ try {
+ f->call(QV4::Value::fromObject(f->engine()->globalObject), args, 1);
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ }
+}
+
+QV4::Value QV4Include::result()
+{
+ return m_resultObject.value();
+}
+
+#define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15
+void QV4Include::finished()
+{
+ m_redirectCount++;
+
+ if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ m_url = m_url.resolved(redirect.toUrl());
+ delete m_reply;
+
+ QNetworkRequest request;
+ request.setUrl(m_url);
+
+ m_reply = m_network->get(request);
+ QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
+ return;
+ }
+ }
+
+ if (m_reply->error() == QNetworkReply::NoError) {
+ QByteArray data = m_reply->readAll();
+
+ QString code = QString::fromUtf8(data);
+ QQmlScript::Parser::extractPragmas(code);
+
+ QV4::Script script(v4, m_qmlglobal.value().asObject(), code, m_url.toString());
+
+ QV4::ExecutionContext *ctx = v4->current;
+ QV4::Object *o = m_resultObject.value().asObject();
+ try {
+ script.parse();
+ script.run();
+ o->put(v4->newString("status"), QV4::Value::fromInt32(Ok));
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ o->put(v4->newString("status"), QV4::Value::fromInt32(Exception));
+ o->put(v4->newString("exception"), e.value());
+ }
+ } else {
+ m_resultObject.value().asObject()->put(v4->newString("status"), QV4::Value::fromInt32(NetworkError));
+ }
+
+ callback(m_callbackFunction.value(), m_resultObject.value());
+
+ disconnect();
+ deleteLater();
+}
+
+/*
+ Documented in qv8engine.cpp
+*/
+QV4::Value QV4Include::include(QV4::SimpleCallContext *ctx)
+{
+ if (!ctx->argumentCount)
+ return QV4::Value::undefinedValue();
+
+ QV4::ExecutionEngine *v4 = ctx->engine;
+ QV8Engine *engine = v4->v8Engine;
+ QQmlContextData *context = QV4::QmlContextWrapper::callingContext(v4);
+
+ if (!context || !context->isJSContext)
+ V4THROW_ERROR("Qt.include(): Can only be called from JavaScript files");
+
+ QUrl url(ctx->engine->resolvedUrl(ctx->arguments[0].toQString()));
+
+ QV4::Value callbackFunction = QV4::Value::undefinedValue();
+ if (ctx->argumentCount >= 2 && ctx->arguments[1].asFunctionObject())
+ callbackFunction = ctx->arguments[1];
+
+ QString localFile = QQmlFile::urlToLocalFileOrQrc(url);
+
+ QV4::Value result = QV4::Value::undefinedValue();
+
+ if (localFile.isEmpty()) {
+
+ QV4Include *i = new QV4Include(url, engine, context,
+ QV4::Value::fromObject(v4->qmlContextObject()),
+ callbackFunction);
+ result = i->result();
+
+ } else {
+
+ QFile f(localFile);
+
+ if (f.open(QIODevice::ReadOnly)) {
+ QByteArray data = f.readAll();
+ QString code = QString::fromUtf8(data);
+ QQmlScript::Parser::extractPragmas(code);
+
+ QV4::Object *qmlglobal = v4->qmlContextObject();
+ QV4::Script script(v4, qmlglobal, code, url.toString());
+
+ QV4::ExecutionContext *ctx = v4->current;
+ try {
+ script.parse();
+ script.run();
+ result = resultValue(v4, Ok);
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ result = resultValue(v4, Exception);
+ result.asObject()->put(v4->newString("exception"), e.value());
+ }
+ } else {
+ result = resultValue(v4, NetworkError);
+ }
+
+ callback(callbackFunction, result);
+ }
+
+ return result;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8include_p.h b/src/qml/qml/v4/qv4include_p.h
index 9f850e82b6..d6bbcd1a60 100644
--- a/src/qml/qml/v8/qv8include_p.h
+++ b/src/qml/qml/v4/qv4include_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QV8INCLUDE_P_H
-#define QV8INCLUDE_P_H
+#ifndef QV4INCLUDE_P_H
+#define QV4INCLUDE_P_H
//
// W A R N I N G
@@ -57,9 +57,9 @@
#include <QtCore/qurl.h>
#include <private/qqmlcontext_p.h>
-#include <private/qqmlguard_p.h>
-#include <private/qv8_p.h>
+#include <private/qv4value_p.h>
+#include <private/qv4context_p.h>
QT_BEGIN_NAMESPACE
@@ -67,7 +67,7 @@ class QQmlEngine;
class QNetworkAccessManager;
class QNetworkReply;
class QV8Engine;
-class QV8Include : public QObject
+class QV4Include : public QObject
{
Q_OBJECT
public:
@@ -78,36 +78,36 @@ public:
Exception = 3
};
- static v8::Handle<v8::Value> include(const v8::Arguments &args);
+ static QV4::Value include(QV4::SimpleCallContext *ctx);
private slots:
void finished();
private:
- QV8Include(const QUrl &, QV8Engine *, QQmlContextData *,
- v8::Handle<v8::Object>, v8::Handle<v8::Function>);
- ~QV8Include();
+ QV4Include(const QUrl &url, QV8Engine *engine, QQmlContextData *context,
+ const QV4::Value &qmlglobal, const QV4::Value &callback);
+ ~QV4Include();
- v8::Handle<v8::Object> result();
+ QV4::Value result();
- static v8::Local<v8::Object> resultValue(Status status = Loading);
- static void callback(QV8Engine *engine, v8::Handle<v8::Function> callback, v8::Handle<v8::Object> status);
+ static QV4::Value resultValue(QV4::ExecutionEngine *v4, Status status = Loading);
+ static void callback(const QV4::Value &callback, const QV4::Value &status);
- QV8Engine *m_engine;
+ QV4::ExecutionEngine *v4;
QNetworkAccessManager *m_network;
- QQmlGuard<QNetworkReply> m_reply;
+ QPointer<QNetworkReply> m_reply;
QUrl m_url;
int m_redirectCount;
- v8::Persistent<v8::Function> m_callbackFunction;
- v8::Persistent<v8::Object> m_resultObject;
+ QV4::PersistentValue m_callbackFunction;
+ QV4::PersistentValue m_resultObject;
QQmlGuardedContextData m_context;
- v8::Persistent<v8::Object> m_qmlglobal;
+ QV4::PersistentValue m_qmlglobal;
};
QT_END_NAMESPACE
-#endif // QV8INCLUDE_P_H
+#endif
diff --git a/src/qml/qml/v4/qv4instruction.cpp b/src/qml/qml/v4/qv4instruction.cpp
deleted file mode 100644
index 103a43a3a3..0000000000
--- a/src/qml/qml/v4/qv4instruction.cpp
+++ /dev/null
@@ -1,532 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4instruction_p.h"
-#include "qv4bindings_p.h"
-
-#include <QtCore/qdebug.h>
-#include <private/qqmlglobal_p.h>
-
-// Define this to do a test dump of all the instructions at startup. This is
-// helpful to test that each instruction's Instr::dump() case uses the correct
-// number of tabs etc and otherwise looks correct.
-// #define DEBUG_INSTR_DUMP
-
-QT_BEGIN_NAMESPACE
-
-namespace QQmlJS {
-
-#ifdef DEBUG_INSTR_DUMP
-static struct DumpInstrAtStartup {
- DumpInstrAtStartup() {
- Bytecode bc;
-#define DUMP_INSTR_AT_STARTUP(I, FMT) { V4InstrData<V4Instr::I> i; bc.append(i); }
- FOR_EACH_V4_INSTR(DUMP_INSTR_AT_STARTUP);
-#undef DUMP_INSTR_AT_STARTUP
- const char *start = bc.constData();
- const char *end = start + bc.size();
- bc.dump(start, end);
- }
-} dump_instr_at_startup;
-#endif
-
-int V4Instr::size(Type type)
-{
-#define V4_RETURN_INSTR_SIZE(I, FMT) case I: return QML_V4_INSTR_SIZE(I, FMT);
- switch (type) {
- FOR_EACH_V4_INSTR(V4_RETURN_INSTR_SIZE)
- }
-#undef V4_RETURN_INSTR_SIZE
- return 0;
-}
-
-void Bytecode::dump(const V4Instr *i, int address) const
-{
- QByteArray leading;
- if (address != -1) {
- leading = QByteArray::number(address);
- leading.prepend(QByteArray(8 - leading.count(), ' '));
- leading.append('\t');
- }
-
-#define INSTR_DUMP qWarning().nospace() << leading.constData()
-
- switch (instructionType(i)) {
- case V4Instr::Noop:
- INSTR_DUMP << '\t' << "Noop";
- break;
- case V4Instr::BindingId:
- INSTR_DUMP << i->id.line << ':' << i->id.column << ':';
- break;
- case V4Instr::SubscribeId:
- INSTR_DUMP << '\t' << "SubscribeId" << "\t\t" << "Id_Offset(" << i->subscribeop.index << ") -> Subscribe_Slot(" << i->subscribeop.offset << ')';
- break;
- case V4Instr::FetchAndSubscribe:
- INSTR_DUMP << '\t' << "FetchAndSubscribe" << '\t' << "Object_Reg(" << i->fetchAndSubscribe.reg << ") Fast_Accessor(" << i->fetchAndSubscribe.property.accessors << ") -> Output_Reg(" << i->fetchAndSubscribe.reg << ") Subscription_Slot(" << i->fetchAndSubscribe.subscription << ')';
- break;
- case V4Instr::LoadId:
- INSTR_DUMP << '\t' << "LoadId" << "\t\t\t" << "Id_Offset(" << i->load.index << ") -> Output_Reg(" << i->load.reg << ')';
- break;
- case V4Instr::LoadScope:
- INSTR_DUMP << '\t' << "LoadScope" << "\t\t" << "-> Output_Reg(" << i->load.reg << ')';
- break;
- case V4Instr::LoadRoot:
- INSTR_DUMP << '\t' << "LoadRoot" << "\t\t" << "-> Output_Reg(" << i->load.reg << ')';
- break;
- case V4Instr::LoadSingletonObject:
- INSTR_DUMP << '\t' << "LoadSingletonObject" << "\t\t" << ") -> Output_Reg(" << i->load.reg << ')';
- break;
- case V4Instr::LoadAttached:
- INSTR_DUMP << '\t' << "LoadAttached" << "\t\t" << "Object_Reg(" << i->attached.reg << ") Attached_Index(" << i->attached.id << ") -> Output_Reg(" << i->attached.output << ')';
- break;
- case V4Instr::UnaryNot:
- INSTR_DUMP << '\t' << "UnaryNot" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::UnaryMinusNumber:
- INSTR_DUMP << '\t' << "UnaryMinusNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::UnaryMinusInt:
- INSTR_DUMP << '\t' << "UnaryMinusInt" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::UnaryPlusNumber:
- INSTR_DUMP << '\t' << "UnaryPlusNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::UnaryPlusInt:
- INSTR_DUMP << '\t' << "UnaryPlusInt" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertBoolToInt:
- INSTR_DUMP << '\t' << "ConvertBoolToInt" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertBoolToJSValue:
- INSTR_DUMP << '\t' << "ConvertBoolToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertBoolToNumber:
- INSTR_DUMP << '\t' << "ConvertBoolToNumber" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertBoolToString:
- INSTR_DUMP << '\t' << "ConvertBoolToString" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertBoolToVariant:
- INSTR_DUMP << '\t' << "ConvertBoolToVariant" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertBoolToVar:
- INSTR_DUMP << '\t' << "ConvertBoolToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertIntToBool:
- INSTR_DUMP << '\t' << "ConvertIntToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertIntToJSValue:
- INSTR_DUMP << '\t' << "ConvertIntToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertIntToNumber:
- INSTR_DUMP << '\t' << "ConvertIntToNumber" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertIntToString:
- INSTR_DUMP << '\t' << "ConvertIntToString" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertIntToVariant:
- INSTR_DUMP << '\t' << "ConvertIntToVariant" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertIntToVar:
- INSTR_DUMP << '\t' << "ConvertIntToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertJSValueToVar:
- INSTR_DUMP << '\t' << "ConvertJSValueToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertNumberToBool:
- INSTR_DUMP << '\t' << "ConvertNumberToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertNumberToInt:
- INSTR_DUMP << '\t' << "ConvertNumberToInt" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertNumberToJSValue:
- INSTR_DUMP << '\t' << "ConvertNumberToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertNumberToString:
- INSTR_DUMP << '\t' << "ConvertNumberToString" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertNumberToVariant:
- INSTR_DUMP << '\t' << "ConvertNumberToVariant" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertNumberToVar:
- INSTR_DUMP << '\t' << "ConvertNumberToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertStringToBool:
- INSTR_DUMP << '\t' << "ConvertStringToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertStringToInt:
- INSTR_DUMP << '\t' << "ConvertStringToInt" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertStringToJSValue:
- INSTR_DUMP << '\t' << "ConvertStringToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertStringToNumber:
- INSTR_DUMP << '\t' << "ConvertStringToNumber" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertStringToUrl:
- INSTR_DUMP << '\t' << "ConvertStringToUrl" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertStringToColor:
- INSTR_DUMP << '\t' << "ConvertStringToColor" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertStringToVariant:
- INSTR_DUMP << '\t' << "ConvertStringToVariant" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertStringToVar:
- INSTR_DUMP << '\t' << "ConvertStringToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertUrlToBool:
- INSTR_DUMP << '\t' << "ConvertUrlToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertUrlToJSValue:
- INSTR_DUMP << '\t' << "ConvertUrlToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertUrlToString:
- INSTR_DUMP << '\t' << "ConvertUrlToString" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertUrlToVariant:
- INSTR_DUMP << '\t' << "ConvertUrlToVariant" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertUrlToVar:
- INSTR_DUMP << '\t' << "ConvertUrlToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertColorToBool:
- INSTR_DUMP << '\t' << "ConvertColorToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertColorToJSValue:
- INSTR_DUMP << '\t' << "ConvertColorToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertColorToString:
- INSTR_DUMP << '\t' << "ConvertColorToString" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertColorToVariant:
- INSTR_DUMP << '\t' << "ConvertColorToVariant" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertColorToVar:
- INSTR_DUMP << '\t' << "ConvertColorToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertObjectToBool:
- INSTR_DUMP << '\t' << "ConvertObjectToBool" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertObjectToJSValue:
- INSTR_DUMP << '\t' << "ConvertObjectToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertObjectToVariant:
- INSTR_DUMP << '\t' << "ConvertObjectToVariant" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertObjectToVar:
- INSTR_DUMP << '\t' << "ConvertObjectToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertVarToJSValue:
- INSTR_DUMP << '\t' << "ConvertVarToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertNullToJSValue:
- INSTR_DUMP << '\t' << "ConvertNullToJSValue" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertNullToObject:
- INSTR_DUMP << '\t' << "ConvertNullToObject" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertNullToVariant:
- INSTR_DUMP << '\t' << "ConvertNullToVariant" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ConvertNullToVar:
- INSTR_DUMP << '\t' << "ConvertNullToVar" << '\t' << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::ResolveUrl:
- INSTR_DUMP << '\t' << "ResolveUrl" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::MathSinNumber:
- INSTR_DUMP << '\t' << "MathSinNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::MathCosNumber:
- INSTR_DUMP << '\t' << "MathCosNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::MathAbsNumber:
- INSTR_DUMP << '\t' << "MathAbsNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::MathRoundNumber:
- INSTR_DUMP << '\t' << "MathRoundNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::MathFloorNumber:
- INSTR_DUMP << '\t' << "MathFloorNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::MathCeilNumber:
- INSTR_DUMP << '\t' << "MathCeilNumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::MathPINumber:
- INSTR_DUMP << '\t' << "MathPINumber" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ')';
- break;
- case V4Instr::LoadNull:
- INSTR_DUMP << '\t' << "LoadNull" << "\t\t" << "Constant(null) -> Output_Reg(" << i->null_value.reg << ')';
- break;
- case V4Instr::LoadNumber:
- INSTR_DUMP << '\t' << "LoadNumber" << "\t\t" << "Constant(" << i->number_value.value << ") -> Output_Reg(" << i->number_value.reg << ')';
- break;
- case V4Instr::LoadInt:
- INSTR_DUMP << '\t' << "LoadInt" << "\t\t\t" << "Constant(" << i->int_value.value << ") -> Output_Reg(" << i->int_value.reg << ')';
- break;
- case V4Instr::LoadBool:
- INSTR_DUMP << '\t' << "LoadBool" << "\t\t" << "Constant(" << i->bool_value.value << ") -> Output_Reg(" << i->bool_value.reg << ')';
- break;
- case V4Instr::LoadString:
- INSTR_DUMP << '\t' << "LoadString" << "\t\t" << "String_DataIndex(" << i->string_value.offset << ") String_Length(" << i->string_value.length << ") -> Output_Register(" << i->string_value.reg << ')';
- break;
- case V4Instr::EnableV4Test:
- INSTR_DUMP << '\t' << "EnableV4Test" << "\t\t" << "String_DataIndex(" << i->string_value.offset << ") String_Length(" << i->string_value.length << ')';
- break;
- case V4Instr::TestV4Store:
- INSTR_DUMP << '\t' << "TestV4Store" << "\t\t" << "Input_Reg(" << i->storetest.reg << ") Reg_Type(" << i->storetest.regType << ')';
- break;
- case V4Instr::BitAndInt:
- INSTR_DUMP << '\t' << "BitAndInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::BitOrInt:
- INSTR_DUMP << '\t' << "BitOrInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::BitXorInt:
- INSTR_DUMP << '\t' << "BitXorInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::AddNumber:
- INSTR_DUMP << '\t' << "AddNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::AddString:
- INSTR_DUMP << '\t' << "AddString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::SubNumber:
- INSTR_DUMP << '\t' << "SubNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::MulNumber:
- INSTR_DUMP << '\t' << "MulNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::DivNumber:
- INSTR_DUMP << '\t' << "DivNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::ModNumber:
- INSTR_DUMP << '\t' << "ModNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::LShiftInt:
- INSTR_DUMP << '\t' << "LShiftInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::RShiftInt:
- INSTR_DUMP << '\t' << "RShiftInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::URShiftInt:
- INSTR_DUMP << '\t' << "URShiftInt" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::GtNumber:
- INSTR_DUMP << '\t' << "GtNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::LtNumber:
- INSTR_DUMP << '\t' << "LtNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::GeNumber:
- INSTR_DUMP << '\t' << "GeNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::LeNumber:
- INSTR_DUMP << '\t' << "LeNumber" << "\t\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::EqualNumber:
- INSTR_DUMP << '\t' << "EqualNumber" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::NotEqualNumber:
- INSTR_DUMP << '\t' << "NotEqualNumber" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::StrictEqualNumber:
- INSTR_DUMP << '\t' << "StrictEqualNumber" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::StrictNotEqualNumber:
- INSTR_DUMP << '\t' << "StrictNotEqualNumber" << '\t' << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::GtString:
- INSTR_DUMP << '\t' << "GtString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::LtString:
- INSTR_DUMP << '\t' << "LtString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::GeString:
- INSTR_DUMP << '\t' << "GeString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::LeString:
- INSTR_DUMP << '\t' << "LeString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::EqualString:
- INSTR_DUMP << '\t' << "EqualString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::NotEqualString:
- INSTR_DUMP << '\t' << "NotEqualString" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::StrictEqualString:
- INSTR_DUMP << '\t' << "StrictEqualString" << '\t' << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::StrictNotEqualString:
- INSTR_DUMP << '\t' << "StrictNotEqualString" << '\t' << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::EqualObject:
- INSTR_DUMP << '\t' << "EqualObject" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::NotEqualObject:
- INSTR_DUMP << '\t' << "NotEqualObject" << "\t\t" << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::StrictEqualObject:
- INSTR_DUMP << '\t' << "StrictEqualObject" << '\t' << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::StrictNotEqualObject:
- INSTR_DUMP << '\t' << "StrictNotEqualObject" << '\t' << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::MathMaxNumber:
- INSTR_DUMP << '\t' << "MathMaxNumber" << '\t' << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::MathMinNumber:
- INSTR_DUMP << '\t' << "MathMinNumber" << '\t' << "Input_Reg(" << i->binaryop.left << ") Input_Reg(" << i->binaryop.right << ") -> Output_Reg(" << i->binaryop.output << ')';
- break;
- case V4Instr::NewString:
- INSTR_DUMP << '\t' << "NewString" << "\t\t" << "Register(" << i->construct.reg << ')';
- break;
- case V4Instr::NewUrl:
- INSTR_DUMP << '\t' << "NewUrl" << "\t\t\t" << "Register(" << i->construct.reg << ')';
- break;
- case V4Instr::CleanupRegister:
- INSTR_DUMP << '\t' << "CleanupRegister" << "\t\t" << "Register(" << i->cleanup.reg << ')';
- break;
- case V4Instr::Fetch:
- INSTR_DUMP << '\t' << "Fetch" << "\t\t\t" << "Object_Reg(" << i->fetch.reg << ") Property_Index(" << i->fetch.index << ") -> Output_Reg(" << i->fetch.reg << ')';
- break;
- case V4Instr::Store:
- INSTR_DUMP << '\t' << "Store" << "\t\t\t" << "Input_Reg(" << i->store.reg << ") -> Object_Reg(" << i->store.output << ") Property_Index(" << i->store.index << ')';
- break;
- case V4Instr::Copy:
- INSTR_DUMP << '\t' << "Copy" << "\t\t\t" << "Input_Reg(" << i->copy.src << ") -> Output_Reg(" << i->copy.reg << ')';
- break;
- case V4Instr::Jump:
- if (i->jump.reg != -1) {
- INSTR_DUMP << '\t' << "Jump" << "\t\t\t" << "Address(" << (address + size() + i->jump.count) << ") [if false == Input_Reg(" << i->jump.reg << ")]";
- } else {
- INSTR_DUMP << '\t' << "Jump" << "\t\t\t" << "Address(" << (address + size() + i->jump.count) << ')';
- }
- break;
- case V4Instr::BranchFalse:
- INSTR_DUMP << '\t' << "BranchFalse" << "\t\t" << "Address(" << (address + size() + i->branchop.offset) << ") [if false == Input_Reg(" << i->branchop.reg << ")]";
- break;
- case V4Instr::BranchTrue:
- INSTR_DUMP << '\t' << "BranchTrue" << "\t\t" << "Address(" << (address + size() + i->branchop.offset) << ") [if true == Input_Reg(" << i->branchop.reg << ")]";
- break;
- case V4Instr::Branch:
- INSTR_DUMP << '\t' << "Branch" << "\t\t\t" << "Address(" << (address + size() + i->branchop.offset) << ')';
- break;
- case V4Instr::Block:
- INSTR_DUMP << '\t' << "Block" << "\t\t\t" << "Mask(" << QByteArray::number(i->blockop.block, 16).constData() << ')';
- break;
- case V4Instr::Throw:
- INSTR_DUMP << '\t' << "Throw" << "\t\t\t" << "InputReg(" << i->throwop.message << ')';
- break;
- default:
- INSTR_DUMP << '\t' << "Unknown";
- break;
- }
-}
-
-void Bytecode::dump(const char *start, const char *end) const
-{
- const char *code = start;
- while (code < end) {
- const V4Instr *instr = reinterpret_cast<const V4Instr *>(code);
- dump(instr, code - start);
- code += V4Instr::size(instructionType(instr));
- }
-}
-
-Bytecode::Bytecode()
-{
-#ifdef QML_THREADED_INTERPRETER
- decodeInstr = QV4Bindings::getDecodeInstrTable();
-#endif
-}
-
-V4Instr::Type Bytecode::instructionType(const V4Instr *instr) const
-{
-#ifdef QML_THREADED_INTERPRETER
- void *code = instr->common.code;
-
-# define CHECK_V4_INSTR_CODE(I, FMT) \
- if (decodeInstr[static_cast<int>(V4Instr::I)] == code) \
- return V4Instr::I;
-
- FOR_EACH_V4_INSTR(CHECK_V4_INSTR_CODE)
- Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid instruction address");
- return static_cast<V4Instr::Type>(0);
-# undef CHECK_V4_INSTR_CODE
-#else
- return static_cast<V4Instr::Type>(instr->common.type);
-#endif
-
-}
-
-void Bytecode::append(V4Instr::Type type, V4Instr &instr)
-{
-#ifdef QML_THREADED_INTERPRETER
- instr.common.code = decodeInstr[static_cast<int>(type)];
-#else
- instr.common.type = type;
-#endif
- d.append(reinterpret_cast<const char *>(&instr), V4Instr::size(type));
-}
-
-int Bytecode::remove(int offset)
-{
- const V4Instr *instr = reinterpret_cast<const V4Instr *>(d.begin() + offset);
- const int instrSize = V4Instr::size(instructionType(instr));
- d.remove(offset, instrSize);
- return instrSize;
-}
-
-const V4Instr &Bytecode::operator[](int offset) const
-{
- return *(reinterpret_cast<const V4Instr *>(d.begin() + offset));
-}
-
-V4Instr &Bytecode::operator[](int offset)
-{
- return *(reinterpret_cast<V4Instr *>(d.begin() + offset));
-}
-
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4instruction_p.h b/src/qml/qml/v4/qv4instruction_p.h
deleted file mode 100644
index 9797abf69d..0000000000
--- a/src/qml/qml/v4/qv4instruction_p.h
+++ /dev/null
@@ -1,483 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4INSTRUCTION_P_H
-#define QV4INSTRUCTION_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 <QtCore/qglobal.h>
-#include <QtCore/qbytearray.h>
-#include <QtCore/qvector.h>
-#include <QtCore/qvarlengtharray.h>
-
-#include <private/qqmlpropertycache_p.h>
-
-QT_BEGIN_NAMESPACE
-
-#define FOR_EACH_V4_INSTR(F) \
- F(Noop, common) \
- F(BindingId, id) \
- F(SubscribeId, subscribeop) \
- F(FetchAndSubscribe, fetchAndSubscribe) \
- F(LoadId, load) \
- F(LoadScope, load) \
- F(LoadRoot, load) \
- F(LoadSingletonObject, load) \
- F(LoadAttached, attached) \
- F(UnaryNot, unaryop) \
- F(UnaryMinusNumber, unaryop) \
- F(UnaryMinusInt, unaryop) \
- F(UnaryPlusNumber, unaryop) \
- F(UnaryPlusInt, unaryop) \
- F(ConvertBoolToInt, unaryop) \
- F(ConvertBoolToJSValue, unaryop) \
- F(ConvertBoolToNumber, unaryop) \
- F(ConvertBoolToString, unaryop) \
- F(ConvertBoolToVariant, unaryop) \
- F(ConvertBoolToVar, unaryop) \
- F(ConvertIntToBool, unaryop) \
- F(ConvertIntToJSValue, unaryop) \
- F(ConvertIntToNumber, unaryop) \
- F(ConvertIntToString, unaryop) \
- F(ConvertIntToVariant, unaryop) \
- F(ConvertIntToVar, unaryop) \
- F(ConvertJSValueToVar, unaryop) \
- F(ConvertNumberToBool, unaryop) \
- F(ConvertNumberToInt, unaryop) \
- F(ConvertNumberToJSValue, unaryop) \
- F(ConvertNumberToString, unaryop) \
- F(ConvertNumberToVariant, unaryop) \
- F(ConvertNumberToVar, unaryop) \
- F(ConvertStringToBool, unaryop) \
- F(ConvertStringToInt, unaryop) \
- F(ConvertStringToJSValue, unaryop) \
- F(ConvertStringToNumber, unaryop) \
- F(ConvertStringToUrl, unaryop) \
- F(ConvertStringToColor, unaryop) \
- F(ConvertStringToVariant, unaryop) \
- F(ConvertStringToVar, unaryop) \
- F(ConvertUrlToBool, unaryop) \
- F(ConvertUrlToJSValue, unaryop) \
- F(ConvertUrlToString, unaryop) \
- F(ConvertUrlToVariant, unaryop) \
- F(ConvertUrlToVar, unaryop) \
- F(ConvertColorToBool, unaryop) \
- F(ConvertColorToJSValue, unaryop) \
- F(ConvertColorToString, unaryop) \
- F(ConvertColorToVariant, unaryop) \
- F(ConvertColorToVar, unaryop) \
- F(ConvertObjectToBool, unaryop) \
- F(ConvertObjectToJSValue, unaryop) \
- F(ConvertObjectToVariant, unaryop) \
- F(ConvertObjectToVar, unaryop) \
- F(ConvertVarToJSValue, unaryop) \
- F(ConvertNullToJSValue, unaryop) \
- F(ConvertNullToObject, unaryop) \
- F(ConvertNullToVariant, unaryop) \
- F(ConvertNullToVar, unaryop) \
- F(ResolveUrl, unaryop) \
- F(MathSinNumber, unaryop) \
- F(MathCosNumber, unaryop) \
- F(MathAbsNumber, unaryop) \
- F(MathRoundNumber, unaryop) \
- F(MathFloorNumber, unaryop) \
- F(MathCeilNumber, unaryop) \
- F(MathPINumber, unaryop) \
- F(LoadNull, null_value) \
- F(LoadNumber, number_value) \
- F(LoadInt, int_value) \
- F(LoadBool, bool_value) \
- F(LoadString, string_value) \
- F(EnableV4Test, string_value) \
- F(TestV4Store, storetest) \
- F(BitAndInt, binaryop) \
- F(BitOrInt, binaryop) \
- F(BitXorInt, binaryop) \
- F(AddNumber, binaryop) \
- F(AddString, binaryop) \
- F(SubNumber, binaryop) \
- F(MulNumber, binaryop) \
- F(DivNumber, binaryop) \
- F(ModNumber, binaryop) \
- F(LShiftInt, binaryop) \
- F(RShiftInt, binaryop) \
- F(URShiftInt, binaryop) \
- F(GtNumber, binaryop) \
- F(LtNumber, binaryop) \
- F(GeNumber, binaryop) \
- F(LeNumber, binaryop) \
- F(EqualNumber, binaryop) \
- F(NotEqualNumber, binaryop) \
- F(StrictEqualNumber, binaryop) \
- F(StrictNotEqualNumber, binaryop) \
- F(GtString, binaryop) \
- F(LtString, binaryop) \
- F(GeString, binaryop) \
- F(LeString, binaryop) \
- F(EqualString, binaryop) \
- F(NotEqualString, binaryop) \
- F(StrictEqualString, binaryop) \
- F(StrictNotEqualString, binaryop) \
- F(EqualObject, binaryop) \
- F(NotEqualObject, binaryop) \
- F(StrictEqualObject, binaryop) \
- F(StrictNotEqualObject, binaryop) \
- F(MathMaxNumber, binaryop) \
- F(MathMinNumber, binaryop) \
- F(NewString, construct) \
- F(NewUrl, construct) \
- F(CleanupRegister, cleanup) \
- F(Copy, copy) \
- F(Fetch, fetch) \
- F(Store, store) \
- F(Jump, jump) \
- F(BranchTrue, branchop) \
- F(BranchFalse, branchop) \
- F(Branch, branchop) \
- F(Block, blockop) \
- F(Throw, throwop)
-
-#if defined(Q_CC_GNU) && (!defined(Q_CC_INTEL) || __INTEL_COMPILER >= 1200)
-# define QML_THREADED_INTERPRETER
-#endif
-
-#ifdef Q_ALIGNOF
-# define QML_V4_INSTR_ALIGN_MASK (Q_ALIGNOF(V4Instr) - 1)
-#else
-# define QML_V4_INSTR_ALIGN_MASK (sizeof(void *) - 1)
-#endif
-
-#define QML_V4_INSTR_ENUM(I, FMT) I,
-#define QML_V4_INSTR_ADDR(I, FMT) &&op_##I,
-#define QML_V4_INSTR_SIZE(I, FMT) ((sizeof(V4Instr::instr_##FMT) + QML_V4_INSTR_ALIGN_MASK) & ~QML_V4_INSTR_ALIGN_MASK)
-
-#ifdef QML_THREADED_INTERPRETER
-# define QML_V4_BEGIN_INSTR(I,FMT) op_##I:
-# define QML_V4_END_INSTR(I,FMT) code += QML_V4_INSTR_SIZE(I, FMT); instr = (const V4Instr *) code; goto *instr->common.code;
-# define QML_V4_INSTR_HEADER void *code;
-#else
-# define QML_V4_BEGIN_INSTR(I,FMT) case V4Instr::I:
-# define QML_V4_END_INSTR(I,FMT) code += QML_V4_INSTR_SIZE(I, FMT); instr = (const V4Instr *) code; break;
-# define QML_V4_INSTR_HEADER quint8 type;
-#endif
-
-class QObject;
-class QQmlNotifier;
-
-namespace QQmlJS {
-
-union Q_AUTOTEST_EXPORT V4Instr {
- enum Type {
- FOR_EACH_V4_INSTR(QML_V4_INSTR_ENUM)
- };
-
- static int size(Type type);
-
- struct instr_common {
- QML_V4_INSTR_HEADER
- };
-
- struct instr_id {
- QML_V4_INSTR_HEADER
- quint16 column;
- quint16 line;
- };
-
- struct instr_init {
- QML_V4_INSTR_HEADER
- quint16 subscriptions;
- quint16 identifiers;
- };
-
- struct instr_subscribeop {
- QML_V4_INSTR_HEADER
- qint8 reg;
- quint16 offset;
- quint32 index;
- };
-
- struct instr_load {
- QML_V4_INSTR_HEADER
- qint8 reg;
- quint32 index;
- };
-
- struct instr_attached {
- QML_V4_INSTR_HEADER
- qint8 output;
- qint8 reg;
- quint8 exceptionId;
- quint32 id;
- };
-
- struct instr_store {
- QML_V4_INSTR_HEADER
- qint8 output;
- qint8 reg;
- quint8 exceptionId;
- quint8 valueType;
- quint32 index;
- };
-
- struct instr_storetest {
- QML_V4_INSTR_HEADER
- qint8 reg;
- qint32 regType;
- };
-
- struct instr_fetchAndSubscribe {
- QML_V4_INSTR_HEADER
- qint8 reg;
- quint8 exceptionId;
- quint8 valueType;
- quint16 subscription;
- QQmlPropertyRawData property;
- };
-
- struct instr_fetch{
- QML_V4_INSTR_HEADER
- qint8 reg;
- quint8 exceptionId;
- quint8 valueType;
- quint32 index;
- quint16 subOffset;
- quint32 subIndex;
- };
-
- struct instr_copy {
- QML_V4_INSTR_HEADER
- qint8 reg;
- qint8 src;
- };
-
- struct instr_construct {
- QML_V4_INSTR_HEADER
- qint8 reg;
- };
-
- struct instr_null_value {
- QML_V4_INSTR_HEADER
- qint8 reg;
- };
-
- struct instr_number_value {
- QML_V4_INSTR_HEADER
- qint8 reg;
- double value; // XXX Makes the instruction 12 bytes
- };
-
- struct instr_int_value {
- QML_V4_INSTR_HEADER
- qint8 reg;
- int value;
- };
-
- struct instr_bool_value {
- QML_V4_INSTR_HEADER
- qint8 reg;
- bool value;
- };
-
- struct instr_string_value {
- QML_V4_INSTR_HEADER
- qint8 reg;
- quint16 length;
- quint32 offset;
- };
-
- struct instr_binaryop {
- QML_V4_INSTR_HEADER
- qint8 output;
- qint8 left;
- qint8 right;
- };
-
- struct instr_unaryop {
- QML_V4_INSTR_HEADER
- qint8 output;
- qint8 src;
- };
-
- struct instr_jump {
- QML_V4_INSTR_HEADER
- qint8 reg;
- quint32 count;
- };
-
- struct instr_find {
- QML_V4_INSTR_HEADER
- qint8 reg;
- qint8 src;
- quint8 exceptionId;
- quint16 name;
- quint16 subscribeIndex;
- };
-
- struct instr_cleanup {
- QML_V4_INSTR_HEADER
- qint8 reg;
- };
-
- struct instr_initstring {
- QML_V4_INSTR_HEADER
- quint16 offset;
- quint32 dataIdx;
- };
-
- struct instr_branchop {
- QML_V4_INSTR_HEADER
- quint8 reg;
- qint16 offset;
- };
-
- struct instr_blockop {
- QML_V4_INSTR_HEADER
- quint32 block;
- };
-
- struct instr_throwop {
- QML_V4_INSTR_HEADER
- quint8 exceptionId;
- quint32 message;
- };
-
- instr_common common;
- instr_id id;
- instr_init init;
- instr_subscribeop subscribeop;
- instr_load load;
- instr_attached attached;
- instr_store store;
- instr_storetest storetest;
- instr_fetchAndSubscribe fetchAndSubscribe;
- instr_fetch fetch;
- instr_copy copy;
- instr_construct construct;
- instr_null_value null_value;
- instr_number_value number_value;
- instr_int_value int_value;
- instr_bool_value bool_value;
- instr_string_value string_value;
- instr_binaryop binaryop;
- instr_unaryop unaryop;
- instr_jump jump;
- instr_find find;
- instr_cleanup cleanup;
- instr_initstring initstring;
- instr_branchop branchop;
- instr_blockop blockop;
- instr_throwop throwop;
-};
-
-template<int N>
-struct V4InstrMeta {
-};
-
-#define QML_V4_INSTR_META_TEMPLATE(I, FMT) \
- template<> struct V4InstrMeta<(int)V4Instr::I> { \
- enum { Size = QML_V4_INSTR_SIZE(I, FMT) }; \
- typedef V4Instr::instr_##FMT DataType; \
- static const DataType &data(const V4Instr &instr) { return instr.FMT; } \
- static void setData(V4Instr &instr, const DataType &v) { instr.FMT = v; } \
- };
-FOR_EACH_V4_INSTR(QML_V4_INSTR_META_TEMPLATE);
-#undef QML_V4_INSTR_META_TEMPLATE
-
-template<int Instr>
-class Q_AUTOTEST_EXPORT V4InstrData : public V4InstrMeta<Instr>::DataType
-{
-};
-
-class Q_AUTOTEST_EXPORT Bytecode
-{
- Q_DISABLE_COPY(Bytecode)
-
-public:
- Bytecode();
-
- const char *constData() const { return d.constData(); }
- int size() const { return d.size(); }
- int count() const { return d.count(); }
- void clear() { d.clear(); }
- bool isEmpty() const { return d.isEmpty(); }
- V4Instr::Type instructionType(const V4Instr *instr) const;
-
- template <int Instr>
- void append(const V4InstrData<Instr> &data)
- {
- V4Instr genericInstr;
- V4InstrMeta<Instr>::setData(genericInstr, data);
- return append(static_cast<V4Instr::Type>(Instr), genericInstr);
- }
- void append(V4Instr::Type type, V4Instr &instr);
-
- int remove(int index);
-
- const V4Instr &operator[](int offset) const;
- V4Instr &operator[](int offset);
-
- void dump(const char *start, const char *end) const;
-
-private:
- void dump(const V4Instr *instr, int = -1) const;
-
- QVarLengthArray<char, 4 * 1024> d;
-#ifdef QML_THREADED_INTERPRETER
- void **decodeInstr;
-#endif
-};
-
-}
-
-QT_END_NAMESPACE
-
-#endif // QV4INSTRUCTION_P_H
-
diff --git a/src/qml/qml/v4/qv4internalclass.cpp b/src/qml/qml/v4/qv4internalclass.cpp
new file mode 100644
index 0000000000..f4edc99545
--- /dev/null
+++ b/src/qml/qml/v4/qv4internalclass.cpp
@@ -0,0 +1,296 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qv4internalclass_p.h>
+#include <qv4string_p.h>
+#include <qv4engine_p.h>
+#include <qv4identifier_p.h>
+#include "qv4object_p.h"
+#include "qv4identifiertable_p.h"
+
+QT_BEGIN_NAMESPACE
+
+uint QV4::qHash(const QV4::InternalClassTransition &t, uint)
+{
+ return t.id->hashValue ^ t.flags;
+}
+
+using namespace QV4;
+
+static const uchar prime_deltas[] = {
+ 0, 0, 1, 3, 1, 5, 3, 3, 1, 9, 7, 5, 3, 9, 25, 3,
+ 1, 21, 3, 21, 7, 15, 9, 5, 3, 29, 15, 0, 0, 0, 0, 0
+};
+
+static inline int primeForNumBits(int numBits)
+{
+ return (1 << numBits) + prime_deltas[numBits];
+}
+
+PropertyHashData::PropertyHashData(int numBits)
+ : numBits(numBits)
+ , size(0)
+{
+ refCount.store(1);
+ alloc = primeForNumBits(numBits);
+ entries = (PropertyHash::Entry *)malloc(alloc*sizeof(PropertyHash::Entry));
+ memset(entries, 0, alloc*sizeof(PropertyHash::Entry));
+}
+
+void PropertyHash::addEntry(const PropertyHash::Entry &entry, int classSize)
+{
+ // fill up to max 50%
+ bool grow = (d->alloc <= d->size*2);
+
+ if (classSize < d->size || grow) {
+ PropertyHashData *dd = new PropertyHashData(grow ? d->numBits + 1 : d->numBits);
+ for (uint i = 0; i < d->alloc; ++i) {
+ const Entry &e = d->entries[i];
+ if (!e.identifier || e.index >= classSize)
+ continue;
+ uint idx = e.identifier->hashValue % dd->alloc;
+ while (dd->entries[idx].identifier) {
+ ++idx;
+ idx %= dd->alloc;
+ }
+ dd->entries[idx] = e;
+ }
+ dd->size = classSize;
+ assert(d->refCount.load() > 1);
+ d->refCount.deref();
+ d = dd;
+ }
+
+ uint idx = entry.identifier->hashValue % d->alloc;
+ while (d->entries[idx].identifier) {
+ ++idx;
+ idx %= d->alloc;
+ }
+ d->entries[idx] = entry;
+ ++d->size;
+}
+
+uint PropertyHash::lookup(const Identifier *identifier) const
+{
+ assert(d->entries);
+
+ uint idx = identifier->hashValue % d->alloc;
+ while (1) {
+ if (d->entries[idx].identifier == identifier)
+ return d->entries[idx].index;
+ if (!d->entries[idx].identifier)
+ return UINT_MAX;
+ ++idx;
+ idx %= d->alloc;
+ }
+}
+
+
+InternalClass::InternalClass(const QV4::InternalClass &other)
+ : engine(other.engine)
+ , propertyTable(other.propertyTable)
+ , nameMap(other.nameMap)
+ , propertyData(other.propertyData)
+ , transitions()
+ , m_sealed(0)
+ , m_frozen(0)
+ , size(other.size)
+{
+}
+
+// ### Should we build this up from the empty class to avoid duplication?
+InternalClass *InternalClass::changeMember(String *string, PropertyAttributes data, uint *index)
+{
+// qDebug() << "InternalClass::changeMember()" << string->toQString() << hex << (uint)data.m_all;
+ data.resolve();
+ uint idx = find(string);
+ if (index)
+ *index = idx;
+
+ assert(idx != UINT_MAX);
+
+ if (data == propertyData[idx])
+ return this;
+
+
+ Transition t = { string->identifier, (int)data.flags() };
+ QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t);
+ if (tit != transitions.constEnd())
+ return tit.value();
+
+ // create a new class and add it to the tree
+ InternalClass *newClass = engine->newClass(*this);
+ newClass->propertyData[idx] = data;
+ return newClass;
+
+}
+
+InternalClass *InternalClass::addMember(String *string, PropertyAttributes data, uint *index)
+{
+// qDebug() << "InternalClass::addMember()" << string->toQString() << size << hex << (uint)data.m_all << data.type();
+ data.resolve();
+ engine->identifierTable->identifier(string);
+
+ if (propertyTable.lookup(string->identifier) < size)
+ return changeMember(string, data, index);
+
+ Transition t = { string->identifier, (int)data.flags() };
+ QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t);
+
+ if (index)
+ *index = size;
+ if (tit != transitions.constEnd())
+ return tit.value();
+
+ // create a new class and add it to the tree
+ InternalClass *newClass = engine->newClass(*this);
+ PropertyHash::Entry e = { string->identifier, size };
+ newClass->propertyTable.addEntry(e, size);
+
+ // The incoming string can come from anywhere, so make sure to
+ // store a string in the nameMap that's guaranteed to get
+ // marked properly during GC.
+ String *name = engine->newIdentifier(string->toQString());
+ newClass->nameMap.append(name);
+
+ newClass->propertyData.append(data);
+ ++newClass->size;
+ transitions.insert(t, newClass);
+ return newClass;
+}
+
+void InternalClass::removeMember(Object *object, Identifier *id)
+{
+ int propIdx = propertyTable.lookup(id);
+ assert(propIdx < size);
+
+ Transition t = { id, -1 };
+ QHash<Transition, InternalClass *>::const_iterator tit = transitions.constFind(t);
+
+ if (tit != transitions.constEnd()) {
+ object->internalClass = tit.value();
+ return;
+ }
+
+ // create a new class and add it to the tree
+ object->internalClass = engine->emptyClass;
+ for (int i = 0; i < nameMap.size(); ++i) {
+ if (i == propIdx)
+ continue;
+ object->internalClass = object->internalClass->addMember(nameMap.at(i), propertyData.at(i));
+ }
+
+ transitions.insert(t, object->internalClass);
+}
+
+uint InternalClass::find(String *string)
+{
+ engine->identifierTable->identifier(string);
+ const Identifier *id = string->identifier;
+
+ uint index = propertyTable.lookup(id);
+ if (index < size)
+ return index;
+
+ return UINT_MAX;
+}
+
+InternalClass *InternalClass::sealed()
+{
+ if (m_sealed)
+ return m_sealed;
+
+ m_sealed = engine->emptyClass;
+ for (int i = 0; i < nameMap.size(); ++i) {
+ PropertyAttributes attrs = propertyData.at(i);
+ attrs.setConfigurable(false);
+ m_sealed = m_sealed->addMember(nameMap.at(i), attrs);
+ }
+
+ m_sealed->m_sealed = m_sealed;
+ return m_sealed;
+}
+
+InternalClass *InternalClass::frozen()
+{
+ if (m_frozen)
+ return m_frozen;
+
+ m_frozen = engine->emptyClass;
+ for (int i = 0; i < nameMap.size(); ++i) {
+ PropertyAttributes attrs = propertyData.at(i);
+ attrs.setWritable(false);
+ attrs.setConfigurable(false);
+ m_frozen = m_frozen->addMember(nameMap.at(i), attrs);
+ }
+
+ m_frozen->m_frozen = m_frozen;
+ m_frozen->m_sealed = m_frozen;
+ return m_frozen;
+}
+
+void InternalClass::destroy()
+{
+ if (!engine)
+ return;
+ engine = 0;
+
+ // Free the memory of the hashes/vectors by calling clear(), which
+ // re-assigns them to the shared null instance. Therefore Internalclass
+ // doesn't need a destructor to be called.
+ propertyTable.~PropertyHash();
+ nameMap.clear();
+ propertyData.clear();
+
+ if (m_sealed)
+ m_sealed->destroy();
+
+ if (m_frozen)
+ m_frozen->destroy();
+
+ for (QHash<Transition, InternalClass *>::ConstIterator it = transitions.begin(), end = transitions.end();
+ it != end; ++it)
+ it.value()->destroy();
+
+ transitions.clear();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4internalclass_p.h b/src/qml/qml/v4/qv4internalclass_p.h
new file mode 100644
index 0000000000..fc6c5352b1
--- /dev/null
+++ b/src/qml/qml/v4/qv4internalclass_p.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4INTERNALCLASS_H
+#define QV4INTERNALCLASS_H
+
+#include <QHash>
+#include <QVector>
+#include "qv4global_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct String;
+struct ExecutionEngine;
+struct Object;
+struct Identifier;
+
+struct PropertyHashData;
+struct PropertyHash
+{
+ struct Entry {
+ const Identifier *identifier;
+ uint index;
+ };
+
+ PropertyHashData *d;
+
+ inline PropertyHash();
+ inline PropertyHash(const PropertyHash &other);
+ inline ~PropertyHash();
+
+ void addEntry(const Entry &entry, int classSize);
+ uint lookup(const Identifier *identifier) const;
+
+private:
+ PropertyHash &operator=(const PropertyHash &other);
+};
+
+struct PropertyHashData
+{
+ PropertyHashData(int numBits);
+ ~PropertyHashData() {
+ free(entries);
+ }
+
+ QBasicAtomicInt refCount;
+ int alloc;
+ int size;
+ int numBits;
+ PropertyHash::Entry *entries;
+};
+
+inline PropertyHash::PropertyHash()
+{
+ d = new PropertyHashData(3);
+}
+
+inline PropertyHash::PropertyHash(const PropertyHash &other)
+{
+ d = other.d;
+ d->refCount.ref();
+}
+
+inline PropertyHash::~PropertyHash()
+{
+ if (!d->refCount.deref())
+ delete d;
+}
+
+struct InternalClassTransition
+{
+ Identifier *id;
+ int flags;
+
+ bool operator==(const InternalClassTransition &other) const
+ { return id == other.id && flags == other.flags; }
+};
+uint qHash(const QV4::InternalClassTransition &t, uint = 0);
+
+struct InternalClass {
+ ExecutionEngine *engine;
+ PropertyHash propertyTable; // id to valueIndex
+ QVector<String *> nameMap;
+
+ QVector<PropertyAttributes> propertyData;
+
+ typedef InternalClassTransition Transition;
+ QHash<Transition, InternalClass *> transitions; // id to next class, positive means add, negative delete
+
+ InternalClass *m_sealed;
+ InternalClass *m_frozen;
+
+ uint size;
+
+ InternalClass *addMember(String *string, PropertyAttributes data, uint *index = 0);
+ InternalClass *changeMember(String *string, PropertyAttributes data, uint *index = 0);
+ void removeMember(Object *object, Identifier *id);
+ uint find(String *s);
+
+ InternalClass *sealed();
+ InternalClass *frozen();
+
+ void destroy();
+
+private:
+ friend struct ExecutionEngine;
+ InternalClass(ExecutionEngine *engine) : engine(engine), m_sealed(0), m_frozen(0), size(0) {}
+ InternalClass(const InternalClass &other);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v4/qv4ir.cpp b/src/qml/qml/v4/qv4ir.cpp
deleted file mode 100644
index 3159cf0d5f..0000000000
--- a/src/qml/qml/v4/qv4ir.cpp
+++ /dev/null
@@ -1,919 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4ir_p.h"
-
-#include <QtCore/qtextstream.h>
-#include <QtCore/qdebug.h>
-#include <math.h>
-
-QT_BEGIN_NAMESPACE
-
-namespace QQmlJS {
-namespace IR {
-
-const char *typeName(Type t)
-{
- switch (t) {
- case InvalidType: return "invalid";
- case UndefinedType: return "undefined";
- case NullType: return "null";
- case VoidType: return "void";
- case StringType: return "string";
- case UrlType: return "QUrl";
- case ColorType: return "QColor";
- case SGAnchorLineType: return "SGAnchorLine";
- case AttachType: return "AttachType";
- case ObjectType: return "object";
- case VariantType: return "variant";
- case VarType: return "var";
- case JSValueType: return "QJSValue";
- case BoolType: return "bool";
- case IntType: return "int";
- case FloatType: return "float";
- case NumberType: return "number";
- default: return "invalid";
- }
-}
-
-inline bool isNumberType(IR::Type ty)
-{
- return ty >= IR::FirstNumberType;
-}
-
-inline bool isStringType(IR::Type ty)
-{
- return ty == IR::StringType || ty == IR::UrlType || ty == IR::ColorType;
-}
-
-IR::Type maxType(IR::Type left, IR::Type right)
-{
- if (isStringType(left) && isStringType(right)) {
- // String promotions (url to string) are more specific than
- // identity conversions (AKA left == right). That's because
- // we want to ensure we convert urls to strings in binary
- // expressions.
- return IR::StringType;
- } else if (left == right)
- return left;
- else if (isNumberType(left) && isNumberType(right)) {
- IR::Type ty = qMax(left, right);
- return ty == FloatType ? NumberType : ty; // promote floats
- } else if ((isNumberType(left) && isStringType(right)) ||
- (isNumberType(right) && isStringType(left)))
- return IR::StringType;
- else
- return IR::InvalidType;
-}
-
-bool isRealType(IR::Type type)
-{
- return type == IR::NumberType || type == IR::FloatType;
-}
-
-const char *opname(AluOp op)
-{
- switch (op) {
- case OpInvalid: return "?";
-
- case OpIfTrue: return "(bool)";
- case OpNot: return "!";
- case OpUMinus: return "-";
- case OpUPlus: return "+";
- case OpCompl: return "~";
-
- case OpBitAnd: return "&";
- case OpBitOr: return "|";
- case OpBitXor: return "^";
-
- case OpAdd: return "+";
- case OpSub: return "-";
- case OpMul: return "*";
- case OpDiv: return "/";
- case OpMod: return "%";
-
- case OpLShift: return "<<";
- case OpRShift: return ">>";
- case OpURShift: return ">>>";
-
- case OpGt: return ">";
- case OpLt: return "<";
- case OpGe: return ">=";
- case OpLe: return "<=";
- case OpEqual: return "==";
- case OpNotEqual: return "!=";
- case OpStrictEqual: return "===";
- case OpStrictNotEqual: return "!==";
-
- case OpAnd: return "&&";
- case OpOr: return "||";
-
- default: return "?";
-
- } // switch
-}
-
-AluOp binaryOperator(int op)
-{
- switch (static_cast<QSOperator::Op>(op)) {
- case QSOperator::Add: return OpAdd;
- case QSOperator::And: return OpAnd;
- case QSOperator::BitAnd: return OpBitAnd;
- case QSOperator::BitOr: return OpBitOr;
- case QSOperator::BitXor: return OpBitXor;
- case QSOperator::Div: return OpDiv;
- case QSOperator::Equal: return OpEqual;
- case QSOperator::Ge: return OpGe;
- case QSOperator::Gt: return OpGt;
- case QSOperator::Le: return OpLe;
- case QSOperator::LShift: return OpLShift;
- case QSOperator::Lt: return OpLt;
- case QSOperator::Mod: return OpMod;
- case QSOperator::Mul: return OpMul;
- case QSOperator::NotEqual: return OpNotEqual;
- case QSOperator::Or: return OpOr;
- case QSOperator::RShift: return OpRShift;
- case QSOperator::StrictEqual: return OpStrictEqual;
- case QSOperator::StrictNotEqual: return OpStrictNotEqual;
- case QSOperator::Sub: return OpSub;
- case QSOperator::URShift: return OpURShift;
- default: return OpInvalid;
- }
-}
-
-void Const::dump(QTextStream &out)
-{
- out << value;
-}
-
-void String::dump(QTextStream &out)
-{
- out << '"' << escape(value) << '"';
-}
-
-QString String::escape(const QStringRef &s)
-{
- QString r;
- for (int i = 0; i < s.length(); ++i) {
- const QChar ch = s.at(i);
- if (ch == QLatin1Char('\n'))
- r += QLatin1String("\\n");
- else if (ch == QLatin1Char('\r'))
- r += QLatin1String("\\r");
- else if (ch == QLatin1Char('\\'))
- r += QLatin1String("\\\\");
- else if (ch == QLatin1Char('"'))
- r += QLatin1String("\\\"");
- else if (ch == QLatin1Char('\''))
- r += QLatin1String("\\'");
- else
- r += ch;
- }
- return r;
-}
-
-void Name::init(Name *base, Type type, const QString *id, Symbol symbol, quint16 line, quint16 column)
-{
- this->type = type;
- this->base = base;
- this->id = id;
- this->symbol = symbol;
- this->ptr = 0;
- this->property = 0;
- this->storage = MemberStorage;
- this->builtin = NoBuiltinSymbol;
- this->line = line;
- this->column = column;
-
- if (id->length() == 8 && *id == QLatin1String("Math.sin")) {
- builtin = MathSinBultinFunction;
- } else if (id->length() == 8 && *id == QLatin1String("Math.cos")) {
- builtin = MathCosBultinFunction;
- } else if (id->length() == 8 && *id == QLatin1String("Math.abs")) {
- builtin = MathAbsBuiltinFunction;
- } else if (id->length() == 10 && *id == QLatin1String("Math.round")) {
- builtin = MathRoundBultinFunction;
- } else if (id->length() == 10 && *id == QLatin1String("Math.floor")) {
- builtin = MathFloorBultinFunction;
- } else if (id->length() == 9 && *id == QLatin1String("Math.ceil")) {
- builtin = MathCeilBuiltinFunction;
- } else if (id->length() == 8 && *id == QLatin1String("Math.max")) {
- builtin = MathMaxBuiltinFunction;
- } else if (id->length() == 8 && *id == QLatin1String("Math.min")) {
- builtin = MathMinBuiltinFunction;
- } else if (id->length() == 7 && *id == QLatin1String("Math.PI")) {
- builtin = MathPIBuiltinConstant;
- this->type = NumberType;
- }
-}
-
-void Name::dump(QTextStream &out)
-{
- if (base) {
- base->dump(out);
- out << '.';
- }
-
- out << *id;
-}
-
-void Temp::dump(QTextStream &out)
-{
- out << 't' << index;
-}
-
-void Unop::dump(QTextStream &out)
-{
- out << opname(op);
- expr->dump(out);
-}
-
-Type Unop::typeForOp(AluOp op, Expr *expr)
-{
- switch (op) {
- case OpIfTrue: return BoolType;
- case OpNot: return BoolType;
-
- case OpUMinus:
- case OpUPlus:
- case OpCompl:
- return maxType(expr->type, NumberType);
-
- default:
- break;
- }
-
- return InvalidType;
-}
-
-void Binop::dump(QTextStream &out)
-{
- left->dump(out);
- out << ' ' << opname(op) << ' ';
- right->dump(out);
-}
-
-Type Binop::typeForOp(AluOp op, Expr *left, Expr *right)
-{
- if (! (left && right))
- return InvalidType;
-
- switch (op) {
- case OpInvalid:
- return InvalidType;
-
- // unary operators
- case OpIfTrue:
- case OpNot:
- case OpUMinus:
- case OpUPlus:
- case OpCompl:
- return InvalidType;
-
- // bit fields
- case OpBitAnd:
- case OpBitOr:
- case OpBitXor:
- return IntType;
-
- case OpAdd:
- if (left->type == StringType)
- return StringType;
- return NumberType;
-
- case OpSub:
- case OpMul:
- case OpDiv:
- case OpMod:
- return NumberType;
-
- case OpLShift:
- case OpRShift:
- case OpURShift:
- return IntType;
-
- case OpAnd:
- case OpOr:
- return BoolType;
-
- case OpGt:
- case OpLt:
- case OpGe:
- case OpLe:
- case OpEqual:
- case OpNotEqual:
- case OpStrictEqual:
- case OpStrictNotEqual:
- return BoolType;
- } // switch
-
- return InvalidType;
-}
-
-void Call::dump(QTextStream &out)
-{
- base->dump(out);
- out << '(';
- for (ExprList *it = args; it; it = it->next) {
- if (it != args)
- out << ", ";
- it->expr->dump(out);
- }
- out << ')';
-}
-
-Type Call::typeForFunction(Expr *base)
-{
- if (! base)
- return InvalidType;
-
- if (Name *name = base->asName()) {
- switch (name->builtin) {
- case MathSinBultinFunction:
- case MathCosBultinFunction:
- case MathAbsBuiltinFunction: //### type could also be Int if input was Int
- case MathMaxBuiltinFunction:
- case MathMinBuiltinFunction:
- return NumberType;
-
- case MathRoundBultinFunction:
- case MathFloorBultinFunction:
- case MathCeilBuiltinFunction:
- return IntType;
-
- case NoBuiltinSymbol:
- case MathPIBuiltinConstant:
- break;
- }
- } // switch
-
- return InvalidType;
-}
-
-void Exp::dump(QTextStream &out, Mode)
-{
- out << "(void) ";
- expr->dump(out);
- out << ';';
-}
-
-void Move::dump(QTextStream &out, Mode)
-{
- target->dump(out);
- out << " = ";
- if (source->type != target->type)
- out << typeName(source->type) << "_to_" << typeName(target->type) << '(';
- source->dump(out);
- if (source->type != target->type)
- out << ')';
- out << ';';
-}
-
-void Jump::dump(QTextStream &out, Mode mode)
-{
- Q_UNUSED(mode);
- out << "goto " << 'L' << target << ';';
-}
-
-void CJump::dump(QTextStream &out, Mode mode)
-{
- Q_UNUSED(mode);
- out << "if (";
- cond->dump(out);
- out << ") goto " << 'L' << iftrue << "; else goto " << 'L' << iffalse << ';';
-}
-
-void Ret::dump(QTextStream &out, Mode)
-{
- out << "return";
- if (expr) {
- out << ' ';
- expr->dump(out);
- }
- out << ';';
-}
-
-Function::~Function()
-{
- qDeleteAll(basicBlocks);
-}
-
-QString *Function::newString(const QString &text)
-{
- return pool->NewString(text);
-}
-
-BasicBlock *Function::newBasicBlock()
-{
- const int index = basicBlocks.size();
- return i(new BasicBlock(this, index));
-}
-
-void Function::dump(QTextStream &out)
-{
- out << "function () {" << endl;
- foreach (BasicBlock *bb, basicBlocks) {
- bb->dump(out);
- }
- out << '}' << endl;
-}
-
-Temp *BasicBlock::TEMP(Type type, int index)
-{
- Temp *e = function->pool->New<Temp>();
- e->init(type, index);
- return e;
-}
-
-Temp *BasicBlock::TEMP(Type type)
-{
- return TEMP(type, function->tempCount++);
-}
-
-Expr *BasicBlock::CONST(Type type, double value)
-{
- Const *e = function->pool->New<Const>();
- e->init(type, value);
- return e;
-}
-
-Expr *BasicBlock::STRING(const QStringRef &value)
-{
- String *e = function->pool->New<String>();
- e->init(value);
- return e;
-}
-
-Name *BasicBlock::NAME(const QString &id, quint16 line, quint16 column)
-{
- return NAME(0, id, line, column);
-}
-
-Name *BasicBlock::NAME(Name *base, const QString &id, quint16 line, quint16 column)
-{
- Name *e = function->pool->New<Name>();
- e->init(base, InvalidType,
- function->newString(id),
- Name::Unbound, line, column);
- return e;
-}
-
-Name *BasicBlock::SYMBOL(Type type, const QString &id, const QQmlMetaObject &meta, QQmlPropertyData *property, Name::Storage storage,
- quint16 line, quint16 column)
-{
- Name *name = SYMBOL(/*base = */ 0, type, id, meta, property, line, column);
- name->storage = storage;
- return name;
-}
-
-Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QQmlMetaObject &meta, QQmlPropertyData *property, Name::Storage storage,
- quint16 line, quint16 column)
-{
- Name *name = function->pool->New<Name>();
- name->init(base, type, function->newString(id),
- Name::Property, line, column);
- name->meta = meta;
- name->property = property;
- name->storage = storage;
- return name;
-}
-
-Name *BasicBlock::SYMBOL(Name *base, Type type, const QString &id, const QQmlMetaObject &meta, QQmlPropertyData *property,
- quint16 line, quint16 column)
-{
- Name *name = function->pool->New<Name>();
- name->init(base, type, function->newString(id),
- Name::Property, line, column);
- name->meta = meta;
- name->property = property;
- return name;
-}
-
-Name *BasicBlock::ID_OBJECT(const QString &id, const QQmlScript::Object *object, quint16 line, quint16 column)
-{
- Name *name = function->pool->New<Name>();
- name->init(/*base = */ 0, IR::ObjectType,
- function->newString(id),
- Name::IdObject, line, column);
- name->idObject = object;
- name->property = 0;
- name->storage = Name::IdStorage;
- return name;
-}
-
-Name *BasicBlock::ATTACH_TYPE(const QString &id, const QQmlType *attachType, Name::Storage storage,
- quint16 line, quint16 column)
-{
- Name *name = function->pool->New<Name>();
- name->init(/*base = */ 0, IR::AttachType,
- function->newString(id),
- Name::AttachType, line, column);
- name->declarativeType = attachType;
- name->storage = storage;
- return name;
-}
-
-Name *BasicBlock::SINGLETON_OBJECT(const QString &id, const QQmlMetaObject &meta, Name::Storage storage,
- quint16 line, quint16 column)
-{
- Name *name = function->pool->New<Name>();
- name->init(/*base = */ 0, IR::ObjectType,
- function->newString(id),
- Name::SingletonObject, line, column);
- name->meta = meta;
- name->storage = storage;
- return name;
-}
-
-Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
-{
- Unop *e = function->pool->New<Unop>();
- e->init(op, expr);
- return e;
-}
-
-Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
-{
- if (left && right) {
- if (Const *c1 = left->asConst()) {
- if (Const *c2 = right->asConst()) {
- const IR::Type ty = Binop::typeForOp(op, left, right);
-
- switch (op) {
- case OpAdd: return CONST(ty, c1->value + c2->value);
- case OpAnd: return CONST(ty, c1->value ? c2->value : 0);
- case OpBitAnd: return CONST(ty, int(c1->value) & int(c2->value));
- case OpBitOr: return CONST(ty, int(c1->value) | int(c2->value));
- case OpBitXor: return CONST(ty, int(c1->value) ^ int(c2->value));
- case OpDiv: return CONST(ty, c1->value / c2->value);
- case OpEqual: return CONST(ty, c1->value == c2->value);
- case OpGe: return CONST(ty, c1->value >= c2->value);
- case OpGt: return CONST(ty, c1->value > c2->value);
- case OpLe: return CONST(ty, c1->value <= c2->value);
- case OpLShift: return CONST(ty, int(c1->value) << int(c2->value));
- case OpLt: return CONST(ty, c1->value < c2->value);
- case OpMod: return CONST(ty, ::fmod(c1->value, c2->value));
- case OpMul: return CONST(ty, c1->value * c2->value);
- case OpNotEqual: return CONST(ty, c1->value != c2->value);
- case OpOr: return CONST(ty, c1->value ? c1->value : c2->value);
- case OpRShift: return CONST(ty, int(c1->value) >> int(c2->value));
- case OpStrictEqual: return CONST(ty, c1->value == c2->value);
- case OpStrictNotEqual: return CONST(ty, c1->value != c2->value);
- case OpSub: return CONST(ty, c1->value - c2->value);
- case OpURShift: return CONST(ty, unsigned(c1->value) >> int(c2->value));
-
- case OpIfTrue: // unary ops
- case OpNot:
- case OpUMinus:
- case OpUPlus:
- case OpCompl:
- case OpInvalid:
- break;
- }
- }
- } else if (op == OpAdd) {
- if (String *s1 = left->asString()) {
- if (String *s2 = right->asString()) {
- return STRING(function->newString(s1->value.toString() + s2->value));
- }
- }
- }
- }
-
- Binop *e = function->pool->New<Binop>();
- e->init(op, left, right);
- return e;
-}
-
-Expr *BasicBlock::CALL(Expr *base, ExprList *args)
-{
- Call *e = function->pool->New<Call>();
- e->init(base, args);
- return e;
-}
-
-Stmt *BasicBlock::EXP(Expr *expr)
-{
- Exp *s = function->pool->New<Exp>();
- s->init(expr);
- statements.append(s);
- return s;
-}
-
-Stmt *BasicBlock::MOVE(Expr *target, Expr *source, bool isMoveForReturn)
-{
- Move *s = function->pool->New<Move>();
- s->init(target, source, isMoveForReturn);
- statements.append(s);
- return s;
-}
-
-Stmt *BasicBlock::JUMP(BasicBlock *target)
-{
- if (isTerminated())
- return 0;
-
- Jump *s = function->pool->New<Jump>();
- s->init(target);
- statements.append(s);
- return s;
-}
-
-Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
-{
- if (isTerminated())
- return 0;
-
- CJump *s = function->pool->New<CJump>();
- s->init(cond, iftrue, iffalse);
- statements.append(s);
- return s;
-}
-
-Stmt *BasicBlock::RET(Expr *expr, Type type, quint16 line, quint16 column)
-{
- if (isTerminated())
- return 0;
-
- Ret *s = function->pool->New<Ret>();
- s->init(expr, type, line, column);
- statements.append(s);
- return s;
-}
-
-void BasicBlock::dump(QTextStream &out)
-{
- out << 'L' << this << ':' << endl;
- foreach (Stmt *s, statements) {
- out << '\t';
- s->dump(out);
- out << endl;
- }
-}
-
-#ifdef DEBUG_IR_STRUCTURE
-
-static const char *symbolname(Name::Symbol s)
-{
- switch (s) {
- case Name::Unbound:
- return "Unbound";
- case Name::IdObject:
- return "IdObject";
- case Name::AttachType:
- return "AttachType";
- case Name::SingletonObject:
- return "SingletonObject";
- case Name::Object:
- return "Object";
- case Name::Property:
- return "Property";
- case Name::Slot:
- return "Slot";
- default:
- Q_ASSERT(!"Unreachable");
- return "Unknown";
- }
-}
-
-static const char *storagename(Name::Storage s)
-{
- switch (s) {
- case Name::MemberStorage:
- return "MemberStorage";
- case Name::IdStorage:
- return "IdStorage";
- case Name::RootStorage:
- return "RootStorage";
- case Name::ScopeStorage:
- return "ScopeStorage";
- default:
- Q_ASSERT(!"Unreachable");
- return "UnknownStorage";
- }
-}
-
-IRDump::IRDump()
-: indentSize(0)
-{
-}
-
-void IRDump::inc()
-{
- indentSize++;
- indentData = QByteArray(indentSize * 4, ' ');
-}
-
-void IRDump::dec()
-{
- indentSize--;
- indentData = QByteArray(indentSize * 4, ' ');
-}
-
-void IRDump::dec();
-
-void IRDump::expression(QQmlJS::IR::Expr *e)
-{
- inc();
-
- e->accept(this);
-
- dec();
-}
-
-void IRDump::basicblock(QQmlJS::IR::BasicBlock *b)
-{
- inc();
-
- qWarning().nospace() << indent() << "BasicBlock " << b << " {";
- for (int ii = 0; ii < b->statements.count(); ++ii) {
- statement(b->statements.at(ii));
- if (ii != (b->statements.count() - 1))
- qWarning();
- }
- qWarning().nospace() << indent() << '}';
-
- dec();
-}
-
-void IRDump::statement(QQmlJS::IR::Stmt *s)
-{
- inc();
-
- s->accept(this);
-
- dec();
-}
-
-void IRDump::function(QQmlJS::IR::Function *f)
-{
- inc();
-
- qWarning().nospace() << indent() << "Function {";
- for (int ii = 0; ii < f->basicBlocks.count(); ++ii) {
- basicblock(f->basicBlocks.at(ii));
- }
- qWarning().nospace() << indent() << '}';
-
- dec();
-}
-
-const char *IRDump::indent()
-{
- return indentData.constData();
-}
-
-void IRDump::visitConst(QQmlJS::IR::Const *e)
-{
- qWarning().nospace() << indent() << "Const:Expr { type: " << typeName(e->type) << ", value: " << e->value << '}';
-}
-
-void IRDump::visitString(QQmlJS::IR::String *e)
-{
- qWarning().nospace() << indent() << "String:Expr { type: " << typeName(e->type) << ", value: " << e->value << '}';
-}
-
-static void namedumprecur(QQmlJS::IR::Name *e, const char *indent)
-{
- if (e->base) namedumprecur(e->base, indent);
- qWarning().nospace() << indent << " { type: " << typeName(e->type) << ", symbol: " << symbolname(e->symbol) << ", storage: " << storagename(e->storage) << ", id: " << e->id << '}';
-}
-
-void IRDump::visitName(QQmlJS::IR::Name *e)
-{
- qWarning().nospace() << indent() << "Name:Expr {";
- namedumprecur(e, indent());
- qWarning().nospace() << indent() << '}';
-}
-
-void IRDump::visitTemp(QQmlJS::IR::Temp *e)
-{
- qWarning().nospace() << indent() << "Temp:Expr { type: " << typeName(e->type) << ", index: " << e->index << " }";
-}
-
-void IRDump::visitUnop(QQmlJS::IR::Unop *e)
-{
- qWarning().nospace() << indent() << "Unop:Expr { ";
- qWarning().nospace() << indent() << " type: " << typeName(e->type) << ", op: " << opname(e->op);
- qWarning().nospace() << indent() << " expr: {";
- expression(e->expr);
- qWarning().nospace() << indent() << " }";
- qWarning().nospace() << indent() << '}';
-}
-
-void IRDump::visitBinop(QQmlJS::IR::Binop *e)
-{
- qWarning().nospace() << indent() << "Binop:Expr { ";
- qWarning().nospace() << indent() << " type: " << typeName(e->type) << ", op: " << opname(e->op);
- qWarning().nospace() << indent() << " left: {";
- inc();
- expression(e->left);
- dec();
- qWarning().nospace() << indent() << " },";
- qWarning().nospace() << indent() << " right: {";
- inc();
- expression(e->right);
- dec();
- qWarning().nospace() << indent() << " }";
- qWarning().nospace() << indent() << '}';
-}
-
-void IRDump::visitCall(QQmlJS::IR::Call *e)
-{
- Q_UNUSED(e);
- qWarning().nospace() << indent() << "Exp::Call { }";
-}
-
-void IRDump::visitExp(QQmlJS::IR::Exp *s)
-{
- qWarning().nospace() << indent() << "Exp:Stmt {";
- expression(s->expr);
- qWarning().nospace() << indent() << '}';
-}
-
-void IRDump::visitMove(QQmlJS::IR::Move *s)
-{
- qWarning().nospace() << indent() << "Move:Stmt {";
- qWarning().nospace() << indent() << " isMoveForReturn: " << s->isMoveForReturn;
- qWarning().nospace() << indent() << " target: {";
- inc();
- expression(s->target);
- dec();
- qWarning().nospace() << indent() << " },";
- qWarning().nospace() << indent() << " source: {";
- inc();
- expression(s->source);
- dec();
- qWarning().nospace() << indent() << " }";
- qWarning().nospace() << indent() << '}';
-}
-
-void IRDump::visitJump(QQmlJS::IR::Jump *s)
-{
- qWarning().nospace() << indent() << "Jump:Stmt { BasicBlock(" << s->target << ") }";
-}
-
-void IRDump::visitCJump(QQmlJS::IR::CJump *s)
-{
- qWarning().nospace() << indent() << "CJump:Stmt {";
- qWarning().nospace() << indent() << " cond: {";
- inc();
- expression(s->cond);
- dec();
- qWarning().nospace() << indent() << " }";
- qWarning().nospace() << indent() << " iftrue: BasicBlock(" << s->iftrue << ')';
- qWarning().nospace() << indent() << " iffalse: BasicBlock(" << s->iffalse << ')';
- qWarning().nospace() << indent() << '}';
-}
-
-void IRDump::visitRet(QQmlJS::IR::Ret *s)
-{
- qWarning().nospace() << indent() << "Ret:Stmt {";
- qWarning().nospace() << indent() << " type: " << typeName(s->type);
- expression(s->expr);
- qWarning().nospace() << indent() << '}';
-}
-#endif
-
-} // end of namespace IR
-} // end of namespace QQmlJS
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4ir_p.h b/src/qml/qml/v4/qv4ir_p.h
deleted file mode 100644
index 701f76d9e4..0000000000
--- a/src/qml/qml/v4/qv4ir_p.h
+++ /dev/null
@@ -1,615 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4IR_P_H
-#define QV4IR_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/qqmljsast_p.h>
-#include <private/qqmljsengine_p.h>
-#include <private/qqmlscript_p.h>
-#include <private/qqmlimport_p.h>
-#include <private/qqmlengine_p.h>
-#include <private/qv4compiler_p.h>
-
-#include <private/qqmlpool_p.h>
-#include <QtCore/qvarlengtharray.h>
-
-// #define DEBUG_IR_STRUCTURE
-
-#ifdef CONST
-# undef CONST
-#endif
-
-QT_BEGIN_NAMESPACE
-
-class QTextStream;
-class QQmlType;
-
-namespace QQmlJS {
-
-namespace IR {
-
-struct BasicBlock;
-struct Function;
-
-struct Stmt;
-struct Expr;
-
-// expressions
-struct Const;
-struct String;
-struct Name;
-struct Temp;
-struct Unop;
-struct Binop;
-struct Call;
-
-// statements
-struct Exp;
-struct Move;
-struct Jump;
-struct CJump;
-struct Ret;
-
-enum AluOp {
- OpInvalid = 0,
-
- OpIfTrue,
- OpNot,
- OpUMinus,
- OpUPlus,
- OpCompl,
-
- OpBitAnd,
- OpBitOr,
- OpBitXor,
-
- OpAdd,
- OpSub,
- OpMul,
- OpDiv,
- OpMod,
-
- OpLShift,
- OpRShift,
- OpURShift,
-
- OpGt,
- OpLt,
- OpGe,
- OpLe,
- OpEqual,
- OpNotEqual,
- OpStrictEqual,
- OpStrictNotEqual,
-
- OpAnd,
- OpOr
-};
-AluOp binaryOperator(int op);
-
-enum Type {
- InvalidType,
- UndefinedType,
- NullType,
- VoidType,
- StringType,
- UrlType,
- ColorType,
- SGAnchorLineType,
- AttachType,
- ObjectType,
- VariantType,
- VarType,
- JSValueType,
-
- FirstNumberType,
- BoolType = FirstNumberType,
- IntType,
- FloatType,
- NumberType
-};
-Type maxType(IR::Type left, IR::Type right);
-bool isRealType(IR::Type type);
-const char *typeName(IR::Type t);
-
-struct ExprVisitor {
- virtual ~ExprVisitor() {}
- virtual void visitConst(Const *) {}
- virtual void visitString(String *) {}
- virtual void visitName(Name *) {}
- virtual void visitTemp(Temp *) {}
- virtual void visitUnop(Unop *) {}
- virtual void visitBinop(Binop *) {}
- virtual void visitCall(Call *) {}
-};
-
-struct StmtVisitor {
- virtual ~StmtVisitor() {}
- virtual void visitExp(Exp *) {}
- virtual void visitMove(Move *) {}
- virtual void visitJump(Jump *) {}
- virtual void visitCJump(CJump *) {}
- virtual void visitRet(Ret *) {}
-};
-
-struct Expr: QQmlPool::POD {
- Type type;
-
- Expr(): type(InvalidType) {}
- virtual ~Expr() {}
- virtual void accept(ExprVisitor *) = 0;
- virtual Const *asConst() { return 0; }
- virtual String *asString() { return 0; }
- virtual Name *asName() { return 0; }
- virtual Temp *asTemp() { return 0; }
- virtual Unop *asUnop() { return 0; }
- virtual Binop *asBinop() { return 0; }
- virtual Call *asCall() { return 0; }
- virtual void dump(QTextStream &out) = 0;
-};
-
-struct ExprList: QQmlPool::POD {
- Expr *expr;
- ExprList *next;
-
- void init(Expr *expr, ExprList *next = 0)
- {
- this->expr = expr;
- this->next = next;
- }
-};
-
-struct Const: Expr {
- double value;
-
- void init(Type type, double value)
- {
- this->type = type;
- this->value = value;
- }
-
- virtual void accept(ExprVisitor *v) { v->visitConst(this); }
- virtual Const *asConst() { return this; }
-
- virtual void dump(QTextStream &out);
-};
-
-struct String: Expr {
- QStringRef value;
-
- void init(const QStringRef &value)
- {
- this->type = StringType;
- this->value = value;
- }
-
- virtual void accept(ExprVisitor *v) { v->visitString(this); }
- virtual String *asString() { return this; }
-
- virtual void dump(QTextStream &out);
- static QString escape(const QStringRef &s);
-};
-
-enum BuiltinSymbol {
- NoBuiltinSymbol,
- MathSinBultinFunction,
- MathCosBultinFunction,
- MathRoundBultinFunction,
- MathFloorBultinFunction,
- MathCeilBuiltinFunction,
- MathAbsBuiltinFunction,
- MathMaxBuiltinFunction,
- MathMinBuiltinFunction,
-
- MathPIBuiltinConstant
-};
-
-struct Name: Expr {
- enum Symbol {
- Unbound,
- IdObject, // This is a load of a id object. Storage will always be IdStorage
- AttachType, // This is a load of an attached object
- SingletonObject, // This is a load of a singleton object
- Object, // XXX what is this for?
- Property, // This is a load of a regular property
- Slot // XXX what is this for?
- };
-
- enum Storage {
- MemberStorage, // This is a property of a previously fetched object
- IdStorage, // This is a load of a id object. Symbol will always be IdObject
- RootStorage, // This is a property of the root object
- ScopeStorage // This is a property of the scope object
- };
-
- Name *base;
- const QString *id;
- Symbol symbol;
- union {
- void *ptr;
- const QQmlType *declarativeType;
- const QQmlScript::Object *idObject;
- };
-
- QQmlMetaObject meta;
- QQmlPropertyData *property;
- Storage storage;
- BuiltinSymbol builtin;
- quint16 line;
- quint16 column;
-
- void init(Name *base, Type type, const QString *id, Symbol symbol, quint16 line, quint16 column);
-
- inline bool is(Symbol s) const { return s == symbol; }
- inline bool isNot(Symbol s) const { return s != symbol; }
-
- virtual void accept(ExprVisitor *v) { v->visitName(this); }
- virtual Name *asName() { return this; }
-
- virtual void dump(QTextStream &out);
-};
-
-struct Temp: Expr {
- int index;
-
- void init(Type type, int index)
- {
- this->type = type;
- this->index = index;
- }
-
- virtual void accept(ExprVisitor *v) { v->visitTemp(this); }
- virtual Temp *asTemp() { return this; }
-
- virtual void dump(QTextStream &out);
-};
-
-struct Unop: Expr {
- AluOp op;
- Expr *expr;
-
- void init(AluOp op, Expr *expr)
- {
- this->type = this->typeForOp(op, expr);
- this->op = op;
- this->expr = expr;
- }
-
- virtual void accept(ExprVisitor *v) { v->visitUnop(this); }
- virtual Unop *asUnop() { return this; }
-
- virtual void dump(QTextStream &out);
-
-private:
- static Type typeForOp(AluOp op, Expr *expr);
-};
-
-struct Binop: Expr {
- AluOp op;
- Expr *left;
- Expr *right;
-
- void init(AluOp op, Expr *left, Expr *right)
- {
- this->type = typeForOp(op, left, right);
- this->op = op;
- this->left = left;
- this->right = right;
- }
-
- virtual void accept(ExprVisitor *v) { v->visitBinop(this); }
- virtual Binop *asBinop() { return this; }
-
- virtual void dump(QTextStream &out);
-
- static Type typeForOp(AluOp op, Expr *left, Expr *right);
-};
-
-struct Call: Expr {
- Expr *base;
- ExprList *args;
-
- void init(Expr *base, ExprList *args)
- {
- this->type = typeForFunction(base);
- this->base = base;
- this->args = args;
- }
-
- Expr *onlyArgument() const {
- if (args && ! args->next)
- return args->expr;
- return 0;
- }
-
- virtual void accept(ExprVisitor *v) { v->visitCall(this); }
- virtual Call *asCall() { return this; }
-
- virtual void dump(QTextStream &out);
-
-private:
- static Type typeForFunction(Expr *base);
-};
-
-struct Stmt: QQmlPool::POD {
- enum Mode {
- HIR,
- MIR
- };
-
- virtual ~Stmt() {}
- virtual Stmt *asTerminator() { return 0; }
-
- virtual void accept(StmtVisitor *) = 0;
- virtual Exp *asExp() { return 0; }
- virtual Move *asMove() { return 0; }
- virtual Jump *asJump() { return 0; }
- virtual CJump *asCJump() { return 0; }
- virtual Ret *asRet() { return 0; }
- virtual void dump(QTextStream &out, Mode mode = HIR) = 0;
-};
-
-struct Exp: Stmt {
- Expr *expr;
-
- void init(Expr *expr)
- {
- this->expr = expr;
- }
-
- virtual void accept(StmtVisitor *v) { v->visitExp(this); }
- virtual Exp *asExp() { return this; }
-
- virtual void dump(QTextStream &out, Mode);
-};
-
-struct Move: Stmt {
- Expr *target;
- Expr *source;
- bool isMoveForReturn;
-
- void init(Expr *target, Expr *source, bool isMoveForReturn)
- {
- this->target = target;
- this->source = source;
- this->isMoveForReturn = isMoveForReturn;
- }
-
- virtual void accept(StmtVisitor *v) { v->visitMove(this); }
- virtual Move *asMove() { return this; }
-
- virtual void dump(QTextStream &out, Mode);
-};
-
-struct Jump: Stmt {
- BasicBlock *target;
-
- void init(BasicBlock *target)
- {
- this->target = target;
- }
-
- virtual Stmt *asTerminator() { return this; }
-
- virtual void accept(StmtVisitor *v) { v->visitJump(this); }
- virtual Jump *asJump() { return this; }
-
- virtual void dump(QTextStream &out, Mode mode);
-};
-
-struct CJump: Stmt {
- Expr *cond;
- BasicBlock *iftrue;
- BasicBlock *iffalse;
-
- void init(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
- {
- this->cond = cond;
- this->iftrue = iftrue;
- this->iffalse = iffalse;
- }
-
- virtual Stmt *asTerminator() { return this; }
-
- virtual void accept(StmtVisitor *v) { v->visitCJump(this); }
- virtual CJump *asCJump() { return this; }
-
- virtual void dump(QTextStream &out, Mode mode);
-};
-
-struct Ret: Stmt {
- Expr *expr;
- Type type;
- quint16 line;
- quint16 column;
-
- void init(Expr *expr, Type type, quint16 line, quint16 column)
- {
- this->expr = expr;
- this->type = type;
- this->line = line;
- this->column = column;
- }
-
- virtual Stmt *asTerminator() { return this; }
-
- virtual void accept(StmtVisitor *v) { v->visitRet(this); }
- virtual Ret *asRet() { return this; }
-
- virtual void dump(QTextStream &out, Mode);
-};
-
-struct Function {
- QQmlPool *pool;
- QVarLengthArray<BasicBlock *, 8> basicBlocks;
- int tempCount;
-
- Function(QQmlPool *pool)
- : pool(pool), tempCount(0) {}
-
- virtual ~Function();
-
- BasicBlock *newBasicBlock();
- QString *newString(const QString &text);
-
- inline BasicBlock *i(BasicBlock *block) { basicBlocks.append(block); return block; }
-
- virtual void dump(QTextStream &out);
-};
-
-struct BasicBlock {
- Function *function;
- int index;
- int offset;
- QVarLengthArray<Stmt *, 32> statements;
-
- BasicBlock(Function *function, int index): function(function), index(index), offset(-1) {}
- ~BasicBlock() {}
-
- template <typename Instr> inline Instr i(Instr i) { statements.append(i); return i; }
-
- inline bool isEmpty() const {
- return statements.isEmpty();
- }
-
- inline Stmt *terminator() const {
- if (! statements.isEmpty() && statements.at(statements.size() - 1)->asTerminator() != 0)
- return statements.at(statements.size() - 1);
- return 0;
- }
-
- inline bool isTerminated() const {
- if (terminator() != 0)
- return true;
- return false;
- }
-
- Temp *TEMP(Type type, int index);
- Temp *TEMP(Type type);
-
- Expr *CONST(Type type, double value);
- Expr *STRING(const QStringRef &value);
-
- Name *NAME(const QString &id, quint16 line, quint16 column);
- Name *NAME(Name *base, const QString &id, quint16 line, quint16 column);
- Name *SYMBOL(Type type, const QString &id, const QQmlMetaObject &meta, QQmlPropertyData *property, Name::Storage storage, quint16 line, quint16 column);
- Name *SYMBOL(Name *base, Type type, const QString &id, const QQmlMetaObject &meta, QQmlPropertyData *property, quint16 line, quint16 column);
- Name *SYMBOL(Name *base, Type type, const QString &id, const QQmlMetaObject &meta, QQmlPropertyData *property, Name::Storage storage, quint16 line, quint16 column);
- Name *ID_OBJECT(const QString &id, const QQmlScript::Object *object, quint16 line, quint16 column);
- Name *ATTACH_TYPE(const QString &id, const QQmlType *attachType, Name::Storage storage, quint16 line, quint16 column);
- Name *SINGLETON_OBJECT(const QString &id, const QQmlMetaObject &meta, Name::Storage storage, quint16 line, quint16 column);
-
- Expr *UNOP(AluOp op, Expr *expr);
- Expr *BINOP(AluOp op, Expr *left, Expr *right);
- Expr *CALL(Expr *base, ExprList *args);
-
- Stmt *EXP(Expr *expr);
- Stmt *MOVE(Expr *target, Expr *source, bool = false);
-
- Stmt *JUMP(BasicBlock *target);
- Stmt *CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse);
- Stmt *RET(Expr *expr, Type type, quint16 line, quint16 column);
-
- void dump(QTextStream &out);
-};
-
-#ifdef DEBUG_IR_STRUCTURE
-struct IRDump : public ExprVisitor,
- public StmtVisitor
-{
-public:
- IRDump();
-
- void expression(QQmlJS::IR::Expr *);
- void basicblock(QQmlJS::IR::BasicBlock *);
- void statement(QQmlJS::IR::Stmt *);
- void function(QQmlJS::IR::Function *);
-protected:
-
- const char *indent();
-
- //
- // expressions
- //
- virtual void visitConst(QQmlJS::IR::Const *e);
- virtual void visitString(QQmlJS::IR::String *e);
- virtual void visitName(QQmlJS::IR::Name *e);
- virtual void visitTemp(QQmlJS::IR::Temp *e);
- virtual void visitUnop(QQmlJS::IR::Unop *e);
- virtual void visitBinop(QQmlJS::IR::Binop *e);
- virtual void visitCall(QQmlJS::IR::Call *e);
-
- //
- // statements
- //
- virtual void visitExp(QQmlJS::IR::Exp *s);
- virtual void visitMove(QQmlJS::IR::Move *s);
- virtual void visitJump(QQmlJS::IR::Jump *s);
- virtual void visitCJump(QQmlJS::IR::CJump *s);
- virtual void visitRet(QQmlJS::IR::Ret *s);
-
-private:
- int indentSize;
- QByteArray indentData;
- void inc();
- void dec();
-};
-#endif
-
-} // end of namespace IR
-
-} // end of namespace QQmlJS
-
-QT_END_NAMESPACE
-
-#endif // QV4IR_P_H
diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp
deleted file mode 100644
index d217b5e2f5..0000000000
--- a/src/qml/qml/v4/qv4irbuilder.cpp
+++ /dev/null
@@ -1,1394 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv4irbuilder_p.h"
-#include "qv4compiler_p_p.h"
-
-#include <private/qqmlglobal_p.h>
-#include <private/qqmlmetatype_p.h>
-#include <private/qqmltypenamecache_p.h>
-
-DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER)
-
-QT_BEGIN_NAMESPACE
-
-using namespace QQmlJS;
-
-static IR::Type irTypeFromVariantType(int t, QQmlEnginePrivate *engine)
-{
- switch (t) {
- case QMetaType::Bool:
- return IR::BoolType;
-
- case QMetaType::Int:
- return IR::IntType;
-
- case QMetaType::Float:
- return IR::FloatType;
-
- case QMetaType::Double:
- return IR::NumberType;
-
- case QMetaType::QString:
- return IR::StringType;
-
- case QMetaType::QUrl:
- return IR::UrlType;
-
- case QMetaType::QColor:
- return IR::ColorType;
-
- default:
- if (t == QQmlMetaType::QQuickAnchorLineMetaTypeId()) {
- return IR::SGAnchorLineType;
- } else if (!engine->metaObjectForType(t).isNull()) {
- return IR::ObjectType;
- } else if (t == qMetaTypeId<QJSValue>()) {
- return IR::JSValueType;
- }
-
- return IR::InvalidType;
- }
-}
-
-QV4IRBuilder::QV4IRBuilder(const QV4Compiler::Expression *expr,
- QQmlEnginePrivate *engine)
-: m_expression(expr), m_engine(engine), _function(0), _block(0), _discard(false),
- _invalidatable(false)
-{
-}
-
-bool QV4IRBuilder::operator()(QQmlJS::IR::Function *function,
- QQmlJS::AST::Node *ast, bool *invalidatable)
-{
- bool discarded = false;
-
- IR::BasicBlock *block = function->newBasicBlock();
-
- qSwap(_discard, discarded);
- qSwap(_function, function);
- qSwap(_block, block);
-
- ExprResult r;
- AST::SourceLocation location;
- if (AST::ExpressionNode *asExpr = ast->expressionCast()) {
- r = expression(asExpr);
- location = asExpr->firstSourceLocation();
- } else if (AST::Statement *asStmt = ast->statementCast()) {
- r = statement(asStmt);
- location = asStmt->firstSourceLocation();
- }
-
- //_block->MOVE(_block->TEMP(IR::InvalidType), r.code);
- if (r.code) {
- IR::Type targetType = IR::InvalidType;
-
- // This is the only operation where variant is supported:
- QQmlPropertyData *data = &m_expression->property->core;
- if (data->propType == QMetaType::QVariant) {
- targetType = (data->isVarProperty() ? IR::VarType : IR::VariantType);
- } else {
- targetType = irTypeFromVariantType(data->propType, m_engine);
- }
-
- if (targetType != r.type()) {
- IR::Expr *x = _block->TEMP(targetType);
- _block->MOVE(x, r, true);
- r.code = x;
- }
- _block->RET(r.code, targetType, location.startLine, location.startColumn);
- }
-
- qSwap(_block, block);
- qSwap(_function, function);
- qSwap(_discard, discarded);
-
- *invalidatable = _invalidatable;
- return !discarded;
-}
-
-bool QV4IRBuilder::buildName(QList<QStringRef> &name,
- AST::Node *node,
- QList<AST::ExpressionNode *> *nodes)
-{
- if (node->kind == AST::Node::Kind_IdentifierExpression) {
- name << static_cast<AST::IdentifierExpression*>(node)->name;
- if (nodes) *nodes << static_cast<AST::IdentifierExpression*>(node);
- } else if (node->kind == AST::Node::Kind_FieldMemberExpression) {
- AST::FieldMemberExpression *expr =
- static_cast<AST::FieldMemberExpression *>(node);
-
- if (!buildName(name, expr->base, nodes))
- return false;
-
- name << expr->name;
- if (nodes) *nodes << expr;
- } else {
- return false;
- }
-
- return true;
-}
-
-void QV4IRBuilder::discard()
-{
- _discard = true;
-}
-
-QV4IRBuilder::ExprResult
-QV4IRBuilder::expression(AST::ExpressionNode *ast)
-{
- ExprResult r;
- if (ast) {
- qSwap(_expr, r);
- accept(ast);
- qSwap(_expr, r);
-
- if (r.is(IR::InvalidType))
- discard();
- else {
- Q_ASSERT(r.hint == r.format);
- }
- }
-
- return r;
-}
-
-void QV4IRBuilder::condition(AST::ExpressionNode *ast, IR::BasicBlock *iftrue, IR::BasicBlock *iffalse)
-{
- if (! ast)
- return;
- ExprResult r(iftrue, iffalse);
- qSwap(_expr, r);
- accept(ast);
- qSwap(_expr, r);
-
- if (r.format != ExprResult::cx) {
- if (! r.code)
- discard();
-
- Q_ASSERT(r.hint == ExprResult::cx);
- Q_ASSERT(r.format == ExprResult::ex);
-
- if (r.type() != IR::BoolType) {
- IR::Temp *t = _block->TEMP(IR::BoolType);
- _block->MOVE(t, r);
- r = t;
- }
-
- _block->CJUMP(_block->UNOP(IR::OpIfTrue, r), iftrue, iffalse);
- }
-}
-
-QV4IRBuilder::ExprResult
-QV4IRBuilder::statement(AST::Statement *ast)
-{
- ExprResult r;
- if (ast) {
- qSwap(_expr, r);
- accept(ast);
- qSwap(_expr, r);
-
- if (r.is(IR::InvalidType))
- discard();
- else {
- Q_ASSERT(r.hint == r.format);
- }
- }
-
- return r;
-}
-
-void QV4IRBuilder::sourceElement(AST::SourceElement *ast)
-{
- accept(ast);
-}
-
-void QV4IRBuilder::implicitCvt(ExprResult &expr, IR::Type type)
-{
- if (expr.type() == type)
- return; // nothing to do
-
- IR::Expr *x = _block->TEMP(type);
- _block->MOVE(x, expr.code);
- expr.code = x;
-}
-
-// QML
-bool QV4IRBuilder::visit(AST::UiProgram *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::UiImportList *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::UiImport *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::UiPublicMember *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::UiSourceElement *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::UiObjectDefinition *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::UiObjectInitializer *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::UiObjectBinding *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::UiScriptBinding *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::UiArrayBinding *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::UiObjectMemberList *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::UiArrayMemberList *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::UiQualifiedId *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-
-// JS
-bool QV4IRBuilder::visit(AST::Program *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::SourceElements *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::FunctionSourceElement *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::StatementSourceElement *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-// object literals
-bool QV4IRBuilder::visit(AST::PropertyAssignmentList *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::PropertyNameAndValue *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::PropertyGetterSetter *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::IdentifierPropertyName *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::StringLiteralPropertyName *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::NumericLiteralPropertyName *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-
-// array literals
-bool QV4IRBuilder::visit(AST::ElementList *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::Elision *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-
-// function calls
-bool QV4IRBuilder::visit(AST::ArgumentList *)
-{
- Q_ASSERT(!"unreachable");
- return false;
-}
-
-// expressions
-bool QV4IRBuilder::visit(AST::ObjectLiteral *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::ArrayLiteral *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::ThisExpression *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::IdentifierExpression *ast)
-{
- const quint16 line = ast->identifierToken.startLine;
- const quint16 column = ast->identifierToken.startColumn;
-
- const QString name = ast->name.toString();
-
- if (name.at(0) == QLatin1Char('u') && name.length() == 9 && name == QLatin1String("undefined")) {
- _expr.code = _block->CONST(IR::UndefinedType, 0); // ### undefined value
- } else if (m_engine->v8engine()->illegalNames().contains(name) ) {
- if (qmlVerboseCompiler()) qWarning() << "*** illegal symbol:" << name;
- return false;
- } else if (const QQmlScript::Object *obj = m_expression->ids->value(name)) {
- IR::Name *code = _block->ID_OBJECT(name, obj, line, column);
- if (obj == m_expression->component)
- code->storage = IR::Name::RootStorage;
- _expr.code = code;
- } else {
-
- QQmlTypeNameCache::Result r = m_expression->importCache->query(name);
- if (r.isValid()) {
- if (r.type) {
- if (r.type->isSingleton()) {
- // Note: we don't need to check singletonType->qobjectCallback here, since
- // we did that check in registerSingletonType() in qqmlmetatype.cpp.
- // We cannot create the QObject Singleton Type Instance here,
- // as we might be running in a loader thread.
- // Thus, V4 can only handle bindings which use Singleton Types which
- // were registered with the templated registration function.
- _expr.code = _block->SINGLETON_OBJECT(name, r.type->singletonInstanceInfo()->instanceMetaObject, IR::Name::MemberStorage, line, column);
- } else {
- _expr.code = _block->ATTACH_TYPE(name, r.type, IR::Name::ScopeStorage, line, column);
- }
- }
- } else {
- bool found = false;
-
- if (m_expression->context != m_expression->component) {
- // RootStorage is more efficient than ScopeStorage, so prefer that if they are the same
- QQmlPropertyCache *cache = m_expression->context->synthCache;
- if (!cache) cache = m_expression->context->metatype;
-
- QQmlPropertyData *data = cache->property(name, 0, 0);
-
- if (data && data->hasRevision()) {
- if (qmlVerboseCompiler())
- qWarning() << "*** versioned symbol:" << name;
- discard();
- return false;
- }
-
- if (data && !data->isFunction()) {
- IR::Type irType = irTypeFromVariantType(data->propType, m_engine);
- _expr.code = _block->SYMBOL(irType, name, QQmlMetaObject(cache), data, IR::Name::ScopeStorage, line, column);
- found = true;
- }
- }
-
- if (!found) {
- QQmlPropertyCache *cache = m_expression->component->synthCache;
- if (!cache) cache = m_expression->component->metatype;
-
- QQmlPropertyData *data = cache->property(name, 0, 0);
-
- if (data && data->hasRevision()) {
- if (qmlVerboseCompiler())
- qWarning() << "*** versioned symbol:" << name;
- discard();
- return false;
- }
-
- if (data && !data->isFunction()) {
- IR::Type irType = irTypeFromVariantType(data->propType, m_engine);
- _expr.code = _block->SYMBOL(irType, name, QQmlMetaObject(cache), data, IR::Name::RootStorage, line, column);
- found = true;
- }
- }
-
- if (!found && qmlVerboseCompiler())
- qWarning() << "*** unknown symbol:" << name;
- }
- }
-
- if (_expr.code && _expr.hint == ExprResult::cx) {
- _expr.format = ExprResult::cx;
-
- if (_expr.type() != IR::BoolType) {
- IR::Temp *t = _block->TEMP(IR::BoolType);
- _block->MOVE(t, _expr);
- _expr.code = t;
- }
-
- _block->CJUMP(_expr.code, _expr.iftrue, _expr.iffalse);
- _expr.code = 0;
- }
-
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::NullExpression *)
-{
- // ### TODO: cx format
- _expr.code = _block->CONST(IR::NullType, 0);
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::TrueLiteral *)
-{
- // ### TODO: cx format
- _expr.code = _block->CONST(IR::BoolType, 1);
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::FalseLiteral *)
-{
- // ### TODO: cx format
- _expr.code = _block->CONST(IR::BoolType, 0);
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::StringLiteral *ast)
-{
- // ### TODO: cx format
- _expr.code = _block->STRING(ast->value);
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::NumericLiteral *ast)
-{
- if (_expr.hint == ExprResult::cx) {
- _expr.format = ExprResult::cx;
- _block->JUMP(ast->value ? _expr.iftrue : _expr.iffalse);
- } else {
- _expr.code = _block->CONST(IR::NumberType, ast->value);
- }
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::RegExpLiteral *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::NestedExpression *)
-{
- return true; // the value of the nested expression
-}
-
-bool QV4IRBuilder::visit(AST::ArrayMemberExpression *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::FieldMemberExpression *ast)
-{
- if (IR::Expr *left = expression(ast->base)) {
- if (IR::Name *baseName = left->asName()) {
- const quint32 line = ast->identifierToken.startLine;
- const quint32 column = ast->identifierToken.startColumn;
-
- QString name = ast->name.toString();
-
- switch(baseName->symbol) {
- case IR::Name::Unbound:
- break;
-
- case IR::Name::AttachType:
- if (name.at(0).isUpper()) {
- QByteArray utf8Name = name.toUtf8();
- const char *enumName = utf8Name.constData();
-
- const QMetaObject *meta = baseName->declarativeType->metaObject();
- bool found = false;
- for (int ii = 0; !found && ii < meta->enumeratorCount(); ++ii) {
- QMetaEnum e = meta->enumerator(ii);
- for (int jj = 0; !found && jj < e.keyCount(); ++jj) {
- if (0 == strcmp(e.key(jj), enumName)) {
- found = true;
- _expr.code = _block->CONST(IR::IntType, e.value(jj));
- }
- }
- }
-
- if (!found && qmlVerboseCompiler())
- qWarning() << "*** unresolved enum:"
- << (*baseName->id + QLatin1Char('.') + ast->name.toString());
- } else if(const QMetaObject *attachedMeta = baseName->declarativeType->attachedPropertiesType()) {
- QQmlPropertyCache *cache = m_engine->cache(attachedMeta);
- QQmlPropertyData *data = cache->property(name, 0, 0);
-
- if (!data || data->isFunction())
- return false; // Don't support methods (or non-existing properties ;)
-
- if (!data->isFinal())
- _invalidatable = true;
-
- IR::Type irType = irTypeFromVariantType(data->propType, m_engine);
- _expr.code = _block->SYMBOL(baseName, irType, name, attachedMeta, data, line, column);
- }
- break;
-
- case IR::Name::SingletonObject: {
- if (name.at(0).isUpper()) {
- QByteArray utf8Name = name.toUtf8();
- const char *enumName = utf8Name.constData();
-
- const QQmlPropertyCache *cache = baseName->meta.propertyCache(m_engine);
- if (!cache) {
- //Happens in some cases where they make properties with uppercase names
- qFatal("QV4: Unable to resolve enum: '%s'",
- QString(*baseName->id + QLatin1Char('.') + ast->name.toString()).toLatin1().constData());
- }
-
- const QMetaObject *meta = cache->firstCppMetaObject();
- bool found = false;
- for (int ii = 0; !found && ii < meta->enumeratorCount(); ++ii) {
- QMetaEnum e = meta->enumerator(ii);
- for (int jj = 0; !found && jj < e.keyCount(); ++jj) {
- if (0 == strcmp(e.key(jj), enumName)) {
- found = true;
- _expr.code = _block->CONST(IR::IntType, e.value(jj));
- }
- }
- }
- if (!found && qmlVerboseCompiler())
- qWarning() << "*** unresolved enum:"
- << (*baseName->id + QLatin1Char('.') + ast->name.toString());
- } else {
- QQmlPropertyCache *cache = baseName->meta.propertyCache(m_engine);
- if (!cache) return false;
- QQmlPropertyData *data = cache->property(name, 0, 0);
-
- if (!data || data->isFunction())
- return false; // Don't support methods (or non-existing properties ;)
-
- if (!data->isFinal())
- _invalidatable = true;
-
- IR::Type irType = irTypeFromVariantType(data->propType, m_engine);
- _expr.code = _block->SYMBOL(baseName, irType, name, baseName->meta, data, line, column);
- }
- }
- break;
-
- case IR::Name::IdObject: {
- const QQmlScript::Object *idObject = baseName->idObject;
- QQmlPropertyCache *cache =
- idObject->synthCache?idObject->synthCache:idObject->metatype;
-
- QQmlPropertyData *data = cache->property(name, 0, 0);
-
- if (!data || data->isFunction())
- return false; // Don't support methods (or non-existing properties ;)
-
- if (data->hasRevision()) {
- if (qmlVerboseCompiler())
- qWarning() << "*** versioned symbol:" << name;
- discard();
- return false;
- }
-
- IR::Type irType = irTypeFromVariantType(data->propType, m_engine);
- _expr.code = _block->SYMBOL(baseName, irType, name, QQmlMetaObject(cache), data, line, column);
- }
- break;
-
- case IR::Name::Property:
- if (baseName->type == IR::ObjectType && !baseName->meta.isNull()) {
- QQmlMetaObject meta = m_engine->metaObjectForType(baseName->property->propType);
- QQmlPropertyCache *cache = meta.propertyCache(m_engine);
- if (!cache)
- return false;
-
- if (QQmlPropertyData *data = cache->property(name, 0, 0)) {
- if (!baseName->property->isFinal() || !data->isFinal())
- _invalidatable = true;
-
- IR::Type irType = irTypeFromVariantType(data->propType, m_engine);
- _expr.code = _block->SYMBOL(baseName, irType, name,
- meta, data, line, column);
- }
- }
- break;
-
- case IR::Name::Object:
- case IR::Name::Slot:
- break;
- }
- }
- }
-
- return false;
-}
-
-bool QV4IRBuilder::preVisit(AST::Node *)
-{
- return ! _discard;
-}
-
-bool QV4IRBuilder::visit(AST::NewMemberExpression *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::NewExpression *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::CallExpression *ast)
-{
- QList<QStringRef> names;
- QList<AST::ExpressionNode *> nameNodes;
-
- names.reserve(4);
- nameNodes.reserve(4);
-
- if (buildName(names, ast->base, &nameNodes)) {
- //ExprResult base = expression(ast->base);
- QString id;
- for (int i = 0; i < names.size(); ++i) {
- if (i)
- id += QLatin1Char('.');
- id += names.at(i);
- }
- const AST::SourceLocation loc = nameNodes.last()->firstSourceLocation();
- IR::Expr *base = _block->NAME(id, loc.startLine, loc.startColumn);
-
- IR::ExprList *args = 0, **argsInserter = &args;
- for (AST::ArgumentList *it = ast->arguments; it; it = it->next) {
- IR::Expr *arg = expression(it->expression);
- *argsInserter = _function->pool->New<IR::ExprList>();
- (*argsInserter)->init(arg);
- argsInserter = &(*argsInserter)->next;
- }
-
- IR::Temp *r = _block->TEMP(IR::InvalidType);
- IR::Expr *call = _block->CALL(base, args);
- _block->MOVE(r, call);
- r->type = call->type;
- _expr.code = r;
- }
-
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::PostIncrementExpression *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::PostDecrementExpression *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::DeleteExpression *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::VoidExpression *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::TypeOfExpression *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::PreIncrementExpression *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::PreDecrementExpression *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::UnaryPlusExpression *ast)
-{
- ExprResult expr = expression(ast->expression);
- if (expr.isNot(IR::InvalidType)) {
- if (expr.code->asConst() != 0) {
- _expr = expr;
- return false;
- }
-
- IR::Expr *code = _block->UNOP(IR::OpUPlus, expr);
- _expr.code = _block->TEMP(code->type);
- _block->MOVE(_expr, code);
- }
-
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::UnaryMinusExpression *ast)
-{
- ExprResult expr = expression(ast->expression);
- if (expr.isNot(IR::InvalidType)) {
- if (IR::Const *c = expr.code->asConst()) {
- _expr = expr;
- _expr.code = _block->CONST(expr->type, -c->value);
- return false;
- }
-
- IR::Expr *code = _block->UNOP(IR::OpUMinus, expr);
- _expr.code = _block->TEMP(code->type);
- _block->MOVE(_expr, code);
- }
-
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::TildeExpression *ast)
-{
- ExprResult expr = expression(ast->expression);
- if (expr.isNot(IR::InvalidType)) {
- if (IR::Const *c = expr.code->asConst()) {
- _expr = expr;
- _expr.code = _block->CONST(expr->type, ~int(c->value));
- return false;
- }
- IR::Expr *code = _block->UNOP(IR::OpCompl, expr);
- _expr.code = _block->TEMP(code->type);
- _block->MOVE(_expr, code);
- }
-
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::NotExpression *ast)
-{
- ExprResult expr = expression(ast->expression);
-
- if (expr.isNot(IR::InvalidType)) {
- if (IR::Const *c = expr.code->asConst()) {
- _expr = expr;
- _expr.code = _block->CONST(IR::BoolType, !c->value);
- return false;
- }
-
- IR::Expr *code = _block->UNOP(IR::OpNot, expr);
- _expr.code = _block->TEMP(code->type);
- _block->MOVE(_expr, code);
-
- } else if (expr.hint == ExprResult::cx) {
- expr.format = ExprResult::cx;
- _block->CJUMP(_block->UNOP(IR::OpNot, expr), _expr.iftrue, _expr.iffalse);
- return false;
- }
-
- return false;
-}
-
-void QV4IRBuilder::binop(AST::BinaryExpression *ast, ExprResult left, ExprResult right)
-{
- if (IR::Type t = maxType(left.type(), right.type())) {
- if (!left->asConst() && !right->asConst()) {
- // the implicit conversions are needed only
- // when compiling non-constant expressions.
- implicitCvt(left, t);
- implicitCvt(right, t);
- }
- } else if ((left.type() != IR::ObjectType && left.type() != IR::NullType) ||
- (right.type() != IR::ObjectType && right.type() != IR::NullType))
- return;
-
- if (_expr.hint == ExprResult::cx) {
- _expr.format = ExprResult::cx;
- _block->CJUMP(_block->BINOP(IR::binaryOperator(ast->op), left, right), _expr.iftrue, _expr.iffalse);
- } else {
- IR::Expr *e = _block->BINOP(IR::binaryOperator(ast->op), left, right);
- if (e->asConst() != 0 || e->asString() != 0)
- _expr.code = e;
- else {
- IR::Temp *t = _block->TEMP(e->type);
- _block->MOVE(t, e);
- _expr.code = t;
- }
- }
-}
-
-bool QV4IRBuilder::visit(AST::BinaryExpression *ast)
-{
- switch (ast->op) {
- case QSOperator::And: {
- if (_expr.hint == ExprResult::cx) {
- _expr.format = ExprResult::cx;
-
- Q_ASSERT(_expr.iffalse != 0);
- Q_ASSERT(_expr.iftrue != 0);
-
- IR::BasicBlock *iftrue = _function->newBasicBlock();
- condition(ast->left, iftrue, _expr.iffalse);
-
- _block = iftrue;
- condition(ast->right, _expr.iftrue, _expr.iffalse);
- } else {
- IR::BasicBlock *iftrue = _function->newBasicBlock();
- IR::BasicBlock *iffalse = _function->newBasicBlock();
- IR::BasicBlock *endif = _function->newBasicBlock();
-
- ExprResult left = expression(ast->left);
- IR::Temp *cond = _block->TEMP(IR::BoolType);
- _block->MOVE(cond, left);
- _block->CJUMP(cond, iftrue, iffalse);
-
- IR::Temp *r = _block->TEMP(IR::InvalidType);
-
- _block = iffalse;
- _block->MOVE(r, cond);
- _block->JUMP(endif);
-
- _block = iftrue;
- ExprResult right = expression(ast->right);
- _block->MOVE(r, right);
- _block->JUMP(endif);
-
- if (left.type() != right.type())
- discard();
-
- _block = endif;
-
- r->type = right.type();
- _expr.code = r;
- }
- } break;
-
- case QSOperator::Or: {
- IR::BasicBlock *iftrue = _function->newBasicBlock();
- IR::BasicBlock *endif = _function->newBasicBlock();
-
- ExprResult left = expression(ast->left);
- IR::Temp *r = _block->TEMP(left.type());
- _block->MOVE(r, left);
-
- IR::Expr *cond = r;
- if (r->type != IR::BoolType) {
- cond = _block->TEMP(IR::BoolType);
- _block->MOVE(cond, r);
- }
-
- _block->CJUMP(_block->UNOP(IR::OpNot, cond), iftrue, endif);
-
- _block = iftrue;
- ExprResult right = expression(ast->right);
- _block->MOVE(r, right);
- _block->JUMP(endif);
-
- if (left.type() != right.type())
- discard();
-
- _expr.code = r;
-
- _block = endif;
- } break;
-
- case QSOperator::Lt:
- case QSOperator::Gt:
- case QSOperator::Le:
- case QSOperator::Ge: {
- ExprResult left = expression(ast->left);
- ExprResult right = expression(ast->right);
- if (left.type() == IR::StringType && right.type() == IR::StringType) {
- binop(ast, left, right);
- } else if (left.isValid() && right.isValid()) {
- implicitCvt(left, IR::NumberType);
- implicitCvt(right, IR::NumberType);
- binop(ast, left, right);
- }
- } break;
-
- case QSOperator::NotEqual:
- case QSOperator::Equal: {
- ExprResult left = expression(ast->left);
- ExprResult right = expression(ast->right);
- if ((left.type() == IR::NullType || left.type() == IR::UndefinedType) &&
- (right.type() == IR::NullType || right.type() == IR::UndefinedType)) {
- const bool isEq = ast->op == QSOperator::Equal;
- if (_expr.hint == ExprResult::cx) {
- _expr.format = ExprResult::cx;
- _block->JUMP(isEq ? _expr.iftrue : _expr.iffalse);
- } else {
- _expr.code = _block->CONST(IR::BoolType, isEq ? 1 : 0);
- }
- } else if ((left.type() == IR::StringType && right.type() >= IR::FirstNumberType) ||
- (left.type() >= IR::FirstNumberType && right.type() == IR::StringType)) {
- implicitCvt(left, IR::NumberType);
- implicitCvt(right, IR::NumberType);
- binop(ast, left, right);
- } else if (left.isValid() && right.isValid()) {
- binop(ast, left, right);
- }
- } break;
-
- case QSOperator::StrictEqual:
- case QSOperator::StrictNotEqual: {
- ExprResult left = expression(ast->left);
- ExprResult right = expression(ast->right);
- if (left.type() == right.type()) {
- binop(ast, left, right);
- } else if (left.type() > IR::BoolType && right.type() > IR::BoolType) {
- // left and right have numeric type (int or real)
- binop(ast, left, right);
- } else if ((left.type() == IR::ObjectType && right.type() == IR::NullType) ||
- (right.type() == IR::ObjectType && left.type() == IR::NullType)) {
- // comparing a qobject with null
- binop(ast, left, right);
- } else if (left.isValid() && right.isValid()) {
- // left and right have different types
- const bool isEq = ast->op == QSOperator::StrictEqual;
- if (_expr.hint == ExprResult::cx) {
- _expr.format = ExprResult::cx;
- _block->JUMP(isEq ? _expr.iffalse : _expr.iftrue);
- } else {
- _expr.code = _block->CONST(IR::BoolType, isEq ? 0 : 1);
- }
- }
- } break;
-
- case QSOperator::BitAnd:
- case QSOperator::BitOr:
- case QSOperator::BitXor:
- case QSOperator::LShift:
- case QSOperator::RShift:
- case QSOperator::URShift: {
- ExprResult left = expression(ast->left);
- if (left.is(IR::InvalidType))
- return false;
-
- ExprResult right = expression(ast->right);
- if (right.is(IR::InvalidType))
- return false;
-
- implicitCvt(left, IR::IntType);
- implicitCvt(right, IR::IntType);
-
- IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
- _expr.code = _block->TEMP(code->type);
- _block->MOVE(_expr.code, code);
-
- } break;
-
- case QSOperator::Add: {
- ExprResult left = expression(ast->left);
- if (left.is(IR::InvalidType))
- return false;
-
- ExprResult right = expression(ast->right);
- if (right.is(IR::InvalidType))
- return false;
-
- if (left.isPrimitive() && right.isPrimitive()) {
- if (left.type() == IR::StringType || right.type() == IR::StringType) {
- implicitCvt(left, IR::StringType);
- implicitCvt(right, IR::StringType);
- }
- binop(ast, left, right);
- }
- } break;
-
- case QSOperator::Div:
- case QSOperator::Mod:
- case QSOperator::Mul:
- case QSOperator::Sub: {
- ExprResult left = expression(ast->left);
- if (left.is(IR::InvalidType))
- return false;
-
- ExprResult right = expression(ast->right);
- if (right.is(IR::InvalidType))
- return false;
-
- IR::Type t = maxType(left.type(), right.type());
- if (t >= IR::FirstNumberType) {
- implicitCvt(left, IR::NumberType);
- implicitCvt(right, IR::NumberType);
-
- IR::Expr *code = _block->BINOP(IR::binaryOperator(ast->op), left, right);
- _expr.code = _block->TEMP(code->type);
- _block->MOVE(_expr.code, code);
- }
- } break;
-
- case QSOperator::In:
- case QSOperator::InstanceOf:
- case QSOperator::Assign:
- case QSOperator::InplaceAnd:
- case QSOperator::InplaceSub:
- case QSOperator::InplaceDiv:
- case QSOperator::InplaceAdd:
- case QSOperator::InplaceLeftShift:
- case QSOperator::InplaceMod:
- case QSOperator::InplaceMul:
- case QSOperator::InplaceOr:
- case QSOperator::InplaceRightShift:
- case QSOperator::InplaceURightShift:
- case QSOperator::InplaceXor:
- // yup, we don't do those.
- break;
- } // switch
-
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::ConditionalExpression *ast)
-{
- IR::BasicBlock *iftrue = _function->newBasicBlock();
- IR::BasicBlock *iffalse = _function->newBasicBlock();
- IR::BasicBlock *endif = _function->newBasicBlock();
-
- condition(ast->expression, iftrue, iffalse);
-
- IR::Temp *r = _block->TEMP(IR::InvalidType);
-
- qSwap(_block, iftrue);
- ExprResult ok = expression(ast->ok);
- _block->MOVE(r, ok);
- _block->JUMP(endif);
- qSwap(_block, iftrue);
-
- qSwap(_block, iffalse);
- ExprResult ko = expression(ast->ko);
- _block->MOVE(r, ko);
- _block->JUMP(endif);
- qSwap(_block, iffalse);
-
- r->type = maxType(ok.type(), ko.type());
- _expr.code = r;
-
- _block = endif;
-
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::Expression *ast)
-{
- _block->EXP(expression(ast->left));
- _expr = expression(ast->right);
-
- return false;
-}
-
-
-// statements
-bool QV4IRBuilder::visit(AST::Block *ast)
-{
- if (ast->statements && ! ast->statements->next) {
- // we have one and only one statement
- accept(ast->statements->statement);
- }
-
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::StatementList *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::VariableStatement *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::VariableDeclarationList *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::VariableDeclaration *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::EmptyStatement *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::ExpressionStatement *ast)
-{
- if (ast->expression) {
- // return the value of this expression
- return true;
- }
-
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::IfStatement *ast)
-{
- if (! ast->ko) {
- // This is an if statement without an else branch.
- discard();
- } else {
- IR::BasicBlock *iftrue = _function->newBasicBlock();
- IR::BasicBlock *iffalse = _function->newBasicBlock();
- IR::BasicBlock *endif = _function->newBasicBlock();
-
- condition(ast->expression, iftrue, iffalse);
-
- IR::Temp *r = _block->TEMP(IR::InvalidType);
-
- qSwap(_block, iftrue);
- ExprResult ok = statement(ast->ok);
- _block->MOVE(r, ok);
- _block->JUMP(endif);
- qSwap(_block, iftrue);
-
- qSwap(_block, iffalse);
- ExprResult ko = statement(ast->ko);
- _block->MOVE(r, ko);
- _block->JUMP(endif);
- qSwap(_block, iffalse);
-
- r->type = maxType(ok.type(), ko.type());
- _expr.code = r;
-
- _block = endif;
- }
-
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::DoWhileStatement *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::WhileStatement *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::ForStatement *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::LocalForStatement *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::ForEachStatement *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::LocalForEachStatement *)
-{
- discard();
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::ContinueStatement *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::BreakStatement *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::ReturnStatement *ast)
-{
- if (ast->expression) {
- // return the value of the expression
- return true;
- }
-
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::WithStatement *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::SwitchStatement *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::CaseBlock *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::CaseClauses *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::CaseClause *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::DefaultClause *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::LabelledStatement *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::ThrowStatement *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::TryStatement *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::Catch *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::Finally *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::FunctionDeclaration *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::FunctionExpression *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::FormalParameterList *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::FunctionBody *)
-{
- return false;
-}
-
-bool QV4IRBuilder::visit(AST::DebuggerStatement *)
-{
- return false;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4irbuilder_p.h b/src/qml/qml/v4/qv4irbuilder_p.h
deleted file mode 100644
index 86baae463d..0000000000
--- a/src/qml/qml/v4/qv4irbuilder_p.h
+++ /dev/null
@@ -1,239 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV4IRBUILDER_P_H
-#define QV4IRBUILDER_P_H
-
-#include <QtCore/qglobal.h>
-
-#include "qv4ir_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QV4IRBuilder : public QQmlJS::AST::Visitor
-{
-public:
- QV4IRBuilder(const QV4Compiler::Expression *, QQmlEnginePrivate *);
-
- bool operator()(QQmlJS::IR::Function *, QQmlJS::AST::Node *, bool *invalidatable);
-
-protected:
- struct ExprResult {
- enum Format {
- ex, // expression
- cx // condition
- };
-
- QQmlJS::IR::Expr *code;
- QQmlJS::IR::BasicBlock *iftrue;
- QQmlJS::IR::BasicBlock *iffalse;
- Format hint; // requested format
- Format format; // instruction format
-
- ExprResult(QQmlJS::IR::Expr *expr = 0)
- : code(expr), iftrue(0), iffalse(0), hint(ex), format(ex) {}
-
- ExprResult(QQmlJS::IR::BasicBlock *iftrue, QQmlJS::IR::BasicBlock *iffalse)
- : code(0), iftrue(iftrue), iffalse(iffalse), hint(cx), format(ex) {}
-
- inline QQmlJS::IR::Type type() const { return code ? code->type : QQmlJS::IR::InvalidType; }
-
- inline QQmlJS::IR::Expr *get() const { return code; }
- inline operator QQmlJS::IR::Expr *() const { return get(); }
- inline QQmlJS::IR::Expr *operator->() const { return get(); }
- inline bool isValid() const { return code ? code->type != QQmlJS::IR::InvalidType : false; }
- inline bool is(QQmlJS::IR::Type t) const { return type() == t; }
- inline bool isNot(QQmlJS::IR::Type t) const { return type() != t; }
-
- bool isPrimitive() const {
- switch (type()) {
- case QQmlJS::IR::UndefinedType: // ### TODO
- case QQmlJS::IR::NullType: // ### TODO
- case QQmlJS::IR::UrlType: // ### TODO
- return false;
-
- case QQmlJS::IR::StringType:
- case QQmlJS::IR::BoolType:
- case QQmlJS::IR::IntType:
- case QQmlJS::IR::FloatType:
- case QQmlJS::IR::NumberType:
- return true;
-
- default:
- return false;
- } // switch
- }
- };
-
- inline void accept(QQmlJS::AST::Node *ast) { QQmlJS::AST::Node::accept(ast, this); }
-
- ExprResult expression(QQmlJS::AST::ExpressionNode *ast);
- ExprResult statement(QQmlJS::AST::Statement *ast);
- void sourceElement(QQmlJS::AST::SourceElement *ast);
- void condition(QQmlJS::AST::ExpressionNode *ast, QQmlJS::IR::BasicBlock *iftrue, QQmlJS::IR::BasicBlock *iffalse);
- void binop(QQmlJS::AST::BinaryExpression *ast, ExprResult left, ExprResult right);
-
- void implicitCvt(ExprResult &expr, QQmlJS::IR::Type type);
-
- virtual bool preVisit(QQmlJS::AST::Node *ast);
-
- // QML
- virtual bool visit(QQmlJS::AST::UiProgram *ast);
- virtual bool visit(QQmlJS::AST::UiImportList *ast);
- virtual bool visit(QQmlJS::AST::UiImport *ast);
- virtual bool visit(QQmlJS::AST::UiPublicMember *ast);
- virtual bool visit(QQmlJS::AST::UiSourceElement *ast);
- virtual bool visit(QQmlJS::AST::UiObjectDefinition *ast);
- virtual bool visit(QQmlJS::AST::UiObjectInitializer *ast);
- virtual bool visit(QQmlJS::AST::UiObjectBinding *ast);
- virtual bool visit(QQmlJS::AST::UiScriptBinding *ast);
- virtual bool visit(QQmlJS::AST::UiArrayBinding *ast);
- virtual bool visit(QQmlJS::AST::UiObjectMemberList *ast);
- virtual bool visit(QQmlJS::AST::UiArrayMemberList *ast);
- virtual bool visit(QQmlJS::AST::UiQualifiedId *ast);
-
- // JS
- virtual bool visit(QQmlJS::AST::Program *ast);
- virtual bool visit(QQmlJS::AST::SourceElements *ast);
- virtual bool visit(QQmlJS::AST::FunctionSourceElement *ast);
- virtual bool visit(QQmlJS::AST::StatementSourceElement *ast);
-
- // object literals
- virtual bool visit(QQmlJS::AST::PropertyAssignmentList *ast);
- virtual bool visit(QQmlJS::AST::PropertyNameAndValue *ast);
- virtual bool visit(QQmlJS::AST::PropertyGetterSetter *ast);
- virtual bool visit(QQmlJS::AST::IdentifierPropertyName *ast);
- virtual bool visit(QQmlJS::AST::StringLiteralPropertyName *ast);
- virtual bool visit(QQmlJS::AST::NumericLiteralPropertyName *ast);
-
- // array literals
- virtual bool visit(QQmlJS::AST::ElementList *ast);
- virtual bool visit(QQmlJS::AST::Elision *ast);
-
- // function calls
- virtual bool visit(QQmlJS::AST::ArgumentList *ast);
-
- // expressions
- virtual bool visit(QQmlJS::AST::ObjectLiteral *ast);
- virtual bool visit(QQmlJS::AST::ArrayLiteral *ast);
- virtual bool visit(QQmlJS::AST::ThisExpression *ast);
- virtual bool visit(QQmlJS::AST::IdentifierExpression *ast);
- virtual bool visit(QQmlJS::AST::NullExpression *ast);
- virtual bool visit(QQmlJS::AST::TrueLiteral *ast);
- virtual bool visit(QQmlJS::AST::FalseLiteral *ast);
- virtual bool visit(QQmlJS::AST::StringLiteral *ast);
- virtual bool visit(QQmlJS::AST::NumericLiteral *ast);
- virtual bool visit(QQmlJS::AST::RegExpLiteral *ast);
- virtual bool visit(QQmlJS::AST::NestedExpression *ast);
- virtual bool visit(QQmlJS::AST::ArrayMemberExpression *ast);
- virtual bool visit(QQmlJS::AST::FieldMemberExpression *ast);
- virtual bool visit(QQmlJS::AST::NewMemberExpression *ast);
- virtual bool visit(QQmlJS::AST::NewExpression *ast);
- virtual bool visit(QQmlJS::AST::CallExpression *ast);
- virtual bool visit(QQmlJS::AST::PostIncrementExpression *ast);
- virtual bool visit(QQmlJS::AST::PostDecrementExpression *ast);
- virtual bool visit(QQmlJS::AST::DeleteExpression *ast);
- virtual bool visit(QQmlJS::AST::VoidExpression *ast);
- virtual bool visit(QQmlJS::AST::TypeOfExpression *ast);
- virtual bool visit(QQmlJS::AST::PreIncrementExpression *ast);
- virtual bool visit(QQmlJS::AST::PreDecrementExpression *ast);
- virtual bool visit(QQmlJS::AST::UnaryPlusExpression *ast);
- virtual bool visit(QQmlJS::AST::UnaryMinusExpression *ast);
- virtual bool visit(QQmlJS::AST::TildeExpression *ast);
- virtual bool visit(QQmlJS::AST::NotExpression *ast);
- virtual bool visit(QQmlJS::AST::BinaryExpression *ast);
- virtual bool visit(QQmlJS::AST::ConditionalExpression *ast);
- virtual bool visit(QQmlJS::AST::Expression *ast);
-
- // statements
- virtual bool visit(QQmlJS::AST::Block *ast);
- virtual bool visit(QQmlJS::AST::StatementList *ast);
- virtual bool visit(QQmlJS::AST::VariableStatement *ast);
- virtual bool visit(QQmlJS::AST::VariableDeclarationList *ast);
- virtual bool visit(QQmlJS::AST::VariableDeclaration *ast);
- virtual bool visit(QQmlJS::AST::EmptyStatement *ast);
- virtual bool visit(QQmlJS::AST::ExpressionStatement *ast);
- virtual bool visit(QQmlJS::AST::IfStatement *ast);
- virtual bool visit(QQmlJS::AST::DoWhileStatement *ast);
- virtual bool visit(QQmlJS::AST::WhileStatement *ast);
- virtual bool visit(QQmlJS::AST::ForStatement *ast);
- virtual bool visit(QQmlJS::AST::LocalForStatement *ast);
- virtual bool visit(QQmlJS::AST::ForEachStatement *ast);
- virtual bool visit(QQmlJS::AST::LocalForEachStatement *ast);
- virtual bool visit(QQmlJS::AST::ContinueStatement *ast);
- virtual bool visit(QQmlJS::AST::BreakStatement *ast);
- virtual bool visit(QQmlJS::AST::ReturnStatement *ast);
- virtual bool visit(QQmlJS::AST::WithStatement *ast);
- virtual bool visit(QQmlJS::AST::SwitchStatement *ast);
- virtual bool visit(QQmlJS::AST::CaseBlock *ast);
- virtual bool visit(QQmlJS::AST::CaseClauses *ast);
- virtual bool visit(QQmlJS::AST::CaseClause *ast);
- virtual bool visit(QQmlJS::AST::DefaultClause *ast);
- virtual bool visit(QQmlJS::AST::LabelledStatement *ast);
- virtual bool visit(QQmlJS::AST::ThrowStatement *ast);
- virtual bool visit(QQmlJS::AST::TryStatement *ast);
- virtual bool visit(QQmlJS::AST::Catch *ast);
- virtual bool visit(QQmlJS::AST::Finally *ast);
- virtual bool visit(QQmlJS::AST::FunctionDeclaration *ast);
- virtual bool visit(QQmlJS::AST::FunctionExpression *ast);
- virtual bool visit(QQmlJS::AST::FormalParameterList *ast);
- virtual bool visit(QQmlJS::AST::FunctionBody *ast);
- virtual bool visit(QQmlJS::AST::DebuggerStatement *ast);
-
-private:
- bool buildName(QList<QStringRef> &name, QQmlJS::AST::Node *node,
- QList<QQmlJS::AST::ExpressionNode *> *nodes);
- void discard();
-
- const QV4Compiler::Expression *m_expression;
- QQmlEnginePrivate *m_engine;
-
- QQmlJS::IR::Function *_function;
- QQmlJS::IR::BasicBlock *_block;
- bool _discard;
- bool _invalidatable;
-
- ExprResult _expr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QV4IRBUILDER_P_H
diff --git a/src/qml/qml/v4/qv4isel_llvm.cpp b/src/qml/qml/v4/qv4isel_llvm.cpp
new file mode 100644
index 0000000000..70378a4d8a
--- /dev/null
+++ b/src/qml/qml/v4/qv4isel_llvm.cpp
@@ -0,0 +1,1388 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wunused-parameter"
+#endif // __clang__
+
+#include <llvm/Analysis/Passes.h>
+#include <llvm/Analysis/Verifier.h>
+#include <llvm/Assembly/PrintModulePass.h>
+#include <llvm/Bitcode/ReaderWriter.h>
+#include <llvm/ExecutionEngine/ExecutionEngine.h>
+#include <llvm/ExecutionEngine/JIT.h>
+#include <llvm/ExecutionEngine/JITMemoryManager.h>
+#include <llvm/Support/FormattedStream.h>
+#include <llvm/Support/Host.h>
+#include <llvm/Support/MemoryBuffer.h>
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/Support/system_error.h>
+#include <llvm/Support/TargetRegistry.h>
+#include <llvm/Support/TargetSelect.h>
+#include <llvm/Target/TargetMachine.h>
+#include <llvm/Transforms/Scalar.h>
+#include <llvm/Transforms/IPO.h>
+#include <llvm/Linker.h>
+
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif // __clang__
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QLibrary>
+#include <QtCore/QStringList>
+#include <QtCore/QTextStream>
+#include <cstdio>
+#include <iostream>
+
+// These includes have to come last, because WTF/Platform.h defines some macros
+// with very unfriendly names that collide with class fields in LLVM.
+#include "qv4isel_llvm_p.h"
+#include "qv4_llvm_p.h"
+#include "qv4jsir_p.h"
+#include "qv4string_p.h"
+#include "qv4global_p.h"
+
+namespace QQmlJS {
+
+Q_QML_EXPORT int compileWithLLVM(V4IR::Module *module, const QString &fileName, LLVMOutputType outputType, int (*exec)(void *))
+{
+ Q_ASSERT(module);
+ Q_ASSERT(exec || outputType != LLVMOutputJit);
+
+ // TODO: should this be done here?
+ LLVMInitializeX86TargetInfo();
+ LLVMInitializeX86Target();
+ LLVMInitializeX86AsmPrinter();
+ LLVMInitializeX86AsmParser();
+ LLVMInitializeX86Disassembler();
+ LLVMInitializeX86TargetMC();
+
+ //----
+
+ llvm::InitializeNativeTarget();
+ LLVM::InstructionSelection llvmIsel(llvm::getGlobalContext());
+
+ const QString moduleName = QFileInfo(fileName).fileName();
+ llvm::StringRef moduleId(moduleName.toUtf8().constData());
+ llvm::Module *llvmModule = new llvm::Module(moduleId, llvmIsel.getContext());
+
+ if (outputType == LLVMOutputJit) {
+ // The execution engine takes ownership of the model. No need to delete it anymore.
+ std::string errStr;
+ llvm::ExecutionEngine *execEngine = llvm::EngineBuilder(llvmModule)
+// .setUseMCJIT(true)
+ .setErrorStr(&errStr).create();
+ if (!execEngine) {
+ std::cerr << "Could not create LLVM JIT: " << errStr << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ llvm::FunctionPassManager functionPassManager(llvmModule);
+ // Set up the optimizer pipeline. Start with registering info about how the
+ // target lays out data structures.
+ functionPassManager.add(new llvm::DataLayout(*execEngine->getDataLayout()));
+ // Promote allocas to registers.
+ functionPassManager.add(llvm::createPromoteMemoryToRegisterPass());
+ // Provide basic AliasAnalysis support for GVN.
+ functionPassManager.add(llvm::createBasicAliasAnalysisPass());
+ // Do simple "peephole" optimizations and bit-twiddling optzns.
+ functionPassManager.add(llvm::createInstructionCombiningPass());
+ // Reassociate expressions.
+ functionPassManager.add(llvm::createReassociatePass());
+ // Eliminate Common SubExpressions.
+ functionPassManager.add(llvm::createGVNPass());
+ // Simplify the control flow graph (deleting unreachable blocks, etc).
+ functionPassManager.add(llvm::createCFGSimplificationPass());
+
+ functionPassManager.doInitialization();
+
+ llvmIsel.buildLLVMModule(module, llvmModule, &functionPassManager);
+
+ llvm::Function *entryPoint = llvmModule->getFunction("%entry");
+ Q_ASSERT(entryPoint);
+ void *funcPtr = execEngine->getPointerToFunction(entryPoint);
+ return exec(funcPtr);
+ } else {
+ llvm::FunctionPassManager functionPassManager(llvmModule);
+ // Set up the optimizer pipeline.
+ // Promote allocas to registers.
+ functionPassManager.add(llvm::createPromoteMemoryToRegisterPass());
+ // Provide basic AliasAnalysis support for GVN.
+ functionPassManager.add(llvm::createBasicAliasAnalysisPass());
+ // Do simple "peephole" optimizations and bit-twiddling optzns.
+ functionPassManager.add(llvm::createInstructionCombiningPass());
+ // Reassociate expressions.
+ functionPassManager.add(llvm::createReassociatePass());
+ // Eliminate Common SubExpressions.
+ functionPassManager.add(llvm::createGVNPass());
+ // Simplify the control flow graph (deleting unreachable blocks, etc).
+ functionPassManager.add(llvm::createCFGSimplificationPass());
+
+ functionPassManager.doInitialization();
+
+ llvmIsel.buildLLVMModule(module, llvmModule, &functionPassManager);
+
+ // TODO: if output type is .ll, print the module to file
+
+ const std::string triple = llvm::sys::getDefaultTargetTriple();
+
+ std::string err;
+ const llvm::Target *target = llvm::TargetRegistry::lookupTarget(triple, err);
+ if (! err.empty()) {
+ std::cerr << err << ", triple: " << triple << std::endl;
+ assert(!"cannot create target for the host triple");
+ }
+
+ std::string cpu;
+ std::string features;
+ llvm::TargetOptions options;
+ llvm::TargetMachine *targetMachine = target->createTargetMachine(triple, cpu, features, options, llvm::Reloc::PIC_);
+ assert(targetMachine);
+
+ llvm::TargetMachine::CodeGenFileType ft;
+ QString ofName;
+
+ if (outputType == LLVMOutputObject) {
+ ft = llvm::TargetMachine::CGFT_ObjectFile;
+ ofName = fileName + QLatin1String(".o");
+ } else if (outputType == LLVMOutputAssembler) {
+ ft = llvm::TargetMachine::CGFT_AssemblyFile;
+ ofName = fileName + QLatin1String(".s");
+ } else {
+ // ft is not used.
+ ofName = fileName + QLatin1String(".ll");
+ }
+
+ llvm::raw_fd_ostream dest(ofName.toUtf8().constData(), err, llvm::raw_fd_ostream::F_Binary);
+ llvm::formatted_raw_ostream destf(dest);
+ if (!err.empty()) {
+ std::cerr << err << std::endl;
+ delete llvmModule;
+ }
+
+ llvm::PassManager globalPassManager;
+ globalPassManager.add(llvm::createScalarReplAggregatesPass());
+ globalPassManager.add(llvm::createInstructionCombiningPass());
+ globalPassManager.add(llvm::createGlobalOptimizerPass());
+ globalPassManager.add(llvm::createFunctionInliningPass(25));
+// globalPassManager.add(llvm::createFunctionInliningPass(125));
+
+ if (outputType == LLVMOutputObject || outputType == LLVMOutputAssembler) {
+ if (targetMachine->addPassesToEmitFile(globalPassManager, destf, ft)) {
+ std::cerr << err << " (probably no DataLayout in TargetMachine)" << std::endl;
+ } else {
+ globalPassManager.run(*llvmModule);
+
+ destf.flush();
+ dest.flush();
+ }
+ } else { // .ll
+ globalPassManager.run(*llvmModule);
+ llvmModule->print(destf, 0);
+
+ destf.flush();
+ dest.flush();
+ }
+
+ delete llvmModule;
+ return EXIT_SUCCESS;
+ }
+}
+
+} // QQmlJS
+
+using namespace QQmlJS;
+using namespace QQmlJS::LLVM;
+
+namespace {
+QTextStream qerr(stderr, QIODevice::WriteOnly);
+}
+
+InstructionSelection::InstructionSelection(llvm::LLVMContext &context)
+ : llvm::IRBuilder<>(context)
+ , _llvmModule(0)
+ , _llvmFunction(0)
+ , _llvmValue(0)
+ , _numberTy(0)
+ , _valueTy(0)
+ , _contextPtrTy(0)
+ , _stringPtrTy(0)
+ , _functionTy(0)
+ , _allocaInsertPoint(0)
+ , _function(0)
+ , _block(0)
+ , _fpm(0)
+{
+}
+
+void InstructionSelection::buildLLVMModule(V4IR::Module *module, llvm::Module *llvmModule, llvm::FunctionPassManager *fpm)
+{
+ qSwap(_llvmModule, llvmModule);
+ qSwap(_fpm, fpm);
+
+ _numberTy = getDoubleTy();
+
+ std::string err;
+
+ llvm::OwningPtr<llvm::MemoryBuffer> buffer;
+ qDebug()<<"llvm runtime:"<<LLVM_RUNTIME;
+ llvm::error_code ec = llvm::MemoryBuffer::getFile(llvm::StringRef(LLVM_RUNTIME), buffer);
+ if (ec) {
+ qWarning() << ec.message().c_str();
+ assert(!"cannot load QML/JS LLVM runtime, you can generate the runtime with the command `make llvm_runtime'");
+ }
+
+ llvm::Module *llvmRuntime = llvm::getLazyBitcodeModule(buffer.get(), getContext(), &err);
+ if (! err.empty()) {
+ qWarning() << err.c_str();
+ assert(!"cannot load QML/JS LLVM runtime");
+ }
+
+ err.clear();
+ llvm::Linker::LinkModules(_llvmModule, llvmRuntime, llvm::Linker::DestroySource, &err);
+ if (! err.empty()) {
+ qWarning() << err.c_str();
+ assert(!"cannot link the QML/JS LLVM runtime");
+ }
+
+ _valueTy = _llvmModule->getTypeByName("struct.QV4::Value");
+ _contextPtrTy = _llvmModule->getTypeByName("struct.QV4::ExecutionContext")->getPointerTo();
+ _stringPtrTy = _llvmModule->getTypeByName("struct.QV4::String")->getPointerTo();
+
+ {
+ llvm::Type *args[] = { _contextPtrTy };
+ _functionTy = llvm::FunctionType::get(getVoidTy(), llvm::makeArrayRef(args), false);
+ }
+
+
+ foreach (V4IR::Function *function, module->functions)
+ (void) compileLLVMFunction(function);
+ qSwap(_fpm, fpm);
+ qSwap(_llvmModule, llvmModule);
+}
+
+void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinTypeofName(const QString &name, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinTypeofValue(V4IR::Temp *value, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinDeleteMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinDeleteName(const QString &name, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinDeleteValue(V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinPostDecrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinPostDecrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinPostDecrementName(const QString &name, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinPostDecrementValue(V4IR::Temp *value, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinPostIncrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinThrow(V4IR::Temp *arg, int line)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinCreateExceptionHandler(V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinFinishTry()
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinPushWithScope(V4IR::Temp *arg)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinPopScope()
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &name)
+{
+ llvm::ConstantInt *isDeletable = getInt1(deletable != 0);
+ llvm::Value *varName = getIdentifier(name);
+ CreateCall3(getRuntimeFunction("__qmljs_builtin_declare_var"),
+ _llvmFunction->arg_begin(), isDeletable, varName);
+}
+
+void InstructionSelection::callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::constructActivationProperty(V4IR::Name *func,
+ V4IR::ExprList *args,
+ V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::loadThisObject(V4IR::Temp *temp)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::loadConst(V4IR::Const *con, V4IR::Temp *temp)
+{
+ llvm::Value *target = getLLVMTemp(temp);
+ llvm::Value *source = CreateLoad(createValue(con));
+ CreateStore(source, target);
+}
+
+void InstructionSelection::loadString(const QString &str, V4IR::Temp *targetTemp)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+void InstructionSelection::setActivationProperty(V4IR::Temp *source, const QString &targetName)
+{
+ llvm::Value *name = getIdentifier(targetName);
+ llvm::Value *src = toValuePtr(source);
+ CreateCall3(getRuntimeFunction("__qmljs_llvm_set_activation_property"),
+ _llvmFunction->arg_begin(), name, src);
+}
+
+void InstructionSelection::initClosure(V4IR::Closure *closure, V4IR::Temp *target)
+{
+ V4IR::Function *f = closure->value;
+ QString name;
+ if (f->name)
+ name = *f->name;
+
+ llvm::Value *args[] = {
+ _llvmFunction->arg_begin(),
+ getLLVMTemp(target),
+ getIdentifier(name),
+ getInt1(f->hasDirectEval),
+ getInt1(f->usesArgumentsObject),
+ getInt1(f->isStrict),
+ getInt1(!f->nestedFunctions.isEmpty()),
+ genStringList(f->formals, "formals", "formal"),
+ getInt32(f->formals.size()),
+ genStringList(f->locals, "locals", "local"),
+ getInt32(f->locals.size())
+ };
+ llvm::Function *callee = _llvmModule->getFunction("__qmljs_llvm_init_closure");
+ CreateCall(callee, args);
+}
+
+void InstructionSelection::getProperty(V4IR::Temp *sourceBase, const QString &sourceName, V4IR::Temp *target)
+{
+ llvm::Value *base = getLLVMTempReference(sourceBase);
+ llvm::Value *name = getIdentifier(sourceName);
+ llvm::Value *t = getLLVMTemp(target);
+ CreateCall4(getRuntimeFunction("__qmljs_llvm_get_property"),
+ _llvmFunction->arg_begin(), t, base, name);
+}
+
+void InstructionSelection::setProperty(V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName)
+{
+ llvm::Value *base = getLLVMTempReference(targetBase);
+ llvm::Value *name = getIdentifier(targetName);
+ llvm::Value *src = toValuePtr(source);
+ CreateCall4(getRuntimeFunction("__qmljs_llvm_set_property"),
+ _llvmFunction->arg_begin(), base, name, src);
+}
+
+void InstructionSelection::getElement(V4IR::Temp *sourceBase, V4IR::Temp *sourceIndex, V4IR::Temp *target)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+
+ llvm::Value *base = getLLVMTempReference(sourceBase);
+ llvm::Value *index = getLLVMTempReference(sourceIndex);
+ llvm::Value *t = getLLVMTemp(target);
+ CreateCall4(getRuntimeFunction("__qmljs_llvm_get_element"),
+ _llvmFunction->arg_begin(), t, base, index);
+}
+
+void InstructionSelection::setElement(V4IR::Temp *source, V4IR::Temp *targetBase, V4IR::Temp *targetIndex)
+{
+ llvm::Value *base = getLLVMTempReference(targetBase);
+ llvm::Value *index = getLLVMTempReference(targetIndex);
+ llvm::Value *src = toValuePtr(source);
+ CreateCall4(getRuntimeFunction("__qmljs_llvm_set_element"),
+ _llvmFunction->arg_begin(), base, index, src);
+}
+
+void InstructionSelection::copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp)
+{
+ llvm::Value *t = getLLVMTemp(targetTemp);
+ llvm::Value *s = getLLVMTemp(sourceTemp);
+ CreateStore(s, t);
+}
+
+void InstructionSelection::unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp)
+{
+ const char *opName = 0;
+ switch (oper) {
+ case V4IR::OpNot: opName = "__qmljs_not"; break;
+ case V4IR::OpUMinus: opName = "__qmljs_uminus"; break;
+ case V4IR::OpUPlus: opName = "__qmljs_uplus"; break;
+ case V4IR::OpCompl: opName = "__qmljs_compl"; break;
+ case V4IR::OpIncrement: opName = "__qmljs_increment"; break;
+ case V4IR::OpDecrement: opName = "__qmljs_decrement"; break;
+ default: assert(!"unreachable"); break;
+ }
+
+ if (opName) {
+ llvm::Value *t = getLLVMTemp(targetTemp);
+ llvm::Value *s = getLLVMTemp(sourceTemp);
+ CreateCall3(getRuntimeFunction(opName),
+ _llvmFunction->arg_begin(), t, s);
+ }
+}
+
+void InstructionSelection::binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target)
+{
+ const char *opName = 0;
+ switch (oper) {
+ case V4IR::OpBitAnd: opName = "__qmljs_llvm_bit_and"; break;
+ case V4IR::OpBitOr: opName = "__qmljs_llvm_bit_or"; break;
+ case V4IR::OpBitXor: opName = "__qmljs_llvm_bit_xor"; break;
+ case V4IR::OpAdd: opName = "__qmljs_llvm_add"; break;
+ case V4IR::OpSub: opName = "__qmljs_llvm_sub"; break;
+ case V4IR::OpMul: opName = "__qmljs_llvm_mul"; break;
+ case V4IR::OpDiv: opName = "__qmljs_llvm_div"; break;
+ case V4IR::OpMod: opName = "__qmljs_llvm_mod"; break;
+ case V4IR::OpLShift: opName = "__qmljs_llvm_shl"; break;
+ case V4IR::OpRShift: opName = "__qmljs_llvm_shr"; break;
+ case V4IR::OpURShift: opName = "__qmljs_llvm_ushr"; break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+
+ if (opName) {
+ llvm::Value *t = getLLVMTemp(target);
+ llvm::Value *s1 = toValuePtr(leftSource);
+ llvm::Value *s2 = toValuePtr(rightSource);
+ CreateCall4(getRuntimeFunction(opName),
+ _llvmFunction->arg_begin(), t, s1, s2);
+ return;
+ }
+}
+
+void InstructionSelection::inplaceNameOp(V4IR::AluOp oper, V4IR::Temp *rightSource, const QString &targetName)
+{
+ const char *opName = 0;
+ switch (oper) {
+ case V4IR::OpBitAnd: opName = "__qmljs_llvm_inplace_bit_and_name"; break;
+ case V4IR::OpBitOr: opName = "__qmljs_llvm_inplace_bit_or_name"; break;
+ case V4IR::OpBitXor: opName = "__qmljs_llvm_inplace_bit_xor_name"; break;
+ case V4IR::OpAdd: opName = "__qmljs_llvm_inplace_add_name"; break;
+ case V4IR::OpSub: opName = "__qmljs_llvm_inplace_sub_name"; break;
+ case V4IR::OpMul: opName = "__qmljs_llvm_inplace_mul_name"; break;
+ case V4IR::OpDiv: opName = "__qmljs_llvm_inplace_div_name"; break;
+ case V4IR::OpMod: opName = "__qmljs_llvm_inplace_mod_name"; break;
+ case V4IR::OpLShift: opName = "__qmljs_llvm_inplace_shl_name"; break;
+ case V4IR::OpRShift: opName = "__qmljs_llvm_inplace_shr_name"; break;
+ case V4IR::OpURShift: opName = "__qmljs_llvm_inplace_ushr_name"; break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+
+ if (opName) {
+ llvm::Value *dst = getIdentifier(targetName);
+ llvm::Value *src = toValuePtr(rightSource);
+ CreateCall3(getRuntimeFunction(opName),
+ _llvmFunction->arg_begin(), dst, src);
+ return;
+ }
+}
+
+void InstructionSelection::inplaceElementOp(V4IR::AluOp oper, V4IR::Temp *source, V4IR::Temp *targetBaseTemp, V4IR::Temp *targetIndexTemp)
+{
+ const char *opName = 0;
+ switch (oper) {
+ case V4IR::OpBitAnd: opName = "__qmljs_llvm_inplace_bit_and_element"; break;
+ case V4IR::OpBitOr: opName = "__qmljs_llvm_inplace_bit_or_element"; break;
+ case V4IR::OpBitXor: opName = "__qmljs_llvm_inplace_bit_xor_element"; break;
+ case V4IR::OpAdd: opName = "__qmljs_llvm_inplace_add_element"; break;
+ case V4IR::OpSub: opName = "__qmljs_llvm_inplace_sub_element"; break;
+ case V4IR::OpMul: opName = "__qmljs_llvm_inplace_mul_element"; break;
+ case V4IR::OpDiv: opName = "__qmljs_llvm_inplace_div_element"; break;
+ case V4IR::OpMod: opName = "__qmljs_llvm_inplace_mod_element"; break;
+ case V4IR::OpLShift: opName = "__qmljs_llvm_inplace_shl_element"; break;
+ case V4IR::OpRShift: opName = "__qmljs_llvm_inplace_shr_element"; break;
+ case V4IR::OpURShift: opName = "__qmljs_llvm_inplace_ushr_element"; break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+
+ if (opName) {
+ llvm::Value *base = getLLVMTemp(targetBaseTemp);
+ llvm::Value *index = getLLVMTemp(targetIndexTemp);
+ llvm::Value *value = toValuePtr(source);
+ CreateCall4(getRuntimeFunction(opName),
+ _llvmFunction->arg_begin(), base, index, value);
+ }
+}
+
+void InstructionSelection::inplaceMemberOp(V4IR::AluOp oper, V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName)
+{
+ const char *opName = 0;
+ switch (oper) {
+ case V4IR::OpBitAnd: opName = "__qmljs_llvm_inplace_bit_and_member"; break;
+ case V4IR::OpBitOr: opName = "__qmljs_llvm_inplace_bit_or_member"; break;
+ case V4IR::OpBitXor: opName = "__qmljs_llvm_inplace_bit_xor_member"; break;
+ case V4IR::OpAdd: opName = "__qmljs_llvm_inplace_add_member"; break;
+ case V4IR::OpSub: opName = "__qmljs_llvm_inplace_sub_member"; break;
+ case V4IR::OpMul: opName = "__qmljs_llvm_inplace_mul_member"; break;
+ case V4IR::OpDiv: opName = "__qmljs_llvm_inplace_div_member"; break;
+ case V4IR::OpMod: opName = "__qmljs_llvm_inplace_mod_member"; break;
+ case V4IR::OpLShift: opName = "__qmljs_llvm_inplace_shl_member"; break;
+ case V4IR::OpRShift: opName = "__qmljs_llvm_inplace_shr_member"; break;
+ case V4IR::OpURShift: opName = "__qmljs_llvm_inplace_ushr_member"; break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+
+ if (opName) {
+ llvm::Value *base = getLLVMTemp(targetBase);
+ llvm::Value *member = getIdentifier(targetName);
+ llvm::Value *value = toValuePtr(source);
+ CreateCall4(getRuntimeFunction(opName),
+ _llvmFunction->arg_begin(), value, base, member);
+ }
+}
+
+llvm::Function *InstructionSelection::getLLVMFunction(V4IR::Function *function)
+{
+ llvm::Function *&f = _functionMap[function];
+ if (! f) {
+ QString name = QStringLiteral("__qmljs_native_");
+ if (function->name) {
+ if (*function->name == QStringLiteral("%entry"))
+ name = *function->name;
+ else
+ name += *function->name;
+ }
+ f = llvm::Function::Create(_functionTy, llvm::Function::ExternalLinkage, // ### make it internal
+ qPrintable(name), _llvmModule);
+ }
+ return f;
+}
+
+llvm::Function *InstructionSelection::compileLLVMFunction(V4IR::Function *function)
+{
+ llvm::Function *llvmFunction = getLLVMFunction(function);
+
+ QHash<V4IR::BasicBlock *, llvm::BasicBlock *> blockMap;
+ QVector<llvm::Value *> tempMap;
+
+ qSwap(_llvmFunction, llvmFunction);
+ qSwap(_function, function);
+ qSwap(_tempMap, tempMap);
+ qSwap(_blockMap, blockMap);
+
+ // create the LLVM blocks
+ foreach (V4IR::BasicBlock *block, _function->basicBlocks)
+ (void) getLLVMBasicBlock(block);
+
+ // entry block
+ SetInsertPoint(getLLVMBasicBlock(_function->basicBlocks.first()));
+
+ llvm::Instruction *allocaInsertPoint = new llvm::BitCastInst(llvm::UndefValue::get(getInt32Ty()),
+ getInt32Ty(), "", GetInsertBlock());
+ qSwap(_allocaInsertPoint, allocaInsertPoint);
+
+ for (int i = 0; i < _function->tempCount; ++i) {
+ llvm::AllocaInst *t = newLLVMTemp(_valueTy);
+ _tempMap.append(t);
+ }
+
+ foreach (llvm::Value *t, _tempMap) {
+ CreateStore(llvm::Constant::getNullValue(_valueTy), t);
+ }
+
+// CreateCall(getRuntimeFunction("__qmljs_llvm_init_this_object"),
+// _llvmFunction->arg_begin());
+
+ foreach (V4IR::BasicBlock *block, _function->basicBlocks) {
+ qSwap(_block, block);
+ SetInsertPoint(getLLVMBasicBlock(_block));
+ foreach (V4IR::Stmt *s, _block->statements)
+ s->accept(this);
+ qSwap(_block, block);
+ }
+
+ qSwap(_allocaInsertPoint, allocaInsertPoint);
+
+ allocaInsertPoint->eraseFromParent();
+
+ qSwap(_blockMap, blockMap);
+ qSwap(_tempMap, tempMap);
+ qSwap(_function, function);
+ qSwap(_llvmFunction, llvmFunction);
+
+ // Validate the generated code, checking for consistency.
+ llvm::verifyFunction(*llvmFunction);
+ // Optimize the function.
+ if (_fpm)
+ _fpm->run(*llvmFunction);
+
+ return llvmFunction;
+}
+
+llvm::BasicBlock *InstructionSelection::getLLVMBasicBlock(V4IR::BasicBlock *block)
+{
+ llvm::BasicBlock *&llvmBlock = _blockMap[block];
+ if (! llvmBlock)
+ llvmBlock = llvm::BasicBlock::Create(getContext(), llvm::Twine(),
+ _llvmFunction);
+ return llvmBlock;
+}
+
+llvm::Value *InstructionSelection::getLLVMTempReference(V4IR::Expr *expr)
+{
+ if (V4IR::Temp *t = expr->asTemp())
+ return getLLVMTemp(t);
+
+ assert(!"TODO!");
+ llvm::Value *addr = newLLVMTemp(_valueTy);
+// CreateStore(getLLVMValue(expr), addr);
+ return addr;
+}
+
+llvm::Value *InstructionSelection::getLLVMCondition(V4IR::Expr *expr)
+{
+ llvm::Value *value = 0;
+ if (V4IR::Temp *t = expr->asTemp()) {
+ value = getLLVMTemp(t);
+ } else {
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+
+#if 0
+ value = getLLVMValue(expr);
+ if (! value) {
+ Q_UNIMPLEMENTED();
+ return getInt1(false);
+ }
+
+ llvm::Value *tmp = newLLVMTemp(_valueTy);
+ CreateStore(value, tmp);
+ value = tmp;
+#endif
+ }
+
+ return CreateCall2(getRuntimeFunction("__qmljs_llvm_to_boolean"),
+ _llvmFunction->arg_begin(),
+ value);
+}
+
+llvm::Value *InstructionSelection::getLLVMTemp(V4IR::Temp *temp)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+ return 0;
+#if 0
+ if (temp->idx < 0) {
+ const int index = -temp->idx -1;
+ return CreateCall2(getRuntimeFunction("__qmljs_llvm_get_argument"),
+ _llvmFunction->arg_begin(), getInt32(index));
+ }
+
+ return _tempMap[temp->idx];
+#endif
+}
+
+llvm::Value *InstructionSelection::getStringPtr(const QString &s)
+{
+ llvm::Value *&value = _stringMap[s];
+ if (! value) {
+ const QByteArray bytes = s.toUtf8();
+ value = CreateGlobalStringPtr(llvm::StringRef(bytes.constData(), bytes.size()));
+ _stringMap[s] = value;
+ }
+ return value;
+}
+
+llvm::Value *InstructionSelection::getIdentifier(const QString &s)
+{
+ llvm::Value *str = getStringPtr(s);
+ llvm::Value *id = CreateCall2(getRuntimeFunction("__qmljs_identifier_from_utf8"),
+ _llvmFunction->arg_begin(), str);
+ return id;
+}
+
+void InstructionSelection::visitJump(V4IR::Jump *s)
+{
+ CreateBr(getLLVMBasicBlock(s->target));
+}
+
+void InstructionSelection::visitCJump(V4IR::CJump *s)
+{
+ CreateCondBr(getLLVMCondition(s->cond),
+ getLLVMBasicBlock(s->iftrue),
+ getLLVMBasicBlock(s->iffalse));
+}
+
+void InstructionSelection::visitRet(V4IR::Ret *s)
+{
+ V4IR::Temp *t = s->expr->asTemp();
+ assert(t != 0);
+ llvm::Value *result = getLLVMTemp(t);
+ llvm::Value *ctx = _llvmFunction->arg_begin();
+ CreateCall2(getRuntimeFunction("__qmljs_llvm_return"), ctx, result);
+ CreateRetVoid();
+}
+
+void InstructionSelection::visitTry(V4IR::Try *)
+{
+ // TODO
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
+
+#if 0
+void InstructionSelection::visitString(V4IR::String *e)
+{
+ llvm::Value *tmp = newLLVMTemp(_valueTy);
+ CreateCall3(getRuntimeFunction("__qmljs_llvm_init_string"),
+ _llvmFunction->arg_begin(), tmp,
+ getStringPtr(*e->value));
+ _llvmValue = CreateLoad(tmp);
+}
+#endif
+
+llvm::AllocaInst *InstructionSelection::newLLVMTemp(llvm::Type *type, llvm::Value *size)
+{
+ llvm::AllocaInst *addr = new llvm::AllocaInst(type, size, llvm::Twine(), _allocaInsertPoint);
+ return addr;
+}
+
+llvm::Value * InstructionSelection::genArguments(V4IR::ExprList *exprs, int &argc)
+{
+ llvm::Value *args = 0;
+
+ argc = 0;
+ for (V4IR::ExprList *it = exprs; it; it = it->next)
+ ++argc;
+
+ if (argc)
+ args = newLLVMTemp(_valueTy, getInt32(argc));
+ else
+ args = llvm::Constant::getNullValue(_valueTy->getPointerTo());
+
+ int i = 0;
+ for (V4IR::ExprList *it = exprs; it; it = it->next) {
+// llvm::Value *arg = getLLVMValue(it->expr);
+// CreateStore(arg, CreateConstGEP1_32(args, i++));
+ }
+
+ return args;
+}
+
+void InstructionSelection::genCallMember(V4IR::Call *e, llvm::Value *result)
+{
+ if (! result)
+ result = newLLVMTemp(_valueTy);
+
+ V4IR::Member *m = e->base->asMember();
+ llvm::Value *thisObject = getLLVMTemp(m->base->asTemp());
+ llvm::Value *name = getIdentifier(*m->name);
+
+ int argc = 0;
+ llvm::Value *args = genArguments(e->args, argc);
+
+ llvm::Value *actuals[] = {
+ _llvmFunction->arg_begin(),
+ result,
+ thisObject,
+ name,
+ args,
+ getInt32(argc)
+ };
+
+ CreateCall(getRuntimeFunction("__qmljs_llvm_call_property"), llvm::ArrayRef<llvm::Value *>(actuals));
+ _llvmValue = CreateLoad(result);
+}
+
+void InstructionSelection::genConstructMember(V4IR::New *e, llvm::Value *result)
+{
+ if (! result)
+ result = newLLVMTemp(_valueTy);
+
+ V4IR::Member *m = e->base->asMember();
+ llvm::Value *thisObject = getLLVMTemp(m->base->asTemp());
+ llvm::Value *name = getIdentifier(*m->name);
+
+ int argc = 0;
+ llvm::Value *args = genArguments(e->args, argc);
+
+ llvm::Value *actuals[] = {
+ _llvmFunction->arg_begin(),
+ result,
+ thisObject,
+ name,
+ args,
+ getInt32(argc)
+ };
+
+ CreateCall(getRuntimeFunction("__qmljs_llvm_construct_property"), llvm::ArrayRef<llvm::Value *>(actuals));
+ _llvmValue = CreateLoad(result);
+}
+
+void InstructionSelection::genCallTemp(V4IR::Call *e, llvm::Value *result)
+{
+ if (! result)
+ result = newLLVMTemp(_valueTy);
+
+ llvm::Value *func = getLLVMTempReference(e->base);
+
+ int argc = 0;
+ llvm::Value *args = genArguments(e->args, argc);
+
+ llvm::Value *thisObject = llvm::Constant::getNullValue(_valueTy->getPointerTo());
+
+ llvm::Value *actuals[] = {
+ _llvmFunction->arg_begin(),
+ result,
+ thisObject,
+ func,
+ args,
+ getInt32(argc)
+ };
+
+ CreateCall(getRuntimeFunction("__qmljs_llvm_call_value"), actuals);
+
+ _llvmValue = CreateLoad(result);
+}
+
+void InstructionSelection::genConstructTemp(V4IR::New *e, llvm::Value *result)
+{
+ if (! result)
+ result = newLLVMTemp(_valueTy);
+
+ llvm::Value *func = getLLVMTempReference(e->base);
+
+ int argc = 0;
+ llvm::Value *args = genArguments(e->args, argc);
+
+ llvm::Value *actuals[] = {
+ _llvmFunction->arg_begin(),
+ result,
+ func,
+ args,
+ getInt32(argc)
+ };
+
+ CreateCall(getRuntimeFunction("__qmljs_llvm_construct_value"), actuals);
+
+ _llvmValue = CreateLoad(result);
+}
+
+void InstructionSelection::genCallName(V4IR::Call *e, llvm::Value *result)
+{
+ V4IR::Name *base = e->base->asName();
+
+ if (! result)
+ result = newLLVMTemp(_valueTy);
+
+ if (! base->id) {
+ switch (base->builtin) {
+ case V4IR::Name::builtin_invalid:
+ break;
+
+ case V4IR::Name::builtin_typeof:
+ CreateCall3(getRuntimeFunction("__qmljs_llvm_typeof"),
+ _llvmFunction->arg_begin(), result, getLLVMTempReference(e->args->expr));
+ _llvmValue = CreateLoad(result);
+ return;
+
+ case V4IR::Name::builtin_throw:
+ CreateCall2(getRuntimeFunction("__qmljs_llvm_throw"),
+ _llvmFunction->arg_begin(), getLLVMTempReference(e->args->expr));
+ _llvmValue = llvm::UndefValue::get(_valueTy);
+ return;
+
+ case V4IR::Name::builtin_finish_try:
+ // ### FIXME.
+ return;
+
+ case V4IR::Name::builtin_foreach_iterator_object:
+ CreateCall3(getRuntimeFunction("__qmljs_llvm_foreach_iterator_object"),
+ _llvmFunction->arg_begin(), result, getLLVMTempReference(e->args->expr));
+ _llvmValue = CreateLoad(result);
+ return;
+
+ case V4IR::Name::builtin_foreach_next_property_name:
+ CreateCall2(getRuntimeFunction("__qmljs_llvm_foreach_next_property_name"),
+ result, getLLVMTempReference(e->args->expr));
+ _llvmValue = CreateLoad(result);
+ return;
+
+ case V4IR::Name::builtin_delete: {
+ if (V4IR::Subscript *subscript = e->args->expr->asSubscript()) {
+ CreateCall4(getRuntimeFunction("__qmljs_llvm_delete_subscript"),
+ _llvmFunction->arg_begin(),
+ result,
+ getLLVMTempReference(subscript->base),
+ getLLVMTempReference(subscript->index));
+ _llvmValue = CreateLoad(result);
+ return;
+ } else if (V4IR::Member *member = e->args->expr->asMember()) {
+ CreateCall4(getRuntimeFunction("__qmljs_llvm_delete_member"),
+ _llvmFunction->arg_begin(),
+ result,
+ getLLVMTempReference(member->base),
+ getIdentifier(*member->name));
+ _llvmValue = CreateLoad(result);
+ return;
+ } else if (V4IR::Name *name = e->args->expr->asName()) {
+ CreateCall3(getRuntimeFunction("__qmljs_llvm_delete_property"),
+ _llvmFunction->arg_begin(),
+ result,
+ getIdentifier(*name->id));
+ _llvmValue = CreateLoad(result);
+ return;
+ } else {
+ CreateCall3(getRuntimeFunction("__qmljs_llvm_delete_value"),
+ _llvmFunction->arg_begin(),
+ result,
+ getLLVMTempReference(e->args->expr));
+ _llvmValue = CreateLoad(result);
+ return;
+ }
+ } break;
+
+ default:
+ Q_UNREACHABLE();
+ }
+ } else {
+ llvm::Value *name = getIdentifier(*base->id);
+
+ int argc = 0;
+ llvm::Value *args = genArguments(e->args, argc);
+
+ CreateCall5(getRuntimeFunction("__qmljs_llvm_call_activation_property"),
+ _llvmFunction->arg_begin(), result, name, args, getInt32(argc));
+
+ _llvmValue = CreateLoad(result);
+ }
+}
+
+void InstructionSelection::genConstructName(V4IR::New *e, llvm::Value *result)
+{
+ V4IR::Name *base = e->base->asName();
+
+ if (! result)
+ result = newLLVMTemp(_valueTy);
+
+ if (! base->id) {
+ Q_UNREACHABLE();
+ } else {
+ llvm::Value *name = getIdentifier(*base->id);
+
+ int argc = 0;
+ llvm::Value *args = genArguments(e->args, argc);
+
+ CreateCall5(getRuntimeFunction("__qmljs_llvm_construct_activation_property"),
+ _llvmFunction->arg_begin(), result, name, args, getInt32(argc));
+
+ _llvmValue = CreateLoad(result);
+ }
+}
+
+#if 0
+void InstructionSelection::visitCall(V4IR::Call *e)
+{
+ if (e->base->asMember()) {
+ genCallMember(e);
+ } else if (e->base->asTemp()) {
+ genCallTemp(e);
+ } else if (e->base->asName()) {
+ genCallName(e);
+ } else if (V4IR::Temp *t = e->base->asTemp()) {
+ llvm::Value *base = getLLVMTemp(t);
+
+ int argc = 0;
+ llvm::Value *args = genArguments(e->args, argc);
+
+ llvm::Value *result = newLLVMTemp(_valueTy);
+ CreateStore(llvm::Constant::getNullValue(_valueTy), result);
+ CreateCall5(getRuntimeFunction("__qmljs_llvm_call_value"),
+ _llvmFunction->arg_begin(), result, base, args, getInt32(argc));
+ _llvmValue = CreateLoad(result);
+ } else {
+ Q_UNIMPLEMENTED();
+ }
+}
+#endif
+
+#if 0
+void InstructionSelection::visitNew(V4IR::New *e)
+{
+ if (e->base->asMember()) {
+ genConstructMember(e);
+ } else if (e->base->asTemp()) {
+ genConstructTemp(e);
+ } else if (e->base->asName()) {
+ genConstructName(e);
+ } else if (V4IR::Temp *t = e->base->asTemp()) {
+ llvm::Value *base = getLLVMTemp(t);
+
+ int argc = 0;
+ llvm::Value *args = genArguments(e->args, argc);
+
+ llvm::Value *result = newLLVMTemp(_valueTy);
+ CreateStore(llvm::Constant::getNullValue(_valueTy), result);
+ CreateCall5(getRuntimeFunction("__qmljs_llvm_construct_value"),
+ _llvmFunction->arg_begin(), result, base, args, getInt32(argc));
+ _llvmValue = CreateLoad(result);
+ } else {
+ Q_UNIMPLEMENTED();
+ }
+}
+#endif
+
+#if 0
+void InstructionSelection::visitSubscript(V4IR::Subscript *e)
+{
+ llvm::Value *result = newLLVMTemp(_valueTy);
+ llvm::Value *base = getLLVMTempReference(e->base);
+ llvm::Value *index = getLLVMTempReference(e->index);
+ CreateCall4(getRuntimeFunction("__qmljs_llvm_get_element"),
+ _llvmFunction->arg_begin(), result, base, index);
+ _llvmValue = CreateLoad(result);
+}
+#endif
+
+#if 0
+void InstructionSelection::visitMember(V4IR::Member *e)
+{
+ llvm::Value *result = newLLVMTemp(_valueTy);
+ llvm::Value *base = getLLVMTempReference(e->base);
+ llvm::Value *name = getIdentifier(*e->name);
+
+ CreateCall4(getRuntimeFunction("__qmljs_llvm_get_property"),
+ _llvmFunction->arg_begin(), result, base, name);
+ _llvmValue = CreateLoad(result);
+}
+#endif
+
+llvm::Function *InstructionSelection::getRuntimeFunction(llvm::StringRef str)
+{
+ llvm::Function *func = _llvmModule->getFunction(str);
+ if (!func) {
+ std::cerr << "Cannot find runtime function \""
+ << str.str() << "\"!" << std::endl;
+ assert(func);
+ }
+ return func;
+}
+
+llvm::Value *InstructionSelection::createValue(V4IR::Const *e)
+{
+ llvm::Value *tmp = newLLVMTemp(_valueTy);
+
+ switch (e->type) {
+ case V4IR::UndefinedType:
+ CreateCall(getRuntimeFunction("__qmljs_llvm_init_undefined"), tmp);
+ break;
+
+ case V4IR::NullType:
+ CreateCall(getRuntimeFunction("__qmljs_llvm_init_null"), tmp);
+ break;
+
+ case V4IR::BoolType:
+ CreateCall2(getRuntimeFunction("__qmljs_llvm_init_boolean"), tmp,
+ getInt1(e->value ? 1 : 0));
+ break;
+
+ case V4IR::NumberType:
+ CreateCall2(getRuntimeFunction("__qmljs_llvm_init_number"), tmp,
+ llvm::ConstantFP::get(_numberTy, e->value));
+ break;
+
+ default:
+ Q_UNREACHABLE();
+ }
+
+ return tmp;
+}
+
+llvm::Value *InstructionSelection::toValuePtr(V4IR::Expr *e)
+{
+ if (V4IR::Temp *t = e->asTemp()) {
+ return getLLVMTemp(t);
+ } else if (V4IR::Const *c = e->asConst()) {
+ return createValue(c);
+ } else {
+ Q_UNREACHABLE();
+ }
+}
+
+llvm::Value *InstructionSelection::genStringList(const QList<const QString *> &strings, const char *arrayName, const char *elementName)
+{
+ llvm::Value *array = CreateAlloca(_stringPtrTy, getInt32(strings.size()),
+ arrayName);
+ for (int i = 0, ei = strings.size(); i < ei; ++i) {
+ llvm::Value *el;
+ if (const QString *string = strings.at(i))
+ el = getIdentifier(*string);
+ else
+ el = llvm::Constant::getNullValue(_stringPtrTy);
+ llvm::Value *ptr = CreateGEP(array, getInt32(i), elementName);
+ CreateStore(el, ptr);
+ }
+
+ return array;
+}
diff --git a/src/qml/qml/v4/qv4isel_llvm_p.h b/src/qml/qml/v4/qv4isel_llvm_p.h
new file mode 100644
index 0000000000..ab0bcb0e23
--- /dev/null
+++ b/src/qml/qml/v4/qv4isel_llvm_p.h
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4ISEL_LLVM_P_H
+#define QV4ISEL_LLVM_P_H
+
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wunused-parameter"
+#endif // __clang__
+
+#include <llvm/Module.h>
+#include <llvm/PassManager.h>
+#include <llvm/IRBuilder.h>
+
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif // __clang__
+
+#include "qv4isel_p.h"
+#include "qv4jsir_p.h"
+
+namespace QQmlJS {
+namespace LLVM {
+
+class InstructionSelection:
+ public llvm::IRBuilder<>,
+ public V4IR::InstructionSelection
+{
+public:
+ InstructionSelection(llvm::LLVMContext &context);
+
+ void buildLLVMModule(V4IR::Module *module, llvm::Module *llvmModule, llvm::FunctionPassManager *fpm);
+
+public: // methods from InstructionSelection:
+ virtual void callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinTypeofName(const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinTypeofValue(V4IR::Temp *value, V4IR::Temp *result);
+ virtual void callBuiltinDeleteMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinDeleteName(const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinDeleteValue(V4IR::Temp *result);
+ virtual void callBuiltinPostDecrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinPostDecrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinPostDecrementName(const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinPostDecrementValue(V4IR::Temp *value, V4IR::Temp *result);
+ virtual void callBuiltinPostIncrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR::Temp *result);
+ virtual void callBuiltinThrow(V4IR::Temp *arg, int line);
+ virtual void callBuiltinCreateExceptionHandler(V4IR::Temp *result);
+ virtual void callBuiltinFinishTry();
+ virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result);
+ virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result);
+ virtual void callBuiltinPushWithScope(V4IR::Temp *arg);
+ virtual void callBuiltinPopScope();
+ virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
+ virtual void callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter);
+ virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value);
+ virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args);
+ virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args);
+ virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void loadThisObject(V4IR::Temp *temp);
+ virtual void loadConst(V4IR::Const *con, V4IR::Temp *temp);
+ virtual void loadString(const QString &str, V4IR::Temp *targetTemp);
+ virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp);
+ virtual void getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp);
+ virtual void setActivationProperty(V4IR::Temp *source, const QString &targetName);
+ virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target);
+ virtual void getProperty(V4IR::Temp *sourceBase, const QString &sourceName, V4IR::Temp *target);
+ virtual void setProperty(V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName);
+ virtual void getElement(V4IR::Temp *sourceBase, V4IR::Temp *sourceIndex, V4IR::Temp *target);
+ virtual void setElement(V4IR::Temp *source, V4IR::Temp *targetBase, V4IR::Temp *targetIndex);
+ virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
+ virtual void unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
+ virtual void binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target);
+ virtual void inplaceNameOp(V4IR::AluOp oper, V4IR::Temp *rightSource, const QString &targetName);
+ virtual void inplaceElementOp(V4IR::AluOp oper, V4IR::Temp *source, V4IR::Temp *targetBaseTemp, V4IR::Temp *targetIndexTemp);
+ virtual void inplaceMemberOp(V4IR::AluOp oper, V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName);
+
+public: // visitor methods for StmtVisitor:
+ virtual void visitJump(V4IR::Jump *);
+ virtual void visitCJump(V4IR::CJump *);
+ virtual void visitRet(V4IR::Ret *);
+ virtual void visitTry(V4IR::Try *);
+
+private:
+ llvm::Function *getRuntimeFunction(llvm::StringRef str);
+ llvm::Function *getLLVMFunction(V4IR::Function *function);
+ llvm::Function *compileLLVMFunction(V4IR::Function *function);
+ llvm::BasicBlock *getLLVMBasicBlock(V4IR::BasicBlock *block);
+ llvm::Value *getLLVMTempReference(V4IR::Expr *expr);
+ llvm::Value *getLLVMCondition(V4IR::Expr *expr);
+ llvm::Value *getLLVMTemp(V4IR::Temp *temp);
+ llvm::Value *getStringPtr(const QString &s);
+ llvm::Value *getIdentifier(const QString &s);
+ llvm::AllocaInst *newLLVMTemp(llvm::Type *type, llvm::Value *size = 0);
+ llvm::Value * genArguments(V4IR::ExprList *args, int &argc);
+ void genCallTemp(V4IR::Call *e, llvm::Value *result = 0);
+ void genCallName(V4IR::Call *e, llvm::Value *result = 0);
+ void genCallMember(V4IR::Call *e, llvm::Value *result = 0);
+ void genConstructTemp(V4IR::New *e, llvm::Value *result = 0);
+ void genConstructName(V4IR::New *e, llvm::Value *result = 0);
+ void genConstructMember(V4IR::New *e, llvm::Value *result = 0);
+ llvm::Value *createValue(V4IR::Const *e);
+ llvm::Value *toValuePtr(V4IR::Expr *e);
+ llvm::Value *genStringList(const QList<const QString *> &strings,
+ const char *arrayName, const char *elementName);
+
+
+private:
+ llvm::Module *_llvmModule;
+ llvm::Function *_llvmFunction;
+ llvm::Value *_llvmValue;
+ llvm::Type *_numberTy;
+ llvm::Type *_valueTy;
+ llvm::Type *_contextPtrTy;
+ llvm::Type *_stringPtrTy;
+ llvm::FunctionType *_functionTy;
+ llvm::Instruction *_allocaInsertPoint;
+ V4IR::Function *_function;
+ V4IR::BasicBlock *_block;
+ QHash<V4IR::Function *, llvm::Function *> _functionMap;
+ QHash<V4IR::BasicBlock *, llvm::BasicBlock *> _blockMap;
+ QVector<llvm::Value *> _tempMap;
+ QHash<QString, llvm::Value *> _stringMap;
+ llvm::FunctionPassManager *_fpm;
+};
+
+} // LLVM namespace
+} // QQmlJS namespace
+
+#endif // QV4ISEL_LLVM_P_H
diff --git a/src/qml/qml/v4/qv4isel_masm.cpp b/src/qml/qml/v4/qv4isel_masm.cpp
new file mode 100644
index 0000000000..af77a7cb17
--- /dev/null
+++ b/src/qml/qml/v4/qv4isel_masm.cpp
@@ -0,0 +1,1450 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4isel_masm_p.h"
+#include "qv4runtime_p.h"
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+#include "qv4regexpobject_p.h"
+#include "qv4unwindhelper_p.h"
+#include "qv4lookup_p.h"
+#include "qv4function_p.h"
+#include "qv4ssa_p.h"
+#include "qv4exception_p.h"
+
+#include <assembler/LinkBuffer.h>
+#include <WTFStubs.h>
+
+#include <iostream>
+#include <cassert>
+
+#if USE(UDIS86)
+# include <udis86.h>
+#endif
+
+using namespace QQmlJS;
+using namespace QQmlJS::MASM;
+using namespace QV4;
+
+namespace {
+class ConvertTemps: protected V4IR::StmtVisitor, protected V4IR::ExprVisitor
+{
+ int _nextFreeStackSlot;
+ QHash<V4IR::Temp, int> _stackSlotForTemp;
+
+ void renumber(V4IR::Temp *t)
+ {
+ if (t->kind != V4IR::Temp::VirtualRegister)
+ return;
+
+ int stackSlot = _stackSlotForTemp.value(*t, -1);
+ if (stackSlot == -1) {
+ stackSlot = _nextFreeStackSlot++;
+ _stackSlotForTemp[*t] = stackSlot;
+ }
+
+ t->kind = V4IR::Temp::StackSlot;
+ t->index = stackSlot;
+ }
+
+public:
+ ConvertTemps()
+ : _nextFreeStackSlot(0)
+ {}
+
+ void toStackSlots(V4IR::Function *function)
+ {
+ _stackSlotForTemp.reserve(function->tempCount);
+
+ foreach (V4IR::BasicBlock *bb, function->basicBlocks)
+ foreach (V4IR::Stmt *s, bb->statements)
+ s->accept(this);
+
+ function->tempCount = _nextFreeStackSlot;
+ }
+
+protected:
+ virtual void visitConst(V4IR::Const *) {}
+ virtual void visitString(V4IR::String *) {}
+ virtual void visitRegExp(V4IR::RegExp *) {}
+ virtual void visitName(V4IR::Name *) {}
+ virtual void visitTemp(V4IR::Temp *e) { renumber(e); }
+ virtual void visitClosure(V4IR::Closure *) {}
+ virtual void visitConvert(V4IR::Convert *e) { e->expr->accept(this); }
+ virtual void visitUnop(V4IR::Unop *e) { e->expr->accept(this); }
+ virtual void visitBinop(V4IR::Binop *e) { e->left->accept(this); e->right->accept(this); }
+ virtual void visitCall(V4IR::Call *e) {
+ e->base->accept(this);
+ for (V4IR::ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+ virtual void visitNew(V4IR::New *e) {
+ e->base->accept(this);
+ for (V4IR::ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+ virtual void visitSubscript(V4IR::Subscript *e) { e->base->accept(this); e->index->accept(this); }
+ virtual void visitMember(V4IR::Member *e) { e->base->accept(this); }
+ virtual void visitExp(V4IR::Exp *s) { s->expr->accept(this); }
+ virtual void visitMove(V4IR::Move *s) { s->target->accept(this); s->source->accept(this); }
+ virtual void visitJump(V4IR::Jump *) {}
+ virtual void visitCJump(V4IR::CJump *s) { s->cond->accept(this); }
+ virtual void visitRet(V4IR::Ret *s) { s->expr->accept(this); }
+ virtual void visitTry(V4IR::Try *s) { s->exceptionVar->accept(this); }
+ virtual void visitPhi(V4IR::Phi *) { Q_UNREACHABLE(); }
+};
+} // anonymous namespace
+
+/* Platform/Calling convention/Architecture specific section */
+
+#if CPU(X86_64)
+static const Assembler::RegisterID calleeSavedRegisters[] = {
+ // Not used: JSC::X86Registers::rbx,
+ // Not used: JSC::X86Registers::r10,
+ JSC::X86Registers::r12, // LocalsRegister
+ // Not used: JSC::X86Registers::r13,
+ JSC::X86Registers::r14 // ContextRegister
+ // Not used: JSC::X86Registers::r15,
+};
+#endif
+
+#if CPU(X86)
+static const Assembler::RegisterID calleeSavedRegisters[] = {
+ // Not used: JSC::X86Registers::ebx,
+ JSC::X86Registers::esi, // ContextRegister
+ JSC::X86Registers::edi // LocalsRegister
+};
+#endif
+
+#if CPU(ARM)
+static const Assembler::RegisterID calleeSavedRegisters[] = {
+ // ### FIXME: remove unused registers.
+ // Keep these in reverse order and make sure to also edit the unwind program in
+ // qv4unwindhelper_p-arm.h when changing this list.
+ JSC::ARMRegisters::r12,
+ JSC::ARMRegisters::r10,
+ JSC::ARMRegisters::r9,
+ JSC::ARMRegisters::r8,
+ JSC::ARMRegisters::r7,
+ JSC::ARMRegisters::r6,
+ JSC::ARMRegisters::r5,
+ JSC::ARMRegisters::r4
+};
+#endif
+
+const int Assembler::calleeSavedRegisterCount = sizeof(calleeSavedRegisters) / sizeof(calleeSavedRegisters[0]);
+
+/* End of platform/calling convention/architecture specific section */
+
+
+const Assembler::VoidType Assembler::Void;
+
+Assembler::Assembler(V4IR::Function* function, QV4::Function *vmFunction, QV4::ExecutionEngine *engine)
+ : _function(function), _vmFunction(vmFunction), _engine(engine), _nextBlock(0)
+{
+}
+
+void Assembler::registerBlock(V4IR::BasicBlock* block, V4IR::BasicBlock *nextBlock)
+{
+ _addrs[block] = label();
+ _nextBlock = nextBlock;
+}
+
+void Assembler::jumpToBlock(V4IR::BasicBlock* current, V4IR::BasicBlock *target)
+{
+ if (target != _nextBlock)
+ _patches[target].append(jump());
+}
+
+void Assembler::addPatch(V4IR::BasicBlock* targetBlock, Jump targetJump)
+{
+ _patches[targetBlock].append(targetJump);
+}
+
+void Assembler::addPatch(DataLabelPtr patch, Label target)
+{
+ DataLabelPatch p;
+ p.dataLabel = patch;
+ p.target = target;
+ _dataLabelPatches.append(p);
+}
+
+void Assembler::addPatch(DataLabelPtr patch, V4IR::BasicBlock *target)
+{
+ _labelPatches[target].append(patch);
+}
+
+Assembler::Pointer Assembler::loadTempAddress(RegisterID reg, V4IR::Temp *t)
+{
+ int32_t offset = 0;
+ int scope = t->scope;
+ QV4::Function *f = _vmFunction;
+ RegisterID context = ContextRegister;
+ if (scope) {
+ loadPtr(Address(ContextRegister, offsetof(ExecutionContext, outer)), ScratchRegister);
+ --scope;
+ f = f->outer;
+ context = ScratchRegister;
+ while (scope) {
+ loadPtr(Address(context, offsetof(ExecutionContext, outer)), context);
+ f = f->outer;
+ --scope;
+ }
+ }
+ switch (t->kind) {
+ case V4IR::Temp::Formal:
+ case V4IR::Temp::ScopedFormal: {
+ loadPtr(Address(context, offsetof(CallContext, arguments)), reg);
+ offset = t->index * sizeof(Value);
+ } break;
+ case V4IR::Temp::Local:
+ case V4IR::Temp::ScopedLocal: {
+ loadPtr(Address(context, offsetof(CallContext, locals)), reg);
+ offset = t->index * sizeof(Value);
+ } break;
+ case V4IR::Temp::StackSlot: {
+ assert(t->scope == 0);
+ const int arg = _function->maxNumberOfArguments + t->index + 1;
+ offset = - sizeof(Value) * (arg + 1);
+ offset -= sizeof(void*) * calleeSavedRegisterCount;
+ reg = LocalsRegister;
+ } break;
+ default:
+ Q_UNIMPLEMENTED();
+ }
+ return Pointer(reg, offset);
+}
+
+template <typename Result, typename Source>
+void Assembler::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);
+ storeReturnValue(result);
+#else
+ loadDouble(source, FPGpr0);
+ storeDouble(FPGpr0, result);
+#endif
+}
+
+template <typename Result>
+void Assembler::copyValue(Result result, V4IR::Expr* 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);
+ storeReturnValue(result);
+#else
+ if (V4IR::Temp *temp = source->asTemp()) {
+ loadDouble(temp, FPGpr0);
+ storeDouble(FPGpr0, result);
+ } else if (V4IR::Const *c = source->asConst()) {
+ QV4::Value v = convertToValue(c);
+ storeValue(v, result);
+ } else {
+ assert(! "not implemented");
+ }
+#endif
+}
+
+
+void Assembler::storeValue(QV4::Value value, V4IR::Temp* destination)
+{
+ Address addr = loadTempAddress(ScratchRegister, destination);
+ storeValue(value, addr);
+}
+
+int Assembler::calculateStackFrameSize(int locals)
+{
+ const int stackSpaceAllocatedOtherwise = StackSpaceAllocatedUponFunctionEntry
+ + RegisterSize; // saved StackFrameRegister
+
+ // space for the locals and the callee saved registers
+ int frameSize = locals * sizeof(QV4::Value) + sizeof(void*) * calleeSavedRegisterCount;
+
+ frameSize = WTF::roundUpToMultipleOf(StackAlignment, frameSize + stackSpaceAllocatedOtherwise);
+ frameSize -= stackSpaceAllocatedOtherwise;
+
+ return frameSize;
+}
+
+void Assembler::enterStandardStackFrame(int locals)
+{
+ platformEnterStandardStackFrame();
+
+ // ### FIXME: Handle through calleeSavedRegisters mechanism
+ // or eliminate StackFrameRegister altogether.
+ push(StackFrameRegister);
+ move(StackPointerRegister, StackFrameRegister);
+
+ int frameSize = calculateStackFrameSize(locals);
+
+ subPtr(TrustedImm32(frameSize), StackPointerRegister);
+
+ for (int i = 0; i < calleeSavedRegisterCount; ++i)
+ storePtr(calleeSavedRegisters[i], Address(StackFrameRegister, -(i + 1) * sizeof(void*)));
+
+ move(StackFrameRegister, LocalsRegister);
+}
+
+void Assembler::leaveStandardStackFrame(int locals)
+{
+ // restore the callee saved registers
+ for (int i = calleeSavedRegisterCount - 1; i >= 0; --i)
+ loadPtr(Address(StackFrameRegister, -(i + 1) * sizeof(void*)), calleeSavedRegisters[i]);
+
+ int frameSize = calculateStackFrameSize(locals);
+ // Work around bug in ARMv7Assembler.h where add32(imm, sp, sp) doesn't
+ // work well for large immediates.
+#if CPU(ARM_THUMB2)
+ move(TrustedImm32(frameSize), JSC::ARMRegisters::r3);
+ add32(JSC::ARMRegisters::r3, StackPointerRegister);
+#else
+ addPtr(TrustedImm32(frameSize), StackPointerRegister);
+#endif
+
+ pop(StackFrameRegister);
+ platformLeaveStandardStackFrame();
+}
+
+
+
+#define OP(op) \
+ { isel_stringIfy(op), op, 0, 0 }
+
+#define INLINE_OP(op, memOp, immOp) \
+ { isel_stringIfy(op), op, memOp, immOp }
+
+#define NULL_OP \
+ { 0, 0, 0, 0 }
+
+const Assembler::BinaryOperationInfo Assembler::binaryOperations[QQmlJS::V4IR::LastAluOp + 1] = {
+ NULL_OP, // OpInvalid
+ NULL_OP, // OpIfTrue
+ NULL_OP, // OpNot
+ NULL_OP, // OpUMinus
+ NULL_OP, // OpUPlus
+ NULL_OP, // OpCompl
+ NULL_OP, // OpIncrement
+ NULL_OP, // OpDecrement
+
+ INLINE_OP(__qmljs_bit_and, &Assembler::inline_and32, &Assembler::inline_and32), // OpBitAnd
+ INLINE_OP(__qmljs_bit_or, &Assembler::inline_or32, &Assembler::inline_or32), // OpBitOr
+ INLINE_OP(__qmljs_bit_xor, &Assembler::inline_xor32, &Assembler::inline_xor32), // OpBitXor
+
+ INLINE_OP(__qmljs_add, &Assembler::inline_add32, &Assembler::inline_add32), // OpAdd
+ INLINE_OP(__qmljs_sub, &Assembler::inline_sub32, &Assembler::inline_sub32), // OpSub
+ INLINE_OP(__qmljs_mul, &Assembler::inline_mul32, &Assembler::inline_mul32), // OpMul
+
+ OP(__qmljs_div), // OpDiv
+ OP(__qmljs_mod), // OpMod
+
+ INLINE_OP(__qmljs_shl, &Assembler::inline_shl32, &Assembler::inline_shl32), // OpLShift
+ INLINE_OP(__qmljs_shr, &Assembler::inline_shr32, &Assembler::inline_shr32), // OpRShift
+ INLINE_OP(__qmljs_ushr, &Assembler::inline_ushr32, &Assembler::inline_ushr32), // OpURShift
+
+ OP(__qmljs_gt), // OpGt
+ OP(__qmljs_lt), // OpLt
+ OP(__qmljs_ge), // OpGe
+ OP(__qmljs_le), // OpLe
+ OP(__qmljs_eq), // OpEqual
+ OP(__qmljs_ne), // OpNotEqual
+ OP(__qmljs_se), // OpStrictEqual
+ OP(__qmljs_sne), // OpStrictNotEqual
+
+ OP(__qmljs_instanceof), // OpInstanceof
+ OP(__qmljs_in), // OpIn
+
+ NULL_OP, // OpAnd
+ NULL_OP // OpOr
+};
+
+void Assembler::generateBinOp(V4IR::AluOp operation, V4IR::Temp* target, V4IR::Temp *left, V4IR::Temp *right)
+{
+ const BinaryOperationInfo& info = binaryOperations[operation];
+ if (!info.fallbackImplementation) {
+ assert(!"unreachable");
+ return;
+ }
+
+ Value leftConst = Value::undefinedValue();
+ Value rightConst = Value::undefinedValue();
+
+ bool canDoInline = info.inlineMemRegOp && info.inlineImmRegOp;
+
+ if (canDoInline) {
+ if (left->asConst()) {
+ leftConst = convertToValue(left->asConst());
+ canDoInline = canDoInline && leftConst.tryIntegerConversion();
+ }
+ if (right->asConst()) {
+ rightConst = convertToValue(right->asConst());
+ canDoInline = canDoInline && rightConst.tryIntegerConversion();
+ }
+ }
+
+ Jump binOpFinished;
+
+ if (canDoInline) {
+
+ Jump leftTypeCheck;
+ if (left->asTemp()) {
+ Address typeAddress = loadTempAddress(ScratchRegister, left->asTemp());
+ typeAddress.offset += offsetof(QV4::Value, tag);
+ leftTypeCheck = branch32(NotEqual, typeAddress, TrustedImm32(QV4::Value::_Integer_Type));
+ }
+
+ Jump rightTypeCheck;
+ if (right->asTemp()) {
+ Address typeAddress = loadTempAddress(ScratchRegister, right->asTemp());
+ typeAddress.offset += offsetof(QV4::Value, tag);
+ rightTypeCheck = branch32(NotEqual, typeAddress, TrustedImm32(QV4::Value::_Integer_Type));
+ }
+
+ if (left->asTemp()) {
+ Address leftValue = loadTempAddress(ScratchRegister, left->asTemp());
+ leftValue.offset += offsetof(QV4::Value, int_32);
+ load32(leftValue, IntegerOpRegister);
+ } else { // left->asConst()
+ move(TrustedImm32(leftConst.integerValue()), IntegerOpRegister);
+ }
+
+ Jump overflowCheck;
+
+ if (right->asTemp()) {
+ Address rightValue = loadTempAddress(ScratchRegister, right->asTemp());
+ rightValue.offset += offsetof(QV4::Value, int_32);
+
+ overflowCheck = (this->*info.inlineMemRegOp)(rightValue, IntegerOpRegister);
+ } else { // right->asConst()
+ overflowCheck = (this->*info.inlineImmRegOp)(TrustedImm32(rightConst.integerValue()), IntegerOpRegister);
+ }
+
+ Address resultAddr = loadTempAddress(ScratchRegister, target);
+ Address resultValueAddr = resultAddr;
+ resultValueAddr.offset += offsetof(QV4::Value, int_32);
+ store32(IntegerOpRegister, resultValueAddr);
+
+ Address resultTypeAddr = resultAddr;
+ resultTypeAddr.offset += offsetof(QV4::Value, tag);
+ store32(TrustedImm32(QV4::Value::_Integer_Type), resultTypeAddr);
+
+ binOpFinished = jump();
+
+ if (leftTypeCheck.isSet())
+ leftTypeCheck.link(this);
+ if (rightTypeCheck.isSet())
+ rightTypeCheck.link(this);
+ if (overflowCheck.isSet())
+ overflowCheck.link(this);
+ }
+
+ // Fallback
+ generateFunctionCallImp(Assembler::Void, info.name, info.fallbackImplementation, ContextRegister,
+ Assembler::PointerToValue(target), Assembler::Reference(left), Assembler::Reference(right));
+
+ if (binOpFinished.isSet())
+ binOpFinished.link(this);
+}
+#if OS(LINUX) || OS(MAC_OS_X)
+static void printDisassembledOutputWithCalls(const char* output, const QHash<void*, const char*>& functions,
+ const QVector<String*> &identifiers)
+{
+ QByteArray processedOutput(output);
+ for (QHash<void*, const char*>::ConstIterator it = functions.begin(), end = functions.end();
+ it != end; ++it) {
+ QByteArray ptrString = QByteArray::number(quintptr(it.key()), 16);
+ ptrString.prepend("0x");
+ processedOutput = processedOutput.replace(ptrString, it.value());
+ }
+ for (QVector<String*>::ConstIterator it = identifiers.begin(), end = identifiers.end();
+ it != end; ++it) {
+ QByteArray ptrString = QByteArray::number(quintptr(*it), 16);
+ ptrString.prepend("0x");
+ QByteArray replacement = "\"" + (*it)->toQString().toUtf8() + "\"";
+ processedOutput = processedOutput.replace(ptrString, replacement);
+ }
+ fprintf(stderr, "%s\n", processedOutput.constData());
+}
+#endif
+
+void Assembler::recordLineNumber(int lineNumber)
+{
+ CodeLineNumerMapping mapping;
+ mapping.location = label();
+ mapping.lineNumber = lineNumber;
+ codeLineNumberMappings << mapping;
+}
+
+
+void Assembler::link(QV4::Function *vmFunc)
+{
+ Label endOfCode = label();
+#if defined(Q_PROCESSOR_ARM) && !defined(Q_OS_IOS)
+ // Let the ARM exception table follow right after that
+ for (int i = 0, nops = UnwindHelper::unwindInfoSize() / 2; i < nops; ++i)
+ nop();
+#endif
+
+ {
+ QHashIterator<V4IR::BasicBlock *, QVector<Jump> > it(_patches);
+ while (it.hasNext()) {
+ it.next();
+ V4IR::BasicBlock *block = it.key();
+ Label target = _addrs.value(block);
+ assert(target.isSet());
+ foreach (Jump jump, it.value())
+ jump.linkTo(target, this);
+ }
+ }
+
+ JSC::JSGlobalData dummy(_engine->executableAllocator);
+ JSC::LinkBuffer linkBuffer(dummy, this, 0);
+ vmFunc->codeSize = linkBuffer.offsetOf(endOfCode);
+
+ vmFunc->lineNumberMappings.resize(codeLineNumberMappings.count());
+ for (int i = 0; i < codeLineNumberMappings.count(); ++i) {
+ QV4::LineNumberMapping mapping;
+ mapping.codeOffset = linkBuffer.offsetOf(codeLineNumberMappings.at(i).location);
+ mapping.lineNumber = codeLineNumberMappings.at(i).lineNumber;
+ vmFunc->lineNumberMappings[i] = mapping;
+ }
+
+ QHash<void*, const char*> functions;
+ foreach (CallToLink ctl, _callsToLink) {
+ linkBuffer.link(ctl.call, ctl.externalFunction);
+ functions[ctl.externalFunction.value()] = ctl.functionName;
+ }
+
+ foreach (const DataLabelPatch &p, _dataLabelPatches)
+ linkBuffer.patch(p.dataLabel, linkBuffer.locationOf(p.target));
+
+ {
+ QHashIterator<V4IR::BasicBlock *, QVector<DataLabelPtr> > it(_labelPatches);
+ while (it.hasNext()) {
+ it.next();
+ V4IR::BasicBlock *block = it.key();
+ Label target = _addrs.value(block);
+ assert(target.isSet());
+ foreach (DataLabelPtr label, it.value())
+ linkBuffer.patch(label, linkBuffer.locationOf(target));
+ }
+ }
+
+#if defined(Q_PROCESSOR_ARM) && !defined(Q_OS_IOS)
+ UnwindHelper::writeARMUnwindInfo(linkBuffer.debugAddress(), linkBuffer.offsetOf(endOfCode));
+#endif
+
+ static bool showCode = !qgetenv("SHOW_CODE").isNull();
+ if (showCode) {
+#if OS(LINUX) && !defined(Q_OS_ANDROID)
+ char* disasmOutput = 0;
+ size_t disasmLength = 0;
+ FILE* disasmStream = open_memstream(&disasmOutput, &disasmLength);
+ WTF::setDataFile(disasmStream);
+#elif OS(MAC_OS_X)
+ struct MemStream {
+ QByteArray buf;
+ static int write(void *cookie, const char *buf, int len) {
+ MemStream *stream = reinterpret_cast<MemStream *>(cookie);
+ stream->buf.append(buf, len);
+ return len;
+ }
+ };
+ MemStream memStream;
+
+ FILE* disasmStream = fwopen(&memStream, MemStream::write);
+ WTF::setDataFile(disasmStream);
+#endif
+
+ QByteArray name = _function->name->toUtf8();
+ if (name.isEmpty()) {
+ name = QByteArray::number(quintptr(_function), 16);
+ name.prepend("IR::Function(0x");
+ name.append(")");
+ }
+ vmFunc->codeRef = linkBuffer.finalizeCodeWithDisassembly("%s", name.data());
+
+ WTF::setDataFile(stderr);
+#if (OS(LINUX) && !defined(Q_OS_ANDROID)) || OS(MAC_OS_X)
+ fclose(disasmStream);
+# if OS(MAC_OS_X)
+ char *disasmOutput = memStream.buf.data();
+# endif
+# if CPU(X86) || CPU(X86_64)
+ QHash<void*, String*> idents;
+ printDisassembledOutputWithCalls(disasmOutput, functions, _vmFunction->identifiers);
+# endif
+# if OS(LINUX)
+ free(disasmOutput);
+# endif
+#endif
+ } else {
+ vmFunc->codeRef = linkBuffer.finalizeCodeWithoutDisassembly();
+ }
+
+ vmFunc->code = (Value (*)(QV4::ExecutionContext *, const uchar *)) vmFunc->codeRef.code().executableAddress();
+}
+
+InstructionSelection::InstructionSelection(QV4::ExecutionEngine *engine, V4IR::Module *module)
+ : EvalInstructionSelection(engine, module)
+ , _block(0)
+ , _function(0)
+ , _vmFunction(0)
+ , _as(0)
+ , _locals(0)
+{
+}
+
+InstructionSelection::~InstructionSelection()
+{
+ delete _as;
+}
+
+void InstructionSelection::run(QV4::Function *vmFunction, V4IR::Function *function)
+{
+ QVector<Lookup> lookups;
+ QSet<V4IR::BasicBlock*> reentryBlocks;
+ qSwap(_function, function);
+ qSwap(_vmFunction, vmFunction);
+ qSwap(_lookups, lookups);
+ qSwap(_reentryBlocks, reentryBlocks);
+ Assembler* oldAssembler = _as;
+ _as = new Assembler(_function, _vmFunction, engine());
+
+ V4IR::Optimizer opt(_function);
+ opt.run();
+ if (opt.isInSSA()) {
+#if CPU(X86_64) && (OS(MAC_OS_X) || OS(LINUX)) && 0
+ // TODO: add a register allocator here.
+#else
+ // No register allocator available for this platform, so:
+ opt.convertOutOfSSA();
+ ConvertTemps().toStackSlots(_function);
+#endif
+ } else {
+ ConvertTemps().toStackSlots(_function);
+ }
+
+ int locals = (_function->tempCount + _function->maxNumberOfArguments) + 1;
+ locals = (locals + 1) & ~1;
+ qSwap(_locals, locals);
+ _as->enterStandardStackFrame(_locals);
+
+ int contextPointer = 0;
+#if !defined(RETURN_VALUE_IN_REGISTER)
+ // When the return VM value doesn't fit into a register, then
+ // the caller provides a pointer for storage as first argument.
+ // That shifts the index the context pointer argument by one.
+ contextPointer++;
+#endif
+
+#ifdef ARGUMENTS_IN_REGISTERS
+ _as->move(_as->registerForArgument(contextPointer), Assembler::ContextRegister);
+#else
+ _as->loadPtr(addressForArgument(contextPointer), Assembler::ContextRegister);
+#endif
+
+ for (int i = 0, ei = _function->basicBlocks.size(); i != ei; ++i) {
+ V4IR::BasicBlock *nextBlock = (i < ei - 1) ? _function->basicBlocks[i + 1] : 0;
+ _block = _function->basicBlocks[i];
+ _as->registerBlock(_block, nextBlock);
+
+ if (_reentryBlocks.contains(_block)) {
+ _as->enterStandardStackFrame(/*locals*/0);
+#ifdef ARGUMENTS_IN_REGISTERS
+ _as->move(Assembler::registerForArgument(0), Assembler::ContextRegister);
+ _as->move(Assembler::registerForArgument(1), Assembler::LocalsRegister);
+#else
+ _as->loadPtr(addressForArgument(0), Assembler::ContextRegister);
+ _as->loadPtr(addressForArgument(1), Assembler::LocalsRegister);
+#endif
+ }
+
+ foreach (V4IR::Stmt *s, _block->statements) {
+ if (s->location.isValid())
+ _as->recordLineNumber(s->location.startLine);
+ s->accept(this);
+ }
+ }
+
+ _as->link(_vmFunction);
+
+ if (_lookups.size()) {
+ _vmFunction->lookups = new Lookup[_lookups.size()];
+ memcpy(_vmFunction->lookups, _lookups.constData(), _lookups.size()*sizeof(Lookup));
+ }
+
+ UnwindHelper::registerFunction(_vmFunction);
+
+ qSwap(_vmFunction, vmFunction);
+ qSwap(_function, function);
+ qSwap(_lookups, lookups);
+ qSwap(_reentryBlocks, reentryBlocks);
+ qSwap(_locals, locals);
+ delete _as;
+ _as = oldAssembler;
+}
+
+void InstructionSelection::callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ int argc = prepareVariableArguments(args);
+ QV4::String *s = identifier(*func->id);
+
+ if (useFastLookups && func->global) {
+ uint index = addGlobalLookup(s);
+ generateFunctionCall(Assembler::Void, __qmljs_call_global_lookup,
+ Assembler::ContextRegister, Assembler::PointerToValue(result),
+ Assembler::TrustedImm32(index),
+ baseAddressForCallArguments(),
+ Assembler::TrustedImm32(argc));
+ } else {
+ generateFunctionCall(Assembler::Void, __qmljs_call_activation_property,
+ Assembler::ContextRegister, Assembler::PointerToValue(result),
+ s,
+ baseAddressForCallArguments(),
+ Assembler::TrustedImm32(argc));
+ }
+}
+
+void InstructionSelection::callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_typeof_member, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::Reference(base), identifier(name));
+}
+
+void InstructionSelection::callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_typeof_element,
+ Assembler::ContextRegister, Assembler::PointerToValue(result),
+ Assembler::Reference(base), Assembler::Reference(index));
+}
+
+void InstructionSelection::callBuiltinTypeofName(const QString &name, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_typeof_name, Assembler::ContextRegister, Assembler::PointerToValue(result), identifier(name));
+}
+
+void InstructionSelection::callBuiltinTypeofValue(V4IR::Temp *value, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_typeof, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::Reference(value));
+}
+
+void InstructionSelection::callBuiltinDeleteMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_delete_member, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::Reference(base), identifier(name));
+}
+
+void InstructionSelection::callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_delete_subscript, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::Reference(base), Assembler::Reference(index));
+}
+
+void InstructionSelection::callBuiltinDeleteName(const QString &name, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_delete_name, Assembler::ContextRegister, Assembler::PointerToValue(result), identifier(name));
+}
+
+void InstructionSelection::callBuiltinDeleteValue(V4IR::Temp *result)
+{
+ _as->storeValue(Value::fromBoolean(false), result);
+}
+
+void InstructionSelection::callBuiltinPostIncrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_post_increment_member, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::PointerToValue(base), identifier(name));
+}
+
+void InstructionSelection::callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_post_increment_element, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::Reference(base), Assembler::PointerToValue(index));
+}
+
+void InstructionSelection::callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_post_increment_name, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), identifier(name));
+}
+
+void InstructionSelection::callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_post_increment,
+ Assembler::PointerToValue(result), Assembler::PointerToValue(value));
+}
+
+void InstructionSelection::callBuiltinPostDecrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_post_decrement_member, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::Reference(base), identifier(name));
+}
+
+void InstructionSelection::callBuiltinPostDecrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_post_decrement_element, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::Reference(base),
+ Assembler::Reference(index));
+}
+
+void InstructionSelection::callBuiltinPostDecrementName(const QString &name, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_post_decrement_name, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), identifier(name));
+}
+
+void InstructionSelection::callBuiltinPostDecrementValue(V4IR::Temp *value, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_post_decrement,
+ Assembler::PointerToValue(result), Assembler::PointerToValue(value));
+}
+
+void InstructionSelection::callBuiltinThrow(V4IR::Temp *arg)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_throw, Assembler::ContextRegister, Assembler::Reference(arg));
+}
+
+typedef void *(*MiddleOfFunctionEntryPoint(ExecutionContext *, void *localsPtr));
+static void *tryWrapper(ExecutionContext *context, void *localsPtr, MiddleOfFunctionEntryPoint tryBody, MiddleOfFunctionEntryPoint catchBody,
+ QV4::String *exceptionVarName, Value *exceptionVar)
+{
+ *exceptionVar = Value::undefinedValue();
+ void *addressToContinueAt = 0;
+ try {
+ addressToContinueAt = tryBody(context, localsPtr);
+ } catch (Exception& ex) {
+ ex.accept(context);
+ *exceptionVar = ex.value();
+ try {
+ ExecutionContext *catchContext = __qmljs_builtin_push_catch_scope(exceptionVarName, ex.value(), context);
+ addressToContinueAt = catchBody(catchContext, localsPtr);
+ context = __qmljs_builtin_pop_scope(catchContext);
+ } catch (Exception& ex) {
+ *exceptionVar = ex.value();
+ ex.accept(context);
+ addressToContinueAt = catchBody(context, localsPtr);
+ }
+ }
+ return addressToContinueAt;
+}
+
+void InstructionSelection::visitTry(V4IR::Try *t)
+{
+ // Call tryWrapper, which is going to re-enter the same function at the address of the try block. At then end
+ // of the try function the JIT code will return with the address of the sub-sequent instruction, which tryWrapper
+ // returns and to which we jump to.
+
+ _reentryBlocks.insert(t->tryBlock);
+ _reentryBlocks.insert(t->catchBlock);
+
+ generateFunctionCall(Assembler::ReturnValueRegister, tryWrapper, Assembler::ContextRegister, Assembler::LocalsRegister,
+ Assembler::ReentryBlock(t->tryBlock), Assembler::ReentryBlock(t->catchBlock),
+ identifier(t->exceptionVarName), Assembler::PointerToValue(t->exceptionVar));
+ _as->jump(Assembler::ReturnValueRegister);
+}
+
+void InstructionSelection::callBuiltinFinishTry()
+{
+ // This assumes that we're in code that was called by tryWrapper, so we return to try wrapper
+ // with the address that we'd like to continue at, which is right after the ret below.
+ Assembler::DataLabelPtr continuation = _as->moveWithPatch(Assembler::TrustedImmPtr(0), Assembler::ReturnValueRegister);
+ _as->leaveStandardStackFrame(/*locals*/0);
+ _as->ret();
+ _as->addPatch(continuation, _as->label());
+}
+
+void InstructionSelection::callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_foreach_iterator_object, Assembler::ContextRegister, Assembler::PointerToValue(result), Assembler::Reference(arg));
+}
+
+void InstructionSelection::callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_foreach_next_property_name, Assembler::PointerToValue(result), Assembler::Reference(arg));
+}
+
+void InstructionSelection::callBuiltinPushWithScope(V4IR::Temp *arg)
+{
+ generateFunctionCall(Assembler::ContextRegister, __qmljs_builtin_push_with_scope, Assembler::Reference(arg), Assembler::ContextRegister);
+}
+
+void InstructionSelection::callBuiltinPopScope()
+{
+ generateFunctionCall(Assembler::ContextRegister, __qmljs_builtin_pop_scope, Assembler::ContextRegister);
+}
+
+void InstructionSelection::callBuiltinDeclareVar(bool deletable, const QString &name)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_declare_var, Assembler::ContextRegister,
+ Assembler::TrustedImm32(deletable), identifier(name));
+}
+
+void InstructionSelection::callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_define_getter_setter, Assembler::ContextRegister,
+ Assembler::Reference(object), identifier(name), Assembler::PointerToValue(getter), Assembler::PointerToValue(setter));
+}
+
+void InstructionSelection::callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_define_property, Assembler::ContextRegister,
+ Assembler::Reference(object), identifier(name), Assembler::PointerToValue(value));
+}
+
+void InstructionSelection::callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args)
+{
+ int length = prepareVariableArguments(args);
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_define_array, Assembler::ContextRegister,
+ Assembler::PointerToValue(result),
+ baseAddressForCallArguments(), Assembler::TrustedImm32(length));
+}
+
+void InstructionSelection::callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args)
+{
+ int argc = 0;
+
+ InternalClass *klass = engine()->emptyClass;
+ V4IR::ExprList *it = args;
+ while (it) {
+ V4IR::Name *name = it->expr->asName();
+ it = it->next;
+
+ bool isData = it->expr->asConst()->value;
+ it = it->next;
+ klass = klass->addMember(identifier(*name->id), isData ? QV4::Attr_Data : QV4::Attr_Accessor);
+
+ _as->copyValue(argumentAddressForCall(argc++), it->expr);
+
+ if (!isData) {
+ it = it->next;
+ _as->copyValue(argumentAddressForCall(argc++), it->expr);
+ }
+
+ it = it->next;
+ }
+
+ generateFunctionCall(Assembler::Void, __qmljs_builtin_define_object_literal, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), baseAddressForCallArguments(),
+ Assembler::TrustedImmPtr(klass));
+}
+
+void InstructionSelection::callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ int argc = prepareVariableArguments(args);
+ V4IR::Temp* thisObject = 0;
+ generateFunctionCall(Assembler::Void, __qmljs_call_value, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::PointerToValue(thisObject),
+ Assembler::Reference(value), baseAddressForCallArguments(), Assembler::TrustedImm32(argc));
+}
+
+void InstructionSelection::loadThisObject(V4IR::Temp *temp)
+{
+#if defined(VALUE_FITS_IN_REGISTER)
+ _as->load64(Pointer(Assembler::ContextRegister, offsetof(ExecutionContext, thisObject)), Assembler::ReturnValueRegister);
+ _as->storeReturnValue(temp);
+#else
+ _as->copyValue(temp, Pointer(Assembler::ContextRegister, offsetof(ExecutionContext, thisObject)));
+#endif
+}
+
+void InstructionSelection::loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp)
+{
+ _as->storeValue(convertToValue(sourceConst), targetTemp);
+}
+
+void InstructionSelection::loadString(const QString &str, V4IR::Temp *targetTemp)
+{
+ Value v = Value::fromString(identifier(str));
+ _as->storeValue(v, targetTemp);
+}
+
+void InstructionSelection::loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp)
+{
+ Value v = Value::fromObject(engine()->newRegExpObject(*sourceRegexp->value,
+ sourceRegexp->flags));
+ _vmFunction->generatedValues.append(v);
+ _as->storeValue(v, targetTemp);
+}
+
+void InstructionSelection::getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp)
+{
+ String *propertyName = identifier(*name->id);
+ if (useFastLookups && name->global) {
+ uint index = addGlobalLookup(propertyName);
+ generateLookupCall(index, offsetof(QV4::Lookup, globalGetter), Assembler::ContextRegister, Assembler::PointerToValue(temp));
+ return;
+ }
+ generateFunctionCall(Assembler::Void, __qmljs_get_activation_property, Assembler::ContextRegister, Assembler::PointerToValue(temp), propertyName);
+}
+
+void InstructionSelection::setActivationProperty(V4IR::Temp *source, const QString &targetName)
+{
+ String *propertyName = identifier(targetName);
+ generateFunctionCall(Assembler::Void, __qmljs_set_activation_property,
+ Assembler::ContextRegister, propertyName, Assembler::Reference(source));
+}
+
+void InstructionSelection::initClosure(V4IR::Closure *closure, V4IR::Temp *target)
+{
+ QV4::Function *vmFunc = vmFunction(closure->value);
+ assert(vmFunc);
+ generateFunctionCall(Assembler::Void, __qmljs_init_closure, Assembler::ContextRegister, Assembler::PointerToValue(target), Assembler::TrustedImmPtr(vmFunc));
+}
+
+void InstructionSelection::getProperty(V4IR::Temp *base, const QString &name, V4IR::Temp *target)
+{
+ if (useFastLookups) {
+ QV4::String *s = identifier(name);
+ uint index = addLookup(s);
+ generateLookupCall(index, offsetof(QV4::Lookup, getter), Assembler::PointerToValue(target),
+ Assembler::Reference(base));
+ } else {
+ generateFunctionCall(Assembler::Void, __qmljs_get_property, Assembler::ContextRegister, Assembler::PointerToValue(target),
+ Assembler::Reference(base), identifier(name));
+ }
+}
+
+void InstructionSelection::setProperty(V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName)
+{
+ if (useFastLookups) {
+ QV4::String *s = identifier(targetName);
+ uint index = addSetterLookup(s);
+ generateLookupCall(index, offsetof(QV4::Lookup, setter), Assembler::Reference(targetBase), Assembler::Reference(source));
+ } else {
+ generateFunctionCall(Assembler::Void, __qmljs_set_property, Assembler::ContextRegister,
+ Assembler::Reference(targetBase),
+ identifier(targetName), Assembler::Reference(source));
+ }
+}
+
+void InstructionSelection::getElement(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *target)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_get_element, Assembler::ContextRegister,
+ Assembler::PointerToValue(target), Assembler::Reference(base),
+ Assembler::Reference(index));
+}
+
+void InstructionSelection::setElement(V4IR::Temp *source, V4IR::Temp *targetBase, V4IR::Temp *targetIndex)
+{
+ generateFunctionCall(Assembler::Void, __qmljs_set_element, Assembler::ContextRegister,
+ Assembler::Reference(targetBase), Assembler::Reference(targetIndex),
+ Assembler::Reference(source));
+}
+
+void InstructionSelection::copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp)
+{
+ _as->copyValue(targetTemp, sourceTemp);
+}
+
+#define setOp(op, opName, operation) \
+ do { op = operation; opName = isel_stringIfy(operation); } while (0)
+
+void InstructionSelection::unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp)
+{
+ UnaryOpName op = 0;
+ const char *opName = 0;
+ switch (oper) {
+ case V4IR::OpIfTrue: assert(!"unreachable"); break;
+ case V4IR::OpNot: setOp(op, opName, __qmljs_not); break;
+ case V4IR::OpUMinus: setOp(op, opName, __qmljs_uminus); break;
+ case V4IR::OpUPlus: setOp(op, opName, __qmljs_uplus); break;
+ case V4IR::OpCompl: setOp(op, opName, __qmljs_compl); break;
+ case V4IR::OpIncrement: setOp(op, opName, __qmljs_increment); break;
+ case V4IR::OpDecrement: setOp(op, opName, __qmljs_decrement); break;
+ default: assert(!"unreachable"); break;
+ } // switch
+
+ if (op)
+ _as->generateFunctionCallImp(Assembler::Void, opName, op, Assembler::PointerToValue(targetTemp),
+ Assembler::Reference(sourceTemp));
+}
+
+void InstructionSelection::binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target)
+{
+ Q_ASSERT(leftSource->asTemp() && rightSource->asTemp());
+ _as->generateBinOp(oper, target, leftSource->asTemp(), rightSource->asTemp());
+}
+
+void InstructionSelection::inplaceNameOp(V4IR::AluOp oper, V4IR::Temp *rightSource, const QString &targetName)
+{
+ InplaceBinOpName op = 0;
+ const char *opName = 0;
+ switch (oper) {
+ case V4IR::OpBitAnd: setOp(op, opName, __qmljs_inplace_bit_and_name); break;
+ case V4IR::OpBitOr: setOp(op, opName, __qmljs_inplace_bit_or_name); break;
+ case V4IR::OpBitXor: setOp(op, opName, __qmljs_inplace_bit_xor_name); break;
+ case V4IR::OpAdd: setOp(op, opName, __qmljs_inplace_add_name); break;
+ case V4IR::OpSub: setOp(op, opName, __qmljs_inplace_sub_name); break;
+ case V4IR::OpMul: setOp(op, opName, __qmljs_inplace_mul_name); break;
+ case V4IR::OpDiv: setOp(op, opName, __qmljs_inplace_div_name); break;
+ case V4IR::OpMod: setOp(op, opName, __qmljs_inplace_mod_name); break;
+ case V4IR::OpLShift: setOp(op, opName, __qmljs_inplace_shl_name); break;
+ case V4IR::OpRShift: setOp(op, opName, __qmljs_inplace_shr_name); break;
+ case V4IR::OpURShift: setOp(op, opName, __qmljs_inplace_ushr_name); break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+ if (op) {
+ _as->generateFunctionCallImp(Assembler::Void, opName, op, Assembler::ContextRegister,
+ identifier(targetName), Assembler::Reference(rightSource));
+ }
+}
+
+void InstructionSelection::inplaceElementOp(V4IR::AluOp oper, V4IR::Temp *source, V4IR::Temp *targetBaseTemp, V4IR::Temp *targetIndexTemp)
+{
+ InplaceBinOpElement op = 0;
+ const char *opName = 0;
+ switch (oper) {
+ case V4IR::OpBitAnd: setOp(op, opName, __qmljs_inplace_bit_and_element); break;
+ case V4IR::OpBitOr: setOp(op, opName, __qmljs_inplace_bit_or_element); break;
+ case V4IR::OpBitXor: setOp(op, opName, __qmljs_inplace_bit_xor_element); break;
+ case V4IR::OpAdd: setOp(op, opName, __qmljs_inplace_add_element); break;
+ case V4IR::OpSub: setOp(op, opName, __qmljs_inplace_sub_element); break;
+ case V4IR::OpMul: setOp(op, opName, __qmljs_inplace_mul_element); break;
+ case V4IR::OpDiv: setOp(op, opName, __qmljs_inplace_div_element); break;
+ case V4IR::OpMod: setOp(op, opName, __qmljs_inplace_mod_element); break;
+ case V4IR::OpLShift: setOp(op, opName, __qmljs_inplace_shl_element); break;
+ case V4IR::OpRShift: setOp(op, opName, __qmljs_inplace_shr_element); break;
+ case V4IR::OpURShift: setOp(op, opName, __qmljs_inplace_ushr_element); break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+
+ if (op) {
+ _as->generateFunctionCallImp(Assembler::Void, opName, op, Assembler::ContextRegister,
+ Assembler::Reference(targetBaseTemp), Assembler::Reference(targetIndexTemp),
+ Assembler::Reference(source));
+ }
+}
+
+void InstructionSelection::inplaceMemberOp(V4IR::AluOp oper, V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName)
+{
+ InplaceBinOpMember op = 0;
+ const char *opName = 0;
+ switch (oper) {
+ case V4IR::OpBitAnd: setOp(op, opName, __qmljs_inplace_bit_and_member); break;
+ case V4IR::OpBitOr: setOp(op, opName, __qmljs_inplace_bit_or_member); break;
+ case V4IR::OpBitXor: setOp(op, opName, __qmljs_inplace_bit_xor_member); break;
+ case V4IR::OpAdd: setOp(op, opName, __qmljs_inplace_add_member); break;
+ case V4IR::OpSub: setOp(op, opName, __qmljs_inplace_sub_member); break;
+ case V4IR::OpMul: setOp(op, opName, __qmljs_inplace_mul_member); break;
+ case V4IR::OpDiv: setOp(op, opName, __qmljs_inplace_div_member); break;
+ case V4IR::OpMod: setOp(op, opName, __qmljs_inplace_mod_member); break;
+ case V4IR::OpLShift: setOp(op, opName, __qmljs_inplace_shl_member); break;
+ case V4IR::OpRShift: setOp(op, opName, __qmljs_inplace_shr_member); break;
+ case V4IR::OpURShift: setOp(op, opName, __qmljs_inplace_ushr_member); break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+
+ if (op) {
+ String* member = identifier(targetName);
+ _as->generateFunctionCallImp(Assembler::Void, opName, op, Assembler::ContextRegister,
+ Assembler::Reference(targetBase), identifier(targetName),
+ Assembler::Reference(source));
+ }
+}
+
+void InstructionSelection::callProperty(V4IR::Temp *base, const QString &name,
+ V4IR::ExprList *args, V4IR::Temp *result)
+{
+ assert(base != 0);
+
+ int argc = prepareVariableArguments(args);
+ QV4::String *s = identifier(name);
+
+ if (useFastLookups) {
+ uint index = addLookup(s);
+ generateFunctionCall(Assembler::Void, __qmljs_call_property_lookup,
+ Assembler::ContextRegister, Assembler::PointerToValue(result),
+ Assembler::Reference(base), Assembler::TrustedImm32(index),
+ baseAddressForCallArguments(),
+ Assembler::TrustedImm32(argc));
+ } else {
+ generateFunctionCall(Assembler::Void, __qmljs_call_property,
+ Assembler::ContextRegister, Assembler::PointerToValue(result),
+ Assembler::Reference(base), s,
+ baseAddressForCallArguments(),
+ Assembler::TrustedImm32(argc));
+ }
+}
+
+void InstructionSelection::callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ assert(base != 0);
+
+ int argc = prepareVariableArguments(args);
+ generateFunctionCall(Assembler::Void, __qmljs_call_element,
+ Assembler::ContextRegister, Assembler::PointerToValue(result),
+ Assembler::Reference(base), Assembler::Reference(index),
+ baseAddressForCallArguments(),
+ Assembler::TrustedImm32(argc));
+}
+
+void InstructionSelection::convertType(V4IR::Temp *source, V4IR::Temp *target)
+{
+ // FIXME: do something more useful with this info
+ copyValue(source, target);
+}
+
+String *InstructionSelection::identifier(const QString &s)
+{
+ String *str = engine()->newIdentifier(s);
+ _vmFunction->identifiers.append(str);
+ return str;
+}
+
+void InstructionSelection::constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ assert(func != 0);
+
+ if (useFastLookups && func->global) {
+ int argc = prepareVariableArguments(args);
+ QV4::String *s = identifier(*func->id);
+
+ uint index = addGlobalLookup(s);
+ generateFunctionCall(Assembler::Void, __qmljs_construct_global_lookup,
+ Assembler::ContextRegister, Assembler::PointerToValue(result),
+ Assembler::TrustedImm32(index),
+ baseAddressForCallArguments(),
+ Assembler::TrustedImm32(argc));
+ return;
+ }
+
+ callRuntimeMethod(result, __qmljs_construct_activation_property, func, args);
+}
+
+void InstructionSelection::constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ int argc = prepareVariableArguments(args);
+ generateFunctionCall(Assembler::Void, __qmljs_construct_property, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::Reference(base), identifier(name), baseAddressForCallArguments(), Assembler::TrustedImm32(argc));
+}
+
+void InstructionSelection::constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result)
+{
+ assert(value != 0);
+
+ int argc = prepareVariableArguments(args);
+ generateFunctionCall(Assembler::Void, __qmljs_construct_value, Assembler::ContextRegister,
+ Assembler::PointerToValue(result), Assembler::Reference(value), baseAddressForCallArguments(), Assembler::TrustedImm32(argc));
+}
+
+void InstructionSelection::visitJump(V4IR::Jump *s)
+{
+ _as->jumpToBlock(_block, s->target);
+}
+
+void InstructionSelection::visitCJump(V4IR::CJump *s)
+{
+ if (V4IR::Temp *t = s->cond->asTemp()) {
+ Address temp = _as->loadTempAddress(Assembler::ScratchRegister, t);
+ Address tag = temp;
+ tag.offset += offsetof(QV4::Value, tag);
+ Assembler::Jump booleanConversion = _as->branch32(Assembler::NotEqual, tag, Assembler::TrustedImm32(QV4::Value::Boolean_Type));
+
+ Address data = temp;
+ data.offset += offsetof(QV4::Value, int_32);
+ _as->load32(data, Assembler::ReturnValueRegister);
+ Assembler::Jump testBoolean = _as->jump();
+
+ booleanConversion.link(_as);
+ {
+ generateFunctionCall(Assembler::ReturnValueRegister, __qmljs_to_boolean, Assembler::Reference(t));
+ }
+
+ testBoolean.link(_as);
+ Assembler::Jump target = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister, Assembler::TrustedImm32(0));
+ _as->addPatch(s->iftrue, target);
+
+ _as->jumpToBlock(_block, s->iffalse);
+ return;
+ } else if (V4IR::Binop *b = s->cond->asBinop()) {
+ if (b->left->asTemp() && b->right->asTemp()) {
+ CmpOp op = 0;
+ const char *opName = 0;
+ switch (b->op) {
+ default: Q_UNREACHABLE(); assert(!"todo"); break;
+ case V4IR::OpGt: setOp(op, opName, __qmljs_cmp_gt); break;
+ case V4IR::OpLt: setOp(op, opName, __qmljs_cmp_lt); break;
+ case V4IR::OpGe: setOp(op, opName, __qmljs_cmp_ge); break;
+ case V4IR::OpLe: setOp(op, opName, __qmljs_cmp_le); break;
+ case V4IR::OpEqual: setOp(op, opName, __qmljs_cmp_eq); break;
+ case V4IR::OpNotEqual: setOp(op, opName, __qmljs_cmp_ne); break;
+ case V4IR::OpStrictEqual: setOp(op, opName, __qmljs_cmp_se); break;
+ case V4IR::OpStrictNotEqual: setOp(op, opName, __qmljs_cmp_sne); break;
+ case V4IR::OpInstanceof: setOp(op, opName, __qmljs_cmp_instanceof); break;
+ case V4IR::OpIn: setOp(op, opName, __qmljs_cmp_in); break;
+ } // switch
+
+ _as->generateFunctionCallImp(Assembler::ReturnValueRegister, opName, op, Assembler::ContextRegister,
+ Assembler::Reference(b->left->asTemp()),
+ Assembler::Reference(b->right->asTemp()));
+
+ Assembler::Jump target = _as->branch32(Assembler::NotEqual, Assembler::ReturnValueRegister, Assembler::TrustedImm32(0));
+ _as->addPatch(s->iftrue, target);
+
+ _as->jumpToBlock(_block, s->iffalse);
+ return;
+ } else {
+ assert(!"wip");
+ }
+ Q_UNIMPLEMENTED();
+ }
+ Q_UNIMPLEMENTED();
+ assert(!"TODO");
+}
+
+void InstructionSelection::visitRet(V4IR::Ret *s)
+{
+ if (V4IR::Temp *t = s->expr->asTemp()) {
+#if defined(RETURN_VALUE_IN_REGISTER)
+#if CPU(X86)
+ Address addr = _as->loadTempAddress(Assembler::ScratchRegister, t);
+ _as->load32(addr, JSC::X86Registers::eax);
+ addr.offset += 4;
+ _as->load32(addr, JSC::X86Registers::edx);
+#else
+ _as->copyValue(Assembler::ReturnValueRegister, t);
+#endif
+#else
+ _as->loadPtr(addressForArgument(0), Assembler::ReturnValueRegister);
+ _as->copyValue(Address(Assembler::ReturnValueRegister, 0), t);
+#endif
+ } else if (V4IR::Const *c = s->expr->asConst()) {
+ _as->copyValue(Assembler::ReturnValueRegister, c);
+ } else {
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+ Q_UNUSED(s);
+ }
+
+ _as->leaveStandardStackFrame(_locals);
+#if !defined(ARGUMENTS_IN_REGISTERS) && !defined(RETURN_VALUE_IN_REGISTER)
+ // Emulate ret(n) instruction
+ // Pop off return address into scratch register ...
+ _as->pop(Assembler::ScratchRegister);
+ // ... and overwrite the invisible argument with
+ // the return address.
+ _as->poke(Assembler::ScratchRegister);
+#endif
+ _as->ret();
+}
+
+int InstructionSelection::prepareVariableArguments(V4IR::ExprList* args)
+{
+ int argc = 0;
+ for (V4IR::ExprList *it = args; it; it = it->next) {
+ ++argc;
+ }
+
+ int i = 0;
+ for (V4IR::ExprList *it = args; it; it = it->next, ++i) {
+// V4IR::Temp *arg = it->expr->asTemp();
+// assert(arg != 0);
+ _as->copyValue(argumentAddressForCall(i), it->expr);
+ }
+
+ return argc;
+}
+
+void InstructionSelection::callRuntimeMethodImp(V4IR::Temp *result, const char* name, ActivationMethod method, V4IR::Expr *base, V4IR::ExprList *args)
+{
+ V4IR::Name *baseName = base->asName();
+ assert(baseName != 0);
+
+ int argc = prepareVariableArguments(args);
+ _as->generateFunctionCallImp(Assembler::Void, name, method, Assembler::ContextRegister, Assembler::PointerToValue(result),
+ identifier(*baseName->id), baseAddressForCallArguments(),
+ Assembler::TrustedImm32(argc));
+}
+
+
+uint InstructionSelection::addLookup(QV4::String *name)
+{
+ uint index = (uint)_lookups.size();
+ QV4::Lookup l;
+ l.getter = Lookup::getterGeneric;
+ for (int i = 0; i < Lookup::Size; ++i)
+ l.classList[i] = 0;
+ l.level = -1;
+ l.index = UINT_MAX;
+ l.name = name;
+ _lookups.append(l);
+ return index;
+}
+
+uint InstructionSelection::addSetterLookup(QV4::String *name)
+{
+ uint index = (uint)_lookups.size();
+ QV4::Lookup l;
+ l.setter = Lookup::setterGeneric;
+ for (int i = 0; i < Lookup::Size; ++i)
+ l.classList[i] = 0;
+ l.level = -1;
+ l.index = UINT_MAX;
+ l.name = name;
+ _lookups.append(l);
+ return index;
+}
+
+uint InstructionSelection::addGlobalLookup(QV4::String *name)
+{
+ uint index = (uint)_lookups.size();
+ QV4::Lookup l;
+ l.globalGetter = Lookup::globalGetterGeneric;
+ for (int i = 0; i < Lookup::Size; ++i)
+ l.classList[i] = 0;
+ l.level = -1;
+ l.index = UINT_MAX;
+ l.name = name;
+ _lookups.append(l);
+ return index;
+}
diff --git a/src/qml/qml/v4/qv4isel_masm_p.h b/src/qml/qml/v4/qv4isel_masm_p.h
new file mode 100644
index 0000000000..b53b0e5c74
--- /dev/null
+++ b/src/qml/qml/v4/qv4isel_masm_p.h
@@ -0,0 +1,938 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4ISEL_MASM_P_H
+#define QV4ISEL_MASM_P_H
+
+#include "qv4global_p.h"
+#include "qv4jsir_p.h"
+#include "qv4isel_p.h"
+#include "qv4isel_util_p.h"
+#include "qv4object_p.h"
+#include "qv4runtime_p.h"
+#include "qv4lookup_p.h"
+
+#include <QtCore/QHash>
+#include <config.h>
+#include <wtf/Vector.h>
+#include <assembler/MacroAssembler.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+namespace MASM {
+
+class Assembler : public JSC::MacroAssembler
+{
+public:
+ Assembler(V4IR::Function* function, QV4::Function *vmFunction, QV4::ExecutionEngine *engine);
+#if CPU(X86)
+
+#undef VALUE_FITS_IN_REGISTER
+#undef ARGUMENTS_IN_REGISTERS
+
+#if OS(WINDOWS)
+ // Returned in EAX:EDX pair
+#define RETURN_VALUE_IN_REGISTER
+#else
+#undef RETURN_VALUE_IN_REGISTER
+#endif
+
+#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
+
+ static const RegisterID StackFrameRegister = JSC::X86Registers::ebp;
+ static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const RegisterID LocalsRegister = JSC::X86Registers::edi;
+ static const RegisterID ContextRegister = JSC::X86Registers::esi;
+ static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID ScratchRegister = JSC::X86Registers::ecx;
+ static const RegisterID IntegerOpRegister = JSC::X86Registers::eax;
+ static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+
+ static const int RegisterSize = 4;
+
+ static const int RegisterArgumentCount = 0;
+ static RegisterID registerForArgument(int)
+ {
+ assert(false);
+ // Not reached.
+ return JSC::X86Registers::eax;
+ }
+
+ // Return address is pushed onto stack by the CPU.
+ static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize;
+ static const int StackShadowSpace = 0;
+ inline void platformEnterStandardStackFrame() {}
+ inline void platformLeaveStandardStackFrame() {}
+#elif CPU(X86_64)
+
+#define VALUE_FITS_IN_REGISTER
+#define ARGUMENTS_IN_REGISTERS
+#define RETURN_VALUE_IN_REGISTER
+#define HAVE_ALU_OPS_WITH_MEM_OPERAND 1
+
+ static const RegisterID StackFrameRegister = JSC::X86Registers::ebp;
+ static const RegisterID StackPointerRegister = JSC::X86Registers::esp;
+ static const RegisterID LocalsRegister = JSC::X86Registers::r12;
+ static const RegisterID ContextRegister = JSC::X86Registers::r14;
+ static const RegisterID ReturnValueRegister = JSC::X86Registers::eax;
+ static const RegisterID ScratchRegister = JSC::X86Registers::r10;
+ static const RegisterID IntegerOpRegister = JSC::X86Registers::eax;
+ static const FPRegisterID FPGpr0 = JSC::X86Registers::xmm0;
+
+ static const int RegisterSize = 8;
+
+#if OS(WINDOWS)
+ static const int RegisterArgumentCount = 4;
+ static RegisterID registerForArgument(int index)
+ {
+ static RegisterID regs[RegisterArgumentCount] = {
+ JSC::X86Registers::ecx,
+ JSC::X86Registers::edx,
+ JSC::X86Registers::r8,
+ JSC::X86Registers::r9
+ };
+ assert(index >= 0 && index < RegisterArgumentCount);
+ return regs[index];
+ };
+ static const int StackShadowSpace = 32;
+#else // Unix
+ static const int RegisterArgumentCount = 6;
+ static RegisterID registerForArgument(int index)
+ {
+ static RegisterID regs[RegisterArgumentCount] = {
+ JSC::X86Registers::edi,
+ JSC::X86Registers::esi,
+ JSC::X86Registers::edx,
+ JSC::X86Registers::ecx,
+ JSC::X86Registers::r8,
+ JSC::X86Registers::r9
+ };
+ assert(index >= 0 && index < RegisterArgumentCount);
+ return regs[index];
+ };
+ static const int StackShadowSpace = 0;
+#endif
+
+ // Return address is pushed onto stack by the CPU.
+ static const int StackSpaceAllocatedUponFunctionEntry = RegisterSize;
+ inline void platformEnterStandardStackFrame() {}
+ inline void platformLeaveStandardStackFrame() {}
+#elif CPU(ARM)
+
+#undef VALUE_FITS_IN_REGISTER
+#define ARGUMENTS_IN_REGISTERS
+#undef RETURN_VALUE_IN_REGISTER
+#undef HAVE_ALU_OPS_WITH_MEM_OPERAND
+
+ static const RegisterID StackFrameRegister = JSC::ARMRegisters::r4;
+ static const RegisterID StackPointerRegister = JSC::ARMRegisters::sp;
+ static const RegisterID LocalsRegister = JSC::ARMRegisters::r7;
+ static const RegisterID ContextRegister = JSC::ARMRegisters::r5;
+ static const RegisterID ReturnValueRegister = JSC::ARMRegisters::r0;
+ static const RegisterID ScratchRegister = JSC::ARMRegisters::r6;
+ static const RegisterID IntegerOpRegister = JSC::ARMRegisters::r0;
+ static const FPRegisterID FPGpr0 = JSC::ARMRegisters::d0;
+
+ static const int RegisterSize = 4;
+
+ static const RegisterID RegisterArgument1 = JSC::ARMRegisters::r0;
+ static const RegisterID RegisterArgument2 = JSC::ARMRegisters::r1;
+ static const RegisterID RegisterArgument3 = JSC::ARMRegisters::r2;
+ static const RegisterID RegisterArgument4 = JSC::ARMRegisters::r3;
+
+ static const int RegisterArgumentCount = 4;
+ static RegisterID registerForArgument(int index)
+ {
+ assert(index >= 0 && index < RegisterArgumentCount);
+ return static_cast<RegisterID>(JSC::ARMRegisters::r0 + index);
+ };
+
+ // Registers saved in platformEnterStandardStackFrame below.
+ static const int StackSpaceAllocatedUponFunctionEntry = 5 * RegisterSize;
+ static const int StackShadowSpace = 0;
+ inline void platformEnterStandardStackFrame()
+ {
+ // Move the register arguments onto the stack as if they were
+ // pushed by the caller, just like on ia32. This gives us consistent
+ // access to the parameters if we need to.
+ push(JSC::ARMRegisters::r3);
+ push(JSC::ARMRegisters::r2);
+ push(JSC::ARMRegisters::r1);
+ push(JSC::ARMRegisters::r0);
+ push(JSC::ARMRegisters::lr);
+ }
+ inline void platformLeaveStandardStackFrame()
+ {
+ pop(JSC::ARMRegisters::lr);
+ addPtr(TrustedImm32(4 * RegisterSize), StackPointerRegister);
+ }
+#else
+#error The JIT needs to be ported to this platform.
+#endif
+ static const int calleeSavedRegisterCount;
+
+#if CPU(X86) || CPU(X86_64)
+ static const int StackAlignment = 16;
+#elif CPU(ARM)
+ // Per AAPCS
+ static const int StackAlignment = 8;
+#else
+#error Stack alignment unknown for this platform.
+#endif
+
+ // Explicit type to allow distinguishing between
+ // pushing an address itself or the value it points
+ // to onto the stack when calling functions.
+ struct Pointer : public Address
+ {
+ explicit Pointer(const Address& addr)
+ : Address(addr)
+ {}
+ explicit Pointer(RegisterID reg, int32_t offset)
+ : Address(reg, offset)
+ {}
+ };
+
+ struct VoidType { VoidType() {} };
+ static const VoidType Void;
+
+
+ typedef JSC::FunctionPtr FunctionPtr;
+
+ struct CallToLink {
+ Call call;
+ FunctionPtr externalFunction;
+ const char* functionName;
+ };
+ struct PointerToValue {
+ PointerToValue(V4IR::Temp *value) : value(value) {}
+ V4IR::Temp *value;
+ };
+ struct Reference {
+ Reference(V4IR::Temp *value) : value(value) {}
+ V4IR::Temp *value;
+ };
+
+ struct ReentryBlock {
+ ReentryBlock(V4IR::BasicBlock *b) : block(b) {}
+ V4IR::BasicBlock *block;
+ };
+
+ void callAbsolute(const char* functionName, FunctionPtr function) {
+ CallToLink ctl;
+ ctl.call = call();
+ ctl.externalFunction = function;
+ ctl.functionName = functionName;
+ _callsToLink.append(ctl);
+ }
+
+ void callAbsolute(const char* /*functionName*/, Address addr) {
+ call(addr);
+ }
+
+ void registerBlock(V4IR::BasicBlock*, V4IR::BasicBlock *nextBlock);
+ void jumpToBlock(V4IR::BasicBlock* current, V4IR::BasicBlock *target);
+ void addPatch(V4IR::BasicBlock* targetBlock, Jump targetJump);
+ void addPatch(DataLabelPtr patch, Label target);
+ void addPatch(DataLabelPtr patch, V4IR::BasicBlock *target);
+
+ Pointer loadTempAddress(RegisterID reg, V4IR::Temp *t);
+
+ void loadArgumentInRegister(RegisterID source, RegisterID dest)
+ {
+ move(source, dest);
+ }
+
+ void loadArgumentInRegister(TrustedImmPtr ptr, RegisterID dest)
+ {
+ move(TrustedImmPtr(ptr), dest);
+ }
+
+ void loadArgumentInRegister(const Pointer& ptr, RegisterID dest)
+ {
+ addPtr(TrustedImm32(ptr.offset), ptr.base, dest);
+ }
+
+ void loadArgumentInRegister(PointerToValue temp, RegisterID dest)
+ {
+ if (!temp.value) {
+ loadArgumentInRegister(TrustedImmPtr(0), dest);
+ } else {
+ Pointer addr = loadTempAddress(dest, temp.value);
+ loadArgumentInRegister(addr, dest);
+ }
+ }
+
+ void loadArgumentInRegister(Reference temp, RegisterID dest)
+ {
+ assert(temp.value);
+ Pointer addr = loadTempAddress(dest, temp.value);
+ loadArgumentInRegister(addr, dest);
+ }
+
+ void loadArgumentInRegister(ReentryBlock block, RegisterID dest)
+ {
+ assert(block.block);
+ DataLabelPtr patch = moveWithPatch(TrustedImmPtr(0), dest);
+ addPatch(patch, block.block);
+ }
+
+#ifdef VALUE_FITS_IN_REGISTER
+ void loadArgumentInRegister(V4IR::Temp* temp, RegisterID dest)
+ {
+ if (!temp) {
+ QV4::Value undefined = QV4::Value::undefinedValue();
+ move(TrustedImm64(undefined.val), dest);
+ } else {
+ Pointer addr = loadTempAddress(dest, temp);
+ load64(addr, dest);
+ }
+ }
+
+ void loadArgumentInRegister(V4IR::Const* c, RegisterID dest)
+ {
+ QV4::Value v = convertToValue(c);
+ move(TrustedImm64(v.val), dest);
+ }
+
+ void loadArgumentInRegister(V4IR::Expr* expr, RegisterID dest)
+ {
+ if (!expr) {
+ QV4::Value undefined = QV4::Value::undefinedValue();
+ move(TrustedImm64(undefined.val), dest);
+ } else if (expr->asTemp()){
+ loadArgumentInRegister(expr->asTemp(), dest);
+ } else if (expr->asConst()) {
+ loadArgumentInRegister(expr->asConst(), dest);
+ } else {
+ assert(!"unimplemented expression type in loadArgument");
+ }
+ }
+#else
+ void loadArgumentInRegister(V4IR::Expr*, RegisterID)
+ {
+ assert(!"unimplemented: expression in loadArgument");
+ }
+#endif
+
+ void loadArgumentInRegister(QV4::String* string, RegisterID dest)
+ {
+ loadArgumentInRegister(TrustedImmPtr(string), dest);
+ }
+
+ void loadArgumentInRegister(TrustedImm32 imm32, RegisterID dest)
+ {
+ xorPtr(dest, dest);
+ if (imm32.m_value)
+ move(imm32, dest);
+ }
+
+ void storeReturnValue(RegisterID dest)
+ {
+ move(ReturnValueRegister, dest);
+ }
+
+#ifdef VALUE_FITS_IN_REGISTER
+ void storeReturnValue(const Pointer &dest)
+ {
+ store64(ReturnValueRegister, dest);
+ }
+
+ void storeReturnValue(V4IR::Temp *temp)
+ {
+ if (!temp)
+ return;
+ Pointer addr = loadTempAddress(ScratchRegister, temp);
+ storeReturnValue(addr);
+ }
+#endif
+
+ void storeReturnValue(VoidType)
+ {
+ }
+
+ template <int StackSlot>
+ void loadArgumentOnStack(RegisterID reg)
+ {
+ poke(reg, StackSlot);
+ }
+
+ template <int StackSlot>
+ void loadArgumentOnStack(TrustedImm32 value)
+ {
+ poke(value, StackSlot);
+ }
+
+ template <int StackSlot>
+ void loadArgumentOnStack(const Pointer& ptr)
+ {
+ addPtr(TrustedImm32(ptr.offset), ptr.base, ScratchRegister);
+ poke(ScratchRegister, StackSlot);
+ }
+
+ template <int StackSlot>
+ void loadArgumentOnStack(PointerToValue temp)
+ {
+ if (temp.value) {
+ Pointer ptr = loadTempAddress(ScratchRegister, temp.value);
+ loadArgumentOnStack<StackSlot>(ptr);
+ } else {
+ poke(TrustedImmPtr(0), StackSlot);
+ }
+ }
+
+ template <int StackSlot>
+ void loadArgumentOnStack(Reference temp)
+ {
+ assert (temp.value);
+
+ Pointer ptr = loadTempAddress(ScratchRegister, temp.value);
+ loadArgumentOnStack<StackSlot>(ptr);
+ }
+
+ template <int StackSlot>
+ void loadArgumentOnStack(ReentryBlock block)
+ {
+ assert(block.block);
+ DataLabelPtr patch = moveWithPatch(TrustedImmPtr(0), ScratchRegister);
+ poke(ScratchRegister, StackSlot);
+ addPatch(patch, block.block);
+ }
+
+ template <int StackSlot>
+ void loadArgumentOnStack(TrustedImmPtr ptr)
+ {
+ move(TrustedImmPtr(ptr), ScratchRegister);
+ poke(ScratchRegister, StackSlot);
+ }
+
+ template <int StackSlot>
+ void loadArgumentOnStack(QV4::String* name)
+ {
+ poke(TrustedImmPtr(name), StackSlot);
+ }
+
+ using JSC::MacroAssembler::loadDouble;
+ void loadDouble(V4IR::Temp* temp, FPRegisterID dest)
+ {
+ Pointer ptr = loadTempAddress(ScratchRegister, temp);
+ loadDouble(ptr, dest);
+ }
+
+ using JSC::MacroAssembler::storeDouble;
+ void storeDouble(FPRegisterID source, V4IR::Temp* temp)
+ {
+ Pointer ptr = loadTempAddress(ScratchRegister, temp);
+ storeDouble(source, ptr);
+ }
+
+ template <typename Result, typename Source>
+ void copyValue(Result result, Source source);
+ template <typename Result>
+ void copyValue(Result result, V4IR::Expr* source);
+
+ void storeValue(QV4::Value value, Address destination)
+ {
+#ifdef VALUE_FITS_IN_REGISTER
+ store64(TrustedImm64(value.val), destination);
+#else
+ store32(TrustedImm32(value.int_32), destination);
+ destination.offset += 4;
+ store32(TrustedImm32(value.tag), destination);
+#endif
+ }
+
+ void storeValue(QV4::Value value, V4IR::Temp* temp);
+
+ static int calculateStackFrameSize(int locals);
+ void enterStandardStackFrame(int locals);
+ void leaveStandardStackFrame(int locals);
+
+ template <int argumentNumber, typename T>
+ void loadArgumentOnStackOrRegister(const T &value)
+ {
+ if (argumentNumber < RegisterArgumentCount)
+ loadArgumentInRegister(value, registerForArgument(argumentNumber));
+ else
+#if OS(WINDOWS) && CPU(X86_64)
+ loadArgumentOnStack<argumentNumber>(value);
+#else // Sanity:
+ loadArgumentOnStack<argumentNumber - RegisterArgumentCount>(value);
+#endif
+ }
+
+ template <int argumentNumber>
+ void loadArgumentOnStackOrRegister(const VoidType &value)
+ {
+ Q_UNUSED(value);
+ }
+
+ template <bool selectFirst, int First, int Second>
+ struct Select
+ {
+ enum { Chosen = First };
+ };
+
+ template <int First, int Second>
+ struct Select<false, First, Second>
+ {
+ enum { Chosen = Second };
+ };
+
+ template <int ArgumentIndex, typename Parameter>
+ struct SizeOnStack
+ {
+ enum { Size = Select<ArgumentIndex >= RegisterArgumentCount, QT_POINTER_SIZE, 0>::Chosen };
+ };
+
+ template <int ArgumentIndex>
+ struct SizeOnStack<ArgumentIndex, VoidType>
+ {
+ enum { Size = 0 };
+ };
+
+
+ template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5, typename Arg6>
+ void generateFunctionCallImp(ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5, Arg6 arg6)
+ {
+ int stackSpaceNeeded = SizeOnStack<0, Arg1>::Size
+ + SizeOnStack<1, Arg2>::Size
+ + SizeOnStack<2, Arg3>::Size
+ + SizeOnStack<3, Arg4>::Size
+ + SizeOnStack<4, Arg5>::Size
+ + SizeOnStack<5, Arg6>::Size
+ + StackShadowSpace;
+
+ if (stackSpaceNeeded) {
+ stackSpaceNeeded = WTF::roundUpToMultipleOf(StackAlignment, stackSpaceNeeded);
+ sub32(TrustedImm32(stackSpaceNeeded), StackPointerRegister);
+ }
+
+ loadArgumentOnStackOrRegister<5>(arg6);
+ loadArgumentOnStackOrRegister<4>(arg5);
+ loadArgumentOnStackOrRegister<3>(arg4);
+ loadArgumentOnStackOrRegister<2>(arg3);
+ loadArgumentOnStackOrRegister<1>(arg2);
+ loadArgumentOnStackOrRegister<0>(arg1);
+
+ callAbsolute(functionName, function);
+
+ storeReturnValue(r);
+
+ if (stackSpaceNeeded)
+ add32(TrustedImm32(stackSpaceNeeded), StackPointerRegister);
+ }
+
+ template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4, typename Arg5>
+ void generateFunctionCallImp(ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4, Arg5 arg5)
+ {
+ generateFunctionCallImp(r, functionName, function, arg1, arg2, arg3, arg4, arg5, VoidType());
+ }
+
+ template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
+ void generateFunctionCallImp(ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3, Arg4 arg4)
+ {
+ generateFunctionCallImp(r, functionName, function, arg1, arg2, arg3, arg4, VoidType());
+ }
+
+ template <typename ArgRet, typename Callable, typename Arg1, typename Arg2, typename Arg3>
+ void generateFunctionCallImp(ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2, Arg3 arg3)
+ {
+ generateFunctionCallImp(r, functionName, function, arg1, arg2, arg3, VoidType(), VoidType());
+ }
+
+ template <typename ArgRet, typename Callable, typename Arg1, typename Arg2>
+ void generateFunctionCallImp(ArgRet r, const char* functionName, Callable function, Arg1 arg1, Arg2 arg2)
+ {
+ generateFunctionCallImp(r, functionName, function, arg1, arg2, VoidType(), VoidType(), VoidType());
+ }
+
+ template <typename ArgRet, typename Callable, typename Arg1>
+ void generateFunctionCallImp(ArgRet r, const char* functionName, Callable function, Arg1 arg1)
+ {
+ generateFunctionCallImp(r, functionName, function, arg1, VoidType(), VoidType(), VoidType(), VoidType());
+ }
+
+ typedef Jump (Assembler::*MemRegBinOp)(Address, RegisterID);
+ typedef Jump (Assembler::*ImmRegBinOp)(TrustedImm32, RegisterID);
+
+ struct BinaryOperationInfo {
+ const char *name;
+ QV4::BinOp fallbackImplementation;
+ MemRegBinOp inlineMemRegOp;
+ ImmRegBinOp inlineImmRegOp;
+ };
+
+ static const BinaryOperationInfo binaryOperations[QQmlJS::V4IR::LastAluOp + 1];
+
+ void generateBinOp(V4IR::AluOp operation, V4IR::Temp* target, V4IR::Temp* left, V4IR::Temp* right);
+
+ Jump inline_add32(Address addr, RegisterID reg)
+ {
+#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
+ return branchAdd32(Overflow, addr, reg);
+#else
+ load32(addr, ScratchRegister);
+ return branchAdd32(Overflow, ScratchRegister, reg);
+#endif
+ }
+
+ Jump inline_add32(TrustedImm32 imm, RegisterID reg)
+ {
+ return branchAdd32(Overflow, imm, reg);
+ }
+
+ Jump inline_sub32(Address addr, RegisterID reg)
+ {
+#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
+ return branchSub32(Overflow, addr, reg);
+#else
+ load32(addr, ScratchRegister);
+ return branchSub32(Overflow, ScratchRegister, reg);
+#endif
+ }
+
+ Jump inline_sub32(TrustedImm32 imm, RegisterID reg)
+ {
+ return branchSub32(Overflow, imm, reg);
+ }
+
+ Jump inline_mul32(Address addr, RegisterID reg)
+ {
+#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
+ return branchMul32(Overflow, addr, reg);
+#else
+ load32(addr, ScratchRegister);
+ return branchMul32(Overflow, ScratchRegister, reg);
+#endif
+ }
+
+ Jump inline_mul32(TrustedImm32 imm, RegisterID reg)
+ {
+ return branchMul32(Overflow, imm, reg, reg);
+ }
+
+ Jump inline_shl32(Address addr, RegisterID reg)
+ {
+ load32(addr, ScratchRegister);
+ and32(TrustedImm32(0x1f), ScratchRegister);
+ lshift32(ScratchRegister, reg);
+ return Jump();
+ }
+
+ Jump inline_shl32(TrustedImm32 imm, RegisterID reg)
+ {
+ imm.m_value &= 0x1f;
+ lshift32(imm, reg);
+ return Jump();
+ }
+
+ Jump inline_shr32(Address addr, RegisterID reg)
+ {
+ load32(addr, ScratchRegister);
+ and32(TrustedImm32(0x1f), ScratchRegister);
+ rshift32(ScratchRegister, reg);
+ return Jump();
+ }
+
+ Jump inline_shr32(TrustedImm32 imm, RegisterID reg)
+ {
+ imm.m_value &= 0x1f;
+ rshift32(imm, reg);
+ return Jump();
+ }
+
+ Jump inline_ushr32(Address addr, RegisterID reg)
+ {
+ load32(addr, ScratchRegister);
+ and32(TrustedImm32(0x1f), ScratchRegister);
+ urshift32(ScratchRegister, reg);
+ return branchTest32(Signed, reg, reg);
+ }
+
+ Jump inline_ushr32(TrustedImm32 imm, RegisterID reg)
+ {
+ imm.m_value &= 0x1f;
+ urshift32(imm, reg);
+ return branchTest32(Signed, reg, reg);
+ }
+
+ Jump inline_and32(Address addr, RegisterID reg)
+ {
+#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
+ and32(addr, reg);
+#else
+ load32(addr, ScratchRegister);
+ and32(ScratchRegister, reg);
+#endif
+ return Jump();
+ }
+
+ Jump inline_and32(TrustedImm32 imm, RegisterID reg)
+ {
+ and32(imm, reg);
+ return Jump();
+ }
+
+ Jump inline_or32(Address addr, RegisterID reg)
+ {
+#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
+ or32(addr, reg);
+#else
+ load32(addr, ScratchRegister);
+ or32(ScratchRegister, reg);
+#endif
+ return Jump();
+ }
+
+ Jump inline_or32(TrustedImm32 imm, RegisterID reg)
+ {
+ or32(imm, reg);
+ return Jump();
+ }
+
+ Jump inline_xor32(Address addr, RegisterID reg)
+ {
+#if HAVE(ALU_OPS_WITH_MEM_OPERAND)
+ xor32(addr, reg);
+#else
+ load32(addr, ScratchRegister);
+ xor32(ScratchRegister, reg);
+#endif
+ return Jump();
+ }
+
+ Jump inline_xor32(TrustedImm32 imm, RegisterID reg)
+ {
+ xor32(imm, reg);
+ return Jump();
+ }
+
+ void link(QV4::Function *vmFunc);
+
+ void recordLineNumber(int lineNumber);
+
+private:
+ V4IR::Function *_function;
+ QV4::Function *_vmFunction;
+ QHash<V4IR::BasicBlock *, Label> _addrs;
+ QHash<V4IR::BasicBlock *, QVector<Jump> > _patches;
+ QList<CallToLink> _callsToLink;
+
+ struct DataLabelPatch {
+ DataLabelPtr dataLabel;
+ Label target;
+ };
+ QList<DataLabelPatch> _dataLabelPatches;
+
+ QHash<V4IR::BasicBlock *, QVector<DataLabelPtr> > _labelPatches;
+ V4IR::BasicBlock *_nextBlock;
+
+ QV4::ExecutionEngine *_engine;
+
+ struct CodeLineNumerMapping
+ {
+ Assembler::Label location;
+ int lineNumber;
+ };
+ QVector<CodeLineNumerMapping> codeLineNumberMappings;
+};
+
+class Q_QML_EXPORT InstructionSelection:
+ protected V4IR::IRDecoder,
+ public EvalInstructionSelection
+{
+public:
+ InstructionSelection(QV4::ExecutionEngine *engine, V4IR::Module *module);
+ ~InstructionSelection();
+
+ virtual void run(QV4::Function *vmFunction, V4IR::Function *function);
+
+protected:
+ virtual void callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinTypeofName(const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinTypeofValue(V4IR::Temp *value, V4IR::Temp *result);
+ virtual void callBuiltinDeleteMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinDeleteName(const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinDeleteValue(V4IR::Temp *result);
+ virtual void callBuiltinPostDecrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinPostDecrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinPostDecrementName(const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinPostDecrementValue(V4IR::Temp *value, V4IR::Temp *result);
+ virtual void callBuiltinPostIncrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result);
+ virtual void callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result);
+ virtual void callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR::Temp *result);
+ virtual void callBuiltinThrow(V4IR::Temp *arg);
+ virtual void callBuiltinFinishTry();
+ virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result);
+ virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result);
+ virtual void callBuiltinPushWithScope(V4IR::Temp *arg);
+ virtual void callBuiltinPopScope();
+ virtual void callBuiltinDeclareVar(bool deletable, const QString &name);
+ virtual void callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter);
+ virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value);
+ virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args);
+ virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args);
+ virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void convertType(V4IR::Temp *source, V4IR::Temp *target);
+ virtual void loadThisObject(V4IR::Temp *temp);
+ virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp);
+ virtual void loadString(const QString &str, V4IR::Temp *targetTemp);
+ virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp);
+ virtual void getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp);
+ virtual void setActivationProperty(V4IR::Temp *source, const QString &targetName);
+ virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target);
+ virtual void getProperty(V4IR::Temp *base, const QString &name, V4IR::Temp *target);
+ virtual void setProperty(V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName);
+ virtual void getElement(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *target);
+ virtual void setElement(V4IR::Temp *source, V4IR::Temp *targetBase, V4IR::Temp *targetIndex);
+ virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
+ virtual void unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp);
+ virtual void binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target);
+ virtual void inplaceNameOp(V4IR::AluOp oper, V4IR::Temp *rightSource, const QString &targetName);
+ virtual void inplaceElementOp(V4IR::AluOp oper, V4IR::Temp *source, V4IR::Temp *targetBaseTemp, V4IR::Temp *targetIndexTemp);
+ virtual void inplaceMemberOp(V4IR::AluOp oper, V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName);
+
+ typedef Assembler::Address Address;
+ typedef Assembler::Pointer Pointer;
+
+ Address addressForArgument(int index) const
+ {
+ // StackFrameRegister 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::StackFrameRegister, (index + 2) * sizeof(void*));
+ }
+
+ // Some run-time functions take (Value* args, int argc). This function is for populating
+ // the args.
+ Pointer argumentAddressForCall(int argument)
+ {
+ const int index = _function->maxNumberOfArguments - argument;
+ return Pointer(Assembler::LocalsRegister, sizeof(QV4::Value) * (-index)
+ - sizeof(void*) // size of ebp
+ - sizeof(void*) * Assembler::calleeSavedRegisterCount
+ );
+ }
+ Pointer baseAddressForCallArguments()
+ {
+ return argumentAddressForCall(0);
+ }
+
+ QV4::String *identifier(const QString &s);
+ virtual void constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result);
+ virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result);
+
+ virtual void visitJump(V4IR::Jump *);
+ virtual void visitCJump(V4IR::CJump *);
+ virtual void visitRet(V4IR::Ret *);
+ virtual void visitTry(V4IR::Try *);
+
+private:
+ #define isel_stringIfyx(s) #s
+ #define isel_stringIfy(s) isel_stringIfyx(s)
+
+ #define generateFunctionCall(t, function, ...) \
+ _as->generateFunctionCallImp(t, isel_stringIfy(function), function, __VA_ARGS__)
+
+ int prepareVariableArguments(V4IR::ExprList* args);
+
+ typedef void (*ActivationMethod)(QV4::ExecutionContext *, QV4::Value *result, QV4::String *name, QV4::Value *args, int argc);
+ void callRuntimeMethodImp(V4IR::Temp *result, const char* name, ActivationMethod method, V4IR::Expr *base, V4IR::ExprList *args);
+#define callRuntimeMethod(result, function, ...) \
+ callRuntimeMethodImp(result, isel_stringIfy(function), function, __VA_ARGS__)
+
+ uint addLookup(QV4::String *name);
+ uint addSetterLookup(QV4::String *name);
+ uint addGlobalLookup(QV4::String *name);
+
+ template <typename Arg1, typename Arg2>
+ void generateLookupCall(uint index, uint getterSetterOffset, Arg1 arg1, Arg2 arg2)
+ {
+ _as->loadPtr(Assembler::Address(Assembler::ContextRegister, offsetof(QV4::ExecutionContext, lookups)),
+ Assembler::ReturnValueRegister);
+
+ Assembler::Pointer lookupAddr(Assembler::ReturnValueRegister, index * sizeof(QV4::Lookup));
+
+ Assembler::Address getterSetter = lookupAddr;
+ getterSetter.offset += getterSetterOffset;
+
+ _as->generateFunctionCallImp(Assembler::Void, "lookup getter/setter", getterSetter, lookupAddr, arg1, arg2);
+ }
+
+ template <typename Arg1>
+ void generateLookupCall(uint index, uint getterSetterOffset, Arg1 arg1)
+ {
+ generateLookupCall(index, getterSetterOffset, arg1, Assembler::VoidType());
+ }
+
+ V4IR::BasicBlock *_block;
+ V4IR::Function* _function;
+ QV4::Function* _vmFunction;
+ QVector<QV4::Lookup> _lookups;
+ Assembler* _as;
+ QSet<V4IR::BasicBlock*> _reentryBlocks;
+ int _locals;
+};
+
+class Q_QML_EXPORT ISelFactory: public EvalISelFactory
+{
+public:
+ virtual ~ISelFactory() {}
+ virtual EvalInstructionSelection *create(QV4::ExecutionEngine *engine, V4IR::Module *module)
+ { return new InstructionSelection(engine, module); }
+ virtual bool jitCompileRegexps() const
+ { return true; }
+};
+
+} // end of namespace MASM
+} // end of namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif // QV4ISEL_MASM_P_H
diff --git a/src/qml/qml/v4/qv4isel_p.cpp b/src/qml/qml/v4/qv4isel_p.cpp
new file mode 100644
index 0000000000..ca8d249f9f
--- /dev/null
+++ b/src/qml/qml/v4/qv4isel_p.cpp
@@ -0,0 +1,440 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4debugging_p.h"
+#include "qv4engine_p.h"
+#include "qv4jsir_p.h"
+#include "qv4isel_p.h"
+#include "qv4isel_util_p.h"
+#include "qv4functionobject_p.h"
+#include "qv4function_p.h"
+
+#include <QString>
+
+#include <cassert>
+
+namespace {
+QTextStream qout(stderr, QIODevice::WriteOnly);
+} // anonymous namespace
+
+using namespace QQmlJS;
+using namespace QQmlJS::V4IR;
+
+EvalInstructionSelection::EvalInstructionSelection(QV4::ExecutionEngine *engine, Module *module)
+ : _engine(engine)
+ , useFastLookups(true)
+{
+ assert(engine);
+ assert(module);
+
+ createFunctionMapping(0, module->rootFunction);
+ foreach (V4IR::Function *f, module->functions) {
+ assert(_irToVM.contains(f));
+ }
+}
+
+EvalInstructionSelection::~EvalInstructionSelection()
+{}
+
+EvalISelFactory::~EvalISelFactory()
+{}
+
+QV4::Function *EvalInstructionSelection::createFunctionMapping(QV4::Function *outer, Function *irFunction)
+{
+ QV4::Function *vmFunction = _engine->newFunction(irFunction->name ? *irFunction->name : QString());
+ _irToVM.insert(irFunction, vmFunction);
+
+ vmFunction->hasDirectEval = irFunction->hasDirectEval;
+ vmFunction->usesArgumentsObject = irFunction->usesArgumentsObject;
+ vmFunction->hasNestedFunctions = !irFunction->nestedFunctions.isEmpty();
+ vmFunction->isStrict = irFunction->isStrict;
+ vmFunction->outer = outer;
+ vmFunction->isNamedExpression = irFunction->isNamedExpression;
+ vmFunction->sourceFile = irFunction->sourceFile;
+
+ if (outer)
+ outer->nestedFunctions.append(vmFunction);
+
+ foreach (const QString *formal, irFunction->formals)
+ if (formal)
+ vmFunction->formals.append(_engine->newString(*formal));
+ foreach (const QString *local, irFunction->locals)
+ if (local)
+ vmFunction->locals.append(_engine->newString(*local));
+
+ foreach (V4IR::Function *function, irFunction->nestedFunctions)
+ createFunctionMapping(vmFunction, function);
+
+ return vmFunction;
+}
+
+QV4::Function *EvalInstructionSelection::vmFunction(Function *f) {
+ QV4::Function *function = _irToVM[f];
+ if (!function->code)
+ run(function, f);
+ return function;
+}
+
+void IRDecoder::visitMove(V4IR::Move *s)
+{
+ if (s->op == V4IR::OpInvalid) {
+ if (V4IR::Name *n = s->target->asName()) {
+ if (s->source->asTemp()) {
+ setActivationProperty(s->source->asTemp(), *n->id);
+ return;
+ }
+ } else if (V4IR::Temp *t = s->target->asTemp()) {
+ if (V4IR::Name *n = s->source->asName()) {
+ if (*n->id == QStringLiteral("this")) // TODO: `this' should be a builtin.
+ loadThisObject(t);
+ else
+ getActivationProperty(n, t);
+ return;
+ } else if (V4IR::Const *c = s->source->asConst()) {
+ loadConst(c, t);
+ return;
+ } else if (V4IR::Temp *t2 = s->source->asTemp()) {
+ copyValue(t2, t);
+ return;
+ } else if (V4IR::String *str = s->source->asString()) {
+ loadString(*str->value, t);
+ return;
+ } else if (V4IR::RegExp *re = s->source->asRegExp()) {
+ loadRegexp(re, t);
+ return;
+ } else if (V4IR::Closure *clos = s->source->asClosure()) {
+ initClosure(clos, t);
+ return;
+ } else if (V4IR::New *ctor = s->source->asNew()) {
+ if (Name *func = ctor->base->asName()) {
+ constructActivationProperty(func, ctor->args, t);
+ return;
+ } else if (V4IR::Member *member = ctor->base->asMember()) {
+ constructProperty(member->base->asTemp(), *member->name, ctor->args, t);
+ return;
+ } else if (V4IR::Temp *value = ctor->base->asTemp()) {
+ constructValue(value, ctor->args, t);
+ return;
+ }
+ } else if (V4IR::Member *m = s->source->asMember()) {
+ if (V4IR::Temp *base = m->base->asTemp()) {
+ getProperty(base, *m->name, t);
+ return;
+ }
+ } else if (V4IR::Subscript *ss = s->source->asSubscript()) {
+ getElement(ss->base->asTemp(), ss->index->asTemp(), t);
+ return;
+ } else if (V4IR::Unop *u = s->source->asUnop()) {
+ if (V4IR::Temp *e = u->expr->asTemp()) {
+ unop(u->op, e, t);
+ return;
+ }
+ } else if (V4IR::Binop *b = s->source->asBinop()) {
+ binop(b->op, b->left, b->right, t);
+ return;
+ } else if (V4IR::Call *c = s->source->asCall()) {
+ if (c->base->asName()) {
+ callBuiltin(c, t);
+ return;
+ } else if (Member *member = c->base->asMember()) {
+ Q_ASSERT(member->base->asTemp());
+ callProperty(member->base->asTemp(), *member->name, c->args, t);
+ return;
+ } else if (Subscript *s = c->base->asSubscript()) {
+ Q_ASSERT(s->base->asTemp());
+ Q_ASSERT(s->index->asTemp());
+ callSubscript(s->base->asTemp(), s->index->asTemp(), c->args, t);
+ return;
+ } else if (V4IR::Temp *value = c->base->asTemp()) {
+ callValue(value, c->args, t);
+ return;
+ }
+ } else if (V4IR::Convert *c = s->source->asConvert()) {
+ Q_ASSERT(c->expr->asTemp());
+ convertType(c->expr->asTemp(), t);
+ return;
+ }
+ } else if (V4IR::Member *m = s->target->asMember()) {
+ if (V4IR::Temp *base = m->base->asTemp()) {
+ if (s->source->asTemp()) {
+ setProperty(s->source->asTemp(), base, *m->name);
+ return;
+ }
+ }
+ } else if (V4IR::Subscript *ss = s->target->asSubscript()) {
+ if (s->source->asTemp()) {
+ setElement(s->source->asTemp(), ss->base->asTemp(), ss->index->asTemp());
+ return;
+ }
+ }
+ } else {
+ // inplace assignment, e.g. x += 1, ++x, ...
+ if (V4IR::Temp *t = s->target->asTemp()) {
+ if (s->source->asTemp()) {
+ binop(s->op, t, s->source->asTemp(), t);
+ return;
+ }
+ } else if (V4IR::Name *n = s->target->asName()) {
+ if (s->source->asTemp()) {
+ inplaceNameOp(s->op, s->source->asTemp(), *n->id);
+ return;
+ }
+ } else if (V4IR::Subscript *ss = s->target->asSubscript()) {
+ if (s->source->asTemp()) {
+ inplaceElementOp(s->op, s->source->asTemp(), ss->base->asTemp(),
+ ss->index->asTemp());
+ return;
+ }
+ } else if (V4IR::Member *m = s->target->asMember()) {
+ if (s->source->asTemp()) {
+ inplaceMemberOp(s->op, s->source->asTemp(), m->base->asTemp(), *m->name);
+ return;
+ }
+ }
+ }
+
+ // For anything else...:
+ Q_UNIMPLEMENTED();
+ s->dump(qout, V4IR::Stmt::MIR);
+ qout << endl;
+ assert(!"TODO");
+}
+
+IRDecoder::~IRDecoder()
+{
+}
+
+void IRDecoder::visitExp(V4IR::Exp *s)
+{
+ if (V4IR::Call *c = s->expr->asCall()) {
+ // These are calls where the result is ignored.
+ if (c->base->asName()) {
+ callBuiltin(c, 0);
+ } else if (Temp *value = c->base->asTemp()) {
+ callValue(value, c->args, 0);
+ } else if (Member *member = c->base->asMember()) {
+ Q_ASSERT(member->base->asTemp());
+ callProperty(member->base->asTemp(), *member->name, c->args, 0);
+ } else if (Subscript *s = c->base->asSubscript()) {
+ Q_ASSERT(s->base->asTemp());
+ Q_ASSERT(s->index->asTemp());
+ callSubscript(s->base->asTemp(), s->index->asTemp(), c->args, 0);
+ } else {
+ Q_UNIMPLEMENTED();
+ }
+ } else {
+ Q_UNIMPLEMENTED();
+ }
+}
+
+void IRDecoder::callBuiltin(V4IR::Call *call, V4IR::Temp *result)
+{
+ V4IR::Name *baseName = call->base->asName();
+ assert(baseName != 0);
+
+ switch (baseName->builtin) {
+ case V4IR::Name::builtin_invalid:
+ callBuiltinInvalid(baseName, call->args, result);
+ return;
+
+ case V4IR::Name::builtin_typeof: {
+ if (V4IR::Member *m = call->args->expr->asMember()) {
+ callBuiltinTypeofMember(m->base->asTemp(), *m->name, result);
+ return;
+ } else if (V4IR::Subscript *ss = call->args->expr->asSubscript()) {
+ callBuiltinTypeofSubscript(ss->base->asTemp(), ss->index->asTemp(), result);
+ return;
+ } else if (V4IR::Name *n = call->args->expr->asName()) {
+ callBuiltinTypeofName(*n->id, result);
+ return;
+ } else if (V4IR::Temp *arg = call->args->expr->asTemp()){
+ assert(arg != 0);
+ callBuiltinTypeofValue(arg, result);
+ return;
+ }
+ } break;
+
+ case V4IR::Name::builtin_delete: {
+ if (V4IR::Member *m = call->args->expr->asMember()) {
+ callBuiltinDeleteMember(m->base->asTemp(), *m->name, result);
+ return;
+ } else if (V4IR::Subscript *ss = call->args->expr->asSubscript()) {
+ callBuiltinDeleteSubscript(ss->base->asTemp(), ss->index->asTemp(), result);
+ return;
+ } else if (V4IR::Name *n = call->args->expr->asName()) {
+ callBuiltinDeleteName(*n->id, result);
+ return;
+ } else if (call->args->expr->asTemp()){
+ // TODO: should throw in strict mode
+ callBuiltinDeleteValue(result);
+ return;
+ }
+ } break;
+
+ case V4IR::Name::builtin_postincrement: {
+ if (V4IR::Member *m = call->args->expr->asMember()) {
+ callBuiltinPostIncrementMember(m->base->asTemp(), *m->name, result);
+ return;
+ } else if (V4IR::Subscript *ss = call->args->expr->asSubscript()) {
+ callBuiltinPostIncrementSubscript(ss->base->asTemp(), ss->index->asTemp(), result);
+ return;
+ } else if (V4IR::Name *n = call->args->expr->asName()) {
+ callBuiltinPostIncrementName(*n->id, result);
+ return;
+ } else if (V4IR::Temp *arg = call->args->expr->asTemp()){
+ assert(arg != 0);
+ callBuiltinPostIncrementValue(arg, result);
+ return;
+ }
+ } break;
+
+ case V4IR::Name::builtin_postdecrement: {
+ if (V4IR::Member *m = call->args->expr->asMember()) {
+ callBuiltinPostDecrementMember(m->base->asTemp(), *m->name, result);
+ return;
+ } else if (V4IR::Subscript *ss = call->args->expr->asSubscript()) {
+ callBuiltinPostDecrementSubscript(ss->base->asTemp(), ss->index->asTemp(), result);
+ return;
+ } else if (V4IR::Name *n = call->args->expr->asName()) {
+ callBuiltinPostDecrementName(*n->id, result);
+ return;
+ } else if (V4IR::Temp *arg = call->args->expr->asTemp()){
+ assert(arg != 0);
+ callBuiltinPostDecrementValue(arg, result);
+ return;
+ }
+ } break;
+
+ case V4IR::Name::builtin_throw: {
+ V4IR::Temp *arg = call->args->expr->asTemp();
+ assert(arg != 0);
+ callBuiltinThrow(arg);
+ } return;
+
+ case V4IR::Name::builtin_finish_try:
+ callBuiltinFinishTry();
+ return;
+
+ case V4IR::Name::builtin_foreach_iterator_object: {
+ V4IR::Temp *arg = call->args->expr->asTemp();
+ assert(arg != 0);
+ callBuiltinForeachIteratorObject(arg, result);
+ } return;
+
+ case V4IR::Name::builtin_foreach_next_property_name: {
+ V4IR::Temp *arg = call->args->expr->asTemp();
+ assert(arg != 0);
+ callBuiltinForeachNextPropertyname(arg, result);
+ } return;
+ case V4IR::Name::builtin_push_with_scope: {
+ V4IR::Temp *arg = call->args->expr->asTemp();
+ assert(arg != 0);
+ callBuiltinPushWithScope(arg);
+ } return;
+
+ case V4IR::Name::builtin_pop_scope:
+ callBuiltinPopScope();
+ return;
+
+ case V4IR::Name::builtin_declare_vars: {
+ if (!call->args)
+ return;
+ V4IR::Const *deletable = call->args->expr->asConst();
+ assert(deletable->type == V4IR::BoolType);
+ for (V4IR::ExprList *it = call->args->next; it; it = it->next) {
+ V4IR::Name *arg = it->expr->asName();
+ assert(arg != 0);
+ callBuiltinDeclareVar(deletable->value != 0, *arg->id);
+ }
+ } return;
+
+ case V4IR::Name::builtin_define_getter_setter: {
+ if (!call->args)
+ return;
+ V4IR::ExprList *args = call->args;
+ V4IR::Temp *object = args->expr->asTemp();
+ assert(object);
+ args = args->next;
+ assert(args);
+ V4IR::Name *name = args->expr->asName();
+ args = args->next;
+ assert(args);
+ V4IR::Temp *getter = args->expr->asTemp();
+ args = args->next;
+ assert(args);
+ V4IR::Temp *setter = args->expr->asTemp();
+
+ callBuiltinDefineGetterSetter(object, *name->id, getter, setter);
+ } return;
+
+ case V4IR::Name::builtin_define_property: {
+ if (!call->args)
+ return;
+ V4IR::ExprList *args = call->args;
+ V4IR::Temp *object = args->expr->asTemp();
+ assert(object);
+ args = args->next;
+ assert(args);
+ V4IR::Name *name = args->expr->asName();
+ args = args->next;
+ assert(args);
+ V4IR::Temp *value = args->expr->asTemp();
+
+ callBuiltinDefineProperty(object, *name->id, value);
+ } return;
+
+ case V4IR::Name::builtin_define_array:
+ callBuiltinDefineArray(result, call->args);
+ return;
+
+ case V4IR::Name::builtin_define_object_literal:
+ callBuiltinDefineObjectLiteral(result, call->args);
+ return;
+
+ default:
+ break;
+ }
+
+ Q_UNIMPLEMENTED();
+ call->dump(qout); qout << endl;
+ assert(!"TODO!");
+ Q_UNREACHABLE();
+}
diff --git a/src/qml/qml/v4/qv4isel_p.h b/src/qml/qml/v4/qv4isel_p.h
new file mode 100644
index 0000000000..ca49b4c8b1
--- /dev/null
+++ b/src/qml/qml/v4/qv4isel_p.h
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4ISEL_P_H
+#define QV4ISEL_P_H
+
+#include "qv4global_p.h"
+#include "qv4jsir_p.h"
+
+#include <qglobal.h>
+#include <QHash>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+struct ExecutionEngine;
+struct Function;
+}
+
+namespace QQmlJS {
+
+class Q_QML_EXPORT EvalInstructionSelection
+{
+public:
+ EvalInstructionSelection(QV4::ExecutionEngine *engine, V4IR::Module *module);
+ virtual ~EvalInstructionSelection() = 0;
+
+ QV4::Function *vmFunction(V4IR::Function *f);
+
+ void setUseFastLookups(bool b) { useFastLookups = b; }
+
+protected:
+ QV4::Function *createFunctionMapping(QV4::Function *outer, V4IR::Function *irFunction);
+ QV4::ExecutionEngine *engine() const { return _engine; }
+ virtual void run(QV4::Function *vmFunction, V4IR::Function *function) = 0;
+
+private:
+ QV4::ExecutionEngine *_engine;
+ QHash<V4IR::Function *, QV4::Function *> _irToVM;
+protected:
+ bool useFastLookups;
+};
+
+class Q_QML_EXPORT EvalISelFactory
+{
+public:
+ virtual ~EvalISelFactory() = 0;
+ virtual EvalInstructionSelection *create(QV4::ExecutionEngine *engine, V4IR::Module *module) = 0;
+ virtual bool jitCompileRegexps() const = 0;
+};
+
+namespace V4IR {
+class Q_QML_EXPORT IRDecoder: protected V4IR::StmtVisitor
+{
+public:
+ virtual ~IRDecoder() = 0;
+
+ virtual void visitPhi(V4IR::Phi *) {}
+
+public: // visitor methods for StmtVisitor:
+ virtual void visitMove(V4IR::Move *s);
+ virtual void visitExp(V4IR::Exp *s);
+
+public: // to implement by subclasses:
+ virtual void callBuiltinInvalid(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result) = 0;
+ virtual void callBuiltinTypeofMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result) = 0;
+ virtual void callBuiltinTypeofSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result) = 0;
+ virtual void callBuiltinTypeofName(const QString &name, V4IR::Temp *result) = 0;
+ virtual void callBuiltinTypeofValue(V4IR::Temp *value, V4IR::Temp *result) = 0;
+ virtual void callBuiltinDeleteMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result) = 0;
+ virtual void callBuiltinDeleteSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result) = 0;
+ virtual void callBuiltinDeleteName(const QString &name, V4IR::Temp *result) = 0;
+ virtual void callBuiltinDeleteValue(V4IR::Temp *result) = 0;
+ virtual void callBuiltinPostDecrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result) = 0;
+ virtual void callBuiltinPostDecrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result) = 0;
+ virtual void callBuiltinPostDecrementName(const QString &name, V4IR::Temp *result) = 0;
+ virtual void callBuiltinPostDecrementValue(V4IR::Temp *value, V4IR::Temp *result) = 0;
+ virtual void callBuiltinPostIncrementMember(V4IR::Temp *base, const QString &name, V4IR::Temp *result) = 0;
+ virtual void callBuiltinPostIncrementSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *result) = 0;
+ virtual void callBuiltinPostIncrementName(const QString &name, V4IR::Temp *result) = 0;
+ virtual void callBuiltinPostIncrementValue(V4IR::Temp *value, V4IR::Temp *result) = 0;
+ virtual void callBuiltinThrow(V4IR::Temp *arg) = 0;
+ virtual void callBuiltinFinishTry() = 0;
+ virtual void callBuiltinForeachIteratorObject(V4IR::Temp *arg, V4IR::Temp *result) = 0;
+ virtual void callBuiltinForeachNextPropertyname(V4IR::Temp *arg, V4IR::Temp *result) = 0;
+ virtual void callBuiltinPushWithScope(V4IR::Temp *arg) = 0;
+ virtual void callBuiltinPopScope() = 0;
+ virtual void callBuiltinDeclareVar(bool deletable, const QString &name) = 0;
+ virtual void callBuiltinDefineGetterSetter(V4IR::Temp *object, const QString &name, V4IR::Temp *getter, V4IR::Temp *setter) = 0;
+ virtual void callBuiltinDefineProperty(V4IR::Temp *object, const QString &name, V4IR::Temp *value) = 0;
+ virtual void callBuiltinDefineArray(V4IR::Temp *result, V4IR::ExprList *args) = 0;
+ virtual void callBuiltinDefineObjectLiteral(V4IR::Temp *result, V4IR::ExprList *args) = 0;
+ virtual void callValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) = 0;
+ virtual void callProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0;
+ virtual void callSubscript(V4IR::Temp *base, V4IR::Temp *index, V4IR::ExprList *args, V4IR::Temp *result) = 0;
+ virtual void convertType(V4IR::Temp *source, V4IR::Temp *target) = 0;
+ virtual void constructActivationProperty(V4IR::Name *func, V4IR::ExprList *args, V4IR::Temp *result) = 0;
+ virtual void constructProperty(V4IR::Temp *base, const QString &name, V4IR::ExprList *args, V4IR::Temp *result) = 0;
+ virtual void constructValue(V4IR::Temp *value, V4IR::ExprList *args, V4IR::Temp *result) = 0;
+ virtual void loadThisObject(V4IR::Temp *temp) = 0;
+ virtual void loadConst(V4IR::Const *sourceConst, V4IR::Temp *targetTemp) = 0;
+ virtual void loadString(const QString &str, V4IR::Temp *targetTemp) = 0;
+ virtual void loadRegexp(V4IR::RegExp *sourceRegexp, V4IR::Temp *targetTemp) = 0;
+ virtual void getActivationProperty(const V4IR::Name *name, V4IR::Temp *temp) = 0;
+ virtual void setActivationProperty(V4IR::Temp *source, const QString &targetName) = 0;
+ virtual void initClosure(V4IR::Closure *closure, V4IR::Temp *target) = 0;
+ virtual void getProperty(V4IR::Temp *base, const QString &name, V4IR::Temp *target) = 0;
+ virtual void setProperty(V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName) = 0;
+ virtual void getElement(V4IR::Temp *base, V4IR::Temp *index, V4IR::Temp *target) = 0;
+ virtual void setElement(V4IR::Temp *source, V4IR::Temp *targetBase, V4IR::Temp *targetIndex) = 0;
+ virtual void copyValue(V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp) = 0;
+ virtual void unop(V4IR::AluOp oper, V4IR::Temp *sourceTemp, V4IR::Temp *targetTemp) = 0;
+ virtual void binop(V4IR::AluOp oper, V4IR::Expr *leftSource, V4IR::Expr *rightSource, V4IR::Temp *target) = 0;
+ virtual void inplaceNameOp(V4IR::AluOp oper, V4IR::Temp *rightSource, const QString &targetName) = 0;
+ virtual void inplaceElementOp(V4IR::AluOp oper, V4IR::Temp *source, V4IR::Temp *targetBaseTemp, V4IR::Temp *targetIndexTemp) = 0;
+ virtual void inplaceMemberOp(V4IR::AluOp oper, V4IR::Temp *source, V4IR::Temp *targetBase, const QString &targetName) = 0;
+
+private:
+ void callBuiltin(V4IR::Call *c, V4IR::Temp *temp);
+};
+} // namespace IR
+
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif // QV4ISEL_P_H
diff --git a/src/qml/qml/v4/qv4isel_util_p.h b/src/qml/qml/v4/qv4isel_util_p.h
new file mode 100644
index 0000000000..5aedaaff1b
--- /dev/null
+++ b/src/qml/qml/v4/qv4isel_util_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4ISEL_UTIL_P_H
+#define QV4ISEL_UTIL_P_H
+
+#include "qv4runtime_p.h"
+#include "qv4jsir_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+inline QV4::Value convertToValue(V4IR::Const *c)
+{
+ switch (c->type) {
+ case V4IR::MissingType:
+ return QV4::Value::emptyValue();
+ case V4IR::NullType:
+ return QV4::Value::nullValue();
+ case V4IR::UndefinedType:
+ return QV4::Value::undefinedValue();
+ case V4IR::BoolType:
+ return QV4::Value::fromBoolean(c->value != 0);
+ case V4IR::SInt32Type:
+ return QV4::Value::fromInt32(int(c->value));
+ case V4IR::UInt32Type:
+ return QV4::Value::fromUInt32(unsigned(c->value));
+ case V4IR::DoubleType:
+ return QV4::Value::fromDouble(c->value);
+ case V4IR::NumberType: {
+ int ival = (int)c->value;
+ // +0 != -0, so we need to convert to double when negating 0
+ if (ival == c->value && !(c->value == 0 && isNegative(c->value))) {
+ return QV4::Value::fromInt32(ival);
+ } else {
+ return QV4::Value::fromDouble(c->value);
+ }
+ }
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
+} // namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif // QV4ISEL_UTIL_P_H
diff --git a/src/qml/qml/v4/qv4jsir.cpp b/src/qml/qml/v4/qv4jsir.cpp
new file mode 100644
index 0000000000..7f8d257429
--- /dev/null
+++ b/src/qml/qml/v4/qv4jsir.cpp
@@ -0,0 +1,1024 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4jsir_p.h"
+#include <private/qqmljsast_p.h>
+
+#include <QtCore/qtextstream.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qset.h>
+#include <cmath>
+#include <cassert>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+namespace V4IR {
+
+QString typeName(Type t)
+{
+ switch (t) {
+ case UnknownType: return QStringLiteral("");
+ case MissingType: return QStringLiteral("missing");
+ case UndefinedType: return QStringLiteral("undefined");
+ case NullType: return QStringLiteral("null");
+ case BoolType: return QStringLiteral("bool");
+ case UInt32Type: return QStringLiteral("uint32");
+ case SInt32Type: return QStringLiteral("int32");
+ case DoubleType: return QStringLiteral("double");
+ case NumberType: return QStringLiteral("number");
+ case StringType: return QStringLiteral("string");
+ case ObjectType: return QStringLiteral("object");
+ default: return QStringLiteral("multiple");
+ }
+}
+
+const char *opname(AluOp op)
+{
+ switch (op) {
+ case OpInvalid: return "?";
+
+ case OpIfTrue: return "(bool)";
+ case OpNot: return "!";
+ case OpUMinus: return "-";
+ case OpUPlus: return "+";
+ case OpCompl: return "~";
+ case OpIncrement: return "++";
+ case OpDecrement: return "--";
+
+ case OpBitAnd: return "&";
+ case OpBitOr: return "|";
+ case OpBitXor: return "^";
+
+ case OpAdd: return "+";
+ case OpSub: return "-";
+ case OpMul: return "*";
+ case OpDiv: return "/";
+ case OpMod: return "%";
+
+ case OpLShift: return "<<";
+ case OpRShift: return ">>";
+ case OpURShift: return ">>>";
+
+ case OpGt: return ">";
+ case OpLt: return "<";
+ case OpGe: return ">=";
+ case OpLe: return "<=";
+ case OpEqual: return "==";
+ case OpNotEqual: return "!=";
+ case OpStrictEqual: return "===";
+ case OpStrictNotEqual: return "!==";
+
+ case OpInstanceof: return "instanceof";
+ case OpIn: return "in";
+
+ case OpAnd: return "&&";
+ case OpOr: return "||";
+
+ default: return "?";
+
+ } // switch
+}
+
+AluOp binaryOperator(int op)
+{
+ switch (static_cast<QSOperator::Op>(op)) {
+ case QSOperator::Add: return OpAdd;
+ case QSOperator::And: return OpAnd;
+ case QSOperator::BitAnd: return OpBitAnd;
+ case QSOperator::BitOr: return OpBitOr;
+ case QSOperator::BitXor: return OpBitXor;
+ case QSOperator::Div: return OpDiv;
+ case QSOperator::Equal: return OpEqual;
+ case QSOperator::Ge: return OpGe;
+ case QSOperator::Gt: return OpGt;
+ case QSOperator::Le: return OpLe;
+ case QSOperator::LShift: return OpLShift;
+ case QSOperator::Lt: return OpLt;
+ case QSOperator::Mod: return OpMod;
+ case QSOperator::Mul: return OpMul;
+ case QSOperator::NotEqual: return OpNotEqual;
+ case QSOperator::Or: return OpOr;
+ case QSOperator::RShift: return OpRShift;
+ case QSOperator::StrictEqual: return OpStrictEqual;
+ case QSOperator::StrictNotEqual: return OpStrictNotEqual;
+ case QSOperator::Sub: return OpSub;
+ case QSOperator::URShift: return OpURShift;
+ case QSOperator::InstanceOf: return OpInstanceof;
+ case QSOperator::In: return OpIn;
+ default: return OpInvalid;
+ }
+}
+
+struct RemoveSharedExpressions: V4IR::StmtVisitor, V4IR::ExprVisitor
+{
+ CloneExpr clone;
+ QSet<Expr *> subexpressions; // contains all the non-cloned subexpressions in the given function
+ Expr *uniqueExpr;
+
+ RemoveSharedExpressions(): uniqueExpr(0) {}
+
+ void operator()(V4IR::Function *function)
+ {
+ subexpressions.clear();
+
+ foreach (BasicBlock *block, function->basicBlocks) {
+ clone.setBasicBlock(block);
+
+ foreach (Stmt *s, block->statements) {
+ s->accept(this);
+ }
+ }
+ }
+
+ template <typename _Expr>
+ _Expr *cleanup(_Expr *expr)
+ {
+ if (subexpressions.contains(expr)) {
+ // the cloned expression is unique by definition
+ // so we don't need to add it to `subexpressions'.
+ return clone(expr);
+ }
+
+ subexpressions.insert(expr);
+ V4IR::Expr *e = expr;
+ qSwap(uniqueExpr, e);
+ expr->accept(this);
+ qSwap(uniqueExpr, e);
+ return static_cast<_Expr *>(e);
+ }
+
+ // statements
+ virtual void visitExp(Exp *s)
+ {
+ s->expr = cleanup(s->expr);
+ }
+
+ virtual void visitMove(Move *s)
+ {
+ s->target = cleanup(s->target);
+ s->source = cleanup(s->source);
+ }
+
+ virtual void visitJump(Jump *)
+ {
+ // nothing to do for Jump statements
+ }
+
+ virtual void visitCJump(CJump *s)
+ {
+ s->cond = cleanup(s->cond);
+ }
+
+ virtual void visitRet(Ret *s)
+ {
+ s->expr = cleanup(s->expr);
+ }
+
+ virtual void visitTry(Try *)
+ {
+ // nothing to do for Try statements
+ }
+
+ virtual void visitPhi(V4IR::Phi *) { Q_UNIMPLEMENTED(); abort(); }
+
+ // expressions
+ virtual void visitConst(Const *) {}
+ virtual void visitString(String *) {}
+ virtual void visitRegExp(RegExp *) {}
+ virtual void visitName(Name *) {}
+ virtual void visitTemp(Temp *) {}
+ virtual void visitClosure(Closure *) {}
+
+ virtual void visitConvert(Convert *e)
+ {
+ e->expr = cleanup(e->expr);
+ }
+
+ virtual void visitUnop(Unop *e)
+ {
+ e->expr = cleanup(e->expr);
+ }
+
+ virtual void visitBinop(Binop *e)
+ {
+ e->left = cleanup(e->left);
+ e->right = cleanup(e->right);
+ }
+
+ virtual void visitCall(Call *e)
+ {
+ e->base = cleanup(e->base);
+ for (V4IR::ExprList *it = e->args; it; it = it->next)
+ it->expr = cleanup(it->expr);
+ }
+
+ virtual void visitNew(New *e)
+ {
+ e->base = cleanup(e->base);
+ for (V4IR::ExprList *it = e->args; it; it = it->next)
+ it->expr = cleanup(it->expr);
+ }
+
+ virtual void visitSubscript(Subscript *e)
+ {
+ e->base = cleanup(e->base);
+ e->index = cleanup(e->index);
+ }
+
+ virtual void visitMember(Member *e)
+ {
+ e->base = cleanup(e->base);
+ }
+};
+
+static QString dumpStart(const Expr *e) {
+ if (e->type == UnknownType)
+// return QStringLiteral("**UNKNOWN**");
+ return QString();
+ else
+ return typeName(e->type) + QStringLiteral("{");
+}
+
+static const char *dumpEnd(const Expr *e) {
+ if (e->type == UnknownType)
+ return "";
+ else
+ return "}";
+}
+
+void Const::dump(QTextStream &out) const
+{
+ if (type != UndefinedType && type != NullType)
+ out << dumpStart(this);
+ switch (type) {
+ case QQmlJS::V4IR::UndefinedType:
+ out << "undefined";
+ break;
+ case QQmlJS::V4IR::NullType:
+ out << "null";
+ break;
+ case QQmlJS::V4IR::BoolType:
+ out << (value ? "true" : "false");
+ break;
+ case QQmlJS::V4IR::MissingType:
+ out << "missing";
+ break;
+ default:
+ out << QString::number(value, 'g', 16);
+ break;
+ }
+ if (type != UndefinedType && type != NullType)
+ out << dumpEnd(this);
+}
+
+void String::dump(QTextStream &out) const
+{
+ out << '"' << escape(*value) << '"';
+}
+
+QString String::escape(const QString &s)
+{
+ QString r;
+ for (int i = 0; i < s.length(); ++i) {
+ const QChar ch = s.at(i);
+ if (ch == QLatin1Char('\n'))
+ r += QStringLiteral("\\n");
+ else if (ch == QLatin1Char('\r'))
+ r += QStringLiteral("\\r");
+ else if (ch == QLatin1Char('\\'))
+ r += QStringLiteral("\\\\");
+ else if (ch == QLatin1Char('"'))
+ r += QStringLiteral("\\\"");
+ else if (ch == QLatin1Char('\''))
+ r += QStringLiteral("\\'");
+ else
+ r += ch;
+ }
+ return r;
+}
+
+void RegExp::dump(QTextStream &out) const
+{
+ char f[3];
+ int i = 0;
+ if (flags & RegExp_Global)
+ f[i++] = 'g';
+ if (flags & RegExp_IgnoreCase)
+ f[i++] = 'i';
+ if (flags & RegExp_Multiline)
+ f[i++] = 'm';
+ f[i] = 0;
+
+ out << '/' << *value << '/' << f;
+}
+
+void Name::initGlobal(const QString *id, quint32 line, quint32 column)
+{
+ this->id = id;
+ this->builtin = builtin_invalid;
+ this->global = true;
+ this->line = line;
+ this->column = column;
+}
+
+void Name::init(const QString *id, quint32 line, quint32 column)
+{
+ this->id = id;
+ this->builtin = builtin_invalid;
+ this->global = false;
+ this->line = line;
+ this->column = column;
+}
+
+void Name::init(Builtin builtin, quint32 line, quint32 column)
+{
+ this->id = 0;
+ this->builtin = builtin;
+ this->global = false;
+ this->line = line;
+ this->column = column;
+}
+
+static const char *builtin_to_string(Name::Builtin b)
+{
+ switch (b) {
+ case Name::builtin_invalid:
+ return "builtin_invalid";
+ case Name::builtin_typeof:
+ return "builtin_typeof";
+ case Name::builtin_delete:
+ return "builtin_delete";
+ case Name::builtin_postincrement:
+ return "builtin_postincrement";
+ case Name::builtin_postdecrement:
+ return "builtin_postdecrement";
+ case Name::builtin_throw:
+ return "builtin_throw";
+ case Name::builtin_finish_try:
+ return "builtin_finish_try";
+ case V4IR::Name::builtin_foreach_iterator_object:
+ return "builtin_foreach_iterator_object";
+ case V4IR::Name::builtin_foreach_next_property_name:
+ return "builtin_foreach_next_property_name";
+ case V4IR::Name::builtin_push_with_scope:
+ return "builtin_push_with_scope";
+ case V4IR::Name::builtin_pop_scope:
+ return "builtin_pop_scope";
+ case V4IR::Name::builtin_declare_vars:
+ return "builtin_declare_vars";
+ case V4IR::Name::builtin_define_property:
+ return "builtin_define_property";
+ case V4IR::Name::builtin_define_array:
+ return "builtin_define_array";
+ case V4IR::Name::builtin_define_getter_setter:
+ return "builtin_define_getter_setter";
+ case V4IR::Name::builtin_define_object_literal:
+ return "builtin_define_object_literal";
+ }
+ return "builtin_(###FIXME)";
+};
+
+void Name::dump(QTextStream &out) const
+{
+ if (id)
+ out << *id;
+ else
+ out << builtin_to_string(builtin);
+}
+
+void Temp::dump(QTextStream &out) const
+{
+ out << dumpStart(this);
+ switch (kind) {
+ case Formal: out << '#' << index; break;
+ case ScopedFormal: out << '#' << index
+ << '@' << scope; break;
+ case Local: out << '$' << index; break;
+ case ScopedLocal: out << '$' << index
+ << '@' << scope; break;
+ case VirtualRegister: out << '%' << index; break;
+ default: out << "INVALID";
+ }
+ out << dumpEnd(this);
+}
+
+bool operator<(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW
+{
+ if (t1.kind < t2.kind) return true;
+ if (t1.kind > t2.kind) return false;
+ if (t1.index < t2.index) return true;
+ if (t1.index > t2.index) return false;
+ return t1.scope < t2.scope;
+}
+
+void Closure::dump(QTextStream &out) const
+{
+ QString name = value->name ? *value->name : QString();
+ if (name.isEmpty())
+ name.sprintf("%p", value);
+ out << "closure(" << name << ')';
+}
+
+void Convert::dump(QTextStream &out) const
+{
+ out << dumpStart(this);
+ out << "convert(";
+ expr->dump(out);
+ out << ')' << dumpEnd(this);
+}
+
+void Unop::dump(QTextStream &out) const
+{
+ out << dumpStart(this) << opname(op);
+ expr->dump(out);
+ out << dumpEnd(this);
+}
+
+void Binop::dump(QTextStream &out) const
+{
+ out << dumpStart(this);
+ left->dump(out);
+ out << ' ' << opname(op) << ' ';
+ right->dump(out);
+ out << dumpEnd(this);
+}
+
+void Call::dump(QTextStream &out) const
+{
+ base->dump(out);
+ out << '(';
+ for (ExprList *it = args; it; it = it->next) {
+ if (it != args)
+ out << ", ";
+ it->expr->dump(out);
+ }
+ out << ')';
+}
+
+void New::dump(QTextStream &out) const
+{
+ out << "new ";
+ base->dump(out);
+ out << '(';
+ for (ExprList *it = args; it; it = it->next) {
+ if (it != args)
+ out << ", ";
+ it->expr->dump(out);
+ }
+ out << ')';
+}
+
+void Subscript::dump(QTextStream &out) const
+{
+ base->dump(out);
+ out << '[';
+ index->dump(out);
+ out << ']';
+}
+
+void Member::dump(QTextStream &out) const
+{
+ base->dump(out);
+ out << '.' << *name;
+}
+
+void Exp::dump(QTextStream &out, Mode)
+{
+ out << "(void) ";
+ expr->dump(out);
+ out << ';';
+}
+
+void Move::dump(QTextStream &out, Mode)
+{
+ target->dump(out);
+ out << ' ';
+ if (op != OpInvalid)
+ out << opname(op);
+ out << "= ";
+// if (source->type != target->type)
+// out << typeName(source->type) << "_to_" << typeName(target->type) << '(';
+ source->dump(out);
+// if (source->type != target->type)
+// out << ')';
+ out << ';';
+}
+
+void Jump::dump(QTextStream &out, Mode mode)
+{
+ Q_UNUSED(mode);
+ out << "goto " << 'L' << target->index << ';';
+}
+
+void CJump::dump(QTextStream &out, Mode mode)
+{
+ Q_UNUSED(mode);
+ out << "if (";
+ cond->dump(out);
+ if (mode == HIR)
+ out << ") goto " << 'L' << iftrue->index << "; else goto " << 'L' << iffalse->index << ';';
+ else
+ out << ") goto " << 'L' << iftrue->index << ";";
+}
+
+void Ret::dump(QTextStream &out, Mode)
+{
+ out << "return";
+ if (expr) {
+ out << ' ';
+ expr->dump(out);
+ }
+ out << ';';
+}
+
+void Try::dump(QTextStream &out, Stmt::Mode mode)
+{
+ out << "try L" << tryBlock->index << "; catch exception in ";
+ exceptionVar->dump(out);
+ out << " with the name " << exceptionVarName << " and go to L" << catchBlock->index << ';';
+}
+
+void Phi::dump(QTextStream &out, Stmt::Mode mode)
+{
+ targetTemp->dump(out);
+ out << " = phi(";
+ for (int i = 0, ei = incoming.size(); i < ei; ++i) {
+ if (i > 0)
+ out << ", ";
+ if (incoming[i])
+ incoming[i]->dump(out);
+ }
+ out << ");";
+}
+
+Function *Module::newFunction(const QString &name, Function *outer)
+{
+ Function *f = new Function(this, outer, name);
+ functions.append(f);
+ if (!outer) {
+ assert(!rootFunction);
+ rootFunction = f;
+ } else {
+ outer->nestedFunctions.append(f);
+ }
+ return f;
+}
+
+Module::~Module()
+{
+ foreach (Function *f, functions) {
+ delete f;
+ }
+}
+
+Function::~Function()
+{
+ // destroy the Stmt::Data blocks manually, because memory pool cleanup won't
+ // call the Stmt destructors.
+ foreach (V4IR::BasicBlock *b, basicBlocks)
+ foreach (V4IR::Stmt *s, b->statements)
+ s->destroyData();
+
+ qDeleteAll(basicBlocks);
+ pool = 0;
+ module = 0;
+}
+
+
+const QString *Function::newString(const QString &text)
+{
+ return &*strings.insert(text);
+}
+
+BasicBlock *Function::newBasicBlock(BasicBlock *containingLoop, BasicBlockInsertMode mode)
+{
+ BasicBlock *block = new BasicBlock(this, containingLoop);
+ return mode == InsertBlock ? insertBasicBlock(block) : block;
+}
+
+void Function::dump(QTextStream &out, Stmt::Mode mode)
+{
+ QString n = name ? *name : QString();
+ if (n.isEmpty())
+ n.sprintf("%p", this);
+ out << "function " << n << "() {" << endl;
+ foreach (const QString *formal, formals)
+ out << "\treceive " << *formal << ';' << endl;
+ foreach (const QString *local, locals)
+ out << "\tlocal " << *local << ';' << endl;
+ foreach (BasicBlock *bb, basicBlocks)
+ bb->dump(out, mode);
+ out << '}' << endl;
+}
+
+void Function::removeSharedExpressions()
+{
+ RemoveSharedExpressions removeSharedExpressions;
+ removeSharedExpressions(this);
+}
+
+int Function::indexOfArgument(const QStringRef &string) const
+{
+ for (int i = formals.size() - 1; i >= 0; --i) {
+ if (*formals.at(i) == string)
+ return i;
+ }
+ return -1;
+}
+unsigned BasicBlock::newTemp()
+{
+ return function->tempCount++;
+}
+
+Temp *BasicBlock::TEMP(unsigned index)
+{
+ Temp *e = function->New<Temp>();
+ e->init(Temp::VirtualRegister, index, 0);
+ return e;
+}
+
+Temp *BasicBlock::ARG(unsigned index, unsigned scope)
+{
+ Temp *e = function->New<Temp>();
+ e->init(scope ? Temp::ScopedFormal : Temp::Formal, index, scope);
+ return e;
+}
+
+Temp *BasicBlock::LOCAL(unsigned index, unsigned scope)
+{
+ Temp *e = function->New<Temp>();
+ e->init(scope ? Temp::ScopedLocal : Temp::Local, index, scope);
+ return e;
+}
+
+Expr *BasicBlock::CONST(Type type, double value)
+{
+ Const *e = function->New<Const>();
+ if (type == NumberType) {
+ int ival = (int)value;
+ // +0 != -0, so we need to convert to double when negating 0
+ if (ival == value && !(value == 0 && isNegative(value)))
+ type = SInt32Type;
+ else
+ type = DoubleType;
+ }
+ e->init(type, value);
+ return e;
+}
+
+Expr *BasicBlock::STRING(const QString *value)
+{
+ String *e = function->New<String>();
+ e->init(value);
+ return e;
+}
+
+Expr *BasicBlock::REGEXP(const QString *value, int flags)
+{
+ RegExp *e = function->New<RegExp>();
+ e->init(value, flags);
+ return e;
+}
+
+Name *BasicBlock::NAME(const QString &id, quint32 line, quint32 column)
+{
+ Name *e = function->New<Name>();
+ e->init(function->newString(id), line, column);
+ return e;
+}
+
+Name *BasicBlock::GLOBALNAME(const QString &id, quint32 line, quint32 column)
+{
+ Name *e = function->New<Name>();
+ e->initGlobal(function->newString(id), line, column);
+ return e;
+}
+
+
+Name *BasicBlock::NAME(Name::Builtin builtin, quint32 line, quint32 column)
+{
+ Name *e = function->New<Name>();
+ e->init(builtin, line, column);
+ return e;
+}
+
+Closure *BasicBlock::CLOSURE(Function *function)
+{
+ Closure *clos = function->New<Closure>();
+ clos->init(function);
+ return clos;
+}
+
+Expr *BasicBlock::CONVERT(Expr *expr, Type type)
+{
+ Convert *e = function->New<Convert>();
+ e->init(expr, type);
+ return e;
+}
+
+Expr *BasicBlock::UNOP(AluOp op, Expr *expr)
+{
+ Unop *e = function->New<Unop>();
+ e->init(op, expr);
+ return e;
+}
+
+Expr *BasicBlock::BINOP(AluOp op, Expr *left, Expr *right)
+{
+ Binop *e = function->New<Binop>();
+ e->init(op, left, right);
+ return e;
+}
+
+Expr *BasicBlock::CALL(Expr *base, ExprList *args)
+{
+ Call *e = function->New<Call>();
+ e->init(base, args);
+ int argc = 0;
+ for (ExprList *it = args; it; it = it->next)
+ ++argc;
+ function->maxNumberOfArguments = qMax(function->maxNumberOfArguments, argc);
+ return e;
+}
+
+Expr *BasicBlock::NEW(Expr *base, ExprList *args)
+{
+ New *e = function->New<New>();
+ e->init(base, args);
+ return e;
+}
+
+Expr *BasicBlock::SUBSCRIPT(Expr *base, Expr *index)
+{
+ Subscript *e = function->New<Subscript>();
+ e->init(base, index);
+ return e;
+}
+
+Expr *BasicBlock::MEMBER(Expr *base, const QString *name)
+{
+ Member*e = function->New<Member>();
+ e->init(base, name);
+ return e;
+}
+
+Stmt *BasicBlock::EXP(Expr *expr)
+{
+ if (isTerminated())
+ return 0;
+
+ Exp *s = function->New<Exp>();
+ s->init(expr);
+ appendStatement(s);
+ return s;
+}
+
+Stmt *BasicBlock::MOVE(Expr *target, Expr *source, AluOp op)
+{
+ if (isTerminated())
+ return 0;
+
+ Move *s = function->New<Move>();
+ s->init(target, source, op);
+ appendStatement(s);
+ return s;
+}
+
+Stmt *BasicBlock::JUMP(BasicBlock *target)
+{
+ if (isTerminated())
+ return 0;
+
+ Jump *s = function->New<Jump>();
+ s->init(target);
+ appendStatement(s);
+
+ assert(! out.contains(target));
+ out.append(target);
+
+ assert(! target->in.contains(this));
+ target->in.append(this);
+
+ return s;
+}
+
+Stmt *BasicBlock::CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
+{
+ if (isTerminated())
+ return 0;
+
+ if (iftrue == iffalse) {
+ MOVE(TEMP(newTemp()), cond);
+ return JUMP(iftrue);
+ }
+
+ CJump *s = function->New<CJump>();
+ s->init(cond, iftrue, iffalse);
+ appendStatement(s);
+
+ assert(! out.contains(iftrue));
+ out.append(iftrue);
+
+ assert(! iftrue->in.contains(this));
+ iftrue->in.append(this);
+
+ assert(! out.contains(iffalse));
+ out.append(iffalse);
+
+ assert(! iffalse->in.contains(this));
+ iffalse->in.append(this);
+
+ return s;
+}
+
+Stmt *BasicBlock::RET(Temp *expr)
+{
+ if (isTerminated())
+ return 0;
+
+ Ret *s = function->New<Ret>();
+ s->init(expr);
+ appendStatement(s);
+ return s;
+}
+
+Stmt *BasicBlock::TRY(BasicBlock *tryBlock, BasicBlock *catchBlock, const QString &exceptionVarName, Temp *exceptionVar)
+{
+ if (isTerminated())
+ return 0;
+
+ Try *t = function->New<Try>();
+ t->init(tryBlock, catchBlock, exceptionVarName, exceptionVar);
+ appendStatement(t);
+
+ assert(! out.contains(tryBlock));
+ out.append(tryBlock);
+
+ assert(! out.contains(catchBlock));
+ out.append(catchBlock);
+
+ assert(! tryBlock->in.contains(this));
+ tryBlock->in.append(this);
+
+ assert(! catchBlock->in.contains(this));
+ catchBlock->in.append(this);
+
+ return t;
+}
+
+void BasicBlock::dump(QTextStream &out, Stmt::Mode mode)
+{
+ out << 'L' << index << ':' << endl;
+ foreach (Stmt *s, statements) {
+ out << '\t';
+ s->dump(out, mode);
+
+ if (s->location.isValid())
+ out << " // line: " << s->location.startLine << " ; column: " << s->location.startColumn;
+
+ out << endl;
+ }
+}
+
+void BasicBlock::appendStatement(Stmt *statement)
+{
+ if (nextLocation.isValid()) {
+ statement->location = nextLocation;
+ nextLocation = AST::SourceLocation();
+ }
+ statements.append(statement);
+}
+
+CloneExpr::CloneExpr(BasicBlock *block)
+ : block(block), cloned(0)
+{
+}
+
+void CloneExpr::setBasicBlock(BasicBlock *block)
+{
+ this->block = block;
+}
+
+ExprList *CloneExpr::clone(ExprList *list)
+{
+ if (! list)
+ return 0;
+
+ ExprList *clonedList = block->function->New<V4IR::ExprList>();
+ clonedList->init(clone(list->expr), clone(list->next));
+ return clonedList;
+}
+
+void CloneExpr::visitConst(Const *e)
+{
+ cloned = block->CONST(e->type, e->value);
+}
+
+void CloneExpr::visitString(String *e)
+{
+ cloned = block->STRING(e->value);
+}
+
+void CloneExpr::visitRegExp(RegExp *e)
+{
+ cloned = block->REGEXP(e->value, e->flags);
+}
+
+void CloneExpr::visitName(Name *e)
+{
+ if (e->id)
+ cloned = block->NAME(*e->id, e->line, e->column);
+ else
+ cloned = block->NAME(e->builtin, e->line, e->column);
+}
+
+void CloneExpr::visitTemp(Temp *e)
+{
+ Temp *t = block->function->New<Temp>();
+ t->init(e->kind, e->index, e->scope);
+ cloned = t;
+}
+
+void CloneExpr::visitClosure(Closure *e)
+{
+ cloned = block->CLOSURE(e->value);
+}
+
+void CloneExpr::visitConvert(Convert *e)
+{
+ cloned = block->CONVERT(clone(e->expr), e->type);
+}
+
+void CloneExpr::visitUnop(Unop *e)
+{
+ cloned = block->UNOP(e->op, clone(e->expr));
+}
+
+void CloneExpr::visitBinop(Binop *e)
+{
+ cloned = block->BINOP(e->op, clone(e->left), clone(e->right));
+}
+
+void CloneExpr::visitCall(Call *e)
+{
+ cloned = block->CALL(clone(e->base), clone(e->args));
+}
+
+void CloneExpr::visitNew(New *e)
+{
+ cloned = block->NEW(clone(e->base), clone(e->args));
+}
+
+void CloneExpr::visitSubscript(Subscript *e)
+{
+ cloned = block->SUBSCRIPT(clone(e->base), clone(e->index));
+}
+
+void CloneExpr::visitMember(Member *e)
+{
+ cloned = block->MEMBER(clone(e->base), e->name);
+}
+
+} // end of namespace IR
+} // end of namespace QQmlJS
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4jsir_p.h b/src/qml/qml/v4/qv4jsir_p.h
new file mode 100644
index 0000000000..659d9870b1
--- /dev/null
+++ b/src/qml/qml/v4/qv4jsir_p.h
@@ -0,0 +1,890 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4JSIR_P_H
+#define QV4JSIR_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 "qv4global_p.h"
+#include <private/qqmljsmemorypool_p.h>
+#include <private/qqmljsastfwd_p.h>
+
+#include <QtCore/QVector>
+#include <QtCore/QString>
+#include <QtCore/QBitArray>
+#include <QtCore/qurl.h>
+
+#ifdef CONST
+#undef CONST
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QTextStream;
+class QQmlType;
+
+namespace QV4 {
+struct ExecutionContext;
+}
+
+namespace QQmlJS {
+
+inline bool isNegative(double d)
+{
+ uchar *dch = (uchar *)&d;
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ return (dch[0] & 0x80);
+ else
+ return (dch[7] & 0x80);
+
+}
+
+namespace V4IR {
+
+struct BasicBlock;
+struct Function;
+struct Module;
+
+struct Stmt;
+struct Expr;
+
+// expressions
+struct Const;
+struct String;
+struct RegExp;
+struct Name;
+struct Temp;
+struct Closure;
+struct Convert;
+struct Unop;
+struct Binop;
+struct Call;
+struct New;
+struct Subscript;
+struct Member;
+
+// statements
+struct Exp;
+struct Move;
+struct Jump;
+struct CJump;
+struct Ret;
+struct Try;
+struct Phi;
+
+enum AluOp {
+ OpInvalid = 0,
+
+ OpIfTrue,
+ OpNot,
+ OpUMinus,
+ OpUPlus,
+ OpCompl,
+ OpIncrement,
+ OpDecrement,
+
+ OpBitAnd,
+ OpBitOr,
+ OpBitXor,
+
+ OpAdd,
+ OpSub,
+ OpMul,
+ OpDiv,
+ OpMod,
+
+ OpLShift,
+ OpRShift,
+ OpURShift,
+
+ OpGt,
+ OpLt,
+ OpGe,
+ OpLe,
+ OpEqual,
+ OpNotEqual,
+ OpStrictEqual,
+ OpStrictNotEqual,
+
+ OpInstanceof,
+ OpIn,
+
+ OpAnd,
+ OpOr,
+
+ LastAluOp = OpOr
+};
+AluOp binaryOperator(int op);
+const char *opname(V4IR::AluOp op);
+
+enum Type {
+ UnknownType = 0,
+
+ MissingType = 1 << 0,
+ UndefinedType = 1 << 1,
+ NullType = 1 << 2,
+ BoolType = 1 << 3,
+
+ SInt32Type = 1 << 4,
+ UInt32Type = 1 << 5,
+ DoubleType = 1 << 6,
+ NumberType = SInt32Type | UInt32Type | DoubleType,
+
+ StringType = 1 << 7,
+ ObjectType = 1 << 8
+};
+QString typeName(Type t);
+
+struct ExprVisitor {
+ virtual ~ExprVisitor() {}
+ virtual void visitConst(Const *) = 0;
+ virtual void visitString(String *) = 0;
+ virtual void visitRegExp(RegExp *) = 0;
+ virtual void visitName(Name *) = 0;
+ virtual void visitTemp(Temp *) = 0;
+ virtual void visitClosure(Closure *) = 0;
+ virtual void visitConvert(Convert *) = 0;
+ virtual void visitUnop(Unop *) = 0;
+ virtual void visitBinop(Binop *) = 0;
+ virtual void visitCall(Call *) = 0;
+ virtual void visitNew(New *) = 0;
+ virtual void visitSubscript(Subscript *) = 0;
+ virtual void visitMember(Member *) = 0;
+};
+
+struct StmtVisitor {
+ virtual ~StmtVisitor() {}
+ virtual void visitExp(Exp *) = 0;
+ virtual void visitMove(Move *) = 0;
+ virtual void visitJump(Jump *) = 0;
+ virtual void visitCJump(CJump *) = 0;
+ virtual void visitRet(Ret *) = 0;
+ virtual void visitTry(Try *) = 0;
+ virtual void visitPhi(Phi *) = 0;
+};
+
+struct Expr {
+ Type type;
+
+ Expr(): type(UnknownType) {}
+ virtual ~Expr() {}
+ virtual void accept(ExprVisitor *) = 0;
+ virtual bool isLValue() { return false; }
+ virtual Const *asConst() { return 0; }
+ virtual String *asString() { return 0; }
+ virtual RegExp *asRegExp() { return 0; }
+ virtual Name *asName() { return 0; }
+ virtual Temp *asTemp() { return 0; }
+ virtual Closure *asClosure() { return 0; }
+ virtual Convert *asConvert() { return 0; }
+ virtual Unop *asUnop() { return 0; }
+ virtual Binop *asBinop() { return 0; }
+ virtual Call *asCall() { return 0; }
+ virtual New *asNew() { return 0; }
+ virtual Subscript *asSubscript() { return 0; }
+ virtual Member *asMember() { return 0; }
+ virtual void dump(QTextStream &out) const = 0;
+};
+
+struct ExprList {
+ Expr *expr;
+ ExprList *next;
+
+ void init(Expr *expr, ExprList *next = 0)
+ {
+ this->expr = expr;
+ this->next = next;
+ }
+};
+
+struct Const: Expr {
+ double value;
+
+ void init(Type type, double value)
+ {
+ this->type = type;
+ this->value = value;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitConst(this); }
+ virtual Const *asConst() { return this; }
+
+ virtual void dump(QTextStream &out) const;
+};
+
+struct String: Expr {
+ const QString *value;
+
+ void init(const QString *value)
+ {
+ this->value = value;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitString(this); }
+ virtual String *asString() { return this; }
+
+ virtual void dump(QTextStream &out) const;
+ static QString escape(const QString &s);
+};
+
+struct RegExp: Expr {
+ // needs to be compatible with the flags in the lexer, and in RegExpObject
+ enum Flags {
+ RegExp_Global = 0x01,
+ RegExp_IgnoreCase = 0x02,
+ RegExp_Multiline = 0x04
+ };
+
+ const QString *value;
+ int flags;
+
+ void init(const QString *value, int flags)
+ {
+ this->value = value;
+ this->flags = flags;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitRegExp(this); }
+ virtual RegExp *asRegExp() { return this; }
+
+ virtual void dump(QTextStream &out) const;
+};
+
+struct Name: Expr {
+ enum Builtin {
+ builtin_invalid,
+ builtin_typeof,
+ builtin_delete,
+ builtin_postincrement,
+ builtin_postdecrement,
+ builtin_throw,
+ builtin_finish_try,
+ builtin_foreach_iterator_object,
+ builtin_foreach_next_property_name,
+ builtin_push_with_scope,
+ builtin_pop_scope,
+ builtin_declare_vars,
+ builtin_define_property,
+ builtin_define_array,
+ builtin_define_getter_setter,
+ builtin_define_object_literal
+ };
+
+ const QString *id;
+ Builtin builtin;
+ bool global;
+ quint32 line;
+ quint32 column;
+
+ void initGlobal(const QString *id, quint32 line, quint32 column);
+ void init(const QString *id, quint32 line, quint32 column);
+ void init(Builtin builtin, quint32 line, quint32 column);
+
+ virtual void accept(ExprVisitor *v) { v->visitName(this); }
+ virtual bool isLValue() { return true; }
+ virtual Name *asName() { return this; }
+
+ virtual void dump(QTextStream &out) const;
+};
+
+struct Temp: Expr {
+ enum Kind {
+ Formal = 0,
+ ScopedFormal,
+ Local,
+ ScopedLocal,
+ VirtualRegister,
+ PhysicalRegister,
+ StackSlot
+ };
+
+ unsigned index;
+ unsigned scope : 29; // how many scopes outside the current one?
+ unsigned kind : 3;
+
+ void init(unsigned kind, unsigned index, unsigned scope)
+ {
+ Q_ASSERT((kind == ScopedLocal && scope != 0) ||
+ (kind == ScopedFormal && scope != 0) ||
+ (scope == 0));
+
+ this->kind = kind;
+ this->index = index;
+ this->scope = scope;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitTemp(this); }
+ virtual bool isLValue() { return true; }
+ virtual Temp *asTemp() { return this; }
+
+ virtual void dump(QTextStream &out) const;
+};
+
+inline bool operator==(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW
+{ return t1.index == t2.index && t1.scope == t2.scope && t1.kind == t2.kind; }
+
+inline uint qHash(const Temp &t, uint seed = 0) Q_DECL_NOTHROW
+{ return t.index ^ (t.kind | (t.scope << 3)) ^ seed; }
+
+bool operator<(const Temp &t1, const Temp &t2) Q_DECL_NOTHROW;
+
+struct Closure: Expr {
+ Function *value;
+
+ void init(Function *value)
+ {
+ this->value = value;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitClosure(this); }
+ virtual Closure *asClosure() { return this; }
+
+ virtual void dump(QTextStream &out) const;
+};
+
+struct Convert: Expr {
+ Expr *expr;
+
+ void init(Expr *expr, Type type)
+ {
+ this->expr = expr;
+ this->type = type;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitConvert(this); }
+ virtual Convert *asConvert() { return this; }
+
+ virtual void dump(QTextStream &out) const;
+};
+
+struct Unop: Expr {
+ AluOp op;
+ Expr *expr;
+
+ void init(AluOp op, Expr *expr)
+ {
+ this->op = op;
+ this->expr = expr;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitUnop(this); }
+ virtual Unop *asUnop() { return this; }
+
+ virtual void dump(QTextStream &out) const;
+};
+
+struct Binop: Expr {
+ AluOp op;
+ Expr *left; // Temp or Const
+ Expr *right; // Temp or Const
+
+ void init(AluOp op, Expr *left, Expr *right)
+ {
+ this->op = op;
+ this->left = left;
+ this->right = right;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitBinop(this); }
+ virtual Binop *asBinop() { return this; }
+
+ virtual void dump(QTextStream &out) const;
+};
+
+struct Call: Expr {
+ Expr *base; // Name, Member, Temp
+ ExprList *args; // List of Temps
+
+ void init(Expr *base, ExprList *args)
+ {
+ this->base = base;
+ this->args = args;
+ }
+
+ Expr *onlyArgument() const {
+ if (args && ! args->next)
+ return args->expr;
+ return 0;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitCall(this); }
+ virtual Call *asCall() { return this; }
+
+ virtual void dump(QTextStream &out) const;
+};
+
+struct New: Expr {
+ Expr *base; // Name, Member, Temp
+ ExprList *args; // List of Temps
+
+ void init(Expr *base, ExprList *args)
+ {
+ this->base = base;
+ this->args = args;
+ }
+
+ Expr *onlyArgument() const {
+ if (args && ! args->next)
+ return args->expr;
+ return 0;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitNew(this); }
+ virtual New *asNew() { return this; }
+
+ virtual void dump(QTextStream &out) const;
+};
+
+struct Subscript: Expr {
+ Expr *base;
+ Expr *index;
+
+ void init(Expr *base, Expr *index)
+ {
+ this->base = base;
+ this->index = index;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitSubscript(this); }
+ virtual bool isLValue() { return true; }
+ virtual Subscript *asSubscript() { return this; }
+
+ virtual void dump(QTextStream &out) const;
+};
+
+struct Member: Expr {
+ Expr *base;
+ const QString *name;
+
+ void init(Expr *base, const QString *name)
+ {
+ this->base = base;
+ this->name = name;
+ }
+
+ virtual void accept(ExprVisitor *v) { v->visitMember(this); }
+ virtual bool isLValue() { return true; }
+ virtual Member *asMember() { return this; }
+
+ virtual void dump(QTextStream &out) const;
+};
+
+struct Stmt {
+ enum Mode {
+ HIR,
+ MIR
+ };
+
+ struct Data {
+ QVector<unsigned> uses;
+ QVector<unsigned> defs;
+ QBitArray liveIn;
+ QBitArray liveOut;
+ };
+
+ Data *d;
+ int id;
+ AST::SourceLocation location;
+
+ Stmt(): d(0), id(-1) {}
+ virtual ~Stmt() { Q_UNREACHABLE(); }
+ virtual Stmt *asTerminator() { return 0; }
+
+ virtual void accept(StmtVisitor *) = 0;
+ virtual Exp *asExp() { return 0; }
+ virtual Move *asMove() { return 0; }
+ virtual Jump *asJump() { return 0; }
+ virtual CJump *asCJump() { return 0; }
+ virtual Ret *asRet() { return 0; }
+ virtual Try *asTry() { return 0; }
+ virtual Phi *asPhi() { return 0; }
+ virtual void dump(QTextStream &out, Mode mode = HIR) = 0;
+
+ void destroyData() {
+ delete d;
+ d = 0;
+ }
+};
+
+struct Exp: Stmt {
+ Expr *expr;
+
+ void init(Expr *expr)
+ {
+ this->expr = expr;
+ }
+
+ virtual void accept(StmtVisitor *v) { v->visitExp(this); }
+ virtual Exp *asExp() { return this; }
+
+ virtual void dump(QTextStream &out, Mode);
+};
+
+struct Move: Stmt {
+ Expr *target; // LHS - Temp, Name, Member or Subscript
+ Expr *source;
+ AluOp op;
+
+ void init(Expr *target, Expr *source, AluOp op)
+ {
+ this->target = target;
+ this->source = source;
+ this->op = op;
+ }
+
+ virtual void accept(StmtVisitor *v) { v->visitMove(this); }
+ virtual Move *asMove() { return this; }
+
+ virtual void dump(QTextStream &out, Mode);
+};
+
+struct Jump: Stmt {
+ BasicBlock *target;
+
+ void init(BasicBlock *target)
+ {
+ this->target = target;
+ }
+
+ virtual Stmt *asTerminator() { return this; }
+
+ virtual void accept(StmtVisitor *v) { v->visitJump(this); }
+ virtual Jump *asJump() { return this; }
+
+ virtual void dump(QTextStream &out, Mode mode);
+};
+
+struct CJump: Stmt {
+ Expr *cond; // Temp, Binop
+ BasicBlock *iftrue;
+ BasicBlock *iffalse;
+
+ void init(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse)
+ {
+ this->cond = cond;
+ this->iftrue = iftrue;
+ this->iffalse = iffalse;
+ }
+
+ virtual Stmt *asTerminator() { return this; }
+
+ virtual void accept(StmtVisitor *v) { v->visitCJump(this); }
+ virtual CJump *asCJump() { return this; }
+
+ virtual void dump(QTextStream &out, Mode mode);
+};
+
+struct Ret: Stmt {
+ Expr *expr;
+
+ void init(Expr *expr)
+ {
+ this->expr = expr;
+ }
+
+ virtual Stmt *asTerminator() { return this; }
+
+ virtual void accept(StmtVisitor *v) { v->visitRet(this); }
+ virtual Ret *asRet() { return this; }
+
+ virtual void dump(QTextStream &out, Mode);
+};
+
+struct Try: Stmt {
+ BasicBlock *tryBlock;
+ BasicBlock *catchBlock;
+ QString exceptionVarName;
+ Temp *exceptionVar; // place to store the caught exception, for use when re-throwing
+
+ void init(BasicBlock *tryBlock, BasicBlock *catchBlock, const QString &exceptionVarName, Temp *exceptionVar)
+ {
+ this->tryBlock = tryBlock;
+ this->catchBlock = catchBlock;
+ this->exceptionVarName = exceptionVarName;
+ this->exceptionVar = exceptionVar;
+ }
+
+ virtual Stmt *asTerminator() { return this; }
+
+ virtual void accept(StmtVisitor *v) { v->visitTry(this); }
+ virtual Try *asTry() { return this; }
+
+ virtual void dump(QTextStream &out, Mode mode);
+};
+
+struct Phi: Stmt {
+ Temp *targetTemp;
+ QVector<Expr *> incoming;
+
+ virtual void accept(StmtVisitor *v) { v->visitPhi(this); }
+ virtual Phi *asPhi() { return this; }
+
+ virtual void dump(QTextStream &out, Mode mode);
+};
+
+struct Q_QML_EXPORT Module {
+ MemoryPool pool;
+ QVector<Function *> functions;
+ Function *rootFunction;
+
+ Function *newFunction(const QString &name, Function *outer);
+
+ Module() : rootFunction(0) {}
+ ~Module();
+};
+
+struct Function {
+ Module *module;
+ MemoryPool *pool;
+ const QString *name;
+ QVector<BasicBlock *> basicBlocks;
+ int tempCount;
+ int maxNumberOfArguments;
+ QSet<QString> strings;
+ QList<const QString *> formals;
+ QList<const QString *> locals;
+ QVector<Function *> nestedFunctions;
+ Function *outer;
+
+ QString sourceFile;
+
+ int insideWithOrCatch;
+
+ uint hasDirectEval: 1;
+ uint usesArgumentsObject : 1;
+ uint isStrict: 1;
+ uint isNamedExpression : 1;
+ uint hasTry: 1;
+ uint hasWith: 1;
+ uint unused : 26;
+
+ template <typename _Tp> _Tp *New() { return new (pool->allocate(sizeof(_Tp))) _Tp(); }
+
+ Function(Module *module, Function *outer, const QString &name)
+ : module(module)
+ , pool(&module->pool)
+ , tempCount(0)
+ , maxNumberOfArguments(0)
+ , outer(outer)
+ , insideWithOrCatch(0)
+ , hasDirectEval(false)
+ , usesArgumentsObject(false)
+ , isStrict(false)
+ , isNamedExpression(false)
+ , hasTry(false)
+ , hasWith(false)
+ , unused(0)
+ { this->name = newString(name); }
+
+ ~Function();
+
+ enum BasicBlockInsertMode {
+ InsertBlock,
+ DontInsertBlock
+ };
+
+ BasicBlock *newBasicBlock(BasicBlock *containingLoop, BasicBlockInsertMode mode = InsertBlock);
+ const QString *newString(const QString &text);
+
+ void RECEIVE(const QString &name) { formals.append(newString(name)); }
+ void LOCAL(const QString &name) { locals.append(newString(name)); }
+
+ inline BasicBlock *insertBasicBlock(BasicBlock *block) { basicBlocks.append(block); return block; }
+
+ void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
+
+ void removeSharedExpressions();
+
+ int indexOfArgument(const QStringRef &string) const;
+
+ bool variablesCanEscape() const
+ { return hasDirectEval || !nestedFunctions.isEmpty(); }
+};
+
+struct BasicBlock {
+ Function *function;
+ QVector<Stmt *> statements;
+ QVector<BasicBlock *> in;
+ QVector<BasicBlock *> out;
+ QBitArray liveIn;
+ QBitArray liveOut;
+ int index;
+ AST::SourceLocation nextLocation;
+
+ BasicBlock(Function *function, BasicBlock *containingLoop)
+ : function(function)
+ , index(-1)
+ , _containingGroup(containingLoop)
+ , _groupStart(false)
+ {}
+ ~BasicBlock() {}
+
+ template <typename Instr> inline Instr i(Instr i) { statements.append(i); return i; }
+
+ inline bool isEmpty() const {
+ return statements.isEmpty();
+ }
+
+ inline Stmt *terminator() const {
+ if (! statements.isEmpty() && statements.at(statements.size() - 1)->asTerminator() != 0)
+ return statements.at(statements.size() - 1);
+ return 0;
+ }
+
+ inline bool isTerminated() const {
+ if (terminator() != 0)
+ return true;
+ return false;
+ }
+
+ unsigned newTemp();
+
+ Temp *TEMP(unsigned kind);
+ Temp *ARG(unsigned index, unsigned scope);
+ Temp *LOCAL(unsigned index, unsigned scope);
+
+ Expr *CONST(Type type, double value);
+ Expr *STRING(const QString *value);
+ Expr *REGEXP(const QString *value, int flags);
+
+ Name *NAME(const QString &id, quint32 line, quint32 column);
+ Name *NAME(Name::Builtin builtin, quint32 line, quint32 column);
+
+ Name *GLOBALNAME(const QString &id, quint32 line, quint32 column);
+
+ Closure *CLOSURE(Function *function);
+
+ Expr *CONVERT(Expr *expr, Type type);
+ Expr *UNOP(AluOp op, Expr *expr);
+ Expr *BINOP(AluOp op, Expr *left, Expr *right);
+ Expr *CALL(Expr *base, ExprList *args = 0);
+ Expr *NEW(Expr *base, ExprList *args = 0);
+ Expr *SUBSCRIPT(Expr *base, Expr *index);
+ Expr *MEMBER(Expr *base, const QString *name);
+
+ Stmt *EXP(Expr *expr);
+
+ Stmt *MOVE(Expr *target, Expr *source, AluOp op = V4IR::OpInvalid);
+
+ Stmt *JUMP(BasicBlock *target);
+ Stmt *CJUMP(Expr *cond, BasicBlock *iftrue, BasicBlock *iffalse);
+ Stmt *RET(Temp *expr);
+ Stmt *TRY(BasicBlock *tryBlock, BasicBlock *catchBlock, const QString &exceptionVarName, Temp *exceptionVar);
+
+ void dump(QTextStream &out, Stmt::Mode mode = Stmt::HIR);
+
+ void appendStatement(Stmt *statement);
+
+ BasicBlock *containingGroup() const
+ { return _containingGroup; }
+
+ bool isGroupStart() const
+ { return _groupStart; }
+
+ void markAsGroupStart()
+ { _groupStart = true; }
+
+private:
+ BasicBlock *_containingGroup;
+ bool _groupStart;
+};
+
+class CloneExpr: protected V4IR::ExprVisitor
+{
+public:
+ explicit CloneExpr(V4IR::BasicBlock *block = 0);
+
+ void setBasicBlock(V4IR::BasicBlock *block);
+
+ template <typename _Expr>
+ _Expr *operator()(_Expr *expr)
+ {
+ return clone(expr);
+ }
+
+ template <typename _Expr>
+ _Expr *clone(_Expr *expr)
+ {
+ Expr *c = expr;
+ qSwap(cloned, c);
+ expr->accept(this);
+ qSwap(cloned, c);
+ return static_cast<_Expr *>(c);
+ }
+
+protected:
+ V4IR::ExprList *clone(V4IR::ExprList *list);
+
+ virtual void visitConst(Const *);
+ virtual void visitString(String *);
+ virtual void visitRegExp(RegExp *);
+ virtual void visitName(Name *);
+ virtual void visitTemp(Temp *);
+ virtual void visitClosure(Closure *);
+ virtual void visitConvert(Convert *);
+ virtual void visitUnop(Unop *);
+ virtual void visitBinop(Binop *);
+ virtual void visitCall(Call *);
+ virtual void visitNew(New *);
+ virtual void visitSubscript(Subscript *);
+ virtual void visitMember(Member *);
+
+private:
+ V4IR::BasicBlock *block;
+ V4IR::Expr *cloned;
+};
+
+} // end of namespace IR
+
+} // end of namespace QQmlJS
+
+QT_END_NAMESPACE
+
+#endif // QV4IR_P_H
diff --git a/src/qml/qml/v4/qv4jsonobject.cpp b/src/qml/qml/v4/qv4jsonobject.cpp
new file mode 100644
index 0000000000..782c388e5a
--- /dev/null
+++ b/src/qml/qml/v4/qv4jsonobject.cpp
@@ -0,0 +1,1040 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qv4jsonobject_p.h>
+#include <qv4objectproto_p.h>
+#include <qv4numberobject_p.h>
+#include <qv4stringobject_p.h>
+#include <qv4booleanobject_p.h>
+#include <qv4objectiterator_p.h>
+#include <qjsondocument.h>
+#include <qstack.h>
+#include <qstringlist.h>
+
+#include <wtf/MathExtras.h>
+
+using namespace QV4;
+
+//#define PARSER_DEBUG
+#ifdef PARSER_DEBUG
+static int indent = 0;
+#define BEGIN qDebug() << QByteArray(4*indent++, ' ').constData()
+#define END --indent
+#define DEBUG qDebug() << QByteArray(4*indent, ' ').constData()
+#else
+#define BEGIN if (1) ; else qDebug()
+#define END do {} while (0)
+#define DEBUG if (1) ; else qDebug()
+#endif
+
+
+class JsonParser
+{
+public:
+ JsonParser(ExecutionContext *context, const QChar *json, int length);
+
+ Value parse(QJsonParseError *error);
+
+private:
+ inline bool eatSpace();
+ inline QChar nextToken();
+
+ Value parseObject();
+ Value parseArray();
+ bool parseMember(Object *o);
+ bool parseString(QString *string);
+ bool parseValue(Value *val);
+ bool parseNumber(Value *val);
+
+ ExecutionContext *context;
+ const QChar *head;
+ const QChar *json;
+ const QChar *end;
+
+ int nestingLevel;
+ QJsonParseError::ParseError lastError;
+};
+
+static const int nestingLimit = 1024;
+
+
+JsonParser::JsonParser(ExecutionContext *context, const QChar *json, int length)
+ : context(context), head(json), json(json), nestingLevel(0), lastError(QJsonParseError::NoError)
+{
+ end = json + length;
+}
+
+
+
+/*
+
+begin-array = ws %x5B ws ; [ left square bracket
+
+begin-object = ws %x7B ws ; { left curly bracket
+
+end-array = ws %x5D ws ; ] right square bracket
+
+end-object = ws %x7D ws ; } right curly bracket
+
+name-separator = ws %x3A ws ; : colon
+
+value-separator = ws %x2C ws ; , comma
+
+Insignificant whitespace is allowed before or after any of the six
+structural characters.
+
+ws = *(
+ %x20 / ; Space
+ %x09 / ; Horizontal tab
+ %x0A / ; Line feed or New line
+ %x0D ; Carriage return
+ )
+
+*/
+
+enum {
+ Space = 0x20,
+ Tab = 0x09,
+ LineFeed = 0x0a,
+ Return = 0x0d,
+ BeginArray = 0x5b,
+ BeginObject = 0x7b,
+ EndArray = 0x5d,
+ EndObject = 0x7d,
+ NameSeparator = 0x3a,
+ ValueSeparator = 0x2c,
+ Quote = 0x22
+};
+
+bool JsonParser::eatSpace()
+{
+ while (json < end) {
+ if (*json > Space)
+ break;
+ if (*json != Space &&
+ *json != Tab &&
+ *json != LineFeed &&
+ *json != Return)
+ break;
+ ++json;
+ }
+ return (json < end);
+}
+
+QChar JsonParser::nextToken()
+{
+ if (!eatSpace())
+ return 0;
+ QChar token = *json++;
+ switch (token.unicode()) {
+ case BeginArray:
+ case BeginObject:
+ case NameSeparator:
+ case ValueSeparator:
+ case EndArray:
+ case EndObject:
+ eatSpace();
+ case Quote:
+ break;
+ default:
+ token = 0;
+ break;
+ }
+ return token;
+}
+
+/*
+ JSON-text = object / array
+*/
+Value JsonParser::parse(QJsonParseError *error)
+{
+#ifdef PARSER_DEBUG
+ indent = 0;
+ qDebug() << ">>>>> parser begin";
+#endif
+
+ eatSpace();
+
+ Value v;
+ if (!parseValue(&v)) {
+#ifdef PARSER_DEBUG
+ qDebug() << ">>>>> parser error";
+#endif
+ if (lastError == QJsonParseError::NoError)
+ lastError = QJsonParseError::IllegalValue;
+ error->offset = json - head;
+ error->error = lastError;
+ return Value::undefinedValue();
+ }
+
+ // some input left...
+ if (eatSpace()) {
+ lastError = QJsonParseError::IllegalValue;
+ error->offset = json - head;
+ error->error = lastError;
+ return Value::undefinedValue();
+ }
+
+ END;
+ error->offset = 0;
+ error->error = QJsonParseError::NoError;
+ return v;
+}
+
+/*
+ object = begin-object [ member *( value-separator member ) ]
+ end-object
+*/
+
+Value JsonParser::parseObject()
+{
+ if (++nestingLevel > nestingLimit) {
+ lastError = QJsonParseError::DeepNesting;
+ return Value::undefinedValue();
+ }
+
+ BEGIN << "parseObject pos=" << json;
+
+ Object *o = context->engine->newObject();
+ Value objectVal = Value::fromObject(o);
+
+ QChar token = nextToken();
+ while (token == Quote) {
+ if (!parseMember(o))
+ return Value::undefinedValue();
+ token = nextToken();
+ if (token != ValueSeparator)
+ break;
+ token = nextToken();
+ if (token == EndObject) {
+ lastError = QJsonParseError::MissingObject;
+ return Value::undefinedValue();
+ }
+ }
+
+ DEBUG << "end token=" << token;
+ if (token != EndObject) {
+ lastError = QJsonParseError::UnterminatedObject;
+ return Value::undefinedValue();
+ }
+
+ END;
+
+ --nestingLevel;
+ return objectVal;
+}
+
+/*
+ member = string name-separator value
+*/
+bool JsonParser::parseMember(Object *o)
+{
+ BEGIN << "parseMember";
+
+ QString key;
+ if (!parseString(&key))
+ return false;
+ QChar token = nextToken();
+ if (token != NameSeparator) {
+ lastError = QJsonParseError::MissingNameSeparator;
+ return false;
+ }
+ Value val;
+ if (!parseValue(&val))
+ return false;
+
+ Property *p = o->insertMember(context->engine->newIdentifier(key), Attr_Data);
+ p->value = val;
+
+ END;
+ return true;
+}
+
+/*
+ array = begin-array [ value *( value-separator value ) ] end-array
+*/
+Value JsonParser::parseArray()
+{
+ BEGIN << "parseArray";
+ ArrayObject *array = context->engine->newArrayObject();
+
+ if (++nestingLevel > nestingLimit) {
+ lastError = QJsonParseError::DeepNesting;
+ return Value::undefinedValue();
+ }
+
+ if (!eatSpace()) {
+ lastError = QJsonParseError::UnterminatedArray;
+ return Value::undefinedValue();
+ }
+ if (*json == EndArray) {
+ nextToken();
+ } else {
+ uint index = 0;
+ while (1) {
+ Value val;
+ if (!parseValue(&val))
+ return Value::undefinedValue();
+ array->arraySet(index, val);
+ QChar token = nextToken();
+ if (token == EndArray)
+ break;
+ else if (token != ValueSeparator) {
+ if (!eatSpace())
+ lastError = QJsonParseError::UnterminatedArray;
+ else
+ lastError = QJsonParseError::MissingValueSeparator;
+ return Value::undefinedValue();
+ }
+ ++index;
+ }
+ }
+
+ DEBUG << "size =" << array->arrayLength();
+ END;
+
+ --nestingLevel;
+ return Value::fromObject(array);
+}
+
+/*
+value = false / null / true / object / array / number / string
+
+*/
+
+bool JsonParser::parseValue(Value *val)
+{
+ BEGIN << "parse Value" << *json;
+
+ switch ((json++)->unicode()) {
+ case 'n':
+ if (end - json < 3) {
+ lastError = QJsonParseError::IllegalValue;
+ return false;
+ }
+ if (*json++ == 'u' &&
+ *json++ == 'l' &&
+ *json++ == 'l') {
+ *val = Value::nullValue();
+ DEBUG << "value: null";
+ END;
+ return true;
+ }
+ lastError = QJsonParseError::IllegalValue;
+ return false;
+ case 't':
+ if (end - json < 3) {
+ lastError = QJsonParseError::IllegalValue;
+ return false;
+ }
+ if (*json++ == 'r' &&
+ *json++ == 'u' &&
+ *json++ == 'e') {
+ *val = Value::fromBoolean(true);
+ DEBUG << "value: true";
+ END;
+ return true;
+ }
+ lastError = QJsonParseError::IllegalValue;
+ return false;
+ case 'f':
+ if (end - json < 4) {
+ lastError = QJsonParseError::IllegalValue;
+ return false;
+ }
+ if (*json++ == 'a' &&
+ *json++ == 'l' &&
+ *json++ == 's' &&
+ *json++ == 'e') {
+ *val = Value::fromBoolean(false);
+ DEBUG << "value: false";
+ END;
+ return true;
+ }
+ lastError = QJsonParseError::IllegalValue;
+ return false;
+ case Quote: {
+ QString value;
+ if (!parseString(&value))
+ return false;
+ DEBUG << "value: string";
+ END;
+ *val = Value::fromString(context, value);
+ return true;
+ }
+ case BeginArray: {
+ *val = parseArray();
+ if (val->isUndefined())
+ return false;
+ DEBUG << "value: array";
+ END;
+ return true;
+ }
+ case BeginObject: {
+ *val = parseObject();
+ if (val->isUndefined())
+ return false;
+ DEBUG << "value: object";
+ END;
+ return true;
+ }
+ case EndArray:
+ lastError = QJsonParseError::MissingObject;
+ return false;
+ default:
+ --json;
+ if (!parseNumber(val))
+ return false;
+ DEBUG << "value: number";
+ END;
+ }
+
+ return true;
+}
+
+
+
+
+
+/*
+ number = [ minus ] int [ frac ] [ exp ]
+ decimal-point = %x2E ; .
+ digit1-9 = %x31-39 ; 1-9
+ e = %x65 / %x45 ; e E
+ exp = e [ minus / plus ] 1*DIGIT
+ frac = decimal-point 1*DIGIT
+ int = zero / ( digit1-9 *DIGIT )
+ minus = %x2D ; -
+ plus = %x2B ; +
+ zero = %x30 ; 0
+
+*/
+
+bool JsonParser::parseNumber(Value *val)
+{
+ BEGIN << "parseNumber" << *json;
+
+ const QChar *start = json;
+ bool isInt = true;
+
+ // minus
+ if (json < end && *json == '-')
+ ++json;
+
+ // int = zero / ( digit1-9 *DIGIT )
+ if (json < end && *json == '0') {
+ ++json;
+ } else {
+ while (json < end && *json >= '0' && *json <= '9')
+ ++json;
+ }
+
+ // frac = decimal-point 1*DIGIT
+ if (json < end && *json == '.') {
+ isInt = false;
+ ++json;
+ while (json < end && *json >= '0' && *json <= '9')
+ ++json;
+ }
+
+ // exp = e [ minus / plus ] 1*DIGIT
+ if (json < end && (*json == 'e' || *json == 'E')) {
+ isInt = false;
+ ++json;
+ if (json < end && (*json == '-' || *json == '+'))
+ ++json;
+ while (json < end && *json >= '0' && *json <= '9')
+ ++json;
+ }
+
+ QString number(start, json - start);
+ DEBUG << "numberstring" << number;
+
+ if (isInt) {
+ bool ok;
+ int n = number.toInt(&ok);
+ if (ok && n < (1<<25) && n > -(1<<25)) {
+ *val = Value::fromInt32(n);
+ END;
+ return true;
+ }
+ }
+
+ bool ok;
+ double d;
+ d = number.toDouble(&ok);
+
+ if (!ok) {
+ lastError = QJsonParseError::IllegalNumber;
+ return false;
+ }
+
+ * val = Value::fromDouble(d);
+
+ END;
+ return true;
+}
+
+/*
+
+ string = quotation-mark *char quotation-mark
+
+ char = unescaped /
+ escape (
+ %x22 / ; " quotation mark U+0022
+ %x5C / ; \ reverse solidus U+005C
+ %x2F / ; / solidus U+002F
+ %x62 / ; b backspace U+0008
+ %x66 / ; f form feed U+000C
+ %x6E / ; n line feed U+000A
+ %x72 / ; r carriage return U+000D
+ %x74 / ; t tab U+0009
+ %x75 4HEXDIG ) ; uXXXX U+XXXX
+
+ escape = %x5C ; \
+
+ quotation-mark = %x22 ; "
+
+ unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
+ */
+static inline bool addHexDigit(QChar digit, uint *result)
+{
+ ushort d = digit.unicode();
+ *result <<= 4;
+ if (d >= '0' && d <= '9')
+ *result |= (d - '0');
+ else if (d >= 'a' && d <= 'f')
+ *result |= (d - 'a') + 10;
+ else if (d >= 'A' && d <= 'F')
+ *result |= (d - 'A') + 10;
+ else
+ return false;
+ return true;
+}
+
+static inline bool scanEscapeSequence(const QChar *&json, const QChar *end, uint *ch)
+{
+ ++json;
+ if (json >= end)
+ return false;
+
+ DEBUG << "scan escape";
+ uint escaped = (json++)->unicode();
+ switch (escaped) {
+ case '"':
+ *ch = '"'; break;
+ case '\\':
+ *ch = '\\'; break;
+ case '/':
+ *ch = '/'; break;
+ case 'b':
+ *ch = 0x8; break;
+ case 'f':
+ *ch = 0xc; break;
+ case 'n':
+ *ch = 0xa; break;
+ case 'r':
+ *ch = 0xd; break;
+ case 't':
+ *ch = 0x9; break;
+ case 'u': {
+ *ch = 0;
+ if (json > end - 4)
+ return false;
+ for (int i = 0; i < 4; ++i) {
+ if (!addHexDigit(*json, ch))
+ return false;
+ ++json;
+ }
+ if (*ch <= 0x1f)
+ return false;
+ return true;
+ }
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+bool JsonParser::parseString(QString *string)
+{
+ BEGIN << "parse string stringPos=" << json;
+
+ while (json < end) {
+ if (*json == '"')
+ break;
+ else if (*json == '\\') {
+ uint ch = 0;
+ if (!scanEscapeSequence(json, end, &ch)) {
+ lastError = QJsonParseError::IllegalEscapeSequence;
+ return false;
+ }
+ qDebug() << "scanEscape" << hex << ch;
+ if (QChar::requiresSurrogates(ch)) {
+ *string += QChar::highSurrogate(ch);
+ *string += QChar::lowSurrogate(ch);
+ } else {
+ *string += QChar(ch);
+ }
+ } else {
+ if (json->unicode() <= 0x1f) {
+ lastError = QJsonParseError::IllegalEscapeSequence;
+ return false;
+ }
+ *string += *json;
+ ++json;
+ }
+ }
+ ++json;
+
+ if (json > end) {
+ lastError = QJsonParseError::UnterminatedString;
+ return false;
+ }
+
+ END;
+ return true;
+}
+
+
+struct Stringify
+{
+ ExecutionContext *ctx;
+ FunctionObject *replacerFunction;
+ QVector<String *> propertyList;
+ QString gap;
+ QString indent;
+
+ QStack<Object *> stack;
+
+ Stringify(ExecutionContext *ctx) : ctx(ctx), replacerFunction(0) {}
+
+ QString Str(const QString &key, Value value);
+ QString JA(ArrayObject *a);
+ QString JO(Object *o);
+
+ QString makeMember(const QString &key, Value v);
+};
+
+static QString quote(const QString &str)
+{
+ QString product = "\"";
+ for (int i = 0; i < str.length(); ++i) {
+ QChar c = str.at(i);
+ switch (c.unicode()) {
+ case '"':
+ product += "\\\"";
+ break;
+ case '\\':
+ product += "\\\\";
+ break;
+ case '\b':
+ product += "\\b";
+ break;
+ case '\f':
+ product += "\\f";
+ break;
+ case '\n':
+ product += "\\n";
+ break;
+ case '\r':
+ product += "\\r";
+ break;
+ case '\t':
+ product += "\\t";
+ break;
+ default:
+ if (c.unicode() <= 0x1f) {
+ product += "\\u00";
+ product += c.unicode() > 0xf ? '1' : '0';
+ product += "0123456789abcdef"[c.unicode() & 0xf];
+ } else {
+ product += c;
+ }
+ }
+ }
+ product += '"';
+ return product;
+}
+
+QString Stringify::Str(const QString &key, Value value)
+{
+ QString result;
+
+ if (Object *o = value.asObject()) {
+ FunctionObject *toJSON = o->get(ctx->engine->newString(QStringLiteral("toJSON"))).asFunctionObject();
+ if (toJSON) {
+ Value arg = Value::fromString(ctx, key);
+ value = toJSON->call(value, &arg, 1);
+ }
+ }
+
+ if (replacerFunction) {
+ Object *holder = ctx->engine->newObject();
+ Value holderValue = Value::fromObject(holder);
+ holder->put(ctx, QString(), value);
+ Value args[2];
+ args[0] = Value::fromString(ctx, key);
+ args[1] = value;
+ value = replacerFunction->call(holderValue, args, 2);
+ }
+
+ if (Object *o = value.asObject()) {
+ if (NumberObject *n = o->asNumberObject())
+ value = n->value;
+ else if (StringObject *so = o->asStringObject())
+ value = so->value;
+ else if (BooleanObject *b =o->asBooleanObject())
+ value = b->value;
+ }
+
+ if (value.isNull())
+ return QStringLiteral("null");
+ if (value.isBoolean())
+ return value.booleanValue() ? QStringLiteral("true") : QStringLiteral("false");
+ if (value.isString())
+ return quote(value.stringValue()->toQString());
+
+ if (value.isNumber()) {
+ double d = value.toNumber();
+ return std::isfinite(d) ? value.toString(ctx)->toQString() : QStringLiteral("null");
+ }
+
+ if (Object *o = value.asObject()) {
+ if (!o->asFunctionObject()) {
+ if (o->asArrayObject())
+ return JA(static_cast<ArrayObject *>(o));
+ else
+ return JO(o);
+ }
+ }
+
+ return QString();
+}
+
+QString Stringify::makeMember(const QString &key, Value v)
+{
+ QString strP = Str(key, v);
+ if (!strP.isEmpty()) {
+ QString member = quote(key) + ':';
+ if (!gap.isEmpty())
+ member += ' ';
+ member += strP;
+ return member;
+ }
+ return QString();
+}
+
+QString Stringify::JO(Object *o)
+{
+ if (stack.contains(o))
+ ctx->throwTypeError();
+
+ QString result;
+ stack.push(o);
+ QString stepback = indent;
+ indent += gap;
+
+ QStringList partial;
+ if (propertyList.isEmpty()) {
+ ObjectIterator it(o, ObjectIterator::EnumerableOnly);
+
+ while (1) {
+ Value v;
+ Value name = it.nextPropertyNameAsString(&v);
+ if (name.isNull())
+ break;
+ QString key = name.toQString();
+ QString member = makeMember(key, v);
+ if (!member.isEmpty())
+ partial += member;
+ }
+ } else {
+ for (int i = 0; i < propertyList.size(); ++i) {
+ bool exists;
+ Value v = o->get(propertyList.at(i), &exists);
+ if (!exists)
+ continue;
+ QString member = makeMember(propertyList.at(i)->toQString(), v);
+ if (!member.isEmpty())
+ partial += member;
+ }
+ }
+
+ if (partial.isEmpty()) {
+ result = QStringLiteral("{}");
+ } else if (gap.isEmpty()) {
+ result = "{" + partial.join(",") + "}";
+ } else {
+ QString separator = ",\n" + indent;
+ result = "{\n" + indent + partial.join(separator) + "\n" + stepback + "}";
+ }
+
+ indent = stepback;
+ stack.pop();
+ return result;
+}
+
+QString Stringify::JA(ArrayObject *a)
+{
+ if (stack.contains(a))
+ ctx->throwTypeError();
+
+ QString result;
+ stack.push(a);
+ QString stepback = indent;
+ indent += gap;
+
+ QStringList partial;
+ uint len = a->arrayLength();
+ for (uint i = 0; i < len; ++i) {
+ bool exists;
+ Value v = a->getIndexed(i, &exists);
+ if (!exists) {
+ partial += QStringLiteral("null");
+ continue;
+ }
+ QString strP = Str(QString::number(i), v);
+ if (!strP.isEmpty())
+ partial += strP;
+ else
+ partial += QStringLiteral("null");
+ }
+
+ if (partial.isEmpty()) {
+ result = QStringLiteral("[]");
+ } else if (gap.isEmpty()) {
+ result = "[" + partial.join(",") + "]";
+ } else {
+ QString separator = ",\n" + indent;
+ result = "[\n" + indent + partial.join(separator) + "\n" + stepback + "]";
+ }
+
+ indent = stepback;
+ stack.pop();
+ return result;
+}
+
+
+JsonObject::JsonObject(ExecutionContext *context)
+ : Object(context->engine)
+{
+ type = Type_JSONObject;
+ prototype = context->engine->objectPrototype;
+
+ defineDefaultProperty(context, QStringLiteral("parse"), method_parse, 2);
+ defineDefaultProperty(context, QStringLiteral("stringify"), method_stringify, 3);
+}
+
+
+Value JsonObject::method_parse(SimpleCallContext *ctx)
+{
+ QString jtext = ctx->argument(0).toString(ctx)->toQString();
+
+ DEBUG << "parsing source = " << jtext;
+ JsonParser parser(ctx, jtext.constData(), jtext.length());
+ QJsonParseError error;
+ Value result = parser.parse(&error);
+ if (error.error != QJsonParseError::NoError) {
+ DEBUG << "parse error" << error.errorString();
+ ctx->throwSyntaxError(0);
+ }
+
+ return result;
+}
+
+Value JsonObject::method_stringify(SimpleCallContext *ctx)
+{
+ Stringify stringify(ctx);
+
+ Object *o = ctx->argument(1).asObject();
+ if (o) {
+ stringify.replacerFunction = o->asFunctionObject();
+ if (o->isArrayObject()) {
+ uint arrayLen = o->arrayLength();
+ for (uint i = 0; i < arrayLen; ++i) {
+ Value v = o->getIndexed(i);
+ if (v.asNumberObject() || v.asStringObject() || v.isNumber())
+ v = __qmljs_to_string(v, ctx);
+ if (v.isString()) {
+ String *s = v.stringValue();
+ if (!stringify.propertyList.contains(s))
+ stringify.propertyList.append(s);
+ }
+ }
+ }
+ }
+
+ Value s = ctx->argument(2);
+ if (NumberObject *n = s.asNumberObject())
+ s = n->value;
+ else if (StringObject *so = s.asStringObject())
+ s = so->value;
+
+ if (s.isNumber()) {
+ stringify.gap = QString(qMin(10, (int)s.toInteger()), ' ');
+ } else if (s.isString()) {
+ stringify.gap = s.stringValue()->toQString().left(10);
+ }
+
+
+ QString result = stringify.Str(QString(), ctx->argument(0));
+ if (result.isEmpty())
+ return Value::undefinedValue();
+ return Value::fromString(ctx, result);
+}
+
+
+
+QV4::Value JsonObject::fromJsonValue(ExecutionEngine *engine, const QJsonValue &value)
+{
+ if (value.isString())
+ return Value::fromString(engine->current, value.toString());
+ else if (value.isDouble())
+ return Value::fromDouble(value.toDouble());
+ else if (value.isBool())
+ return Value::fromBoolean(value.toBool());
+ else if (value.isArray())
+ return fromJsonArray(engine, value.toArray());
+ else if (value.isObject())
+ return fromJsonObject(engine, value.toObject());
+ else if (value.isNull())
+ return Value::nullValue();
+ else
+ return Value::undefinedValue();
+}
+
+QJsonValue JsonObject::toJsonValue(const QV4::Value &value,
+ V4ObjectSet &visitedObjects)
+{
+ if (String *s = value.asString())
+ return QJsonValue(s->toQString());
+ else if (value.isNumber())
+ return QJsonValue(value.toNumber());
+ else if (value.isBoolean())
+ return QJsonValue((bool)value.booleanValue());
+ else if (ArrayObject *a = value.asArrayObject())
+ return toJsonArray(a, visitedObjects);
+ else if (Object *o = value.asObject())
+ return toJsonObject(o, visitedObjects);
+ else if (value.isNull())
+ return QJsonValue(QJsonValue::Null);
+ else
+ return QJsonValue(QJsonValue::Undefined);
+}
+
+QV4::Value JsonObject::fromJsonObject(ExecutionEngine *engine, const QJsonObject &object)
+{
+ Object *o = engine->newObject();
+ for (QJsonObject::const_iterator it = object.begin(); it != object.end(); ++it)
+ o->put(engine->newString(it.key()), fromJsonValue(engine, it.value()));
+ return Value::fromObject(o);
+}
+
+QJsonObject JsonObject::toJsonObject(QV4::Object *o, V4ObjectSet &visitedObjects)
+{
+ QJsonObject result;
+ if (!o || o->asFunctionObject())
+ return result;
+
+ if (visitedObjects.contains(o)) {
+ // Avoid recursion.
+ // For compatibility with QVariant{List,Map} conversion, we return an
+ // empty object (and no error is thrown).
+ return result;
+ }
+
+ visitedObjects.insert(o);
+
+ ObjectIterator it(o, ObjectIterator::EnumerableOnly);
+ while (1) {
+ Value v;
+ Value name = it.nextPropertyNameAsString(&v);
+ if (name.isNull())
+ break;
+
+ QString key = name.toQString();
+ if (!v.asFunctionObject())
+ result.insert(key, toJsonValue(v, visitedObjects));
+ }
+
+ visitedObjects.remove(o);
+
+ return result;
+}
+
+QV4::Value JsonObject::fromJsonArray(ExecutionEngine *engine, const QJsonArray &array)
+{
+ int size = array.size();
+ ArrayObject *a = engine->newArrayObject();
+ a->arrayReserve(size);
+ a->arrayDataLen = size;
+ for (int i = 0; i < size; i++)
+ a->arrayData[i].value = fromJsonValue(engine, array.at(i));
+ a->setArrayLengthUnchecked(size);
+ return Value::fromObject(a);
+}
+
+QJsonArray JsonObject::toJsonArray(ArrayObject *a, V4ObjectSet &visitedObjects)
+{
+ QJsonArray result;
+ if (!a)
+ return result;
+
+ if (visitedObjects.contains(a)) {
+ // Avoid recursion.
+ // For compatibility with QVariant{List,Map} conversion, we return an
+ // empty array (and no error is thrown).
+ return result;
+ }
+
+ visitedObjects.insert(a);
+
+ quint32 length = a->arrayLength();
+ for (quint32 i = 0; i < length; ++i) {
+ Value v = a->getIndexed(i);
+ result.append(toJsonValue(v.asFunctionObject() ? QV4::Value::nullValue() : v, visitedObjects));
+ }
+
+ visitedObjects.remove(a);
+
+ return result;
+}
diff --git a/src/qml/qml/v8/qscriptisolate_p.h b/src/qml/qml/v4/qv4jsonobject_p.h
index da35069e33..ccd99d5488 100644
--- a/src/qml/qml/v8/qscriptisolate_p.h
+++ b/src/qml/qml/v4/qv4jsonobject_p.h
@@ -38,52 +38,48 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+#ifndef QV4JSONOBJECTS_H
+#define QV4SJONOBJECTS_H
-#ifndef APIPREAMBLE_P_H
-#define APIPREAMBLE_P_H
-
-#include <private/qv8_p.h>
-#include "qv8engine_p.h"
+#include "qv4object_p.h"
+#include <qjsonarray.h>
+#include <qjsonobject.h>
+#include <qjsonvalue.h>
QT_BEGIN_NAMESPACE
-/**
- \internal
- Class used to switch to the right isolate. It does the same thing as v8::Isolate::Scope but
- it checks for a null engine.
- \attention We decided to put context switching "up" which means that it should be as high
- as possible on call stack. And it should be switched at most once per public API function call.
-*/
-class QScriptIsolate {
+namespace QV4 {
+
+struct JsonObject : Object {
+private:
+ typedef QSet<QV4::Object *> V4ObjectSet;
public:
- // OperationMode was introduced to reduce number of checking for a null engine pointer. If we
- // know that given pointer is not null than we should pass NotNullEngine as constructor argument
- // that would nicely remove checking on compilation time.
- enum OperationMode {Default, NotNullEngine};
- inline QScriptIsolate(const QV8Engine *engine, const OperationMode mode = Default)
- : m_engine(engine)
- , m_mode(mode)
- {
- if (m_mode == NotNullEngine || m_engine) {
- Q_ASSERT(m_engine);
- m_engine->context()->Enter();
- }
- }
+ JsonObject(ExecutionContext *context);
+
+ static Value method_parse(SimpleCallContext *ctx);
+ static Value method_stringify(SimpleCallContext *ctx);
- inline ~QScriptIsolate()
- {
- if (m_mode == NotNullEngine || m_engine) {
- m_engine->context()->Exit();
- }
- }
+ static QV4::Value fromJsonValue(ExecutionEngine *engine, const QJsonValue &value);
+ static QV4::Value fromJsonObject(ExecutionEngine *engine, const QJsonObject &object);
+ static QV4::Value fromJsonArray(ExecutionEngine *engine, const QJsonArray &array);
+
+ static inline QJsonValue toJsonValue(const QV4::Value &value)
+ { V4ObjectSet visitedObjects; return toJsonValue(value, visitedObjects); }
+ static inline QJsonObject toJsonObject(QV4::Object *o)
+ { V4ObjectSet visitedObjects; return toJsonObject(o, visitedObjects); }
+ static inline QJsonArray toJsonArray(QV4::ArrayObject *a)
+ { V4ObjectSet visitedObjects; return toJsonArray(a, visitedObjects); }
private:
- Q_DISABLE_COPY(QScriptIsolate)
- const QV8Engine *m_engine;
- const OperationMode m_mode;
+ static QJsonValue toJsonValue(const QV4::Value &value, V4ObjectSet &visitedObjects);
+ static QJsonObject toJsonObject(QV4::Object *o, V4ObjectSet &visitedObjects);
+ static QJsonArray toJsonArray(QV4::ArrayObject *a, V4ObjectSet &visitedObjects);
+
};
+}
QT_END_NAMESPACE
-#endif // APIPREAMBLE_P_H
+#endif
+
diff --git a/src/qml/qml/v4/qv4lookup.cpp b/src/qml/qml/v4/qv4lookup.cpp
new file mode 100644
index 0000000000..b5ea877bd4
--- /dev/null
+++ b/src/qml/qml/v4/qv4lookup.cpp
@@ -0,0 +1,365 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qv4lookup_p.h"
+#include "qv4functionobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+Property *Lookup::lookup(Object *obj, PropertyAttributes *attrs)
+{
+ int i = 0;
+ while (i < level && obj && obj->internalClass == classList[i]) {
+ obj = obj->prototype;
+ ++i;
+ }
+
+ if (index != UINT_MAX && obj->internalClass == classList[i]) {
+ *attrs = obj->internalClass->propertyData.at(index);
+ return obj->memberData + index;
+ }
+
+ while (i < Size && obj) {
+ classList[i] = obj->internalClass;
+
+ index = obj->internalClass->find(name);
+ if (index != UINT_MAX) {
+ level = i;
+ *attrs = obj->internalClass->propertyData.at(index);
+ return obj->memberData + index;
+ }
+
+ obj = obj->prototype;
+ ++i;
+ }
+ level = i;
+
+ while (obj) {
+ index = obj->internalClass->find(name);
+ if (index != UINT_MAX) {
+ *attrs = obj->internalClass->propertyData.at(index);
+ return obj->memberData + index;
+ }
+
+ obj = obj->prototype;
+ }
+ return 0;
+}
+
+
+void Lookup::getterGeneric(QV4::Lookup *l, QV4::Value *result, const QV4::Value &object)
+{
+ if (Object *o = object.asObject()) {
+ o->getLookup(l, result);
+ return;
+ }
+
+ Value res;
+ if (Managed *m = object.asManaged()) {
+ res = m->get(l->name);
+ } else {
+ ExecutionContext *ctx = l->name->engine()->current;
+ Object *o = __qmljs_convert_to_object(ctx, object);
+ res = o->get(l->name);
+ }
+ if (result)
+ *result = res;
+}
+
+void Lookup::getter0(Lookup *l, Value *result, const Value &object)
+{
+ if (Object *o = object.asObject()) {
+ if (l->classList[0] == o->internalClass) {
+ if (result)
+ *result = o->memberData[l->index].value;
+ return;
+ }
+ }
+ l->getter = getterGeneric;
+ getterGeneric(l, result, object);
+}
+
+void Lookup::getter1(Lookup *l, Value *result, const Value &object)
+{
+ if (Object *o = object.asObject()) {
+ if (l->classList[0] == o->internalClass &&
+ l->classList[1] == o->prototype->internalClass) {
+ if (result)
+ *result = o->prototype->memberData[l->index].value;
+ return;
+ }
+ }
+ l->getter = getterGeneric;
+ getterGeneric(l, result, object);
+}
+
+void Lookup::getter2(Lookup *l, Value *result, const Value &object)
+{
+ if (Object *o = object.asObject()) {
+ if (l->classList[0] == o->internalClass) {
+ o = o->prototype;
+ if (l->classList[1] == o->internalClass) {
+ o = o->prototype;
+ if (l->classList[2] == o->internalClass) {
+ if (result)
+ *result = o->memberData[l->index].value;
+ return;
+ }
+ }
+ }
+ }
+ l->getter = getterGeneric;
+ getterGeneric(l, result, object);
+}
+
+void Lookup::getterAccessor0(Lookup *l, Value *result, const Value &object)
+{
+ if (Object *o = object.asObject()) {
+ if (l->classList[0] == o->internalClass) {
+ Value res;
+ FunctionObject *getter = o->memberData[l->index].getter();
+ if (!getter)
+ res = Value::undefinedValue();
+ else
+ res = getter->call(object, 0, 0);
+ if (result)
+ *result = res;
+ return;
+ }
+ }
+ l->getter = getterGeneric;
+ getterGeneric(l, result, object);
+}
+
+void Lookup::getterAccessor1(Lookup *l, Value *result, const Value &object)
+{
+ if (Object *o = object.asObject()) {
+ if (l->classList[0] == o->internalClass &&
+ l->classList[1] == o->prototype->internalClass) {
+ Value res;
+ FunctionObject *getter = o->prototype->memberData[l->index].getter();
+ if (!getter)
+ res = Value::undefinedValue();
+ else
+ res = getter->call(object, 0, 0);
+ if (result)
+ *result = res;
+ return;
+ }
+ }
+ l->getter = getterGeneric;
+ getterGeneric(l, result, object);
+}
+
+void Lookup::getterAccessor2(Lookup *l, Value *result, const Value &object)
+{
+ if (Object *o = object.asObject()) {
+ if (l->classList[0] == o->internalClass) {
+ o = o->prototype;
+ if (l->classList[1] == o->internalClass) {
+ o = o->prototype;
+ if (l->classList[2] == o->internalClass) {
+ Value res;
+ FunctionObject *getter = o->memberData[l->index].getter();
+ if (!getter)
+ res = Value::undefinedValue();
+ else
+ res = getter->call(object, 0, 0);
+ if (result)
+ *result = res;
+ return;
+ }
+ }
+ }
+ }
+ l->getter = getterGeneric;
+ getterGeneric(l, result, object);
+}
+
+
+void Lookup::globalGetterGeneric(Lookup *l, ExecutionContext *ctx, Value *result)
+{
+ Object *o = ctx->engine->globalObject;
+ PropertyAttributes attrs;
+ Property *p = l->lookup(o, &attrs);
+ if (p) {
+ if (attrs.isData()) {
+ if (l->level == 0)
+ l->globalGetter = globalGetter0;
+ else if (l->level == 1)
+ l->globalGetter = globalGetter1;
+ else if (l->level == 2)
+ l->globalGetter = globalGetter2;
+ *result = p->value;
+ return;
+ } else {
+ if (l->level == 0)
+ l->globalGetter = globalGetterAccessor0;
+ else if (l->level == 1)
+ l->globalGetter = globalGetterAccessor1;
+ else if (l->level == 2)
+ l->globalGetter = globalGetterAccessor2;
+ Value res = o->getValue(p, attrs);
+ if (result)
+ *result = res;
+ return;
+ }
+ }
+ ctx->throwReferenceError(Value::fromString(l->name));
+}
+
+void Lookup::globalGetter0(Lookup *l, ExecutionContext *ctx, Value *result)
+{
+ Object *o = ctx->engine->globalObject;
+ if (l->classList[0] == o->internalClass) {
+ *result = o->memberData[l->index].value;
+ return;
+ }
+ l->globalGetter = globalGetterGeneric;
+ globalGetterGeneric(l, ctx, result);
+}
+
+void Lookup::globalGetter1(Lookup *l, ExecutionContext *ctx, Value *result)
+{
+ Object *o = ctx->engine->globalObject;
+ if (l->classList[0] == o->internalClass &&
+ l->classList[1] == o->prototype->internalClass) {
+ *result = o->prototype->memberData[l->index].value;
+ return;
+ }
+ l->globalGetter = globalGetterGeneric;
+ globalGetterGeneric(l, ctx, result);
+}
+
+void Lookup::globalGetter2(Lookup *l, ExecutionContext *ctx, Value *result)
+{
+ Object *o = ctx->engine->globalObject;
+ if (l->classList[0] == o->internalClass) {
+ o = o->prototype;
+ if (l->classList[1] == o->internalClass) {
+ o = o->prototype;
+ if (l->classList[2] == o->internalClass) {
+ *result = o->prototype->memberData[l->index].value;
+ return;
+ }
+ }
+ }
+ l->globalGetter = globalGetterGeneric;
+ globalGetterGeneric(l, ctx, result);
+}
+
+void Lookup::globalGetterAccessor0(Lookup *l, ExecutionContext *ctx, Value *result)
+{
+ Object *o = ctx->engine->globalObject;
+ if (l->classList[0] == o->internalClass) {
+ FunctionObject *getter = o->memberData[l->index].getter();
+ if (!getter)
+ *result = Value::undefinedValue();
+ else
+ *result = getter->call(Value::undefinedValue(), 0, 0);
+ return;
+ }
+ l->globalGetter = globalGetterGeneric;
+ globalGetterGeneric(l, ctx, result);
+}
+
+void Lookup::globalGetterAccessor1(Lookup *l, ExecutionContext *ctx, Value *result)
+{
+ Object *o = ctx->engine->globalObject;
+ if (l->classList[0] == o->internalClass &&
+ l->classList[1] == o->prototype->internalClass) {
+ FunctionObject *getter = o->prototype->memberData[l->index].getter();
+ if (!getter)
+ *result = Value::undefinedValue();
+ else
+ *result = getter->call(Value::undefinedValue(), 0, 0);
+ return;
+ }
+ l->globalGetter = globalGetterGeneric;
+ globalGetterGeneric(l, ctx, result);
+}
+
+void Lookup::globalGetterAccessor2(Lookup *l, ExecutionContext *ctx, Value *result)
+{
+ Object *o = ctx->engine->globalObject;
+ if (l->classList[0] == o->internalClass) {
+ o = o->prototype;
+ if (l->classList[1] == o->internalClass) {
+ o = o->prototype;
+ if (l->classList[2] == o->internalClass) {
+ FunctionObject *getter = o->memberData[l->index].getter();
+ if (!getter)
+ *result = Value::undefinedValue();
+ else
+ *result = getter->call(Value::undefinedValue(), 0, 0);
+ return;
+ }
+ }
+ }
+ l->globalGetter = globalGetterGeneric;
+ globalGetterGeneric(l, ctx, result);
+}
+
+void Lookup::setterGeneric(Lookup *l, const Value &object, const Value &value)
+{
+ Object *o = object.asObject();
+ if (!o) {
+ o = __qmljs_convert_to_object(l->name->engine()->current, object);
+ o->put(l->name, value);
+ return;
+ }
+ o->setLookup(l, value);
+}
+
+void Lookup::setter0(Lookup *l, const Value &object, const Value &value)
+{
+ Object *o = object.asObject();
+ if (o && o->internalClass == l->classList[0]) {
+ o->memberData[l->index].value = value;
+ return;
+ }
+
+ l->setter = setterGeneric;
+ setterGeneric(l, object, value);
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8sqlerrors.cpp b/src/qml/qml/v4/qv4lookup_p.h
index e06069cddd..e77552826a 100644
--- a/src/qml/qml/v8/qv8sqlerrors.cpp
+++ b/src/qml/qml/v4/qv4lookup_p.h
@@ -38,27 +38,57 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+#ifndef QV4LOOKUP_H
+#define QV4LOOKUP_H
-#include "qv8sqlerrors_p.h"
-#include "qv8engine_p.h"
+#include "qv4global_p.h"
+#include "qv4runtime_p.h"
+#include "qv4engine_p.h"
+#include "qv4context_p.h"
+#include "qv4object_p.h"
+#include "qv4internalclass_p.h"
QT_BEGIN_NAMESPACE
-void qt_add_sqlexceptions(QV8Engine *engine)
-{
- // SQL Exception
- v8::PropertyAttribute attributes = (v8::PropertyAttribute)(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
+namespace QV4 {
+
+struct Lookup {
+ enum { Size = 3 };
+ union {
+ void (*getter)(Lookup *l, Value *result, const Value &object);
+ void (*globalGetter)(Lookup *l, ExecutionContext *ctx, Value *result);
+ void (*setter)(Lookup *l, const Value &object, const Value &v);
+ };
+ InternalClass *classList[Size];
+ int level;
+ uint index;
+ String *name;
+
+ static void getterGeneric(Lookup *l, Value *result, const Value &object);
+ static void getter0(Lookup *l, Value *result, const Value &object);
+ static void getter1(Lookup *l, Value *result, const Value &object);
+ static void getter2(Lookup *l, Value *result, const Value &object);
+ static void getterAccessor0(Lookup *l, Value *result, const Value &object);
+ static void getterAccessor1(Lookup *l, Value *result, const Value &object);
+ static void getterAccessor2(Lookup *l, Value *result, const Value &object);
+
+ static void globalGetterGeneric(Lookup *l, ExecutionContext *ctx, Value *result);
+ static void globalGetter0(Lookup *l, ExecutionContext *ctx, Value *result);
+ static void globalGetter1(Lookup *l, ExecutionContext *ctx, Value *result);
+ static void globalGetter2(Lookup *l, ExecutionContext *ctx, Value *result);
+ static void globalGetterAccessor0(Lookup *l, ExecutionContext *ctx, Value *result);
+ static void globalGetterAccessor1(Lookup *l, ExecutionContext *ctx, Value *result);
+ static void globalGetterAccessor2(Lookup *l, ExecutionContext *ctx, Value *result);
+
+ static void setterGeneric(Lookup *l, const Value &object, const Value &value);
+ static void setter0(Lookup *l, const Value &object, const Value &value);
+
+ Property *lookup(Object *obj, PropertyAttributes *attrs);
+
+};
- v8::Local<v8::Object> sqlexception = v8::Object::New();
- sqlexception->Set(v8::String::New("UNKNOWN_ERR"), v8::Integer::New(SQLEXCEPTION_UNKNOWN_ERR), attributes);
- sqlexception->Set(v8::String::New("DATABASE_ERR"), v8::Integer::New(SQLEXCEPTION_DATABASE_ERR), attributes);
- sqlexception->Set(v8::String::New("VERSION_ERR"), v8::Integer::New(SQLEXCEPTION_VERSION_ERR), attributes);
- sqlexception->Set(v8::String::New("TOO_LARGE_ERR"), v8::Integer::New(SQLEXCEPTION_TOO_LARGE_ERR), attributes);
- sqlexception->Set(v8::String::New("QUOTA_ERR"), v8::Integer::New(SQLEXCEPTION_QUOTA_ERR), attributes);
- sqlexception->Set(v8::String::New("SYNTAX_ERR"), v8::Integer::New(SQLEXCEPTION_SYNTAX_ERR), attributes);
- sqlexception->Set(v8::String::New("CONSTRAINT_ERR"), v8::Integer::New(SQLEXCEPTION_CONSTRAINT_ERR), attributes);
- sqlexception->Set(v8::String::New("TIMEOUT_ERR"), v8::Integer::New(SQLEXCEPTION_TIMEOUT_ERR), attributes);
- engine->global()->Set(v8::String::New("SQLException"), sqlexception);
}
QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v4/qv4managed.cpp b/src/qml/qml/v4/qv4managed.cpp
new file mode 100644
index 0000000000..19adb354e3
--- /dev/null
+++ b/src/qml/qml/v4/qv4managed.cpp
@@ -0,0 +1,212 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4managed_p.h"
+#include "qv4mm_p.h"
+#include "qv4errorobject_p.h"
+
+using namespace QV4;
+
+const ManagedVTable Managed::static_vtbl =
+{
+ call,
+ construct,
+ 0 /*markObjects*/,
+ destroy,
+ 0 /*collectDeletables*/,
+ hasInstance,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ isEqualTo,
+ 0,
+ "Managed",
+};
+
+
+void *Managed::operator new(size_t size, MemoryManager *mm)
+{
+ assert(mm);
+
+ return mm->allocManaged(size);
+}
+
+void Managed::operator delete(void *ptr)
+{
+ if (!ptr)
+ return;
+
+ Managed *m = static_cast<Managed *>(ptr);
+ m->vtbl = 0;
+ m->_data = 0;
+ m->~Managed();
+}
+
+void Managed::operator delete(void *ptr, MemoryManager *mm)
+{
+ Q_UNUSED(mm);
+
+ operator delete(ptr);
+}
+
+ExecutionEngine *Managed::engine() const
+{
+ return internalClass ? internalClass->engine : 0;
+}
+
+QString Managed::className() const
+{
+ const char *s = 0;
+ switch (Type(type)) {
+ case Type_Invalid:
+ case Type_String:
+ return QString();
+ case Type_Object:
+ s = "Object";
+ break;
+ case Type_ArrayObject:
+ s = "Array";
+ break;
+ case Type_FunctionObject:
+ s = "Function";
+ break;
+ case Type_BooleanObject:
+ s = "Boolean";
+ break;
+ case Type_NumberObject:
+ s = "Number";
+ break;
+ case Type_StringObject:
+ s = "String";
+ break;
+ case Type_DateObject:
+ s = "Date";
+ break;
+ case Type_RegExpObject:
+ s = "RegExp";
+ break;
+ case Type_ErrorObject:
+ switch (ErrorObject::ErrorType(subtype)) {
+ case ErrorObject::Error:
+ s = "Error";
+ break;
+ case ErrorObject::EvalError:
+ s = "EvalError";
+ break;
+ case ErrorObject::RangeError:
+ s = "RangeError";
+ break;
+ case ErrorObject::ReferenceError:
+ s = "ReferenceError";
+ break;
+ case ErrorObject::SyntaxError:
+ s = "SyntaxError";
+ break;
+ case ErrorObject::TypeError:
+ s = "TypeError";
+ break;
+ case ErrorObject::URIError:
+ s = "URIError";
+ break;
+ }
+ break;
+ case Type_ArgumentsObject:
+ s = "Arguments";
+ break;
+ case Type_JSONObject:
+ s = "JSON";
+ break;
+ case Type_MathObject:
+ s = "Math";
+ break;
+ case Type_ForeachIteratorObject:
+ s = "__ForeachIterator";
+ break;
+ }
+ return QString::fromLatin1(s);
+}
+
+bool Managed::hasInstance(Managed *m, const Value &)
+{
+ m->engine()->current->throwTypeError();
+}
+
+Value Managed::construct(Managed *m, Value *, int)
+{
+ m->engine()->current->throwTypeError();
+}
+
+Value Managed::call(Managed *m, const Value &, Value *, int)
+{
+ m->engine()->current->throwTypeError();
+}
+
+void Managed::getLookup(Managed *m, Lookup *, Value *)
+{
+ m->engine()->current->throwTypeError();
+}
+
+void Managed::setLookup(Managed *m, Lookup *, const Value &)
+{
+ m->engine()->current->throwTypeError();
+}
+
+bool Managed::isEqualTo(Managed *, Managed *)
+{
+ return false;
+}
+
+Value Managed::get(String *name, bool *hasProperty)
+{
+ return vtbl->get(this, name, hasProperty);
+}
+
+Value Managed::getIndexed(uint index, bool *hasProperty)
+{
+ return vtbl->getIndexed(this, index, hasProperty);
+}
diff --git a/src/qml/qml/v4/qv4managed_p.h b/src/qml/qml/v4/qv4managed_p.h
new file mode 100644
index 0000000000..5e3c142bb8
--- /dev/null
+++ b/src/qml/qml/v4/qv4managed_p.h
@@ -0,0 +1,321 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QMLJS_MANAGED_H
+#define QMLJS_MANAGED_H
+
+#include <QtCore/QString>
+#include <QtCore/QVector>
+#include <QtCore/QDebug>
+#include "qv4global_p.h"
+#include "qv4value_def_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+#define Q_MANAGED_CHECK \
+ template <typename T> inline void qt_check_for_QMANAGED_macro(const T &_q_argument) const \
+ { int i = qYouForgotTheQ_MANAGED_Macro(this, &_q_argument); i = i + 1; }
+
+template <typename T>
+inline int qYouForgotTheQ_MANAGED_Macro(T, T) { return 0; }
+
+template <typename T1, typename T2>
+inline void qYouForgotTheQ_MANAGED_Macro(T1, T2) {}
+
+#define Q_MANAGED \
+ public: \
+ Q_MANAGED_CHECK \
+ static const QV4::ManagedVTable static_vtbl;
+
+struct GCDeletable
+{
+ GCDeletable() : next(0), lastCall(false) {}
+ virtual ~GCDeletable() {}
+ GCDeletable *next;
+ bool lastCall;
+};
+
+struct ManagedVTable
+{
+ Value (*call)(Managed *, const Value &thisObject, Value *args, int argc);
+ Value (*construct)(Managed *, Value *args, int argc);
+ void (*markObjects)(Managed *);
+ void (*destroy)(Managed *);
+ void (*collectDeletables)(Managed *, GCDeletable **deletable);
+ bool (*hasInstance)(Managed *, const Value &value);
+ Value (*get)(Managed *, String *name, bool *hasProperty);
+ Value (*getIndexed)(Managed *, uint index, bool *hasProperty);
+ void (*put)(Managed *, String *name, const Value &value);
+ void (*putIndexed)(Managed *, uint index, const Value &value);
+ PropertyAttributes (*query)(const Managed *, String *name);
+ PropertyAttributes (*queryIndexed)(const Managed *, uint index);
+ bool (*deleteProperty)(Managed *m, String *name);
+ bool (*deleteIndexedProperty)(Managed *m, uint index);
+ void (*getLookup)(Managed *m, Lookup *l, Value *result);
+ void (*setLookup)(Managed *m, Lookup *l, const Value &v);
+ bool (*isEqualTo)(Managed *m, Managed *other);
+ Property *(*advanceIterator)(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes);
+ const char *className;
+};
+
+#define DEFINE_MANAGED_VTABLE(classname) \
+const QV4::ManagedVTable classname::static_vtbl = \
+{ \
+ call, \
+ construct, \
+ markObjects, \
+ destroy, \
+ 0, \
+ hasInstance, \
+ get, \
+ getIndexed, \
+ put, \
+ putIndexed, \
+ query, \
+ queryIndexed, \
+ deleteProperty, \
+ deleteIndexedProperty, \
+ getLookup, \
+ setLookup, \
+ isEqualTo, \
+ advanceIterator, \
+ #classname \
+}
+
+#define DEFINE_MANAGED_VTABLE_WITH_DELETABLES(classname) \
+const QV4::ManagedVTable classname::static_vtbl = \
+{ \
+ call, \
+ construct, \
+ markObjects, \
+ destroy, \
+ collectDeletables, \
+ hasInstance, \
+ get, \
+ getIndexed, \
+ put, \
+ putIndexed, \
+ query, \
+ queryIndexed, \
+ deleteProperty, \
+ deleteIndexedProperty, \
+ getLookup, \
+ setLookup, \
+ isEqualTo, \
+ advanceIterator, \
+ #classname \
+}
+
+struct Q_QML_EXPORT Managed
+{
+private:
+ void *operator new(size_t);
+ Managed(const Managed &other);
+ void operator = (const Managed &other);
+
+protected:
+ Managed(InternalClass *internal)
+ : _data(0), vtbl(&static_vtbl), internalClass(internal)
+ { inUse = 1; extensible = 1; }
+
+public:
+ void *operator new(size_t size, MemoryManager *mm);
+ void operator delete(void *ptr);
+ void operator delete(void *ptr, MemoryManager *mm);
+
+ inline void mark() {
+ if (markBit)
+ return;
+ markBit = 1;
+ if (vtbl->markObjects)
+ vtbl->markObjects(this);
+ }
+
+ enum Type {
+ Type_Invalid,
+ Type_String,
+ Type_Object,
+ Type_ArrayObject,
+ Type_FunctionObject,
+ Type_BooleanObject,
+ Type_NumberObject,
+ Type_StringObject,
+ Type_DateObject,
+ Type_RegExpObject,
+ Type_ErrorObject,
+ Type_ArgumentsObject,
+ Type_JSONObject,
+ Type_MathObject,
+ Type_ForeachIteratorObject,
+ Type_RegExp,
+
+ Type_QmlSequence
+ };
+
+ ExecutionEngine *engine() const;
+
+ template <typename T>
+ T *as() {
+#if !defined(QT_NO_QOBJECT_CHECK)
+ reinterpret_cast<T *>(this)->qt_check_for_QMANAGED_macro(*reinterpret_cast<T *>(this));
+#endif
+ return vtbl == &T::static_vtbl ? static_cast<T *>(this) : 0;
+ }
+ template <typename T>
+ const T *as() const {
+#if !defined(QT_NO_QOBJECT_CHECK)
+ reinterpret_cast<T *>(this)->qt_check_for_QMANAGED_macro(*reinterpret_cast<T *>(const_cast<Managed *>(this)));
+#endif
+ return vtbl == &T::static_vtbl ? static_cast<const T *>(this) : 0;
+ }
+
+ ArrayObject *asArrayObject() { return type == Type_ArrayObject ? reinterpret_cast<ArrayObject *>(this) : 0; }
+ FunctionObject *asFunctionObject() { return type == Type_FunctionObject ? reinterpret_cast<FunctionObject *>(this) : 0; }
+ BooleanObject *asBooleanObject() { return type == Type_BooleanObject ? reinterpret_cast<BooleanObject *>(this) : 0; }
+ NumberObject *asNumberObject() { return type == Type_NumberObject ? reinterpret_cast<NumberObject *>(this) : 0; }
+ StringObject *asStringObject() { return type == Type_StringObject ? reinterpret_cast<StringObject *>(this) : 0; }
+ DateObject *asDateObject() { return type == Type_DateObject ? reinterpret_cast<DateObject *>(this) : 0; }
+ ErrorObject *asErrorObject() { return type == Type_ErrorObject ? reinterpret_cast<ErrorObject *>(this) : 0; }
+ ArgumentsObject *asArgumentsObject() { return type == Type_ArgumentsObject ? reinterpret_cast<ArgumentsObject *>(this) : 0; }
+
+ bool isListType() const { return type == Type_QmlSequence; }
+
+ bool isArrayObject() const { return type == Type_ArrayObject; }
+ bool isStringObject() const { return type == Type_StringObject; }
+
+ QString className() const;
+
+ Managed **nextFreeRef() {
+ return reinterpret_cast<Managed **>(this);
+ }
+ Managed *nextFree() {
+ return *reinterpret_cast<Managed **>(this);
+ }
+ void setNextFree(Managed *m) {
+ *reinterpret_cast<Managed **>(this) = m;
+ }
+
+ inline bool hasInstance(const Value &v) {
+ return vtbl->hasInstance(this, v);
+ }
+ Value construct(Value *args, int argc);
+ Value call(const Value &thisObject, Value *args, int argc);
+ Value get(String *name, bool *hasProperty = 0);
+ Value getIndexed(uint index, bool *hasProperty = 0);
+ void put(String *name, const Value &value)
+ { vtbl->put(this, name, value); }
+ void putIndexed(uint index, const Value &value)
+ { vtbl->putIndexed(this, index, value); }
+ PropertyAttributes query(String *name) const
+ { return vtbl->query(this, name); }
+ PropertyAttributes queryIndexed(uint index) const
+ { return vtbl->queryIndexed(this, index); }
+
+ bool deleteProperty(String *name)
+ { return vtbl->deleteProperty(this, name); }
+ bool deleteIndexedProperty(uint index)
+ { return vtbl->deleteIndexedProperty(this, index); }
+ void getLookup(Lookup *l, Value *result)
+ { vtbl->getLookup(this, l, result); }
+ void setLookup(Lookup *l, const Value &v)
+ { vtbl->setLookup(this, l, v); }
+
+ bool isEqualTo(Managed *other)
+ { return vtbl->isEqualTo(this, other); }
+ Property *advanceIterator(ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes)
+ { return vtbl->advanceIterator(this, it, name, index, attributes); }
+
+ static void destroy(Managed *that) { that->_data = 0; }
+ static bool hasInstance(Managed *that, const Value &value);
+ static Value construct(Managed *m, Value *, int);
+ static Value call(Managed *m, const Value &, Value *, int);
+ static void getLookup(Managed *m, Lookup *, Value *);
+ static void setLookup(Managed *m, Lookup *l, const Value &v);
+ static bool isEqualTo(Managed *m, Managed *other);
+
+ uint internalType() const {
+ return type;
+ }
+
+ union {
+ uint _data;
+ struct {
+ uint markBit : 1;
+ uint inUse : 1;
+ uint extensible : 1; // used by Object
+ uint isNonStrictArgumentsObject : 1;
+ uint isBuiltinFunction : 1; // used by FunctionObject
+ uint needsActivation : 1; // used by FunctionObject
+ uint usesArgumentsObject : 1; // used by FunctionObject
+ uint strictMode : 1; // used by FunctionObject
+ uint type : 8;
+ mutable uint subtype : 3;
+ uint bindingKeyFlag : 1;
+ uint unused : 12;
+ };
+ };
+
+protected:
+
+ static const ManagedVTable static_vtbl;
+
+ const ManagedVTable *vtbl;
+public:
+ InternalClass *internalClass;
+
+private:
+ friend class MemoryManager;
+ friend struct Identifiers;
+ friend struct ObjectIterator;
+};
+
+// ### Not a good placement
+template<typename T>
+inline T *Value::as() const { Managed *m = isObject() ? managed() : 0; return m ? m->as<T>() : 0; }
+
+
+}
+
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v4/qv4math_p.h b/src/qml/qml/v4/qv4math_p.h
new file mode 100644
index 0000000000..a3a3715545
--- /dev/null
+++ b/src/qml/qml/v4/qv4math_p.h
@@ -0,0 +1,147 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QMLJS_MATH_H
+#define QMLJS_MATH_H
+
+#include <qglobal.h>
+
+#ifndef QMLJS_LLVM_RUNTIME
+# include <QtCore/qnumeric.h>
+#endif // QMLJS_LLVM_RUNTIME
+#include <cmath>
+
+#if defined(Q_CC_GNU)
+#define QMLJS_READONLY __attribute((const))
+#else
+#define QMLJS_READONLY
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+#if !defined(QMLJS_LLVM_RUNTIME) && defined(Q_CC_GNU) && defined(Q_PROCESSOR_X86)
+
+static inline QMLJS_READONLY Value add_int32(int a, int b)
+{
+ quint8 overflow = 0;
+ int aa = a;
+
+ asm ("addl %2, %1\n"
+ "seto %0"
+ : "=q" (overflow), "=r" (aa)
+ : "r" (b), "1" (aa)
+ : "cc"
+ );
+ if (!overflow)
+ return Value::fromInt32(aa);
+ return Value::fromDouble((double)a + (double)b);
+}
+
+static inline QMLJS_READONLY Value sub_int32(int a, int b)
+{
+ quint8 overflow = 0;
+ int aa = a;
+
+ asm ("subl %2, %1\n"
+ "seto %0"
+ : "=q" (overflow), "=r" (aa)
+ : "r" (b), "1" (aa)
+ : "cc"
+ );
+ if (!overflow)
+ return Value::fromInt32(aa);
+ return Value::fromDouble((double)a - (double)b);
+}
+
+static inline QMLJS_READONLY Value mul_int32(int a, int b)
+{
+ quint8 overflow = 0;
+ int aa = a;
+
+ asm ("imul %2, %1\n"
+ "setc %0"
+ : "=q" (overflow), "=r" (aa)
+ : "r" (b), "1" (aa)
+ : "cc"
+ );
+ if (!overflow)
+ return Value::fromInt32(aa);
+ return Value::fromDouble((double)a * (double)b);
+}
+
+#else
+
+static inline QMLJS_READONLY Value add_int32(int a, int b)
+{
+ qint64 result = a + b;
+ if (result > INT_MAX || result < INT_MIN)
+ return Value::fromDouble(result);
+ return Value::fromInt32(static_cast<int>(result));
+}
+
+static inline QMLJS_READONLY Value sub_int32(int a, int b)
+{
+ qint64 result = a - b;
+ if (result > INT_MAX || result < INT_MIN)
+ return Value::fromDouble(result);
+ return Value::fromInt32(static_cast<int>(result));
+}
+
+static inline QMLJS_READONLY Value mul_int32(int a, int b)
+{
+ qint64 result = a * b;
+ if (result > INT_MAX || result < INT_MIN)
+ return Value::fromDouble(result);
+ return Value::fromInt32(static_cast<int>(result));
+}
+
+#endif // defined(QMLJS_INLINE_MATH)
+
+}
+
+QT_END_NAMESPACE
+
+#ifdef QMLJS_READONLY
+#undef QMLJS_READONLY
+#endif
+
+#endif // QMLJS_MATH_H
diff --git a/src/qml/qml/v4/qv4mathobject.cpp b/src/qml/qml/v4/qv4mathobject.cpp
new file mode 100644
index 0000000000..7aa56f51bd
--- /dev/null
+++ b/src/qml/qml/v4/qv4mathobject.cpp
@@ -0,0 +1,311 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4mathobject_p.h"
+#include "qv4objectproto_p.h"
+
+#include <cmath>
+#include <qmath.h>
+#include <qnumeric.h>
+
+using namespace QV4;
+
+static const double qt_PI = 2.0 * ::asin(1.0);
+
+MathObject::MathObject(ExecutionContext *ctx)
+ : Object(ctx->engine)
+{
+ type = Type_MathObject;
+ prototype = ctx->engine->objectPrototype;
+
+ defineReadonlyProperty(ctx->engine, QStringLiteral("E"), Value::fromDouble(::exp(1.0)));
+ defineReadonlyProperty(ctx->engine, QStringLiteral("LN2"), Value::fromDouble(::log(2.0)));
+ defineReadonlyProperty(ctx->engine, QStringLiteral("LN10"), Value::fromDouble(::log(10.0)));
+ defineReadonlyProperty(ctx->engine, QStringLiteral("LOG2E"), Value::fromDouble(1.0/::log(2.0)));
+ defineReadonlyProperty(ctx->engine, QStringLiteral("LOG10E"), Value::fromDouble(1.0/::log(10.0)));
+ defineReadonlyProperty(ctx->engine, QStringLiteral("PI"), Value::fromDouble(qt_PI));
+ defineReadonlyProperty(ctx->engine, QStringLiteral("SQRT1_2"), Value::fromDouble(::sqrt(0.5)));
+ defineReadonlyProperty(ctx->engine, QStringLiteral("SQRT2"), Value::fromDouble(::sqrt(2.0)));
+
+ defineDefaultProperty(ctx, QStringLiteral("abs"), method_abs, 1);
+ defineDefaultProperty(ctx, QStringLiteral("acos"), method_acos, 1);
+ defineDefaultProperty(ctx, QStringLiteral("asin"), method_asin, 0);
+ defineDefaultProperty(ctx, QStringLiteral("atan"), method_atan, 1);
+ defineDefaultProperty(ctx, QStringLiteral("atan2"), method_atan2, 2);
+ defineDefaultProperty(ctx, QStringLiteral("ceil"), method_ceil, 1);
+ defineDefaultProperty(ctx, QStringLiteral("cos"), method_cos, 1);
+ defineDefaultProperty(ctx, QStringLiteral("exp"), method_exp, 1);
+ defineDefaultProperty(ctx, QStringLiteral("floor"), method_floor, 1);
+ defineDefaultProperty(ctx, QStringLiteral("log"), method_log, 1);
+ defineDefaultProperty(ctx, QStringLiteral("max"), method_max, 2);
+ defineDefaultProperty(ctx, QStringLiteral("min"), method_min, 2);
+ defineDefaultProperty(ctx, QStringLiteral("pow"), method_pow, 2);
+ defineDefaultProperty(ctx, QStringLiteral("random"), method_random, 0);
+ defineDefaultProperty(ctx, QStringLiteral("round"), method_round, 1);
+ defineDefaultProperty(ctx, QStringLiteral("sin"), method_sin, 1);
+ defineDefaultProperty(ctx, QStringLiteral("sqrt"), method_sqrt, 1);
+ defineDefaultProperty(ctx, QStringLiteral("tan"), method_tan, 1);
+}
+
+/* copies the sign from y to x and returns the result */
+static double copySign(double x, double y)
+{
+ uchar *xch = (uchar *)&x;
+ uchar *ych = (uchar *)&y;
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ xch[0] = (xch[0] & 0x7f) | (ych[0] & 0x80);
+ else
+ xch[7] = (xch[7] & 0x7f) | (ych[7] & 0x80);
+ return x;
+}
+
+Value MathObject::method_abs(SimpleCallContext *context)
+{
+ if (!context->argumentCount)
+ return Value::fromDouble(qSNaN());
+
+ if (context->arguments[0].isInteger()) {
+ int i = context->arguments[0].integerValue();
+ return Value::fromInt32(i < 0 ? - i : i);
+ }
+
+ double v = context->arguments[0].toNumber();
+ if (v == 0) // 0 | -0
+ return Value::fromDouble(0);
+
+ return Value::fromDouble(v < 0 ? -v : v);
+}
+
+Value MathObject::method_acos(SimpleCallContext *context)
+{
+ double v = context->argumentCount ? context->arguments[0].toNumber() : 2;
+ if (v > 1)
+ return Value::fromDouble(qSNaN());
+
+ return Value::fromDouble(::acos(v));
+}
+
+Value MathObject::method_asin(SimpleCallContext *context)
+{
+ double v = context->argumentCount ? context->arguments[0].toNumber() : 2;
+ if (v > 1)
+ return Value::fromDouble(qSNaN());
+ else
+ return Value::fromDouble(::asin(v));
+}
+
+Value MathObject::method_atan(SimpleCallContext *context)
+{
+ double v = context->argumentCount ? context->arguments[0].toNumber() : qSNaN();
+ if (v == 0.0)
+ return Value::fromDouble(v);
+ else
+ return Value::fromDouble(::atan(v));
+}
+
+Value MathObject::method_atan2(SimpleCallContext *context)
+{
+ double v1 = context->argumentCount ? context->arguments[0].toNumber() : qSNaN();
+ double v2 = context->argumentCount > 1 ? context->arguments[1].toNumber() : qSNaN();
+
+ if ((v1 < 0) && qIsFinite(v1) && qIsInf(v2) && (copySign(1.0, v2) == 1.0))
+ return Value::fromDouble(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 Value::fromDouble(qt_PI);
+ } else if ((copySign(1.0, v1) == -1.0) && (copySign(1.0, v2) == -1.0)) {
+ return Value::fromDouble(-qt_PI);
+ }
+ }
+ return Value::fromDouble(::atan2(v1, v2));
+}
+
+Value MathObject::method_ceil(SimpleCallContext *context)
+{
+ double v = context->argumentCount ? context->arguments[0].toNumber() : qSNaN();
+ if (v < 0.0 && v > -1.0)
+ return Value::fromDouble(copySign(0, -1.0));
+ else
+ return Value::fromDouble(::ceil(v));
+}
+
+Value MathObject::method_cos(SimpleCallContext *context)
+{
+ double v = context->argumentCount ? context->arguments[0].toNumber() : qSNaN();
+ return Value::fromDouble(::cos(v));
+}
+
+Value MathObject::method_exp(SimpleCallContext *context)
+{
+ double v = context->argumentCount ? context->arguments[0].toNumber() : qSNaN();
+ if (qIsInf(v)) {
+ if (copySign(1.0, v) == -1.0)
+ return Value::fromDouble(0);
+ else
+ return Value::fromDouble(qInf());
+ } else {
+ return Value::fromDouble(::exp(v));
+ }
+}
+
+Value MathObject::method_floor(SimpleCallContext *context)
+{
+ double v = context->argumentCount ? context->arguments[0].toNumber() : qSNaN();
+ return Value::fromDouble(::floor(v));
+}
+
+Value MathObject::method_log(SimpleCallContext *context)
+{
+ double v = context->argumentCount ? context->arguments[0].toNumber() : qSNaN();
+ if (v < 0)
+ return Value::fromDouble(qSNaN());
+ else
+ return Value::fromDouble(::log(v));
+}
+
+Value MathObject::method_max(SimpleCallContext *context)
+{
+ double mx = -qInf();
+ for (unsigned i = 0; i < context->argumentCount; ++i) {
+ double x = context->arguments[i].toNumber();
+ if (x > mx || std::isnan(x))
+ mx = x;
+ }
+ return Value::fromDouble(mx);
+}
+
+Value MathObject::method_min(SimpleCallContext *context)
+{
+ double mx = qInf();
+ for (unsigned i = 0; i < context->argumentCount; ++i) {
+ double x = context->arguments[i].toNumber();
+ if ((x == 0 && mx == x && copySign(1.0, x) == -1.0)
+ || (x < mx) || std::isnan(x)) {
+ mx = x;
+ }
+ }
+ return Value::fromDouble(mx);
+}
+
+Value MathObject::method_pow(SimpleCallContext *context)
+{
+ double x = context->argumentCount > 0 ? context->arguments[0].toNumber() : qSNaN();
+ double y = context->argumentCount > 1 ? context->arguments[1].toNumber() : qSNaN();
+
+ if (std::isnan(y))
+ return Value::fromDouble(qSNaN());
+
+ if (y == 0) {
+ return Value::fromDouble(1);
+ } else if (((x == 1) || (x == -1)) && std::isinf(y)) {
+ return Value::fromDouble(qSNaN());
+ } else if (((x == 0) && copySign(1.0, x) == 1.0) && (y < 0)) {
+ return Value::fromDouble(qInf());
+ } else if ((x == 0) && copySign(1.0, x) == -1.0) {
+ if (y < 0) {
+ if (::fmod(-y, 2.0) == 1.0)
+ return Value::fromDouble(-qInf());
+ else
+ return Value::fromDouble(qInf());
+ } else if (y > 0) {
+ if (::fmod(y, 2.0) == 1.0)
+ return Value::fromDouble(copySign(0, -1.0));
+ else
+ return Value::fromDouble(0);
+ }
+ }
+
+#ifdef Q_OS_AIX
+ else if (qIsInf(x) && copySign(1.0, x) == -1.0) {
+ if (y > 0) {
+ if (::fmod(y, 2.0) == 1.0)
+ return Value::fromDouble(-qInf());
+ else
+ return Value::fromDouble(qInf());
+ } else if (y < 0) {
+ if (::fmod(-y, 2.0) == 1.0)
+ return Value::fromDouble(copySign(0, -1.0));
+ else
+ return Value::fromDouble(0);
+ }
+ }
+#endif
+ else {
+ return Value::fromDouble(::pow(x, y));
+ }
+ // ###
+ return Value::fromDouble(qSNaN());
+}
+
+Value MathObject::method_random(SimpleCallContext *)
+{
+ return Value::fromDouble(qrand() / (double) RAND_MAX);
+}
+
+Value MathObject::method_round(SimpleCallContext *context)
+{
+ double v = context->argumentCount ? context->arguments[0].toNumber() : qSNaN();
+ v = copySign(::floor(v + 0.5), v);
+ return Value::fromDouble(v);
+}
+
+Value MathObject::method_sin(SimpleCallContext *context)
+{
+ double v = context->argumentCount ? context->arguments[0].toNumber() : qSNaN();
+ return Value::fromDouble(::sin(v));
+}
+
+Value MathObject::method_sqrt(SimpleCallContext *context)
+{
+ double v = context->argumentCount ? context->arguments[0].toNumber() : qSNaN();
+ return Value::fromDouble(::sqrt(v));
+}
+
+Value MathObject::method_tan(SimpleCallContext *context)
+{
+ double v = context->argumentCount ? context->arguments[0].toNumber() : qSNaN();
+ if (v == 0.0)
+ return Value::fromDouble(v);
+ else
+ return Value::fromDouble(::tan(v));
+}
+
diff --git a/src/qml/qml/v4/qv4mathobject_p.h b/src/qml/qml/v4/qv4mathobject_p.h
new file mode 100644
index 0000000000..03c36bcc68
--- /dev/null
+++ b/src/qml/qml/v4/qv4mathobject_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4MATHOBJECT_H
+#define QV$MATHOBJECT_H
+
+#include "qv4object_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct MathObject: Object
+{
+ MathObject(ExecutionContext *ctx);
+
+ static Value method_abs(SimpleCallContext *context);
+ static Value method_acos(SimpleCallContext *context);
+ static Value method_asin(SimpleCallContext *context);
+ static Value method_atan(SimpleCallContext *context);
+ static Value method_atan2(SimpleCallContext *context);
+ static Value method_ceil(SimpleCallContext *context);
+ static Value method_cos(SimpleCallContext *context);
+ static Value method_exp(SimpleCallContext *context);
+ static Value method_floor(SimpleCallContext *context);
+ static Value method_log(SimpleCallContext *context);
+ static Value method_max(SimpleCallContext *context);
+ static Value method_min(SimpleCallContext *context);
+ static Value method_pow(SimpleCallContext *context);
+ static Value method_random(SimpleCallContext *context);
+ static Value method_round(SimpleCallContext *context);
+ static Value method_sin(SimpleCallContext *context);
+ static Value method_sqrt(SimpleCallContext *context);
+ static Value method_tan(SimpleCallContext *context);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QMLJS_OBJECTS_H
diff --git a/src/qml/qml/v4/qv4mm.cpp b/src/qml/qml/v4/qv4mm.cpp
new file mode 100644
index 0000000000..0e53a2088f
--- /dev/null
+++ b/src/qml/qml/v4/qv4mm.cpp
@@ -0,0 +1,605 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4engine_p.h"
+#include "qv4object_p.h"
+#include "qv4objectproto_p.h"
+#include "qv4mm_p.h"
+#include "qv4qobjectwrapper_p.h"
+#include <qqmlengine.h>
+#include "PageAllocation.h"
+#include "StdLibExtras.h"
+
+#include <QTime>
+#include <QVector>
+#include <QVector>
+#include <QMap>
+
+#include <iostream>
+#include <cstdlib>
+#include "qv4alloca_p.h"
+
+#ifdef V4_USE_VALGRIND
+#include <valgrind/valgrind.h>
+#include <valgrind/memcheck.h>
+#endif
+
+#if OS(QNX)
+#include <sys/storage.h> // __tls()
+#endif
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+using namespace WTF;
+
+static const std::size_t CHUNK_SIZE = 1024*32;
+
+struct MemoryManager::Data
+{
+ bool enableGC;
+ bool gcBlocked;
+ bool scribble;
+ bool aggressiveGC;
+ ExecutionEngine *engine;
+ quintptr *stackTop;
+
+ enum { MaxItemSize = 512 };
+ Managed *smallItems[MaxItemSize/16];
+ uint nChunks[MaxItemSize/16];
+ uint availableItems[MaxItemSize/16];
+ uint allocCount[MaxItemSize/16];
+ struct Chunk {
+ PageAllocation memory;
+ int chunkSize;
+ };
+
+ QVector<Chunk> heapChunks;
+ QHash<Managed *, uint> protectedObject;
+
+ // statistics:
+#ifdef DETAILED_MM_STATS
+ QVector<unsigned> allocSizeCounters;
+#endif // DETAILED_MM_STATS
+
+ Data(bool enableGC)
+ : enableGC(enableGC)
+ , gcBlocked(false)
+ , engine(0)
+ , stackTop(0)
+ {
+ memset(smallItems, 0, sizeof(smallItems));
+ memset(nChunks, 0, sizeof(nChunks));
+ memset(availableItems, 0, sizeof(availableItems));
+ memset(allocCount, 0, sizeof(allocCount));
+ scribble = !qgetenv("MM_SCRIBBLE").isEmpty();
+ aggressiveGC = !qgetenv("MM_AGGRESSIVE_GC").isEmpty();
+ }
+
+ ~Data()
+ {
+ for (QVector<Chunk>::iterator i = heapChunks.begin(), ei = heapChunks.end(); i != ei; ++i)
+ i->memory.deallocate();
+ }
+};
+
+#define SCRIBBLE(obj, c, size) \
+ if (m_d->scribble) \
+ ::memset((void *)(obj + 1), c, size - sizeof(Managed));
+
+
+namespace QV4 {
+
+bool operator<(const MemoryManager::Data::Chunk &a, const MemoryManager::Data::Chunk &b)
+{
+ return a.memory.base() < b.memory.base();
+}
+
+} // namespace QV4
+
+MemoryManager::MemoryManager()
+ : m_d(new Data(true))
+ , m_contextList(0)
+ , m_persistentValues(0)
+ , m_weakValues(0)
+{
+ setEnableGC(true);
+#ifdef V4_USE_VALGRIND
+ VALGRIND_CREATE_MEMPOOL(this, 0, true);
+#endif
+
+#if OS(QNX)
+ // TLS is at the top of each thread's stack,
+ // so the stack base for thread is the result of __tls()
+ m_d->stackTop = reinterpret_cast<quintptr *>(
+ (((uintptr_t)__tls() + __PAGESIZE - 1) & ~(__PAGESIZE - 1)));
+#elif USE(PTHREADS)
+# if OS(DARWIN)
+ void *st = pthread_get_stackaddr_np(pthread_self());
+ m_d->stackTop = static_cast<quintptr *>(st);
+# else
+ void* stackBottom = 0;
+ pthread_attr_t attr;
+ pthread_getattr_np(pthread_self(), &attr);
+ size_t stackSize = 0;
+ pthread_attr_getstack(&attr, &stackBottom, &stackSize);
+ pthread_attr_destroy(&attr);
+
+ m_d->stackTop = static_cast<quintptr *>(stackBottom) + stackSize/sizeof(quintptr);
+# endif
+#elif OS(WINDOWS)
+ PNT_TIB tib = (PNT_TIB)NtCurrentTeb();
+ m_d->stackTop = static_cast<quintptr*>(tib->StackBase);
+#else
+# error "Unsupported platform: no way to get the top-of-stack."
+#endif
+
+}
+
+Managed *MemoryManager::alloc(std::size_t size)
+{
+ if (m_d->aggressiveGC)
+ runGC();
+#ifdef DETAILED_MM_STATS
+ willAllocate(size);
+#endif // DETAILED_MM_STATS
+
+ assert(size >= 16);
+ assert(size % 16 == 0);
+
+ size_t pos = size >> 4;
+ ++m_d->allocCount[pos];
+
+ // fits into a small bucket
+ assert(size < MemoryManager::Data::MaxItemSize);
+
+ Managed *m = m_d->smallItems[pos];
+ if (m)
+ goto found;
+
+ // try to free up space, otherwise allocate
+ if (m_d->allocCount[pos] > (m_d->availableItems[pos] >> 1) && !m_d->aggressiveGC) {
+ runGC();
+ m = m_d->smallItems[pos];
+ if (m)
+ goto found;
+ }
+
+ // no free item available, allocate a new chunk
+ {
+ // allocate larger chunks at a time to avoid excessive GC, but cap at 64M chunks
+ uint shift = ++m_d->nChunks[pos];
+ if (shift > 10)
+ shift = 10;
+ std::size_t allocSize = CHUNK_SIZE*(1 << shift);
+ allocSize = roundUpToMultipleOf(WTF::pageSize(), allocSize);
+ Data::Chunk allocation;
+ allocation.memory = PageAllocation::allocate(allocSize, OSAllocator::JSGCHeapPages);
+ allocation.chunkSize = size;
+ m_d->heapChunks.append(allocation);
+ qSort(m_d->heapChunks);
+ char *chunk = (char *)allocation.memory.base();
+ char *end = chunk + allocation.memory.size() - size;
+ memset(chunk, 0, allocation.memory.size());
+ Managed **last = &m_d->smallItems[pos];
+ while (chunk <= end) {
+ Managed *o = reinterpret_cast<Managed *>(chunk);
+ o->_data = 0;
+ *last = o;
+ last = o->nextFreeRef();
+ chunk += size;
+ }
+ *last = 0;
+ m = m_d->smallItems[pos];
+ m_d->availableItems[pos] += allocation.memory.size()/size - 1;
+#ifdef V4_USE_VALGRIND
+ VALGRIND_MAKE_MEM_NOACCESS(allocation.memory, allocation.chunkSize);
+#endif
+ }
+
+ found:
+#ifdef V4_USE_VALGRIND
+ VALGRIND_MEMPOOL_ALLOC(this, m, size);
+#endif
+
+ m_d->smallItems[pos] = m->nextFree();
+ return m;
+}
+
+void MemoryManager::mark()
+{
+ m_d->engine->markObjects();
+
+ for (QHash<Managed *, uint>::const_iterator it = m_d->protectedObject.begin(); it != m_d->protectedObject.constEnd(); ++it)
+ it.key()->mark();
+
+ PersistentValuePrivate *persistent = m_persistentValues;
+ while (persistent) {
+ if (!persistent->refcount) {
+ PersistentValuePrivate *n = persistent->next;
+ persistent->removeFromList();
+ delete persistent;
+ persistent = n;
+ continue;
+ }
+ if (Managed *m = persistent->value.asManaged())
+ m->mark();
+ persistent = persistent->next;
+ }
+
+ // push all caller saved registers to the stack, so we can find the objects living in these registers
+#if COMPILER(MSVC)
+# if CPU(X86_64)
+ HANDLE thread = GetCurrentThread();
+ WOW64_CONTEXT ctxt;
+ /*bool success =*/ Wow64GetThreadContext(thread, &ctxt);
+# elif CPU(X86)
+ HANDLE thread = GetCurrentThread();
+ CONTEXT ctxt;
+ /*bool success =*/ GetThreadContext(thread, &ctxt);
+# endif // CPU
+#elif COMPILER(CLANG) || COMPILER(GCC)
+# if CPU(X86_64)
+ quintptr regs[5];
+ asm(
+ "mov %%rbp, %0\n"
+ "mov %%r12, %1\n"
+ "mov %%r13, %2\n"
+ "mov %%r14, %3\n"
+ "mov %%r15, %4\n"
+ : "=m" (regs[0]), "=m" (regs[1]), "=m" (regs[2]), "=m" (regs[3]), "=m" (regs[4])
+ :
+ :
+ );
+# endif // CPU
+#endif // COMPILER
+
+ collectFromStack();
+
+ // Preserve QObject ownership rules within JavaScript: A parent with c++ ownership
+ // keeps all of its children alive in JavaScript.
+
+ // Do this _after_ collectFromStack to ensure that processing the weak
+ // managed objects in the loop down there doesn't make then end up as leftovers
+ // on the stack and thus always get collected.
+ for (PersistentValuePrivate *weak = m_weakValues; weak; weak = weak->next) {
+ if (!weak->refcount)
+ continue;
+ QObjectWrapper *qobjectWrapper = weak->value.as<QObjectWrapper>();
+ if (!qobjectWrapper)
+ continue;
+ QObject *qobject = qobjectWrapper->object();
+ if (!qobject)
+ continue;
+ bool keepAlive = QQmlData::keepAliveDuringGarbageCollection(qobject);
+
+ if (!keepAlive) {
+ if (QObject *parent = qobject->parent()) {
+ while (parent->parent())
+ parent = parent->parent();
+
+ keepAlive = QQmlData::keepAliveDuringGarbageCollection(parent);
+ }
+ }
+
+ if (keepAlive)
+ qobjectWrapper->mark();
+ }
+}
+
+std::size_t MemoryManager::sweep(bool lastSweep)
+{
+ PersistentValuePrivate *weak = m_weakValues;
+ while (weak) {
+ if (!weak->refcount) {
+ PersistentValuePrivate *n = weak->next;
+ weak->removeFromList();
+ delete weak;
+ weak = n;
+ continue;
+ }
+ if (Managed *m = weak->value.asManaged()) {
+ if (!m->markBit) {
+ weak->value = Value::emptyValue();
+ PersistentValuePrivate *n = weak->next;
+ weak->removeFromList();
+ weak = n;
+ continue;
+ }
+ }
+ weak = weak->next;
+ }
+
+ if (MultiplyWrappedQObjectMap *multiplyWrappedQObjects = m_d->engine->m_multiplyWrappedQObjects) {
+ for (MultiplyWrappedQObjectMap::Iterator it = multiplyWrappedQObjects->begin(); it != multiplyWrappedQObjects->end();) {
+ if (!it.value()->markBit)
+ it = multiplyWrappedQObjects->erase(it);
+ else
+ ++it;
+ }
+ }
+
+ std::size_t freedCount = 0;
+ GCDeletable *deletable = 0;
+ GCDeletable **firstDeletable = &deletable;
+
+ for (QVector<Data::Chunk>::iterator i = m_d->heapChunks.begin(), ei = m_d->heapChunks.end(); i != ei; ++i)
+ freedCount += sweep(reinterpret_cast<char*>(i->memory.base()), i->memory.size(), i->chunkSize, &deletable);
+
+ ExecutionContext *ctx = m_contextList;
+ ExecutionContext **n = &m_contextList;
+ while (ctx) {
+ ExecutionContext *next = ctx->next;
+ if (!ctx->marked) {
+ free(ctx);
+ *n = next;
+ } else {
+ ctx->marked = false;
+ n = &ctx->next;
+ }
+ ctx = next;
+ }
+
+ deletable = *firstDeletable;
+ while (deletable) {
+ GCDeletable *next = deletable->next;
+ deletable->lastCall = lastSweep;
+ delete deletable;
+ deletable = next;
+ }
+
+ return freedCount;
+}
+
+std::size_t MemoryManager::sweep(char *chunkStart, std::size_t chunkSize, size_t size, GCDeletable **deletable)
+{
+// qDebug("chunkStart @ %p, size=%x, pos=%x (%x)", chunkStart, size, size>>4, m_d->smallItems[size >> 4]);
+ std::size_t freedCount = 0;
+
+ Managed **f = &m_d->smallItems[size >> 4];
+
+#ifdef V4_USE_VALGRIND
+ VALGRIND_DISABLE_ERROR_REPORTING;
+#endif
+ for (char *chunk = chunkStart, *chunkEnd = chunk + chunkSize - size; chunk <= chunkEnd; chunk += size) {
+ Managed *m = reinterpret_cast<Managed *>(chunk);
+// qDebug("chunk @ %p, size = %lu, in use: %s, mark bit: %s",
+// chunk, m->size, (m->inUse ? "yes" : "no"), (m->markBit ? "true" : "false"));
+
+ assert((intptr_t) chunk % 16 == 0);
+
+ if (m->inUse) {
+ if (m->markBit) {
+ m->markBit = 0;
+ } else {
+// qDebug() << "-- collecting it." << m << *f << m->nextFree();
+#ifdef V4_USE_VALGRIND
+ VALGRIND_ENABLE_ERROR_REPORTING;
+#endif
+ if (m->vtbl->collectDeletables)
+ m->vtbl->collectDeletables(m, deletable);
+ m->vtbl->destroy(m);
+
+ m->setNextFree(*f);
+#ifdef V4_USE_VALGRIND
+ VALGRIND_DISABLE_ERROR_REPORTING;
+ VALGRIND_MEMPOOL_FREE(this, m);
+#endif
+ *f = m;
+ SCRIBBLE(m, 0x99, size);
+ ++freedCount;
+ }
+ }
+ }
+#ifdef V4_USE_VALGRIND
+ VALGRIND_ENABLE_ERROR_REPORTING;
+#endif
+
+ return freedCount;
+}
+
+bool MemoryManager::isGCBlocked() const
+{
+ return m_d->gcBlocked;
+}
+
+void MemoryManager::setGCBlocked(bool blockGC)
+{
+ m_d->gcBlocked = blockGC;
+}
+
+void MemoryManager::runGC()
+{
+ if (!m_d->enableGC || m_d->gcBlocked) {
+// qDebug() << "Not running GC.";
+ return;
+ }
+
+// QTime t; t.start();
+
+// qDebug() << ">>>>>>>>runGC";
+
+ mark();
+// std::cerr << "GC: marked " << marks
+// << " objects in " << t.elapsed()
+// << "ms" << std::endl;
+
+// t.restart();
+ /*std::size_t freedCount =*/ sweep();
+// std::cerr << "GC: sweep freed " << freedCount
+// << " objects in " << t.elapsed()
+// << "ms" << std::endl;
+ memset(m_d->allocCount, 0, sizeof(m_d->allocCount));
+}
+
+void MemoryManager::setEnableGC(bool enableGC)
+{
+ m_d->enableGC = enableGC;
+}
+
+MemoryManager::~MemoryManager()
+{
+ PersistentValuePrivate *persistent = m_persistentValues;
+ while (persistent) {
+ PersistentValuePrivate *n = persistent->next;
+ persistent->value = Value::undefinedValue();
+ persistent->engine = 0;
+ persistent->prev = 0;
+ persistent->next = 0;
+ persistent = n;
+ }
+
+ sweep(/*lastSweep*/true);
+#ifdef V4_USE_VALGRIND
+ VALGRIND_DESTROY_MEMPOOL(this);
+#endif
+}
+
+void MemoryManager::protect(Managed *m)
+{
+ ++m_d->protectedObject[m];
+}
+
+void MemoryManager::unprotect(Managed *m)
+{
+ if (!--m_d->protectedObject[m])
+ m_d->protectedObject.remove(m);
+}
+
+static inline void add(QVector<Managed *> &values, const Value &v)
+{
+ if (Object *o = v.asObject())
+ values.append(o);
+}
+
+void MemoryManager::setExecutionEngine(ExecutionEngine *engine)
+{
+ m_d->engine = engine;
+}
+
+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]) {
+ std::cerr << "\t" << (i << 4) << " bytes chunks: " << count << std::endl;
+ }
+ }
+#endif // DETAILED_MM_STATS
+}
+
+ExecutionEngine *MemoryManager::engine() const
+{
+ return m_d->engine;
+}
+
+#ifdef DETAILED_MM_STATS
+void MemoryManager::willAllocate(std::size_t size)
+{
+ unsigned alignedSize = (size + 15) >> 4;
+ QVector<unsigned> &counters = m_d->allocSizeCounters;
+ if ((unsigned) counters.size() < alignedSize + 1)
+ counters.resize(alignedSize + 1);
+ counters[alignedSize]++;
+}
+
+#endif // DETAILED_MM_STATS
+
+void MemoryManager::collectFromStack() const
+{
+ quintptr valueOnStack = 0;
+
+ if (!m_d->heapChunks.count())
+ return;
+
+ quintptr *current = (&valueOnStack) + 1;
+// qDebug() << "collectFromStack";// << top << current << &valueOnStack;
+
+#if V4_USE_VALGRIND
+ VALGRIND_MAKE_MEM_DEFINED(current, (m_d->stackTop - current)*sizeof(quintptr));
+#endif
+
+ char** heapChunkBoundaries = (char**)alloca(m_d->heapChunks.count() * 2 * sizeof(char*));
+ char** heapChunkBoundariesEnd = heapChunkBoundaries + 2 * m_d->heapChunks.count();
+ int i = 0;
+ for (QVector<Data::Chunk>::Iterator it = m_d->heapChunks.begin(), end =
+ m_d->heapChunks.end(); it != end; ++it) {
+ heapChunkBoundaries[i++] = reinterpret_cast<char*>(it->memory.base()) - 1;
+ heapChunkBoundaries[i++] = reinterpret_cast<char*>(it->memory.base()) + it->memory.size() - it->chunkSize;
+ }
+ assert(i == m_d->heapChunks.count() * 2);
+
+ for (; current < m_d->stackTop; ++current) {
+ char* genericPtr =
+#if QT_POINTER_SIZE == 8
+ reinterpret_cast<char *>((*current) & ~(quint64(Value::Type_Mask) << Value::Tag_Shift));
+#else
+ reinterpret_cast<char *>(*current);
+#endif
+
+ if (genericPtr < *heapChunkBoundaries || genericPtr > *(heapChunkBoundariesEnd - 1))
+ continue;
+ int index = qLowerBound(heapChunkBoundaries, heapChunkBoundariesEnd, genericPtr) - heapChunkBoundaries;
+ // An odd index means the pointer is _before_ the end of a heap chunk and therefore valid.
+ assert(index >= 0 && index < m_d->heapChunks.count() * 2);
+ if (index & 1) {
+ int size = m_d->heapChunks.at(index >> 1).chunkSize;
+ Managed *m = reinterpret_cast<Managed *>(genericPtr);
+// qDebug() << " inside" << size;
+
+ if (((quintptr)m - (quintptr)heapChunkBoundaries[index-1] - 1 ) % size)
+ // wrongly aligned value, skip it
+ continue;
+
+ if (!m->inUse)
+ // Skip pointers to already freed objects, they are bogus as well
+ continue;
+
+// qDebug() << " marking";
+ m->mark();
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4mm_p.h b/src/qml/qml/v4/qv4mm_p.h
new file mode 100644
index 0000000000..f72d23dc9a
--- /dev/null
+++ b/src/qml/qml/v4/qv4mm_p.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4GC_H
+#define QV4GC_H
+
+#include "qv4global_p.h"
+#include "qv4context_p.h"
+
+#include <QScopedPointer>
+
+//#define DETAILED_MM_STATS
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct ExecutionEngine;
+struct ExecutionContext;
+struct Managed;
+struct GCDeletable;
+
+class Q_QML_EXPORT MemoryManager
+{
+ MemoryManager(const MemoryManager &);
+ MemoryManager &operator=(const MemoryManager&);
+
+public:
+ struct Data;
+
+ class GCBlocker
+ {
+ public:
+ GCBlocker(MemoryManager *mm)
+ : mm(mm)
+ , wasBlocked(mm->isGCBlocked())
+ {
+ mm->setGCBlocked(true);
+ }
+
+ ~GCBlocker()
+ {
+ mm->setGCBlocked(wasBlocked);
+ }
+
+ private:
+ MemoryManager *mm;
+ bool wasBlocked;
+ };
+
+public:
+ MemoryManager();
+ ~MemoryManager();
+
+ void protect(Managed *m);
+ void unprotect(Managed *m);
+
+ // 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 occurances 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; }
+
+ inline Managed *allocManaged(std::size_t size)
+ {
+ size = align(size);
+ Managed *o = alloc(size);
+ return o;
+ }
+
+ ExecutionContext *allocContext(uint size);
+
+ bool isGCBlocked() const;
+ void setGCBlocked(bool blockGC);
+ void runGC();
+
+ void setEnableGC(bool enableGC);
+ void setExecutionEngine(ExecutionEngine *engine);
+
+ void dumpStats() const;
+
+protected:
+ /// expects size to be aligned
+ // TODO: try to inline
+ Managed *alloc(std::size_t size);
+
+ ExecutionEngine *engine() const;
+
+#ifdef DETAILED_MM_STATS
+ void willAllocate(std::size_t size);
+#endif // DETAILED_MM_STATS
+
+private:
+ void collectFromStack() const;
+ void mark();
+ std::size_t sweep(bool lastSweep = false);
+ std::size_t sweep(char *chunkStart, std::size_t chunkSize, size_t size, GCDeletable **deletable);
+
+protected:
+ QScopedPointer<Data> m_d;
+ ExecutionContext *m_contextList;
+public:
+ PersistentValuePrivate *m_persistentValues;
+ PersistentValuePrivate *m_weakValues;
+};
+
+inline ExecutionContext *MemoryManager::allocContext(uint size)
+{
+ ExecutionContext *newContext = (ExecutionContext *)malloc(size);
+ newContext->next = m_contextList;
+ m_contextList = newContext;
+ return newContext;
+}
+
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4GC_H
diff --git a/src/qml/qml/v4/qv4numberobject.cpp b/src/qml/qml/v4/qv4numberobject.cpp
new file mode 100644
index 0000000000..266fa792dc
--- /dev/null
+++ b/src/qml/qml/v4/qv4numberobject.cpp
@@ -0,0 +1,257 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4numberobject_p.h"
+#include <QtCore/qnumeric.h>
+#include <QtCore/qmath.h>
+#include <QtCore/QDebug>
+#include <cassert>
+#include <double-conversion.h>
+
+using namespace QV4;
+
+DEFINE_MANAGED_VTABLE(NumberCtor);
+
+NumberCtor::NumberCtor(ExecutionContext *scope)
+ : FunctionObject(scope, scope->engine->newIdentifier(QStringLiteral("Number")))
+{
+ vtbl = &static_vtbl;
+}
+
+Value NumberCtor::construct(Managed *m, Value *args, int argc)
+{
+ double d = argc ? args[0].toNumber() : 0.;
+ return Value::fromObject(m->engine()->newNumberObject(Value::fromDouble(d)));
+}
+
+Value NumberCtor::call(Managed *, const Value &, Value *argv, int argc)
+{
+ double d = argc ? argv[0].toNumber() : 0.;
+ return Value::fromDouble(d);
+}
+
+void NumberPrototype::init(ExecutionContext *ctx, const Value &ctor)
+{
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this));
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(1));
+
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine, QStringLiteral("NaN"), Value::fromDouble(qSNaN()));
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine, QStringLiteral("NEGATIVE_INFINITY"), Value::fromDouble(-qInf()));
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine, QStringLiteral("POSITIVE_INFINITY"), Value::fromDouble(qInf()));
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine, QStringLiteral("MAX_VALUE"), Value::fromDouble(1.7976931348623158e+308));
+
+#ifdef __INTEL_COMPILER
+# pragma warning( push )
+# pragma warning(disable: 239)
+#endif
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine, QStringLiteral("MIN_VALUE"), Value::fromDouble(5e-324));
+#ifdef __INTEL_COMPILER
+# pragma warning( pop )
+#endif
+
+ defineDefaultProperty(ctx, QStringLiteral("constructor"), ctor);
+ defineDefaultProperty(ctx, QStringLiteral("toString"), method_toString);
+ defineDefaultProperty(ctx, QStringLiteral("toLocaleString"), method_toLocaleString);
+ defineDefaultProperty(ctx, QStringLiteral("valueOf"), method_valueOf);
+ defineDefaultProperty(ctx, QStringLiteral("toFixed"), method_toFixed, 1);
+ defineDefaultProperty(ctx, QStringLiteral("toExponential"), method_toExponential);
+ defineDefaultProperty(ctx, QStringLiteral("toPrecision"), method_toPrecision);
+}
+
+Value NumberPrototype::method_toString(SimpleCallContext *ctx)
+{
+ double num;
+ if (ctx->thisObject.isNumber()) {
+ num = ctx->thisObject.asDouble();
+ } else {
+ NumberObject *thisObject = ctx->thisObject.asNumberObject();
+ if (!thisObject)
+ ctx->throwTypeError();
+ num = thisObject->value.asDouble();
+ }
+
+ Value arg = ctx->argument(0);
+ if (!arg.isUndefined()) {
+ int radix = arg.toInt32();
+ if (radix < 2 || radix > 36) {
+ ctx->throwError(QString::fromLatin1("Number.prototype.toString: %0 is not a valid radix")
+ .arg(radix));
+ return Value::undefinedValue();
+ }
+
+ if (std::isnan(num)) {
+ return Value::fromString(ctx, QStringLiteral("NaN"));
+ } else if (qIsInf(num)) {
+ return Value::fromString(ctx, QLatin1String(num < 0 ? "-Infinity" : "Infinity"));
+ }
+
+ if (radix != 10) {
+ QString str;
+ bool negative = false;
+ if (num < 0) {
+ negative = true;
+ num = -num;
+ }
+ double frac = num - ::floor(num);
+ num = Value::toInteger(num);
+ do {
+ char c = (char)::fmod(num, radix);
+ c = (c < 10) ? (c + '0') : (c - 10 + 'a');
+ str.prepend(QLatin1Char(c));
+ num = ::floor(num / radix);
+ } while (num != 0);
+ if (frac != 0) {
+ str.append(QLatin1Char('.'));
+ do {
+ frac = frac * radix;
+ char c = (char)::floor(frac);
+ c = (c < 10) ? (c + '0') : (c - 10 + 'a');
+ str.append(QLatin1Char(c));
+ frac = frac - ::floor(frac);
+ } while (frac != 0);
+ }
+ if (negative)
+ str.prepend(QLatin1Char('-'));
+ return Value::fromString(ctx, str);
+ }
+ }
+
+ String *str = Value::fromDouble(num).toString(ctx);
+ return Value::fromString(str);
+}
+
+Value NumberPrototype::method_toLocaleString(SimpleCallContext *ctx)
+{
+ NumberObject *thisObject = ctx->thisObject.asNumberObject();
+ if (!thisObject)
+ ctx->throwTypeError();
+
+ String *str = thisObject->value.toString(ctx);
+ return Value::fromString(str);
+}
+
+Value NumberPrototype::method_valueOf(SimpleCallContext *ctx)
+{
+ NumberObject *thisObject = ctx->thisObject.asNumberObject();
+ if (!thisObject)
+ ctx->throwTypeError();
+
+ return thisObject->value;
+}
+
+Value NumberPrototype::method_toFixed(SimpleCallContext *ctx)
+{
+ NumberObject *thisObject = ctx->thisObject.asNumberObject();
+ if (!thisObject)
+ ctx->throwTypeError();
+
+ double fdigits = 0;
+
+ if (ctx->argumentCount > 0)
+ fdigits = ctx->argument(0).toInteger();
+
+ if (std::isnan(fdigits))
+ fdigits = 0;
+
+ if (fdigits < 0 || fdigits > 20)
+ ctx->throwRangeError(ctx->thisObject);
+
+ double v = thisObject->value.asDouble();
+ QString str;
+ if (std::isnan(v))
+ str = QString::fromLatin1("NaN");
+ else if (qIsInf(v))
+ str = QString::fromLatin1(v < 0 ? "-Infinity" : "Infinity");
+ else if (v < 1.e21)
+ str = QString::number(v, 'f', int (fdigits));
+ else
+ return __qmljs_string_from_number(ctx, v);
+ return Value::fromString(ctx, str);
+}
+
+Value NumberPrototype::method_toExponential(SimpleCallContext *ctx)
+{
+ NumberObject *thisObject = ctx->thisObject.asNumberObject();
+ if (!thisObject)
+ ctx->throwTypeError();
+
+ Value fraction = ctx->argument(0);
+ int fdigits = -1;
+
+ if (!fraction.isUndefined()) {
+ int fdigits = ctx->argument(0).toInt32();
+ if (fdigits < 0 || fdigits > 20) {
+ String *error = ctx->engine->newString(QStringLiteral("Number.prototype.toExponential: fractionDigits out of range"));
+ ctx->throwRangeError(Value::fromString(error));
+ }
+ }
+
+ char str[100];
+ double_conversion::StringBuilder builder(str, sizeof(str));
+ double_conversion::DoubleToStringConverter::EcmaScriptConverter().ToExponential(thisObject->value.asDouble(), fdigits, &builder);
+ QString result = QString::fromLatin1(builder.Finalize());
+
+ return Value::fromString(ctx, result);
+}
+
+Value NumberPrototype::method_toPrecision(SimpleCallContext *ctx)
+{
+ NumberObject *thisObject = ctx->thisObject.asNumberObject();
+ if (!thisObject)
+ ctx->throwTypeError();
+
+ Value prec = ctx->argument(0);
+ if (prec.isUndefined())
+ return __qmljs_to_string(thisObject->value, ctx);
+
+ double precision = prec.toInt32();
+ if (precision < 1 || precision > 21) {
+ String *error = ctx->engine->newString(QStringLiteral("Number.prototype.toPrecision: precision out of range"));
+ ctx->throwRangeError(Value::fromString(error));
+ }
+
+ char str[100];
+ double_conversion::StringBuilder builder(str, sizeof(str));
+ double_conversion::DoubleToStringConverter::EcmaScriptConverter().ToPrecision(thisObject->value.asDouble(), precision, &builder);
+ QString result = QString::fromLatin1(builder.Finalize());
+
+ return Value::fromString(ctx, result);
+}
diff --git a/src/qml/qml/v4/qv4numberobject_p.h b/src/qml/qml/v4/qv4numberobject_p.h
new file mode 100644
index 0000000000..0c06451c98
--- /dev/null
+++ b/src/qml/qml/v4/qv4numberobject_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4NUMBEROBJECT_H
+#define QV4NUMBEROBJECT_H
+
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+#include <QtCore/qnumeric.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct NumberCtor: FunctionObject
+{
+ NumberCtor(ExecutionContext *scope);
+
+ static Value construct(Managed *that, Value *args, int argc);
+ static Value call(Managed *, const Value &, Value *, int);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct NumberPrototype: NumberObject
+{
+ NumberPrototype(ExecutionEngine *engine): NumberObject(engine, Value::fromDouble(0)) {}
+ void init(ExecutionContext *ctx, const Value &ctor);
+
+ static Value method_toString(SimpleCallContext *ctx);
+ static Value method_toLocaleString(SimpleCallContext *ctx);
+ static Value method_valueOf(SimpleCallContext *ctx);
+ static Value method_toFixed(SimpleCallContext *ctx);
+ static Value method_toExponential(SimpleCallContext *ctx);
+ static Value method_toPrecision(SimpleCallContext *ctx);
+};
+
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4ECMAOBJECTS_P_H
diff --git a/src/qml/qml/v4/qv4object.cpp b/src/qml/qml/v4/qv4object.cpp
new file mode 100644
index 0000000000..16b57871af
--- /dev/null
+++ b/src/qml/qml/v4/qv4object.cpp
@@ -0,0 +1,1383 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4object_p.h"
+#include "qv4jsir_p.h"
+#include "qv4isel_p.h"
+#include "qv4objectproto_p.h"
+#include "qv4stringobject_p.h"
+#include "qv4argumentsobject_p.h"
+#include "qv4mm_p.h"
+#include "qv4lookup_p.h"
+
+#include <private/qqmljsengine_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljsast_p.h>
+#include <qv4jsir_p.h>
+#include <qv4codegen_p.h>
+#include "private/qlocale_tools_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtCore/QDebug>
+#include <cassert>
+#include <typeinfo>
+#include <iostream>
+#include <stdint.h>
+#include "qv4alloca_p.h"
+
+using namespace QV4;
+
+DEFINE_MANAGED_VTABLE(Object);
+
+Object::Object(ExecutionEngine *engine)
+ : Managed(engine->emptyClass)
+ , prototype(0)
+ , memberDataAlloc(InlinePropertySize), memberData(inlineProperties)
+ , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayAttributes(0), arrayData(0), sparseArray(0)
+{
+ vtbl = &static_vtbl;
+ type = Type_Object;
+ memset(memberData, 0, sizeof(Property)*memberDataAlloc);
+}
+
+Object::Object(ExecutionContext *context)
+ : Managed(context->engine->emptyClass)
+ , prototype(0)
+ , memberDataAlloc(InlinePropertySize), memberData(inlineProperties)
+ , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayAttributes(0), arrayData(0), sparseArray(0)
+{
+ vtbl = &static_vtbl;
+ type = Type_Object;
+ memset(memberData, 0, sizeof(Property)*memberDataAlloc);
+}
+
+Object::Object(ExecutionEngine *engine, InternalClass *internalClass)
+ : Managed(internalClass)
+ , prototype(0)
+ , memberDataAlloc(InlinePropertySize), memberData(inlineProperties)
+ , arrayOffset(0), arrayDataLen(0), arrayAlloc(0), arrayAttributes(0), arrayData(0), sparseArray(0)
+{
+ vtbl = &static_vtbl;
+ type = Type_Object;
+
+ if (internalClass->size >= memberDataAlloc) {
+ memberDataAlloc = internalClass->size;
+ memberData = new Property[memberDataAlloc];
+ }
+ memset(memberData, 0, sizeof(Property)*memberDataAlloc);
+}
+
+Object::~Object()
+{
+ if (memberData != inlineProperties)
+ delete [] memberData;
+ delete [] (arrayData - (sparseArray ? 0 : arrayOffset));
+ if (arrayAttributes)
+ delete [] (arrayAttributes - (sparseArray ? 0 : arrayOffset));
+ delete sparseArray;
+ _data = 0;
+}
+
+void Object::destroy(Managed *that)
+{
+ static_cast<Object *>(that)->~Object();
+}
+
+void Object::put(ExecutionContext *ctx, const QString &name, const Value &value)
+{
+ put(ctx->engine->newString(name), value);
+}
+
+Value Object::getValue(const Value &thisObject, const Property *p, PropertyAttributes attrs)
+{
+ if (!attrs.isAccessor())
+ return p->value;
+ FunctionObject *getter = p->getter();
+ if (!getter)
+ return Value::undefinedValue();
+
+ return getter->call(thisObject, 0, 0);
+}
+
+void Object::putValue(Property *pd, PropertyAttributes attrs, const Value &value)
+{
+ if (attrs.isAccessor()) {
+ if (pd->set) {
+ Value args[1];
+ args[0] = value;
+ pd->set->call(Value::fromObject(this), args, 1);
+ return;
+ }
+ goto reject;
+ }
+
+ if (!attrs.isWritable())
+ goto reject;
+
+ pd->value = value;
+ return;
+
+ reject:
+ if (engine()->current->strictMode)
+ engine()->current->throwTypeError();
+
+}
+
+void Object::inplaceBinOp(ExecutionContext *ctx, BinOp op, String *name, const Value &rhs)
+{
+ Value v = get(name);
+ Value result;
+ op(ctx, &result, v, rhs);
+ put(name, result);
+}
+
+void Object::inplaceBinOp(ExecutionContext *ctx, BinOp op, const Value &index, const Value &rhs)
+{
+ uint idx = index.asArrayIndex();
+ if (idx < UINT_MAX) {
+ bool hasProperty = false;
+ Value v = getIndexed(idx, &hasProperty);
+ Value result;
+ op(ctx, &result, v, rhs);
+ putIndexed(idx, result);
+ return;
+ }
+ String *name = index.toString(ctx);
+ assert(name);
+ inplaceBinOp(ctx, op, name, rhs);
+}
+
+void Object::defineDefaultProperty(String *name, Value value)
+{
+ Property *pd = insertMember(name, Attr_Data|Attr_NotEnumerable);
+ pd->value = value;
+}
+
+void Object::defineDefaultProperty(ExecutionContext *context, const QString &name, Value value)
+{
+ defineDefaultProperty(context->engine->newIdentifier(name), value);
+}
+
+void Object::defineDefaultProperty(ExecutionEngine *engine, const QString &name, Value value)
+{
+ defineDefaultProperty(engine->newIdentifier(name), value);
+}
+
+void Object::defineDefaultProperty(ExecutionContext *context, const QString &name, Value (*code)(SimpleCallContext *), int argumentCount)
+{
+ Q_UNUSED(argumentCount);
+ String *s = context->engine->newIdentifier(name);
+ FunctionObject* function = context->engine->newBuiltinFunction(context, s, code);
+ function->defineReadonlyProperty(context->engine->id_length, Value::fromInt32(argumentCount));
+ defineDefaultProperty(s, Value::fromObject(function));
+}
+
+void Object::defineDefaultProperty(ExecutionEngine *engine, const QString &name, Value (*code)(SimpleCallContext *), int argumentCount)
+{
+ Q_UNUSED(argumentCount);
+ String *s = engine->newIdentifier(name);
+ FunctionObject* function = engine->newBuiltinFunction(engine->rootContext, s, code);
+ function->defineReadonlyProperty(engine->id_length, Value::fromInt32(argumentCount));
+ defineDefaultProperty(s, Value::fromObject(function));
+}
+
+void Object::defineAccessorProperty(ExecutionEngine *engine, const QString &name,
+ Value (*getter)(SimpleCallContext *), Value (*setter)(SimpleCallContext *))
+{
+ String *s = engine->newString(name);
+ defineAccessorProperty(s, getter, setter);
+}
+
+void Object::defineAccessorProperty(String *name, Value (*getter)(SimpleCallContext *), Value (*setter)(SimpleCallContext *))
+{
+ ExecutionEngine *v4 = engine();
+ Property *p = insertMember(name, QV4::Attr_Accessor|QV4::Attr_NotConfigurable|QV4::Attr_NotEnumerable);
+ if (getter)
+ p->setGetter(v4->newBuiltinFunction(v4->rootContext, name, getter));
+ if (setter)
+ p->setSetter(v4->newBuiltinFunction(v4->rootContext, name, setter));
+}
+
+void Object::defineReadonlyProperty(ExecutionEngine *engine, const QString &name, Value value)
+{
+ defineReadonlyProperty(engine->newIdentifier(name), value);
+}
+
+void Object::defineReadonlyProperty(String *name, Value value)
+{
+ Property *pd = insertMember(name, Attr_ReadOnly);
+ pd->value = value;
+}
+
+void Object::markObjects(Managed *that)
+{
+ Object *o = static_cast<Object *>(that);
+ if (o->prototype)
+ o->prototype->mark();
+
+ for (int i = 0; i < o->internalClass->size; ++i) {
+ const Property &pd = o->memberData[i];
+ if (o->internalClass->propertyData[i].isData()) {
+ if (Managed *m = pd.value.asManaged())
+ m->mark();
+ } else {
+ if (pd.getter())
+ pd.getter()->mark();
+ if (pd.setter())
+ pd.setter()->mark();
+ }
+ }
+ o->markArrayObjects();
+}
+
+Property *Object::insertMember(String *s, PropertyAttributes attributes)
+{
+ uint idx;
+ internalClass = internalClass->addMember(s, attributes, &idx);
+
+ if (idx >= memberDataAlloc) {
+ memberDataAlloc = qMax((uint)8, 2*memberDataAlloc);
+ Property *newMemberData = new Property[memberDataAlloc];
+ memcpy(newMemberData, memberData, sizeof(Property)*idx);
+ memset(newMemberData + idx, 0, sizeof(Property)*(memberDataAlloc - idx));
+ if (memberData != inlineProperties)
+ delete [] memberData;
+ memberData = newMemberData;
+ }
+ return memberData + idx;
+}
+
+// Section 8.12.1
+Property *Object::__getOwnProperty__(String *name, PropertyAttributes *attrs)
+{
+ uint idx = name->asArrayIndex();
+ if (idx != UINT_MAX)
+ return __getOwnProperty__(idx, attrs);
+
+ uint member = internalClass->find(name);
+ if (member < UINT_MAX) {
+ if (attrs)
+ *attrs = internalClass->propertyData[member];
+ return memberData + member;
+ }
+
+ if (attrs)
+ *attrs = Attr_Invalid;
+ return 0;
+}
+
+Property *Object::__getOwnProperty__(uint index, PropertyAttributes *attrs)
+{
+ uint pidx = propertyIndexFromArrayIndex(index);
+ if (pidx < UINT_MAX) {
+ Property *p = arrayData + pidx;
+ if (!arrayAttributes || arrayAttributes[pidx].isData()) {
+ if (attrs)
+ *attrs = arrayAttributes ? arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
+ return p;
+ } else if (arrayAttributes[pidx].isAccessor()) {
+ if (attrs)
+ *attrs = arrayAttributes ? arrayAttributes[pidx] : PropertyAttributes(Attr_Accessor);
+ return p;
+ }
+ }
+ if (isStringObject()) {
+ if (attrs)
+ *attrs = Attr_NotConfigurable|Attr_NotWritable;
+ return static_cast<StringObject *>(this)->getIndex(index);
+ }
+
+ if (attrs)
+ *attrs = Attr_Invalid;
+ return 0;
+}
+
+// Section 8.12.2
+Property *Object::__getPropertyDescriptor__(String *name, PropertyAttributes *attrs) const
+{
+ uint idx = name->asArrayIndex();
+ if (idx != UINT_MAX)
+ return __getPropertyDescriptor__(idx);
+
+
+ const Object *o = this;
+ while (o) {
+ uint idx = o->internalClass->find(name);
+ if (idx < UINT_MAX) {
+ if (attrs)
+ *attrs = o->internalClass->propertyData[idx];
+ return o->memberData + idx;
+ }
+
+ o = o->prototype;
+ }
+ if (attrs)
+ *attrs = Attr_Invalid;
+ return 0;
+}
+
+Property *Object::__getPropertyDescriptor__(uint index, PropertyAttributes *attrs) const
+{
+ const Object *o = this;
+ while (o) {
+ uint pidx = o->propertyIndexFromArrayIndex(index);
+ if (pidx < UINT_MAX) {
+ Property *p = o->arrayData + pidx;
+ if (!o->arrayAttributes || !o->arrayAttributes[pidx].isGeneric()) {
+ if (attrs)
+ *attrs = o->arrayAttributes ? o->arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
+ return p;
+ }
+ }
+ if (o->isStringObject()) {
+ Property *p = static_cast<const StringObject *>(o)->getIndex(index);
+ if (p) {
+ if (attrs)
+ *attrs = (Attr_NotWritable|Attr_NotConfigurable);
+ return p;
+ }
+ }
+ o = o->prototype;
+ }
+ if (attrs)
+ *attrs = Attr_Invalid;
+ return 0;
+}
+
+bool Object::__hasProperty__(String *name) const
+{
+ if (__getPropertyDescriptor__(name))
+ return true;
+ return !query(name).isEmpty();
+}
+
+Value Object::get(Managed *m, String *name, bool *hasProperty)
+{
+ return static_cast<Object *>(m)->internalGet(name, hasProperty);
+}
+
+Value Object::getIndexed(Managed *m, uint index, bool *hasProperty)
+{
+ return static_cast<Object *>(m)->internalGetIndexed(index, hasProperty);
+}
+
+void Object::put(Managed *m, String *name, const Value &value)
+{
+ static_cast<Object *>(m)->internalPut(name, value);
+}
+
+void Object::putIndexed(Managed *m, uint index, const Value &value)
+{
+ static_cast<Object *>(m)->internalPutIndexed(index, value);
+}
+
+PropertyAttributes Object::query(const Managed *m, String *name)
+{
+ uint idx = name->asArrayIndex();
+ if (idx != UINT_MAX)
+ return queryIndexed(m, idx);
+
+ const Object *o = static_cast<const Object *>(m);
+ while (o) {
+ uint idx = o->internalClass->find(name);
+ if (idx < UINT_MAX)
+ return o->internalClass->propertyData[idx];
+
+ o = o->prototype;
+ }
+ return Attr_Invalid;
+}
+
+PropertyAttributes Object::queryIndexed(const Managed *m, uint index)
+{
+ const Object *o = static_cast<const Object *>(m);
+ while (o) {
+ uint pidx = o->propertyIndexFromArrayIndex(index);
+ if (pidx < UINT_MAX) {
+ if (o->arrayAttributes)
+ return o->arrayAttributes[pidx];
+ return Attr_Data;
+ }
+ if (o->isStringObject()) {
+ Property *p = static_cast<const StringObject *>(o)->getIndex(index);
+ if (p)
+ return Attr_Data;
+ }
+ o = o->prototype;
+ }
+ return Attr_Invalid;
+}
+
+bool Object::deleteProperty(Managed *m, String *name)
+{
+ return static_cast<Object *>(m)->internalDeleteProperty(name);
+}
+
+bool Object::deleteIndexedProperty(Managed *m, uint index)
+{
+ return static_cast<Object *>(m)->internalDeleteIndexedProperty(index);
+}
+
+void Object::getLookup(Managed *m, Lookup *l, Value *result)
+{
+ Object *o = static_cast<Object *>(m);
+ PropertyAttributes attrs;
+ Property *p = l->lookup(o, &attrs);
+ if (p) {
+ if (attrs.isData()) {
+ if (l->level == 0)
+ l->getter = Lookup::getter0;
+ else if (l->level == 1)
+ l->getter = Lookup::getter1;
+ else if (l->level == 2)
+ l->getter = Lookup::getter2;
+ if (result)
+ *result = p->value;
+ return;
+ } else {
+ if (l->level == 0)
+ l->getter = Lookup::getterAccessor0;
+ else if (l->level == 1)
+ l->getter = Lookup::getterAccessor1;
+ else if (l->level == 2)
+ l->getter = Lookup::getterAccessor2;
+ if (result)
+ *result = p->value;
+ Value res = o->getValue(p, attrs);
+ if (result)
+ *result = res;
+ return;
+ }
+ } else if (result) {
+ *result = Value::undefinedValue();
+ }
+}
+
+void Object::setLookup(Managed *m, Lookup *l, const Value &value)
+{
+ Object *o = static_cast<Object *>(m);
+
+ uint idx = o->internalClass->find(l->name);
+ if (!o->isArrayObject() || idx != ArrayObject::LengthPropertyIndex) {
+ if (idx != UINT_MAX && o->internalClass->propertyData[idx].isData() && o->internalClass->propertyData[idx].isWritable()) {
+ l->classList[0] = o->internalClass;
+ l->index = idx;
+ l->setter = Lookup::setter0;
+ o->memberData[idx].value = value;
+ return;
+ }
+
+ if (idx != UINT_MAX) {
+ o->putValue(o->memberData + idx, o->internalClass->propertyData[idx], value);
+ return;
+ }
+ }
+
+ o->put(l->name, value);
+}
+
+Property *Object::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs)
+{
+ Object *o = static_cast<Object *>(m);
+ *name = 0;
+ *index = UINT_MAX;
+
+ if (!it->arrayIndex)
+ it->arrayNode = o->sparseArrayBegin();
+
+ // sparse arrays
+ if (it->arrayNode) {
+ while (it->arrayNode != o->sparseArrayEnd()) {
+ int k = it->arrayNode->key();
+ uint pidx = it->arrayNode->value;
+ Property *p = o->arrayData + pidx;
+ it->arrayNode = it->arrayNode->nextNode();
+ PropertyAttributes a = o->arrayAttributes ? o->arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
+ if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
+ it->arrayIndex = k + 1;
+ *index = k;
+ if (attrs)
+ *attrs = a;
+ return p;
+ }
+ }
+ it->arrayNode = 0;
+ it->arrayIndex = UINT_MAX;
+ }
+ // dense arrays
+ while (it->arrayIndex < o->arrayDataLen) {
+ uint pidx = o->propertyIndexFromArrayIndex(it->arrayIndex);
+ Property *p = o->arrayData + pidx;
+ PropertyAttributes a = o->arrayAttributes ? o->arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
+ ++it->arrayIndex;
+ if ((!o->arrayAttributes || !o->arrayAttributes[pidx].isGeneric())
+ && (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable())) {
+ *index = it->arrayIndex - 1;
+ if (attrs)
+ *attrs = a;
+ return p;
+ }
+ }
+
+ while (it->memberIndex < o->internalClass->size) {
+ String *n = o->internalClass->nameMap.at(it->memberIndex);
+ assert(n);
+
+ Property *p = o->memberData + it->memberIndex;
+ PropertyAttributes a = o->internalClass->propertyData[it->memberIndex];
+ ++it->memberIndex;
+ if (!(it->flags & ObjectIterator::EnumerableOnly) || a.isEnumerable()) {
+ *name = n;
+ if (attrs)
+ *attrs = a;
+ return p;
+ }
+ }
+
+ return 0;
+}
+
+// Section 8.12.3
+Value Object::internalGet(String *name, bool *hasProperty)
+{
+ uint idx = name->asArrayIndex();
+ if (idx != UINT_MAX)
+ return getIndexed(idx, hasProperty);
+
+ name->makeIdentifier();
+
+ Object *o = this;
+ while (o) {
+ uint idx = o->internalClass->find(name);
+ if (idx < UINT_MAX) {
+ if (hasProperty)
+ *hasProperty = true;
+ return getValue(o->memberData + idx, o->internalClass->propertyData.at(idx));
+ }
+
+ o = o->prototype;
+ }
+
+ if (hasProperty)
+ *hasProperty = false;
+ return Value::undefinedValue();
+}
+
+Value Object::internalGetIndexed(uint index, bool *hasProperty)
+{
+ Property *pd = 0;
+ PropertyAttributes attrs = Attr_Data;
+ Object *o = this;
+ while (o) {
+ uint pidx = o->propertyIndexFromArrayIndex(index);
+ if (pidx < UINT_MAX) {
+ if (!o->arrayAttributes || !o->arrayAttributes[pidx].isGeneric()) {
+ pd = o->arrayData + pidx;
+ if (o->arrayAttributes)
+ attrs = o->arrayAttributes[pidx];
+ break;
+ }
+ }
+ if (o->isStringObject()) {
+ pd = static_cast<StringObject *>(o)->getIndex(index);
+ if (pd) {
+ attrs = (Attr_NotWritable|Attr_NotConfigurable);
+ break;
+ }
+ }
+ o = o->prototype;
+ }
+
+ if (pd) {
+ if (hasProperty)
+ *hasProperty = true;
+ return getValue(pd, attrs);
+ }
+
+ if (hasProperty)
+ *hasProperty = false;
+ return Value::undefinedValue();
+}
+
+
+// Section 8.12.5
+void Object::internalPut(String *name, const Value &value)
+{
+ uint idx = name->asArrayIndex();
+ if (idx != UINT_MAX)
+ return putIndexed(idx, value);
+
+ name->makeIdentifier();
+
+ uint member = internalClass->find(name);
+ Property *pd = 0;
+ PropertyAttributes attrs;
+ if (member < UINT_MAX) {
+ pd = memberData + member;
+ attrs = internalClass->propertyData[member];
+ }
+
+ // clause 1
+ if (pd) {
+ if (attrs.isAccessor()) {
+ if (pd->setter())
+ goto cont;
+ goto reject;
+ } else if (!attrs.isWritable())
+ goto reject;
+ else if (isArrayObject() && name->isEqualTo(engine()->id_length)) {
+ bool ok;
+ uint l = value.asArrayLength(&ok);
+ if (!ok)
+ engine()->current->throwRangeError(value);
+ ok = setArrayLength(l);
+ if (!ok)
+ goto reject;
+ } else {
+ pd->value = value;
+ }
+ return;
+ } else if (!prototype) {
+ if (!extensible)
+ goto reject;
+ } else {
+ // clause 4
+ if ((pd = prototype->__getPropertyDescriptor__(name, &attrs))) {
+ if (attrs.isAccessor()) {
+ if (!pd->setter())
+ goto reject;
+ } else if (!extensible || !attrs.isWritable()) {
+ goto reject;
+ }
+ } else if (!extensible) {
+ goto reject;
+ }
+ }
+
+ cont:
+
+ // Clause 5
+ if (pd && attrs.isAccessor()) {
+ assert(pd->setter() != 0);
+
+ Value args[1];
+ args[0] = value;
+ pd->setter()->call(Value::fromObject(this), args, 1);
+ return;
+ }
+
+ {
+ Property *p = insertMember(name, Attr_Data);
+ p->value = value;
+ return;
+ }
+
+ reject:
+ if (engine()->current->strictMode) {
+ QString message = QStringLiteral("Cannot assign to read-only property \"");
+ message += name->toQString();
+ message += QLatin1Char('\"');
+ engine()->current->throwTypeError(message);
+ }
+}
+
+void Object::internalPutIndexed(uint index, const Value &value)
+{
+ Property *pd = 0;
+ PropertyAttributes attrs;
+
+ uint pidx = propertyIndexFromArrayIndex(index);
+ if (pidx < UINT_MAX) {
+ if (arrayAttributes && arrayAttributes[pidx].isGeneric()) {
+ pidx = UINT_MAX;
+ } else {
+ pd = arrayData + pidx;
+ attrs = arrayAttributes ? arrayAttributes[pidx] : PropertyAttributes(Attr_Data);
+ }
+ }
+
+ if (!pd && isStringObject()) {
+ pd = static_cast<StringObject *>(this)->getIndex(index);
+ if (pd)
+ // not writable
+ goto reject;
+ }
+
+ // clause 1
+ if (pd) {
+ if (attrs.isAccessor()) {
+ if (pd->setter())
+ goto cont;
+ goto reject;
+ } else if (!attrs.isWritable())
+ goto reject;
+ else
+ pd->value = value;
+ return;
+ } else if (!prototype) {
+ if (!extensible)
+ goto reject;
+ } else {
+ // clause 4
+ if ((pd = prototype->__getPropertyDescriptor__(index, &attrs))) {
+ if (attrs.isAccessor()) {
+ if (!pd->setter())
+ goto reject;
+ } else if (!extensible || !attrs.isWritable()) {
+ goto reject;
+ }
+ } else if (!extensible) {
+ goto reject;
+ }
+ }
+
+ cont:
+
+ // Clause 5
+ if (pd && attrs.isAccessor()) {
+ assert(pd->setter() != 0);
+
+ Value args[1];
+ args[0] = value;
+ pd->setter()->call(Value::fromObject(this), args, 1);
+ return;
+ }
+
+ arraySet(index, value);
+ return;
+
+ reject:
+ if (engine()->current->strictMode)
+ engine()->current->throwTypeError();
+}
+
+// Section 8.12.7
+bool Object::internalDeleteProperty(String *name)
+{
+ uint idx = name->asArrayIndex();
+ if (idx != UINT_MAX)
+ return deleteIndexedProperty(idx);
+
+ name->makeIdentifier();
+
+ uint memberIdx = internalClass->find(name);
+ if (memberIdx != UINT_MAX) {
+ if (internalClass->propertyData[memberIdx].isConfigurable()) {
+ internalClass->removeMember(this, name->identifier);
+ memmove(memberData + memberIdx, memberData + memberIdx + 1, (internalClass->size - memberIdx)*sizeof(Property));
+ return true;
+ }
+ if (engine()->current->strictMode)
+ engine()->current->throwTypeError();
+ return false;
+ }
+
+ return true;
+}
+
+bool Object::internalDeleteIndexedProperty(uint index)
+{
+ uint pidx = propertyIndexFromArrayIndex(index);
+ if (pidx == UINT_MAX)
+ return true;
+ if (arrayAttributes && arrayAttributes[pidx].isGeneric())
+ return true;
+
+ if (!arrayAttributes || arrayAttributes[pidx].isConfigurable()) {
+ arrayData[pidx].value = Value::undefinedValue();
+ if (!arrayAttributes)
+ ensureArrayAttributes();
+ arrayAttributes[pidx].clear();
+ if (sparseArray) {
+ arrayData[pidx].value.int_32 = arrayFreeList;
+ arrayFreeList = pidx;
+ }
+ return true;
+ }
+
+ if (engine()->current->strictMode)
+ engine()->current->throwTypeError();
+ return false;
+}
+
+// Section 8.12.9
+bool Object::__defineOwnProperty__(ExecutionContext *ctx, String *name, const Property &p, PropertyAttributes attrs)
+{
+ uint idx = name->asArrayIndex();
+ if (idx != UINT_MAX)
+ return __defineOwnProperty__(ctx, idx, p, attrs);
+
+ name->makeIdentifier();
+
+ Property *current;
+ PropertyAttributes *cattrs;
+
+ if (isArrayObject() && name->isEqualTo(ctx->engine->id_length)) {
+ assert(ArrayObject::LengthPropertyIndex == internalClass->find(ctx->engine->id_length));
+ Property *lp = memberData + ArrayObject::LengthPropertyIndex;
+ cattrs = internalClass->propertyData.data() + ArrayObject::LengthPropertyIndex;
+ if (attrs.isEmpty() || p.isSubset(attrs, *lp, *cattrs))
+ return true;
+ if (!cattrs->isWritable() || attrs.type() == PropertyAttributes::Accessor || attrs.isConfigurable() || attrs.isEnumerable())
+ goto reject;
+ bool succeeded = true;
+ if (attrs.type() == PropertyAttributes::Data) {
+ bool ok;
+ uint l = p.value.asArrayLength(&ok);
+ if (!ok)
+ ctx->throwRangeError(p.value);
+ succeeded = setArrayLength(l);
+ }
+ if (attrs.hasWritable() && !attrs.isWritable())
+ cattrs->setWritable(false);
+ if (!succeeded)
+ goto reject;
+ return true;
+ }
+
+ // Clause 1
+ {
+ uint member = internalClass->find(name);
+ current = (member < UINT_MAX) ? memberData + member : 0;
+ cattrs = internalClass->propertyData.data() + member;
+ }
+
+ if (!current) {
+ // clause 3
+ if (!extensible)
+ goto reject;
+ // clause 4
+ Property *pd = insertMember(name, attrs);
+ *pd = p;
+ pd->fullyPopulated(&attrs);
+ return true;
+ }
+
+ return __defineOwnProperty__(ctx, current, name, p, attrs);
+reject:
+ if (ctx->strictMode)
+ ctx->throwTypeError();
+ return false;
+}
+
+bool Object::__defineOwnProperty__(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs)
+{
+ Property *current = 0;
+
+ // 15.4.5.1, 4b
+ if (isArrayObject() && index >= arrayLength() && !internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
+ goto reject;
+
+ if (isNonStrictArgumentsObject)
+ return static_cast<ArgumentsObject *>(this)->defineOwnProperty(ctx, index, p, attrs);
+
+ // Clause 1
+ {
+ uint pidx = propertyIndexFromArrayIndex(index);
+ if (pidx < UINT_MAX && (!arrayAttributes || !arrayAttributes[pidx].isGeneric()))
+ current = arrayData + pidx;
+ if (!current && isStringObject())
+ current = static_cast<StringObject *>(this)->getIndex(index);
+ }
+
+ if (!current) {
+ // clause 3
+ if (!extensible)
+ goto reject;
+ // clause 4
+ Property *pd = arrayInsert(index, attrs);
+ *pd = p;
+ pd->fullyPopulated(&attrs);
+ return true;
+ }
+
+ return __defineOwnProperty__(ctx, current, 0 /*member*/, p, attrs);
+reject:
+ if (ctx->strictMode)
+ ctx->throwTypeError();
+ return false;
+}
+
+bool Object::__defineOwnProperty__(ExecutionContext *ctx, Property *current, String *member, const Property &p, PropertyAttributes attrs)
+{
+ // clause 5
+ if (attrs.isEmpty())
+ return true;
+
+ PropertyAttributes cattrs = Attr_Data;
+ if (member)
+ cattrs = internalClass->propertyData[current - memberData];
+ else if (arrayAttributes)
+ cattrs = arrayAttributes[current - arrayData];
+
+ // clause 6
+ if (p.isSubset(attrs, *current, cattrs))
+ return true;
+
+ // clause 7
+ if (!cattrs.isConfigurable()) {
+ if (attrs.isConfigurable())
+ goto reject;
+ if (attrs.hasEnumerable() && attrs.isEnumerable() != cattrs.isEnumerable())
+ goto reject;
+ }
+
+ // clause 8
+ if (attrs.isGeneric())
+ goto accept;
+
+ // clause 9
+ if (cattrs.isData() != attrs.isData()) {
+ // 9a
+ if (!cattrs.isConfigurable())
+ goto reject;
+ if (cattrs.isData()) {
+ // 9b
+ cattrs.setType(PropertyAttributes::Accessor);
+ cattrs.clearWritable();
+ current->setGetter(0);
+ current->setSetter(0);
+ } else {
+ // 9c
+ cattrs.setType(PropertyAttributes::Data);
+ cattrs.setWritable(false);
+ current->value = Value::undefinedValue();
+ }
+ } else if (cattrs.isData() && attrs.isData()) { // clause 10
+ if (!cattrs.isConfigurable() && !cattrs.isWritable()) {
+ if (attrs.isWritable() || !current->value.sameValue(p.value))
+ goto reject;
+ }
+ } else { // clause 10
+ assert(cattrs.isAccessor() && attrs.isAccessor());
+ if (!cattrs.isConfigurable()) {
+ if (p.getter() && !(current->getter() == p.getter() || (!current->getter() && (quintptr)p.getter() == 0x1)))
+ goto reject;
+ if (p.setter() && !(current->setter() == p.setter() || (!current->setter() && (quintptr)p.setter() == 0x1)))
+ goto reject;
+ }
+ }
+
+ accept:
+
+ current->merge(cattrs, p, attrs);
+ if (member) {
+ internalClass = internalClass->changeMember(member, cattrs);
+ } else {
+ if (cattrs != Attr_Data)
+ ensureArrayAttributes();
+ if (arrayAttributes)
+ arrayAttributes[current - arrayData] = cattrs;
+ }
+ return true;
+ reject:
+ if (ctx->strictMode)
+ ctx->throwTypeError();
+ return false;
+}
+
+
+bool Object::__defineOwnProperty__(ExecutionContext *ctx, const QString &name, const Property &p, PropertyAttributes attrs)
+{
+ return __defineOwnProperty__(ctx, ctx->engine->newString(name), p, attrs);
+}
+
+
+void Object::copyArrayData(Object *other)
+{
+ arrayReserve(other->arrayDataLen);
+ arrayDataLen = other->arrayDataLen;
+ memcpy(arrayData, other->arrayData, arrayDataLen*sizeof(Property));
+ arrayOffset = 0;
+ if (other->sparseArray) {
+ sparseArray = new SparseArray(*other->sparseArray);
+ arrayFreeList = other->arrayFreeList;
+ }
+ if (isArrayObject())
+ setArrayLengthUnchecked(other->arrayLength());
+}
+
+
+Value Object::arrayIndexOf(Value v, uint fromIndex, uint endIndex, ExecutionContext *ctx, Object *o)
+{
+ bool protoHasArray = false;
+ Object *p = o;
+ while ((p = p->prototype))
+ if (p->arrayDataLen)
+ protoHasArray = true;
+
+ if (protoHasArray || o->arrayAttributes) {
+ // lets be safe and slow
+ for (uint i = fromIndex; i < endIndex; ++i) {
+ bool exists;
+ Value value = o->getIndexed(i, &exists);
+ if (exists && __qmljs_strict_equal(value, v))
+ return Value::fromDouble(i);
+ }
+ } else if (sparseArray) {
+ for (SparseArrayNode *n = sparseArray->lowerBound(fromIndex); n != sparseArray->end() && n->key() < endIndex; n = n->nextNode()) {
+ Value value = o->getValue(arrayData + n->value, arrayAttributes ? arrayAttributes[n->value] : Attr_Data);
+ if (__qmljs_strict_equal(value, v))
+ return Value::fromDouble(n->key());
+ }
+ } else {
+ if ((int) endIndex > arrayDataLen)
+ endIndex = arrayDataLen;
+ Property *pd = arrayData;
+ Property *end = pd + endIndex;
+ pd += fromIndex;
+ while (pd < end) {
+ if (!arrayAttributes || !arrayAttributes[pd - arrayData].isGeneric()) {
+ Value value = o->getValue(pd, arrayAttributes ? arrayAttributes[pd - arrayData] : Attr_Data);
+ if (__qmljs_strict_equal(value, v))
+ return Value::fromDouble(pd - arrayData);
+ }
+ ++pd;
+ }
+ }
+ return Value::fromInt32(-1);
+}
+
+void Object::arrayConcat(const ArrayObject *other)
+{
+ int newLen = arrayDataLen + other->arrayLength();
+ if (other->sparseArray)
+ initSparse();
+ // ### copy attributes as well!
+ if (sparseArray) {
+ if (other->sparseArray) {
+ for (const SparseArrayNode *it = other->sparseArray->begin(); it != other->sparseArray->end(); it = it->nextNode())
+ arraySet(arrayDataLen + it->key(), other->arrayData + it->value);
+ } else {
+ int oldSize = arrayDataLen;
+ arrayReserve(oldSize + other->arrayLength());
+ memcpy(arrayData + oldSize, other->arrayData, other->arrayLength()*sizeof(Property));
+ if (arrayAttributes)
+ std::fill(arrayAttributes + oldSize, arrayAttributes + oldSize + other->arrayLength(), PropertyAttributes(Attr_Data));
+ for (uint i = 0; i < other->arrayLength(); ++i) {
+ SparseArrayNode *n = sparseArray->insert(arrayDataLen + i);
+ n->value = oldSize + i;
+ }
+ }
+ } else {
+ int oldSize = arrayLength();
+ arrayReserve(oldSize + other->arrayDataLen);
+ if (oldSize > arrayDataLen) {
+ ensureArrayAttributes();
+ std::fill(arrayAttributes + arrayDataLen, arrayAttributes + oldSize, PropertyAttributes());
+ }
+ arrayDataLen = oldSize + other->arrayDataLen;
+ if (other->arrayAttributes) {
+ for (int i = 0; i < arrayDataLen; ++i) {
+ bool exists;
+ arrayData[oldSize + i].value = const_cast<ArrayObject *>(other)->getIndexed(i, &exists);
+ if (arrayAttributes)
+ arrayAttributes[oldSize + i] = Attr_Data;
+ if (!exists) {
+ ensureArrayAttributes();
+ arrayAttributes[oldSize + i].clear();
+ }
+ }
+ } else {
+ memcpy(arrayData + oldSize, other->arrayData, other->arrayDataLen*sizeof(Property));
+ if (arrayAttributes)
+ std::fill(arrayAttributes + oldSize, arrayAttributes + oldSize + other->arrayDataLen, PropertyAttributes(Attr_Data));
+ }
+ }
+ setArrayLengthUnchecked(newLen);
+}
+
+void Object::arraySort(ExecutionContext *context, Object *thisObject, const Value &comparefn, uint len)
+{
+ if (!arrayDataLen)
+ return;
+
+ if (sparseArray) {
+ context->throwUnimplemented("Object::sort unimplemented for sparse arrays");
+ return;
+ }
+
+ if (len > arrayDataLen)
+ len = arrayDataLen;
+
+ // The spec says the sorting goes through a series of get,put and delete operations.
+ // this implies that the attributes don't get sorted around.
+ // behavior of accessor properties is implementation defined. We simply turn them all
+ // into data properties and then sort. This is in line with the sentence above.
+ if (arrayAttributes) {
+ for (uint i = 0; i < len; i++) {
+ if (arrayAttributes[i].isGeneric()) {
+ while (--len > i)
+ if (!arrayAttributes[len].isGeneric())
+ break;
+ arrayData[i].value = getValue(arrayData + len, arrayAttributes[len]);
+ arrayAttributes[i] = Attr_Data;
+ arrayAttributes[len].clear();
+ } else if (arrayAttributes[i].isAccessor()) {
+ arrayData[i].value = getValue(arrayData + i, arrayAttributes[i]);
+ arrayAttributes[i] = Attr_Data;
+ }
+ }
+ }
+
+ ArrayElementLessThan lessThan(context, thisObject, comparefn);
+
+ Property *begin = arrayData;
+ // We deliberately choose qSort over std::sort here, because with
+ // MSVC in debug builds, std::sort has an ASSERT() that verifies
+ // that the return values of lessThan are perfectly consistent
+ // and aborts otherwise. We do not want JavaScript to easily crash
+ // the entire application and therefore choose qSort, which doesn't
+ // have this property.
+ qSort(begin, begin + len, lessThan);
+}
+
+
+void Object::initSparse()
+{
+ if (!sparseArray) {
+ sparseArray = new SparseArray;
+ for (int i = 0; i < arrayDataLen; ++i) {
+ if (!arrayAttributes || !arrayAttributes[i].isGeneric()) {
+ SparseArrayNode *n = sparseArray->insert(i);
+ n->value = i + arrayOffset;
+ }
+ }
+
+ uint off = arrayOffset;
+ if (!arrayOffset) {
+ arrayFreeList = arrayDataLen;
+ } else {
+ arrayFreeList = 0;
+ arrayData -= off;
+ arrayAlloc += off;
+ int o = off;
+ for (int i = 0; i < o - 1; ++i) {
+ arrayData[i].value = Value::fromInt32(i + 1);
+ }
+ arrayData[o - 1].value = Value::fromInt32(arrayDataLen + off);
+ }
+ for (int i = arrayDataLen + off; i < arrayAlloc; ++i) {
+ arrayData[i].value = Value::fromInt32(i + 1);
+ }
+ }
+}
+
+void Object::arrayReserve(uint n)
+{
+ if (n < 8)
+ n = 8;
+ if (n >= arrayAlloc) {
+ uint off;
+ if (sparseArray) {
+ assert(arrayFreeList == arrayAlloc);
+ // ### FIXME
+ arrayDataLen = arrayAlloc;
+ off = 0;
+ } else {
+ off = arrayOffset;
+ }
+ arrayAlloc = qMax(n, 2*arrayAlloc);
+ Property *newArrayData = new Property[arrayAlloc];
+ if (arrayData) {
+ memcpy(newArrayData, arrayData, sizeof(Property)*arrayDataLen);
+ delete [] (arrayData - off);
+ }
+ arrayData = newArrayData;
+ if (sparseArray) {
+ for (uint i = arrayFreeList; i < arrayAlloc; ++i) {
+ arrayData[i].value = Value::emptyValue();
+ arrayData[i].value = Value::fromInt32(i + 1);
+ }
+ } else {
+ arrayOffset = 0;
+ }
+
+ if (arrayAttributes) {
+ PropertyAttributes *newAttrs = new PropertyAttributes[arrayAlloc];
+ memcpy(newAttrs, arrayAttributes, sizeof(PropertyAttributes)*arrayDataLen);
+ delete [] (arrayAttributes - off);
+
+ arrayAttributes = newAttrs;
+ if (sparseArray) {
+ for (uint i = arrayFreeList; i < arrayAlloc; ++i)
+ arrayAttributes[i] = Attr_Invalid;
+ }
+ }
+ }
+}
+
+void Object::ensureArrayAttributes()
+{
+ if (arrayAttributes)
+ return;
+
+ arrayAttributes = new PropertyAttributes[arrayAlloc];
+ for (uint i = 0; i < arrayDataLen; ++i)
+ arrayAttributes[i] = Attr_Data;
+ for (uint i = arrayDataLen; i < arrayAlloc; ++i)
+ arrayAttributes[i] = Attr_Invalid;
+}
+
+
+bool Object::setArrayLength(uint newLen) {
+ assert(isArrayObject());
+ const Property *lengthProperty = memberData + ArrayObject::LengthPropertyIndex;
+ if (lengthProperty && !internalClass->propertyData[ArrayObject::LengthPropertyIndex].isWritable())
+ return false;
+ uint oldLen = arrayLength();
+ bool ok = true;
+ if (newLen < oldLen) {
+ if (sparseArray) {
+ SparseArrayNode *begin = sparseArray->lowerBound(newLen);
+ if (begin != sparseArray->end()) {
+ SparseArrayNode *it = sparseArray->end()->previousNode();
+ while (1) {
+ Property &pd = arrayData[it->value];
+ if (arrayAttributes) {
+ if (!arrayAttributes[it->value].isConfigurable()) {
+ ok = false;
+ newLen = it->key() + 1;
+ break;
+ } else {
+ arrayAttributes[it->value].clear();
+ }
+ }
+ pd.value.tag = Value::_Empty_Type;
+ pd.value.int_32 = arrayFreeList;
+ arrayFreeList = it->value;
+ bool brk = (it == begin);
+ SparseArrayNode *prev = it->previousNode();
+ sparseArray->erase(it);
+ if (brk)
+ break;
+ it = prev;
+ }
+ }
+ } else {
+ Property *it = arrayData + arrayDataLen;
+ const Property *begin = arrayData + newLen;
+ while (--it >= begin) {
+ if (arrayAttributes) {
+ if (!arrayAttributes[it - arrayData].isEmpty() && !arrayAttributes[it - arrayData].isConfigurable()) {
+ ok = false;
+ newLen = it - arrayData + 1;
+ break;
+ } else {
+ arrayAttributes[it - arrayData].clear();
+ }
+ it->value = Value::emptyValue();
+ }
+ }
+ arrayDataLen = newLen;
+ }
+ } else {
+ if (newLen >= 0x100000)
+ initSparse();
+ }
+ setArrayLengthUnchecked(newLen);
+ return ok;
+}
+
+void Object::markArrayObjects() const
+{
+ for (uint i = 0; i < arrayDataLen; ++i) {
+ const Property &pd = arrayData[i];
+ if (!arrayAttributes || arrayAttributes[i].isData()) {
+ if (Managed *m = pd.value.asManaged())
+ m->mark();
+ } else if (arrayAttributes[i].isAccessor()) {
+ if (pd.getter())
+ pd.getter()->mark();
+ if (pd.setter())
+ pd.setter()->mark();
+ }
+ }
+}
+
+ArrayObject::ArrayObject(ExecutionEngine *engine, const QStringList &list)
+ : Object(engine)
+{
+ init(engine);
+
+ // Converts a QStringList to JS.
+ // The result is a new Array object with length equal to the length
+ // of the QStringList, and the elements being the QStringList's
+ // elements converted to JS Strings.
+ int len = list.count();
+ arrayReserve(len);
+ for (int ii = 0; ii < len; ++ii)
+ arrayData[ii].value = Value::fromString(engine->newString(list.at(ii)));
+ setArrayLengthUnchecked(len);
+}
+
+void ArrayObject::init(ExecutionEngine *engine)
+{
+ type = Type_ArrayObject;
+ internalClass = engine->arrayClass;
+
+ memberData = new Property[4];
+ memberData[LengthPropertyIndex].value = Value::fromInt32(0);
+}
+
+QStringList ArrayObject::toQStringList() const
+{
+ QStringList result;
+
+ QV4::ExecutionEngine *engine = internalClass->engine;
+
+ uint32_t length = arrayLength();
+ for (uint32_t i = 0; i < length; ++i)
+ result.append(const_cast<ArrayObject *>(this)->getIndexed(i).toString(engine->current)->toQString());
+ return result;
+}
+
+
+DEFINE_MANAGED_VTABLE(ForEachIteratorObject);
+
+void ForEachIteratorObject::markObjects(Managed *that)
+{
+ ForEachIteratorObject *o = static_cast<ForEachIteratorObject *>(that);
+ Object::markObjects(that);
+ if (o->it.object)
+ o->it.object->mark();
+}
diff --git a/src/qml/qml/v4/qv4object_p.h b/src/qml/qml/v4/qv4object_p.h
new file mode 100644
index 0000000000..a6f1c04abd
--- /dev/null
+++ b/src/qml/qml/v4/qv4object_p.h
@@ -0,0 +1,432 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QMLJS_OBJECTS_H
+#define QMLJS_OBJECTS_H
+
+#include "qv4global_p.h"
+#include "qv4runtime_p.h"
+#include "qv4engine_p.h"
+#include "qv4context_p.h"
+#include "qv4sparsearray_p.h"
+#include "qv4string_p.h"
+#include "qv4codegen_p.h"
+#include "qv4isel_p.h"
+#include "qv4managed_p.h"
+#include "qv4property_p.h"
+#include "qv4internalclass_p.h"
+#include "qv4objectiterator_p.h"
+
+#include <QtCore/QString>
+#include <QtCore/QHash>
+#include <QtCore/QScopedPointer>
+#include <cstdio>
+#include <cassert>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct Function;
+struct Lookup;
+struct Object;
+struct ObjectIterator;
+struct BooleanObject;
+struct NumberObject;
+struct StringObject;
+struct ArrayObject;
+struct DateObject;
+struct FunctionObject;
+struct RegExpObject;
+struct ErrorObject;
+struct ArgumentsObject;
+struct ExecutionContext;
+struct CallContext;
+struct ExecutionEngine;
+class MemoryManager;
+
+struct ObjectPrototype;
+struct StringPrototype;
+struct NumberPrototype;
+struct BooleanPrototype;
+struct ArrayPrototype;
+struct FunctionPrototype;
+struct DatePrototype;
+struct RegExpPrototype;
+struct ErrorPrototype;
+struct EvalErrorPrototype;
+struct RangeErrorPrototype;
+struct ReferenceErrorPrototype;
+struct SyntaxErrorPrototype;
+struct TypeErrorPrototype;
+struct URIErrorPrototype;
+
+typedef Value (*PropertyEnumeratorFunction)(Object *object);
+typedef PropertyAttributes (*PropertyQueryFunction)(const Object *object, String *name);
+
+struct Q_QML_EXPORT Object: Managed {
+ Object *prototype;
+ uint memberDataAlloc;
+ Property *memberData;
+
+ union {
+ uint arrayFreeList;
+ uint arrayOffset;
+ };
+ uint arrayDataLen;
+ uint arrayAlloc;
+ PropertyAttributes *arrayAttributes;
+ Property *arrayData;
+ SparseArray *sparseArray;
+
+ enum {
+ InlinePropertySize = 4
+ };
+ Property inlineProperties[InlinePropertySize];
+
+ Object(ExecutionEngine *engine);
+ Object(ExecutionContext *context);
+ Object(ExecutionEngine *engine, InternalClass *internalClass);
+ ~Object();
+
+ Property *__getOwnProperty__(String *name, PropertyAttributes *attrs = 0);
+ Property *__getOwnProperty__(uint index, PropertyAttributes *attrs = 0);
+
+ Property *__getPropertyDescriptor__(String *name, PropertyAttributes *attrs = 0) const;
+ Property *__getPropertyDescriptor__(uint index, PropertyAttributes *attrs = 0) const;
+
+ bool __hasProperty__(String *name) const;
+ bool __hasProperty__(uint index) const {
+ return __getPropertyDescriptor__(index);
+ }
+
+ bool __defineOwnProperty__(ExecutionContext *ctx, Property *current, String *member, const Property &p, PropertyAttributes attrs);
+ bool __defineOwnProperty__(ExecutionContext *ctx, String *name, const Property &p, PropertyAttributes attrs);
+ bool __defineOwnProperty__(ExecutionContext *ctx, uint index, const Property &p, PropertyAttributes attrs);
+ bool __defineOwnProperty__(ExecutionContext *ctx, const QString &name, const Property &p, PropertyAttributes attrs);
+
+ //
+ // helpers
+ //
+ void put(ExecutionContext *ctx, const QString &name, const Value &value);
+
+ static Value getValue(const Value &thisObject, const Property *p, PropertyAttributes attrs);
+ Value getValue(const Property *p, PropertyAttributes attrs) const {
+ return getValue(Value::fromObject(const_cast<Object *>(this)), p, attrs);
+ }
+
+ void putValue(Property *pd, PropertyAttributes attrs, const Value &value);
+
+ void inplaceBinOp(ExecutionContext *ctx, BinOp op, String *name, const Value &rhs);
+ void inplaceBinOp(ExecutionContext *ctx, BinOp op, const Value &index, const Value &rhs);
+
+ /* The spec default: Writable: true, Enumerable: false, Configurable: true */
+ void defineDefaultProperty(String *name, Value value);
+ void defineDefaultProperty(ExecutionContext *context, const QString &name, Value value);
+ void defineDefaultProperty(ExecutionEngine *engine, const QString &name, Value value);
+ void defineDefaultProperty(ExecutionContext *context, const QString &name, Value (*code)(SimpleCallContext *), int count = 0);
+ void defineDefaultProperty(ExecutionEngine *engine, const QString &name, Value (*code)(SimpleCallContext *), int count = 0);
+ void defineAccessorProperty(ExecutionEngine *engine, const QString &name, Value (*getter)(SimpleCallContext *), Value (*setter)(SimpleCallContext *));
+ void defineAccessorProperty(String *name, Value (*getter)(SimpleCallContext *), Value (*setter)(SimpleCallContext *));
+ /* Fixed: Writable: false, Enumerable: false, Configurable: false */
+ void defineReadonlyProperty(ExecutionEngine *engine, const QString &name, Value value);
+ void defineReadonlyProperty(String *name, Value value);
+
+ Property *insertMember(String *s, PropertyAttributes attributes);
+
+ inline ExecutionEngine *engine() const { return internalClass->engine; }
+
+ // Array handling
+
+ uint allocArrayValue() {
+ uint idx = arrayFreeList;
+ if (arrayAlloc <= arrayFreeList)
+ arrayReserve(arrayAlloc + 1);
+ arrayFreeList = arrayData[arrayFreeList].value.uint_32;
+ if (arrayAttributes)
+ arrayAttributes[idx].setType(PropertyAttributes::Data);
+ return idx;
+ }
+
+ uint allocArrayValue(Value v) {
+ uint idx = allocArrayValue();
+ Property *pd = &arrayData[idx];
+ pd->value = v;
+ return idx;
+ }
+ void freeArrayValue(int idx) {
+ Property &pd = arrayData[idx];
+ pd.value.tag = Value::_Empty_Type;
+ pd.value.int_32 = arrayFreeList;
+ arrayFreeList = idx;
+ if (arrayAttributes)
+ arrayAttributes[idx].clear();
+ }
+
+ void getArrayHeadRoom() {
+ assert(!sparseArray && !arrayOffset);
+ arrayOffset = qMax(arrayDataLen >> 2, (uint)16);
+ Property *newArray = new Property[arrayOffset + arrayAlloc];
+ memcpy(newArray + arrayOffset, arrayData, arrayDataLen*sizeof(Property));
+ delete [] arrayData;
+ arrayData = newArray + arrayOffset;
+ if (arrayAttributes) {
+ PropertyAttributes *newAttrs = new PropertyAttributes[arrayOffset + arrayAlloc];
+ memcpy(newAttrs + arrayOffset, arrayAttributes, arrayDataLen*sizeof(PropertyAttributes));
+ delete [] arrayAttributes;
+ arrayAttributes = newAttrs + arrayOffset;
+ }
+ }
+
+public:
+ void copyArrayData(Object *other);
+ void initSparse();
+
+ uint arrayLength() const;
+ bool setArrayLength(uint newLen);
+
+ void setArrayLengthUnchecked(uint l);
+
+ Property *arrayInsert(uint index, PropertyAttributes attributes = Attr_Data) {
+
+ Property *pd;
+ if (!sparseArray && (index < 0x1000 || index < arrayDataLen + (arrayDataLen >> 2))) {
+ if (index >= arrayAlloc)
+ arrayReserve(index + 1);
+ if (index >= arrayDataLen) {
+ ensureArrayAttributes();
+ for (uint i = arrayDataLen; i < index; ++i)
+ arrayAttributes[i].clear();
+ arrayDataLen = index + 1;
+ }
+ pd = arrayData + index;
+ } else {
+ initSparse();
+ SparseArrayNode *n = sparseArray->insert(index);
+ if (n->value == UINT_MAX)
+ n->value = allocArrayValue();
+ pd = arrayData + n->value;
+ }
+ if (index >= arrayLength())
+ setArrayLengthUnchecked(index + 1);
+ if (arrayAttributes || attributes != Attr_Data) {
+ if (!arrayAttributes)
+ ensureArrayAttributes();
+ attributes.resolve();
+ arrayAttributes[pd - arrayData] = attributes;
+ }
+ return pd;
+ }
+
+ void arraySet(uint index, const Property *pd) {
+ *arrayInsert(index) = *pd;
+ }
+
+ void arraySet(uint index, Value value) {
+ Property *pd = arrayInsert(index);
+ pd->value = value;
+ }
+
+ uint propertyIndexFromArrayIndex(uint index) const
+ {
+ if (!sparseArray) {
+ if (index >= arrayDataLen)
+ return UINT_MAX;
+ return index;
+ } else {
+ SparseArrayNode *n = sparseArray->findNode(index);
+ if (!n)
+ return UINT_MAX;
+ return n->value;
+ }
+ }
+
+ Property *arrayAt(uint index) const {
+ uint pidx = propertyIndexFromArrayIndex(index);
+ if (pidx == UINT_MAX)
+ return 0;
+ return arrayData + pidx;
+ }
+
+ Property *nonSparseArrayAt(uint index) const {
+ if (sparseArray)
+ return 0;
+ if (index >= arrayDataLen)
+ return 0;
+ return arrayData + index;
+ }
+
+ void markArrayObjects() const;
+
+ void push_back(Value v) {
+ uint idx = arrayLength();
+ if (!sparseArray) {
+ if (idx >= arrayAlloc)
+ arrayReserve(idx + 1);
+ arrayData[idx].value = v;
+ arrayDataLen = idx + 1;
+ } else {
+ uint idx = allocArrayValue(v);
+ sparseArray->push_back(idx, arrayLength());
+ }
+ setArrayLengthUnchecked(idx + 1);
+ }
+
+ SparseArrayNode *sparseArrayBegin() { return sparseArray ? sparseArray->begin() : 0; }
+ SparseArrayNode *sparseArrayEnd() { return sparseArray ? sparseArray->end() : 0; }
+
+ void arrayConcat(const ArrayObject *other);
+ void arraySort(ExecutionContext *context, Object *thisObject, const Value &comparefn, uint arrayDataLen);
+ Value arrayIndexOf(Value v, uint fromIndex, uint arrayDataLen, ExecutionContext *ctx, Object *o);
+
+ void arrayReserve(uint n);
+ void ensureArrayAttributes();
+
+ inline Value get(String *name, bool *hasProperty = 0)
+ { return vtbl->get(this, name, hasProperty); }
+ inline Value getIndexed(uint idx, bool *hasProperty = 0)
+ { return vtbl->getIndexed(this, idx, hasProperty); }
+ inline void put(String *name, const Value &v)
+ { vtbl->put(this, name, v); }
+ inline void putIndexed(uint idx, const Value &v)
+ { vtbl->putIndexed(this, idx, v); }
+ using Managed::get;
+ using Managed::getIndexed;
+ using Managed::put;
+ using Managed::putIndexed;
+ using Managed::query;
+ using Managed::queryIndexed;
+ using Managed::deleteProperty;
+ using Managed::deleteIndexedProperty;
+ using Managed::getLookup;
+ using Managed::setLookup;
+ using Managed::advanceIterator;
+protected:
+ static const ManagedVTable static_vtbl;
+ static void destroy(Managed *that);
+ static void markObjects(Managed *that);
+ static Value get(Managed *m, String *name, bool *hasProperty);
+ static Value getIndexed(Managed *m, uint index, bool *hasProperty);
+ static void put(Managed *m, String *name, const Value &value);
+ static void putIndexed(Managed *m, uint index, const Value &value);
+ static PropertyAttributes query(const Managed *m, String *name);
+ static PropertyAttributes queryIndexed(const Managed *m, uint index);
+ static bool deleteProperty(Managed *m, String *name);
+ static bool deleteIndexedProperty(Managed *m, uint index);
+ static void getLookup(Managed *m, Lookup *l, Value *result);
+ static void setLookup(Managed *m, Lookup *l, const Value &v);
+ static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes);
+
+
+private:
+ Value internalGet(String *name, bool *hasProperty);
+ Value internalGetIndexed(uint index, bool *hasProperty);
+ void internalPut(String *name, const Value &value);
+ void internalPutIndexed(uint index, const Value &value);
+ bool internalDeleteProperty(String *name);
+ bool internalDeleteIndexedProperty(uint index);
+
+ friend struct ObjectIterator;
+ friend struct ObjectPrototype;
+};
+
+struct ForEachIteratorObject: Object {
+ Q_MANAGED
+ ObjectIterator it;
+ ForEachIteratorObject(ExecutionContext *ctx, Object *o)
+ : Object(ctx->engine), it(o, ObjectIterator::EnumerableOnly|ObjectIterator::WithProtoChain) {
+ vtbl = &static_vtbl;
+ type = Type_ForeachIteratorObject;
+ }
+
+ Value nextPropertyName() { return it.nextPropertyNameAsString(); }
+
+protected:
+ static void markObjects(Managed *that);
+};
+
+struct BooleanObject: Object {
+ Value value;
+ BooleanObject(ExecutionEngine *engine, const Value &value): Object(engine), value(value) { type = Type_BooleanObject; }
+};
+
+struct NumberObject: Object {
+ Value value;
+ NumberObject(ExecutionEngine *engine, const Value &value): Object(engine), value(value) { type = Type_NumberObject; }
+};
+
+struct ArrayObject: Object {
+ enum {
+ LengthPropertyIndex = 0
+ };
+
+ ArrayObject(ExecutionEngine *engine) : Object(engine) { init(engine); }
+ ArrayObject(ExecutionEngine *engine, const QStringList &list);
+ void init(ExecutionEngine *engine);
+
+ QStringList toQStringList() const;
+};
+
+inline uint Object::arrayLength() const
+{
+ if (isArrayObject()) {
+ // length is always the first property of an array
+ Value v = memberData[ArrayObject::LengthPropertyIndex].value;
+ if (v.isInteger())
+ return v.integerValue();
+ return Value::toUInt32(v.doubleValue());
+ }
+ return 0;
+}
+
+inline void Object::setArrayLengthUnchecked(uint l)
+{
+ if (isArrayObject()) {
+ // length is always the first property of an array
+ Property &lengthProperty = memberData[ArrayObject::LengthPropertyIndex];
+ lengthProperty.value = Value::fromUInt32(l);
+ }
+}
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QMLJS_OBJECTS_H
diff --git a/src/qml/qml/v4/qv4objectiterator.cpp b/src/qml/qml/v4/qv4objectiterator.cpp
new file mode 100644
index 0000000000..a89bfdb797
--- /dev/null
+++ b/src/qml/qml/v4/qv4objectiterator.cpp
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "qv4objectiterator_p.h"
+#include "qv4object_p.h"
+#include "qv4stringobject_p.h"
+#include "qv4identifier_p.h"
+
+using namespace QV4;
+
+ObjectIterator::ObjectIterator(Object *o, uint flags)
+ : object(o)
+ , current(o)
+ , arrayNode(0)
+ , arrayIndex(0)
+ , memberIndex(0)
+ , flags(flags)
+{
+ tmpDynamicProperty.value = Value::undefinedValue();
+}
+
+Property *ObjectIterator::next(String **name, uint *index, PropertyAttributes *attrs)
+{
+ Property *p = 0;
+ *name = 0;
+ *index = UINT_MAX;
+ while (1) {
+ if (!current)
+ break;
+
+ while (p = current->advanceIterator(this, name, index, attrs)) {
+ // check the property is not already defined earlier in the proto chain
+ if (current != object) {
+ Property *pp;
+ if (*name) {
+ pp = object->__getPropertyDescriptor__(*name);
+ } else {
+ assert (*index != UINT_MAX);
+ pp = object->__getPropertyDescriptor__(*index);
+ }
+ if (pp != p)
+ continue;
+ }
+ return p;
+ }
+
+ if (flags & WithProtoChain)
+ current = current->prototype;
+ else
+ current = 0;
+
+ arrayIndex = 0;
+ memberIndex = 0;
+ }
+ return 0;
+}
+
+Value ObjectIterator::nextPropertyName(Value *value)
+{
+ PropertyAttributes attrs;
+ uint index;
+ String *name;
+ Property *p = next(&name, &index, &attrs);
+ if (!p)
+ return Value::nullValue();
+
+ if (value)
+ *value = object->getValue(p, attrs);
+
+ if (name)
+ return Value::fromString(name);
+ assert(index < UINT_MAX);
+ return Value::fromDouble(index);
+}
+
+Value ObjectIterator::nextPropertyNameAsString(Value *value)
+{
+ PropertyAttributes attrs;
+ uint index;
+ String *name;
+ Property *p = next(&name, &index, &attrs);
+ if (!p)
+ return Value::nullValue();
+
+ if (value)
+ *value = object->getValue(p, attrs);
+
+ if (name)
+ return Value::fromString(name);
+ assert(index < UINT_MAX);
+ return Value::fromString(object->engine()->newString(QString::number(index)));
+}
diff --git a/src/qml/qml/v4/qv4objectiterator_p.h b/src/qml/qml/v4/qv4objectiterator_p.h
new file mode 100644
index 0000000000..95439397f5
--- /dev/null
+++ b/src/qml/qml/v4/qv4objectiterator_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4OBJECTITERATOR_H
+#define QV4OBJECTITERATOR_H
+
+#include "qv4global_p.h"
+#include "qv4property_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct SparseArrayNode;
+struct Object;
+struct ArrayObject;
+struct PropertyAttributes;
+struct ExecutionContext;
+struct Property;
+struct String;
+struct InternalClass;
+
+struct Q_QML_EXPORT ObjectIterator
+{
+ enum Flags {
+ NoFlags = 0,
+ EnumerableOnly = 0x1,
+ WithProtoChain = 0x2,
+ };
+
+ Object *object;
+ Object *current;
+ SparseArrayNode *arrayNode;
+ uint arrayIndex;
+ uint memberIndex;
+ uint flags;
+
+ Property tmpDynamicProperty;
+
+ ObjectIterator(Object *o, uint flags);
+ Property *next(String **name, uint *index, PropertyAttributes *attributes = 0);
+ Value nextPropertyName(Value *value = 0);
+ Value nextPropertyNameAsString(Value *value = 0);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v4/qv4objectproto.cpp b/src/qml/qml/v4/qv4objectproto.cpp
new file mode 100644
index 0000000000..462c9ca81e
--- /dev/null
+++ b/src/qml/qml/v4/qv4objectproto.cpp
@@ -0,0 +1,624 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qv4objectproto_p.h"
+#include "qv4mm_p.h"
+#include <QtCore/qnumeric.h>
+#include <QtCore/qmath.h>
+#include <QtCore/QDateTime>
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+#include <cassert>
+
+#include <private/qqmljsengine_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljsast_p.h>
+#include <qv4jsir_p.h>
+#include <qv4codegen_p.h>
+#include <qv4isel_masm_p.h>
+
+#ifndef Q_OS_WIN
+# include <time.h>
+# ifndef Q_OS_VXWORKS
+# include <sys/time.h>
+# else
+# include "qplatformdefs.h"
+# endif
+#else
+# include <windows.h>
+#endif
+
+using namespace QV4;
+
+
+DEFINE_MANAGED_VTABLE(ObjectCtor);
+
+ObjectCtor::ObjectCtor(ExecutionContext *scope)
+ : FunctionObject(scope, scope->engine->newIdentifier(QStringLiteral("Object")))
+{
+ vtbl = &static_vtbl;
+}
+
+Value ObjectCtor::construct(Managed *that, Value *args, int argc)
+{
+ ObjectCtor *ctor = static_cast<ObjectCtor *>(that);
+ ExecutionEngine *v4 = that->engine();
+ if (!argc || args[0].isUndefined() || args[0].isNull()) {
+ Object *obj = v4->newObject();
+ Value proto = ctor->get(v4->id_prototype);
+ if (proto.isObject())
+ obj->prototype = proto.objectValue();
+ return Value::fromObject(obj);
+ }
+ return __qmljs_to_object(v4->current, args[0]);
+}
+
+Value ObjectCtor::call(Managed *m, const Value &/*thisObject*/, Value *args, int argc)
+{
+ if (!argc || args[0].isUndefined() || args[0].isNull())
+ return Value::fromObject(m->engine()->newObject());
+ return __qmljs_to_object(m->engine()->current, args[0]);
+}
+
+void ObjectPrototype::init(ExecutionContext *ctx, const Value &ctor)
+{
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this));
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(1));
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("getPrototypeOf"), method_getPrototypeOf, 1);
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("getOwnPropertyDescriptor"), method_getOwnPropertyDescriptor, 2);
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("getOwnPropertyNames"), method_getOwnPropertyNames, 1);
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("create"), method_create, 2);
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("defineProperty"), method_defineProperty, 3);
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("defineProperties"), method_defineProperties, 2);
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("seal"), method_seal, 1);
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("freeze"), method_freeze, 1);
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("preventExtensions"), method_preventExtensions, 1);
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("isSealed"), method_isSealed, 1);
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("isFrozen"), method_isFrozen, 1);
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("isExtensible"), method_isExtensible, 1);
+ ctor.objectValue()->defineDefaultProperty(ctx, QStringLiteral("keys"), method_keys, 1);
+
+ defineDefaultProperty(ctx, QStringLiteral("constructor"), ctor);
+ defineDefaultProperty(ctx, QStringLiteral("toString"), method_toString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("toLocaleString"), method_toLocaleString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("valueOf"), method_valueOf, 0);
+ defineDefaultProperty(ctx, QStringLiteral("hasOwnProperty"), method_hasOwnProperty, 1);
+ defineDefaultProperty(ctx, QStringLiteral("isPrototypeOf"), method_isPrototypeOf, 1);
+ defineDefaultProperty(ctx, QStringLiteral("propertyIsEnumerable"), method_propertyIsEnumerable, 1);
+ defineDefaultProperty(ctx, QStringLiteral("__defineGetter__"), method_defineGetter, 2);
+ defineDefaultProperty(ctx, QStringLiteral("__defineSetter__"), method_defineSetter, 2);
+
+ ExecutionEngine *v4 = ctx->engine;
+ Property *p = insertMember(v4->id___proto__, Attr_Accessor|Attr_NotEnumerable);
+ p->setGetter(v4->newBuiltinFunction(v4->rootContext, v4->id___proto__, method_get_proto));
+ p->setSetter(v4->newBuiltinFunction(v4->rootContext, v4->id___proto__, method_set_proto));
+}
+
+Value ObjectPrototype::method_getPrototypeOf(SimpleCallContext *ctx)
+{
+ Value o = ctx->argument(0);
+ if (! o.isObject())
+ ctx->throwTypeError();
+
+ Object *p = o.objectValue()->prototype;
+ return p ? Value::fromObject(p) : Value::nullValue();
+}
+
+Value ObjectPrototype::method_getOwnPropertyDescriptor(SimpleCallContext *ctx)
+{
+ Value O = ctx->argument(0);
+ if (!O.isObject())
+ ctx->throwTypeError();
+
+ String *name = ctx->argument(1).toString(ctx);
+ PropertyAttributes attrs;
+ Property *desc = O.objectValue()->__getOwnProperty__(name, &attrs);
+ return fromPropertyDescriptor(ctx, desc, attrs);
+}
+
+Value ObjectPrototype::method_getOwnPropertyNames(SimpleCallContext *context)
+{
+ Object *O = context->argumentCount ? context->arguments[0].asObject() : 0;
+ if (!O)
+ context->throwTypeError();
+
+ ArrayObject *array = getOwnPropertyNames(context->engine, context->arguments[0]);
+ return Value::fromObject(array);
+}
+
+Value ObjectPrototype::method_create(SimpleCallContext *ctx)
+{
+ Value O = ctx->argument(0);
+ if (!O.isObject() && !O.isNull())
+ ctx->throwTypeError();
+
+ Object *newObject = ctx->engine->newObject();
+ newObject->prototype = O.asObject();
+
+ Value objValue = Value::fromObject(newObject);
+ if (ctx->argumentCount > 1 && !ctx->argument(1).isUndefined()) {
+ ctx->arguments[0] = objValue;
+ method_defineProperties(ctx);
+ }
+
+ return objValue;
+}
+
+Value ObjectPrototype::method_defineProperty(SimpleCallContext *ctx)
+{
+ Value O = ctx->argument(0);
+ if (!O.isObject())
+ ctx->throwTypeError();
+
+ String *name = ctx->argument(1).toString(ctx);
+
+ Value attributes = ctx->argument(2);
+ Property pd;
+ PropertyAttributes attrs;
+ toPropertyDescriptor(ctx, attributes, &pd, &attrs);
+
+ if (!O.objectValue()->__defineOwnProperty__(ctx, name, pd, attrs))
+ ctx->throwTypeError();
+
+ return O;
+}
+
+Value ObjectPrototype::method_defineProperties(SimpleCallContext *ctx)
+{
+ Value O = ctx->argument(0);
+ if (!O.isObject())
+ ctx->throwTypeError();
+
+ Object *o = ctx->argument(1).toObject(ctx);
+
+ ObjectIterator it(o, ObjectIterator::EnumerableOnly);
+ while (1) {
+ uint index;
+ String *name;
+ PropertyAttributes attrs;
+ Property *pd = it.next(&name, &index, &attrs);
+ if (!pd)
+ break;
+ Property n;
+ PropertyAttributes nattrs;
+ toPropertyDescriptor(ctx, o->getValue(pd, attrs), &n, &nattrs);
+ bool ok;
+ if (name)
+ ok = O.objectValue()->__defineOwnProperty__(ctx, name, n, nattrs);
+ else
+ ok = O.objectValue()->__defineOwnProperty__(ctx, index, n, nattrs);
+ if (!ok)
+ ctx->throwTypeError();
+ }
+
+ return O;
+}
+
+Value ObjectPrototype::method_seal(SimpleCallContext *ctx)
+{
+ if (!ctx->argument(0).isObject())
+ ctx->throwTypeError();
+
+ Object *o = ctx->argument(0).objectValue();
+ o->extensible = false;
+
+ o->internalClass = o->internalClass->sealed();
+
+ o->ensureArrayAttributes();
+ for (uint i = 0; i < o->arrayDataLen; ++i) {
+ if (!o->arrayAttributes[i].isGeneric())
+ o->arrayAttributes[i].setConfigurable(false);
+ }
+
+ return ctx->argument(0);
+}
+
+Value ObjectPrototype::method_freeze(SimpleCallContext *ctx)
+{
+ if (!ctx->argument(0).isObject())
+ ctx->throwTypeError();
+
+ Object *o = ctx->argument(0).objectValue();
+ o->extensible = false;
+
+ o->internalClass = o->internalClass->frozen();
+
+ o->ensureArrayAttributes();
+ for (uint i = 0; i < o->arrayDataLen; ++i) {
+ if (!o->arrayAttributes[i].isGeneric())
+ o->arrayAttributes[i].setConfigurable(false);
+ if (o->arrayAttributes[i].isData())
+ o->arrayAttributes[i].setWritable(false);
+ }
+ return ctx->argument(0);
+}
+
+Value ObjectPrototype::method_preventExtensions(SimpleCallContext *ctx)
+{
+ if (!ctx->argument(0).isObject())
+ ctx->throwTypeError();
+
+ Object *o = ctx->argument(0).objectValue();
+ o->extensible = false;
+ return ctx->argument(0);
+}
+
+Value ObjectPrototype::method_isSealed(SimpleCallContext *ctx)
+{
+ if (!ctx->argument(0).isObject())
+ ctx->throwTypeError();
+
+ Object *o = ctx->argument(0).objectValue();
+ if (o->extensible)
+ return Value::fromBoolean(false);
+
+ if (o->internalClass != o->internalClass->sealed())
+ return Value::fromBoolean(false);
+
+ if (!o->arrayDataLen)
+ return Value::fromBoolean(true);
+
+ if (!o->arrayAttributes)
+ return Value::fromBoolean(false);
+
+ for (uint i = 0; i < o->arrayDataLen; ++i) {
+ if (!o->arrayAttributes[i].isGeneric())
+ if (o->arrayAttributes[i].isConfigurable())
+ return Value::fromBoolean(false);
+ }
+
+ return Value::fromBoolean(true);
+}
+
+Value ObjectPrototype::method_isFrozen(SimpleCallContext *ctx)
+{
+ if (!ctx->argument(0).isObject())
+ ctx->throwTypeError();
+
+ Object *o = ctx->argument(0).objectValue();
+ if (o->extensible)
+ return Value::fromBoolean(false);
+
+ if (o->internalClass != o->internalClass->frozen())
+ return Value::fromBoolean(false);
+
+ if (!o->arrayDataLen)
+ return Value::fromBoolean(true);
+
+ if (!o->arrayAttributes)
+ return Value::fromBoolean(false);
+
+ for (uint i = 0; i < o->arrayDataLen; ++i) {
+ if (!o->arrayAttributes[i].isGeneric())
+ if (o->arrayAttributes[i].isConfigurable() || o->arrayAttributes[i].isWritable())
+ return Value::fromBoolean(false);
+ }
+
+ return Value::fromBoolean(true);
+}
+
+Value ObjectPrototype::method_isExtensible(SimpleCallContext *ctx)
+{
+ if (!ctx->argument(0).isObject())
+ ctx->throwTypeError();
+
+ Object *o = ctx->argument(0).objectValue();
+ return Value::fromBoolean(o->extensible);
+}
+
+Value ObjectPrototype::method_keys(SimpleCallContext *ctx)
+{
+ if (!ctx->argument(0).isObject())
+ ctx->throwTypeError();
+
+ Object *o = ctx->argument(0).objectValue();
+
+ ArrayObject *a = ctx->engine->newArrayObject();
+
+ ObjectIterator it(o, ObjectIterator::EnumerableOnly);
+ while (1) {
+ Value name = it.nextPropertyNameAsString();
+ if (name.isNull())
+ break;
+ a->push_back(name);
+ }
+
+ return Value::fromObject(a);
+}
+
+Value ObjectPrototype::method_toString(SimpleCallContext *ctx)
+{
+ if (ctx->thisObject.isUndefined()) {
+ return Value::fromString(ctx, QStringLiteral("[object Undefined]"));
+ } else if (ctx->thisObject.isNull()) {
+ return Value::fromString(ctx, QStringLiteral("[object Null]"));
+ } else {
+ Value obj = __qmljs_to_object(ctx, ctx->thisObject);
+ QString className = obj.objectValue()->className();
+ return Value::fromString(ctx, QString::fromUtf8("[object %1]").arg(className));
+ }
+}
+
+Value ObjectPrototype::method_toLocaleString(SimpleCallContext *ctx)
+{
+ Object *o = ctx->thisObject.toObject(ctx);
+ Value ts = o->get(ctx->engine->newString(QStringLiteral("toString")));
+ FunctionObject *f = ts.asFunctionObject();
+ if (!f)
+ ctx->throwTypeError();
+ return f->call(Value::fromObject(o), 0, 0);
+}
+
+Value ObjectPrototype::method_valueOf(SimpleCallContext *ctx)
+{
+ return Value::fromObject(ctx->thisObject.toObject(ctx));
+}
+
+Value ObjectPrototype::method_hasOwnProperty(SimpleCallContext *ctx)
+{
+ String *P = ctx->argument(0).toString(ctx);
+ Object *O = ctx->thisObject.toObject(ctx);
+ bool r = O->__getOwnProperty__(P) != 0;
+ return Value::fromBoolean(r);
+}
+
+Value ObjectPrototype::method_isPrototypeOf(SimpleCallContext *ctx)
+{
+ Value V = ctx->argument(0);
+ if (! V.isObject())
+ return Value::fromBoolean(false);
+
+ Object *O = ctx->thisObject.toObject(ctx);
+ Object *proto = V.objectValue()->prototype;
+ while (proto) {
+ if (O == proto)
+ return Value::fromBoolean(true);
+ proto = proto->prototype;
+ }
+ return Value::fromBoolean(false);
+}
+
+Value ObjectPrototype::method_propertyIsEnumerable(SimpleCallContext *ctx)
+{
+ String *p = ctx->argument(0).toString(ctx);
+
+ Object *o = ctx->thisObject.toObject(ctx);
+ PropertyAttributes attrs;
+ o->__getOwnProperty__(p, &attrs);
+ return Value::fromBoolean(attrs.isEnumerable());
+}
+
+Value ObjectPrototype::method_defineGetter(SimpleCallContext *ctx)
+{
+ if (ctx->argumentCount < 2)
+ ctx->throwTypeError();
+ String *prop = ctx->argument(0).toString(ctx);
+
+ FunctionObject *f = ctx->argument(1).asFunctionObject();
+ if (!f)
+ ctx->throwTypeError();
+
+ Object *o = ctx->thisObject.asObject();
+ if (!o) {
+ if (!ctx->thisObject.isUndefined())
+ return Value::undefinedValue();
+ o = ctx->engine->globalObject;
+ }
+
+ Property pd = Property::fromAccessor(f, 0);
+ o->__defineOwnProperty__(ctx, prop, pd, Attr_Accessor);
+ return Value::undefinedValue();
+}
+
+Value ObjectPrototype::method_defineSetter(SimpleCallContext *ctx)
+{
+ if (ctx->argumentCount < 2)
+ ctx->throwTypeError();
+ String *prop = ctx->argument(0).toString(ctx);
+
+ FunctionObject *f = ctx->argument(1).asFunctionObject();
+ if (!f)
+ ctx->throwTypeError();
+
+ Object *o = ctx->thisObject.asObject();
+ if (!o) {
+ if (!ctx->thisObject.isUndefined())
+ return Value::undefinedValue();
+ o = ctx->engine->globalObject;
+ }
+
+ Property pd = Property::fromAccessor(0, f);
+ o->__defineOwnProperty__(ctx, prop, pd, Attr_Accessor);
+ return Value::undefinedValue();
+}
+
+Value ObjectPrototype::method_get_proto(SimpleCallContext *ctx)
+{
+ Object *o = ctx->thisObject.asObject();
+ if (!o)
+ ctx->throwTypeError();
+
+ return Value::fromObject(o->prototype);
+}
+
+Value ObjectPrototype::method_set_proto(SimpleCallContext *ctx)
+{
+ Object *o = ctx->thisObject.asObject();
+ if (!o)
+ ctx->throwTypeError();
+
+ Value proto = ctx->argument(0);
+ bool ok = false;
+ if (proto.isNull()) {
+ o->prototype = 0;
+ ok = true;
+ } else if (Object *p = proto.asObject()) {
+ if (o->prototype == p) {
+ ok = true;
+ } else if (o->extensible) {
+ Object *pp = p;
+ while (pp) {
+ if (pp == o)
+ break;
+ pp = pp->prototype;
+ }
+ if (!pp) {
+ ok = true;
+ o->prototype = p;
+ }
+ }
+ }
+ if (!ok)
+ ctx->throwTypeError(QStringLiteral("Cyclic __proto__ value"));
+ return Value::undefinedValue();
+}
+
+void ObjectPrototype::toPropertyDescriptor(ExecutionContext *ctx, Value v, Property *desc, PropertyAttributes *attrs)
+{
+ if (!v.isObject())
+ ctx->throwTypeError();
+
+ Object *o = v.objectValue();
+
+ attrs->clear();
+ desc->setGetter(0);
+ desc->setSetter(0);
+
+ if (o->__hasProperty__(ctx->engine->id_enumerable))
+ attrs->setEnumerable(o->get(ctx->engine->id_enumerable).toBoolean());
+
+ if (o->__hasProperty__(ctx->engine->id_configurable))
+ attrs->setConfigurable(o->get(ctx->engine->id_configurable).toBoolean());
+
+ if (o->__hasProperty__(ctx->engine->id_get)) {
+ Value get = o->get(ctx->engine->id_get);
+ FunctionObject *f = get.asFunctionObject();
+ if (f) {
+ desc->setGetter(f);
+ } else if (get.isUndefined()) {
+ desc->setGetter((FunctionObject *)0x1);
+ } else {
+ ctx->throwTypeError();
+ }
+ attrs->setType(PropertyAttributes::Accessor);
+ }
+
+ if (o->__hasProperty__(ctx->engine->id_set)) {
+ Value set = o->get(ctx->engine->id_set);
+ FunctionObject *f = set.asFunctionObject();
+ if (f) {
+ desc->setSetter(f);
+ } else if (set.isUndefined()) {
+ desc->setSetter((FunctionObject *)0x1);
+ } else {
+ ctx->throwTypeError();
+ }
+ attrs->setType(PropertyAttributes::Accessor);
+ }
+
+ if (o->__hasProperty__(ctx->engine->id_writable)) {
+ if (attrs->isAccessor())
+ ctx->throwTypeError();
+ attrs->setWritable(o->get(ctx->engine->id_writable).toBoolean());
+ // writable forces it to be a data descriptor
+ desc->value = Value::undefinedValue();
+ }
+
+ if (o->__hasProperty__(ctx->engine->id_value)) {
+ if (attrs->isAccessor())
+ ctx->throwTypeError();
+ desc->value = o->get(ctx->engine->id_value);
+ attrs->setType(PropertyAttributes::Data);
+ }
+
+ if (attrs->isGeneric())
+ desc->value = Value::emptyValue();
+}
+
+
+Value ObjectPrototype::fromPropertyDescriptor(ExecutionContext *ctx, const Property *desc, PropertyAttributes attrs)
+{
+ if (!desc)
+ return Value::undefinedValue();
+
+ ExecutionEngine *engine = ctx->engine;
+// Let obj be the result of creating a new object as if by the expression new Object() where Object is the standard built-in constructor with that name.
+ Object *o = engine->newObject();
+
+ Property pd;
+ if (attrs.isData()) {
+ pd.value = desc->value;
+ o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("value")), pd, Attr_Data);
+ pd.value = Value::fromBoolean(attrs.isWritable());
+ o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("writable")), pd, Attr_Data);
+ } else {
+ pd.value = desc->getter() ? Value::fromObject(desc->getter()) : Value::undefinedValue();
+ o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("get")), pd, Attr_Data);
+ pd.value = desc->setter() ? Value::fromObject(desc->setter()) : Value::undefinedValue();
+ o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("set")), pd, Attr_Data);
+ }
+ pd.value = Value::fromBoolean(attrs.isEnumerable());
+ o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("enumerable")), pd, Attr_Data);
+ pd.value = Value::fromBoolean(attrs.isConfigurable());
+ o->__defineOwnProperty__(ctx, engine->newString(QStringLiteral("configurable")), pd, Attr_Data);
+
+ return Value::fromObject(o);
+}
+
+
+ArrayObject *ObjectPrototype::getOwnPropertyNames(ExecutionEngine *v4, const Value &o)
+{
+ ArrayObject *array = v4->newArrayObject();
+ Object *O = o.asObject();
+ if (!O)
+ return array;
+
+ ObjectIterator it(O, ObjectIterator::NoFlags);
+ while (1) {
+ Value name = it.nextPropertyNameAsString();
+ if (name.isNull())
+ break;
+ array->push_back(name);
+ }
+ return array;
+}
diff --git a/src/qml/qml/v4/qv4objectproto_p.h b/src/qml/qml/v4/qv4objectproto_p.h
new file mode 100644
index 0000000000..ca2e77ca42
--- /dev/null
+++ b/src/qml/qml/v4/qv4objectproto_p.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4ECMAOBJECTS_P_H
+#define QV4ECMAOBJECTS_P_H
+
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+#include <QtCore/qnumeric.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct ObjectCtor: FunctionObject
+{
+ ObjectCtor(ExecutionContext *scope);
+
+ static Value construct(Managed *that, Value *args, int argc);
+ static Value call(Managed *that, const Value &, Value *, int);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct ObjectPrototype: Object
+{
+ ObjectPrototype(ExecutionEngine *engine) : Object(engine) {}
+
+ void init(ExecutionContext *ctx, const Value &ctor);
+
+ static Value method_getPrototypeOf(SimpleCallContext *ctx);
+ static Value method_getOwnPropertyDescriptor(SimpleCallContext *ctx);
+ static Value method_getOwnPropertyNames(SimpleCallContext *context);
+ static Value method_create(SimpleCallContext *ctx);
+ static Value method_defineProperty(SimpleCallContext *ctx);
+ static Value method_defineProperties(SimpleCallContext *ctx);
+ static Value method_seal(SimpleCallContext *ctx);
+ static Value method_freeze(SimpleCallContext *ctx);
+ static Value method_preventExtensions(SimpleCallContext *ctx);
+ static Value method_isSealed(SimpleCallContext *ctx);
+ static Value method_isFrozen(SimpleCallContext *ctx);
+ static Value method_isExtensible(SimpleCallContext *ctx);
+ static Value method_keys(SimpleCallContext *ctx);
+
+ static Value method_toString(SimpleCallContext *ctx);
+ static Value method_toLocaleString(SimpleCallContext *ctx);
+ static Value method_valueOf(SimpleCallContext *ctx);
+ static Value method_hasOwnProperty(SimpleCallContext *ctx);
+ static Value method_isPrototypeOf(SimpleCallContext *ctx);
+ static Value method_propertyIsEnumerable(SimpleCallContext *ctx);
+
+ static Value method_defineGetter(SimpleCallContext *ctx);
+ static Value method_defineSetter(SimpleCallContext *ctx);
+
+ static Value method_get_proto(SimpleCallContext *ctx);
+ static Value method_set_proto(SimpleCallContext *ctx);
+
+ static void toPropertyDescriptor(ExecutionContext *ctx, Value v, Property *desc, PropertyAttributes *attrs);
+ static Value fromPropertyDescriptor(ExecutionContext *ctx, const Property *desc, PropertyAttributes attrs);
+
+ static ArrayObject *getOwnPropertyNames(ExecutionEngine *v4, const Value &o);
+};
+
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4ECMAOBJECTS_P_H
diff --git a/src/qml/qml/v4/qv4property_p.h b/src/qml/qml/v4/qv4property_p.h
new file mode 100644
index 0000000000..024ad3c720
--- /dev/null
+++ b/src/qml/qml/v4/qv4property_p.h
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4PROPERTYDESCRIPTOR_H
+#define QV4PROPERTYDESCRIPTOR_H
+
+#include "qv4global_p.h"
+#include "qv4value_p.h"
+#include "qv4internalclass_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct FunctionObject;
+
+struct Property {
+ union {
+ Value value;
+ struct {
+ FunctionObject *get;
+ FunctionObject *set;
+ };
+ };
+
+ // Section 8.10
+ inline void fullyPopulated(PropertyAttributes *attrs) {
+ if (!attrs->hasType()) {
+ value = Value::undefinedValue();
+ }
+ if (attrs->type() == PropertyAttributes::Accessor) {
+ attrs->clearWritable();
+ if (get == (FunctionObject *)0x1)
+ get = 0;
+ if (set == (FunctionObject *)0x1)
+ set = 0;
+ }
+ attrs->resolve();
+ }
+
+ static inline Property fromValue(Value v) {
+ Property pd;
+ pd.value = v;
+ return pd;
+ }
+ static inline Property fromAccessor(FunctionObject *getter, FunctionObject *setter) {
+ Property pd;
+ pd.get = getter;
+ pd.set = setter;
+ return pd;
+ }
+
+ static Property genericDescriptor() {
+ Property pd;
+ pd.value = Value::emptyValue();
+ return pd;
+ }
+
+ inline bool isSubset(const PropertyAttributes &attrs, const Property &other, PropertyAttributes otherAttrs) const;
+ inline void merge(PropertyAttributes &attrs, const Property &other, PropertyAttributes otherAttrs);
+
+ inline FunctionObject *getter() const { return get; }
+ inline FunctionObject *setter() const { return set; }
+ inline void setGetter(FunctionObject *g) { get = g; }
+ inline void setSetter(FunctionObject *s) { set = s; }
+};
+
+inline bool Property::isSubset(const PropertyAttributes &attrs, const Property &other, PropertyAttributes otherAttrs) const
+{
+ if (attrs.type() != PropertyAttributes::Generic && attrs.type() != otherAttrs.type())
+ return false;
+ if (attrs.hasEnumerable() && attrs.isEnumerable() != otherAttrs.isEnumerable())
+ return false;
+ if (attrs.hasConfigurable() && attrs.isConfigurable() != otherAttrs.isConfigurable())
+ return false;
+ if (attrs.hasWritable() && attrs.isWritable() != otherAttrs.isWritable())
+ return false;
+ if (attrs.type() == PropertyAttributes::Data && !value.sameValue(other.value))
+ return false;
+ if (attrs.type() == PropertyAttributes::Accessor) {
+ if (get != other.get)
+ return false;
+ if (set != other.set)
+ return false;
+ }
+ return true;
+}
+
+inline void Property::merge(PropertyAttributes &attrs, const Property &other, PropertyAttributes otherAttrs)
+{
+ if (otherAttrs.hasEnumerable())
+ attrs.setEnumerable(otherAttrs.isEnumerable());
+ if (otherAttrs.hasConfigurable())
+ attrs.setConfigurable(otherAttrs.isConfigurable());
+ if (otherAttrs.hasWritable())
+ attrs.setWritable(otherAttrs.isWritable());
+ if (otherAttrs.type() == PropertyAttributes::Accessor) {
+ attrs.setType(PropertyAttributes::Accessor);
+ if (other.get)
+ get = (other.get == (FunctionObject *)0x1) ? 0 : other.get;
+ if (other.set)
+ set = (other.set == (FunctionObject *)0x1) ? 0 : other.set;
+ } else if (otherAttrs.type() == PropertyAttributes::Data){
+ attrs.setType(PropertyAttributes::Data);
+ value = other.value;
+ }
+}
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v4/qv4qmlextensions.cpp b/src/qml/qml/v4/qv4qmlextensions.cpp
new file mode 100644
index 0000000000..a55330ff67
--- /dev/null
+++ b/src/qml/qml/v4/qv4qmlextensions.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4qmlextensions_p.h"
+#include "qv4object_p.h"
+
+using namespace QV4;
+
+void QmlExtensions::markObjects()
+{
+ if (valueTypeWrapperPrototype)
+ valueTypeWrapperPrototype->mark();
+}
diff --git a/src/qml/qml/v4/qv4qmlextensions_p.h b/src/qml/qml/v4/qv4qmlextensions_p.h
new file mode 100644
index 0000000000..cf9e287efe
--- /dev/null
+++ b/src/qml/qml/v4/qv4qmlextensions_p.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4QMLEXTENSIONS_P_H
+#define QV4QMLEXTENSIONS_P_H
+
+#include <qtqmlglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+struct Object;
+
+struct Q_QML_EXPORT QmlExtensions
+{
+ QmlExtensions()
+ : valueTypeWrapperPrototype(0)
+ {}
+
+ Object *valueTypeWrapperPrototype;
+
+ void markObjects();
+};
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v4/qv4qobjectwrapper.cpp b/src/qml/qml/v4/qv4qobjectwrapper.cpp
new file mode 100644
index 0000000000..f79675845b
--- /dev/null
+++ b/src/qml/qml/v4/qv4qobjectwrapper.cpp
@@ -0,0 +1,1792 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4qobjectwrapper_p.h"
+
+#include <private/qqmlpropertycache_p.h>
+#include <private/qqmlengine_p.h>
+#include <private/qqmlvmemetaobject_p.h>
+#include <private/qqmlbinding_p.h>
+#include <private/qjsvalue_p.h>
+#include <private/qqmlaccessors_p.h>
+#include <private/qqmlexpression_p.h>
+#include <private/qqmlglobal_p.h>
+#include <private/qqmltypewrapper_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qqmlcontextwrapper_p.h>
+#include <private/qqmllistwrapper_p.h>
+#include <private/qv8engine_p.h>
+
+#include <private/qv4functionobject_p.h>
+#include <private/qv4runtime_p.h>
+#include <private/qv4variantobject_p.h>
+#include <private/qv4sequenceobject_p.h>
+#include <private/qv4objectproto_p.h>
+#include <private/qv4jsonobject_p.h>
+#include <private/qv4regexpobject_p.h>
+
+#include <QtQml/qjsvalue.h>
+#include <QtCore/qjsonarray.h>
+#include <QtCore/qjsonobject.h>
+#include <QtCore/qjsonvalue.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qatomic.h>
+
+QT_BEGIN_NAMESPACE
+
+#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
+# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
+// The code in this file does not violate strict aliasing, but GCC thinks it does
+// so turn off the warnings for us to have a clean build
+# pragma GCC diagnostic ignored "-Wstrict-aliasing"
+# endif
+#endif
+
+
+using namespace QV4;
+
+static QPair<QObject *, int> extractQtMethod(QV4::FunctionObject *function)
+{
+ if (function && function->subtype == QV4::FunctionObject::WrappedQtMethod) {
+ QObjectMethod *method = static_cast<QObjectMethod*>(function);
+ return qMakePair(method->object(), method->methodIndex());
+ }
+
+ return qMakePair((QObject *)0, -1);
+}
+
+static QPair<QObject *, int> extractQtSignal(const Value &value)
+{
+ if (QV4::FunctionObject *function = value.asFunctionObject())
+ return extractQtMethod(function);
+
+ if (QV4::QmlSignalHandler *handler = value.as<QV4::QmlSignalHandler>())
+ return qMakePair(handler->object(), handler->signalIndex());
+
+ return qMakePair((QObject *)0, -1);
+}
+
+
+struct ReadAccessor {
+ static inline void Indirect(QObject *object, const QQmlPropertyData &property,
+ void *output, QQmlNotifier **n)
+ {
+ Q_ASSERT(n == 0);
+ Q_UNUSED(n);
+
+ void *args[] = { output, 0 };
+ QMetaObject::metacall(object, QMetaObject::ReadProperty, property.coreIndex, args);
+ }
+
+ static inline void Direct(QObject *object, const QQmlPropertyData &property,
+ void *output, QQmlNotifier **n)
+ {
+ Q_ASSERT(n == 0);
+ Q_UNUSED(n);
+
+ void *args[] = { output, 0 };
+ object->qt_metacall(QMetaObject::ReadProperty, property.coreIndex, args);
+ }
+
+ static inline void Accessor(QObject *object, const QQmlPropertyData &property,
+ void *output, QQmlNotifier **n)
+ {
+ Q_ASSERT(property.accessors);
+
+ property.accessors->read(object, property.accessorData, output);
+ if (n) property.accessors->notifier(object, property.accessorData, n);
+ }
+};
+
+static inline QV4::Value valueToHandle(QV4::ExecutionEngine *, int v)
+{ return QV4::Value::fromInt32(v); }
+static inline QV4::Value valueToHandle(QV4::ExecutionEngine *, uint v)
+{ return QV4::Value::fromUInt32(v); }
+static inline QV4::Value valueToHandle(QV4::ExecutionEngine *, bool v)
+{ return QV4::Value::fromBoolean(v); }
+static inline QV4::Value valueToHandle(QV4::ExecutionEngine *e, const QString &v)
+{ return QV4::Value::fromString(e, v); }
+static inline QV4::Value valueToHandle(QV4::ExecutionEngine *, float v)
+{ return QV4::Value::fromDouble(v); }
+static inline QV4::Value valueToHandle(QV4::ExecutionEngine *, double v)
+{ return QV4::Value::fromDouble(v); }
+static inline QV4::Value valueToHandle(QV4::ExecutionEngine *e, QObject *v)
+{ return QV4::QObjectWrapper::wrap(e, v); }
+
+// Load value properties
+template<void (*ReadFunction)(QObject *, const QQmlPropertyData &,
+ void *, QQmlNotifier **)>
+static QV4::Value LoadProperty(QV8Engine *engine, QObject *object,
+ const QQmlPropertyData &property,
+ QQmlNotifier **notifier)
+{
+ Q_ASSERT(!property.isFunction());
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+
+ if (property.isQObject()) {
+ QObject *rv = 0;
+ ReadFunction(object, property, &rv, notifier);
+ return QV4::QObjectWrapper::wrap(v4, rv);
+ } else if (property.isQList()) {
+ return QmlListWrapper::create(engine, object, property.coreIndex, property.propType);
+ } else if (property.propType == QMetaType::QReal) {
+ qreal v = 0;
+ ReadFunction(object, property, &v, notifier);
+ return valueToHandle(v4, v);
+ } else if (property.propType == QMetaType::Int || property.isEnum()) {
+ int v = 0;
+ ReadFunction(object, property, &v, notifier);
+ return valueToHandle(v4, v);
+ } else if (property.propType == QMetaType::Bool) {
+ bool v = false;
+ ReadFunction(object, property, &v, notifier);
+ return valueToHandle(v4, v);
+ } else if (property.propType == QMetaType::QString) {
+ QString v;
+ ReadFunction(object, property, &v, notifier);
+ return valueToHandle(v4, v);
+ } else if (property.propType == QMetaType::UInt) {
+ uint v = 0;
+ ReadFunction(object, property, &v, notifier);
+ return valueToHandle(v4, v);
+ } else if (property.propType == QMetaType::Float) {
+ float v = 0;
+ ReadFunction(object, property, &v, notifier);
+ return valueToHandle(v4, v);
+ } else if (property.propType == QMetaType::Double) {
+ double v = 0;
+ ReadFunction(object, property, &v, notifier);
+ return valueToHandle(v4, v);
+ } else if (property.isV4Handle()) {
+ QQmlV4Handle handle;
+ ReadFunction(object, property, &handle, notifier);
+ return handle.toValue();
+ } else if (property.propType == qMetaTypeId<QJSValue>()) {
+ QJSValue v;
+ ReadFunction(object, property, &v, notifier);
+ return QJSValuePrivate::get(v)->getValue(v4);
+ } else if (property.isQVariant()) {
+ QVariant v;
+ ReadFunction(object, property, &v, notifier);
+
+ if (QQmlValueTypeFactory::isValueType(v.userType())) {
+ if (QQmlValueType *valueType = QQmlValueTypeFactory::valueType(v.userType()))
+ return QV4::QmlValueTypeWrapper::create(engine, object, property.coreIndex, valueType); // VariantReference value-type.
+ }
+
+ return engine->fromVariant(v);
+ } else if (QQmlValueTypeFactory::isValueType(property.propType)) {
+ Q_ASSERT(notifier == 0);
+
+ if (QQmlValueType *valueType = QQmlValueTypeFactory::valueType(property.propType))
+ return QV4::QmlValueTypeWrapper::create(engine, object, property.coreIndex, valueType);
+ } else {
+ Q_ASSERT(notifier == 0);
+
+ // see if it's a sequence type
+ bool succeeded = false;
+ QV4::Value retn = QV4::SequencePrototype::newSequence(v4, property.propType, object, property.coreIndex, &succeeded);
+ if (succeeded)
+ return retn;
+ }
+
+ if (property.propType == QMetaType::UnknownType) {
+ QMetaProperty p = object->metaObject()->property(property.coreIndex);
+ qWarning("QMetaProperty::read: Unable to handle unregistered datatype '%s' for property "
+ "'%s::%s'", p.typeName(), object->metaObject()->className(), p.name());
+ return QV4::Value::undefinedValue();
+ } else {
+ QVariant v(property.propType, (void *)0);
+ ReadFunction(object, property, v.data(), notifier);
+ return engine->fromVariant(v);
+ }
+}
+
+QObjectWrapper::QObjectWrapper(ExecutionEngine *engine, QObject *object)
+ : Object(engine)
+ , m_object(object)
+{
+ vtbl = &static_vtbl;
+ prototype = engine->objectPrototype;
+
+ m_destroy = engine->newIdentifier(QStringLiteral("destroy"));
+ m_toString = engine->newIdentifier(QStringLiteral("toString"));
+}
+
+void QObjectWrapper::initializeBindings(ExecutionEngine *engine)
+{
+ engine->functionPrototype->defineDefaultProperty(engine, QStringLiteral("connect"), method_connect);
+ engine->functionPrototype->defineDefaultProperty(engine, QStringLiteral("disconnect"), method_disconnect);
+}
+
+QQmlPropertyData *QObjectWrapper::findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const
+{
+ QQmlData *ddata = QQmlData::get(m_object, false);
+ if (!ddata)
+ return 0;
+ QQmlPropertyData *result = 0;
+ if (ddata && ddata->propertyCache)
+ result = ddata->propertyCache->property(name, m_object, qmlContext);
+ if (!result)
+ result = QQmlPropertyCache::property(engine->v8Engine->engine(), m_object, name, qmlContext, *local);
+ return result;
+}
+
+Value QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty, bool includeImports)
+{
+ if (QQmlData::wasDeleted(m_object)) {
+ if (hasProperty)
+ *hasProperty = false;
+ return QV4::Value::undefinedValue();
+ }
+
+ if (name->isEqualTo(m_destroy) || name->isEqualTo(m_toString)) {
+ int index = name->isEqualTo(m_destroy) ? QV4::QObjectMethod::DestroyMethod : QV4::QObjectMethod::ToStringMethod;
+ QV4::Value method = QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, index);
+ if (hasProperty)
+ *hasProperty = true;
+ return method;
+ }
+
+ QQmlPropertyData local;
+ QQmlPropertyData *result = findProperty(ctx->engine, qmlContext, name, revisionMode, &local);
+
+ if (!result) {
+ if (includeImports && name->startsWithUpper()) {
+ // Check for attached properties
+ if (qmlContext && qmlContext->imports) {
+ QQmlTypeNameCache::Result r = qmlContext->imports->query(name);
+
+ if (hasProperty)
+ *hasProperty = true;
+
+ if (r.isValid()) {
+ if (r.scriptIndex != -1) {
+ return QV4::Value::undefinedValue();
+ } else if (r.type) {
+ return QmlTypeWrapper::create(ctx->engine->v8Engine, m_object, r.type, QmlTypeWrapper::ExcludeEnums);
+ } else if (r.importNamespace) {
+ return QmlTypeWrapper::create(ctx->engine->v8Engine, m_object, qmlContext->imports, r.importNamespace, QmlTypeWrapper::ExcludeEnums);
+ }
+ Q_ASSERT(!"Unreachable");
+ }
+ }
+ }
+ return QV4::Object::get(this, name, hasProperty);
+ }
+
+ QQmlData::flushPendingBinding(m_object, result->coreIndex);
+ QQmlData *ddata = QQmlData::get(m_object, false);
+
+ if (revisionMode == QV4::QObjectWrapper::CheckRevision && result->hasRevision()) {
+ if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result)) {
+ if (hasProperty)
+ *hasProperty = false;
+ return QV4::Value::undefinedValue();
+ }
+ }
+
+ if (hasProperty)
+ *hasProperty = true;
+
+ if (result->isFunction() && !result->isVarProperty()) {
+ if (result->isVMEFunction()) {
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_object);
+ Q_ASSERT(vmemo);
+ return vmemo->vmeMethod(result->coreIndex);
+ } else if (result->isV4Function()) {
+ return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, result->coreIndex, QV4::Value::fromObject(ctx->engine->qmlContextObject()));
+ } else if (result->isSignalHandler()) {
+ QV4::QmlSignalHandler *handler = new (ctx->engine->memoryManager) QV4::QmlSignalHandler(ctx->engine, m_object, result->coreIndex);
+
+ QV4::String *connect = ctx->engine->newIdentifier(QStringLiteral("connect"));
+ QV4::String *disconnect = ctx->engine->newIdentifier(QStringLiteral("disconnect"));
+ handler->put(connect, ctx->engine->functionPrototype->get(connect));
+ handler->put(disconnect, ctx->engine->functionPrototype->get(disconnect));
+
+ return QV4::Value::fromObject(handler);
+ } else {
+ return QV4::QObjectMethod::create(ctx->engine->rootContext, m_object, result->coreIndex);
+ }
+ }
+
+ QQmlEnginePrivate *ep = ctx->engine->v8Engine->engine() ? QQmlEnginePrivate::get(ctx->engine->v8Engine->engine()) : 0;
+
+ if (result->hasAccessors()) {
+ QQmlNotifier *n = 0;
+ QQmlNotifier **nptr = 0;
+
+ if (ep && ep->propertyCapture && result->accessors->notifier)
+ nptr = &n;
+
+ QV4::Value rv = LoadProperty<ReadAccessor::Accessor>(ctx->engine->v8Engine, m_object, *result, nptr);
+
+ if (result->accessors->notifier) {
+ if (n) ep->captureProperty(n);
+ } else {
+ ep->captureProperty(m_object, result->coreIndex, result->notifyIndex);
+ }
+
+ return rv;
+ }
+
+ if (ep && !result->isConstant())
+ ep->captureProperty(m_object, result->coreIndex, result->notifyIndex);
+
+ if (result->isVarProperty()) {
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(m_object);
+ Q_ASSERT(vmemo);
+ return vmemo->vmeProperty(result->coreIndex);
+ } else if (result->isDirect()) {
+ return LoadProperty<ReadAccessor::Direct>(ctx->engine->v8Engine, m_object, *result, 0);
+ } else {
+ return LoadProperty<ReadAccessor::Indirect>(ctx->engine->v8Engine, m_object, *result, 0);
+ }
+}
+
+Value QObjectWrapper::getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, bool *hasProperty)
+{
+ if (QQmlData::wasDeleted(object)) {
+ if (hasProperty)
+ *hasProperty = false;
+ return QV4::Value::nullValue();
+ }
+
+ if (!QQmlData::get(object, true)) {
+ if (hasProperty)
+ *hasProperty = false;
+ return QV4::Value::nullValue();
+ }
+
+ QObjectWrapper *wrapper = wrap(ctx->engine, object).as<QV4::QObjectWrapper>();
+ if (!wrapper) {
+ if (hasProperty)
+ *hasProperty = false;
+ return QV4::Value::nullValue();
+ }
+ return wrapper->getQmlProperty(ctx, qmlContext, name, revisionMode, hasProperty);
+}
+
+bool QObjectWrapper::setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, QObjectWrapper::RevisionMode revisionMode, const Value &value)
+{
+ if (QQmlData::wasDeleted(object))
+ return false;
+
+ QQmlPropertyData local;
+ QQmlPropertyData *result = 0;
+ {
+ result = QQmlPropertyCache::property(ctx->engine->v8Engine->engine(), object, name, qmlContext, local);
+ }
+
+ if (!result)
+ return false;
+
+ if (revisionMode == QV4::QObjectWrapper::CheckRevision && result->hasRevision()) {
+ QQmlData *ddata = QQmlData::get(object);
+ if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result))
+ return false;
+ }
+
+ if (!result->isWritable() && !result->isQList()) {
+ QString error = QLatin1String("Cannot assign to read-only property \"") +
+ name->toQString() + QLatin1Char('\"');
+ ctx->throwTypeError(error);
+ }
+
+ QQmlBinding *newBinding = 0;
+ if (FunctionObject *f = value.asFunctionObject()) {
+ if (!f->bindingKeyFlag) {
+ if (!result->isVarProperty() && result->propType != qMetaTypeId<QJSValue>()) {
+ // assigning a JS function to a non var or QJSValue property or is not allowed.
+ QString error = QLatin1String("Cannot assign JavaScript function to ");
+ if (!QMetaType::typeName(result->propType))
+ error += QLatin1String("[unknown property type]");
+ else
+ error += QLatin1String(QMetaType::typeName(result->propType));
+ ctx->throwError(error);
+ }
+ } else {
+ // binding assignment.
+ QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->engine);
+
+ QV4::ExecutionEngine::StackFrame frame = ctx->engine->currentStackFrame();
+
+ newBinding = new QQmlBinding(value, object, callingQmlContext, frame.source,
+ qmlSourceCoordinate(frame.line), qmlSourceCoordinate(frame.column));
+ newBinding->setTarget(object, *result, callingQmlContext);
+ newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
+ QQmlBinding::RequiresThisObject);
+ }
+ }
+
+ QQmlAbstractBinding *oldBinding =
+ QQmlPropertyPrivate::setBinding(object, result->coreIndex, -1, newBinding);
+ if (oldBinding)
+ oldBinding->destroy();
+
+ if (!newBinding && result->isVarProperty()) {
+ // allow assignment of "special" values (null, undefined, function) to var properties
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
+ Q_ASSERT(vmemo);
+ vmemo->setVMEProperty(result->coreIndex, value);
+ return true;
+ }
+
+#define PROPERTY_STORE(cpptype, value) \
+ cpptype o = value; \
+ int status = -1; \
+ int flags = 0; \
+ void *argv[] = { &o, 0, &status, &flags }; \
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, result->coreIndex, argv);
+
+ if (value.isNull() && result->isQObject()) {
+ PROPERTY_STORE(QObject*, 0);
+ } else if (value.isUndefined() && result->isResettable()) {
+ void *a[] = { 0 };
+ QMetaObject::metacall(object, QMetaObject::ResetProperty, result->coreIndex, a);
+ } else if (value.isUndefined() && result->propType == qMetaTypeId<QVariant>()) {
+ PROPERTY_STORE(QVariant, QVariant());
+ } else if (value.isUndefined() && result->propType == QMetaType::QJsonValue) {
+ PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined));
+ } else if (!newBinding && result->propType == qMetaTypeId<QJSValue>()) {
+ PROPERTY_STORE(QJSValue, new QJSValuePrivate(ctx->engine, value));
+ } else if (value.isUndefined()) {
+ QString error = QLatin1String("Cannot assign [undefined] to ");
+ if (!QMetaType::typeName(result->propType))
+ error += QLatin1String("[unknown property type]");
+ else
+ error += QLatin1String(QMetaType::typeName(result->propType));
+ ctx->throwError(error);
+ } else if (value.asFunctionObject()) {
+ // this is handled by the binding creation above
+ } else if (result->propType == QMetaType::Int && value.isNumber()) {
+ PROPERTY_STORE(int, qRound(value.asDouble()));
+ } else if (result->propType == QMetaType::QReal && value.isNumber()) {
+ PROPERTY_STORE(qreal, qreal(value.asDouble()));
+ } else if (result->propType == QMetaType::Float && value.isNumber()) {
+ PROPERTY_STORE(float, float(value.asDouble()));
+ } else if (result->propType == QMetaType::Double && value.isNumber()) {
+ PROPERTY_STORE(double, double(value.asDouble()));
+ } else if (result->propType == QMetaType::QString && value.isString()) {
+ PROPERTY_STORE(QString, value.toQString());
+ } else if (result->isVarProperty()) {
+ QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
+ Q_ASSERT(vmemo);
+ vmemo->setVMEProperty(result->coreIndex, value);
+ } else {
+ QVariant v;
+ if (result->isQList())
+ v = ctx->engine->v8Engine->toVariant(value, qMetaTypeId<QList<QObject *> >());
+ else
+ v = ctx->engine->v8Engine->toVariant(value, result->propType);
+
+ QQmlContextData *callingQmlContext = QV4::QmlContextWrapper::callingContext(ctx->engine);
+ if (!QQmlPropertyPrivate::write(object, *result, v, callingQmlContext)) {
+ const char *valueType = 0;
+ if (v.userType() == QVariant::Invalid) valueType = "null";
+ else valueType = QMetaType::typeName(v.userType());
+
+ const char *targetTypeName = QMetaType::typeName(result->propType);
+ if (!targetTypeName)
+ targetTypeName = "an unregistered type";
+
+ QString error = QLatin1String("Cannot assign ") +
+ QLatin1String(valueType) +
+ QLatin1String(" to ") +
+ QLatin1String(targetTypeName);
+ ctx->throwError(error);
+ }
+ }
+
+ return true;
+}
+
+Value QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
+{
+ if (QQmlData::wasDeleted(object))
+ return QV4::Value::nullValue();
+
+ QQmlData *ddata = QQmlData::get(object, true);
+ if (!ddata)
+ return QV4::Value::undefinedValue();
+
+ if (ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isEmpty()) {
+ // We own the JS object
+ return ddata->jsWrapper.value();
+ } else if (ddata->jsWrapper.isEmpty() &&
+ (ddata->jsEngineId == engine->m_engineId || // We own the QObject
+ ddata->jsEngineId == 0 || // No one owns the QObject
+ !ddata->hasTaintedV8Object)) { // Someone else has used the QObject, but it isn't tainted
+
+ QV4::Value rv = create(engine, ddata, object);
+ ddata->jsWrapper = rv;
+ ddata->jsEngineId = engine->m_engineId;
+ return rv;
+
+ } else {
+ // If this object is tainted, we have to check to see if it is in our
+ // tainted object list
+ Object *alternateWrapper = 0;
+ if (engine->m_multiplyWrappedQObjects && ddata->hasTaintedV8Object)
+ alternateWrapper = engine->m_multiplyWrappedQObjects->value(object);
+
+ // If our tainted handle doesn't exist or has been collected, and there isn't
+ // a handle in the ddata, we can assume ownership of the ddata->v8object
+ if (ddata->jsWrapper.isEmpty() && !alternateWrapper) {
+ QV4::Value result = create(engine, ddata, object);
+ ddata->jsWrapper = result;
+ ddata->jsEngineId = engine->m_engineId;
+ return result;
+ }
+
+ if (!alternateWrapper) {
+ alternateWrapper = create(engine, ddata, object).asObject();
+ if (!engine->m_multiplyWrappedQObjects)
+ engine->m_multiplyWrappedQObjects = new MultiplyWrappedQObjectMap;
+ engine->m_multiplyWrappedQObjects->insert(object, alternateWrapper);
+ ddata->hasTaintedV8Object = true;
+ }
+
+ return QV4::Value::fromObject(alternateWrapper);
+ }
+}
+
+QV4::Value QObjectWrapper::create(ExecutionEngine *engine, QQmlData *ddata, QObject *object)
+{
+ QQmlEngine *qmlEngine = engine->v8Engine->engine();
+ if (!ddata->propertyCache && qmlEngine) {
+ ddata->propertyCache = QQmlEnginePrivate::get(qmlEngine)->cache(object);
+ if (ddata->propertyCache) ddata->propertyCache->addref();
+ }
+
+ return Value::fromObject(new (engine->memoryManager) QV4::QObjectWrapper(engine, object));
+}
+
+QV4::Value QObjectWrapper::get(Managed *m, String *name, bool *hasProperty)
+{
+ QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
+ ExecutionEngine *v4 = m->engine();
+ QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4);
+ return that->getQmlProperty(v4->current, qmlContext, name, IgnoreRevision, hasProperty, /*includeImports*/ true);
+}
+
+void QObjectWrapper::put(Managed *m, String *name, const Value &value)
+{
+ QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
+ ExecutionEngine *v4 = m->engine();
+
+ if (QQmlData::wasDeleted(that->m_object))
+ return;
+
+ QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(v4);
+ if (!setQmlProperty(v4->current, qmlContext, that->m_object, name, QV4::QObjectWrapper::IgnoreRevision, value)) {
+ QString error = QLatin1String("Cannot assign to non-existent property \"") +
+ name->toQString() + QLatin1Char('\"');
+ v4->current->throwError(error);
+ }
+}
+
+PropertyAttributes QObjectWrapper::query(const Managed *m, String *name)
+{
+ const QObjectWrapper *that = static_cast<const QObjectWrapper*>(m);
+ ExecutionEngine *engine = that->engine();
+ QQmlContextData *qmlContext = QV4::QmlContextWrapper::callingContext(engine);
+ QQmlPropertyData local;
+ if (that->findProperty(engine, qmlContext, name, IgnoreRevision, &local)
+ || name->isEqualTo(that->m_destroy) || name->isEqualTo(that->m_toString))
+ return QV4::Attr_Data;
+ else
+ return QV4::Object::query(m, name);
+}
+
+Property *QObjectWrapper::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes)
+{
+ *name = 0;
+ *index = UINT_MAX;
+
+ QObjectWrapper *that = static_cast<QObjectWrapper*>(m);
+
+ if (!that->m_object)
+ return QV4::Object::advanceIterator(m, it, name, index, attributes);
+
+ const QMetaObject *mo = that->m_object->metaObject();
+ const int propertyCount = mo->propertyCount();
+ if (it->arrayIndex < propertyCount) {
+ *name = that->engine()->newString(QString::fromUtf8(mo->property(it->arrayIndex).name()));
+ ++it->arrayIndex;
+ if (attributes)
+ *attributes = QV4::Attr_Data;
+ it->tmpDynamicProperty.value = that->get(*name);
+ return &it->tmpDynamicProperty;
+ }
+ const int methodCount = mo->methodCount();
+ if (it->arrayIndex < propertyCount + methodCount) {
+ *name = that->engine()->newString(QString::fromUtf8(mo->method(it->arrayIndex - propertyCount).name()));
+ ++it->arrayIndex;
+ if (attributes)
+ *attributes = QV4::Attr_Data;
+ it->tmpDynamicProperty.value = that->get(*name);
+ return &it->tmpDynamicProperty;
+ }
+ return QV4::Object::advanceIterator(m, it, name, index, attributes);
+}
+
+namespace QV4 {
+
+struct QObjectSlotDispatcher : public QtPrivate::QSlotObjectBase
+{
+ QV4::PersistentValue function;
+ QV4::PersistentValue thisObject;
+ int signalIndex;
+
+ QObjectSlotDispatcher()
+ : QtPrivate::QSlotObjectBase(&impl)
+ , signalIndex(-1)
+ {}
+
+ static void impl(int which, QSlotObjectBase *this_, QObject *r, void **metaArgs, bool *ret)
+ {
+ switch (which) {
+ case Destroy: {
+ delete static_cast<QObjectSlotDispatcher*>(this_);
+ }
+ break;
+ case Call: {
+ QObjectSlotDispatcher *This = static_cast<QObjectSlotDispatcher*>(this_);
+ QVarLengthArray<int, 9> dummy;
+ int *argsTypes = QQmlPropertyCache::methodParameterTypes(r, This->signalIndex, dummy, 0);
+
+ int argCount = argsTypes ? argsTypes[0]:0;
+
+ QV4::FunctionObject *f = This->function.value().asFunctionObject();
+ QV4::ExecutionEngine *v4 = f->internalClass->engine;
+ QV4::ExecutionContext *ctx = v4->current;
+
+ QVarLengthArray<QV4::Value, 9> args(argCount);
+ for (int ii = 0; ii < argCount; ++ii) {
+ int type = argsTypes[ii + 1];
+ if (type == qMetaTypeId<QVariant>()) {
+ args[ii] = v4->v8Engine->fromVariant(*((QVariant *)metaArgs[ii + 1]));
+ } else {
+ args[ii] = v4->v8Engine->fromVariant(QVariant(type, metaArgs[ii + 1]));
+ }
+ }
+
+ try {
+ f->call(This->thisObject.isEmpty() ? Value::fromObject(v4->globalObject) : This->thisObject.value(), args.data(), argCount);
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ QQmlError error;
+ QQmlExpressionPrivate::exceptionToError(e, error);
+ if (error.description().isEmpty())
+ error.setDescription(QString(QLatin1String("Unknown exception occurred during evaluation of connected function: %1")).arg(f->name->toQString()));
+ QQmlEnginePrivate::get(v4->v8Engine->engine())->warning(error);
+ }
+ }
+ break;
+ case Compare: {
+ QObjectSlotDispatcher *connection = static_cast<QObjectSlotDispatcher*>(this_);
+ if (connection->function.isEmpty()) {
+ *ret = false;
+ return;
+ }
+
+ // This is tricky. Normally the metaArgs[0] pointer is a pointer to the _function_
+ // for the new-style QObject::connect. Here we use the engine pointer as sentinel
+ // to distinguish those type of QSlotObjectBase connections from our QML connections.
+ QV4::ExecutionEngine *v4 = reinterpret_cast<QV4::ExecutionEngine*>(metaArgs[0]);
+ if (v4 != connection->function.engine()) {
+ *ret = false;
+ return;
+ }
+
+ QV4::Value function = *reinterpret_cast<QV4::Value*>(metaArgs[1]);
+ QV4::Value thisObject = *reinterpret_cast<QV4::Value*>(metaArgs[2]);
+ QObject *receiverToDisconnect = reinterpret_cast<QObject*>(metaArgs[3]);
+ int slotIndexToDisconnect = *reinterpret_cast<int*>(metaArgs[4]);
+
+ if (slotIndexToDisconnect != -1) {
+ // This is a QObject function wrapper
+ if (connection->thisObject.isEmpty() == thisObject.isEmpty() &&
+ (connection->thisObject.isEmpty() || __qmljs_strict_equal(connection->thisObject, thisObject))) {
+
+ QPair<QObject *, int> connectedFunctionData = extractQtMethod(connection->function.value().asFunctionObject());
+ if (connectedFunctionData.first == receiverToDisconnect &&
+ connectedFunctionData.second == slotIndexToDisconnect) {
+ *ret = true;
+ return;
+ }
+ }
+ } else {
+ // This is a normal JS function
+ if (__qmljs_strict_equal(connection->function, function) &&
+ connection->thisObject.isEmpty() == thisObject.isEmpty() &&
+ (connection->thisObject.isEmpty() || __qmljs_strict_equal(connection->thisObject, thisObject))) {
+ *ret = true;
+ return;
+ }
+ }
+
+ *ret = false;
+ }
+ break;
+ case NumOperations:
+ break;
+ }
+ };
+};
+
+} // namespace QV4
+
+Value QObjectWrapper::method_connect(SimpleCallContext *ctx)
+{
+ if (ctx->argumentCount == 0)
+ V4THROW_ERROR("Function.prototype.connect: no arguments given");
+
+ QPair<QObject *, int> signalInfo = extractQtSignal(ctx->thisObject);
+ QObject *signalObject = signalInfo.first;
+ int signalIndex = signalInfo.second;
+
+ if (signalIndex < 0)
+ V4THROW_ERROR("Function.prototype.connect: this object is not a signal");
+
+ if (!signalObject)
+ V4THROW_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");
+
+ QV4::QObjectSlotDispatcher *slot = new QV4::QObjectSlotDispatcher;
+ slot->signalIndex = signalIndex;
+
+ if (ctx->argumentCount == 1) {
+ slot->function = ctx->arguments[0];
+ } else if (ctx->argumentCount >= 2) {
+ slot->thisObject = ctx->arguments[0];
+ slot->function = ctx->arguments[1];
+ }
+
+ if (!slot->function.value().asFunctionObject())
+ V4THROW_ERROR("Function.prototype.connect: target is not a function");
+
+ if (!slot->thisObject.isEmpty() && !slot->thisObject.value().isObject())
+ V4THROW_ERROR("Function.prototype.connect: target this is not an object");
+
+ QObjectPrivate::connect(signalObject, signalIndex, slot, Qt::AutoConnection);
+
+ return QV4::Value::undefinedValue();
+}
+
+Value QObjectWrapper::method_disconnect(SimpleCallContext *ctx)
+{
+ if (ctx->argumentCount == 0)
+ V4THROW_ERROR("Function.prototype.disconnect: no arguments given");
+
+ QPair<QObject *, int> signalInfo = extractQtSignal(ctx->thisObject);
+ QObject *signalObject = signalInfo.first;
+ int signalIndex = signalInfo.second;
+
+ if (signalIndex == -1)
+ V4THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
+
+ if (!signalObject)
+ V4THROW_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");
+
+ QV4::Value functionValue = QV4::Value::emptyValue();
+ QV4::Value functionThisValue = QV4::Value::emptyValue();
+
+ if (ctx->argumentCount == 1) {
+ functionValue = ctx->arguments[0];
+ } else if (ctx->argumentCount >= 2) {
+ functionThisValue = ctx->arguments[0];
+ functionValue = ctx->arguments[1];
+ }
+
+ if (!functionValue.asFunctionObject())
+ V4THROW_ERROR("Function.prototype.disconnect: target is not a function");
+
+ if (!functionThisValue.isEmpty() && !functionThisValue.isObject())
+ V4THROW_ERROR("Function.prototype.disconnect: target this is not an object");
+
+ QPair<QObject *, int> functionData = extractQtMethod(functionValue.asFunctionObject());
+
+ void *a[] = {
+ ctx->engine,
+ &functionValue,
+ &functionThisValue,
+ functionData.first,
+ &functionData.second
+ };
+
+ QObjectPrivate::disconnect(signalObject, signalIndex, reinterpret_cast<void**>(&a));
+
+ return QV4::Value::undefinedValue();
+}
+
+static void markChildQObjectsRecursively(QObject *parent)
+{
+ const QObjectList &children = parent->children();
+ for (int i = 0; i < children.count(); ++i) {
+ QObject *child = children.at(i);
+ QQmlData *ddata = QQmlData::get(child, /*create*/false);
+ if (ddata)
+ ddata->jsWrapper.markOnce();
+ markChildQObjectsRecursively(child);
+ }
+}
+
+void QObjectWrapper::markObjects(Managed *that)
+{
+ QObjectWrapper *This = static_cast<QObjectWrapper*>(that);
+
+ if (QObject *o = This->m_object.data()) {
+ QQmlVMEMetaObject *vme = QQmlVMEMetaObject::get(o);
+ if (vme)
+ vme->mark();
+
+ // Children usually don't need to be marked, the gc keeps them alive.
+ // But in the rare case of a "floating" QObject without a parent that
+ // _gets_ marked (we've been called here!) then we also need to
+ // propagate the marking down to the children recursively.
+ if (!o->parent())
+ markChildQObjectsRecursively(o);
+ }
+
+ QV4::Object::markObjects(that);
+}
+
+namespace {
+ struct QObjectDeleter : public QV4::GCDeletable
+ {
+ QObjectDeleter(QObject *o)
+ : m_objectToDelete(o)
+ {}
+ ~QObjectDeleter()
+ {
+ QQmlData *ddata = QQmlData::get(m_objectToDelete, false);
+ if (ddata && ddata->ownContext && ddata->context)
+ ddata->context->emitDestruction();
+ // This object is notionally destroyed now
+ ddata->isQueuedForDeletion = true;
+ if (lastCall)
+ delete m_objectToDelete;
+ else
+ m_objectToDelete->deleteLater();
+ }
+
+ QObject *m_objectToDelete;
+ };
+}
+
+void QObjectWrapper::collectDeletables(Managed *m, GCDeletable **deletable)
+{
+ QObjectWrapper *This = static_cast<QObjectWrapper*>(m);
+ QPointer<QObject> &object = This->m_object;
+ if (!object)
+ return;
+
+ QQmlData *ddata = QQmlData::get(object, false);
+ if (!ddata)
+ return;
+
+ if (object->parent() || ddata->indestructible)
+ return;
+
+ QObjectDeleter *deleter = new QObjectDeleter(object);
+ object = 0;
+ deleter->next = *deletable;
+ *deletable = deleter;
+}
+
+DEFINE_MANAGED_VTABLE_WITH_DELETABLES(QObjectWrapper);
+
+// XXX TODO: Need to review all calls to QQmlEngine *engine() to confirm QObjects work
+// correctly in a worker thread
+
+namespace {
+
+template<typename A, typename B, typename C, typename D, typename E,
+ typename F, typename G, typename H>
+class MaxSizeOf8 {
+ template<typename Z, typename X>
+ struct SMax {
+ char dummy[sizeof(Z) > sizeof(X) ? sizeof(Z) : sizeof(X)];
+ };
+public:
+ static const size_t Size = sizeof(SMax<A, SMax<B, SMax<C, SMax<D, SMax<E, SMax<F, SMax<G, H> > > > > > >);
+};
+
+struct CallArgument {
+ inline CallArgument();
+ inline ~CallArgument();
+ inline void *dataPtr();
+
+ inline void initAsType(int type);
+ inline void fromValue(int type, QV8Engine *, const QV4::Value&);
+ inline QV4::Value toValue(QV8Engine *);
+
+private:
+ CallArgument(const CallArgument &);
+
+ inline void cleanup();
+
+ union {
+ float floatValue;
+ double doubleValue;
+ quint32 intValue;
+ bool boolValue;
+ QObject *qobjectPtr;
+
+ char allocData[MaxSizeOf8<QVariant,
+ QString,
+ QList<QObject *>,
+ QJSValue,
+ QQmlV4Handle,
+ QJsonArray,
+ QJsonObject,
+ QJsonValue>::Size];
+ qint64 q_for_alignment;
+ };
+
+ // Pointers to allocData
+ union {
+ QString *qstringPtr;
+ QVariant *qvariantPtr;
+ QList<QObject *> *qlistPtr;
+ QJSValue *qjsValuePtr;
+ QQmlV4Handle *handlePtr;
+ QJsonArray *jsonArrayPtr;
+ QJsonObject *jsonObjectPtr;
+ QJsonValue *jsonValuePtr;
+ };
+
+ int type;
+};
+}
+
+namespace {
+struct CallArgs
+{
+ CallArgs(int length, QV4::Value *args) : _length(length), _args(args) {}
+ int Length() const { return _length; }
+ QV4::Value operator[](int idx) { return _args[idx]; }
+
+private:
+ int _length;
+ QV4::Value *_args;
+};
+}
+
+static QV4::Value CallMethod(QObject *object, int index, int returnType, int argCount,
+ int *argTypes, QV8Engine *engine, CallArgs &callArgs)
+{
+ if (argCount > 0) {
+
+ // Special handling is required for value types.
+ // We need to save the current value in a temporary,
+ // and reapply it after converting all arguments.
+ // This avoids the "overwriting copy-value-type-value"
+ // problem during Q_INVOKABLE function invocation.
+ QQmlValueType *valueTypeObject = qobject_cast<QQmlValueType*>(object);
+ QVariant valueTypeValue;
+ if (valueTypeObject)
+ valueTypeValue = valueTypeObject->value();
+
+ // Convert all arguments.
+ QVarLengthArray<CallArgument, 9> args(argCount + 1);
+ args[0].initAsType(returnType);
+ for (int ii = 0; ii < argCount; ++ii)
+ args[ii + 1].fromValue(argTypes[ii], engine, callArgs[ii]);
+ QVarLengthArray<void *, 9> argData(args.count());
+ for (int ii = 0; ii < args.count(); ++ii)
+ argData[ii] = args[ii].dataPtr();
+
+ // Reinstate saved value type object value if required.
+ if (valueTypeObject)
+ valueTypeObject->setValue(valueTypeValue);
+
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, argData.data());
+
+ return args[0].toValue(engine);
+
+ } else if (returnType != QMetaType::Void) {
+
+ CallArgument arg;
+ arg.initAsType(returnType);
+
+ void *args[] = { arg.dataPtr() };
+
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
+
+ return arg.toValue(engine);
+
+ } else {
+
+ void *args[] = { 0 };
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
+ return QV4::Value::undefinedValue();
+
+ }
+}
+
+/*!
+ Returns the match score for converting \a actual to be of type \a conversionType. A
+ zero score means "perfect match" whereas a higher score is worse.
+
+ The conversion table is copied out of the \l QScript::callQtMethod() function.
+*/
+static int MatchScore(const QV4::Value &actual, int conversionType)
+{
+ if (actual.isNumber()) {
+ switch (conversionType) {
+ case QMetaType::Double:
+ return 0;
+ case QMetaType::Float:
+ return 1;
+ case QMetaType::LongLong:
+ case QMetaType::ULongLong:
+ return 2;
+ case QMetaType::Long:
+ case QMetaType::ULong:
+ return 3;
+ case QMetaType::Int:
+ case QMetaType::UInt:
+ return 4;
+ case QMetaType::Short:
+ case QMetaType::UShort:
+ return 5;
+ break;
+ case QMetaType::Char:
+ case QMetaType::UChar:
+ return 6;
+ case QMetaType::QJsonValue:
+ return 5;
+ default:
+ return 10;
+ }
+ } else if (actual.isString()) {
+ switch (conversionType) {
+ case QMetaType::QString:
+ return 0;
+ case QMetaType::QJsonValue:
+ return 5;
+ default:
+ return 10;
+ }
+ } else if (actual.isBoolean()) {
+ switch (conversionType) {
+ case QMetaType::Bool:
+ return 0;
+ case QMetaType::QJsonValue:
+ return 5;
+ default:
+ return 10;
+ }
+ } else if (actual.asDateObject()) {
+ switch (conversionType) {
+ case QMetaType::QDateTime:
+ return 0;
+ case QMetaType::QDate:
+ return 1;
+ case QMetaType::QTime:
+ return 2;
+ default:
+ return 10;
+ }
+ } else if (actual.as<QV4::RegExpObject>()) {
+ switch (conversionType) {
+ case QMetaType::QRegExp:
+ return 0;
+ default:
+ return 10;
+ }
+ } else if (actual.asArrayObject()) {
+ switch (conversionType) {
+ case QMetaType::QJsonArray:
+ return 3;
+ case QMetaType::QStringList:
+ case QMetaType::QVariantList:
+ return 5;
+ case QMetaType::QVector4D:
+ case QMetaType::QMatrix4x4:
+ return 6;
+ case QMetaType::QVector3D:
+ return 7;
+ default:
+ return 10;
+ }
+ } else if (actual.isNull()) {
+ switch (conversionType) {
+ case QMetaType::VoidStar:
+ case QMetaType::QObjectStar:
+ case QMetaType::QJsonValue:
+ return 0;
+ default: {
+ const char *typeName = QMetaType::typeName(conversionType);
+ if (typeName && typeName[strlen(typeName) - 1] == '*')
+ return 0;
+ else
+ return 10;
+ }
+ }
+ } else if (QV4::Object *obj = actual.asObject()) {
+ QV8Engine *engine = obj->engine()->v8Engine;
+
+ if (QV4::VariantObject *v = obj->as<QV4::VariantObject>()) {
+ if (conversionType == qMetaTypeId<QVariant>())
+ return 0;
+ if (engine->toVariant(actual, -1).userType() == conversionType)
+ return 0;
+ else
+ return 10;
+ }
+
+ if (obj->as<QObjectWrapper>()) {
+ switch (conversionType) {
+ case QMetaType::QObjectStar:
+ return 0;
+ default:
+ return 10;
+ }
+ }
+
+ if (obj->as<QV4::QmlValueTypeWrapper>()) {
+ if (engine->toVariant(actual, -1).userType() == conversionType)
+ return 0;
+ return 10;
+ } else if (conversionType == QMetaType::QJsonObject) {
+ return 5;
+ } else {
+ return 10;
+ }
+
+ } else {
+ return 10;
+ }
+}
+
+static inline int QMetaObject_methods(const QMetaObject *metaObject)
+{
+ struct Private
+ {
+ int revision;
+ int className;
+ int classInfoCount, classInfoData;
+ int methodCount, methodData;
+ };
+
+ return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
+}
+
+/*!
+Returns the next related method, if one, or 0.
+*/
+static const QQmlPropertyData * RelatedMethod(QObject *object,
+ const QQmlPropertyData *current,
+ QQmlPropertyData &dummy)
+{
+ QQmlPropertyCache *cache = QQmlData::get(object)->propertyCache;
+ if (!current->isOverload())
+ return 0;
+
+ Q_ASSERT(!current->overrideIndexIsProperty);
+
+ if (cache) {
+ return cache->method(current->overrideIndex);
+ } else {
+ const QMetaObject *mo = object->metaObject();
+ int methodOffset = mo->methodCount() - QMetaObject_methods(mo);
+
+ while (methodOffset > current->overrideIndex) {
+ mo = mo->superClass();
+ methodOffset -= QMetaObject_methods(mo);
+ }
+
+ QMetaMethod method = mo->method(current->overrideIndex);
+ dummy.load(method);
+
+ // Look for overloaded methods
+ QByteArray methodName = method.name();
+ for (int ii = current->overrideIndex - 1; ii >= methodOffset; --ii) {
+ if (methodName == mo->method(ii).name()) {
+ dummy.setFlags(dummy.getFlags() | QQmlPropertyData::IsOverload);
+ dummy.overrideIndexIsProperty = 0;
+ dummy.overrideIndex = ii;
+ return &dummy;
+ }
+ }
+
+ return &dummy;
+ }
+}
+
+static QV4::Value CallPrecise(QObject *object, const QQmlPropertyData &data,
+ QV8Engine *engine, CallArgs &callArgs)
+{
+ QByteArray unknownTypeError;
+
+ int returnType = QQmlPropertyCache::methodReturnType(object, data, &unknownTypeError);
+
+ if (returnType == QMetaType::UnknownType) {
+ QString typeName = QString::fromLatin1(unknownTypeError);
+ QString error = QString::fromLatin1("Unknown method return type: %1").arg(typeName);
+ QV8Engine::getV4(engine)->current->throwError(error);
+ }
+
+ if (data.hasArguments()) {
+
+ int *args = 0;
+ QVarLengthArray<int, 9> dummy;
+
+ args = QQmlPropertyCache::methodParameterTypes(object, data.coreIndex, dummy,
+ &unknownTypeError);
+
+ if (!args) {
+ QString typeName = QString::fromLatin1(unknownTypeError);
+ QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(typeName);
+ QV8Engine::getV4(engine)->current->throwError(error);
+ }
+
+ if (args[0] > callArgs.Length()) {
+ QString error = QLatin1String("Insufficient arguments");
+ QV8Engine::getV4(engine)->current->throwError(error);
+ }
+
+ return CallMethod(object, data.coreIndex, returnType, args[0], args + 1, engine, callArgs);
+
+ } else {
+
+ return CallMethod(object, data.coreIndex, returnType, 0, 0, engine, callArgs);
+
+ }
+}
+
+/*!
+Resolve the overloaded method to call. The algorithm works conceptually like this:
+ 1. Resolve the set of overloads it is *possible* to call.
+ Impossible overloads include those that have too many parameters or have parameters
+ of unknown type.
+ 2. Filter the set of overloads to only contain those with the closest number of
+ parameters.
+ For example, if we are called with 3 parameters and there are 2 overloads that
+ take 2 parameters and one that takes 3, eliminate the 2 parameter overloads.
+ 3. Find the best remaining overload based on its match score.
+ If two or more overloads have the same match score, call the last one. The match
+ score is constructed by adding the matchScore() result for each of the parameters.
+*/
+static QV4::Value CallOverloaded(QObject *object, const QQmlPropertyData &data,
+ QV8Engine *engine, CallArgs &callArgs)
+{
+ int argumentCount = callArgs.Length();
+
+ const QQmlPropertyData *best = 0;
+ int bestParameterScore = INT_MAX;
+ int bestMatchScore = INT_MAX;
+
+ // Special handling is required for value types.
+ // We need to save the current value in a temporary,
+ // and reapply it after converting all arguments.
+ // This avoids the "overwriting copy-value-type-value"
+ // problem during Q_INVOKABLE function invocation.
+ QQmlValueType *valueTypeObject = qobject_cast<QQmlValueType*>(object);
+ QVariant valueTypeValue;
+ if (valueTypeObject)
+ valueTypeValue = valueTypeObject->value();
+
+ QQmlPropertyData dummy;
+ const QQmlPropertyData *attempt = &data;
+
+ do {
+ QVarLengthArray<int, 9> dummy;
+ int methodArgumentCount = 0;
+ int *methodArgTypes = 0;
+ if (attempt->hasArguments()) {
+ typedef QQmlPropertyCache PC;
+ int *args = PC::methodParameterTypes(object, attempt->coreIndex, dummy, 0);
+ if (!args) // Must be an unknown argument
+ continue;
+
+ methodArgumentCount = args[0];
+ methodArgTypes = args + 1;
+ }
+
+ if (methodArgumentCount > argumentCount)
+ continue; // We don't have sufficient arguments to call this method
+
+ int methodParameterScore = argumentCount - methodArgumentCount;
+ if (methodParameterScore > bestParameterScore)
+ continue; // We already have a better option
+
+ int methodMatchScore = 0;
+ for (int ii = 0; ii < methodArgumentCount; ++ii)
+ methodMatchScore += MatchScore(callArgs[ii], methodArgTypes[ii]);
+
+ if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
+ best = attempt;
+ bestParameterScore = methodParameterScore;
+ bestMatchScore = methodMatchScore;
+ }
+
+ if (bestParameterScore == 0 && bestMatchScore == 0)
+ break; // We can't get better than that
+
+ } while((attempt = RelatedMethod(object, attempt, dummy)) != 0);
+
+ if (best) {
+ if (valueTypeObject)
+ valueTypeObject->setValue(valueTypeValue);
+ return CallPrecise(object, *best, engine, callArgs);
+ } else {
+ QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
+ const QQmlPropertyData *candidate = &data;
+ while (candidate) {
+ error += QLatin1String("\n ") +
+ QString::fromUtf8(object->metaObject()->method(candidate->coreIndex).methodSignature().constData());
+ candidate = RelatedMethod(object, candidate, dummy);
+ }
+
+ QV8Engine::getV4(engine)->current->throwError(error);
+ }
+}
+
+CallArgument::CallArgument()
+: type(QVariant::Invalid)
+{
+}
+
+CallArgument::~CallArgument()
+{
+ cleanup();
+}
+
+void CallArgument::cleanup()
+{
+ if (type == QMetaType::QString) {
+ qstringPtr->~QString();
+ } else if (type == -1 || type == QMetaType::QVariant) {
+ qvariantPtr->~QVariant();
+ } else if (type == qMetaTypeId<QJSValue>()) {
+ qjsValuePtr->~QJSValue();
+ } else if (type == qMetaTypeId<QList<QObject *> >()) {
+ qlistPtr->~QList<QObject *>();
+ } else if (type == QMetaType::QJsonArray) {
+ jsonArrayPtr->~QJsonArray();
+ } else if (type == QMetaType::QJsonObject) {
+ jsonObjectPtr->~QJsonObject();
+ } else if (type == QMetaType::QJsonValue) {
+ jsonValuePtr->~QJsonValue();
+ }
+}
+
+void *CallArgument::dataPtr()
+{
+ if (type == -1)
+ return qvariantPtr->data();
+ else
+ return (void *)&allocData;
+}
+
+void CallArgument::initAsType(int callType)
+{
+ if (type != 0) { cleanup(); type = 0; }
+ if (callType == QMetaType::UnknownType) return;
+
+ if (callType == qMetaTypeId<QJSValue>()) {
+ qjsValuePtr = new (&allocData) QJSValue();
+ type = callType;
+ } else if (callType == QMetaType::Int ||
+ callType == QMetaType::UInt ||
+ callType == QMetaType::Bool ||
+ callType == QMetaType::Double ||
+ callType == QMetaType::Float) {
+ type = callType;
+ } else if (callType == QMetaType::QObjectStar) {
+ qobjectPtr = 0;
+ type = callType;
+ } else if (callType == QMetaType::QString) {
+ qstringPtr = new (&allocData) QString();
+ type = callType;
+ } else if (callType == QMetaType::QVariant) {
+ type = callType;
+ qvariantPtr = new (&allocData) QVariant();
+ } else if (callType == qMetaTypeId<QList<QObject *> >()) {
+ type = callType;
+ qlistPtr = new (&allocData) QList<QObject *>();
+ } else if (callType == qMetaTypeId<QQmlV4Handle>()) {
+ type = callType;
+ handlePtr = new (&allocData) QQmlV4Handle;
+ } else if (callType == QMetaType::QJsonArray) {
+ type = callType;
+ jsonArrayPtr = new (&allocData) QJsonArray();
+ } else if (callType == QMetaType::QJsonObject) {
+ type = callType;
+ jsonObjectPtr = new (&allocData) QJsonObject();
+ } else if (callType == QMetaType::QJsonValue) {
+ type = callType;
+ jsonValuePtr = new (&allocData) QJsonValue();
+ } else if (callType == QMetaType::Void) {
+ type = -1;
+ qvariantPtr = new (&allocData) QVariant();
+ } else {
+ type = -1;
+ qvariantPtr = new (&allocData) QVariant(callType, (void *)0);
+ }
+}
+
+void CallArgument::fromValue(int callType, QV8Engine *engine, const QV4::Value &value)
+{
+ if (type != 0) { cleanup(); type = 0; }
+
+ if (callType == qMetaTypeId<QJSValue>()) {
+ qjsValuePtr = new (&allocData) QJSValue(new QJSValuePrivate(QV8Engine::getV4(engine), value));
+ type = qMetaTypeId<QJSValue>();
+ } else if (callType == QMetaType::Int) {
+ intValue = quint32(value.toInt32());
+ type = callType;
+ } else if (callType == QMetaType::UInt) {
+ intValue = quint32(value.toUInt32());
+ type = callType;
+ } else if (callType == QMetaType::Bool) {
+ boolValue = value.toBoolean();
+ type = callType;
+ } else if (callType == QMetaType::Double) {
+ doubleValue = double(value.toNumber());
+ type = callType;
+ } else if (callType == QMetaType::Float) {
+ floatValue = float(value.toNumber());
+ type = callType;
+ } else if (callType == QMetaType::QString) {
+ if (value.isNull() || value.isUndefined())
+ qstringPtr = new (&allocData) QString();
+ else
+ qstringPtr = new (&allocData) QString(value.toQString());
+ type = callType;
+ } else if (callType == QMetaType::QObjectStar) {
+ qobjectPtr = 0;
+ if (QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>())
+ qobjectPtr = qobjectWrapper->object();
+ type = callType;
+ } else if (callType == qMetaTypeId<QVariant>()) {
+ qvariantPtr = new (&allocData) QVariant(engine->toVariant(value, -1));
+ type = callType;
+ } else if (callType == qMetaTypeId<QList<QObject*> >()) {
+ qlistPtr = new (&allocData) QList<QObject *>();
+ if (QV4::ArrayObject *array = value.asArrayObject()) {
+ uint32_t length = array->arrayLength();
+ for (uint32_t ii = 0; ii < length; ++ii) {
+ QObject *o = 0;
+ if (QV4::QObjectWrapper *qobjectWrapper = array->getIndexed(ii).as<QV4::QObjectWrapper>())
+ o = qobjectWrapper->object();
+ qlistPtr->append(o);
+ }
+ } else {
+ QObject *o = 0;
+ if (QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>())
+ o = qobjectWrapper->object();
+ qlistPtr->append(o);
+ }
+ type = callType;
+ } else if (callType == qMetaTypeId<QQmlV4Handle>()) {
+ handlePtr = new (&allocData) QQmlV4Handle(QQmlV4Handle(value));
+ type = callType;
+ } else if (callType == QMetaType::QJsonArray) {
+ jsonArrayPtr = new (&allocData) QJsonArray(QV4::JsonObject::toJsonArray(value.asArrayObject()));
+ type = callType;
+ } else if (callType == QMetaType::QJsonObject) {
+ jsonObjectPtr = new (&allocData) QJsonObject(QV4::JsonObject::toJsonObject(value.asObject()));
+ type = callType;
+ } else if (callType == QMetaType::QJsonValue) {
+ jsonValuePtr = new (&allocData) QJsonValue(QV4::JsonObject::toJsonValue(value));
+ type = callType;
+ } else if (callType == QMetaType::Void) {
+ *qvariantPtr = QVariant();
+ } else {
+ qvariantPtr = new (&allocData) QVariant();
+ type = -1;
+
+ QQmlEnginePrivate *ep = engine->engine() ? QQmlEnginePrivate::get(engine->engine()) : 0;
+ QVariant v = engine->toVariant(value, -1); // why -1 instead of callType?
+
+ if (v.userType() == callType) {
+ *qvariantPtr = v;
+ } else if (v.canConvert(callType)) {
+ *qvariantPtr = v;
+ qvariantPtr->convert(callType);
+ } else if (QV4::SequencePrototype::isSequenceType(callType) && v.userType() == qMetaTypeId<QVariantList>()) {
+ // convert the JS array to a sequence of the correct type.
+ QVariant seqV = engine->toVariant(value, callType);
+ *qvariantPtr = seqV;
+ } else {
+ QQmlMetaObject mo = ep ? ep->rawMetaObjectForType(callType) : QQmlMetaObject();
+ if (!mo.isNull()) {
+ QObject *obj = ep->toQObject(v);
+
+ if (obj != 0 && !QQmlMetaObject::canConvert(obj, mo))
+ obj = 0;
+
+ *qvariantPtr = QVariant(callType, &obj);
+ } else {
+ *qvariantPtr = QVariant(callType, (void *)0);
+ }
+ }
+ }
+}
+
+QV4::Value CallArgument::toValue(QV8Engine *engine)
+{
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ if (type == qMetaTypeId<QJSValue>()) {
+ return QJSValuePrivate::get(*qjsValuePtr)->getValue(v4);
+ } else if (type == QMetaType::Int) {
+ return QV4::Value::fromInt32(int(intValue));
+ } else if (type == QMetaType::UInt) {
+ return QV4::Value::fromUInt32(intValue);
+ } else if (type == QMetaType::Bool) {
+ return QV4::Value::fromBoolean(boolValue);
+ } else if (type == QMetaType::Double) {
+ return QV4::Value::fromDouble(doubleValue);
+ } else if (type == QMetaType::Float) {
+ return QV4::Value::fromDouble(floatValue);
+ } else if (type == QMetaType::QString) {
+ return engine->toString(*qstringPtr);
+ } else if (type == QMetaType::QObjectStar) {
+ QObject *object = qobjectPtr;
+ if (object)
+ QQmlData::get(object, true)->setImplicitDestructible();
+ return QV4::QObjectWrapper::wrap(v4, object);
+ } else if (type == qMetaTypeId<QList<QObject *> >()) {
+ // XXX Can this be made more by using Array as a prototype and implementing
+ // directly against QList<QObject*>?
+ QList<QObject *> &list = *qlistPtr;
+ QV4::ArrayObject *array = v4->newArrayObject();
+ array->arrayReserve(list.count());
+ array->arrayDataLen = list.count();
+ for (int ii = 0; ii < list.count(); ++ii)
+ array->arrayData[ii].value = QV4::QObjectWrapper::wrap(v4, list.at(ii));
+ array->setArrayLengthUnchecked(list.count());
+ return QV4::Value::fromObject(array);
+ } else if (type == qMetaTypeId<QQmlV4Handle>()) {
+ return handlePtr->toValue();
+ } else if (type == QMetaType::QJsonArray) {
+ return QV4::JsonObject::fromJsonArray(v4, *jsonArrayPtr);
+ } else if (type == QMetaType::QJsonObject) {
+ return QV4::JsonObject::fromJsonObject(v4, *jsonObjectPtr);
+ } else if (type == QMetaType::QJsonValue) {
+ return QV4::JsonObject::fromJsonValue(v4, *jsonValuePtr);
+ } else if (type == -1 || type == qMetaTypeId<QVariant>()) {
+ QVariant value = *qvariantPtr;
+ QV4::Value rv = engine->fromVariant(value);
+ if (QV4::QObjectWrapper *qobjectWrapper = rv.as<QV4::QObjectWrapper>()) {
+ if (QObject *object = qobjectWrapper->object())
+ QQmlData::get(object, true)->setImplicitDestructible();
+ }
+ return rv;
+ } else {
+ return QV4::Value::undefinedValue();
+ }
+}
+
+Value QObjectMethod::create(ExecutionContext *scope, QObject *object, int index, const Value &qmlGlobal)
+{
+ return Value::fromObject(new (scope->engine->memoryManager) QObjectMethod(scope, object, index, qmlGlobal));
+}
+
+QObjectMethod::QObjectMethod(ExecutionContext *scope, QObject *object, int index, const Value &qmlGlobal)
+ : FunctionObject(scope)
+ , m_object(object)
+ , m_index(index)
+ , m_qmlGlobal(qmlGlobal)
+{
+ vtbl = &static_vtbl;
+ subtype = WrappedQtMethod;
+}
+
+QV4::Value QObjectMethod::method_toString(QV4::ExecutionContext *ctx)
+{
+ QString result;
+ if (m_object) {
+ QString objectName = m_object->objectName();
+
+ result += QString::fromUtf8(m_object->metaObject()->className());
+ result += QLatin1String("(0x");
+ result += QString::number((quintptr)m_object.data(),16);
+
+ if (!objectName.isEmpty()) {
+ result += QLatin1String(", \"");
+ result += objectName;
+ result += QLatin1Char('\"');
+ }
+
+ result += QLatin1Char(')');
+ } else {
+ result = QLatin1String("null");
+ }
+
+ return QV4::Value::fromString(ctx, result);
+}
+
+QV4::Value QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, Value *args, int argc)
+{
+ if (!m_object)
+ return QV4::Value::undefinedValue();
+ if (QQmlData::keepAliveDuringGarbageCollection(m_object))
+ ctx->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object"));
+
+ int delay = 0;
+ if (argc > 0)
+ delay = args[0].toUInt32();
+
+ if (delay > 0)
+ QTimer::singleShot(delay, m_object, SLOT(deleteLater()));
+ else
+ m_object->deleteLater();
+
+ return QV4::Value::undefinedValue();
+}
+
+Value QObjectMethod::call(Managed *m, const Value &thisObject, Value *args, int argc)
+{
+ QObjectMethod *This = static_cast<QObjectMethod*>(m);
+ return This->callInternal(thisObject, args, argc);
+}
+
+Value QObjectMethod::callInternal(const Value &, Value *args, int argc)
+{
+ ExecutionContext *context = engine()->current;
+ if (m_index == DestroyMethod)
+ return method_destroy(context, args, argc);
+ else if (m_index == ToStringMethod)
+ return method_toString(context);
+
+ QObject *object = m_object.data();
+ if (!object)
+ return QV4::Value::undefinedValue();
+
+ QQmlData *ddata = QQmlData::get(object);
+ if (!ddata)
+ return QV4::Value::undefinedValue();
+
+ QV8Engine *v8Engine = context->engine->v8Engine;
+
+ QQmlPropertyData method;
+
+ if (QQmlData *ddata = static_cast<QQmlData *>(QObjectPrivate::get(object)->declarativeData)) {
+ if (ddata->propertyCache) {
+ QQmlPropertyData *d = ddata->propertyCache->method(m_index);
+ if (!d)
+ return QV4::Value::undefinedValue();
+ method = *d;
+ }
+ }
+
+ if (method.coreIndex == -1) {
+ method.load(object->metaObject()->method(m_index));
+
+ if (method.coreIndex == -1)
+ return QV4::Value::undefinedValue();
+ }
+
+ if (method.isV4Function()) {
+ QV4::Value rv = QV4::Value::undefinedValue();
+
+ QQmlV4Function func(argc, args, &rv, m_qmlGlobal.value(),
+ QmlContextWrapper::getContext(m_qmlGlobal.value()),
+ v8Engine);
+ QQmlV4Function *funcptr = &func;
+
+ void *args[] = { 0, &funcptr };
+ QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, method.coreIndex, args);
+
+ return rv;
+ }
+
+ CallArgs callArgs(argc, args);
+ if (!method.isOverload()) {
+ return CallPrecise(object, method, v8Engine, callArgs);
+ } else {
+ return CallOverloaded(object, method, v8Engine, callArgs);
+ }
+}
+
+DEFINE_MANAGED_VTABLE(QObjectMethod);
+
+QmlSignalHandler::QmlSignalHandler(ExecutionEngine *engine, QObject *object, int signalIndex)
+ : Object(engine)
+ , m_object(object)
+ , m_signalIndex(signalIndex)
+{
+ vtbl = &static_vtbl;
+ prototype = engine->objectPrototype;
+}
+
+DEFINE_MANAGED_VTABLE(QmlSignalHandler);
+
+void MultiplyWrappedQObjectMap::insert(QObject *key, Object *value)
+{
+ QHash<QObject*, Object*>::insert(key, value);
+ connect(key, SIGNAL(destroyed(QObject*)), this, SLOT(removeDestroyedObject(QObject*)));
+}
+
+MultiplyWrappedQObjectMap::Iterator MultiplyWrappedQObjectMap::erase(MultiplyWrappedQObjectMap::Iterator it)
+{
+ disconnect(it.key(), SIGNAL(destroyed(QObject*)), this, SLOT(removeDestroyedObject(QObject*)));
+ return QHash<QObject*, Object*>::erase(it);
+}
+
+void MultiplyWrappedQObjectMap::remove(QObject *key)
+{
+ Iterator it = find(key);
+ if (it == end())
+ return;
+ erase(it);
+}
+
+void MultiplyWrappedQObjectMap::removeDestroyedObject(QObject *object)
+{
+ QHash<QObject*, Object*>::remove(object);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/qml/qml/v4/qv4qobjectwrapper_p.h b/src/qml/qml/v4/qv4qobjectwrapper_p.h
new file mode 100644
index 0000000000..6580d19fe9
--- /dev/null
+++ b/src/qml/qml/v4/qv4qobjectwrapper_p.h
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4QOBJECTWRAPPER_P_H
+#define QV4QOBJECTWRAPPER_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 <QtCore/qglobal.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qhash.h>
+#include <private/qhashedstring_p.h>
+#include <private/qqmldata_p.h>
+#include <private/qqmlpropertycache_p.h>
+#include <private/qintrusivelist_p.h>
+
+#include <private/qv4value_p.h>
+#include <private/qv4functionobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+class QQmlData;
+class QQmlPropertyCache;
+class QQmlPropertyData;
+
+namespace QV4 {
+struct QObjectSlotDispatcher;
+
+struct Q_QML_EXPORT QObjectWrapper : public QV4::Object
+{
+ Q_MANAGED
+
+ enum RevisionMode { IgnoreRevision, CheckRevision };
+
+ static void initializeBindings(ExecutionEngine *engine);
+
+ QObject *object() const { return m_object.data(); }
+
+ Value getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, bool *hasProperty = 0, bool includeImports = false);
+ static Value getQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, bool *hasProperty = 0);
+
+ static bool setQmlProperty(ExecutionContext *ctx, QQmlContextData *qmlContext, QObject *object, String *name, RevisionMode revisionMode, const Value &value);
+
+ static Value wrap(ExecutionEngine *engine, QObject *object);
+
+ using Object::get;
+
+private:
+ static Value create(ExecutionEngine *engine, QQmlData *ddata, QObject *object);
+
+ QObjectWrapper(ExecutionEngine *engine, QObject *object);
+
+ QQmlPropertyData *findProperty(ExecutionEngine *engine, QQmlContextData *qmlContext, String *name, RevisionMode revisionMode, QQmlPropertyData *local) const;
+
+ QPointer<QObject> m_object;
+ String *m_destroy;
+ String *m_toString;
+
+ static Value get(Managed *m, String *name, bool *hasProperty);
+ static void put(Managed *m, String *name, const Value &value);
+ static PropertyAttributes query(const Managed *, String *name);
+ static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes);
+ static void markObjects(Managed *that);
+ static void collectDeletables(Managed *m, GCDeletable **deletable);
+ static void destroy(Managed *that)
+ {
+ static_cast<QObjectWrapper *>(that)->~QObjectWrapper();
+ }
+
+ static Value method_connect(SimpleCallContext *ctx);
+ static Value method_disconnect(SimpleCallContext *ctx);
+};
+
+struct QObjectMethod : public QV4::FunctionObject
+{
+ Q_MANAGED
+
+ enum { DestroyMethod = -1, ToStringMethod = -2 };
+
+ static Value create(QV4::ExecutionContext *scope, QObject *object, int index, const Value &qmlGlobal = Value::undefinedValue());
+
+ int methodIndex() const { return m_index; }
+ QObject *object() const { return m_object.data(); }
+
+private:
+ QObjectMethod(QV4::ExecutionContext *scope, QObject *object, int index, const QV4::Value &qmlGlobal);
+
+ QV4::Value method_toString(QV4::ExecutionContext *ctx);
+ QV4::Value method_destroy(QV4::ExecutionContext *ctx, Value *args, int argc);
+
+ QPointer<QObject> m_object;
+ int m_index;
+ QV4::PersistentValue m_qmlGlobal;
+
+ static Value call(Managed *, const Value &thisObject, Value *args, int argc);
+
+ Value callInternal(const Value &, Value *args, int argc);
+
+ static void destroy(Managed *that)
+ {
+ static_cast<QObjectMethod *>(that)->~QObjectMethod();
+ }
+};
+
+struct QmlSignalHandler : public QV4::Object
+{
+ Q_MANAGED
+
+ QmlSignalHandler(ExecutionEngine *engine, QObject *object, int signalIndex);
+
+ int signalIndex() const { return m_signalIndex; }
+ QObject *object() const { return m_object.data(); }
+
+private:
+ QPointer<QObject> m_object;
+ int m_signalIndex;
+
+ static void destroy(Managed *that)
+ {
+ static_cast<QmlSignalHandler *>(that)->~QmlSignalHandler();
+ }
+};
+
+class MultiplyWrappedQObjectMap : public QObject,
+ private QHash<QObject*, Object*>
+{
+ Q_OBJECT
+public:
+ typedef QHash<QObject*, Object*>::ConstIterator ConstIterator;
+ typedef QHash<QObject*, Object*>::Iterator Iterator;
+
+ ConstIterator begin() const { return QHash<QObject*, Object*>::constBegin(); }
+ Iterator begin() { return QHash<QObject*, Object*>::begin(); }
+ ConstIterator end() const { return QHash<QObject*, Object*>::constEnd(); }
+ Iterator end() { return QHash<QObject*, Object*>::end(); }
+
+ void insert(QObject *key, Object *value);
+ Object *value(QObject *key) const { return QHash<QObject*, Object*>::value(key, 0); }
+ Iterator erase(Iterator it);
+ void remove(QObject *key);
+
+private slots:
+ void removeDestroyedObject(QObject*);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4QOBJECTWRAPPER_P_H
+
+
diff --git a/src/qml/qml/v4/qv4regexp.cpp b/src/qml/qml/v4/qv4regexp.cpp
new file mode 100644
index 0000000000..ab01ce7650
--- /dev/null
+++ b/src/qml/qml/v4/qv4regexp.cpp
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4regexp_p.h"
+
+#include "qv4engine_p.h"
+
+using namespace QV4;
+
+RegExpCache::~RegExpCache()
+{
+ for (RegExpCache::Iterator it = begin(), e = end();
+ it != e; ++it)
+ it.value()->m_cache = 0;
+ clear();
+}
+
+DEFINE_MANAGED_VTABLE(RegExp);
+
+uint RegExp::match(const QString &string, int start, uint *matchOffsets)
+{
+ if (!isValid())
+ return JSC::Yarr::offsetNoMatch;
+
+ WTF::String s(string);
+
+#if ENABLE(YARR_JIT)
+ if (!m_jitCode.isFallBack() && m_jitCode.has16BitCode())
+ return m_jitCode.execute(s.characters16(), start, s.length(), (int*)matchOffsets).start;
+#endif
+
+ return JSC::Yarr::interpret(m_byteCode.get(), s.characters16(), string.length(), start, matchOffsets);
+}
+
+RegExp* RegExp::create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline)
+{
+ RegExpCacheKey key(pattern, ignoreCase, multiline);
+
+ RegExpCache *cache = engine->regExpCache;
+ if (cache) {
+ if (RegExp *result = cache->value(key))
+ return result;
+ }
+
+ RegExp *result = new (engine->memoryManager) RegExp(engine, pattern, ignoreCase, multiline);
+
+ if (!cache)
+ cache = engine->regExpCache = new RegExpCache;
+
+ result->m_cache = cache;
+ cache->insert(key, result);
+
+ return result;
+}
+
+RegExp::RegExp(ExecutionEngine* engine, const QString &pattern, bool ignoreCase, bool multiline)
+ : Managed(engine->emptyClass)
+ , m_pattern(pattern)
+ , m_cache(0)
+ , m_subPatternCount(0)
+ , m_ignoreCase(ignoreCase)
+ , m_multiLine(multiline)
+{
+ vtbl = &static_vtbl;
+ type = Type_RegExpObject;
+
+ if (!engine)
+ return;
+ const char* error = 0;
+ JSC::Yarr::YarrPattern yarrPattern(WTF::String(pattern), ignoreCase, multiline, &error);
+ if (error)
+ return;
+ m_subPatternCount = yarrPattern.m_numSubpatterns;
+ m_byteCode = JSC::Yarr::byteCompile(yarrPattern, engine->bumperPointerAllocator);
+#if ENABLE(YARR_JIT)
+ if (!yarrPattern.m_containsBackreferences && engine->iselFactory->jitCompileRegexps()) {
+ JSC::JSGlobalData dummy(engine->regExpAllocator);
+ JSC::Yarr::jitCompile(yarrPattern, JSC::Yarr::Char16, &dummy, m_jitCode);
+ }
+#endif
+}
+
+RegExp::~RegExp()
+{
+ if (m_cache) {
+ RegExpCacheKey key(this);
+ m_cache->remove(key);
+ }
+ _data = 0;
+}
+
+void RegExp::destroy(Managed *that)
+{
+ static_cast<RegExp*>(that)->~RegExp();
+}
+
+void RegExp::markObjects(Managed *that)
+{
+}
+
+Value RegExp::get(Managed *m, String *name, bool *hasProperty)
+{
+ return Value::undefinedValue();
+}
+
+Value RegExp::getIndexed(Managed *m, uint index, bool *hasProperty)
+{
+ return Value::undefinedValue();
+}
+
+void RegExp::put(Managed *m, String *name, const Value &value)
+{
+}
+
+void RegExp::putIndexed(Managed *m, uint index, const Value &value)
+{
+}
+
+PropertyAttributes RegExp::query(const Managed *m, String *name)
+{
+ return Attr_Invalid;
+}
+
+PropertyAttributes RegExp::queryIndexed(const Managed *m, uint index)
+{
+ return Attr_Invalid;
+}
+
+bool RegExp::deleteProperty(Managed *, String *)
+{
+ return false;
+}
+
+bool RegExp::deleteIndexedProperty(Managed *m, uint index)
+{
+ return false;
+}
+
+Property *RegExp::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes)
+{
+ return 0;
+}
diff --git a/src/qml/qml/v4/qv4regexp_p.h b/src/qml/qml/v4/qv4regexp_p.h
new file mode 100644
index 0000000000..6edbd4b2ad
--- /dev/null
+++ b/src/qml/qml/v4/qv4regexp_p.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4REGEXP_H
+#define QV4REGEXP_H
+
+#include <QString>
+#include <QVector>
+
+#include <wtf/RefPtr.h>
+#include <wtf/FastAllocBase.h>
+#include <wtf/BumpPointerAllocator.h>
+
+#include <limits.h>
+
+#include <yarr/Yarr.h>
+#include <yarr/YarrInterpreter.h>
+#include <yarr/YarrJIT.h>
+
+#include "qv4managed_p.h"
+#include "qv4engine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct ExecutionEngine;
+
+struct RegExpCacheKey
+{
+ RegExpCacheKey(const QString &pattern, bool ignoreCase, bool multiLine)
+ : pattern(pattern)
+ , ignoreCase(ignoreCase)
+ , multiLine(multiLine)
+ { }
+ explicit inline RegExpCacheKey(const RegExp *re);
+
+ bool operator==(const RegExpCacheKey &other) const
+ { return pattern == other.pattern && ignoreCase == other.ignoreCase && multiLine == other.multiLine; }
+ bool operator!=(const RegExpCacheKey &other) const
+ { return !operator==(other); }
+
+ QString pattern;
+ uint ignoreCase : 1;
+ uint multiLine : 1;
+};
+
+inline uint qHash(const RegExpCacheKey& key, uint seed = 0) Q_DECL_NOTHROW
+{ return qHash(key.pattern, seed); }
+
+class RegExpCache : public QHash<RegExpCacheKey, RegExp*>
+{
+public:
+ ~RegExpCache();
+};
+
+class RegExp : public Managed
+{
+ Q_MANAGED
+public:
+ static RegExp* create(ExecutionEngine* engine, const QString& pattern, bool ignoreCase = false, bool multiline = false);
+ ~RegExp();
+
+ QString pattern() const { return m_pattern; }
+
+ bool isValid() const { return m_byteCode.get(); }
+
+ uint match(const QString& string, int start, uint *matchOffsets);
+
+ bool ignoreCase() const { return m_ignoreCase; }
+ bool multiLine() const { return m_multiLine; }
+ int captureCount() const { return m_subPatternCount + 1; }
+
+protected:
+ static void destroy(Managed *that);
+ static void markObjects(Managed *that);
+ static Value get(Managed *m, String *name, bool *hasProperty);
+ static Value getIndexed(Managed *m, uint index, bool *hasProperty);
+ static void put(Managed *m, String *name, const Value &value);
+ static void putIndexed(Managed *m, uint index, const Value &value);
+ static PropertyAttributes query(const Managed *m, String *name);
+ static PropertyAttributes queryIndexed(const Managed *m, uint index);
+ static bool deleteProperty(Managed *, String *);
+ static bool deleteIndexedProperty(Managed *m, uint index);
+ static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attributes);
+
+private:
+ friend class RegExpCache;
+ Q_DISABLE_COPY(RegExp);
+ RegExp(ExecutionEngine* engine, const QString& pattern, bool ignoreCase, bool multiline);
+
+ const QString m_pattern;
+ OwnPtr<JSC::Yarr::BytecodePattern> m_byteCode;
+#if ENABLE(YARR_JIT)
+ JSC::Yarr::YarrCodeBlock m_jitCode;
+#endif
+ RegExpCache *m_cache;
+ int m_subPatternCount;
+ const bool m_ignoreCase;
+ const bool m_multiLine;
+};
+
+inline RegExpCacheKey::RegExpCacheKey(const RegExp *re)
+ : pattern(re->pattern())
+ , ignoreCase(re->ignoreCase())
+ , multiLine(re->multiLine())
+{}
+
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4REGEXP_H
diff --git a/src/qml/qml/v4/qv4regexpobject.cpp b/src/qml/qml/v4/qv4regexpobject.cpp
new file mode 100644
index 0000000000..0dc14e5722
--- /dev/null
+++ b/src/qml/qml/v4/qv4regexpobject.cpp
@@ -0,0 +1,359 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4regexpobject_p.h"
+#include "qv4jsir_p.h"
+#include "qv4isel_p.h"
+#include "qv4objectproto_p.h"
+#include "qv4stringobject_p.h"
+#include "qv4mm_p.h"
+
+#include <private/qqmljsengine_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljsast_p.h>
+#include <qv4jsir_p.h>
+#include <qv4codegen_p.h>
+#include "private/qlocale_tools_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtCore/QDebug>
+#include <QtCore/qregexp.h>
+#include <cassert>
+#include <typeinfo>
+#include <iostream>
+#include "qv4alloca_p.h"
+
+QT_BEGIN_NAMESPACE
+
+Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
+
+using namespace QV4;
+
+DEFINE_MANAGED_VTABLE(RegExpObject);
+
+RegExpObject::RegExpObject(ExecutionEngine *engine, RegExp* value, bool global)
+ : Object(engine)
+ , value(value)
+ , global(global)
+{
+ init(engine);
+}
+
+// Converts a QRegExp to a JS RegExp.
+// The conversion is not 100% exact since ECMA regexp and QRegExp
+// have different semantics/flags, but we try to do our best.
+RegExpObject::RegExpObject(ExecutionEngine *engine, const QRegExp &re)
+ : Object(engine)
+ , value(0)
+ , global(false)
+{
+ // Convert the pattern to a ECMAScript pattern.
+ QString pattern = QT_PREPEND_NAMESPACE(qt_regexp_toCanonical)(re.pattern(), re.patternSyntax());
+ if (re.isMinimal()) {
+ QString ecmaPattern;
+ int len = pattern.length();
+ ecmaPattern.reserve(len);
+ int i = 0;
+ const QChar *wc = pattern.unicode();
+ bool inBracket = false;
+ while (i < len) {
+ QChar c = wc[i++];
+ ecmaPattern += c;
+ switch (c.unicode()) {
+ case '?':
+ case '+':
+ case '*':
+ case '}':
+ if (!inBracket)
+ ecmaPattern += QLatin1Char('?');
+ break;
+ case '\\':
+ if (i < len)
+ ecmaPattern += wc[i++];
+ break;
+ case '[':
+ inBracket = true;
+ break;
+ case ']':
+ inBracket = false;
+ break;
+ default:
+ break;
+ }
+ }
+ pattern = ecmaPattern;
+ }
+
+ value = RegExp::create(engine, pattern, re.caseSensitivity() == Qt::CaseInsensitive, false);
+
+ init(engine);
+}
+
+void RegExpObject::init(ExecutionEngine *engine)
+{
+ vtbl = &static_vtbl;
+ type = Type_RegExpObject;
+
+ Property *lastIndexProperty = insertMember(engine->newIdentifier(QStringLiteral("lastIndex")),
+ Attr_NotEnumerable|Attr_NotConfigurable);
+ lastIndexProperty->value = Value::fromInt32(0);
+ if (!this->value)
+ return;
+
+ QString p = this->value->pattern();
+ if (p.isEmpty()) {
+ p = QStringLiteral("(?:)");
+ } else {
+ // escape certain parts, see ch. 15.10.4
+ p.replace('/', QLatin1String("\\/"));
+ }
+
+ defineReadonlyProperty(engine->newIdentifier(QStringLiteral("source")), Value::fromString(engine->newString(p)));
+ defineReadonlyProperty(engine->newIdentifier(QStringLiteral("global")), Value::fromBoolean(global));
+ defineReadonlyProperty(engine->newIdentifier(QStringLiteral("ignoreCase")), Value::fromBoolean(this->value->ignoreCase()));
+ defineReadonlyProperty(engine->newIdentifier(QStringLiteral("multiline")), Value::fromBoolean(this->value->multiLine()));
+}
+
+
+void RegExpObject::destroy(Managed *that)
+{
+ static_cast<RegExpObject *>(that)->~RegExpObject();
+}
+
+void RegExpObject::markObjects(Managed *that)
+{
+ RegExpObject *re = static_cast<RegExpObject*>(that);
+ if (re->value)
+ re->value->mark();
+ Object::markObjects(that);
+}
+
+Property *RegExpObject::lastIndexProperty(ExecutionContext *ctx)
+{
+ assert(0 == internalClass->find(ctx->engine->newIdentifier(QStringLiteral("lastIndex"))));
+ return &memberData[0];
+}
+
+// Converts a JS RegExp to a QRegExp.
+// The conversion is not 100% exact since ECMA regexp and QRegExp
+// have different semantics/flags, but we try to do our best.
+QRegExp RegExpObject::toQRegExp() const
+{
+ Qt::CaseSensitivity caseSensitivity = value->ignoreCase() ? Qt::CaseInsensitive : Qt::CaseSensitive;
+ return QRegExp(value->pattern(), caseSensitivity, QRegExp::RegExp2);
+}
+
+QString RegExpObject::toString() const
+{
+ QString result = QChar('/') + source();
+ result += QChar('/');
+ if (global)
+ result += QChar('g');
+ if (value->ignoreCase())
+ result += QChar('i');
+ if (value->multiLine())
+ result += QChar('m');
+ return result;
+}
+
+QString RegExpObject::source() const
+{
+ return const_cast<RegExpObject *>(this)->get(internalClass->engine->newIdentifier(QStringLiteral("source"))).stringValue()->toQString();
+}
+
+uint RegExpObject::flags() const
+{
+ uint f = 0;
+ if (global)
+ f |= QV4::RegExpObject::RegExp_Global;
+ if (value->ignoreCase())
+ f |= QV4::RegExpObject::RegExp_IgnoreCase;
+ if (value->multiLine())
+ f |= QV4::RegExpObject::RegExp_Multiline;
+ return f;
+}
+
+DEFINE_MANAGED_VTABLE(RegExpCtor);
+
+RegExpCtor::RegExpCtor(ExecutionContext *scope)
+ : FunctionObject(scope, scope->engine->newIdentifier(QStringLiteral("RegExp")))
+{
+ vtbl = &static_vtbl;
+}
+
+Value RegExpCtor::construct(Managed *m, Value *argv, int argc)
+{
+ Value r = argc > 0 ? argv[0] : Value::undefinedValue();
+ Value f = argc > 1 ? argv[1] : Value::undefinedValue();
+ ExecutionContext *ctx = m->engine()->current;
+ if (RegExpObject *re = r.as<RegExpObject>()) {
+ if (!f.isUndefined())
+ ctx->throwTypeError();
+
+ RegExpObject *o = ctx->engine->newRegExpObject(re->value, re->global);
+ return Value::fromObject(o);
+ }
+
+ QString pattern;
+ if (!r.isUndefined())
+ pattern = r.toString(ctx)->toQString();
+
+ bool global = false;
+ bool ignoreCase = false;
+ bool multiLine = false;
+ if (!f.isUndefined()) {
+ f = __qmljs_to_string(f, ctx);
+ QString str = f.stringValue()->toQString();
+ for (int i = 0; i < str.length(); ++i) {
+ if (str.at(i) == QChar('g') && !global) {
+ global = true;
+ } else if (str.at(i) == QChar('i') && !ignoreCase) {
+ ignoreCase = true;
+ } else if (str.at(i) == QChar('m') && !multiLine) {
+ multiLine = true;
+ } else {
+ ctx->throwSyntaxError(0);
+ }
+ }
+ }
+
+ RegExp* re = RegExp::create(ctx->engine, pattern, ignoreCase, multiLine);
+ if (!re->isValid())
+ ctx->throwSyntaxError(0);
+
+ RegExpObject *o = ctx->engine->newRegExpObject(re, global);
+ return Value::fromObject(o);
+}
+
+Value RegExpCtor::call(Managed *that, const Value &, Value *argv, int argc)
+{
+ if (argc > 0 && argv[0].as<RegExpObject>()) {
+ if (argc == 1 || argv[1].isUndefined())
+ return argv[0];
+ }
+
+ return construct(that, argv, argc);
+}
+
+void RegExpPrototype::init(ExecutionContext *ctx, const Value &ctor)
+{
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_prototype, Value::fromObject(this));
+ ctor.objectValue()->defineReadonlyProperty(ctx->engine->id_length, Value::fromInt32(2));
+ defineDefaultProperty(ctx, QStringLiteral("constructor"), ctor);
+ defineDefaultProperty(ctx, QStringLiteral("exec"), method_exec, 1);
+ defineDefaultProperty(ctx, QStringLiteral("test"), method_test, 1);
+ defineDefaultProperty(ctx, QStringLiteral("toString"), method_toString, 0);
+ defineDefaultProperty(ctx, QStringLiteral("compile"), method_compile, 2);
+}
+
+Value RegExpPrototype::method_exec(SimpleCallContext *ctx)
+{
+ RegExpObject *r = ctx->thisObject.as<RegExpObject>();
+ if (!r)
+ ctx->throwTypeError();
+
+ Value arg = ctx->argument(0);
+ arg = __qmljs_to_string(arg, ctx);
+ QString s = arg.stringValue()->toQString();
+
+ int offset = r->global ? r->lastIndexProperty(ctx)->value.toInt32() : 0;
+ if (offset < 0 || offset > s.length()) {
+ r->lastIndexProperty(ctx)->value = Value::fromInt32(0);
+ return Value::nullValue();
+ }
+
+ uint* matchOffsets = (uint*)alloca(r->value->captureCount() * 2 * sizeof(uint));
+ int result = r->value->match(s, offset, matchOffsets);
+ if (result == -1) {
+ r->lastIndexProperty(ctx)->value = Value::fromInt32(0);
+ return Value::nullValue();
+ }
+
+ // fill in result data
+ ArrayObject *array = ctx->engine->newArrayObject();
+ for (int i = 0; i < r->value->captureCount(); ++i) {
+ int start = matchOffsets[i * 2];
+ int end = matchOffsets[i * 2 + 1];
+ Value entry = Value::undefinedValue();
+ if (start != -1 && end != -1)
+ entry = Value::fromString(ctx, s.mid(start, end - start));
+ array->push_back(entry);
+ }
+
+ array->put(ctx, QLatin1String("index"), Value::fromInt32(result));
+ array->put(ctx, QLatin1String("input"), arg);
+
+ if (r->global)
+ r->lastIndexProperty(ctx)->value = Value::fromInt32(matchOffsets[1]);
+
+ return Value::fromObject(array);
+}
+
+Value RegExpPrototype::method_test(SimpleCallContext *ctx)
+{
+ Value r = method_exec(ctx);
+ return Value::fromBoolean(!r.isNull());
+}
+
+Value RegExpPrototype::method_toString(SimpleCallContext *ctx)
+{
+ RegExpObject *r = ctx->thisObject.as<RegExpObject>();
+ if (!r)
+ ctx->throwTypeError();
+
+ return Value::fromString(ctx, r->toString());
+}
+
+Value RegExpPrototype::method_compile(SimpleCallContext *ctx)
+{
+ RegExpObject *r = ctx->thisObject.as<RegExpObject>();
+ if (!r)
+ ctx->throwTypeError();
+
+ RegExpObject *re = ctx->engine->regExpCtor.asFunctionObject()->construct(ctx->arguments, ctx->argumentCount).as<RegExpObject>();
+
+ r->value = re->value;
+ r->global = re->global;
+ return Value::undefinedValue();
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4regexpobject_p.h b/src/qml/qml/v4/qv4regexpobject_p.h
new file mode 100644
index 0000000000..0b9b7122a9
--- /dev/null
+++ b/src/qml/qml/v4/qv4regexpobject_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4REGEXPOBJECT_H
+#define QV4REGEXPOBJECT_H
+
+#include "qv4runtime_p.h"
+#include "qv4engine_p.h"
+#include "qv4context_p.h"
+#include "qv4functionobject_p.h"
+#include "qv4string_p.h"
+#include "qv4codegen_p.h"
+#include "qv4isel_p.h"
+#include "qv4managed_p.h"
+#include "qv4property_p.h"
+#include "qv4objectiterator_p.h"
+#include "qv4regexp_p.h"
+
+#include <QtCore/QString>
+#include <QtCore/QHash>
+#include <QtCore/QScopedPointer>
+#include <cstdio>
+#include <cassert>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct RegExp;
+
+struct RegExpObject: Object {
+ Q_MANAGED
+ // needs to be compatible with the flags in qv4jsir_p.h
+ enum Flags {
+ RegExp_Global = 0x01,
+ RegExp_IgnoreCase = 0x02,
+ RegExp_Multiline = 0x04
+ };
+
+ RegExp* value;
+ Property *lastIndexProperty(ExecutionContext *ctx);
+ bool global;
+ RegExpObject(ExecutionEngine *engine, RegExp* value, bool global);
+ RegExpObject(ExecutionEngine *engine, const QRegExp &re);
+ ~RegExpObject() {}
+
+ void init(ExecutionEngine *engine);
+
+ QRegExp toQRegExp() const;
+ QString toString() const;
+ QString source() const;
+ uint flags() const;
+
+protected:
+ static void destroy(Managed *that);
+ static void markObjects(Managed *that);
+};
+
+
+struct RegExpCtor: FunctionObject
+{
+ RegExpCtor(ExecutionContext *scope);
+
+ static Value construct(Managed *m, Value *args, int argc);
+ static Value call(Managed *that, const Value &, Value *, int);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct RegExpPrototype: RegExpObject
+{
+ RegExpPrototype(ExecutionEngine* engine): RegExpObject(engine, RegExp::create(engine, QString()), false) {}
+ void init(ExecutionContext *ctx, const Value &ctor);
+
+ static Value method_exec(SimpleCallContext *ctx);
+ static Value method_test(SimpleCallContext *ctx);
+ static Value method_toString(SimpleCallContext *ctx);
+ static Value method_compile(SimpleCallContext *ctx);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QMLJS_OBJECTS_H
diff --git a/src/qml/qml/v4/qv4runtime.cpp b/src/qml/qml/v4/qv4runtime.cpp
new file mode 100644
index 0000000000..deccb3d4ea
--- /dev/null
+++ b/src/qml/qml/v4/qv4runtime.cpp
@@ -0,0 +1,1269 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4global_p.h"
+#include "qv4runtime_p.h"
+#include "qv4object_p.h"
+#include "qv4jsir_p.h"
+#include "qv4objectproto_p.h"
+#include "qv4globalobject_p.h"
+#include "qv4stringobject_p.h"
+#include "qv4lookup_p.h"
+#include "qv4function_p.h"
+#include "qv4exception_p.h"
+#include "private/qlocale_tools_p.h"
+
+#include <QtCore/qmath.h>
+#include <QtCore/qnumeric.h>
+#include <QtCore/QDebug>
+#include <cstdio>
+#include <cassert>
+#include <typeinfo>
+#include <stdlib.h>
+
+#include "../../../3rdparty/double-conversion/double-conversion.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+void __qmljs_numberToString(QString *result, double num, int radix)
+{
+ Q_ASSERT(result);
+
+ if (std::isnan(num)) {
+ *result = QStringLiteral("NaN");
+ return;
+ } else if (qIsInf(num)) {
+ *result = QLatin1String(num < 0 ? "-Infinity" : "Infinity");
+ return;
+ }
+
+ if (radix == 10) {
+ char str[100];
+ double_conversion::StringBuilder builder(str, sizeof(str));
+ double_conversion::DoubleToStringConverter::EcmaScriptConverter().ToShortest(num, &builder);
+ *result = QString::fromLatin1(builder.Finalize());
+ return;
+ }
+
+ result->clear();
+ bool negative = false;
+
+ if (num < 0) {
+ negative = true;
+ num = -num;
+ }
+
+ double frac = num - ::floor(num);
+ num = Value::toInteger(num);
+
+ do {
+ char c = (char)::fmod(num, radix);
+ c = (c < 10) ? (c + '0') : (c - 10 + 'a');
+ result->prepend(QLatin1Char(c));
+ num = ::floor(num / radix);
+ } while (num != 0);
+
+ if (frac != 0) {
+ result->append(QLatin1Char('.'));
+ do {
+ frac = frac * radix;
+ char c = (char)::floor(frac);
+ c = (c < 10) ? (c + '0') : (c - 10 + 'a');
+ result->append(QLatin1Char(c));
+ frac = frac - ::floor(frac);
+ } while (frac != 0);
+ }
+
+ if (negative)
+ result->prepend(QLatin1Char('-'));
+}
+
+void __qmljs_init_closure(ExecutionContext *ctx, Value *result, Function *clos)
+{
+ assert(clos);
+ *result = Value::fromObject(ctx->engine->newScriptFunction(ctx, clos));
+}
+
+Function *__qmljs_register_function(ExecutionContext *ctx, String *name,
+ bool hasDirectEval,
+ bool usesArgumentsObject, bool isStrict,
+ bool hasNestedFunctions,
+ String **formals, unsigned formalCount,
+ String **locals, unsigned localCount)
+{
+ Function *f = ctx->engine->newFunction(name ? name->toQString() : QString());
+
+ f->hasDirectEval = hasDirectEval;
+ f->usesArgumentsObject = usesArgumentsObject;
+ f->isStrict = isStrict;
+ f->hasNestedFunctions = hasNestedFunctions;
+
+ for (unsigned i = 0; i < formalCount; ++i)
+ if (formals[i])
+ f->formals.append(formals[i]);
+ for (unsigned i = 0; i < localCount; ++i)
+ if (locals[i])
+ f->locals.append(locals[i]);
+
+ return f;
+}
+
+void __qmljs_delete_subscript(ExecutionContext *ctx, Value *result, const Value &base, const Value &index)
+{
+ if (Object *o = base.asObject()) {
+ uint n = index.asArrayIndex();
+ if (n < UINT_MAX) {
+ Value res = Value::fromBoolean(o->deleteIndexedProperty(n));
+ if (result)
+ *result = res;
+ return;
+ }
+ }
+
+ String *name = index.toString(ctx);
+ __qmljs_delete_member(ctx, result, base, name);
+}
+
+void __qmljs_delete_member(ExecutionContext *ctx, Value *result, const Value &base, String *name)
+{
+ Object *obj = base.toObject(ctx);
+ Value res = Value::fromBoolean(obj->deleteProperty(name));
+ if (result)
+ *result = res;
+}
+
+void __qmljs_delete_name(ExecutionContext *ctx, Value *result, String *name)
+{
+ Value res = Value::fromBoolean(ctx->deleteProperty(name));
+ if (result)
+ *result = res;
+}
+
+void __qmljs_add_helper(ExecutionContext *ctx, Value *result, const Value &left, const Value &right)
+{
+ Value pleft = __qmljs_to_primitive(left, PREFERREDTYPE_HINT);
+ Value pright = __qmljs_to_primitive(right, PREFERREDTYPE_HINT);
+ if (pleft.isString() || pright.isString()) {
+ if (!pleft.isString())
+ pleft = __qmljs_to_string(pleft, ctx);
+ if (!pright.isString())
+ pright = __qmljs_to_string(pright, ctx);
+ String *string = __qmljs_string_concat(ctx, pleft.stringValue(), pright.stringValue());
+ *result = Value::fromString(string);
+ return;
+ }
+ double x = __qmljs_to_number(pleft);
+ double y = __qmljs_to_number(pright);
+ *result = Value::fromDouble(x + y);
+}
+
+void __qmljs_instanceof(ExecutionContext *ctx, Value *result, const Value &left, const Value &right)
+{
+ Object *o = right.asObject();
+ if (!o)
+ ctx->throwTypeError();
+
+ bool r = o->hasInstance(left);
+ *result = Value::fromBoolean(r);
+}
+
+void __qmljs_in(ExecutionContext *ctx, Value *result, const Value &left, const Value &right)
+{
+ if (!right.isObject())
+ ctx->throwTypeError();
+ String *s = left.toString(ctx);
+ bool r = right.objectValue()->__hasProperty__(s);
+ *result = Value::fromBoolean(r);
+}
+
+void __qmljs_inplace_bit_and_name(ExecutionContext *ctx, String *name, const Value &value)
+{
+ ctx->inplaceBitOp(name, value, __qmljs_bit_and);
+}
+
+void __qmljs_inplace_bit_or_name(ExecutionContext *ctx, String *name, const Value &value)
+{
+ ctx->inplaceBitOp(name, value, __qmljs_bit_or);
+}
+
+void __qmljs_inplace_bit_xor_name(ExecutionContext *ctx, String *name, const Value &value)
+{
+ ctx->inplaceBitOp(name, value, __qmljs_bit_xor);
+}
+
+void __qmljs_inplace_add_name(ExecutionContext *ctx, String *name, const Value &value)
+{
+ ctx->inplaceBitOp(name, value, __qmljs_add);
+}
+
+void __qmljs_inplace_sub_name(ExecutionContext *ctx, String *name, const Value &value)
+{
+ ctx->inplaceBitOp(name, value, __qmljs_sub);
+}
+
+void __qmljs_inplace_mul_name(ExecutionContext *ctx, String *name, const Value &value)
+{
+ ctx->inplaceBitOp(name, value, __qmljs_mul);
+}
+
+void __qmljs_inplace_div_name(ExecutionContext *ctx, String *name, const Value &value)
+{
+ ctx->inplaceBitOp(name, value, __qmljs_div);
+}
+
+void __qmljs_inplace_mod_name(ExecutionContext *ctx, String *name, const Value &value)
+{
+ ctx->inplaceBitOp(name, value, __qmljs_mod);
+}
+
+void __qmljs_inplace_shl_name(ExecutionContext *ctx, String *name, const Value &value)
+{
+ ctx->inplaceBitOp(name, value, __qmljs_shl);
+}
+
+void __qmljs_inplace_shr_name(ExecutionContext *ctx, String *name, const Value &value)
+{
+ ctx->inplaceBitOp(name, value, __qmljs_shr);
+}
+
+void __qmljs_inplace_ushr_name(ExecutionContext *ctx, String *name, const Value &value)
+{
+ ctx->inplaceBitOp(name, value, __qmljs_ushr);
+}
+
+void __qmljs_inplace_bit_and_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs)
+{
+ Object *obj = base.toObject(ctx);
+ obj->inplaceBinOp(ctx, __qmljs_bit_and, index, rhs);
+}
+
+void __qmljs_inplace_bit_or_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs)
+{
+ Object *obj = base.toObject(ctx);
+ obj->inplaceBinOp(ctx, __qmljs_bit_or, index, rhs);
+}
+
+void __qmljs_inplace_bit_xor_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs)
+{
+ Object *obj = base.toObject(ctx);
+ obj->inplaceBinOp(ctx, __qmljs_bit_xor, index, rhs);
+}
+
+void __qmljs_inplace_add_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs)
+{
+ Object *obj = base.toObject(ctx);
+ obj->inplaceBinOp(ctx, __qmljs_add, index, rhs);
+}
+
+void __qmljs_inplace_sub_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs)
+{
+ Object *obj = base.toObject(ctx);
+ obj->inplaceBinOp(ctx, __qmljs_sub, index, rhs);
+}
+
+void __qmljs_inplace_mul_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs)
+{
+ Object *obj = base.toObject(ctx);
+ obj->inplaceBinOp(ctx, __qmljs_mul, index, rhs);
+}
+
+void __qmljs_inplace_div_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs)
+{
+ Object *obj = base.toObject(ctx);
+ obj->inplaceBinOp(ctx, __qmljs_div, index, rhs);
+}
+
+void __qmljs_inplace_mod_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs)
+{
+ Object *obj = base.toObject(ctx);
+ obj->inplaceBinOp(ctx, __qmljs_mod, index, rhs);
+}
+
+void __qmljs_inplace_shl_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs)
+{
+ Object *obj = base.toObject(ctx);
+ obj->inplaceBinOp(ctx, __qmljs_shl, index, rhs);
+}
+
+void __qmljs_inplace_shr_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs)
+{
+ Object *obj = base.toObject(ctx);
+ obj->inplaceBinOp(ctx, __qmljs_shr, index, rhs);
+}
+
+void __qmljs_inplace_ushr_element(ExecutionContext *ctx, const Value &base, const Value &index, const Value &rhs)
+{
+ Object *obj = base.toObject(ctx);
+ obj->inplaceBinOp(ctx, __qmljs_ushr, index, rhs);
+}
+
+void __qmljs_inplace_bit_and_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs)
+{
+ Object *o = base.toObject(ctx);
+ o->inplaceBinOp(ctx, __qmljs_bit_and, name, rhs);
+}
+
+void __qmljs_inplace_bit_or_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs)
+{
+ Object *o = base.toObject(ctx);
+ o->inplaceBinOp(ctx, __qmljs_bit_or, name, rhs);
+}
+
+void __qmljs_inplace_bit_xor_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs)
+{
+ Object *o = base.toObject(ctx);
+ o->inplaceBinOp(ctx, __qmljs_bit_xor, name, rhs);
+}
+
+void __qmljs_inplace_add_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs)
+{
+ Object *o = base.toObject(ctx);
+ o->inplaceBinOp(ctx, __qmljs_add, name, rhs);
+}
+
+void __qmljs_inplace_sub_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs)
+{
+ Object *o = base.toObject(ctx);
+ o->inplaceBinOp(ctx, __qmljs_sub, name, rhs);
+}
+
+void __qmljs_inplace_mul_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs)
+{
+ Object *o = base.toObject(ctx);
+ o->inplaceBinOp(ctx, __qmljs_mul, name, rhs);
+}
+
+void __qmljs_inplace_div_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs)
+{
+ Object *o = base.toObject(ctx);
+ o->inplaceBinOp(ctx, __qmljs_div, name, rhs);
+}
+
+void __qmljs_inplace_mod_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs)
+{
+ Object *o = base.toObject(ctx);
+ o->inplaceBinOp(ctx, __qmljs_mod, name, rhs);
+}
+
+void __qmljs_inplace_shl_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs)
+{
+ Object *o = base.toObject(ctx);
+ o->inplaceBinOp(ctx, __qmljs_shl, name, rhs);
+}
+
+void __qmljs_inplace_shr_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs)
+{
+ Object *o = base.toObject(ctx);
+ o->inplaceBinOp(ctx, __qmljs_shr, name, rhs);
+}
+
+void __qmljs_inplace_ushr_member(ExecutionContext *ctx, const Value &base, String *name, const Value &rhs)
+{
+ Object *o = base.toObject(ctx);
+ o->inplaceBinOp(ctx, __qmljs_ushr, name, rhs);
+}
+
+double __qmljs_string_to_number(const QString &string)
+{
+ QString s = string.trimmed();
+ if (s.startsWith(QLatin1String("0x")) || s.startsWith(QLatin1String("0X")))
+ return s.toLong(0, 16);
+ bool ok;
+ QByteArray ba = s.toLatin1();
+ const char *begin = ba.constData();
+ const char *end = 0;
+ double d = qstrtod(begin, &end, &ok);
+ if (end - begin != ba.size()) {
+ if (ba == "Infinity" || ba == "+Infinity")
+ d = Q_INFINITY;
+ else if (ba == "-Infinity")
+ d = -Q_INFINITY;
+ else
+ d = std::numeric_limits<double>::quiet_NaN();
+ }
+ return d;
+}
+
+Value __qmljs_string_from_number(ExecutionContext *ctx, double number)
+{
+ QString qstr;
+ __qmljs_numberToString(&qstr, number, 10);
+ String *string = ctx->engine->newString(qstr);
+ return Value::fromString(string);
+}
+
+String *__qmljs_string_concat(ExecutionContext *ctx, String *first, String *second)
+{
+ const QString &a = first->toQString();
+ const QString &b = second->toQString();
+ QString newStr(a.length() + b.length(), Qt::Uninitialized);
+ QChar *data = newStr.data();
+ memcpy(data, a.constData(), a.length()*sizeof(QChar));
+ data += a.length();
+ memcpy(data, b.constData(), b.length()*sizeof(QChar));
+
+ return ctx->engine->newString(newStr);
+}
+
+Value __qmljs_object_default_value(Object *object, int typeHint)
+{
+ if (typeHint == PREFERREDTYPE_HINT) {
+ if (object->asDateObject())
+ typeHint = STRING_HINT;
+ else
+ typeHint = NUMBER_HINT;
+ }
+
+ ExecutionEngine *engine = object->internalClass->engine;
+ String *meth1 = engine->newString("toString");
+ String *meth2 = engine->newString("valueOf");
+
+ if (typeHint == NUMBER_HINT)
+ qSwap(meth1, meth2);
+
+ ExecutionContext *ctx = engine->current;
+
+ Value conv = object->get(meth1);
+ if (FunctionObject *o = conv.asFunctionObject()) {
+ Value r = o->call(Value::fromObject(object), 0, 0);
+ if (r.isPrimitive())
+ return r;
+ }
+
+ conv = object->get(meth2);
+ if (FunctionObject *o = conv.asFunctionObject()) {
+ Value r = o->call(Value::fromObject(object), 0, 0);
+ if (r.isPrimitive())
+ return r;
+ }
+
+ ctx->throwTypeError();
+ return Value::undefinedValue();
+}
+
+Bool __qmljs_to_boolean(const Value &value)
+{
+ return value.toBoolean();
+}
+
+
+Object *__qmljs_convert_to_object(ExecutionContext *ctx, const Value &value)
+{
+ assert(!value.isObject());
+ switch (value.type()) {
+ case Value::Undefined_Type:
+ case Value::Null_Type:
+ ctx->throwTypeError();
+ case Value::Boolean_Type:
+ return ctx->engine->newBooleanObject(value);
+ case Value::String_Type:
+ return ctx->engine->newStringObject(value);
+ break;
+ case Value::Object_Type:
+ Q_UNREACHABLE();
+ case Value::Integer_Type:
+ default: // double
+ return ctx->engine->newNumberObject(value);
+ }
+}
+
+String *__qmljs_convert_to_string(ExecutionContext *ctx, const Value &value)
+{
+ switch (value.type()) {
+ case Value::Undefined_Type:
+ return ctx->engine->id_undefined;
+ case Value::Null_Type:
+ return ctx->engine->id_null;
+ case Value::Boolean_Type:
+ if (value.booleanValue())
+ return ctx->engine->id_true;
+ else
+ return ctx->engine->id_false;
+ case Value::String_Type:
+ return value.stringValue();
+ case Value::Object_Type: {
+ Value prim = __qmljs_to_primitive(value, STRING_HINT);
+ if (prim.isPrimitive())
+ return __qmljs_convert_to_string(ctx, prim);
+ else
+ ctx->throwTypeError();
+ }
+ case Value::Integer_Type:
+ return __qmljs_string_from_number(ctx, value.int_32).stringValue();
+ default: // double
+ return __qmljs_string_from_number(ctx, value.doubleValue()).stringValue();
+ } // switch
+}
+
+void __qmljs_set_property(ExecutionContext *ctx, const Value &object, String *name, const Value &value)
+{
+ Object *o = object.toObject(ctx);
+ o->put(name, value);
+}
+
+void __qmljs_get_element(ExecutionContext *ctx, Value *result, const Value &object, const Value &index)
+{
+ uint idx = index.asArrayIndex();
+
+ Object *o = object.asObject();
+ if (!o) {
+ if (idx < UINT_MAX) {
+ if (String *str = object.asString()) {
+ if (idx >= (uint)str->toQString().length()) {
+ if (result)
+ *result = Value::undefinedValue();
+ return;
+ }
+ const QString s = str->toQString().mid(idx, 1);
+ if (result)
+ *result = Value::fromString(ctx, s);
+ return;
+ }
+ }
+
+ if (object.isNull() || object.isUndefined()) {
+ QString message = QStringLiteral("Cannot read property '%1' of %2").arg(index.toQString()).arg(object.toQString());
+ ctx->throwTypeError(message);
+ }
+
+ o = __qmljs_convert_to_object(ctx, object);
+ }
+
+ if (idx < UINT_MAX) {
+ uint pidx = o->propertyIndexFromArrayIndex(idx);
+ if (pidx < UINT_MAX) {
+ if (!o->arrayAttributes || o->arrayAttributes[pidx].isData()) {
+ if (result)
+ *result = o->arrayData[pidx].value;
+ return;
+ }
+ }
+
+ Value res = o->getIndexed(idx);
+ if (result)
+ *result = res;
+ return;
+ }
+
+ String *name = index.toString(ctx);
+ Value res = o->get(name);
+ if (result)
+ *result = res;
+}
+
+void __qmljs_set_element(ExecutionContext *ctx, const Value &object, const Value &index, const Value &value)
+{
+ Object *o = object.toObject(ctx);
+
+ uint idx = index.asArrayIndex();
+ if (idx < UINT_MAX) {
+ uint pidx = o->propertyIndexFromArrayIndex(idx);
+ if (pidx < UINT_MAX) {
+ if (o->arrayAttributes && !o->arrayAttributes[pidx].isEmpty() && !o->arrayAttributes[pidx].isWritable()) {
+ if (ctx->strictMode)
+ ctx->throwTypeError();
+ return;
+ }
+
+ Property *p = o->arrayData + pidx;
+ if (!o->arrayAttributes || o->arrayAttributes[pidx].isData()) {
+ p->value = value;
+ return;
+ }
+
+ if (o->arrayAttributes[pidx].isAccessor()) {
+ FunctionObject *setter = p->setter();
+ if (!setter) {
+ if (ctx->strictMode)
+ ctx->throwTypeError();
+ return;
+ }
+
+ Value args[1];
+ args[0] = value;
+ setter->call(Value::fromObject(o), args, 1);
+ return;
+ }
+ }
+ o->putIndexed(idx, value);
+ return;
+ }
+
+ String *name = index.toString(ctx);
+ o->put(name, value);
+}
+
+void __qmljs_foreach_iterator_object(ExecutionContext *ctx, Value *result, const Value &in)
+{
+ Object *o = 0;
+ if (!in.isNull() && !in.isUndefined())
+ o = in.toObject(ctx);
+ Object *it = ctx->engine->newForEachIteratorObject(ctx, o);
+ *result = Value::fromObject(it);
+}
+
+void __qmljs_foreach_next_property_name(Value *result, const Value &foreach_iterator)
+{
+ assert(foreach_iterator.isObject());
+
+ ForEachIteratorObject *it = static_cast<ForEachIteratorObject *>(foreach_iterator.objectValue());
+ assert(it->as<ForEachIteratorObject>());
+
+ *result = it->nextPropertyName();
+}
+
+
+void __qmljs_set_activation_property(ExecutionContext *ctx, String *name, const Value &value)
+{
+ ctx->setProperty(name, value);
+}
+
+void __qmljs_get_property(ExecutionContext *ctx, Value *result, const Value &object, String *name)
+{
+ Value res;
+ Managed *m = object.asManaged();
+ if (m) {
+ res = m->get(name);
+ } else {
+ if (object.isNull() || object.isUndefined()) {
+ QString message = QStringLiteral("Cannot read property '%1' of %2").arg(name->toQString()).arg(object.toQString());
+ ctx->throwTypeError(message);
+ }
+
+ m = __qmljs_convert_to_object(ctx, object);
+ res = m->get(name);
+ }
+ if (result)
+ *result = res;
+}
+
+void __qmljs_get_activation_property(ExecutionContext *ctx, Value *result, String *name)
+{
+ *result = ctx->getProperty(name);
+}
+
+uint __qmljs_equal(const Value &x, const Value &y)
+{
+ if (x.type() == y.type()) {
+ switch (x.type()) {
+ case Value::Undefined_Type:
+ return true;
+ case Value::Null_Type:
+ return true;
+ case Value::Boolean_Type:
+ return x.booleanValue() == y.booleanValue();
+ break;
+ case Value::Integer_Type:
+ return x.integerValue() == y.integerValue();
+ case Value::String_Type:
+ return x.stringValue()->isEqualTo(y.stringValue());
+ case Value::Object_Type:
+ if (x.objectValue() == y.objectValue())
+ return true;
+ return x.objectValue()->isEqualTo(y.objectValue());
+ default: // double
+ return x.doubleValue() == y.doubleValue();
+ }
+ // unreachable
+ } else {
+ if (x.isNumber() && y.isNumber())
+ return x.asDouble() == y.asDouble();
+ if (x.isNull() && y.isUndefined()) {
+ return true;
+ } else if (x.isUndefined() && y.isNull()) {
+ return true;
+ } else if (x.isNumber() && y.isString()) {
+ Value ny = Value::fromDouble(__qmljs_to_number(y));
+ return __qmljs_equal(x, ny);
+ } else if (x.isString() && y.isNumber()) {
+ Value nx = Value::fromDouble(__qmljs_to_number(x));
+ return __qmljs_equal(nx, y);
+ } else if (x.isBoolean()) {
+ Value nx = Value::fromDouble((double) x.booleanValue());
+ return __qmljs_equal(nx, y);
+ } else if (y.isBoolean()) {
+ Value ny = Value::fromDouble((double) y.booleanValue());
+ return __qmljs_equal(x, ny);
+ } else if ((x.isNumber() || x.isString()) && y.isObject()) {
+ Value py = __qmljs_to_primitive(y, PREFERREDTYPE_HINT);
+ return __qmljs_equal(x, py);
+ } else if (x.isObject() && (y.isNumber() || y.isString())) {
+ Value px = __qmljs_to_primitive(x, PREFERREDTYPE_HINT);
+ return __qmljs_equal(px, y);
+ }
+ }
+
+ return false;
+}
+
+Bool __qmljs_strict_equal(const Value &x, const Value &y)
+{
+ TRACE2(x, y);
+
+ if (x.rawValue() == y.rawValue()) {
+ if (x.isDouble())
+ return !std::isnan(x.doubleValue());
+ return true;
+ }
+ if (x.isNumber() && y.isNumber())
+ return x.asDouble() == y.asDouble();
+ if (x.isString() && y.isString())
+ return x.stringValue()->isEqualTo(y.stringValue());
+ return false;
+}
+
+
+void __qmljs_call_global_lookup(ExecutionContext *context, Value *result, uint index, Value *args, int argc)
+{
+ Lookup *l = context->lookups + index;
+ Value v;
+ l->globalGetter(l, context, &v);
+ FunctionObject *o = v.asFunctionObject();
+ if (!o)
+ context->throwTypeError();
+
+ Value thisObject = Value::undefinedValue();
+
+ if (o == context->engine->evalFunction && l->name->isEqualTo(context->engine->id_eval)) {
+ Value res = static_cast<EvalFunction *>(o)->evalCall(thisObject, args, argc, true);
+ if (result)
+ *result = res;
+ return;
+ }
+
+ Value res = o->call(thisObject, args, argc);
+ if (result)
+ *result = res;
+}
+
+
+void __qmljs_call_activation_property(ExecutionContext *context, Value *result, String *name, Value *args, int argc)
+{
+ Object *base;
+ Value func = context->getPropertyAndBase(name, &base);
+ FunctionObject *o = func.asFunctionObject();
+ if (!o) {
+ QString objectAsString = QStringLiteral("[null]");
+ if (base)
+ objectAsString = Value::fromObject(base).toQString();
+ QString msg = QStringLiteral("Property '%1' of object %2 is not a function").arg(name->toQString()).arg(objectAsString);
+ context->throwTypeError(msg);
+ }
+
+ Value thisObject = base ? Value::fromObject(base) : Value::undefinedValue();
+
+ if (o == context->engine->evalFunction && name->isEqualTo(context->engine->id_eval)) {
+ Value res = static_cast<EvalFunction *>(o)->evalCall(thisObject, args, argc, true);
+ if (result)
+ *result = res;
+ return;
+ }
+
+ Value res = o->call(thisObject, args, argc);
+ if (result)
+ *result = res;
+}
+
+void __qmljs_call_property(ExecutionContext *context, Value *result, const Value &thatObject, String *name, Value *args, int argc)
+{
+ Value thisObject = thatObject;
+ Managed *baseObject = thisObject.asManaged();
+ if (!baseObject) {
+ if (thisObject.isNull() || thisObject.isUndefined()) {
+ QString message = QStringLiteral("Cannot call method '%1' of %2").arg(name->toQString()).arg(thisObject.toQString());
+ context->throwTypeError(message);
+ }
+
+ baseObject = __qmljs_convert_to_object(context, thisObject);
+ thisObject = Value::fromObject(static_cast<Object *>(baseObject));
+ }
+
+ Value func = baseObject->get(name);
+ FunctionObject *o = func.asFunctionObject();
+ if (!o) {
+ QString error = QString("Property '%1' of object %2 is not a function").arg(name->toQString(), thisObject.toQString());
+ context->throwTypeError(error);
+ }
+
+ Value res = o->call(thisObject, args, argc);
+ if (result)
+ *result = res;
+}
+
+void __qmljs_call_property_lookup(ExecutionContext *context, Value *result, const Value &thisObject, uint index, Value *args, int argc)
+{
+ Lookup *l = context->lookups + index;
+
+ Object *baseObject;
+ if (thisObject.isObject())
+ baseObject = thisObject.objectValue();
+ else if (thisObject.isString())
+ baseObject = context->engine->stringPrototype;
+ else
+ baseObject = __qmljs_convert_to_object(context, thisObject);
+
+ PropertyAttributes attrs;
+ Property *p = l->lookup(baseObject, &attrs);
+ if (!p)
+ context->throwTypeError();
+ Value func = attrs.isData() ? p->value : baseObject->getValue(p, attrs);
+ FunctionObject *o = func.asFunctionObject();
+ if (!o)
+ context->throwTypeError();
+
+ Value res = o->call(thisObject, args, argc);
+ if (result)
+ *result = res;
+}
+
+void __qmljs_call_element(ExecutionContext *context, Value *result, const Value &that, const Value &index, Value *args, int argc)
+{
+ Object *baseObject = that.toObject(context);
+ Value thisObject = Value::fromObject(baseObject);
+
+ Value func = baseObject->get(index.toString(context));
+ Object *o = func.asObject();
+ if (!o)
+ context->throwTypeError();
+
+ Value res = o->call(thisObject, args, argc);
+ if (result)
+ *result = res;
+}
+
+void __qmljs_call_value(ExecutionContext *context, Value *result, const Value *thisObject, const Value &func, Value *args, int argc)
+{
+ Object *o = func.asObject();
+ if (!o)
+ context->throwTypeError();
+ Value res = o->call(thisObject ? *thisObject : Value::undefinedValue(), args, argc);
+ if (result)
+ *result = res;
+}
+
+
+void __qmljs_construct_global_lookup(ExecutionContext *context, Value *result, uint index, Value *args, int argc)
+{
+ Lookup *l = context->lookups + index;
+ Value func;
+ l->globalGetter(l, context, &func);
+
+ if (Object *f = func.asObject()) {
+ Value res = f->construct(args, argc);
+ if (result)
+ *result = res;
+ return;
+ }
+
+ context->throwTypeError();
+}
+
+
+void __qmljs_construct_activation_property(ExecutionContext *context, Value *result, String *name, Value *args, int argc)
+{
+ Value func = context->getProperty(name);
+ __qmljs_construct_value(context, result, func, args, argc);
+}
+
+void __qmljs_construct_value(ExecutionContext *context, Value *result, const Value &func, Value *args, int argc)
+{
+ if (Object *f = func.asObject()) {
+ Value res = f->construct(args, argc);
+ if (result)
+ *result = res;
+ return;
+ }
+
+ context->throwTypeError();
+}
+
+void __qmljs_construct_property(ExecutionContext *context, Value *result, const Value &base, String *name, Value *args, int argc)
+{
+ Object *thisObject = base.toObject(context);
+
+ Value func = thisObject->get(name);
+ if (Object *f = func.asObject()) {
+ Value res = f->construct(args, argc);
+ if (result)
+ *result = res;
+ return;
+ }
+
+ context->throwTypeError();
+}
+
+void __qmljs_throw(ExecutionContext *context, const Value &value)
+{
+ Exception::throwException(context, value);
+}
+
+void __qmljs_builtin_typeof(ExecutionContext *ctx, Value *result, const Value &value)
+{
+ if (!result)
+ return;
+ String *res = 0;
+ switch (value.type()) {
+ case Value::Undefined_Type:
+ res = ctx->engine->id_undefined;
+ break;
+ case Value::Null_Type:
+ res = ctx->engine->id_object;
+ break;
+ case Value::Boolean_Type:
+ res = ctx->engine->id_boolean;
+ break;
+ case Value::String_Type:
+ res = ctx->engine->id_string;
+ break;
+ case Value::Object_Type:
+ if (value.objectValue()->asFunctionObject())
+ res = ctx->engine->id_function;
+ else
+ res = ctx->engine->id_object; // ### implementation-defined
+ break;
+ default:
+ res = ctx->engine->id_number;
+ break;
+ }
+ *result = Value::fromString(res);
+}
+
+void __qmljs_builtin_typeof_name(ExecutionContext *context, Value *result, String *name)
+{
+ Value res;
+ __qmljs_builtin_typeof(context, &res, context->getPropertyNoThrow(name));
+ if (result)
+ *result = res;
+}
+
+void __qmljs_builtin_typeof_member(ExecutionContext *context, Value *result, const Value &base, String *name)
+{
+ Object *obj = base.toObject(context);
+ Value res;
+ __qmljs_builtin_typeof(context, &res, obj->get(name));
+ if (result)
+ *result = res;
+}
+
+void __qmljs_builtin_typeof_element(ExecutionContext *context, Value *result, const Value &base, const Value &index)
+{
+ String *name = index.toString(context);
+ Object *obj = base.toObject(context);
+ Value res;
+ __qmljs_builtin_typeof(context, &res, obj->get(name));
+ if (result)
+ *result = res;
+}
+
+void __qmljs_builtin_post_increment(Value *result, Value *val)
+{
+ if (val->isInteger() && val->integerValue() < INT_MAX) {
+ if (result)
+ *result = *val;
+ val->int_32 += 1;
+ return;
+ }
+
+ double d = __qmljs_to_number(*val);
+ *val = Value::fromDouble(d + 1);
+ if (result)
+ *result = Value::fromDouble(d);
+}
+
+void __qmljs_builtin_post_increment_name(ExecutionContext *context, Value *result, String *name)
+{
+ Value v = context->getProperty(name);
+
+ if (v.isInteger() && v.integerValue() < INT_MAX) {
+ if (result)
+ *result = v;
+ v.int_32 += 1;
+ } else {
+ double d = __qmljs_to_number(v);
+ if (result)
+ *result = Value::fromDouble(d);
+ v = Value::fromDouble(d + 1);
+ }
+
+ context->setProperty(name, v);
+}
+
+void __qmljs_builtin_post_increment_member(ExecutionContext *context, Value *result, const Value &base, String *name)
+{
+ Object *o = base.toObject(context);
+
+ Value v = o->get(name);
+
+ if (v.isInteger() && v.integerValue() < INT_MAX) {
+ if (result)
+ *result = v;
+ v.int_32 += 1;
+ } else {
+ double d = __qmljs_to_number(v);
+ if (result)
+ *result = Value::fromDouble(d);
+ v = Value::fromDouble(d + 1);
+ }
+
+ o->put(name, v);
+}
+
+void __qmljs_builtin_post_increment_element(ExecutionContext *context, Value *result, const Value &base, const Value *index)
+{
+ Object *o = base.toObject(context);
+
+ uint idx = index->asArrayIndex();
+
+ if (idx == UINT_MAX) {
+ String *s = index->toString(context);
+ return __qmljs_builtin_post_increment_member(context, result, base, s);
+ }
+
+ Value v = o->getIndexed(idx);
+
+ if (v.isInteger() && v.integerValue() < INT_MAX) {
+ if (result)
+ *result = v;
+ v.int_32 += 1;
+ } else {
+ double d = __qmljs_to_number(v);
+ if (result)
+ *result = Value::fromDouble(d);
+ v = Value::fromDouble(d + 1);
+ }
+
+ o->putIndexed(idx, v);
+}
+
+void __qmljs_builtin_post_decrement(Value *result, Value *val)
+{
+ if (val->isInteger() && val->integerValue() > INT_MIN) {
+ if (result)
+ *result = *val;
+ val->int_32 -= 1;
+ return;
+ }
+
+ double d = __qmljs_to_number(*val);
+ *val = Value::fromDouble(d - 1);
+ if (result)
+ *result = Value::fromDouble(d);
+}
+
+void __qmljs_builtin_post_decrement_name(ExecutionContext *context, Value *result, String *name)
+{
+ Value v = context->getProperty(name);
+
+ if (v.isInteger() && v.integerValue() > INT_MIN) {
+ if (result)
+ *result = v;
+ v.int_32 -= 1;
+ } else {
+ double d = __qmljs_to_number(v);
+ if (result)
+ *result = Value::fromDouble(d);
+ v = Value::fromDouble(d - 1);
+ }
+
+ context->setProperty(name, v);
+}
+
+void __qmljs_builtin_post_decrement_member(ExecutionContext *context, Value *result, const Value &base, String *name)
+{
+ Object *o = base.toObject(context);
+
+ Value v = o->get(name);
+
+ if (v.isInteger() && v.integerValue() > INT_MIN) {
+ if (result)
+ *result = v;
+ v.int_32 -= 1;
+ } else {
+ double d = __qmljs_to_number(v);
+ if (result)
+ *result = Value::fromDouble(d);
+ v = Value::fromDouble(d - 1);
+ }
+
+ o->put(name, v);
+}
+
+void __qmljs_builtin_post_decrement_element(ExecutionContext *context, Value *result, const Value &base, const Value &index)
+{
+ Object *o = base.toObject(context);
+
+ uint idx = index.asArrayIndex();
+
+ if (idx == UINT_MAX) {
+ String *s = index.toString(context);
+ return __qmljs_builtin_post_decrement_member(context, result, base, s);
+ }
+
+ Value v = o->getIndexed(idx);
+
+ if (v.isInteger() && v.integerValue() > INT_MIN) {
+ if (result)
+ *result = v;
+ v.int_32 -= 1;
+ } else {
+ double d = __qmljs_to_number(v);
+ if (result)
+ *result = Value::fromDouble(d);
+ v = Value::fromDouble(d - 1);
+ }
+
+ o->putIndexed(idx, v);
+}
+
+ExecutionContext *__qmljs_builtin_push_with_scope(const Value &o, ExecutionContext *ctx)
+{
+ Object *obj = o.toObject(ctx);
+ return ctx->engine->newWithContext(obj);
+}
+
+ExecutionContext *__qmljs_builtin_push_catch_scope(String *exceptionVarName, const Value &exceptionValue, ExecutionContext *ctx)
+{
+ return ctx->engine->newCatchContext(exceptionVarName, exceptionValue);
+}
+
+ExecutionContext *__qmljs_builtin_pop_scope(ExecutionContext *ctx)
+{
+ return ctx->engine->popContext();
+}
+
+void __qmljs_builtin_declare_var(ExecutionContext *ctx, bool deletable, String *name)
+{
+ ctx->createMutableBinding(name, deletable);
+}
+
+void __qmljs_builtin_define_property(ExecutionContext *ctx, const Value &object, String *name, Value *val)
+{
+ Object *o = object.asObject();
+ assert(o);
+
+ uint idx = name->asArrayIndex();
+ Property *pd = (idx != UINT_MAX) ? o->arrayInsert(idx) : o->insertMember(name, Attr_Data);
+ pd->value = val ? *val : Value::undefinedValue();
+}
+
+void __qmljs_builtin_define_array(ExecutionContext *ctx, Value *array, Value *values, uint length)
+{
+ ArrayObject *a = ctx->engine->newArrayObject();
+
+ // ### FIXME: We need to allocate the array data to avoid crashes other places
+ // This should rather be done when required
+ a->arrayReserve(length);
+ if (length) {
+ a->arrayDataLen = length;
+ Property *pd = a->arrayData;
+ for (uint i = 0; i < length; ++i) {
+ if (values[i].isEmpty()) {
+ a->ensureArrayAttributes();
+ pd->value = Value::undefinedValue();
+ a->arrayAttributes[i].clear();
+ } else {
+ pd->value = values[i];
+ }
+ ++pd;
+ }
+ a->setArrayLengthUnchecked(length);
+ }
+ *array = Value::fromObject(a);
+}
+
+void __qmljs_builtin_define_getter_setter(ExecutionContext *ctx, const Value &object, String *name, const Value *getter, const Value *setter)
+{
+ Object *o = object.asObject();
+ assert(o);
+
+ uint idx = name->asArrayIndex();
+ Property *pd = (idx != UINT_MAX) ? o->arrayInsert(idx, Attr_Accessor) : o->insertMember(name, Attr_Accessor);
+ pd->setGetter(getter ? getter->asFunctionObject() : 0);
+ pd->setSetter(setter ? setter->asFunctionObject() : 0);
+}
+
+void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value *args, QV4::InternalClass *klass)
+{
+ Object *o = ctx->engine->newObject(klass);
+
+ for (int i = 0; i < klass->size; ++i) {
+ if (klass->propertyData[i].isData())
+ o->memberData[i].value = *args++;
+ else {
+ o->memberData[i].setGetter(args->asFunctionObject());
+ args++;
+ o->memberData[i].setSetter(args->asFunctionObject());
+ args++;
+ }
+ }
+
+ *result = Value::fromObject(o);
+}
+
+void __qmljs_increment(Value *result, const Value &value)
+{
+ TRACE1(value);
+
+ if (value.isInteger())
+ *result = Value::fromInt32(value.integerValue() + 1);
+ else {
+ double d = __qmljs_to_number(value);
+ *result = Value::fromDouble(d + 1);
+ }
+}
+
+void __qmljs_decrement(Value *result, const Value &value)
+{
+ TRACE1(value);
+
+ if (value.isInteger())
+ *result = Value::fromInt32(value.integerValue() - 1);
+ else {
+ double d = __qmljs_to_number(value);
+ *result = Value::fromDouble(d - 1);
+ }
+}
+
+} // namespace QV4
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4runtime_p.h b/src/qml/qml/v4/qv4runtime_p.h
new file mode 100644
index 0000000000..e6e6e0f3a0
--- /dev/null
+++ b/src/qml/qml/v4/qv4runtime_p.h
@@ -0,0 +1,717 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QMLJS_RUNTIME_H
+#define QMLJS_RUNTIME_H
+
+#include "qv4global_p.h"
+#include "qv4value_p.h"
+#include "qv4math_p.h"
+
+
+#include <QtCore/QString>
+#include <QtCore/qnumeric.h>
+#include <QtCore/QDebug>
+#include <QtCore/qurl.h>
+
+#include <cmath>
+#include <cassert>
+#include <limits>
+
+//#include <wtf/MathExtras.h>
+
+#ifdef DO_TRACE_INSTR
+# define TRACE1(x) fprintf(stderr, " %s\n", __FUNCTION__);
+# define TRACE2(x, y) fprintf(stderr, " %s\n", __FUNCTION__);
+#else
+# define TRACE1(x)
+# define TRACE2(x, y)
+#endif // TRACE1
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+enum TypeHint {
+ PREFERREDTYPE_HINT,
+ NUMBER_HINT,
+ STRING_HINT
+};
+
+struct Function;
+struct Object;
+struct String;
+struct ExecutionContext;
+struct FunctionObject;
+struct BooleanObject;
+struct NumberObject;
+struct StringObject;
+struct DateObject;
+struct RegExpObject;
+struct ArrayObject;
+struct ErrorObject;
+struct ExecutionEngine;
+struct InternalClass;
+
+// context
+void __qmljs_call_activation_property(QV4::ExecutionContext *, QV4::Value *result, QV4::String *name, QV4::Value *args, int argc);
+void __qmljs_call_property(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &that, QV4::String *name, QV4::Value *args, int argc);
+void __qmljs_call_property_lookup(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &thisObject, uint index, QV4::Value *args, int argc);
+void __qmljs_call_element(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &that, const QV4::Value &index, QV4::Value *args, int argc);
+void __qmljs_call_value(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value *thisObject, const QV4::Value &func, QV4::Value *args, int argc);
+
+void __qmljs_construct_activation_property(QV4::ExecutionContext *, QV4::Value *result, QV4::String *name, QV4::Value *args, int argc);
+void __qmljs_construct_property(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &base, QV4::String *name, QV4::Value *args, int argc);
+void __qmljs_construct_value(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &func, QV4::Value *args, int argc);
+
+void __qmljs_builtin_typeof(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &val);
+void __qmljs_builtin_typeof_name(QV4::ExecutionContext *context, QV4::Value* result, QV4::String *name);
+void __qmljs_builtin_typeof_member(QV4::ExecutionContext* context, QV4::Value* result, const QV4::Value &base, QV4::String *name);
+void __qmljs_builtin_typeof_element(QV4::ExecutionContext* context, QV4::Value *result, const QV4::Value &base, const QV4::Value &index);
+
+void __qmljs_builtin_post_increment(QV4::Value *result, QV4::Value *val);
+void __qmljs_builtin_post_increment_name(QV4::ExecutionContext *context, QV4::Value *result, QV4::String *name);
+void __qmljs_builtin_post_increment_member(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &base, QV4::String *name);
+void __qmljs_builtin_post_increment_element(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &base, const QV4::Value *index);
+
+void __qmljs_builtin_post_decrement(QV4::Value *result, QV4::Value *val);
+void __qmljs_builtin_post_decrement_name(QV4::ExecutionContext *context, QV4::Value *result, QV4::String *name);
+void __qmljs_builtin_post_decrement_member(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &base, QV4::String *name);
+void __qmljs_builtin_post_decrement_element(QV4::ExecutionContext *context, QV4::Value *result, const QV4::Value &base, const QV4::Value &index);
+
+void Q_NORETURN __qmljs_builtin_rethrow(QV4::ExecutionContext *context);
+QV4::ExecutionContext *__qmljs_builtin_push_with_scope(const QV4::Value &o, QV4::ExecutionContext *ctx);
+QV4::ExecutionContext *__qmljs_builtin_push_catch_scope(QV4::String *exceptionVarName, const QV4::Value &exceptionValue, QV4::ExecutionContext *ctx);
+QV4::ExecutionContext *__qmljs_builtin_pop_scope(QV4::ExecutionContext *ctx);
+void __qmljs_builtin_declare_var(QV4::ExecutionContext *ctx, bool deletable, QV4::String *name);
+void __qmljs_builtin_define_property(QV4::ExecutionContext *ctx, const QV4::Value &object, QV4::String *name, QV4::Value *val);
+void __qmljs_builtin_define_array(QV4::ExecutionContext *ctx, QV4::Value *array, QV4::Value *values, uint length);
+void __qmljs_builtin_define_getter_setter(QV4::ExecutionContext *ctx, const QV4::Value &object, QV4::String *name, const QV4::Value *getter, const QV4::Value *setter);
+void __qmljs_builtin_define_object_literal(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value *args, QV4::InternalClass *klass);
+
+// constructors
+void __qmljs_init_closure(QV4::ExecutionContext *ctx, QV4::Value *result, QV4::Function *clos);
+QV4::Function *__qmljs_register_function(QV4::ExecutionContext *ctx, QV4::String *name,
+ bool hasDirectEval,
+ bool usesArgumentsObject, bool isStrict,
+ bool hasNestedFunctions,
+ QV4::String **formals, unsigned formalCount,
+ QV4::String **locals, unsigned localCount);
+
+// strings
+Q_QML_EXPORT double __qmljs_string_to_number(const QString &s);
+QV4::Value __qmljs_string_from_number(QV4::ExecutionContext *ctx, double number);
+QV4::String *__qmljs_string_concat(QV4::ExecutionContext *ctx, QV4::String *first, QV4::String *second);
+
+// objects
+Q_QML_EXPORT QV4::Value __qmljs_object_default_value(QV4::Object *object, int typeHint);
+void __qmljs_set_activation_property(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value& value);
+void __qmljs_set_property(QV4::ExecutionContext *ctx, const QV4::Value &object, QV4::String *name, const QV4::Value &value);
+void __qmljs_get_property(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &object, QV4::String *name);
+void __qmljs_get_activation_property(QV4::ExecutionContext *ctx, QV4::Value *result, QV4::String *name);
+
+void __qmljs_call_global_lookup(QV4::ExecutionContext *context, QV4::Value *result, uint index, QV4::Value *args, int argc);
+void __qmljs_construct_global_lookup(QV4::ExecutionContext *context, QV4::Value *result, uint index, QV4::Value *args, int argc);
+
+
+void __qmljs_get_element(QV4::ExecutionContext *ctx, QV4::Value *retval, const QV4::Value &object, const QV4::Value &index);
+void __qmljs_set_element(QV4::ExecutionContext *ctx, const QV4::Value &object, const QV4::Value &index, const QV4::Value &value);
+
+// For each
+void __qmljs_foreach_iterator_object(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &in);
+void __qmljs_foreach_next_property_name(QV4::Value *result, const QV4::Value &foreach_iterator);
+
+// type conversion and testing
+QV4::Value __qmljs_to_primitive(const QV4::Value &value, int typeHint);
+QV4::Bool __qmljs_to_boolean(const QV4::Value &value);
+double __qmljs_to_number(const QV4::Value &value);
+QV4::Value __qmljs_to_string(const QV4::Value &value, QV4::ExecutionContext *ctx);
+Q_QML_EXPORT QV4::String *__qmljs_convert_to_string(QV4::ExecutionContext *ctx, const QV4::Value &value);
+void __qmljs_numberToString(QString *result, double num, int radix = 10);
+QV4::Value __qmljs_to_object(QV4::ExecutionContext *ctx, const QV4::Value &value);
+QV4::Object *__qmljs_convert_to_object(QV4::ExecutionContext *ctx, const QV4::Value &value);
+
+QV4::Bool __qmljs_equal(const QV4::Value &x, const QV4::Value &y);
+Q_QML_EXPORT QV4::Bool __qmljs_strict_equal(const QV4::Value &x, const QV4::Value &y);
+
+// unary operators
+typedef void (*UnaryOpName)(QV4::Value *, const QV4::Value &);
+void __qmljs_uplus(QV4::Value *result, const QV4::Value &value);
+void __qmljs_uminus(QV4::Value *result, const QV4::Value &value);
+void __qmljs_compl(QV4::Value *result, const QV4::Value &value);
+void __qmljs_not(QV4::Value *result, const QV4::Value &value);
+void __qmljs_increment(QV4::Value *result, const QV4::Value &value);
+void __qmljs_decrement(QV4::Value *result, const QV4::Value &value);
+
+void __qmljs_delete_subscript(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &base, const QV4::Value &index);
+void __qmljs_delete_member(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &base, QV4::String *name);
+void __qmljs_delete_name(QV4::ExecutionContext *ctx, QV4::Value *result, QV4::String *name);
+
+void Q_NORETURN __qmljs_throw(QV4::ExecutionContext*, const QV4::Value &value);
+
+// binary operators
+typedef void (*BinOp)(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+
+void __qmljs_instanceof(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_in(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_bit_or(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_bit_xor(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_bit_and(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_add(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_sub(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_mul(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_div(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_mod(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_shl(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_shr(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_ushr(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_gt(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_lt(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_ge(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_le(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_eq(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_ne(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_se(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+void __qmljs_sne(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+
+void __qmljs_add_helper(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right);
+
+
+typedef void (*InplaceBinOpName)(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value);
+void __qmljs_inplace_bit_and_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value);
+void __qmljs_inplace_bit_or_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value);
+void __qmljs_inplace_bit_xor_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value);
+void __qmljs_inplace_add_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value);
+void __qmljs_inplace_sub_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value);
+void __qmljs_inplace_mul_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value);
+void __qmljs_inplace_div_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value);
+void __qmljs_inplace_mod_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value);
+void __qmljs_inplace_shl_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value);
+void __qmljs_inplace_shr_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value);
+void __qmljs_inplace_ushr_name(QV4::ExecutionContext *ctx, QV4::String *name, const QV4::Value &value);
+
+typedef void (*InplaceBinOpElement)(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs);
+void __qmljs_inplace_bit_and_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs);
+void __qmljs_inplace_bit_or_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs);
+void __qmljs_inplace_bit_xor_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs);
+void __qmljs_inplace_add_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs);
+void __qmljs_inplace_sub_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs);
+void __qmljs_inplace_mul_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs);
+void __qmljs_inplace_div_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs);
+void __qmljs_inplace_mod_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs);
+void __qmljs_inplace_shl_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs);
+void __qmljs_inplace_shr_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs);
+void __qmljs_inplace_ushr_element(QV4::ExecutionContext *ctx, const QV4::Value &base, const QV4::Value &index, const QV4::Value &rhs);
+
+typedef void (*InplaceBinOpMember)(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs);
+void __qmljs_inplace_bit_and_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs);
+void __qmljs_inplace_bit_or_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs);
+void __qmljs_inplace_bit_xor_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs);
+void __qmljs_inplace_add_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs);
+void __qmljs_inplace_sub_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs);
+void __qmljs_inplace_mul_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs);
+void __qmljs_inplace_div_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs);
+void __qmljs_inplace_mod_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs);
+void __qmljs_inplace_shl_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs);
+void __qmljs_inplace_shr_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs);
+void __qmljs_inplace_ushr_member(QV4::ExecutionContext *ctx, const QV4::Value &base, QV4::String *name, const QV4::Value &rhs);
+
+typedef QV4::Bool (*CmpOp)(QV4::ExecutionContext *ctx, const QV4::Value &left, const QV4::Value &right);
+QV4::Bool __qmljs_cmp_gt(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right);
+QV4::Bool __qmljs_cmp_lt(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right);
+QV4::Bool __qmljs_cmp_ge(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right);
+QV4::Bool __qmljs_cmp_le(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right);
+QV4::Bool __qmljs_cmp_eq(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right);
+QV4::Bool __qmljs_cmp_ne(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right);
+QV4::Bool __qmljs_cmp_se(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right);
+QV4::Bool __qmljs_cmp_sne(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right);
+QV4::Bool __qmljs_cmp_instanceof(QV4::ExecutionContext *ctx, const QV4::Value &left, const QV4::Value &right);
+QV4::Bool __qmljs_cmp_in(QV4::ExecutionContext *ctx, const QV4::Value &left, const QV4::Value &right);
+
+// type conversion and testing
+inline QV4::Value __qmljs_to_primitive(const QV4::Value &value, int typeHint)
+{
+ QV4::Object *o = value.asObject();
+ if (!o)
+ return value;
+ return __qmljs_object_default_value(o, typeHint);
+}
+
+inline double __qmljs_to_number(const QV4::Value &value)
+{
+ switch (value.type()) {
+ case QV4::Value::Undefined_Type:
+ return std::numeric_limits<double>::quiet_NaN();
+ case QV4::Value::Null_Type:
+ return 0;
+ case QV4::Value::Boolean_Type:
+ return (value.booleanValue() ? 1. : 0.);
+ case QV4::Value::Integer_Type:
+ return value.int_32;
+ case QV4::Value::String_Type:
+ return __qmljs_string_to_number(value.stringValue()->toQString());
+ case QV4::Value::Object_Type: {
+ QV4::Value prim = __qmljs_to_primitive(value, QV4::NUMBER_HINT);
+ return __qmljs_to_number(prim);
+ }
+ default: // double
+ return value.doubleValue();
+ }
+}
+
+inline QV4::Value __qmljs_to_string(const QV4::Value &value, QV4::ExecutionContext *ctx)
+{
+ if (value.isString())
+ return value;
+ return QV4::Value::fromString(__qmljs_convert_to_string(ctx, value));
+}
+
+inline QV4::Value __qmljs_to_object(QV4::ExecutionContext *ctx, const QV4::Value &value)
+{
+ if (value.isObject())
+ return value;
+ return QV4::Value::fromObject(__qmljs_convert_to_object(ctx, value));
+}
+
+
+inline void __qmljs_uplus(QV4::Value *result, const QV4::Value &value)
+{
+ TRACE1(value);
+
+ *result = value;
+ if (result->tryIntegerConversion())
+ return;
+
+ double n = __qmljs_to_number(value);
+ *result = QV4::Value::fromDouble(n);
+}
+
+inline void __qmljs_uminus(QV4::Value *result, const QV4::Value &value)
+{
+ TRACE1(value);
+
+ // +0 != -0, so we need to convert to double when negating 0
+ if (value.isInteger() && value.integerValue())
+ *result = QV4::Value::fromInt32(-value.integerValue());
+ else {
+ double n = __qmljs_to_number(value);
+ *result = QV4::Value::fromDouble(-n);
+ }
+}
+
+inline void __qmljs_compl(QV4::Value *result, const QV4::Value &value)
+{
+ TRACE1(value);
+
+ int n;
+ if (value.isConvertibleToInt())
+ n = value.int_32;
+ else
+ n = QV4::Value::toInt32(__qmljs_to_number(value));
+
+ *result = QV4::Value::fromInt32(~n);
+}
+
+inline void __qmljs_not(QV4::Value *result, const QV4::Value &value)
+{
+ TRACE1(value);
+
+ bool b = value.toBoolean();
+ *result = QV4::Value::fromBoolean(!b);
+}
+
+// binary operators
+inline void __qmljs_bit_or(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ if (QV4::Value::integerCompatible(left, right)) {
+ *result = QV4::Value::fromInt32(left.integerValue() | right.integerValue());
+ return;
+ }
+
+ int lval = QV4::Value::toInt32(__qmljs_to_number(left));
+ int rval = QV4::Value::toInt32(__qmljs_to_number(right));
+ *result = QV4::Value::fromInt32(lval | rval);
+}
+
+inline void __qmljs_bit_xor(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ if (QV4::Value::integerCompatible(left, right)) {
+ *result = QV4::Value::fromInt32(left.integerValue() ^ right.integerValue());
+ return;
+ }
+
+ int lval = QV4::Value::toInt32(__qmljs_to_number(left));
+ int rval = QV4::Value::toInt32(__qmljs_to_number(right));
+ *result = QV4::Value::fromInt32(lval ^ rval);
+}
+
+inline void __qmljs_bit_and(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ if (QV4::Value::integerCompatible(left, right)) {
+ *result = QV4::Value::fromInt32(left.integerValue() & right.integerValue());
+ return;
+ }
+
+ int lval = QV4::Value::toInt32(__qmljs_to_number(left));
+ int rval = QV4::Value::toInt32(__qmljs_to_number(right));
+ *result = QV4::Value::fromInt32(lval & rval);
+}
+
+inline void __qmljs_add(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ if (QV4::Value::integerCompatible(left, right)) {
+ *result = add_int32(left.integerValue(), right.integerValue());
+ return;
+ }
+
+ if (QV4::Value::bothDouble(left, right)) {
+ *result = QV4::Value::fromDouble(left.doubleValue() + right.doubleValue());
+ return;
+ }
+
+ __qmljs_add_helper(ctx, result, left, right);
+}
+
+inline void __qmljs_sub(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ if (QV4::Value::integerCompatible(left, right)) {
+ *result = sub_int32(left.integerValue(), right.integerValue());
+ return;
+ }
+
+ double lval = __qmljs_to_number(left);
+ double rval = __qmljs_to_number(right);
+ *result = QV4::Value::fromDouble(lval - rval);
+}
+
+inline void __qmljs_mul(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ if (QV4::Value::integerCompatible(left, right)) {
+ *result = mul_int32(left.integerValue(), right.integerValue());
+ return;
+ }
+
+ double lval = __qmljs_to_number(left);
+ double rval = __qmljs_to_number(right);
+ *result = QV4::Value::fromDouble(lval * rval);
+}
+
+inline void __qmljs_div(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ double lval = __qmljs_to_number(left);
+ double rval = __qmljs_to_number(right);
+ *result = QV4::Value::fromDouble(lval / rval);
+}
+
+inline void __qmljs_mod(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ if (QV4::Value::integerCompatible(left, right) && right.integerValue() != 0) {
+ int intRes = left.integerValue() % right.integerValue();
+ if (intRes != 0 || left.integerValue() >= 0) {
+ *result = QV4::Value::fromInt32(intRes);
+ return;
+ }
+ }
+
+ double lval = __qmljs_to_number(left);
+ double rval = __qmljs_to_number(right);
+ *result = QV4::Value::fromDouble(std::fmod(lval, rval));
+}
+
+inline void __qmljs_shl(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ if (QV4::Value::integerCompatible(left, right)) {
+ *result = QV4::Value::fromInt32(left.integerValue() << ((uint(right.integerValue()) & 0x1f)));
+ return;
+ }
+
+ int lval = QV4::Value::toInt32(__qmljs_to_number(left));
+ unsigned rval = QV4::Value::toUInt32(__qmljs_to_number(right)) & 0x1f;
+ *result = QV4::Value::fromInt32(lval << rval);
+}
+
+inline void __qmljs_shr(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ if (QV4::Value::integerCompatible(left, right)) {
+ *result = QV4::Value::fromInt32(left.integerValue() >> ((uint(right.integerValue()) & 0x1f)));
+ return;
+ }
+
+ int lval = QV4::Value::toInt32(__qmljs_to_number(left));
+ unsigned rval = QV4::Value::toUInt32(__qmljs_to_number(right)) & 0x1f;
+ *result = QV4::Value::fromInt32(lval >> rval);
+}
+
+inline void __qmljs_ushr(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ uint res;
+ if (QV4::Value::integerCompatible(left, right)) {
+ res = uint(left.integerValue()) >> (uint(right.integerValue()) & 0x1f);
+ } else {
+ unsigned lval = QV4::Value::toUInt32(__qmljs_to_number(left));
+ unsigned rval = QV4::Value::toUInt32(__qmljs_to_number(right)) & 0x1f;
+ res = lval >> rval;
+ }
+
+ if (res > INT_MAX)
+ *result = QV4::Value::fromDouble(res);
+ else
+ *result = QV4::Value::fromInt32(res);
+}
+
+inline void __qmljs_gt(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ *result = QV4::Value::fromBoolean(__qmljs_cmp_gt(ctx, left, right));
+}
+
+inline void __qmljs_lt(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ *result = QV4::Value::fromBoolean(__qmljs_cmp_lt(ctx, left, right));
+}
+
+inline void __qmljs_ge(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ *result = QV4::Value::fromBoolean(__qmljs_cmp_ge(ctx, left, right));
+}
+
+inline void __qmljs_le(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ *result = QV4::Value::fromBoolean(__qmljs_cmp_le(ctx, left, right));
+}
+
+inline void __qmljs_eq(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ *result = QV4::Value::fromBoolean(__qmljs_cmp_eq(ctx, left, right));
+}
+
+inline void __qmljs_ne(QV4::ExecutionContext *ctx, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ *result = QV4::Value::fromBoolean(!__qmljs_cmp_eq(ctx, left, right));
+}
+
+inline void __qmljs_se(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ bool r = __qmljs_strict_equal(left, right);
+ *result = QV4::Value::fromBoolean(r);
+}
+
+inline void __qmljs_sne(QV4::ExecutionContext *, QV4::Value *result, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ bool r = ! __qmljs_strict_equal(left, right);
+ *result = QV4::Value::fromBoolean(r);
+}
+
+inline QV4::Bool __qmljs_cmp_gt(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+ if (QV4::Value::integerCompatible(left, right))
+ return left.integerValue() > right.integerValue();
+
+ QV4::Value l = __qmljs_to_primitive(left, QV4::NUMBER_HINT);
+ QV4::Value r = __qmljs_to_primitive(right, QV4::NUMBER_HINT);
+
+ if (QV4::Value::bothDouble(l, r)) {
+ return l.doubleValue() > r.doubleValue();
+ } else if (l.isString() && r.isString()) {
+ return r.stringValue()->compare(l.stringValue());
+ } else {
+ double dl = __qmljs_to_number(l);
+ double dr = __qmljs_to_number(r);
+ return dl > dr;
+ }
+}
+
+inline QV4::Bool __qmljs_cmp_lt(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+ if (QV4::Value::integerCompatible(left, right))
+ return left.integerValue() < right.integerValue();
+
+ QV4::Value l = __qmljs_to_primitive(left, QV4::NUMBER_HINT);
+ QV4::Value r = __qmljs_to_primitive(right, QV4::NUMBER_HINT);
+
+ if (QV4::Value::bothDouble(l, r)) {
+ return l.doubleValue() < r.doubleValue();
+ } else if (l.isString() && r.isString()) {
+ return l.stringValue()->compare(r.stringValue());
+ } else {
+ double dl = __qmljs_to_number(l);
+ double dr = __qmljs_to_number(r);
+ return dl < dr;
+ }
+}
+
+inline QV4::Bool __qmljs_cmp_ge(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+ if (QV4::Value::integerCompatible(left, right))
+ return left.integerValue() >= right.integerValue();
+
+ QV4::Value l = __qmljs_to_primitive(left, QV4::NUMBER_HINT);
+ QV4::Value r = __qmljs_to_primitive(right, QV4::NUMBER_HINT);
+
+ if (QV4::Value::bothDouble(l, r)) {
+ return l.doubleValue() >= r.doubleValue();
+ } else if (l.isString() && r.isString()) {
+ return !l.stringValue()->compare(r.stringValue());
+ } else {
+ double dl = __qmljs_to_number(l);
+ double dr = __qmljs_to_number(r);
+ return dl >= dr;
+ }
+}
+
+inline QV4::Bool __qmljs_cmp_le(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+ if (QV4::Value::integerCompatible(left, right))
+ return left.integerValue() <= right.integerValue();
+
+ QV4::Value l = __qmljs_to_primitive(left, QV4::NUMBER_HINT);
+ QV4::Value r = __qmljs_to_primitive(right, QV4::NUMBER_HINT);
+
+ if (QV4::Value::bothDouble(l, r)) {
+ return l.doubleValue() <= r.doubleValue();
+ } else if (l.isString() && r.isString()) {
+ return !r.stringValue()->compare(l.stringValue());
+ } else {
+ double dl = __qmljs_to_number(l);
+ double dr = __qmljs_to_number(r);
+ return dl <= dr;
+ }
+}
+
+inline QV4::Bool __qmljs_cmp_eq(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ // need to test for doubles first as NaN != NaN
+ if (QV4::Value::bothDouble(left, right))
+ return left.doubleValue() == right.doubleValue();
+ if (left.val == right.val)
+ return true;
+ if (left.isString() && right.isString())
+ return left.stringValue()->isEqualTo(right.stringValue());
+
+ return __qmljs_equal(left, right);
+}
+
+inline QV4::Bool __qmljs_cmp_ne(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ return !__qmljs_cmp_eq(0, left, right);
+}
+
+inline QV4::Bool __qmljs_cmp_se(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ return __qmljs_strict_equal(left, right);
+}
+
+inline QV4::Bool __qmljs_cmp_sne(QV4::ExecutionContext *, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ return ! __qmljs_strict_equal(left, right);
+}
+
+inline QV4::Bool __qmljs_cmp_instanceof(QV4::ExecutionContext *ctx, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ QV4::Value v;
+ __qmljs_instanceof(ctx, &v, left, right);
+ return v.booleanValue();
+}
+
+inline uint __qmljs_cmp_in(QV4::ExecutionContext *ctx, const QV4::Value &left, const QV4::Value &right)
+{
+ TRACE2(left, right);
+
+ QV4::Value v;
+ __qmljs_in(ctx, &v, left, right);
+ return v.booleanValue();
+}
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QMLJS_RUNTIME_H
diff --git a/src/qml/qml/v4/qv4script.cpp b/src/qml/qml/v4/qv4script.cpp
new file mode 100644
index 0000000000..3de218a451
--- /dev/null
+++ b/src/qml/qml/v4/qv4script.cpp
@@ -0,0 +1,249 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4script_p.h"
+#include "qv4mm_p.h"
+#include "qv4functionobject_p.h"
+#include "qv4function_p.h"
+#include "qv4context_p.h"
+#include "qv4debugging_p.h"
+#include "qv4exception_p.h"
+
+#include <private/qqmljsengine_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljsast_p.h>
+#include <qv4jsir_p.h>
+#include <qv4codegen_p.h>
+
+#include <QtCore/QDebug>
+#include <QtCore/QString>
+
+using namespace QV4;
+
+struct QmlBindingWrapper : FunctionObject
+{
+ QmlBindingWrapper(ExecutionContext *scope, Function *f, Object *qml)
+ : FunctionObject(scope, scope->engine->id_eval)
+ , qml(qml)
+ {
+ vtbl = &static_vtbl;
+ function = f;
+ usesArgumentsObject = function->usesArgumentsObject;
+ needsActivation = function->needsActivation();
+ defineReadonlyProperty(scope->engine->id_length, Value::fromInt32(1));
+
+ qmlContext = scope->engine->newQmlContext(this, qml);
+ scope->engine->popContext();
+ }
+
+ static Value call(Managed *that, const Value &, Value *, int);
+ static void markObjects(Managed *m)
+ {
+ QmlBindingWrapper *wrapper = static_cast<QmlBindingWrapper*>(m);
+ if (wrapper->qml)
+ wrapper->qml->mark();
+ FunctionObject::markObjects(m);
+ wrapper->qmlContext->mark();
+ }
+
+protected:
+ static const ManagedVTable static_vtbl;
+
+private:
+ Object *qml;
+ CallContext *qmlContext;
+
+};
+
+DEFINE_MANAGED_VTABLE(QmlBindingWrapper);
+
+Value QmlBindingWrapper::call(Managed *that, const Value &, Value *, int)
+{
+ ExecutionEngine *engine = that->engine();
+ QmlBindingWrapper *This = static_cast<QmlBindingWrapper *>(that);
+
+ CallContext *ctx = This->qmlContext;
+ std::fill(ctx->locals, ctx->locals + ctx->function->varCount, Value::undefinedValue());
+ engine->pushContext(ctx);
+ Value result = This->function->code(ctx, This->function->codeData);
+ engine->popContext();
+
+ return result;
+
+}
+
+
+void Script::parse()
+{
+ if (parsed)
+ return;
+
+ using namespace QQmlJS;
+
+ parsed = true;
+
+ ExecutionEngine *v4 = scope->engine;
+
+ MemoryManager::GCBlocker gcBlocker(v4->memoryManager);
+
+ V4IR::Module module;
+
+ QQmlJS::Engine ee, *engine = &ee;
+ Lexer lexer(engine);
+ lexer.setCode(sourceCode, line, parseAsBinding);
+ Parser parser(engine);
+
+ const bool parsed = parser.parseProgram();
+
+ DiagnosticMessage *error = 0, **errIt = &error;
+ foreach (const QQmlJS::DiagnosticMessage &m, parser.diagnosticMessages()) {
+ if (m.isError()) {
+ *errIt = new DiagnosticMessage;
+ (*errIt)->fileName = sourceFile;
+ (*errIt)->offset = m.loc.offset;
+ (*errIt)->length = m.loc.length;
+ (*errIt)->startLine = m.loc.startLine;
+ (*errIt)->startColumn = m.loc.startColumn;
+ (*errIt)->type = DiagnosticMessage::Error;
+ (*errIt)->message = m.message;
+ errIt = &(*errIt)->next;
+ } else {
+ qWarning() << sourceFile << ':' << m.loc.startLine << ':' << m.loc.startColumn
+ << ": warning: " << m.message;
+ }
+ }
+ if (error)
+ scope->throwSyntaxError(error);
+
+ if (parsed) {
+ using namespace AST;
+ Program *program = AST::cast<Program *>(parser.rootNode());
+ if (!program) {
+ // if parsing was successful, and we have no program, then
+ // we're done...:
+ return;
+ }
+
+ QStringList inheritedLocals;
+ if (inheritContext)
+ for (String * const *i = scope->variables(), * const *ei = i + scope->variableCount(); i < ei; ++i)
+ inheritedLocals.append(*i ? (*i)->toQString() : QString());
+
+ Codegen cg(scope, strictMode);
+ V4IR::Function *globalIRCode = cg(sourceFile, sourceCode, program, &module,
+ parseAsBinding ? QQmlJS::Codegen::QmlBinding : QQmlJS::Codegen::EvalCode, inheritedLocals);
+ QScopedPointer<EvalInstructionSelection> isel(v4->iselFactory->create(v4, &module));
+ if (inheritContext)
+ isel->setUseFastLookups(false);
+ if (globalIRCode)
+ vmFunction = isel->vmFunction(globalIRCode);
+ }
+
+ if (!vmFunction)
+ // ### FIX file/line number
+ v4->current->throwError(QV4::Value::fromObject(v4->newSyntaxErrorObject(v4->current, 0)));
+}
+
+Value Script::run()
+{
+ if (!parsed)
+ parse();
+ if (!vmFunction)
+ return Value::undefinedValue();
+
+ QV4::ExecutionEngine *engine = scope->engine;
+
+ if (qml.isEmpty()) {
+ TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction);
+
+ bool strict = scope->strictMode;
+ Lookup *lookups = scope->lookups;
+
+ scope->strictMode = vmFunction->isStrict;
+ scope->lookups = vmFunction->lookups;
+
+ QV4::Value result;
+ try {
+ result = vmFunction->code(scope, vmFunction->codeData);
+ } catch (Exception &e) {
+ scope->strictMode = strict;
+ scope->lookups = lookups;
+ throw;
+ }
+
+ return result;
+
+ } else {
+ FunctionObject *f = new (engine->memoryManager) QmlBindingWrapper(scope, vmFunction, qml.value().asObject());
+ return f->call(Value::undefinedValue(), 0, 0);
+ }
+}
+
+Function *Script::function()
+{
+ if (!parsed)
+ parse();
+ return vmFunction;
+}
+
+Value Script::qmlBinding()
+{
+ if (!parsed)
+ parse();
+ QV4::ExecutionEngine *v4 = scope->engine;
+ return Value::fromObject(new (v4->memoryManager) QmlBindingWrapper(scope, vmFunction, qml.value().asObject()));
+}
+
+QV4::Value Script::evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject)
+{
+ QV4::Script qmlScript(engine, scopeObject, script, QString());
+
+ QV4::ExecutionContext *ctx = engine->current;
+ QV4::Value result = QV4::Value::undefinedValue();
+ try {
+ qmlScript.parse();
+ result = qmlScript.run();
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ }
+ return result;
+}
diff --git a/src/qml/qml/v4/qv4script_p.h b/src/qml/qml/v4/qv4script_p.h
new file mode 100644
index 0000000000..274a87db26
--- /dev/null
+++ b/src/qml/qml/v4/qv4script_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4SCRIPT_H
+#define QV4SCRIPT_H
+
+#include "qv4global_p.h"
+#include "qv4engine_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct ExecutionContext;
+
+struct Q_QML_EXPORT Script {
+ Script(ExecutionContext *scope, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
+ : sourceFile(source), line(line), column(column), sourceCode(sourceCode)
+ , scope(scope), strictMode(false), inheritContext(false), parsed(false)
+ , vmFunction(0), parseAsBinding(false) {}
+ Script(ExecutionEngine *engine, Object *qml, const QString &sourceCode, const QString &source = QString(), int line = 1, int column = 0)
+ : sourceFile(source), line(line), column(column), sourceCode(sourceCode)
+ , scope(engine->rootContext), strictMode(false), inheritContext(true), parsed(false)
+ , qml(Value::fromObject(qml)), vmFunction(0), parseAsBinding(true) {}
+ QString sourceFile;
+ int line;
+ int column;
+ QString sourceCode;
+ ExecutionContext *scope;
+ bool strictMode;
+ bool inheritContext;
+ bool parsed;
+ QV4::PersistentValue qml;
+ Function *vmFunction;
+ bool parseAsBinding;
+
+ void parse();
+ Value run();
+ Value qmlBinding();
+
+ Function *function();
+
+
+ static Value evaluate(ExecutionEngine *engine, const QString &script, Object *scopeObject);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v4/qv4sequenceobject.cpp b/src/qml/qml/v4/qv4sequenceobject.cpp
new file mode 100644
index 0000000000..c4d9a71519
--- /dev/null
+++ b/src/qml/qml/v4/qv4sequenceobject.cpp
@@ -0,0 +1,651 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQml/qqml.h>
+
+#include "qv4sequenceobject_p.h"
+
+#include <private/qv4functionobject_p.h>
+#include <private/qv4arrayobject_p.h>
+#include <private/qqmlengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+// helper function to generate valid warnings if errors occur during sequence operations.
+static void generateWarning(QV4::ExecutionContext *ctx, const QString& description)
+{
+ QQmlEngine *engine = ctx->engine->v8Engine->engine();
+ if (!engine)
+ return;
+ QQmlError retn;
+ retn.setDescription(description);
+
+ QV4::ExecutionEngine::StackFrame frame = ctx->engine->currentStackFrame();
+
+ retn.setLine(frame.line);
+ retn.setUrl(QUrl(frame.source));
+ QQmlEnginePrivate::warning(engine, retn);
+}
+
+// F(elementType, elementTypeName, sequenceType, defaultValue)
+#define FOREACH_QML_SEQUENCE_TYPE(F) \
+ F(int, Int, QList<int>, 0) \
+ F(qreal, Real, QList<qreal>, 0.0) \
+ F(bool, Bool, QList<bool>, false) \
+ F(QString, String, QList<QString>, QString()) \
+ F(QString, QString, QStringList, QString()) \
+ F(QUrl, Url, QList<QUrl>, QUrl())
+
+static QV4::Value convertElementToValue(QV4::ExecutionEngine *engine, const QString &element)
+{
+ return QV4::Value::fromString(engine, element);
+}
+
+static QV4::Value convertElementToValue(QV4::ExecutionEngine *, int element)
+{
+ return QV4::Value::fromInt32(element);
+}
+
+static QV4::Value convertElementToValue(QV4::ExecutionEngine *engine, const QUrl &element)
+{
+ return QV4::Value::fromString(engine, element.toString());
+}
+
+static QV4::Value convertElementToValue(QV4::ExecutionEngine *, qreal element)
+{
+ return QV4::Value::fromDouble(element);
+}
+
+static QV4::Value convertElementToValue(QV4::ExecutionEngine *, bool element)
+{
+ return QV4::Value::fromBoolean(element);
+}
+
+static QString convertElementToString(const QString &element)
+{
+ return element;
+}
+
+static QString convertElementToString(int element)
+{
+ return QString::number(element);
+}
+
+static QString convertElementToString(const QUrl &element)
+{
+ return element.toString();
+}
+
+static QString convertElementToString(qreal element)
+{
+ QString qstr;
+ __qmljs_numberToString(&qstr, element, 10);
+ return qstr;
+}
+
+static QString convertElementToString(bool element)
+{
+ if (element)
+ return QStringLiteral("true");
+ else
+ return QStringLiteral("false");
+}
+
+template <typename ElementType> ElementType convertValueToElement(const QV4::Value &value);
+
+template <> QString convertValueToElement(const QV4::Value &value)
+{
+ return value.toQString();
+}
+
+template <> int convertValueToElement(const QV4::Value &value)
+{
+ return value.toInt32();
+}
+
+template <> QUrl convertValueToElement(const QV4::Value &value)
+{
+ return QUrl(value.toQString());
+}
+
+template <> qreal convertValueToElement(const QV4::Value &value)
+{
+ return value.toNumber();
+}
+
+template <> bool convertValueToElement(const QV4::Value &value)
+{
+ return value.toBoolean();
+}
+
+template <typename Container>
+class QQmlSequence : public QV4::Object
+{
+ Q_MANAGED
+public:
+ QQmlSequence(QV4::ExecutionEngine *engine, const Container &container)
+ : QV4::Object(engine)
+ , m_container(container)
+ , m_object(0)
+ , m_propertyIndex(-1)
+ , m_isReference(false)
+ {
+ type = Type_QmlSequence;
+ vtbl = &static_vtbl;
+ prototype = engine->sequencePrototype;
+ init(engine);
+ }
+
+ QQmlSequence(QV4::ExecutionEngine *engine, QObject *object, int propertyIndex)
+ : QV4::Object(engine)
+ , m_object(object)
+ , m_propertyIndex(propertyIndex)
+ , m_isReference(true)
+ {
+ type = Type_QmlSequence;
+ vtbl = &static_vtbl;
+ prototype = engine->sequencePrototype;
+ loadReference();
+ init(engine);
+ }
+
+ void init(ExecutionEngine *engine)
+ {
+ defineAccessorProperty(engine, QStringLiteral("length"), method_get_length, method_set_length);
+ }
+
+ QV4::Value containerGetIndexed(uint index, bool *hasProperty)
+ {
+ /* Qt containers have int (rather than uint) allowable indexes. */
+ if (index > INT_MAX) {
+ generateWarning(engine()->current, QLatin1String("Index out of range during indexed get"));
+ if (hasProperty)
+ *hasProperty = false;
+ return QV4::Value::undefinedValue();
+ }
+ if (m_isReference) {
+ if (!m_object) {
+ if (hasProperty)
+ *hasProperty = false;
+ return QV4::Value::undefinedValue();
+ }
+ loadReference();
+ }
+ qint32 signedIdx = static_cast<qint32>(index);
+ if (signedIdx < m_container.count()) {
+ if (hasProperty)
+ *hasProperty = true;
+ return convertElementToValue(engine(), m_container.at(signedIdx));
+ }
+ if (hasProperty)
+ *hasProperty = false;
+ return QV4::Value::undefinedValue();
+ }
+
+ void containerPutIndexed(uint index, const QV4::Value &value)
+ {
+ /* Qt containers have int (rather than uint) allowable indexes. */
+ if (index > INT_MAX) {
+ generateWarning(engine()->current, QLatin1String("Index out of range during indexed set"));
+ return;
+ }
+
+ if (m_isReference) {
+ if (!m_object)
+ return;
+ loadReference();
+ }
+
+ qint32 signedIdx = static_cast<qint32>(index);
+
+ int count = m_container.count();
+
+ typename Container::value_type element = convertValueToElement<typename Container::value_type>(value);
+
+ if (signedIdx == count) {
+ m_container.append(element);
+ } else if (signedIdx < count) {
+ m_container[signedIdx] = element;
+ } else {
+ /* according to ECMA262r3 we need to insert */
+ /* the value at the given index, increasing length to index+1. */
+ m_container.reserve(signedIdx + 1);
+ while (signedIdx > count++) {
+ m_container.append(typename Container::value_type());
+ }
+ m_container.append(element);
+ }
+
+ if (m_isReference)
+ storeReference();
+ }
+
+ QV4::PropertyAttributes containerQueryIndexed(uint index) const
+ {
+ /* Qt containers have int (rather than uint) allowable indexes. */
+ if (index > INT_MAX) {
+ generateWarning(engine()->current, QLatin1String("Index out of range during indexed query"));
+ return QV4::Attr_Invalid;
+ }
+ if (m_isReference) {
+ if (!m_object)
+ return QV4::Attr_Invalid;
+ loadReference();
+ }
+ qint32 signedIdx = static_cast<qint32>(index);
+ return (signedIdx < m_container.count()) ? QV4::Attr_Data : QV4::Attr_Invalid;
+ }
+
+ Property *containerAdvanceIterator(ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs)
+ {
+ *name = 0;
+ *index = UINT_MAX;
+
+ if (m_isReference) {
+ if (!m_object)
+ return QV4::Object::advanceIterator(this, it, name, index, attrs);
+ loadReference();
+ }
+
+ if (it->arrayIndex < m_container.count()) {
+ if (attrs)
+ *attrs = QV4::Attr_Data;
+ *index = it->arrayIndex;
+ ++it->arrayIndex;
+ it->tmpDynamicProperty.value = convertElementToValue(engine(), m_container.at(*index));
+ return &it->tmpDynamicProperty;
+ }
+ return QV4::Object::advanceIterator(this, it, name, index, attrs);
+ }
+
+ bool containerDeleteIndexedProperty(uint index)
+ {
+ /* Qt containers have int (rather than uint) allowable indexes. */
+ if (index > INT_MAX)
+ return false;
+ if (m_isReference) {
+ if (!m_object)
+ return false;
+ loadReference();
+ }
+ qint32 signedIdx = static_cast<qint32>(index);
+
+ if (signedIdx >= m_container.count())
+ return false;
+
+ /* according to ECMA262r3 it should be Undefined, */
+ /* but we cannot, so we insert a default-value instead. */
+ m_container.replace(signedIdx, typename Container::value_type());
+
+ if (m_isReference)
+ storeReference();
+
+ return true;
+ }
+
+ bool containerIsEqualTo(Managed *other)
+ {
+ QQmlSequence<Container> *otherSequence = other->as<QQmlSequence<Container> >();
+ if (!otherSequence)
+ return false;
+ if (m_isReference && otherSequence->m_isReference) {
+ return m_object == otherSequence->m_object && m_propertyIndex == otherSequence->m_propertyIndex;
+ } else if (!m_isReference && !otherSequence->m_isReference) {
+ return this == otherSequence;
+ }
+ return false;
+ }
+
+ struct DefaultCompareFunctor
+ {
+ bool operator()(typename Container::value_type lhs, typename Container::value_type rhs)
+ {
+ return convertElementToString(lhs) < convertElementToString(rhs);
+ }
+ };
+
+ struct CompareFunctor
+ {
+ CompareFunctor(QV4::ExecutionContext *ctx, const QV4::Value &compareFn)
+ : m_ctx(ctx), m_compareFn(compareFn)
+ {}
+
+ bool operator()(typename Container::value_type lhs, typename Container::value_type rhs)
+ {
+ QV4::Managed *fun = this->m_compareFn.asManaged();
+ QV4::Value argv[2] = {
+ convertElementToValue(this->m_ctx->engine, lhs),
+ convertElementToValue(this->m_ctx->engine, rhs)
+ };
+ QV4::Value result = fun->call(QV4::Value::fromObject(this->m_ctx->engine->globalObject), argv, 2);
+ return result.toNumber() < 0;
+ }
+
+ private:
+ QV4::ExecutionContext *m_ctx;
+ QV4::Value m_compareFn;
+ };
+
+ void sort(QV4::SimpleCallContext *ctx)
+ {
+ if (m_isReference) {
+ if (!m_object)
+ return;
+ loadReference();
+ }
+
+ if (ctx->argumentCount == 1 && ctx->arguments[0].asFunctionObject()) {
+ QV4::Value compareFn = ctx->arguments[0];
+ CompareFunctor cf(ctx, compareFn);
+ qSort(m_container.begin(), m_container.end(), cf);
+ } else {
+ DefaultCompareFunctor cf;
+ qSort(m_container.begin(), m_container.end(), cf);
+ }
+
+ if (m_isReference)
+ storeReference();
+ }
+
+ static QV4::Value method_get_length(QV4::SimpleCallContext *ctx)
+ {
+ QQmlSequence<Container> *This = ctx->thisObject.as<QQmlSequence<Container> >();
+ if (!This)
+ ctx->throwTypeError();
+
+ if (This->m_isReference) {
+ if (!This->m_object)
+ return QV4::Value::fromInt32(0);
+ This->loadReference();
+ }
+ return QV4::Value::fromInt32(This->m_container.count());
+ }
+
+ static QV4::Value method_set_length(QV4::SimpleCallContext* ctx)
+ {
+ QQmlSequence<Container> *This = ctx->thisObject.as<QQmlSequence<Container> >();
+ if (!This)
+ ctx->throwTypeError();
+
+ quint32 newLength = ctx->arguments[0].toUInt32();
+ /* Qt containers have int (rather than uint) allowable indexes. */
+ if (newLength > INT_MAX) {
+ generateWarning(ctx, QLatin1String("Index out of range during length set"));
+ return QV4::Value::undefinedValue();
+ }
+ /* Read the sequence from the QObject property if we're a reference */
+ if (This->m_isReference) {
+ if (!This->m_object)
+ return QV4::Value::undefinedValue();
+ This->loadReference();
+ }
+ /* Determine whether we need to modify the sequence */
+ qint32 newCount = static_cast<qint32>(newLength);
+ qint32 count = This->m_container.count();
+ if (newCount == count) {
+ return QV4::Value::undefinedValue();
+ } else if (newCount > count) {
+ /* according to ECMA262r3 we need to insert */
+ /* undefined values increasing length to newLength. */
+ /* We cannot, so we insert default-values instead. */
+ This->m_container.reserve(newCount);
+ while (newCount > count++) {
+ This->m_container.append(typename Container::value_type());
+ }
+ } else {
+ /* according to ECMA262r3 we need to remove */
+ /* elements until the sequence is the required length. */
+ while (newCount < count) {
+ count--;
+ This->m_container.removeAt(count);
+ }
+ }
+ /* write back if required. */
+ if (This->m_isReference) {
+ /* write back. already checked that object is non-null, so skip that check here. */
+ This->storeReference();
+ }
+ return QV4::Value::undefinedValue();
+ }
+
+ QVariant toVariant() const
+ { return QVariant::fromValue<Container>(m_container); }
+
+ static QVariant toVariant(QV4::ArrayObject *array)
+ {
+ Container result;
+ uint32_t length = array->arrayLength();
+ for (uint32_t i = 0; i < length; ++i)
+ result << convertValueToElement<typename Container::value_type>(array->getIndexed(i));
+ return QVariant::fromValue(result);
+ }
+
+private:
+ void loadReference() const
+ {
+ Q_ASSERT(m_object);
+ Q_ASSERT(m_isReference);
+ void *a[] = { &m_container, 0 };
+ QMetaObject::metacall(m_object, QMetaObject::ReadProperty, m_propertyIndex, a);
+ }
+
+ void storeReference()
+ {
+ Q_ASSERT(m_object);
+ Q_ASSERT(m_isReference);
+ int status = -1;
+ QQmlPropertyPrivate::WriteFlags flags = QQmlPropertyPrivate::DontRemoveBinding;
+ void *a[] = { &m_container, 0, &status, &flags };
+ QMetaObject::metacall(m_object, QMetaObject::WriteProperty, m_propertyIndex, a);
+ }
+
+ mutable Container m_container;
+ QPointer<QObject> m_object;
+ int m_propertyIndex;
+ bool m_isReference;
+
+ static QV4::Value getIndexed(QV4::Managed *that, uint index, bool *hasProperty)
+ { return static_cast<QQmlSequence<Container> *>(that)->containerGetIndexed(index, hasProperty); }
+ static void putIndexed(Managed *that, uint index, const QV4::Value &value)
+ { static_cast<QQmlSequence<Container> *>(that)->containerPutIndexed(index, value); }
+ static QV4::PropertyAttributes queryIndexed(const QV4::Managed *that, uint index)
+ { return static_cast<const QQmlSequence<Container> *>(that)->containerQueryIndexed(index); }
+ static bool deleteIndexedProperty(QV4::Managed *that, uint index)
+ { return static_cast<QQmlSequence<Container> *>(that)->containerDeleteIndexedProperty(index); }
+ static bool isEqualTo(Managed *that, Managed *other)
+ { return static_cast<QQmlSequence<Container> *>(that)->containerIsEqualTo(other); }
+ static Property *advanceIterator(Managed *that, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs)
+ { return static_cast<QQmlSequence<Container> *>(that)->containerAdvanceIterator(it, name, index, attrs); }
+
+ static void destroy(Managed *that)
+ {
+ static_cast<QQmlSequence<Container> *>(that)->~QQmlSequence<Container>();
+ }
+};
+
+typedef QQmlSequence<QStringList> QQmlQStringList;
+template<>
+DEFINE_MANAGED_VTABLE(QQmlQStringList);
+typedef QQmlSequence<QList<QString> > QQmlStringList;
+template<>
+DEFINE_MANAGED_VTABLE(QQmlStringList);
+typedef QQmlSequence<QList<int> > QQmlIntList;
+template<>
+DEFINE_MANAGED_VTABLE(QQmlIntList);
+typedef QQmlSequence<QList<QUrl> > QQmlUrlList;
+template<>
+DEFINE_MANAGED_VTABLE(QQmlUrlList);
+typedef QQmlSequence<QList<bool> > QQmlBoolList;
+template<>
+DEFINE_MANAGED_VTABLE(QQmlBoolList);
+typedef QQmlSequence<QList<qreal> > QQmlRealList;
+template<>
+DEFINE_MANAGED_VTABLE(QQmlRealList);
+
+#define REGISTER_QML_SEQUENCE_METATYPE(unused, unused2, SequenceType, unused3) qRegisterMetaType<SequenceType>(#SequenceType);
+SequencePrototype::SequencePrototype(ExecutionEngine *engine)
+ : QV4::Object(engine)
+{
+ prototype = engine->arrayPrototype;
+ FOREACH_QML_SEQUENCE_TYPE(REGISTER_QML_SEQUENCE_METATYPE)
+}
+#undef REGISTER_QML_SEQUENCE_METATYPE
+
+void SequencePrototype::init(QV4::ExecutionEngine *engine)
+{
+ defineDefaultProperty(engine, QStringLiteral("sort"), method_sort, 1);
+ defineDefaultProperty(engine, QStringLiteral("valueOf"), method_valueOf, 0);
+}
+
+QV4::Value SequencePrototype::method_sort(QV4::SimpleCallContext *ctx)
+{
+ QV4::Object *o = ctx->thisObject.asObject();
+ if (!o || !o->isListType())
+ ctx->throwTypeError();
+
+ if (ctx->argumentCount >= 2)
+ return ctx->thisObject;
+
+#define CALL_SORT(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue) \
+ if (QQml##SequenceElementTypeName##List *s = o->as<QQml##SequenceElementTypeName##List>()) { \
+ s->sort(ctx); \
+ } else
+
+ FOREACH_QML_SEQUENCE_TYPE(CALL_SORT)
+
+#undef CALL_SORT
+ return ctx->thisObject;
+}
+
+#define IS_SEQUENCE(unused1, unused2, SequenceType, unused3) \
+ if (sequenceTypeId == qMetaTypeId<SequenceType>()) { \
+ return true; \
+ } else
+
+bool SequencePrototype::isSequenceType(int sequenceTypeId)
+{
+ FOREACH_QML_SEQUENCE_TYPE(IS_SEQUENCE) { /* else */ return false; }
+}
+#undef IS_SEQUENCE
+
+#define NEW_REFERENCE_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \
+ if (sequenceType == qMetaTypeId<SequenceType>()) { \
+ QV4::Object *obj = new (engine->memoryManager) QQml##ElementTypeName##List(engine, object, propertyIndex); \
+ return QV4::Value::fromObject(obj); \
+ } else
+
+QV4::Value SequencePrototype::newSequence(QV4::ExecutionEngine *engine, int sequenceType, QObject *object, int propertyIndex, bool *succeeded)
+{
+ // This function is called when the property is a QObject Q_PROPERTY of
+ // the given sequence type. Internally we store a typed-sequence
+ // (as well as object ptr + property index for updated-read and write-back)
+ // and so access/mutate avoids variant conversion.
+ *succeeded = true;
+ FOREACH_QML_SEQUENCE_TYPE(NEW_REFERENCE_SEQUENCE) { /* else */ *succeeded = false; return QV4::Value::undefinedValue(); }
+}
+#undef NEW_REFERENCE_SEQUENCE
+
+#define NEW_COPY_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \
+ if (sequenceType == qMetaTypeId<SequenceType>()) { \
+ QV4::Object *obj = new (engine->memoryManager) QQml##ElementTypeName##List(engine, v.value<SequenceType >()); \
+ return QV4::Value::fromObject(obj); \
+ } else
+
+QV4::Value SequencePrototype::fromVariant(QV4::ExecutionEngine *engine, const QVariant& v, bool *succeeded)
+{
+ // This function is called when assigning a sequence value to a normal JS var
+ // in a JS block. Internally, we store a sequence of the specified type.
+ // Access and mutation is extremely fast since it will not need to modify any
+ // QObject property.
+ int sequenceType = v.userType();
+ *succeeded = true;
+ FOREACH_QML_SEQUENCE_TYPE(NEW_COPY_SEQUENCE) { /* else */ *succeeded = false; return QV4::Value::undefinedValue(); }
+}
+#undef NEW_COPY_SEQUENCE
+
+#define SEQUENCE_TO_VARIANT(ElementType, ElementTypeName, SequenceType, unused) \
+ if (QQml##ElementTypeName##List *list = object->as<QQml##ElementTypeName##List>()) \
+ return list->toVariant(); \
+ else
+
+QVariant SequencePrototype::toVariant(QV4::Object *object)
+{
+ Q_ASSERT(object->isListType());
+ FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_TO_VARIANT) { /* else */ return QVariant(); }
+}
+
+#define SEQUENCE_TO_VARIANT(ElementType, ElementTypeName, SequenceType, unused) \
+ if (typeHint == qMetaTypeId<SequenceType>()) { \
+ return QQml##ElementTypeName##List::toVariant(a); \
+ } else
+
+QVariant SequencePrototype::toVariant(const QV4::Value &array, int typeHint, bool *succeeded)
+{
+ *succeeded = true;
+
+ QV4::ArrayObject *a = array.asArrayObject();
+ if (!a) {
+ *succeeded = false;
+ return QVariant();
+ }
+ FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_TO_VARIANT) { /* else */ *succeeded = false; return QVariant(); }
+}
+
+#undef SEQUENCE_TO_VARIANT
+
+#define MAP_META_TYPE(ElementType, ElementTypeName, SequenceType, unused) \
+ if (object->as<QQml##ElementTypeName##List>()) { \
+ return qMetaTypeId<SequenceType>(); \
+ } else
+
+int SequencePrototype::metaTypeForSequence(QV4::Object *object)
+{
+ FOREACH_QML_SEQUENCE_TYPE(MAP_META_TYPE)
+ /*else*/ {
+ return -1;
+ }
+}
+
+#undef MAP_META_TYPE
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/qqmlintegercache_p.h b/src/qml/qml/v4/qv4sequenceobject_p.h
index 8b2f97267e..2cade45092 100644
--- a/src/qml/qml/qqmlintegercache_p.h
+++ b/src/qml/qml/v4/qv4sequenceobject_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QQMLINTEGERCACHE_P_H
-#define QQMLINTEGERCACHE_P_H
+#ifndef QV4SEQUENCEWRAPPER_P_H
+#define QV4SEQUENCEWRAPPER_P_H
//
// W A R N I N G
@@ -53,45 +53,39 @@
// We mean it.
//
-#include <private/qqmlrefcount_p.h>
-#include <private/qhashedstring_p.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qvariant.h>
+
+#include "qv4value_p.h"
+#include "qv4object_p.h"
QT_BEGIN_NAMESPACE
-class QQmlType;
-class QQmlEngine;
-class QQmlIntegerCache : public QQmlRefCount
+namespace QV4 {
+
+struct SequencePrototype : public QV4::Object
{
-public:
- QQmlIntegerCache();
- virtual ~QQmlIntegerCache();
+ SequencePrototype(QV4::ExecutionEngine *engine);
- inline int count() const;
- void add(const QString &, int);
- void reserve(int);
+ void init(QV4::ExecutionEngine *engine);
- int value(const QString &);
- inline int value(const QHashedV8String &);
+ static QV4::Value method_valueOf(QV4::SimpleCallContext *ctx)
+ {
+ return QV4::Value::fromString(ctx->thisObject.toString(ctx));
+ }
- QString findId(int value) const;
+ static QV4::Value method_sort(QV4::SimpleCallContext *ctx);
-private:
- typedef QStringHash<int> StringCache;
- StringCache stringCache;
+ static bool isSequenceType(int sequenceTypeId);
+ static QV4::Value newSequence(QV4::ExecutionEngine *engine, int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded);
+ static QV4::Value fromVariant(QV4::ExecutionEngine *engine, const QVariant& v, bool *succeeded);
+ static int metaTypeForSequence(QV4::Object *object);
+ static QVariant toVariant(QV4::Object *object);
+ static QVariant toVariant(const QV4::Value &array, int typeHint, bool *succeeded);
};
-int QQmlIntegerCache::value(const QHashedV8String &name)
-{
- int *result = stringCache.value(name);
- return result?*result:-1;
-}
-
-int QQmlIntegerCache::count() const
-{
- return stringCache.count();
}
QT_END_NAMESPACE
-#endif // QQMLINTEGERCACHE_P_H
-
+#endif // QV4SEQUENCEWRAPPER_P_H
diff --git a/src/qml/qml/v8/qv8worker.cpp b/src/qml/qml/v4/qv4serialize.cpp
index 9556e146ef..f7389dc6d7 100644
--- a/src/qml/qml/v8/qv8worker.cpp
+++ b/src/qml/qml/v4/qv4serialize.cpp
@@ -39,13 +39,22 @@
**
****************************************************************************/
-#include "qv8worker_p.h"
+#include "qv4serialize_p.h"
+#include <private/qv8engine_p.h>
#include <private/qqmllistmodel_p.h>
#include <private/qqmllistmodelworkeragent_p.h>
+#include <private/qv4value_p.h>
+#include <private/qv4dateobject_p.h>
+#include <private/qv4regexpobject_p.h>
+#include <private/qv4sequenceobject_p.h>
+#include <private/qv4objectproto_p.h>
+
QT_BEGIN_NAMESPACE
+using namespace QV4;
+
// We allow the following JavaScript types to be passed between the main and
// the secondary thread:
// + undefined
@@ -138,20 +147,19 @@ static inline void *popPtr(const char *&data)
// serialization/deserialization failures
#define ALIGN(size) (((size) + 3) & ~3)
-void QV8Worker::serialize(QByteArray &data, v8::Handle<v8::Value> v, QV8Engine *engine)
+void Serialize::serialize(QByteArray &data, const QV4::Value &v, QV8Engine *engine)
{
- if (v.IsEmpty()) {
- } else if (v->IsUndefined()) {
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ if (v.isEmpty()) {
+ } else if (v.isUndefined()) {
push(data, valueheader(WorkerUndefined));
- } else if (v->IsNull()) {
+ } else if (v.isNull()) {
push(data, valueheader(WorkerNull));
- } else if (v->IsTrue()) {
- push(data, valueheader(WorkerTrue));
- } else if (v->IsFalse()) {
- push(data, valueheader(WorkerFalse));
- } else if (v->IsString()) {
- v8::Handle<v8::String> string = v->ToString();
- int length = string->Length() + 1;
+ } else if (v.isBoolean()) {
+ push(data, valueheader(v.booleanValue() == true ? WorkerTrue : WorkerFalse));
+ } else if (QV4::String *s = v.asString()) {
+ const QString &qstr = s->toQString();
+ int length = qstr.length();
if (length > 0xFFFFFF) {
push(data, valueheader(WorkerUndefined));
return;
@@ -165,14 +173,13 @@ void QV8Worker::serialize(QByteArray &data, v8::Handle<v8::Value> v, QV8Engine *
data.resize(data.size() + utf16size);
char *buffer = data.data() + offset;
- string->Write((uint16_t*)buffer);
- } else if (v->IsFunction()) {
+ memcpy(buffer, qstr.constData(), length*sizeof(QChar));
+ } else if (v.asFunctionObject()) {
// XXX TODO: Implement passing function objects between the main and
// worker scripts
push(data, valueheader(WorkerUndefined));
- } else if (v->IsArray()) {
- v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(v);
- uint32_t length = array->Length();
+ } else if (QV4::ArrayObject *array = v.asArrayObject()) {
+ uint32_t length = array->arrayLength();
if (length > 0xFFFFFF) {
push(data, valueheader(WorkerUndefined));
return;
@@ -180,29 +187,27 @@ void QV8Worker::serialize(QByteArray &data, v8::Handle<v8::Value> v, QV8Engine *
reserve(data, sizeof(quint32) + length * sizeof(quint32));
push(data, valueheader(WorkerArray, length));
for (uint32_t ii = 0; ii < length; ++ii)
- serialize(data, array->Get(ii), engine);
- } else if (v->IsInt32()) {
+ serialize(data, array->getIndexed(ii), engine);
+ } else if (v.isInteger()) {
reserve(data, 2 * sizeof(quint32));
push(data, valueheader(WorkerInt32));
- push(data, (quint32)v->Int32Value());
- } else if (v->IsUint32()) {
- reserve(data, 2 * sizeof(quint32));
- push(data, valueheader(WorkerUint32));
- push(data, v->Uint32Value());
- } else if (v->IsNumber()) {
+ push(data, (quint32)v.integerValue());
+// } else if (v->IsUint32()) {
+// reserve(data, 2 * sizeof(quint32));
+// push(data, valueheader(WorkerUint32));
+// push(data, v->Uint32Value());
+ } else if (v.isNumber()) {
reserve(data, sizeof(quint32) + sizeof(double));
push(data, valueheader(WorkerNumber));
- push(data, v->NumberValue());
- } else if (v->IsDate()) {
+ push(data, v.asDouble());
+ } else if (QV4::DateObject *d = v.asDateObject()) {
reserve(data, sizeof(quint32) + sizeof(double));
push(data, valueheader(WorkerDate));
- push(data, v8::Handle<v8::Date>::Cast(v)->NumberValue());
- } else if (v->IsRegExp()) {
- v8::Handle<v8::RegExp> regexp = v8::Handle<v8::RegExp>::Cast(v);
- quint32 flags = regexp->GetFlags();
- v8::Local<v8::String> source = regexp->GetSource();
-
- int length = source->Length() + 1;
+ push(data, d->value.asDouble());
+ } else if (QV4::RegExpObject *re = v.as<RegExpObject>()) {
+ quint32 flags = re->flags();
+ QString pattern = re->source();
+ int length = pattern.length() + 1;
if (length > 0xFFFFFF) {
push(data, valueheader(WorkerUndefined));
return;
@@ -212,98 +217,97 @@ void QV8Worker::serialize(QByteArray &data, v8::Handle<v8::Value> v, QV8Engine *
reserve(data, sizeof(quint32) + utf16size);
push(data, valueheader(WorkerRegexp, flags));
push(data, (quint32)length);
+
int offset = data.size();
data.resize(data.size() + utf16size);
char *buffer = data.data() + offset;
- source->Write((uint16_t*)buffer);
- } else if (v->IsObject() && !v->ToObject()->GetExternalResource()) {
- v8::Handle<v8::Object> object = v->ToObject();
- v8::Local<v8::Array> properties = engine->getOwnPropertyNames(object);
- quint32 length = properties->Length();
- if (length > 0xFFFFFF) {
- push(data, valueheader(WorkerUndefined));
- return;
- }
- push(data, valueheader(WorkerObject, length));
- v8::TryCatch tc;
- for (quint32 ii = 0; ii < length; ++ii) {
- v8::Local<v8::String> str = properties->Get(ii)->ToString();
- serialize(data, str, engine);
-
- v8::Local<v8::Value> val = object->Get(str);
- if (tc.HasCaught()) {
- serialize(data, v8::Undefined(), engine);
- tc.Reset();
- } else {
- serialize(data, val, engine);
- }
- }
- } else if (engine->isQObject(v)) {
- // XXX TODO: Generalize passing objects between the main thread and worker scripts so
+ memcpy(buffer, pattern.constData(), length*sizeof(QChar));
+ } else if (QV4::QObjectWrapper *qobjectWrapper = v.as<QV4::QObjectWrapper>()) {
+ // XXX TODO: Generalize passing objects between the main thread and worker scripts so
// that others can trivially plug in their elements.
- QQmlListModel *lm = qobject_cast<QQmlListModel *>(engine->toQObject(v));
+ QQmlListModel *lm = qobject_cast<QQmlListModel *>(qobjectWrapper->object());
if (lm && lm->agent()) {
QQmlListModelWorkerAgent *agent = lm->agent();
agent->addref();
push(data, valueheader(WorkerListModel));
push(data, (void *)agent);
return;
- }
+ }
// No other QObject's are allowed to be sent
push(data, valueheader(WorkerUndefined));
- } else {
- // we can convert sequences, but not other types with external data.
- if (v->IsObject()) {
- v8::Handle<v8::Object> seqObj = v->ToObject();
- QV8ObjectResource *r = static_cast<QV8ObjectResource *>(seqObj->GetExternalResource());
- if (r->resourceType() == QV8ObjectResource::SequenceType) {
- QVariant sequenceVariant = engine->sequenceWrapper()->toVariant(r);
- if (!sequenceVariant.isNull()) {
- // valid sequence. we generate a length (sequence length + 1 for the sequence type)
- uint32_t seqLength = engine->sequenceWrapper()->sequenceLength(r);
- uint32_t length = seqLength + 1;
- if (length > 0xFFFFFF) {
- push(data, valueheader(WorkerUndefined));
- return;
- }
- reserve(data, sizeof(quint32) + length * sizeof(quint32));
- push(data, valueheader(WorkerSequence, length));
- serialize(data, v8::Integer::New(sequenceVariant.userType()), engine); // sequence type
- for (uint32_t ii = 0; ii < seqLength; ++ii) {
- serialize(data, seqObj->Get(ii), engine); // sequence elements
- }
-
- return;
- }
+ } else if (QV4::Object *o = v.asObject()) {
+
+ if (o->isListType()) {
+ // valid sequence. we generate a length (sequence length + 1 for the sequence type)
+ uint32_t seqLength = o->get(v4->id_length).toUInt32();
+ uint32_t length = seqLength + 1;
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
}
+ reserve(data, sizeof(quint32) + length * sizeof(quint32));
+ push(data, valueheader(WorkerSequence, length));
+ serialize(data, QV4::Value::fromInt32(QV4::SequencePrototype::metaTypeForSequence(o)), engine); // sequence type
+ for (uint32_t ii = 0; ii < seqLength; ++ii)
+ serialize(data, o->getIndexed(ii), engine); // sequence elements
+
+ return;
+ }
+
+ // regular object
+ QV4::ArrayObject *properties = QV4::ObjectPrototype::getOwnPropertyNames(v4, v);
+ quint32 length = properties->arrayLength();
+ if (length > 0xFFFFFF) {
+ push(data, valueheader(WorkerUndefined));
+ return;
}
+ push(data, valueheader(WorkerObject, length));
+
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ for (quint32 ii = 0; ii < length; ++ii) {
+ QV4::String *s = properties->getIndexed(ii).asString();
+ serialize(data, QV4::Value::fromString(s), engine);
+
+ bool hasCaught = false;
+ QV4::ExecutionContext *ctx = v4->current;
+ QV4::Value val = QV4::Value::undefinedValue();
+ try {
+ val = o->get(s);
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ }
- // not a sequence.
+ serialize(data, val, engine);
+ }
+ return;
+ } else {
push(data, valueheader(WorkerUndefined));
}
}
-v8::Handle<v8::Value> QV8Worker::deserialize(const char *&data, QV8Engine *engine)
+QV4::Value Serialize::deserialize(const char *&data, QV8Engine *engine)
{
quint32 header = popUint32(data);
Type type = headertype(header);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+
switch (type) {
case WorkerUndefined:
- return v8::Undefined();
+ return QV4::Value::undefinedValue();
case WorkerNull:
- return v8::Null();
+ return QV4::Value::nullValue();
case WorkerTrue:
- return v8::True();
+ return QV4::Value::fromBoolean(true);
case WorkerFalse:
- return v8::False();
+ return QV4::Value::fromBoolean(false);
case WorkerString:
{
quint32 size = headersize(header);
- v8::Local<v8::String> string = v8::String::New((uint16_t*)data, size - 1);
+ QString qstr((QChar *)data, size);
data += ALIGN(size * sizeof(uint16_t));
- return string;
+ return QV4::Value::fromString(v4->newString(qstr));
}
case WorkerFunction:
Q_ASSERT(!"Unreachable");
@@ -311,49 +315,49 @@ v8::Handle<v8::Value> QV8Worker::deserialize(const char *&data, QV8Engine *engin
case WorkerArray:
{
quint32 size = headersize(header);
- v8::Local<v8::Array> array = v8::Array::New(size);
+ QV4::ArrayObject *a = v4->newArrayObject();
for (quint32 ii = 0; ii < size; ++ii) {
- array->Set(ii, deserialize(data, engine));
+ a->putIndexed(ii, deserialize(data, engine));
}
- return array;
+ return QV4::Value::fromObject(a);
}
case WorkerObject:
{
quint32 size = headersize(header);
- v8::Local<v8::Object> o = v8::Object::New();
+ QV4::Object *o = v4->newObject();
for (quint32 ii = 0; ii < size; ++ii) {
- v8::Handle<v8::Value> name = deserialize(data, engine);
- v8::Handle<v8::Value> value = deserialize(data, engine);
- o->Set(name, value);
+ QV4::Value name = deserialize(data, engine);
+ QV4::Value value = deserialize(data, engine);
+ o->put(name.asString(), value);
}
- return o;
+ return QV4::Value::fromObject(o);
}
case WorkerInt32:
- return v8::Integer::New((qint32)popUint32(data));
+ return QV4::Value::fromInt32((qint32)popUint32(data));
case WorkerUint32:
- return v8::Integer::NewFromUnsigned(popUint32(data));
+ return QV4::Value::fromUInt32(popUint32(data));
case WorkerNumber:
- return v8::Number::New(popDouble(data));
+ return QV4::Value::fromDouble(popDouble(data));
case WorkerDate:
- return v8::Date::New(popDouble(data));
+ return QV4::Value::fromObject(v4->newDateObject(QV4::Value::fromDouble(popDouble(data))));
case WorkerRegexp:
{
quint32 flags = headersize(header);
quint32 length = popUint32(data);
- v8::Local<v8::String> source = v8::String::New((uint16_t*)data, length - 1);
+ QString pattern = QString((QChar *)data, length - 1);
data += ALIGN(length * sizeof(uint16_t));
- return v8::RegExp::New(source, (v8::RegExp::Flags)flags);
+ return QV4::Value::fromObject(v4->newRegExpObject(pattern, flags));
}
case WorkerListModel:
{
void *ptr = popPtr(data);
QQmlListModelWorkerAgent *agent = (QQmlListModelWorkerAgent *)ptr;
- v8::Handle<v8::Value> rv = engine->newQObject(agent);
- if (rv->IsObject()) {
- QQmlListModelWorkerAgent::VariantRef ref(agent);
- QVariant var = qVariantFromValue(ref);
- rv->ToObject()->SetHiddenValue(v8::String::New("qml::ref"), engine->fromVariant(var));
- }
+ QV4::Value rv = QV4::QObjectWrapper::wrap(v4, agent);
+ // ### Find a better solution then the ugly property
+ QQmlListModelWorkerAgent::VariantRef ref(agent);
+ QVariant var = qVariantFromValue(ref);
+ rv.asObject()->defineReadonlyProperty(v4->newString("__qml:hidden:ref"), engine->fromVariant(var));
+
agent->release();
agent->setV8Engine(engine);
return rv;
@@ -363,26 +367,29 @@ v8::Handle<v8::Value> QV8Worker::deserialize(const char *&data, QV8Engine *engin
bool succeeded = false;
quint32 length = headersize(header);
quint32 seqLength = length - 1;
- int sequenceType = deserialize(data, engine)->Int32Value();
- v8::Local<v8::Array> array = v8::Array::New(seqLength);
+ int sequenceType = deserialize(data, engine).integerValue();
+ QV4::ArrayObject *array = v4->newArrayObject();
+ array->arrayReserve(seqLength);
+ array->arrayDataLen = seqLength;
for (quint32 ii = 0; ii < seqLength; ++ii)
- array->Set(ii, deserialize(data, engine));
- QVariant seqVariant = engine->sequenceWrapper()->toVariant(array, sequenceType, &succeeded);
- return engine->sequenceWrapper()->fromVariant(seqVariant, &succeeded);
+ array->arrayData[ii].value = deserialize(data, engine);
+ array->setArrayLengthUnchecked(seqLength);
+ QVariant seqVariant = QV4::SequencePrototype::toVariant(QV4::Value::fromObject(array), sequenceType, &succeeded);
+ return QV4::SequencePrototype::fromVariant(v4, seqVariant, &succeeded);
}
}
Q_ASSERT(!"Unreachable");
- return v8::Undefined();
+ return QV4::Value::undefinedValue();
}
-QByteArray QV8Worker::serialize(v8::Handle<v8::Value> value, QV8Engine *engine)
+QByteArray Serialize::serialize(const QV4::Value &value, QV8Engine *engine)
{
QByteArray rv;
serialize(rv, value, engine);
return rv;
}
-v8::Handle<v8::Value> QV8Worker::deserialize(const QByteArray &data, QV8Engine *engine)
+QV4::Value Serialize::deserialize(const QByteArray &data, QV8Engine *engine)
{
const char *stream = data.constData();
return deserialize(stream, engine);
diff --git a/src/qml/qml/v8/qv8worker_p.h b/src/qml/qml/v4/qv4serialize_p.h
index 113b0bb37f..5a04c9d25f 100644
--- a/src/qml/qml/v8/qv8worker_p.h
+++ b/src/qml/qml/v4/qv4serialize_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QV8WORKER_P_H
-#define QV8WORKER_P_H
+#ifndef QV4SERIALIZE_P_H
+#define QV4SERIALIZE_P_H
//
// W A R N I N G
@@ -53,23 +53,28 @@
// We mean it.
//
-#include "qv8engine_p.h"
+#include <QtCore/qbytearray.h>
+#include <private/qv4value_p.h>
QT_BEGIN_NAMESPACE
-class QV8Worker {
+class QV8Engine;
+
+namespace QV4 {
+
+class Serialize {
public:
- struct SavedData {
- };
- static QByteArray serialize(v8::Handle<v8::Value>, QV8Engine *);
- static v8::Handle<v8::Value> deserialize(const QByteArray &, QV8Engine *);
+ static QByteArray serialize(const Value &, QV8Engine *);
+ static Value deserialize(const QByteArray &, QV8Engine *);
private:
- static void serialize(QByteArray &, v8::Handle<v8::Value>, QV8Engine *);
- static v8::Handle<v8::Value> deserialize(const char *&, QV8Engine *);
+ static void serialize(QByteArray &, const Value &, QV8Engine *);
+ static Value deserialize(const char *&, QV8Engine *);
};
+}
+
QT_END_NAMESPACE
#endif // QV8WORKER_P_H
diff --git a/src/qml/qml/v4/qv4sparsearray.cpp b/src/qml/qml/v4/qv4sparsearray.cpp
new file mode 100644
index 0000000000..835a0d004f
--- /dev/null
+++ b/src/qml/qml/v4/qv4sparsearray.cpp
@@ -0,0 +1,459 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4sparsearray_p.h"
+#include "qv4runtime_p.h"
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+#include <stdlib.h>
+
+#ifdef QT_QMAP_DEBUG
+# include <qstring.h>
+# include <qvector.h>
+#endif
+
+using namespace QV4;
+
+bool ArrayElementLessThan::operator()(const Property &p1, const Property &p2) const
+{
+ Value v1 = p1.value;
+ Value v2 = p2.value;
+
+ if (v1.isUndefined())
+ return false;
+ if (v2.isUndefined())
+ return true;
+ if (!m_comparefn.isUndefined()) {
+ Value args[] = { v1, v2 };
+ Value result = Value::undefinedValue();
+ __qmljs_call_value(m_context, &result, /*thisObject*/0, m_comparefn, args, 2);
+ return result.toNumber() <= 0;
+ }
+ return v1.toString(m_context)->toQString() < v2.toString(m_context)->toQString();
+}
+
+
+const SparseArrayNode *SparseArrayNode::nextNode() const
+{
+ const SparseArrayNode *n = this;
+ if (n->right) {
+ n = n->right;
+ while (n->left)
+ n = n->left;
+ } else {
+ const SparseArrayNode *y = n->parent();
+ while (y && n == y->right) {
+ n = y;
+ y = n->parent();
+ }
+ n = y;
+ }
+ return n;
+}
+
+const SparseArrayNode *SparseArrayNode::previousNode() const
+{
+ const SparseArrayNode *n = this;
+ if (n->left) {
+ n = n->left;
+ while (n->right)
+ n = n->right;
+ } else {
+ const SparseArrayNode *y = n->parent();
+ while (y && n == y->left) {
+ n = y;
+ y = n->parent();
+ }
+ n = y;
+ }
+ return n;
+}
+
+SparseArrayNode *SparseArrayNode::copy(SparseArray *d) const
+{
+ SparseArrayNode *n = d->createNode(size_left, 0, false);
+ n->value = value;
+ n->setColor(color());
+ if (left) {
+ n->left = left->copy(d);
+ n->left->setParent(n);
+ } else {
+ n->left = 0;
+ }
+ if (right) {
+ n->right = right->copy(d);
+ n->right->setParent(n);
+ } else {
+ n->right = 0;
+ }
+ return n;
+}
+
+/*
+ x y
+ \ / \
+ y --> x b
+ / \ \
+ a b a
+*/
+void SparseArray::rotateLeft(SparseArrayNode *x)
+{
+ SparseArrayNode *&root = header.left;
+ SparseArrayNode *y = x->right;
+ x->right = y->left;
+ if (y->left != 0)
+ y->left->setParent(x);
+ y->setParent(x->parent());
+ if (x == root)
+ root = y;
+ else if (x == x->parent()->left)
+ x->parent()->left = y;
+ else
+ x->parent()->right = y;
+ y->left = x;
+ x->setParent(y);
+ y->size_left += x->size_left;
+}
+
+
+/*
+ x y
+ / / \
+ y --> a x
+ / \ /
+ a b b
+*/
+void SparseArray::rotateRight(SparseArrayNode *x)
+{
+ SparseArrayNode *&root = header.left;
+ SparseArrayNode *y = x->left;
+ x->left = y->right;
+ if (y->right != 0)
+ y->right->setParent(x);
+ y->setParent(x->parent());
+ if (x == root)
+ root = y;
+ else if (x == x->parent()->right)
+ x->parent()->right = y;
+ else
+ x->parent()->left = y;
+ y->right = x;
+ x->setParent(y);
+ x->size_left -= y->size_left;
+}
+
+
+void SparseArray::rebalance(SparseArrayNode *x)
+{
+ SparseArrayNode *&root = header.left;
+ x->setColor(SparseArrayNode::Red);
+ while (x != root && x->parent()->color() == SparseArrayNode::Red) {
+ if (x->parent() == x->parent()->parent()->left) {
+ SparseArrayNode *y = x->parent()->parent()->right;
+ if (y && y->color() == SparseArrayNode::Red) {
+ x->parent()->setColor(SparseArrayNode::Black);
+ y->setColor(SparseArrayNode::Black);
+ x->parent()->parent()->setColor(SparseArrayNode::Red);
+ x = x->parent()->parent();
+ } else {
+ if (x == x->parent()->right) {
+ x = x->parent();
+ rotateLeft(x);
+ }
+ x->parent()->setColor(SparseArrayNode::Black);
+ x->parent()->parent()->setColor(SparseArrayNode::Red);
+ rotateRight (x->parent()->parent());
+ }
+ } else {
+ SparseArrayNode *y = x->parent()->parent()->left;
+ if (y && y->color() == SparseArrayNode::Red) {
+ x->parent()->setColor(SparseArrayNode::Black);
+ y->setColor(SparseArrayNode::Black);
+ x->parent()->parent()->setColor(SparseArrayNode::Red);
+ x = x->parent()->parent();
+ } else {
+ if (x == x->parent()->left) {
+ x = x->parent();
+ rotateRight(x);
+ }
+ x->parent()->setColor(SparseArrayNode::Black);
+ x->parent()->parent()->setColor(SparseArrayNode::Red);
+ rotateLeft(x->parent()->parent());
+ }
+ }
+ }
+ root->setColor(SparseArrayNode::Black);
+}
+
+void SparseArray::deleteNode(SparseArrayNode *z)
+{
+ SparseArrayNode *&root = header.left;
+ SparseArrayNode *y = z;
+ SparseArrayNode *x;
+ SparseArrayNode *x_parent;
+ if (y->left == 0) {
+ x = y->right;
+ if (y == mostLeftNode) {
+ if (x)
+ mostLeftNode = x; // It cannot have (left) children due the red black invariant.
+ else
+ mostLeftNode = y->parent();
+ }
+ } else {
+ if (y->right == 0) {
+ x = y->left;
+ } else {
+ y = y->right;
+ while (y->left != 0)
+ y = y->left;
+ x = y->right;
+ }
+ }
+ if (y != z) {
+ z->left->setParent(y);
+ y->left = z->left;
+ if (y != z->right) {
+ x_parent = y->parent();
+ if (x)
+ x->setParent(y->parent());
+ y->parent()->left = x;
+ y->right = z->right;
+ z->right->setParent(y);
+ } else {
+ x_parent = y;
+ }
+ if (root == z)
+ root = y;
+ else if (z->parent()->left == z)
+ z->parent()->left = y;
+ else
+ z->parent()->right = y;
+ y->setParent(z->parent());
+ // Swap the colors
+ SparseArrayNode::Color c = y->color();
+ y->setColor(z->color());
+ z->setColor(c);
+ y = z;
+ } else {
+ x_parent = y->parent();
+ if (x)
+ x->setParent(y->parent());
+ if (root == z)
+ root = x;
+ else if (z->parent()->left == z)
+ z->parent()->left = x;
+ else
+ z->parent()->right = x;
+ }
+ if (y->color() != SparseArrayNode::Red) {
+ while (x != root && (x == 0 || x->color() == SparseArrayNode::Black)) {
+ if (x == x_parent->left) {
+ SparseArrayNode *w = x_parent->right;
+ if (w->color() == SparseArrayNode::Red) {
+ w->setColor(SparseArrayNode::Black);
+ x_parent->setColor(SparseArrayNode::Red);
+ rotateLeft(x_parent);
+ w = x_parent->right;
+ }
+ if ((w->left == 0 || w->left->color() == SparseArrayNode::Black) &&
+ (w->right == 0 || w->right->color() == SparseArrayNode::Black)) {
+ w->setColor(SparseArrayNode::Red);
+ x = x_parent;
+ x_parent = x_parent->parent();
+ } else {
+ if (w->right == 0 || w->right->color() == SparseArrayNode::Black) {
+ if (w->left)
+ w->left->setColor(SparseArrayNode::Black);
+ w->setColor(SparseArrayNode::Red);
+ rotateRight(w);
+ w = x_parent->right;
+ }
+ w->setColor(x_parent->color());
+ x_parent->setColor(SparseArrayNode::Black);
+ if (w->right)
+ w->right->setColor(SparseArrayNode::Black);
+ rotateLeft(x_parent);
+ break;
+ }
+ } else {
+ SparseArrayNode *w = x_parent->left;
+ if (w->color() == SparseArrayNode::Red) {
+ w->setColor(SparseArrayNode::Black);
+ x_parent->setColor(SparseArrayNode::Red);
+ rotateRight(x_parent);
+ w = x_parent->left;
+ }
+ if ((w->right == 0 || w->right->color() == SparseArrayNode::Black) &&
+ (w->left == 0 || w->left->color() == SparseArrayNode::Black)) {
+ w->setColor(SparseArrayNode::Red);
+ x = x_parent;
+ x_parent = x_parent->parent();
+ } else {
+ if (w->left == 0 || w->left->color() == SparseArrayNode::Black) {
+ if (w->right)
+ w->right->setColor(SparseArrayNode::Black);
+ w->setColor(SparseArrayNode::Red);
+ rotateLeft(w);
+ w = x_parent->left;
+ }
+ w->setColor(x_parent->color());
+ x_parent->setColor(SparseArrayNode::Black);
+ if (w->left)
+ w->left->setColor(SparseArrayNode::Black);
+ rotateRight(x_parent);
+ break;
+ }
+ }
+ }
+ if (x)
+ x->setColor(SparseArrayNode::Black);
+ }
+ free(y);
+ --numEntries;
+}
+
+void SparseArray::recalcMostLeftNode()
+{
+ mostLeftNode = &header;
+ while (mostLeftNode->left)
+ mostLeftNode = mostLeftNode->left;
+}
+
+static inline int qMapAlignmentThreshold()
+{
+ // malloc on 32-bit platforms should return pointers that are 8-byte
+ // aligned or more while on 64-bit platforms they should be 16-byte aligned
+ // or more
+ return 2 * sizeof(void*);
+}
+
+static inline void *qMapAllocate(int alloc, int alignment)
+{
+ return alignment > qMapAlignmentThreshold()
+ ? qMallocAligned(alloc, alignment)
+ : ::malloc(alloc);
+}
+
+static inline void qMapDeallocate(SparseArrayNode *node, int alignment)
+{
+ if (alignment > qMapAlignmentThreshold())
+ qFreeAligned(node);
+ else
+ ::free(node);
+}
+
+SparseArrayNode *SparseArray::createNode(uint sl, SparseArrayNode *parent, bool left)
+{
+ SparseArrayNode *node = static_cast<SparseArrayNode *>(qMapAllocate(sizeof(SparseArrayNode), Q_ALIGNOF(SparseArrayNode)));
+ Q_CHECK_PTR(node);
+
+ node->p = (quintptr)parent;
+ node->left = 0;
+ node->right = 0;
+ node->size_left = sl;
+ node->value = UINT_MAX;
+ ++numEntries;
+
+ if (parent) {
+ if (left) {
+ parent->left = node;
+ if (parent == mostLeftNode)
+ mostLeftNode = node;
+ } else {
+ parent->right = node;
+ }
+ node->setParent(parent);
+ rebalance(node);
+ }
+ return node;
+}
+
+void SparseArray::freeTree(SparseArrayNode *root, int alignment)
+{
+ if (root->left)
+ freeTree(root->left, alignment);
+ if (root->right)
+ freeTree(root->right, alignment);
+ qMapDeallocate(root, alignment);
+}
+
+SparseArray::SparseArray()
+ : numEntries(0)
+{
+ header.p = 0;
+ header.left = 0;
+ header.right = 0;
+ mostLeftNode = &header;
+}
+
+SparseArray::SparseArray(const SparseArray &other)
+{
+ header.p = 0;
+ header.right = 0;
+ if (other.header.left) {
+ header.left = other.header.left->copy(this);
+ header.left->setParent(&header);
+ recalcMostLeftNode();
+ }
+}
+
+SparseArrayNode *SparseArray::insert(uint akey)
+{
+ SparseArrayNode *n = root();
+ SparseArrayNode *y = end();
+ bool left = true;
+ uint s = akey;
+ while (n) {
+ y = n;
+ if (s == n->size_left) {
+ return n;
+ } else if (s < n->size_left) {
+ left = true;
+ n = n->left;
+ } else {
+ left = false;
+ s -= n->size_left;
+ n = n->right;
+ }
+ }
+
+ return createNode(s, y, left);
+}
diff --git a/src/qml/qml/v4/qv4sparsearray_p.h b/src/qml/qml/v4/qv4sparsearray_p.h
new file mode 100644
index 0000000000..384d2ef045
--- /dev/null
+++ b/src/qml/qml/v4/qv4sparsearray_p.h
@@ -0,0 +1,367 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4ARRAY_H
+#define QV4ARRAY_H
+
+#include "qv4global_p.h"
+#include <QtCore/qmap.h>
+#include "qv4value_p.h"
+#include "qv4property_p.h"
+#include <assert.h>
+
+#ifdef Q_MAP_DEBUG
+#include <QtCore/qdebug.h>
+#endif
+
+#include <new>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct SparseArray;
+
+class ArrayElementLessThan
+{
+public:
+ inline ArrayElementLessThan(ExecutionContext *context, Object *thisObject, const Value &comparefn)
+ : m_context(context), thisObject(thisObject), m_comparefn(comparefn) {}
+
+ bool operator()(const Property &v1, const Property &v2) const;
+
+private:
+ ExecutionContext *m_context;
+ Object *thisObject;
+ Value m_comparefn;
+};
+
+
+struct SparseArrayNode
+{
+ quintptr p;
+ SparseArrayNode *left;
+ SparseArrayNode *right;
+ uint size_left;
+ uint value;
+
+ enum Color { Red = 0, Black = 1 };
+ enum { Mask = 3 }; // reserve the second bit as well
+
+ const SparseArrayNode *nextNode() const;
+ SparseArrayNode *nextNode() { return const_cast<SparseArrayNode *>(const_cast<const SparseArrayNode *>(this)->nextNode()); }
+ const SparseArrayNode *previousNode() const;
+ SparseArrayNode *previousNode() { return const_cast<SparseArrayNode *>(const_cast<const SparseArrayNode *>(this)->previousNode()); }
+
+ Color color() const { return Color(p & 1); }
+ void setColor(Color c) { if (c == Black) p |= Black; else p &= ~Black; }
+ SparseArrayNode *parent() const { return reinterpret_cast<SparseArrayNode *>(p & ~Mask); }
+ void setParent(SparseArrayNode *pp) { p = (p & Mask) | quintptr(pp); }
+
+ uint key() const {
+ uint k = size_left;
+ const SparseArrayNode *n = this;
+ while (SparseArrayNode *p = n->parent()) {
+ if (p && p->right == n)
+ k += p->size_left;
+ n = p;
+ }
+ return k;
+ }
+
+ SparseArrayNode *copy(SparseArray *d) const;
+
+ SparseArrayNode *lowerBound(uint key);
+ SparseArrayNode *upperBound(uint key);
+};
+
+
+inline SparseArrayNode *SparseArrayNode::lowerBound(uint akey)
+{
+ SparseArrayNode *n = this;
+ SparseArrayNode *last = 0;
+ while (n) {
+ if (akey <= n->size_left) {
+ last = n;
+ n = n->left;
+ } else {
+ akey -= n->size_left;
+ n = n->right;
+ }
+ }
+ return last;
+}
+
+
+inline SparseArrayNode *SparseArrayNode::upperBound(uint akey)
+{
+ SparseArrayNode *n = this;
+ SparseArrayNode *last = 0;
+ while (n) {
+ if (akey < n->size_left) {
+ last = n;
+ n = n->left;
+ } else {
+ akey -= n->size_left;
+ n = n->right;
+ }
+ }
+ return last;
+}
+
+
+
+struct Q_QML_EXPORT SparseArray
+{
+ SparseArray();
+ ~SparseArray() {
+ if (root())
+ freeTree(header.left, Q_ALIGNOF(SparseArrayNode));
+ }
+
+ SparseArray(const SparseArray &other);
+private:
+ SparseArray &operator=(const SparseArray &other);
+
+ int numEntries;
+ SparseArrayNode header;
+ SparseArrayNode *mostLeftNode;
+
+ void rotateLeft(SparseArrayNode *x);
+ void rotateRight(SparseArrayNode *x);
+ void rebalance(SparseArrayNode *x);
+ void recalcMostLeftNode();
+
+ SparseArrayNode *root() const { return header.left; }
+
+ void deleteNode(SparseArrayNode *z);
+
+
+public:
+ SparseArrayNode *createNode(uint sl, SparseArrayNode *parent, bool left);
+ void freeTree(SparseArrayNode *root, int alignment);
+
+ SparseArrayNode *findNode(uint akey) const;
+
+ uint pop_front();
+ void push_front(uint at);
+ uint pop_back(uint len);
+ void push_back(uint at, uint len);
+
+ QList<int> keys() const;
+
+ const SparseArrayNode *end() const { return &header; }
+ SparseArrayNode *end() { return &header; }
+ const SparseArrayNode *begin() const { if (root()) return mostLeftNode; return end(); }
+ SparseArrayNode *begin() { if (root()) return mostLeftNode; return end(); }
+
+ SparseArrayNode *erase(SparseArrayNode *n);
+
+ SparseArrayNode *lowerBound(uint key);
+ const SparseArrayNode *lowerBound(uint key) const;
+ SparseArrayNode *upperBound(uint key);
+ const SparseArrayNode *upperBound(uint key) const;
+ SparseArrayNode *insert(uint akey);
+
+ // STL compatibility
+ typedef uint key_type;
+ typedef int mapped_type;
+ typedef qptrdiff difference_type;
+ typedef int size_type;
+
+#ifdef Q_MAP_DEBUG
+ void dump() const;
+#endif
+};
+
+inline SparseArrayNode *SparseArray::findNode(uint akey) const
+{
+ SparseArrayNode *n = root();
+
+ while (n) {
+ if (akey == n->size_left) {
+ return n;
+ } else if (akey < n->size_left) {
+ n = n->left;
+ } else {
+ akey -= n->size_left;
+ n = n->right;
+ }
+ }
+
+ return 0;
+}
+
+inline uint SparseArray::pop_front()
+{
+ uint idx = UINT_MAX ;
+
+ SparseArrayNode *n = findNode(0);
+ if (n) {
+ idx = n->value;
+ deleteNode(n);
+ // adjust all size_left indices on the path to leftmost item by 1
+ SparseArrayNode *n = root();
+ while (n) {
+ n->size_left -= 1;
+ n = n->left;
+ }
+ }
+ return idx;
+}
+
+inline void SparseArray::push_front(uint value)
+{
+ // adjust all size_left indices on the path to leftmost item by 1
+ SparseArrayNode *n = root();
+ while (n) {
+ n->size_left += 1;
+ n = n->left;
+ }
+ n = insert(0);
+ n->value = value;
+}
+
+inline uint SparseArray::pop_back(uint len)
+{
+ uint idx = UINT_MAX;
+ if (!len)
+ return idx;
+
+ SparseArrayNode *n = findNode(len - 1);
+ if (n) {
+ idx = n->value;
+ deleteNode(n);
+ }
+ return idx;
+}
+
+inline void SparseArray::push_back(uint index, uint len)
+{
+ SparseArrayNode *n = insert(len);
+ n->value = index;
+}
+
+#ifdef Q_MAP_DEBUG
+
+void SparseArray::dump() const
+{
+ const_iterator it = begin();
+ qDebug() << "map dump:";
+ while (it != end()) {
+ const SparseArrayNode *n = it.i;
+ int depth = 0;
+ while (n && n != root()) {
+ ++depth;
+ n = n->parent();
+ }
+ QByteArray space(4*depth, ' ');
+ qDebug() << space << (it.i->color() == SparseArrayNode::Red ? "Red " : "Black") << it.i << it.i->left << it.i->right
+ << it.key() << it.value();
+ ++it;
+ }
+ qDebug() << "---------";
+}
+#endif
+
+
+inline SparseArrayNode *SparseArray::erase(SparseArrayNode *n)
+{
+ if (n == end())
+ return n;
+
+ SparseArrayNode *next = n->nextNode();
+ deleteNode(n);
+ return next;
+}
+
+inline QList<int> SparseArray::keys() const
+{
+ QList<int> res;
+ res.reserve(numEntries);
+ SparseArrayNode *n = mostLeftNode;
+ while (n != end()) {
+ res.append(n->key());
+ n = n->nextNode();
+ }
+ return res;
+}
+
+inline const SparseArrayNode *SparseArray::lowerBound(uint akey) const
+{
+ const SparseArrayNode *lb = root()->lowerBound(akey);
+ if (!lb)
+ lb = end();
+ return lb;
+}
+
+
+inline SparseArrayNode *SparseArray::lowerBound(uint akey)
+{
+ SparseArrayNode *lb = root()->lowerBound(akey);
+ if (!lb)
+ lb = end();
+ return lb;
+}
+
+
+inline const SparseArrayNode *SparseArray::upperBound(uint akey) const
+{
+ const SparseArrayNode *ub = root()->upperBound(akey);
+ if (!ub)
+ ub = end();
+ return ub;
+}
+
+
+inline SparseArrayNode *SparseArray::upperBound(uint akey)
+{
+ SparseArrayNode *ub = root()->upperBound(akey);
+ if (!ub)
+ ub = end();
+ return ub;
+}
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QMAP_H
diff --git a/src/qml/qml/v4/qv4ssa.cpp b/src/qml/qml/v4/qv4ssa.cpp
new file mode 100644
index 0000000000..a139ed9fff
--- /dev/null
+++ b/src/qml/qml/v4/qv4ssa.cpp
@@ -0,0 +1,2122 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4ssa_p.h"
+#include "qv4util_p.h"
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QStringList>
+#include <QtCore/QSet>
+#include <QtCore/QBuffer>
+#include <QtCore/QLinkedList>
+#include <QtCore/QStack>
+#include <qv4runtime_p.h>
+#include <qv4context_p.h>
+#include <cmath>
+#include <iostream>
+#include <cassert>
+
+#ifdef CONST
+#undef CONST
+#endif
+
+#define QV4_NO_LIVENESS
+#undef SHOW_SSA
+
+QT_USE_NAMESPACE
+
+using namespace QQmlJS;
+using namespace V4IR;
+
+namespace {
+
+QTextStream qout(stdout, QIODevice::WriteOnly);
+
+void showMeTheCode(Function *function)
+{
+ static bool showCode = !qgetenv("SHOW_CODE").isNull();
+ if (showCode) {
+ QVector<Stmt *> code;
+ QHash<Stmt *, BasicBlock *> leader;
+
+ foreach (BasicBlock *block, function->basicBlocks) {
+ if (block->statements.isEmpty())
+ continue;
+ leader.insert(block->statements.first(), block);
+ foreach (Stmt *s, block->statements) {
+ code.append(s);
+ }
+ }
+
+ QString name;
+ if (function->name && !function->name->isEmpty())
+ name = *function->name;
+ else
+ name.sprintf("%p", function);
+
+ qout << "function " << name << "(";
+ for (int i = 0; i < function->formals.size(); ++i) {
+ if (i != 0)
+ qout << ", ";
+ qout << *function->formals.at(i);
+ }
+ qout << ")" << endl
+ << "{" << endl;
+
+ foreach (const QString *local, function->locals) {
+ qout << " var " << *local << ';' << endl;
+ }
+
+ for (int i = 0; i < code.size(); ++i) {
+ Stmt *s = code.at(i);
+
+ if (BasicBlock *bb = leader.value(s)) {
+ qout << endl;
+ QByteArray str;
+ str.append('L');
+ str.append(QByteArray::number(bb->index));
+ str.append(':');
+ for (int i = 66 - str.length(); i; --i)
+ str.append(' ');
+ qout << str;
+ qout << "// predecessor blocks:";
+ foreach (BasicBlock *in, bb->in)
+ qout << " L" << in->index;
+ if (bb->in.isEmpty())
+ qout << "(none)";
+ if (BasicBlock *container = bb->containingGroup())
+ qout << "; container block: L" << container->index;
+ if (bb->isGroupStart())
+ qout << "; group start";
+ qout << endl;
+ }
+ Stmt *n = (i + 1) < code.size() ? code.at(i + 1) : 0;
+// if (n && s->asJump() && s->asJump()->target == leader.value(n)) {
+// continue;
+// }
+
+ QByteArray str;
+ QBuffer buf(&str);
+ buf.open(QIODevice::WriteOnly);
+ QTextStream out(&buf);
+ if (s->id > 0)
+ out << s->id << ": ";
+ s->dump(out, Stmt::MIR);
+ out.flush();
+
+ if (s->location.isValid())
+ qout << " // line: " << s->location.startLine << " column: " << s->location.startColumn << endl;
+
+#ifndef QV4_NO_LIVENESS
+ for (int i = 60 - str.size(); i >= 0; --i)
+ str.append(' ');
+
+ qout << " " << str;
+
+ // if (! s->uses.isEmpty()) {
+ // qout << " // uses:";
+ // foreach (unsigned use, s->uses) {
+ // qout << " %" << use;
+ // }
+ // }
+
+ // if (! s->defs.isEmpty()) {
+ // qout << " // defs:";
+ // foreach (unsigned def, s->defs) {
+ // qout << " %" << def;
+ // }
+ // }
+
+# if 0
+ if (! s->d->liveIn.isEmpty()) {
+ qout << " // lives in:";
+ for (int i = 0; i < s->d->liveIn.size(); ++i) {
+ if (s->d->liveIn.testBit(i))
+ qout << " %" << i;
+ }
+ }
+# else
+ if (! s->d->liveOut.isEmpty()) {
+ qout << " // lives out:";
+ for (int i = 0; i < s->d->liveOut.size(); ++i) {
+ if (s->d->liveOut.testBit(i))
+ qout << " %" << i;
+ }
+ }
+# endif
+#else
+ qout << " " << str;
+#endif
+
+ qout << endl;
+
+ if (n && s->asCJump() /*&& s->asCJump()->iffalse != leader.value(n)*/) {
+ qout << " else goto L" << s->asCJump()->iffalse->index << ";" << endl;
+ }
+ }
+
+ qout << "}" << endl
+ << endl;
+ }
+}
+
+class DominatorTree {
+ int N;
+ QHash<BasicBlock *, int> dfnum;
+ QVector<BasicBlock *> vertex;
+ QHash<BasicBlock *, BasicBlock *> parent;
+ QHash<BasicBlock *, BasicBlock *> ancestor;
+ QHash<BasicBlock *, BasicBlock *> best;
+ QHash<BasicBlock *, BasicBlock *> semi;
+ QHash<BasicBlock *, BasicBlock *> idom;
+ QHash<BasicBlock *, BasicBlock *> samedom;
+ QHash<BasicBlock *, QSet<BasicBlock *> > bucket;
+
+ void DFS(BasicBlock *p, BasicBlock *n) {
+ if (dfnum[n] == 0) {
+ dfnum[n] = N;
+ vertex[N] = n;
+ parent[n] = p;
+ ++N;
+ foreach (BasicBlock *w, n->out)
+ DFS(n, w);
+ }
+ }
+
+ BasicBlock *ancestorWithLowestSemi(BasicBlock *v) {
+ BasicBlock *a = ancestor[v];
+ if (ancestor[a]) {
+ BasicBlock *b = ancestorWithLowestSemi(a);
+ ancestor[v] = ancestor[a];
+ if (dfnum[semi[b]] < dfnum[semi[best[v]]])
+ best[v] = b;
+ }
+ return best[v];
+ }
+
+ void link(BasicBlock *p, BasicBlock *n) {
+ ancestor[n] = p;
+ best[n] = n;
+ }
+
+ void calculateIDoms(const QVector<BasicBlock *> &nodes) {
+ Q_ASSERT(nodes.first()->in.isEmpty());
+ vertex.resize(nodes.size());
+ foreach (BasicBlock *n, nodes) {
+ dfnum[n] = 0;
+ semi[n] = 0;
+ ancestor[n] = 0;
+ idom[n] = 0;
+ samedom[n] = 0;
+ }
+
+ DFS(0, nodes.first());
+ Q_ASSERT(N == nodes.size()); // fails with unreachable nodes...
+
+ for (int i = N - 1; i > 0; --i) {
+ BasicBlock *n = vertex[i];
+ BasicBlock *p = parent[n];
+ BasicBlock *s = p;
+
+ foreach (BasicBlock *v, n->in) {
+ BasicBlock *ss;
+ if (dfnum[v] <= dfnum[n])
+ ss = v;
+ else
+ ss = semi[ancestorWithLowestSemi(v)];
+ if (dfnum[ss] < dfnum[s])
+ s = ss;
+ }
+ semi[n] = s;
+ bucket[s].insert(n);
+ link(p, n);
+ foreach (BasicBlock *v, bucket[p]) {
+ BasicBlock *y = ancestorWithLowestSemi(v);
+ Q_ASSERT(semi[y] == p);
+ if (semi[y] == semi[v])
+ idom[v] = p;
+ else
+ samedom[v] = y;
+ }
+ bucket[p].clear();
+ }
+ for (int i = 1; i < N; ++i) {
+ BasicBlock *n = vertex[i];
+ Q_ASSERT(ancestor[n] && ((semi[n] && dfnum[ancestor[n]] <= dfnum[semi[n]]) || semi[n] == n));
+ Q_ASSERT(bucket[n].isEmpty());
+ if (BasicBlock *sdn = samedom[n])
+ idom[n] = idom[sdn];
+ }
+
+#ifdef SHOW_SSA
+ qout << "Immediate dominators:" << endl;
+ foreach (BasicBlock *to, nodes) {
+ qout << '\t';
+ if (BasicBlock *from = idom.value(to))
+ qout << from->index;
+ else
+ qout << "(none)";
+ qout << " -> " << to->index << endl;
+ }
+#endif // SHOW_SSA
+ }
+
+ bool dominates(BasicBlock *dominator, BasicBlock *dominated) const {
+ for (BasicBlock *it = dominated; it; it = idom[it]) {
+ if (it == dominator)
+ return true;
+ }
+
+ return false;
+ }
+
+ void computeDF(BasicBlock *n) {
+ if (DF.contains(n))
+ return; // TODO: verify this!
+
+ QSet<BasicBlock *> S;
+ foreach (BasicBlock *y, n->out)
+ if (idom[y] != n)
+ S.insert(y);
+
+ /*
+ * foreach child c of n in the dominator tree
+ * computeDF[c]
+ * foreach element w of DF[c]
+ * if n does not dominate w or if n = w
+ * S.insert(w)
+ * DF[n] = S;
+ */
+ foreach (BasicBlock *c, children[n]) {
+ computeDF(c);
+ foreach (BasicBlock *w, DF[c])
+ if (!dominates(n, w) || n == w)
+ S.insert(w);
+ }
+ DF[n] = S;
+
+#ifdef SHOW_SSA
+ qout << "\tDF[" << n->index << "]: {";
+ QList<BasicBlock *> SList = S.values();
+ for (int i = 0; i < SList.size(); ++i) {
+ if (i > 0)
+ qout << ", ";
+ qout << SList[i]->index;
+ }
+ qout << "}" << endl;
+#endif // SHOW_SSA
+#ifndef QT_NO_DEBUG
+ foreach (BasicBlock *fBlock, S) {
+ Q_ASSERT(!dominates(n, fBlock) || fBlock == n);
+ bool hasDominatedSucc = false;
+ foreach (BasicBlock *succ, fBlock->in)
+ if (dominates(n, succ))
+ hasDominatedSucc = true;
+ if (!hasDominatedSucc) {
+ qout << fBlock->index << " in DF[" << n->index << "] has no dominated predecessors" << endl;
+ }
+ Q_ASSERT(hasDominatedSucc);
+ }
+#endif // !QT_NO_DEBUG
+ }
+
+ QHash<BasicBlock *, QSet<BasicBlock *> > children;
+ QHash<BasicBlock *, QSet<BasicBlock *> > DF;
+
+public:
+ DominatorTree(const QVector<BasicBlock *> &nodes)
+ : N(0)
+ {
+ calculateIDoms(nodes);
+
+ // compute children of n
+ foreach (BasicBlock *n, nodes)
+ children[idom[n]].insert(n);
+
+#ifdef SHOW_SSA
+ qout << "Dominator Frontiers:" << endl;
+#endif // SHOW_SSA
+ foreach (BasicBlock *n, nodes)
+ computeDF(n);
+ }
+
+ QSet<BasicBlock *> operator[](BasicBlock *n) const {
+ return DF[n];
+ }
+
+ BasicBlock *immediateDominator(BasicBlock *bb) const {
+ return idom[bb];
+ }
+};
+
+class VariableCollector: public StmtVisitor, ExprVisitor {
+ QHash<Temp, QSet<BasicBlock *> > _defsites;
+ QHash<BasicBlock *, QSet<Temp> > A_orig;
+ QSet<Temp> nonLocals;
+ QSet<Temp> killed;
+
+ BasicBlock *currentBB;
+ const bool variablesCanEscape;
+ bool isCollectable(Temp *t) const
+ {
+ switch (t->kind) {
+ case Temp::Formal:
+ case Temp::ScopedFormal:
+ case Temp::ScopedLocal:
+ return false;
+ case Temp::Local:
+ return !variablesCanEscape;
+ case Temp::VirtualRegister:
+ return true;
+ default:
+ // PhysicalRegister and StackSlot can only get inserted later.
+ Q_ASSERT(!"Invalid temp kind!");
+ return false;
+ }
+ }
+
+public:
+ VariableCollector(Function *function)
+ : variablesCanEscape(function->variablesCanEscape())
+ {
+#ifdef SHOW_SSA
+ qout << "Variables collected:" << endl;
+#endif // SHOW_SSA
+
+ foreach (BasicBlock *bb, function->basicBlocks) {
+ currentBB = bb;
+ killed.clear();
+ killed.reserve(bb->statements.size() / 2);
+ foreach (Stmt *s, bb->statements) {
+ s->accept(this);
+ }
+ }
+
+#ifdef SHOW_SSA
+ qout << "Non-locals:" << endl;
+ foreach (const Temp &nonLocal, nonLocals) {
+ qout << "\t";
+ nonLocal.dump(qout);
+ qout << endl;
+ }
+
+ qout << "end collected variables." << endl;
+#endif // SHOW_SSA
+ }
+
+ QList<Temp> vars() const {
+ return _defsites.keys();
+ }
+
+ QSet<BasicBlock *> defsite(const Temp &n) const {
+ return _defsites[n];
+ }
+
+ QSet<Temp> inBlock(BasicBlock *n) const {
+ return A_orig[n];
+ }
+
+ bool isNonLocal(const Temp &var) const { return nonLocals.contains(var); }
+
+protected:
+ virtual void visitPhi(Phi *) {};
+ virtual void visitConvert(Convert *e) { e->expr->accept(this); };
+
+ virtual void visitConst(Const *) {}
+ virtual void visitString(String *) {}
+ virtual void visitRegExp(RegExp *) {}
+ virtual void visitName(Name *) {}
+ virtual void visitClosure(Closure *) {}
+ virtual void visitUnop(Unop *e) { e->expr->accept(this); }
+ virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
+ virtual void visitSubscript(Subscript *e) { e->base->accept(this); e->index->accept(this); }
+ virtual void visitMember(Member *e) { e->base->accept(this); }
+ virtual void visitExp(Exp *s) { s->expr->accept(this); }
+ virtual void visitJump(Jump *) {}
+ virtual void visitCJump(CJump *s) { s->cond->accept(this); }
+ virtual void visitRet(Ret *s) { s->expr->accept(this); }
+ virtual void visitTry(Try *) { // ### TODO
+ }
+
+ virtual void visitCall(Call *e) {
+ e->base->accept(this);
+ for (ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+
+ virtual void visitNew(New *e) {
+ e->base->accept(this);
+ for (ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+
+ virtual void visitMove(Move *s) {
+ s->source->accept(this);
+
+ if (Temp *t = s->target->asTemp()) {
+ if (isCollectable(t)) {
+#ifdef SHOW_SSA
+ qout << '\t';
+ t->dump(qout);
+ qout << " -> L" << currentBB->index << endl;
+#endif // SHOW_SSA
+
+ _defsites[*t].insert(currentBB);
+ A_orig[currentBB].insert(*t);
+
+ // For semi-pruned SSA:
+ killed.insert(*t);
+ }
+ }
+ }
+
+ virtual void visitTemp(Temp *t)
+ {
+ if (isCollectable(t))
+ if (!killed.contains(*t))
+ nonLocals.insert(*t);
+ }
+};
+
+void insertPhiNode(const Temp &a, BasicBlock *y, Function *f) {
+#if defined(SHOW_SSA)
+ qout << "-> inserted phi node for variable ";
+ a.dump(qout);
+ qout << " in block " << y->index << endl;
+#endif
+
+ Phi *phiNode = f->New<Phi>();
+ phiNode->targetTemp = f->New<Temp>();
+ phiNode->targetTemp->init(a.kind, a.index, 0);
+ y->statements.prepend(phiNode);
+
+ phiNode->incoming.resize(y->in.size());
+ for (int i = 0, ei = y->in.size(); i < ei; ++i) {
+ Temp *t = f->New<Temp>();
+ t->init(a.kind, a.index, 0);
+ phiNode->incoming[i] = t;
+ }
+}
+
+class VariableRenamer: public StmtVisitor, public ExprVisitor
+{
+ Function *function;
+ QHash<Temp, QStack<unsigned> > stack;
+ QSet<BasicBlock *> seen;
+
+ QHash<Temp, unsigned> defCounts;
+
+ const bool variablesCanEscape;
+ bool isRenamable(Temp *t) const
+ {
+ switch (t->kind) {
+ case Temp::Formal:
+ case Temp::ScopedFormal:
+ case Temp::ScopedLocal:
+ return false;
+ case Temp::Local:
+ return !variablesCanEscape;
+ case Temp::VirtualRegister:
+ return true;
+ default:
+ Q_ASSERT(!"Invalid temp kind!");
+ return false;
+ }
+ }
+ int nextFreeTemp() {
+ const int next = function->tempCount++;
+// qDebug()<<"Next free temp:"<<next;
+ return next;
+ }
+
+ /*
+
+ Initialization:
+ for each variable a
+ count[a] = 0;
+ stack[a] = empty;
+ push 0 onto stack
+
+ Rename(n) =
+ for each statement S in block n [1]
+ if S not in a phi-function
+ for each use of some variable x in S
+ i = top(stack[x])
+ replace the use of x with x_i in S
+ for each definition of some variable a in S
+ count[a] = count[a] + 1
+ i = count[a]
+ push i onto stack[a]
+ replace definition of a with definition of a_i in S
+ for each successor Y of block n [2]
+ Suppose n is the j-th predecessor of Y
+ for each phi function in Y
+ suppose the j-th operand of the phi-function is a
+ i = top(stack[a])
+ replace the j-th operand with a_i
+ for each child X of n [3]
+ Rename(X)
+ for each statement S in block n [4]
+ for each definition of some variable a in S
+ pop stack[a]
+
+ */
+
+public:
+ VariableRenamer(Function *f)
+ : function(f)
+ , variablesCanEscape(f->variablesCanEscape())
+ {
+ if (!variablesCanEscape) {
+ Temp t;
+ t.init(Temp::Local, 0, 0);
+ for (int i = 0, ei = f->locals.size(); i != ei; ++i) {
+ t.index = i;
+ stack[t].push(nextFreeTemp());
+ }
+ }
+
+ Temp t;
+ t.init(Temp::VirtualRegister, 0, 0);
+ for (int i = 0, ei = f->tempCount; i != ei; ++i) {
+ t.index = i;
+ stack[t].push(i);
+ }
+ }
+
+ void run() {
+ foreach (BasicBlock *n, function->basicBlocks)
+ rename(n);
+
+#ifdef SHOW_SSA
+// qout << "Temp to local mapping:" << endl;
+// foreach (int key, tempMapping.keys())
+// qout << '\t' << key << " -> " << tempMapping[key] << endl;
+#endif
+ }
+
+ void rename(BasicBlock *n) {
+ if (seen.contains(n))
+ return;
+ seen.insert(n);
+// qDebug() << "I: L"<<n->index;
+
+ // [1]:
+ foreach (Stmt *s, n->statements)
+ s->accept(this);
+
+ QHash<Temp, unsigned> dc = defCounts;
+ defCounts.clear();
+
+ // [2]:
+ foreach (BasicBlock *Y, n->out) {
+ const int j = Y->in.indexOf(n);
+ Q_ASSERT(j >= 0 && j < Y->in.size());
+ foreach (Stmt *s, Y->statements) {
+ if (Phi *phi = s->asPhi()) {
+ Temp *t = phi->incoming[j]->asTemp();
+ unsigned newTmp = stack[*t].top();
+// qDebug()<<"I: replacing phi use"<<a<<"with"<<newTmp<<"in L"<<Y->index;
+ t->index = newTmp;
+ t->kind = Temp::VirtualRegister;
+ } else {
+ break;
+ }
+ }
+ }
+
+ // [3]:
+ foreach (BasicBlock *X, n->out)
+ rename(X);
+
+ // [4]:
+ for (QHash<Temp, unsigned>::const_iterator i = dc.begin(), ei = dc.end(); i != ei; ++i) {
+// qDebug()<<i.key() <<" -> " << i.value();
+ for (unsigned j = 0, ej = i.value(); j < ej; ++j)
+ stack[i.key()].pop();
+ }
+ }
+
+protected:
+ virtual void visitTemp(Temp *e) { // only called for uses, not defs
+ if (isRenamable(e)) {
+// qDebug()<<"I: replacing use of"<<e->index<<"with"<<stack[e->index].top();
+ e->index = stack[*e].top();
+ e->kind = Temp::VirtualRegister;
+ }
+ }
+
+ virtual void visitMove(Move *s) {
+ // uses:
+ s->source->accept(this);
+
+ // defs:
+ if (Temp *t = s->target->asTemp())
+ renameTemp(t);
+ else
+ s->target->accept(this);
+ }
+
+ void renameTemp(Temp *t) {
+ if (isRenamable(t)) {
+ defCounts[*t] = defCounts.value(*t, 0) + 1;
+ const int newIdx = nextFreeTemp();
+ stack[*t].push(newIdx);
+// qDebug()<<"I: replacing def of"<<a<<"with"<<newIdx;
+ t->kind = Temp::VirtualRegister;
+ t->index = newIdx;
+ }
+ }
+
+ virtual void visitConvert(Convert *e) { e->expr->accept(this); }
+ virtual void visitPhi(Phi *s) { renameTemp(s->targetTemp); }
+
+ virtual void visitExp(Exp *s) { s->expr->accept(this); }
+
+ virtual void visitJump(Jump *) {}
+ virtual void visitCJump(CJump *s) { s->cond->accept(this); }
+ virtual void visitRet(Ret *s) { s->expr->accept(this); }
+ virtual void visitTry(Try *s) { /* this should never happen */ }
+
+ virtual void visitConst(Const *) {}
+ virtual void visitString(String *) {}
+ virtual void visitRegExp(RegExp *) {}
+ virtual void visitName(Name *) {}
+ virtual void visitClosure(Closure *) {}
+ virtual void visitUnop(Unop *e) { e->expr->accept(this); }
+ virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
+ virtual void visitCall(Call *e) {
+ e->base->accept(this);
+ for (ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+
+ virtual void visitNew(New *e) {
+ e->base->accept(this);
+ for (ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+
+ virtual void visitSubscript(Subscript *e) {
+ e->base->accept(this);
+ e->index->accept(this);
+ }
+
+ virtual void visitMember(Member *e) {
+ e->base->accept(this);
+ }
+};
+
+void convertToSSA(Function *function, const DominatorTree &df)
+{
+#ifdef SHOW_SSA
+ qout << "Converting function ";
+ if (function->name)
+ qout << *function->name;
+ else
+ qout << "<no name>";
+ qout << " to SSA..." << endl;
+#endif // SHOW_SSA
+
+ // Collect all applicable variables:
+ VariableCollector variables(function);
+
+ // Place phi functions:
+ QHash<BasicBlock *, QSet<Temp> > A_phi;
+ foreach (Temp a, variables.vars()) {
+ if (!variables.isNonLocal(a))
+ continue; // for semi-pruned SSA
+
+ QList<BasicBlock *> W = QList<BasicBlock *>::fromSet(variables.defsite(a));
+ while (!W.isEmpty()) {
+ BasicBlock *n = W.first();
+ W.removeFirst();
+ foreach (BasicBlock *y, df[n]) {
+ if (!A_phi[y].contains(a)) {
+ insertPhiNode(a, y, function);
+ A_phi[y].insert(a);
+ if (!variables.inBlock(y).contains(a))
+ W.append(y);
+ }
+ }
+ }
+ }
+ showMeTheCode(function);
+
+ // Rename variables:
+ VariableRenamer(function).run();
+}
+
+class DefUsesCalculator: public StmtVisitor, public ExprVisitor {
+public:
+ struct DefUse {
+ DefUse()
+ : defStmt(0)
+ , blockOfStatement(0)
+ {}
+ Stmt *defStmt;
+ BasicBlock *blockOfStatement;
+ QList<Stmt *> uses;
+ };
+
+private:
+ const bool _variablesCanEscape;
+ QHash<Temp, DefUse> _defUses;
+ QHash<Stmt *, QList<Temp> > _usesPerStatement;
+
+ BasicBlock *_block;
+ Stmt *_stmt;
+
+ bool isCollectible(Temp *t) const {
+ switch (t->kind) {
+ case Temp::Formal:
+ case Temp::ScopedFormal:
+ case Temp::ScopedLocal:
+ return false;
+ case Temp::Local:
+ return !_variablesCanEscape;
+ case Temp::VirtualRegister:
+ return true;
+ default:
+ Q_UNREACHABLE();
+ return false;
+ }
+ }
+
+ void addUse(Temp *t) {
+ Q_ASSERT(t);
+ if (!isCollectible(t))
+ return;
+
+ _defUses[*t].uses.append(_stmt);
+ _usesPerStatement[_stmt].append(*t);
+ }
+
+ void addDef(Temp *t) {
+ if (!isCollectible(t))
+ return;
+
+ Q_ASSERT(!_defUses.contains(*t) || _defUses.value(*t).defStmt == 0 || _defUses.value(*t).defStmt == _stmt);
+
+ DefUse &defUse = _defUses[*t];
+ defUse.defStmt = _stmt;
+ defUse.blockOfStatement = _block;
+ }
+
+public:
+ DefUsesCalculator(Function *function)
+ : _variablesCanEscape(function->variablesCanEscape())
+ {
+ foreach (BasicBlock *bb, function->basicBlocks) {
+ _block = bb;
+ foreach (Stmt *stmt, bb->statements) {
+ _stmt = stmt;
+ stmt->accept(this);
+ }
+ }
+
+ QMutableHashIterator<Temp, DefUse> it(_defUses);
+ while (it.hasNext()) {
+ it.next();
+ if (!it.value().defStmt)
+ it.remove();
+ }
+ }
+
+ QList<Temp> defs() const {
+ return _defUses.keys();
+ }
+
+ void removeDef(const Temp &var) {
+ _defUses.remove(var);
+ }
+
+ void addUses(const Temp &variable, const QList<Stmt *> &newUses)
+ { _defUses[variable].uses.append(newUses); }
+
+ int useCount(const Temp &variable) const
+ { return _defUses[variable].uses.size(); }
+
+ Stmt *defStmt(const Temp &variable) const
+ { return _defUses[variable].defStmt; }
+
+ BasicBlock *defStmtBlock(const Temp &variable) const
+ { return _defUses[variable].blockOfStatement; }
+
+ void removeUse(Stmt *usingStmt, const Temp &var)
+ { _defUses[var].uses.removeAll(usingStmt); }
+
+ QList<Temp> usedVars(Stmt *s) const
+ { return _usesPerStatement[s]; }
+
+ QList<Stmt *> uses(const Temp &var) const
+ { return _defUses[var].uses; }
+
+ void dump() const
+ {
+ foreach (const Temp &var, _defUses.keys()) {
+ const DefUse &du = _defUses[var];
+ var.dump(qout);
+ qout<<" -> defined in block "<<du.blockOfStatement->index<<", statement: ";
+ du.defStmt->dump(qout);
+ qout<<endl<<" uses:"<<endl;
+ foreach (Stmt *s, du.uses) {
+ qout<<" ";s->dump(qout);qout<<endl;
+ }
+ }
+ }
+
+protected:
+ virtual void visitExp(Exp *s) { s->expr->accept(this); }
+ virtual void visitJump(Jump *) {}
+ virtual void visitCJump(CJump *s) { s->cond->accept(this); }
+ virtual void visitRet(Ret *s) { s->expr->accept(this); }
+ virtual void visitTry(Try *) {}
+
+ virtual void visitPhi(Phi *s) {
+ addDef(s->targetTemp);
+ foreach (Expr *e, s->incoming)
+ addUse(e->asTemp());
+ }
+
+ virtual void visitMove(Move *s) {
+ if (Temp *t = s->target->asTemp())
+ addDef(t);
+ else
+ s->target->accept(this);
+
+ s->source->accept(this);
+ }
+
+ virtual void visitTemp(Temp *e) { addUse(e); }
+
+ virtual void visitConst(Const *) {}
+ virtual void visitString(String *) {}
+ virtual void visitRegExp(RegExp *) {}
+ virtual void visitName(Name *) {}
+ virtual void visitClosure(Closure *) {}
+ virtual void visitConvert(Convert *e) { e->expr->accept(this); }
+ virtual void visitUnop(Unop *e) { e->expr->accept(this); }
+ virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
+ virtual void visitSubscript(Subscript *e) { e->base->accept(this); e->index->accept(this); }
+ virtual void visitMember(Member *e) { e->base->accept(this); }
+ virtual void visitCall(Call *e) {
+ e->base->accept(this);
+ for (ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+
+ virtual void visitNew(New *e) {
+ e->base->accept(this);
+ for (ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+};
+
+bool hasPhiOnlyUses(Phi *phi, const DefUsesCalculator &defUses, QSet<Phi *> &collectedPhis)
+{
+ collectedPhis.insert(phi);
+ foreach (Stmt *use, defUses.uses(*phi->targetTemp)) {
+ if (Phi *dependentPhi = use->asPhi()) {
+ if (!collectedPhis.contains(dependentPhi)) {
+ if (!hasPhiOnlyUses(dependentPhi, defUses, collectedPhis))
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ return true;
+}
+
+void cleanupPhis(DefUsesCalculator &defUses)
+{
+ QLinkedList<Phi *> phis;
+ foreach (const Temp &def, defUses.defs())
+ if (Phi *phi = defUses.defStmt(def)->asPhi())
+ phis.append(phi);
+
+ QSet<Phi *> toRemove;
+ while (!phis.isEmpty()) {
+ Phi *phi = phis.first();
+ phis.removeFirst();
+ if (toRemove.contains(phi))
+ continue;
+ QSet<Phi *> collectedPhis;
+ if (hasPhiOnlyUses(phi, defUses, collectedPhis))
+ toRemove.unite(collectedPhis);
+ }
+
+ foreach (Phi *phi, toRemove) {
+ Temp targetVar = *phi->targetTemp;
+
+ BasicBlock *bb = defUses.defStmtBlock(targetVar);
+ int idx = bb->statements.indexOf(phi);
+ bb->statements.remove(idx);
+
+ foreach (const Temp &usedVar, defUses.usedVars(phi))
+ defUses.removeUse(phi, usedVar);
+ defUses.removeDef(targetVar);
+ }
+}
+
+class DeadCodeElimination: public ExprVisitor {
+ const bool variablesCanEscape;
+ DefUsesCalculator &_defUses;
+ QVector<Temp> _worklist;
+
+public:
+ DeadCodeElimination(DefUsesCalculator &defUses, Function *function)
+ : variablesCanEscape(function->variablesCanEscape())
+ , _defUses(defUses)
+ {
+ _worklist = QVector<Temp>::fromList(_defUses.defs());
+ }
+
+ void run() {
+ while (!_worklist.isEmpty()) {
+ const Temp v = _worklist.first();
+ _worklist.removeFirst();
+
+ if (_defUses.useCount(v) == 0) {
+// qDebug()<<"-"<<v<<"has no uses...";
+ Stmt *s = _defUses.defStmt(v);
+ if (!s) {
+ _defUses.removeDef(v);
+ } else if (!hasSideEffect(s)) {
+#ifdef SHOW_SSA
+ qout<<"-- defining stmt for";
+ v.dump(qout);
+ qout<<"has no side effect"<<endl;
+#endif
+ QVector<Stmt *> &stmts = _defUses.defStmtBlock(v)->statements;
+ int idx = stmts.indexOf(s);
+ if (idx != -1)
+ stmts.remove(idx);
+ foreach (const Temp &usedVar, _defUses.usedVars(s)) {
+ _defUses.removeUse(s, usedVar);
+ _worklist.append(usedVar);
+ }
+ _defUses.removeDef(v);
+ }
+ }
+ }
+
+#ifdef SHOW_SSA
+ qout<<"******************* After dead-code elimination:";
+ _defUses.dump();
+#endif
+ }
+
+private:
+ bool _sideEffect;
+
+ bool hasSideEffect(Stmt *s) {
+ // TODO: check if this can be moved to IR building.
+ _sideEffect = false;
+ if (Move *move = s->asMove()) {
+ if (Temp *t = move->target->asTemp()) {
+ switch (t->kind) {
+ case Temp::Formal:
+ case Temp::ScopedFormal:
+ case Temp::ScopedLocal:
+ return true;
+ case Temp::Local:
+ if (variablesCanEscape)
+ return true;
+ else
+ break;
+ case Temp::VirtualRegister:
+ break;
+ default:
+ Q_ASSERT(!"Invalid temp kind!");
+ return true;
+ }
+ move->source->accept(this);
+ } else {
+ return true;
+ }
+ }
+ return _sideEffect;
+ }
+
+protected:
+ virtual void visitConst(Const *) {}
+ virtual void visitString(String *) {}
+ virtual void visitRegExp(RegExp *) {}
+ virtual void visitName(Name *e) {
+ // TODO: maybe we can distinguish between built-ins of which we know that they do not have
+ // a side-effect.
+ if (e->builtin == Name::builtin_invalid || (e->id && *e->id != QStringLiteral("this")))
+ _sideEffect = true;
+ }
+ virtual void visitTemp(Temp *e) {
+ }
+ virtual void visitClosure(Closure *) {}
+ virtual void visitConvert(Convert *e) {
+ // we do not have type information yet, so:
+ _sideEffect = true;
+ }
+
+ virtual void visitUnop(Unop *e) {
+ switch (e->op) {
+ case OpIncrement:
+ case OpDecrement:
+ _sideEffect = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!_sideEffect) e->expr->accept(this);
+ }
+ virtual void visitBinop(Binop *e) { if (!_sideEffect) e->left->accept(this); if (!_sideEffect) e->right->accept(this); }
+ virtual void visitSubscript(Subscript *e) {
+ // TODO: see if we can have subscript accesses without side effect
+ _sideEffect = true;
+ }
+ virtual void visitMember(Member *e) {
+ // TODO: see if we can have member accesses without side effect
+ _sideEffect = true;
+ }
+ virtual void visitCall(Call *e) {
+ _sideEffect = true; // TODO: there are built-in functions that have no side effect.
+ }
+ virtual void visitNew(New *e) {
+ _sideEffect = true; // TODO: there are built-in types that have no side effect.
+ }
+};
+
+class TypeInference: public StmtVisitor, public ExprVisitor {
+ bool _variablesCanEscape;
+ const DefUsesCalculator &_defUses;
+ QHash<Temp, int> _tempTypes;
+ QSet<Stmt *> _worklist;
+ struct TypingResult {
+ int type;
+ bool fullyTyped;
+
+ TypingResult(int type, bool fullyTyped): type(type), fullyTyped(fullyTyped) {}
+ explicit TypingResult(int type = UnknownType): type(type), fullyTyped(type != UnknownType) {}
+ };
+ TypingResult _ty;
+
+public:
+ TypeInference(const DefUsesCalculator &defUses)
+ : _defUses(defUses)
+ , _ty(UnknownType)
+ {}
+
+ void run(Function *function) {
+ _variablesCanEscape = function->variablesCanEscape();
+
+ // TODO: the worklist handling looks a bit inefficient... check if there is something better
+ _worklist.clear();
+ for (int i = 0, ei = function->basicBlocks.size(); i != ei; ++i) {
+ BasicBlock *bb = function->basicBlocks[i];
+ if (i == 0 || !bb->in.isEmpty())
+ foreach (Stmt *s, bb->statements)
+ _worklist.insert(s);
+ }
+
+ while (!_worklist.isEmpty()) {
+ QList<Stmt *> worklist = _worklist.values();
+ _worklist.clear();
+ while (!worklist.isEmpty()) {
+ Stmt *s = worklist.first();
+ worklist.removeFirst();
+#if defined(SHOW_SSA)
+ qout<<"Typing stmt ";s->dump(qout);qout<<endl;
+#endif
+
+ if (!run(s)) {
+ _worklist.insert(s);
+#if defined(SHOW_SSA)
+ qout<<"Pushing back stmt: ";
+ s->dump(qout);qout<<endl;
+ } else {
+ qout<<"Finished: ";
+ s->dump(qout);qout<<endl;
+#endif
+ }
+ }
+ }
+ }
+
+private:
+ bool run(Stmt *s) {
+ TypingResult ty;
+ std::swap(_ty, ty);
+ s->accept(this);
+ std::swap(_ty, ty);
+ return ty.fullyTyped;
+ }
+
+ TypingResult run(Expr *e) {
+ TypingResult ty;
+ std::swap(_ty, ty);
+ e->accept(this);
+ std::swap(_ty, ty);
+
+ if (ty.type != UnknownType)
+ setType(e, ty.type);
+ return ty;
+ }
+
+ bool isAlwaysAnObject(Temp *t) {
+ switch (t->kind) {
+ case Temp::Formal:
+ case Temp::ScopedFormal:
+ case Temp::ScopedLocal:
+ return true;
+ case Temp::Local:
+ return _variablesCanEscape;
+ default:
+ return false;
+ }
+ }
+
+ void setType(Expr *e, int ty) {
+ if (Temp *t = e->asTemp()) {
+#if defined(SHOW_SSA)
+ qout<<"Setting type for "<< (t->scope?"scoped temp ":"temp ") <<t->index<< " to "<<typeName(Type(ty)) << " (" << ty << ")" << endl;
+#endif
+ if (isAlwaysAnObject(t)) {
+ e->type = ObjectType;
+ } else {
+ e->type = (Type) ty;
+
+ if (_tempTypes[*t] != ty) {
+ _tempTypes[*t] = ty;
+
+#if defined(SHOW_SSA)
+ foreach (Stmt *s, _defUses.uses(*t)) {
+ qout << "Pushing back dependent stmt: ";
+ s->dump(qout);
+ qout << endl;
+ }
+#endif
+
+ _worklist += QSet<Stmt *>::fromList(_defUses.uses(*t));
+ }
+ }
+ } else {
+ e->type = (Type) ty;
+ }
+ }
+
+protected:
+ virtual void visitConst(Const *e) { _ty = TypingResult(e->type); }
+ virtual void visitString(String *) { _ty = TypingResult(StringType); }
+ virtual void visitRegExp(RegExp *) { _ty = TypingResult(ObjectType); }
+ virtual void visitName(Name *) { _ty = TypingResult(ObjectType); }
+ virtual void visitTemp(Temp *e) {
+ if (isAlwaysAnObject(e))
+ _ty = TypingResult(ObjectType);
+ else
+ _ty = TypingResult(_tempTypes.value(*e, UnknownType));
+ setType(e, _ty.type);
+ }
+ virtual void visitClosure(Closure *) { _ty = TypingResult(ObjectType); } // TODO: VERIFY THIS!
+ virtual void visitConvert(Convert *e) {
+ _ty = run(e->expr);
+ }
+
+ virtual void visitUnop(Unop *e) {
+ _ty = run(e->expr);
+ switch (e->op) {
+ case OpUPlus: _ty.type = DoubleType; return;
+ case OpUMinus: _ty.type = DoubleType; return;
+ case OpCompl: _ty.type = SInt32Type; return;
+ case OpNot: _ty.type = BoolType; return;
+
+ case OpIncrement:
+ case OpDecrement:
+ Q_ASSERT(!"Inplace operators should have been removed!");
+ default:
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+ }
+ }
+
+ virtual void visitBinop(Binop *e) {
+ TypingResult leftTy = run(e->left);
+ TypingResult rightTy = run(e->right);
+ _ty.fullyTyped = leftTy.fullyTyped && rightTy.fullyTyped;
+
+ switch (e->op) {
+ case OpAdd:
+ if (leftTy.type & StringType || rightTy.type & StringType)
+ _ty.type = StringType;
+ else if (leftTy.type != UnknownType && rightTy.type != UnknownType)
+ _ty.type = DoubleType;
+ else
+ _ty.type = UnknownType;
+ break;
+ case OpSub:
+ _ty.type = DoubleType;
+ break;
+
+ case OpMul:
+ case OpDiv:
+ case OpMod:
+ _ty.type = DoubleType;
+ break;
+
+ case OpBitAnd:
+ case OpBitOr:
+ case OpBitXor:
+ case OpLShift:
+ case OpRShift:
+ _ty.type = SInt32Type;
+ break;
+ case OpURShift:
+ _ty.type = UInt32Type;
+ break;
+
+ case OpGt:
+ case OpLt:
+ case OpGe:
+ case OpLe:
+ case OpEqual:
+ case OpNotEqual:
+ case OpStrictEqual:
+ case OpStrictNotEqual:
+ case OpAnd:
+ case OpOr:
+ case OpInstanceof:
+ case OpIn:
+ _ty.type = BoolType;
+ break;
+
+ default:
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+ }
+ }
+
+ virtual void visitCall(Call *e) {
+ _ty = run(e->base);
+ for (ExprList *it = e->args; it; it = it->next)
+ _ty.fullyTyped &= run(it->expr).fullyTyped;
+ _ty.type = ObjectType;
+ }
+ virtual void visitNew(New *e) {
+ _ty = run(e->base);
+ for (ExprList *it = e->args; it; it = it->next)
+ _ty.fullyTyped &= run(it->expr).fullyTyped;
+ _ty.type = ObjectType;
+ }
+ virtual void visitSubscript(Subscript *e) {
+ _ty.fullyTyped = run(e->base).fullyTyped && run(e->index).fullyTyped;
+ _ty.type = ObjectType;
+ }
+
+ virtual void visitMember(Member *e) {
+ // TODO: for QML, try to do a static lookup
+ _ty = run(e->base);
+ _ty.type = ObjectType;
+ }
+
+ virtual void visitExp(Exp *s) { _ty = run(s->expr); }
+ virtual void visitMove(Move *s) {
+ TypingResult sourceTy = run(s->source);
+ Q_ASSERT(s->op == OpInvalid);
+ if (Temp *t = s->target->asTemp()) {
+ setType(t, sourceTy.type);
+ _ty = sourceTy;
+ return;
+ }
+
+ _ty = run(s->target);
+ _ty.fullyTyped &= sourceTy.fullyTyped;
+ }
+
+ virtual void visitJump(Jump *) { _ty = TypingResult(MissingType); }
+ virtual void visitCJump(CJump *s) { _ty = run(s->cond); }
+ virtual void visitRet(Ret *s) { _ty = run(s->expr); }
+ virtual void visitTry(Try *s) { setType(s->exceptionVar, ObjectType); _ty = TypingResult(MissingType); }
+ virtual void visitPhi(Phi *s) {
+ _ty = run(s->incoming[0]);
+ for (int i = 1, ei = s->incoming.size(); i != ei; ++i) {
+ TypingResult ty = run(s->incoming[i]);
+ _ty.type |= ty.type;
+ _ty.fullyTyped &= ty.fullyTyped;
+ }
+
+ // TODO: check & double check the next condition!
+ if (_ty.type & ObjectType || _ty.type & UndefinedType || _ty.type & NullType)
+ _ty.type = ObjectType;
+ else if (_ty.type & NumberType)
+ _ty.type = DoubleType;
+
+ setType(s->targetTemp, _ty.type);
+ }
+};
+
+class TypePropagation: public StmtVisitor, public ExprVisitor {
+ Type _ty;
+
+ void run(Expr *&e, Type requestedType = UnknownType) {
+ qSwap(_ty, requestedType);
+ e->accept(this);
+ qSwap(_ty, requestedType);
+
+ if (requestedType != UnknownType)
+ if (e->type != requestedType)
+ if (requestedType & NumberType) {
+// qDebug()<<"adding conversion from"<<typeName(e->type)<<"to"<<typeName(requestedType);
+ addConversion(e, requestedType);
+ }
+ }
+
+ struct Conversion {
+ Expr **expr;
+ Type targetType;
+ Stmt *stmt;
+
+ Conversion(Expr **expr = 0, Type targetType = UnknownType, Stmt *stmt = 0)
+ : expr(expr)
+ , targetType(targetType)
+ , stmt(stmt)
+ {}
+ };
+
+ Stmt *_currStmt;
+ QVector<Conversion> _conversions;
+
+ void addConversion(Expr *&expr, Type targetType) {
+ _conversions.append(Conversion(&expr, targetType, _currStmt));
+ }
+
+public:
+ TypePropagation() : _ty(UnknownType) {}
+
+ void run(Function *f) {
+ foreach (BasicBlock *bb, f->basicBlocks) {
+ _conversions.clear();
+
+ foreach (Stmt *s, bb->statements) {
+ _currStmt = s;
+ s->accept(this);
+ }
+
+ foreach (const Conversion &conversion, _conversions) {
+ if (conversion.stmt->asMove() && conversion.stmt->asMove()->source->asTemp()) {
+ *conversion.expr = bb->CONVERT(*conversion.expr, conversion.targetType);
+ } else {
+ Temp *target = bb->TEMP(bb->newTemp());
+ target->type = conversion.targetType;
+ Expr *convert = bb->CONVERT(*conversion.expr, conversion.targetType);
+ Move *convCall = f->New<Move>();
+ convCall->init(target, convert, OpInvalid);
+
+ Temp *source = bb->TEMP(target->index);
+ source->type = conversion.targetType;
+ *conversion.expr = source;
+
+ int idx = bb->statements.indexOf(conversion.stmt);
+ bb->statements.insert(idx, convCall);
+ }
+ }
+ }
+ }
+
+protected:
+ virtual void visitConst(Const *c) {
+ if (_ty & NumberType && c->type & NumberType) {
+ c->type = _ty;
+ }
+ }
+
+ virtual void visitString(String *) {}
+ virtual void visitRegExp(RegExp *) {}
+ virtual void visitName(Name *) {}
+ virtual void visitTemp(Temp *) {}
+ virtual void visitClosure(Closure *) {}
+ virtual void visitConvert(Convert *e) { run(e->expr, e->type); }
+ virtual void visitUnop(Unop *e) { run(e->expr, e->type); }
+ virtual void visitBinop(Binop *e) {
+ // FIXME: This routine needs more tuning!
+ switch (e->op) {
+ case OpAdd:
+ case OpSub:
+ case OpMul:
+ case OpDiv:
+ case OpMod:
+ case OpBitAnd:
+ case OpBitOr:
+ case OpBitXor:
+ case OpLShift:
+ case OpRShift:
+ case OpURShift:
+ run(e->left, e->type);
+ run(e->right, e->type);
+ break;
+
+ case OpGt:
+ case OpLt:
+ case OpGe:
+ case OpLe:
+ if (e->left->type == DoubleType)
+ run(e->right, DoubleType);
+ else if (e->right->type == DoubleType)
+ run(e->left, DoubleType);
+ else {
+ run(e->left, e->type);
+ run(e->right, e->type);
+ }
+ break;
+
+ case OpEqual:
+ case OpNotEqual:
+ case OpStrictEqual:
+ case OpStrictNotEqual:
+ break;
+
+ case OpInstanceof:
+ case OpIn:
+ run(e->left, e->type);
+ run(e->right, e->type);
+ break;
+
+ default:
+ Q_UNIMPLEMENTED();
+ Q_UNREACHABLE();
+ }
+ }
+ virtual void visitCall(Call *e) {
+ run(e->base);
+ for (ExprList *it = e->args; it; it = it->next)
+ run(it->expr);
+ }
+ virtual void visitNew(New *e) {
+ run(e->base);
+ for (ExprList *it = e->args; it; it = it->next)
+ run(it->expr);
+ }
+ virtual void visitSubscript(Subscript *e) { run(e->base); run(e->index); }
+ virtual void visitMember(Member *e) { run(e->base); }
+ virtual void visitExp(Exp *s) { run(s->expr); }
+ virtual void visitMove(Move *s) {
+ run(s->target);
+ run(s->source, s->target->type);
+ }
+ virtual void visitJump(Jump *) {}
+ virtual void visitCJump(CJump *s) {
+ run(s->cond, BoolType);
+ }
+ virtual void visitRet(Ret *s) { run(s->expr); }
+ virtual void visitTry(Try *) {}
+ virtual void visitPhi(Phi *s) {
+ Type ty = s->targetTemp->type;
+ foreach (Expr *e, s->incoming)
+ if (e->asConst())
+ run(e, ty);
+ }
+};
+
+void doEdgeSplitting(Function *f)
+{
+ const QVector<BasicBlock *> oldBBs = f->basicBlocks;
+
+ foreach (BasicBlock *bb, oldBBs) {
+ if (bb->in.size() > 1) {
+ for (int inIdx = 0, eInIdx = bb->in.size(); inIdx != eInIdx; ++inIdx) {
+ BasicBlock *inBB = bb->in[inIdx];
+ if (inBB->out.size() > 1) { // this should have been split!
+#if defined(SHOW_SSA)
+ qDebug() << "Splitting edge from block" << inBB->index << "to block" << bb->index;
+#endif
+
+ // create the basic block:
+ BasicBlock *newBB = new BasicBlock(f, bb->containingGroup());
+ newBB->index = f->basicBlocks.last()->index + 1;
+ f->basicBlocks.append(newBB);
+ Jump *s = f->New<Jump>();
+ s->init(bb);
+ newBB->statements.append(s);
+
+ // rewire the old outgoing edge
+ int outIdx = inBB->out.indexOf(bb);
+ inBB->out[outIdx] = newBB;
+ newBB->in.append(inBB);
+
+ // rewire the old incoming edge
+ bb->in[inIdx] = newBB;
+ newBB->out.append(bb);
+
+ // patch the terminator
+ Stmt *terminator = inBB->terminator();
+ if (Jump *j = terminator->asJump()) {
+ Q_ASSERT(outIdx == 0);
+ j->target = newBB;
+ } else if (CJump *j = terminator->asCJump()) {
+ if (outIdx == 0)
+ j->iftrue = newBB;
+ else if (outIdx == 1)
+ j->iffalse = newBB;
+ else
+ Q_ASSERT(!"Invalid out edge index for CJUMP!");
+ } else {
+ Q_ASSERT(!"Unknown terminator!");
+ }
+ }
+ }
+ }
+ }
+}
+
+QHash<BasicBlock *, BasicBlock *> scheduleBlocks(Function *function, const DominatorTree &df)
+{
+ struct I {
+ const DominatorTree &df;
+ QHash<BasicBlock *, BasicBlock *> &startEndLoops;
+ QSet<BasicBlock *> visited;
+ QVector<BasicBlock *> &sequence;
+ BasicBlock *currentGroup;
+ QList<BasicBlock *> postponed;
+
+ I(const DominatorTree &df, QVector<BasicBlock *> &sequence,
+ QHash<BasicBlock *, BasicBlock *> &startEndLoops)
+ : df(df)
+ , sequence(sequence)
+ , startEndLoops(startEndLoops)
+ , currentGroup(0)
+ {}
+
+ void DFS(BasicBlock *bb) {
+ Q_ASSERT(bb);
+ if (visited.contains(bb))
+ return;
+
+ if (bb->containingGroup() != currentGroup) {
+ postponed.append(bb);
+ return;
+ }
+ if (bb->isGroupStart())
+ currentGroup = bb;
+ else if (bb->in.size() > 1)
+ foreach (BasicBlock *inBB, bb->in)
+ if (!visited.contains(inBB))
+ return;
+
+ Q_ASSERT(df.immediateDominator(bb) == 0 || sequence.contains(df.immediateDominator(bb)));
+ layout(bb);
+ if (Stmt *terminator = bb->terminator()) {
+ if (Jump *j = terminator->asJump()) {
+ Q_ASSERT(bb->out.size() == 1);
+ DFS(j->target);
+ } else if (CJump *cj = terminator->asCJump()) {
+ Q_ASSERT(bb->out.size() == 2);
+ DFS(cj->iftrue);
+ DFS(cj->iffalse);
+ } else if (terminator->asRet()) {
+ Q_ASSERT(bb->out.size() == 0);
+ // nothing to do.
+ } else {
+ Q_UNREACHABLE();
+ }
+ } else {
+ Q_UNREACHABLE();
+ }
+
+ if (bb->isGroupStart()) {
+ currentGroup = bb->containingGroup();
+ startEndLoops.insert(bb, sequence.last());
+ QList<BasicBlock *> p = postponed;
+ foreach (BasicBlock *pBB, p)
+ DFS(pBB);
+ }
+ }
+
+ void layout(BasicBlock *bb) {
+ sequence.append(bb);
+ visited.insert(bb);
+ postponed.removeAll(bb);
+ }
+ };
+
+ QVector<BasicBlock *> sequence;
+ sequence.reserve(function->basicBlocks.size());
+ QHash<BasicBlock *, BasicBlock *> startEndLoops;
+ I(df, sequence, startEndLoops).DFS(function->basicBlocks.first());
+ qSwap(function->basicBlocks, sequence);
+
+ showMeTheCode(function);
+ return startEndLoops;
+}
+
+void checkCriticalEdges(QVector<BasicBlock *> basicBlocks) {
+ foreach (BasicBlock *bb, basicBlocks) {
+ if (bb && bb->out.size() > 1) {
+ foreach (BasicBlock *bb2, bb->out) {
+ if (bb2 && bb2->in.size() > 1) {
+ qout << "found critical edge between block "
+ << bb->index << " and block " << bb2->index;
+ Q_ASSERT(false);
+ }
+ }
+ }
+ }
+}
+
+void cleanupBasicBlocks(Function *function)
+{
+// showMeTheCode(function);
+
+ // remove all basic blocks that have no incoming edges, but skip the entry block
+ QVector<BasicBlock *> W = function->basicBlocks;
+ W.removeFirst();
+ QSet<BasicBlock *> toRemove;
+
+ while (!W.isEmpty()) {
+ BasicBlock *bb = W.first();
+ W.removeFirst();
+ if (toRemove.contains(bb))
+ continue;
+ if (bb->in.isEmpty()) {
+ foreach (BasicBlock *outBB, bb->out) {
+ int idx = outBB->in.indexOf(bb);
+ if (idx != -1) {
+ outBB->in.remove(idx);
+ W.append(outBB);
+ }
+ }
+ toRemove.insert(bb);
+ }
+ }
+
+ // TODO: merge 2 basic blocks A and B if A has one outgoing edge (to B), B has one incoming
+ // edge (from A), but not when A has more than 1 incoming edge and B has more than one
+ // outgoing edge.
+
+ foreach (BasicBlock *bb, toRemove) {
+ foreach (Stmt *s, bb->statements)
+ s->destroyData();
+ int idx = function->basicBlocks.indexOf(bb);
+ if (idx != -1)
+ function->basicBlocks.remove(idx);
+ delete bb;
+ }
+
+ // re-number all basic blocks:
+ for (int i = 0; i < function->basicBlocks.size(); ++i)
+ function->basicBlocks[i]->index = i;
+}
+
+class InputOutputCollector: protected StmtVisitor, protected ExprVisitor {
+ const bool variablesCanEscape;
+
+public:
+ QList<Temp> inputs;
+ QList<Temp> outputs;
+
+ InputOutputCollector(bool variablesCanEscape): variablesCanEscape(variablesCanEscape) {}
+
+ void collect(Stmt *s) {
+ inputs.clear();
+ outputs.clear();
+ s->accept(this);
+ }
+
+protected:
+ virtual void visitConst(Const *) {}
+ virtual void visitString(String *) {}
+ virtual void visitRegExp(RegExp *) {}
+ virtual void visitName(Name *) {}
+ virtual void visitTemp(Temp *e) {
+ switch (e->kind) {
+ case Temp::Local:
+ if (!variablesCanEscape)
+ inputs.append(*e);
+ break;
+
+ case Temp::VirtualRegister:
+ inputs.append(*e);
+ break;
+
+ default:
+ break;
+ }
+ }
+ virtual void visitClosure(Closure *) {}
+ virtual void visitConvert(Convert *e) { e->expr->accept(this); }
+ virtual void visitUnop(Unop *e) { e->expr->accept(this); }
+ virtual void visitBinop(Binop *e) { e->left->accept(this); e->right->accept(this); }
+ virtual void visitCall(Call *e) {
+ e->base->accept(this);
+ for (ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+ virtual void visitNew(New *e) {
+ e->base->accept(this);
+ for (ExprList *it = e->args; it; it = it->next)
+ it->expr->accept(this);
+ }
+ virtual void visitSubscript(Subscript *e) { e->base->accept(this); e->index->accept(this); }
+ virtual void visitMember(Member *e) { e->base->accept(this); }
+ virtual void visitExp(Exp *s) { s->expr->accept(this); }
+ virtual void visitMove(Move *s) {
+ s->source->accept(this);
+ if (Temp *t = s->target->asTemp()) {
+ if ((t->kind == Temp::Local && !variablesCanEscape) || t->kind == Temp::VirtualRegister)
+ outputs.append(*t);
+ else
+ s->target->accept(this);
+ } else {
+ s->target->accept(this);
+ }
+ }
+ virtual void visitJump(Jump *) {}
+ virtual void visitCJump(CJump *s) { s->cond->accept(this); }
+ virtual void visitRet(Ret *s) { s->expr->accept(this); }
+ virtual void visitTry(Try *) {}
+ virtual void visitPhi(Phi *s) {
+ // Handled separately
+ }
+};
+
+/*
+ * The algorithm is described in:
+ *
+ * Linear Scan Register Allocation on SSA Form
+ * Christian Wimmer & Michael Franz, CGO'10, April 24-28, 2010
+ *
+ * There is one slight difference w.r.t. the phi-nodes: in the artice, the phi nodes are attached
+ * to the basic-blocks. Therefore, in the algorithm in the article, the ranges for input parameters
+ * for phi nodes run from their definition upto the branch instruction into the block with the phi
+ * node. In our representation, phi nodes are mostly treaded as normal instructions, so we have to
+ * enlarge the range to cover the phi node itself.
+ */
+class LifeRanges {
+ typedef QSet<Temp> LiveRegs;
+
+ QHash<BasicBlock *, LiveRegs> _liveIn;
+ QHash<Temp, LifeTimeInterval> _intervals;
+ QList<LifeTimeInterval> _sortedRanges;
+
+public:
+ LifeRanges(Function *function, const QHash<BasicBlock *, BasicBlock *> &startEndLoops)
+ {
+ int id = 0;
+ foreach (BasicBlock *bb, function->basicBlocks) {
+ foreach (Stmt *s, bb->statements) {
+ if (s->asPhi())
+ s->id = id + 1;
+ else
+ s->id = ++id;
+ }
+ }
+
+ for (int i = function->basicBlocks.size() - 1; i >= 0; --i) {
+ BasicBlock *bb = function->basicBlocks[i];
+ buildIntervals(bb, startEndLoops.value(bb, 0), function->variablesCanEscape());
+ }
+
+ _sortedRanges.reserve(_intervals.size());
+ for (QHash<Temp, LifeTimeInterval>::const_iterator i = _intervals.begin(), ei = _intervals.end(); i != ei; ++i) {
+ LifeTimeInterval range = i.value();
+ range.setTemp(i.key());
+ _sortedRanges.append(range);
+ }
+ qSort(_sortedRanges.begin(), _sortedRanges.end(), LifeTimeInterval::lessThan);
+ }
+
+ QList<LifeTimeInterval> ranges() const { return _sortedRanges; }
+
+ void dump() const
+ {
+ qout << "Life ranges:" << endl;
+ qout << "Intervals:" << endl;
+ foreach (const LifeTimeInterval &range, _sortedRanges) {
+ range.dump();
+ qout << endl;
+ }
+
+ foreach (BasicBlock *bb, _liveIn.keys()) {
+ qout << "L" << bb->index <<" live-in: ";
+ QList<Temp> live = QList<Temp>::fromSet(_liveIn.value(bb));
+ qSort(live);
+ for (int i = 0; i < live.size(); ++i) {
+ if (i > 0) qout << ", ";
+ live[i].dump(qout);
+ }
+ qout << endl;
+ }
+ }
+
+private:
+ void buildIntervals(BasicBlock *bb, BasicBlock *loopEnd, bool variablesCanEscape)
+ {
+ LiveRegs live;
+ foreach (BasicBlock *successor, bb->out) {
+ live.unite(_liveIn[successor]);
+ const int bbIndex = successor->in.indexOf(bb);
+ Q_ASSERT(bbIndex >= 0);
+
+ foreach (Stmt *s, successor->statements) {
+ if (Phi *phi = s->asPhi()) {
+ if (Temp *t = phi->incoming[bbIndex]->asTemp())
+ live.insert(*t);
+ } else {
+ break;
+ }
+ }
+ }
+
+ foreach (const Temp &opd, live)
+ _intervals[opd].addRange(bb->statements.first(), bb->statements.last());
+
+ InputOutputCollector collector(variablesCanEscape);
+ for (int i = bb->statements.size() - 1; i >= 0; --i) {
+ Stmt *s = bb->statements[i];
+ if (Phi *phi = s->asPhi()) {
+ live.remove(*phi->targetTemp);
+ continue;
+ }
+ collector.collect(s);
+ foreach (const Temp &opd, collector.outputs) {
+ _intervals[opd].setFrom(s);
+ live.remove(opd);
+ }
+ foreach (const Temp &opd, collector.inputs) {
+ _intervals[opd].addRange(bb->statements.first(), s);
+ live.insert(opd);
+ }
+ }
+
+ if (loopEnd) { // Meaning: bb is a loop header, because loopEnd is set to non-null.
+ foreach (const Temp &opd, live)
+ _intervals[opd].addRange(bb->statements.first(), loopEnd->statements.last());
+ }
+
+ _liveIn[bb] = live;
+ }
+};
+} // anonymous namespace
+
+void LifeTimeInterval::setFrom(Stmt *from) {
+ Q_ASSERT(from && from->id > 0);
+
+ if (_ranges.isEmpty()) // this is the case where there is no use, only a define
+ _ranges.push_front(Range(from->id, from->id));
+ else
+ _ranges.first().start = from->id;
+}
+
+void LifeTimeInterval::addRange(Stmt *from, Stmt *to) {
+ Q_ASSERT(from && from->id > 0);
+ Q_ASSERT(to && to->id > 0);
+ Q_ASSERT(to->id >= from->id);
+
+ if (_ranges.isEmpty()) {
+ _ranges.push_front(Range(from->id, to->id));
+ return;
+ }
+
+ Range *p = &_ranges.first();
+ if (to->id + 1 >= p->start && p->end + 1 >= from->id) {
+ p->start = qMin(p->start, from->id);
+ p->end = qMax(p->end, to->id);
+ while (_ranges.count() > 1) {
+ Range *p1 = &_ranges[1];
+ if (p->end + 1 < p1->start || p1->end + 1 < p->start)
+ break;
+ p1->start = qMin(p->start, p1->start);
+ p1->end = qMax(p->end, p1->end);
+ _ranges.pop_front();
+ p = &_ranges.first();
+ }
+ } else {
+ Q_ASSERT(to->id < p->start);
+ _ranges.push_front(Range(from->id, to->id));
+ }
+}
+
+void LifeTimeInterval::dump() const {
+ _temp.dump(qout);
+ qout << ": ";
+ if (_ranges.isEmpty())
+ qout << "(none)";
+ for (int i = 0; i < _ranges.size(); ++i) {
+ if (i > 0) qout << ", ";
+ qout << _ranges[i].start << " - " << _ranges[i].end;
+ }
+ if (_reg != Invalid)
+ qout << " (register " << _reg << ")";
+}
+
+bool LifeTimeInterval::lessThan(const LifeTimeInterval &r1, const LifeTimeInterval &r2) {
+ if (r1._ranges.first().start == r2._ranges.first().start)
+ return r1._ranges.last().end < r2._ranges.last().end;
+ else
+ return r1._ranges.first().start < r2._ranges.first().start;
+}
+
+void Optimizer::run()
+{
+#if defined(SHOW_SSA)
+ qout << "##### NOW IN FUNCTION " << (_function->name ? qPrintable(*_function->name) : "anonymous!")
+ << " with " << _function->basicBlocks.size() << " basic blocks." << endl << flush;
+#endif
+
+ // Number all basic blocks, so we have nice numbers in the dumps:
+ for (int i = 0; i < function->basicBlocks.size(); ++i)
+ function->basicBlocks[i]->index = i;
+ showMeTheCode(function);
+
+ cleanupBasicBlocks(function);
+
+ function->removeSharedExpressions();
+
+// showMeTheCode(function);
+
+ if (!function->hasTry && !function->hasWith) {
+// qout << "Starting edge splitting..." << endl;
+ doEdgeSplitting(function);
+// showMeTheCode(function);
+
+ // Calculate the dominator tree:
+ DominatorTree df(function->basicBlocks);
+
+ convertToSSA(function, df);
+// showMeTheCode(function);
+
+// qout << "Starting def/uses calculation..." << endl;
+ DefUsesCalculator defUses(function);
+
+// qout << "Cleaning up phi nodes..." << endl;
+ cleanupPhis(defUses);
+// showMeTheCode(function);
+
+// qout << "Starting dead-code elimination..." << endl;
+ DeadCodeElimination(defUses, function).run();
+// showMeTheCode(function);
+
+// qout << "Running type inference..." << endl;
+ TypeInference(defUses).run(function);
+// showMeTheCode(function);
+
+// qout << "Doing type propagation..." << endl;
+ TypePropagation().run(function);
+// showMeTheCode(function);
+
+// qout << "Doing block scheduling..." << endl;
+ startEndLoops = scheduleBlocks(function, df);
+// showMeTheCode(function);
+
+#ifndef QT_NO_DEBUG
+ checkCriticalEdges(function->basicBlocks);
+#endif
+
+// qout << "Finished." << endl;
+ inSSA = true;
+ } else {
+ inSSA = false;
+ }
+}
+
+namespace {
+void insertMove(Function *function, BasicBlock *basicBlock, Temp *target, Expr *source) {
+ if (target->type != source->type)
+ source = basicBlock->CONVERT(source, target->type);
+
+ Move *s = function->New<Move>();
+ s->init(target, source, OpInvalid);
+ basicBlock->statements.insert(basicBlock->statements.size() - 1, s);
+}
+}
+
+/*
+ * Quick function to convert out of SSA, so we can put the stuff through the ISel phases. This
+ * has to be replaced by a phase in the specific ISel back-ends and do register allocation at the
+ * same time. That way the huge number of redundant moves generated by this function are eliminated.
+ */
+void Optimizer::convertOutOfSSA() {
+ // We assume that edge-splitting is already done.
+ foreach (BasicBlock *bb, function->basicBlocks) {
+ QVector<Stmt *> &stmts = bb->statements;
+ while (!stmts.isEmpty()) {
+ Stmt *s = stmts.first();
+ if (Phi *phi = s->asPhi()) {
+ stmts.removeFirst();
+ for (int i = 0, ei = phi->incoming.size(); i != ei; ++i)
+ insertMove(function, bb->in[i], phi->targetTemp, phi->incoming[i]);
+ } else {
+ break;
+ }
+ }
+ }
+}
+
+QList<Optimizer::SSADeconstructionMove> Optimizer::ssaDeconstructionMoves(BasicBlock *basicBlock)
+{
+ QList<SSADeconstructionMove> moves;
+
+ foreach (BasicBlock *outEdge, basicBlock->out) {
+ int inIdx = outEdge->in.indexOf(basicBlock);
+ Q_ASSERT(inIdx >= 0);
+ foreach (Stmt *s, outEdge->statements) {
+ if (Phi *phi = s->asPhi()) {
+ SSADeconstructionMove m;
+ m.source = phi->incoming[inIdx];
+ m.target = phi->targetTemp;
+ moves.append(m);
+ } else {
+ break;
+ }
+ }
+ }
+
+ return moves;
+}
+
+QList<LifeTimeInterval> Optimizer::lifeRanges() const
+{
+ Q_ASSERT(isInSSA());
+
+ LifeRanges lifeRanges(function, startEndLoops);
+// lifeRanges.dump();
+// showMeTheCode(function);
+ return lifeRanges.ranges();
+}
diff --git a/src/qml/qml/v4/qv4compiler_p.h b/src/qml/qml/v4/qv4ssa_p.h
index 5b6cee2a55..097a40eff1 100644
--- a/src/qml/qml/v4/qv4compiler_p.h
+++ b/src/qml/qml/v4/qv4ssa_p.h
@@ -39,67 +39,89 @@
**
****************************************************************************/
-#ifndef QV4COMPILER_P_H
-#define QV4COMPILER_P_H
+#ifndef QV4SSA_P_H
+#define QV4SSA_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 "qv4jsir_p.h"
-#include <private/qqmlexpression_p.h>
-#include <private/qqmlbinding_p.h>
-#include <private/qqmlcompiler_p.h>
+QT_BEGIN_NAMESPACE
+namespace QQmlJS {
+namespace V4IR {
-#include <private/qv8_p.h>
+class LifeTimeInterval {
+ struct Range {
+ int start;
+ int end;
-Q_DECLARE_METATYPE(v8::Handle<v8::Value>)
+ Range(int start = Invalid, int end = Invalid)
+ : start(start)
+ , end(end)
+ {}
+ };
-QT_BEGIN_NAMESPACE
+ Temp _temp;
+ QList<Range> _ranges;
+ int _reg;
-class QQmlTypeNameCache;
-class QV4CompilerPrivate;
-class Q_AUTOTEST_EXPORT QV4Compiler
-{
public:
- QV4Compiler();
- ~QV4Compiler();
+ static const int Invalid = -1;
+
+ LifeTimeInterval()
+ : _reg(Invalid)
+ {}
+
+ void setTemp(const Temp &temp) { this->_temp = temp; }
+ Temp temp() const { return _temp; }
+
+ void setFrom(Stmt *from);
+ void addRange(Stmt *from, Stmt *to);
+
+ int start() const { return _ranges.first().start; }
+ int end() const { return _ranges.last().end; }
+
+ int reg() const { return _reg; }
+ void setReg(int reg) { _reg = reg; }
- // Returns true if bindings were compiled
- bool isValid() const;
+ void dump() const;
+ static bool lessThan(const LifeTimeInterval &r1, const LifeTimeInterval &r2);
+};
- struct Expression
+class Optimizer
+{
+public:
+ struct SSADeconstructionMove
{
- Expression(const QQmlImports &imp) : imports(imp) {}
- QQmlScript::Object *component;
- QQmlScript::Object *context;
- QQmlScript::Property *property;
- QQmlScript::Variant expression;
- QQmlCompilerTypes::IdList *ids;
- QQmlTypeNameCache *importCache;
- QQmlImports imports;
+ Expr *source;
+ Temp *target;
+
+ bool needsConversion() const
+ { return target->type != source->type; }
};
- // -1 on failure, otherwise the binding index to use
- int compile(const Expression &, QQmlEnginePrivate *, bool *);
+public:
+ Optimizer(Function *function)
+ : function(function)
+ , inSSA(false)
+ {}
- // Returns the compiled program
- QByteArray program() const;
+ void run();
+ void convertOutOfSSA();
+
+ bool isInSSA() const
+ { return inSSA; }
+
+ QList<SSADeconstructionMove> ssaDeconstructionMoves(BasicBlock *basicBlock);
+
+ QList<LifeTimeInterval> lifeRanges() const;
- static void dump(const QByteArray &);
- static void enableBindingsTest(bool);
- static void enableV4(bool);
private:
- QV4CompilerPrivate *d;
+ Function *function;
+ bool inSSA;
+ QHash<BasicBlock *, BasicBlock *> startEndLoops;
};
+} // V4IR namespace
+} // QQmlJS namespace
QT_END_NAMESPACE
-#endif // QV4COMPILER_P_H
-
+#endif // QV4SSA_P_H
diff --git a/src/qml/qml/v4/qv4stacktrace.cpp b/src/qml/qml/v4/qv4stacktrace.cpp
new file mode 100644
index 0000000000..1cc2e53556
--- /dev/null
+++ b/src/qml/qml/v4/qv4stacktrace.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#if defined(_WIN32)
+#include <windows.h>
+#include <DbgHelp.h>
+#endif
+
+#include "qv4stacktrace_p.h"
+#include "qv4function_p.h"
+#include "qv4engine_p.h"
+#include "qv4unwindhelper_p.h"
+
+#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_MAC)
+#define HAVE_GNU_BACKTRACE
+#include <execinfo.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+NativeStackTrace::NativeStackTrace(ExecutionContext *context)
+{
+ engine = context->engine;
+ currentNativeFrame = 0;
+
+#if defined(HAVE_GNU_BACKTRACE)
+ UnwindHelper::prepareForUnwind(context);
+
+ nativeFrameCount = backtrace(&trace[0], sizeof(trace) / sizeof(trace[0]));
+#elif defined(Q_OS_WIN)
+
+ int machineType = 0;
+
+ CONTEXT winContext;
+ memset(&winContext, 0, sizeof(winContext));
+ winContext.ContextFlags = CONTEXT_FULL;
+ RtlCaptureContext(&winContext);
+
+ STACKFRAME64 sf64;
+ memset(&sf64, 0, sizeof(sf64));
+
+#if defined(Q_PROCESSOR_X86_32)
+ machineType = IMAGE_FILE_MACHINE_I386;
+
+ sf64.AddrFrame.Offset = winContext.Ebp;
+ sf64.AddrFrame.Mode = AddrModeFlat;
+ sf64.AddrPC.Offset = winContext.Eip;
+ sf64.AddrPC.Mode = AddrModeFlat;
+ sf64.AddrStack.Offset = winContext.Esp;
+ sf64.AddrStack.Mode = AddrModeFlat;
+
+#elif defined(Q_PROCESSOR_X86_64)
+ machineType = IMAGE_FILE_MACHINE_AMD64;
+
+ sf64.AddrFrame.Offset = winContext.Rbp;
+ sf64.AddrFrame.Mode = AddrModeFlat;
+ sf64.AddrPC.Offset = winContext.Rip;
+ sf64.AddrPC.Mode = AddrModeFlat;
+ sf64.AddrStack.Offset = winContext.Rsp;
+ sf64.AddrStack.Mode = AddrModeFlat;
+
+#else
+#error "Platform unsupported!"
+#endif
+
+ nativeFrameCount = 0;
+
+ while (StackWalk64(machineType, GetCurrentProcess(), GetCurrentThread(), &sf64, &winContext, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0)) {
+
+ if (sf64.AddrReturn.Offset == 0)
+ break;
+
+ trace[nativeFrameCount] = reinterpret_cast<void*>(sf64.AddrReturn.Offset);
+ nativeFrameCount++;
+ if (nativeFrameCount >= sizeof(trace) / sizeof(trace[0]))
+ break;
+ }
+
+#else
+ nativeFrameCount = 0;
+#endif
+ }
+
+NativeFrame NativeStackTrace::nextFrame() {
+ NativeFrame frame;
+ frame.function = 0;
+ frame.line = -1;
+
+ for (; currentNativeFrame < nativeFrameCount && !frame.function; ++currentNativeFrame) {
+ quintptr pc = reinterpret_cast<quintptr>(trace[currentNativeFrame]);
+ // The pointers from the back trace point to the return address, but we are interested in
+ // the caller site.
+ pc = pc - 1;
+
+ Function *f = engine->functionForProgramCounter(pc);
+ if (!f)
+ continue;
+
+ frame.function = f;
+ frame.line = f->lineNumberForProgramCounter(pc - reinterpret_cast<quintptr>(f->code));
+ }
+
+ return frame;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4stacktrace_p.h b/src/qml/qml/v4/qv4stacktrace_p.h
new file mode 100644
index 0000000000..79cb4d1813
--- /dev/null
+++ b/src/qml/qml/v4/qv4stacktrace_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4STACKTRACE_P_H
+#define QV4STACKTRACE_P_H
+
+#include <qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct Function;
+struct ExecutionEngine;
+struct ExecutionContext;
+
+struct NativeFrame {
+ Function *function;
+ int line;
+};
+
+struct NativeStackTrace
+{
+ void *trace[100];
+ int nativeFrameCount;
+ int currentNativeFrame;
+ ExecutionEngine *engine;
+
+ NativeStackTrace(ExecutionContext *context);
+
+ NativeFrame nextFrame();
+};
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif // QV4STACKTRACE_P_H
diff --git a/src/qml/qml/v4/qv4string.cpp b/src/qml/qml/v4/qv4string.cpp
new file mode 100644
index 0000000000..bfdee2d2cc
--- /dev/null
+++ b/src/qml/qml/v4/qv4string.cpp
@@ -0,0 +1,304 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4string_p.h"
+#include "qv4identifiertable_p.h"
+#include "qv4runtime_p.h"
+#include "qv4objectproto_p.h"
+#include "qv4stringobject_p.h"
+#include <QtCore/QHash>
+
+using namespace QV4;
+
+static uint toArrayIndex(const QChar *ch, const QChar *end, bool *ok)
+{
+ *ok = false;
+ uint i = ch->unicode() - '0';
+ if (i > 9)
+ return UINT_MAX;
+ ++ch;
+ // reject "01", "001", ...
+ if (i == 0 && ch != end)
+ return UINT_MAX;
+
+ while (ch < end) {
+ uint x = ch->unicode() - '0';
+ if (x > 9)
+ return UINT_MAX;
+ uint n = i*10 + x;
+ if (n < i)
+ // overflow
+ return UINT_MAX;
+ i = n;
+ ++ch;
+ }
+ *ok = true;
+ return i;
+}
+
+static uint toArrayIndex(const char *ch, const char *end, bool *ok)
+{
+ *ok = false;
+ uint i = *ch - '0';
+ if (i > 9)
+ return UINT_MAX;
+ ++ch;
+ // reject "01", "001", ...
+ if (i == 0 && ch != end)
+ return UINT_MAX;
+
+ while (ch < end) {
+ uint x = *ch - '0';
+ if (x > 9)
+ return UINT_MAX;
+ uint n = i*10 + x;
+ if (n < i)
+ // overflow
+ return UINT_MAX;
+ i = n;
+ ++ch;
+ }
+ *ok = true;
+ return i;
+}
+
+
+const ManagedVTable String::static_vtbl =
+{
+ call,
+ construct,
+ 0 /*markObjects*/,
+ destroy,
+ 0 /*collectDeletables*/,
+ hasInstance,
+ get,
+ getIndexed,
+ put,
+ putIndexed,
+ query,
+ queryIndexed,
+ deleteProperty,
+ deleteIndexedProperty,
+ 0 /*getLookup*/,
+ 0 /*setLookup*/,
+ Managed::isEqualTo,
+ 0 /*advanceIterator*/,
+ "String",
+};
+
+void String::destroy(Managed *that)
+{
+ static_cast<String*>(that)->~String();
+}
+
+Value String::get(Managed *m, String *name, bool *hasProperty)
+{
+ String *that = static_cast<String *>(m);
+ ExecutionEngine *v4 = m->engine();
+ if (name == v4->id_length) {
+ if (hasProperty)
+ *hasProperty = true;
+ return Value::fromInt32(that->_text.length());
+ }
+ PropertyAttributes attrs;
+ Property *pd = v4->stringPrototype->__getPropertyDescriptor__(name, &attrs);
+ if (!pd || attrs.isGeneric()) {
+ if (hasProperty)
+ *hasProperty = false;
+ return Value::undefinedValue();
+ }
+ if (hasProperty)
+ *hasProperty = true;
+ return v4->stringPrototype->getValue(Value::fromString(that), pd, attrs);
+}
+
+Value String::getIndexed(Managed *m, uint index, bool *hasProperty)
+{
+ String *that = static_cast<String *>(m);
+ ExecutionEngine *engine = that->engine();
+ if (index < that->_text.length()) {
+ if (hasProperty)
+ *hasProperty = true;
+ return Value::fromString(engine->newString(that->toQString().mid(index, 1)));
+ }
+ PropertyAttributes attrs;
+ Property *pd = engine->stringPrototype->__getPropertyDescriptor__(index, &attrs);
+ if (!pd || attrs.isGeneric()) {
+ if (hasProperty)
+ *hasProperty = false;
+ return Value::undefinedValue();
+ }
+ if (hasProperty)
+ *hasProperty = true;
+ return engine->stringPrototype->getValue(Value::fromString(that), pd, attrs);
+}
+
+void String::put(Managed *m, String *name, const Value &value)
+{
+ String *that = static_cast<String *>(m);
+ Object *o = that->engine()->newStringObject(Value::fromString(that));
+ o->put(name, value);
+}
+
+void String::putIndexed(Managed *m, uint index, const Value &value)
+{
+ String *that = static_cast<String *>(m);
+ Object *o = m->engine()->newStringObject(Value::fromString(that));
+ o->putIndexed(index, value);
+}
+
+PropertyAttributes String::query(const Managed *m, String *name)
+{
+ uint idx = name->asArrayIndex();
+ if (idx != UINT_MAX)
+ return queryIndexed(m, idx);
+ return Attr_Invalid;
+}
+
+PropertyAttributes String::queryIndexed(const Managed *m, uint index)
+{
+ const String *that = static_cast<const String *>(m);
+ return (index < that->_text.length()) ? Attr_NotConfigurable|Attr_NotWritable : Attr_Invalid;
+}
+
+bool String::deleteProperty(Managed *, String *)
+{
+ return false;
+}
+
+bool String::deleteIndexedProperty(Managed *m, uint index)
+{
+ return false;
+}
+
+String::String(ExecutionEngine *engine, const QString &text)
+ : Managed(engine ? engine->emptyClass : 0), _text(text), identifier(0), stringHash(UINT_MAX)
+{
+ vtbl = &static_vtbl;
+ type = Type_String;
+ subtype = StringType_Unknown;
+}
+
+uint String::toUInt(bool *ok) const
+{
+ *ok = true;
+
+ if (subtype == StringType_Unknown)
+ createHashValue();
+ if (subtype >= StringType_UInt)
+ return stringHash;
+
+ // ### this conversion shouldn't be required
+ double d = __qmljs_string_to_number(toQString());
+ uint l = (uint)d;
+ if (d == l)
+ return l;
+ *ok = false;
+ return UINT_MAX;
+}
+
+void String::makeIdentifierImpl()
+{
+ engine()->identifierTable->identifier(this);
+}
+
+void String::createHashValue() const
+{
+ const QChar *ch = _text.constData();
+ const QChar *end = ch + _text.length();
+
+ // array indices get their number as hash value
+ bool ok;
+ stringHash = toArrayIndex(ch, end, &ok);
+ if (ok) {
+ subtype = (stringHash == UINT_MAX) ? StringType_UInt : StringType_ArrayIndex;
+ return;
+ }
+
+ uint h = 0xffffffff;
+ while (ch < end) {
+ h = 31 * h + ch->unicode();
+ ++ch;
+ }
+
+ stringHash = h;
+ subtype = StringType_Regular;
+}
+
+uint String::createHashValue(const QChar *ch, int length)
+{
+ const QChar *end = ch + length;
+
+ // array indices get their number as hash value
+ bool ok;
+ uint stringHash = toArrayIndex(ch, end, &ok);
+ if (ok)
+ return stringHash;
+
+ uint h = 0xffffffff;
+ while (ch < end) {
+ h = 31 * h + ch->unicode();
+ ++ch;
+ }
+
+ return h;
+}
+
+uint String::createHashValue(const char *ch, int length)
+{
+ const char *end = ch + length;
+
+ // array indices get their number as hash value
+ bool ok;
+ uint stringHash = toArrayIndex(ch, end, &ok);
+ if (ok)
+ return stringHash;
+
+ uint h = 0xffffffff;
+ while (ch < end) {
+ if (*ch >= 0x80)
+ return UINT_MAX;
+ h = 31 * h + *ch;
+ ++ch;
+ }
+
+ return h;
+}
diff --git a/src/qml/qml/v4/qv4string_p.h b/src/qml/qml/v4/qv4string_p.h
new file mode 100644
index 0000000000..629fa506b7
--- /dev/null
+++ b/src/qml/qml/v4/qv4string_p.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4STRING_H
+#define QV4STRING_H
+
+#include <QtCore/qstring.h>
+#include "qv4managed_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct ExecutionEngine;
+struct Identifier;
+
+struct Q_QML_EXPORT String : public Managed {
+ enum StringType {
+ StringType_Unknown,
+ StringType_Regular,
+ StringType_UInt,
+ StringType_ArrayIndex
+ };
+
+ String() : Managed(0), identifier(0), stringHash(UINT_MAX)
+ { vtbl = &static_vtbl; type = Type_String; subtype = StringType_Unknown; }
+ String(ExecutionEngine *engine, const QString &text);
+ ~String() { _data = 0; }
+
+ inline bool isEqualTo(const String *other) const {
+ if (this == other)
+ return true;
+ if (hashValue() != other->hashValue())
+ return false;
+ if (identifier && identifier == other->identifier)
+ return true;
+ if (subtype >= StringType_UInt && subtype == other->subtype)
+ return true;
+
+ return toQString() == other->toQString();
+ }
+ inline bool compare(const String *other) {
+ return toQString() < other->toQString();
+ }
+
+ inline bool isEmpty() const { return _text.isEmpty(); }
+ inline const QString &toQString() const {
+ return _text;
+ }
+
+ inline unsigned hashValue() const {
+ if (subtype == StringType_Unknown)
+ createHashValue();
+
+ return stringHash;
+ }
+ uint asArrayIndex() const {
+ if (subtype == StringType_Unknown)
+ createHashValue();
+ if (subtype == StringType_ArrayIndex)
+ return stringHash;
+ return UINT_MAX;
+ }
+ uint toUInt(bool *ok) const;
+
+ void makeIdentifier() {
+ if (identifier)
+ return;
+ makeIdentifierImpl();
+ }
+
+ void makeIdentifierImpl();
+
+ void createHashValue() const;
+ static uint createHashValue(const QChar *ch, int length);
+ static uint createHashValue(const char *ch, int length);
+
+ bool startsWithUpper() const {
+ return _text.length() && _text.at(0).isUpper();
+ }
+ int length() const {
+ return _text.length();
+ }
+
+ QString _text;
+ mutable Identifier *identifier;
+ mutable uint stringHash;
+
+protected:
+ static void destroy(Managed *);
+ static Value get(Managed *m, String *name, bool *hasProperty);
+ static Value getIndexed(Managed *m, uint index, bool *hasProperty);
+ static void put(Managed *m, String *name, const Value &value);
+ static void putIndexed(Managed *m, uint index, const Value &value);
+ static PropertyAttributes query(const Managed *m, String *name);
+ static PropertyAttributes queryIndexed(const Managed *m, uint index);
+ static bool deleteProperty(Managed *, String *);
+ static bool deleteIndexedProperty(Managed *m, uint index);
+
+ static const ManagedVTable static_vtbl;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v4/qv4stringobject.cpp b/src/qml/qml/v4/qv4stringobject.cpp
new file mode 100644
index 0000000000..5afedd3d4f
--- /dev/null
+++ b/src/qml/qml/v4/qv4stringobject.cpp
@@ -0,0 +1,761 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qv4stringobject_p.h"
+#include "qv4regexpobject_p.h"
+#include "qv4objectproto_p.h"
+#include "qv4mm_p.h"
+#include <QtCore/qnumeric.h>
+#include <QtCore/qmath.h>
+#include <QtCore/QDateTime>
+#include <QtCore/QStringList>
+#include <QtCore/QDebug>
+#include <cmath>
+#include <qmath.h>
+#include <qnumeric.h>
+#include <cassert>
+
+#include <private/qqmljsengine_p.h>
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsparser_p.h>
+#include <private/qqmljsast_p.h>
+#include <qv4jsir_p.h>
+#include <qv4codegen_p.h>
+#include <qv4isel_masm_p.h>
+
+#ifndef Q_OS_WIN
+# include <time.h>
+# ifndef Q_OS_VXWORKS
+# include <sys/time.h>
+# else
+# include "qplatformdefs.h"
+# endif
+#else
+# include <windows.h>
+#endif
+
+using namespace QV4;
+
+DEFINE_MANAGED_VTABLE(StringObject);
+
+StringObject::StringObject(ExecutionEngine *engine, const Value &value)
+ : Object(engine), value(value)
+{
+ vtbl = &static_vtbl;
+ type = Type_StringObject;
+
+ tmpProperty.value = Value::undefinedValue();
+
+ assert(value.isString());
+ defineReadonlyProperty(engine->id_length, Value::fromUInt32(value.stringValue()->toQString().length()));
+}
+
+Property *StringObject::getIndex(uint index) const
+{
+ QString str = value.stringValue()->toQString();
+ if (index >= (uint)str.length())
+ return 0;
+ String *result = internalClass->engine->newString(str.mid(index, 1));
+ tmpProperty.value = Value::fromString(result);
+ return &tmpProperty;
+}
+
+bool StringObject::deleteIndexedProperty(Managed *m, uint index)
+{
+ StringObject *o = m->asStringObject();
+ if (!o)
+ m->engine()->current->throwTypeError();
+
+ if (index < o->value.stringValue()->toQString().length()) {
+ if (m->engine()->current->strictMode)
+ m->engine()->current->throwTypeError();
+ return false;
+ }
+ return true;
+}
+
+Property *StringObject::advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs)
+{
+ StringObject *s = static_cast<StringObject *>(m);
+ uint slen = s->value.stringValue()->toQString().length();
+ if (it->arrayIndex < slen) {
+ while (it->arrayIndex < slen) {
+ *index = it->arrayIndex;
+ ++it->arrayIndex;
+ if (attrs)
+ *attrs = s->arrayAttributes ? s->arrayAttributes[it->arrayIndex] : PropertyAttributes(Attr_NotWritable|Attr_NotConfigurable);
+ return s->__getOwnProperty__(*index);
+ }
+ it->arrayNode = s->sparseArrayBegin();
+ // iterate until we're past the end of the string
+ while (it->arrayNode && it->arrayNode->key() < slen)
+ it->arrayNode = it->arrayNode->nextNode();
+ }
+
+ return Object::advanceIterator(m, it, name, index, attrs);
+}
+
+void StringObject::markObjects(Managed *that)
+{
+ StringObject *o = static_cast<StringObject *>(that);
+ o->value.stringValue()->mark();
+ Object::markObjects(that);
+}
+
+DEFINE_MANAGED_VTABLE(StringCtor);
+
+StringCtor::StringCtor(ExecutionContext *scope)
+ : FunctionObject(scope, scope->engine->newIdentifier(QStringLiteral("String")))
+{
+ vtbl = &static_vtbl;
+}
+
+Value StringCtor::construct(Managed *m, Value *argv, int argc)
+{
+ Value value;
+ if (argc)
+ value = Value::fromString(argv[0].toString(m->engine()->current));
+ else
+ value = Value::fromString(m->engine()->current, QString());
+ return Value::fromObject(m->engine()->newStringObject(value));
+}
+
+Value StringCtor::call(Managed *m, const Value &, Value *argv, int argc)
+{
+ Value value;
+ if (argc)
+ value = Value::fromString(argv[0].toString(m->engine()->current));
+ else
+ value = Value::fromString(m->engine()->current, QString());
+ return value;
+}
+
+void StringPrototype::init(ExecutionEngine *engine, const Value &ctor)
+{
+ ctor.objectValue()->defineReadonlyProperty(engine->id_prototype, Value::fromObject(this));
+ ctor.objectValue()->defineReadonlyProperty(engine->id_length, Value::fromInt32(1));
+ ctor.objectValue()->defineDefaultProperty(engine, QStringLiteral("fromCharCode"), method_fromCharCode, 1);
+
+ defineDefaultProperty(engine, QStringLiteral("constructor"), ctor);
+ defineDefaultProperty(engine, QStringLiteral("toString"), method_toString);
+ defineDefaultProperty(engine, QStringLiteral("valueOf"), method_toString); // valueOf and toString are identical
+ defineDefaultProperty(engine, QStringLiteral("charAt"), method_charAt, 1);
+ defineDefaultProperty(engine, QStringLiteral("charCodeAt"), method_charCodeAt, 1);
+ defineDefaultProperty(engine, QStringLiteral("concat"), method_concat, 1);
+ defineDefaultProperty(engine, QStringLiteral("indexOf"), method_indexOf, 1);
+ defineDefaultProperty(engine, QStringLiteral("lastIndexOf"), method_lastIndexOf, 1);
+ defineDefaultProperty(engine, QStringLiteral("localeCompare"), method_localeCompare, 1);
+ defineDefaultProperty(engine, QStringLiteral("match"), method_match, 1);
+ defineDefaultProperty(engine, QStringLiteral("replace"), method_replace, 2);
+ defineDefaultProperty(engine, QStringLiteral("search"), method_search, 1);
+ defineDefaultProperty(engine, QStringLiteral("slice"), method_slice, 2);
+ defineDefaultProperty(engine, QStringLiteral("split"), method_split, 2);
+ defineDefaultProperty(engine, QStringLiteral("substr"), method_substr, 2);
+ defineDefaultProperty(engine, QStringLiteral("substring"), method_substring, 2);
+ defineDefaultProperty(engine, QStringLiteral("toLowerCase"), method_toLowerCase);
+ defineDefaultProperty(engine, QStringLiteral("toLocaleLowerCase"), method_toLocaleLowerCase);
+ defineDefaultProperty(engine, QStringLiteral("toUpperCase"), method_toUpperCase);
+ defineDefaultProperty(engine, QStringLiteral("toLocaleUpperCase"), method_toLocaleUpperCase);
+ defineDefaultProperty(engine, QStringLiteral("trim"), method_trim);
+}
+
+static QString getThisString(ExecutionContext *ctx)
+{
+ String* str = 0;
+ Value thisObject = ctx->thisObject;
+ if (StringObject *thisString = thisObject.asStringObject())
+ str = thisString->value.stringValue();
+ else if (thisObject.isUndefined() || thisObject.isNull())
+ ctx->throwTypeError();
+ else
+ str = ctx->thisObject.toString(ctx);
+ return str->toQString();
+}
+
+static QString getThisString(ExecutionContext *context, Value thisObject)
+{
+ if (thisObject.isString())
+ return thisObject.stringValue()->toQString();
+
+ String* str = 0;
+ if (StringObject *thisString = thisObject.asStringObject())
+ str = thisString->value.stringValue();
+ else if (thisObject.isUndefined() || thisObject.isNull())
+ context->throwTypeError();
+ else
+ str = thisObject.toString(context);
+ return str->toQString();
+}
+
+Value StringPrototype::method_toString(SimpleCallContext *context)
+{
+ if (context->thisObject.isString())
+ return context->thisObject;
+
+ StringObject *o = context->thisObject.asStringObject();
+ if (!o)
+ context->throwTypeError();
+ return o->value;
+}
+
+Value StringPrototype::method_charAt(SimpleCallContext *context)
+{
+ const QString str = getThisString(context, context->thisObject);
+
+ int pos = 0;
+ if (context->argumentCount > 0)
+ pos = (int) context->arguments[0].toInteger();
+
+ QString result;
+ if (pos >= 0 && pos < str.length())
+ result += str.at(pos);
+
+ return Value::fromString(context, result);
+}
+
+Value StringPrototype::method_charCodeAt(SimpleCallContext *context)
+{
+ const QString str = getThisString(context, context->thisObject);
+
+ int pos = 0;
+ if (context->argumentCount > 0)
+ pos = (int) context->arguments[0].toInteger();
+
+
+ if (pos >= 0 && pos < str.length())
+ return Value::fromInt32(str.at(pos).unicode());
+
+ return Value::fromDouble(qSNaN());
+}
+
+Value StringPrototype::method_concat(SimpleCallContext *context)
+{
+ QString value = getThisString(context, context->thisObject);
+
+ for (int i = 0; i < context->argumentCount; ++i) {
+ Value v = __qmljs_to_string(context->arguments[i], context);
+ assert(v.isString());
+ value += v.stringValue()->toQString();
+ }
+
+ return Value::fromString(context, value);
+}
+
+Value StringPrototype::method_indexOf(SimpleCallContext *context)
+{
+ QString value = getThisString(context, context->thisObject);
+
+ QString searchString;
+ if (context->argumentCount)
+ searchString = context->arguments[0].toString(context)->toQString();
+
+ int pos = 0;
+ if (context->argumentCount > 1)
+ pos = (int) context->arguments[1].toInteger();
+
+ int index = -1;
+ if (! value.isEmpty())
+ index = value.indexOf(searchString, qMin(qMax(pos, 0), value.length()));
+
+ return Value::fromDouble(index);
+}
+
+Value StringPrototype::method_lastIndexOf(SimpleCallContext *context)
+{
+ const QString value = getThisString(context, context->thisObject);
+
+ QString searchString;
+ if (context->argumentCount) {
+ Value v = __qmljs_to_string(context->arguments[0], context);
+ searchString = v.stringValue()->toQString();
+ }
+
+ Value posArg = context->argumentCount > 1 ? context->arguments[1] : Value::undefinedValue();
+ double position = __qmljs_to_number(posArg);
+ if (std::isnan(position))
+ position = +qInf();
+ else
+ position = trunc(position);
+
+ int pos = trunc(qMin(qMax(position, 0.0), double(value.length())));
+ if (!searchString.isEmpty() && pos == value.length())
+ --pos;
+ if (searchString.isNull() && pos == 0)
+ return Value::fromDouble(-1);
+ int index = value.lastIndexOf(searchString, pos);
+ return Value::fromDouble(index);
+}
+
+Value StringPrototype::method_localeCompare(SimpleCallContext *context)
+{
+ const QString value = getThisString(context, context->thisObject);
+ const QString that = (context->argumentCount ? context->arguments[0] : Value::undefinedValue()).toString(context)->toQString();
+ return Value::fromDouble(QString::localeAwareCompare(value, that));
+}
+
+Value StringPrototype::method_match(SimpleCallContext *context)
+{
+ if (context->thisObject.isUndefined() || context->thisObject.isNull())
+ context->throwTypeError();
+
+ String *s = context->thisObject.toString(context);
+
+ Value regexp = context->argumentCount ? context->arguments[0] : Value::undefinedValue();
+ RegExpObject *rx = regexp.as<RegExpObject>();
+ if (!rx)
+ rx = context->engine->regExpCtor.asFunctionObject()->construct(&regexp, 1).as<RegExpObject>();
+
+ if (!rx)
+ // ### CHECK
+ context->throwTypeError();
+
+ bool global = rx->global;
+
+ // ### use the standard builtin function, not the one that might be redefined in the proto
+ FunctionObject *exec = context->engine->regExpPrototype->get(context->engine->newString(QStringLiteral("exec")), 0).asFunctionObject();
+
+ Value arg = Value::fromString(s);
+ if (!global)
+ return exec->call(Value::fromObject(rx), &arg, 1);
+
+ String *lastIndex = context->engine->newString(QStringLiteral("lastIndex"));
+ rx->put(lastIndex, Value::fromInt32(0));
+ ArrayObject *a = context->engine->newArrayObject();
+
+ double previousLastIndex = 0;
+ uint n = 0;
+ while (1) {
+ Value result = exec->call(Value::fromObject(rx), &arg, 1);
+ if (result.isNull())
+ break;
+ assert(result.isObject());
+ double thisIndex = rx->get(lastIndex, 0).toInteger();
+ if (previousLastIndex == thisIndex) {
+ previousLastIndex = thisIndex + 1;
+ rx->put(lastIndex, Value::fromDouble(previousLastIndex));
+ } else {
+ previousLastIndex = thisIndex;
+ }
+ Value matchStr = result.objectValue()->getIndexed(0);
+ a->arraySet(n, matchStr);
+ ++n;
+ }
+ if (!n)
+ return Value::nullValue();
+
+ return Value::fromObject(a);
+
+}
+
+static QString makeReplacementString(const QString &input, const QString& replaceValue, uint* matchOffsets, int captureCount)
+{
+ QString result;
+ result.reserve(replaceValue.length());
+ for (int i = 0; i < replaceValue.length(); ++i) {
+ if (replaceValue.at(i) == QLatin1Char('$') && i < replaceValue.length() - 1) {
+ char ch = replaceValue.at(++i).toLatin1();
+ uint substStart = JSC::Yarr::offsetNoMatch;
+ uint substEnd = JSC::Yarr::offsetNoMatch;
+ if (ch == '$') {
+ result += ch;
+ continue;
+ } else if (ch == '&') {
+ substStart = matchOffsets[0];
+ substEnd = matchOffsets[1];
+ } else if (ch == '`') {
+ substStart = 0;
+ substEnd = matchOffsets[0];
+ } else if (ch == '\'') {
+ substStart = matchOffsets[1];
+ substEnd = input.length();
+ } else if (ch >= '1' && ch <= '9') {
+ char capture = ch - '0';
+ if (capture > 0 && capture < captureCount) {
+ substStart = matchOffsets[capture * 2];
+ substEnd = matchOffsets[capture * 2 + 1];
+ }
+ } else if (ch == '0' && i < replaceValue.length() - 1) {
+ int capture = (ch - '0') * 10;
+ ch = replaceValue.at(++i).toLatin1();
+ capture += ch - '0';
+ if (capture > 0 && capture < captureCount) {
+ substStart = matchOffsets[capture * 2];
+ substEnd = matchOffsets[capture * 2 + 1];
+ }
+ }
+ if (substStart != JSC::Yarr::offsetNoMatch && substEnd != JSC::Yarr::offsetNoMatch)
+ result += input.midRef(substStart, substEnd - substStart);
+ } else {
+ result += replaceValue.at(i);
+ }
+ }
+ return result;
+}
+
+Value StringPrototype::method_replace(SimpleCallContext *ctx)
+{
+ QString string;
+ if (StringObject *thisString = ctx->thisObject.asStringObject())
+ string = thisString->value.stringValue()->toQString();
+ else
+ string = ctx->thisObject.toString(ctx)->toQString();
+
+ int numCaptures = 0;
+ QVarLengthArray<uint, 16> matchOffsets;
+ int numStringMatches = 0;
+
+ Value searchValue = ctx->argument(0);
+ RegExpObject *regExp = searchValue.as<RegExpObject>();
+ if (regExp) {
+ uint offset = 0;
+ while (true) {
+ int oldSize = matchOffsets.size();
+ matchOffsets.resize(matchOffsets.size() + regExp->value->captureCount() * 2);
+ if (regExp->value->match(string, offset, matchOffsets.data() + oldSize) == JSC::Yarr::offsetNoMatch) {
+ matchOffsets.resize(oldSize);
+ break;
+ }
+ if (!regExp->global)
+ break;
+ offset = qMax(offset + 1, matchOffsets[oldSize + 1]);
+ }
+ if (regExp->global)
+ regExp->lastIndexProperty(ctx)->value = Value::fromUInt32(0);
+ numStringMatches = matchOffsets.size() / (regExp->value->captureCount() * 2);
+ numCaptures = regExp->value->captureCount();
+ } else {
+ numCaptures = 1;
+ QString searchString = searchValue.toString(ctx)->toQString();
+ int idx = string.indexOf(searchString);
+ if (idx != -1) {
+ numStringMatches = 1;
+ matchOffsets.resize(2);
+ matchOffsets[0] = idx;
+ matchOffsets[1] = idx + searchString.length();
+ }
+ }
+
+ QString result = string;
+ Value replaceValue = ctx->argument(1);
+ if (FunctionObject* searchCallback = replaceValue.asFunctionObject()) {
+ int replacementDelta = 0;
+ int argc = numCaptures + 2;
+ Value *args = (Value*)alloca((numCaptures + 2) * sizeof(Value));
+ for (int i = 0; i < numStringMatches; ++i) {
+ for (int k = 0; k < numCaptures; ++k) {
+ int idx = (i * numCaptures + k) * 2;
+ uint start = matchOffsets[idx];
+ uint end = matchOffsets[idx + 1];
+ Value entry = Value::undefinedValue();
+ if (start != JSC::Yarr::offsetNoMatch && end != JSC::Yarr::offsetNoMatch)
+ entry = Value::fromString(ctx, string.mid(start, end - start));
+ args[k] = entry;
+ }
+ uint matchStart = matchOffsets[i * numCaptures * 2];
+ uint matchEnd = matchOffsets[i * numCaptures * 2 + 1];
+ args[numCaptures] = Value::fromUInt32(matchStart);
+ args[numCaptures + 1] = Value::fromString(ctx, string);
+ Value replacement = searchCallback->call(Value::undefinedValue(), args, argc);
+ QString replacementString = replacement.toString(ctx)->toQString();
+ result.replace(replacementDelta + matchStart, matchEnd - matchStart, replacementString);
+ replacementDelta += replacementString.length() - matchEnd + matchStart;
+ }
+ } else {
+ QString newString = replaceValue.toString(ctx)->toQString();
+ int replacementDelta = 0;
+
+ for (int i = 0; i < numStringMatches; ++i) {
+ int baseIndex = i * numCaptures * 2;
+ uint matchStart = matchOffsets[baseIndex];
+ uint matchEnd = matchOffsets[baseIndex + 1];
+ if (matchStart == JSC::Yarr::offsetNoMatch)
+ continue;
+
+ QString replacement = makeReplacementString(string, newString, matchOffsets.data() + baseIndex, numCaptures);
+ result.replace(replacementDelta + matchStart, matchEnd - matchStart, replacement);
+ replacementDelta += replacement.length() - matchEnd + matchStart;
+ }
+ }
+
+ return Value::fromString(ctx, result);
+}
+
+Value StringPrototype::method_search(SimpleCallContext *ctx)
+{
+ QString string;
+ if (StringObject *thisString = ctx->thisObject.asStringObject())
+ string = thisString->value.stringValue()->toQString();
+ else
+ string = ctx->thisObject.toString(ctx)->toQString();
+
+ Value regExpValue = ctx->argument(0);
+ RegExpObject *regExp = regExpValue.as<RegExpObject>();
+ if (!regExp) {
+ regExpValue = ctx->engine->regExpCtor.asFunctionObject()->construct(&regExpValue, 1);
+ regExp = regExpValue.as<RegExpObject>();
+ }
+ uint* matchOffsets = (uint*)alloca(regExp->value->captureCount() * 2 * sizeof(uint));
+ uint result = regExp->value->match(string, /*offset*/0, matchOffsets);
+ if (result == JSC::Yarr::offsetNoMatch)
+ return Value::fromInt32(-1);
+ return Value::fromUInt32(result);
+}
+
+Value StringPrototype::method_slice(SimpleCallContext *ctx)
+{
+ const QString text = getThisString(ctx);
+ const double length = text.length();
+
+ double start = ctx->argument(0).toInteger();
+ double end = ctx->argument(1).isUndefined()
+ ? length : ctx->argument(1).toInteger();
+
+ if (start < 0)
+ start = qMax(length + start, 0.);
+ else
+ start = qMin(start, length);
+
+ if (end < 0)
+ end = qMax(length + end, 0.);
+ else
+ end = qMin(end, length);
+
+ const int intStart = int(start);
+ const int intEnd = int(end);
+
+ int count = qMax(0, intEnd - intStart);
+ return Value::fromString(ctx, text.mid(intStart, count));
+}
+
+Value StringPrototype::method_split(SimpleCallContext *ctx)
+{
+ QString text;
+ if (StringObject *thisObject = ctx->thisObject.asStringObject())
+ text = thisObject->value.stringValue()->toQString();
+ else
+ text = ctx->thisObject.toString(ctx)->toQString();
+
+ Value separatorValue = ctx->argumentCount > 0 ? ctx->argument(0) : Value::undefinedValue();
+ Value limitValue = ctx->argumentCount > 1 ? ctx->argument(1) : Value::undefinedValue();
+
+ ArrayObject* array = ctx->engine->newArrayObject();
+ Value result = Value::fromObject(array);
+
+ if (separatorValue.isUndefined()) {
+ if (limitValue.isUndefined()) {
+ array->push_back(Value::fromString(ctx, text));
+ return result;
+ }
+ return Value::fromString(ctx, text.left(limitValue.toInteger()));
+ }
+
+ uint limit = limitValue.isUndefined() ? UINT_MAX : limitValue.toUInt32();
+
+ if (limit == 0)
+ return result;
+
+ if (RegExpObject* re = separatorValue.as<RegExpObject>()) {
+ if (re->value->pattern().isEmpty()) {
+ re = 0;
+ separatorValue = Value::fromString(ctx, QString());
+ }
+ }
+
+ if (RegExpObject* re = separatorValue.as<RegExpObject>()) {
+ uint offset = 0;
+ uint* matchOffsets = (uint*)alloca(re->value->captureCount() * 2 * sizeof(uint));
+ while (true) {
+ uint result = re->value->match(text, offset, matchOffsets);
+ if (result == JSC::Yarr::offsetNoMatch)
+ break;
+
+ array->push_back(Value::fromString(ctx, text.mid(offset, matchOffsets[0] - offset)));
+ offset = qMax(offset + 1, matchOffsets[1]);
+
+ if (array->arrayLength() >= limit)
+ break;
+
+ for (int i = 1; i < re->value->captureCount(); ++i) {
+ uint start = matchOffsets[i * 2];
+ uint end = matchOffsets[i * 2 + 1];
+ array->push_back(Value::fromString(ctx, text.mid(start, end - start)));
+ if (array->arrayLength() >= limit)
+ break;
+ }
+ }
+ if (array->arrayLength() < limit)
+ array->push_back(Value::fromString(ctx, text.mid(offset)));
+ } else {
+ QString separator = separatorValue.toString(ctx)->toQString();
+ if (separator.isEmpty()) {
+ for (uint i = 0; i < qMin(limit, uint(text.length())); ++i)
+ array->push_back(Value::fromString(ctx, text.mid(i, 1)));
+ return result;
+ }
+
+ int start = 0;
+ int end;
+ while ((end = text.indexOf(separator, start)) != -1) {
+ array->push_back(Value::fromString(ctx, text.mid(start, end - start)));
+ start = end + separator.size();
+ if (array->arrayLength() >= limit)
+ break;
+ }
+ if (array->arrayLength() < limit && start != -1)
+ array->push_back(Value::fromString(ctx, text.mid(start)));
+ }
+ return result;
+}
+
+Value StringPrototype::method_substr(SimpleCallContext *context)
+{
+ const QString value = getThisString(context, context->thisObject);
+
+ double start = 0;
+ if (context->argumentCount > 0)
+ start = context->arguments[0].toInteger();
+
+ double length = +qInf();
+ if (context->argumentCount > 1)
+ length = context->arguments[1].toInteger();
+
+ double count = value.length();
+ if (start < 0)
+ start = qMax(count + start, 0.0);
+
+ length = qMin(qMax(length, 0.0), count - start);
+
+ qint32 x = Value::toInt32(start);
+ qint32 y = Value::toInt32(length);
+ return Value::fromString(context, value.mid(x, y));
+}
+
+Value StringPrototype::method_substring(SimpleCallContext *context)
+{
+ QString value = getThisString(context, context->thisObject);
+ int length = value.length();
+
+ double start = 0;
+ double end = length;
+
+ if (context->argumentCount > 0)
+ start = context->arguments[0].toInteger();
+
+ Value endValue = context->argumentCount > 1 ? context->arguments[1] : Value::undefinedValue();
+ if (!endValue.isUndefined())
+ end = endValue.toInteger();
+
+ if (std::isnan(start) || start < 0)
+ start = 0;
+
+ if (std::isnan(end) || end < 0)
+ end = 0;
+
+ if (start > length)
+ start = length;
+
+ if (end > length)
+ end = length;
+
+ if (start > end) {
+ double was = start;
+ start = end;
+ end = was;
+ }
+
+ qint32 x = (int)start;
+ qint32 y = (int)(end - start);
+ return Value::fromString(context, value.mid(x, y));
+}
+
+Value StringPrototype::method_toLowerCase(SimpleCallContext *ctx)
+{
+ QString value = getThisString(ctx);
+ return Value::fromString(ctx, value.toLower());
+}
+
+Value StringPrototype::method_toLocaleLowerCase(SimpleCallContext *ctx)
+{
+ return method_toLowerCase(ctx);
+}
+
+Value StringPrototype::method_toUpperCase(SimpleCallContext *ctx)
+{
+ QString value = getThisString(ctx);
+ return Value::fromString(ctx, value.toUpper());
+}
+
+Value StringPrototype::method_toLocaleUpperCase(SimpleCallContext *ctx)
+{
+ return method_toUpperCase(ctx);
+}
+
+Value StringPrototype::method_fromCharCode(SimpleCallContext *context)
+{
+ QString str(context->argumentCount, Qt::Uninitialized);
+ QChar *ch = str.data();
+ for (int i = 0; i < context->argumentCount; ++i) {
+ *ch = QChar(context->arguments[i].toUInt16());
+ ++ch;
+ }
+ return Value::fromString(context, str);
+}
+
+Value StringPrototype::method_trim(SimpleCallContext *ctx)
+{
+ if (ctx->thisObject.isNull() || ctx->thisObject.isUndefined())
+ ctx->throwTypeError();
+
+ QString s = __qmljs_to_string(ctx->thisObject, ctx).stringValue()->toQString();
+ const QChar *chars = s.constData();
+ int start, end;
+ for (start = 0; start < s.length(); ++start) {
+ if (!chars[start].isSpace() && chars[start].unicode() != 0xfeff)
+ break;
+ }
+ for (end = s.length() - 1; end >= start; --end) {
+ if (!chars[end].isSpace() && chars[end].unicode() != 0xfeff)
+ break;
+ }
+
+ return Value::fromString(ctx, QString(chars + start, end - start + 1));
+}
diff --git a/src/qml/qml/v4/qv4stringobject_p.h b/src/qml/qml/v4/qv4stringobject_p.h
new file mode 100644
index 0000000000..0ef6596235
--- /dev/null
+++ b/src/qml/qml/v4/qv4stringobject_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4STRINGOBJECT_P_H
+#define QV4STRINGOBJECT_P_H
+
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+#include <QtCore/qnumeric.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+struct StringObject: Object {
+ Q_MANAGED
+
+ Value value;
+ mutable Property tmpProperty;
+ StringObject(ExecutionEngine *engine, const Value &value);
+
+ Property *getIndex(uint index) const;
+
+ static bool deleteIndexedProperty(Managed *m, uint index);
+
+protected:
+ static Property *advanceIterator(Managed *m, ObjectIterator *it, String **name, uint *index, PropertyAttributes *attrs);
+ static void markObjects(Managed *that);
+};
+
+struct StringCtor: FunctionObject
+{
+ StringCtor(ExecutionContext *scope);
+
+ static Value construct(Managed *m, Value *args, int argc);
+ static Value call(Managed *that, const Value &, Value *, int);
+
+protected:
+ static const ManagedVTable static_vtbl;
+};
+
+struct StringPrototype: StringObject
+{
+ StringPrototype(ExecutionEngine *engine): StringObject(engine, Value::fromString(engine, QString())) {}
+ void init(ExecutionEngine *engine, const Value &ctor);
+
+ static Value method_toString(SimpleCallContext *context);
+ static Value method_charAt(SimpleCallContext *context);
+ static Value method_charCodeAt(SimpleCallContext *context);
+ static Value method_concat(SimpleCallContext *context);
+ static Value method_indexOf(SimpleCallContext *context);
+ static Value method_lastIndexOf(SimpleCallContext *context);
+ static Value method_localeCompare(SimpleCallContext *context);
+ static Value method_match(SimpleCallContext *context);
+ static Value method_replace(SimpleCallContext *ctx);
+ static Value method_search(SimpleCallContext *ctx);
+ static Value method_slice(SimpleCallContext *ctx);
+ static Value method_split(SimpleCallContext *ctx);
+ static Value method_substr(SimpleCallContext *context);
+ static Value method_substring(SimpleCallContext *context);
+ static Value method_toLowerCase(SimpleCallContext *ctx);
+ static Value method_toLocaleLowerCase(SimpleCallContext *ctx);
+ static Value method_toUpperCase(SimpleCallContext *ctx);
+ static Value method_toLocaleUpperCase(SimpleCallContext *ctx);
+ static Value method_fromCharCode(SimpleCallContext *context);
+ static Value method_trim(SimpleCallContext *ctx);
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4ECMAOBJECTS_P_H
diff --git a/src/qml/qml/v4/qv4syntaxchecker.cpp b/src/qml/qml/v4/qv4syntaxchecker.cpp
new file mode 100644
index 0000000000..a4f7423cd7
--- /dev/null
+++ b/src/qml/qml/v4/qv4syntaxchecker.cpp
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4syntaxchecker_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace QQmlJS;
+
+SyntaxChecker::SyntaxChecker()
+ : Lexer(&m_engine)
+ , m_stateStack(128)
+{
+}
+
+void QQmlJS::SyntaxChecker::clearText()
+{
+ m_code.clear();
+ m_tokens.clear();
+}
+
+void SyntaxChecker::appendText(const QString &text)
+{
+ m_code += text;
+}
+
+QString SyntaxChecker::text() const
+{
+ return m_code;
+}
+
+bool SyntaxChecker::canEvaluate()
+{
+ int yyaction = 0;
+ int yytoken = -1;
+ int yytos = -1;
+
+ setCode(m_code, 1);
+
+ m_tokens.clear();
+ m_tokens.append(T_FEED_JS_PROGRAM);
+
+ do {
+ if (++yytos == m_stateStack.size())
+ m_stateStack.resize(m_stateStack.size() * 2);
+
+ m_stateStack[yytos] = yyaction;
+
+again:
+ if (yytoken == -1 && action_index[yyaction] != -TERMINAL_COUNT) {
+ if (m_tokens.isEmpty())
+ yytoken = lex();
+ else
+ yytoken = m_tokens.takeFirst();
+ }
+
+ yyaction = t_action(yyaction, yytoken);
+ if (yyaction > 0) {
+ if (yyaction == ACCEPT_STATE) {
+ --yytos;
+ return true;
+ }
+ yytoken = -1;
+ } else if (yyaction < 0) {
+ const int ruleno = -yyaction - 1;
+ yytos -= rhs[ruleno];
+ yyaction = nt_action(m_stateStack[yytos], lhs[ruleno] - TERMINAL_COUNT);
+ }
+ } while (yyaction);
+
+ const int errorState = m_stateStack[yytos];
+ if (t_action(errorState, T_AUTOMATIC_SEMICOLON) && canInsertAutomaticSemicolon(yytoken)) {
+ yyaction = errorState;
+ m_tokens.prepend(yytoken);
+ yytoken = T_SEMICOLON;
+ goto again;
+ }
+
+ if (yytoken != EOF_SYMBOL)
+ return true;
+
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4syntaxchecker_p.h b/src/qml/qml/v4/qv4syntaxchecker_p.h
new file mode 100644
index 0000000000..bdb88b0525
--- /dev/null
+++ b/src/qml/qml/v4/qv4syntaxchecker_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4SYNTAXCHECKER_P_H
+#define QV4SYNTAXCHECKER_P_H
+
+#include <private/qqmljslexer_p.h>
+#include <private/qqmljsengine_p.h>
+
+#include <QtCore/QVector>
+#include <QtCore/QString>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+namespace QQmlJS {
+
+class SyntaxChecker: Lexer
+{
+public:
+ SyntaxChecker();
+
+ QString text() const;
+ void clearText();
+ void appendText(const QString &text);
+
+ bool canEvaluate();
+
+private:
+ Engine m_engine;
+ QVector<int> m_stateStack;
+ QList<int> m_tokens;
+ QString m_code;
+};
+
+} // end of QQmlJS namespace
+
+QT_END_NAMESPACE
+
+#endif // QV4SYNTAXCHECKER_P_H
diff --git a/src/qml/qml/v4/qv4unwindhelper.cpp b/src/qml/qml/v4/qv4unwindhelper.cpp
new file mode 100644
index 0000000000..beb5132626
--- /dev/null
+++ b/src/qml/qml/v4/qv4unwindhelper.cpp
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qv4unwindhelper_p.h>
+
+#include <wtf/Platform.h>
+
+#if CPU(X86_64) && (OS(LINUX) || OS(MAC_OS_X))
+# define USE_DW2_HELPER
+#elif CPU(X86) && COMPILER(GCC)
+# define USE_DW2_HELPER
+#elif CPU(ARM) && (OS(LINUX) || OS(QNX))
+# define USE_ARM_HELPER
+#elif OS(WINDOWS)
+ // SJLJ will unwind on Windows
+# define USE_NULL_HELPER
+#elif OS(IOS)
+ // SJLJ will unwind on iOS
+# define USE_NULL_HELPER
+#else
+# warning "Unsupported/untested platform!"
+# define USE_NULL_HELPER
+#endif
+
+#ifdef USE_DW2_HELPER
+# include <qv4unwindhelper_p-dw2.h>
+#endif // USE_DW2_HELPER
+
+#ifdef USE_ARM_HELPER
+# include <qv4unwindhelper_p-arm.h>
+#endif // USE_ARM_HELPER
+
+QT_BEGIN_NAMESPACE
+
+#ifdef USE_NULL_HELPER
+using namespace QV4;
+void UnwindHelper::prepareForUnwind(ExecutionContext *) {}
+void UnwindHelper::registerFunction(Function *function) {Q_UNUSED(function);}
+void UnwindHelper::registerFunctions(const QVector<Function *> &functions) {Q_UNUSED(functions);}
+void UnwindHelper::deregisterFunction(Function *function) {Q_UNUSED(function);}
+void UnwindHelper::deregisterFunctions(const QVector<Function *> &functions) {Q_UNUSED(functions);}
+#endif // USE_NULL_HELPER
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v4/qv4unwindhelper_p-arm.h b/src/qml/qml/v4/qv4unwindhelper_p-arm.h
new file mode 100644
index 0000000000..dd1f1e4856
--- /dev/null
+++ b/src/qml/qml/v4/qv4unwindhelper_p-arm.h
@@ -0,0 +1,233 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4UNWINDHELPER_PDW2_H
+#define QV4UNWINDHELPER_PDW2_H
+
+#include "qv4unwindhelper_p.h"
+#include "qv4functionobject_p.h"
+#include "qv4function_p.h"
+#include <wtf/Platform.h>
+
+#include <QMap>
+#include <QMutex>
+
+#define __USE_GNU
+#include <dlfcn.h>
+
+#if USE(LIBUNWIND_DEBUG)
+#include <libunwind.h>
+#include <execinfo.h>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+static void *removeThumbBit(void *addr)
+{
+ return reinterpret_cast<void*>(reinterpret_cast<intptr_t>(addr) & ~1u);
+}
+
+static QMutex functionProtector;
+static QMap<quintptr, Function*> allFunctions;
+
+static Function *lookupFunction(void *pc)
+{
+ quintptr key = reinterpret_cast<quintptr>(pc);
+ QMap<quintptr, Function*>::ConstIterator it = allFunctions.lowerBound(key);
+ if (it != allFunctions.begin() && allFunctions.count() > 0)
+ --it;
+ if (it == allFunctions.end())
+ return 0;
+
+ quintptr codeStart = reinterpret_cast<quintptr>(removeThumbBit((*it)->codeRef.code().executableAddress()));
+ if (key < codeStart || key >= codeStart + (*it)->codeSize)
+ return 0;
+ return *it;
+}
+
+
+/* Program:
+vsp = r4 (REG_TO_SP r4)
+vsp -= 8 * 4 -- > vsp = vsp - (7 << 2) - 4
+pop r12, r10, r9, r8, r7, r6, r5, r4
+pop r4
+pop lr
+pop r0, r1, r2, r3
+*/
+
+#define REG_TO_SP 0b10010000
+#define VSP_MINUS 0b01000000
+#define POP_REG_MULTI 0b10000000
+#define POP_R4_MULTI 0b10100000
+#define POP_R4_R14_MULTI 0b10101000
+#define POP_R0_TO_R3 0b10110001
+#define FINISH 0b10110000
+
+#define MK_UW_WORD(first, second, third, fourth) \
+ (((first) << 24) | \
+ ((second) << 16) | \
+ ((third) << 8) | \
+ (fourth))
+
+static unsigned int extbl[] = {
+ MK_UW_WORD(0x80 | // High bit set to indicate that this isn't a PREL31
+ 2, // Choose personality routine #2
+ 2, // Number of 4 byte words used to encode remaining unwind instructions
+ REG_TO_SP | 4, // Encoded program from above.
+ VSP_MINUS | 7),
+ MK_UW_WORD(POP_REG_MULTI | 1, 0b01111111,
+ POP_R4_R14_MULTI,
+ POP_R0_TO_R3),
+ MK_UW_WORD(0b00001111,
+ FINISH,
+ FINISH,
+ FINISH)
+};
+
+static unsigned write_prel31(unsigned *addr, void *ptr)
+{
+ int delta = (char *)ptr - (char*)addr;
+ if (delta < 0)
+ delta |= (1 << 30);
+ else
+ delta &= ~(1 << 30);
+ *addr = ((unsigned)delta) & 0x7fffffffU;
+}
+
+void UnwindHelper::deregisterFunction(Function *function)
+{
+ QMutexLocker locker(&functionProtector);
+ allFunctions.remove(reinterpret_cast<quintptr>(function->code));
+}
+
+void UnwindHelper::deregisterFunctions(const QVector<Function *> &functions)
+{
+ QMutexLocker locker(&functionProtector);
+ foreach (Function *f, functions)
+ allFunctions.remove(reinterpret_cast<quintptr>(f->code));
+}
+
+void UnwindHelper::registerFunction(Function *function)
+{
+ QMutexLocker locker(&functionProtector);
+ allFunctions.insert(reinterpret_cast<quintptr>(function->code), function);
+}
+
+void UnwindHelper::registerFunctions(const QVector<Function *> &functions)
+{
+ QMutexLocker locker(&functionProtector);
+ foreach (Function *f, functions)
+ allFunctions.insert(reinterpret_cast<quintptr>(f->code), f);
+}
+
+void UnwindHelper::prepareForUnwind(ExecutionContext *)
+{
+}
+
+int UnwindHelper::unwindInfoSize()
+{
+ return 2 * sizeof(unsigned int) // 2 extbl entries
+ + sizeof(extbl);
+}
+
+void UnwindHelper::writeARMUnwindInfo(void *codeAddr, int codeSize)
+{
+ unsigned int *exidx = (unsigned int *)((char *)codeAddr + codeSize);
+
+ unsigned char *exprog = (unsigned char *)((unsigned char *)codeAddr + codeSize + 8);
+
+ write_prel31(exidx, codeAddr);
+ exidx[1] = 4; // PREL31 offset to extbl, which follows right afterwards
+
+ memcpy(exprog, extbl, sizeof(extbl));
+
+#if USE(LIBUNWIND_DEBUG)
+ unw_dyn_info_t *info = (unw_dyn_info_t*)malloc(sizeof(unw_dyn_info_t));
+ info->start_ip = (unw_word_t)codeAddr;
+ info->end_ip = info->start_ip + codeSize;
+ info->gp = 0;
+ info->format = UNW_INFO_FORMAT_ARM_EXIDX;
+ info->u.rti.name_ptr = 0;
+ info->u.rti.segbase = 0;
+ info->u.rti.table_len = 8;
+ info->u.rti.table_data = (unw_word_t)exidx;
+ _U_dyn_register(info);
+#endif
+}
+
+}
+
+QT_END_NAMESPACE
+
+#if defined(Q_OS_ANDROID)
+extern "C" void *dl_unwind_find_exidx(void *pc, int *entryCount);
+#endif
+
+extern "C" Q_DECL_EXPORT void *__gnu_Unwind_Find_exidx(void *pc, int *entryCount)
+{
+#if !defined(Q_OS_ANDROID)
+ typedef void *(*Old_Unwind_Find_exidx)(void*, int*);
+ static Old_Unwind_Find_exidx oldFunction = 0;
+ if (!oldFunction)
+ oldFunction = (Old_Unwind_Find_exidx)dlsym(RTLD_NEXT, "__gnu_Unwind_Find_exidx");
+#endif
+
+ {
+ QMutexLocker locker(&QT_PREPEND_NAMESPACE(QV4::functionProtector));
+ QV4::Function *function = QT_PREPEND_NAMESPACE(QV4::lookupFunction(pc));
+ if (function) {
+ *entryCount = 1;
+ void * codeStart = QT_PREPEND_NAMESPACE(QV4::removeThumbBit(function->codeRef.code().executableAddress()));
+ // At the end of the function we store our synthetic exception table entry.
+ return (char *)codeStart + function->codeSize;
+ }
+ }
+
+#if defined(Q_OS_ANDROID)
+ return dl_unwind_find_exidx(pc, entryCount);
+#else
+ return oldFunction(pc, entryCount);
+#endif
+}
+
+#endif // QV4UNWINDHELPER_PDW2_H
diff --git a/src/qml/qml/v4/qv4unwindhelper_p-dw2.h b/src/qml/qml/v4/qv4unwindhelper_p-dw2.h
new file mode 100644
index 0000000000..57615f0999
--- /dev/null
+++ b/src/qml/qml/v4/qv4unwindhelper_p-dw2.h
@@ -0,0 +1,191 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QV4UNWINDHELPER_PDW2_H
+#define QV4UNWINDHELPER_PDW2_H
+
+#include "qv4unwindhelper_p.h"
+#include "qv4functionobject_p.h"
+#include "qv4function_p.h"
+#include <wtf/Platform.h>
+#include <wtf/PageAllocation.h>
+#include <ExecutableAllocator.h>
+
+#include <QMap>
+#include <QMutex>
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+namespace {
+#if CPU(X86_64)
+// Generated by fdegen
+static const unsigned char cie_fde_data[] = {
+ 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x1, 0x0, 0x8, 0x78, 0x10, 0xc, 0x7, 0x8,
+ 0x90, 0x1, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0,
+ 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x41, 0x13, 0x7e, 0x86,
+ 0x2, 0x43, 0xd, 0x6, 0x8c, 0x3, 0x8e, 0x4,
+ 0x0, 0x0, 0x0, 0x0
+};
+static const int fde_offset = 20;
+static const int initial_location_offset = 28;
+static const int address_range_offset = 36;
+#elif CPU(X86)
+static const unsigned char cie_fde_data[] = {
+ 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x1, 0x0, 0x4, 0x7c, 0x8, 0xc, 0x4, 0x4,
+ 0x88, 0x1, 0x0, 0x0, 0x20, 0x0, 0x0, 0x0,
+ 0x18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x41, 0x13, 0x7e, 0x85,
+ 0x2, 0x43, 0xd, 0x5, 0x86, 0x3, 0x87, 0x4,
+ 0x0, 0x0, 0x0, 0x0,
+};
+static const int fde_offset = 20;
+static const int initial_location_offset = 28;
+static const int address_range_offset = 32;
+#endif
+
+void writeIntPtrValue(unsigned char *addr, intptr_t val)
+{
+ addr[0] = (val >> 0) & 0xff;
+ addr[1] = (val >> 8) & 0xff;
+ addr[2] = (val >> 16) & 0xff;
+ addr[3] = (val >> 24) & 0xff;
+#if QT_POINTER_SIZE == 8
+ addr[4] = (val >> 32) & 0xff;
+ addr[5] = (val >> 40) & 0xff;
+ addr[6] = (val >> 48) & 0xff;
+ addr[7] = (val >> 56) & 0xff;
+#endif
+}
+} // anonymous namespace
+
+extern "C" void __register_frame(void *fde);
+extern "C" void __deregister_frame(void *fde);
+
+struct UnwindInfo : public ExecutableAllocator::PlatformUnwindInfo
+{
+ UnwindInfo(const QByteArray &cieFde);
+ virtual ~UnwindInfo();
+ QByteArray data;
+};
+
+UnwindInfo::UnwindInfo(const QByteArray &cieFde)
+ : data(cieFde)
+{
+ __register_frame(data.data() + fde_offset);
+}
+
+UnwindInfo::~UnwindInfo()
+{
+ __deregister_frame(data.data() + fde_offset);
+}
+
+static void ensureUnwindInfo(Function *f)
+{
+ if (!f->codeRef)
+ return; // Not a JIT generated function
+
+ JSC::ExecutableMemoryHandle *handle = f->codeRef.executableMemory();
+ if (!handle)
+ return;
+ ExecutableAllocator::ChunkOfPages *chunk = handle->chunk();
+
+ // Already registered?
+ if (chunk->unwindInfo)
+ return;
+
+ QByteArray info;
+ info.resize(sizeof(cie_fde_data));
+
+ unsigned char *cie_and_fde = reinterpret_cast<unsigned char *>(info.data());
+ memcpy(cie_and_fde, cie_fde_data, sizeof(cie_fde_data));
+
+ intptr_t ptr = static_cast<char *>(chunk->pages->base()) - static_cast<char *>(0);
+ writeIntPtrValue(cie_and_fde + initial_location_offset, ptr);
+
+ writeIntPtrValue(cie_and_fde + address_range_offset, chunk->pages->size());
+
+ chunk->unwindInfo = new UnwindInfo(info);
+}
+
+void UnwindHelper::prepareForUnwind(ExecutionContext *context)
+{
+ for (ExecutionContext *ctx = context; ctx; ctx = ctx->parent) {
+ if (CallContext *callCtx = ctx->asCallContext())
+ if (FunctionObject *fobj = callCtx->function)
+ if (Function *fun = fobj->function)
+ ensureUnwindInfo(fun);
+ for (ExecutionContext::EvalCode *code = ctx->currentEvalCode;
+ code; code = code->next)
+ ensureUnwindInfo(code->function);
+ }
+
+ if (context->engine->globalCode)
+ ensureUnwindInfo(context->engine->globalCode);
+}
+
+void UnwindHelper::registerFunction(Function *)
+{
+}
+
+void UnwindHelper::registerFunctions(const QVector<Function *>&)
+{
+}
+
+void UnwindHelper::deregisterFunction(Function *)
+{
+}
+
+void UnwindHelper::deregisterFunctions(const QVector<Function *> &)
+{
+}
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4UNWINDHELPER_PDW2_H
diff --git a/src/qml/qml/qqmlintegercache.cpp b/src/qml/qml/v4/qv4unwindhelper_p.h
index 3b44c3dc37..9ef564449a 100644
--- a/src/qml/qml/qqmlintegercache.cpp
+++ b/src/qml/qml/v4/qv4unwindhelper_p.h
@@ -39,44 +39,34 @@
**
****************************************************************************/
-#include "qqmlintegercache_p.h"
+#ifndef QV4UNWINDHELPER_H
+#define QV4UNWINDHELPER_H
-QT_BEGIN_NAMESPACE
-
-QQmlIntegerCache::QQmlIntegerCache()
-{
-}
+#include <QtCore/QVector>
-QQmlIntegerCache::~QQmlIntegerCache()
-{
-}
+QT_BEGIN_NAMESPACE
-QString QQmlIntegerCache::findId(int value) const
-{
- for (StringCache::ConstIterator iter = stringCache.begin();
- iter != stringCache.end(); ++iter) {
- if (iter.value() == value)
- return iter.key();
- }
- return QString();
-}
+namespace QV4 {
-void QQmlIntegerCache::reserve(int size)
-{
- stringCache.reserve(size);
-}
+struct Function;
+struct ExecutionContext;
-void QQmlIntegerCache::add(const QString &id, int value)
+class UnwindHelper
{
- Q_ASSERT(!stringCache.contains(id));
+public:
+ static void prepareForUnwind(ExecutionContext *ctx);
+ static void registerFunction(Function *function);
+ static void registerFunctions(const QVector<Function *> &functions);
+ static void deregisterFunction(Function *function);
+ static void deregisterFunctions(const QVector<Function *> &functions);
+#ifdef Q_PROCESSOR_ARM
+ static int unwindInfoSize();
+ static void writeARMUnwindInfo(void *codeAddr, int codeSize);
+#endif
+};
- stringCache.insert(id, value);
-}
-
-int QQmlIntegerCache::value(const QString &id)
-{
- int *rv = stringCache.value(id);
- return rv?*rv:-1;
}
QT_END_NAMESPACE
+
+#endif // QV4UNWINDHELPER_H
diff --git a/src/qml/qml/v8/qv8stringwrapper.cpp b/src/qml/qml/v4/qv4util_p.h
index f069c57b52..dbd9f89faa 100644
--- a/src/qml/qml/v8/qv8stringwrapper.cpp
+++ b/src/qml/qml/v4/qv4util_p.h
@@ -38,41 +38,37 @@
** $QT_END_LICENSE$
**
****************************************************************************/
+#ifndef QV4UTIL_H
+#define QV4UTIL_H
-#include "qv8stringwrapper_p.h"
-#include "qjsconverter_p.h"
-#include "qjsconverter_impl_p.h"
+#include "qv4global_p.h"
QT_BEGIN_NAMESPACE
-QV8StringWrapper::QV8StringWrapper()
-{
-}
-
-QV8StringWrapper::~QV8StringWrapper()
-{
-}
+namespace QV4 {
-void QV8StringWrapper::init()
+template <typename T>
+struct TemporaryAssignment
{
-}
-
-void QV8StringWrapper::destroy()
-{
-}
-
-v8::Local<v8::String> QV8StringWrapper::toString(const QString &qstr)
-{
- return QJSConverter::toString(qstr);
-}
-
-QString QV8StringWrapper::toString(v8::Handle<v8::String> jsstr)
-{
- if (jsstr.IsEmpty()) {
- return QString();
- } else {
- return QJSConverter::toString(jsstr);
+ TemporaryAssignment(T &var, const T& temporaryValue)
+ : variable(var)
+ , savedValue(var)
+ {
+ variable = temporaryValue;
+ }
+ ~TemporaryAssignment()
+ {
+ variable = savedValue;
}
+ T &variable;
+ T savedValue;
+private:
+ TemporaryAssignment(const TemporaryAssignment<T>&);
+ TemporaryAssignment operator=(const TemporaryAssignment<T>&);
+};
+
}
QT_END_NAMESPACE
+
+#endif // QV4UTIL_H
diff --git a/src/qml/qml/v4/qv4value.cpp b/src/qml/qml/v4/qv4value.cpp
new file mode 100644
index 0000000000..a41262f12f
--- /dev/null
+++ b/src/qml/qml/v4/qv4value.cpp
@@ -0,0 +1,403 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include <qv4engine_p.h>
+#include <qv4object_p.h>
+#include <qv4objectproto_p.h>
+#include "qv4mm_p.h"
+#include "qv4exception_p.h"
+
+#include <wtf/MathExtras.h>
+
+using namespace QV4;
+
+int Value::toUInt16() const
+{
+ if (isConvertibleToInt())
+ return (ushort)(uint)integerValue();
+
+ double number = __qmljs_to_number(*this);
+
+ double D16 = 65536.0;
+ if ((number >= 0 && number < D16))
+ return static_cast<ushort>(number);
+
+ if (!std::isfinite(number))
+ return +0;
+
+ double d = ::floor(::fabs(number));
+ if (std::signbit(number))
+ d = -d;
+
+ number = ::fmod(d , D16);
+
+ if (number < 0)
+ number += D16;
+
+ return (unsigned short)number;
+}
+
+double Value::toInteger() const
+{
+ if (isConvertibleToInt())
+ return int_32;
+
+ return Value::toInteger(__qmljs_to_number(*this));
+}
+
+double Value::toNumber() const
+{
+ return __qmljs_to_number(*this);
+}
+
+QString Value::toQString() const
+{
+ switch (type()) {
+ case Value::Undefined_Type:
+ return QStringLiteral("undefined");
+ case Value::Null_Type:
+ return QStringLiteral("null");
+ case Value::Boolean_Type:
+ if (booleanValue())
+ return QStringLiteral("true");
+ else
+ return QStringLiteral("false");
+ case Value::String_Type:
+ return stringValue()->toQString();
+ case Value::Object_Type: {
+ ExecutionContext *ctx = objectValue()->internalClass->engine->current;
+ try {
+ Value prim = __qmljs_to_primitive(*this, STRING_HINT);
+ if (prim.isPrimitive())
+ return prim.toQString();
+ } catch (Exception &e) {
+ e.accept(ctx);
+ try {
+ Value prim = __qmljs_to_primitive(e.value(), STRING_HINT);
+ if (prim.isPrimitive())
+ return prim.toQString();
+ } catch(Exception &e) {
+ e.accept(ctx);
+ }
+ }
+ return QString();
+ }
+ case Value::Integer_Type: {
+ QString str;
+ __qmljs_numberToString(&str, (double)int_32, 10);
+ return str;
+ }
+ default: { // double
+ QString str;
+ __qmljs_numberToString(&str, doubleValue(), 10);
+ return str;
+ }
+ } // switch
+}
+
+bool Value::sameValue(Value other) const {
+ if (val == other.val)
+ return true;
+ if (isString() && other.isString())
+ return stringValue()->isEqualTo(other.stringValue());
+ if (isInteger())
+ return int_32 ? (double(int_32) == other.dbl) : (other.val == 0);
+ if (other.isInteger())
+ return other.int_32 ? (dbl == double(other.int_32)) : (val == 0);
+ return false;
+}
+
+Value Value::fromString(ExecutionContext *ctx, const QString &s)
+{
+ return fromString(ctx->engine->newString(s));
+}
+
+Value Value::fromString(ExecutionEngine *engine, const QString &s)
+{
+ return fromString(engine->newString(s));
+}
+
+
+int Value::toInt32(double number)
+{
+ const double D32 = 4294967296.0;
+ const double D31 = D32 / 2.0;
+
+ if ((number >= -D31 && number < D31))
+ return static_cast<int>(number);
+
+
+ if (!std::isfinite(number))
+ return 0;
+
+ double d = ::floor(::fabs(number));
+ if (std::signbit(number))
+ d = -d;
+
+ number = ::fmod(d , D32);
+
+ if (number < -D31)
+ number += D32;
+ else if (number >= D31)
+ number -= D32;
+
+ return int(number);
+}
+
+unsigned int Value::toUInt32(double number)
+{
+ const double D32 = 4294967296.0;
+ if ((number >= 0 && number < D32))
+ return static_cast<uint>(number);
+
+ if (!std::isfinite(number))
+ return +0;
+
+ double d = ::floor(::fabs(number));
+ if (std::signbit(number))
+ d = -d;
+
+ number = ::fmod(d , D32);
+
+ if (number < 0)
+ number += D32;
+
+ return unsigned(number);
+}
+
+double Value::toInteger(double number)
+{
+ if (std::isnan(number))
+ return +0;
+ else if (! number || std::isinf(number))
+ return number;
+ const double v = floor(fabs(number));
+ return std::signbit(number) ? -v : v;
+}
+
+String *Value::toString(ExecutionContext *ctx) const
+{
+ if (isString())
+ return stringValue();
+ return __qmljs_convert_to_string(ctx, *this);
+}
+
+Value Value::property(ExecutionContext *ctx, String *name) const
+{
+ return isObject() ? objectValue()->get(name) : undefinedValue();
+}
+
+
+PersistentValue::PersistentValue(const Value &val)
+ : d(new PersistentValuePrivate(val))
+{
+}
+
+PersistentValue::PersistentValue(const PersistentValue &other)
+ : d(other.d)
+{
+ if (d)
+ d->ref();
+}
+
+PersistentValue &PersistentValue::operator=(const PersistentValue &other)
+{
+ if (d == other.d)
+ return *this;
+
+ // the memory manager cleans up those with a refcount of 0
+
+ if (d)
+ d->deref();
+ d = other.d;
+ if (d)
+ d->ref();
+
+ return *this;
+}
+
+PersistentValue &PersistentValue::operator =(const Value &other)
+{
+ if (!d) {
+ d = new PersistentValuePrivate(other);
+ return *this;
+ }
+ d = d->detach(other);
+ return *this;
+}
+
+PersistentValue::~PersistentValue()
+{
+ if (d)
+ d->deref();
+}
+
+WeakValue::WeakValue(const Value &val)
+ : d(new PersistentValuePrivate(val, /*engine*/0, /*weak*/true))
+{
+}
+
+WeakValue::WeakValue(const WeakValue &other)
+ : d(other.d)
+{
+ if (d)
+ d->ref();
+}
+
+WeakValue &WeakValue::operator=(const WeakValue &other)
+{
+ if (d == other.d)
+ return *this;
+
+ // the memory manager cleans up those with a refcount of 0
+
+ if (d)
+ d->deref();
+ d = other.d;
+ if (d)
+ d->ref();
+
+ return *this;
+}
+
+WeakValue &WeakValue::operator =(const Value &other)
+{
+ if (!d) {
+ d = new PersistentValuePrivate(other, /*engine*/0, /*weak*/true);
+ return *this;
+ }
+ d = d->detach(other, /*weak*/true);
+ return *this;
+}
+
+
+WeakValue::~WeakValue()
+{
+ if (d)
+ d->deref();
+}
+
+void WeakValue::markOnce()
+{
+ if (!d)
+ return;
+ Managed *m = d->value.asManaged();
+ if (!m)
+ return;
+ m->mark();
+}
+
+PersistentValuePrivate::PersistentValuePrivate(const Value &v, ExecutionEngine *e, bool weak)
+ : value(v)
+ , refcount(1)
+ , prev(0)
+ , next(0)
+ , engine(e)
+{
+ if (!engine) {
+ Managed *m = v.asManaged();
+ if (!m)
+ return;
+
+ engine = m->engine();
+ }
+ if (engine) {
+ PersistentValuePrivate **listRoot = weak ? &engine->memoryManager->m_weakValues : &engine->memoryManager->m_persistentValues;
+
+ prev = listRoot;
+ next = *listRoot;
+ *prev = this;
+ if (next)
+ next->prev = &this->next;
+ }
+}
+
+PersistentValuePrivate::~PersistentValuePrivate()
+{
+}
+
+void PersistentValuePrivate::removeFromList()
+{
+ if (prev) {
+ if (next)
+ next->prev = prev;
+ *prev = next;
+ next = 0;
+ prev = 0;
+ }
+}
+
+void PersistentValuePrivate::deref()
+{
+ // if engine is not 0, they are registered with the memory manager
+ // and will get cleaned up in the next gc run
+ if (!--refcount) {
+ removeFromList();
+ delete this;
+ }
+}
+
+PersistentValuePrivate *PersistentValuePrivate::detach(const QV4::Value &value, bool weak)
+{
+ if (refcount == 1) {
+ this->value = value;
+
+ Managed *m = value.asManaged();
+ if (!prev) {
+ if (m) {
+ ExecutionEngine *engine = m->engine();
+ if (engine) {
+ PersistentValuePrivate **listRoot = weak ? &engine->memoryManager->m_weakValues : &engine->memoryManager->m_persistentValues;
+ prev = listRoot;
+ next = *listRoot;
+ *prev = this;
+ if (next)
+ next->prev = &this->next;
+ }
+ }
+ } else if (!m)
+ removeFromList();
+
+ return this;
+ }
+ --refcount;
+ return new PersistentValuePrivate(value, engine, weak);
+}
+
diff --git a/src/qml/qml/v4/qv4value_def_p.h b/src/qml/qml/v4/qv4value_def_p.h
new file mode 100644
index 0000000000..2e3a9c0425
--- /dev/null
+++ b/src/qml/qml/v4/qv4value_def_p.h
@@ -0,0 +1,280 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QV4VALUE_DEF_P_H
+#define QV4VALUE_DEF_P_H
+
+#include <QtCore/QString>
+#include "qv4global_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+typedef uint Bool;
+
+struct Q_QML_EXPORT Value
+{
+ union {
+ quint64 val;
+ double dbl;
+ struct {
+#if Q_BYTE_ORDER != Q_LITTLE_ENDIAN
+ uint tag;
+#endif
+ union {
+ uint uint_32;
+ int int_32;
+#if QT_POINTER_SIZE == 4
+ Managed *m;
+ Object *o;
+ String *s;
+#endif
+ };
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ uint tag;
+#endif
+ };
+ };
+
+ enum Masks {
+ NotDouble_Mask = 0xfffc0000,
+ Type_Mask = 0xffff8000,
+ Immediate_Mask = NotDouble_Mask | 0x00008000,
+ Special_Mask = Immediate_Mask | 0x20000,
+ Tag_Shift = 32
+ };
+ enum ValueType {
+ Undefined_Type = Immediate_Mask | 0x00000,
+ Null_Type = Immediate_Mask | 0x10000,
+ Boolean_Type = Immediate_Mask | 0x20000,
+ Integer_Type = Immediate_Mask | 0x30000,
+ Object_Type = NotDouble_Mask | 0x00000,
+ String_Type = NotDouble_Mask | 0x10000,
+ Deleted_Type = NotDouble_Mask | 0x30000
+ };
+
+ enum ImmediateFlags {
+ ConvertibleToInt = Immediate_Mask | 0x1
+ };
+
+ enum ValueTypeInternal {
+ _Undefined_Type = Undefined_Type,
+ _Empty_Type = Deleted_Type,
+ _Null_Type = Null_Type | ConvertibleToInt,
+ _Boolean_Type = Boolean_Type | ConvertibleToInt,
+ _Integer_Type = Integer_Type | ConvertibleToInt,
+ _Object_Type = Object_Type,
+ _String_Type = String_Type
+
+ };
+
+ inline unsigned type() const {
+ return tag & Type_Mask;
+ }
+
+ // used internally in property
+ inline bool isEmpty() const { return tag == _Empty_Type; }
+
+ inline bool isUndefined() const { return tag == _Undefined_Type; }
+ inline bool isNull() const { return tag == _Null_Type; }
+ inline bool isBoolean() const { return tag == _Boolean_Type; }
+ inline bool isInteger() const { return tag == _Integer_Type; }
+ inline bool isDouble() const { return (tag & NotDouble_Mask) != NotDouble_Mask; }
+ inline bool isNumber() const { return tag == _Integer_Type || (tag & NotDouble_Mask) != NotDouble_Mask; }
+#if QT_POINTER_SIZE == 8
+ inline bool isString() const { return (tag & Type_Mask) == String_Type; }
+ inline bool isObject() const { return (tag & Type_Mask) == Object_Type; }
+#else
+ inline bool isString() const { return tag == String_Type; }
+ inline bool isObject() const { return tag == Object_Type; }
+#endif
+ inline bool isConvertibleToInt() const { return (tag & ConvertibleToInt) == ConvertibleToInt; }
+ inline bool isInt32() {
+ if (tag == _Integer_Type)
+ return true;
+ if (isDouble()) {
+ int i = (int)dbl;
+ if (i == dbl) {
+ int_32 = i;
+ tag = _Integer_Type;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool booleanValue() const {
+ return int_32;
+ }
+ double doubleValue() const {
+ return dbl;
+ }
+ void setDouble(double d) {
+ dbl = d;
+ }
+ double asDouble() const {
+ if (tag == _Integer_Type)
+ return int_32;
+ return dbl;
+ }
+ int integerValue() const {
+ return int_32;
+ }
+
+#if QT_POINTER_SIZE == 8
+ String *stringValue() const {
+ return (String *)(val & ~(quint64(Type_Mask) << Tag_Shift));
+ }
+ Object *objectValue() const {
+ return (Object *)(val & ~(quint64(Type_Mask) << Tag_Shift));
+ }
+ Managed *managed() const {
+ return (Managed *)(val & ~(quint64(Type_Mask) << Tag_Shift));
+ }
+#else
+ String *stringValue() const {
+ return s;
+ }
+ Object *objectValue() const {
+ return o;
+ }
+ Managed *managed() const {
+ return m;
+ }
+#endif
+
+ quint64 rawValue() const {
+ return val;
+ }
+
+ static Value emptyValue();
+ static Value undefinedValue();
+ static Value nullValue();
+ static Value fromBoolean(Bool b);
+ static Value fromDouble(double d);
+ static Value fromInt32(int i);
+ static Value fromUInt32(uint i);
+ static Value fromString(String *s);
+ static Value fromObject(Object *o);
+
+#ifndef QMLJS_LLVM_RUNTIME
+ static Value fromString(ExecutionContext *ctx, const QString &fromString);
+ static Value fromString(ExecutionEngine *engine, const QString &s);
+#endif
+
+ static double toInteger(double fromNumber);
+ static int toInt32(double value);
+ static unsigned int toUInt32(double value);
+
+ int toUInt16() const;
+ int toInt32() const;
+ unsigned int toUInt32() const;
+
+ bool toBoolean() const;
+ double toInteger() const;
+ double toNumber() const;
+ QString toQString() const;
+ String *toString(ExecutionContext *ctx) const;
+ Object *toObject(ExecutionContext *ctx) const;
+
+ inline bool isPrimitive() const { return !isObject(); }
+#if QT_POINTER_SIZE == 8
+ inline bool integerCompatible() const {
+ const quint64 mask = quint64(ConvertibleToInt) << 32;
+ return (val & mask) == mask;
+ }
+ static inline bool integerCompatible(Value a, Value b) {
+ const quint64 mask = quint64(ConvertibleToInt) << 32;
+ return ((a.val & b.val) & mask) == mask;
+ }
+ static inline bool bothDouble(Value a, Value b) {
+ const quint64 mask = quint64(NotDouble_Mask) << 32;
+ return ((a.val | b.val) & mask) != mask;
+ }
+#else
+ inline bool integerCompatible() const {
+ return (tag & ConvertibleToInt) == ConvertibleToInt;
+ }
+ static inline bool integerCompatible(Value a, Value b) {
+ return ((a.tag & b.tag) & ConvertibleToInt) == ConvertibleToInt;
+ }
+ static inline bool bothDouble(Value a, Value b) {
+ return ((a.tag | b.tag) & NotDouble_Mask) != NotDouble_Mask;
+ }
+#endif
+ inline bool tryIntegerConversion() {
+ bool b = isConvertibleToInt();
+ if (b)
+ tag = _Integer_Type;
+ return b;
+ }
+
+ String *asString() const;
+ Managed *asManaged() const;
+ Object *asObject() const;
+ FunctionObject *asFunctionObject() const;
+ BooleanObject *asBooleanObject() const;
+ NumberObject *asNumberObject() const;
+ StringObject *asStringObject() const;
+ DateObject *asDateObject() const;
+ ArrayObject *asArrayObject() const;
+ ErrorObject *asErrorObject() const;
+
+ template<typename T> inline T *as() const;
+
+ uint asArrayIndex() const;
+ uint asArrayLength(bool *ok) const;
+
+ Value property(ExecutionContext *ctx, String *name) const;
+
+ inline ExecutionEngine *engine() const;
+
+ // Section 9.12
+ bool sameValue(Value other) const;
+
+ inline void mark() const;
+};
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QV4VALUE_DEF_P_H
diff --git a/src/qml/qml/v4/qv4value_p.h b/src/qml/qml/v4/qv4value_p.h
new file mode 100644
index 0000000000..6d3f0e6edc
--- /dev/null
+++ b/src/qml/qml/v4/qv4value_p.h
@@ -0,0 +1,426 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QMLJS_VALUE_H
+#define QMLJS_VALUE_H
+
+#include <cmath> // this HAS to come
+
+#include <QtCore/QString>
+#include <QtCore/qnumeric.h>
+#include "qv4global_p.h"
+#include "qv4string_p.h"
+#include <QtCore/QDebug>
+#include "qv4managed_p.h"
+
+//#include <wtf/MathExtras.h>
+
+#include "qv4value_def_p.h"
+
+QT_BEGIN_NAMESPACE
+
+namespace QV4 {
+
+double __qmljs_to_number(const QV4::Value &value);
+Q_QML_EXPORT QV4::String *__qmljs_convert_to_string(QV4::ExecutionContext *ctx, const QV4::Value &value);
+QV4::Object *__qmljs_convert_to_object(QV4::ExecutionContext *ctx, const QV4::Value &value);
+
+
+inline ExecutionEngine *Value::engine() const {
+ Managed *m = asManaged();
+ return m ? m->engine() : 0;
+}
+
+inline void Value::mark() const {
+ Managed *m = asManaged();
+ if (m)
+ m->mark();
+}
+
+inline Value Value::undefinedValue()
+{
+ Value v;
+#if QT_POINTER_SIZE == 8
+ v.val = quint64(_Undefined_Type) << Tag_Shift;
+#else
+ v.tag = _Undefined_Type;
+ v.int_32 = 0;
+#endif
+ return v;
+}
+
+inline Value Value::nullValue()
+{
+ Value v;
+#if QT_POINTER_SIZE == 8
+ v.val = quint64(_Null_Type) << Tag_Shift;
+#else
+ v.tag = _Null_Type;
+ v.int_32 = 0;
+#endif
+ return v;
+}
+
+inline Value Value::emptyValue()
+{
+ Value v;
+ v.tag = Value::_Empty_Type;
+ v.uint_32 = 0;
+ return v;
+}
+
+
+inline Value Value::fromBoolean(Bool b)
+{
+ Value v;
+ v.tag = _Boolean_Type;
+ v.int_32 = (bool)b;
+ return v;
+}
+
+inline Value Value::fromDouble(double d)
+{
+ Value v;
+ v.dbl = d;
+ return v;
+}
+
+inline Value Value::fromInt32(int i)
+{
+ Value v;
+ v.tag = _Integer_Type;
+ v.int_32 = i;
+ return v;
+}
+
+inline Value Value::fromUInt32(uint i)
+{
+ Value v;
+ if (i < INT_MAX) {
+ v.tag = _Integer_Type;
+ v.int_32 = (int)i;
+ } else {
+ v.dbl = i;
+ }
+ return v;
+}
+
+inline Value Value::fromString(String *s)
+{
+ Value v;
+#if QT_POINTER_SIZE == 8
+ v.val = (quint64)s;
+ v.val |= quint64(_String_Type) << Tag_Shift;
+#else
+ v.tag = _String_Type;
+ v.s = s;
+#endif
+ return v;
+}
+
+inline Value Value::fromObject(Object *o)
+{
+ Value v;
+#if QT_POINTER_SIZE == 8
+ v.val = (quint64)o;
+ v.val |= quint64(_Object_Type) << Tag_Shift;
+#else
+ v.tag = _Object_Type;
+ v.o = o;
+#endif
+ return v;
+}
+
+inline bool Value::toBoolean() const
+{
+ switch (type()) {
+ case Value::Undefined_Type:
+ case Value::Null_Type:
+ return false;
+ case Value::Boolean_Type:
+ case Value::Integer_Type:
+ return (bool)int_32;
+ case Value::String_Type:
+ return stringValue()->toQString().length() > 0;
+ case Value::Object_Type:
+ return true;
+ default: // double
+ if (! doubleValue() || std::isnan(doubleValue()))
+ return false;
+ return true;
+ }
+}
+
+inline Object *Value::toObject(ExecutionContext *ctx) const
+{
+ if (isObject())
+ return objectValue();
+ return __qmljs_convert_to_object(ctx, *this);
+}
+
+inline int Value::toInt32() const
+{
+ if (isConvertibleToInt())
+ return int_32;
+ double d;
+ if (isDouble())
+ d = dbl;
+ else
+ d = __qmljs_to_number(*this);
+
+ const double D32 = 4294967296.0;
+ const double D31 = D32 / 2.0;
+
+ if ((d >= -D31 && d < D31))
+ return static_cast<int>(d);
+
+ return Value::toInt32(__qmljs_to_number(*this));
+}
+
+inline unsigned int Value::toUInt32() const
+{
+ if (isConvertibleToInt())
+ return (unsigned) int_32;
+ double d;
+ if (isDouble())
+ d = dbl;
+ else
+ d = __qmljs_to_number(*this);
+
+ const double D32 = 4294967296.0;
+ if (dbl >= 0 && dbl < D32)
+ return static_cast<uint>(dbl);
+ return toUInt32(d);
+}
+
+inline uint Value::asArrayIndex() const
+{
+ if (isInteger() && int_32 >= 0)
+ return (uint)int_32;
+ if (!isDouble())
+ return UINT_MAX;
+ uint idx = (uint)dbl;
+ if (idx != dbl)
+ return UINT_MAX;
+ return idx;
+}
+
+inline uint Value::asArrayLength(bool *ok) const
+{
+ *ok = true;
+ if (isConvertibleToInt() && int_32 >= 0)
+ return (uint)int_32;
+ if (isDouble()) {
+ uint idx = (uint)dbl;
+ if ((double)idx != dbl) {
+ *ok = false;
+ return UINT_MAX;
+ }
+ return idx;
+ }
+ if (isString())
+ return stringValue()->toUInt(ok);
+
+ uint idx = toUInt32();
+ double d = toNumber();
+ if (d != idx) {
+ *ok = false;
+ return UINT_MAX;
+ }
+ return idx;
+}
+
+inline String *Value::asString() const
+{
+ if (isString())
+ return stringValue();
+ return 0;
+}
+
+inline Managed *Value::asManaged() const
+{
+ if (isObject() || isString())
+ return managed();
+ return 0;
+}
+
+inline Object *Value::asObject() const
+{
+ return isObject() ? objectValue() : 0;
+}
+
+inline FunctionObject *Value::asFunctionObject() const
+{
+ return isObject() ? managed()->asFunctionObject() : 0;
+}
+
+inline BooleanObject *Value::asBooleanObject() const
+{
+ return isObject() ? managed()->asBooleanObject() : 0;
+}
+
+inline NumberObject *Value::asNumberObject() const
+{
+ return isObject() ? managed()->asNumberObject() : 0;
+}
+
+inline StringObject *Value::asStringObject() const
+{
+ return isObject() ? managed()->asStringObject() : 0;
+}
+
+inline DateObject *Value::asDateObject() const
+{
+ return isObject() ? managed()->asDateObject() : 0;
+}
+
+inline ArrayObject *Value::asArrayObject() const
+{
+ return isObject() ? managed()->asArrayObject() : 0;
+}
+
+inline ErrorObject *Value::asErrorObject() const
+{
+ return isObject() ? managed()->asErrorObject() : 0;
+}
+
+// ###
+inline Value Managed::construct(Value *args, int argc) {
+ return vtbl->construct(this, args, argc);
+}
+inline Value Managed::call(const Value &thisObject, Value *args, int argc) {
+ return vtbl->call(this, thisObject, args, argc);
+}
+
+struct PersistentValuePrivate
+{
+ PersistentValuePrivate(const Value &v, ExecutionEngine *engine = 0, bool weak = false);
+ virtual ~PersistentValuePrivate();
+ Value value;
+ uint refcount;
+ QV4::ExecutionEngine *engine;
+ PersistentValuePrivate **prev;
+ PersistentValuePrivate *next;
+
+ void removeFromList();
+ void ref() { ++refcount; }
+ void deref();
+ PersistentValuePrivate *detach(const QV4::Value &value, bool weak = false);
+
+ bool checkEngine(QV4::ExecutionEngine *otherEngine) {
+ if (!engine) {
+ Q_ASSERT(!value.isObject());
+ engine = otherEngine;
+ }
+ return (engine == otherEngine);
+ }
+};
+
+class Q_QML_EXPORT PersistentValue
+{
+public:
+ PersistentValue() : d(0) {}
+ PersistentValue(const Value &val);
+ PersistentValue(const PersistentValue &other);
+ PersistentValue &operator=(const PersistentValue &other);
+ PersistentValue &operator=(const Value &other);
+ ~PersistentValue();
+
+ Value value() const {
+ return d ? d->value : Value::emptyValue();
+ }
+
+ ExecutionEngine *engine() {
+ if (!d)
+ return 0;
+ Managed *m = d->value.asManaged();
+ return m ? m->engine() : 0;
+ }
+
+ operator Value() const { return value(); }
+
+ bool isEmpty() const { return !d || d->value.isEmpty(); }
+ void clear() {
+ *this = PersistentValue();
+ }
+
+private:
+ PersistentValuePrivate *d;
+};
+
+class Q_QML_EXPORT WeakValue
+{
+public:
+ WeakValue() : d(0) {}
+ WeakValue(const Value &val);
+ WeakValue(const WeakValue &other);
+ WeakValue &operator=(const WeakValue &other);
+ WeakValue &operator=(const Value &other);
+ ~WeakValue();
+
+ Value value() const {
+ return d ? d->value : Value::emptyValue();
+ }
+
+ ExecutionEngine *engine() {
+ if (!d)
+ return 0;
+ Managed *m = d->value.asManaged();
+ return m ? m->engine() : 0;
+ }
+
+ operator Value() const { return value(); }
+
+ bool isEmpty() const { return !d || d->value.isEmpty(); }
+ void clear() {
+ *this = WeakValue();
+ }
+
+ void markOnce();
+
+private:
+ PersistentValuePrivate *d;
+};
+
+} // namespace QV4
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/qml/qml/v4/qv4variantobject.cpp b/src/qml/qml/v4/qv4variantobject.cpp
new file mode 100644
index 0000000000..f18c5b582e
--- /dev/null
+++ b/src/qml/qml/v4/qv4variantobject.cpp
@@ -0,0 +1,203 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4variantobject_p.h"
+#include "qv4functionobject_p.h"
+#include "qv4objectproto_p.h"
+#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qv8engine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+DEFINE_MANAGED_VTABLE(VariantObject);
+
+VariantObject::VariantObject(ExecutionEngine *engine, const QVariant &value)
+ : Object(engine)
+ , ExecutionEngine::ScarceResourceData(value)
+ , m_vmePropertyReferenceCount(0)
+{
+ vtbl = &static_vtbl;
+ prototype = engine->variantPrototype;
+ if (isScarce())
+ internalClass->engine->scarceResources.insert(this);
+}
+
+QVariant VariantObject::toVariant(const QV4::Value &v)
+{
+ if (Object *o = v.asObject())
+ return o->engine()->v8Engine->variantFromJS(v);
+
+ if (v.isString())
+ return QVariant(v.stringValue()->toQString());
+ if (v.isBoolean())
+ return QVariant(v.booleanValue());
+ if (v.isNumber()) {
+ QV4::Value val = v;
+ if (val.isInt32())
+ return QVariant(val.integerValue());
+ return QVariant(v.asDouble());
+ }
+ if (v.isNull())
+ return QVariant(QMetaType::VoidStar, 0);
+ assert (v.isUndefined() || v.isEmpty());
+ return QVariant();
+}
+
+bool VariantObject::isScarce() const
+{
+ QVariant::Type t = data.type();
+ return t == QVariant::Pixmap || t == QVariant::Image;
+}
+
+void VariantObject::destroy(Managed *that)
+{
+ VariantObject *v = static_cast<VariantObject *>(that);
+ if (v->isScarce())
+ v->node.remove();
+ v->~VariantObject();
+}
+
+bool VariantObject::isEqualTo(Managed *m, Managed *other)
+{
+ QV4::VariantObject *lv = m->as<QV4::VariantObject>();
+ assert(lv);
+
+ if (QV4::VariantObject *rv = other->as<QV4::VariantObject>())
+ return lv->data == rv->data;
+
+ if (QV4::QmlValueTypeWrapper *v = other->as<QmlValueTypeWrapper>())
+ return v->isEqual(lv->data);
+
+ return false;
+}
+
+void VariantObject::addVmePropertyReference()
+{
+ if (isScarce() && ++m_vmePropertyReferenceCount == 1) {
+ // remove from the ep->scarceResources list
+ // since it is now no longer eligible to be
+ // released automatically by the engine.
+ node.remove();
+ }
+}
+
+void VariantObject::removeVmePropertyReference()
+{
+ if (isScarce() && --m_vmePropertyReferenceCount == 0) {
+ // and add to the ep->scarceResources list
+ // since it is now eligible to be released
+ // automatically by the engine.
+ internalClass->engine->scarceResources.insert(this);
+ }
+}
+
+
+VariantPrototype::VariantPrototype(ExecutionEngine *engine)
+ : VariantObject(engine, QVariant())
+{
+ prototype = engine->objectPrototype;
+}
+
+void VariantPrototype::init(ExecutionEngine *engine)
+{
+ defineDefaultProperty(engine, QStringLiteral("preserve"), method_preserve, 0);
+ defineDefaultProperty(engine, QStringLiteral("destroy"), method_destroy, 0);
+ defineDefaultProperty(engine, QStringLiteral("valueOf"), method_valueOf, 0);
+ defineDefaultProperty(engine, QStringLiteral("toString"), method_toString, 0);
+}
+
+QV4::Value VariantPrototype::method_preserve(SimpleCallContext *ctx)
+{
+ VariantObject *o = ctx->thisObject.as<QV4::VariantObject>();
+ if (o && o->isScarce())
+ o->node.remove();
+ return Value::undefinedValue();
+}
+
+QV4::Value VariantPrototype::method_destroy(SimpleCallContext *ctx)
+{
+ VariantObject *o = ctx->thisObject.as<QV4::VariantObject>();
+ if (o) {
+ if (o->isScarce())
+ o->node.remove();
+ o->data = QVariant();
+ }
+ return QV4::Value::undefinedValue();
+}
+
+QV4::Value VariantPrototype::method_toString(SimpleCallContext *ctx)
+{
+ VariantObject *o = ctx->thisObject.as<QV4::VariantObject>();
+ if (!o)
+ return Value::undefinedValue();
+ QString result = o->data.toString();
+ if (result.isEmpty() && !o->data.canConvert(QVariant::String))
+ result = QString::fromLatin1("QVariant(%0)").arg(QString::fromLatin1(o->data.typeName()));
+ return Value::fromString(ctx->engine->newString(result));
+}
+
+QV4::Value VariantPrototype::method_valueOf(SimpleCallContext *ctx)
+{
+ VariantObject *o = ctx->thisObject.as<QV4::VariantObject>();
+ if (o) {
+ QVariant v = o->data;
+ switch (v.type()) {
+ case QVariant::Invalid:
+ return Value::undefinedValue();
+ case QVariant::String:
+ return Value::fromString(ctx->engine->newString(v.toString()));
+ case QVariant::Int:
+ return Value::fromInt32(v.toInt());
+ case QVariant::Double:
+ case QVariant::UInt:
+ return Value::fromDouble(v.toDouble());
+ case QVariant::Bool:
+ return Value::fromBoolean(v.toBool());
+ default:
+ break;
+ }
+ }
+ return ctx->thisObject;
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8variantresource_p.h b/src/qml/qml/v4/qv4variantobject_p.h
index 1c65861c98..876539aae1 100644
--- a/src/qml/qml/v8/qv8variantresource_p.h
+++ b/src/qml/qml/v4/qv4variantobject_p.h
@@ -39,8 +39,8 @@
**
****************************************************************************/
-#ifndef QV8VARIANTRESOURCE_P_H
-#define QV8VARIANTRESOURCE_P_H
+#ifndef QV4VARIANTOBJECT_P_H
+#define QV4VARIANTOBJECT_P_H
//
// W A R N I N G
@@ -54,28 +54,49 @@
//
#include <QtCore/qglobal.h>
-#include <private/qv8_p.h>
-#include <private/qv8engine_p.h>
-#include <private/qqmlengine_p.h>
+#include <QtQml/qqmllist.h>
+#include <QtCore/qvariant.h>
+
+#include <private/qv4value_p.h>
+#include <private/qv4object_p.h>
QT_BEGIN_NAMESPACE
-class QV8VariantResource : public QV8ObjectResource,
- public QQmlEnginePrivate::ScarceResourceData
-{
- V8_RESOURCE_TYPE(VariantType)
+namespace QV4 {
+struct VariantObject : Object, public ExecutionEngine::ScarceResourceData
+{
+ Q_MANAGED
public:
- QV8VariantResource(QV8Engine *engine, const QVariant &data);
+ VariantObject(ExecutionEngine *engine, const QVariant &value);
+
+ static QVariant toVariant(const QV4::Value &v);
void addVmePropertyReference();
void removeVmePropertyReference();
-
- bool m_isScarceResource;
+ bool isScarce() const;
int m_vmePropertyReferenceCount;
+
+ static void destroy(Managed *that);
+ static bool isEqualTo(Managed *m, Managed *other);
};
+struct VariantPrototype : VariantObject
+{
+public:
+ VariantPrototype(ExecutionEngine *engine);
+
+ void init(ExecutionEngine *engine);
+
+ static Value method_preserve(SimpleCallContext *ctx);
+ static Value method_destroy(SimpleCallContext *ctx);
+ static Value method_toString(SimpleCallContext *ctx);
+ static Value method_valueOf(SimpleCallContext *ctx);
+};
+
+}
+
QT_END_NAMESPACE
-#endif // QV8VARIANTRESOURCE_P_H
+#endif
diff --git a/src/qml/qml/v4/v4.pri b/src/qml/qml/v4/v4.pri
index b6784851d8..1c63b4962a 100644
--- a/src/qml/qml/v4/v4.pri
+++ b/src/qml/qml/v4/v4.pri
@@ -1,15 +1,198 @@
+include(llvm_installation.pri)
+include(../../../3rdparty/masm/masm-defs.pri)
+
+CONFIG += exceptions
+
+!llvm: DEFINES += QMLJS_NO_LLVM
+
+CONFIG += warn_off
+
+INCLUDEPATH += $$PWD
+INCLUDEPATH += $$OUT_PWD
+
+SOURCES += \
+ $$PWD/qv4codegen.cpp \
+ $$PWD/qv4ssa.cpp \
+ $$PWD/qv4jsir.cpp \
+ $$PWD/qv4engine.cpp \
+ $$PWD/qv4context.cpp \
+ $$PWD/qv4runtime.cpp \
+ $$PWD/qv4value.cpp \
+ $$PWD/qv4syntaxchecker.cpp \
+ $$PWD/qv4isel_masm.cpp \
+ $$PWD/llvm_runtime.cpp \
+ $$PWD/qv4isel_p.cpp \
+ $$PWD/qv4debugging.cpp \
+ $$PWD/qv4lookup.cpp \
+ $$PWD/qv4identifier.cpp \
+ $$PWD/qv4identifiertable.cpp \
+ $$PWD/qv4mm.cpp \
+ $$PWD/qv4managed.cpp \
+ $$PWD/qv4internalclass.cpp \
+ $$PWD/qv4sparsearray.cpp \
+ $$PWD/qv4arrayobject.cpp \
+ $$PWD/qv4argumentsobject.cpp \
+ $$PWD/qv4booleanobject.cpp \
+ $$PWD/qv4dateobject.cpp \
+ $$PWD/qv4errorobject.cpp \
+ $$PWD/qv4function.cpp \
+ $$PWD/qv4functionobject.cpp \
+ $$PWD/qv4globalobject.cpp \
+ $$PWD/qv4jsonobject.cpp \
+ $$PWD/qv4mathobject.cpp \
+ $$PWD/qv4numberobject.cpp \
+ $$PWD/qv4object.cpp \
+ $$PWD/qv4objectproto.cpp \
+ $$PWD/qv4regexpobject.cpp \
+ $$PWD/qv4stringobject.cpp \
+ $$PWD/qv4variantobject.cpp \
+ $$PWD/qv4string.cpp \
+ $$PWD/qv4objectiterator.cpp \
+ $$PWD/qv4regexp.cpp \
+ $$PWD/qv4unwindhelper.cpp \
+ $$PWD/qv4serialize.cpp \
+ $$PWD/qv4script.cpp \
+ $$PWD/qv4executableallocator.cpp \
+ $$PWD/qv4sequenceobject.cpp \
+ $$PWD/qv4include.cpp \
+ $$PWD/qv4qobjectwrapper.cpp \
+ $$PWD/qv4qmlextensions.cpp \
+ $$PWD/qv4stacktrace.cpp \
+ $$PWD/qv4exception.cpp
+
HEADERS += \
- $$PWD/qv4compiler_p.h \
- $$PWD/qv4compiler_p_p.h \
- $$PWD/qv4ir_p.h \
- $$PWD/qv4irbuilder_p.h \
- $$PWD/qv4instruction_p.h \
- $$PWD/qv4bindings_p.h \
- $$PWD/qv4program_p.h \
+ $$PWD/qv4global_p.h \
+ $$PWD/qv4codegen_p.h \
+ $$PWD/qv4ssa_p.h \
+ $$PWD/qv4jsir_p.h \
+ $$PWD/qv4engine_p.h \
+ $$PWD/qv4context_p.h \
+ $$PWD/qv4runtime_p.h \
+ $$PWD/qv4math_p.h \
+ $$PWD/qv4value_p.h \
+ $$PWD/qv4value_def_p.h \
+ $$PWD/qv4syntaxchecker_p.h \
+ $$PWD/qv4isel_masm_p.h \
+ $$PWD/qv4isel_p.h \
+ $$PWD/qv4isel_util_p.h \
+ $$PWD/qv4debugging_p.h \
+ $$PWD/qv4lookup_p.h \
+ $$PWD/qv4identifier_p.h \
+ $$PWD/qv4identifiertable_p.h \
+ $$PWD/qv4mm_p.h \
+ $$PWD/qv4managed_p.h \
+ $$PWD/qv4internalclass_p.h \
+ $$PWD/qv4sparsearray_p.h \
+ $$PWD/qv4arrayobject_p.h \
+ $$PWD/qv4argumentsobject_p.h \
+ $$PWD/qv4booleanobject_p.h \
+ $$PWD/qv4dateobject_p.h \
+ $$PWD/qv4errorobject_p.h \
+ $$PWD/qv4function_p.h \
+ $$PWD/qv4functionobject_p.h \
+ $$PWD/qv4globalobject_p.h \
+ $$PWD/qv4jsonobject_p.h \
+ $$PWD/qv4mathobject_p.h \
+ $$PWD/qv4numberobject_p.h \
+ $$PWD/qv4object_p.h \
+ $$PWD/qv4objectproto_p.h \
+ $$PWD/qv4regexpobject_p.h \
+ $$PWD/qv4stringobject_p.h \
+ $$PWD/qv4variantobject_p.h \
+ $$PWD/qv4string_p.h \
+ $$PWD/qv4property_p.h \
+ $$PWD/qv4objectiterator_p.h \
+ $$PWD/qv4regexp_p.h \
+ $$PWD/qv4unwindhelper_p.h \
+ $$PWD/qv4unwindhelper_p-dw2.h \
+ $$PWD/qv4unwindhelper_p-arm.h \
+ $$PWD/qv4serialize_p.h \
+ $$PWD/qv4script_p.h \
+ $$PWD/qv4util_p.h \
+ $$PWD/qv4executableallocator_p.h \
+ $$PWD/qv4sequenceobject_p.h \
+ $$PWD/qv4include_p.h \
+ $$PWD/qv4qobjectwrapper_p.h \
+ $$PWD/qv4qmlextensions_p.h \
+ $$PWD/qv4stacktrace_p.h \
+ $$PWD/qv4exception_p.h
+
+llvm-libs {
SOURCES += \
- $$PWD/qv4compiler.cpp \
- $$PWD/qv4ir.cpp \
- $$PWD/qv4irbuilder.cpp \
- $$PWD/qv4instruction.cpp \
- $$PWD/qv4bindings.cpp \
+ $$PWD/qv4isel_llvm.cpp
+
+HEADERS += \
+ $$PWD/qv4isel_llvm_p.h \
+ $$PWD/qv4_llvm_p.h
+
+LLVM_RUNTIME_BC = $$PWD/llvm_runtime.bc
+DEFINES += LLVM_RUNTIME="\"\\\"$$LLVM_RUNTIME_BC\\\"\""
+DEFINES += QMLJS_WITH_LLVM
+
+INCLUDEPATH += \
+ $$system($$LLVM_CONFIG --includedir)
+
+QMAKE_CXXFLAGS += $$system($$LLVM_CONFIG --cppflags) -fvisibility-inlines-hidden
+QMAKE_CXXFLAGS -= -pedantic
+QMAKE_CXXFLAGS -= -Wcovered-switch-default
+
+LIBS += \
+ $$system($$LLVM_CONFIG --ldflags) \
+ $$system($$LLVM_CONFIG --libs core jit bitreader linker ipo target x86 arm native)
+
+QMAKE_EXTRA_TARGETS += gen_llvm_runtime
+
+GEN_LLVM_RUNTIME_FLAGS = $$system($$LLVM_CONFIG --cppflags)
+GEN_LLVM_RUNTIME_FLAGS -= -pedantic
+
+gen_llvm_runtime.target = llvm_runtime
+gen_llvm_runtime.commands = clang -O2 -emit-llvm -c -I$$PWD -I$$PWD/../3rdparty/masm $$join(QT.core.includes, " -I", "-I") $$GEN_LLVM_RUNTIME_FLAGS -DQMLJS_LLVM_RUNTIME llvm_runtime.cpp -o $$LLVM_RUNTIME_BC
+}
+
+# Use SSE2 floating point math on 32 bit instead of the default
+# 387 to make test results pass on 32 and on 64 bit builds.
+linux-g++*:isEqual(QT_ARCH,i386) {
+ QMAKE_CFLAGS += -march=pentium4 -msse2 -mfpmath=sse
+ QMAKE_CXXFLAGS += -march=pentium4 -msse2 -mfpmath=sse
+}
+
+linux*|mac {
+ LIBS += -ldl
+}
+
+# Only on Android/ARM at the moment, because only there we have issues
+# replacing __gnu_Unwind_Find_exidx with our own implementation,
+# and thus require static libgcc linkage.
+android:equals(QT_ARCH, "arm"):*g++* {
+ static_libgcc = $$system($$QMAKE_CXX -print-file-name=libgcc.a)
+ LIBS += $$static_libgcc
+ SOURCES += $$PWD/qv4exception_gcc.cpp
+ DEFINES += V4_CXX_ABI_EXCEPTION
+}
+
+debug-with-libunwind {
+ UW_INC=$$(LIBUNWIND_INCLUDES)
+ isEmpty(UW_INC): error("Please set LIBUNWIND_INCLUDES")
+ INCLUDEPATH += $$UW_INC
+ UW_LIBS=$$(LIBUNWIND_LIBS)
+ isEmpty(UW_LIBS): error("Please set LIBUNWIND_LIBS")
+ LIBS += -L$$UW_LIBS
+ equals(QT_ARCH, arm): LIBS += -lunwind-arm
+ LIBS += -lunwind-dwarf-common -lunwind-dwarf-local -lunwind-elf32 -lunwind
+ DEFINES += WTF_USE_LIBUNWIND_DEBUG=1
+}
+
+valgrind {
+ DEFINES += V4_USE_VALGRIND
+}
+
+ios: DEFINES += ENABLE_ASSEMBLER_WX_EXCLUSIVE=1
+
+win32 {
+ LIBS_PRIVATE += -lDbgHelp
+}
+
+include(moth/moth.pri)
+include(../../../3rdparty/masm/masm.pri)
+include(../../../3rdparty/double-conversion/double-conversion.pri)
diff --git a/src/qml/qml/v8/qjsconverter_impl_p.h b/src/qml/qml/v8/qjsconverter_impl_p.h
deleted file mode 100644
index 4b17d5ed31..0000000000
--- a/src/qml/qml/v8/qjsconverter_impl_p.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qjsconverter_p.h"
-#include <stdlib.h>
-
-#ifndef QJSCONVERTER_IMPL_P_H
-#define QJSCONVERTER_IMPL_P_H
-
-#ifdef Q_OS_QNX
-#include <malloc.h>
-#endif
-
-QT_BEGIN_NAMESPACE
-
-extern char *qdtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **digits_str);
-Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
-
-
-quint32 QJSConverter::toArrayIndex(const QString& string)
-{
- // FIXME this function should be exported by JSC C API.
- bool ok;
- quint32 idx = string.toUInt(&ok);
- if (!ok || toString(idx) != string)
- idx = 0xffffffff;
-
- return idx;
-}
-
-QString QJSConverter::toString(v8::Handle<v8::String> jsString)
-{
- if (jsString.IsEmpty())
- return QString();
- QString qstr;
- qstr.resize(jsString->Length());
- jsString->Write(reinterpret_cast<uint16_t*>(qstr.data()));
- return qstr;
-}
-
-v8::Local<v8::String> QJSConverter::toString(const QString& string)
-{
- return v8::String::New(reinterpret_cast<const uint16_t*>(string.data()), string.size());
-}
-
-QString QJSConverter::toString(double value)
-{
- // FIXME this should be easier. The ideal fix is to create
- // a new function in V8 API which could cover the functionality.
-
- if (qIsNaN(value))
- return QString::fromLatin1("NaN");
- if (qIsInf(value))
- return QString::fromLatin1(value < 0 ? "-Infinity" : "Infinity");
- if (!value)
- return QString::fromLatin1("0");
-
- QVarLengthArray<char, 25> buf;
- int decpt;
- int sign;
- char* result = 0;
- char* endresult;
- (void)qdtoa(value, 0, 0, &decpt, &sign, &endresult, &result);
-
- if (!result)
- return QString();
-
- int resultLen = endresult - result;
- if (decpt <= 0 && decpt > -6) {
- buf.resize(-decpt + 2 + sign);
- memset(buf.data(), '0', -decpt + 2 + sign);
- if (sign) // fix the sign.
- buf[0] = '-';
- buf[sign + 1] = '.';
- buf.append(result, resultLen);
- } else {
- if (sign)
- buf.append('-');
- int length = buf.size() - sign + resultLen;
- if (decpt <= 21 && decpt > 0) {
- if (length <= decpt) {
- const char* zeros = "0000000000000000000000000";
- buf.append(result, resultLen);
- buf.append(zeros, decpt - length);
- } else {
- buf.append(result, decpt);
- buf.append('.');
- buf.append(result + decpt, resultLen - decpt);
- }
- } else if (result[0] >= '0' && result[0] <= '9') {
- if (length > 1) {
- buf.append(result, 1);
- buf.append('.');
- buf.append(result + 1, resultLen - 1);
- } else
- buf.append(result, resultLen);
- buf.append('e');
- buf.append(decpt >= 0 ? '+' : '-');
- int e = qAbs(decpt - 1);
- if (e >= 100)
- buf.append('0' + e / 100);
- if (e >= 10)
- buf.append('0' + (e % 100) / 10);
- buf.append('0' + e % 10);
- }
- }
- free(result);
- buf.append(0);
- return QString::fromLatin1(buf.constData());
-}
-
-// return a mask of v8::PropertyAttribute that may also contains QScriptValue::PropertyGetter or QScriptValue::PropertySetter
-uint QJSConverter::toPropertyAttributes(const QFlags<QJSValuePrivate::PropertyFlag>& flags)
-{
- uint attr = 0;
- if (flags.testFlag(QJSValuePrivate::ReadOnly))
- attr |= v8::ReadOnly;
- if (flags.testFlag(QJSValuePrivate::Undeletable))
- attr |= v8::DontDelete;
- if (flags.testFlag(QJSValuePrivate::SkipInEnumeration))
- attr |= v8::DontEnum;
- // if (flags.testFlag(QScriptValue::PropertyGetter))
- // attr |= QScriptValue::PropertyGetter;
- // if (flags.testFlag(QScriptValue::PropertySetter))
- // attr |= QScriptValue::PropertySetter;
- return attr;
-}
-
-// Converts a JS RegExp to a QRegExp.
-// The conversion is not 100% exact since ECMA regexp and QRegExp
-// have different semantics/flags, but we try to do our best.
-QRegExp QJSConverter::toRegExp(v8::Handle<v8::RegExp> jsRegExp)
-{
- QString pattern = QJSConverter::toString(jsRegExp->GetSource());
- Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive;
- if (jsRegExp->GetFlags() & v8::RegExp::kIgnoreCase)
- caseSensitivity = Qt::CaseInsensitive;
- return QRegExp(pattern, caseSensitivity, QRegExp::RegExp2);
-}
-
-// Converts a QRegExp to a JS RegExp.
-// The conversion is not 100% exact since ECMA regexp and QRegExp
-// have different semantics/flags, but we try to do our best.
-v8::Local<v8::RegExp> QJSConverter::toRegExp(const QRegExp &re)
-{
- // Convert the pattern to a ECMAScript pattern.
- QString pattern = qt_regexp_toCanonical(re.pattern(), re.patternSyntax());
- if (re.isMinimal()) {
- QString ecmaPattern;
- int len = pattern.length();
- ecmaPattern.reserve(len);
- int i = 0;
- const QChar *wc = pattern.unicode();
- bool inBracket = false;
- while (i < len) {
- QChar c = wc[i++];
- ecmaPattern += c;
- switch (c.unicode()) {
- case '?':
- case '+':
- case '*':
- case '}':
- if (!inBracket)
- ecmaPattern += QLatin1Char('?');
- break;
- case '\\':
- if (i < len)
- ecmaPattern += wc[i++];
- break;
- case '[':
- inBracket = true;
- break;
- case ']':
- inBracket = false;
- break;
- default:
- break;
- }
- }
- pattern = ecmaPattern;
- }
-
- int flags = v8::RegExp::kNone;
- if (re.caseSensitivity() == Qt::CaseInsensitive)
- flags |= v8::RegExp::kIgnoreCase;
-
- return v8::RegExp::New(QJSConverter::toString(pattern), static_cast<v8::RegExp::Flags>(flags));
-}
-
-// Converts a QStringList to JS.
-// The result is a new Array object with length equal to the length
-// of the QStringList, and the elements being the QStringList's
-// elements converted to JS Strings.
-v8::Local<v8::Array> QJSConverter::toStringList(const QStringList &lst)
-{
- v8::Local<v8::Array> result = v8::Array::New(lst.size());
- for (int i = 0; i < lst.size(); ++i)
- result->Set(i, toString(lst.at(i)));
- return result;
-}
-
-// Converts a JS Array object to a QStringList.
-// The result is a QStringList with length equal to the length
-// of the JS Array, and elements being the JS Array's elements
-// converted to QStrings.
-QStringList QJSConverter::toStringList(v8::Handle<v8::Array> jsArray)
-{
- QStringList result;
- uint32_t length = jsArray->Length();
- for (uint32_t i = 0; i < length; ++i)
- result.append(toString(jsArray->Get(i)->ToString()));
- return result;
-}
-
-
-// Converts a JS Date to a QDateTime.
-QDateTime QJSConverter::toDateTime(v8::Handle<v8::Date> jsDate)
-{
- return QDateTime::fromMSecsSinceEpoch(jsDate->NumberValue());
-}
-
-// Converts a QDateTime to a JS Date.
-v8::Local<v8::Value> QJSConverter::toDateTime(const QDateTime &dt)
-{
- double date;
- if (!dt.isValid())
- date = qSNaN();
- else
- date = dt.toMSecsSinceEpoch();
- return v8::Date::New(date);
-}
-
-QT_END_NAMESPACE
-
-#endif // QJSCONVERTER_IMPL_P_H
diff --git a/src/qml/qml/v8/qjsconverter_p.h b/src/qml/qml/v8/qjsconverter_p.h
deleted file mode 100644
index 5f6633f580..0000000000
--- a/src/qml/qml/v8/qjsconverter_p.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QJSCONVERTER_P_H
-#define QJSCONVERTER_P_H
-
-#include "qjsvalue_p.h"
-#include <QtCore/qglobal.h>
-#include <QtCore/qnumeric.h>
-#include <QtCore/qstring.h>
-#include <QtCore/qstringlist.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qregexp.h>
-#include <QtCore/qdatetime.h>
-
-#include <private/qv8_p.h>
-
-QT_BEGIN_NAMESPACE
-
-/*
- \internal
- \class QJSConverter
- QJSValue and QJSEngine helper class. This class's responsibility is to convert values
- between JS values and Qt/C++ values.
-
- This is a nice way to inline these functions in both QJSValue and QJSEngine.
-*/
-class QJSConverter {
-public:
- static inline quint32 toArrayIndex(const QString& string);
-
- static inline QString toString(v8::Handle<v8::String> jsString);
- static inline v8::Local<v8::String> toString(const QString& string);
- static inline QString toString(double value);
-
- enum {
- PropertyAttributeMask = v8::ReadOnly | v8::DontDelete | v8::DontEnum,
- };
- // return a mask of v8::PropertyAttribute that may also contains QScriptValue::PropertyGetter or QScriptValue::PropertySetter
- static inline uint toPropertyAttributes(const QFlags<QJSValuePrivate::PropertyFlag>& flags);
-
- // Converts a JS RegExp to a QRegExp.
- // The conversion is not 100% exact since ECMA regexp and QRegExp
- // have different semantics/flags, but we try to do our best.
- static inline QRegExp toRegExp(v8::Handle<v8::RegExp> jsRegExp);
-
- // Converts a QRegExp to a JS RegExp.
- // The conversion is not 100% exact since ECMA regexp and QRegExp
- // have different semantics/flags, but we try to do our best.
- static inline v8::Local<v8::RegExp> toRegExp(const QRegExp &re);
-
- // Converts a QStringList to JS.
- // The result is a new Array object with length equal to the length
- // of the QStringList, and the elements being the QStringList's
- // elements converted to JS Strings.
- static inline v8::Local<v8::Array> toStringList(const QStringList &lst);
-
- // Converts a JS Array object to a QStringList.
- // The result is a QStringList with length equal to the length
- // of the JS Array, and elements being the JS Array's elements
- // converted to QStrings.
- static inline QStringList toStringList(v8::Handle<v8::Array> jsArray);
-
- // Converts a JS Date to a QDateTime.
- static inline QDateTime toDateTime(v8::Handle<v8::Date> jsDate);
-
- // Converts a QDateTime to a JS Date.
- static inline v8::Local<v8::Value> toDateTime(const QDateTime &dt);
-};
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/qml/v8/qjsengine.cpp b/src/qml/qml/v8/qjsengine.cpp
index dbd0851fec..554487cf13 100644
--- a/src/qml/qml/v8/qjsengine.cpp
+++ b/src/qml/qml/v8/qjsengine.cpp
@@ -43,10 +43,14 @@
#include "qjsengine_p.h"
#include "qjsvalue.h"
#include "qjsvalue_p.h"
-#include "qscriptisolate_p.h"
-#include "qscript_impl_p.h"
#include "qv8engine_p.h"
+#include "private/qv4engine_p.h"
+#include "private/qv4mm_p.h"
+#include "private/qv4globalobject_p.h"
+#include "private/qv4script_p.h"
+#include "private/qv4exception_p.h"
+
#include <QtCore/qdatetime.h>
#include <QtCore/qmetaobject.h>
#include <QtCore/qstringlist.h>
@@ -62,13 +66,13 @@
#include <qmutex.h>
#include <qwaitcondition.h>
#include <private/qqmlglobal_p.h>
+#include <qqmlengine.h>
#undef Q_D
#undef Q_Q
#define Q_D(blah)
#define Q_Q(blah)
-Q_DECLARE_METATYPE(QObjectList)
Q_DECLARE_METATYPE(QList<int>)
/*!
@@ -223,9 +227,7 @@ QJSEngine::~QJSEngine()
*/
void QJSEngine::collectGarbage()
{
- Q_D(QJSEngine);
- QScriptIsolate api(d);
- d->collectGarbage();
+ d->m_v4Engine->memoryManager->runGC();
}
/*!
@@ -258,10 +260,18 @@ void QJSEngine::collectGarbage()
*/
QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, int lineNumber)
{
- Q_D(QJSEngine);
- QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
- v8::HandleScope handleScope;
- return QJSValuePrivate::get(d->evaluate(program, fileName, qmlSourceCoordinate(lineNumber)));
+ QV4::ExecutionContext *ctx = d->m_v4Engine->current;
+ try {
+ QV4::Script script(ctx, program, fileName, lineNumber);
+ script.strictMode = ctx->strictMode;
+ script.inheritContext = true;
+ script.parse();
+ QV4::Value result = script.run();
+ return new QJSValuePrivate(d->m_v4Engine, result);
+ } catch (QV4::Exception& ex) {
+ ex.accept(ctx);
+ return new QJSValuePrivate(d->m_v4Engine, ex.value());
+ }
}
/*!
@@ -274,10 +284,7 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in
*/
QJSValue QJSEngine::newObject()
{
- Q_D(QJSEngine);
- QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
- v8::HandleScope handleScope;
- return QJSValuePrivate::get(new QJSValuePrivate(d, v8::Object::New()));
+ return new QJSValuePrivate(d->m_v4Engine->newObject());
}
/*!
@@ -287,10 +294,11 @@ QJSValue QJSEngine::newObject()
*/
QJSValue QJSEngine::newArray(uint length)
{
- Q_D(QJSEngine);
- QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
- v8::HandleScope handleScope;
- return QJSValuePrivate::get(d->newArray(length));
+ QV4::ArrayObject *array = d->m_v4Engine->newArrayObject();
+ if (length < 0x1000)
+ array->arrayReserve(length);
+ array->setArrayLengthUnchecked(length);
+ return new QJSValuePrivate(array);
}
/*!
@@ -316,9 +324,9 @@ QJSValue QJSEngine::newArray(uint length)
QJSValue QJSEngine::newQObject(QObject *object)
{
Q_D(QJSEngine);
- QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
- v8::HandleScope handleScope;
- return d->scriptValueFromInternal(d->newQObject(object, QV8Engine::JavaScriptOwnership));
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(d);
+ QQmlEngine::setObjectOwnership(object, QQmlEngine::JavaScriptOwnership);
+ return new QJSValuePrivate(v4, QV4::QObjectWrapper::wrap(v4, object));
}
/*!
@@ -333,10 +341,7 @@ QJSValue QJSEngine::newQObject(QObject *object)
*/
QJSValue QJSEngine::globalObject() const
{
- Q_D(const QJSEngine);
- QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
- v8::HandleScope handleScope;
- return d->scriptValueFromInternal(d->global());
+ return new QJSValuePrivate(d->m_v4Engine->globalObject);
}
/*!
@@ -346,9 +351,7 @@ QJSValue QJSEngine::globalObject() const
QJSValue QJSEngine::create(int type, const void *ptr)
{
Q_D(QJSEngine);
- QScriptIsolate api(d, QScriptIsolate::NotNullEngine);
- v8::HandleScope handleScope;
- return d->scriptValueFromInternal(d->metaTypeToJS(type, ptr));
+ return new QJSValuePrivate(d->m_v4Engine, d->metaTypeToJS(type, ptr));
}
/*!
@@ -358,51 +361,49 @@ QJSValue QJSEngine::create(int type, const void *ptr)
bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
{
QJSValuePrivate *vp = QJSValuePrivate::get(value);
- QV8Engine *engine = vp->engine();
+ QV8Engine *engine = vp->engine ? vp->engine->v8Engine : 0;
if (engine) {
- QScriptIsolate api(engine, QScriptIsolate::NotNullEngine);
- v8::HandleScope handleScope;
- return engine->metaTypeFromJS(*vp, type, ptr);
+ return engine->metaTypeFromJS(vp->getValue(engine->m_v4Engine), type, ptr);
} else {
switch (type) {
case QMetaType::Bool:
- *reinterpret_cast<bool*>(ptr) = vp->toBool();
+ *reinterpret_cast<bool*>(ptr) = vp->value.toBoolean();
return true;
case QMetaType::Int:
- *reinterpret_cast<int*>(ptr) = vp->toInt32();
+ *reinterpret_cast<int*>(ptr) = vp->value.toInt32();
return true;
case QMetaType::UInt:
- *reinterpret_cast<uint*>(ptr) = vp->toUInt32();
+ *reinterpret_cast<uint*>(ptr) = vp->value.toUInt32();
return true;
case QMetaType::LongLong:
- *reinterpret_cast<qlonglong*>(ptr) = vp->toInteger();
+ *reinterpret_cast<qlonglong*>(ptr) = vp->value.toInteger();
return true;
case QMetaType::ULongLong:
- *reinterpret_cast<qulonglong*>(ptr) = vp->toInteger();
+ *reinterpret_cast<qulonglong*>(ptr) = vp->value.toInteger();
return true;
case QMetaType::Double:
- *reinterpret_cast<double*>(ptr) = vp->toNumber();
+ *reinterpret_cast<double*>(ptr) = vp->value.toNumber();
return true;
case QMetaType::QString:
- *reinterpret_cast<QString*>(ptr) = vp->toString();
+ *reinterpret_cast<QString*>(ptr) = value.toString();
return true;
case QMetaType::Float:
- *reinterpret_cast<float*>(ptr) = vp->toNumber();
+ *reinterpret_cast<float*>(ptr) = vp->value.toNumber();
return true;
case QMetaType::Short:
- *reinterpret_cast<short*>(ptr) = vp->toInt32();
+ *reinterpret_cast<short*>(ptr) = vp->value.toInt32();
return true;
case QMetaType::UShort:
- *reinterpret_cast<unsigned short*>(ptr) = vp->toUInt16();
+ *reinterpret_cast<unsigned short*>(ptr) = vp->value.toUInt16();
return true;
case QMetaType::Char:
- *reinterpret_cast<char*>(ptr) = vp->toInt32();
+ *reinterpret_cast<char*>(ptr) = vp->value.toInt32();
return true;
case QMetaType::UChar:
- *reinterpret_cast<unsigned char*>(ptr) = vp->toUInt16();
+ *reinterpret_cast<unsigned char*>(ptr) = vp->value.toUInt16();
return true;
case QMetaType::QChar:
- *reinterpret_cast<QChar*>(ptr) = vp->toUInt16();
+ *reinterpret_cast<QChar*>(ptr) = vp->value.toUInt16();
return true;
default:
return false;
@@ -424,35 +425,6 @@ bool QJSEngine::convertV2(const QJSValue &value, int type, void *ptr)
\sa toScriptValue()
*/
-/*!
- \internal
-
- Returns this engine's internal V8 context.
-
- The context enables direct use of the V8 API.
- The caller is responsible for ensuring that a handle scope is in place,
- and for entering/exiting the context.
- Example:
-
- \code
- QJSEngine eng;
- ...
- v8::HandleScope handleScope;
- v8::Local<v8::Context> context = qt_QJSEngineV8Context(&eng);
- v8::Context::Scope contextScope(context);
-
- // Do stuff (e.g., call v8::Script::Compile()) ...
- \endcode
-
- \sa qt_QJSValueV8Value()
-*/
-Q_QML_EXPORT v8::Local<v8::Context> qt_QJSEngineV8Context(QJSEngine *engine)
-{
- Q_ASSERT(engine != 0);
- QV8Engine *d = engine->handle();
- return v8::Local<v8::Context>::New(d->context());
-}
-
QT_END_NAMESPACE
#include "moc_qjsengine.cpp"
diff --git a/src/qml/qml/v8/qjsvalue.cpp b/src/qml/qml/v8/qjsvalue.cpp
index 87be773218..2fab183bd0 100644
--- a/src/qml/qml/v8/qjsvalue.cpp
+++ b/src/qml/qml/v8/qjsvalue.cpp
@@ -39,14 +39,42 @@
**
****************************************************************************/
-#include "qscriptisolate_p.h"
+#include <QtCore/qstring.h>
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qdatetime.h>
#include "qjsengine.h"
-#include "qv8engine_p.h"
#include "qjsvalue.h"
#include "qjsvalue_p.h"
-#include "qscript_impl_p.h"
-#include "qscriptshareddata_p.h"
-#include <QtCore/qstring.h>
+#include "qv4value_p.h"
+#include "qv4object_p.h"
+#include "qv4functionobject_p.h"
+#include "qv4dateobject_p.h"
+#include "qv4runtime_p.h"
+#include "qv4variantobject_p.h"
+#include "qv4regexpobject_p.h"
+#include "qv8engine_p.h"
+#include <private/qv4mm_p.h>
+#include <private/qv4exception_p.h>
+
+QV4::Value QJSValuePrivate::getValue(QV4::ExecutionEngine *e)
+{
+ if (!this->engine)
+ this->engine = e;
+ else if (this->engine != e) {
+ qWarning("JSValue can't be reassigned to another engine.");
+ return QV4::Value::emptyValue();
+ }
+ if (value.asString() == &string) {
+ value = QV4::Value::fromString(engine->newString(string.toQString()));
+ PersistentValuePrivate **listRoot = &engine->memoryManager->m_persistentValues;
+ prev = listRoot;
+ next = *listRoot;
+ *prev = this;
+ if (next)
+ next->prev = &this->next;
+ }
+ return value;
+}
/*!
\since 5.0
@@ -114,11 +142,18 @@
QT_BEGIN_NAMESPACE
+using namespace QV4;
+
/*!
Constructs a new QJSValue with a boolean \a value.
*/
QJSValue::QJSValue(bool value)
- : d_ptr(new QJSValuePrivate(value))
+ : d(new QJSValuePrivate(0, Value::fromBoolean(value)))
+{
+}
+
+QJSValue::QJSValue(QJSValuePrivate *dd)
+ : d(dd)
{
}
@@ -126,7 +161,7 @@ QJSValue::QJSValue(bool value)
Constructs a new QJSValue with a number \a value.
*/
QJSValue::QJSValue(int value)
- : d_ptr(new QJSValuePrivate(value))
+ : d(new QJSValuePrivate(0, Value::fromInt32(value)))
{
}
@@ -134,7 +169,7 @@ QJSValue::QJSValue(int value)
Constructs a new QJSValue with a number \a value.
*/
QJSValue::QJSValue(uint value)
- : d_ptr(new QJSValuePrivate(value))
+ : d(new QJSValuePrivate(0, Value::fromUInt32(value)))
{
}
@@ -142,7 +177,7 @@ QJSValue::QJSValue(uint value)
Constructs a new QJSValue with a number \a value.
*/
QJSValue::QJSValue(double value)
- : d_ptr(new QJSValuePrivate(value))
+ : d(new QJSValuePrivate(0, Value::fromDouble(value)))
{
}
@@ -150,7 +185,7 @@ QJSValue::QJSValue(double value)
Constructs a new QJSValue with a string \a value.
*/
QJSValue::QJSValue(const QString& value)
- : d_ptr(new QJSValuePrivate(value))
+ : d(new QJSValuePrivate(value))
{
}
@@ -158,7 +193,7 @@ QJSValue::QJSValue(const QString& value)
Constructs a new QJSValue with a special \a value.
*/
QJSValue::QJSValue(SpecialValue value)
- : d_ptr(new QJSValuePrivate(value))
+ : d(new QJSValuePrivate(0, value == UndefinedValue ? Value::undefinedValue() : Value::nullValue()))
{
}
@@ -166,7 +201,7 @@ QJSValue::QJSValue(SpecialValue value)
Constructs a new QJSValue with a string \a value.
*/
QJSValue::QJSValue(const QLatin1String &value)
- : d_ptr(new QJSValuePrivate(value))
+ : d(new QJSValuePrivate(value))
{
}
@@ -175,30 +210,12 @@ QJSValue::QJSValue(const QLatin1String &value)
*/
#ifndef QT_NO_CAST_FROM_ASCII
QJSValue::QJSValue(const char *value)
- : d_ptr(new QJSValuePrivate(QString::fromLatin1(value)))
+ : d(new QJSValuePrivate(QString::fromLatin1(value)))
{
}
#endif
/*!
- Constructs a new QJSValue from private
- \internal
-*/
-QJSValue::QJSValue(QJSValuePrivate* d)
- : d_ptr(d)
-{
-}
-
-/*!
- Constructs a new QJSValue from private
- \internal
-*/
-QJSValue::QJSValue(QScriptPassPointer<QJSValuePrivate> d)
- : d_ptr(d.give())
-{
-}
-
-/*!
Constructs a new QJSValue that is a copy of \a other.
Note that if \a other is an object (i.e., isObject() would return
@@ -206,8 +223,9 @@ QJSValue::QJSValue(QScriptPassPointer<QJSValuePrivate> d)
the new script value (i.e., the object itself is not copied).
*/
QJSValue::QJSValue(const QJSValue& other)
- : d_ptr(other.d_ptr)
+ : d(other.d)
{
+ d->ref();
}
/*!
@@ -215,6 +233,7 @@ QJSValue::QJSValue(const QJSValue& other)
*/
QJSValue::~QJSValue()
{
+ d->deref();
}
/*!
@@ -225,9 +244,7 @@ QJSValue::~QJSValue()
*/
bool QJSValue::isBool() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->isBool();
+ return d->value.isBoolean();
}
/*!
@@ -238,9 +255,7 @@ bool QJSValue::isBool() const
*/
bool QJSValue::isNumber() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->isNumber();
+ return d->value.isNumber();
}
/*!
@@ -249,9 +264,7 @@ bool QJSValue::isNumber() const
*/
bool QJSValue::isNull() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->isNull();
+ return d->value.isNull();
}
/*!
@@ -262,9 +275,7 @@ bool QJSValue::isNull() const
*/
bool QJSValue::isString() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->isString();
+ return d->value.isString();
}
/*!
@@ -273,9 +284,7 @@ bool QJSValue::isString() const
*/
bool QJSValue::isUndefined() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->isUndefined();
+ return d->value.isUndefined();
}
/*!
@@ -284,9 +293,8 @@ bool QJSValue::isUndefined() const
*/
bool QJSValue::isError() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->isError();
+ Object *o = d->value.asObject();
+ return o && o->asErrorObject();
}
/*!
@@ -297,10 +305,8 @@ bool QJSValue::isError() const
*/
bool QJSValue::isArray() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->isArray();
- }
+ return d->value.asArrayObject();
+}
/*!
Returns true if this QJSValue is of the Object type; otherwise
@@ -313,9 +319,7 @@ bool QJSValue::isArray() const
*/
bool QJSValue::isObject() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->isObject();
+ return d->value.asObject();
}
/*!
@@ -326,9 +330,7 @@ bool QJSValue::isObject() const
*/
bool QJSValue::isCallable() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->isCallable();
+ return d->value.asFunctionObject();
}
/*!
@@ -339,9 +341,8 @@ bool QJSValue::isCallable() const
*/
bool QJSValue::isVariant() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->isVariant();
+ Managed *m = d->value.asManaged();
+ return m ? m->as<QV4::VariantObject>() : 0;
}
/*!
@@ -358,9 +359,7 @@ bool QJSValue::isVariant() const
*/
QString QJSValue::toString() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->toString();
+ return d->value.toQString();
}
/*!
@@ -377,9 +376,13 @@ QString QJSValue::toString() const
*/
double QJSValue::toNumber() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->toNumber();
+ QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+ try {
+ return d->value.toNumber();
+ } catch (Exception &e) {
+ e.accept(ctx);
+ return 0;
+ }
}
/*!
@@ -396,9 +399,13 @@ double QJSValue::toNumber() const
*/
bool QJSValue::toBool() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->toBool();
+ QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+ try {
+ return d->value.toBoolean();
+ } catch (Exception &e) {
+ e.accept(ctx);
+ return false;
+ }
}
/*!
@@ -415,9 +422,13 @@ bool QJSValue::toBool() const
*/
qint32 QJSValue::toInt() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->toInt32();
+ QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+ try {
+ return d->value.toInt32();
+ } catch (Exception &e) {
+ e.accept(ctx);
+ return 0;
+ }
}
/*!
@@ -434,9 +445,13 @@ qint32 QJSValue::toInt() const
*/
quint32 QJSValue::toUInt() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->toUInt32();
+ QV4::ExecutionContext *ctx = d->engine ? d->engine->current : 0;
+ try {
+ return d->value.toUInt32();
+ } catch (Exception &e) {
+ e.accept(ctx);
+ return 0;
+ }
}
/*!
@@ -463,9 +478,7 @@ quint32 QJSValue::toUInt() const
*/
QVariant QJSValue::toVariant() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->toVariant();
+ return QV4::VariantObject::toVariant(d->value);
}
/*!
@@ -485,9 +498,32 @@ QVariant QJSValue::toVariant() const
*/
QJSValue QJSValue::call(const QJSValueList &args)
{
- Q_D(QJSValue);
- QScriptIsolate api(d->engine());
- return d->call(/*thisObject=*/0, args);
+ FunctionObject *f = d->value.asFunctionObject();
+ if (!f)
+ return QJSValue();
+
+ ExecutionEngine *engine = d->engine;
+ assert(engine);
+
+ QVarLengthArray<Value, 9> arguments(args.length());
+ for (int i = 0; i < args.size(); ++i) {
+ if (!args.at(i).d->checkEngine(engine)) {
+ qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine");
+ return QJSValue();
+ }
+ arguments[i] = args.at(i).d->getValue(engine);
+ }
+
+ Value result;
+ QV4::ExecutionContext *ctx = engine->current;
+ try {
+ result = f->call(Value::fromObject(engine->globalObject), arguments.data(), arguments.size());
+ } catch (Exception &e) {
+ e.accept(ctx);
+ result = e.value();
+ }
+
+ return new QJSValuePrivate(engine, result);
}
/*!
@@ -512,9 +548,37 @@ QJSValue QJSValue::call(const QJSValueList &args)
*/
QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList &args)
{
- Q_D(QJSValue);
- QScriptIsolate api(d->engine());
- return d->call(QJSValuePrivate::get(instance), args);
+ FunctionObject *f = d->value.asFunctionObject();
+ if (!f)
+ return QJSValue();
+
+ ExecutionEngine *engine = d->engine;
+ assert(engine);
+
+ if (!instance.d->checkEngine(engine)) {
+ qWarning("QJSValue::call() failed: cannot call function with thisObject created in a different engine");
+ return QJSValue();
+ }
+
+ QVarLengthArray<Value, 9> arguments(args.length());
+ for (int i = 0; i < args.size(); ++i) {
+ if (!args.at(i).d->checkEngine(engine)) {
+ qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine");
+ return QJSValue();
+ }
+ arguments[i] = args.at(i).d->getValue(engine);
+ }
+
+ Value result;
+ QV4::ExecutionContext *ctx = engine->current;
+ try {
+ result = f->call(instance.d->getValue(engine), arguments.data(), arguments.size());
+ } catch (Exception &e) {
+ e.accept(ctx);
+ result = e.value();
+ }
+
+ return new QJSValuePrivate(engine, result);
}
/*!
@@ -537,9 +601,32 @@ QJSValue QJSValue::callWithInstance(const QJSValue &instance, const QJSValueList
*/
QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
{
- Q_D(QJSValue);
- QScriptIsolate api(d->engine());
- return QJSValuePrivate::get(d->callAsConstructor(args));
+ FunctionObject *f = d->value.asFunctionObject();
+ if (!f)
+ return QJSValue();
+
+ ExecutionEngine *engine = d->engine;
+ assert(engine);
+
+ QVarLengthArray<Value, 9> arguments(args.length());
+ for (int i = 0; i < args.size(); ++i) {
+ if (!args.at(i).d->checkEngine(engine)) {
+ qWarning("QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine");
+ return QJSValue();
+ }
+ arguments[i] = args.at(i).d->getValue(engine);
+ }
+
+ Value result;
+ QV4::ExecutionContext *ctx = engine->current;
+ try {
+ result = f->construct(arguments.data(), arguments.size());
+ } catch (Exception &e) {
+ e.accept(ctx);
+ result = e.value();
+ }
+
+ return new QJSValuePrivate(engine, result);
}
#ifdef QT_DEPRECATED
@@ -553,11 +640,9 @@ QJSValue QJSValue::callAsConstructor(const QJSValueList &args)
*/
QJSEngine* QJSValue::engine() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- QV8Engine* engine = d->engine();
+ QV4::ExecutionEngine *engine = d->engine;
if (engine)
- return QV8Engine::get(engine);
+ return engine->v8Engine->publicEngine();
return 0;
}
@@ -572,14 +657,18 @@ QJSEngine* QJSValue::engine() const
*/
QJSValue QJSValue::prototype() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return QJSValuePrivate::get(d->prototype());
+ Object *o = d->value.asObject();
+ if (!o)
+ return QJSValue();
+ if (!o->prototype)
+ return QJSValue(NullValue);
+ return new QJSValuePrivate(o->internalClass->engine, Value::fromObject(o->prototype));
}
/*!
If this QJSValue is an object, sets the internal prototype
(\c{__proto__} property) of this object to be \a prototype;
+ if the QJSValue is null, it sets the prototype to null;
otherwise does nothing.
The internal prototype should not be confused with the public
@@ -590,9 +679,30 @@ QJSValue QJSValue::prototype() const
*/
void QJSValue::setPrototype(const QJSValue& prototype)
{
- Q_D(QJSValue);
- QScriptIsolate api(d->engine());
- d->setPrototype(QJSValuePrivate::get(prototype));
+ Object *o = d->value.asObject();
+ if (!o)
+ return;
+ if (prototype.d->value.isNull()) {
+ o->prototype = 0;
+ return;
+ }
+
+ Object *p = prototype.d->value.asObject();
+ if (!p)
+ return;
+ if (o->engine() != p->engine()) {
+ qWarning("QJSValue::setPrototype() failed: cannot set a prototype created in a different engine");
+ return;
+ }
+ Object *pp = p;
+ while (pp) {
+ if (pp == o) {
+ qWarning("QJSValue::setPrototype() failed: cyclic prototype value");
+ return;
+ }
+ pp = pp->prototype;
+ }
+ o->prototype = p;
}
/*!
@@ -604,8 +714,11 @@ void QJSValue::setPrototype(const QJSValue& prototype)
*/
QJSValue& QJSValue::operator=(const QJSValue& other)
{
- d_ptr = other.d_ptr;
- return *this;
+ if (d == other.d)
+ return *this;
+ d->deref();
+ d = other.d;
+ d->ref();
}
/*!
@@ -634,10 +747,7 @@ QJSValue& QJSValue::operator=(const QJSValue& other)
*/
bool QJSValue::equals(const QJSValue& other) const
{
- Q_D(const QJSValue);
- QJSValuePrivate* otherValue = QJSValuePrivate::get(other);
- QScriptIsolate api(d->engine() ? d->engine() : otherValue->engine());
- return d_ptr->equals(otherValue);
+ return __qmljs_equal(d->value, other.d->value);
}
/*!
@@ -664,10 +774,7 @@ bool QJSValue::equals(const QJSValue& other) const
*/
bool QJSValue::strictlyEquals(const QJSValue& other) const
{
- Q_D(const QJSValue);
- QJSValuePrivate* o = QJSValuePrivate::get(other);
- QScriptIsolate api(d->engine() ? d->engine() : o->engine());
- return d_ptr->strictlyEquals(o);
+ return __qmljs_strict_equal(d->value, other.d->value);
}
/*!
@@ -685,9 +792,25 @@ bool QJSValue::strictlyEquals(const QJSValue& other) const
*/
QJSValue QJSValue::property(const QString& name) const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return QJSValuePrivate::get(d->property(name));
+ Object *o = d->value.asObject();
+ if (!o)
+ return QJSValue();
+
+ ExecutionEngine *engine = d->engine;
+ String *s = engine->newString(name);
+ uint idx = s->asArrayIndex();
+ if (idx < UINT_MAX)
+ return property(idx);
+
+ s->makeIdentifier();
+ QV4::ExecutionContext *ctx = engine->current;
+ try {
+ QV4::Value v = o->get(s);
+ return new QJSValuePrivate(engine, v);
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ return new QJSValuePrivate(engine, e.value());
+ }
}
/*!
@@ -704,9 +827,19 @@ QJSValue QJSValue::property(const QString& name) const
*/
QJSValue QJSValue::property(quint32 arrayIndex) const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return QJSValuePrivate::get(d->property(arrayIndex));
+ Object *o = d->value.asObject();
+ if (!o)
+ return QJSValue();
+
+ ExecutionEngine *engine = d->engine;
+ QV4::ExecutionContext *ctx = engine->current;
+ try {
+ QV4::Value v = arrayIndex == UINT_MAX ? o->get(engine->id_uintMax) : o->getIndexed(arrayIndex);
+ return new QJSValuePrivate(engine, v);
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ return new QJSValuePrivate(engine, e.value());
+ }
}
/*!
@@ -722,9 +855,30 @@ QJSValue QJSValue::property(quint32 arrayIndex) const
*/
void QJSValue::setProperty(const QString& name, const QJSValue& value)
{
- Q_D(QJSValue);
- QScriptIsolate api(d->engine());
- d->setProperty(name, QJSValuePrivate::get(value));
+ Object *o = d->value.asObject();
+ if (!o)
+ return;
+
+ if (!value.d->checkEngine(o->engine())) {
+ qWarning("QJSValue::setProperty(%s) failed: cannot set value created in a different engine", name.toUtf8().constData());
+ return;
+ }
+
+ ExecutionEngine *engine = d->engine;
+ String *s = engine->newString(name);
+ uint idx = s->asArrayIndex();
+ if (idx < UINT_MAX) {
+ setProperty(idx, value);
+ return;
+ }
+
+ QV4::ExecutionContext *ctx = engine->current;
+ s->makeIdentifier();
+ try {
+ o->put(s, value.d->getValue(engine));
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ }
}
/*!
@@ -741,9 +895,20 @@ void QJSValue::setProperty(const QString& name, const QJSValue& value)
*/
void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
{
- Q_D(QJSValue);
- QScriptIsolate api(d->engine());
- d->setProperty(arrayIndex, QJSValuePrivate::get(value));
+ Object *o = d->value.asObject();
+ if (!o)
+ return;
+
+ ExecutionEngine *engine = d->engine;
+ QV4::ExecutionContext *ctx = engine->current;
+ try {
+ if (arrayIndex != UINT_MAX)
+ o->putIndexed(arrayIndex, value.d->getValue(engine));
+ else
+ o->put(engine->id_uintMax, value.d->getValue(engine));
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ }
}
/*!
@@ -768,9 +933,13 @@ void QJSValue::setProperty(quint32 arrayIndex, const QJSValue& value)
*/
bool QJSValue::deleteProperty(const QString &name)
{
- Q_D(QJSValue);
- QScriptIsolate api(d->engine());
- return d->deleteProperty(name);
+ Object *o = d->value.asObject();
+ if (!o)
+ return false;
+
+ ExecutionEngine *engine = d->engine;
+ String *s = engine->newString(name);
+ return o->deleteProperty(s);
}
/*!
@@ -781,9 +950,13 @@ bool QJSValue::deleteProperty(const QString &name)
*/
bool QJSValue::hasProperty(const QString &name) const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->hasProperty(name);
+ Object *o = d->value.asObject();
+ if (!o)
+ return false;
+
+ ExecutionEngine *engine = d->engine;
+ String *s = engine->newIdentifier(name);
+ return o->__hasProperty__(s);
}
/*!
@@ -794,9 +967,13 @@ bool QJSValue::hasProperty(const QString &name) const
*/
bool QJSValue::hasOwnProperty(const QString &name) const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->hasOwnProperty(name);
+ Object *o = d->value.asObject();
+ if (!o)
+ return false;
+
+ ExecutionEngine *engine = d->engine;
+ String *s = engine->newIdentifier(name);
+ return o->__getOwnProperty__(s);
}
/*!
@@ -811,9 +988,11 @@ bool QJSValue::hasOwnProperty(const QString &name) const
*/
QObject *QJSValue::toQObject() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->toQObject();
+ QV4::QObjectWrapper *o = d->value.as<QV4::QObjectWrapper>();
+ if (!o)
+ return 0;
+
+ return o->object();
}
/*!
@@ -825,9 +1004,10 @@ QObject *QJSValue::toQObject() const
*/
QDateTime QJSValue::toDateTime() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->toDataTime();
+ QV4::DateObject *date = d->value.asDateObject();
+ if (!date)
+ return QDateTime();
+ return date->toQDateTime();
}
/*!
@@ -838,9 +1018,7 @@ QDateTime QJSValue::toDateTime() const
*/
bool QJSValue::isDate() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->isDate();
+ return d->value.asDateObject();
}
/*!
@@ -849,9 +1027,7 @@ bool QJSValue::isDate() const
*/
bool QJSValue::isRegExp() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->isRegExp();
+ return d->value.as<RegExpObject>();
}
/*!
@@ -865,35 +1041,7 @@ bool QJSValue::isRegExp() const
*/
bool QJSValue::isQObject() const
{
- Q_D(const QJSValue);
- QScriptIsolate api(d->engine());
- return d->isQObject();
-}
-
-/*!
- \internal
-
- Returns this value's internal V8 value, or an empty handle if
- the QJSValue isn't bound to a QJSEngine.
-
- The V8 value enables direct use of the V8 API.
- The caller is responsible for ensuring that a handle scope is in place.
- Example:
-
- \code
- QJSValue value = ...;
- v8::HandleScope handleScope;
- v8::Local<v8::Value> v8value = qt_QJSValueV8Value(value);
-
- // Do something with the V8 value (e.g., call v8::Value::IsInt32()) ...
- \endcode
-
- \sa qt_QJSEngineV8Context()
-*/
-Q_QML_EXPORT v8::Local<v8::Value> qt_QJSValueV8Value(const QJSValue &value)
-{
- QJSValuePrivate *d = QJSValuePrivate::get(value);
- return v8::Local<v8::Value>::New(d->handle());
+ return d->value.as<QV4::QObjectWrapper>() != 0;
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qjsvalue.h b/src/qml/qml/v8/qjsvalue.h
index efd52ce880..cf02ad819e 100644
--- a/src/qml/qml/v8/qjsvalue.h
+++ b/src/qml/qml/v8/qjsvalue.h
@@ -45,8 +45,7 @@
#include <QtQml/qtqmlglobal.h>
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
-#include <QtCore/qsharedpointer.h>
-#include <QtCore/qshareddata.h>
+#include <QtCore/qmetatype.h>
QT_BEGIN_NAMESPACE
@@ -59,10 +58,7 @@ struct QMetaObject;
class QDateTime;
typedef QList<QJSValue> QJSValueList;
-
class QJSValuePrivate;
-struct QScriptValuePrivatePointerDeleter;
-template <class T> class QScriptPassPointer;
class Q_QML_EXPORT QJSValue
{
@@ -137,18 +133,13 @@ public:
QT_DEPRECATED QJSEngine *engine() const;
#endif
+ QJSValue(QJSValuePrivate *dd);
private:
+ friend class QJSValuePrivate;
// force compile error, prevent QJSValue(bool) to be called
-
QJSValue(void *) Q_DECL_EQ_DELETE;
- QJSValue(QJSValuePrivate*);
- QJSValue(QScriptPassPointer<QJSValuePrivate>);
-
-private:
- QExplicitlySharedDataPointer<QJSValuePrivate> d_ptr;
-
- Q_DECLARE_PRIVATE(QJSValue)
+ QJSValuePrivate *d;
};
QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qjsvalue_impl_p.h b/src/qml/qml/v8/qjsvalue_impl_p.h
deleted file mode 100644
index 2e779c22e9..0000000000
--- a/src/qml/qml/v8/qjsvalue_impl_p.h
+++ /dev/null
@@ -1,950 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// 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.
-//
-
-#ifndef QJSVALUE_IMPL_P_H
-#define QJSVALUE_IMPL_P_H
-
-#include "qjsconverter_p.h"
-#include "qjsvalue_p.h"
-#include "qv8engine_p.h"
-#include "qscriptisolate_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QJSValuePrivate* QJSValuePrivate::get(const QJSValue& q) { Q_ASSERT(q.d_ptr.data()); return q.d_ptr.data(); }
-
-QJSValue QJSValuePrivate::get(const QJSValuePrivate* d)
-{
- Q_ASSERT(d);
- return QJSValue(const_cast<QJSValuePrivate*>(d));
-}
-
-QJSValue QJSValuePrivate::get(QScriptPassPointer<QJSValuePrivate> d)
-{
- Q_ASSERT(d);
- return QJSValue(d);
-}
-
-QJSValue QJSValuePrivate::get(QJSValuePrivate* d)
-{
- Q_ASSERT(d);
- return QJSValue(d);
-}
-
-QJSValuePrivate::QJSValuePrivate(bool value)
- : m_engine(0), m_state(CBool), u(value)
-{
-}
-
-QJSValuePrivate::QJSValuePrivate(int value)
- : m_engine(0), m_state(CNumber), u(value)
-{
-}
-
-QJSValuePrivate::QJSValuePrivate(uint value)
- : m_engine(0), m_state(CNumber), u(value)
-{
-}
-
-QJSValuePrivate::QJSValuePrivate(double value)
- : m_engine(0), m_state(CNumber), u(value)
-{
-}
-
-QJSValuePrivate::QJSValuePrivate(const QString& value)
- : m_engine(0), m_state(CString), u(new QString(value))
-{
-}
-
-QJSValuePrivate::QJSValuePrivate(QJSValue::SpecialValue value)
- : m_engine(0), m_state(value == QJSValue::NullValue ? CNull : CUndefined)
-{
-}
-
-QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, bool value)
- : m_engine(engine), m_state(JSValue)
-{
- Q_ASSERT(engine);
- v8::HandleScope handleScope;
- m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
- m_engine->registerValue(this);
-}
-
-QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, int value)
- : m_engine(engine), m_state(JSValue)
-{
- Q_ASSERT(engine);
- v8::HandleScope handleScope;
- m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
- m_engine->registerValue(this);
-}
-
-QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, uint value)
- : m_engine(engine), m_state(JSValue)
-{
- Q_ASSERT(engine);
- v8::HandleScope handleScope;
- m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
- m_engine->registerValue(this);
-}
-
-QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, double value)
- : m_engine(engine), m_state(JSValue)
-{
- Q_ASSERT(engine);
- v8::HandleScope handleScope;
- m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
- m_engine->registerValue(this);
-}
-
-QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, const QString& value)
- : m_engine(engine), m_state(JSValue)
-{
- Q_ASSERT(engine);
- v8::HandleScope handleScope;
- m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
- m_engine->registerValue(this);
-}
-
-QJSValuePrivate::QJSValuePrivate(QV8Engine* engine, QJSValue::SpecialValue value)
- : m_engine(engine), m_state(JSValue)
-{
- Q_ASSERT(engine);
- v8::HandleScope handleScope;
- m_value = v8::Persistent<v8::Value>::New(m_engine->makeJSValue(value));
- m_engine->registerValue(this);
-}
-
-QJSValuePrivate::QJSValuePrivate(QV8Engine *engine, v8::Handle<v8::Value> value)
- : m_engine(engine), m_state(JSValue), m_value(v8::Persistent<v8::Value>::New(value))
-{
- Q_ASSERT(engine);
- // It shouldn't happen, v8 shows errors by returning an empty handler. This is important debug
- // information and it can't be simply ignored.
- Q_ASSERT(!value.IsEmpty());
- m_engine->registerValue(this);
-}
-
-QJSValuePrivate::~QJSValuePrivate()
-{
- if (isJSBased()) {
- m_engine->unregisterValue(this);
- QScriptIsolate api(m_engine);
- m_value.Dispose();
- } else if (isStringBased()) {
- delete u.m_string;
- }
-}
-
-bool QJSValuePrivate::toBool() const
-{
- switch (m_state) {
- case JSValue:
- {
- v8::HandleScope scope;
- return m_value->ToBoolean()->Value();
- }
- case CNumber:
- return !(qIsNaN(u.m_number) || !u.m_number);
- case CBool:
- return u.m_bool;
- case CNull:
- case CUndefined:
- return false;
- case CString:
- return u.m_string->length();
- }
-
- Q_ASSERT_X(false, "toBool()", "Not all states are included in the previous switch statement.");
- return false; // Avoid compiler warning.
-}
-
-double QJSValuePrivate::toNumber() const
-{
- switch (m_state) {
- case JSValue:
- {
- v8::HandleScope scope;
- return m_value->ToNumber()->Value();
- }
- case CNumber:
- return u.m_number;
- case CBool:
- return u.m_bool ? 1 : 0;
- case CNull:
- case CUndefined:
- return qQNaN();
- case CString:
- bool ok;
- double result = u.m_string->toDouble(&ok);
- if (ok)
- return result;
- result = u.m_string->toInt(&ok, 0); // Try other bases.
- if (ok)
- return result;
- if (*u.m_string == QLatin1String("Infinity"))
- return qInf();
- if (*u.m_string == QLatin1String("-Infinity"))
- return -qInf();
- return u.m_string->length() ? qQNaN() : 0;
- }
-
- Q_ASSERT_X(false, "toNumber()", "Not all states are included in the previous switch statement.");
- return 0; // Avoid compiler warning.
-}
-
-QString QJSValuePrivate::toString() const
-{
- switch (m_state) {
- case CBool:
- return u.m_bool ? QString::fromLatin1("true") : QString::fromLatin1("false");
- case CString:
- return *u.m_string;
- case CNumber:
- return QJSConverter::toString(u.m_number);
- case CNull:
- return QString::fromLatin1("null");
- case CUndefined:
- return QString::fromLatin1("undefined");
- case JSValue:
- Q_ASSERT(!m_value.IsEmpty());
- v8::HandleScope handleScope;
- v8::TryCatch tryCatch;
- v8::Local<v8::String> result = m_value->ToString();
- if (result.IsEmpty())
- result = tryCatch.Exception()->ToString();
- return QJSConverter::toString(result);
- }
-
- Q_ASSERT_X(false, "toString()", "Not all states are included in the previous switch statement.");
- return QString(); // Avoid compiler warning.
-}
-
-QVariant QJSValuePrivate::toVariant() const
-{
- switch (m_state) {
- case CBool:
- return QVariant(u.m_bool);
- case CString:
- return QVariant(*u.m_string);
- case CNumber:
- return QVariant(u.m_number);
- case CNull:
- return QVariant(QMetaType::VoidStar, 0);
- case CUndefined:
- return QVariant();
- case JSValue:
- break;
- }
-
- Q_ASSERT(m_state == JSValue);
- Q_ASSERT(!m_value.IsEmpty());
- Q_ASSERT(m_engine);
-
- v8::HandleScope handleScope;
- return m_engine->variantFromJS(m_value);
-}
-
-inline QDateTime QJSValuePrivate::toDataTime() const
-{
- if (!isDate())
- return QDateTime();
-
- v8::HandleScope handleScope;
- return QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(m_value));
-
-}
-
-QObject* QJSValuePrivate::toQObject() const
-{
- if (!isJSBased())
- return 0;
-
- v8::HandleScope handleScope;
- return engine()->qtObjectFromJS(m_value);
-}
-
-double QJSValuePrivate::toInteger() const
-{
- double result = toNumber();
- if (qIsNaN(result))
- return 0;
- if (qIsInf(result))
- return result;
-
- // Must use floor explicitly rather than qFloor here. On some
- // platforms qFloor will cast the value to a single precision float and use
- // floorf() which results in test failures.
- return (result > 0) ? floor(result) : -1 * floor(-result);
-}
-
-qint32 QJSValuePrivate::toInt32() const
-{
- double result = toInteger();
- // Orginaly it should look like that (result == 0 || qIsInf(result) || qIsNaN(result)), but
- // some of these operation are invoked in toInteger subcall.
- if (qIsInf(result))
- return 0;
- return result;
-}
-
-quint32 QJSValuePrivate::toUInt32() const
-{
- double result = toInteger();
- // Orginaly it should look like that (result == 0 || qIsInf(result) || qIsNaN(result)), but
- // some of these operation are invoked in toInteger subcall.
- if (qIsInf(result))
- return 0;
-
- // The explicit casts are required to avoid undefined behaviour. For example, casting
- // a negative double directly to an unsigned int on ARM NEON FPU results in the value
- // being set to zero. Casting to a signed int first ensures well defined behaviour.
- return (quint32) (qint32) result;
-}
-
-quint16 QJSValuePrivate::toUInt16() const
-{
- return toInt32();
-}
-
-inline bool QJSValuePrivate::isArray() const
-{
- return isJSBased() && m_value->IsArray();
-}
-
-inline bool QJSValuePrivate::isBool() const
-{
- return m_state == CBool || (isJSBased() && m_value->IsBoolean());
-}
-
-inline bool QJSValuePrivate::isCallable() const
-{
- if (isFunction())
- return true;
- if (isObject()) {
- // Our C++ wrappers register function handlers but not always act as callables.
- return v8::Object::Cast(*m_value)->IsCallable();
- }
- return false;
-}
-
-inline bool QJSValuePrivate::isError() const
-{
- if (!isJSBased())
- return false;
- v8::HandleScope handleScope;
- return m_value->IsError();
-}
-
-inline bool QJSValuePrivate::isFunction() const
-{
- return isJSBased() && m_value->IsFunction();
-}
-
-inline bool QJSValuePrivate::isNull() const
-{
- return m_state == CNull || (isJSBased() && m_value->IsNull());
-}
-
-inline bool QJSValuePrivate::isNumber() const
-{
- return m_state == CNumber || (isJSBased() && m_value->IsNumber());
-}
-
-inline bool QJSValuePrivate::isObject() const
-{
- return isJSBased() && m_value->IsObject();
-}
-
-inline bool QJSValuePrivate::isString() const
-{
- return m_state == CString || (isJSBased() && m_value->IsString());
-}
-
-inline bool QJSValuePrivate::isUndefined() const
-{
- return m_state == CUndefined || (isJSBased() && m_value->IsUndefined());
-}
-
-inline bool QJSValuePrivate::isVariant() const
-{
- return isJSBased() && m_engine->isVariant(m_value);
-}
-
-bool QJSValuePrivate::isDate() const
-{
- return (isJSBased() && m_value->IsDate());
-}
-
-bool QJSValuePrivate::isRegExp() const
-{
- return (isJSBased() && m_value->IsRegExp());
-}
-
-bool QJSValuePrivate::isQObject() const
-{
- return isJSBased() && engine()->isQObject(m_value);
-}
-
-inline bool QJSValuePrivate::equals(QJSValuePrivate* other)
-{
- if (!isJSBased() && !other->isJSBased()) {
- switch (m_state) {
- case CNull:
- case CUndefined:
- return other->isUndefined() || other->isNull();
- case CNumber:
- switch (other->m_state) {
- case CBool:
- case CString:
- return u.m_number == other->toNumber();
- case CNumber:
- return u.m_number == other->u.m_number;
- default:
- return false;
- }
- case CBool:
- switch (other->m_state) {
- case CBool:
- return u.m_bool == other->u.m_bool;
- case CNumber:
- return toNumber() == other->u.m_number;
- case CString:
- return toNumber() == other->toNumber();
- default:
- return false;
- }
- case CString:
- switch (other->m_state) {
- case CBool:
- return toNumber() == other->toNumber();
- case CNumber:
- return toNumber() == other->u.m_number;
- case CString:
- return *u.m_string == *other->u.m_string;
- default:
- return false;
- }
- default:
- Q_ASSERT_X(false, "QJSValue::equals", "Not all states are included in the previous switch statement.");
- }
- }
-
- v8::HandleScope handleScope;
- if (isJSBased() && !other->isJSBased()) {
- if (!other->assignEngine(engine())) {
- qWarning("QJSValue::equals: cannot compare to a value created in a different engine");
- return false;
- }
- } else if (!isJSBased() && other->isJSBased()) {
- if (!assignEngine(other->engine())) {
- qWarning("QJSValue::equals: cannot compare to a value created in a different engine");
- return false;
- }
- }
-
- Q_ASSERT(this->engine() && other->engine());
- if (this->engine() != other->engine()) {
- qWarning("QJSValue::equals: cannot compare to a value created in a different engine");
- return false;
- }
- return m_value->Equals(other->m_value);
-}
-
-inline bool QJSValuePrivate::strictlyEquals(QJSValuePrivate* other)
-{
- if (isJSBased()) {
- // We can't compare these two values without binding to the same engine.
- if (!other->isJSBased()) {
- if (other->assignEngine(engine()))
- return m_value->StrictEquals(other->m_value);
- return false;
- }
- if (other->engine() != engine()) {
- qWarning("QJSValue::strictlyEquals: cannot compare to a value created in a different engine");
- return false;
- }
- return m_value->StrictEquals(other->m_value);
- }
- if (isStringBased()) {
- if (other->isStringBased())
- return *u.m_string == *(other->u.m_string);
- if (other->isJSBased()) {
- assignEngine(other->engine());
- return m_value->StrictEquals(other->m_value);
- }
- }
- if (isNumberBased()) {
- if (other->isJSBased()) {
- assignEngine(other->engine());
- return m_value->StrictEquals(other->m_value);
- }
- if (m_state != other->m_state)
- return false;
- if (m_state == CNumber)
- return u.m_number == other->u.m_number;
- Q_ASSERT(m_state == CBool);
- return u.m_bool == other->u.m_bool;
- }
-
- return (isUndefined() && other->isUndefined())
- || (isNull() && other->isNull());
-}
-
-inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::prototype() const
-{
- if (isObject()) {
- v8::HandleScope handleScope;
- return new QJSValuePrivate(engine(), v8::Handle<v8::Object>::Cast(m_value)->GetPrototype());
- }
- return new QJSValuePrivate();
-}
-
-inline void QJSValuePrivate::setPrototype(QJSValuePrivate* prototype)
-{
- if (isObject() && (prototype->isObject() || prototype->isNull())) {
- if (engine() != prototype->engine()) {
- if (prototype->engine()) {
- qWarning("QJSValue::setPrototype() failed: cannot set a prototype created in a different engine");
- return;
- }
- prototype->assignEngine(engine());
- }
- v8::HandleScope handleScope;
- if (!v8::Handle<v8::Object>::Cast(m_value)->SetPrototype(*prototype))
- qWarning("QJSValue::setPrototype() failed: cyclic prototype value");
- }
-}
-
-inline void QJSValuePrivate::setProperty(const QString& name, QJSValuePrivate* value, uint attribs)
-{
- if (!isObject())
- return;
- v8::HandleScope handleScope;
- setProperty(QJSConverter::toString(name), value, attribs);
-}
-
-inline void QJSValuePrivate::setProperty(v8::Handle<v8::String> name, QJSValuePrivate* value, uint attribs)
-{
- if (!isObject())
- return;
-
- if (!value->isJSBased())
- value->assignEngine(engine());
-
- if (engine() != value->engine()) {
- qWarning("QJSValue::setProperty(%s) failed: "
- "cannot set value created in a different engine",
- qPrintable(QJSConverter::toString(name)));
- return;
- }
-
- v8::TryCatch tryCatch;
-// if (attribs & (QJSValue::PropertyGetter | QJSValue::PropertySetter)) {
-// engine()->originalGlobalObject()->defineGetterOrSetter(*this, name, value->m_value, attribs);
-// } else {
- v8::Object::Cast(*m_value)->Set(name, value->m_value, v8::PropertyAttribute(attribs & QJSConverter::PropertyAttributeMask));
-// }
-}
-
-inline void QJSValuePrivate::setProperty(quint32 index, QJSValuePrivate* value, uint attribs)
-{
- // FIXME this method should by integrated with other overloads to use the same code patch.
- // for now it is not possible as v8 doesn't allow to set property attributes using index based api.
-
- if (!isObject())
- return;
-
- if (attribs) {
- // FIXME we don't need to convert index to a string.
- //Object::Set(int,value) do not take attributes.
- setProperty(QString::number(index), value, attribs);
- return;
- }
-
- if (!value->isJSBased())
- value->assignEngine(engine());
-
- if (engine() != value->engine()) {
- qWarning("QJSValue::setProperty() failed: cannot set value created in a different engine");
- return;
- }
-
- v8::HandleScope handleScope;
- v8::Object::Cast(*m_value)->Set(index, value->m_value);
-}
-
-inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(const QString& name) const
-{
- if (!isObject())
- return new QJSValuePrivate();
- if (!name.length())
- return new QJSValuePrivate(engine());
-
- v8::HandleScope handleScope;
- return property(QJSConverter::toString(name));
-}
-
-inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(v8::Handle<v8::String> name) const
-{
- Q_ASSERT(!name.IsEmpty());
- if (!isObject())
- return new QJSValuePrivate();
- return property<>(name);
-}
-
-inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(quint32 index) const
-{
- if (!isObject())
- return new QJSValuePrivate();
- return property<>(index);
-}
-
-template<typename T>
-inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::property(T name) const
-{
- Q_ASSERT(isObject());
- v8::HandleScope handleScope;
- v8::Handle<v8::Object> self(v8::Object::Cast(*m_value));
-
- v8::TryCatch tryCatch;
- v8::Handle<v8::Value> result = self->Get(name);
- if (tryCatch.HasCaught())
- result = tryCatch.Exception();
- if (result.IsEmpty())
- return new QJSValuePrivate(engine());
- return new QJSValuePrivate(engine(), result);
-}
-
-inline bool QJSValuePrivate::deleteProperty(const QString& name)
-{
- if (!isObject())
- return false;
-
- v8::HandleScope handleScope;
- v8::Handle<v8::Object> self(v8::Handle<v8::Object>::Cast(m_value));
- return self->Delete(QJSConverter::toString(name));
-}
-
-inline bool QJSValuePrivate::hasProperty(const QString &name) const
-{
- if (!isObject())
- return false;
-
- v8::HandleScope handleScope;
- v8::Handle<v8::Object> self(v8::Handle<v8::Object>::Cast(m_value));
- return self->Has(QJSConverter::toString(name));
-}
-
-inline bool QJSValuePrivate::hasOwnProperty(const QString &name) const
-{
- if (!isObject())
- return false;
-
- v8::HandleScope handleScope;
- v8::Handle<v8::Object> self(v8::Handle<v8::Object>::Cast(m_value));
- return self->HasOwnProperty(QJSConverter::toString(name));
-}
-
-inline QJSValuePrivate::PropertyFlags QJSValuePrivate::propertyFlags(const QString& name) const
-{
- if (!isObject())
- return QJSValuePrivate::PropertyFlags(0);
-
- v8::HandleScope handleScope;
- return engine()->getPropertyFlags(v8::Handle<v8::Object>::Cast(m_value), QJSConverter::toString(name));
-}
-
-inline QJSValuePrivate::PropertyFlags QJSValuePrivate::propertyFlags(v8::Handle<v8::String> name) const
-{
- if (!isObject())
- return QJSValuePrivate::PropertyFlags(0);
-
- v8::HandleScope handleScope;
- return engine()->getPropertyFlags(v8::Handle<v8::Object>::Cast(m_value), name);
-}
-
-inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::call(QJSValuePrivate* thisObject, const QJSValueList& args)
-{
- if (!isCallable())
- return new QJSValuePrivate();
-
- v8::HandleScope handleScope;
-
- // Convert all arguments and bind to the engine.
- int argc = args.size();
- QVarLengthArray<v8::Handle<v8::Value>, 8> argv(argc);
- if (!prepareArgumentsForCall(argv.data(), args)) {
- qWarning("QJSValue::call() failed: cannot call function with argument created in a different engine");
- return new QJSValuePrivate(engine());
- }
-
- return call(thisObject, argc, argv.data());
-}
-
-QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::call(QJSValuePrivate* thisObject, int argc, v8::Handle<v8::Value> *argv)
-{
- QV8Engine *e = engine();
-
- v8::Handle<v8::Object> recv;
-
- if (!thisObject || !thisObject->isObject()) {
- recv = v8::Handle<v8::Object>(v8::Object::Cast(*e->global()));
- } else {
- if (!thisObject->assignEngine(e)) {
- qWarning("QJSValue::call() failed: cannot call function with thisObject created in a different engine");
- return new QJSValuePrivate(engine());
- }
-
- recv = v8::Handle<v8::Object>(v8::Object::Cast(*thisObject->m_value));
- }
-
- if (argc < 0) {
- v8::Local<v8::Value> exeption = v8::Exception::TypeError(v8::String::New("Arguments must be an array"));
- return new QJSValuePrivate(e, exeption);
- }
-
- v8::TryCatch tryCatch;
- v8::Handle<v8::Value> result = v8::Object::Cast(*m_value)->CallAsFunction(recv, argc, argv);
-
- if (result.IsEmpty()) {
- result = tryCatch.Exception();
- // TODO: figure out why v8 doesn't always produce an exception value.
- //Q_ASSERT(!result.IsEmpty());
- if (result.IsEmpty())
- result = v8::Exception::Error(v8::String::New("missing exception value"));
- }
-
- return new QJSValuePrivate(e, result);
-}
-
-inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::callAsConstructor(int argc, v8::Handle<v8::Value> *argv)
-{
- QV8Engine *e = engine();
-
- if (argc < 0) {
- v8::Local<v8::Value> exeption = v8::Exception::TypeError(v8::String::New("Arguments must be an array"));
- return new QJSValuePrivate(e, exeption);
- }
-
- v8::TryCatch tryCatch;
- v8::Handle<v8::Value> result = v8::Object::Cast(*m_value)->CallAsConstructor(argc, argv);
-
- if (result.IsEmpty())
- result = tryCatch.Exception();
-
- return new QJSValuePrivate(e, result);
-}
-
-inline QScriptPassPointer<QJSValuePrivate> QJSValuePrivate::callAsConstructor(const QJSValueList& args)
-{
- if (!isCallable())
- return new QJSValuePrivate();
-
- v8::HandleScope handleScope;
-
- // Convert all arguments and bind to the engine.
- int argc = args.size();
- QVarLengthArray<v8::Handle<v8::Value>, 8> argv(argc);
- if (!prepareArgumentsForCall(argv.data(), args)) {
- qWarning("QJSValue::callAsConstructor() failed: cannot construct function with argument created in a different engine");
- return new QJSValuePrivate(engine());
- }
-
- return callAsConstructor(argc, argv.data());
-}
-
-/*! \internal
- * Make sure this value is associated with a v8 value belonging to this engine.
- * If the value belongs to another engine, returns false.
- */
-bool QJSValuePrivate::assignEngine(QV8Engine* engine)
-{
- Q_ASSERT(engine);
- v8::HandleScope handleScope;
- switch (m_state) {
- case CBool:
- m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(u.m_bool));
- break;
- case CString:
- m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(*u.m_string));
- delete u.m_string;
- break;
- case CNumber:
- m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(u.m_number));
- break;
- case CNull:
- m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(QJSValue::NullValue));
- break;
- case CUndefined:
- m_value = v8::Persistent<v8::Value>::New(engine->makeJSValue(QJSValue::UndefinedValue));
- break;
- default:
- if (this->engine() == engine)
- return true;
- else if (!isJSBased())
- Q_ASSERT_X(!isJSBased(), "assignEngine()", "Not all states are included in the previous switch statement.");
- else
- qWarning("JSValue can't be rassigned to an another engine.");
- return false;
- }
- m_engine = engine;
- m_state = JSValue;
-
- m_engine->registerValue(this);
- return true;
-}
-
-/*!
- \internal
- Invalidates this value (makes it undefined).
-
- Does not remove the value from the engine's list of
- registered values; that's the responsibility of the caller.
-*/
-void QJSValuePrivate::invalidate()
-{
- if (isJSBased()) {
- m_value.Dispose();
- m_value.Clear();
- } else if (isStringBased()) {
- delete u.m_string;
- }
- m_engine = 0;
- m_state = CUndefined;
-}
-
-QV8Engine* QJSValuePrivate::engine() const
-{
- return m_engine;
-}
-
-inline QJSValuePrivate::operator v8::Handle<v8::Value>() const
-{
- Q_ASSERT(isJSBased());
- return m_value;
-}
-
-inline QJSValuePrivate::operator v8::Handle<v8::Object>() const
-{
- Q_ASSERT(isObject());
- return v8::Handle<v8::Object>::Cast(m_value);
-}
-
-inline v8::Handle<v8::Value> QJSValuePrivate::handle() const
-{
- return m_value;
-}
-
-/*!
- * Return a v8::Handle, assign to the engine if needed.
- */
-v8::Handle<v8::Value> QJSValuePrivate::asV8Value(QV8Engine* engine)
-{
- if (!m_engine) {
- if (!assignEngine(engine))
- return v8::Handle<v8::Value>();
- }
- Q_ASSERT(isJSBased());
- return m_value;
-}
-
-/*!
- \internal
- Returns true if QSV have an engine associated.
-*/
-bool QJSValuePrivate::isJSBased() const
-{
-#ifndef QT_NO_DEBUG
- // internals check.
- if (m_state >= JSValue)
- Q_ASSERT(!m_value.IsEmpty());
- else
- Q_ASSERT(m_value.IsEmpty());
-#endif
- return m_state >= JSValue;
-}
-
-/*!
- \internal
- Returns true if current value of QSV is placed in m_number.
-*/
-bool QJSValuePrivate::isNumberBased() const { return m_state == CNumber || m_state == CBool; }
-
-/*!
- \internal
- Returns true if current value of QSV is placed in m_string.
-*/
-bool QJSValuePrivate::isStringBased() const { return m_state == CString; }
-
-/*!
- \internal
- Converts arguments and bind them to the engine.
- \attention argv should be big enough
-*/
-inline bool QJSValuePrivate::prepareArgumentsForCall(v8::Handle<v8::Value> argv[], const QJSValueList& args) const
-{
- QJSValueList::const_iterator i = args.constBegin();
- for (int j = 0; i != args.constEnd(); j++, i++) {
- QJSValuePrivate* value = QJSValuePrivate::get(*i);
- if ((value->isJSBased() && engine() != value->engine())
- || (!value->isJSBased() && !value->assignEngine(engine())))
- // Different engines are not allowed!
- return false;
- argv[j] = *value;
- }
- return true;
-}
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/qml/v8/qjsvalue_p.h b/src/qml/qml/v8/qjsvalue_p.h
index c4c8d415d4..ef94dea555 100644
--- a/src/qml/qml/v8/qjsvalue_p.h
+++ b/src/qml/qml/v8/qjsvalue_p.h
@@ -53,161 +53,47 @@
#ifndef QJSVALUE_P_H
#define QJSVALUE_P_H
-#include <private/qv8_p.h>
-
-#include <QtCore/qbytearray.h>
-#include <QtCore/qdatetime.h>
-#include <QtCore/qmath.h>
-#include <QtCore/qvarlengtharray.h>
-#include <qdebug.h>
-
-#include <private/qintrusivelist_p.h>
-#include "qscriptshareddata_p.h"
-#include "qjsvalue.h"
+#include <qjsvalue.h>
+#include <private/qv4value_p.h>
+#include <private/qv4string_p.h>
+#include <private/qv4engine_p.h>
+#include <private/qv4object_p.h>
QT_BEGIN_NAMESPACE
-class QV8Engine;
-
/*!
\internal
\class QJSValuePrivate
*/
-class QJSValuePrivate
- : public QSharedData
+class QJSValuePrivate : public QV4::PersistentValuePrivate
{
public:
- enum PropertyFlag {
- ReadOnly = 0x00000001,
- Undeletable = 0x00000002,
- SkipInEnumeration = 0x00000004
- };
- Q_DECLARE_FLAGS(PropertyFlags, PropertyFlag)
-
- inline static QJSValuePrivate* get(const QJSValue& q);
- inline static QJSValue get(const QJSValuePrivate* d);
- inline static QJSValue get(QJSValuePrivate* d);
- inline static QJSValue get(QScriptPassPointer<QJSValuePrivate> d);
- inline ~QJSValuePrivate();
-
- inline QJSValuePrivate(bool value);
- inline QJSValuePrivate(int value);
- inline QJSValuePrivate(uint value);
- inline QJSValuePrivate(double value);
- inline QJSValuePrivate(const QString& value);
- inline QJSValuePrivate(QJSValue::SpecialValue value = QJSValue::UndefinedValue);
-
- inline QJSValuePrivate(QV8Engine *engine, bool value);
- inline QJSValuePrivate(QV8Engine *engine, int value);
- inline QJSValuePrivate(QV8Engine *engine, uint value);
- inline QJSValuePrivate(QV8Engine *engine, double value);
- inline QJSValuePrivate(QV8Engine *engine, const QString& value);
- inline QJSValuePrivate(QV8Engine *engine, QJSValue::SpecialValue value = QJSValue::UndefinedValue);
- inline QJSValuePrivate(QV8Engine *engine, v8::Handle<v8::Value>);
- inline void invalidate();
-
- inline bool toBool() const;
- inline double toNumber() const;
- inline QString toString() const;
- inline double toInteger() const;
- inline qint32 toInt32() const;
- inline quint32 toUInt32() const;
- inline quint16 toUInt16() const;
- inline QDateTime toDataTime() const;
- inline QObject *toQObject() const;
- inline QVariant toVariant() const;
-
- inline bool isArray() const;
- inline bool isBool() const;
- inline bool isCallable() const;
- inline bool isError() const;
- inline bool isFunction() const;
- inline bool isNull() const;
- inline bool isNumber() const;
- inline bool isObject() const;
- inline bool isString() const;
- inline bool isUndefined() const;
- inline bool isVariant() const;
- inline bool isDate() const;
- inline bool isRegExp() const;
- inline bool isQObject() const;
-
- inline bool equals(QJSValuePrivate* other);
- inline bool strictlyEquals(QJSValuePrivate* other);
-
- inline QScriptPassPointer<QJSValuePrivate> prototype() const;
- inline void setPrototype(QJSValuePrivate* prototype);
-
- inline void setProperty(const QString &name, QJSValuePrivate *value, uint attribs = 0);
- inline void setProperty(v8::Handle<v8::String> name, QJSValuePrivate *value, uint attribs = 0);
- inline void setProperty(quint32 index, QJSValuePrivate* value, uint attribs = 0);
- inline QScriptPassPointer<QJSValuePrivate> property(const QString& name) const;
- inline QScriptPassPointer<QJSValuePrivate> property(v8::Handle<v8::String> name) const;
- inline QScriptPassPointer<QJSValuePrivate> property(quint32 index) const;
- template<typename T>
- inline QScriptPassPointer<QJSValuePrivate> property(T name) const;
- inline bool deleteProperty(const QString& name);
- inline bool hasProperty(const QString &name) const;
- inline bool hasOwnProperty(const QString &name) const;
- inline PropertyFlags propertyFlags(const QString& name) const;
- inline PropertyFlags propertyFlags(v8::Handle<v8::String> name) const;
-
- inline QScriptPassPointer<QJSValuePrivate> call(QJSValuePrivate* thisObject, const QJSValueList& args);
- inline QScriptPassPointer<QJSValuePrivate> call(QJSValuePrivate* thisObject, const QJSValue& arguments);
- inline QScriptPassPointer<QJSValuePrivate> call(QJSValuePrivate* thisObject, int argc, v8::Handle< v8::Value >* argv);
- inline QScriptPassPointer<QJSValuePrivate> callAsConstructor(int argc, v8::Handle<v8::Value> *argv);
- inline QScriptPassPointer<QJSValuePrivate> callAsConstructor(const QJSValueList& args);
- inline QScriptPassPointer<QJSValuePrivate> callAsConstructor(const QJSValue& arguments);
-
- inline bool assignEngine(QV8Engine *engine);
- inline QV8Engine *engine() const;
-
- inline operator v8::Handle<v8::Value>() const;
- inline operator v8::Handle<v8::Object>() const;
- inline v8::Handle<v8::Value> handle() const;
- inline v8::Handle<v8::Value> asV8Value(QV8Engine *engine);
-private:
- QIntrusiveListNode m_node;
- QV8Engine *m_engine;
-
- // Please, update class documentation when you change the enum.
- enum State {
- CString = 0x1000,
- CNumber,
- CBool,
- CNull,
- CUndefined,
- JSValue = 0x2000 // V8 values are equal or higher then this value.
- // JSPrimitive,
- // JSObject
- } m_state;
-
- union CValue {
- bool m_bool;
- double m_number;
- QString* m_string;
-
- CValue() : m_number(0) {}
- CValue(bool value) : m_bool(value) {}
- CValue(int number) : m_number(number) {}
- CValue(uint number) : m_number(number) {}
- CValue(double number) : m_number(number) {}
- CValue(QString* string) : m_string(string) {}
- } u;
- // v8::Persistent is not a POD, so can't be part of the union.
- v8::Persistent<v8::Value> m_value;
-
- Q_DISABLE_COPY(QJSValuePrivate)
- inline bool isJSBased() const;
- inline bool isNumberBased() const;
- inline bool isStringBased() const;
- inline bool prepareArgumentsForCall(v8::Handle<v8::Value> argv[], const QJSValueList& arguments) const;
-
- friend class QV8Engine;
+ QJSValuePrivate(QV4::ExecutionEngine *engine, const QV4::Value &v)
+ : PersistentValuePrivate(v, engine)
+ {
+ if (value.isEmpty())
+ value = QV4::Value::undefinedValue();
+ }
+ QJSValuePrivate(QV4::Object *o)
+ : PersistentValuePrivate(QV4::Value::fromObject(o))
+ { }
+ QJSValuePrivate(QV4::String *s)
+ : PersistentValuePrivate(QV4::Value::fromString(s))
+ { }
+ QJSValuePrivate(const QString &s)
+ : PersistentValuePrivate(QV4::Value::undefinedValue())
+ , string(0, s)
+ {
+ value = QV4::Value::fromString(&string);
+ }
+
+ QV4::Value getValue(QV4::ExecutionEngine *e);
+
+ static QJSValuePrivate *get(const QJSValue &v) { return v.d; }
+
+ QV4::String string;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QJSValuePrivate::PropertyFlags)
-
QT_END_NAMESPACE
#endif
diff --git a/src/qml/qml/v8/qjsvalueiterator.cpp b/src/qml/qml/v8/qjsvalueiterator.cpp
index 67646c9eb4..aa1ecd6e54 100644
--- a/src/qml/qml/v8/qjsvalueiterator.cpp
+++ b/src/qml/qml/v8/qjsvalueiterator.cpp
@@ -41,14 +41,24 @@
#include "qjsvalueiterator.h"
#include "qjsvalueiterator_p.h"
-
-#include "qscriptisolate_p.h"
#include "qjsvalue_p.h"
-#include "qv8engine_p.h"
-#include "qscript_impl_p.h"
+#include "private/qv4string_p.h"
+#include "private/qv4object_p.h"
+#include "private/qv4exception_p.h"
QT_BEGIN_NAMESPACE
+QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValue &v)
+ : value(v)
+ , iterator(QJSValuePrivate::get(v)->value.asObject(), QV4::ObjectIterator::NoFlags)
+ , currentName(0)
+ , currentIndex(UINT_MAX)
+ , nextName(0)
+ , nextIndex(UINT_MAX)
+{
+}
+
+
/*!
\class QJSValueIterator
@@ -84,14 +94,17 @@ QT_BEGIN_NAMESPACE
first property).
*/
QJSValueIterator::QJSValueIterator(const QJSValue& object)
- : d_ptr(new QJSValueIteratorPrivate(QJSValuePrivate::get(object)))
-{}
+ : d_ptr(new QJSValueIteratorPrivate(object))
+{
+ d_ptr->iterator.next(&d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes);
+}
/*!
Destroys the iterator.
*/
QJSValueIterator::~QJSValueIterator()
-{}
+{
+}
/*!
Returns true if there is at least one item ahead of the iterator
@@ -102,9 +115,9 @@ QJSValueIterator::~QJSValueIterator()
*/
bool QJSValueIterator::hasNext() const
{
- Q_D(const QJSValueIterator);
- QScriptIsolate api(d->engine());
- return d->hasNext();
+ if (!QJSValuePrivate::get(d_ptr->value)->value.isObject())
+ return false;
+ return d_ptr->nextName != 0 || d_ptr->nextIndex != UINT_MAX;
}
/*!
@@ -120,9 +133,14 @@ bool QJSValueIterator::hasNext() const
*/
bool QJSValueIterator::next()
{
- Q_D(QJSValueIterator);
- QScriptIsolate api(d->engine());
- return d->next();
+ if (!QJSValuePrivate::get(d_ptr->value)->value.isObject())
+ return false;
+ d_ptr->currentName = d_ptr->nextName;
+ d_ptr->currentIndex = d_ptr->nextIndex;
+ d_ptr->currentAttributes = d_ptr->nextAttributes;
+
+ d_ptr->iterator.next(&d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes);
+ return d_ptr->nextName != 0 || d_ptr->nextIndex != UINT_MAX;
}
/*!
@@ -133,9 +151,13 @@ bool QJSValueIterator::next()
*/
QString QJSValueIterator::name() const
{
- Q_D(const QJSValueIterator);
- QScriptIsolate api(d->engine());
- return d_ptr->name();
+ if (!QJSValuePrivate::get(d_ptr->value)->value.isObject())
+ return false;
+ if (d_ptr->currentName)
+ return d_ptr->currentName->toQString();
+ if (d_ptr->currentIndex < UINT_MAX)
+ return QString::number(d_ptr->currentIndex);
+ return QString();
}
@@ -147,9 +169,25 @@ QString QJSValueIterator::name() const
*/
QJSValue QJSValueIterator::value() const
{
- Q_D(const QJSValueIterator);
- QScriptIsolate api(d->engine());
- return QJSValuePrivate::get(d->value());
+ if (!QJSValuePrivate::get(d_ptr->value)->value.isObject())
+ return QJSValue();
+
+ QV4::Object *o = d_ptr->iterator.object;
+ QV4::ExecutionEngine *engine = o->internalClass->engine;
+ QV4::ExecutionContext *ctx = engine->current;
+ try {
+ QV4::Value v;
+ if (d_ptr->currentName)
+ v = o->get(d_ptr->currentName);
+ else if (d_ptr->currentIndex != UINT_MAX)
+ v = o->getIndexed(d_ptr->currentIndex);
+ else
+ return QJSValue();
+ return new QJSValuePrivate(engine, v);
+ } catch (QV4::Exception &e) {
+ e.accept(ctx);
+ return QJSValue();
+ }
}
@@ -160,9 +198,8 @@ QJSValue QJSValueIterator::value() const
*/
QJSValueIterator& QJSValueIterator::operator=(QJSValue& object)
{
- Q_D(QJSValueIterator);
- QScriptIsolate api(d->engine());
- d_ptr.reset(new QJSValueIteratorPrivate(QJSValuePrivate::get(object)));
+ d_ptr->iterator = QV4::ObjectIterator(QJSValuePrivate::get(object)->value.asObject(), QV4::ObjectIterator::NoFlags);
+ d_ptr->iterator.next(&d_ptr->nextName, &d_ptr->nextIndex, &d_ptr->nextAttributes);
return *this;
}
diff --git a/src/qml/qml/v8/qjsvalueiterator.h b/src/qml/qml/v8/qjsvalueiterator.h
index b4f90a44b7..e204558e90 100644
--- a/src/qml/qml/v8/qjsvalueiterator.h
+++ b/src/qml/qml/v8/qjsvalueiterator.h
@@ -42,8 +42,8 @@
#ifndef QSCRIPTVALUEITERATOR_H
#define QSCRIPTVALUEITERATOR_H
-#include <QtQml/qtqmlglobal.h>
#include <QtQml/qjsvalue.h>
+#include <QtQml/qtqmlglobal.h>
#include <QtCore/qscopedpointer.h>
QT_BEGIN_NAMESPACE
diff --git a/src/qml/qml/v8/qjsvalueiterator_impl_p.h b/src/qml/qml/v8/qjsvalueiterator_impl_p.h
deleted file mode 100644
index f7b6943f57..0000000000
--- a/src/qml/qml/v8/qjsvalueiterator_impl_p.h
+++ /dev/null
@@ -1,143 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QJSVALUEITERATOR_IMPL_P_H
-#define QJSVALUEITERATOR_IMPL_P_H
-
-#include "qjsvalueiterator_p.h"
-#include <private/qv8engine_p.h>
-#include "qjsconverter_p.h"
-
-QT_BEGIN_NAMESPACE
-
-inline QJSValueIteratorPrivate::QJSValueIteratorPrivate(const QJSValuePrivate* value)
- : m_object(const_cast<QJSValuePrivate*>(value))
- , m_index(0)
- , m_count(0)
-{
- Q_ASSERT(value);
- QV8Engine *engine = m_object->engine();
- if (!m_object->isObject())
- m_object = 0;
- else {
- QScriptIsolate api(engine, QScriptIsolate::NotNullEngine);
- v8::HandleScope scope;
-
- v8::Handle<v8::Value> tmp = *value;
- v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(tmp);
- v8::Local<v8::Array> names;
-
- // FIXME we need newer V8!
- //names = obj->GetOwnPropertyNames();
- names = engine->getOwnPropertyNames(obj);
- m_names = v8::Persistent<v8::Array>::New(names);
- m_count = names->Length();
-
- engine->registerValueIterator(this);
- }
-}
-
-inline QJSValueIteratorPrivate::~QJSValueIteratorPrivate()
-{
- if (isValid()) {
- engine()->unregisterValueIterator(this);
- m_names.Dispose();
- }
-}
-
-inline void QJSValueIteratorPrivate::invalidate()
-{
- m_names.Dispose();
- m_object.reset();
- m_index = 0;
- m_count = 0;
-}
-
-inline bool QJSValueIteratorPrivate::hasNext() const
-{
- return isValid() ? m_index < m_count : false;
-}
-
-inline bool QJSValueIteratorPrivate::next()
-{
- if (hasNext()) {
- ++m_index;
- return true;
- }
- return false;
-}
-
-inline QString QJSValueIteratorPrivate::name() const
-{
- if (!isValid())
- return QString();
-
- v8::HandleScope handleScope;
- return QJSConverter::toString(m_names->Get(m_index - 1)->ToString());
-}
-
-inline QScriptPassPointer<QJSValuePrivate> QJSValueIteratorPrivate::value() const
-{
- if (!isValid())
- return new QJSValuePrivate();
-
- v8::HandleScope handleScope;
- return m_object->property(m_names->Get(m_index - 1)->ToString());
-}
-
-inline bool QJSValueIteratorPrivate::isValid() const
-{
- bool result = m_object ? !m_object->isUndefined() : false;
- // We know that if this object is still valid then it is an object
- // if this assumption is not correct then some other logic in this class
- // have to be changed too.
- Q_ASSERT(!result || m_object->isObject());
- return result;
-}
-
-inline QV8Engine* QJSValueIteratorPrivate::engine() const
-{
- return m_object ? m_object->engine() : 0;
-}
-
-QT_END_NAMESPACE
-
-#endif // QJSVALUEITERATOR_IMPL_P_H
diff --git a/src/qml/qml/v8/qjsvalueiterator_p.h b/src/qml/qml/v8/qjsvalueiterator_p.h
index 2d36ac3ca5..7687f896a1 100644
--- a/src/qml/qml/v8/qjsvalueiterator_p.h
+++ b/src/qml/qml/v8/qjsvalueiterator_p.h
@@ -42,10 +42,8 @@
#ifndef QJSVALUEITERATOR_P_H
#define QJSVALUEITERATOR_P_H
-#include <private/qintrusivelist_p.h>
-#include "qjsvalue_p.h"
-
-#include <private/qv8_p.h>
+#include "qjsvalue.h"
+#include "private/qv4objectiterator_p.h"
QT_BEGIN_NAMESPACE
@@ -54,30 +52,16 @@ class QV8Engine;
class QJSValueIteratorPrivate
{
public:
- inline QJSValueIteratorPrivate(const QJSValuePrivate* value);
- inline ~QJSValueIteratorPrivate();
-
- inline bool hasNext() const;
- inline bool next();
-
- inline QString name() const;
-
- inline QScriptPassPointer<QJSValuePrivate> value() const;
-
- inline bool isValid() const;
- inline QV8Engine* engine() const;
-
- inline void invalidate();
-private:
- Q_DISABLE_COPY(QJSValueIteratorPrivate)
-
- QIntrusiveListNode m_node;
- QScriptSharedDataPointer<QJSValuePrivate> m_object;
- v8::Persistent<v8::Array> m_names;
- uint32_t m_index;
- uint32_t m_count;
-
- friend class QV8Engine;
+ QJSValueIteratorPrivate(const QJSValue &v);
+
+ QJSValue value;
+ QV4::ObjectIterator iterator;
+ QV4::PropertyAttributes currentAttributes;
+ QV4::String *currentName;
+ uint currentIndex;
+ QV4::PropertyAttributes nextAttributes;
+ QV4::String *nextName;
+ uint nextIndex;
};
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 457d0bb969..97736355d4 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -47,12 +47,21 @@
#include <private/qqmlstringconverters_p.h>
#include <private/qqmllocale_p.h>
#include <private/qv8engine_p.h>
-#include <private/qjsconverter_impl_p.h>
#include <private/qv8profilerservice_p.h>
#include <private/qqmlprofilerservice_p.h>
#include <private/qqmlglobal_p.h>
+#include <private/qqmlplatform_p.h>
+
+#include <private/qv4engine_p.h>
+#include <private/qv4functionobject_p.h>
+#include <private/qv4include_p.h>
+#include <private/qv4context_p.h>
+#include <private/qv4stringobject_p.h>
+#include <private/qv4mm_p.h>
+#include <private/qv4jsonobject_p.h>
+
#include <QtCore/qstring.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qcryptographichash.h>
@@ -65,336 +74,105 @@
QT_BEGIN_NAMESPACE
-namespace QQmlBuiltinFunctions {
-
-enum ConsoleLogTypes {
- Log,
- Warn,
- Error
-};
-
-static void jsContext(v8::Handle<v8::Value> *file, int *line, v8::Handle<v8::Value> *function) {
- v8::Local<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(1);
- if (stackTrace->GetFrameCount()) {
- v8::Local<v8::StackFrame> frame = stackTrace->GetFrame(0);
- *file = frame->GetScriptName();
- *line = frame->GetLineNumber();
- *function = frame->GetFunctionName();
- }
-}
-
-static QString jsStack() {
- QStringList stackFrames;
-
- //The v8 default is currently 10 stack frames.
- v8::Handle<v8::StackTrace> stackTrace =
- v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
- int stackCount = stackTrace->GetFrameCount();
-
- for (int i = 0; i < stackCount; i++) {
- v8::Local<v8::StackFrame> frame = stackTrace->GetFrame(i);
- v8::Handle<v8::String> function(frame->GetFunctionName());
- v8::Handle<v8::String> script(frame->GetScriptName());
- int lineNumber = frame->GetLineNumber();
- int columnNumber = frame->GetColumn();
-
- QString stackFrame =
- QString::fromLatin1("%1 (%2:%3:%4)").arg(QJSConverter::toString(function),
- QJSConverter::toString(script),
- QString::number(lineNumber),
- QString::number(columnNumber));
- stackFrames.append(stackFrame);
- }
- return stackFrames.join(QLatin1String("\n"));
-}
-
-v8::Handle<v8::Value> console(ConsoleLogTypes logType, const v8::Arguments &args,
- bool printStack = false)
-{
- v8::HandleScope handleScope;
-
- QString result;
- QV8Engine *engine = V8ENGINE();
- for (int i = 0; i < args.Length(); ++i) {
- if (i != 0)
- result.append(QLatin1Char(' '));
-
- v8::Local<v8::Value> value = args[i];
-
- v8::TryCatch tryCatch;
- v8::Local<v8::String> toString = value->ToString();
- if (tryCatch.HasCaught()) {
- // toString() threw Exception
- // Is it possible for value to be anything other than Object?
- QString str;
- if (value->IsObject()) {
- str = QStringLiteral("[object Object]");
- } else {
- toString = tryCatch.Exception()->ToString();
- str = QStringLiteral("toString() threw exception: %1")
- .arg(engine->toString(toString));
- }
- result.append(str);
- continue;
- }
-
- QString tmp = engine->toString(toString);
- if (value->IsArray())
- result.append(QStringLiteral("[%1]").arg(tmp));
- else
- result.append(tmp);
- }
-
- if (printStack) {
- result.append(QLatin1String("\n"));
- result.append(jsStack());
- }
-
- v8::Handle<v8::Value> fileHandle;
- v8::Handle<v8::Value> functionHandle;
- int line;
-
- jsContext(&fileHandle, &line, &functionHandle);
-
- switch (logType) {
- case Log:
- QMessageLogger(*v8::String::AsciiValue(fileHandle), line,
- *v8::String::AsciiValue(functionHandle)).debug("%s", qPrintable(result));
- break;
- case Warn:
- QMessageLogger(*v8::String::AsciiValue(fileHandle), line,
- *v8::String::AsciiValue(functionHandle)).warning("%s", qPrintable(result));
- break;
- case Error:
- QMessageLogger(*v8::String::AsciiValue(fileHandle), line,
- *v8::String::AsciiValue(functionHandle)).critical("%s", qPrintable(result));
- break;
- default:
- break;
- }
+using namespace QV4;
- return v8::Undefined();
-}
+DEFINE_MANAGED_VTABLE(QtObject);
-v8::Handle<v8::Value> gc(const v8::Arguments &args)
+struct StaticQtMetaObject : public QObject
{
- Q_UNUSED(args);
- QV8Engine::gc();
- return v8::Undefined();
-}
-
-v8::Handle<v8::Value> consoleError(const v8::Arguments &args)
-{
- return console(Error, args);
-}
-
-v8::Handle<v8::Value> consoleLog(const v8::Arguments &args)
-{
- //console.log
- //console.debug
- //console.info
- //print
- return console(Log, args);
-}
+ static const QMetaObject *get()
+ { return &staticQtMetaObject; }
+};
-v8::Handle<v8::Value> consoleProfile(const v8::Arguments &args)
+QV4::QtObject::QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine)
+ : Object(v4)
+ , m_platform(0)
+ , m_application(0)
{
- //DeclarativeDebugTrace cannot handle nested profiling
- //although v8 can handle several profiling at once,
- //we do not allow that. Hence, we pass an empty(default) title
- Q_UNUSED(args);
- QString title;
-
-
-
- v8::Handle<v8::Value> file;
- v8::Handle<v8::Value> function;
- int line;
- jsContext(&file, &line, &function);
-
- if (QQmlProfilerService::startProfiling()) {
- QV8ProfilerService::instance()->startProfiling(title);
-
- QMessageLogger(*v8::String::AsciiValue(file), line,
- *v8::String::AsciiValue(function)).debug("Profiling started.");
- } else {
- QMessageLogger(*v8::String::AsciiValue(file), line,
- *v8::String::AsciiValue(function)).warning(
- "Profiling is already in progress. First, end current profiling session.");
+ vtbl = &static_vtbl;
+
+ // Set all the enums from the "Qt" namespace
+ const QMetaObject *qtMetaObject = StaticQtMetaObject::get();
+ for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) {
+ QMetaEnum enumerator = qtMetaObject->enumerator(ii);
+ for (int jj = 0; jj < enumerator.keyCount(); ++jj) {
+ put(v4->newString(enumerator.key(jj)), QV4::Value::fromInt32(enumerator.value(jj)));
+ }
}
-
- return v8::Undefined();
-}
-
-v8::Handle<v8::Value> consoleProfileEnd(const v8::Arguments &args)
-{
- //DeclarativeDebugTrace cannot handle nested profiling
- //although v8 can handle several profiling at once,
- //we do not allow that. Hence, we pass an empty(default) title
- Q_UNUSED(args);
- QString title;
-
- v8::Handle<v8::Value> file;
- v8::Handle<v8::Value> function;
- int line;
- jsContext(&file, &line, &function);
-
- if (QQmlProfilerService::stopProfiling()) {
- QV8ProfilerService *profiler = QV8ProfilerService::instance();
- profiler->stopProfiling(title);
- QQmlProfilerService::sendProfilingData();
- profiler->sendProfilingData();
-
- QMessageLogger(*v8::String::AsciiValue(file), line,
- *v8::String::AsciiValue(function)).debug("Profiling ended.");
- } else {
- QMessageLogger(*v8::String::AsciiValue(file), line,
- *v8::String::AsciiValue(function)).warning("Profiling was not started.");
+ put(v4->newString("Asynchronous"), QV4::Value::fromInt32(0));
+ put(v4->newString("Synchronous"), QV4::Value::fromInt32(1));
+
+ defineDefaultProperty(v4, QStringLiteral("include"), QV4Include::include);
+ defineDefaultProperty(v4, QStringLiteral("isQtObject"), method_isQtObject);
+ defineDefaultProperty(v4, QStringLiteral("rgba"), method_rgba);
+ defineDefaultProperty(v4, QStringLiteral("hsla"), method_hsla);
+ defineDefaultProperty(v4, QStringLiteral("colorEqual"), method_colorEqual);
+ defineDefaultProperty(v4, QStringLiteral("rect"), method_rect);
+ defineDefaultProperty(v4, QStringLiteral("point"), method_point);
+ defineDefaultProperty(v4, QStringLiteral("size"), method_size);
+ defineDefaultProperty(v4, QStringLiteral("font"), method_font);
+
+ defineDefaultProperty(v4, QStringLiteral("vector2d"), method_vector2d);
+ defineDefaultProperty(v4, QStringLiteral("vector3d"), method_vector3d);
+ defineDefaultProperty(v4, QStringLiteral("vector4d"), method_vector4d);
+ defineDefaultProperty(v4, QStringLiteral("quaternion"), method_quaternion);
+ defineDefaultProperty(v4, QStringLiteral("matrix4x4"), method_matrix4x4);
+
+ defineDefaultProperty(v4, QStringLiteral("formatDate"), method_formatDate);
+ defineDefaultProperty(v4, QStringLiteral("formatTime"), method_formatTime);
+ defineDefaultProperty(v4, QStringLiteral("formatDateTime"), method_formatDateTime);
+
+ defineDefaultProperty(v4, QStringLiteral("openUrlExternally"), method_openUrlExternally);
+ defineDefaultProperty(v4, QStringLiteral("fontFamilies"), method_fontFamilies);
+ defineDefaultProperty(v4, QStringLiteral("md5"), method_md5);
+ defineDefaultProperty(v4, QStringLiteral("btoa"), method_btoa);
+ defineDefaultProperty(v4, QStringLiteral("atob"), method_atob);
+ defineDefaultProperty(v4, QStringLiteral("resolvedUrl"), method_resolvedUrl);
+ defineDefaultProperty(v4, QStringLiteral("locale"), method_locale);
+ defineDefaultProperty(v4, QStringLiteral("binding"), method_binding);
+
+ if (qmlEngine) {
+ defineDefaultProperty(v4, QStringLiteral("lighter"), method_lighter);
+ defineDefaultProperty(v4, QStringLiteral("darker"), method_darker);
+ defineDefaultProperty(v4, QStringLiteral("tint"), method_tint);
+ defineDefaultProperty(v4, QStringLiteral("quit"), method_quit);
+ defineDefaultProperty(v4, QStringLiteral("createQmlObject"), method_createQmlObject);
+ defineDefaultProperty(v4, QStringLiteral("createComponent"), method_createComponent);
}
- return v8::Undefined();
-}
-
-v8::Handle<v8::Value> consoleTime(const v8::Arguments &args)
-{
- if (args.Length() != 1)
- V8THROW_ERROR("console.time(): Invalid arguments");
- QString name = V8ENGINE()->toString(args[0]);
- V8ENGINE()->startTimer(name);
- return v8::Undefined();
-}
-
-v8::Handle<v8::Value> consoleTimeEnd(const v8::Arguments &args)
-{
- if (args.Length() != 1)
- V8THROW_ERROR("console.time(): Invalid arguments");
- QString name = V8ENGINE()->toString(args[0]);
- bool wasRunning;
- qint64 elapsed = V8ENGINE()->stopTimer(name, &wasRunning);
- if (wasRunning) {
- qDebug("%s: %llims", qPrintable(name), elapsed);
+ {
+ String *s = v4->newString(QStringLiteral("platform"));
+ Property *p = insertMember(s, Attr_Accessor);
+ FunctionObject* f = v4->newBuiltinFunction(v4->rootContext, s, method_get_platform);
+ p->setGetter(f);
}
- return v8::Undefined();
-}
-
-v8::Handle<v8::Value> consoleCount(const v8::Arguments &args)
-{
- // first argument: name to print. Ignore any additional arguments
- QString name;
- if (args.Length() > 0)
- name = V8ENGINE()->toString(args[0]);
-
- v8::Handle<v8::StackTrace> stackTrace =
- v8::StackTrace::CurrentStackTrace(1, v8::StackTrace::kOverview);
-
- if (stackTrace->GetFrameCount()) {
- v8::Local<v8::StackFrame> frame = stackTrace->GetFrame(0);
-
- QString scriptName = V8ENGINE()->toString(frame->GetScriptName());
- QString functionName = V8ENGINE()->toString(frame->GetFunctionName());
- int line = frame->GetLineNumber();
- int column = frame->GetColumn();
-
- int value = V8ENGINE()->consoleCountHelper(scriptName, line, column);
- QString message = name + QLatin1String(": ") + QString::number(value);
-
- QMessageLogger(qPrintable(scriptName), line,
- qPrintable(functionName)).debug("%s", qPrintable(message));
+ {
+ String *s = v4->newString(QStringLiteral("application"));
+ Property *p = insertMember(s, Attr_Accessor);
+ FunctionObject* f = v4->newBuiltinFunction(v4->rootContext, s, method_get_application);
+ p->setGetter(f);
}
-
- return v8::Undefined();
-}
-
-v8::Handle<v8::Value> consoleTrace(const v8::Arguments &args)
-{
- if (args.Length() != 0)
- V8THROW_ERROR("console.trace(): Invalid arguments");
-
- QString stack = jsStack();
-
- v8::Handle<v8::Value> file;
- v8::Handle<v8::Value> function;
- int line;
- jsContext(&file, &line, &function);
-
- QMessageLogger(*v8::String::AsciiValue(file), line, *v8::String::AsciiValue(function)).debug(
- "%s", qPrintable(stack));
- return v8::Undefined();
-}
-
-v8::Handle<v8::Value> consoleWarn(const v8::Arguments &args)
-{
- return console(Warn, args);
-}
-
-v8::Handle<v8::Value> consoleAssert(const v8::Arguments &args)
-{
- if (args.Length() == 0)
- V8THROW_ERROR("console.assert(): Missing argument");
-
- if (!args[0]->ToBoolean()->Value()) {
- QString message;
- for (int i = 1; i < args.Length(); ++i) {
- if (i != 1)
- message.append(QLatin1Char(' '));
-
- v8::Local<v8::Value> value = args[i];
- message.append(V8ENGINE()->toString(value->ToString()));
- }
-
- QString stack = jsStack();
-
- v8::Handle<v8::Value> file;
- v8::Handle<v8::Value> function;
- int line;
- jsContext(&file, &line, &function);
-
- QMessageLogger(*v8::String::AsciiValue(file), line, *v8::String::AsciiValue(function)).critical(
- "%s\n%s", qPrintable(message), qPrintable(stack));
-
+#ifndef QT_NO_IM
+ {
+ String *s = v4->newString(QStringLiteral("inputMethod"));
+ Property *p = insertMember(s, Attr_Accessor);
+ FunctionObject* f = v4->newBuiltinFunction(v4->rootContext, s, method_get_inputMethod);
+ p->setGetter(f);
}
- return v8::Undefined();
-}
-
-v8::Handle<v8::Value> consoleException(const v8::Arguments &args)
-{
- if (args.Length() == 0)
- V8THROW_ERROR("console.exception(): Missing argument");
-
- console(Error, args, true);
-
- return v8::Undefined();
+#endif
}
-v8::Handle<v8::Value> stringArg(const v8::Arguments &args)
-{
- QString value = V8ENGINE()->toString(args.This()->ToString());
- if (args.Length() != 1)
- V8THROW_ERROR("String.arg(): Invalid arguments");
-
- v8::Handle<v8::Value> arg = args[0];
- if (arg->IsUint32())
- return V8ENGINE()->toString(value.arg(arg->Uint32Value()));
- else if (arg->IsInt32())
- return V8ENGINE()->toString(value.arg(arg->Int32Value()));
- else if (arg->IsNumber())
- return V8ENGINE()->toString(value.arg(arg->NumberValue()));
- else if (arg->IsBoolean())
- return V8ENGINE()->toString(value.arg(arg->BooleanValue()));
-
- return V8ENGINE()->toString(value.arg(V8ENGINE()->toString(arg)));
-}
/*!
\qmlmethod bool Qt::isQtObject(object)
Returns true if \c object is a valid reference to a Qt or QML object, otherwise false.
*/
-v8::Handle<v8::Value> isQtObject(const v8::Arguments &args)
+Value QtObject::method_isQtObject(QV4::SimpleCallContext *ctx)
{
- if (args.Length() == 0)
- return v8::Boolean::New(false);
+ if (ctx->argumentCount == 0)
+ return QV4::Value::fromBoolean(false);
- return v8::Boolean::New(0 != V8ENGINE()->toQObject(args[0]));
+ return QV4::Value::fromBoolean(ctx->arguments[0].as<QV4::QObjectWrapper>() != 0);
}
/*!
@@ -403,16 +181,16 @@ v8::Handle<v8::Value> isQtObject(const v8::Arguments &args)
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.
*/
-v8::Handle<v8::Value> rgba(const v8::Arguments &args)
+Value QtObject::method_rgba(QV4::SimpleCallContext *ctx)
{
- int argCount = args.Length();
+ int argCount = ctx->argumentCount;
if (argCount < 3 || argCount > 4)
- V8THROW_ERROR("Qt.rgba(): Invalid arguments");
+ V4THROW_ERROR("Qt.rgba(): Invalid arguments");
- double r = args[0]->NumberValue();
- double g = args[1]->NumberValue();
- double b = args[2]->NumberValue();
- double a = (argCount == 4) ? args[3]->NumberValue() : 1;
+ double r = ctx->arguments[0].toNumber();
+ double g = ctx->arguments[1].toNumber();
+ double b = ctx->arguments[2].toNumber();
+ double a = (argCount == 4) ? ctx->arguments[3].toNumber() : 1;
if (r < 0.0) r=0.0;
if (r > 1.0) r=1.0;
@@ -423,7 +201,7 @@ v8::Handle<v8::Value> rgba(const v8::Arguments &args)
if (a < 0.0) a=0.0;
if (a > 1.0) a=1.0;
- return V8ENGINE()->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a));
+ return ctx->engine->v8Engine->fromVariant(QQml_colorProvider()->fromRgbF(r, g, b, a));
}
/*!
@@ -432,16 +210,16 @@ v8::Handle<v8::Value> rgba(const v8::Arguments &args)
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.
*/
-v8::Handle<v8::Value> hsla(const v8::Arguments &args)
+Value QtObject::method_hsla(QV4::SimpleCallContext *ctx)
{
- int argCount = args.Length();
+ int argCount = ctx->argumentCount;
if (argCount < 3 || argCount > 4)
- V8THROW_ERROR("Qt.hsla(): Invalid arguments");
+ V4THROW_ERROR("Qt.hsla(): Invalid arguments");
- double h = args[0]->NumberValue();
- double s = args[1]->NumberValue();
- double l = args[2]->NumberValue();
- double a = (argCount == 4) ? args[3]->NumberValue() : 1;
+ double h = ctx->arguments[0].toNumber();
+ double s = ctx->arguments[1].toNumber();
+ double l = ctx->arguments[2].toNumber();
+ double a = (argCount == 4) ? ctx->arguments[3].toNumber() : 1;
if (h < 0.0) h=0.0;
if (h > 1.0) h=1.0;
@@ -452,7 +230,7 @@ v8::Handle<v8::Value> hsla(const v8::Arguments &args)
if (a < 0.0) a=0.0;
if (a > 1.0) a=1.0;
- return V8ENGINE()->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a));
+ return ctx->engine->v8Engine->fromVariant(QQml_colorProvider()->fromHslF(h, s, l, a));
}
/*!
@@ -463,35 +241,37 @@ 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.
*/
-v8::Handle<v8::Value> colorEqual(const v8::Arguments &args)
+Value QtObject::method_colorEqual(QV4::SimpleCallContext *ctx)
{
- if (args.Length() != 2)
- V8THROW_ERROR("Qt.colorEqual(): Invalid arguments");
+ if (ctx->argumentCount != 2)
+ V4THROW_ERROR("Qt.colorEqual(): Invalid arguments");
bool ok = false;
- QVariant lhs = V8ENGINE()->toVariant(args[0], -1);
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+
+ QVariant lhs = v8engine->toVariant(ctx->arguments[0], -1);
if (lhs.userType() == QVariant::String) {
lhs = QQmlStringConverters::colorFromString(lhs.toString(), &ok);
if (!ok) {
- V8THROW_ERROR("Qt.colorEqual(): Invalid color name");
+ V4THROW_ERROR("Qt.colorEqual(): Invalid color name");
}
} else if (lhs.userType() != QVariant::Color) {
- V8THROW_ERROR("Qt.colorEqual(): Invalid arguments");
+ V4THROW_ERROR("Qt.colorEqual(): Invalid arguments");
}
- QVariant rhs = V8ENGINE()->toVariant(args[1], -1);
+ QVariant rhs = v8engine->toVariant(ctx->arguments[1], -1);
if (rhs.userType() == QVariant::String) {
rhs = QQmlStringConverters::colorFromString(rhs.toString(), &ok);
if (!ok) {
- V8THROW_ERROR("Qt.colorEqual(): Invalid color name");
+ V4THROW_ERROR("Qt.colorEqual(): Invalid color name");
}
} else if (rhs.userType() != QVariant::Color) {
- V8THROW_ERROR("Qt.colorEqual(): Invalid arguments");
+ V4THROW_ERROR("Qt.colorEqual(): Invalid arguments");
}
bool equal = (lhs == rhs);
- return V8ENGINE()->fromVariant(equal);
+ return QV4::Value::fromBoolean(equal);
}
/*!
@@ -501,141 +281,147 @@ 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.
*/
-v8::Handle<v8::Value> rect(const v8::Arguments &args)
+Value QtObject::method_rect(QV4::SimpleCallContext *ctx)
{
- if (args.Length() != 4)
- V8THROW_ERROR("Qt.rect(): Invalid arguments");
+ if (ctx->argumentCount != 4)
+ V4THROW_ERROR("Qt.rect(): Invalid arguments");
- double x = args[0]->NumberValue();
- double y = args[1]->NumberValue();
- double w = args[2]->NumberValue();
- double h = args[3]->NumberValue();
+ double x = ctx->arguments[0].toNumber();
+ double y = ctx->arguments[1].toNumber();
+ double w = ctx->arguments[2].toNumber();
+ double h = ctx->arguments[3].toNumber();
- return V8ENGINE()->fromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
+ return ctx->engine->v8Engine->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.
*/
-v8::Handle<v8::Value> point(const v8::Arguments &args)
+Value QtObject::method_point(QV4::SimpleCallContext *ctx)
{
- if (args.Length() != 2)
- V8THROW_ERROR("Qt.point(): Invalid arguments");
+ if (ctx->argumentCount != 2)
+ V4THROW_ERROR("Qt.point(): Invalid arguments");
- double x = args[0]->ToNumber()->Value();
- double y = args[1]->ToNumber()->Value();
+ double x = ctx->arguments[0].toNumber();
+ double y = ctx->arguments[1].toNumber();
- return V8ENGINE()->fromVariant(QVariant::fromValue(QPointF(x, y)));
+ return ctx->engine->v8Engine->fromVariant(QVariant::fromValue(QPointF(x, y)));
}
/*!
\qmlmethod Qt::size(int width, int height)
Returns a Size with the specified \c width and \c height.
*/
-v8::Handle<v8::Value> size(const v8::Arguments &args)
+Value QtObject::method_size(QV4::SimpleCallContext *ctx)
{
- if (args.Length() != 2)
- V8THROW_ERROR("Qt.size(): Invalid arguments");
+ if (ctx->argumentCount != 2)
+ V4THROW_ERROR("Qt.size(): Invalid arguments");
- double w = args[0]->ToNumber()->Value();
- double h = args[1]->ToNumber()->Value();
+ double w = ctx->arguments[0].toNumber();
+ double h = ctx->arguments[1].toNumber();
- return V8ENGINE()->fromVariant(QVariant::fromValue(QSizeF(w, h)));
+ return ctx->engine->v8Engine->fromVariant(QVariant::fromValue(QSizeF(w, h)));
}
/*!
+\qmlmethod Qt::font(object fontSpecifier)
+Returns a Font with the properties specified in the \c fontSpecifier object
+or the nearest matching font. The \c fontSpecifier object should contain
+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.
+*/
+Value QtObject::method_font(QV4::SimpleCallContext *ctx)
+{
+ if (ctx->argumentCount != 1 || !ctx->arguments[0].isObject())
+ V4THROW_ERROR("Qt.font(): Invalid arguments");
+
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+ bool ok = false;
+ QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, QQmlV4Handle(ctx->arguments[0]), v8engine, &ok);
+ if (!ok)
+ V4THROW_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified");
+ return v8engine->fromVariant(v);
+}
+
+
+
+/*!
\qmlmethod Qt::vector2d(real x, real y)
Returns a Vector2D with the specified \c x and \c y.
*/
-v8::Handle<v8::Value> vector2d(const v8::Arguments &args)
+Value QtObject::method_vector2d(QV4::SimpleCallContext *ctx)
{
- if (args.Length() != 2)
- V8THROW_ERROR("Qt.vector2d(): Invalid arguments");
+ if (ctx->argumentCount != 2)
+ V4THROW_ERROR("Qt.vector2d(): Invalid arguments");
float xy[3]; // qvector2d uses float internally
- xy[0] = args[0]->ToNumber()->Value();
- xy[1] = args[1]->ToNumber()->Value();
+ xy[0] = ctx->arguments[0].toNumber();
+ xy[1] = ctx->arguments[1].toNumber();
const void *params[] = { xy };
- return V8ENGINE()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector2D, 1, params));
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+ return v8engine->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.
*/
-v8::Handle<v8::Value> vector3d(const v8::Arguments &args)
+Value QtObject::method_vector3d(QV4::SimpleCallContext *ctx)
{
- if (args.Length() != 3)
- V8THROW_ERROR("Qt.vector3d(): Invalid arguments");
+ if (ctx->argumentCount != 3)
+ V4THROW_ERROR("Qt.vector3d(): Invalid arguments");
float xyz[3]; // qvector3d uses float internally
- xyz[0] = args[0]->ToNumber()->Value();
- xyz[1] = args[1]->ToNumber()->Value();
- xyz[2] = args[2]->ToNumber()->Value();
+ xyz[0] = ctx->arguments[0].toNumber();
+ xyz[1] = ctx->arguments[1].toNumber();
+ xyz[2] = ctx->arguments[2].toNumber();
const void *params[] = { xyz };
- return V8ENGINE()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector3D, 1, params));
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+ return v8engine->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.
*/
-v8::Handle<v8::Value> vector4d(const v8::Arguments &args)
+Value QtObject::method_vector4d(QV4::SimpleCallContext *ctx)
{
- if (args.Length() != 4)
- V8THROW_ERROR("Qt.vector4d(): Invalid arguments");
+ if (ctx->argumentCount != 4)
+ V4THROW_ERROR("Qt.vector4d(): Invalid arguments");
float xyzw[4]; // qvector4d uses float internally
- xyzw[0] = args[0]->ToNumber()->Value();
- xyzw[1] = args[1]->ToNumber()->Value();
- xyzw[2] = args[2]->ToNumber()->Value();
- xyzw[3] = args[3]->ToNumber()->Value();
+ xyzw[0] = ctx->arguments[0].toNumber();
+ xyzw[1] = ctx->arguments[1].toNumber();
+ xyzw[2] = ctx->arguments[2].toNumber();
+ xyzw[3] = ctx->arguments[3].toNumber();
const void *params[] = { xyzw };
- return V8ENGINE()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QVector4D, 1, params));
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+ return v8engine->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.
*/
-v8::Handle<v8::Value> quaternion(const v8::Arguments &args)
+Value QtObject::method_quaternion(QV4::SimpleCallContext *ctx)
{
- if (args.Length() != 4)
- V8THROW_ERROR("Qt.quaternion(): Invalid arguments");
+ if (ctx->argumentCount != 4)
+ V4THROW_ERROR("Qt.quaternion(): Invalid arguments");
qreal sxyz[4]; // qquaternion uses qreal internally
- sxyz[0] = args[0]->ToNumber()->Value();
- sxyz[1] = args[1]->ToNumber()->Value();
- sxyz[2] = args[2]->ToNumber()->Value();
- sxyz[3] = args[3]->ToNumber()->Value();
+ sxyz[0] = ctx->arguments[0].toNumber();
+ sxyz[1] = ctx->arguments[1].toNumber();
+ sxyz[2] = ctx->arguments[2].toNumber();
+ sxyz[3] = ctx->arguments[3].toNumber();
const void *params[] = { sxyz };
- return V8ENGINE()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QQuaternion, 1, params));
-}
-
-/*!
-\qmlmethod Qt::font(object fontSpecifier)
-Returns a Font with the properties specified in the \c fontSpecifier object
-or the nearest matching font. The \c fontSpecifier object should contain
-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.
-*/
-v8::Handle<v8::Value> font(const v8::Arguments &args)
-{
- if (args.Length() != 1 || !args[0]->IsObject())
- V8THROW_ERROR("Qt.font(): Invalid arguments");
-
- v8::Handle<v8::Object> obj = args[0]->ToObject();
- bool ok = false;
- QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QFont, QQmlV8Handle::fromHandle(obj), V8ENGINE(), &ok);
- if (!ok)
- V8THROW_ERROR("Qt.font(): Invalid argument: no valid font subproperties specified");
- return V8ENGINE()->fromVariant(v);
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+ return v8engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QQuaternion, 1, params));
}
/*!
@@ -645,40 +431,41 @@ Alternatively, the function may be called with a single argument
where that argument is a JavaScript array which contains the sixteen
matrix values.
*/
-v8::Handle<v8::Value> matrix4x4(const v8::Arguments &args)
+Value QtObject::method_matrix4x4(QV4::SimpleCallContext *ctx)
{
- if (args.Length() == 1 && args[0]->IsObject()) {
- v8::Handle<v8::Object> obj = args[0]->ToObject();
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+
+ if (ctx->argumentCount == 1 && ctx->arguments[0].isObject()) {
bool ok = false;
- QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, QQmlV8Handle::fromHandle(obj), V8ENGINE(), &ok);
+ QVariant v = QQml_valueTypeProvider()->createVariantFromJsObject(QMetaType::QMatrix4x4, QQmlV4Handle(ctx->arguments[0]), v8engine, &ok);
if (!ok)
- V8THROW_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array");
- return V8ENGINE()->fromVariant(v);
+ V4THROW_ERROR("Qt.matrix4x4(): Invalid argument: not a valid matrix4x4 values array");
+ return v8engine->fromVariant(v);
}
- if (args.Length() != 16)
- V8THROW_ERROR("Qt.matrix4x4(): Invalid arguments");
+ if (ctx->argumentCount != 16)
+ V4THROW_ERROR("Qt.matrix4x4(): Invalid arguments");
qreal vals[16]; // qmatrix4x4 uses qreal internally
- vals[0] = args[0]->ToNumber()->Value();
- vals[1] = args[1]->ToNumber()->Value();
- vals[2] = args[2]->ToNumber()->Value();
- vals[3] = args[3]->ToNumber()->Value();
- vals[4] = args[4]->ToNumber()->Value();
- vals[5] = args[5]->ToNumber()->Value();
- vals[6] = args[6]->ToNumber()->Value();
- vals[7] = args[7]->ToNumber()->Value();
- vals[8] = args[8]->ToNumber()->Value();
- vals[9] = args[9]->ToNumber()->Value();
- vals[10] = args[10]->ToNumber()->Value();
- vals[11] = args[11]->ToNumber()->Value();
- vals[12] = args[12]->ToNumber()->Value();
- vals[13] = args[13]->ToNumber()->Value();
- vals[14] = args[14]->ToNumber()->Value();
- vals[15] = args[15]->ToNumber()->Value();
+ vals[0] = ctx->arguments[0].toNumber();
+ vals[1] = ctx->arguments[1].toNumber();
+ vals[2] = ctx->arguments[2].toNumber();
+ vals[3] = ctx->arguments[3].toNumber();
+ vals[4] = ctx->arguments[4].toNumber();
+ vals[5] = ctx->arguments[5].toNumber();
+ vals[6] = ctx->arguments[6].toNumber();
+ vals[7] = ctx->arguments[7].toNumber();
+ vals[8] = ctx->arguments[8].toNumber();
+ vals[9] = ctx->arguments[9].toNumber();
+ vals[10] = ctx->arguments[10].toNumber();
+ vals[11] = ctx->arguments[11].toNumber();
+ vals[12] = ctx->arguments[12].toNumber();
+ vals[13] = ctx->arguments[13].toNumber();
+ vals[14] = ctx->arguments[14].toNumber();
+ vals[15] = ctx->arguments[15].toNumber();
const void *params[] = { vals };
- return V8ENGINE()->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 1, params));
+ return v8engine->fromVariant(QQml_valueTypeProvider()->createValueType(QMetaType::QMatrix4x4, 1, params));
}
/*!
@@ -695,27 +482,28 @@ 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).
*/
-v8::Handle<v8::Value> lighter(const v8::Arguments &args)
+Value QtObject::method_lighter(QV4::SimpleCallContext *ctx)
{
- if (args.Length() != 1 && args.Length() != 2)
- V8THROW_ERROR("Qt.lighter(): Invalid arguments");
+ if (ctx->argumentCount != 1 && ctx->argumentCount != 2)
+ V4THROW_ERROR("Qt.lighter(): Invalid arguments");
- QVariant v = V8ENGINE()->toVariant(args[0], -1);
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+ QVariant v = v8engine->toVariant(ctx->arguments[0], -1);
if (v.userType() == QVariant::String) {
bool ok = false;
v = QQmlStringConverters::colorFromString(v.toString(), &ok);
if (!ok) {
- return v8::Null();
+ return QV4::Value::nullValue();
}
} else if (v.userType() != QVariant::Color) {
- return v8::Null();
+ return QV4::Value::nullValue();
}
qreal factor = 1.5;
- if (args.Length() == 2)
- factor = args[1]->ToNumber()->Value();
+ if (ctx->argumentCount == 2)
+ factor = ctx->arguments[1].toNumber();
- return V8ENGINE()->fromVariant(QQml_colorProvider()->lighter(v, factor));
+ return v8engine->fromVariant(QQml_colorProvider()->lighter(v, factor));
}
/*!
@@ -733,27 +521,28 @@ 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).
*/
-v8::Handle<v8::Value> darker(const v8::Arguments &args)
+Value QtObject::method_darker(QV4::SimpleCallContext *ctx)
{
- if (args.Length() != 1 && args.Length() != 2)
- V8THROW_ERROR("Qt.darker(): Invalid arguments");
+ if (ctx->argumentCount != 1 && ctx->argumentCount != 2)
+ V4THROW_ERROR("Qt.darker(): Invalid arguments");
- QVariant v = V8ENGINE()->toVariant(args[0], -1);
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+ QVariant v = v8engine->toVariant(ctx->arguments[0], -1);
if (v.userType() == QVariant::String) {
bool ok = false;
v = QQmlStringConverters::colorFromString(v.toString(), &ok);
if (!ok) {
- return v8::Null();
+ return QV4::Value::nullValue();
}
} else if (v.userType() != QVariant::Color) {
- return v8::Null();
+ return QV4::Value::nullValue();
}
qreal factor = 2.0;
- if (args.Length() == 2)
- factor = args[1]->ToNumber()->Value();
+ if (ctx->argumentCount == 2)
+ factor = ctx->arguments[1].toNumber();
- return V8ENGINE()->fromVariant(QQml_colorProvider()->darker(v, factor));
+ return v8engine->fromVariant(QQml_colorProvider()->darker(v, factor));
}
/*!
@@ -780,36 +569,38 @@ v8::Handle<v8::Value> darker(const v8::Arguments &args)
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.
*/
-v8::Handle<v8::Value> tint(const v8::Arguments &args)
+Value QtObject::method_tint(QV4::SimpleCallContext *ctx)
{
- if (args.Length() != 2)
- V8THROW_ERROR("Qt.tint(): Invalid arguments");
+ if (ctx->argumentCount != 2)
+ V4THROW_ERROR("Qt.tint(): Invalid arguments");
+
+ QV8Engine *v8engine = ctx->engine->v8Engine;
// base color
- QVariant v1 = V8ENGINE()->toVariant(args[0], -1);
+ QVariant v1 = v8engine->toVariant(ctx->arguments[0], -1);
if (v1.userType() == QVariant::String) {
bool ok = false;
v1 = QQmlStringConverters::colorFromString(v1.toString(), &ok);
if (!ok) {
- return v8::Null();
+ return QV4::Value::nullValue();
}
} else if (v1.userType() != QVariant::Color) {
- return v8::Null();
+ return QV4::Value::nullValue();
}
// tint color
- QVariant v2 = V8ENGINE()->toVariant(args[1], -1);
+ QVariant v2 = v8engine->toVariant(ctx->arguments[1], -1);
if (v2.userType() == QVariant::String) {
bool ok = false;
v2 = QQmlStringConverters::colorFromString(v2.toString(), &ok);
if (!ok) {
- return v8::Null();
+ return QV4::Value::nullValue();
}
} else if (v2.userType() != QVariant::Color) {
- return v8::Null();
+ return QV4::Value::nullValue();
}
- return V8ENGINE()->fromVariant(QQml_colorProvider()->tint(v1, v2));
+ return v8engine->fromVariant(QQml_colorProvider()->tint(v1, v2));
}
/*!
@@ -828,30 +619,32 @@ If \a format is not specified, \a date is formatted using
\sa Locale
*/
-v8::Handle<v8::Value> formatDate(const v8::Arguments &args)
+Value QtObject::method_formatDate(QV4::SimpleCallContext *ctx)
{
- if (args.Length() < 1 || args.Length() > 2)
- V8THROW_ERROR("Qt.formatDate(): Invalid arguments");
+ if (ctx->argumentCount < 1 || ctx->argumentCount > 2)
+ V4THROW_ERROR("Qt.formatDate(): Invalid arguments");
+
+ QV8Engine *v8engine = ctx->engine->v8Engine;
Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- QDate date = V8ENGINE()->toVariant(args[0], -1).toDateTime().date();
+ QDate date = v8engine->toVariant(ctx->arguments[0], -1).toDateTime().date();
QString formattedDate;
- if (args.Length() == 2) {
- if (args[1]->IsString()) {
- QString format = V8ENGINE()->toVariant(args[1], -1).toString();
+ if (ctx->argumentCount == 2) {
+ if (String *s = ctx->arguments[1].asString()) {
+ QString format = s->toQString();
formattedDate = date.toString(format);
- } else if (args[1]->IsNumber()) {
- quint32 intFormat = args[1]->ToNumber()->Value();
+ } else if (ctx->arguments[1].isNumber()) {
+ quint32 intFormat = ctx->arguments[1].asDouble();
Qt::DateFormat format = Qt::DateFormat(intFormat);
formattedDate = date.toString(format);
} else {
- V8THROW_ERROR("Qt.formatDate(): Invalid date format");
+ V4THROW_ERROR("Qt.formatDate(): Invalid date format");
}
} else {
formattedDate = date.toString(enumFormat);
}
- return V8ENGINE()->fromVariant(QVariant::fromValue(formattedDate));
+ return v8engine->fromVariant(QVariant::fromValue(formattedDate));
}
/*!
@@ -869,36 +662,38 @@ If \a format is not specified, \a time is formatted using
\sa Locale
*/
-v8::Handle<v8::Value> formatTime(const v8::Arguments &args)
+Value QtObject::method_formatTime(QV4::SimpleCallContext *ctx)
{
- if (args.Length() < 1 || args.Length() > 2)
- V8THROW_ERROR("Qt.formatTime(): Invalid arguments");
+ if (ctx->argumentCount < 1 || ctx->argumentCount > 2)
+ V4THROW_ERROR("Qt.formatTime(): Invalid arguments");
- QVariant argVariant = V8ENGINE()->toVariant(args[0], -1);
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+
+ QVariant argVariant = v8engine->toVariant(ctx->arguments[0], -1);
QTime time;
- if (args[0]->IsDate() || (argVariant.type() == QVariant::String))
+ if (ctx->arguments[0].asDateObject() || (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 (args.Length() == 2) {
- if (args[1]->IsString()) {
- QString format = V8ENGINE()->toVariant(args[1], -1).toString();
+ if (ctx->argumentCount == 2) {
+ if (String *s = ctx->arguments[1].asString()) {
+ QString format = s->toQString();
formattedTime = time.toString(format);
- } else if (args[1]->IsNumber()) {
- quint32 intFormat = args[1]->ToNumber()->Value();
+ } else if (ctx->arguments[1].isNumber()) {
+ quint32 intFormat = ctx->arguments[1].asDouble();
Qt::DateFormat format = Qt::DateFormat(intFormat);
formattedTime = time.toString(format);
} else {
- V8THROW_ERROR("Qt.formatTime(): Invalid time format");
+ V4THROW_ERROR("Qt.formatTime(): Invalid time format");
}
} else {
formattedTime = time.toString(enumFormat);
}
- return V8ENGINE()->fromVariant(QVariant::fromValue(formattedTime));
+ return v8engine->fromVariant(QVariant::fromValue(formattedTime));
}
/*!
@@ -991,118 +786,125 @@ with the \a format values below to produce the following results:
\sa Locale
*/
-v8::Handle<v8::Value> formatDateTime(const v8::Arguments &args)
+Value QtObject::method_formatDateTime(QV4::SimpleCallContext *ctx)
{
- if (args.Length() < 1 || args.Length() > 2)
- V8THROW_ERROR("Qt.formatDateTime(): Invalid arguments");
+ if (ctx->argumentCount < 1 || ctx->argumentCount > 2)
+ V4THROW_ERROR("Qt.formatDateTime(): Invalid arguments");
+
+ QV8Engine *v8engine = ctx->engine->v8Engine;
Qt::DateFormat enumFormat = Qt::DefaultLocaleShortDate;
- QDateTime dt = V8ENGINE()->toVariant(args[0], -1).toDateTime();
+ QDateTime dt = v8engine->toVariant(ctx->arguments[0], -1).toDateTime();
QString formattedDt;
- if (args.Length() == 2) {
- if (args[1]->IsString()) {
- QString format = V8ENGINE()->toVariant(args[1], -1).toString();
+ if (ctx->argumentCount == 2) {
+ if (String *s = ctx->arguments[1].asString()) {
+ QString format = s->toQString();
formattedDt = dt.toString(format);
- } else if (args[1]->IsNumber()) {
- quint32 intFormat = args[1]->ToNumber()->Value();
+ } else if (ctx->arguments[1].isNumber()) {
+ quint32 intFormat = ctx->arguments[1].asDouble();
Qt::DateFormat format = Qt::DateFormat(intFormat);
formattedDt = dt.toString(format);
} else {
- V8THROW_ERROR("Qt.formatDateTime(): Invalid datetime format");
+ V4THROW_ERROR("Qt.formatDateTime(): Invalid datetime format");
}
} else {
formattedDt = dt.toString(enumFormat);
}
- return V8ENGINE()->fromVariant(QVariant::fromValue(formattedDt));
+ return v8engine->fromVariant(QVariant::fromValue(formattedDt));
}
/*!
\qmlmethod bool Qt::openUrlExternally(url target)
Attempts to open the specified \c target url in an external application, based on the user's desktop preferences. Returns true if it succeeds, and false otherwise.
*/
-v8::Handle<v8::Value> openUrlExternally(const v8::Arguments &args)
+Value QtObject::method_openUrlExternally(QV4::SimpleCallContext *ctx)
{
- if (args.Length() != 1)
- return V8ENGINE()->fromVariant(false);
+ if (ctx->argumentCount != 1)
+ return QV4::Value::fromBoolean(false);
- QUrl url(V8ENGINE()->toVariant(resolvedUrl(args), -1).toUrl());
- return V8ENGINE()->fromVariant(QQml_guiProvider()->openUrlExternally(url));
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+
+ QUrl url(method_resolvedUrl(ctx).toQString());
+ return v8engine->fromVariant(QQml_guiProvider()->openUrlExternally(url));
}
/*!
\qmlmethod url Qt::resolvedUrl(url url)
Returns \a url resolved relative to the URL of the caller.
*/
-v8::Handle<v8::Value> resolvedUrl(const v8::Arguments &args)
+Value QtObject::method_resolvedUrl(QV4::SimpleCallContext *ctx)
{
- QUrl url = V8ENGINE()->toVariant(args[0], -1).toUrl();
- QQmlEngine *e = V8ENGINE()->engine();
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+
+ QUrl url = v8engine->toVariant(ctx->arguments[0], -1).toUrl();
+ QQmlEngine *e = v8engine->engine();
QQmlEnginePrivate *p = 0;
if (e) p = QQmlEnginePrivate::get(e);
if (p) {
- QQmlContextData *ctxt = V8ENGINE()->callingContext();
+ QQmlContextData *ctxt = v8engine->callingContext();
if (ctxt)
- return V8ENGINE()->toString(ctxt->resolvedUrl(url).toString());
+ return Value::fromString(ctx, ctxt->resolvedUrl(url).toString());
else
- return V8ENGINE()->toString(url.toString());
+ return Value::fromString(ctx, url.toString());
}
- return V8ENGINE()->toString(e->baseUrl().resolved(url).toString());
+ return Value::fromString(ctx, e->baseUrl().resolved(url).toString());
}
/*!
\qmlmethod list<string> Qt::fontFamilies()
Returns a list of the font families available to the application.
*/
-v8::Handle<v8::Value> fontFamilies(const v8::Arguments &args)
+Value QtObject::method_fontFamilies(SimpleCallContext *ctx)
{
- if (args.Length() != 0)
- V8THROW_ERROR("Qt.fontFamilies(): Invalid arguments");
+ if (ctx->argumentCount != 0)
+ V4THROW_ERROR("Qt.fontFamilies(): Invalid arguments");
- return V8ENGINE()->fromVariant(QVariant(QQml_guiProvider()->fontFamilies()));
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+ return v8engine->fromVariant(QVariant(QQml_guiProvider()->fontFamilies()));
}
/*!
\qmlmethod string Qt::md5(data)
Returns a hex string of the md5 hash of \c data.
*/
-v8::Handle<v8::Value> md5(const v8::Arguments &args)
+Value QtObject::method_md5(SimpleCallContext *ctx)
{
- if (args.Length() != 1)
- V8THROW_ERROR("Qt.md5(): Invalid arguments");
+ if (ctx->argumentCount != 1)
+ V4THROW_ERROR("Qt.md5(): Invalid arguments");
- QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
+ QByteArray data = ctx->arguments[0].toQString().toUtf8();
QByteArray result = QCryptographicHash::hash(data, QCryptographicHash::Md5);
- return V8ENGINE()->toString(QLatin1String(result.toHex()));
+ return Value::fromString(ctx, QLatin1String(result.toHex()));
}
/*!
\qmlmethod string Qt::btoa(data)
Binary to ASCII - this function returns a base64 encoding of \c data.
*/
-v8::Handle<v8::Value> btoa(const v8::Arguments &args)
+Value QtObject::method_btoa(SimpleCallContext *ctx)
{
- if (args.Length() != 1)
- V8THROW_ERROR("Qt.btoa(): Invalid arguments");
+ if (ctx->argumentCount != 1)
+ V4THROW_ERROR("Qt.btoa(): Invalid arguments");
- QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
+ QByteArray data = ctx->arguments[0].toQString().toUtf8();
- return V8ENGINE()->toString(QLatin1String(data.toBase64()));
+ return Value::fromString(ctx, QLatin1String(data.toBase64()));
}
/*!
\qmlmethod string Qt::atob(data)
ASCII to binary - this function returns a base64 decoding of \c data.
*/
-v8::Handle<v8::Value> atob(const v8::Arguments &args)
+Value QtObject::method_atob(SimpleCallContext *ctx)
{
- if (args.Length() != 1)
- V8THROW_ERROR("Qt.atob(): Invalid arguments");
+ if (ctx->argumentCount != 1)
+ V4THROW_ERROR("Qt.atob(): Invalid arguments");
- QByteArray data = V8ENGINE()->toString(args[0]->ToString()).toUtf8();
+ QByteArray data = ctx->arguments[0].toQString().toLatin1();
- return V8ENGINE()->toString(QLatin1String(QByteArray::fromBase64(data)));
+ return Value::fromString(ctx, QString::fromUtf8(QByteArray::fromBase64(data)));
}
/*!
@@ -1112,10 +914,12 @@ Within the \l {Prototyping with qmlscene}, this causes the launcher application
to quit a C++ application when this method is called, connect the
QQmlEngine::quit() signal to the QCoreApplication::quit() slot.
*/
-v8::Handle<v8::Value> quit(const v8::Arguments &args)
+Value QtObject::method_quit(SimpleCallContext *ctx)
{
- QQmlEnginePrivate::get(V8ENGINE()->engine())->sendQuit();
- return v8::Undefined();
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+
+ QQmlEnginePrivate::get(v8engine->engine())->sendQuit();
+ return QV4::Value::undefinedValue();
}
/*!
@@ -1142,35 +946,35 @@ If this is the case, consider using \l{QtQml2::Qt::createComponent()}{Qt.createC
See \l {Dynamic QML Object Creation from JavaScript} for more information on using this function.
*/
-v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args)
+Value QtObject::method_createQmlObject(SimpleCallContext *ctx)
{
- if (args.Length() < 2 || args.Length() > 3)
- V8THROW_ERROR("Qt.createQmlObject(): Invalid arguments");
+ if (ctx->argumentCount < 2 || ctx->argumentCount > 3)
+ V4THROW_ERROR("Qt.createQmlObject(): Invalid arguments");
struct Error {
- static v8::Local<v8::Value> create(QV8Engine *engine, const QList<QQmlError> &errors) {
+ static Value create(QV8Engine *engine, const QList<QQmlError> &errors) {
QString errorstr = QLatin1String("Qt.createQmlObject(): failed to create object: ");
- v8::Local<v8::Array> qmlerrors = v8::Array::New(errors.count());
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QV4::ArrayObject *qmlerrors = v4->newArrayObject();
for (int ii = 0; ii < errors.count(); ++ii) {
const QQmlError &error = errors.at(ii);
errorstr += QLatin1String("\n ") + error.toString();
- v8::Local<v8::Object> qmlerror = v8::Object::New();
- qmlerror->Set(v8::String::New("lineNumber"), v8::Integer::New(error.line()));
- qmlerror->Set(v8::String::New("columnNumber"), v8::Integer::New(error.column()));
- qmlerror->Set(v8::String::New("fileName"), engine->toString(error.url().toString()));
- qmlerror->Set(v8::String::New("message"), engine->toString(error.description()));
- qmlerrors->Set(ii, qmlerror);
+ QV4::Object *qmlerror = v4->newObject();
+ qmlerror->put(v4->newString("lineNumber"), QV4::Value::fromInt32(error.line()));
+ qmlerror->put(v4->newString("columnNumber"), QV4::Value::fromInt32(error.column()));
+ qmlerror->put(v4->newString("fileName"), engine->toString(error.url().toString()));
+ qmlerror->put(v4->newString("message"), engine->toString(error.description()));
+ qmlerrors->putIndexed(ii, QV4::Value::fromObject(qmlerror));
}
- v8::Local<v8::Value> error = v8::Exception::Error(engine->toString(errorstr));
- v8::Local<v8::Object> errorObject = error->ToObject();
- errorObject->Set(v8::String::New("qmlErrors"), qmlerrors);
- return error;
+ QV4::Object *errorObject = v4->newErrorObject(engine->toString(errorstr));
+ errorObject->put(v4->newString("qmlErrors"), Value::fromObject(qmlerrors));
+ return Value::fromObject(errorObject);
}
};
- QV8Engine *v8engine = V8ENGINE();
+ QV8Engine *v8engine = ctx->engine->v8Engine;
QQmlEngine *engine = v8engine->engine();
QQmlContextData *context = v8engine->callingContext();
@@ -1181,33 +985,35 @@ v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args)
effectiveContext = context->asQQmlContext();
Q_ASSERT(context && effectiveContext);
- QString qml = v8engine->toString(args[0]->ToString());
+ QString qml = ctx->arguments[0].toQString();
if (qml.isEmpty())
- return v8::Null();
+ return QV4::Value::nullValue();
QUrl url;
- if (args.Length() > 2)
- url = QUrl(v8engine->toString(args[2]->ToString()));
+ if (ctx->argumentCount > 2)
+ url = QUrl(ctx->arguments[2].toQString());
else
url = QUrl(QLatin1String("inline"));
if (url.isValid() && url.isRelative())
url = context->resolvedUrl(url);
- QObject *parentArg = v8engine->toQObject(args[1]);
+ QObject *parentArg = 0;
+ if (QV4::QObjectWrapper *qobjectWrapper = ctx->arguments[1].as<QV4::QObjectWrapper>())
+ parentArg = qobjectWrapper->object();
if (!parentArg)
- V8THROW_ERROR("Qt.createQmlObject(): Missing parent object");
+ V4THROW_ERROR("Qt.createQmlObject(): Missing parent object");
QQmlComponent component(engine);
component.setData(qml.toUtf8(), url);
if (component.isError()) {
- v8::ThrowException(Error::create(v8engine, component.errors()));
- return v8::Undefined();
+ ctx->throwError(Error::create(v8engine, component.errors()));
+ return QV4::Value::undefinedValue();
}
if (!component.isReady())
- V8THROW_ERROR("Qt.createQmlObject(): Component is not ready");
+ V4THROW_ERROR("Qt.createQmlObject(): Component is not ready");
QObject *obj = component.beginCreate(effectiveContext);
if (obj) {
@@ -1226,13 +1032,13 @@ v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args)
component.completeCreate();
if (component.isError()) {
- v8::ThrowException(Error::create(v8engine, component.errors()));
- return v8::Undefined();
+ ctx->throwError(Error::create(v8engine, component.errors()));
+ return QV4::Value::undefinedValue();
}
Q_ASSERT(obj);
- return v8engine->newQObject(obj);
+ return QV4::QObjectWrapper::wrap(ctx->engine, obj);
}
/*!
@@ -1266,14 +1072,14 @@ 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{QtQml2::Qt::createQmlObject()}{Qt.createQmlObject()}.
*/
-v8::Handle<v8::Value> createComponent(const v8::Arguments &args)
+Value QtObject::method_createComponent(SimpleCallContext *ctx)
{
- const char *invalidArgs = "Qt.createComponent(): Invalid arguments";
- const char *invalidParent = "Qt.createComponent(): Invalid parent object";
- if (args.Length() < 1 || args.Length() > 3)
- V8THROW_ERROR(invalidArgs);
+ const QString invalidArgs = QStringLiteral("Qt.createComponent(): Invalid arguments");
+ const QString invalidParent = QStringLiteral("Qt.createComponent(): Invalid parent object");
+ if (ctx->argumentCount < 1 || ctx->argumentCount > 3)
+ ctx->throwError(invalidArgs);
- QV8Engine *v8engine = V8ENGINE();
+ QV8Engine *v8engine = ctx->engine->v8Engine;
QQmlEngine *engine = v8engine->engine();
QQmlContextData *context = v8engine->callingContext();
@@ -1282,39 +1088,40 @@ v8::Handle<v8::Value> createComponent(const v8::Arguments &args)
effectiveContext = 0;
Q_ASSERT(context);
- QString arg = v8engine->toString(args[0]->ToString());
+ QString arg = ctx->arguments[0].toQString();
if (arg.isEmpty())
- return v8::Null();
+ return QV4::Value::nullValue();
QQmlComponent::CompilationMode compileMode = QQmlComponent::PreferSynchronous;
QObject *parentArg = 0;
int consumedCount = 1;
- if (args.Length() > 1) {
- const v8::Local<v8::Value> &lastArg = args[args.Length()-1];
+ if (ctx->argumentCount > 1) {
+ Value lastArg = ctx->arguments[ctx->argumentCount-1];
// The second argument could be the mode enum
- if (args[1]->IsInt32()) {
- int mode = args[1]->Int32Value();
+ if (ctx->arguments[1].isInteger()) {
+ int mode = ctx->arguments[1].integerValue();
if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous))
- V8THROW_ERROR(invalidArgs);
+ ctx->throwError(invalidArgs);
compileMode = QQmlComponent::CompilationMode(mode);
consumedCount += 1;
} else {
// The second argument could be the parent only if there are exactly two args
- if ((args.Length() != 2) || !(lastArg->IsObject() || lastArg->IsNull()))
- V8THROW_ERROR(invalidArgs);
+ if ((ctx->argumentCount != 2) || !(lastArg.isObject() || lastArg.isNull()))
+ ctx->throwError(invalidArgs);
}
- if (consumedCount < args.Length()) {
- if (lastArg->IsObject()) {
- parentArg = v8engine->toQObject(lastArg);
+ if (consumedCount < ctx->argumentCount) {
+ if (lastArg.isObject()) {
+ if (QV4::QObjectWrapper *qobjectWrapper = lastArg.as<QV4::QObjectWrapper>())
+ parentArg = qobjectWrapper->object();
if (!parentArg)
- V8THROW_ERROR(invalidParent);
- } else if (lastArg->IsNull()) {
+ ctx->throwError(invalidParent);
+ } else if (lastArg.isNull()) {
parentArg = 0;
} else {
- V8THROW_ERROR(invalidParent);
+ ctx->throwError(invalidParent);
}
}
}
@@ -1325,9 +1132,471 @@ v8::Handle<v8::Value> createComponent(const v8::Arguments &args)
QQmlData::get(c, true)->explicitIndestructibleSet = false;
QQmlData::get(c)->indestructible = false;
- return v8engine->newQObject(c);
+ return QV4::QObjectWrapper::wrap(ctx->engine, c);
+}
+
+/*!
+ \qmlmethod Qt::locale(name)
+
+ Returns a JS object representing the locale with the specified
+ name, which has the format "language[_territory][.codeset][@modifier]"
+ or "C", where:
+
+ \list
+ \li language is a lowercase, two-letter, ISO 639 language code,
+ \li territory is an uppercase, two-letter, ISO 3166 country code,
+ \li and codeset and modifier are ignored.
+ \endlist
+
+ If the string violates the locale format, or language is not a
+ valid ISO 369 code, the "C" locale is used instead. If country
+ is not present, or is not a valid ISO 3166 code, the most
+ appropriate country is chosen for the specified language.
+
+ \sa QtQuick2::Locale
+*/
+Value QtObject::method_locale(SimpleCallContext *ctx)
+{
+ QString code;
+ if (ctx->argumentCount > 1)
+ V4THROW_ERROR("locale() requires 0 or 1 argument");
+ if (ctx->argumentCount == 1 && !ctx->arguments[0].isString())
+ V4THROW_TYPE("locale(): argument (locale code) must be a string");
+
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+ if (ctx->argumentCount == 1)
+ code = ctx->arguments[0].toQString();
+
+ return QQmlLocale::locale(v8engine, code);
+}
+
+namespace {
+
+struct BindingFunction : public QV4::FunctionObject
+{
+ Q_MANAGED
+ BindingFunction(FunctionObject *originalFunction)
+ : QV4::FunctionObject(originalFunction->scope, originalFunction->name)
+ , originalFunction(originalFunction)
+ {
+ vtbl = &static_vtbl;
+ bindingKeyFlag = true;
+ }
+
+ static Value call(Managed *that, const Value &thisObject, Value *argv, int argc)
+ {
+ BindingFunction *This = static_cast<BindingFunction*>(that);
+ return This->originalFunction->call(thisObject, argv, argc);
+ }
+
+ static void markObjects(Managed *that)
+ {
+ BindingFunction *This = static_cast<BindingFunction*>(that);
+ This->originalFunction->mark();
+ QV4::FunctionObject::markObjects(that);
+ }
+
+ QV4::FunctionObject *originalFunction;
+};
+
+DEFINE_MANAGED_VTABLE(BindingFunction);
+
}
+/*!
+ \qmlmethod Qt::binding(function)
+
+ Returns a JS object representing a binding expression which may be
+ assigned to any property in imperative code to cause a binding
+ assignment.
+
+ There are two main use-cases for the function: firstly, in imperative
+ JavaScript code to cause a binding assignment:
+
+ \snippet qml/qtBinding.1.qml 0
+
+ and secondly, when defining initial property values of dynamically
+ constructed objects (via Component.createObject() or
+ Loader.setSource()) as being bound to the result of an expression.
+
+ For example, assuming the existence of a DynamicText component:
+ \snippet qml/DynamicText.qml 0
+
+ the output from:
+ \snippet qml/qtBinding.2.qml 0
+
+ and from:
+ \snippet qml/qtBinding.3.qml 0
+
+ should both be:
+ \code
+ Root text extra text
+ Modified root text extra text
+ Dynamic text extra text
+ Modified dynamic text extra text
+ \endcode
+
+ This function cannot be used in property binding declarations
+ (see the documentation on \l{qml-javascript-assignment}{binding
+ declarations and binding assignments}) except when the result is
+ stored in an array bound to a var property.
+
+ \snippet qml/qtBinding.4.qml 0
+
+ \note In \l {Qt Quick 1}, all function assignment was treated as
+ binding assignment, so the Qt.binding() function is new in
+ \l {Qt Quick}{Qt Quick 2}.
+
+ \since QtQuick 2.0
+*/
+Value QtObject::method_binding(SimpleCallContext *ctx)
+{
+ if (ctx->argumentCount != 1)
+ V4THROW_ERROR("binding() requires 1 argument");
+ QV4::FunctionObject *f = ctx->arguments[0].asFunctionObject();
+ if (!f)
+ V4THROW_TYPE("binding(): argument (binding expression) must be a function");
+
+ return QV4::Value::fromObject(new (ctx->engine->memoryManager) BindingFunction(f));
+}
+
+
+Value QtObject::method_get_platform(SimpleCallContext *ctx)
+{
+ // ### inefficient. Should be just a value based getter
+ Object *o = ctx->thisObject.asObject();
+ if (!o)
+ ctx->throwTypeError();
+ QtObject *qt = o->as<QtObject>();
+ if (!qt)
+ ctx->throwTypeError();
+
+ if (!qt->m_platform)
+ // Only allocate a platform object once
+ qt->m_platform = new QQmlPlatform(ctx->engine->v8Engine->publicEngine());
+
+ return QV4::QObjectWrapper::wrap(ctx->engine, qt->m_platform);
+}
+
+Value QtObject::method_get_application(SimpleCallContext *ctx)
+{
+ // ### inefficient. Should be just a value based getter
+ Object *o = ctx->thisObject.asObject();
+ if (!o)
+ ctx->throwTypeError();
+ QtObject *qt = o->as<QtObject>();
+ if (!qt)
+ ctx->throwTypeError();
+
+ if (!qt->m_application)
+ // Only allocate an application object once
+ qt->m_application = QQml_guiProvider()->application(ctx->engine->v8Engine->publicEngine());
+
+ return QV4::QObjectWrapper::wrap(ctx->engine, qt->m_application);
+}
+
+#ifndef QT_NO_IM
+Value QtObject::method_get_inputMethod(SimpleCallContext *ctx)
+{
+ QObject *o = QQml_guiProvider()->inputMethod();
+ QQmlEngine::setObjectOwnership(o, QQmlEngine::CppOwnership);
+ return QV4::QObjectWrapper::wrap(ctx->engine, o);
+}
+#endif
+
+
+QV4::ConsoleObject::ConsoleObject(ExecutionEngine *v4)
+ : Object(v4)
+{
+ defineDefaultProperty(v4, QStringLiteral("debug"), method_log);
+ defineDefaultProperty(v4, QStringLiteral("log"), method_log);
+ defineDefaultProperty(v4, QStringLiteral("info"), method_log);
+ defineDefaultProperty(v4, QStringLiteral("warn"), method_warn);
+ defineDefaultProperty(v4, QStringLiteral("error"), method_error);
+ defineDefaultProperty(v4, QStringLiteral("assert"), method_assert);
+
+ defineDefaultProperty(v4, QStringLiteral("count"), method_count);
+ defineDefaultProperty(v4, QStringLiteral("profile"), method_profile);
+ defineDefaultProperty(v4, QStringLiteral("profileEnd"), method_profileEnd);
+ defineDefaultProperty(v4, QStringLiteral("time"), method_time);
+ defineDefaultProperty(v4, QStringLiteral("timeEnd"), method_timeEnd);
+ defineDefaultProperty(v4, QStringLiteral("trace"), method_trace);
+ defineDefaultProperty(v4, QStringLiteral("exception"), method_exception);
+}
+
+
+enum ConsoleLogTypes {
+ Log,
+ Warn,
+ Error
+};
+
+static QString jsStack(QV4::ExecutionEngine *engine) {
+ QString stack;
+
+ QVector<QV4::ExecutionEngine::StackFrame> stackTrace = engine->stackTrace(10);
+
+ for (int i = 0; i < stackTrace.count(); i++) {
+ const QV4::ExecutionEngine::StackFrame &frame = stackTrace.at(i);
+
+ QString stackFrame;
+ if (frame.column >= 0)
+ stackFrame = QString::fromLatin1("%1 (%2:%3:%4)").arg(frame.function,
+ frame.source,
+ QString::number(frame.line),
+ QString::number(frame.column));
+ else
+ stackFrame = QString::fromLatin1("%1 (%2:%3)").arg(frame.function,
+ frame.source,
+ QString::number(frame.line));
+
+ if (i)
+ stack += QChar('\n');
+ stack += stackFrame;
+ }
+ return stack;
+}
+
+static QV4::Value writeToConsole(ConsoleLogTypes logType, SimpleCallContext *ctx,
+ bool printStack = false)
+{
+ QString result;
+ QV4::ExecutionEngine *v4 = ctx->engine;
+
+ for (int i = 0; i < ctx->argumentCount; ++i) {
+ if (i != 0)
+ result.append(QLatin1Char(' '));
+
+ QV4::Value value = ctx->arguments[i];
+ if (value.asArrayObject())
+ result.append(QStringLiteral("[") + value.toQString() + QStringLiteral("]"));
+ else
+ result.append(value.toQString());
+ }
+
+ if (printStack) {
+ result.append(QLatin1String("\n"));
+ result.append(jsStack(v4));
+ }
+
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
+ QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
+ switch (logType) {
+ case Log:
+ logger.debug("%s", qPrintable(result));
+ break;
+ case Warn:
+ logger.warning("%s", qPrintable(result));
+ break;
+ case Error:
+ logger.critical("%s", qPrintable(result));
+ break;
+ default:
+ break;
+ }
+
+ return QV4::Value::undefinedValue();
+}
+
+QV4::Value ConsoleObject::method_error(SimpleCallContext *ctx)
+{
+ return writeToConsole(Error, ctx);
+}
+
+QV4::Value ConsoleObject::method_log(SimpleCallContext *ctx)
+{
+ //console.log
+ //console.debug
+ //console.info
+ //print
+ return writeToConsole(Log, ctx);
+}
+
+QV4::Value ConsoleObject::method_profile(SimpleCallContext *ctx)
+{
+ //DeclarativeDebugTrace cannot handle nested profiling
+ //although v8 can handle several profiling at once,
+ //we do not allow that. Hence, we pass an empty(default) title
+ QString title;
+ QV4::ExecutionEngine *v4 = ctx->engine;
+
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
+ QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
+ if (QQmlProfilerService::startProfiling()) {
+ QV8ProfilerService::instance()->startProfiling(title);
+
+ logger.debug("Profiling started.");
+ } else {
+ logger.warning("Profiling is already in progress. First, end current profiling session.");
+ }
+
+ return QV4::Value::undefinedValue();
+}
+
+QV4::Value ConsoleObject::method_profileEnd(SimpleCallContext *ctx)
+{
+ //DeclarativeDebugTrace cannot handle nested profiling
+ //although v8 can handle several profiling at once,
+ //we do not allow that. Hence, we pass an empty(default) title
+ QString title;
+
+ QV4::ExecutionEngine *v4 = ctx->engine;
+
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
+ QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
+
+ if (QQmlProfilerService::stopProfiling()) {
+ QV8ProfilerService *profiler = QV8ProfilerService::instance();
+ profiler->stopProfiling(title);
+ QQmlProfilerService::sendProfilingData();
+ profiler->sendProfilingData();
+
+ logger.debug("Profiling ended.");
+ } else {
+ logger.warning("Profiling was not started.");
+ }
+
+ return QV4::Value::undefinedValue();
+}
+
+QV4::Value ConsoleObject::method_time(SimpleCallContext *ctx)
+{
+ if (ctx->argumentCount != 1)
+ V4THROW_ERROR("console.time(): Invalid arguments");
+
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+
+ QString name = ctx->arguments[0].toQString();
+ v8engine->startTimer(name);
+ return QV4::Value::undefinedValue();
+}
+
+QV4::Value ConsoleObject::method_timeEnd(SimpleCallContext *ctx)
+{
+ if (ctx->argumentCount != 1)
+ V4THROW_ERROR("console.time(): Invalid arguments");
+
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+
+ QString name = ctx->arguments[0].toQString();
+ bool wasRunning;
+ qint64 elapsed = v8engine->stopTimer(name, &wasRunning);
+ if (wasRunning) {
+ qDebug("%s: %llims", qPrintable(name), elapsed);
+ }
+ return QV4::Value::undefinedValue();
+}
+
+QV4::Value ConsoleObject::method_count(SimpleCallContext *ctx)
+{
+ // first argument: name to print. Ignore any additional arguments
+ QString name;
+ if (ctx->argumentCount > 0)
+ name = ctx->arguments[0].toQString();
+
+ QV4::ExecutionEngine *v4 = ctx->engine;
+ QV8Engine *v8engine = ctx->engine->v8Engine;
+
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
+
+ QString scriptName = frame.source;
+
+ int value = v8engine->consoleCountHelper(scriptName, frame.line, frame.column);
+ QString message = name + QLatin1String(": ") + QString::number(value);
+
+ QMessageLogger(qPrintable(scriptName), frame.line,
+ qPrintable(frame.function)).debug("%s", qPrintable(message));
+
+ return QV4::Value::undefinedValue();
+}
+
+QV4::Value ConsoleObject::method_trace(SimpleCallContext *ctx)
+{
+ if (ctx->argumentCount != 0)
+ V4THROW_ERROR("console.trace(): Invalid arguments");
+
+ QV4::ExecutionEngine *v4 = ctx->engine;
+
+ QString stack = jsStack(v4);
+
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
+ QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
+
+ logger.debug("%s", qPrintable(stack));
+ return QV4::Value::undefinedValue();
+}
+
+QV4::Value ConsoleObject::method_warn(SimpleCallContext *ctx)
+{
+ return writeToConsole(Warn, ctx);
+}
+
+QV4::Value ConsoleObject::method_assert(SimpleCallContext *ctx)
+{
+ if (ctx->argumentCount == 0)
+ V4THROW_ERROR("console.assert(): Missing argument");
+
+ QV4::ExecutionEngine *v4 = ctx->engine;
+
+ if (!ctx->arguments[0].toBoolean()) {
+ QString message;
+ for (int i = 1; i < ctx->argumentCount; ++i) {
+ if (i != 1)
+ message.append(QLatin1Char(' '));
+
+ message.append(ctx->arguments[i].toQString());
+ }
+
+ QString stack = jsStack(v4);
+
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
+ QMessageLogger logger(frame.source.toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
+ logger.critical("%s\n%s", qPrintable(message), qPrintable(stack));
+
+ }
+ return QV4::Value::undefinedValue();
+}
+
+QV4::Value ConsoleObject::method_exception(SimpleCallContext *ctx)
+{
+ if (ctx->argumentCount == 0)
+ V4THROW_ERROR("console.exception(): Missing argument");
+
+ writeToConsole(Error, ctx, true);
+
+ return QV4::Value::undefinedValue();
+}
+
+
+
+void QV4::GlobalExtensions::init(QQmlEngine *qmlEngine, Object *globalObject)
+{
+ QV4::ExecutionEngine *v4 = globalObject->engine();
+
+#ifndef QT_NO_TRANSLATION
+ globalObject->defineDefaultProperty(v4, QStringLiteral("qsTranslate"), method_qsTranslate);
+ globalObject->defineDefaultProperty(v4, QStringLiteral("QT_TRANSLATE_NOOP"), method_qsTranslateNoOp);
+ globalObject->defineDefaultProperty(v4, QStringLiteral("qsTr"), method_qsTr);
+ globalObject->defineDefaultProperty(v4, QStringLiteral("QT_TR_NOOP"), method_qsTrNoOp);
+ globalObject->defineDefaultProperty(v4, QStringLiteral("qsTrId"), method_qsTrId);
+ globalObject->defineDefaultProperty(v4, QStringLiteral("QT_TRID_NOOP"), method_qsTrIdNoOp);
+#endif
+
+ globalObject->defineDefaultProperty(v4, QStringLiteral("print"), ConsoleObject::method_log);
+ globalObject->defineDefaultProperty(v4, QStringLiteral("gc"), method_gc);
+
+ Value console = QV4::Value::fromObject(new (v4->memoryManager) QV4::ConsoleObject(v4));
+ globalObject->defineDefaultProperty(v4, QStringLiteral("console"), console);
+
+ Value qt = QV4::Value::fromObject(new (v4->memoryManager) QV4::QtObject(v4, qmlEngine));
+ globalObject->defineDefaultProperty(v4, QStringLiteral("Qt"), qt);
+
+ // string prototype extension
+ QV4::Object *stringProto = v4->stringPrototype;
+ stringProto->defineDefaultProperty(v4, QStringLiteral("arg"), string_arg);
+}
+
+
#ifndef QT_NO_TRANSLATION
/*!
\qmlmethod string Qt::qsTranslate(string context, string sourceText, string disambiguation, int n)
@@ -1346,39 +1615,38 @@ v8::Handle<v8::Value> createComponent(const v8::Arguments &args)
\sa {Internationalization and Localization with Qt Quick}
*/
-v8::Handle<v8::Value> qsTranslate(const v8::Arguments &args)
+Value GlobalExtensions::method_qsTranslate(SimpleCallContext *ctx)
{
- if (args.Length() < 2)
- V8THROW_ERROR("qsTranslate() requires at least two arguments");
- if (!args[0]->IsString())
- V8THROW_ERROR("qsTranslate(): first argument (context) must be a string");
- if (!args[1]->IsString())
- V8THROW_ERROR("qsTranslate(): second argument (sourceText) must be a string");
- if ((args.Length() > 2) && !args[2]->IsString())
- V8THROW_ERROR("qsTranslate(): third argument (disambiguation) must be a string");
-
- QV8Engine *v8engine = V8ENGINE();
- QString context = v8engine->toString(args[0]);
- QString text = v8engine->toString(args[1]);
+ if (ctx->argumentCount < 2)
+ V4THROW_ERROR("qsTranslate() requires at least two arguments");
+ if (!ctx->arguments[0].isString())
+ V4THROW_ERROR("qsTranslate(): first argument (context) must be a string");
+ if (!ctx->arguments[1].isString())
+ V4THROW_ERROR("qsTranslate(): second argument (sourceText) must be a string");
+ if ((ctx->argumentCount > 2) && !ctx->arguments[2].isString())
+ V4THROW_ERROR("qsTranslate(): third argument (disambiguation) must be a string");
+
+ QString context = ctx->arguments[0].toQString();
+ QString text = ctx->arguments[1].toQString();
QString comment;
- if (args.Length() > 2) comment = v8engine->toString(args[2]);
+ if (ctx->argumentCount > 2) comment = ctx->arguments[2].toQString();
int i = 3;
- if (args.Length() > i && args[i]->IsString()) {
+ if (ctx->argumentCount > i && ctx->arguments[i].isString()) {
qWarning("qsTranslate(): specifying the encoding as fourth argument is deprecated");
++i;
}
int n = -1;
- if (args.Length() > i)
- n = args[i]->Int32Value();
+ if (ctx->argumentCount > i)
+ n = ctx->arguments[i].toInt32();
QString result = QCoreApplication::translate(context.toUtf8().constData(),
text.toUtf8().constData(),
comment.toUtf8().constData(),
n);
- return v8engine->toString(result);
+ return Value::fromString(ctx, result);
}
/*!
@@ -1403,11 +1671,11 @@ v8::Handle<v8::Value> qsTranslate(const v8::Arguments &args)
\sa {Internationalization and Localization with Qt Quick}
*/
-v8::Handle<v8::Value> qsTranslateNoOp(const v8::Arguments &args)
+Value GlobalExtensions::method_qsTranslateNoOp(SimpleCallContext *ctx)
{
- if (args.Length() < 2)
- return v8::Undefined();
- return args[1];
+ if (ctx->argumentCount < 2)
+ return QV4::Value::undefinedValue();
+ return ctx->arguments[1];
}
/*!
@@ -1427,36 +1695,36 @@ v8::Handle<v8::Value> qsTranslateNoOp(const v8::Arguments &args)
\sa {Internationalization and Localization with Qt Quick}
*/
-v8::Handle<v8::Value> qsTr(const v8::Arguments &args)
+Value GlobalExtensions::method_qsTr(SimpleCallContext *ctx)
{
- if (args.Length() < 1)
- V8THROW_ERROR("qsTr() requires at least one argument");
- if (!args[0]->IsString())
- V8THROW_ERROR("qsTr(): first argument (sourceText) must be a string");
- if ((args.Length() > 1) && !args[1]->IsString())
- V8THROW_ERROR("qsTr(): second argument (disambiguation) must be a string");
- if ((args.Length() > 2) && !args[2]->IsNumber())
- V8THROW_ERROR("qsTr(): third argument (n) must be a number");
-
- QV8Engine *v8engine = V8ENGINE();
+ if (ctx->argumentCount < 1)
+ V4THROW_ERROR("qsTr() requires at least one argument");
+ if (!ctx->arguments[0].isString())
+ V4THROW_ERROR("qsTr(): first argument (sourceText) must be a string");
+ if ((ctx->argumentCount > 1) && !ctx->arguments[1].isString())
+ V4THROW_ERROR("qsTr(): second argument (disambiguation) must be a string");
+ if ((ctx->argumentCount > 2) && !ctx->arguments[2].isNumber())
+ V4THROW_ERROR("qsTr(): third argument (n) must be a number");
+
+ QV8Engine *v8engine = ctx->engine->v8Engine;
QQmlContextData *ctxt = v8engine->callingContext();
QString path = ctxt->url.toString();
int lastSlash = path.lastIndexOf(QLatin1Char('/'));
QString context = (lastSlash > -1) ? path.mid(lastSlash + 1, path.length()-lastSlash-5) : QString();
- QString text = v8engine->toString(args[0]);
+ QString text = ctx->arguments[0].toQString();
QString comment;
- if (args.Length() > 1)
- comment = v8engine->toString(args[1]);
+ if (ctx->argumentCount > 1)
+ comment = ctx->arguments[1].toQString();
int n = -1;
- if (args.Length() > 2)
- n = args[2]->Int32Value();
+ if (ctx->argumentCount > 2)
+ n = ctx->arguments[2].toInt32();
QString result = QCoreApplication::translate(context.toUtf8().constData(), text.toUtf8().constData(),
comment.toUtf8().constData(), n);
- return v8engine->toString(result);
+ return Value::fromString(ctx, result);
}
/*!
@@ -1481,11 +1749,11 @@ v8::Handle<v8::Value> qsTr(const v8::Arguments &args)
\sa {Internationalization and Localization with Qt Quick}
*/
-v8::Handle<v8::Value> qsTrNoOp(const v8::Arguments &args)
+Value GlobalExtensions::method_qsTrNoOp(SimpleCallContext *ctx)
{
- if (args.Length() < 1)
- return v8::Undefined();
- return args[0];
+ if (ctx->argumentCount < 1)
+ return QV4::Value::undefinedValue();
+ return ctx->arguments[0];
}
/*!
@@ -1518,21 +1786,20 @@ v8::Handle<v8::Value> qsTrNoOp(const v8::Arguments &args)
\sa QT_TRID_NOOP, {Internationalization and Localization with Qt Quick}
*/
-v8::Handle<v8::Value> qsTrId(const v8::Arguments &args)
+Value GlobalExtensions::method_qsTrId(SimpleCallContext *ctx)
{
- if (args.Length() < 1)
- V8THROW_ERROR("qsTrId() requires at least one argument");
- if (!args[0]->IsString())
- V8THROW_TYPE("qsTrId(): first argument (id) must be a string");
- if (args.Length() > 1 && !args[1]->IsNumber())
- V8THROW_TYPE("qsTrId(): second argument (n) must be a number");
+ if (ctx->argumentCount < 1)
+ V4THROW_ERROR("qsTrId() requires at least one argument");
+ if (!ctx->arguments[0].isString())
+ V4THROW_TYPE("qsTrId(): first argument (id) must be a string");
+ if (ctx->argumentCount > 1 && !ctx->arguments[1].isNumber())
+ V4THROW_TYPE("qsTrId(): second argument (n) must be a number");
int n = -1;
- if (args.Length() > 1)
- n = args[1]->Int32Value();
+ if (ctx->argumentCount > 1)
+ n = ctx->arguments[1].toInt32();
- QV8Engine *v8engine = V8ENGINE();
- return v8engine->toString(qtTrId(v8engine->toString(args[0]).toUtf8().constData(), n));
+ return Value::fromString(ctx, qtTrId(ctx->arguments[0].toQString().toUtf8().constData(), n));
}
/*!
@@ -1551,108 +1818,41 @@ v8::Handle<v8::Value> qsTrId(const v8::Arguments &args)
\sa qsTrId(), {Internationalization and Localization with Qt Quick}
*/
-v8::Handle<v8::Value> qsTrIdNoOp(const v8::Arguments &args)
+Value GlobalExtensions::method_qsTrIdNoOp(SimpleCallContext *ctx)
{
- if (args.Length() < 1)
- return v8::Undefined();
- return args[0];
+ if (ctx->argumentCount < 1)
+ return QV4::Value::undefinedValue();
+ return ctx->arguments[0];
}
#endif // QT_NO_TRANSLATION
-/*!
- \qmlmethod Qt::locale(name)
- Returns a JS object representing the locale with the specified
- name, which has the format "language[_territory][.codeset][@modifier]"
- or "C", where:
-
- \list
- \li language is a lowercase, two-letter, ISO 639 language code,
- \li territory is an uppercase, two-letter, ISO 3166 country code,
- \li and codeset and modifier are ignored.
- \endlist
-
- If the string violates the locale format, or language is not a
- valid ISO 369 code, the "C" locale is used instead. If country
- is not present, or is not a valid ISO 3166 code, the most
- appropriate country is chosen for the specified language.
-
- \sa QtQuick2::Locale
-*/
-v8::Handle<v8::Value> locale(const v8::Arguments &args)
+QV4::Value GlobalExtensions::method_gc(SimpleCallContext *ctx)
{
- QString code;
- if (args.Length() > 1)
- V8THROW_ERROR("locale() requires 0 or 1 argument");
- if (args.Length() == 1 && !args[0]->IsString())
- V8THROW_TYPE("locale(): argument (locale code) must be a string");
-
- QV8Engine *v8engine = V8ENGINE();
- if (args.Length() == 1)
- code = v8engine->toString(args[0]);
+ ctx->engine->memoryManager->runGC();
- return QQmlLocale::locale(v8engine, code);
+ return QV4::Value::undefinedValue();
}
-/*!
- \qmlmethod Qt::binding(function)
-
- Returns a JS object representing a binding expression which may be
- assigned to any property in imperative code to cause a binding
- assignment.
- There are two main use-cases for the function: firstly, in imperative
- JavaScript code to cause a binding assignment:
- \snippet qml/qtBinding.1.qml 0
-
- and secondly, when defining initial property values of dynamically
- constructed objects (via Component.createObject() or
- Loader.setSource()) as being bound to the result of an expression.
-
- For example, assuming the existence of a DynamicText component:
- \snippet qml/DynamicText.qml 0
-
- the output from:
- \snippet qml/qtBinding.2.qml 0
-
- and from:
- \snippet qml/qtBinding.3.qml 0
-
- should both be:
- \code
- Root text extra text
- Modified root text extra text
- Dynamic text extra text
- Modified dynamic text extra text
- \endcode
-
- This function cannot be used in property binding declarations
- (see the documentation on \l{qml-javascript-assignment}{binding
- declarations and binding assignments}) except when the result is
- stored in an array bound to a var property.
-
- \snippet qml/qtBinding.4.qml 0
-
- \note In \l {Qt Quick 1}, all function assignment was treated as
- binding assignment, so the Qt.binding() function is new in
- \l {Qt Quick}{Qt Quick 2}.
-
- \since QtQuick 2.0
-*/
-v8::Handle<v8::Value> binding(const v8::Arguments &args)
+Value GlobalExtensions::string_arg(SimpleCallContext *ctx)
{
- QString code;
- if (args.Length() != 1)
- V8THROW_ERROR("binding() requires 1 argument");
- if (!args[0]->IsFunction())
- V8THROW_TYPE("binding(): argument (binding expression) must be a function");
-
- v8::Handle<v8::Object> rv = args[0]->ToObject()->Clone();
- rv->SetHiddenValue(V8ENGINE()->bindingFlagKey(), v8::Boolean::New(true));
- return rv;
+ QString value = ctx->thisObject.toQString();
+ if (ctx->argumentCount != 1)
+ V4THROW_ERROR("String.arg(): Invalid arguments");
+
+ QV4::Value arg = ctx->arguments[0];
+ if (arg.isInteger())
+ return Value::fromString(ctx, value.arg(arg.integerValue()));
+ else if (arg.isDouble())
+ return Value::fromString(ctx, value.arg(arg.doubleValue()));
+ else if (arg.isBoolean())
+ return Value::fromString(ctx, value.arg(arg.booleanValue()));
+
+ return Value::fromString(ctx, value.arg(arg.toQString()));
}
-} // namespace QQmlBuiltinFunctions
QT_END_NAMESPACE
+
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
index f73802b136..d03605f48a 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions_p.h
@@ -54,63 +54,98 @@
//
#include <QtCore/qglobal.h>
-#include <private/qv8_p.h>
+#include <private/qv4object_p.h>
QT_BEGIN_NAMESPACE
-namespace QQmlBuiltinFunctions
+class QQmlEngine;
+class QV8Engine;
+
+namespace QV4 {
+
+struct QtObject : Object
+{
+ Q_MANAGED
+ QtObject(ExecutionEngine *v4, QQmlEngine *qmlEngine);
+
+ static Value method_isQtObject(SimpleCallContext *ctx);
+ static Value method_rgba(SimpleCallContext *ctx);
+ static Value method_hsla(SimpleCallContext *ctx);
+ static Value method_colorEqual(SimpleCallContext *ctx);
+ static Value method_font(SimpleCallContext *ctx);
+ static Value method_rect(SimpleCallContext *ctx);
+ static Value method_point(SimpleCallContext *ctx);
+ static Value method_size(SimpleCallContext *ctx);
+ static Value method_vector2d(SimpleCallContext *ctx);
+ static Value method_vector3d(SimpleCallContext *ctx);
+ static Value method_vector4d(SimpleCallContext *ctx);
+ static Value method_quaternion(SimpleCallContext *ctx);
+ static Value method_matrix4x4(SimpleCallContext *ctx);
+ static Value method_lighter(SimpleCallContext *ctx);
+ static Value method_darker(SimpleCallContext *ctx);
+ static Value method_tint(SimpleCallContext *ctx);
+ static Value method_formatDate(SimpleCallContext *ctx);
+ static Value method_formatTime(SimpleCallContext *ctx);
+ static Value method_formatDateTime(SimpleCallContext *ctx);
+ static Value method_openUrlExternally(SimpleCallContext *ctx);
+ static Value method_fontFamilies(SimpleCallContext *ctx);
+ static Value method_md5(SimpleCallContext *ctx);
+ static Value method_btoa(SimpleCallContext *ctx);
+ static Value method_atob(SimpleCallContext *ctx);
+ static Value method_quit(SimpleCallContext *ctx);
+ static Value method_resolvedUrl(SimpleCallContext *ctx);
+ static Value method_createQmlObject(SimpleCallContext *ctx);
+ static Value method_createComponent(SimpleCallContext *ctx);
+ static Value method_locale(SimpleCallContext *ctx);
+ static Value method_binding(SimpleCallContext *ctx);
+
+ static Value method_get_platform(SimpleCallContext *ctx);
+ static Value method_get_application(SimpleCallContext *ctx);
+#ifndef QT_NO_IM
+ static Value method_get_inputMethod(SimpleCallContext *ctx);
+#endif
+
+ QObject *m_platform;
+ QObject *m_application;
+};
+
+struct ConsoleObject : Object
{
-v8::Handle<v8::Value> gc(const v8::Arguments &args);
-v8::Handle<v8::Value> consoleError(const v8::Arguments &args);
-v8::Handle<v8::Value> consoleLog(const v8::Arguments &args);
-v8::Handle<v8::Value> consoleProfile(const v8::Arguments &args);
-v8::Handle<v8::Value> consoleProfileEnd(const v8::Arguments &args);
-v8::Handle<v8::Value> consoleTime(const v8::Arguments &args);
-v8::Handle<v8::Value> consoleTimeEnd(const v8::Arguments &args);
-v8::Handle<v8::Value> consoleCount(const v8::Arguments &args);
-v8::Handle<v8::Value> consoleTrace(const v8::Arguments &args);
-v8::Handle<v8::Value> consoleWarn(const v8::Arguments &args);
-v8::Handle<v8::Value> consoleAssert(const v8::Arguments &args);
-v8::Handle<v8::Value> consoleException(const v8::Arguments &args);
-v8::Handle<v8::Value> isQtObject(const v8::Arguments &args);
-v8::Handle<v8::Value> rgba(const v8::Arguments &args);
-v8::Handle<v8::Value> hsla(const v8::Arguments &args);
-v8::Handle<v8::Value> colorEqual(const v8::Arguments &args);
-v8::Handle<v8::Value> font(const v8::Arguments &args);
-v8::Handle<v8::Value> rect(const v8::Arguments &args);
-v8::Handle<v8::Value> point(const v8::Arguments &args);
-v8::Handle<v8::Value> size(const v8::Arguments &args);
-v8::Handle<v8::Value> vector2d(const v8::Arguments &args);
-v8::Handle<v8::Value> vector3d(const v8::Arguments &args);
-v8::Handle<v8::Value> vector4d(const v8::Arguments &args);
-v8::Handle<v8::Value> quaternion(const v8::Arguments &args);
-v8::Handle<v8::Value> matrix4x4(const v8::Arguments &args);
-v8::Handle<v8::Value> lighter(const v8::Arguments &args);
-v8::Handle<v8::Value> darker(const v8::Arguments &args);
-v8::Handle<v8::Value> tint(const v8::Arguments &args);
-v8::Handle<v8::Value> formatDate(const v8::Arguments &args);
-v8::Handle<v8::Value> formatTime(const v8::Arguments &args);
-v8::Handle<v8::Value> formatDateTime(const v8::Arguments &args);
-v8::Handle<v8::Value> openUrlExternally(const v8::Arguments &args);
-v8::Handle<v8::Value> fontFamilies(const v8::Arguments &args);
-v8::Handle<v8::Value> md5(const v8::Arguments &args);
-v8::Handle<v8::Value> btoa(const v8::Arguments &args);
-v8::Handle<v8::Value> atob(const v8::Arguments &args);
-v8::Handle<v8::Value> quit(const v8::Arguments &args);
-v8::Handle<v8::Value> resolvedUrl(const v8::Arguments &args);
-v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args);
-v8::Handle<v8::Value> createComponent(const v8::Arguments &args);
+ ConsoleObject(ExecutionEngine *v4);
+
+ static Value method_error(SimpleCallContext *ctx);
+ static Value method_log(SimpleCallContext *ctx);
+ static Value method_profile(SimpleCallContext *ctx);
+ static Value method_profileEnd(SimpleCallContext *ctx);
+ static Value method_time(SimpleCallContext *ctx);
+ static Value method_timeEnd(SimpleCallContext *ctx);
+ static Value method_count(SimpleCallContext *ctx);
+ static Value method_trace(SimpleCallContext *ctx);
+ static Value method_warn(SimpleCallContext *ctx);
+ static Value method_assert(SimpleCallContext *ctx);
+ static Value method_exception(SimpleCallContext *ctx);
+
+};
+
+struct GlobalExtensions {
+ static void init(QQmlEngine *qmlEngine, Object *globalObject);
+
#ifndef QT_NO_TRANSLATION
-v8::Handle<v8::Value> qsTranslate(const v8::Arguments &args);
-v8::Handle<v8::Value> qsTranslateNoOp(const v8::Arguments &args);
-v8::Handle<v8::Value> qsTr(const v8::Arguments &args);
-v8::Handle<v8::Value> qsTrNoOp(const v8::Arguments &args);
-v8::Handle<v8::Value> qsTrId(const v8::Arguments &args);
-v8::Handle<v8::Value> qsTrIdNoOp(const v8::Arguments &args);
+ static Value method_qsTranslate(SimpleCallContext *ctx);
+ static Value method_qsTranslateNoOp(SimpleCallContext *ctx);
+ static Value method_qsTr(SimpleCallContext *ctx);
+ static Value method_qsTrNoOp(SimpleCallContext *ctx);
+ static Value method_qsTrId(SimpleCallContext *ctx);
+ static Value method_qsTrIdNoOp(SimpleCallContext *ctx);
#endif
-v8::Handle<v8::Value> stringArg(const v8::Arguments &args);
-v8::Handle<v8::Value> locale(const v8::Arguments &args);
-v8::Handle<v8::Value> binding(const v8::Arguments &args);
+ static Value method_gc(SimpleCallContext *ctx);
+
+ // on String:prototype
+ static Value string_arg(SimpleCallContext *ctx);
+
+};
+
+
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qscriptoriginalglobalobject_p.h b/src/qml/qml/v8/qscriptoriginalglobalobject_p.h
deleted file mode 100644
index 2ecdbdac91..0000000000
--- a/src/qml/qml/v8/qscriptoriginalglobalobject_p.h
+++ /dev/null
@@ -1,177 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QSCRIPTORIGINALGLOBALOBJECT_P_H
-#define QSCRIPTORIGINALGLOBALOBJECT_P_H
-
-#include "QtCore/qglobal.h"
-#include "qjsvalue_p.h"
-
-#include <private/qv8_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QV8Engine;
-
-/*!
- \internal
- This class is a workaround for missing V8 API functionality. This class keeps all important
- properties of an original (default) global object, so we can use it even if the global object was
- changed.
-
- FIXME this class is a container for workarounds :-) it should be replaced by proper API calls.
-
- The class have to be created on the QV8Engine creation time (before any change got applied to
- global object).
-
- \attention All methods (apart from constructor) assumes that a context and a scope are prepared correctly.
-*/
-class QScriptOriginalGlobalObject
-{
-public:
- inline QScriptOriginalGlobalObject() {}
- inline void init(v8::Handle<v8::Context> context);
- inline void destroy();
-
- inline QJSValuePrivate::PropertyFlags getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property);
- inline v8::Local<v8::Object> getOwnPropertyDescriptor(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property) const;
- inline bool strictlyEquals(v8::Handle<v8::Object> object);
-private:
- Q_DISABLE_COPY(QScriptOriginalGlobalObject)
-
- // Copy of constructors and prototypes used in isType functions.
- v8::Persistent<v8::Function> m_ownPropertyDescriptor;
- v8::Persistent<v8::Object> m_globalObject;
-};
-
-void QScriptOriginalGlobalObject::init(v8::Handle<v8::Context> context)
-{
- // Please notice that engine is not fully initialized at this point.
-
- v8::Context::Scope contextScope(context);
-
- v8::HandleScope scope;
-
- m_globalObject = v8::Persistent<v8::Object>::New(context->Global());
-
- v8::Local<v8::Object> objectConstructor = m_globalObject->Get(v8::String::New("Object"))->ToObject();
- Q_ASSERT(objectConstructor->IsObject());
- { // Initialize m_ownPropertyDescriptor.
- v8::Local<v8::Value> ownPropertyDescriptor = objectConstructor->Get(v8::String::New("getOwnPropertyDescriptor"));
- Q_ASSERT(!ownPropertyDescriptor.IsEmpty());
- m_ownPropertyDescriptor = v8::Persistent<v8::Function>::New(v8::Local<v8::Function>::Cast(ownPropertyDescriptor));
- }
-}
-
-/*!
- \internal
- QScriptOriginalGlobalObject lives as long as QV8Engine that keeps it. In ~QSEP
- the v8 context is removed, so we need to remove our handlers before. to break this dependency
- destroy method should be called before or insight QSEP destructor.
-*/
-inline void QScriptOriginalGlobalObject::destroy()
-{
- m_ownPropertyDescriptor.Dispose();
- m_globalObject.Dispose();
- // After this line this instance is unusable.
-}
-
-inline QJSValuePrivate::PropertyFlags QScriptOriginalGlobalObject::getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property)
-{
- Q_ASSERT(object->IsObject());
- Q_ASSERT(!property.IsEmpty());
- v8::Local<v8::Object> descriptor = getOwnPropertyDescriptor(object, property);
- if (descriptor.IsEmpty()) {
-// // Property isn't owned by this object.
-// if (!(mode & QScriptValue::ResolvePrototype))
-// return 0;
- v8::Local<v8::Value> prototype = object->GetPrototype();
- if (prototype->IsNull())
- return 0;
- return getPropertyFlags(v8::Local<v8::Object>::Cast(prototype), property);
- }
- v8::Local<v8::String> writableName = v8::String::New("writable");
- v8::Local<v8::String> configurableName = v8::String::New("configurable");
- v8::Local<v8::String> enumerableName = v8::String::New("enumerable");
-// v8::Local<v8::String> getName = v8::String::New("get");
-// v8::Local<v8::String> setName = v8::String::New("set");
-
- unsigned flags = 0;
-
- if (!descriptor->Get(configurableName)->BooleanValue())
- flags |= QJSValuePrivate::Undeletable;
- if (!descriptor->Get(enumerableName)->BooleanValue())
- flags |= QJSValuePrivate::SkipInEnumeration;
-
- //"writable" is only a property of the descriptor if it is not an accessor
- if (descriptor->Has(writableName)) {
- if (!descriptor->Get(writableName)->BooleanValue())
- flags |= QJSValuePrivate::ReadOnly;
- } else {
-// if (descriptor->Get(getName)->IsObject())
-// flags |= QScriptValue::PropertyGetter;
-// if (descriptor->Get(setName)->IsObject())
-// flags |= QScriptValue::PropertySetter;
- }
-
- return QJSValuePrivate::PropertyFlag(flags);
-}
-
-inline v8::Local<v8::Object> QScriptOriginalGlobalObject::getOwnPropertyDescriptor(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property) const
-{
- Q_ASSERT(object->IsObject());
- Q_ASSERT(!property.IsEmpty());
- // FIXME do we need try catch here?
- v8::Handle<v8::Value> argv[] = {object, property};
- v8::Local<v8::Value> descriptor = m_ownPropertyDescriptor->Call(m_globalObject, /* argc */ 2, argv);
- if (descriptor.IsEmpty() || !descriptor->IsObject())
- return v8::Local<v8::Object>();
- return v8::Local<v8::Object>::Cast(descriptor);
-}
-
-inline bool QScriptOriginalGlobalObject::strictlyEquals(v8::Handle<v8::Object> object)
-{
- return m_globalObject->GetPrototype()->StrictEquals(object);
-}
-
-QT_END_NAMESPACE
-
-#endif
diff --git a/src/qml/qml/v8/qscriptshareddata_p.h b/src/qml/qml/v8/qscriptshareddata_p.h
deleted file mode 100644
index 70289cba46..0000000000
--- a/src/qml/qml/v8/qscriptshareddata_p.h
+++ /dev/null
@@ -1,169 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-//
-// 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.
-//
-
-#ifndef QSCRIPTSHAREDDATA_P_H
-#define QSCRIPTSHAREDDATA_P_H
-
-#include "qglobal.h"
-#include "qshareddata.h"
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \internal
- This class should have the same interface as the QSharedData, but implementation doesn't
- need to be thread safe, so atomic ref count was replaced by normal integer value.
-*/
-class QScriptSharedData
-{
-public:
- class ReferenceCounter {
- // FIXME shouldn't it be uint or something longer?
- mutable int m_ref;
- ReferenceCounter(int ref) : m_ref(ref) {}
- ~ReferenceCounter() { Q_ASSERT_X(!m_ref, Q_FUNC_INFO, "Memory problem found"); }
- public:
- bool ref() { return ++m_ref; }
- bool deref() { return --m_ref; }
- friend class QScriptSharedData;
- };
-
- ReferenceCounter ref;
- inline QScriptSharedData() : ref(0) { }
-
-private:
- Q_DISABLE_COPY(QScriptSharedData)
-};
-
-
-template <class T> class QScriptPassPointer;
-
-// FIXME: that could be reimplemented to not check for a null value.
-template<class T>
-class QScriptSharedDataPointer : public QExplicitlySharedDataPointer<T>
-{
-public:
- inline QScriptSharedDataPointer() {}
- explicit QScriptSharedDataPointer(QScriptPassPointer<T> data) : QExplicitlySharedDataPointer<T>(data.give()) {}
- explicit QScriptSharedDataPointer(T *data) : QExplicitlySharedDataPointer<T>(data) {}
-
- inline QScriptSharedDataPointer<T> &operator=(const QScriptPassPointer<T> &other)
- {
- this->QExplicitlySharedDataPointer<T>::operator =(other.give());
- return *this;
- }
- inline QScriptSharedDataPointer<T> &operator=(T *other)
- {
- this->QExplicitlySharedDataPointer<T>::operator =(other);
- return *this;
- }
-};
-
-// FIXME: that could be reimplemented to not check for a null value.
-template <class T>
-class QScriptPassPointer {
-public:
- QScriptPassPointer(T *data) : m_ptr(data) {}
- inline QScriptPassPointer() { m_ptr = 0; }
- inline QScriptPassPointer(const QScriptPassPointer<T> &other) : m_ptr(other.give()) {}
- inline ~QScriptPassPointer() { Q_ASSERT_X(!m_ptr, Q_FUNC_INFO, "Ownership of the QScriptPassPointer hasn't been taken"); }
-
- inline T &operator*() const { return *m_ptr; }
- inline T *operator->() { return m_ptr; }
- inline T *operator->() const { return m_ptr; }
- inline T *data() const { return m_ptr; }
- inline const T *constData() const { return m_ptr; }
-
- inline bool operator==(const QScriptPassPointer<T> &other) const { return m_ptr == other.m_ptr; }
- inline bool operator!=(const QScriptPassPointer<T> &other) const { return m_ptr != other.m_ptr; }
- inline bool operator==(const QScriptSharedDataPointer<T> &other) const { return m_ptr == other.m_ptr; }
- inline bool operator!=(const QScriptSharedDataPointer<T> &other) const { return m_ptr != other.m_ptr; }
- inline bool operator==(const T *ptr) const { return m_ptr == ptr; }
- inline bool operator!=(const T *ptr) const { return m_ptr != ptr; }
-
- inline operator bool () const { return m_ptr != 0; }
- inline bool operator!() const { return !m_ptr; }
-
- inline QScriptPassPointer<T> & operator=(const QScriptPassPointer<T> &other)
- {
- if (other.m_ptr != m_ptr) {
- if (m_ptr)
- delete m_ptr;
- m_ptr = other.give();
- }
- return *this;
- }
-
- inline QScriptPassPointer &operator=(T *other)
- {
- if (other != m_ptr) {
- if (m_ptr)
- delete m_ptr;
- m_ptr = other;
- }
- return *this;
- }
-
- inline T* give() const
- {
- T* result = m_ptr;
- m_ptr = 0;
- return result;
- }
-
-private:
- mutable T* m_ptr;
-};
-
-QT_END_NAMESPACE
-
-#endif // QSCRIPTSHAREDDATA_P_H
diff --git a/src/qml/qml/v8/qv4domerrors.cpp b/src/qml/qml/v8/qv4domerrors.cpp
new file mode 100644
index 0000000000..63c79f85c2
--- /dev/null
+++ b/src/qml/qml/v8/qv4domerrors.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4domerrors_p.h"
+#include "qv4object_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+void qt_add_domexceptions(ExecutionEngine *e)
+{
+ Object *domexception = e->newObject();
+ domexception->defineReadonlyProperty(e, QStringLiteral("INDEX_SIZE_ERR"), Value::fromInt32(DOMEXCEPTION_INDEX_SIZE_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("DOMSTRING_SIZE_ERR"), Value::fromInt32(DOMEXCEPTION_DOMSTRING_SIZE_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("HIERARCHY_REQUEST_ERR"), Value::fromInt32(DOMEXCEPTION_HIERARCHY_REQUEST_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("WRONG_DOCUMENT_ERR"), Value::fromInt32(DOMEXCEPTION_WRONG_DOCUMENT_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("INVALID_CHARACTER_ERR"), Value::fromInt32(DOMEXCEPTION_INVALID_CHARACTER_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("NO_DATA_ALLOWED_ERR"), Value::fromInt32(DOMEXCEPTION_NO_DATA_ALLOWED_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("NO_MODIFICATION_ALLOWED_ERR"), Value::fromInt32(DOMEXCEPTION_NO_MODIFICATION_ALLOWED_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("NOT_FOUND_ERR"), Value::fromInt32(DOMEXCEPTION_NOT_FOUND_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("NOT_SUPPORTED_ERR"), Value::fromInt32(DOMEXCEPTION_NOT_SUPPORTED_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("INUSE_ATTRIBUTE_ERR"), Value::fromInt32(DOMEXCEPTION_INUSE_ATTRIBUTE_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("INVALID_STATE_ERR"), Value::fromInt32(DOMEXCEPTION_INVALID_STATE_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("SYNTAX_ERR"), Value::fromInt32(DOMEXCEPTION_SYNTAX_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("INVALID_MODIFICATION_ERR"), Value::fromInt32(DOMEXCEPTION_INVALID_MODIFICATION_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("NAMESPACE_ERR"), Value::fromInt32(DOMEXCEPTION_NAMESPACE_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("INVALID_ACCESS_ERR"), Value::fromInt32(DOMEXCEPTION_INVALID_ACCESS_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("VALIDATION_ERR"), Value::fromInt32(DOMEXCEPTION_VALIDATION_ERR));
+ domexception->defineReadonlyProperty(e, QStringLiteral("TYPE_MISMATCH_ERR"), Value::fromInt32(DOMEXCEPTION_TYPE_MISMATCH_ERR));
+ e->globalObject->defineDefaultProperty(e->current, QStringLiteral("DOMException"), Value::fromObject(domexception));
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8domerrors_p.h b/src/qml/qml/v8/qv4domerrors_p.h
index 8fd1ccb6d6..ed38886e15 100644
--- a/src/qml/qml/v8/qv8domerrors_p.h
+++ b/src/qml/qml/v8/qv4domerrors_p.h
@@ -76,14 +76,19 @@ QT_BEGIN_NAMESPACE
#define DOMEXCEPTION_VALIDATION_ERR 16
#define DOMEXCEPTION_TYPE_MISMATCH_ERR 17
-#define V8THROW_DOM(error, string) { \
- v8::Local<v8::Value> v = v8::Exception::Error(v8::String::New(string)); \
- v->ToObject()->Set(v8::String::New("code"), v8::Integer::New(error)); \
- v8::ThrowException(v); \
- return v8::Handle<v8::Value>(); \
+#define V4THROW_DOM(error, string) { \
+ QV4::Value v = QV4::Value::fromString(ctx, QStringLiteral(string)); \
+ QV4::Object *ex = ctx->engine->newErrorObject(v); \
+ ex->put(ctx->engine->newIdentifier(QStringLiteral("code")), QV4::Value::fromInt32(error)); \
+ ctx->throwError(QV4::Value::fromObject(ex)); \
}
-class QV8Engine;
-void qt_add_domexceptions(QV8Engine *engine);
+
+namespace QV4 {
+struct ExecutionEngine;
+}
+
+
+void qt_add_domexceptions(QV4::ExecutionEngine *e);
QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv4sqlerrors.cpp b/src/qml/qml/v8/qv4sqlerrors.cpp
new file mode 100644
index 0000000000..bd5a9fdc83
--- /dev/null
+++ b/src/qml/qml/v8/qv4sqlerrors.cpp
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qv4sqlerrors_p.h"
+#include "private/qv4engine_p.h"
+#include "private/qv4object_p.h"
+
+QT_BEGIN_NAMESPACE
+
+using namespace QV4;
+
+void qt_add_sqlexceptions(QV4::ExecutionEngine *engine)
+{
+ Object *sqlexception = engine->newObject();
+ sqlexception->defineReadonlyProperty(engine, QStringLiteral("UNKNOWN_ERR"), Value::fromInt32(SQLEXCEPTION_UNKNOWN_ERR));
+ sqlexception->defineReadonlyProperty(engine, QStringLiteral("DATABASE_ERR"), Value::fromInt32(SQLEXCEPTION_DATABASE_ERR));
+ sqlexception->defineReadonlyProperty(engine, QStringLiteral("VERSION_ERR"), Value::fromInt32(SQLEXCEPTION_VERSION_ERR));
+ sqlexception->defineReadonlyProperty(engine, QStringLiteral("TOO_LARGE_ERR"), Value::fromInt32(SQLEXCEPTION_TOO_LARGE_ERR));
+ sqlexception->defineReadonlyProperty(engine, QStringLiteral("QUOTA_ERR"), Value::fromInt32(SQLEXCEPTION_QUOTA_ERR));
+ sqlexception->defineReadonlyProperty(engine, QStringLiteral("SYNTAX_ERR"), Value::fromInt32(SQLEXCEPTION_SYNTAX_ERR));
+ sqlexception->defineReadonlyProperty(engine, QStringLiteral("CONSTRAINT_ERR"), Value::fromInt32(SQLEXCEPTION_CONSTRAINT_ERR));
+ sqlexception->defineReadonlyProperty(engine, QStringLiteral("TIMEOUT_ERR"), Value::fromInt32(SQLEXCEPTION_TIMEOUT_ERR));
+ engine->globalObject->defineDefaultProperty(engine->current, QStringLiteral("SQLException"), Value::fromObject(sqlexception));
+}
+
+QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8sqlerrors_p.h b/src/qml/qml/v8/qv4sqlerrors_p.h
index 8a612d69ab..0433d534f9 100644
--- a/src/qml/qml/v8/qv8sqlerrors_p.h
+++ b/src/qml/qml/v8/qv4sqlerrors_p.h
@@ -65,8 +65,11 @@ QT_BEGIN_NAMESPACE
#define SQLEXCEPTION_CONSTRAINT_ERR 7
#define SQLEXCEPTION_TIMEOUT_ERR 8
-class QV8Engine;
-void qt_add_sqlexceptions(QV8Engine *engine);
+namespace QV4 {
+struct ExecutionEngine;
+}
+
+void qt_add_sqlexceptions(QV4::ExecutionEngine *engine);
QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8bindings.cpp b/src/qml/qml/v8/qv8bindings.cpp
deleted file mode 100644
index 757d9d9cf6..0000000000
--- a/src/qml/qml/v8/qv8bindings.cpp
+++ /dev/null
@@ -1,334 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv8bindings_p.h"
-
-#include <private/qv8_p.h>
-#include <private/qqmlbinding_p.h>
-#include <private/qqmlcompiler_p.h>
-#include <private/qqmlproperty_p.h>
-#include <private/qqmlexpression_p.h>
-#include <private/qobject_p.h>
-#include <private/qqmltrace_p.h>
-#include <private/qqmlprofilerservice_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QQmlAbstractBinding::VTable QV8Bindings_Binding_vtable = {
- QV8Bindings::Binding::destroy,
- QQmlAbstractBinding::default_expression,
- QV8Bindings::Binding::propertyIndex,
- QV8Bindings::Binding::object,
- QV8Bindings::Binding::setEnabled,
- QV8Bindings::Binding::update,
- QV8Bindings::Binding::retargetBinding
-};
-
-static QQmlJavaScriptExpression::VTable QV8Bindings_Binding_jsvtable = {
- QV8Bindings::Binding::expressionIdentifier,
- QV8Bindings::Binding::expressionChanged
-};
-
-QV8Bindings::Binding::Binding()
-: QQmlJavaScriptExpression(&QV8Bindings_Binding_jsvtable), QQmlAbstractBinding(V8), parent(0)
-{
-}
-
-void QV8Bindings::Binding::setEnabled(QQmlAbstractBinding *_This, bool e,
- QQmlPropertyPrivate::WriteFlags flags)
-{
- QV8Bindings::Binding *This = static_cast<QV8Bindings::Binding *>(_This);
-
- if (This->enabledFlag() != e) {
- This->setEnabledFlag(e);
-
- if (e) This->update(flags);
- }
-}
-
-void QV8Bindings::refresh()
-{
- int count = functions()->Length();
- for (int ii = 0; ii < count; ++ii)
- bindings[ii].refresh();
-}
-
-void QV8Bindings::Binding::refresh()
-{
- update();
-}
-
-int QV8Bindings::Binding::propertyIndex(const QQmlAbstractBinding *_This)
-{
- const QV8Bindings::Binding *This = static_cast<const QV8Bindings::Binding *>(_This);
- if (This->target.hasValue()) return This->target.constValue()->targetProperty;
- else return This->instruction->property.encodedIndex();
-}
-
-QObject *QV8Bindings::Binding::object(const QQmlAbstractBinding *_This)
-{
- const QV8Bindings::Binding *This = static_cast<const QV8Bindings::Binding *>(_This);
-
- if (This->target.hasValue()) return This->target.constValue()->target;
- else return *This->target;
-}
-
-QObject *QV8Bindings::Binding::object() const
-{
- if (target.hasValue()) return target.constValue()->target;
- else return *target;
-}
-
-void QV8Bindings::Binding::retargetBinding(QQmlAbstractBinding *_This, QObject *t, int i)
-{
- QV8Bindings::Binding *This = static_cast<QV8Bindings::Binding *>(_This);
-
- This->target.value().target = t;
- This->target.value().targetProperty = i;
-}
-
-void QV8Bindings::Binding::update(QQmlAbstractBinding *_This, QQmlPropertyPrivate::WriteFlags flags)
-{
- QV8Bindings::Binding *This = static_cast<QV8Bindings::Binding *>(_This);
- This->update(flags);
-}
-
-void QV8Bindings::Binding::dump()
-{
- qWarning() << parent->url() << instruction->line << instruction->column;
-}
-
-void QV8Bindings::Binding::update(QQmlPropertyPrivate::WriteFlags flags)
-{
- if (!enabledFlag())
- return;
-
- QQmlContextData *context = parent->context();
-
- if (!context || !context->isValid())
- return;
-
- // Check that the target has not been deleted
- if (QQmlData::wasDeleted(object()))
- return;
-
- int lineNo = qmlSourceCoordinate(instruction->line);
- int columnNo = qmlSourceCoordinate(instruction->column);
-
- QQmlTrace trace("V8 Binding Update");
- trace.addDetail("URL", parent->url());
- trace.addDetail("Line", lineNo);
- trace.addDetail("Column", columnNo);
-
- QQmlBindingProfiler prof(parent->urlString(), lineNo, columnNo, QQmlProfilerService::V8Binding);
-
- if (!updatingFlag()) {
- setUpdatingFlag(true);
-
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(context->engine);
-
- bool isUndefined = false;
-
- DeleteWatcher watcher(this);
- ep->referenceScarceResources();
-
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(ep->v8engine()->context());
- v8::Local<v8::Value> result =
- evaluate(context,
- v8::Handle<v8::Function>::Cast(parent->functions()->Get(instruction->value)),
- &isUndefined);
-
- trace.event("writing V8 result");
- bool needsErrorLocationData = false;
- if (!watcher.wasDeleted() && !destroyedFlag() && !hasError()) {
- typedef QQmlPropertyPrivate PP;
- needsErrorLocationData = !PP::writeBinding(*target, instruction->property, context, this, result,
- isUndefined, flags);
- }
-
- if (!watcher.wasDeleted() && !destroyedFlag()) {
-
- if (needsErrorLocationData)
- delayedError()->setErrorLocation(parent->url(), instruction->line, 0);
-
- if (hasError()) {
- delayedError()->setErrorObject(object());
- if (!delayedError()->addError(ep)) ep->warning(this->error(context->engine));
- } else {
- clearError();
- }
-
- setUpdatingFlag(false);
- }
-
- ep->dereferenceScarceResources();
-
- } else {
- QQmlProperty p = QQmlPropertyPrivate::restore(*target, instruction->property, context);
- QQmlAbstractBinding::printBindingLoopError(p);
- }
-}
-
-QString QV8Bindings::Binding::expressionIdentifier(QQmlJavaScriptExpression *e)
-{
- Binding *This = static_cast<Binding *>(e);
- return This->parent->urlString() + QLatin1Char(':') +
- QString::number(qmlSourceCoordinate(This->instruction->line));
-}
-
-void QV8Bindings::Binding::expressionChanged(QQmlJavaScriptExpression *e)
-{
- Binding *This = static_cast<Binding *>(e);
- This->update(QQmlPropertyPrivate::DontRemoveBinding);
-}
-
-void QV8Bindings::Binding::destroy(QQmlAbstractBinding *_This, QQmlAbstractBinding::DestroyMode mode)
-{
- QV8Bindings::Binding *This = static_cast<QV8Bindings::Binding *>(_This);
-
- if (mode == QQmlAbstractBinding::DisconnectBinding)
- This->clearGuards();
-
- This->setEnabledFlag(false);
- This->setDestroyedFlag(true);
- This->removeFromObject();
- This->clear();
- This->clearError();
- This->parent->release();
-}
-
-QV8Bindings::QV8Bindings(QQmlCompiledData::V8Program *program,
- quint16 line,
- QQmlContextData *context)
-: program(program), bindings(0), refCount(1)
-{
- QV8Engine *engine = QQmlEnginePrivate::getV8Engine(context->engine);
-
- if (program->bindings.IsEmpty()) {
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(engine->context());
-
- v8::Local<v8::Script> script;
- bool compileFailed = false;
- {
- v8::TryCatch try_catch;
- const QByteArray &source = program->program;
- script = engine->qmlModeCompile(source.constData(), source.length(),
- program->cdata->name, line);
- if (try_catch.HasCaught()) {
- // The binding was not compiled. There are some exceptional cases which the
- // expression rewriter does not rewrite properly (e.g., \r-terminated lines
- // are not rewritten correctly but this bug is demed out-of-scope to fix for
- // performance reasons; see QTBUG-24064).
- compileFailed = true;
- QQmlError error;
- error.setDescription(QString(QLatin1String("Exception occurred during compilation of binding at line: %1")).arg(line));
- v8::Local<v8::Message> message = try_catch.Message();
- if (!message.IsEmpty())
- QQmlExpressionPrivate::exceptionToError(message, error);
- QQmlEnginePrivate::get(engine->engine())->warning(error);
- program->bindings = qPersistentNew(v8::Array::New());
- }
- }
-
- if (!compileFailed) {
- v8::Local<v8::Value> result = script->Run(engine->contextWrapper()->sharedContext());
- if (result->IsArray()) {
- program->bindings = qPersistentNew(v8::Local<v8::Array>::Cast(result));
- program->program.clear(); // We don't need the source anymore
- }
- }
- }
-
- int bindingsCount = functions()->Length();
- if (bindingsCount) bindings = new QV8Bindings::Binding[bindingsCount];
-
- setContext(context);
-}
-
-QV8Bindings::~QV8Bindings()
-{
- program = 0;
-
- delete [] bindings;
- bindings = 0;
-}
-
-QQmlAbstractBinding *
-QV8Bindings::configBinding(QObject *target, QObject *scope,
- const QQmlInstruction::instr_assignBinding *i)
-{
- if (!bindings) // initialization failed.
- return 0;
-
- QV8Bindings::Binding *rv = bindings + i->value;
-
- rv->instruction = i;
- rv->target = target;
- rv->setScopeObject(scope);
- rv->setUseSharedContext(true);
- rv->setNotifyOnValueChanged(true);
- rv->parent = this;
-
- if (!i->isFallback)
- addref(); // This is decremented in Binding::destroy()
-
- return rv;
-}
-
-const QUrl &QV8Bindings::url() const
-{
- return program->cdata->url;
-}
-
-const QString &QV8Bindings::urlString() const
-{
- return program->cdata->name;
-}
-
-v8::Persistent<v8::Array> &QV8Bindings::functions() const
-{
- return program->bindings;
-}
-
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8bindings_p.h b/src/qml/qml/v8/qv8bindings_p.h
deleted file mode 100644
index 98b367ac72..0000000000
--- a/src/qml/qml/v8/qv8bindings_p.h
+++ /dev/null
@@ -1,161 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV8BINDINGS_P_H
-#define QV8BINDINGS_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/qpointervaluepair_p.h>
-#include <private/qqmlpropertycache_p.h>
-#include <private/qqmlinstruction_p.h>
-#include <private/qqmlexpression_p.h>
-#include <private/qqmlcompiler_p.h>
-#include <private/qflagpointer_p.h>
-#include <private/qqmlbinding_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QQmlCompiledData;
-
-class QV8BindingsPrivate;
-class QV8Bindings : public QQmlAbstractExpression
-{
-public:
- QV8Bindings(QQmlCompiledData::V8Program *,
- quint16 line,
- QQmlContextData *context);
- virtual ~QV8Bindings();
-
- QQmlAbstractBinding *configBinding(QObject *target, QObject *scope,
- const QQmlInstruction::instr_assignBinding *);
-
- // Inherited from QQmlAbstractExpression
- virtual void refresh();
-
- struct Binding : public QQmlJavaScriptExpression,
- public QQmlAbstractBinding {
- Binding();
-
- void update() { QQmlAbstractBinding::update(); }
- void refresh();
-
- // "Inherited" from QQmlJavaScriptExpression
- static QString expressionIdentifier(QQmlJavaScriptExpression *);
- static void expressionChanged(QQmlJavaScriptExpression *);
-
- // "Inherited" from QQmlAbstractBinding
- static void destroy(QQmlAbstractBinding *, QQmlAbstractBinding::DestroyMode mode);
- static int propertyIndex(const QQmlAbstractBinding *);
- static QObject *object(const QQmlAbstractBinding *);
- static void setEnabled(QQmlAbstractBinding *, bool, QQmlPropertyPrivate::WriteFlags);
- static void update(QQmlAbstractBinding *, QQmlPropertyPrivate::WriteFlags);
- static void retargetBinding(QQmlAbstractBinding *, QObject *, int);
-
- QObject *object() const;
- void update(QQmlPropertyPrivate::WriteFlags flags);
-
- void dump();
-
- QV8Bindings *parent;
-
- struct Retarget {
- QObject *target;
- int targetProperty;
- };
-
- // To save memory, we store flags inside the instruction pointer.
- // target.flag1: destroyed
- // instruction.flag1: enabled
- // instruction.flag2: updating
- QPointerValuePair<QObject, Retarget> target;
- QFlagPointer<const QQmlInstruction::instr_assignBinding> instruction;
-
- inline bool destroyedFlag() const { return target.flag(); }
- inline void setDestroyedFlag(bool v) { return target.setFlagValue(v); }
- inline bool enabledFlag() const { return instruction.flag(); }
- inline void setEnabledFlag(bool v) { instruction.setFlagValue(v); }
- inline bool updatingFlag() const { return instruction.flag2(); }
- inline void setUpdatingFlag(bool v) { instruction.setFlag2Value(v); }
- };
-
- inline void addref();
- inline void release();
-
- QQmlAbstractBinding *binding(int index) const { return bindings + index; }
-
-private:
- Q_DISABLE_COPY(QV8Bindings)
-
- const QUrl &url() const;
- const QString &urlString() const;
- v8::Persistent<v8::Array> &functions() const;
-
- QQmlCompiledData::V8Program *program;
- Binding *bindings;
- int refCount;
-};
-
-void QV8Bindings::addref()
-{
- ++refCount;
-}
-
-void QV8Bindings::release()
-{
- if (0 == --refCount)
- delete this;
-}
-
-QT_END_NAMESPACE
-
-#endif // QV8BINDINGS_P_H
-
-
diff --git a/src/qml/qml/v8/qv8contextwrapper.cpp b/src/qml/qml/v8/qv8contextwrapper.cpp
deleted file mode 100644
index 630a3e5a7c..0000000000
--- a/src/qml/qml/v8/qv8contextwrapper.cpp
+++ /dev/null
@@ -1,430 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv8contextwrapper_p.h"
-#include "qv8engine_p.h"
-
-#include <private/qqmlengine_p.h>
-#include <private/qqmlcontext_p.h>
-
-QT_BEGIN_NAMESPACE
-
-static QString internal(QLatin1String("You've stumbled onto an internal implementation detail "
- "that should never have been exposed."));
-
-class QV8ContextResource : public QV8ObjectResource
-{
- V8_RESOURCE_TYPE(ContextType)
-
-public:
- QV8ContextResource(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext = false);
- ~QV8ContextResource();
-
- inline QQmlContextData *getContext() const;
- inline QObject *getScopeObject() const;
-
- quint32 isSharedContext:1;
- quint32 hasSubContexts:1;
- quint32 readOnly:1;
- quint32 ownsContext:1;
- quint32 dummy:28;
-
- // This is a pretty horrible hack, and an abuse of external strings. When we create a
- // sub-context (a context created by a Qt.include() in an external javascript file),
- // we pass a specially crafted SubContext external string as the v8::Script::Data() to
- // the script, which contains a pointer to the context. We can then access the
- // v8::Script::Data() later on to resolve names and URLs against the sub-context instead
- // of the main outer context.
- struct SubContext : public v8::String::ExternalStringResource {
- SubContext(QQmlContextData *context) : context(context) {}
- QQmlGuardedContextData context;
-
- virtual const uint16_t* data() const { return (const uint16_t *)internal.constData(); }
- virtual size_t length() const { return internal.length(); }
- };
-
-private:
- QQmlGuardedContextData context;
- QQmlGuard<QObject> scopeObject;
-
-};
-
-QV8ContextResource::QV8ContextResource(QV8Engine *engine, QQmlContextData *context, QObject *scopeObject, bool ownsContext)
-: QV8ObjectResource(engine), isSharedContext(false), hasSubContexts(false), readOnly(true),
- ownsContext(ownsContext), context(context), scopeObject(scopeObject)
-{
-}
-
-QV8ContextResource::~QV8ContextResource()
-{
- if (context && ownsContext)
- context->destroy();
-}
-
-// Returns the scope object
-QObject *QV8ContextResource::getScopeObject() const
-{
- if (isSharedContext)
- return QQmlEnginePrivate::get(engine->engine())->sharedScope;
- else
- return scopeObject;
-}
-
-// Returns the context, including resolving a subcontext
-QQmlContextData *QV8ContextResource::getContext() const
-{
- if (isSharedContext)
- return QQmlEnginePrivate::get(engine->engine())->sharedContext;
-
- if (!hasSubContexts)
- return context;
-
- v8::Local<v8::Value> callingdata = v8::Context::GetCallingScriptData();
- if (callingdata.IsEmpty() || !callingdata->IsString())
- return context;
-
- v8::Local<v8::String> callingstring = callingdata->ToString();
- Q_ASSERT(callingstring->IsExternal());
- Q_ASSERT(callingstring->GetExternalStringResource());
-
- SubContext *sc = static_cast<SubContext *>(callingstring->GetExternalStringResource());
- return sc->context;
-}
-
-QV8ContextWrapper::QV8ContextWrapper()
-: m_engine(0)
-{
-}
-
-QV8ContextWrapper::~QV8ContextWrapper()
-{
-}
-
-void QV8ContextWrapper::destroy()
-{
- qPersistentDispose(m_sharedContext);
- qPersistentDispose(m_urlConstructor);
- qPersistentDispose(m_constructor);
-}
-
-void QV8ContextWrapper::init(QV8Engine *engine)
-{
- m_engine = engine;
- {
- v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetHasExternalResource(true);
- ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
- m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
- }
- {
- v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetHasExternalResource(true);
- ft->InstanceTemplate()->SetFallbackPropertyHandler(NullGetter, NullSetter);
- m_urlConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
- }
- {
- v8::Local<v8::Object> sharedContext = m_constructor->NewInstance();
- QV8ContextResource *r = new QV8ContextResource(engine, 0, 0);
- r->isSharedContext = true;
- sharedContext->SetExternalResource(r);
- m_sharedContext = qPersistentNew<v8::Object>(sharedContext);
- }
-}
-
-v8::Local<v8::Object> QV8ContextWrapper::qmlScope(QQmlContextData *ctxt, QObject *scope)
-{
- // XXX NewInstance() should be optimized
- v8::Local<v8::Object> rv = m_constructor->NewInstance();
- QV8ContextResource *r = new QV8ContextResource(m_engine, ctxt, scope);
- rv->SetExternalResource(r);
- return rv;
-}
-
-v8::Local<v8::Object> QV8ContextWrapper::urlScope(const QUrl &url)
-{
- QQmlContextData *context = new QQmlContextData;
- context->url = url;
- context->isInternal = true;
- context->isJSContext = true;
-
- // XXX NewInstance() should be optimized
- v8::Local<v8::Object> rv = m_urlConstructor->NewInstance();
- QV8ContextResource *r = new QV8ContextResource(m_engine, context, 0, true);
- rv->SetExternalResource(r);
- return rv;
-}
-
-void QV8ContextWrapper::setReadOnly(v8::Handle<v8::Object> qmlglobal, bool readOnly)
-{
- QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(qmlglobal);
- Q_ASSERT(resource);
- resource->readOnly = readOnly;
-}
-
-void QV8ContextWrapper::addSubContext(v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Script> script,
- QQmlContextData *ctxt)
-{
- QV8ContextResource *resource = v8_resource_cast<QV8ContextResource>(qmlglobal);
- Q_ASSERT(resource);
- resource->hasSubContexts = true;
- script->SetData(v8::String::NewExternal(new QV8ContextResource::SubContext(ctxt)));
-}
-
-QQmlContextData *QV8ContextWrapper::callingContext()
-{
- v8::Local<v8::Object> qmlglobal = v8::Context::GetCallingQmlGlobal();
- if (qmlglobal.IsEmpty()) return 0;
-
- QV8ContextResource *r = v8_resource_cast<QV8ContextResource>(qmlglobal);
- return r?r->getContext():0;
-}
-
-QQmlContextData *QV8ContextWrapper::context(v8::Handle<v8::Value> value)
-{
- if (!value->IsObject())
- return 0;
-
- v8::Handle<v8::Object> qmlglobal = v8::Handle<v8::Object>::Cast(value);
- QV8ContextResource *r = v8_resource_cast<QV8ContextResource>(qmlglobal);
- return r?r->getContext():0;
-}
-
-void QV8ContextWrapper::takeContextOwnership(v8::Handle<v8::Object> qmlglobal)
-{
- QV8ContextResource *r = v8_resource_cast<QV8ContextResource>(qmlglobal);
- r->ownsContext = true;
-}
-
-v8::Handle<v8::Value> QV8ContextWrapper::NullGetter(v8::Local<v8::String>,
- const v8::AccessorInfo &)
-{
- // V8 will throw a ReferenceError if appropriate ("typeof" should not throw)
- return v8::Handle<v8::Value>();
-}
-
-v8::Handle<v8::Value> QV8ContextWrapper::Getter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
-{
- QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This());
-
- // Its possible we could delay the calculation of the "actual" context (in the case
- // of sub contexts) until it is definately needed.
- QQmlContextData *context = resource->getContext();
- QQmlContextData *expressionContext = context;
-
- if (!context)
- return v8::Undefined();
-
- if (v8::Context::GetCallingQmlGlobal() != info.This())
- return v8::Handle<v8::Value>();
-
- // Search type (attached property/enum/imported scripts) names
- // while (context) {
- // Search context properties
- // Search scope object
- // Search context object
- // context = context->parent
- // }
-
- QV8Engine *engine = resource->engine;
-
- QObject *scopeObject = resource->getScopeObject();
-
- QHashedV8String propertystring(property);
-
- if (context->imports && QV8Engine::startsWithUpper(property)) {
- // Search for attached properties, enums and imported scripts
- QQmlTypeNameCache::Result r = context->imports->query(propertystring);
-
- if (r.isValid()) {
- if (r.scriptIndex != -1) {
- int index = r.scriptIndex;
- if (index < context->importedScripts.count())
- return context->importedScripts.at(index);
- else
- return v8::Undefined();
- } else if (r.type) {
- return engine->typeWrapper()->newObject(scopeObject, r.type);
- } else if (r.importNamespace) {
- return engine->typeWrapper()->newObject(scopeObject, context->imports, r.importNamespace);
- }
- Q_ASSERT(!"Unreachable");
- }
-
- // Fall through
- }
-
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(engine->engine());
- QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
-
- while (context) {
- // Search context properties
- if (context->propertyNames) {
- int propertyIdx = context->propertyNames->value(propertystring);
-
- if (propertyIdx != -1) {
-
- if (propertyIdx < context->idValueCount) {
-
- ep->captureProperty(&context->idValues[propertyIdx].bindings);
- return engine->newQObject(context->idValues[propertyIdx]);
- } else {
-
- QQmlContextPrivate *cp = context->asQQmlContextPrivate();
-
- ep->captureProperty(context->asQQmlContext(), -1,
- propertyIdx + cp->notifyIndex);
-
- const QVariant &value = cp->propertyValues.at(propertyIdx);
- if (value.userType() == qMetaTypeId<QList<QObject*> >()) {
- QQmlListProperty<QObject> prop(context->asQQmlContext(), (void*) qintptr(propertyIdx),
- QQmlContextPrivate::context_count,
- QQmlContextPrivate::context_at);
- return engine->listWrapper()->newList(prop, qMetaTypeId<QQmlListProperty<QObject> >());
- } else {
- return engine->fromVariant(cp->propertyValues.at(propertyIdx));
- }
- }
- }
- }
-
- // Search scope object
- if (scopeObject) {
- v8::Handle<v8::Value> result = qobjectWrapper->getProperty(scopeObject, propertystring,
- context, QV8QObjectWrapper::CheckRevision);
- if (!result.IsEmpty()) return result;
- }
- scopeObject = 0;
-
-
- // Search context object
- if (context->contextObject) {
- v8::Handle<v8::Value> result = qobjectWrapper->getProperty(context->contextObject, propertystring,
- context, QV8QObjectWrapper::CheckRevision);
- if (!result.IsEmpty()) return result;
- }
-
- context = context->parent;
- }
-
- expressionContext->unresolvedNames = true;
-
- // V8 will throw a ReferenceError if appropriate ("typeof" should not throw)
- return v8::Handle<v8::Value>();
-}
-
-v8::Handle<v8::Value> QV8ContextWrapper::NullSetter(v8::Local<v8::String> property,
- v8::Local<v8::Value>,
- const v8::AccessorInfo &info)
-{
- QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This());
-
- QV8Engine *engine = resource->engine;
-
- if (!resource->readOnly) {
- return v8::Handle<v8::Value>();
- } else {
- QString error = QLatin1String("Invalid write to global property \"") + engine->toString(property) +
- QLatin1Char('"');
- v8::ThrowException(v8::Exception::Error(engine->toString(error)));
- return v8::Handle<v8::Value>();
- }
-}
-
-v8::Handle<v8::Value> QV8ContextWrapper::Setter(v8::Local<v8::String> property,
- v8::Local<v8::Value> value,
- const v8::AccessorInfo &info)
-{
- QV8ContextResource *resource = v8_resource_check<QV8ContextResource>(info.This());
-
- // Its possible we could delay the calculation of the "actual" context (in the case
- // of sub contexts) until it is definately needed.
- QQmlContextData *context = resource->getContext();
- QQmlContextData *expressionContext = context;
-
- if (!context)
- return v8::Undefined();
-
- if (v8::Context::GetCallingQmlGlobal() != info.This())
- return v8::Handle<v8::Value>();
-
- // See QV8ContextWrapper::Getter for resolution order
-
- QV8Engine *engine = resource->engine;
- QObject *scopeObject = resource->getScopeObject();
-
- QHashedV8String propertystring(property);
-
- QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
-
- while (context) {
- // Search context properties
- if (context->propertyNames && -1 != context->propertyNames->value(propertystring))
- return value;
-
- // Search scope object
- if (scopeObject &&
- qobjectWrapper->setProperty(scopeObject, propertystring, context, value, QV8QObjectWrapper::CheckRevision))
- return value;
- scopeObject = 0;
-
- // Search context object
- if (context->contextObject &&
- qobjectWrapper->setProperty(context->contextObject, propertystring, context, value,
- QV8QObjectWrapper::CheckRevision))
- return value;
-
- context = context->parent;
- }
-
- expressionContext->unresolvedNames = true;
-
- if (!resource->readOnly) {
- return v8::Handle<v8::Value>();
- } else {
- QString error = QLatin1String("Invalid write to global property \"") + engine->toString(property) +
- QLatin1Char('"');
- v8::ThrowException(v8::Exception::Error(engine->toString(error)));
- return v8::Undefined();
- }
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8contextwrapper_p.h b/src/qml/qml/v8/qv8contextwrapper_p.h
deleted file mode 100644
index 3e14a019a7..0000000000
--- a/src/qml/qml/v8/qv8contextwrapper_p.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV8CONTEXTWRAPPER_P_H
-#define QV8CONTEXTWRAPPER_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 <QtCore/qglobal.h>
-#include <private/qtqmlglobal_p.h>
-#include <private/qv8_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QUrl;
-class QObject;
-class QV8Engine;
-class QQmlContextData;
-class Q_QML_PRIVATE_EXPORT QV8ContextWrapper
-{
-public:
- QV8ContextWrapper();
- ~QV8ContextWrapper();
-
- void init(QV8Engine *);
- void destroy();
-
- v8::Local<v8::Object> qmlScope(QQmlContextData *ctxt, QObject *scope);
- v8::Local<v8::Object> urlScope(const QUrl &);
-
- void setReadOnly(v8::Handle<v8::Object>, bool);
-
- void addSubContext(v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Script>,
- QQmlContextData *ctxt);
-
- QQmlContextData *callingContext();
- QQmlContextData *context(v8::Handle<v8::Value>);
-
- inline v8::Handle<v8::Object> sharedContext() const;
-
- void takeContextOwnership(v8::Handle<v8::Object> qmlglobal);
-
-private:
- static v8::Handle<v8::Value> NullGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> NullSetter(v8::Local<v8::String> property,
- v8::Local<v8::Value> value,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
- v8::Local<v8::Value> value,
- const v8::AccessorInfo &info);
-
- QV8Engine *m_engine;
- v8::Persistent<v8::Function> m_constructor;
- v8::Persistent<v8::Function> m_urlConstructor;
- v8::Persistent<v8::Object> m_sharedContext;
-};
-
-v8::Handle<v8::Object> QV8ContextWrapper::sharedContext() const
-{
- return m_sharedContext;
-}
-
-QT_END_NAMESPACE
-
-#endif // QV8CONTEXTWRAPPER_P_H
-
diff --git a/src/qml/qml/v8/qv8debug_p.h b/src/qml/qml/v8/qv8debug_p.h
index 6576839e42..87e4e13c7d 100644
--- a/src/qml/qml/v8/qv8debug_p.h
+++ b/src/qml/qml/v8/qv8debug_p.h
@@ -39,4 +39,4 @@
**
****************************************************************************/
-#include <private/v8-debug.h>
+//#include <private/v8-debug.h>
diff --git a/src/qml/qml/v8/qv8domerrors.cpp b/src/qml/qml/v8/qv8domerrors.cpp
deleted file mode 100644
index d3a36f75c1..0000000000
--- a/src/qml/qml/v8/qv8domerrors.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv8domerrors_p.h"
-#include "qv8engine_p.h"
-
-QT_BEGIN_NAMESPACE
-
-void qt_add_domexceptions(QV8Engine *engine)
-{
- // DOM Exception
- v8::PropertyAttribute attributes = (v8::PropertyAttribute)(v8::ReadOnly | v8::DontEnum | v8::DontDelete);
-
- v8::Local<v8::Object> domexception = v8::Object::New();
- domexception->Set(v8::String::New("INDEX_SIZE_ERR"), v8::Integer::New(DOMEXCEPTION_INDEX_SIZE_ERR), attributes);
- domexception->Set(v8::String::New("DOMSTRING_SIZE_ERR"), v8::Integer::New(DOMEXCEPTION_DOMSTRING_SIZE_ERR), attributes);
- domexception->Set(v8::String::New("HIERARCHY_REQUEST_ERR"), v8::Integer::New(DOMEXCEPTION_HIERARCHY_REQUEST_ERR), attributes);
- domexception->Set(v8::String::New("WRONG_DOCUMENT_ERR"), v8::Integer::New(DOMEXCEPTION_WRONG_DOCUMENT_ERR), attributes);
- domexception->Set(v8::String::New("INVALID_CHARACTER_ERR"), v8::Integer::New(DOMEXCEPTION_INVALID_CHARACTER_ERR), attributes);
- domexception->Set(v8::String::New("NO_DATA_ALLOWED_ERR"), v8::Integer::New(DOMEXCEPTION_NO_DATA_ALLOWED_ERR), attributes);
- domexception->Set(v8::String::New("NO_MODIFICATION_ALLOWED_ERR"), v8::Integer::New(DOMEXCEPTION_NO_MODIFICATION_ALLOWED_ERR), attributes);
- domexception->Set(v8::String::New("NOT_FOUND_ERR"), v8::Integer::New(DOMEXCEPTION_NOT_FOUND_ERR), attributes);
- domexception->Set(v8::String::New("NOT_SUPPORTED_ERR"), v8::Integer::New(DOMEXCEPTION_NOT_SUPPORTED_ERR), attributes);
- domexception->Set(v8::String::New("INUSE_ATTRIBUTE_ERR"), v8::Integer::New(DOMEXCEPTION_INUSE_ATTRIBUTE_ERR), attributes);
- domexception->Set(v8::String::New("INVALID_STATE_ERR"), v8::Integer::New(DOMEXCEPTION_INVALID_STATE_ERR), attributes);
- domexception->Set(v8::String::New("SYNTAX_ERR"), v8::Integer::New(DOMEXCEPTION_SYNTAX_ERR), attributes);
- domexception->Set(v8::String::New("INVALID_MODIFICATION_ERR"), v8::Integer::New(DOMEXCEPTION_INVALID_MODIFICATION_ERR), attributes);
- domexception->Set(v8::String::New("NAMESPACE_ERR"), v8::Integer::New(DOMEXCEPTION_NAMESPACE_ERR), attributes);
- domexception->Set(v8::String::New("INVALID_ACCESS_ERR"), v8::Integer::New(DOMEXCEPTION_INVALID_ACCESS_ERR), attributes);
- domexception->Set(v8::String::New("VALIDATION_ERR"), v8::Integer::New(DOMEXCEPTION_VALIDATION_ERR), attributes);
- domexception->Set(v8::String::New("TYPE_MISMATCH_ERR"), v8::Integer::New(DOMEXCEPTION_TYPE_MISMATCH_ERR), attributes);
- engine->global()->Set(v8::String::New("DOMException"), domexception);
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp
index e80da46fc9..804a6e3e50 100644
--- a/src/qml/qml/v8/qv8engine.cpp
+++ b/src/qml/qml/v8/qv8engine.cpp
@@ -41,10 +41,7 @@
#include "qv8engine_p.h"
-#include "qv8contextwrapper_p.h"
-#include "qv8valuetypewrapper_p.h"
-#include "qv8sequencewrapper_p.h"
-#include "qv8include_p.h"
+#include "qv4sequenceobject_p.h"
#include "qjsengine_p.h"
#include <private/qqmlbuiltinfunctions_p.h>
@@ -55,14 +52,31 @@
#include <private/qqmlglobal_p.h>
#include <private/qqmlmemoryprofiler_p.h>
#include <private/qqmlplatform_p.h>
+#include <private/qjsvalue_p.h>
+#include <private/qqmltypewrapper_p.h>
+#include <private/qqmlcontextwrapper_p.h>
+#include <private/qqmlvaluetypewrapper_p.h>
+#include <private/qqmllistwrapper_p.h>
-#include "qscript_impl_p.h"
-#include "qv8domerrors_p.h"
-#include "qv8sqlerrors_p.h"
+#include "qv4domerrors_p.h"
+#include "qv4sqlerrors_p.h"
#include <QtCore/qjsonarray.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsonvalue.h>
+#include <QtCore/qdatetime.h>
+
+#include <private/qv4value_p.h>
+#include <private/qv4dateobject_p.h>
+#include <private/qv4objectiterator_p.h>
+#include <private/qv4mm_p.h>
+#include <private/qv4objectproto_p.h>
+#include <private/qv4globalobject_p.h>
+#include <private/qv4regexpobject_p.h>
+#include <private/qv4variantobject_p.h>
+#include <private/qv4script_p.h>
+#include <private/qv4include_p.h>
+#include <private/qv4jsonobject_p.h>
Q_DECLARE_METATYPE(QList<int>)
@@ -71,107 +85,25 @@ Q_DECLARE_METATYPE(QList<int>)
// QQmlEngine is not available
QT_BEGIN_NAMESPACE
-static bool ObjectComparisonCallback(v8::Local<v8::Object> lhs, v8::Local<v8::Object> rhs)
-{
- if (lhs == rhs)
- return true;
-
- if (lhs.IsEmpty() || rhs.IsEmpty())
- return false;
- QV8ObjectResource *lhsr = static_cast<QV8ObjectResource*>(lhs->GetExternalResource());
- QV8ObjectResource *rhsr = static_cast<QV8ObjectResource*>(rhs->GetExternalResource());
-
- if (lhsr && rhsr) {
- Q_ASSERT(lhsr->engine == rhsr->engine);
- QV8ObjectResource::ResourceType lhst = lhsr->resourceType();
- QV8ObjectResource::ResourceType rhst = rhsr->resourceType();
-
- switch (lhst) {
- case QV8ObjectResource::ValueTypeType:
- // a value type might be equal to a variant or another value type
- if (rhst == QV8ObjectResource::ValueTypeType) {
- return lhsr->engine->valueTypeWrapper()->isEqual(lhsr, lhsr->engine->valueTypeWrapper()->toVariant(rhsr));
- } else if (rhst == QV8ObjectResource::VariantType) {
- return lhsr->engine->valueTypeWrapper()->isEqual(lhsr, lhsr->engine->variantWrapper()->toVariant(rhsr));
- }
- break;
- case QV8ObjectResource::VariantType:
- // a variant might be equal to a value type or other variant.
- if (rhst == QV8ObjectResource::VariantType) {
- return lhsr->engine->variantWrapper()->toVariant(lhsr) ==
- lhsr->engine->variantWrapper()->toVariant(rhsr);
- } else if (rhst == QV8ObjectResource::ValueTypeType) {
- return rhsr->engine->valueTypeWrapper()->isEqual(rhsr, rhsr->engine->variantWrapper()->toVariant(lhsr));
- }
- break;
- case QV8ObjectResource::SequenceType:
- // a sequence might be equal to itself.
- if (rhst == QV8ObjectResource::SequenceType) {
- return lhsr->engine->sequenceWrapper()->isEqual(lhsr, rhsr);
- }
- break;
- default:
- break;
- }
- }
-
- return false;
-}
-
-
-QV8Engine::QV8Engine(QJSEngine* qq, ContextOwnership ownership)
+QV8Engine::QV8Engine(QJSEngine* qq)
: q(qq)
, m_engine(0)
- , m_ownsV8Context(ownership == CreateNewContext)
, m_xmlHttpRequestData(0)
, m_listModelData(0)
- , m_platform(0)
- , m_application(0)
{
QML_MEMORY_SCOPE_STRING("QV8Engine::QV8Engine");
qMetaTypeId<QJSValue>();
qMetaTypeId<QList<int> >();
- QByteArray v8args = qgetenv("V8ARGS");
- // change default v8 behaviour to not relocate breakpoints across lines
- if (!v8args.contains("breakpoint_relocation"))
- v8args.append(" --nobreakpoint_relocation");
- v8::V8::SetFlagsFromString(v8args.constData(), v8args.length());
-
- ensurePerThreadIsolate();
-
- v8::HandleScope handle_scope;
- m_context = (ownership == CreateNewContext) ? v8::Context::New() : v8::Persistent<v8::Context>::New(v8::Context::GetCurrent());
- qPersistentRegister(m_context);
- m_originalGlobalObject.init(m_context);
- v8::Context::Scope context_scope(m_context);
-
- v8::V8::SetUserObjectComparisonCallbackFunction(ObjectComparisonCallback);
- QV8GCCallback::registerGcPrologueCallback();
- m_strongReferencer = qPersistentNew(v8::Object::New());
-
- m_bindingFlagKey = qPersistentNew(v8::String::New("qml::binding"));
+ m_v4Engine = new QV4::ExecutionEngine;
+ m_v4Engine->v8Engine = this;
- m_stringWrapper.init();
- m_contextWrapper.init(this);
- m_qobjectWrapper.init(this);
- m_typeWrapper.init(this);
- m_listWrapper.init(this);
- m_variantWrapper.init(this);
- m_valueTypeWrapper.init(this);
- m_sequenceWrapper.init(this);
- m_jsonWrapper.init(this);
-
- {
- v8::Handle<v8::Value> v = global()->Get(v8::String::New("Object"))->ToObject()->Get(v8::String::New("getOwnPropertyNames"));
- m_getOwnPropertyNames = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(v));
- }
+ QV4::QObjectWrapper::initializeBindings(m_v4Engine);
}
QV8Engine::~QV8Engine()
{
- Q_ASSERT_X(v8::Isolate::GetCurrent(), "QV8Engine::~QV8Engine()", "called after v8::Isolate has exited");
for (int ii = 0; ii < m_extensionData.count(); ++ii)
delete m_extensionData[ii];
m_extensionData.clear();
@@ -181,105 +113,52 @@ QV8Engine::~QV8Engine()
delete m_listModelData;
m_listModelData = 0;
- qPersistentDispose(m_freezeObject);
- qPersistentDispose(m_getOwnPropertyNames);
-
- invalidateAllValues();
-
- qPersistentDispose(m_strongReferencer);
-
- m_jsonWrapper.destroy();
- m_sequenceWrapper.destroy();
- m_valueTypeWrapper.destroy();
- m_variantWrapper.destroy();
- m_listWrapper.destroy();
- m_typeWrapper.destroy();
- m_qobjectWrapper.destroy();
- m_contextWrapper.destroy();
- m_stringWrapper.destroy();
-
- qPersistentDispose(m_bindingFlagKey);
-
- m_originalGlobalObject.destroy();
-
- if (m_ownsV8Context)
- qPersistentDispose(m_context);
-}
-
-QString QV8Engine::toStringStatic(v8::Handle<v8::Value> jsstr)
-{
- return toStringStatic(jsstr->ToString());
-}
-
-QString QV8Engine::toStringStatic(v8::Handle<v8::String> jsstr)
-{
- QString qstr;
- qstr.resize(jsstr->Length());
- jsstr->Write((uint16_t*)qstr.data());
- return qstr;
+ delete m_v4Engine;
}
-QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint)
+QVariant QV8Engine::toVariant(const QV4::Value &value, int typeHint)
{
- if (value.IsEmpty())
+ if (value.isEmpty())
return QVariant();
+ if (QV4::VariantObject *v = value.as<QV4::VariantObject>())
+ return v->data;
+
if (typeHint == QVariant::Bool)
- return QVariant(value->BooleanValue());
+ return QVariant(value.toBoolean());
if (typeHint == QMetaType::QJsonValue)
- return QVariant::fromValue(jsonValueFromJS(value));
+ return QVariant::fromValue(QV4::JsonObject::toJsonValue(value));
if (typeHint == qMetaTypeId<QJSValue>())
- return QVariant::fromValue(scriptValueFromInternal(value));
-
- if (value->IsObject()) {
- QV8ObjectResource *r = (QV8ObjectResource *)value->ToObject()->GetExternalResource();
- if (r) {
- switch (r->resourceType()) {
- case QV8ObjectResource::Context2DStyleType:
- case QV8ObjectResource::Context2DPixelArrayType:
- case QV8ObjectResource::SignalHandlerType:
- case QV8ObjectResource::IncubatorType:
- case QV8ObjectResource::VisualDataItemType:
- case QV8ObjectResource::ContextType:
- case QV8ObjectResource::XMLHttpRequestType:
- case QV8ObjectResource::DOMNodeType:
- case QV8ObjectResource::SQLDatabaseType:
- case QV8ObjectResource::ListModelType:
- case QV8ObjectResource::Context2DType:
- case QV8ObjectResource::ParticleDataType:
- case QV8ObjectResource::LocaleDataType:
- case QV8ObjectResource::ChangeSetArrayType:
- return QVariant();
- case QV8ObjectResource::TypeType:
- return m_typeWrapper.toVariant(r);
- case QV8ObjectResource::QObjectType:
- return qVariantFromValue<QObject *>(m_qobjectWrapper.toQObject(r));
- case QV8ObjectResource::ListType:
- return m_listWrapper.toVariant(r);
- case QV8ObjectResource::VariantType:
- return m_variantWrapper.toVariant(r);
- case QV8ObjectResource::ValueTypeType:
- return m_valueTypeWrapper.toVariant(r);
- case QV8ObjectResource::SequenceType:
- return m_sequenceWrapper.toVariant(r);
- }
- } else if (typeHint == QMetaType::QJsonObject
- && !value->IsArray() && !value->IsFunction()) {
- return QVariant::fromValue(jsonObjectFromJS(value));
- }
- }
-
- if (value->IsArray()) {
- v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
+ return QVariant::fromValue(QJSValue(new QJSValuePrivate(m_v4Engine, value)));
+
+ if (QV4::Object *object = value.asObject()) {
+ if (typeHint == QMetaType::QJsonObject
+ && !value.asArrayObject() && !value.asFunctionObject()) {
+ return QVariant::fromValue(QV4::JsonObject::toJsonObject(object));
+ } else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) {
+ return qVariantFromValue<QObject *>(wrapper->object());
+ } else if (QV4::QmlContextWrapper *wrapper = object->as<QV4::QmlContextWrapper>()) {
+ return QVariant();
+ } else if (QV4::QmlTypeWrapper *w = object->as<QV4::QmlTypeWrapper>()) {
+ return w->toVariant();
+ } else if (QV4::QmlValueTypeWrapper *v = object->as<QV4::QmlValueTypeWrapper>()) {
+ return v->toVariant();
+ } else if (QV4::QmlListWrapper *l = object->as<QV4::QmlListWrapper>()) {
+ return l->toVariant();
+ } else if (object->isListType())
+ return QV4::SequencePrototype::toVariant(object);
+ }
+
+ if (QV4::ArrayObject *a = value.asArrayObject()) {
if (typeHint == qMetaTypeId<QList<QObject *> >()) {
QList<QObject *> list;
- uint32_t length = array->Length();
+ uint32_t length = a->arrayLength();
for (uint32_t ii = 0; ii < length; ++ii) {
- v8::Local<v8::Value> arrayItem = array->Get(ii);
- if (arrayItem->IsObject()) {
- list << toQObject(arrayItem->ToObject());
+ QV4::Value arrayItem = a->getIndexed(ii);
+ if (QV4::QObjectWrapper *qobjectWrapper = arrayItem.as<QV4::QObjectWrapper>()) {
+ list << qobjectWrapper->object();
} else {
list << 0;
}
@@ -287,11 +166,11 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint)
return qVariantFromValue<QList<QObject*> >(list);
} else if (typeHint == QMetaType::QJsonArray) {
- return QVariant::fromValue(jsonArrayFromJS(value));
+ return QVariant::fromValue(QV4::JsonObject::toJsonArray(a));
}
bool succeeded = false;
- QVariant retn = m_sequenceWrapper.toVariant(array, typeHint, &succeeded);
+ QVariant retn = QV4::SequencePrototype::toVariant(value, typeHint, &succeeded);
if (succeeded)
return retn;
}
@@ -299,36 +178,44 @@ QVariant QV8Engine::toVariant(v8::Handle<v8::Value> value, int typeHint)
return toBasicVariant(value);
}
-static v8::Handle<v8::Array> arrayFromStringList(QV8Engine *engine, const QStringList &list)
+static QV4::Value arrayFromStringList(QV8Engine *engine, const QStringList &list)
{
- v8::Context::Scope scope(engine->context());
- v8::Local<v8::Array> result = v8::Array::New(list.count());
- for (int ii = 0; ii < list.count(); ++ii)
- result->Set(ii, engine->toString(list.at(ii)));
- return result;
+ QV4::ExecutionEngine *e = QV8Engine::getV4(engine);
+ QV4::ArrayObject *a = e->newArrayObject();
+ int len = list.count();
+ a->arrayReserve(len);
+ a->arrayDataLen = len;
+ for (int ii = 0; ii < len; ++ii)
+ a->arrayData[ii].value = QV4::Value::fromString(e->newString(list.at(ii)));
+ a->setArrayLengthUnchecked(len);
+ return QV4::Value::fromObject(a);
}
-static v8::Handle<v8::Array> arrayFromVariantList(QV8Engine *engine, const QVariantList &list)
+static QV4::Value arrayFromVariantList(QV8Engine *engine, const QVariantList &list)
{
- v8::Context::Scope scope(engine->context());
- v8::Local<v8::Array> result = v8::Array::New(list.count());
- for (int ii = 0; ii < list.count(); ++ii)
- result->Set(ii, engine->fromVariant(list.at(ii)));
- return result;
+ QV4::ExecutionEngine *e = QV8Engine::getV4(engine);
+ QV4::ArrayObject *a = e->newArrayObject();
+ int len = list.count();
+ a->arrayReserve(len);
+ a->arrayDataLen = len;
+ for (int ii = 0; ii < len; ++ii)
+ a->arrayData[ii].value = engine->fromVariant(list.at(ii));
+ a->setArrayLengthUnchecked(len);
+ return QV4::Value::fromObject(a);
}
-static v8::Handle<v8::Object> objectFromVariantMap(QV8Engine *engine, const QVariantMap &map)
+static QV4::Value objectFromVariantMap(QV8Engine *engine, const QVariantMap &map)
{
- v8::Context::Scope scope(engine->context());
- v8::Local<v8::Object> object = v8::Object::New();
+ QV4::ExecutionEngine *e = QV8Engine::getV4(engine);
+ QV4::Object *o = e->newObject();
for (QVariantMap::ConstIterator iter = map.begin(); iter != map.end(); ++iter)
- object->Set(engine->toString(iter.key()), engine->fromVariant(iter.value()));
- return object;
+ o->put(e->newString(iter.key()), engine->fromVariant(iter.value()));
+ return QV4::Value::fromObject(o);
}
Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
-v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant)
+QV4::Value QV8Engine::fromVariant(const QVariant &variant)
{
int type = variant.userType();
const void *ptr = variant.constData();
@@ -337,47 +224,47 @@ v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant)
switch (QMetaType::Type(type)) {
case QMetaType::UnknownType:
case QMetaType::Void:
- return v8::Undefined();
+ return QV4::Value::undefinedValue();
case QMetaType::Bool:
- return v8::Boolean::New(*reinterpret_cast<const bool*>(ptr));
+ return QV4::Value::fromBoolean(*reinterpret_cast<const bool*>(ptr));
case QMetaType::Int:
- return v8::Integer::New(*reinterpret_cast<const int*>(ptr));
+ return QV4::Value::fromInt32(*reinterpret_cast<const int*>(ptr));
case QMetaType::UInt:
- return v8::Integer::NewFromUnsigned(*reinterpret_cast<const uint*>(ptr));
+ return QV4::Value::fromUInt32(*reinterpret_cast<const uint*>(ptr));
case QMetaType::LongLong:
- return v8::Number::New(*reinterpret_cast<const qlonglong*>(ptr));
+ return QV4::Value::fromDouble(*reinterpret_cast<const qlonglong*>(ptr));
case QMetaType::ULongLong:
- return v8::Number::New(*reinterpret_cast<const qulonglong*>(ptr));
+ return QV4::Value::fromDouble(*reinterpret_cast<const qulonglong*>(ptr));
case QMetaType::Double:
- return v8::Number::New(*reinterpret_cast<const double*>(ptr));
+ return QV4::Value::fromDouble(*reinterpret_cast<const double*>(ptr));
case QMetaType::QString:
- return m_stringWrapper.toString(*reinterpret_cast<const QString*>(ptr));
+ return QV4::Value::fromString(m_v4Engine->current, *reinterpret_cast<const QString*>(ptr));
case QMetaType::Float:
- return v8::Number::New(*reinterpret_cast<const float*>(ptr));
+ return QV4::Value::fromDouble(*reinterpret_cast<const float*>(ptr));
case QMetaType::Short:
- return v8::Integer::New(*reinterpret_cast<const short*>(ptr));
+ return QV4::Value::fromInt32(*reinterpret_cast<const short*>(ptr));
case QMetaType::UShort:
- return v8::Integer::NewFromUnsigned(*reinterpret_cast<const unsigned short*>(ptr));
+ return QV4::Value::fromUInt32(*reinterpret_cast<const unsigned short*>(ptr));
case QMetaType::Char:
- return v8::Integer::New(*reinterpret_cast<const char*>(ptr));
+ return QV4::Value::fromInt32(*reinterpret_cast<const char*>(ptr));
case QMetaType::UChar:
- return v8::Integer::NewFromUnsigned(*reinterpret_cast<const unsigned char*>(ptr));
+ return QV4::Value::fromUInt32(*reinterpret_cast<const unsigned char*>(ptr));
case QMetaType::QChar:
- return v8::Integer::New((*reinterpret_cast<const QChar*>(ptr)).unicode());
+ return QV4::Value::fromInt32((*reinterpret_cast<const QChar*>(ptr)).unicode());
case QMetaType::QDateTime:
- return v8::Date::New(qtDateTimeToJsDate(*reinterpret_cast<const QDateTime *>(ptr)));
+ return QV4::Value::fromObject(m_v4Engine->newDateObject(*reinterpret_cast<const QDateTime *>(ptr)));
case QMetaType::QDate:
- return v8::Date::New(qtDateTimeToJsDate(QDateTime(*reinterpret_cast<const QDate *>(ptr))));
+ return QV4::Value::fromObject(m_v4Engine->newDateObject(QDateTime(*reinterpret_cast<const QDate *>(ptr))));
case QMetaType::QTime:
- return v8::Date::New(qtDateTimeToJsDate(QDateTime(QDate(1970,1,1), *reinterpret_cast<const QTime *>(ptr))));
+ return QV4::Value::fromObject(m_v4Engine->newDateObject(QDateTime(QDate(1970,1,1), *reinterpret_cast<const QTime *>(ptr))));
case QMetaType::QRegExp:
- return QJSConverter::toRegExp(*reinterpret_cast<const QRegExp *>(ptr));
+ return QV4::Value::fromObject(m_v4Engine->newRegExpObject(*reinterpret_cast<const QRegExp *>(ptr)));
case QMetaType::QObjectStar:
- return newQObject(*reinterpret_cast<QObject* const *>(ptr));
+ return QV4::QObjectWrapper::wrap(m_v4Engine, *reinterpret_cast<QObject* const *>(ptr));
case QMetaType::QStringList:
{
bool succeeded = false;
- v8::Handle<v8::Value> retn = m_sequenceWrapper.fromVariant(variant, &succeeded);
+ QV4::Value retn = QV4::SequencePrototype::fromVariant(m_v4Engine, variant, &succeeded);
if (succeeded)
return retn;
return arrayFromStringList(this, *reinterpret_cast<const QStringList *>(ptr));
@@ -387,97 +274,63 @@ v8::Handle<v8::Value> QV8Engine::fromVariant(const QVariant &variant)
case QMetaType::QVariantMap:
return objectFromVariantMap(this, *reinterpret_cast<const QVariantMap *>(ptr));
case QMetaType::QJsonValue:
- return jsonValueToJS(*reinterpret_cast<const QJsonValue *>(ptr));
+ return QV4::JsonObject::fromJsonValue(m_v4Engine, *reinterpret_cast<const QJsonValue *>(ptr));
case QMetaType::QJsonObject:
- return jsonObjectToJS(*reinterpret_cast<const QJsonObject *>(ptr));
+ return QV4::JsonObject::fromJsonObject(m_v4Engine, *reinterpret_cast<const QJsonObject *>(ptr));
case QMetaType::QJsonArray:
- return jsonArrayToJS(*reinterpret_cast<const QJsonArray *>(ptr));
+ return QV4::JsonObject::fromJsonArray(m_v4Engine, *reinterpret_cast<const QJsonArray *>(ptr));
default:
break;
}
if (QQmlValueType *vt = QQmlValueTypeFactory::valueType(type))
- return m_valueTypeWrapper.newValueType(variant, vt);
+ return QV4::QmlValueTypeWrapper::create(this, variant, vt);
} else {
if (type == qMetaTypeId<QQmlListReference>()) {
typedef QQmlListReferencePrivate QDLRP;
QDLRP *p = QDLRP::get((QQmlListReference*)ptr);
if (p->object) {
- return m_listWrapper.newList(p->property, p->propertyType);
+ return QV4::QmlListWrapper::create(this, p->property, p->propertyType);
} else {
- return v8::Null();
+ return QV4::Value::nullValue();
}
} else if (type == qMetaTypeId<QJSValue>()) {
const QJSValue *value = reinterpret_cast<const QJSValue *>(ptr);
QJSValuePrivate *valuep = QJSValuePrivate::get(*value);
- if (valuep->assignEngine(this))
- return v8::Local<v8::Value>::New(*valuep);
+ return valuep->getValue(m_v4Engine);
} else if (type == qMetaTypeId<QList<QObject *> >()) {
// XXX Can this be made more by using Array as a prototype and implementing
// directly against QList<QObject*>?
const QList<QObject *> &list = *(QList<QObject *>*)ptr;
- v8::Local<v8::Array> array = v8::Array::New(list.count());
+ QV4::ArrayObject *a = m_v4Engine->newArrayObject();
+ a->arrayReserve(list.count());
+ a->arrayDataLen = list.count();
for (int ii = 0; ii < list.count(); ++ii)
- array->Set(ii, newQObject(list.at(ii)));
- return array;
+ a->arrayData[ii].value = QV4::QObjectWrapper::wrap(m_v4Engine, list.at(ii));
+ a->setArrayLengthUnchecked(list.count());
+ return QV4::Value::fromObject(a);
}
bool objOk;
QObject *obj = QQmlMetaType::toQObject(variant, &objOk);
if (objOk)
- return newQObject(obj);
+ return QV4::QObjectWrapper::wrap(m_v4Engine, obj);
bool succeeded = false;
- v8::Handle<v8::Value> retn = m_sequenceWrapper.fromVariant(variant, &succeeded);
+ QV4::Value retn = QV4::SequencePrototype::fromVariant(m_v4Engine, variant, &succeeded);
if (succeeded)
return retn;
if (QQmlValueType *vt = QQmlValueTypeFactory::valueType(type))
- return m_valueTypeWrapper.newValueType(variant, vt);
+ return QV4::QmlValueTypeWrapper::create(this, variant, vt);
}
// XXX TODO: To be compatible, we still need to handle:
// + QObjectList
// + QList<int>
- return m_variantWrapper.newVariant(variant);
-}
-
-// A handle scope and context must be entered
-v8::Local<v8::Script> QV8Engine::qmlModeCompile(const QString &source,
- const QString &fileName,
- quint16 lineNumber)
-{
- v8::Local<v8::String> v8source = m_stringWrapper.toString(source);
- v8::Local<v8::String> v8fileName = m_stringWrapper.toString(fileName);
-
- v8::ScriptOrigin origin(v8fileName, v8::Integer::New(lineNumber - 1));
-
- v8::Local<v8::Script> script = v8::Script::Compile(v8source, &origin, 0, v8::Handle<v8::String>(),
- v8::Script::QmlMode);
-
- return script;
-}
-
-// A handle scope and context must be entered.
-// source can be either ascii or utf8.
-v8::Local<v8::Script> QV8Engine::qmlModeCompile(const char *source, int sourceLength,
- const QString &fileName,
- quint16 lineNumber)
-{
- if (sourceLength == -1)
- sourceLength = int(strlen(source));
-
- v8::Local<v8::String> v8source = v8::String::New(source, sourceLength);
- v8::Local<v8::String> v8fileName = m_stringWrapper.toString(fileName);
-
- v8::ScriptOrigin origin(v8fileName, v8::Integer::New(lineNumber - 1));
-
- v8::Local<v8::Script> script = v8::Script::Compile(v8source, &origin, 0, v8::Handle<v8::String>(),
- v8::Script::QmlMode);
-
- return script;
+ return QV4::Value::fromObject(m_v4Engine->newVariantObject(variant));
}
QNetworkAccessManager *QV8Engine::networkAccessManager()
@@ -485,27 +338,14 @@ QNetworkAccessManager *QV8Engine::networkAccessManager()
return QQmlEnginePrivate::get(m_engine)->getNetworkAccessManager();
}
-const QStringHash<bool> &QV8Engine::illegalNames() const
+const QV4::IdentifierHash<bool> &QV8Engine::illegalNames() const
{
return m_illegalNames;
}
-// Requires a handle scope
-v8::Local<v8::Array> QV8Engine::getOwnPropertyNames(v8::Handle<v8::Object> o)
-{
- // FIXME Newer v8 have API for this function
- v8::TryCatch tc;
- v8::Handle<v8::Value> args[] = { o };
- v8::Local<v8::Value> r = m_getOwnPropertyNames->Call(global(), 1, args);
- if (tc.HasCaught())
- return v8::Array::New();
- else
- return v8::Local<v8::Array>::Cast(r);
-}
-
QQmlContextData *QV8Engine::callingContext()
{
- return m_contextWrapper.callingContext();
+ return QV4::QmlContextWrapper::callingContext(m_v4Engine);
}
// Converts a JS value to a QVariant.
@@ -517,178 +357,59 @@ QQmlContextData *QV8Engine::callingContext()
// Date -> QVariant(QDateTime)
// RegExp -> QVariant(QRegExp)
// [Any other object] -> QVariantMap(...)
-QVariant QV8Engine::toBasicVariant(v8::Handle<v8::Value> value)
+QVariant QV8Engine::toBasicVariant(const QV4::Value &value)
{
- if (value->IsNull() || value->IsUndefined())
+ if (value.isNull() || value.isUndefined())
return QVariant();
- if (value->IsBoolean())
- return value->ToBoolean()->Value();
- if (value->IsInt32())
- return value->ToInt32()->Value();
- if (value->IsNumber())
- return value->ToNumber()->Value();
- if (value->IsString())
- return m_stringWrapper.toString(value->ToString());
- if (value->IsDate())
- return qtDateTimeFromJsDate(v8::Handle<v8::Date>::Cast(value)->NumberValue());
+ if (value.isBoolean())
+ return value.booleanValue();
+ if (value.isInteger())
+ return value.integerValue();
+ if (value.isNumber())
+ return value.asDouble();
+ if (value.isString())
+ return value.stringValue()->toQString();
+ if (QV4::DateObject *d = value.asDateObject())
+ return d->toQDateTime();
// NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
- Q_ASSERT(value->IsObject());
+ Q_ASSERT(value.isObject());
- if (value->IsRegExp()) {
- v8::Context::Scope scope(context());
- return QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(value));
- }
- if (value->IsArray()) {
- v8::Context::Scope scope(context());
+ if (QV4::RegExpObject *re = value.as<QV4::RegExpObject>())
+ return re->toQRegExp();
+ if (QV4::ArrayObject *a = value.asArrayObject()) {
QVariantList rv;
- v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
- int length = array->Length();
+ int length = a->arrayLength();
for (int ii = 0; ii < length; ++ii)
- rv << toVariant(array->Get(ii), -1);
+ rv << toVariant(a->getIndexed(ii), -1);
return rv;
}
- if (!value->IsFunction()) {
- v8::Context::Scope scope(context());
- v8::Handle<v8::Object> object = value->ToObject();
- return variantMapFromJS(object);
- }
+ if (!value.asFunctionObject())
+ return variantMapFromJS(value.asObject());
return QVariant();
}
-struct StaticQtMetaObject : public QObject
+void QV8Engine::initializeGlobal()
{
- static const QMetaObject *get()
- { return &staticQtMetaObject; }
-};
+ QV4::GlobalExtensions::init(m_engine, m_v4Engine->globalObject);
-void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global)
-{
- using namespace QQmlBuiltinFunctions;
-
- v8::Local<v8::Object> console = v8::Object::New();
- v8::Local<v8::Function> consoleLogFn = V8FUNCTION(consoleLog, this);
-
- console->Set(v8::String::New("debug"), consoleLogFn);
- console->Set(v8::String::New("log"), consoleLogFn);
- console->Set(v8::String::New("info"), consoleLogFn);
- console->Set(v8::String::New("warn"), V8FUNCTION(consoleWarn, this));
- console->Set(v8::String::New("error"), V8FUNCTION(consoleError, this));
- console->Set(v8::String::New("assert"), V8FUNCTION(consoleAssert, this));
-
- console->Set(v8::String::New("count"), V8FUNCTION(consoleCount, this));
- console->Set(v8::String::New("profile"), V8FUNCTION(consoleProfile, this));
- console->Set(v8::String::New("profileEnd"), V8FUNCTION(consoleProfileEnd, this));
- console->Set(v8::String::New("time"), V8FUNCTION(consoleTime, this));
- console->Set(v8::String::New("timeEnd"), V8FUNCTION(consoleTimeEnd, this));
- console->Set(v8::String::New("trace"), V8FUNCTION(consoleTrace, this));
- console->Set(v8::String::New("exception"), V8FUNCTION(consoleException, this));
-
- v8::Local<v8::Object> qt = v8::Object::New();
-
- // Set all the enums from the "Qt" namespace
- const QMetaObject *qtMetaObject = StaticQtMetaObject::get();
- for (int ii = 0; ii < qtMetaObject->enumeratorCount(); ++ii) {
- QMetaEnum enumerator = qtMetaObject->enumerator(ii);
- for (int jj = 0; jj < enumerator.keyCount(); ++jj) {
- qt->Set(v8::String::New(enumerator.key(jj)), v8::Integer::New(enumerator.value(jj)));
- }
- }
- qt->Set(v8::String::New("Asynchronous"), v8::Integer::New(0));
- qt->Set(v8::String::New("Synchronous"), v8::Integer::New(1));
-
- qt->Set(v8::String::New("include"), V8FUNCTION(QV8Include::include, this));
- qt->Set(v8::String::New("isQtObject"), V8FUNCTION(isQtObject, this));
- qt->Set(v8::String::New("rgba"), V8FUNCTION(rgba, this));
- qt->Set(v8::String::New("hsla"), V8FUNCTION(hsla, this));
- qt->Set(v8::String::New("colorEqual"), V8FUNCTION(colorEqual, this));
- qt->Set(v8::String::New("font"), V8FUNCTION(font, this));
- qt->Set(v8::String::New("rect"), V8FUNCTION(rect, this));
- qt->Set(v8::String::New("point"), V8FUNCTION(point, this));
- qt->Set(v8::String::New("size"), V8FUNCTION(size, this));
-
- qt->Set(v8::String::New("vector2d"), V8FUNCTION(vector2d, this));
- qt->Set(v8::String::New("vector3d"), V8FUNCTION(vector3d, this));
- qt->Set(v8::String::New("vector4d"), V8FUNCTION(vector4d, this));
- qt->Set(v8::String::New("quaternion"), V8FUNCTION(quaternion, this));
- qt->Set(v8::String::New("matrix4x4"), V8FUNCTION(matrix4x4, this));
-
- qt->Set(v8::String::New("formatDate"), V8FUNCTION(formatDate, this));
- qt->Set(v8::String::New("formatTime"), V8FUNCTION(formatTime, this));
- qt->Set(v8::String::New("formatDateTime"), V8FUNCTION(formatDateTime, this));
-
- qt->Set(v8::String::New("openUrlExternally"), V8FUNCTION(openUrlExternally, this));
- qt->Set(v8::String::New("fontFamilies"), V8FUNCTION(fontFamilies, this));
- qt->Set(v8::String::New("md5"), V8FUNCTION(md5, this));
- qt->Set(v8::String::New("btoa"), V8FUNCTION(btoa, this));
- qt->Set(v8::String::New("atob"), V8FUNCTION(atob, this));
- qt->Set(v8::String::New("resolvedUrl"), V8FUNCTION(resolvedUrl, this));
- qt->Set(v8::String::New("locale"), V8FUNCTION(locale, this));
- qt->Set(v8::String::New("binding"), V8FUNCTION(binding, this));
-
- if (m_engine) {
- qt->SetAccessor(v8::String::New("platform"), getPlatform, 0, v8::External::New(this));
- qt->SetAccessor(v8::String::New("application"), getApplication, 0, v8::External::New(this));
-#ifndef QT_NO_IM
- qt->SetAccessor(v8::String::New("inputMethod"), getInputMethod, 0, v8::External::New(this));
-#endif
- qt->Set(v8::String::New("lighter"), V8FUNCTION(lighter, this));
- qt->Set(v8::String::New("darker"), V8FUNCTION(darker, this));
- qt->Set(v8::String::New("tint"), V8FUNCTION(tint, this));
- qt->Set(v8::String::New("quit"), V8FUNCTION(quit, this));
- qt->Set(v8::String::New("createQmlObject"), V8FUNCTION(createQmlObject, this));
- qt->Set(v8::String::New("createComponent"), V8FUNCTION(createComponent, this));
- }
-
-#ifndef QT_NO_TRANSLATION
- global->Set(v8::String::New("qsTranslate"), V8FUNCTION(qsTranslate, this));
- global->Set(v8::String::New("QT_TRANSLATE_NOOP"), V8FUNCTION(qsTranslateNoOp, this));
- global->Set(v8::String::New("qsTr"), V8FUNCTION(qsTr, this));
- global->Set(v8::String::New("QT_TR_NOOP"), V8FUNCTION(qsTrNoOp, this));
- global->Set(v8::String::New("qsTrId"), V8FUNCTION(qsTrId, this));
- global->Set(v8::String::New("QT_TRID_NOOP"), V8FUNCTION(qsTrIdNoOp, this));
-#endif
+ QQmlLocale::registerStringLocaleCompare(m_v4Engine);
+ QQmlDateExtension::registerExtension(m_v4Engine);
+ QQmlNumberExtension::registerExtension(m_v4Engine);
- global->Set(v8::String::New("print"), consoleLogFn);
- global->Set(v8::String::New("console"), console);
- global->Set(v8::String::New("Qt"), qt);
- global->Set(v8::String::New("gc"), V8FUNCTION(QQmlBuiltinFunctions::gc, this));
-
- {
-#define STRING_ARG "(function(stringArg) { "\
- " String.prototype.arg = (function() {"\
- " return stringArg.apply(this, arguments);"\
- " })"\
- "})"
-
- v8::Local<v8::Script> registerArg = v8::Script::New(v8::String::New(STRING_ARG), 0, 0, v8::Handle<v8::String>(), v8::Script::NativeMode);
- v8::Local<v8::Value> result = registerArg->Run();
- Q_ASSERT(result->IsFunction());
- v8::Local<v8::Function> registerArgFunc = v8::Local<v8::Function>::Cast(result);
- v8::Handle<v8::Value> args = V8FUNCTION(stringArg, this);
- registerArgFunc->Call(v8::Local<v8::Object>::Cast(registerArgFunc), 1, &args);
-#undef STRING_ARG
- }
-
- QQmlLocale::registerStringLocaleCompare(this);
- QQmlDateExtension::registerExtension(this);
- QQmlNumberExtension::registerExtension(this);
-
- qt_add_domexceptions(this);
+ qt_add_domexceptions(m_v4Engine);
m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(this);
- qt_add_sqlexceptions(this);
+ qt_add_sqlexceptions(m_v4Engine);
{
- v8::Handle<v8::Value> args[] = { global };
- v8::Local<v8::Value> names = m_getOwnPropertyNames->Call(global, 1, args);
- v8::Local<v8::Array> namesArray = v8::Local<v8::Array>::Cast(names);
- for (quint32 ii = 0; ii < namesArray->Length(); ++ii)
- m_illegalNames.insert(toString(namesArray->Get(ii)), true);
+ m_illegalNames = QV4::IdentifierHash<bool>(m_v4Engine);
+ for (uint i = 0; i < m_v4Engine->globalObject->internalClass->size; ++i)
+ m_illegalNames.add(m_v4Engine->globalObject->internalClass->nameMap.at(i)->toQString(), true);
}
{
@@ -710,63 +431,24 @@ void QV8Engine::initializeGlobal(v8::Handle<v8::Object> global)
" }"\
"})"
- v8::Local<v8::Script> freeze = v8::Script::New(v8::String::New(FREEZE_SOURCE));
- v8::Local<v8::Value> result = freeze->Run();
- Q_ASSERT(result->IsFunction());
- m_freezeObject = qPersistentNew(v8::Local<v8::Function>::Cast(result));
+ QV4::Value result = QV4::Script::evaluate(m_v4Engine, QString::fromUtf8(FREEZE_SOURCE), 0);
+ Q_ASSERT(result.asFunctionObject());
+ m_freezeObject = result;
#undef FREEZE_SOURCE
}
}
-void QV8Engine::freezeObject(v8::Handle<v8::Value> value)
+void QV8Engine::freezeObject(const QV4::Value &value)
{
- v8::Handle<v8::Value> args[] = { value };
- m_freezeObject->Call(global(), 1, args);
+ QV4::Value args = value;
+ m_freezeObject.value().asFunctionObject()->call(QV4::Value::fromObject(m_v4Engine->globalObject), &args, 1);
}
void QV8Engine::gc()
{
- v8::V8::LowMemoryNotification();
- while (!v8::V8::IdleNotification()) {}
-}
-
-#ifdef QML_GLOBAL_HANDLE_DEBUGGING
-#include <QtCore/qthreadstorage.h>
-static QThreadStorage<QSet<void *> *> QV8Engine_activeHandles;
-
-void QV8Engine::registerHandle(void *handle)
-{
- if (!handle) {
- qWarning("Attempting to register a null handle");
- return;
- }
-
- if (!QV8Engine_activeHandles.hasLocalData())
- QV8Engine_activeHandles.setLocalData(new QSet<void *>);
-
- if (QV8Engine_activeHandles.localData()->contains(handle)) {
- qFatal("Handle %p already alive", handle);
- } else {
- QV8Engine_activeHandles.localData()->insert(handle);
- }
+ m_v4Engine->memoryManager->runGC();
}
-void QV8Engine::releaseHandle(void *handle)
-{
- if (!handle)
- return;
-
- if (!QV8Engine_activeHandles.hasLocalData())
- QV8Engine_activeHandles.setLocalData(new QSet<void *>);
-
- if (QV8Engine_activeHandles.localData()->contains(handle)) {
- QV8Engine_activeHandles.localData()->remove(handle);
- } else {
- qFatal("Handle %p already dead", handle);
- }
-}
-#endif
-
struct QV8EngineRegistrationData
{
QV8EngineRegistrationData() : extensionCount(0) {}
@@ -797,115 +479,10 @@ void QV8Engine::setExtensionData(int index, Deletable *data)
m_extensionData[index] = data;
}
-double QV8Engine::qtDateTimeToJsDate(const QDateTime &dt)
-{
- if (!dt.isValid()) {
- return qSNaN();
- }
-
- return dt.toMSecsSinceEpoch();
-}
-
-QDateTime QV8Engine::qtDateTimeFromJsDate(double jsDate)
-{
- if (qIsNaN(jsDate))
- return QDateTime();
-
- return QDateTime::fromMSecsSinceEpoch(jsDate);
-}
-
-v8::Persistent<v8::Object> *QV8Engine::findOwnerAndStrength(QObject *object, bool *shouldBeStrong)
-{
- QQmlData *data = QQmlData::get(object);
- if (data && data->rootObjectInCreation) { // When the object is still being created it may not show up to the GC.
- *shouldBeStrong = true;
- return 0;
- }
-
- QObject *parent = object->parent();
- if (!parent) {
- // if the object has JS ownership, the object's v8object owns the lifetime of the persistent value.
- if (QQmlEngine::objectOwnership(object) == QQmlEngine::JavaScriptOwnership) {
- *shouldBeStrong = false;
- return &(QQmlData::get(object)->v8object);
- }
-
- // no parent, and has CPP ownership - doesn't have an implicit parent.
- *shouldBeStrong = true;
- return 0;
- }
-
- // if it is owned by CPP, it's root parent may still be owned by JS.
- // in that case, the owner of the persistent handle is the root parent's v8object.
- while (parent->parent())
- parent = parent->parent();
-
- if (QQmlEngine::objectOwnership(parent) == QQmlEngine::JavaScriptOwnership) {
- // root parent is owned by JS. It's v8object owns the persistent value in question.
- *shouldBeStrong = false;
- return &(QQmlData::get(parent)->v8object);
- } else {
- // root parent has CPP ownership. The persistent value should not be made weak.
- *shouldBeStrong = true;
- return 0;
- }
-}
-
-void QV8Engine::addRelationshipForGC(QObject *object, v8::Persistent<v8::Value> handle)
-{
- if (!object || handle.IsEmpty())
- return;
-
- bool handleShouldBeStrong = false;
- v8::Persistent<v8::Object> *implicitOwner = findOwnerAndStrength(object, &handleShouldBeStrong);
- if (handleShouldBeStrong) {
- v8::V8::AddImplicitReferences(m_strongReferencer, &handle, 1);
- } else if (!implicitOwner->IsEmpty()) {
- v8::V8::AddImplicitReferences(*implicitOwner, &handle, 1);
- }
-}
-
-void QV8Engine::addRelationshipForGC(QObject *object, QObject *other)
-{
- if (!object || !other)
- return;
-
- bool handleShouldBeStrong = false;
- v8::Persistent<v8::Object> *implicitOwner = findOwnerAndStrength(object, &handleShouldBeStrong);
- v8::Persistent<v8::Value> handle = QQmlData::get(other, true)->v8object;
- if (handle.IsEmpty()) // no JS data to keep alive.
- return;
- else if (handleShouldBeStrong)
- v8::V8::AddImplicitReferences(m_strongReferencer, &handle, 1);
- else if (!implicitOwner->IsEmpty())
- v8::V8::AddImplicitReferences(*implicitOwner, &handle, 1);
-}
-
-static QThreadStorage<QV8Engine::ThreadData*> perThreadEngineData;
-
-bool QV8Engine::hasThreadData()
-{
- return perThreadEngineData.hasLocalData();
-}
-
-QV8Engine::ThreadData *QV8Engine::threadData()
-{
- Q_ASSERT(perThreadEngineData.hasLocalData());
- return perThreadEngineData.localData();
-}
-
-void QV8Engine::ensurePerThreadIsolate()
-{
- if (!perThreadEngineData.hasLocalData())
- perThreadEngineData.setLocalData(new ThreadData);
-}
-
void QV8Engine::initQmlGlobalObject()
{
- v8::HandleScope handels;
- v8::Context::Scope contextScope(m_context);
- initializeGlobal(m_context->Global());
- freezeObject(m_context->Global());
+ initializeGlobal();
+ freezeObject(QV4::Value::fromObject(m_v4Engine->globalObject));
}
void QV8Engine::setEngine(QQmlEngine *engine)
@@ -914,40 +491,51 @@ void QV8Engine::setEngine(QQmlEngine *engine)
initQmlGlobalObject();
}
-v8::Handle<v8::Value> QV8Engine::throwException(v8::Handle<v8::Value> value)
+QV4::Value QV8Engine::global()
{
- v8::ThrowException(value);
- return value;
+ return QV4::Value::fromObject(m_v4Engine->globalObject);
}
// Converts a QVariantList to JS.
// The result is a new Array object with length equal to the length
// of the QVariantList, and the elements being the QVariantList's
// elements converted to JS, recursively.
-v8::Local<v8::Array> QV8Engine::variantListToJS(const QVariantList &lst)
+QV4::Value QV8Engine::variantListToJS(const QVariantList &lst)
{
- v8::Local<v8::Array> result = v8::Array::New(lst.size());
- for (int i = 0; i < lst.size(); ++i)
- result->Set(i, variantToJS(lst.at(i)));
- return result;
+ QV4::ArrayObject *a = m_v4Engine->newArrayObject();
+ a->arrayReserve(lst.size());
+ a->arrayDataLen = lst.size();
+ for (int i = 0; i < lst.size(); i++)
+ a->arrayData[i].value = variantToJS(lst.at(i));
+ a->setArrayLengthUnchecked(lst.size());
+ return QV4::Value::fromObject(a);
}
// Converts a JS Array object to a QVariantList.
// The result is a QVariantList with length equal to the length
// of the JS Array, and elements being the JS Array's elements
// converted to QVariants, recursively.
-QVariantList QV8Engine::variantListFromJS(v8::Handle<v8::Array> jsArray,
+QVariantList QV8Engine::variantListFromJS(QV4::ArrayObject *a,
V8ObjectSet &visitedObjects)
{
QVariantList result;
- if (visitedObjects.contains(jsArray))
- return result; // Avoid recursion.
- v8::HandleScope handleScope;
- visitedObjects.insert(jsArray);
- uint32_t length = jsArray->Length();
- for (uint32_t i = 0; i < length; ++i)
- result.append(variantFromJS(jsArray->Get(i), visitedObjects));
- visitedObjects.remove(jsArray);
+ if (!a)
+ return result;
+
+ if (visitedObjects.contains(a))
+ // Avoid recursion.
+ return result;
+
+ visitedObjects.insert(a);
+
+ quint32 length = a->arrayLength();
+ for (quint32 i = 0; i < length; ++i) {
+ QV4::Value v = a->getIndexed(i);
+ result.append(variantFromJS(v, visitedObjects));
+ }
+
+ visitedObjects.remove(a);
+
return result;
}
@@ -955,91 +543,100 @@ QVariantList QV8Engine::variantListFromJS(v8::Handle<v8::Array> jsArray,
// The result is a new Object object with property names being
// the keys of the QVariantMap, and values being the values of
// the QVariantMap converted to JS, recursively.
-v8::Local<v8::Object> QV8Engine::variantMapToJS(const QVariantMap &vmap)
+QV4::Value QV8Engine::variantMapToJS(const QVariantMap &vmap)
{
- v8::Local<v8::Object> result = v8::Object::New();
+ QV4::Object *o = m_v4Engine->newObject();
QVariantMap::const_iterator it;
- for (it = vmap.constBegin(); it != vmap.constEnd(); ++it)
- result->Set(QJSConverter::toString(it.key()), variantToJS(it.value()));
- return result;
+ for (it = vmap.constBegin(); it != vmap.constEnd(); ++it) {
+ QV4::Property *p = o->insertMember(m_v4Engine->newIdentifier(it.key()), QV4::Attr_Data);
+ p->value = variantToJS(it.value());
+ }
+ return QV4::Value::fromObject(o);
}
// Converts a JS Object to a QVariantMap.
// The result is a QVariantMap with keys being the property names
// of the object, and values being the values of the JS object's
// properties converted to QVariants, recursively.
-QVariantMap QV8Engine::variantMapFromJS(v8::Handle<v8::Object> jsObject,
+QVariantMap QV8Engine::variantMapFromJS(QV4::Object *o,
V8ObjectSet &visitedObjects)
{
QVariantMap result;
- v8::HandleScope handleScope;
- v8::Handle<v8::Array> propertyNames = jsObject->GetPropertyNames();
- uint32_t length = propertyNames->Length();
- if (length == 0)
+ if (!o || o->asFunctionObject())
return result;
- if (visitedObjects.contains(jsObject))
- return result; // Avoid recursion.
+ if (visitedObjects.contains(o)) {
+ // Avoid recursion.
+ // For compatibility with QVariant{List,Map} conversion, we return an
+ // empty object (and no error is thrown).
+ return result;
+ }
+
+ visitedObjects.insert(o);
+
+ QV4::ObjectIterator it(o, QV4::ObjectIterator::EnumerableOnly);
+ while (1) {
+ QV4::Value v;
+ QV4::Value name = it.nextPropertyNameAsString(&v);
+ if (name.isNull())
+ break;
- visitedObjects.insert(jsObject);
- // TODO: Only object's own property names. Include non-enumerable properties.
- for (uint32_t i = 0; i < length; ++i) {
- v8::Handle<v8::Value> name = propertyNames->Get(i);
- result.insert(QJSConverter::toString(name->ToString()),
- variantFromJS(jsObject->Get(name), visitedObjects));
+ QString key = name.toQString();
+ result.insert(key, variantFromJS(v, visitedObjects));
}
- visitedObjects.remove(jsObject);
+
+ visitedObjects.remove(o);
return result;
}
// Converts the meta-type defined by the given type and data to JS.
// Returns the value if conversion succeeded, an empty handle otherwise.
-v8::Handle<v8::Value> QV8Engine::metaTypeToJS(int type, const void *data)
+QV4::Value QV8Engine::metaTypeToJS(int type, const void *data)
{
Q_ASSERT(data != 0);
- v8::Handle<v8::Value> result;
+ QV4::Value result;
// check if it's one of the types we know
switch (QMetaType::Type(type)) {
case QMetaType::UnknownType:
case QMetaType::Void:
- return v8::Undefined();
+ return QV4::Value::undefinedValue();
case QMetaType::Bool:
- return v8::Boolean::New(*reinterpret_cast<const bool*>(data));
+ return QV4::Value::fromBoolean(*reinterpret_cast<const bool*>(data));
case QMetaType::Int:
- return v8::Int32::New(*reinterpret_cast<const int*>(data));
+ return QV4::Value::fromInt32(*reinterpret_cast<const int*>(data));
case QMetaType::UInt:
- return v8::Uint32::New(*reinterpret_cast<const uint*>(data));
+ return QV4::Value::fromUInt32(*reinterpret_cast<const uint*>(data));
case QMetaType::LongLong:
- return v8::Number::New(double(*reinterpret_cast<const qlonglong*>(data)));
+ return QV4::Value::fromDouble(double(*reinterpret_cast<const qlonglong*>(data)));
case QMetaType::ULongLong:
#if defined(Q_OS_WIN) && defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 12008804
#pragma message("** NOTE: You need the Visual Studio Processor Pack to compile support for 64bit unsigned integers.")
- return v8::Number::New(double((qlonglong)*reinterpret_cast<const qulonglong*>(data)));
+ return QV4::Value::fromDouble(double((qlonglong)*reinterpret_cast<const qulonglong*>(data)));
#elif defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET)
- return v8::Number::New(double((qlonglong)*reinterpret_cast<const qulonglong*>(data)));
+ return QV4::Value::fromDouble(double((qlonglong)*reinterpret_cast<const qulonglong*>(data)));
#else
- return v8::Number::New(double(*reinterpret_cast<const qulonglong*>(data)));
+ return QV4::Value::fromDouble(double(*reinterpret_cast<const qulonglong*>(data)));
#endif
case QMetaType::Double:
- return v8::Number::New(double(*reinterpret_cast<const double*>(data)));
+ return QV4::Value::fromDouble(*reinterpret_cast<const double*>(data));
case QMetaType::QString:
- return QJSConverter::toString(*reinterpret_cast<const QString*>(data));
+ return QV4::Value::fromString(m_v4Engine->current, *reinterpret_cast<const QString*>(data));
case QMetaType::Float:
- return v8::Number::New(*reinterpret_cast<const float*>(data));
+ return QV4::Value::fromDouble(*reinterpret_cast<const float*>(data));
case QMetaType::Short:
- return v8::Int32::New(*reinterpret_cast<const short*>(data));
+ return QV4::Value::fromInt32(*reinterpret_cast<const short*>(data));
case QMetaType::UShort:
- return v8::Uint32::New(*reinterpret_cast<const unsigned short*>(data));
+ return QV4::Value::fromUInt32(*reinterpret_cast<const unsigned short*>(data));
case QMetaType::Char:
- return v8::Int32::New(*reinterpret_cast<const char*>(data));
+ return QV4::Value::fromInt32(*reinterpret_cast<const char*>(data));
case QMetaType::UChar:
- return v8::Uint32::New(*reinterpret_cast<const unsigned char*>(data));
+ return QV4::Value::fromUInt32(*reinterpret_cast<const unsigned char*>(data));
case QMetaType::QChar:
- return v8::Uint32::New((*reinterpret_cast<const QChar*>(data)).unicode());
+ return QV4::Value::fromUInt32((*reinterpret_cast<const QChar*>(data)).unicode());
case QMetaType::QStringList:
- result = QJSConverter::toStringList(*reinterpret_cast<const QStringList *>(data));
+ result = QV4::Value::fromObject(m_v4Engine->newArrayObject(*reinterpret_cast<const QStringList *>(data)));
break;
case QMetaType::QVariantList:
result = variantListToJS(*reinterpret_cast<const QVariantList *>(data));
@@ -1048,39 +645,39 @@ v8::Handle<v8::Value> QV8Engine::metaTypeToJS(int type, const void *data)
result = variantMapToJS(*reinterpret_cast<const QVariantMap *>(data));
break;
case QMetaType::QDateTime:
- result = QJSConverter::toDateTime(*reinterpret_cast<const QDateTime *>(data));
+ result = QV4::Value::fromObject(m_v4Engine->newDateObject(*reinterpret_cast<const QDateTime *>(data)));
break;
case QMetaType::QDate:
- result = QJSConverter::toDateTime(QDateTime(*reinterpret_cast<const QDate *>(data)));
+ result = QV4::Value::fromObject(m_v4Engine->newDateObject(QDateTime(*reinterpret_cast<const QDate *>(data))));
break;
case QMetaType::QRegExp:
- result = QJSConverter::toRegExp(*reinterpret_cast<const QRegExp *>(data));
+ result = QV4::Value::fromObject(m_v4Engine->newRegExpObject(*reinterpret_cast<const QRegExp *>(data)));
break;
case QMetaType::QObjectStar:
- result = newQObject(*reinterpret_cast<QObject* const *>(data));
+ result = QV4::QObjectWrapper::wrap(m_v4Engine, *reinterpret_cast<QObject* const *>(data));
break;
case QMetaType::QVariant:
result = variantToJS(*reinterpret_cast<const QVariant*>(data));
break;
case QMetaType::QJsonValue:
- result = jsonValueToJS(*reinterpret_cast<const QJsonValue *>(data));
+ result = QV4::JsonObject::fromJsonValue(m_v4Engine, *reinterpret_cast<const QJsonValue *>(data));
break;
case QMetaType::QJsonObject:
- result = jsonObjectToJS(*reinterpret_cast<const QJsonObject *>(data));
+ result = QV4::JsonObject::fromJsonObject(m_v4Engine, *reinterpret_cast<const QJsonObject *>(data));
break;
case QMetaType::QJsonArray:
- result = jsonArrayToJS(*reinterpret_cast<const QJsonArray *>(data));
+ result = QV4::JsonObject::fromJsonArray(m_v4Engine, *reinterpret_cast<const QJsonArray *>(data));
break;
default:
if (type == qMetaTypeId<QJSValue>()) {
- return QJSValuePrivate::get(*reinterpret_cast<const QJSValue*>(data))->asV8Value(this);
+ return QJSValuePrivate::get(*reinterpret_cast<const QJSValue*>(data))->getValue(m_v4Engine);
} else {
QByteArray typeName = QMetaType::typeName(type);
if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(data)) {
- return v8::Null();
+ return QV4::Value::nullValue();
} else {
// Fall back to wrapping in a QVariant.
- result = newVariant(QVariant(type, data));
+ result = QV4::Value::fromObject(m_v4Engine->newVariantObject(QVariant(type, data)));
}
}
}
@@ -1090,102 +687,104 @@ v8::Handle<v8::Value> QV8Engine::metaTypeToJS(int type, const void *data)
// Converts a JS value to a meta-type.
// data must point to a place that can store a value of the given type.
// Returns true if conversion succeeded, false otherwise.
-bool QV8Engine::metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data) {
+bool QV8Engine::metaTypeFromJS(const QV4::Value &value, int type, void *data) {
// check if it's one of the types we know
switch (QMetaType::Type(type)) {
case QMetaType::Bool:
- *reinterpret_cast<bool*>(data) = value->ToBoolean()->Value();
+ *reinterpret_cast<bool*>(data) = value.toBoolean();
return true;
case QMetaType::Int:
- *reinterpret_cast<int*>(data) = value->ToInt32()->Value();
+ *reinterpret_cast<int*>(data) = value.toInt32();
return true;
case QMetaType::UInt:
- *reinterpret_cast<uint*>(data) = value->ToUint32()->Value();
+ *reinterpret_cast<uint*>(data) = value.toUInt32();
return true;
case QMetaType::LongLong:
- *reinterpret_cast<qlonglong*>(data) = qlonglong(value->ToInteger()->Value());
+ *reinterpret_cast<qlonglong*>(data) = qlonglong(value.toInteger());
return true;
case QMetaType::ULongLong:
- *reinterpret_cast<qulonglong*>(data) = qulonglong(value->ToInteger()->Value());
+ *reinterpret_cast<qulonglong*>(data) = qulonglong(value.toInteger());
return true;
case QMetaType::Double:
- *reinterpret_cast<double*>(data) = value->ToNumber()->Value();
+ *reinterpret_cast<double*>(data) = value.toNumber();
return true;
case QMetaType::QString:
- if (value->IsUndefined() || value->IsNull())
+ if (value.isUndefined() || value.isNull())
*reinterpret_cast<QString*>(data) = QString();
else
- *reinterpret_cast<QString*>(data) = QJSConverter::toString(value->ToString());
+ *reinterpret_cast<QString*>(data) = value.toString(m_v4Engine->current)->toQString();
return true;
case QMetaType::Float:
- *reinterpret_cast<float*>(data) = value->ToNumber()->Value();
+ *reinterpret_cast<float*>(data) = value.toNumber();
return true;
case QMetaType::Short:
- *reinterpret_cast<short*>(data) = short(value->ToInt32()->Value());
+ *reinterpret_cast<short*>(data) = short(value.toInt32());
return true;
case QMetaType::UShort:
- *reinterpret_cast<unsigned short*>(data) = ushort(value->ToInt32()->Value()); // ### QScript::ToUInt16()
+ *reinterpret_cast<unsigned short*>(data) = value.toUInt16();
return true;
case QMetaType::Char:
- *reinterpret_cast<char*>(data) = char(value->ToInt32()->Value());
+ *reinterpret_cast<char*>(data) = char(value.toInt32());
return true;
case QMetaType::UChar:
- *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->ToInt32()->Value());
+ *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value.toInt32());
return true;
case QMetaType::QChar:
- if (value->IsString()) {
- QString str = QJSConverter::toString(v8::Handle<v8::String>::Cast(value));
+ if (value.isString()) {
+ QString str = value.stringValue()->toQString();
*reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0);
} else {
- *reinterpret_cast<QChar*>(data) = QChar(ushort(value->ToInt32()->Value())); // ### QScript::ToUInt16()
+ *reinterpret_cast<QChar*>(data) = QChar(ushort(value.toUInt16()));
}
return true;
case QMetaType::QDateTime:
- if (value->IsDate()) {
- *reinterpret_cast<QDateTime *>(data) = QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value));
+ if (QV4::DateObject *d = value.asDateObject()) {
+ *reinterpret_cast<QDateTime *>(data) = d->toQDateTime();
return true;
} break;
case QMetaType::QDate:
- if (value->IsDate()) {
- *reinterpret_cast<QDate *>(data) = QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value)).date();
+ if (QV4::DateObject *d = value.asDateObject()) {
+ *reinterpret_cast<QDate *>(data) = d->toQDateTime().date();
return true;
} break;
case QMetaType::QRegExp:
- if (value->IsRegExp()) {
- *reinterpret_cast<QRegExp *>(data) = QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(value));
+ if (QV4::RegExpObject *r = value.as<QV4::RegExpObject>()) {
+ *reinterpret_cast<QRegExp *>(data) = r->toQRegExp();
return true;
} break;
- case QMetaType::QObjectStar:
- if (isQObject(value) || value->IsNull()) {
+ case QMetaType::QObjectStar: {
+ QV4::QObjectWrapper *qobjectWrapper = value.as<QV4::QObjectWrapper>();
+ if (qobjectWrapper || value.isNull()) {
*reinterpret_cast<QObject* *>(data) = qtObjectFromJS(value);
return true;
} break;
+ }
case QMetaType::QStringList:
- if (value->IsArray()) {
- *reinterpret_cast<QStringList *>(data) = QJSConverter::toStringList(v8::Handle<v8::Array>::Cast(value));
+ if (QV4::ArrayObject *a = value.asArrayObject()) {
+ *reinterpret_cast<QStringList *>(data) = a->toQStringList();
return true;
} break;
case QMetaType::QVariantList:
- if (value->IsArray()) {
- *reinterpret_cast<QVariantList *>(data) = variantListFromJS(v8::Handle<v8::Array>::Cast(value));
+ if (QV4::ArrayObject *a = value.asArrayObject()) {
+ *reinterpret_cast<QVariantList *>(data) = variantListFromJS(a);
return true;
} break;
case QMetaType::QVariantMap:
- if (value->IsObject()) {
- *reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(v8::Handle<v8::Object>::Cast(value));
+ if (QV4::Object *o = value.asObject()) {
+ *reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(o);
return true;
} break;
case QMetaType::QVariant:
*reinterpret_cast<QVariant*>(data) = variantFromJS(value);
return true;
case QMetaType::QJsonValue:
- *reinterpret_cast<QJsonValue *>(data) = jsonValueFromJS(value);
+ *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(value);
return true;
case QMetaType::QJsonObject:
- *reinterpret_cast<QJsonObject *>(data) = jsonObjectFromJS(value);
+ *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(value.asObject());
return true;
case QMetaType::QJsonArray:
- *reinterpret_cast<QJsonArray *>(data) = jsonArrayFromJS(value);
+ *reinterpret_cast<QJsonArray *>(data) = QV4::JsonObject::toJsonArray(value.asArrayObject());
return true;
default:
;
@@ -1215,25 +814,25 @@ bool QV8Engine::metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data
QByteArray name = QMetaType::typeName(type);
if (convertToNativeQObject(value, name, reinterpret_cast<void* *>(data)))
return true;
- if (isVariant(value) && name.endsWith('*')) {
+ if (value.as<QV4::VariantObject>() && name.endsWith('*')) {
int valueType = QMetaType::type(name.left(name.size()-1));
- QVariant &var = variantValue(value);
+ QVariant &var = value.as<QV4::VariantObject>()->data;
if (valueType == var.userType()) {
// We have T t, T* is requested, so return &t.
*reinterpret_cast<void* *>(data) = var.data();
return true;
- } else {
+ } else if (QV4::Object *o = value.asObject()) {
// Look in the prototype chain.
- v8::Handle<v8::Value> proto = value->ToObject()->GetPrototype();
- while (proto->IsObject()) {
+ QV4::Object *proto = o->prototype;
+ while (proto) {
bool canCast = false;
- if (isVariant(proto)) {
- canCast = (type == variantValue(proto).userType())
- || (valueType && (valueType == variantValue(proto).userType()));
+ if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) {
+ const QVariant &v = vo->data;
+ canCast = (type == v.userType()) || (valueType && (valueType == v.userType()));
}
- else if (isQObject(proto)) {
+ else if (proto->as<QV4::QObjectWrapper>()) {
QByteArray className = name.left(name.size()-1);
- if (QObject *qobject = qtObjectFromJS(proto))
+ if (QObject *qobject = qtObjectFromJS(QV4::Value::fromObject(proto)))
canCast = qobject->qt_metacast(className) != 0;
}
if (canCast) {
@@ -1244,14 +843,14 @@ bool QV8Engine::metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data
*reinterpret_cast<void* *>(data) = var.data();
return true;
}
- proto = proto->ToObject()->GetPrototype();
+ proto = proto->prototype;
}
}
- } else if (value->IsNull() && name.endsWith('*')) {
+ } else if (value.isNull() && name.endsWith('*')) {
*reinterpret_cast<void* *>(data) = 0;
return true;
} else if (type == qMetaTypeId<QJSValue>()) {
- *reinterpret_cast<QJSValue*>(data) = QJSValuePrivate::get(new QJSValuePrivate(this, value));
+ *reinterpret_cast<QJSValue*>(data) = QJSValuePrivate::get(new QJSValuePrivate(m_v4Engine, value));
return true;
}
@@ -1259,7 +858,7 @@ bool QV8Engine::metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data
}
// Converts a QVariant to JS.
-v8::Handle<v8::Value> QV8Engine::variantToJS(const QVariant &value)
+QV4::Value QV8Engine::variantToJS(const QVariant &value)
{
return metaTypeToJS(value.userType(), value.constData());
}
@@ -1274,71 +873,40 @@ v8::Handle<v8::Value> QV8Engine::variantToJS(const QVariant &value)
// Date -> QVariant(QDateTime)
// RegExp -> QVariant(QRegExp)
// [Any other object] -> QVariantMap(...)
-QVariant QV8Engine::variantFromJS(v8::Handle<v8::Value> value,
+QVariant QV8Engine::variantFromJS(const QV4::Value &value,
V8ObjectSet &visitedObjects)
{
- Q_ASSERT(!value.IsEmpty());
- if (value->IsUndefined())
+ Q_ASSERT(!value.isEmpty());
+ if (value.isUndefined())
return QVariant();
- if (value->IsNull())
+ if (value.isNull())
return QVariant(QMetaType::VoidStar, 0);
- if (value->IsBoolean())
- return value->ToBoolean()->Value();
- if (value->IsInt32())
- return value->ToInt32()->Value();
- if (value->IsNumber())
- return value->ToNumber()->Value();
- if (value->IsString())
- return QJSConverter::toString(value->ToString());
- Q_ASSERT(value->IsObject());
- if (value->IsArray())
- return variantListFromJS(v8::Handle<v8::Array>::Cast(value), visitedObjects);
- if (value->IsDate())
- return QJSConverter::toDateTime(v8::Handle<v8::Date>::Cast(value));
- if (value->IsRegExp())
- return QJSConverter::toRegExp(v8::Handle<v8::RegExp>::Cast(value));
- if (isVariant(value))
- return variantValue(value);
- if (isQObject(value))
+ if (value.isBoolean())
+ return value.booleanValue();
+ if (value.isInteger())
+ return value.integerValue();
+ if (value.isNumber())
+ return value.asDouble();
+ if (value.isString())
+ return value.stringValue()->toQString();
+ Q_ASSERT(value.isObject());
+ if (QV4::ArrayObject *a = value.asArrayObject())
+ return variantListFromJS(a, visitedObjects);
+ if (QV4::DateObject *d = value.asDateObject())
+ return d->toQDateTime();
+ if (QV4::RegExpObject *re = value.as<QV4::RegExpObject>())
+ return re->toQRegExp();
+ if (QV4::VariantObject *v = value.as<QV4::VariantObject>())
+ return v->data;
+ if (value.as<QV4::QObjectWrapper>())
return qVariantFromValue(qtObjectFromJS(value));
- if (isValueType(value))
- return toValueType(value);
- return variantMapFromJS(value->ToObject(), visitedObjects);
+ if (QV4::QmlValueTypeWrapper *v = value.as<QV4::QmlValueTypeWrapper>())
+ return v->toVariant();
+ return variantMapFromJS(value.asObject(), visitedObjects);
}
-v8::Handle<v8::Value> QV8Engine::jsonValueToJS(const QJsonValue &value)
-{
- return m_jsonWrapper.fromJsonValue(value);
-}
-QJsonValue QV8Engine::jsonValueFromJS(v8::Handle<v8::Value> value)
-{
- return m_jsonWrapper.toJsonValue(value);
-}
-
-v8::Local<v8::Object> QV8Engine::jsonObjectToJS(const QJsonObject &object)
-{
- return m_jsonWrapper.fromJsonObject(object);
-}
-
-QJsonObject QV8Engine::jsonObjectFromJS(v8::Handle<v8::Value> value)
-{
- return m_jsonWrapper.toJsonObject(value);
-}
-
-v8::Local<v8::Array> QV8Engine::jsonArrayToJS(const QJsonArray &array)
-{
- return m_jsonWrapper.fromJsonArray(array);
-}
-
-QJsonArray QV8Engine::jsonArrayFromJS(v8::Handle<v8::Value> value)
-{
- return m_jsonWrapper.toJsonArray(value);
-}
-
-bool QV8Engine::convertToNativeQObject(v8::Handle<v8::Value> value,
- const QByteArray &targetType,
- void **result)
+bool QV8Engine::convertToNativeQObject(const QV4::Value &value, const QByteArray &targetType, void **result)
{
if (!targetType.endsWith('*'))
return false;
@@ -1353,73 +921,22 @@ bool QV8Engine::convertToNativeQObject(v8::Handle<v8::Value> value,
return false;
}
-QObject *QV8Engine::qtObjectFromJS(v8::Handle<v8::Value> value)
+QObject *QV8Engine::qtObjectFromJS(const QV4::Value &value)
{
- if (!value->IsObject())
+ if (!value.isObject())
return 0;
- QV8ObjectResource *r = (QV8ObjectResource *)value->ToObject()->GetExternalResource();
- if (!r)
- return 0;
- QV8ObjectResource::ResourceType type = r->resourceType();
- if (type == QV8ObjectResource::QObjectType)
- return qobjectWrapper()->toQObject(r);
- else if (type == QV8ObjectResource::VariantType) {
- QVariant variant = variantWrapper()->toVariant(r);
+
+ if (QV4::VariantObject *v = value.as<QV4::VariantObject>()) {
+ QVariant variant = v->data;
int type = variant.userType();
if (type == QMetaType::QObjectStar)
return *reinterpret_cast<QObject* const *>(variant.constData());
}
- return 0;
-}
-
-
-QVariant &QV8Engine::variantValue(v8::Handle<v8::Value> value)
-{
- return variantWrapper()->variantValue(value);
-}
-
-// Creates a QVariant wrapper object.
-v8::Local<v8::Object> QV8Engine::newVariant(const QVariant &value)
-{
- return variantWrapper()->newVariant(value);
-}
-
-QScriptPassPointer<QJSValuePrivate> QV8Engine::evaluate(v8::Handle<v8::Script> script, v8::TryCatch& tryCatch)
-{
- v8::HandleScope handleScope;
-
- if (script.IsEmpty()) {
- v8::Handle<v8::Value> exception = tryCatch.Exception();
- if (exception.IsEmpty()) {
- // This is possible on syntax errors like { a:12, b:21 } <- missing "(", ")" around expression.
- return new QJSValuePrivate(this);
- }
- return new QJSValuePrivate(this, exception);
- }
- v8::Handle<v8::Value> result;
- result = script->Run();
- if (result.IsEmpty()) {
- v8::Handle<v8::Value> exception = tryCatch.Exception();
- // TODO: figure out why v8 doesn't always produce an exception value
- //Q_ASSERT(!exception.IsEmpty());
- if (exception.IsEmpty())
- exception = v8::Exception::Error(v8::String::New("missing exception value"));
- return new QJSValuePrivate(this, exception);
- }
- return new QJSValuePrivate(this, result);
-}
-
-QJSValue QV8Engine::scriptValueFromInternal(v8::Handle<v8::Value> value) const
-{
- if (value.IsEmpty())
- return QJSValuePrivate::get(new QJSValuePrivate(const_cast<QV8Engine*>(this)));
- return QJSValuePrivate::get(new QJSValuePrivate(const_cast<QV8Engine*>(this), value));
-}
-
-QScriptPassPointer<QJSValuePrivate> QV8Engine::newArray(uint length)
-{
- return new QJSValuePrivate(this, v8::Array::New(length));
+ QV4::QObjectWrapper *wrapper = value.as<QV4::QObjectWrapper>();
+ if (!wrapper)
+ return 0;
+ return wrapper->object();
}
void QV8Engine::startTimer(const QString &timerName)
@@ -1449,107 +966,9 @@ int QV8Engine::consoleCountHelper(const QString &file, quint16 line, quint16 col
return number;
}
-v8::Handle<v8::Value> QV8Engine::getPlatform(v8::Local<v8::String>, const v8::AccessorInfo &info)
-{
- QV8Engine *engine = reinterpret_cast<QV8Engine*>(v8::External::Cast(*info.Data())->Value());
- if (!engine->m_platform) {
- // Only allocate a platform object once
- engine->m_platform = new QQmlPlatform(engine->m_engine);
- }
- return engine->newQObject(engine->m_platform);
-}
-
-v8::Handle<v8::Value> QV8Engine::getApplication(v8::Local<v8::String>, const v8::AccessorInfo &info)
+QV4::Value QV8Engine::toString(const QString &string)
{
- QV8Engine *engine = reinterpret_cast<QV8Engine*>(v8::External::Cast(*info.Data())->Value());
- if (!engine->m_application) {
- // Only allocate an application object once
- engine->m_application = QQml_guiProvider()->application(engine->m_engine);
- }
- return engine->newQObject(engine->m_application);
-}
-
-#ifndef QT_NO_IM
-v8::Handle<v8::Value> QV8Engine::getInputMethod(v8::Local<v8::String>, const v8::AccessorInfo &info)
-{
- QV8Engine *engine = reinterpret_cast<QV8Engine*>(v8::External::Cast(*info.Data())->Value());
- return engine->newQObject(QQml_guiProvider()->inputMethod(), CppOwnership);
-}
-#endif
-
-void QV8GCCallback::registerGcPrologueCallback()
-{
- QV8Engine::ThreadData *td = QV8Engine::threadData();
- if (!td->gcPrologueCallbackRegistered) {
- td->gcPrologueCallbackRegistered = true;
- v8::V8::AddGCPrologueCallback(QV8GCCallback::garbageCollectorPrologueCallback, v8::kGCTypeMarkSweepCompact);
- }
-}
-
-QV8GCCallback::Node::Node(PrologueCallback callback)
- : prologueCallback(callback)
-{
-}
-
-QV8GCCallback::Node::~Node()
-{
- node.remove();
-}
-
-/*
- Ensure that each persistent handle is strong if it has CPP ownership
- and has no implicitly JS owned object owner in its parent chain, and
- weak otherwise.
-
- Any weak handle whose parent object is still alive will have an implicit
- reference (between the parent and the handle) added, so that it will
- not be collected.
-
- Note that this callback is registered only for kGCTypeMarkSweepCompact
- collection cycles, as it is during collection cycles of that type
- in which weak persistent handle callbacks are called when required.
- */
-void QV8GCCallback::garbageCollectorPrologueCallback(v8::GCType, v8::GCCallbackFlags)
-{
- if (!QV8Engine::hasThreadData())
- return;
-
- QV8Engine::ThreadData *td = QV8Engine::threadData();
- QV8GCCallback::Node *currNode = td->gcCallbackNodes.first();
-
- while (currNode) {
- // The client which adds itself to the list is responsible
- // for maintaining the correct implicit references in the
- // specified callback.
- currNode->prologueCallback(currNode);
- currNode = td->gcCallbackNodes.next(currNode);
- }
-}
-
-void QV8GCCallback::addGcCallbackNode(QV8GCCallback::Node *node)
-{
- QV8Engine::ThreadData *td = QV8Engine::threadData();
- td->gcCallbackNodes.insert(node);
-}
-
-QV8Engine::ThreadData::ThreadData()
- : gcPrologueCallbackRegistered(false)
-{
- if (!v8::Isolate::GetCurrent()) {
- isolate = v8::Isolate::New();
- isolate->Enter();
- } else {
- isolate = 0;
- }
-}
-
-QV8Engine::ThreadData::~ThreadData()
-{
- if (isolate) {
- isolate->Exit();
- isolate->Dispose();
- isolate = 0;
- }
+ return QV4::Value::fromString(m_v4Engine->newString(string));
}
QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8engine_impl_p.h b/src/qml/qml/v8/qv8engine_impl_p.h
deleted file mode 100644
index 8879b67ebb..0000000000
--- a/src/qml/qml/v8/qv8engine_impl_p.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV8ENGINE_IMPL_P_H
-#define QV8ENGINE_IMPL_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 "qv8engine_p.h"
-#include "qjsvalue_p.h"
-#include "qjsconverter_p.h"
-#include "qjsvalueiterator_p.h"
-
-QT_BEGIN_NAMESPACE
-
-inline v8::Handle<v8::Value> QV8Engine::makeJSValue(bool value)
-{
- return value ? v8::True() : v8::False();
-}
-
-inline v8::Local<v8::Value> QV8Engine::makeJSValue(int value)
-{
- return v8::Integer::New(value);
-}
-
-inline v8::Local<v8::Value> QV8Engine::makeJSValue(uint value)
-{
- return v8::Integer::NewFromUnsigned(value);
-}
-
-inline v8::Local<v8::Value> QV8Engine::makeJSValue(double value)
-{
- return v8::Number::New(value);
-}
-
-inline v8::Handle<v8::Value> QV8Engine::makeJSValue(QJSValue::SpecialValue value) {
- if (value == QJSValue::NullValue)
- return v8::Null();
- return v8::Undefined();
-}
-
-inline v8::Local<v8::Value> QV8Engine::makeJSValue(const QString &value)
-{
- return QJSConverter::toString(value);
-}
-
-class QtScriptBagCleaner
-{
-public:
- template<class T>
- void operator () (T* value) const
- {
- value->reinitialize();
- }
- void operator () (QJSValueIteratorPrivate *iterator) const
- {
- iterator->invalidate();
- }
-};
-
-inline void QV8Engine::registerValue(QJSValuePrivate *data)
-{
- m_values.insert(data);
-}
-
-inline void QV8Engine::unregisterValue(QJSValuePrivate *data)
-{
- m_values.remove(data);
-}
-
-inline void QV8Engine::invalidateAllValues()
-{
- ValueList::iterator it;
- for (it = m_values.begin(); it != m_values.end(); it = it.erase())
- (*it)->invalidate();
- Q_ASSERT(m_values.isEmpty());
-}
-
-inline void QV8Engine::registerValueIterator(QJSValueIteratorPrivate *data)
-{
- m_valueIterators.insert(data);
-}
-
-inline void QV8Engine::unregisterValueIterator(QJSValueIteratorPrivate *data)
-{
- m_valueIterators.remove(data);
-}
-
-inline void QV8Engine::invalidateAllIterators()
-{
- ValueIteratorList::iterator it;
- for (it = m_valueIterators.begin(); it != m_valueIterators.end(); it = it.erase())
- (*it)->invalidate();
- Q_ASSERT(m_valueIterators.isEmpty());
-}
-
-/*!
- \internal
- \note property can be index (v8::Integer) or a property (v8::String) name, according to ECMA script
- property would be converted to a string.
-*/
-inline QJSValuePrivate::PropertyFlags QV8Engine::getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property)
-{
- QJSValuePrivate::PropertyFlags flags = m_originalGlobalObject.getPropertyFlags(object, property);
- return flags;
-}
-
-QScriptPassPointer<QJSValuePrivate> QV8Engine::evaluate(const QString& program, const QString& fileName, quint16 lineNumber)
-{
- v8::TryCatch tryCatch;
- v8::ScriptOrigin scriptOrigin(QJSConverter::toString(fileName), v8::Integer::New(lineNumber - 1));
- v8::Handle<v8::Script> script;
- script = v8::Script::Compile(QJSConverter::toString(program), &scriptOrigin);
- if (script.IsEmpty()) {
- // TODO: Why don't we get the exception, as with Script::Compile()?
- // Q_ASSERT(tryCatch.HasCaught());
- v8::Handle<v8::Value> error = v8::Exception::SyntaxError(v8::String::New(""));
- return new QJSValuePrivate(this, error);
- }
- return evaluate(script, tryCatch);
-}
-
-QT_END_NAMESPACE
-
-#endif // QV8ENGINE_IMPL_P_H
diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h
index 5ae0963178..4c2cccd28d 100644
--- a/src/qml/qml/v8/qv8engine_p.h
+++ b/src/qml/qml/v8/qv8engine_p.h
@@ -62,39 +62,24 @@
#include <QtCore/QElapsedTimer>
#include <QtCore/QThreadStorage>
-#include <private/qv8_p.h>
#include <qjsengine.h>
#include <qjsvalue.h>
-#include "qjsvalue_p.h"
#include "qjsvalueiterator_p.h"
-#include "qscriptoriginalglobalobject_p.h"
-#include "qscripttools_p.h"
+#include "private/qintrusivelist_p.h"
#include <private/qqmlpropertycache_p.h>
-#include "qv8objectresource_p.h"
-#include "qv8contextwrapper_p.h"
-#include "qv8qobjectwrapper_p.h"
-#include "qv8stringwrapper_p.h"
-#include "qv8typewrapper_p.h"
-#include "qv8listwrapper_p.h"
-#include "qv8variantwrapper_p.h"
-#include "qv8valuetypewrapper_p.h"
-#include "qv8sequencewrapper_p.h"
-#include "qv8jsonwrapper_p.h"
-
-namespace v8 {
-
-// Needed for V8ObjectSet
-inline uint qHash(const v8::Handle<v8::Object> &object, uint seed = 0)
-{
- return (object->GetIdentityHash() ^ seed);
-}
-
-}
+#include <private/qv4qobjectwrapper_p.h>
+#include <private/qv4value_p.h>
+#include <private/qv4object_p.h>
+#include <private/qv4identifier_p.h>
QT_BEGIN_NAMESPACE
+namespace QV4 {
+ struct ArrayObject;
+ struct ExecutionEngine;
+}
// Uncomment the following line to enable global handle debugging. When enabled, all the persistent
// handles allocated using qPersistentNew() (or registered with qPersistentRegsiter()) and disposed
@@ -102,32 +87,11 @@ QT_BEGIN_NAMESPACE
// a handle, qFatal() is called.
// #define QML_GLOBAL_HANDLE_DEBUGGING
-#define V8ENGINE() ((QV8Engine *)v8::External::Cast(*args.Data())->Value())
-#define V8FUNCTION(function, engine) v8::FunctionTemplate::New(function, v8::External::New((QV8Engine*)engine))->GetFunction()
-#define V8THROW_ERROR(string) { \
- v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
- return v8::Handle<v8::Value>(); \
-}
-#define V8THROW_TYPE(string) { \
- v8::ThrowException(v8::Exception::TypeError(v8::String::New(string))); \
- return v8::Handle<v8::Value>(); \
-}
-#define V8ENGINE_ACCESSOR() ((QV8Engine *)v8::External::Cast(*info.Data())->Value());
-#define V8THROW_ERROR_SETTER(string) { \
- v8::ThrowException(v8::Exception::Error(v8::String::New(string))); \
- return; \
-}
+#define V4THROW_ERROR(string) \
+ ctx->throwError(QString::fromUtf8(string));
-#define V8ASSERT_TYPE(condition, string) \
- if (!(condition)) { \
- v8::ThrowException(v8::Exception::TypeError(v8::String::New(string))); \
- return v8::Handle<v8::Value>(); \
- }
-#define V8ASSERT_TYPE_SETTER(condition, string) \
- if (!(condition)) { \
- v8::ThrowException(v8::Exception::TypeError(v8::String::New(string))); \
- return; \
- }
+#define V4THROW_TYPE(string) \
+ ctx->throwTypeError(QStringLiteral(string));
#define V8_DEFINE_EXTENSION(dataclass, datafunction) \
static inline dataclass *datafunction(QV8Engine *engine) \
@@ -147,19 +111,6 @@ QT_BEGIN_NAMESPACE
return rv; \
} \
-template<class T>
-inline T *v8_resource_cast(v8::Handle<v8::Object> object) {
- QV8ObjectResource *resource = static_cast<QV8ObjectResource *>(object->GetExternalResource());
- return (resource && (quint32)resource->resourceType() == (quint32)T::V8ResourceType)?static_cast<T *>(resource):0;
-}
-
-template<class T>
-inline T *v8_resource_check(v8::Handle<v8::Object> object) {
- T *resource = static_cast<T *>(object->GetExternalResource());
- Q_ASSERT(resource && resource->resourceType() == (quint32)T::V8ResourceType);
- return resource;
-}
-
// Used to allow a QObject method take and return raw V8 handles without having to expose
// v8 in the public API.
// Use like this:
@@ -172,50 +123,51 @@ inline T *v8_resource_check(v8::Handle<v8::Object> object) {
// valid during the call. If the return value isn't set within myMethod(), the will return
// undefined.
class QV8Engine;
-class QQmlV8Function
+class QQmlV4Function
{
public:
- int Length() const { return _ac; }
- v8::Local<v8::Value> operator[](int idx) { return (*_a)->Get(idx); }
- QQmlContextData *context() { return _c; }
- v8::Handle<v8::Object> qmlGlobal() { return *_g; }
- void returnValue(v8::Handle<v8::Value> rv) { *_r = rv; }
- QV8Engine *engine() const { return _e; }
+ int length() const { return argc; }
+ QV4::Value operator[](int idx) { return args[idx]; }
+ QQmlContextData *context() { return ctx; }
+ QV4::Value qmlGlobal() { return global; }
+ void setReturnValue(const QV4::Value &rv) { *retVal = rv; }
+ QV8Engine *engine() const { return e; }
private:
- friend class QV8QObjectWrapper;
- QQmlV8Function();
- QQmlV8Function(const QQmlV8Function &);
- QQmlV8Function &operator=(const QQmlV8Function &);
+ friend struct QV4::QObjectMethod;
+ QQmlV4Function();
+ QQmlV4Function(const QQmlV4Function &);
+ QQmlV4Function &operator=(const QQmlV4Function &);
- QQmlV8Function(int length, v8::Handle<v8::Object> &args,
- v8::Handle<v8::Value> &rv, v8::Handle<v8::Object> &global,
+ QQmlV4Function(int length, QV4::Value *args,
+ QV4::Value *rv, const QV4::Value &global,
QQmlContextData *c, QV8Engine *e)
- : _ac(length), _a(&args), _r(&rv), _g(&global), _c(c), _e(e) {}
-
- int _ac;
- v8::Handle<v8::Object> *_a;
- v8::Handle<v8::Value> *_r;
- v8::Handle<v8::Object> *_g;
- QQmlContextData *_c;
- QV8Engine *_e;
+ : argc(length), args(args), retVal(rv), global(global), ctx(c), e(e) {}
+
+ int argc;
+ QV4::Value *args;
+ QV4::Value *retVal;
+ QV4::Value global;
+ QQmlContextData *ctx;
+ QV8Engine *e;
};
-class QQmlV8Handle
+class Q_QML_PRIVATE_EXPORT QQmlV4Handle
{
public:
- QQmlV8Handle() : d(0) {}
- QQmlV8Handle(const QQmlV8Handle &other) : d(other.d) {}
- QQmlV8Handle &operator=(const QQmlV8Handle &other) { d = other.d; return *this; }
-
- static QQmlV8Handle fromHandle(v8::Handle<v8::Value> h) {
- return QQmlV8Handle(*h);
- }
- v8::Handle<v8::Value> toHandle() const {
- return v8::Handle<v8::Value>((v8::Value *)d);
+ QQmlV4Handle() : d(0) {}
+ QQmlV4Handle(const QQmlV4Handle &other) : d(other.d) {}
+ QQmlV4Handle &operator=(const QQmlV4Handle &other) { d = other.d; return *this; }
+ explicit QQmlV4Handle(const QV4::Value &v) : d(v.val) {}
+
+ QV4::Value toValue() const {
+ QV4::Value v;
+ v.val = d;
+ return v;
}
+
private:
- QQmlV8Handle(void *d) : d(d) {}
- void *d;
+ QQmlV4Handle(quint64 h) : d(h) {}
+ quint64 d;
};
class QObject;
@@ -224,39 +176,17 @@ class QQmlValueType;
class QNetworkAccessManager;
class QQmlContextData;
-class Q_AUTOTEST_EXPORT QV8GCCallback
-{
-private:
- class ThreadData;
-public:
- static void garbageCollectorPrologueCallback(v8::GCType, v8::GCCallbackFlags);
- static void registerGcPrologueCallback();
-
- class Q_AUTOTEST_EXPORT Node {
- public:
- typedef void (*PrologueCallback)(Node *node);
- Node(PrologueCallback callback);
- ~Node();
-
- QIntrusiveListNode node;
- PrologueCallback prologueCallback;
- };
-
- static void addGcCallbackNode(Node *node);
-};
-
class Q_QML_PRIVATE_EXPORT QV8Engine
{
- typedef QSet<v8::Handle<v8::Object> > V8ObjectSet;
+ friend class QJSEngine;
+ typedef QSet<QV4::Object *> V8ObjectSet;
public:
static QV8Engine* get(QJSEngine* q) { Q_ASSERT(q); return q->handle(); }
- static QJSEngine* get(QV8Engine* d) { Q_ASSERT(d); return d->q; }
+// static QJSEngine* get(QV8Engine* d) { Q_ASSERT(d); return d->q; }
+ static QV4::ExecutionEngine *getV4(QJSEngine *q) { return q->handle()->m_v4Engine; }
+ static QV4::ExecutionEngine *getV4(QV8Engine *d) { return d->m_v4Engine; }
- enum ContextOwnership {
- AdoptCurrentContext,
- CreateNewContext
- };
- QV8Engine(QJSEngine* qq, ContextOwnership ownership = CreateNewContext);
+ QV8Engine(QJSEngine* qq);
virtual ~QV8Engine();
// This enum should be in sync with QQmlEngine::ObjectOwnership
@@ -269,24 +199,8 @@ public:
void initQmlGlobalObject();
void setEngine(QQmlEngine *engine);
QQmlEngine *engine() { return m_engine; }
- v8::Local<v8::Object> global() { return m_context->Global(); }
- v8::Handle<v8::Context> context() const { return m_context; }
-
- inline void registerValue(QJSValuePrivate *data);
- inline void unregisterValue(QJSValuePrivate *data);
- inline void invalidateAllValues();
-
- inline void registerValueIterator(QJSValueIteratorPrivate *data);
- inline void unregisterValueIterator(QJSValueIteratorPrivate *data);
- inline void invalidateAllIterators();
-
- QV8ContextWrapper *contextWrapper() { return &m_contextWrapper; }
- QV8QObjectWrapper *qobjectWrapper() { return &m_qobjectWrapper; }
- QV8TypeWrapper *typeWrapper() { return &m_typeWrapper; }
- QV8ListWrapper *listWrapper() { return &m_listWrapper; }
- QV8VariantWrapper *variantWrapper() { return &m_variantWrapper; }
- QV8ValueTypeWrapper *valueTypeWrapper() { return &m_valueTypeWrapper; }
- QV8SequenceWrapper *sequenceWrapper() { return &m_sequenceWrapper; }
+ QJSEngine *publicEngine() { return q; }
+ QV4::Value global();
void *xmlHttpRequestData() { return m_xmlHttpRequestData; }
@@ -295,55 +209,13 @@ public:
QQmlContextData *callingContext();
- v8::Local<v8::Array> getOwnPropertyNames(v8::Handle<v8::Object>);
- inline QJSValuePrivate::PropertyFlags getPropertyFlags(v8::Handle<v8::Object> object, v8::Handle<v8::Value> property);
- void freezeObject(v8::Handle<v8::Value>);
-
- inline QString toString(v8::Handle<v8::Value> string);
- inline QString toString(v8::Handle<v8::String> string);
- static QString toStringStatic(v8::Handle<v8::Value>);
- static QString toStringStatic(v8::Handle<v8::String>);
- static inline bool startsWithUpper(v8::Handle<v8::String>);
-
- QVariant toVariant(v8::Handle<v8::Value>, int typeHint);
- v8::Handle<v8::Value> fromVariant(const QVariant &);
- inline bool isVariant(v8::Handle<v8::Value>);
-
- // Compile \a source (from \a fileName at \a lineNumber) in QML mode
- v8::Local<v8::Script> qmlModeCompile(const QString &source,
- const QString &fileName = QString(),
- quint16 lineNumber = 1);
- v8::Local<v8::Script> qmlModeCompile(const char *source, int sourceLength = -1,
- const QString &fileName = QString(),
- quint16 lineNumber = 1);
-
- // Return the QML global "scope" object for the \a ctxt context and \a scope object.
- inline v8::Local<v8::Object> qmlScope(QQmlContextData *ctxt, QObject *scope);
-
- // Return a JS wrapper for the given QObject \a object
- inline v8::Handle<v8::Value> newQObject(QObject *object);
- inline v8::Handle<v8::Value> newQObject(QObject *object, const ObjectOwnership ownership);
- inline bool isQObject(v8::Handle<v8::Value>);
- inline QObject *toQObject(v8::Handle<v8::Value>);
-
- // Return a JS string for the given QString \a string
- inline v8::Local<v8::String> toString(const QString &string);
-
- // Create a new value type object
- inline v8::Handle<v8::Value> newValueType(QObject *, int coreIndex, QQmlValueType *);
- inline v8::Handle<v8::Value> newValueType(const QVariant &, QQmlValueType *);
- inline bool isValueType(v8::Handle<v8::Value>) const;
- inline QVariant toValueType(v8::Handle<v8::Value> obj);
+ void freezeObject(const QV4::Value &value);
- // Create a new sequence type object
- inline v8::Handle<v8::Value> newSequence(int sequenceType, QObject *, int coreIndex, bool *succeeded);
+ QVariant toVariant(const QV4::Value &value, int typeHint);
+ QV4::Value fromVariant(const QVariant &);
- // Create a new QVariant object. This doesn't examine the type of the variant, but always returns
- // a QVariant wrapper
- inline v8::Handle<v8::Value> newQVariant(const QVariant &);
-
- // Return the JS string key for the "function is a binding" flag
- inline v8::Handle<v8::String> bindingFlagKey() const;
+ // Return a JS string for the given QString \a string
+ QV4::Value toString(const QString &string);
// Return the network access manager for this engine. By default this returns the network
// access manager of the QQmlEngine. It is overridden in the case of a threaded v8
@@ -351,18 +223,10 @@ public:
virtual QNetworkAccessManager *networkAccessManager();
// Return the list of illegal id names (the names of the properties on the global object)
- const QStringHash<bool> &illegalNames() const;
+ const QV4::IdentifierHash<bool> &illegalNames() const;
inline void collectGarbage() { gc(); }
- static void gc();
-
- v8::Handle<v8::Value> throwException(v8::Handle<v8::Value> value);
-
-#ifdef QML_GLOBAL_HANDLE_DEBUGGING
- // Used for handle debugging
- static void registerHandle(void *);
- static void releaseHandle(void *);
-#endif
+ void gc();
static QMutex *registrationMutex();
static int registerExtension();
@@ -370,49 +234,25 @@ public:
inline Deletable *extensionData(int) const;
void setExtensionData(int, Deletable *);
- inline v8::Handle<v8::Value> makeJSValue(bool value);
- inline v8::Local<v8::Value> makeJSValue(int value);
- inline v8::Local<v8::Value> makeJSValue(uint value);
- inline v8::Local<v8::Value> makeJSValue(double value);
- inline v8::Handle<v8::Value> makeJSValue(QJSValue::SpecialValue value);
- inline v8::Local<v8::Value> makeJSValue(const QString &value);
-
- inline QScriptPassPointer<QJSValuePrivate> evaluate(const QString &program, const QString &fileName = QString(), quint16 lineNumber = 1);
- QScriptPassPointer<QJSValuePrivate> evaluate(v8::Handle<v8::Script> script, v8::TryCatch& tryCatch);
-
- QScriptPassPointer<QJSValuePrivate> newArray(uint length);
- v8::Local<v8::Object> newVariant(const QVariant &variant);
-
- v8::Local<v8::Array> variantListToJS(const QVariantList &lst);
- inline QVariantList variantListFromJS(v8::Handle<v8::Array> jsArray)
- { V8ObjectSet visitedObjects; return variantListFromJS(jsArray, visitedObjects); }
+ QV4::Value variantListToJS(const QVariantList &lst);
+ inline QVariantList variantListFromJS(QV4::ArrayObject *array)
+ { V8ObjectSet visitedObjects; return variantListFromJS(array, visitedObjects); }
- v8::Local<v8::Object> variantMapToJS(const QVariantMap &vmap);
- inline QVariantMap variantMapFromJS(v8::Handle<v8::Object> jsObject)
- { V8ObjectSet visitedObjects; return variantMapFromJS(jsObject, visitedObjects); }
+ QV4::Value variantMapToJS(const QVariantMap &vmap);
+ inline QVariantMap variantMapFromJS(QV4::Object *object)
+ { V8ObjectSet visitedObjects; return variantMapFromJS(object, visitedObjects); }
- v8::Handle<v8::Value> variantToJS(const QVariant &value);
- inline QVariant variantFromJS(v8::Handle<v8::Value> value)
+ QV4::Value variantToJS(const QVariant &value);
+ inline QVariant variantFromJS(const QV4::Value &value)
{ V8ObjectSet visitedObjects; return variantFromJS(value, visitedObjects); }
- v8::Handle<v8::Value> jsonValueToJS(const QJsonValue &value);
- QJsonValue jsonValueFromJS(v8::Handle<v8::Value> value);
- v8::Local<v8::Object> jsonObjectToJS(const QJsonObject &object);
- QJsonObject jsonObjectFromJS(v8::Handle<v8::Value> value);
- v8::Local<v8::Array> jsonArrayToJS(const QJsonArray &array);
- QJsonArray jsonArrayFromJS(v8::Handle<v8::Value> value);
+ QV4::Value metaTypeToJS(int type, const void *data);
+ bool metaTypeFromJS(const QV4::Value &value, int type, void *data);
- v8::Handle<v8::Value> metaTypeToJS(int type, const void *data);
- bool metaTypeFromJS(v8::Handle<v8::Value> value, int type, void *data);
-
- bool convertToNativeQObject(v8::Handle<v8::Value> value,
+ bool convertToNativeQObject(const QV4::Value &value,
const QByteArray &targetType,
void **result);
- QVariant &variantValue(v8::Handle<v8::Value> value);
-
- QJSValue scriptValueFromInternal(v8::Handle<v8::Value>) const;
-
// used for console.time(), console.timeEnd()
void startTimer(const QString &timerName);
qint64 stopTimer(const QString &timerName, bool *wasRunning);
@@ -420,222 +260,40 @@ public:
// used for console.count()
int consoleCountHelper(const QString &file, quint16 line, quint16 column);
- QObject *qtObjectFromJS(v8::Handle<v8::Value> value);
-
- static QDateTime qtDateTimeFromJsDate(double jsDate);
-
- void addRelationshipForGC(QObject *object, v8::Persistent<v8::Value> handle);
- void addRelationshipForGC(QObject *object, QObject *other);
-
- static v8::Handle<v8::Value> getPlatform(v8::Local<v8::String> property, const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> getApplication(v8::Local<v8::String> property, const v8::AccessorInfo &info);
-#ifndef QT_NO_IM
- static v8::Handle<v8::Value> getInputMethod(v8::Local<v8::String> property, const v8::AccessorInfo &info);
-#endif
-
- struct ThreadData {
- ThreadData();
- ~ThreadData();
- v8::Isolate* isolate;
- bool gcPrologueCallbackRegistered;
- QIntrusiveList<QV8GCCallback::Node, &QV8GCCallback::Node::node> gcCallbackNodes;
- };
-
- static bool hasThreadData();
- static ThreadData* threadData();
- static void ensurePerThreadIsolate();
-
- v8::Persistent<v8::Object> m_strongReferencer;
+ QObject *qtObjectFromJS(const QV4::Value &value);
protected:
QJSEngine* q;
QQmlEngine *m_engine;
- bool m_ownsV8Context;
- v8::Persistent<v8::Context> m_context;
- QScriptOriginalGlobalObject m_originalGlobalObject;
- v8::Persistent<v8::String> m_bindingFlagKey;
+ QV4::ExecutionEngine *m_v4Engine;
- QV8StringWrapper m_stringWrapper;
- QV8ContextWrapper m_contextWrapper;
- QV8QObjectWrapper m_qobjectWrapper;
- QV8TypeWrapper m_typeWrapper;
- QV8ListWrapper m_listWrapper;
- QV8VariantWrapper m_variantWrapper;
- QV8ValueTypeWrapper m_valueTypeWrapper;
- QV8SequenceWrapper m_sequenceWrapper;
- QV8JsonWrapper m_jsonWrapper;
-
- v8::Persistent<v8::Function> m_getOwnPropertyNames;
- v8::Persistent<v8::Function> m_freezeObject;
+ QV4::PersistentValue m_freezeObject;
void *m_xmlHttpRequestData;
QVector<Deletable *> m_extensionData;
Deletable *m_listModelData;
- QStringHash<bool> m_illegalNames;
+ QV4::IdentifierHash<bool> m_illegalNames;
QElapsedTimer m_time;
QHash<QString, qint64> m_startedTimers;
QHash<QString, quint32> m_consoleCount;
- QObject *m_platform;
- QObject *m_application;
-
- QVariant toBasicVariant(v8::Handle<v8::Value>);
+ QVariant toBasicVariant(const QV4::Value &);
- void initializeGlobal(v8::Handle<v8::Object>);
-
- double qtDateTimeToJsDate(const QDateTime &dt);
+ void initializeGlobal();
private:
- QVariantList variantListFromJS(v8::Handle<v8::Array> jsArray, V8ObjectSet &visitedObjects);
- QVariantMap variantMapFromJS(v8::Handle<v8::Object> jsObject, V8ObjectSet &visitedObjects);
- QVariant variantFromJS(v8::Handle<v8::Value> value, V8ObjectSet &visitedObjects);
-
- static v8::Persistent<v8::Object> *findOwnerAndStrength(QObject *object, bool *shouldBeStrong);
-
- typedef QScriptIntrusiveList<QJSValuePrivate, &QJSValuePrivate::m_node> ValueList;
- ValueList m_values;
- typedef QScriptIntrusiveList<QJSValueIteratorPrivate, &QJSValueIteratorPrivate::m_node> ValueIteratorList;
- ValueIteratorList m_valueIterators;
+ QVariantList variantListFromJS(QV4::ArrayObject *array, V8ObjectSet &visitedObjects);
+ QVariantMap variantMapFromJS(QV4::Object *object, V8ObjectSet &visitedObjects);
+ QVariant variantFromJS(const QV4::Value &value, V8ObjectSet &visitedObjects);
Q_DISABLE_COPY(QV8Engine)
};
-// Allocate a new Persistent handle. *ALL* persistent handles in QML must be allocated
-// using this method.
-template<class T>
-v8::Persistent<T> qPersistentNew(v8::Handle<T> that)
-{
- v8::Persistent<T> rv = v8::Persistent<T>::New(that);
-#ifdef QML_GLOBAL_HANDLE_DEBUGGING
- QV8Engine::registerHandle(*rv);
-#endif
- return rv;
-}
-
-// Register a Persistent handle that was returned to you by V8 (such as by
-// v8::Context::New). This allows us to do handle tracking on these handles too.
-template<class T>
-void qPersistentRegister(v8::Persistent<T> handle)
-{
-#ifdef QML_GLOBAL_HANDLE_DEBUGGING
- QV8Engine::registerHandle(*handle);
-#else
- Q_UNUSED(handle);
-#endif
-}
-
-// Dispose and clear a persistent handle. *ALL* persistent handles in QML must be
-// disposed using this method.
-template<class T>
-void qPersistentDispose(v8::Persistent<T> &that)
-{
-#ifdef QML_GLOBAL_HANDLE_DEBUGGING
- QV8Engine::releaseHandle(*that);
-#endif
- that.Dispose();
- that.Clear();
-}
-
-QString QV8Engine::toString(v8::Handle<v8::Value> string)
-{
- return m_stringWrapper.toString(string->ToString());
-}
-
-QString QV8Engine::toString(v8::Handle<v8::String> string)
-{
- return m_stringWrapper.toString(string);
-}
-
-bool QV8Engine::isVariant(v8::Handle<v8::Value> value)
-{
- return m_variantWrapper.isVariant(value);
-}
-
-v8::Local<v8::Object> QV8Engine::qmlScope(QQmlContextData *ctxt, QObject *scope)
-{
- return m_contextWrapper.qmlScope(ctxt, scope);
-}
-
-bool QV8Engine::isQObject(v8::Handle<v8::Value> obj)
-{
- return obj->IsObject()?m_qobjectWrapper.isQObject(v8::Handle<v8::Object>::Cast(obj)):false;
-}
-
-QObject *QV8Engine::toQObject(v8::Handle<v8::Value> obj)
-{
- return obj->IsObject()?m_qobjectWrapper.toQObject(v8::Handle<v8::Object>::Cast(obj)):0;
-}
-
-v8::Handle<v8::Value> QV8Engine::newQObject(QObject *object)
-{
- return m_qobjectWrapper.newQObject(object);
-}
-
-v8::Handle<v8::Value> QV8Engine::newQObject(QObject *object, const ObjectOwnership ownership)
-{
- if (!object)
- return v8::Null();
-
- v8::Handle<v8::Value> result = newQObject(object);
- QQmlData *ddata = QQmlData::get(object, true);
- if (ownership == JavaScriptOwnership && ddata) {
- ddata->indestructible = false;
- ddata->explicitIndestructibleSet = true;
- }
- return result;
-}
-
-v8::Local<v8::String> QV8Engine::toString(const QString &string)
-{
- return m_stringWrapper.toString(string);
-}
-
-v8::Handle<v8::Value> QV8Engine::newValueType(QObject *object, int property, QQmlValueType *type)
-{
- return m_valueTypeWrapper.newValueType(object, property, type);
-}
-
-v8::Handle<v8::Value> QV8Engine::newValueType(const QVariant &value, QQmlValueType *type)
-{
- return m_valueTypeWrapper.newValueType(value, type);
-}
-
-bool QV8Engine::isValueType(v8::Handle<v8::Value> obj) const
-{
- return obj->IsObject()?m_valueTypeWrapper.isValueType(v8::Handle<v8::Object>::Cast(obj)):false;
-}
-
-QVariant QV8Engine::toValueType(v8::Handle<v8::Value> obj)
-{
- return obj->IsObject()?m_valueTypeWrapper.toVariant(v8::Handle<v8::Object>::Cast(obj)):QVariant();
-}
-
-v8::Handle<v8::Value> QV8Engine::newSequence(int sequenceType, QObject *object, int property, bool *succeeded)
-{
- return m_sequenceWrapper.newSequence(sequenceType, object, property, succeeded);
-}
-
-v8::Handle<v8::String> QV8Engine::bindingFlagKey() const
-{
- return m_bindingFlagKey;
-}
-
-// XXX Can this be made more optimal? It is called prior to resolving each and every
-// unqualified name in QV8ContextWrapper.
-bool QV8Engine::startsWithUpper(v8::Handle<v8::String> string)
-{
- v8::String::Value value(string);
- Q_ASSERT(*value != NULL);
- uint16_t c = **value;
- return (c >= 'A' && c <= 'Z') ||
- (c > 127 && QChar::category(c) == QChar::Letter_Uppercase);
-}
-
QV8Engine::Deletable *QV8Engine::extensionData(int index) const
{
if (index < m_extensionData.count())
@@ -646,6 +304,6 @@ QV8Engine::Deletable *QV8Engine::extensionData(int index) const
QT_END_NAMESPACE
-Q_DECLARE_METATYPE(QQmlV8Handle)
+Q_DECLARE_METATYPE(QQmlV4Handle)
#endif // QQMLV8ENGINE_P_H
diff --git a/src/qml/qml/v8/qv8include.cpp b/src/qml/qml/v8/qv8include.cpp
deleted file mode 100644
index 101c3d24c3..0000000000
--- a/src/qml/qml/v8/qv8include.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv8include_p.h"
-
-#include <QtQml/qjsengine.h>
-#include <QtNetwork/qnetworkrequest.h>
-#include <QtNetwork/qnetworkreply.h>
-#include <QtCore/qfile.h>
-#include <QtQml/qqmlfile.h>
-
-#include <private/qqmlengine_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QV8Include::QV8Include(const QUrl &url, QV8Engine *engine, QQmlContextData *context,
- v8::Handle<v8::Object> qmlglobal, v8::Handle<v8::Function> callback)
-: m_engine(engine), m_network(0), m_reply(0), m_url(url), m_redirectCount(0), m_context(context)
-{
- m_qmlglobal = qPersistentNew<v8::Object>(qmlglobal);
- if (!callback.IsEmpty())
- m_callbackFunction = qPersistentNew<v8::Function>(callback);
-
- m_resultObject = qPersistentNew<v8::Object>(resultValue());
-
- m_network = engine->networkAccessManager();
-
- QNetworkRequest request;
- request.setUrl(url);
-
- m_reply = m_network->get(request);
- QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
-}
-
-QV8Include::~QV8Include()
-{
- delete m_reply; m_reply = 0;
- qPersistentDispose(m_callbackFunction);
- qPersistentDispose(m_resultObject);
-}
-
-v8::Local<v8::Object> QV8Include::resultValue(Status status)
-{
- // XXX It seems inefficient to create this object from scratch each time.
- v8::Local<v8::Object> result = v8::Object::New();
- result->Set(v8::String::New("OK"), v8::Integer::New(Ok));
- result->Set(v8::String::New("LOADING"), v8::Integer::New(Loading));
- result->Set(v8::String::New("NETWORK_ERROR"), v8::Integer::New(NetworkError));
- result->Set(v8::String::New("EXCEPTION"), v8::Integer::New(Exception));
-
- result->Set(v8::String::New("status"), v8::Integer::New(status));
-
- return result;
-}
-
-void QV8Include::callback(QV8Engine *engine, v8::Handle<v8::Function> callback, v8::Handle<v8::Object> status)
-{
- if (!callback.IsEmpty()) {
- v8::Handle<v8::Value> args[] = { status };
- v8::TryCatch tc;
- callback->Call(engine->global(), 1, args);
- }
-}
-
-v8::Handle<v8::Object> QV8Include::result()
-{
- return m_resultObject;
-}
-
-#define INCLUDE_MAXIMUM_REDIRECT_RECURSION 15
-void QV8Include::finished()
-{
- m_redirectCount++;
-
- if (m_redirectCount < INCLUDE_MAXIMUM_REDIRECT_RECURSION) {
- QVariant redirect = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
- if (redirect.isValid()) {
- m_url = m_url.resolved(redirect.toUrl());
- delete m_reply;
-
- QNetworkRequest request;
- request.setUrl(m_url);
-
- m_reply = m_network->get(request);
- QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished()));
- return;
- }
- }
-
- v8::HandleScope handle_scope;
-
- if (m_reply->error() == QNetworkReply::NoError) {
- QByteArray data = m_reply->readAll();
-
- QString code = QString::fromUtf8(data);
- QQmlScript::Parser::extractPragmas(code);
-
- QQmlContextData *importContext = new QQmlContextData;
- importContext->isInternal = true;
- importContext->isJSContext = true;
- importContext->url = m_url;
- importContext->isPragmaLibraryContext = m_context->isPragmaLibraryContext;
- importContext->setParent(m_context, true);
-
- v8::Context::Scope ctxtscope(m_engine->context());
- v8::TryCatch try_catch;
-
- v8::Local<v8::Script> script = m_engine->qmlModeCompile(code, m_url.toString());
-
- if (!try_catch.HasCaught()) {
- m_engine->contextWrapper()->addSubContext(m_qmlglobal, script, importContext);
- script->Run(m_qmlglobal);
- }
-
- if (try_catch.HasCaught()) {
- m_resultObject->Set(v8::String::New("status"), v8::Integer::New(Exception));
- m_resultObject->Set(v8::String::New("exception"), try_catch.Exception());
- } else {
- m_resultObject->Set(v8::String::New("status"), v8::Integer::New(Ok));
- }
- } else {
- m_resultObject->Set(v8::String::New("status"), v8::Integer::New(NetworkError));
- }
-
- callback(m_engine, m_callbackFunction, m_resultObject);
-
- disconnect();
- deleteLater();
-}
-
-/*
- Documented in qv8engine.cpp
-*/
-v8::Handle<v8::Value> QV8Include::include(const v8::Arguments &args)
-{
- if (args.Length() == 0)
- return v8::Undefined();
-
- QV8Engine *engine = V8ENGINE();
- QQmlContextData *context = engine->callingContext();
-
- if (!context || !context->isJSContext)
- V8THROW_ERROR("Qt.include(): Can only be called from JavaScript files");
-
- QUrl url(context->resolvedUrl(QUrl(engine->toString(args[0]->ToString()))));
-
- v8::Local<v8::Function> callbackFunction;
- if (args.Length() >= 2 && args[1]->IsFunction())
- callbackFunction = v8::Local<v8::Function>::Cast(args[1]);
-
- QString localFile = QQmlFile::urlToLocalFileOrQrc(url);
-
- v8::Local<v8::Object> result;
-
- if (localFile.isEmpty()) {
-
- QV8Include *i = new QV8Include(url, engine, context,
- v8::Context::GetCallingQmlGlobal(),
- callbackFunction);
- result = v8::Local<v8::Object>::New(i->result());
-
- } else {
-
- QFile f(localFile);
-
- if (f.open(QIODevice::ReadOnly)) {
- QByteArray data = f.readAll();
- QString code = QString::fromUtf8(data);
- QQmlScript::Parser::extractPragmas(code);
-
- QQmlContextData *importContext = new QQmlContextData;
- importContext->isInternal = true;
- importContext->isJSContext = true;
- importContext->url = url;
- importContext->setParent(context, true);
-
- v8::TryCatch try_catch;
-
- v8::Local<v8::Script> script = engine->qmlModeCompile(code, url.toString());
-
- if (!try_catch.HasCaught()) {
- v8::Local<v8::Object> qmlglobal = v8::Context::GetCallingQmlGlobal();
- engine->contextWrapper()->addSubContext(qmlglobal, script, importContext);
- script->Run(qmlglobal);
- }
-
- if (try_catch.HasCaught()) {
- result = resultValue(Exception);
- result->Set(v8::String::New("exception"), try_catch.Exception());
- } else {
- result = resultValue(Ok);
- }
-
- } else {
- result = resultValue(NetworkError);
- }
-
- callback(engine, callbackFunction, result);
- }
-
- if (result.IsEmpty())
- return v8::Undefined();
- else
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8jsonwrapper.cpp b/src/qml/qml/v8/qv8jsonwrapper.cpp
deleted file mode 100644
index 4d89551894..0000000000
--- a/src/qml/qml/v8/qv8jsonwrapper.cpp
+++ /dev/null
@@ -1,181 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv8jsonwrapper_p.h"
-#include "qv8engine_p.h"
-#include "qjsconverter_impl_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QV8JsonWrapper::QV8JsonWrapper()
-: m_engine(0)
-{
-}
-
-QV8JsonWrapper::~QV8JsonWrapper()
-{
-}
-
-void QV8JsonWrapper::init(QV8Engine *engine)
-{
- m_engine = engine;
-}
-
-void QV8JsonWrapper::destroy()
-{
-}
-
-v8::Handle<v8::Value> QV8JsonWrapper::fromJsonValue(const QJsonValue &value)
-{
- if (value.isString())
- return QJSConverter::toString(value.toString());
- else if (value.isDouble())
- return v8::Number::New(value.toDouble());
- else if (value.isBool())
- return value.toBool() ? v8::True() : v8::False();
- else if (value.isArray())
- return fromJsonArray(value.toArray());
- else if (value.isObject())
- return fromJsonObject(value.toObject());
- else if (value.isNull())
- return v8::Null();
- else
- return v8::Undefined();
-}
-
-QJsonValue QV8JsonWrapper::toJsonValue(v8::Handle<v8::Value> value,
- V8ObjectSet &visitedObjects)
-{
- if (value->IsString())
- return QJsonValue(QJSConverter::toString(value.As<v8::String>()));
- else if (value->IsNumber())
- return QJsonValue(value->NumberValue());
- else if (value->IsBoolean())
- return QJsonValue(value->BooleanValue());
- else if (value->IsArray())
- return toJsonArray(value.As<v8::Array>(), visitedObjects);
- else if (value->IsObject())
- return toJsonObject(value.As<v8::Object>(), visitedObjects);
- else if (value->IsNull())
- return QJsonValue(QJsonValue::Null);
- else
- return QJsonValue(QJsonValue::Undefined);
-}
-
-v8::Local<v8::Object> QV8JsonWrapper::fromJsonObject(const QJsonObject &object)
-{
- v8::Local<v8::Object> v8object = v8::Object::New();
- for (QJsonObject::const_iterator it = object.begin(); it != object.end(); ++it)
- v8object->Set(QJSConverter::toString(it.key()), fromJsonValue(it.value()));
- return v8object;
-}
-
-QJsonObject QV8JsonWrapper::toJsonObject(v8::Handle<v8::Value> value,
- V8ObjectSet &visitedObjects)
-{
- QJsonObject result;
- if (!value->IsObject() || value->IsArray() || value->IsFunction())
- return result;
-
- v8::Handle<v8::Object> v8object(value.As<v8::Object>());
- if (visitedObjects.contains(v8object)) {
- // Avoid recursion.
- // For compatibility with QVariant{List,Map} conversion, we return an
- // empty object (and no error is thrown).
- return result;
- }
-
- visitedObjects.insert(v8object);
-
- v8::Local<v8::Array> propertyNames = m_engine->getOwnPropertyNames(v8object);
- uint32_t length = propertyNames->Length();
- for (uint32_t i = 0; i < length; ++i) {
- v8::Local<v8::Value> name = propertyNames->Get(i);
- v8::Local<v8::Value> propertyValue = v8object->Get(name);
- if (!propertyValue->IsFunction())
- result.insert(QJSConverter::toString(name->ToString()),
- toJsonValue(propertyValue, visitedObjects));
- }
-
- visitedObjects.remove(v8object);
-
- return result;
-}
-
-v8::Local<v8::Array> QV8JsonWrapper::fromJsonArray(const QJsonArray &array)
-{
- int size = array.size();
- v8::Local<v8::Array> v8array = v8::Array::New(size);
- for (int i = 0; i < size; i++)
- v8array->Set(i, fromJsonValue(array.at(i)));
- return v8array;
-}
-
-QJsonArray QV8JsonWrapper::toJsonArray(v8::Handle<v8::Value> value,
- V8ObjectSet &visitedObjects)
-{
- QJsonArray result;
- if (!value->IsArray())
- return result;
-
- v8::Handle<v8::Array> v8array(value.As<v8::Array>());
- if (visitedObjects.contains(v8array)) {
- // Avoid recursion.
- // For compatibility with QVariant{List,Map} conversion, we return an
- // empty array (and no error is thrown).
- return result;
- }
-
- visitedObjects.insert(v8array);
-
- uint32_t length = v8array->Length();
- for (uint32_t i = 0; i < length; ++i) {
- v8::Local<v8::Value> element = v8array->Get(i);
- if (!element->IsFunction())
- result.append(toJsonValue(element, visitedObjects));
- }
-
- visitedObjects.remove(v8array);
-
- return result;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8listwrapper.cpp b/src/qml/qml/v8/qv8listwrapper.cpp
deleted file mode 100644
index d3ce9f8fc2..0000000000
--- a/src/qml/qml/v8/qv8listwrapper.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv8listwrapper_p.h"
-#include "qv8engine_p.h"
-#include <private/qqmllist_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QV8ListResource : public QV8ObjectResource
-{
- V8_RESOURCE_TYPE(ListType)
-public:
- QV8ListResource(QV8Engine *engine) : QV8ObjectResource(engine) {}
-
- QQmlGuard<QObject> object;
- QQmlListProperty<QObject> property;
- int propertyType;
-};
-
-QV8ListWrapper::QV8ListWrapper()
-: m_engine(0)
-{
-}
-
-QV8ListWrapper::~QV8ListWrapper()
-{
-}
-
-void QV8ListWrapper::init(QV8Engine *engine)
-{
- m_engine = engine;
- v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter, 0, 0, Enumerator);
- ft->InstanceTemplate()->SetIndexedPropertyHandler(IndexedGetter);
- ft->InstanceTemplate()->SetAccessor(v8::String::New("length"), LengthGetter, 0,
- v8::Handle<v8::Value>(), v8::DEFAULT,
- v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete | v8::DontEnum));
- ft->InstanceTemplate()->SetHasExternalResource(true);
- m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
-}
-
-void QV8ListWrapper::destroy()
-{
- qPersistentDispose(m_constructor);
-}
-
-v8::Handle<v8::Value> QV8ListWrapper::newList(QObject *object, int propId, int propType)
-{
- if (!object || propId == -1)
- return v8::Null();
-
- // XXX NewInstance() should be optimized
- v8::Local<v8::Object> rv = m_constructor->NewInstance();
- QV8ListResource *r = new QV8ListResource(m_engine);
- r->object = object;
- r->propertyType = propType;
- void *args[] = { &r->property, 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, propId, args);
- rv->SetExternalResource(r);
- return rv;
-}
-
-v8::Handle<v8::Value> QV8ListWrapper::newList(const QQmlListProperty<QObject> &prop, int propType)
-{
- // XXX NewInstance() should be optimized
- v8::Local<v8::Object> rv = m_constructor->NewInstance();
- QV8ListResource *r = new QV8ListResource(m_engine);
- r->object = prop.object;
- r->property = prop;
- r->propertyType = propType;
- rv->SetExternalResource(r);
- return rv;
-}
-
-QVariant QV8ListWrapper::toVariant(v8::Handle<v8::Object> obj)
-{
- QV8ListResource *resource = v8_resource_cast<QV8ListResource>(obj);
- if (resource) return toVariant(resource);
- else return QVariant();
-}
-
-QVariant QV8ListWrapper::toVariant(QV8ObjectResource *r)
-{
- Q_ASSERT(r->resourceType() == QV8ObjectResource::ListType);
- QV8ListResource *resource = static_cast<QV8ListResource *>(r);
-
- if (!resource->object)
- return QVariant();
-
- return QVariant::fromValue(QQmlListReferencePrivate::init(resource->property, resource->propertyType,
- m_engine->engine()));
-}
-
-v8::Handle<v8::Value> QV8ListWrapper::Getter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
- Q_UNUSED(info);
- return v8::Handle<v8::Value>();
-}
-
-v8::Handle<v8::Value> QV8ListWrapper::Setter(v8::Local<v8::String> property,
- v8::Local<v8::Value> value,
- const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
- Q_UNUSED(info);
- return value;
-}
-
-v8::Handle<v8::Value> QV8ListWrapper::IndexedGetter(uint32_t index, const v8::AccessorInfo &info)
-{
- QV8ListResource *resource = v8_resource_cast<QV8ListResource>(info.This());
-
- if (!resource || resource->object.isNull()) return v8::Undefined();
-
- quint32 count = resource->property.count?resource->property.count(&resource->property):0;
- if (index < count && resource->property.at) {
- return resource->engine->newQObject(resource->property.at(&resource->property, index));
- } else {
- return v8::Undefined();
- }
-}
-
-v8::Handle<v8::Value> QV8ListWrapper::LengthGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
-
- QV8ListResource *resource = v8_resource_cast<QV8ListResource>(info.This());
-
- if (!resource || resource->object.isNull()) return v8::Undefined();
-
- quint32 count = resource->property.count?resource->property.count(&resource->property):0;
-
- return v8::Integer::NewFromUnsigned(count);
-}
-
-v8::Handle<v8::Array> QV8ListWrapper::Enumerator(const v8::AccessorInfo &info)
-{
- QV8ListResource *resource = v8_resource_cast<QV8ListResource>(info.This());
-
- if (!resource || resource->object.isNull()) return v8::Array::New();
-
- quint32 count = resource->property.count?resource->property.count(&resource->property):0;
-
- v8::Local<v8::Array> rv = v8::Array::New(count);
-
- for (uint ii = 0; ii < count; ++ii)
- rv->Set(ii, v8::Number::New(ii));
-
- return rv;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8listwrapper_p.h b/src/qml/qml/v8/qv8listwrapper_p.h
deleted file mode 100644
index 3d780dc12c..0000000000
--- a/src/qml/qml/v8/qv8listwrapper_p.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV8LISTWRAPPER_P_H
-#define QV8LISTWRAPPER_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 <QtCore/qglobal.h>
-#include <QtQml/qqmllist.h>
-#include <private/qv8_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QV8Engine;
-class QV8ObjectResource;
-class QV8ListWrapper
-{
-public:
- QV8ListWrapper();
- ~QV8ListWrapper();
-
- void init(QV8Engine *);
- void destroy();
-
- v8::Handle<v8::Value> newList(QObject *, int, int);
- v8::Handle<v8::Value> newList(const QQmlListProperty<QObject> &, int);
- QVariant toVariant(v8::Handle<v8::Object>);
- QVariant toVariant(QV8ObjectResource *);
-
-private:
- static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
- v8::Local<v8::Value> value,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> IndexedGetter(uint32_t index,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> LengthGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo &info);
-
- QV8Engine *m_engine;
- v8::Persistent<v8::Function> m_constructor;
-};
-
-QT_END_NAMESPACE
-
-#endif // QV8LISTWRAPPER_P_H
-
diff --git a/src/qml/qml/v8/qv8profiler_p.h b/src/qml/qml/v8/qv8profiler_p.h
index 458532dd7d..39a87f2156 100644
--- a/src/qml/qml/v8/qv8profiler_p.h
+++ b/src/qml/qml/v8/qv8profiler_p.h
@@ -39,4 +39,4 @@
**
****************************************************************************/
-#include <private/v8-profiler.h>
+//#include <private/v8-profiler.h>
diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp
deleted file mode 100644
index 53f70ad132..0000000000
--- a/src/qml/qml/v8/qv8qobjectwrapper.cpp
+++ /dev/null
@@ -1,2283 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv8qobjectwrapper_p.h"
-#include "qv8contextwrapper_p.h"
-#include "qv8engine_p.h"
-
-#include <private/qqmlguard_p.h>
-#include <private/qqmlpropertycache_p.h>
-#include <private/qqmlengine_p.h>
-#include <private/qqmlvmemetaobject_p.h>
-#include <private/qqmlbinding_p.h>
-#include <private/qjsvalue_p.h>
-#include <private/qscript_impl_p.h>
-#include <private/qqmlaccessors_p.h>
-#include <private/qqmlexpression_p.h>
-#include <private/qqmlglobal_p.h>
-
-#include <QtQml/qjsvalue.h>
-#include <QtCore/qjsonarray.h>
-#include <QtCore/qjsonobject.h>
-#include <QtCore/qjsonvalue.h>
-#include <QtCore/qvarlengtharray.h>
-#include <QtCore/qtimer.h>
-#include <QtCore/qatomic.h>
-
-QT_BEGIN_NAMESPACE
-
-#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
-# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405
-// The code in this file does not violate strict aliasing, but GCC thinks it does
-// so turn off the warnings for us to have a clean build
-# pragma GCC diagnostic ignored "-Wstrict-aliasing"
-# endif
-#endif
-
-#define QOBJECT_TOSTRING_INDEX -2
-#define QOBJECT_DESTROY_INDEX -3
-
-// XXX TODO: Need to review all calls to QQmlEngine *engine() to confirm QObjects work
-// correctly in a worker thread
-
-class QV8QObjectInstance : public QQmlGuard<QObject>
-{
-public:
- QV8QObjectInstance(QObject *o, QV8QObjectWrapper *w)
- : QQmlGuard<QObject>(o), wrapper(w)
- {
- }
-
- ~QV8QObjectInstance()
- {
- qPersistentDispose(v8object);
- }
-
- virtual void objectDestroyed(QObject *o)
- {
- if (wrapper)
- wrapper->m_taintedObjects.remove(o);
- delete this;
- }
-
- v8::Persistent<v8::Object> v8object;
- QV8QObjectWrapper *wrapper;
-};
-
-class QV8SignalHandlerResource : public QV8ObjectResource
-{
- V8_RESOURCE_TYPE(SignalHandlerType)
-public:
- QV8SignalHandlerResource(QV8Engine *engine, QObject *object, int index);
-
- QQmlGuard<QObject> object;
- int index;
-};
-
-namespace {
-
-template<typename A, typename B, typename C, typename D, typename E,
- typename F, typename G, typename H>
-class MaxSizeOf8 {
- template<typename Z, typename X>
- struct SMax {
- char dummy[sizeof(Z) > sizeof(X) ? sizeof(Z) : sizeof(X)];
- };
-public:
- static const size_t Size = sizeof(SMax<A, SMax<B, SMax<C, SMax<D, SMax<E, SMax<F, SMax<G, H> > > > > > >);
-};
-
-struct CallArgument {
- inline CallArgument();
- inline ~CallArgument();
- inline void *dataPtr();
-
- inline void initAsType(int type);
- inline void fromValue(int type, QV8Engine *, v8::Handle<v8::Value>);
- inline v8::Handle<v8::Value> toValue(QV8Engine *);
-
-private:
- CallArgument(const CallArgument &);
-
- inline void cleanup();
-
- union {
- float floatValue;
- double doubleValue;
- quint32 intValue;
- bool boolValue;
- QObject *qobjectPtr;
-
- char allocData[MaxSizeOf8<QVariant,
- QString,
- QList<QObject *>,
- QJSValue,
- QQmlV8Handle,
- QJsonArray,
- QJsonObject,
- QJsonValue>::Size];
- qint64 q_for_alignment;
- };
-
- // Pointers to allocData
- union {
- QString *qstringPtr;
- QVariant *qvariantPtr;
- QList<QObject *> *qlistPtr;
- QJSValue *qjsValuePtr;
- QQmlV8Handle *handlePtr;
- QJsonArray *jsonArrayPtr;
- QJsonObject *jsonObjectPtr;
- QJsonValue *jsonValuePtr;
- };
-
- int type;
-};
-}
-
-QV8QObjectResource::QV8QObjectResource(QV8Engine *engine, QObject *object)
-: QV8ObjectResource(engine), object(object)
-{
-}
-
-QV8SignalHandlerResource::QV8SignalHandlerResource(QV8Engine *engine, QObject *object, int index)
-: QV8ObjectResource(engine), object(object), index(index)
-{
-}
-
-static QAtomicInt objectIdCounter(1);
-
-QV8QObjectWrapper::QV8QObjectWrapper()
-: m_engine(0), m_id(objectIdCounter.fetchAndAddOrdered(1))
-{
-}
-
-QV8QObjectWrapper::~QV8QObjectWrapper()
-{
- for (TaintedHash::Iterator iter = m_taintedObjects.begin();
- iter != m_taintedObjects.end();
- ++iter) {
- (*iter)->wrapper = 0;
- }
- m_taintedObjects.clear();
-}
-
-void QV8QObjectWrapper::destroy()
-{
- qDeleteAll(m_connections);
- m_connections.clear();
-
- qPersistentDispose(m_hiddenObject);
- qPersistentDispose(m_destroySymbol);
- qPersistentDispose(m_toStringSymbol);
- qPersistentDispose(m_signalHandlerConstructor);
- qPersistentDispose(m_methodConstructor);
- qPersistentDispose(m_constructor);
-
- QIntrusiveList<QV8QObjectResource, &QV8QObjectResource::weakResource>::iterator i = m_javaScriptOwnedWeakQObjects.begin();
- for (; i != m_javaScriptOwnedWeakQObjects.end(); ++i) {
- QV8QObjectResource *resource = *i;
- Q_ASSERT(resource);
- deleteWeakQObject(resource, true);
- }
-}
-
-struct ReadAccessor {
- static inline void Indirect(QObject *object, const QQmlPropertyData &property,
- void *output, QQmlNotifier **n)
- {
- Q_ASSERT(n == 0);
- Q_UNUSED(n);
-
- void *args[] = { output, 0 };
- QMetaObject::metacall(object, QMetaObject::ReadProperty, property.coreIndex, args);
- }
-
- static inline void Direct(QObject *object, const QQmlPropertyData &property,
- void *output, QQmlNotifier **n)
- {
- Q_ASSERT(n == 0);
- Q_UNUSED(n);
-
- void *args[] = { output, 0 };
- object->qt_metacall(QMetaObject::ReadProperty, property.coreIndex, args);
- }
-
- static inline void Accessor(QObject *object, const QQmlPropertyData &property,
- void *output, QQmlNotifier **n)
- {
- Q_ASSERT(property.accessors);
-
- property.accessors->read(object, property.accessorData, output);
- if (n) property.accessors->notifier(object, property.accessorData, n);
- }
-};
-
-static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *, int v)
-{ return v8::Integer::New(v); }
-static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *, uint v)
-{ return v8::Integer::NewFromUnsigned(v); }
-static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *, bool v)
-{ return v8::Boolean::New(v); }
-static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *e, const QString &v)
-{ return e->toString(v); }
-static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *, float v)
-{ return v8::Number::New(v); }
-static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *, double v)
-{ return v8::Number::New(v); }
-static inline v8::Handle<v8::Value> valueToHandle(QV8Engine *e, QObject *v)
-{ return e->newQObject(v); }
-
-template<typename T, void (*ReadFunction)(QObject *, const QQmlPropertyData &,
- void *, QQmlNotifier **)>
-static v8::Handle<v8::Value> GenericValueGetter(v8::Local<v8::String>, const v8::AccessorInfo &info)
-{
- v8::Handle<v8::Object> This = info.This();
- QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(This);
-
- QObject *object = resource->object;
- if (QQmlData::wasDeleted(object)) return v8::Undefined();
-
- QQmlPropertyData *property =
- (QQmlPropertyData *)v8::External::Cast(*info.Data())->Value();
-
- QQmlEngine *engine = resource->engine->engine();
- QQmlEnginePrivate *ep = engine?QQmlEnginePrivate::get(engine):0;
-
- T value = T();
-
- if (ep && ep->propertyCapture) {
- if (ReadFunction == ReadAccessor::Accessor && property->accessors->notifier) {
- QQmlNotifier *notifier = 0;
- ReadFunction(object, *property, &value, &notifier);
- if (notifier) ep->captureProperty(notifier);
- } else if (!property->isConstant()) {
- ep->captureProperty(object, property->coreIndex, property->notifyIndex);
- ReadFunction(object, *property, &value, 0);
- } else {
- ReadFunction(object, *property, &value, 0);
- }
- } else {
- ReadFunction(object, *property, &value, 0);
- }
-
- return valueToHandle(resource->engine, value);
-}
-
-#define FAST_GETTER_FUNCTION(property, cpptype) \
- (property->hasAccessors()?((v8::AccessorGetter)GenericValueGetter<cpptype, &ReadAccessor::Accessor>):(property->isDirect()?((v8::AccessorGetter)GenericValueGetter<cpptype, &ReadAccessor::Direct>):((v8::AccessorGetter)GenericValueGetter<cpptype, &ReadAccessor::Indirect>)))
-
-static quint32 toStringHash = quint32(-1);
-static quint32 destroyHash = quint32(-1);
-
-void QV8QObjectWrapper::init(QV8Engine *engine)
-{
- m_engine = engine;
-
- m_toStringSymbol = qPersistentNew<v8::String>(v8::String::NewSymbol("toString"));
- m_destroySymbol = qPersistentNew<v8::String>(v8::String::NewSymbol("destroy"));
- m_hiddenObject = qPersistentNew<v8::Object>(v8::Object::New());
-
- m_toStringString = QHashedV8String(m_toStringSymbol);
- m_destroyString = QHashedV8String(m_destroySymbol);
-
- toStringHash = m_toStringString.hash();
- destroyHash = m_destroyString.hash();
-
- {
- v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter, Query, 0, Enumerator);
- ft->InstanceTemplate()->SetHasExternalResource(true);
- m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
- }
- {
- v8::ScriptOrigin origin(m_hiddenObject); // Hack to allow us to identify these functions
-#define CREATE_FUNCTION_SOURCE \
- "(function(method) { "\
- "return (function(object, data, qmlglobal) { "\
- "return (function() { "\
- "return method(object, data, qmlglobal, arguments.length, arguments); "\
- "});"\
- "});"\
- "})"
- v8::Local<v8::Script> script = v8::Script::New(v8::String::New(CREATE_FUNCTION_SOURCE), &origin, 0,
- v8::Handle<v8::String>(), v8::Script::NativeMode);
-#undef CREATE_FUNCTION_SOURCE
- v8::Local<v8::Function> fn = v8::Local<v8::Function>::Cast(script->Run());
- v8::Handle<v8::Value> invokeFn = v8::FunctionTemplate::New(Invoke)->GetFunction();
- v8::Handle<v8::Value> args[] = { invokeFn };
- v8::Local<v8::Function> createFn = v8::Local<v8::Function>::Cast(fn->Call(engine->global(), 1, args));
- m_methodConstructor = qPersistentNew<v8::Function>(createFn);
- }
-
- v8::Local<v8::Function> connect = V8FUNCTION(Connect, engine);
- v8::Local<v8::Function> disconnect = V8FUNCTION(Disconnect, engine);
-
- {
- v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetHasExternalResource(true);
- ft->PrototypeTemplate()->Set(v8::String::New("connect"), connect, v8::DontEnum);
- ft->PrototypeTemplate()->Set(v8::String::New("disconnect"), disconnect, v8::DontEnum);
- m_signalHandlerConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
- }
-
- {
- v8::Local<v8::Object> prototype = engine->global()->Get(v8::String::New("Function"))->ToObject()->Get(v8::String::New("prototype"))->ToObject();
- prototype->Set(v8::String::New("connect"), connect, v8::DontEnum);
- prototype->Set(v8::String::New("disconnect"), disconnect, v8::DontEnum);
- }
-}
-
-bool QV8QObjectWrapper::isQObject(v8::Handle<v8::Object> obj)
-{
- return v8_resource_cast<QV8QObjectResource>(obj) != 0;
-}
-
-QObject *QV8QObjectWrapper::toQObject(v8::Handle<v8::Object> obj)
-{
- QV8QObjectResource *r = v8_resource_cast<QV8QObjectResource>(obj);
- return r?r->object:0;
-}
-
-// r *MUST* be a QV8ObjectResource (r->type() == QV8ObjectResource::QObjectType)
-QObject *QV8QObjectWrapper::toQObject(QV8ObjectResource *r)
-{
- Q_ASSERT(r->resourceType() == QV8ObjectResource::QObjectType);
- return static_cast<QV8QObjectResource *>(r)->object;
-}
-
-// Load value properties
-template<void (*ReadFunction)(QObject *, const QQmlPropertyData &,
- void *, QQmlNotifier **)>
-static v8::Handle<v8::Value> LoadProperty(QV8Engine *engine, QObject *object,
- const QQmlPropertyData &property,
- QQmlNotifier **notifier)
-{
- Q_ASSERT(!property.isFunction());
-
- if (property.isQObject()) {
- QObject *rv = 0;
- ReadFunction(object, property, &rv, notifier);
- return engine->newQObject(rv);
- } else if (property.isQList()) {
- return engine->listWrapper()->newList(object, property.coreIndex, property.propType);
- } else if (property.propType == QMetaType::QReal) {
- qreal v = 0;
- ReadFunction(object, property, &v, notifier);
- return valueToHandle(engine, v);
- } else if (property.propType == QMetaType::Int || property.isEnum()) {
- int v = 0;
- ReadFunction(object, property, &v, notifier);
- return valueToHandle(engine, v);
- } else if (property.propType == QMetaType::Bool) {
- bool v = false;
- ReadFunction(object, property, &v, notifier);
- return valueToHandle(engine, v);
- } else if (property.propType == QMetaType::QString) {
- QString v;
- ReadFunction(object, property, &v, notifier);
- return valueToHandle(engine, v);
- } else if (property.propType == QMetaType::UInt) {
- uint v = 0;
- ReadFunction(object, property, &v, notifier);
- return valueToHandle(engine, v);
- } else if (property.propType == QMetaType::Float) {
- float v = 0;
- ReadFunction(object, property, &v, notifier);
- return valueToHandle(engine, v);
- } else if (property.propType == QMetaType::Double) {
- double v = 0;
- ReadFunction(object, property, &v, notifier);
- return valueToHandle(engine, v);
- } else if (property.isV8Handle()) {
- QQmlV8Handle handle;
- ReadFunction(object, property, &handle, notifier);
- return handle.toHandle();
- } else if (property.propType == qMetaTypeId<QJSValue>()) {
- QJSValue v;
- ReadFunction(object, property, &v, notifier);
- return QJSValuePrivate::get(v)->asV8Value(engine);
- } else if (property.isQVariant()) {
- QVariant v;
- ReadFunction(object, property, &v, notifier);
-
- if (QQmlValueTypeFactory::isValueType(v.userType())) {
- if (QQmlValueType *valueType = QQmlValueTypeFactory::valueType(v.userType()))
- return engine->newValueType(object, property.coreIndex, valueType); // VariantReference value-type.
- }
-
- return engine->fromVariant(v);
- } else if (QQmlValueTypeFactory::isValueType(property.propType)) {
- Q_ASSERT(notifier == 0);
-
- if (QQmlValueType *valueType = QQmlValueTypeFactory::valueType(property.propType))
- return engine->newValueType(object, property.coreIndex, valueType);
- } else {
- Q_ASSERT(notifier == 0);
-
- // see if it's a sequence type
- bool succeeded = false;
- v8::Handle<v8::Value> retn = engine->newSequence(property.propType, object, property.coreIndex,
- &succeeded);
- if (succeeded)
- return retn;
- }
-
- if (property.propType == QMetaType::UnknownType) {
- QMetaProperty p = object->metaObject()->property(property.coreIndex);
- qWarning("QMetaProperty::read: Unable to handle unregistered datatype '%s' for property "
- "'%s::%s'", p.typeName(), object->metaObject()->className(), p.name());
- return v8::Undefined();
- } else {
- QVariant v(property.propType, (void *)0);
- ReadFunction(object, property, v.data(), notifier);
- return engine->fromVariant(v);
- }
-}
-
-v8::Handle<v8::Value> QV8QObjectWrapper::GetProperty(QV8Engine *engine, QObject *object,
- v8::Handle<v8::Value> *objectHandle,
- const QHashedV8String &property,
- QQmlContextData *context,
- QV8QObjectWrapper::RevisionMode revisionMode)
-{
- // XXX More recent versions of V8 introduced "Callable" objects. It is possible that these
- // will be a faster way of creating QObject method objects.
- struct MethodClosure {
- static v8::Handle<v8::Value> create(QV8Engine *engine, QObject *object,
- v8::Handle<v8::Value> *objectHandle,
- int index) {
- v8::Handle<v8::Value> argv[] = {
- objectHandle?*objectHandle:engine->newQObject(object),
- v8::Integer::New(index)
- };
- Q_ASSERT(argv[0]->IsObject());
- return engine->qobjectWrapper()->m_methodConstructor->Call(engine->global(), 2, argv);
- }
- static v8::Handle<v8::Value> createWithGlobal(QV8Engine *engine, QObject *object,
- v8::Handle<v8::Value> *objectHandle,
- int index) {
- v8::Handle<v8::Value> argv[] = {
- objectHandle?*objectHandle:engine->newQObject(object),
- v8::Integer::New(index),
- v8::Context::GetCallingQmlGlobal()
- };
- Q_ASSERT(argv[0]->IsObject());
- return engine->qobjectWrapper()->m_methodConstructor->Call(engine->global(), 3, argv);
- }
- };
-
- if (QQmlData::wasDeleted(object))
- return v8::Handle<v8::Value>();
-
- {
- // Comparing the hash first actually makes a measurable difference here, at least on x86
- quint32 hash = property.hash();
- if (hash == toStringHash && engine->qobjectWrapper()->m_toStringString == property) {
- return MethodClosure::create(engine, object, objectHandle, QOBJECT_TOSTRING_INDEX);
- } else if (hash == destroyHash && engine->qobjectWrapper()->m_destroyString == property) {
- return MethodClosure::create(engine, object, objectHandle, QOBJECT_DESTROY_INDEX);
- }
- }
-
- QQmlPropertyData local;
- QQmlPropertyData *result = 0;
- {
- QQmlData *ddata = QQmlData::get(object, false);
- if (ddata && ddata->propertyCache)
- result = ddata->propertyCache->property(property, object, context);
- if (!result)
- result = QQmlPropertyCache::property(engine->engine(), object, property, context, local);
- }
-
- if (!result)
- return v8::Handle<v8::Value>();
-
- QQmlData::flushPendingBinding(object, result->coreIndex);
-
- if (revisionMode == QV8QObjectWrapper::CheckRevision && result->hasRevision()) {
- QQmlData *ddata = QQmlData::get(object);
- if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result))
- return v8::Handle<v8::Value>();
- }
-
- if (result->isFunction() && !result->isVarProperty()) {
- if (result->isVMEFunction()) {
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
- Q_ASSERT(vmemo);
- return vmemo->vmeMethod(result->coreIndex);
- } else if (result->isV8Function()) {
- return MethodClosure::createWithGlobal(engine, object, objectHandle, result->coreIndex);
- } else if (result->isSignalHandler()) {
- v8::Local<v8::Object> handler = engine->qobjectWrapper()->m_signalHandlerConstructor->NewInstance();
- QV8SignalHandlerResource *r = new QV8SignalHandlerResource(engine, object, result->coreIndex);
- handler->SetExternalResource(r);
- return handler;
- } else {
- return MethodClosure::create(engine, object, objectHandle, result->coreIndex);
- }
- }
-
- QQmlEnginePrivate *ep =
- engine->engine()?QQmlEnginePrivate::get(engine->engine()):0;
-
- if (result->hasAccessors()) {
- QQmlNotifier *n = 0;
- QQmlNotifier **nptr = 0;
-
- if (ep && ep->propertyCapture && result->accessors->notifier)
- nptr = &n;
-
- v8::Handle<v8::Value> rv = LoadProperty<ReadAccessor::Accessor>(engine, object, *result, nptr);
-
- if (result->accessors->notifier) {
- if (n) ep->captureProperty(n);
- } else {
- ep->captureProperty(object, result->coreIndex, result->notifyIndex);
- }
-
- return rv;
- }
-
- if (ep && !result->isConstant())
- ep->captureProperty(object, result->coreIndex, result->notifyIndex);
-
- if (result->isVarProperty()) {
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
- Q_ASSERT(vmemo);
- return vmemo->vmeProperty(result->coreIndex);
- } else if (result->isDirect()) {
- return LoadProperty<ReadAccessor::Direct>(engine, object, *result, 0);
- } else {
- return LoadProperty<ReadAccessor::Indirect>(engine, object, *result, 0);
- }
-}
-
-// Setter for writable properties. Shared between the interceptor and fast property accessor
-static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropertyData *property,
- v8::Handle<v8::Value> value)
-{
- QQmlBinding *newBinding = 0;
- if (value->IsFunction()) {
- if (value->ToObject()->GetHiddenValue(engine->bindingFlagKey()).IsEmpty()) {
- if (!property->isVarProperty() && property->propType != qMetaTypeId<QJSValue>()) {
- // assigning a JS function to a non var or QJSValue property or is not allowed.
- QString error = QLatin1String("Cannot assign JavaScript function to ");
- if (!QMetaType::typeName(property->propType))
- error += QLatin1String("[unknown property type]");
- else
- error += QLatin1String(QMetaType::typeName(property->propType));
- v8::ThrowException(v8::Exception::Error(engine->toString(error)));
- return;
- }
- } else {
- // binding assignment.
- QQmlContextData *context = engine->callingContext();
- v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
-
- v8::Local<v8::StackTrace> trace =
- v8::StackTrace::CurrentStackTrace(1, (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber |
- v8::StackTrace::kScriptName));
- v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
- int lineNumber = frame->GetLineNumber();
- int columnNumber = frame->GetColumn();
- QString url = engine->toString(frame->GetScriptName());
-
- newBinding = new QQmlBinding(&function, object, context, url, qmlSourceCoordinate(lineNumber), qmlSourceCoordinate(columnNumber));
- newBinding->setTarget(object, *property, context);
- newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
- QQmlBinding::RequiresThisObject);
- }
- }
-
- QQmlAbstractBinding *oldBinding =
- QQmlPropertyPrivate::setBinding(object, property->coreIndex, -1, newBinding);
- if (oldBinding)
- oldBinding->destroy();
-
- if (!newBinding && property->isVarProperty()) {
- // allow assignment of "special" values (null, undefined, function) to var properties
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
- Q_ASSERT(vmemo);
- vmemo->setVMEProperty(property->coreIndex, value);
- return;
- }
-
-#define PROPERTY_STORE(cpptype, value) \
- cpptype o = value; \
- int status = -1; \
- int flags = 0; \
- void *argv[] = { &o, 0, &status, &flags }; \
- QMetaObject::metacall(object, QMetaObject::WriteProperty, property->coreIndex, argv);
-
- if (value->IsNull() && property->isQObject()) {
- PROPERTY_STORE(QObject*, 0);
- } else if (value->IsUndefined() && property->isResettable()) {
- void *a[] = { 0 };
- QMetaObject::metacall(object, QMetaObject::ResetProperty, property->coreIndex, a);
- } else if (value->IsUndefined() && property->propType == qMetaTypeId<QVariant>()) {
- PROPERTY_STORE(QVariant, QVariant());
- } else if (value->IsUndefined() && property->propType == QMetaType::QJsonValue) {
- PROPERTY_STORE(QJsonValue, QJsonValue(QJsonValue::Undefined));
- } else if (!newBinding && property->propType == qMetaTypeId<QJSValue>()) {
- PROPERTY_STORE(QJSValue, engine->scriptValueFromInternal(value));
- } else if (value->IsUndefined()) {
- QString error = QLatin1String("Cannot assign [undefined] to ");
- if (!QMetaType::typeName(property->propType))
- error += QLatin1String("[unknown property type]");
- else
- error += QLatin1String(QMetaType::typeName(property->propType));
- v8::ThrowException(v8::Exception::Error(engine->toString(error)));
- } else if (value->IsFunction()) {
- // this is handled by the binding creation above
- } else if (property->propType == QMetaType::Int && value->IsNumber()) {
- PROPERTY_STORE(int, qRound(value->ToNumber()->Value()));
- } else if (property->propType == QMetaType::QReal && value->IsNumber()) {
- PROPERTY_STORE(qreal, qreal(value->ToNumber()->Value()));
- } else if (property->propType == QMetaType::Float && value->IsNumber()) {
- PROPERTY_STORE(float, float(value->ToNumber()->Value()));
- } else if (property->propType == QMetaType::Double && value->IsNumber()) {
- PROPERTY_STORE(double, double(value->ToNumber()->Value()));
- } else if (property->propType == QMetaType::QString && value->IsString()) {
- PROPERTY_STORE(QString, engine->toString(value->ToString()));
- } else if (property->isVarProperty()) {
- QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(object);
- Q_ASSERT(vmemo);
- vmemo->setVMEProperty(property->coreIndex, value);
- } else {
- QVariant v;
- if (property->isQList())
- v = engine->toVariant(value, qMetaTypeId<QList<QObject *> >());
- else
- v = engine->toVariant(value, property->propType);
-
- QQmlContextData *context = engine->callingContext();
- if (!QQmlPropertyPrivate::write(object, *property, v, context)) {
- const char *valueType = 0;
- if (v.userType() == QVariant::Invalid) valueType = "null";
- else valueType = QMetaType::typeName(v.userType());
-
- const char *targetTypeName = QMetaType::typeName(property->propType);
- if (!targetTypeName)
- targetTypeName = "an unregistered type";
-
- QString error = QLatin1String("Cannot assign ") +
- QLatin1String(valueType) +
- QLatin1String(" to ") +
- QLatin1String(targetTypeName);
- v8::ThrowException(v8::Exception::Error(engine->toString(error)));
- }
- }
-}
-
-bool QV8QObjectWrapper::SetProperty(QV8Engine *engine, QObject *object, const QHashedV8String &property, QQmlContextData *context,
- v8::Handle<v8::Value> value, QV8QObjectWrapper::RevisionMode revisionMode)
-{
- if (engine->qobjectWrapper()->m_toStringString == property ||
- engine->qobjectWrapper()->m_destroyString == property)
- return true;
-
- if (QQmlData::wasDeleted(object))
- return false;
-
- QQmlPropertyData local;
- QQmlPropertyData *result = 0;
- result = QQmlPropertyCache::property(engine->engine(), object, property, context, local);
-
- if (!result)
- return false;
-
- if (revisionMode == QV8QObjectWrapper::CheckRevision && result->hasRevision()) {
- QQmlData *ddata = QQmlData::get(object);
- if (ddata && ddata->propertyCache && !ddata->propertyCache->isAllowedInRevision(result))
- return false;
- }
-
- if (!result->isWritable() && !result->isQList()) {
- QString error = QLatin1String("Cannot assign to read-only property \"") +
- engine->toString(property.string()) + QLatin1Char('\"');
- v8::ThrowException(v8::Exception::Error(engine->toString(error)));
- return true;
- }
-
- StoreProperty(engine, object, result, value);
-
- return true;
-}
-
-v8::Handle<v8::Value> QV8QObjectWrapper::Getter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
-{
- QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
-
- if (QQmlData::wasDeleted(resource->object))
- return v8::Handle<v8::Value>();
-
- QObject *object = resource->object;
-
- QHashedV8String propertystring(property);
-
- QV8Engine *v8engine = resource->engine;
- QQmlContextData *context = v8engine->callingContext();
-
- v8::Handle<v8::Value> This = info.This();
- v8::Handle<v8::Value> result = GetProperty(v8engine, object, &This, propertystring,
- context, QV8QObjectWrapper::IgnoreRevision);
- if (!result.IsEmpty())
- return result;
-
- if (QV8Engine::startsWithUpper(property)) {
- // Check for attached properties
- if (context && context->imports) {
- QQmlTypeNameCache::Result r = context->imports->query(propertystring);
-
- if (r.isValid()) {
- if (r.scriptIndex != -1) {
- return v8::Undefined();
- } else if (r.type) {
- return v8engine->typeWrapper()->newObject(object, r.type, QV8TypeWrapper::ExcludeEnums);
- } else if (r.importNamespace) {
- return v8engine->typeWrapper()->newObject(object, context->imports, r.importNamespace,
- QV8TypeWrapper::ExcludeEnums);
- }
- Q_ASSERT(!"Unreachable");
- }
- }
- }
-
- return v8::Handle<v8::Value>();
-}
-
-v8::Handle<v8::Value> QV8QObjectWrapper::Setter(v8::Local<v8::String> property,
- v8::Local<v8::Value> value,
- const v8::AccessorInfo &info)
-{
- QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
-
- if (QQmlData::wasDeleted(resource->object))
- return value;
-
- QObject *object = resource->object;
-
- QHashedV8String propertystring(property);
-
- QV8Engine *v8engine = resource->engine;
- QQmlContextData *context = v8engine->callingContext();
- bool result = SetProperty(v8engine, object, propertystring, context, value, QV8QObjectWrapper::IgnoreRevision);
-
- if (!result) {
- QString error = QLatin1String("Cannot assign to non-existent property \"") +
- v8engine->toString(property) + QLatin1Char('\"');
- v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
- return value;
- }
-
- return value;
-}
-
-v8::Handle<v8::Integer> QV8QObjectWrapper::Query(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
-{
- QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
-
- if (resource->object.isNull())
- return v8::Handle<v8::Integer>();
-
- QV8Engine *engine = resource->engine;
- QObject *object = resource->object;
- QQmlContextData *context = engine->callingContext();
-
- QHashedV8String propertystring(property);
-
- QQmlPropertyData local;
- QQmlPropertyData *result = 0;
- result = QQmlPropertyCache::property(engine->engine(), object, propertystring, context, local);
-
- if (!result)
- return v8::Handle<v8::Integer>();
- else if (!result->isWritable() && !result->isQList())
- return v8::Integer::New(v8::ReadOnly | v8::DontDelete);
- else
- return v8::Integer::New(v8::DontDelete);
-}
-
-v8::Handle<v8::Array> QV8QObjectWrapper::Enumerator(const v8::AccessorInfo &info)
-{
- QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
-
- if (resource->object.isNull())
- return v8::Array::New();
-
- QObject *object = resource->object;
-
- QStringList result;
-
- QQmlEnginePrivate *ep = resource->engine->engine()
- ? QQmlEnginePrivate::get(resource->engine->engine())
- : 0;
-
- QQmlPropertyCache *cache = 0;
- QQmlData *ddata = QQmlData::get(object);
- if (ddata)
- cache = ddata->propertyCache;
-
- if (!cache) {
- cache = ep ? ep->cache(object) : 0;
- if (cache) {
- if (ddata) { cache->addref(); ddata->propertyCache = cache; }
- } else {
- // Not cachable - fall back to QMetaObject (eg. dynamic meta object)
- const QMetaObject *mo = object->metaObject();
- int pc = mo->propertyCount();
- int po = mo->propertyOffset();
- for (int i=po; i<pc; ++i)
- result << QString::fromUtf8(mo->property(i).name());
- }
- } else {
- result = cache->propertyNames();
- }
-
- v8::Local<v8::Array> rv = v8::Array::New(result.count());
-
- for (int ii = 0; ii < result.count(); ++ii)
- rv->Set(ii, resource->engine->toString(result.at(ii)));
-
- return rv;
-}
-
-static void FastValueSetter(v8::Local<v8::String>, v8::Local<v8::Value> value,
- const v8::AccessorInfo& info)
-{
- QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
-
- if (QQmlData::wasDeleted(resource->object))
- return;
-
- QObject *object = resource->object;
-
- QQmlPropertyData *property =
- (QQmlPropertyData *)v8::External::Cast(*info.Data())->Value();
-
- int index = property->coreIndex;
-
- QQmlData *ddata = QQmlData::get(object, false);
- Q_ASSERT(ddata);
- Q_ASSERT(ddata->propertyCache);
-
- QQmlPropertyData *pdata = ddata->propertyCache->property(index);
- Q_ASSERT(pdata);
-
- Q_ASSERT(pdata->isWritable() || pdata->isQList());
-
- StoreProperty(resource->engine, object, pdata, value);
-}
-
-static void FastValueSetterReadOnly(v8::Local<v8::String> property, v8::Local<v8::Value>,
- const v8::AccessorInfo& info)
-{
- QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(info.This());
-
- if (QQmlData::wasDeleted(resource->object))
- return;
-
- QV8Engine *v8engine = resource->engine;
-
- QString error = QLatin1String("Cannot assign to read-only property \"") +
- v8engine->toString(property) + QLatin1Char('\"');
- v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
-}
-
-void QV8QObjectWrapper::WeakQObjectReferenceCallback(v8::Persistent<v8::Value> handle, void *wrapper)
-{
- Q_ASSERT(handle->IsObject());
- v8::Handle<v8::Object> v8object = handle->ToObject();
- QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(v8object);
- Q_ASSERT(resource);
-
- static_cast<QV8QObjectWrapper*>(wrapper)->unregisterWeakQObjectReference(resource);
- if (static_cast<QV8QObjectWrapper*>(wrapper)->deleteWeakQObject(resource, false)) {
- // dispose
- v8object->SetExternalResource(0);
- delete resource;
- qPersistentDispose(handle);
- } else {
- handle.MakeWeak(0, WeakQObjectReferenceCallback); // revive.
- }
-}
-
-static void WeakQObjectInstanceCallback(v8::Persistent<v8::Value> handle, void *data)
-{
- QV8QObjectInstance *instance = (QV8QObjectInstance *)data;
- instance->v8object.Clear();
- qPersistentDispose(handle);
-}
-
-v8::Local<v8::Object> QQmlPropertyCache::newQObject(QObject *object, QV8Engine *engine)
-{
- Q_ASSERT(object);
- Q_ASSERT(this->engine);
-
- Q_ASSERT(QQmlData::get(object, false));
- Q_ASSERT(QQmlData::get(object, false)->propertyCache == this);
-
- // Setup constructor
- if (constructor.IsEmpty()) {
- v8::Local<v8::FunctionTemplate> ft;
-
- const QHashedString toString(QStringLiteral("toString"));
- const QHashedString destroy(QStringLiteral("destroy"));
-
- // As we use hash linking, or with property overrides, it is possible that iterating
- // over the values can yield duplicates. To combat this, we must unique'ify our properties.
- const bool checkForDuplicates = stringCache.isLinked() || _hasPropertyOverrides;
-
- StringCache uniqueHash;
- if (checkForDuplicates)
- uniqueHash.reserve(stringCache.count());
-
- // XXX TODO: Enables fast property accessors. These more than double the property access
- // performance, but the cost of setting up this structure hasn't been measured so
- // its not guaranteed that this is a win overall. We need to try and measure the cost.
- for (StringCache::ConstIterator iter = stringCache.begin(); iter != stringCache.end(); ++iter) {
- if (iter.equals(toString) || iter.equals(destroy))
- continue;
-
- if (checkForDuplicates) {
- if (uniqueHash.contains(iter))
- continue;
- uniqueHash.insert(iter);
- }
-
- QQmlPropertyData *property = (*iter).second;
- if (property->notFullyResolved()) resolve(property);
-
- if (property->isFunction())
- continue;
-
- v8::AccessorGetter fastgetter = 0;
-
- if (property->isQObject())
- fastgetter = FAST_GETTER_FUNCTION(property, QObject*);
- else if (property->propType == QMetaType::Int || property->isEnum())
- fastgetter = FAST_GETTER_FUNCTION(property, int);
- else if (property->propType == QMetaType::Bool)
- fastgetter = FAST_GETTER_FUNCTION(property, bool);
- else if (property->propType == QMetaType::QString)
- fastgetter = FAST_GETTER_FUNCTION(property, QString);
- else if (property->propType == QMetaType::UInt)
- fastgetter = FAST_GETTER_FUNCTION(property, uint);
- else if (property->propType == QMetaType::Float)
- fastgetter = FAST_GETTER_FUNCTION(property, float);
- else if (property->propType == QMetaType::Double)
- fastgetter = FAST_GETTER_FUNCTION(property, double);
-
- if (fastgetter) {
- if (ft.IsEmpty()) {
- ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetFallbackPropertyHandler(QV8QObjectWrapper::Getter,
- QV8QObjectWrapper::Setter,
- QV8QObjectWrapper::Query,
- 0,
- QV8QObjectWrapper::Enumerator);
- ft->InstanceTemplate()->SetHasExternalResource(true);
- }
-
- v8::AccessorSetter fastsetter = FastValueSetter;
- if (!property->isWritable())
- fastsetter = FastValueSetterReadOnly;
-
- // We wrap the raw QQmlPropertyData pointer here. This is safe as the
- // pointer will remain valid at least as long as the lifetime of any QObject's of
- // this type and the property accessor checks if the object is 0 (deleted) before
- // dereferencing the pointer.
- ft->InstanceTemplate()->SetAccessor(engine->toString(iter.key()), fastgetter, fastsetter,
- v8::External::New(property));
- }
- }
-
- if (ft.IsEmpty()) {
- constructor = qPersistentNew<v8::Function>(engine->qobjectWrapper()->m_constructor);
- } else {
- ft->InstanceTemplate()->SetFallbackPropertyHandler(QV8QObjectWrapper::Getter,
- QV8QObjectWrapper::Setter,
- QV8QObjectWrapper::Query,
- 0,
- QV8QObjectWrapper::Enumerator);
- ft->InstanceTemplate()->SetHasExternalResource(true);
- constructor = qPersistentNew<v8::Function>(ft->GetFunction());
- }
-
- QQmlCleanup::addToEngine(this->engine);
- }
-
- v8::Local<v8::Object> result = constructor->NewInstance();
- QV8QObjectResource *r = new QV8QObjectResource(engine, object);
- result->SetExternalResource(r);
- return result;
-}
-
-v8::Local<v8::Object> QV8QObjectWrapper::newQObject(QObject *object, QQmlData *ddata, QV8Engine *engine)
-{
- v8::Local<v8::Object> rv;
-
- if (!ddata->propertyCache && engine->engine()) {
- ddata->propertyCache = QQmlEnginePrivate::get(engine->engine())->cache(object);
- if (ddata->propertyCache) ddata->propertyCache->addref();
- }
-
- if (ddata->propertyCache && ddata->propertyCache->qmlEngine() == engine->engine()) {
- rv = ddata->propertyCache->newQObject(object, engine);
- } else {
- // XXX NewInstance() should be optimized
- rv = m_constructor->NewInstance();
- QV8QObjectResource *r = new QV8QObjectResource(engine, object);
- rv->SetExternalResource(r);
- }
-
- return rv;
-}
-
-/*
-As V8 doesn't support an equality callback, for QObject's we have to return exactly the same
-V8 handle for subsequent calls to newQObject for the same QObject. To do this we have a two
-pronged strategy:
- 1. If there is no current outstanding V8 handle to the QObject, we create one and store a
- persistent handle in QQmlData::v8object. We mark the QV8QObjectWrapper that
- "owns" this handle by setting the QQmlData::v8objectid to the id of this
- QV8QObjectWrapper.
- 2. If another QV8QObjectWrapper has create the handle in QQmlData::v8object we create
- an entry in the m_taintedObject hash where we store the handle and mark the object as
- "tainted" in the QQmlData::hasTaintedV8Object flag.
-We have to mark the object as tainted to ensure that we search our m_taintedObject hash even
-in the case that the original QV8QObjectWrapper owner of QQmlData::v8object has
-released the handle.
-*/
-v8::Handle<v8::Value> QV8QObjectWrapper::newQObject(QObject *object)
-{
- if (QQmlData::wasDeleted(object))
- return v8::Null();
-
- QQmlData *ddata = QQmlData::get(object, true);
- if (!ddata)
- return v8::Undefined();
-
- if (ddata->v8objectid == m_id && !ddata->v8object.IsEmpty()) {
- // We own the v8object
- return v8::Local<v8::Object>::New(ddata->v8object);
- } else if (ddata->v8object.IsEmpty() &&
- (ddata->v8objectid == m_id || // We own the QObject
- ddata->v8objectid == 0 || // No one owns the QObject
- !ddata->hasTaintedV8Object)) { // Someone else has used the QObject, but it isn't tainted
-
- v8::Local<v8::Object> rv = newQObject(object, ddata, m_engine);
- ddata->v8object = qPersistentNew<v8::Object>(rv);
- ddata->v8object.MakeWeak(this, WeakQObjectReferenceCallback);
- ddata->v8objectid = m_id;
- QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(rv);
- registerWeakQObjectReference(resource);
- return rv;
-
- } else {
- // If this object is tainted, we have to check to see if it is in our
- // tainted object list
- TaintedHash::Iterator iter =
- ddata->hasTaintedV8Object?m_taintedObjects.find(object):m_taintedObjects.end();
- bool found = iter != m_taintedObjects.end();
-
- // If our tainted handle doesn't exist or has been collected, and there isn't
- // a handle in the ddata, we can assume ownership of the ddata->v8object
- if ((!found || (*iter)->v8object.IsEmpty()) && ddata->v8object.IsEmpty()) {
- v8::Local<v8::Object> rv = newQObject(object, ddata, m_engine);
- ddata->v8object = qPersistentNew<v8::Object>(rv);
- ddata->v8object.MakeWeak(this, WeakQObjectReferenceCallback);
- ddata->v8objectid = m_id;
- QV8QObjectResource *resource = v8_resource_check<QV8QObjectResource>(rv);
- registerWeakQObjectReference(resource);
-
- if (found) {
- delete (*iter);
- m_taintedObjects.erase(iter);
- }
-
- return rv;
- } else if (!found) {
- QV8QObjectInstance *instance = new QV8QObjectInstance(object, this);
- iter = m_taintedObjects.insert(object, instance);
- ddata->hasTaintedV8Object = true;
- }
-
- if ((*iter)->v8object.IsEmpty()) {
- v8::Local<v8::Object> rv = newQObject(object, ddata, m_engine);
- (*iter)->v8object = qPersistentNew<v8::Object>(rv);
- (*iter)->v8object.MakeWeak((*iter), WeakQObjectInstanceCallback);
- }
-
- return v8::Local<v8::Object>::New((*iter)->v8object);
- }
-}
-
-// returns true if the object's qqmldata v8object handle should
-// be disposed by the caller, false if it should not be (due to
-// creation status, etc).
-bool QV8QObjectWrapper::deleteWeakQObject(QV8QObjectResource *resource, bool calledFromEngineDtor)
-{
- QObject *object = resource->object;
- if (object) {
- QQmlData *ddata = QQmlData::get(object, false);
- if (ddata) {
- if (!calledFromEngineDtor && ddata->rootObjectInCreation) {
- // if weak ref callback is triggered (by gc) for a root object
- // prior to completion of creation, we should NOT delete it.
- return false;
- }
-
- ddata->v8object.Clear();
- if (!object->parent() && !ddata->indestructible) {
- // This object is notionally destroyed now
- if (ddata->ownContext && ddata->context)
- ddata->context->emitDestruction();
- ddata->isQueuedForDeletion = true;
- if (calledFromEngineDtor)
- delete object;
- else
- object->deleteLater();
- }
- }
- }
-
- return true;
-}
-
-QPair<QObject *, int> QV8QObjectWrapper::ExtractQtSignal(QV8Engine *engine, v8::Handle<v8::Object> object)
-{
- if (object->IsFunction())
- return ExtractQtMethod(engine, v8::Handle<v8::Function>::Cast(object));
-
- if (QV8SignalHandlerResource *resource = v8_resource_cast<QV8SignalHandlerResource>(object))
- return qMakePair(resource->object.data(), resource->index);
-
- return qMakePair((QObject *)0, -1);
-}
-
-QPair<QObject *, int> QV8QObjectWrapper::ExtractQtMethod(QV8Engine *engine, v8::Handle<v8::Function> function)
-{
- v8::ScriptOrigin origin = function->GetScriptOrigin();
- if (origin.ResourceName()->StrictEquals(engine->qobjectWrapper()->m_hiddenObject)) {
-
- // This is one of our special QObject method wrappers
- v8::Handle<v8::Value> args[] = { engine->qobjectWrapper()->m_hiddenObject };
- v8::Local<v8::Value> data = function->Call(engine->global(), 1, args);
-
- if (data->IsArray()) {
- v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(data);
- return qMakePair(engine->toQObject(array->Get(0)), array->Get(1)->Int32Value());
- }
-
- // In theory this can't fall through, but I suppose V8 might run out of memory or something
- }
-
- return qMakePair((QObject *)0, -1);
-}
-
-class QV8QObjectConnectionList : public QObject, public QQmlGuard<QObject>
-{
-public:
- QV8QObjectConnectionList(QObject *object, QV8Engine *engine);
- ~QV8QObjectConnectionList();
-
- struct Connection {
- Connection()
- : needsDestroy(false) {}
- Connection(const Connection &other)
- : thisObject(other.thisObject), function(other.function), needsDestroy(false) {}
- Connection &operator=(const Connection &other) {
- thisObject = other.thisObject;
- function = other.function;
- needsDestroy = other.needsDestroy;
- return *this;
- }
-
- v8::Persistent<v8::Object> thisObject;
- v8::Persistent<v8::Function> function;
-
- void dispose() {
- qPersistentDispose(thisObject);
- qPersistentDispose(function);
- }
-
- bool needsDestroy;
- };
-
- struct ConnectionList : public QList<Connection> {
- ConnectionList() : connectionsInUse(0), connectionsNeedClean(false) {}
- int connectionsInUse;
- bool connectionsNeedClean;
- };
-
- QV8Engine *engine;
-
- typedef QHash<int, ConnectionList> SlotHash;
- SlotHash slotHash;
- bool needsDestroy;
- int inUse;
-
- virtual void objectDestroyed(QObject *);
- virtual int qt_metacall(QMetaObject::Call, int, void **);
-};
-
-QV8QObjectConnectionList::QV8QObjectConnectionList(QObject *object, QV8Engine *engine)
-: QQmlGuard<QObject>(object), engine(engine), needsDestroy(false), inUse(0)
-{
-}
-
-QV8QObjectConnectionList::~QV8QObjectConnectionList()
-{
- for (SlotHash::Iterator iter = slotHash.begin(); iter != slotHash.end(); ++iter) {
- QList<Connection> &connections = *iter;
- for (int ii = 0; ii < connections.count(); ++ii) {
- qPersistentDispose(connections[ii].thisObject);
- qPersistentDispose(connections[ii].function);
- }
- }
- slotHash.clear();
-}
-
-void QV8QObjectConnectionList::objectDestroyed(QObject *object)
-{
- engine->qobjectWrapper()->m_connections.remove(object);
-
- if (inUse)
- needsDestroy = true;
- else
- delete this;
-}
-
-int QV8QObjectConnectionList::qt_metacall(QMetaObject::Call method, int index, void **metaArgs)
-{
- if (method == QMetaObject::InvokeMetaMethod) {
- SlotHash::Iterator iter = slotHash.find(index);
- if (iter == slotHash.end())
- return -1;
- ConnectionList &connectionList = *iter;
- if (connectionList.isEmpty())
- return -1;
-
- inUse++;
-
- connectionList.connectionsInUse++;
-
- QList<Connection> connections = connectionList;
-
- QVarLengthArray<int, 9> dummy;
- int *argsTypes = QQmlPropertyCache::methodParameterTypes(data(), index, dummy, 0);
-
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(engine->context());
-
- int argCount = argsTypes?argsTypes[0]:0;
- QVarLengthArray<v8::Handle<v8::Value>, 9> args(argCount);
-
- for (int ii = 0; ii < argCount; ++ii) {
- int type = argsTypes[ii + 1];
- if (type == qMetaTypeId<QVariant>()) {
- args[ii] = engine->fromVariant(*((QVariant *)metaArgs[ii + 1]));
- } else {
- args[ii] = engine->fromVariant(QVariant(type, metaArgs[ii + 1]));
- }
- }
-
- for (int ii = 0; ii < connections.count(); ++ii) {
- Connection &connection = connections[ii];
- if (connection.needsDestroy)
- continue;
-
- v8::TryCatch try_catch;
- if (connection.thisObject.IsEmpty()) {
- connection.function->Call(engine->global(), argCount, args.data());
- } else {
- connection.function->Call(connection.thisObject, argCount, args.data());
- }
-
- if (try_catch.HasCaught()) {
- QQmlError error;
- error.setDescription(QString(QLatin1String("Unknown exception occurred during evaluation of connected function: %1")).arg(engine->toString(connection.function->GetName())));
- v8::Local<v8::Message> message = try_catch.Message();
- if (!message.IsEmpty())
- QQmlExpressionPrivate::exceptionToError(message, error);
- QQmlEnginePrivate::get(engine->engine())->warning(error);
- }
- }
-
- connectionList.connectionsInUse--;
- if (connectionList.connectionsInUse == 0 && connectionList.connectionsNeedClean) {
- for (QList<Connection>::Iterator iter = connectionList.begin();
- iter != connectionList.end(); ) {
- if (iter->needsDestroy) {
- iter->dispose();
- iter = connectionList.erase(iter);
- } else {
- ++iter;
- }
- }
- }
-
- inUse--;
- if (inUse == 0 && needsDestroy)
- delete this;
- }
-
- return -1;
-}
-
-v8::Handle<v8::Value> QV8QObjectWrapper::Connect(const v8::Arguments &args)
-{
- if (args.Length() == 0)
- V8THROW_ERROR("Function.prototype.connect: no arguments given");
-
- QV8Engine *engine = V8ENGINE();
-
- QPair<QObject *, int> signalInfo = ExtractQtSignal(engine, args.This());
- QObject *signalObject = signalInfo.first;
- int signalIndex = signalInfo.second;
-
- if (signalIndex < 0)
- V8THROW_ERROR("Function.prototype.connect: this object is not a signal");
-
- if (!signalObject)
- V8THROW_ERROR("Function.prototype.connect: cannot connect to deleted QObject");
-
- if (signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
- V8THROW_ERROR("Function.prototype.connect: this object is not a signal");
-
- v8::Local<v8::Value> functionValue;
- v8::Local<v8::Value> functionThisValue;
-
- if (args.Length() == 1) {
- functionValue = args[0];
- } else {
- functionThisValue = args[0];
- functionValue = args[1];
- }
-
- if (!functionValue->IsFunction())
- V8THROW_ERROR("Function.prototype.connect: target is not a function");
-
- if (!functionThisValue.IsEmpty() && !functionThisValue->IsObject())
- V8THROW_ERROR("Function.prototype.connect: target this is not an object");
-
- QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
- QHash<QObject *, QV8QObjectConnectionList *> &connections = qobjectWrapper->m_connections;
- QHash<QObject *, QV8QObjectConnectionList *>::Iterator iter = connections.find(signalObject);
- if (iter == connections.end())
- iter = connections.insert(signalObject, new QV8QObjectConnectionList(signalObject, engine));
-
- QV8QObjectConnectionList *connectionList = *iter;
- QV8QObjectConnectionList::SlotHash::Iterator slotIter = connectionList->slotHash.find(signalIndex);
- if (slotIter == connectionList->slotHash.end()) {
- slotIter = connectionList->slotHash.insert(signalIndex, QV8QObjectConnectionList::ConnectionList());
- QMetaObject::connect(signalObject, signalIndex, connectionList, signalIndex);
- }
-
- QV8QObjectConnectionList::Connection connection;
- if (!functionThisValue.IsEmpty())
- connection.thisObject = qPersistentNew<v8::Object>(functionThisValue->ToObject());
- connection.function = qPersistentNew<v8::Function>(v8::Handle<v8::Function>::Cast(functionValue));
-
- slotIter->append(connection);
-
- return v8::Undefined();
-}
-
-v8::Handle<v8::Value> QV8QObjectWrapper::Disconnect(const v8::Arguments &args)
-{
- if (args.Length() == 0)
- V8THROW_ERROR("Function.prototype.disconnect: no arguments given");
-
- QV8Engine *engine = V8ENGINE();
-
- QPair<QObject *, int> signalInfo = ExtractQtSignal(engine, args.This());
- QObject *signalObject = signalInfo.first;
- int signalIndex = signalInfo.second;
-
- if (signalIndex == -1)
- V8THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
-
- if (!signalObject)
- V8THROW_ERROR("Function.prototype.disconnect: cannot disconnect from deleted QObject");
-
- if (signalIndex < 0 || signalObject->metaObject()->method(signalIndex).methodType() != QMetaMethod::Signal)
- V8THROW_ERROR("Function.prototype.disconnect: this object is not a signal");
-
- v8::Local<v8::Value> functionValue;
- v8::Local<v8::Value> functionThisValue;
-
- if (args.Length() == 1) {
- functionValue = args[0];
- } else {
- functionThisValue = args[0];
- functionValue = args[1];
- }
-
- if (!functionValue->IsFunction())
- V8THROW_ERROR("Function.prototype.disconnect: target is not a function");
-
- if (!functionThisValue.IsEmpty() && !functionThisValue->IsObject())
- V8THROW_ERROR("Function.prototype.disconnect: target this is not an object");
-
- QV8QObjectWrapper *qobjectWrapper = engine->qobjectWrapper();
- QHash<QObject *, QV8QObjectConnectionList *> &connectionsList = qobjectWrapper->m_connections;
- QHash<QObject *, QV8QObjectConnectionList *>::Iterator iter = connectionsList.find(signalObject);
- if (iter == connectionsList.end())
- return v8::Undefined(); // Nothing to disconnect from
-
- QV8QObjectConnectionList *connectionList = *iter;
- QV8QObjectConnectionList::SlotHash::Iterator slotIter = connectionList->slotHash.find(signalIndex);
- if (slotIter == connectionList->slotHash.end())
- return v8::Undefined(); // Nothing to disconnect from
-
- QV8QObjectConnectionList::ConnectionList &connections = *slotIter;
-
- v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(functionValue);
- QPair<QObject *, int> functionData = ExtractQtMethod(engine, function);
-
- if (functionData.second != -1) {
- // This is a QObject function wrapper
- for (int ii = 0; ii < connections.count(); ++ii) {
- QV8QObjectConnectionList::Connection &connection = connections[ii];
-
- if (connection.thisObject.IsEmpty() == functionThisValue.IsEmpty() &&
- (connection.thisObject.IsEmpty() || connection.thisObject->StrictEquals(functionThisValue))) {
-
- QPair<QObject *, int> connectedFunctionData = ExtractQtMethod(engine, connection.function);
- if (connectedFunctionData == functionData) {
- // Match!
- if (connections.connectionsInUse) {
- connection.needsDestroy = true;
- connections.connectionsNeedClean = true;
- } else {
- connection.dispose();
- connections.removeAt(ii);
- }
- return v8::Undefined();
- }
- }
- }
-
- } else {
- // This is a normal JS function
- for (int ii = 0; ii < connections.count(); ++ii) {
- QV8QObjectConnectionList::Connection &connection = connections[ii];
- if (connection.function->StrictEquals(function) &&
- connection.thisObject.IsEmpty() == functionThisValue.IsEmpty() &&
- (connection.thisObject.IsEmpty() || connection.thisObject->StrictEquals(functionThisValue))) {
- // Match!
- if (connections.connectionsInUse) {
- connection.needsDestroy = true;
- connections.connectionsNeedClean = true;
- } else {
- connection.dispose();
- connections.removeAt(ii);
- }
- return v8::Undefined();
- }
- }
- }
-
- return v8::Undefined();
-}
-
-/*!
- \fn v8::Handle<v8::Value> QV8QObjectWrapper::getProperty(QObject *object, const QHashedV8String &property, QV8QObjectWrapper::RevisionMode revisionMode)
-
- Get the \a property of \a object. Returns an empty handle if the property doesn't exist.
-
- Only searches for real properties of \a object (including methods), not attached properties etc.
-*/
-
-/*
- \fn bool QV8QObjectWrapper::setProperty(QObject *object, const QHashedV8String &property, v8::Handle<v8::Value> value, RevisionMode revisionMode)
-
- Set the \a property of \a object to \a value.
-
- Returns true if the property was "set" - even if this results in an exception being thrown -
- and false if the object has no such property.
-
- Only searches for real properties of \a object (including methods), not attached properties etc.
-*/
-
-namespace {
-struct CallArgs
-{
- CallArgs(int length, v8::Handle<v8::Object> *args) : _length(length), _args(args) {}
- int Length() const { return _length; }
- v8::Local<v8::Value> operator[](int idx) { return (*_args)->Get(idx); }
-
-private:
- int _length;
- v8::Handle<v8::Object> *_args;
-};
-}
-
-static v8::Handle<v8::Value> CallMethod(QObject *object, int index, int returnType, int argCount,
- int *argTypes, QV8Engine *engine, CallArgs &callArgs)
-{
- if (argCount > 0) {
-
- // Special handling is required for value types.
- // We need to save the current value in a temporary,
- // and reapply it after converting all arguments.
- // This avoids the "overwriting copy-value-type-value"
- // problem during Q_INVOKABLE function invocation.
- QQmlValueType *valueTypeObject = qobject_cast<QQmlValueType*>(object);
- QVariant valueTypeValue;
- if (valueTypeObject)
- valueTypeValue = valueTypeObject->value();
-
- // Convert all arguments.
- QVarLengthArray<CallArgument, 9> args(argCount + 1);
- args[0].initAsType(returnType);
- for (int ii = 0; ii < argCount; ++ii)
- args[ii + 1].fromValue(argTypes[ii], engine, callArgs[ii]);
- QVarLengthArray<void *, 9> argData(args.count());
- for (int ii = 0; ii < args.count(); ++ii)
- argData[ii] = args[ii].dataPtr();
-
- // Reinstate saved value type object value if required.
- if (valueTypeObject)
- valueTypeObject->setValue(valueTypeValue);
-
- QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, argData.data());
-
- return args[0].toValue(engine);
-
- } else if (returnType != QMetaType::Void) {
-
- CallArgument arg;
- arg.initAsType(returnType);
-
- void *args[] = { arg.dataPtr() };
-
- QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
-
- return arg.toValue(engine);
-
- } else {
-
- void *args[] = { 0 };
- QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, index, args);
- return v8::Undefined();
-
- }
-}
-
-/*!
- Returns the match score for converting \a actual to be of type \a conversionType. A
- zero score means "perfect match" whereas a higher score is worse.
-
- The conversion table is copied out of the \l QScript::callQtMethod()
- function.
-*/
-static int MatchScore(v8::Handle<v8::Value> actual, int conversionType)
-{
- if (actual->IsNumber()) {
- switch (conversionType) {
- case QMetaType::Double:
- return 0;
- case QMetaType::Float:
- return 1;
- case QMetaType::LongLong:
- case QMetaType::ULongLong:
- return 2;
- case QMetaType::Long:
- case QMetaType::ULong:
- return 3;
- case QMetaType::Int:
- case QMetaType::UInt:
- return 4;
- case QMetaType::Short:
- case QMetaType::UShort:
- return 5;
- break;
- case QMetaType::Char:
- case QMetaType::UChar:
- return 6;
- case QMetaType::QJsonValue:
- return 5;
- default:
- return 10;
- }
- } else if (actual->IsString()) {
- switch (conversionType) {
- case QMetaType::QString:
- return 0;
- case QMetaType::QJsonValue:
- return 5;
- default:
- return 10;
- }
- } else if (actual->IsBoolean()) {
- switch (conversionType) {
- case QMetaType::Bool:
- return 0;
- case QMetaType::QJsonValue:
- return 5;
- default:
- return 10;
- }
- } else if (actual->IsDate()) {
- switch (conversionType) {
- case QMetaType::QDateTime:
- return 0;
- case QMetaType::QDate:
- return 1;
- case QMetaType::QTime:
- return 2;
- default:
- return 10;
- }
- } else if (actual->IsRegExp()) {
- switch (conversionType) {
- case QMetaType::QRegExp:
- return 0;
- default:
- return 10;
- }
- } else if (actual->IsArray()) {
- switch (conversionType) {
- case QMetaType::QJsonArray:
- return 3;
- case QMetaType::QStringList:
- case QMetaType::QVariantList:
- return 5;
- case QMetaType::QVector4D:
- case QMetaType::QMatrix4x4:
- return 6;
- case QMetaType::QVector3D:
- return 7;
- default:
- return 10;
- }
- } else if (actual->IsNull()) {
- switch (conversionType) {
- case QMetaType::VoidStar:
- case QMetaType::QObjectStar:
- case QMetaType::QJsonValue:
- return 0;
- default: {
- const char *typeName = QMetaType::typeName(conversionType);
- if (typeName && typeName[strlen(typeName) - 1] == '*')
- return 0;
- else
- return 10;
- }
- }
- } else if (actual->IsObject()) {
- v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(actual);
-
- QV8ObjectResource *r = static_cast<QV8ObjectResource *>(obj->GetExternalResource());
- if (r && r->resourceType() == QV8ObjectResource::QObjectType) {
- switch (conversionType) {
- case QMetaType::QObjectStar:
- return 0;
- default:
- return 10;
- }
- } else if (r && r->resourceType() == QV8ObjectResource::VariantType) {
- if (conversionType == qMetaTypeId<QVariant>())
- return 0;
- else if (r->engine->toVariant(actual, -1).userType() == conversionType)
- return 0;
- else
- return 10;
- } else if (r && r->resourceType() == QV8ObjectResource::ValueTypeType) {
- if (r->engine->toVariant(actual, -1).userType() == conversionType)
- return 0;
- return 10;
- } else if (conversionType == QMetaType::QJsonObject) {
- return 5;
- } else {
- return 10;
- }
-
- } else {
- return 10;
- }
-}
-
-static inline int QMetaObject_methods(const QMetaObject *metaObject)
-{
- struct Private
- {
- int revision;
- int className;
- int classInfoCount, classInfoData;
- int methodCount, methodData;
- };
-
- return reinterpret_cast<const Private *>(metaObject->d.data)->methodCount;
-}
-
-/*!
-Returns the next related method, if one, or 0.
-*/
-static const QQmlPropertyData * RelatedMethod(QObject *object,
- const QQmlPropertyData *current,
- QQmlPropertyData &dummy)
-{
- QQmlPropertyCache *cache = QQmlData::get(object)->propertyCache;
- if (!current->isOverload())
- return 0;
-
- Q_ASSERT(!current->overrideIndexIsProperty);
-
- if (cache) {
- return cache->method(current->overrideIndex);
- } else {
- const QMetaObject *mo = object->metaObject();
- int methodOffset = mo->methodCount() - QMetaObject_methods(mo);
-
- while (methodOffset > current->overrideIndex) {
- mo = mo->superClass();
- methodOffset -= QMetaObject_methods(mo);
- }
-
- QMetaMethod method = mo->method(current->overrideIndex);
- dummy.load(method);
-
- // Look for overloaded methods
- QByteArray methodName = method.name();
- for (int ii = current->overrideIndex - 1; ii >= methodOffset; --ii) {
- if (methodName == mo->method(ii).name()) {
- dummy.setFlags(dummy.getFlags() | QQmlPropertyData::IsOverload);
- dummy.overrideIndexIsProperty = 0;
- dummy.overrideIndex = ii;
- return &dummy;
- }
- }
-
- return &dummy;
- }
-}
-
-static v8::Handle<v8::Value> CallPrecise(QObject *object, const QQmlPropertyData &data,
- QV8Engine *engine, CallArgs &callArgs)
-{
- QByteArray unknownTypeError;
-
- int returnType = QQmlPropertyCache::methodReturnType(object, data, &unknownTypeError);
-
- if (returnType == QMetaType::UnknownType) {
- QString typeName = QString::fromLatin1(unknownTypeError);
- QString error = QString::fromLatin1("Unknown method return type: %1").arg(typeName);
- v8::ThrowException(v8::Exception::Error(engine->toString(error)));
- return v8::Handle<v8::Value>();
- }
-
- if (data.hasArguments()) {
-
- int *args = 0;
- QVarLengthArray<int, 9> dummy;
-
- args = QQmlPropertyCache::methodParameterTypes(object, data.coreIndex, dummy,
- &unknownTypeError);
-
- if (!args) {
- QString typeName = QString::fromLatin1(unknownTypeError);
- QString error = QString::fromLatin1("Unknown method parameter type: %1").arg(typeName);
- v8::ThrowException(v8::Exception::Error(engine->toString(error)));
- return v8::Handle<v8::Value>();
- }
-
- if (args[0] > callArgs.Length()) {
- QString error = QLatin1String("Insufficient arguments");
- v8::ThrowException(v8::Exception::Error(engine->toString(error)));
- return v8::Handle<v8::Value>();
- }
-
- return CallMethod(object, data.coreIndex, returnType, args[0], args + 1, engine, callArgs);
-
- } else {
-
- return CallMethod(object, data.coreIndex, returnType, 0, 0, engine, callArgs);
-
- }
-}
-
-/*!
-Resolve the overloaded method to call. The algorithm works conceptually like this:
- 1. Resolve the set of overloads it is *possible* to call.
- Impossible overloads include those that have too many parameters or have parameters
- of unknown type.
- 2. Filter the set of overloads to only contain those with the closest number of
- parameters.
- For example, if we are called with 3 parameters and there are 2 overloads that
- take 2 parameters and one that takes 3, eliminate the 2 parameter overloads.
- 3. Find the best remaining overload based on its match score.
- If two or more overloads have the same match score, call the last one. The match
- score is constructed by adding the matchScore() result for each of the parameters.
-*/
-static v8::Handle<v8::Value> CallOverloaded(QObject *object, const QQmlPropertyData &data,
- QV8Engine *engine, CallArgs &callArgs)
-{
- int argumentCount = callArgs.Length();
-
- const QQmlPropertyData *best = 0;
- int bestParameterScore = INT_MAX;
- int bestMatchScore = INT_MAX;
-
- // Special handling is required for value types.
- // We need to save the current value in a temporary,
- // and reapply it after converting all arguments.
- // This avoids the "overwriting copy-value-type-value"
- // problem during Q_INVOKABLE function invocation.
- QQmlValueType *valueTypeObject = qobject_cast<QQmlValueType*>(object);
- QVariant valueTypeValue;
- if (valueTypeObject)
- valueTypeValue = valueTypeObject->value();
-
- QQmlPropertyData dummy;
- const QQmlPropertyData *attempt = &data;
-
- do {
- QVarLengthArray<int, 9> dummy;
- int methodArgumentCount = 0;
- int *methodArgTypes = 0;
- if (attempt->hasArguments()) {
- typedef QQmlPropertyCache PC;
- int *args = PC::methodParameterTypes(object, attempt->coreIndex, dummy, 0);
- if (!args) // Must be an unknown argument
- continue;
-
- methodArgumentCount = args[0];
- methodArgTypes = args + 1;
- }
-
- if (methodArgumentCount > argumentCount)
- continue; // We don't have sufficient arguments to call this method
-
- int methodParameterScore = argumentCount - methodArgumentCount;
- if (methodParameterScore > bestParameterScore)
- continue; // We already have a better option
-
- int methodMatchScore = 0;
- for (int ii = 0; ii < methodArgumentCount; ++ii)
- methodMatchScore += MatchScore(callArgs[ii], methodArgTypes[ii]);
-
- if (bestParameterScore > methodParameterScore || bestMatchScore > methodMatchScore) {
- best = attempt;
- bestParameterScore = methodParameterScore;
- bestMatchScore = methodMatchScore;
- }
-
- if (bestParameterScore == 0 && bestMatchScore == 0)
- break; // We can't get better than that
-
- } while((attempt = RelatedMethod(object, attempt, dummy)) != 0);
-
- if (best) {
- if (valueTypeObject)
- valueTypeObject->setValue(valueTypeValue);
- return CallPrecise(object, *best, engine, callArgs);
- } else {
- QString error = QLatin1String("Unable to determine callable overload. Candidates are:");
- const QQmlPropertyData *candidate = &data;
- while (candidate) {
- error += QLatin1String("\n ") +
- QString::fromUtf8(object->metaObject()->method(candidate->coreIndex).methodSignature().constData());
- candidate = RelatedMethod(object, candidate, dummy);
- }
-
- v8::ThrowException(v8::Exception::Error(engine->toString(error)));
- return v8::Handle<v8::Value>();
- }
-}
-
-static v8::Handle<v8::Value> ToString(QV8Engine *engine, QObject *object, int, v8::Handle<v8::Object>)
-{
- QString result;
- if (object) {
- QString objectName = object->objectName();
-
- result += QString::fromUtf8(object->metaObject()->className());
- result += QLatin1String("(0x");
- result += QString::number((quintptr)object,16);
-
- if (!objectName.isEmpty()) {
- result += QLatin1String(", \"");
- result += objectName;
- result += QLatin1Char('\"');
- }
-
- result += QLatin1Char(')');
- } else {
- result = QLatin1String("null");
- }
-
- return engine->toString(result);
-}
-
-static v8::Handle<v8::Value> Destroy(QV8Engine *, QObject *object, int argCount, v8::Handle<v8::Object> args)
-{
- QQmlData *ddata = QQmlData::get(object, false);
- if (!ddata || ddata->indestructible || ddata->rootObjectInCreation) {
- const char *error = "Invalid attempt to destroy() an indestructible object";
- v8::ThrowException(v8::Exception::Error(v8::String::New(error)));
- return v8::Undefined();
- }
-
- int delay = 0;
- if (argCount > 0)
- delay = args->Get(0)->Uint32Value();
-
- if (delay > 0)
- QTimer::singleShot(delay, object, SLOT(deleteLater()));
- else
- object->deleteLater();
-
- return v8::Undefined();
-}
-
-v8::Handle<v8::Value> QV8QObjectWrapper::Invoke(const v8::Arguments &args)
-{
- // object, index, qmlglobal, argCount, args
- Q_ASSERT(args.Length() == 5);
- Q_ASSERT(args[0]->IsObject());
-
- QV8QObjectResource *resource = v8_resource_cast<QV8QObjectResource>(args[0]->ToObject());
-
- if (!resource)
- return v8::Undefined();
-
- int argCount = args[3]->Int32Value();
- v8::Handle<v8::Object> arguments = v8::Handle<v8::Object>::Cast(args[4]);
-
- // Special hack to return info about this closure.
- if (argCount == 1 && arguments->Get(0)->StrictEquals(resource->engine->qobjectWrapper()->m_hiddenObject)) {
- v8::Local<v8::Array> data = v8::Array::New(2);
- data->Set(0, args[0]);
- data->Set(1, args[1]);
- return data;
- }
-
- QObject *object = resource->object;
- int index = args[1]->Int32Value();
-
- if (!object)
- return v8::Undefined();
-
- if (index < 0) {
- // Builtin functions
- if (index == QOBJECT_TOSTRING_INDEX) {
- return ToString(resource->engine, object, argCount, arguments);
- } else if (index == QOBJECT_DESTROY_INDEX) {
- return Destroy(resource->engine, object, argCount, arguments);
- } else {
- return v8::Undefined();
- }
- }
-
- QQmlPropertyData method;
-
- if (QQmlData *ddata = static_cast<QQmlData *>(QObjectPrivate::get(object)->declarativeData)) {
- if (ddata->propertyCache) {
- QQmlPropertyData *d = ddata->propertyCache->method(index);
- if (!d)
- return v8::Undefined();
- method = *d;
- }
- }
-
- if (method.coreIndex == -1) {
- method.load(object->metaObject()->method(index));
-
- if (method.coreIndex == -1)
- return v8::Undefined();
- }
-
- if (method.isV8Function()) {
- v8::Handle<v8::Value> rv;
- v8::Handle<v8::Object> qmlglobal = args[2]->ToObject();
-
- QQmlV8Function func(argCount, arguments, rv, qmlglobal,
- resource->engine->contextWrapper()->context(qmlglobal),
- resource->engine);
- QQmlV8Function *funcptr = &func;
-
- void *args[] = { 0, &funcptr };
- QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, method.coreIndex, args);
-
- if (rv.IsEmpty()) return v8::Undefined();
- return rv;
- }
-
- CallArgs callArgs(argCount, &arguments);
- if (!method.isOverload()) {
- return CallPrecise(object, method, resource->engine, callArgs);
- } else {
- return CallOverloaded(object, method, resource->engine, callArgs);
- }
-}
-
-CallArgument::CallArgument()
-: type(QVariant::Invalid)
-{
-}
-
-CallArgument::~CallArgument()
-{
- cleanup();
-}
-
-void CallArgument::cleanup()
-{
- if (type == QMetaType::QString) {
- qstringPtr->~QString();
- } else if (type == -1 || type == QMetaType::QVariant) {
- qvariantPtr->~QVariant();
- } else if (type == qMetaTypeId<QJSValue>()) {
- qjsValuePtr->~QJSValue();
- } else if (type == qMetaTypeId<QList<QObject *> >()) {
- qlistPtr->~QList<QObject *>();
- } else if (type == QMetaType::QJsonArray) {
- jsonArrayPtr->~QJsonArray();
- } else if (type == QMetaType::QJsonObject) {
- jsonObjectPtr->~QJsonObject();
- } else if (type == QMetaType::QJsonValue) {
- jsonValuePtr->~QJsonValue();
- }
-}
-
-void *CallArgument::dataPtr()
-{
- if (type == -1)
- return qvariantPtr->data();
- else
- return (void *)&allocData;
-}
-
-void CallArgument::initAsType(int callType)
-{
- if (type != 0) { cleanup(); type = 0; }
- if (callType == QMetaType::UnknownType) return;
-
- if (callType == qMetaTypeId<QJSValue>()) {
- qjsValuePtr = new (&allocData) QJSValue();
- type = callType;
- } else if (callType == QMetaType::Int ||
- callType == QMetaType::UInt ||
- callType == QMetaType::Bool ||
- callType == QMetaType::Double ||
- callType == QMetaType::Float) {
- type = callType;
- } else if (callType == QMetaType::QObjectStar) {
- qobjectPtr = 0;
- type = callType;
- } else if (callType == QMetaType::QString) {
- qstringPtr = new (&allocData) QString();
- type = callType;
- } else if (callType == QMetaType::QVariant) {
- type = callType;
- qvariantPtr = new (&allocData) QVariant();
- } else if (callType == qMetaTypeId<QList<QObject *> >()) {
- type = callType;
- qlistPtr = new (&allocData) QList<QObject *>();
- } else if (callType == qMetaTypeId<QQmlV8Handle>()) {
- type = callType;
- handlePtr = new (&allocData) QQmlV8Handle;
- } else if (callType == QMetaType::QJsonArray) {
- type = callType;
- jsonArrayPtr = new (&allocData) QJsonArray();
- } else if (callType == QMetaType::QJsonObject) {
- type = callType;
- jsonObjectPtr = new (&allocData) QJsonObject();
- } else if (callType == QMetaType::QJsonValue) {
- type = callType;
- jsonValuePtr = new (&allocData) QJsonValue();
- } else if (callType == QMetaType::Void) {
- type = -1;
- qvariantPtr = new (&allocData) QVariant();
- } else {
- type = -1;
- qvariantPtr = new (&allocData) QVariant(callType, (void *)0);
- }
-}
-
-void CallArgument::fromValue(int callType, QV8Engine *engine, v8::Handle<v8::Value> value)
-{
- if (type != 0) { cleanup(); type = 0; }
-
- if (callType == qMetaTypeId<QJSValue>()) {
- qjsValuePtr = new (&allocData) QJSValue(QJSValuePrivate::get(new QJSValuePrivate(engine, value)));
- type = qMetaTypeId<QJSValue>();
- } else if (callType == QMetaType::Int) {
- intValue = quint32(value->Int32Value());
- type = callType;
- } else if (callType == QMetaType::UInt) {
- intValue = quint32(value->Uint32Value());
- type = callType;
- } else if (callType == QMetaType::Bool) {
- boolValue = value->BooleanValue();
- type = callType;
- } else if (callType == QMetaType::Double) {
- doubleValue = double(value->NumberValue());
- type = callType;
- } else if (callType == QMetaType::Float) {
- floatValue = float(value->NumberValue());
- type = callType;
- } else if (callType == QMetaType::QString) {
- if (value->IsNull() || value->IsUndefined())
- qstringPtr = new (&allocData) QString();
- else
- qstringPtr = new (&allocData) QString(engine->toString(value->ToString()));
- type = callType;
- } else if (callType == QMetaType::QObjectStar) {
- qobjectPtr = engine->toQObject(value);
- type = callType;
- } else if (callType == qMetaTypeId<QVariant>()) {
- qvariantPtr = new (&allocData) QVariant(engine->toVariant(value, -1));
- type = callType;
- } else if (callType == qMetaTypeId<QList<QObject*> >()) {
- qlistPtr = new (&allocData) QList<QObject *>();
- if (value->IsArray()) {
- v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
- uint32_t length = array->Length();
- for (uint32_t ii = 0; ii < length; ++ii)
- qlistPtr->append(engine->toQObject(array->Get(ii)));
- } else {
- qlistPtr->append(engine->toQObject(value));
- }
- type = callType;
- } else if (callType == qMetaTypeId<QQmlV8Handle>()) {
- handlePtr = new (&allocData) QQmlV8Handle(QQmlV8Handle::fromHandle(value));
- type = callType;
- } else if (callType == QMetaType::QJsonArray) {
- jsonArrayPtr = new (&allocData) QJsonArray(engine->jsonArrayFromJS(value));
- type = callType;
- } else if (callType == QMetaType::QJsonObject) {
- jsonObjectPtr = new (&allocData) QJsonObject(engine->jsonObjectFromJS(value));
- type = callType;
- } else if (callType == QMetaType::QJsonValue) {
- jsonValuePtr = new (&allocData) QJsonValue(engine->jsonValueFromJS(value));
- type = callType;
- } else if (callType == QMetaType::Void) {
- *qvariantPtr = QVariant();
- } else {
- qvariantPtr = new (&allocData) QVariant();
- type = -1;
-
- QQmlEnginePrivate *ep = engine->engine() ? QQmlEnginePrivate::get(engine->engine()) : 0;
- QVariant v = engine->toVariant(value, -1); // why -1 instead of callType?
-
- if (v.userType() == callType) {
- *qvariantPtr = v;
- } else if (v.canConvert(callType)) {
- *qvariantPtr = v;
- qvariantPtr->convert(callType);
- } else if (engine->sequenceWrapper()->isSequenceType(callType) && v.userType() == qMetaTypeId<QVariantList>()) {
- // convert the JS array to a sequence of the correct type.
- QVariant seqV = engine->toVariant(value, callType);
- *qvariantPtr = seqV;
- } else {
- QQmlMetaObject mo = ep ? ep->rawMetaObjectForType(callType) : QQmlMetaObject();
- if (!mo.isNull()) {
- QObject *obj = ep->toQObject(v);
-
- if (obj != 0 && !QQmlMetaObject::canConvert(obj, mo))
- obj = 0;
-
- *qvariantPtr = QVariant(callType, &obj);
- } else {
- *qvariantPtr = QVariant(callType, (void *)0);
- }
- }
- }
-}
-
-v8::Handle<v8::Value> CallArgument::toValue(QV8Engine *engine)
-{
- if (type == qMetaTypeId<QJSValue>()) {
- return QJSValuePrivate::get(*qjsValuePtr)->asV8Value(engine);
- } else if (type == QMetaType::Int) {
- return v8::Integer::New(int(intValue));
- } else if (type == QMetaType::UInt) {
- return v8::Integer::NewFromUnsigned(intValue);
- } else if (type == QMetaType::Bool) {
- return v8::Boolean::New(boolValue);
- } else if (type == QMetaType::Double) {
- return v8::Number::New(doubleValue);
- } else if (type == QMetaType::Float) {
- return v8::Number::New(floatValue);
- } else if (type == QMetaType::QString) {
- return engine->toString(*qstringPtr);
- } else if (type == QMetaType::QObjectStar) {
- QObject *object = qobjectPtr;
- if (object)
- QQmlData::get(object, true)->setImplicitDestructible();
- return engine->newQObject(object);
- } else if (type == qMetaTypeId<QList<QObject *> >()) {
- // XXX Can this be made more by using Array as a prototype and implementing
- // directly against QList<QObject*>?
- QList<QObject *> &list = *qlistPtr;
- v8::Local<v8::Array> array = v8::Array::New(list.count());
- for (int ii = 0; ii < list.count(); ++ii)
- array->Set(ii, engine->newQObject(list.at(ii)));
- return array;
- } else if (type == qMetaTypeId<QQmlV8Handle>()) {
- return handlePtr->toHandle();
- } else if (type == QMetaType::QJsonArray) {
- return engine->jsonArrayToJS(*jsonArrayPtr);
- } else if (type == QMetaType::QJsonObject) {
- return engine->jsonObjectToJS(*jsonObjectPtr);
- } else if (type == QMetaType::QJsonValue) {
- return engine->jsonValueToJS(*jsonValuePtr);
- } else if (type == -1 || type == qMetaTypeId<QVariant>()) {
- QVariant value = *qvariantPtr;
- v8::Handle<v8::Value> rv = engine->fromVariant(value);
- if (QObject *object = engine->toQObject(rv))
- QQmlData::get(object, true)->setImplicitDestructible();
- return rv;
- } else {
- return v8::Undefined();
- }
-}
-
-QT_END_NAMESPACE
-
diff --git a/src/qml/qml/v8/qv8qobjectwrapper_p.h b/src/qml/qml/v8/qv8qobjectwrapper_p.h
deleted file mode 100644
index cbd6505846..0000000000
--- a/src/qml/qml/v8/qv8qobjectwrapper_p.h
+++ /dev/null
@@ -1,186 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV8QOBJECTWRAPPER_P_H
-#define QV8QOBJECTWRAPPER_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 <QtCore/qglobal.h>
-#include <QtCore/qmetatype.h>
-#include <QtCore/qpair.h>
-#include <QtCore/qhash.h>
-#include <private/qv8_p.h>
-#include <private/qhashedstring_p.h>
-#include <private/qqmldata_p.h>
-#include <private/qqmlpropertycache_p.h>
-#include <private/qintrusivelist_p.h>
-#include "qv8objectresource_p.h"
-
-QT_BEGIN_NAMESPACE
-
-class QObject;
-class QV8Engine;
-class QQmlData;
-class QV8ObjectResource;
-class QV8QObjectInstance;
-class QV8QObjectConnectionList;
-class QQmlPropertyCache;
-
-class QV8QObjectResource : public QV8ObjectResource
-{
- V8_RESOURCE_TYPE(QObjectType)
-
-public:
- QV8QObjectResource(QV8Engine *engine, QObject *object);
-
- QQmlGuard<QObject> object;
- QIntrusiveListNode weakResource;
-};
-
-class Q_QML_PRIVATE_EXPORT QV8QObjectWrapper
-{
-public:
- QV8QObjectWrapper();
- ~QV8QObjectWrapper();
-
- void init(QV8Engine *);
- void destroy();
-
- v8::Handle<v8::Value> newQObject(QObject *object);
- bool isQObject(v8::Handle<v8::Object>);
- QObject *toQObject(v8::Handle<v8::Object>);
- static QObject *toQObject(QV8ObjectResource *);
-
- enum RevisionMode { IgnoreRevision, CheckRevision };
- inline v8::Handle<v8::Value> getProperty(QObject *, const QHashedV8String &, QQmlContextData *, RevisionMode);
- inline bool setProperty(QObject *, const QHashedV8String &, QQmlContextData *, v8::Handle<v8::Value>, RevisionMode);
-
- void registerWeakQObjectReference(QV8QObjectResource *resource)
- {
- m_javaScriptOwnedWeakQObjects.insert(resource);
- }
-
- void unregisterWeakQObjectReference(QV8QObjectResource *resource)
- {
- m_javaScriptOwnedWeakQObjects.remove(resource);
- }
-
-private:
- friend class QQmlPropertyCache;
- friend class QV8QObjectConnectionList;
- friend class QV8QObjectInstance;
-
- v8::Local<v8::Object> newQObject(QObject *, QQmlData *, QV8Engine *);
- bool deleteWeakQObject(QV8QObjectResource *resource, bool calledFromEngineDtor = false);
- static v8::Handle<v8::Value> GetProperty(QV8Engine *, QObject *, v8::Handle<v8::Value> *,
- const QHashedV8String &, QQmlContextData *, QV8QObjectWrapper::RevisionMode);
- static bool SetProperty(QV8Engine *, QObject *, const QHashedV8String &, QQmlContextData *,
- v8::Handle<v8::Value>, QV8QObjectWrapper::RevisionMode);
- static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
- v8::Local<v8::Value> value,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Integer> Query(v8::Local<v8::String> property,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> Connect(const v8::Arguments &args);
- static v8::Handle<v8::Value> Disconnect(const v8::Arguments &args);
- static v8::Handle<v8::Value> Invoke(const v8::Arguments &args);
- static QPair<QObject *, int> ExtractQtMethod(QV8Engine *, v8::Handle<v8::Function>);
- static QPair<QObject *, int> ExtractQtSignal(QV8Engine *, v8::Handle<v8::Object>);
- static void WeakQObjectReferenceCallback(v8::Persistent<v8::Value> handle, void *wrapper);
-
- QV8Engine *m_engine;
- quint32 m_id;
- v8::Persistent<v8::Function> m_constructor;
- v8::Persistent<v8::Function> m_methodConstructor;
- v8::Persistent<v8::Function> m_signalHandlerConstructor;
- v8::Persistent<v8::String> m_toStringSymbol;
- v8::Persistent<v8::String> m_destroySymbol;
- QHashedV8String m_toStringString;
- QHashedV8String m_destroyString;
- v8::Persistent<v8::Object> m_hiddenObject;
- QHash<QObject *, QV8QObjectConnectionList *> m_connections;
- typedef QHash<QObject *, QV8QObjectInstance *> TaintedHash;
- TaintedHash m_taintedObjects;
- QIntrusiveList<QV8QObjectResource, &QV8QObjectResource::weakResource> m_javaScriptOwnedWeakQObjects;
-};
-
-v8::Handle<v8::Value> QV8QObjectWrapper::getProperty(QObject *object, const QHashedV8String &string,
- QQmlContextData *context, RevisionMode mode)
-{
- QQmlData *dd = QQmlData::get(object, false);
- if (!dd || !dd->propertyCache || m_toStringString == string || m_destroyString == string ||
- dd->propertyCache->property(string, object, context)) {
- return GetProperty(m_engine, object, 0, string, context, mode);
- } else {
- return v8::Handle<v8::Value>();
- }
-}
-
-bool QV8QObjectWrapper::setProperty(QObject *object, const QHashedV8String &string,
- QQmlContextData *context, v8::Handle<v8::Value> value, RevisionMode mode)
-{
- QQmlData *dd = QQmlData::get(object, false);
- if (!dd || !dd->propertyCache || m_toStringString == string || m_destroyString == string ||
- dd->propertyCache->property(string, object, context)) {
- return SetProperty(m_engine, object, string, context, value, mode);
- } else {
- return false;
- }
-}
-
-QT_END_NAMESPACE
-
-#endif // QV8QOBJECTWRAPPER_P_H
-
-
diff --git a/src/qml/qml/v8/qv8sequencewrapper.cpp b/src/qml/qml/v8/qv8sequencewrapper.cpp
deleted file mode 100644
index b1e0c41771..0000000000
--- a/src/qml/qml/v8/qv8sequencewrapper.cpp
+++ /dev/null
@@ -1,323 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <QtQml/qqml.h>
-
-#include "qv8sequencewrapper_p.h"
-#include "qv8sequencewrapper_p_p.h"
-#include "qv8engine_p.h"
-
-QT_BEGIN_NAMESPACE
-
-QV8SequenceWrapper::QV8SequenceWrapper()
- : m_engine(0)
-{
-}
-
-QV8SequenceWrapper::~QV8SequenceWrapper()
-{
-}
-
-#define REGISTER_QML_SEQUENCE_METATYPE(unused, unused2, SequenceType, unused3) qRegisterMetaType<SequenceType>();
-void QV8SequenceWrapper::init(QV8Engine *engine)
-{
- FOREACH_QML_SEQUENCE_TYPE(REGISTER_QML_SEQUENCE_METATYPE)
-
- m_engine = engine;
- m_toString = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ToString)->GetFunction());
- m_valueOf = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ValueOf)->GetFunction());
-
- QString defaultSortString = QLatin1String(
- "(function compare(x,y) {"
- " if (x === y) return 0;"
- " x = x.toString();"
- " y = y.toString();"
- " if (x == y) return 0;"
- " else return x < y ? -1 : 1;"
- "})");
-
- m_sort = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(Sort)->GetFunction());
- m_arrayPrototype = qPersistentNew<v8::Value>(v8::Array::New(1)->GetPrototype());
- v8::Local<v8::Script> defaultSortCompareScript = v8::Script::Compile(engine->toString(defaultSortString));
- m_defaultSortComparer = qPersistentNew<v8::Function>(v8::Handle<v8::Function>(v8::Function::Cast(*defaultSortCompareScript->Run())));
-
- v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
- ft->InstanceTemplate()->SetIndexedPropertyHandler(IndexedGetter, IndexedSetter, 0, IndexedDeleter, IndexedEnumerator);
- ft->InstanceTemplate()->SetAccessor(v8::String::New("length"), LengthGetter, LengthSetter,
- v8::Handle<v8::Value>(), v8::DEFAULT,
- v8::PropertyAttribute(v8::DontDelete | v8::DontEnum));
- ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0,
- m_toString, v8::DEFAULT,
- v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete | v8::DontEnum));
- ft->InstanceTemplate()->SetAccessor(v8::String::New("valueOf"), ValueOfGetter, 0,
- m_valueOf, v8::DEFAULT,
- v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete | v8::DontEnum));
- ft->InstanceTemplate()->SetAccessor(v8::String::New("sort"), SortGetter, 0,
- m_sort, v8::DEFAULT,
- v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete | v8::DontEnum));
- ft->InstanceTemplate()->SetHasExternalResource(true);
- ft->InstanceTemplate()->MarkAsUseUserObjectComparison();
- m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
-}
-#undef REGISTER_QML_SEQUENCE_METATYPE
-
-void QV8SequenceWrapper::destroy()
-{
- qPersistentDispose(m_defaultSortComparer);
- qPersistentDispose(m_sort);
- qPersistentDispose(m_arrayPrototype);
- qPersistentDispose(m_toString);
- qPersistentDispose(m_valueOf);
- qPersistentDispose(m_constructor);
-}
-
-#define IS_SEQUENCE(unused1, unused2, SequenceType, unused3) \
- if (sequenceTypeId == qMetaTypeId<SequenceType>()) { \
- return true; \
- } else
-
-bool QV8SequenceWrapper::isSequenceType(int sequenceTypeId) const
-{
- FOREACH_QML_SEQUENCE_TYPE(IS_SEQUENCE) { /* else */ return false; }
-}
-#undef IS_SEQUENCE
-
-bool QV8SequenceWrapper::isEqual(QV8ObjectResource *lhs, QV8ObjectResource *rhs)
-{
- Q_ASSERT(lhs && rhs && lhs->resourceType() == QV8ObjectResource::SequenceType && rhs->resourceType() == QV8ObjectResource::SequenceType);
- QV8SequenceResource *lr = static_cast<QV8SequenceResource *>(lhs);
- QV8SequenceResource *rr = static_cast<QV8SequenceResource *>(rhs);
- return lr->isEqual(rr);
-}
-
-quint32 QV8SequenceWrapper::sequenceLength(QV8ObjectResource *r)
-{
- Q_ASSERT(r->resourceType() == QV8ObjectResource::SequenceType);
- QV8SequenceResource *sr = static_cast<QV8SequenceResource *>(r);
- Q_ASSERT(sr);
- return sr->lengthGetter();
-}
-
-#define NEW_REFERENCE_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \
- if (sequenceType == qMetaTypeId<SequenceType>()) { \
- r = new QV8##ElementTypeName##SequenceResource(m_engine, object, propertyIndex); \
- } else
-
-v8::Local<v8::Object> QV8SequenceWrapper::newSequence(int sequenceType, QObject *object, int propertyIndex, bool *succeeded)
-{
- // This function is called when the property is a QObject Q_PROPERTY of
- // the given sequence type. Internally we store a typed-sequence
- // (as well as object ptr + property index for updated-read and write-back)
- // and so access/mutate avoids variant conversion.
- *succeeded = true;
- QV8SequenceResource *r = 0;
- FOREACH_QML_SEQUENCE_TYPE(NEW_REFERENCE_SEQUENCE) { /* else */ *succeeded = false; return v8::Local<v8::Object>(); }
-
- v8::Local<v8::Object> rv = m_constructor->NewInstance();
- rv->SetExternalResource(r);
- rv->SetPrototype(m_arrayPrototype);
- return rv;
-}
-#undef NEW_REFERENCE_SEQUENCE
-
-#define NEW_COPY_SEQUENCE(ElementType, ElementTypeName, SequenceType, unused) \
- if (sequenceType == qMetaTypeId<SequenceType>()) { \
- r = new QV8##ElementTypeName##SequenceResource(m_engine, v.value<SequenceType>()); \
- } else
-
-v8::Local<v8::Object> QV8SequenceWrapper::fromVariant(const QVariant& v, bool *succeeded)
-{
- // This function is called when assigning a sequence value to a normal JS var
- // in a JS block. Internally, we store a sequence of the specified type.
- // Access and mutation is extremely fast since it will not need to modify any
- // QObject property.
- int sequenceType = v.userType();
- *succeeded = true;
- QV8SequenceResource *r = 0;
- FOREACH_QML_SEQUENCE_TYPE(NEW_COPY_SEQUENCE) { /* else */ *succeeded = false; return v8::Local<v8::Object>(); }
-
- v8::Local<v8::Object> rv = m_constructor->NewInstance();
- rv->SetExternalResource(r);
- rv->SetPrototype(m_arrayPrototype);
- return rv;
-}
-#undef NEW_COPY_SEQUENCE
-
-QVariant QV8SequenceWrapper::toVariant(QV8ObjectResource *r)
-{
- Q_ASSERT(r->resourceType() == QV8ObjectResource::SequenceType);
- QV8SequenceResource *resource = static_cast<QV8SequenceResource *>(r);
- return resource->toVariant();
-}
-
-#define SEQUENCE_TO_VARIANT(ElementType, ElementTypeName, SequenceType, unused) \
- if (typeHint == qMetaTypeId<SequenceType>()) { \
- return QV8##ElementTypeName##SequenceResource::toVariant(m_engine, array, length, succeeded); \
- } else
-
-QVariant QV8SequenceWrapper::toVariant(v8::Handle<v8::Array> array, int typeHint, bool *succeeded)
-{
- *succeeded = true;
- uint32_t length = array->Length();
- FOREACH_QML_SEQUENCE_TYPE(SEQUENCE_TO_VARIANT) { /* else */ *succeeded = false; return QVariant(); }
-}
-#undef SEQUENCE_TO_VARIANT
-
-v8::Handle<v8::Value> QV8SequenceWrapper::IndexedSetter(quint32 index, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
-{
- QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
- Q_ASSERT(sr);
- return sr->indexedSetter(index, value);
-}
-
-v8::Handle<v8::Value> QV8SequenceWrapper::IndexedGetter(quint32 index, const v8::AccessorInfo &info)
-{
- QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
- Q_ASSERT(sr);
- return sr->indexedGetter(index);
-}
-
-v8::Handle<v8::Boolean> QV8SequenceWrapper::IndexedDeleter(quint32 index, const v8::AccessorInfo &info)
-{
- QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
- Q_ASSERT(sr);
- return sr->indexedDeleter(index);
-}
-
-v8::Handle<v8::Array> QV8SequenceWrapper::IndexedEnumerator(const v8::AccessorInfo &info)
-{
- QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
- Q_ASSERT(sr);
- return sr->indexedEnumerator();
-}
-
-v8::Handle<v8::Value> QV8SequenceWrapper::LengthGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
- QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
- Q_ASSERT(sr);
- return v8::Integer::NewFromUnsigned(sr->lengthGetter());
-}
-
-void QV8SequenceWrapper::LengthSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
- QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(info.This());
- Q_ASSERT(sr);
- sr->lengthSetter(value);
-}
-
-v8::Handle<v8::Value> QV8SequenceWrapper::ToStringGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
- return info.Data();
-}
-
-v8::Handle<v8::Value> QV8SequenceWrapper::ValueOfGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
- return info.Data();
-}
-
-v8::Handle<v8::Value> QV8SequenceWrapper::SortGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
- return info.Data();
-}
-
-v8::Handle<v8::Value> QV8SequenceWrapper::Sort(const v8::Arguments &args)
-{
- int argCount = args.Length();
-
- if (argCount < 2) {
- QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(args.This());
- Q_ASSERT(sr);
-
- qint32 length = sr->lengthGetter();
- if (length > 1) {
- v8::Handle<v8::Function> jsCompareFn = sr->engine->sequenceWrapper()->m_defaultSortComparer;
- if (argCount == 1 && args[0]->IsFunction())
- jsCompareFn = v8::Handle<v8::Function>(v8::Function::Cast(*args[0]));
-
- sr->sort(jsCompareFn);
- }
- }
-
- return args.This();
-}
-
-v8::Handle<v8::Value> QV8SequenceWrapper::ToString(const v8::Arguments &args)
-{
- QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(args.This());
- Q_ASSERT(sr);
- return sr->toString();
-}
-
-v8::Handle<v8::Value> QV8SequenceWrapper::ValueOf(const v8::Arguments &args)
-{
- QV8SequenceResource *sr = v8_resource_cast<QV8SequenceResource>(args.This());
- Q_ASSERT(sr);
- v8::Handle<v8::Value> tostringValue = sr->toString();
- if (!tostringValue.IsEmpty())
- return tostringValue;
- return v8::Integer::NewFromUnsigned(sr->lengthGetter());
-}
-
-v8::Handle<v8::Value> QV8SequenceWrapper::Getter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
- Q_UNUSED(info);
- return v8::Handle<v8::Value>();
-}
-
-v8::Handle<v8::Value> QV8SequenceWrapper::Setter(v8::Local<v8::String> property,
- v8::Local<v8::Value> value,
- const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
- Q_UNUSED(info);
- return value;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8sequencewrapper_p.h b/src/qml/qml/v8/qv8sequencewrapper_p.h
deleted file mode 100644
index c403abc6b6..0000000000
--- a/src/qml/qml/v8/qv8sequencewrapper_p.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV8SEQUENCEWRAPPER_P_H
-#define QV8SEQUENCEWRAPPER_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 <QtCore/qglobal.h>
-#include <QtCore/qvariant.h>
-#include <private/qv8_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QV8Engine;
-class QV8ObjectResource;
-
-class QV8SequenceWrapper
-{
-public:
- QV8SequenceWrapper();
- ~QV8SequenceWrapper();
-
- void init(QV8Engine *);
- void destroy();
-
- bool isSequenceType(int sequenceTypeId) const;
-
- bool isEqual(QV8ObjectResource *lhs, const QVariant &rhs);
- bool isEqual(QV8ObjectResource *lhs, QV8ObjectResource *rhs);
- quint32 sequenceLength(QV8ObjectResource *);
-
- v8::Local<v8::Object> newSequence(int sequenceTypeId, QObject *object, int propertyIndex, bool *succeeded);
- v8::Local<v8::Object> fromVariant(const QVariant& v, bool *succeeded);
- QVariant toVariant(QV8ObjectResource *);
- QVariant toVariant(v8::Handle<v8::Array> array, int typeHint, bool *succeeded);
-
-private:
- QV8Engine *m_engine;
-
- v8::Persistent<v8::Function> m_constructor;
- v8::Persistent<v8::Function> m_toString;
- v8::Persistent<v8::Function> m_valueOf;
- v8::Persistent<v8::Function> m_sort;
- v8::Persistent<v8::Value> m_arrayPrototype;
- v8::Persistent<v8::Function> m_defaultSortComparer;
-
- static v8::Handle<v8::Value> IndexedGetter(quint32 index, const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> IndexedSetter(quint32 index, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
- static v8::Handle<v8::Boolean> IndexedDeleter(quint32 index, const v8::AccessorInfo &info);
- static v8::Handle<v8::Array> IndexedEnumerator(const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> LengthGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info);
- static void LengthSetter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> ToStringGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> ToString(const v8::Arguments &args);
- static v8::Handle<v8::Value> ValueOfGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> SortGetter(v8::Local<v8::String> property, const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> ValueOf(const v8::Arguments &args);
- static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property, const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property, v8::Local<v8::Value> value, const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> Sort(const v8::Arguments &args);
-};
-
-
-QT_END_NAMESPACE
-
-#endif // QV8SEQUENCEWRAPPER_P_H
diff --git a/src/qml/qml/v8/qv8sequencewrapper_p_p.h b/src/qml/qml/v8/qv8sequencewrapper_p_p.h
deleted file mode 100644
index ff9df7d4a0..0000000000
--- a/src/qml/qml/v8/qv8sequencewrapper_p_p.h
+++ /dev/null
@@ -1,512 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV8SEQUENCEWRAPPER_P_P_H
-#define QV8SEQUENCEWRAPPER_P_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/qqmlengine_p.h>
-#include <private/qqmlmetatype_p.h>
-
-QT_BEGIN_NAMESPACE
-
-/*!
- \internal
- \class QV8SequenceResource
- \brief The abstract base class of the external resource used in sequence type objects
-
- Every sequence type object returned by QV8SequenceWrapper::fromVariant() or
- QV8SequenceWrapper::newSequence() has a type-specific QV8SequenceResource which
- contains the type name, the meta type ids of the sequence and sequence element
- types, as well as either the sequence data (copy) or object pointer and property
- index (reference) data associated with the sequence.
- */
-class QV8SequenceResource : public QV8ObjectResource
-{
- V8_RESOURCE_TYPE(SequenceType)
-
-public:
- virtual ~QV8SequenceResource() {}
-
- enum ObjectType { Reference, Copy };
-
- virtual QVariant toVariant() = 0;
- virtual bool isEqual(const QV8SequenceResource *v) = 0;
-
- virtual quint32 lengthGetter() = 0;
- virtual void lengthSetter(v8::Handle<v8::Value> value) = 0;
- virtual v8::Handle<v8::Value> indexedSetter(quint32 index, v8::Handle<v8::Value> value) = 0;
- virtual v8::Handle<v8::Value> indexedGetter(quint32 index) = 0;
- virtual v8::Handle<v8::Boolean> indexedDeleter(quint32 index) = 0;
- virtual v8::Handle<v8::Array> indexedEnumerator() = 0;
- virtual v8::Handle<v8::Value> toString() = 0;
- virtual void sort(v8::Handle<v8::Function> comparer) = 0;
-
- ObjectType objectType;
- QByteArray typeName;
- int sequenceMetaTypeId;
- int elementMetaTypeId;
-
-protected:
- QV8SequenceResource(QV8Engine *engine, ObjectType type, const QByteArray &name, int sequenceId, int elementId)
- : QV8ObjectResource(engine), objectType(type), typeName(name), sequenceMetaTypeId(sequenceId), elementMetaTypeId(elementId)
- {
- }
-};
-
-// helper function to generate valid warnings if errors occur during sequence operations.
-static void generateWarning(QV8Engine *engine, const QString& description)
-{
- if (!engine)
- return;
- v8::Local<v8::StackTrace> currStack = v8::StackTrace::CurrentStackTrace(1);
- if (currStack.IsEmpty())
- return;
- v8::Local<v8::StackFrame> currFrame = currStack->GetFrame(0);
- if (currFrame.IsEmpty())
- return;
-
- QQmlError retn;
- retn.setDescription(description);
- retn.setLine(currFrame->GetLineNumber());
- retn.setUrl(QUrl(engine->toString(currFrame->GetScriptName())));
- QQmlEnginePrivate::warning(engine->engine(), retn);
-}
-
-
-static int convertV8ValueToInt(QV8Engine *, v8::Handle<v8::Value> v)
-{
- return v->Int32Value();
-}
-
-static v8::Handle<v8::Value> convertIntToV8Value(QV8Engine *, int v)
-{
- return v8::Integer::New(v);
-}
-
-static QString convertIntToString(QV8Engine *, int v)
-{
- return QString::number(v);
-}
-
-static qreal convertV8ValueToReal(QV8Engine *, v8::Handle<v8::Value> v)
-{
- return v->NumberValue();
-}
-
-static v8::Handle<v8::Value> convertRealToV8Value(QV8Engine *, qreal v)
-{
- return v8::Number::New(v);
-}
-
-static QString convertRealToString(QV8Engine *, qreal v)
-{
- return QString::number(v);
-}
-
-static bool convertV8ValueToBool(QV8Engine *, v8::Handle<v8::Value> v)
-{
- return v->BooleanValue();
-}
-
-static v8::Handle<v8::Value> convertBoolToV8Value(QV8Engine *, bool v)
-{
- return v8::Boolean::New(v);
-}
-
-static QString convertBoolToString(QV8Engine *, bool v)
-{
- if (v)
- return QLatin1String("true");
- return QLatin1String("false");
-}
-
-static QString convertV8ValueToString(QV8Engine *e, v8::Handle<v8::Value> v)
-{
- return e->toString(v->ToString());
-}
-
-static v8::Handle<v8::Value> convertStringToV8Value(QV8Engine *e, const QString &v)
-{
- return e->toString(v);
-}
-
-static QString convertStringToString(QV8Engine *, const QString &v)
-{
- return v;
-}
-
-static QString convertV8ValueToQString(QV8Engine *e, v8::Handle<v8::Value> v)
-{
- return e->toString(v->ToString());
-}
-
-static v8::Handle<v8::Value> convertQStringToV8Value(QV8Engine *e, const QString &v)
-{
- return e->toString(v);
-}
-
-static QString convertQStringToString(QV8Engine *, const QString &v)
-{
- return v;
-}
-
-static QUrl convertV8ValueToUrl(QV8Engine *e, v8::Handle<v8::Value> v)
-{
- return QUrl(e->toString(v->ToString()));
-}
-
-static v8::Handle<v8::Value> convertUrlToV8Value(QV8Engine *e, const QUrl &v)
-{
- return e->toString(QLatin1String(v.toEncoded().data()));
-}
-
-static QString convertUrlToString(QV8Engine *, const QUrl &v)
-{
- return v.toString();
-}
-
-
-/*
- \internal
- \class QV8<Type>SequenceResource
- \brief The external resource used in sequence type objects
-
- Every sequence type object returned by QV8SequenceWrapper::newSequence() has
- a QV8<Type>SequenceResource which contains a property index and a pointer
- to the object which contains the property.
-
- Every sequence type object returned by QV8SequenceWrapper::fromVariant() has
- a QV8<Type>SequenceResource which contains a copy of the sequence value.
- Operations on the sequence are implemented directly in terms of that sequence data.
-
- There exists one QV8<Type>SequenceResource instance for every JavaScript Object
- (sequence) instance returned from QV8SequenceWrapper::newSequence() or
- QV8SequenceWrapper::fromVariant().
- */
-
-// F(elementType, elementTypeName, sequenceType, defaultValue)
-#define FOREACH_QML_SEQUENCE_TYPE(F) \
- F(int, Int, QList<int>, 0) \
- F(qreal, Real, QList<qreal>, 0.0) \
- F(bool, Bool, QList<bool>, false) \
- F(QString, String, QList<QString>, QString()) \
- F(QString, QString, QStringList, QString()) \
- F(QUrl, Url, QList<QUrl>, QUrl())
-
-#define QML_SEQUENCE_TYPE_RESOURCE(SequenceElementType, SequenceElementTypeName, SequenceType, DefaultValue, ConversionToV8fn, ConversionFromV8fn, ToStringfn) \
- QT_END_NAMESPACE \
- Q_DECLARE_METATYPE(SequenceType) \
- QT_BEGIN_NAMESPACE \
- class QV8##SequenceElementTypeName##SequenceResource : public QV8SequenceResource { \
- public:\
- QV8##SequenceElementTypeName##SequenceResource(QV8Engine *engine, QObject *obj, int propIdx) \
- : QV8SequenceResource(engine, QV8SequenceResource::Reference, #SequenceType, qMetaTypeId<SequenceType>(), qMetaTypeId<SequenceElementType>()) \
- , object(obj), propertyIndex(propIdx) \
- { \
- } \
- QV8##SequenceElementTypeName##SequenceResource(QV8Engine *engine, const SequenceType &value) \
- : QV8SequenceResource(engine, QV8SequenceResource::Copy, #SequenceType, qMetaTypeId<SequenceType>(), qMetaTypeId<SequenceElementType>()) \
- , object(0), propertyIndex(-1), c(value) \
- { \
- } \
- ~QV8##SequenceElementTypeName##SequenceResource() \
- { \
- } \
- static QVariant toVariant(QV8Engine *e, v8::Handle<v8::Array> array, uint32_t length, bool *succeeded) \
- { \
- SequenceType list; \
- list.reserve(length); \
- for (uint32_t ii = 0; ii < length; ++ii) { \
- list.append(ConversionFromV8fn(e, array->Get(ii))); \
- } \
- *succeeded = true; \
- return QVariant::fromValue<SequenceType>(list); \
- } \
- QVariant toVariant() \
- { \
- if (objectType == QV8SequenceResource::Reference) { \
- if (!object) \
- return QVariant(); \
- loadReference(); \
- } \
- return QVariant::fromValue<SequenceType>(c); \
- } \
- bool isEqual(const QV8SequenceResource *v) \
- { \
- /* Note: two different sequences can never be equal (even if they */ \
- /* contain the same elements in the same order) in order to */ \
- /* maintain JavaScript semantics. However, if they both reference */ \
- /* the same QObject+propertyIndex, they are equal. */ \
- if (objectType == QV8SequenceResource::Reference && v->objectType == QV8SequenceResource::Reference) { \
- if (sequenceMetaTypeId == v->sequenceMetaTypeId) { \
- const QV8##SequenceElementTypeName##SequenceResource *rhs = static_cast<const QV8##SequenceElementTypeName##SequenceResource *>(v); \
- return (object != 0 && object == rhs->object && propertyIndex == rhs->propertyIndex); \
- } \
- } else if (objectType == QV8SequenceResource::Copy && v->objectType == QV8SequenceResource::Copy) { \
- if (sequenceMetaTypeId == v->sequenceMetaTypeId) { \
- const QV8##SequenceElementTypeName##SequenceResource *rhs = static_cast<const QV8##SequenceElementTypeName##SequenceResource *>(v); \
- return (this == rhs); \
- } \
- } \
- return false; \
- } \
- quint32 lengthGetter() \
- { \
- if (objectType == QV8SequenceResource::Reference) { \
- if (!object) \
- return 0; \
- loadReference(); \
- } \
- return static_cast<quint32>(c.count()); \
- } \
- void lengthSetter(v8::Handle<v8::Value> value) \
- { \
- /* Get the new required length */ \
- if (value.IsEmpty() || !value->IsUint32()) \
- return; \
- quint32 newLength = value->Uint32Value(); \
- /* Qt containers have int (rather than uint) allowable indexes. */ \
- if (newLength > INT_MAX) { \
- generateWarning(engine, QLatin1String("Index out of range during length set")); \
- return; \
- } \
- /* Read the sequence from the QObject property if we're a reference */ \
- if (objectType == QV8SequenceResource::Reference) { \
- if (!object) \
- return; \
- loadReference(); \
- } \
- /* Determine whether we need to modify the sequence */ \
- qint32 newCount = static_cast<qint32>(newLength); \
- qint32 count = c.count(); \
- if (newCount == count) { \
- return; \
- } else if (newCount > count) { \
- /* according to ECMA262r3 we need to insert */ \
- /* undefined values increasing length to newLength. */ \
- /* We cannot, so we insert default-values instead. */ \
- c.reserve(newCount); \
- while (newCount > count++) { \
- c.append(DefaultValue); \
- } \
- } else { \
- /* according to ECMA262r3 we need to remove */ \
- /* elements until the sequence is the required length. */ \
- while (newCount < count) { \
- count--; \
- c.removeAt(count); \
- } \
- } \
- /* write back if required. */ \
- if (objectType == QV8SequenceResource::Reference) { \
- /* write back. already checked that object is non-null, so skip that check here. */ \
- storeReference(); \
- } \
- return; \
- } \
- v8::Handle<v8::Value> indexedSetter(quint32 index, v8::Handle<v8::Value> value) \
- { \
- /* Qt containers have int (rather than uint) allowable indexes. */ \
- if (index > INT_MAX) { \
- generateWarning(engine, QLatin1String("Index out of range during indexed set")); \
- return v8::Undefined(); \
- } \
- if (objectType == QV8SequenceResource::Reference) { \
- if (!object) \
- return v8::Undefined(); \
- loadReference(); \
- } \
- /* modify the sequence */ \
- SequenceElementType elementValue = ConversionFromV8fn(engine, value); \
- qint32 count = c.count(); \
- qint32 signedIdx = static_cast<qint32>(index); \
- if (signedIdx == count) { \
- c.append(elementValue); \
- } else if (signedIdx < count) { \
- c[index] = elementValue; \
- } else { \
- /* according to ECMA262r3 we need to insert */ \
- /* the value at the given index, increasing length to index+1. */ \
- c.reserve(signedIdx + 1); \
- while (signedIdx > count++) { \
- c.append(DefaultValue); \
- } \
- c.append(elementValue); \
- } \
- /* write back. already checked that object is non-null, so skip that check here. */ \
- if (objectType == QV8SequenceResource::Reference) \
- storeReference(); \
- return value; \
- } \
- v8::Handle<v8::Value> indexedGetter(quint32 index) \
- { \
- /* Qt containers have int (rather than uint) allowable indexes. */ \
- if (index > INT_MAX) { \
- generateWarning(engine, QLatin1String("Index out of range during indexed get")); \
- return v8::Undefined(); \
- } \
- if (objectType == QV8SequenceResource::Reference) { \
- if (!object) \
- return v8::Undefined(); \
- loadReference(); \
- } \
- qint32 count = c.count(); \
- qint32 signedIdx = static_cast<qint32>(index); \
- if (signedIdx < count) \
- return ConversionToV8fn(engine, c.at(signedIdx)); \
- return v8::Undefined(); \
- } \
- v8::Handle<v8::Boolean> indexedDeleter(quint32 index) \
- { \
- /* Qt containers have int (rather than uint) allowable indexes. */ \
- if (index > INT_MAX) \
- return v8::Boolean::New(false); \
- /* Read in the sequence from the QObject */ \
- if (objectType == QV8SequenceResource::Reference) { \
- if (!object) \
- return v8::Boolean::New(false); \
- loadReference(); \
- } \
- qint32 signedIdx = static_cast<qint32>(index); \
- if (signedIdx < c.count()) { \
- /* according to ECMA262r3 it should be Undefined, */ \
- /* but we cannot, so we insert a default-value instead. */ \
- c.replace(signedIdx, DefaultValue); \
- if (objectType == QV8SequenceResource::Reference) { \
- /* write back. already checked that object is non-null, so skip that check here. */ \
- storeReference(); \
- } \
- return v8::Boolean::New(true); \
- } \
- return v8::Boolean::New(false); \
- } \
- v8::Handle<v8::Array> indexedEnumerator() \
- { \
- if (objectType == QV8SequenceResource::Reference) { \
- if (!object) \
- return v8::Handle<v8::Array>(); \
- loadReference(); \
- } \
- qint32 count = c.count(); \
- v8::Local<v8::Array> retn = v8::Array::New(count); \
- for (qint32 i = 0; i < count; ++i) { \
- retn->Set(static_cast<quint32>(i), v8::Integer::NewFromUnsigned(static_cast<quint32>(i))); \
- } \
- return retn; \
- } \
- v8::Handle<v8::Value> toString() \
- { \
- if (objectType == QV8SequenceResource::Reference) { \
- if (!object) \
- return v8::Undefined(); \
- loadReference(); \
- } \
- QString str; \
- qint32 count = c.count(); \
- for (qint32 i = 0; i < count; ++i) { \
- str += QString(QLatin1String("%1,")).arg(ToStringfn(engine, c[i])); \
- } \
- str.chop(1); \
- return engine->toString(str); \
- } \
- void loadReference() \
- { \
- Q_ASSERT(object); \
- Q_ASSERT(objectType == QV8SequenceResource::Reference); \
- void *a[] = { &c, 0 }; \
- QMetaObject::metacall(object, QMetaObject::ReadProperty, propertyIndex, a); \
- } \
- void storeReference() \
- { \
- Q_ASSERT(object); \
- Q_ASSERT(objectType == QV8SequenceResource::Reference); \
- int status = -1; \
- QQmlPropertyPrivate::WriteFlags flags = \
- QQmlPropertyPrivate::DontRemoveBinding; \
- void *a[] = { &c, 0, &status, &flags }; \
- QMetaObject::metacall(object, QMetaObject::WriteProperty, propertyIndex, a); \
- } \
- class CompareFunctor \
- { \
- public: \
- CompareFunctor(QV8Engine *engine, v8::Handle<v8::Function> f) : jsFn(f), eng(engine) {} \
- bool operator()(SequenceElementType e0, SequenceElementType e1) \
- { \
- v8::Handle<v8::Value> argv[2] = { eng->fromVariant(e0), eng->fromVariant(e1) }; \
- v8::Handle<v8::Value> compareValue = jsFn->Call(eng->global(), 2, argv); \
- return compareValue->NumberValue() < 0; \
- } \
- private: \
- v8::Handle<v8::Function> jsFn; \
- QV8Engine *eng; \
- }; \
- void sort(v8::Handle<v8::Function> jsCompareFunction) \
- { \
- CompareFunctor cf(engine, jsCompareFunction); \
- qSort(c.begin(), c.end(), cf); \
- } \
- private: \
- QQmlGuard<QObject> object; \
- int propertyIndex; \
- SequenceType c; \
- };
-
-#define GENERATE_QML_SEQUENCE_TYPE_RESOURCE(ElementType, ElementTypeName, SequenceType, DefaultValue) \
- QML_SEQUENCE_TYPE_RESOURCE(ElementType, ElementTypeName, SequenceType, DefaultValue, convert##ElementTypeName##ToV8Value, convertV8ValueTo##ElementTypeName, convert##ElementTypeName##ToString)
-
-FOREACH_QML_SEQUENCE_TYPE(GENERATE_QML_SEQUENCE_TYPE_RESOURCE)
-#undef GENERATE_QML_SEQUENCE_TYPE_RESOURCE
-#undef QML_SEQUENCE_TYPE_RESOURCE
-
-QT_END_NAMESPACE
-
-#endif // QV8SEQUENCEWRAPPER_P_P_H
diff --git a/src/qml/qml/v8/qv8typewrapper.cpp b/src/qml/qml/v8/qv8typewrapper.cpp
deleted file mode 100644
index 820f0b3ee6..0000000000
--- a/src/qml/qml/v8/qv8typewrapper.cpp
+++ /dev/null
@@ -1,307 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv8contextwrapper_p.h"
-#include "qv8engine_p.h"
-
-#include <private/qqmlengine_p.h>
-#include <private/qqmlcontext_p.h>
-
-#include <private/qjsvalue_p.h>
-#include <private/qscript_impl_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QV8TypeResource : public QV8ObjectResource
-{
- V8_RESOURCE_TYPE(TypeType)
-
-public:
- QV8TypeResource(QV8Engine *engine);
- virtual ~QV8TypeResource();
-
- QV8TypeWrapper::TypeNameMode mode;
-
- QQmlGuard<QObject> object;
-
- QQmlType *type;
- QQmlTypeNameCache *typeNamespace;
- const void *importNamespace;
-};
-
-QV8TypeResource::QV8TypeResource(QV8Engine *engine)
-: QV8ObjectResource(engine), mode(QV8TypeWrapper::IncludeEnums), type(0), typeNamespace(0), importNamespace(0)
-{
-}
-
-QV8TypeResource::~QV8TypeResource()
-{
- if (typeNamespace) typeNamespace->release();
-}
-
-QV8TypeWrapper::QV8TypeWrapper()
-: m_engine(0)
-{
-}
-
-QV8TypeWrapper::~QV8TypeWrapper()
-{
-}
-
-void QV8TypeWrapper::destroy()
-{
- qPersistentDispose(m_constructor);
-}
-
-void QV8TypeWrapper::init(QV8Engine *engine)
-{
- m_engine = engine;
- v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
- ft->InstanceTemplate()->SetHasExternalResource(true);
- m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
-}
-
-// Returns a type wrapper for type t on o. This allows access of enums, and attached properties.
-v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QQmlType *t, TypeNameMode mode)
-{
- Q_ASSERT(t);
- // XXX NewInstance() should be optimized
- v8::Local<v8::Object> rv = m_constructor->NewInstance();
- QV8TypeResource *r = new QV8TypeResource(m_engine);
- r->mode = mode; r->object = o; r->type = t;
- rv->SetExternalResource(r);
- return rv;
-}
-
-// Returns a type wrapper for importNamespace (of t) on o. This allows nested resolution of a type in a
-// namespace.
-v8::Local<v8::Object> QV8TypeWrapper::newObject(QObject *o, QQmlTypeNameCache *t,
- const void *importNamespace, TypeNameMode mode)
-{
- Q_ASSERT(t);
- Q_ASSERT(importNamespace);
- // XXX NewInstance() should be optimized
- v8::Local<v8::Object> rv = m_constructor->NewInstance();
- QV8TypeResource *r = new QV8TypeResource(m_engine);
- t->addref();
- r->mode = mode; r->object = o; r->typeNamespace = t; r->importNamespace = importNamespace;
- rv->SetExternalResource(r);
- return rv;
-}
-
-QVariant QV8TypeWrapper::toVariant(QV8ObjectResource *r)
-{
- Q_ASSERT(r->resourceType() == QV8ObjectResource::TypeType);
- QV8TypeResource *resource = static_cast<QV8TypeResource *>(r);
- QV8Engine *v8engine = resource->engine;
-
- if (resource->type && resource->type->isSingleton()) {
- QQmlEngine *e = v8engine->engine();
- QQmlType::SingletonInstanceInfo *siinfo = resource->type->singletonInstanceInfo();
- siinfo->init(e); // note: this will also create QJSValue singleton which isn't strictly required.
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- if (qobjectSingleton) {
- return QVariant::fromValue<QObject*>(qobjectSingleton);
- }
- }
-
- // only QObject Singleton Type can be converted to a variant.
- return QVariant();
-}
-
-v8::Handle<v8::Value> QV8TypeWrapper::Getter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
-{
- QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This());
-
- if (!resource)
- return v8::Undefined();
-
- QV8Engine *v8engine = resource->engine;
- QQmlContextData *context = v8engine->callingContext();
-
- QObject *object = resource->object;
-
- QHashedV8String propertystring(property);
-
- if (resource->type) {
- QQmlType *type = resource->type;
-
- // singleton types are handled differently to other types.
- if (type->isSingleton()) {
- QQmlEngine *e = v8engine->engine();
- QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
- siinfo->init(e);
-
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- if (qobjectSingleton) {
- // check for enum value
- if (QV8Engine::startsWithUpper(property)) {
- if (resource->mode == IncludeEnums) {
- QString name = v8engine->toString(property);
-
- // ### Optimize
- QByteArray enumName = name.toUtf8();
- const QMetaObject *metaObject = qobjectSingleton->metaObject();
- for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) {
- QMetaEnum e = metaObject->enumerator(ii);
- bool ok;
- int value = e.keyToValue(enumName.constData(), &ok);
- if (ok)
- return v8::Integer::New(value);
- }
- }
- }
-
- // check for property.
- v8::Handle<v8::Value> rv = v8engine->qobjectWrapper()->getProperty(qobjectSingleton, propertystring, context, QV8QObjectWrapper::IgnoreRevision);
- return rv;
- } else if (!siinfo->scriptApi(e).isUndefined()) {
- // NOTE: if used in a binding, changes will not trigger re-evaluation since non-NOTIFYable.
- QJSValuePrivate *apiprivate = QJSValuePrivate::get(siinfo->scriptApi(e));
- QScopedPointer<QJSValuePrivate> propertyValue(apiprivate->property(property).give());
- return propertyValue->asV8Value(v8engine);
- }
-
- // Fall through to return empty handle
-
- } else {
-
- if (QV8Engine::startsWithUpper(property)) {
- bool ok = false;
- int value = type->enumValue(propertystring, &ok);
- if (ok)
- return v8::Integer::New(value);
-
- // Fall through to return empty handle
-
- } else if (resource->object) {
- QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
- if (ao)
- return v8engine->qobjectWrapper()->getProperty(ao, propertystring, context,
- QV8QObjectWrapper::IgnoreRevision);
-
- // Fall through to return empty handle
- }
-
- // Fall through to return empty handle
- }
-
- // Fall through to return empty handle
-
- } else if (resource->typeNamespace) {
- Q_ASSERT(resource->importNamespace);
- QQmlTypeNameCache::Result r = resource->typeNamespace->query(propertystring,
- resource->importNamespace);
-
- if (r.isValid()) {
- QQmlContextData *context = v8engine->callingContext();
- if (r.type) {
- return v8engine->typeWrapper()->newObject(object, r.type, resource->mode);
- } else if (r.scriptIndex != -1) {
- int index = r.scriptIndex;
- if (index < context->importedScripts.count())
- return context->importedScripts.at(index);
- } else if (r.importNamespace) {
- return v8engine->typeWrapper()->newObject(object, context->imports, r.importNamespace);
- }
-
- return v8::Undefined();
-
- }
-
- // Fall through to return empty handle
-
- } else {
- Q_ASSERT(!"Unreachable");
- }
-
- return v8::Handle<v8::Value>();
-}
-
-v8::Handle<v8::Value> QV8TypeWrapper::Setter(v8::Local<v8::String> property,
- v8::Local<v8::Value> value,
- const v8::AccessorInfo &info)
-{
- QV8TypeResource *resource = v8_resource_cast<QV8TypeResource>(info.This());
-
- if (!resource)
- return value;
-
- QV8Engine *v8engine = resource->engine;
- QQmlContextData *context = v8engine->callingContext();
-
- QHashedV8String propertystring(property);
-
- QQmlType *type = resource->type;
- if (type && !type->isSingleton() && resource->object) {
- QObject *object = resource->object;
- QObject *ao = qmlAttachedPropertiesObjectById(type->attachedPropertiesId(), object);
- if (ao)
- v8engine->qobjectWrapper()->setProperty(ao, propertystring, context, value,
- QV8QObjectWrapper::IgnoreRevision);
- } else if (type && type->isSingleton()) {
- QQmlEngine *e = v8engine->engine();
- QQmlType::SingletonInstanceInfo *siinfo = type->singletonInstanceInfo();
- siinfo->init(e);
-
- QObject *qobjectSingleton = siinfo->qobjectApi(e);
- if (qobjectSingleton) {
- v8engine->qobjectWrapper()->setProperty(qobjectSingleton, propertystring, context, value,
- QV8QObjectWrapper::IgnoreRevision);
- } else if (!siinfo->scriptApi(e).isUndefined()) {
- QScopedPointer<QJSValuePrivate> setvalp(new QJSValuePrivate(v8engine, value));
- QJSValuePrivate *apiprivate = QJSValuePrivate::get(siinfo->scriptApi(e));
- if (apiprivate->propertyFlags(property) & QJSValuePrivate::ReadOnly) {
- QString error = QLatin1String("Cannot assign to read-only property \"") +
- v8engine->toString(property) + QLatin1Char('\"');
- v8::ThrowException(v8::Exception::Error(v8engine->toString(error)));
- } else {
- apiprivate->setProperty(property, setvalp.data());
- }
- }
- }
-
- return value;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8valuetypewrapper.cpp b/src/qml/qml/v8/qv8valuetypewrapper.cpp
deleted file mode 100644
index d5d977d9c4..0000000000
--- a/src/qml/qml/v8/qv8valuetypewrapper.cpp
+++ /dev/null
@@ -1,452 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv8valuetypewrapper_p.h"
-#include "qv8engine_p.h"
-
-#include <private/qqmlvaluetype_p.h>
-#include <private/qqmlbinding_p.h>
-#include <private/qqmlglobal_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QV8ValueTypeResource : public QV8ObjectResource
-{
- V8_RESOURCE_TYPE(ValueTypeType)
-
-public:
- enum ObjectType { Reference, Copy };
-
- QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType);
-
- ObjectType objectType;
- QQmlValueType *type;
-};
-
-class QV8ValueTypeReferenceResource : public QV8ValueTypeResource
-{
-public:
- QV8ValueTypeReferenceResource(QV8Engine *engine);
-
- QQmlGuard<QObject> object;
- int property;
-};
-
-class QV8ValueTypeCopyResource : public QV8ValueTypeResource
-{
-public:
- QV8ValueTypeCopyResource(QV8Engine *engine);
-
- QVariant value;
-};
-
-QV8ValueTypeResource::QV8ValueTypeResource(QV8Engine *engine, ObjectType objectType)
-: QV8ObjectResource(engine), objectType(objectType)
-{
-}
-
-QV8ValueTypeReferenceResource::QV8ValueTypeReferenceResource(QV8Engine *engine)
-: QV8ValueTypeResource(engine, Reference)
-{
-}
-
-QV8ValueTypeCopyResource::QV8ValueTypeCopyResource(QV8Engine *engine)
-: QV8ValueTypeResource(engine, Copy)
-{
-}
-
-QV8ValueTypeWrapper::QV8ValueTypeWrapper()
-: m_engine(0)
-{
-}
-
-QV8ValueTypeWrapper::~QV8ValueTypeWrapper()
-{
-}
-
-void QV8ValueTypeWrapper::destroy()
-{
- qPersistentDispose(m_toString);
- qPersistentDispose(m_constructor);
- qPersistentDispose(m_toStringSymbol);
-}
-
-static quint32 toStringHash = -1;
-
-void QV8ValueTypeWrapper::init(QV8Engine *engine)
-{
- m_engine = engine;
- m_toString = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ToString)->GetFunction());
- v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetNamedPropertyHandler(Getter, Setter);
- ft->InstanceTemplate()->SetHasExternalResource(true);
- ft->InstanceTemplate()->MarkAsUseUserObjectComparison();
- ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0,
- m_toString, v8::DEFAULT,
- v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
- m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
-
- m_toStringSymbol = qPersistentNew<v8::String>(v8::String::NewSymbol("toString"));
- m_toStringString = QHashedV8String(m_toStringSymbol);
- toStringHash = m_toStringString.hash();
-}
-
-v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(QObject *object, int property, QQmlValueType *type)
-{
- // XXX NewInstance() should be optimized
- v8::Local<v8::Object> rv = m_constructor->NewInstance();
- QV8ValueTypeReferenceResource *r = new QV8ValueTypeReferenceResource(m_engine);
- r->type = type; r->object = object; r->property = property;
- rv->SetExternalResource(r);
- return rv;
-}
-
-v8::Local<v8::Object> QV8ValueTypeWrapper::newValueType(const QVariant &value, QQmlValueType *type)
-{
- // XXX NewInstance() should be optimized
- v8::Local<v8::Object> rv = m_constructor->NewInstance();
- QV8ValueTypeCopyResource *r = new QV8ValueTypeCopyResource(m_engine);
- r->type = type; r->value = value;
- rv->SetExternalResource(r);
- return rv;
-}
-
-static bool readReferenceValue(QV8ValueTypeReferenceResource *reference)
-{
- // A reference resource may be either a "true" reference (eg, to a QVector3D property)
- // or a "variant" reference (eg, to a QVariant property which happens to contain a value-type).
- QMetaProperty writebackProperty = reference->object->metaObject()->property(reference->property);
- if (writebackProperty.userType() == QMetaType::QVariant) {
- // variant-containing-value-type reference
- QVariant variantReferenceValue;
- reference->type->readVariantValue(reference->object, reference->property, &variantReferenceValue);
- int variantReferenceType = variantReferenceValue.userType();
- if (variantReferenceType != reference->type->userType()) {
- // This is a stale VariantReference. That is, the variant has been
- // overwritten with a different type in the meantime.
- // We need to modify this reference to the updated value type, if
- // possible, or return false if it is not a value type.
- if (QQmlValueTypeFactory::isValueType(variantReferenceType)) {
- reference->type = QQmlValueTypeFactory::valueType(variantReferenceType);
- if (!reference->type) {
- return false;
- }
- } else {
- return false;
- }
- }
- reference->type->setValue(variantReferenceValue);
- } else {
- // value-type reference
- reference->type->read(reference->object, reference->property);
- }
- return true;
-}
-
-bool QV8ValueTypeWrapper::isValueType(v8::Handle<v8::Object> obj) const
-{
- QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(obj);
- return (r != 0);
-}
-
-QVariant QV8ValueTypeWrapper::toVariant(v8::Handle<v8::Object> obj, int typeHint, bool *succeeded)
-{
- // NOTE: obj must not be an external resource object (ie, wrapper object)
- // instead, it is a normal js object which one of the value-type providers
- // may know how to convert to the given type.
- return QQml_valueTypeProvider()->createVariantFromJsObject(typeHint, QQmlV8Handle::fromHandle(obj), m_engine, succeeded);
-}
-
-QVariant QV8ValueTypeWrapper::toVariant(v8::Handle<v8::Object> obj)
-{
- QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(obj);
- if (r) return toVariant(r);
- else return QVariant();
-}
-
-QVariant QV8ValueTypeWrapper::toVariant(QV8ObjectResource *r)
-{
- Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType);
- QV8ValueTypeResource *resource = static_cast<QV8ValueTypeResource *>(r);
-
- if (resource->objectType == QV8ValueTypeResource::Reference) {
- QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
-
- if (reference->object && readReferenceValue(reference)) {
- return reference->type->value();
- } else {
- return QVariant();
- }
-
- } else {
- Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
-
- QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
-
- return copy->value;
- }
-}
-
-bool QV8ValueTypeWrapper::isEqual(QV8ObjectResource *r, const QVariant& value)
-{
- Q_ASSERT(r->resourceType() == QV8ObjectResource::ValueTypeType);
- QV8ValueTypeResource *resource = static_cast<QV8ValueTypeResource *>(r);
-
- if (resource->objectType == QV8ValueTypeResource::Reference) {
- QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
- if (reference->object && readReferenceValue(reference)) {
- return reference->type->isEqual(value);
- } else {
- return false;
- }
- } else {
- Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
- QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
- resource->type->setValue(copy->value);
- if (resource->type->isEqual(value))
- return true;
- return (value == copy->value);
- }
-}
-
-v8::Handle<v8::Value> QV8ValueTypeWrapper::ToStringGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
- return info.Data();
-}
-
-v8::Handle<v8::Value> QV8ValueTypeWrapper::ToString(const v8::Arguments &args)
-{
- QV8ValueTypeResource *resource = v8_resource_cast<QV8ValueTypeResource>(args.This());
- if (resource) {
- if (resource->objectType == QV8ValueTypeResource::Reference) {
- QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(resource);
- if (reference->object && readReferenceValue(reference)) {
- return resource->engine->toString(resource->type->toString());
- } else {
- return v8::Undefined();
- }
- } else {
- Q_ASSERT(resource->objectType == QV8ValueTypeResource::Copy);
- QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(resource);
- resource->type->setValue(copy->value);
- return resource->engine->toString(resource->type->toString());
- }
- } else {
- return v8::Undefined();
- }
-}
-
-v8::Handle<v8::Value> QV8ValueTypeWrapper::Getter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
-{
- QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(info.This());
- if (!r) return v8::Handle<v8::Value>();
-
- QHashedV8String propertystring(property);
-
- {
- // Comparing the hash first actually makes a measurable difference here, at least on x86
- quint32 hash = propertystring.hash();
- if (hash == toStringHash &&
- r->engine->valueTypeWrapper()->m_toStringString == propertystring) {
- return r->engine->valueTypeWrapper()->m_toString;
- }
- }
-
- // Note: readReferenceValue() can change the reference->type.
- if (r->objectType == QV8ValueTypeResource::Reference) {
- QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
-
- if (!reference->object || !readReferenceValue(reference))
- return v8::Handle<v8::Value>();
-
- } else {
- Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
-
- QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
-
- r->type->setValue(copy->value);
- }
-
- QQmlPropertyData local;
- QQmlPropertyData *result = 0;
- {
- QQmlData *ddata = QQmlData::get(r->type, false);
- if (ddata && ddata->propertyCache)
- result = ddata->propertyCache->property(propertystring, 0, 0);
- else
- result = QQmlPropertyCache::property(r->engine->engine(), r->type,
- propertystring, 0, local);
- }
-
- if (!result)
- return v8::Handle<v8::Value>();
-
- if (result->isFunction()) {
- // calling a Q_INVOKABLE function of a value type
- QQmlContextData *context = r->engine->callingContext();
- return r->engine->qobjectWrapper()->getProperty(r->type, propertystring, context, QV8QObjectWrapper::IgnoreRevision);
- }
-
-#define VALUE_TYPE_LOAD(metatype, cpptype, constructor) \
- if (result->propType == metatype) { \
- cpptype v; \
- void *args[] = { &v, 0 }; \
- r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args); \
- return constructor(v); \
- }
-
- // These four types are the most common used by the value type wrappers
- VALUE_TYPE_LOAD(QMetaType::QReal, qreal, v8::Number::New);
- VALUE_TYPE_LOAD(QMetaType::Int, int, v8::Integer::New);
- VALUE_TYPE_LOAD(QMetaType::QString, QString, r->engine->toString);
- VALUE_TYPE_LOAD(QMetaType::Bool, bool, v8::Boolean::New);
-
- QVariant v(result->propType, (void *)0);
- void *args[] = { v.data(), 0 };
- r->type->qt_metacall(QMetaObject::ReadProperty, result->coreIndex, args);
- return r->engine->fromVariant(v);
-#undef VALUE_TYPE_ACCESSOR
-}
-
-v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Local<v8::String> property,
- v8::Local<v8::Value> value,
- const v8::AccessorInfo &info)
-{
- QV8ValueTypeResource *r = v8_resource_cast<QV8ValueTypeResource>(info.This());
- if (!r) return value;
-
- QByteArray propName = r->engine->toString(property).toUtf8();
- if (r->objectType == QV8ValueTypeResource::Reference) {
- QV8ValueTypeReferenceResource *reference = static_cast<QV8ValueTypeReferenceResource *>(r);
- QMetaProperty writebackProperty = reference->object->metaObject()->property(reference->property);
-
- if (!reference->object || !writebackProperty.isWritable() || !readReferenceValue(reference))
- return value;
-
- // we lookup the index after readReferenceValue() since it can change the reference->type.
- int index = r->type->metaObject()->indexOfProperty(propName.constData());
- if (index == -1)
- return value;
- QMetaProperty p = r->type->metaObject()->property(index);
-
- QQmlBinding *newBinding = 0;
-
- if (value->IsFunction()) {
- if (value->ToObject()->GetHiddenValue(r->engine->bindingFlagKey()).IsEmpty()) {
- // assigning a JS function to a non-var-property is not allowed.
- QString error = QLatin1String("Cannot assign JavaScript function to value-type property");
- v8::ThrowException(v8::Exception::Error(r->engine->toString(error)));
- return value;
- }
-
- QQmlContextData *context = r->engine->callingContext();
- v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
-
- QQmlPropertyData cacheData;
- cacheData.setFlags(QQmlPropertyData::IsWritable |
- QQmlPropertyData::IsValueTypeVirtual);
- cacheData.propType = reference->object->metaObject()->property(reference->property).userType();
- cacheData.coreIndex = reference->property;
- cacheData.valueTypeFlags = 0;
- cacheData.valueTypeCoreIndex = index;
- cacheData.valueTypePropType = p.userType();
-
- v8::Local<v8::StackTrace> trace =
- v8::StackTrace::CurrentStackTrace(1,
- (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber |
- v8::StackTrace::kScriptName));
- v8::Local<v8::StackFrame> frame = trace->GetFrame(0);
- int lineNumber = frame->GetLineNumber();
- int columnNumber = frame->GetColumn();
- QString url = r->engine->toString(frame->GetScriptName());
-
- newBinding = new QQmlBinding(&function, reference->object, context,
- url, qmlSourceCoordinate(lineNumber), qmlSourceCoordinate(columnNumber));
- newBinding->setTarget(reference->object, cacheData, context);
- newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
- QQmlBinding::RequiresThisObject);
- }
-
- QQmlAbstractBinding *oldBinding =
- QQmlPropertyPrivate::setBinding(reference->object, reference->property, index, newBinding);
- if (oldBinding)
- oldBinding->destroy();
-
- if (!value->IsFunction()) {
- QVariant v = r->engine->toVariant(value, -1);
-
- if (p.isEnumType() && (QMetaType::Type)v.type() == QMetaType::Double)
- v = v.toInt();
-
- p.write(reference->type, v);
-
- if (writebackProperty.userType() == QMetaType::QVariant) {
- QVariant variantReferenceValue = r->type->value();
- reference->type->writeVariantValue(reference->object, reference->property, 0, &variantReferenceValue);
- } else {
- reference->type->write(reference->object, reference->property, 0);
- }
- }
-
- } else {
- Q_ASSERT(r->objectType == QV8ValueTypeResource::Copy);
-
- QV8ValueTypeCopyResource *copy = static_cast<QV8ValueTypeCopyResource *>(r);
-
- int index = r->type->metaObject()->indexOfProperty(propName.constData());
- if (index == -1)
- return value;
-
- QVariant v = r->engine->toVariant(value, -1);
-
- r->type->setValue(copy->value);
- QMetaProperty p = r->type->metaObject()->property(index);
- p.write(r->type, v);
- copy->value = r->type->value();
- }
-
- return value;
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8valuetypewrapper_p.h b/src/qml/qml/v8/qv8valuetypewrapper_p.h
deleted file mode 100644
index d22874639a..0000000000
--- a/src/qml/qml/v8/qv8valuetypewrapper_p.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV8VALUETYPEWRAPPER_P_H
-#define QV8VALUETYPEWRAPPER_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 <QtCore/qglobal.h>
-#include <QtQml/qqmllist.h>
-#include <private/qtqmlglobal_p.h>
-#include <private/qv8_p.h>
-#include <private/qhashedstring_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QV8Engine;
-class QV8ObjectResource;
-class QQmlValueType;
-class Q_QML_PRIVATE_EXPORT QV8ValueTypeWrapper
-{
-public:
- QV8ValueTypeWrapper();
- ~QV8ValueTypeWrapper();
-
- void init(QV8Engine *);
- void destroy();
-
- v8::Local<v8::Object> newValueType(QObject *, int, QQmlValueType *);
- v8::Local<v8::Object> newValueType(const QVariant &, QQmlValueType *);
-
- bool isValueType(v8::Handle<v8::Object>) const;
-
- QVariant toVariant(v8::Handle<v8::Object>, int typeHint, bool *succeeded);
- QVariant toVariant(v8::Handle<v8::Object>);
- QVariant toVariant(QV8ObjectResource *);
-
- static bool isEqual(QV8ObjectResource *, const QVariant& value);
-
-private:
- static v8::Handle<v8::Value> ToStringGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> ToString(const v8::Arguments &args);
- static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
- v8::Local<v8::Value> value,
- const v8::AccessorInfo &info);
-
- QV8Engine *m_engine;
- v8::Persistent<v8::Function> m_constructor;
- v8::Persistent<v8::Function> m_toString;
- v8::Persistent<v8::String> m_toStringSymbol;
- QHashedV8String m_toStringString;
-};
-
-QT_END_NAMESPACE
-
-#endif // QV8VALUETYPEWRAPPER_P_H
-
-
diff --git a/src/qml/qml/v8/qv8variantwrapper.cpp b/src/qml/qml/v8/qv8variantwrapper.cpp
deleted file mode 100644
index bea016a905..0000000000
--- a/src/qml/qml/v8/qv8variantwrapper.cpp
+++ /dev/null
@@ -1,279 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qv8variantwrapper_p.h"
-#include "qv8variantresource_p.h"
-#include "qv8engine_p.h"
-#include <private/qqmlengine_p.h>
-
-QT_BEGIN_NAMESPACE
-
-QV8VariantResource::QV8VariantResource(QV8Engine *engine, const QVariant &data)
-: QV8ObjectResource(engine), QQmlEnginePrivate::ScarceResourceData(data), m_isScarceResource(false), m_vmePropertyReferenceCount(0)
-{
-}
-
-void QV8VariantResource::addVmePropertyReference()
-{
- if (m_isScarceResource && ++m_vmePropertyReferenceCount == 1) {
- // remove from the ep->scarceResources list
- // since it is now no longer eligible to be
- // released automatically by the engine.
- node.remove();
- }
-}
-
-void QV8VariantResource::removeVmePropertyReference()
-{
- if (m_isScarceResource && --m_vmePropertyReferenceCount == 0) {
- // and add to the ep->scarceResources list
- // since it is now eligible to be released
- // automatically by the engine.
- QQmlEnginePrivate::get(engine->engine())->scarceResources.insert(this);
- }
-}
-
-QV8VariantWrapper::QV8VariantWrapper()
-: m_engine(0)
-{
-}
-
-QV8VariantWrapper::~QV8VariantWrapper()
-{
-}
-
-void QV8VariantWrapper::init(QV8Engine *engine)
-{
- m_engine = engine;
- m_toString = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ToString)->GetFunction());
- m_valueOf = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(ValueOf)->GetFunction());
-
- {
- v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
- ft->InstanceTemplate()->SetHasExternalResource(true);
- ft->InstanceTemplate()->MarkAsUseUserObjectComparison();
- ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0,
- m_toString, v8::DEFAULT,
- v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
- ft->InstanceTemplate()->SetAccessor(v8::String::New("valueOf"), ValueOfGetter, 0,
- m_valueOf, v8::DEFAULT,
- v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
- m_constructor = qPersistentNew<v8::Function>(ft->GetFunction());
- }
- {
- m_preserve = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(Preserve)->GetFunction());
- m_destroy = qPersistentNew<v8::Function>(v8::FunctionTemplate::New(Destroy)->GetFunction());
- v8::Local<v8::FunctionTemplate> ft = v8::FunctionTemplate::New();
- ft->InstanceTemplate()->SetFallbackPropertyHandler(Getter, Setter);
- ft->InstanceTemplate()->SetHasExternalResource(true);
- ft->InstanceTemplate()->MarkAsUseUserObjectComparison();
- ft->InstanceTemplate()->SetAccessor(v8::String::New("preserve"), PreserveGetter, 0,
- m_preserve, v8::DEFAULT,
- v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
- ft->InstanceTemplate()->SetAccessor(v8::String::New("destroy"), DestroyGetter, 0,
- m_destroy, v8::DEFAULT,
- v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
- ft->InstanceTemplate()->SetAccessor(v8::String::New("toString"), ToStringGetter, 0,
- m_toString, v8::DEFAULT,
- v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
- ft->InstanceTemplate()->SetAccessor(v8::String::New("valueOf"), ValueOfGetter, 0,
- m_valueOf, v8::DEFAULT,
- v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
- m_scarceConstructor = qPersistentNew<v8::Function>(ft->GetFunction());
- }
-
-}
-
-void QV8VariantWrapper::destroy()
-{
- qPersistentDispose(m_valueOf);
- qPersistentDispose(m_toString);
- qPersistentDispose(m_destroy);
- qPersistentDispose(m_preserve);
- qPersistentDispose(m_scarceConstructor);
- qPersistentDispose(m_constructor);
-}
-
-v8::Local<v8::Object> QV8VariantWrapper::newVariant(const QVariant &value)
-{
- bool scarceResource = value.type() == QVariant::Pixmap ||
- value.type() == QVariant::Image;
-
- // XXX NewInstance() should be optimized
- v8::Local<v8::Object> rv;
- QV8VariantResource *r = new QV8VariantResource(m_engine, value);
-
- if (scarceResource) {
- QQmlEnginePrivate *ep = QQmlEnginePrivate::get(m_engine->engine());
- Q_ASSERT(ep->scarceResourcesRefCount);
- rv = m_scarceConstructor->NewInstance();
- r->m_isScarceResource = true;
- ep->scarceResources.insert(r);
- } else {
- rv = m_constructor->NewInstance();
- }
-
- rv->SetExternalResource(r);
- return rv;
-}
-
-bool QV8VariantWrapper::isVariant(v8::Handle<v8::Value> value)
-{
- return value->IsObject() && v8_resource_cast<QV8VariantResource>(value->ToObject());
-}
-
-QVariant QV8VariantWrapper::toVariant(v8::Handle<v8::Object> obj)
-{
- QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(obj);
- return r?r->data:QVariant();
-}
-
-QVariant QV8VariantWrapper::toVariant(QV8ObjectResource *r)
-{
- Q_ASSERT(r->resourceType() == QV8ObjectResource::VariantType);
- return static_cast<QV8VariantResource *>(r)->data;
-}
-
-QVariant &QV8VariantWrapper::variantValue(v8::Handle<v8::Value> value)
-{
- Q_ASSERT(isVariant(value));
- QV8VariantResource *r = v8_resource_cast<QV8VariantResource>(value->ToObject());
- return static_cast<QV8VariantResource *>(r)->data;
-}
-
-v8::Handle<v8::Value> QV8VariantWrapper::Getter(v8::Local<v8::String> /* property */,
- const v8::AccessorInfo & /* info */)
-{
- return v8::Handle<v8::Value>();
-}
-
-v8::Handle<v8::Value> QV8VariantWrapper::Setter(v8::Local<v8::String> /* property */,
- v8::Local<v8::Value> value,
- const v8::AccessorInfo & /* info */)
-{
- return value;
-}
-
-v8::Handle<v8::Value> QV8VariantWrapper::PreserveGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
- return info.Data();
-}
-
-v8::Handle<v8::Value> QV8VariantWrapper::DestroyGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
- return info.Data();
-}
-
-v8::Handle<v8::Value> QV8VariantWrapper::ToStringGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
- return info.Data();
-}
-
-v8::Handle<v8::Value> QV8VariantWrapper::ValueOfGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info)
-{
- Q_UNUSED(property);
- return info.Data();
-}
-
-v8::Handle<v8::Value> QV8VariantWrapper::Preserve(const v8::Arguments &args)
-{
- QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
- if (resource) {
- resource->node.remove();
- }
- return v8::Undefined();
-}
-
-v8::Handle<v8::Value> QV8VariantWrapper::Destroy(const v8::Arguments &args)
-{
- QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
- if (resource) {
- resource->data = QVariant();
- resource->node.remove();
- }
- return v8::Undefined();
-}
-
-v8::Handle<v8::Value> QV8VariantWrapper::ToString(const v8::Arguments &args)
-{
- QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
- if (resource) {
- QString result = resource->data.toString();
- if (result.isEmpty() && !resource->data.canConvert(QVariant::String))
- result = QString::fromLatin1("QVariant(%0)").arg(QString::fromLatin1(resource->data.typeName()));
- return resource->engine->toString(result);
- } else {
- return v8::Undefined();
- }
-}
-
-v8::Handle<v8::Value> QV8VariantWrapper::ValueOf(const v8::Arguments &args)
-{
- QV8VariantResource *resource = v8_resource_cast<QV8VariantResource>(args.This());
- if (resource) {
- QVariant v = resource->data;
- switch (v.type()) {
- case QVariant::Invalid:
- return v8::Undefined();
- case QVariant::String:
- return resource->engine->toString(v.toString());
- case QVariant::Int:
- case QVariant::Double:
- case QVariant::UInt:
- return v8::Number::New(v.toDouble());
- case QVariant::Bool:
- return v8::Boolean::New(v.toBool());
- default:
- break;
- }
- }
- return args.This();
-}
-
-QT_END_NAMESPACE
diff --git a/src/qml/qml/v8/qv8variantwrapper_p.h b/src/qml/qml/v8/qv8variantwrapper_p.h
deleted file mode 100644
index 9f634b938d..0000000000
--- a/src/qml/qml/v8/qv8variantwrapper_p.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
-**
-** This file is part of the QtQml module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3.0 as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU General Public License version 3.0 requirements will be
-** met: http://www.gnu.org/copyleft/gpl.html.
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QV8VARIANTWRAPPER_P_H
-#define QV8VARIANTWRAPPER_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 <QtCore/qglobal.h>
-#include <QtQml/qqmllist.h>
-#include <private/qv8_p.h>
-
-QT_BEGIN_NAMESPACE
-
-class QV8Engine;
-class QV8ObjectResource;
-class QV8VariantWrapper
-{
-public:
- QV8VariantWrapper();
- ~QV8VariantWrapper();
-
- void init(QV8Engine *);
- void destroy();
-
- v8::Local<v8::Object> newVariant(const QVariant &);
- bool isVariant(v8::Handle<v8::Value>);
- static QVariant toVariant(v8::Handle<v8::Object>);
- static QVariant toVariant(QV8ObjectResource *);
- QVariant &variantValue(v8::Handle<v8::Value>);
-
-private:
- static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> Setter(v8::Local<v8::String> property,
- v8::Local<v8::Value> value,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> PreserveGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> DestroyGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> ToStringGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> ValueOfGetter(v8::Local<v8::String> property,
- const v8::AccessorInfo &info);
- static v8::Handle<v8::Value> Preserve(const v8::Arguments &args);
- static v8::Handle<v8::Value> Destroy(const v8::Arguments &args);
- static v8::Handle<v8::Value> ToString(const v8::Arguments &args);
- static v8::Handle<v8::Value> ValueOf(const v8::Arguments &args);
-
- QV8Engine *m_engine;
- v8::Persistent<v8::Function> m_constructor;
- v8::Persistent<v8::Function> m_scarceConstructor;
- v8::Persistent<v8::Function> m_preserve;
- v8::Persistent<v8::Function> m_destroy;
- v8::Persistent<v8::Function> m_toString;
- v8::Persistent<v8::Function> m_valueOf;
-};
-
-QT_END_NAMESPACE
-
-#endif // QV8VARIANTWRAPPER_P_H
-
diff --git a/src/qml/qml/v8/script.pri b/src/qml/qml/v8/script.pri
index 3439413f5e..f70588ec7b 100644
--- a/src/qml/qml/v8/script.pri
+++ b/src/qml/qml/v8/script.pri
@@ -9,13 +9,4 @@ HEADERS += \
$$PWD/qjsvalue.h \
$$PWD/qjsvalue_p.h \
$$PWD/qjsvalueiterator.h \
- $$PWD/qjsvalue_impl_p.h \
- $$PWD/qjsconverter_p.h \
- $$PWD/qjsconverter_impl_p.h \
- $$PWD/qscriptisolate_p.h \
- $$PWD/qscriptshareddata_p.h \
- $$PWD/qscripttools_p.h \
- $$PWD/qscript_impl_p.h \
- $$PWD/qscriptoriginalglobalobject_p.h \
- $$PWD/qjsvalueiterator_p.h \
- $$PWD/qjsvalueiterator_impl_p.h
+ $$PWD/qjsvalueiterator_p.h
diff --git a/src/qml/qml/v8/v8.pri b/src/qml/qml/v8/v8.pri
index 33a0ad10a1..d3edc591a7 100644
--- a/src/qml/qml/v8/v8.pri
+++ b/src/qml/qml/v8/v8.pri
@@ -1,44 +1,16 @@
include(script.pri)
HEADERS += \
- $$PWD/qv8_p.h \
$$PWD/qv8debug_p.h \
$$PWD/qv8profiler_p.h \
- $$PWD/qv8stringwrapper_p.h \
$$PWD/qv8engine_p.h \
- $$PWD/qv8sequencewrapper_p.h \
- $$PWD/qv8sequencewrapper_p_p.h \
- $$PWD/qv8contextwrapper_p.h \
- $$PWD/qv8qobjectwrapper_p.h \
- $$PWD/qv8typewrapper_p.h \
- $$PWD/qv8listwrapper_p.h \
- $$PWD/qv8variantwrapper_p.h \
- $$PWD/qv8variantresource_p.h \
- $$PWD/qv8valuetypewrapper_p.h \
- $$PWD/qv8jsonwrapper_p.h \
- $$PWD/qv8include_p.h \
- $$PWD/qv8worker_p.h \
- $$PWD/qv8bindings_p.h \
- $$PWD/qv8engine_impl_p.h \
- $$PWD/qv8domerrors_p.h \
- $$PWD/qv8sqlerrors_p.h \
- $$PWD/qqmlbuiltinfunctions_p.h \
- $$PWD/qv8objectresource_p.h
+ $$PWD/qv4domerrors_p.h \
+ $$PWD/qv4sqlerrors_p.h \
+ $$PWD/qqmlbuiltinfunctions_p.h
SOURCES += \
- $$PWD/qv8stringwrapper.cpp \
$$PWD/qv8engine.cpp \
- $$PWD/qv8sequencewrapper.cpp \
- $$PWD/qv8contextwrapper.cpp \
- $$PWD/qv8qobjectwrapper.cpp \
- $$PWD/qv8typewrapper.cpp \
- $$PWD/qv8listwrapper.cpp \
- $$PWD/qv8variantwrapper.cpp \
- $$PWD/qv8valuetypewrapper.cpp \
- $$PWD/qv8jsonwrapper.cpp \
- $$PWD/qv8include.cpp \
- $$PWD/qv8worker.cpp \
- $$PWD/qv8bindings.cpp \
- $$PWD/qv8domerrors.cpp \
- $$PWD/qv8sqlerrors.cpp \
+ $$PWD/qv4domerrors.cpp \
+ $$PWD/qv4sqlerrors.cpp \
$$PWD/qqmlbuiltinfunctions.cpp
+