Bump package version to 5.5.90+alpha1
[platform/upstream/qtdeclarative.git] / src / qml / jsruntime / qv4engine.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL21$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** $QT_END_LICENSE$
31 **
32 ****************************************************************************/
33 #include <qv4engine_p.h>
34 #include <qv4context_p.h>
35 #include <qv4value_p.h>
36 #include <qv4object_p.h>
37 #include <qv4objectproto_p.h>
38 #include <qv4objectiterator_p.h>
39 #include <qv4arrayobject_p.h>
40 #include <qv4booleanobject_p.h>
41 #include <qv4globalobject_p.h>
42 #include <qv4errorobject_p.h>
43 #include <qv4functionobject_p.h>
44 #include "qv4function_p.h"
45 #include <qv4mathobject_p.h>
46 #include <qv4numberobject_p.h>
47 #include <qv4regexpobject_p.h>
48 #include <qv4regexp_p.h>
49 #include <qv4variantobject_p.h>
50 #include <qv4runtime_p.h>
51 #include <private/qv4mm_p.h>
52 #include <qv4argumentsobject_p.h>
53 #include <qv4dateobject_p.h>
54 #include <qv4jsonobject_p.h>
55 #include <qv4stringobject_p.h>
56 #include <qv4identifiertable_p.h>
57 #include "qv4debugging_p.h"
58 #include "qv4profiling_p.h"
59 #include "qv4executableallocator_p.h"
60 #include "qv4sequenceobject_p.h"
61 #include "qv4qobjectwrapper_p.h"
62 #include "qv4memberdata_p.h"
63 #include "qv4arraybuffer_p.h"
64 #include "qv4dataview_p.h"
65 #include "qv4typedarray_p.h"
66 #include <private/qv8engine_p.h>
67 #include <private/qjsvalue_p.h>
68 #include <private/qqmlcontextwrapper_p.h>
69 #include <private/qqmltypewrapper_p.h>
70 #include <private/qqmlvaluetypewrapper_p.h>
71 #include <private/qqmlvaluetype_p.h>
72 #include <private/qqmllistwrapper_p.h>
73 #include <private/qqmllist_p.h>
74 #include <private/qqmllocale_p.h>
75
76 #include <QtCore/QTextStream>
77 #include <QDateTime>
78
79 #ifdef V4_ENABLE_JIT
80 #include "qv4isel_masm_p.h"
81 #endif // V4_ENABLE_JIT
82
83 #include "qv4isel_moth_p.h"
84
85 #if USE(PTHREADS)
86 #  include <pthread.h>
87 #  include <sys/resource.h>
88 #if HAVE(PTHREAD_NP_H)
89 #  include <pthread_np.h>
90 #endif
91 #endif
92
93 #ifdef V4_USE_VALGRIND
94 #include <valgrind/memcheck.h>
95 #endif
96
97 QT_BEGIN_NAMESPACE
98
99 using namespace QV4;
100
101 static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1);
102
103 static ReturnedValue throwTypeError(CallContext *ctx)
104 {
105     return ctx->engine()->throwTypeError();
106 }
107
108 const int MinimumStackSize = 256; // in kbytes
109
110 QT_WARNING_PUSH
111 QT_WARNING_DISABLE_MSVC(4172) // MSVC 2015: warning C4172: returning address of local variable or temporary: dummy
112
113 quintptr getStackLimit()
114 {
115     quintptr stackLimit;
116 #if USE(PTHREADS) && !OS(QNX)
117 #  if OS(DARWIN)
118     pthread_t thread_self = pthread_self();
119     void *stackTop = pthread_get_stackaddr_np(thread_self);
120     stackLimit = reinterpret_cast<quintptr>(stackTop);
121     quintptr size = 0;
122     if (pthread_main_np()) {
123         rlimit limit;
124         getrlimit(RLIMIT_STACK, &limit);
125         size = limit.rlim_cur;
126     } else
127         size = pthread_get_stacksize_np(thread_self);
128     stackLimit -= size;
129 #  elif defined(__hppa)
130     // On some architectures the stack grows upwards. All of these are rather exotic, so simply assume
131     // everything is fine there.
132     // Known examples:
133     // -HP PA-RISC
134     stackLimit = 0;
135
136 #  else
137     pthread_attr_t attr;
138 #if HAVE(PTHREAD_NP_H) && OS(FREEBSD)
139     // on FreeBSD pthread_attr_init() must be called otherwise getting the attrs crashes
140     if (pthread_attr_init(&attr) == 0 && pthread_attr_get_np(pthread_self(), &attr) == 0) {
141 #else
142     if (pthread_getattr_np(pthread_self(), &attr) == 0) {
143 #endif
144         void *stackBottom = Q_NULLPTR;
145         size_t stackSize = 0;
146
147         pthread_attr_getstack(&attr, &stackBottom, &stackSize);
148         pthread_attr_destroy(&attr);
149
150 #        if defined(Q_OS_ANDROID)
151         // Bionic pretends that the main thread has a tiny stack; work around it
152         if (gettid() == getpid()) {
153             rlimit limit;
154             getrlimit(RLIMIT_STACK, &limit);
155             stackBottom = reinterpret_cast<void*>(reinterpret_cast<quintptr>(stackBottom) + stackSize - limit.rlim_cur);
156         }
157 #       endif
158
159         stackLimit = reinterpret_cast<quintptr>(stackBottom);
160     } else {
161         int dummy;
162         // this is inexact, as part of the stack is used when being called here,
163         // but let's simply default to 1MB from where the stack is right now
164         stackLimit = reinterpret_cast<qintptr>(&dummy) - 1024*1024;
165     }
166
167 #  endif
168 // This is wrong. StackLimit is the currently committed stack size, not the real end.
169 // only way to get that limit is apparently by using VirtualQuery (Yuck)
170 //#elif OS(WINDOWS)
171 //    PNT_TIB tib = (PNT_TIB)NtCurrentTeb();
172 //    stackLimit = static_cast<quintptr>(tib->StackLimit);
173 #else
174     int dummy;
175     // this is inexact, as part of the stack is used when being called here,
176     // but let's simply default to 1MB from where the stack is right now
177     // (Note: triggers warning C4172 as of MSVC 2015, returning address of local variable)
178     stackLimit = reinterpret_cast<qintptr>(&dummy) - 1024*1024;
179 #endif
180
181     // 256k slack
182     return stackLimit + MinimumStackSize*1024;
183 }
184
185 QT_WARNING_POP
186
187 QJSEngine *ExecutionEngine::jsEngine() const
188 {
189     return v8Engine->publicEngine();
190 }
191
192 QQmlEngine *ExecutionEngine::qmlEngine() const
193 {
194     return v8Engine->engine();
195 }
196
197 ExecutionEngine::ExecutionEngine(EvalISelFactory *factory)
198     : current(0)
199     , hasException(false)
200     , memoryManager(new QV4::MemoryManager(this))
201     , executableAllocator(new QV4::ExecutableAllocator)
202     , regExpAllocator(new QV4::ExecutableAllocator)
203     , bumperPointerAllocator(new WTF::BumpPointerAllocator)
204     , jsStack(new WTF::PageAllocation)
205     , debugger(0)
206     , profiler(0)
207     , globalCode(0)
208     , v8Engine(0)
209     , argumentsAccessors(0)
210     , nArgumentsAccessors(0)
211     , m_engineId(engineSerial.fetchAndAddOrdered(1))
212     , regExpCache(0)
213     , m_multiplyWrappedQObjects(0)
214 {
215     MemoryManager::GCBlocker gcBlocker(memoryManager);
216
217     if (!factory) {
218
219 #ifdef V4_ENABLE_JIT
220         static const bool forceMoth = !qgetenv("QV4_FORCE_INTERPRETER").isEmpty();
221         if (forceMoth)
222             factory = new Moth::ISelFactory;
223         else
224             factory = new JIT::ISelFactory;
225 #else // !V4_ENABLE_JIT
226         factory = new Moth::ISelFactory;
227 #endif // V4_ENABLE_JIT
228     }
229     iselFactory.reset(factory);
230
231     // reserve space for the JS stack
232     // we allow it to grow to 2 times JSStackLimit, as we can overshoot due to garbage collection
233     // and ScopedValues allocated outside of JIT'ed methods.
234     *jsStack = WTF::PageAllocation::allocate(2 * JSStackLimit, WTF::OSAllocator::JSVMStackPages,
235                                              /* writable */ true, /* executable */ false,
236                                              /* includesGuardPages */ true);
237     jsStackBase = (Value *)jsStack->base();
238     jsStackTop = jsStackBase;
239
240     exceptionValue = jsAlloca(1);
241     globalObject = static_cast<Object *>(jsAlloca(1));
242     jsObjects = jsAlloca(NJSObjects);
243     typedArrayPrototype = static_cast<Object *>(jsAlloca(NTypedArrayTypes));
244     typedArrayCtors = static_cast<FunctionObject *>(jsAlloca(NTypedArrayTypes));
245     jsStrings = jsAlloca(NJSStrings);
246
247 #ifdef V4_USE_VALGRIND
248     VALGRIND_MAKE_MEM_UNDEFINED(jsStackBase, 2*JSStackLimit);
249 #endif
250
251     // set up stack limits
252     jsStackLimit = jsStackBase + JSStackLimit/sizeof(Value);
253     cStackLimit = getStackLimit();
254     if (!recheckCStackLimits())
255         qFatal("Fatal: Not enough stack space available for QML. Please increase the process stack size to more than %d KBytes.", MinimumStackSize);
256
257     identifierTable = new IdentifierTable(this);
258
259     classPool = new InternalClassPool;
260
261     emptyClass =  new (classPool) InternalClass(this);
262
263     jsStrings[String_Empty] = newIdentifier(QString());
264     jsStrings[String_undefined] = newIdentifier(QStringLiteral("undefined"));
265     jsStrings[String_null] = newIdentifier(QStringLiteral("null"));
266     jsStrings[String_true] = newIdentifier(QStringLiteral("true"));
267     jsStrings[String_false] = newIdentifier(QStringLiteral("false"));
268     jsStrings[String_boolean] = newIdentifier(QStringLiteral("boolean"));
269     jsStrings[String_number] = newIdentifier(QStringLiteral("number"));
270     jsStrings[String_string] = newIdentifier(QStringLiteral("string"));
271     jsStrings[String_object] = newIdentifier(QStringLiteral("object"));
272     jsStrings[String_function] = newIdentifier(QStringLiteral("function"));
273     jsStrings[String_length] = newIdentifier(QStringLiteral("length"));
274     jsStrings[String_prototype] = newIdentifier(QStringLiteral("prototype"));
275     jsStrings[String_constructor] = newIdentifier(QStringLiteral("constructor"));
276     jsStrings[String_arguments] = newIdentifier(QStringLiteral("arguments"));
277     jsStrings[String_caller] = newIdentifier(QStringLiteral("caller"));
278     jsStrings[String_callee] = newIdentifier(QStringLiteral("callee"));
279     jsStrings[String_this] = newIdentifier(QStringLiteral("this"));
280     jsStrings[String___proto__] = newIdentifier(QStringLiteral("__proto__"));
281     jsStrings[String_enumerable] = newIdentifier(QStringLiteral("enumerable"));
282     jsStrings[String_configurable] = newIdentifier(QStringLiteral("configurable"));
283     jsStrings[String_writable] = newIdentifier(QStringLiteral("writable"));
284     jsStrings[String_value] = newIdentifier(QStringLiteral("value"));
285     jsStrings[String_get] = newIdentifier(QStringLiteral("get"));
286     jsStrings[String_set] = newIdentifier(QStringLiteral("set"));
287     jsStrings[String_eval] = newIdentifier(QStringLiteral("eval"));
288     jsStrings[String_uintMax] = newIdentifier(QStringLiteral("4294967295"));
289     jsStrings[String_name] = newIdentifier(QStringLiteral("name"));
290     jsStrings[String_index] = newIdentifier(QStringLiteral("index"));
291     jsStrings[String_input] = newIdentifier(QStringLiteral("input"));
292     jsStrings[String_toString] = newIdentifier(QStringLiteral("toString"));
293     jsStrings[String_destroy] = newIdentifier(QStringLiteral("destroy"));
294     jsStrings[String_valueOf] = newIdentifier(QStringLiteral("valueOf"));
295     jsStrings[String_byteLength] = newIdentifier(QStringLiteral("byteLength"));
296     jsStrings[String_byteOffset] = newIdentifier(QStringLiteral("byteOffset"));
297     jsStrings[String_buffer] = newIdentifier(QStringLiteral("buffer"));
298     jsStrings[String_lastIndex] = newIdentifier(QStringLiteral("lastIndex"));
299
300     jsObjects[ObjectProto] = memoryManager->alloc<ObjectPrototype>(emptyClass, (QV4::Object *)0);
301
302     arrayClass = emptyClass->addMember(id_length(), Attr_NotConfigurable|Attr_NotEnumerable);
303     jsObjects[ArrayProto] = memoryManager->alloc<ArrayPrototype>(arrayClass, objectPrototype());
304
305     InternalClass *argsClass = emptyClass->addMember(id_length(), Attr_NotEnumerable);
306     argumentsObjectClass = argsClass->addMember(id_callee(), Attr_Data|Attr_NotEnumerable);
307     strictArgumentsObjectClass = argsClass->addMember(id_callee(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
308     strictArgumentsObjectClass = strictArgumentsObjectClass->addMember(id_caller(), Attr_Accessor|Attr_NotConfigurable|Attr_NotEnumerable);
309
310     *static_cast<Value *>(globalObject) = newObject();
311     Q_ASSERT(globalObject->d()->vtable());
312     initRootContext();
313
314     jsObjects[StringProto] = memoryManager->alloc<StringPrototype>(emptyClass, objectPrototype());
315     jsObjects[NumberProto] = memoryManager->alloc<NumberPrototype>(emptyClass, objectPrototype());
316     jsObjects[BooleanProto] = memoryManager->alloc<BooleanPrototype>(emptyClass, objectPrototype());
317     jsObjects[DateProto] = memoryManager->alloc<DatePrototype>(emptyClass, objectPrototype());
318
319     uint index;
320     InternalClass *functionProtoClass = emptyClass->addMember(id_prototype(), Attr_NotEnumerable, &index);
321     Q_ASSERT(index == Heap::FunctionObject::Index_Prototype);
322     jsObjects[FunctionProto] = memoryManager->alloc<FunctionPrototype>(functionProtoClass, objectPrototype());
323     functionClass = emptyClass->addMember(id_prototype(), Attr_NotEnumerable|Attr_NotConfigurable, &index);
324     Q_ASSERT(index == Heap::FunctionObject::Index_Prototype);
325     simpleScriptFunctionClass = functionClass->addMember(id_name(), Attr_ReadOnly, &index);
326     Q_ASSERT(index == Heap::SimpleScriptFunction::Index_Name);
327     simpleScriptFunctionClass = simpleScriptFunctionClass->addMember(id_length(), Attr_ReadOnly, &index);
328     Q_ASSERT(index == Heap::SimpleScriptFunction::Index_Length);
329     protoClass = emptyClass->addMember(id_constructor(), Attr_NotEnumerable, &index);
330     Q_ASSERT(index == Heap::FunctionObject::Index_ProtoConstructor);
331
332     jsObjects[RegExpProto] = memoryManager->alloc<RegExpPrototype>(this);
333     regExpExecArrayClass = arrayClass->addMember(id_index(), Attr_Data, &index);
334     Q_ASSERT(index == RegExpObject::Index_ArrayIndex);
335     regExpExecArrayClass = regExpExecArrayClass->addMember(id_input(), Attr_Data, &index);
336     Q_ASSERT(index == RegExpObject::Index_ArrayInput);
337
338     jsObjects[ErrorProto] = memoryManager->alloc<ErrorPrototype>(emptyClass, objectPrototype());
339     jsObjects[EvalErrorProto] = memoryManager->alloc<EvalErrorPrototype>(emptyClass, errorPrototype());
340     jsObjects[RangeErrorProto] = memoryManager->alloc<RangeErrorPrototype>(emptyClass, errorPrototype());
341     jsObjects[ReferenceErrorProto] = memoryManager->alloc<ReferenceErrorPrototype>(emptyClass, errorPrototype());
342     jsObjects[SyntaxErrorProto] = memoryManager->alloc<SyntaxErrorPrototype>(emptyClass, errorPrototype());
343     jsObjects[TypeErrorProto] = memoryManager->alloc<TypeErrorPrototype>(emptyClass, errorPrototype());
344     jsObjects[URIErrorProto] = memoryManager->alloc<URIErrorPrototype>(emptyClass, errorPrototype());
345
346     jsObjects[VariantProto] = memoryManager->alloc<VariantPrototype>(emptyClass, objectPrototype());
347     Q_ASSERT(variantPrototype()->prototype() == objectPrototype()->d());
348
349     Scope scope(this);
350     jsObjects[SequenceProto] = ScopedValue(scope, memoryManager->alloc<SequencePrototype>(arrayClass, arrayPrototype()));
351
352     ScopedContext global(scope, rootContext());
353     jsObjects[Object_Ctor] = memoryManager->alloc<ObjectCtor>(global);
354     jsObjects[String_Ctor] = memoryManager->alloc<StringCtor>(global);
355     jsObjects[Number_Ctor] = memoryManager->alloc<NumberCtor>(global);
356     jsObjects[Boolean_Ctor] = memoryManager->alloc<BooleanCtor>(global);
357     jsObjects[Array_Ctor] = memoryManager->alloc<ArrayCtor>(global);
358     jsObjects[Function_Ctor] = memoryManager->alloc<FunctionCtor>(global);
359     jsObjects[Date_Ctor] = memoryManager->alloc<DateCtor>(global);
360     jsObjects[RegExp_Ctor] = memoryManager->alloc<RegExpCtor>(global);
361     jsObjects[Error_Ctor] = memoryManager->alloc<ErrorCtor>(global);
362     jsObjects[EvalError_Ctor] = memoryManager->alloc<EvalErrorCtor>(global);
363     jsObjects[RangeError_Ctor] = memoryManager->alloc<RangeErrorCtor>(global);
364     jsObjects[ReferenceError_Ctor] = memoryManager->alloc<ReferenceErrorCtor>(global);
365     jsObjects[SyntaxError_Ctor] = memoryManager->alloc<SyntaxErrorCtor>(global);
366     jsObjects[TypeError_Ctor] = memoryManager->alloc<TypeErrorCtor>(global);
367     jsObjects[URIError_Ctor] = memoryManager->alloc<URIErrorCtor>(global);
368
369     static_cast<ObjectPrototype *>(objectPrototype())->init(this, objectCtor());
370     static_cast<StringPrototype *>(stringPrototype())->init(this, stringCtor());
371     static_cast<NumberPrototype *>(numberPrototype())->init(this, numberCtor());
372     static_cast<BooleanPrototype *>(booleanPrototype())->init(this, booleanCtor());
373     static_cast<ArrayPrototype *>(arrayPrototype())->init(this, arrayCtor());
374     static_cast<DatePrototype *>(datePrototype())->init(this, dateCtor());
375     static_cast<FunctionPrototype *>(functionPrototype())->init(this, functionCtor());
376     static_cast<RegExpPrototype *>(regExpPrototype())->init(this, regExpCtor());
377     static_cast<ErrorPrototype *>(errorPrototype())->init(this, errorCtor());
378     static_cast<EvalErrorPrototype *>(evalErrorPrototype())->init(this, evalErrorCtor());
379     static_cast<RangeErrorPrototype *>(rangeErrorPrototype())->init(this, rangeErrorCtor());
380     static_cast<ReferenceErrorPrototype *>(referenceErrorPrototype())->init(this, referenceErrorCtor());
381     static_cast<SyntaxErrorPrototype *>(syntaxErrorPrototype())->init(this, syntaxErrorCtor());
382     static_cast<TypeErrorPrototype *>(typeErrorPrototype())->init(this, typeErrorCtor());
383     static_cast<URIErrorPrototype *>(uRIErrorPrototype())->init(this, uRIErrorCtor());
384
385     static_cast<VariantPrototype *>(variantPrototype())->init();
386     sequencePrototype()->cast<SequencePrototype>()->init();
387
388
389     // typed arrays
390
391     jsObjects[ArrayBuffer_Ctor] = memoryManager->alloc<ArrayBufferCtor>(global);
392     jsObjects[ArrayBufferProto] = memoryManager->alloc<ArrayBufferPrototype>(emptyClass, objectPrototype());
393     static_cast<ArrayBufferPrototype *>(arrayBufferPrototype())->init(this, arrayBufferCtor());
394
395     jsObjects[DataView_Ctor] = memoryManager->alloc<DataViewCtor>(global);
396     jsObjects[DataViewProto] = memoryManager->alloc<DataViewPrototype>(emptyClass, objectPrototype());
397     static_cast<DataViewPrototype *>(dataViewPrototype())->init(this, dataViewCtor());
398     jsObjects[ValueTypeProto] = (Heap::Base *) 0;
399
400     for (int i = 0; i < Heap::TypedArray::NTypes; ++i) {
401         static_cast<Value &>(typedArrayCtors[i]) = memoryManager->alloc<TypedArrayCtor>(global, Heap::TypedArray::Type(i));
402         static_cast<Value &>(typedArrayPrototype[i]) = memoryManager->alloc<TypedArrayPrototype>(this, Heap::TypedArray::Type(i));
403         typedArrayPrototype[i].as<TypedArrayPrototype>()->init(this, static_cast<TypedArrayCtor *>(typedArrayCtors[i].as<Object>()));
404     }
405
406     //
407     // set up the global object
408     //
409     rootContext()->d()->global = globalObject->d();
410     rootContext()->d()->callData->thisObject = globalObject;
411     Q_ASSERT(globalObject->d()->vtable());
412
413     globalObject->defineDefaultProperty(QStringLiteral("Object"), *objectCtor());
414     globalObject->defineDefaultProperty(QStringLiteral("String"), *stringCtor());
415     globalObject->defineDefaultProperty(QStringLiteral("Number"), *numberCtor());
416     globalObject->defineDefaultProperty(QStringLiteral("Boolean"), *booleanCtor());
417     globalObject->defineDefaultProperty(QStringLiteral("Array"), *arrayCtor());
418     globalObject->defineDefaultProperty(QStringLiteral("Function"), *functionCtor());
419     globalObject->defineDefaultProperty(QStringLiteral("Date"), *dateCtor());
420     globalObject->defineDefaultProperty(QStringLiteral("RegExp"), *regExpCtor());
421     globalObject->defineDefaultProperty(QStringLiteral("Error"), *errorCtor());
422     globalObject->defineDefaultProperty(QStringLiteral("EvalError"), *evalErrorCtor());
423     globalObject->defineDefaultProperty(QStringLiteral("RangeError"), *rangeErrorCtor());
424     globalObject->defineDefaultProperty(QStringLiteral("ReferenceError"), *referenceErrorCtor());
425     globalObject->defineDefaultProperty(QStringLiteral("SyntaxError"), *syntaxErrorCtor());
426     globalObject->defineDefaultProperty(QStringLiteral("TypeError"), *typeErrorCtor());
427     globalObject->defineDefaultProperty(QStringLiteral("URIError"), *uRIErrorCtor());
428
429     globalObject->defineDefaultProperty(QStringLiteral("ArrayBuffer"), *arrayBufferCtor());
430     globalObject->defineDefaultProperty(QStringLiteral("DataView"), *dataViewCtor());
431     ScopedString str(scope);
432     for (int i = 0; i < Heap::TypedArray::NTypes; ++i)
433         globalObject->defineDefaultProperty((str = typedArrayCtors[i].as<FunctionObject>()->name())->toQString(), typedArrayCtors[i]);
434     ScopedObject o(scope);
435     globalObject->defineDefaultProperty(QStringLiteral("Math"), (o = memoryManager->alloc<MathObject>(this)));
436     globalObject->defineDefaultProperty(QStringLiteral("JSON"), (o = memoryManager->alloc<JsonObject>(this)));
437
438     globalObject->defineReadonlyProperty(QStringLiteral("undefined"), Primitive::undefinedValue());
439     globalObject->defineReadonlyProperty(QStringLiteral("NaN"), Primitive::fromDouble(std::numeric_limits<double>::quiet_NaN()));
440     globalObject->defineReadonlyProperty(QStringLiteral("Infinity"), Primitive::fromDouble(Q_INFINITY));
441
442
443     jsObjects[Eval_Function] = memoryManager->alloc<EvalFunction>(global);
444     globalObject->defineDefaultProperty(QStringLiteral("eval"), *evalFunction());
445
446     globalObject->defineDefaultProperty(QStringLiteral("parseInt"), GlobalFunctions::method_parseInt, 2);
447     globalObject->defineDefaultProperty(QStringLiteral("parseFloat"), GlobalFunctions::method_parseFloat, 1);
448     globalObject->defineDefaultProperty(QStringLiteral("isNaN"), GlobalFunctions::method_isNaN, 1);
449     globalObject->defineDefaultProperty(QStringLiteral("isFinite"), GlobalFunctions::method_isFinite, 1);
450     globalObject->defineDefaultProperty(QStringLiteral("decodeURI"), GlobalFunctions::method_decodeURI, 1);
451     globalObject->defineDefaultProperty(QStringLiteral("decodeURIComponent"), GlobalFunctions::method_decodeURIComponent, 1);
452     globalObject->defineDefaultProperty(QStringLiteral("encodeURI"), GlobalFunctions::method_encodeURI, 1);
453     globalObject->defineDefaultProperty(QStringLiteral("encodeURIComponent"), GlobalFunctions::method_encodeURIComponent, 1);
454     globalObject->defineDefaultProperty(QStringLiteral("escape"), GlobalFunctions::method_escape, 1);
455     globalObject->defineDefaultProperty(QStringLiteral("unescape"), GlobalFunctions::method_unescape, 1);
456
457     ScopedString name(scope, newString(QStringLiteral("thrower")));
458     jsObjects[ThrowerObject] = BuiltinFunction::create(global, name, ::throwTypeError);
459 }
460
461 ExecutionEngine::~ExecutionEngine()
462 {
463     delete debugger;
464     debugger = 0;
465     delete profiler;
466     profiler = 0;
467     delete m_multiplyWrappedQObjects;
468     m_multiplyWrappedQObjects = 0;
469     delete identifierTable;
470     delete memoryManager;
471
472     QSet<QV4::CompiledData::CompilationUnit*> remainingUnits;
473     qSwap(compilationUnits, remainingUnits);
474     foreach (QV4::CompiledData::CompilationUnit *unit, remainingUnits)
475         unit->unlink();
476
477     emptyClass->destroy();
478     delete classPool;
479     delete bumperPointerAllocator;
480     delete regExpCache;
481     delete regExpAllocator;
482     delete executableAllocator;
483     jsStack->deallocate();
484     delete jsStack;
485     delete [] argumentsAccessors;
486 }
487
488 void ExecutionEngine::enableDebugger()
489 {
490     Q_ASSERT(!debugger);
491     debugger = new Debugging::Debugger(this);
492     iselFactory.reset(new Moth::ISelFactory);
493 }
494
495 void ExecutionEngine::enableProfiler()
496 {
497     Q_ASSERT(!profiler);
498     profiler = new QV4::Profiling::Profiler(this);
499 }
500
501 void ExecutionEngine::initRootContext()
502 {
503     Scope scope(this);
504     Scoped<GlobalContext> r(scope, memoryManager->allocManaged<GlobalContext>(sizeof(GlobalContext::Data) + sizeof(CallData)));
505     new (r->d()) GlobalContext::Data(this);
506     r->d()->callData = reinterpret_cast<CallData *>(r->d() + 1);
507     r->d()->callData->tag = QV4::Value::_Integer_Type;
508     r->d()->callData->argc = 0;
509     r->d()->callData->thisObject = globalObject;
510     r->d()->callData->args[0] = Encode::undefined();
511
512     jsObjects[RootContect] = r;
513 }
514
515 InternalClass *ExecutionEngine::newClass(const InternalClass &other)
516 {
517     return new (classPool) InternalClass(other);
518 }
519
520 Heap::ExecutionContext *ExecutionEngine::pushGlobalContext()
521 {
522     Scope scope(this);
523     Scoped<GlobalContext> g(scope, memoryManager->alloc<GlobalContext>(this));
524     g->d()->callData = rootContext()->d()->callData;
525
526     Q_ASSERT(currentContext() == g->d());
527     return g->d();
528 }
529
530
531 Heap::Object *ExecutionEngine::newObject()
532 {
533     Scope scope(this);
534     ScopedObject object(scope, memoryManager->alloc<Object>(this));
535     return object->d();
536 }
537
538 Heap::Object *ExecutionEngine::newObject(InternalClass *internalClass, QV4::Object *prototype)
539 {
540     Scope scope(this);
541     ScopedObject object(scope, memoryManager->alloc<Object>(internalClass, prototype));
542     return object->d();
543 }
544
545 Heap::String *ExecutionEngine::newString(const QString &s)
546 {
547     Scope scope(this);
548     return ScopedString(scope, memoryManager->allocWithStringData<String>(s.length() * sizeof(QChar), s))->d();
549 }
550
551 Heap::String *ExecutionEngine::newIdentifier(const QString &text)
552 {
553     return identifierTable->insertString(text);
554 }
555
556 Heap::Object *ExecutionEngine::newStringObject(const String *string)
557 {
558     Scope scope(this);
559     Scoped<StringObject> object(scope, memoryManager->alloc<StringObject>(this, string));
560     return object->d();
561 }
562
563 Heap::Object *ExecutionEngine::newNumberObject(double value)
564 {
565     Scope scope(this);
566     Scoped<NumberObject> object(scope, memoryManager->alloc<NumberObject>(this, value));
567     return object->d();
568 }
569
570 Heap::Object *ExecutionEngine::newBooleanObject(bool b)
571 {
572     Scope scope(this);
573     ScopedObject object(scope, memoryManager->alloc<BooleanObject>(this, b));
574     return object->d();
575 }
576
577 Heap::ArrayObject *ExecutionEngine::newArrayObject(int count)
578 {
579     Scope scope(this);
580     ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(this));
581
582     if (count) {
583         if (count < 0x1000)
584             object->arrayReserve(count);
585         object->setArrayLengthUnchecked(count);
586     }
587     return object->d();
588 }
589
590 Heap::ArrayObject *ExecutionEngine::newArrayObject(const QStringList &list)
591 {
592     Scope scope(this);
593     ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(this, list));
594     return object->d();
595 }
596
597 Heap::ArrayObject *ExecutionEngine::newArrayObject(InternalClass *ic, Object *prototype)
598 {
599     Scope scope(this);
600     ScopedArrayObject object(scope, memoryManager->alloc<ArrayObject>(ic, prototype));
601     return object->d();
602 }
603
604 Heap::ArrayBuffer *ExecutionEngine::newArrayBuffer(const QByteArray &array)
605 {
606     Scope scope(this);
607     Scoped<ArrayBuffer> object(scope, memoryManager->alloc<ArrayBuffer>(this, array));
608     return object->d();
609 }
610
611
612 Heap::DateObject *ExecutionEngine::newDateObject(const Value &value)
613 {
614     Scope scope(this);
615     Scoped<DateObject> object(scope, memoryManager->alloc<DateObject>(this, value));
616     return object->d();
617 }
618
619 Heap::DateObject *ExecutionEngine::newDateObject(const QDateTime &dt)
620 {
621     Scope scope(this);
622     Scoped<DateObject> object(scope, memoryManager->alloc<DateObject>(this, dt));
623     return object->d();
624 }
625
626 Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QString &pattern, int flags)
627 {
628     bool global = (flags & IR::RegExp::RegExp_Global);
629     bool ignoreCase = false;
630     bool multiline = false;
631     if (flags & IR::RegExp::RegExp_IgnoreCase)
632         ignoreCase = true;
633     if (flags & IR::RegExp::RegExp_Multiline)
634         multiline = true;
635
636     Scope scope(this);
637     Scoped<RegExp> re(scope, RegExp::create(this, pattern, ignoreCase, multiline));
638     return newRegExpObject(re, global);
639 }
640
641 Heap::RegExpObject *ExecutionEngine::newRegExpObject(RegExp *re, bool global)
642 {
643     Scope scope(this);
644     Scoped<RegExpObject> object(scope, memoryManager->alloc<RegExpObject>(this, re, global));
645     return object->d();
646 }
647
648 Heap::RegExpObject *ExecutionEngine::newRegExpObject(const QRegExp &re)
649 {
650     Scope scope(this);
651     Scoped<RegExpObject> object(scope, memoryManager->alloc<RegExpObject>(this, re));
652     return object->d();
653 }
654
655 Heap::Object *ExecutionEngine::newErrorObject(const Value &value)
656 {
657     Scope scope(this);
658     ScopedObject object(scope, memoryManager->alloc<ErrorObject>(emptyClass, errorPrototype(), value));
659     return object->d();
660 }
661
662 Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message)
663 {
664     Scope scope(this);
665     ScopedString s(scope, newString(message));
666     ScopedObject error(scope, memoryManager->alloc<SyntaxErrorObject>(this, s));
667     return error->d();
668 }
669
670 Heap::Object *ExecutionEngine::newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column)
671 {
672     Scope scope(this);
673     ScopedObject error(scope, memoryManager->alloc<SyntaxErrorObject>(this, message, fileName, line, column));
674     return error->d();
675 }
676
677
678 Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message)
679 {
680     Scope scope(this);
681     ScopedObject o(scope, memoryManager->alloc<ReferenceErrorObject>(this, message));
682     return o->d();
683 }
684
685 Heap::Object *ExecutionEngine::newReferenceErrorObject(const QString &message, const QString &fileName, int lineNumber, int columnNumber)
686 {
687     Scope scope(this);
688     ScopedObject o(scope, memoryManager->alloc<ReferenceErrorObject>(this, message, fileName, lineNumber, columnNumber));
689     return o->d();
690 }
691
692
693 Heap::Object *ExecutionEngine::newTypeErrorObject(const QString &message)
694 {
695     Scope scope(this);
696     ScopedObject o(scope, memoryManager->alloc<TypeErrorObject>(this, message));
697     return o->d();
698 }
699
700 Heap::Object *ExecutionEngine::newRangeErrorObject(const QString &message)
701 {
702     Scope scope(this);
703     ScopedObject o(scope, memoryManager->alloc<RangeErrorObject>(this, message));
704     return o->d();
705 }
706
707 Heap::Object *ExecutionEngine::newURIErrorObject(const Value &message)
708 {
709     Scope scope(this);
710     ScopedObject o(scope, memoryManager->alloc<URIErrorObject>(this, message));
711     return o->d();
712 }
713
714 Heap::Object *ExecutionEngine::newVariantObject(const QVariant &v)
715 {
716     Scope scope(this);
717     ScopedObject o(scope, memoryManager->alloc<VariantObject>(this, v));
718     return o->d();
719 }
720
721 Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o)
722 {
723     Scope scope(this);
724     ScopedObject obj(scope, memoryManager->alloc<ForEachIteratorObject>(this, o));
725     return obj->d();
726 }
727
728 Heap::QmlContext *ExecutionEngine::qmlContext() const
729 {
730     Heap::ExecutionContext *ctx = currentContext();
731
732     if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer)
733         ctx = ctx->parent;
734
735     if (!ctx->outer)
736         return 0;
737
738     while (ctx->outer && ctx->outer->type != Heap::ExecutionContext::Type_GlobalContext)
739         ctx = ctx->outer;
740
741     Q_ASSERT(ctx);
742     if (ctx->type != Heap::ExecutionContext::Type_QmlContext)
743         return 0;
744
745     return static_cast<Heap::QmlContext *>(ctx);
746 }
747
748 Heap::QmlContextWrapper *ExecutionEngine::qmlContextObject() const
749 {
750     Heap::QmlContext *ctx = qmlContext();
751     if (!ctx)
752         return 0;
753     Q_ASSERT(ctx->qml);
754     return ctx->qml;
755 }
756
757 QObject *ExecutionEngine::qmlScopeObject() const
758 {
759     return qmlContextObject()->scopeObject;
760 }
761
762 ReturnedValue ExecutionEngine::qmlSingletonWrapper(String *name)
763 {
764     QQmlContextData *ctx = callingQmlContext();
765     if (!ctx->imports)
766         return Encode::undefined();
767     // Search for attached properties, enums and imported scripts
768     QQmlTypeNameCache::Result r = ctx->imports->query(name);
769
770     Q_ASSERT(r.isValid());
771     Q_ASSERT(r.type);
772     Q_ASSERT(r.type->isSingleton());
773
774     QQmlType::SingletonInstanceInfo *siinfo = r.type->singletonInstanceInfo();
775     QQmlEngine *e = qmlEngine();
776     siinfo->init(e);
777
778     if (QObject *qobjectSingleton = siinfo->qobjectApi(e))
779         return QV4::QObjectWrapper::wrap(this, qobjectSingleton);
780     return QJSValuePrivate::convertedToValue(this, siinfo->scriptApi(e));
781 }
782
783 QQmlContextData *ExecutionEngine::callingQmlContext() const
784 {
785     Heap::QmlContextWrapper *w = qmlContextObject();
786
787     return w ? w->context.contextData() : 0;
788 }
789
790 QVector<StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
791 {
792     Scope scope(const_cast<ExecutionEngine *>(this));
793     ScopedString name(scope);
794     QVector<StackFrame> stack;
795
796     ScopedContext c(scope, currentContext());
797     ScopedFunctionObject function(scope);
798     while (c && frameLimit) {
799         function = c->getFunctionObject();
800         if (function) {
801             StackFrame frame;
802             if (const Function *f = function->function())
803                 frame.source = f->sourceFile();
804             name = function->name();
805             frame.function = name->toQString();
806             frame.line = -1;
807             frame.column = -1;
808
809             if (function->function())
810                 // line numbers can be negative for places where you can't set a real breakpoint
811                 frame.line = qAbs(c->d()->lineNumber);
812
813             stack.append(frame);
814             --frameLimit;
815         }
816         c = c->d()->parent;
817     }
818
819     if (frameLimit && globalCode) {
820         StackFrame frame;
821         frame.source = globalCode->sourceFile();
822         frame.function = globalCode->name()->toQString();
823         frame.line = rootContext()->d()->lineNumber;
824         frame.column = -1;
825
826         stack.append(frame);
827     }
828     return stack;
829 }
830
831 StackFrame ExecutionEngine::currentStackFrame() const
832 {
833     StackFrame frame;
834     frame.line = -1;
835     frame.column = -1;
836
837     QVector<StackFrame> trace = stackTrace(/*limit*/ 1);
838     if (!trace.isEmpty())
839         frame = trace.first();
840
841     return frame;
842 }
843
844 /* Helper and "C" linkage exported function to format a GDBMI stacktrace for
845  * invocation by a debugger.
846  * Sample GDB invocation: print qt_v4StackTrace((void*)0x7fffffffb290)
847  * Sample CDB invocation: .call Qt5Qmld!qt_v4StackTrace(0x7fffffffb290) ; gh
848  * Note: The helper is there to suppress MSVC warning 4190 about anything
849  * with UDT return types in a "C" linkage function. */
850
851 static inline char *v4StackTrace(const ExecutionContext *context)
852 {
853     QString result;
854     QTextStream str(&result);
855     str << "stack=[";
856     if (context && context->d()->engine) {
857         const QVector<StackFrame> stackTrace = context->d()->engine->stackTrace(20);
858         for (int i = 0; i < stackTrace.size(); ++i) {
859             if (i)
860                 str << ',';
861             const QUrl url(stackTrace.at(i).source);
862             const QString fileName = url.isLocalFile() ? url.toLocalFile() : url.toString();
863             str << "frame={level=\"" << i << "\",func=\"" << stackTrace.at(i).function
864                 << "\",file=\"" << fileName << "\",fullname=\"" << fileName
865                 << "\",line=\"" << stackTrace.at(i).line << "\",language=\"js\"}";
866         }
867     }
868     str << ']';
869     return qstrdup(result.toLocal8Bit().constData());
870 }
871
872 extern "C" Q_QML_EXPORT char *qt_v4StackTrace(void *executionContext)
873 {
874     return v4StackTrace(reinterpret_cast<const ExecutionContext *>(executionContext));
875 }
876
877 QUrl ExecutionEngine::resolvedUrl(const QString &file)
878 {
879     QUrl src(file);
880     if (!src.isRelative())
881         return src;
882
883     QUrl base;
884     Scope scope(this);
885     ScopedContext c(scope, currentContext());
886     while (c) {
887         CallContext *callCtx = c->asCallContext();
888         if (callCtx && callCtx->d()->function) {
889             if (callCtx->d()->function->function)
890                 base.setUrl(callCtx->d()->function->function->sourceFile());
891             break;
892         }
893         c = c->d()->parent;
894     }
895
896     if (base.isEmpty() && globalCode)
897         base.setUrl(globalCode->sourceFile());
898
899     if (base.isEmpty())
900         return src;
901
902     return base.resolved(src);
903 }
904
905 void ExecutionEngine::requireArgumentsAccessors(int n)
906 {
907     if (n <= nArgumentsAccessors)
908         return;
909
910     Scope scope(this);
911     ScopedFunctionObject get(scope);
912     ScopedFunctionObject set(scope);
913
914     if (n >= nArgumentsAccessors) {
915         Property *oldAccessors = argumentsAccessors;
916         int oldSize = nArgumentsAccessors;
917         nArgumentsAccessors = qMax(8, n);
918         argumentsAccessors = new Property[nArgumentsAccessors];
919         if (oldAccessors) {
920             memcpy(argumentsAccessors, oldAccessors, oldSize*sizeof(Property));
921             delete [] oldAccessors;
922         }
923         ScopedContext global(scope, scope.engine->rootContext());
924         for (int i = oldSize; i < nArgumentsAccessors; ++i) {
925             argumentsAccessors[i].value = ScopedValue(scope, memoryManager->alloc<ArgumentsGetterFunction>(global, i));
926             argumentsAccessors[i].set = ScopedValue(scope, memoryManager->alloc<ArgumentsSetterFunction>(global, i));
927         }
928     }
929 }
930
931 void ExecutionEngine::markObjects()
932 {
933     identifierTable->mark(this);
934
935     for (int i = 0; i < nArgumentsAccessors; ++i) {
936         const Property &pd = argumentsAccessors[i];
937         if (Heap::FunctionObject *getter = pd.getter())
938             getter->mark(this);
939         if (Heap::FunctionObject *setter = pd.setter())
940             setter->mark(this);
941     }
942
943     Heap::ExecutionContext *c = currentContext();
944     while (c) {
945         Q_ASSERT(c->inUse());
946         if (!c->isMarked()) {
947             c->setMarkBit();
948             c->vtable()->markObjects(c, this);
949         }
950         c = c->parent;
951     }
952
953     classPool->markObjects(this);
954
955     for (QSet<CompiledData::CompilationUnit*>::ConstIterator it = compilationUnits.constBegin(), end = compilationUnits.constEnd();
956          it != end; ++it)
957         (*it)->markObjects(this);
958 }
959
960 ReturnedValue ExecutionEngine::throwError(const Value &value)
961 {
962     // we can get in here with an exception already set, as the runtime
963     // doesn't check after every operation that can throw.
964     // in this case preserve the first exception to give correct error
965     // information
966     if (hasException)
967         return Encode::undefined();
968
969     hasException = true;
970     *exceptionValue = value;
971     QV4::Scope scope(this);
972     QV4::Scoped<ErrorObject> error(scope, value);
973     if (!!error)
974         exceptionStackTrace = error->d()->stackTrace;
975     else
976         exceptionStackTrace = stackTrace();
977
978     if (debugger)
979         debugger->aboutToThrow();
980
981     return Encode::undefined();
982 }
983
984 ReturnedValue ExecutionEngine::catchException(StackTrace *trace)
985 {
986     Q_ASSERT(hasException);
987     if (trace)
988         *trace = exceptionStackTrace;
989     exceptionStackTrace.clear();
990     hasException = false;
991     ReturnedValue res = exceptionValue->asReturnedValue();
992     *exceptionValue = Primitive::emptyValue();
993     return res;
994 }
995
996 ReturnedValue ExecutionEngine::throwError(const QString &message)
997 {
998     Scope scope(this);
999     ScopedValue v(scope, newString(message));
1000     v = newErrorObject(v);
1001     return throwError(v);
1002 }
1003
1004 ReturnedValue ExecutionEngine::throwSyntaxError(const QString &message, const QString &fileName, int line, int column)
1005 {
1006     Scope scope(this);
1007     ScopedObject error(scope, newSyntaxErrorObject(message, fileName, line, column));
1008     return throwError(error);
1009 }
1010
1011 ReturnedValue ExecutionEngine::throwSyntaxError(const QString &message)
1012 {
1013     Scope scope(this);
1014     ScopedObject error(scope, newSyntaxErrorObject(message));
1015     return throwError(error);
1016 }
1017
1018
1019 ReturnedValue ExecutionEngine::throwTypeError()
1020 {
1021     Scope scope(this);
1022     ScopedObject error(scope, newTypeErrorObject(QStringLiteral("Type error")));
1023     return throwError(error);
1024 }
1025
1026 ReturnedValue ExecutionEngine::throwTypeError(const QString &message)
1027 {
1028     Scope scope(this);
1029     ScopedObject error(scope, newTypeErrorObject(message));
1030     return throwError(error);
1031 }
1032
1033 ReturnedValue ExecutionEngine::throwReferenceError(const Value &value)
1034 {
1035     Scope scope(this);
1036     ScopedString s(scope, value.toString(this));
1037     QString msg = s->toQString() + QStringLiteral(" is not defined");
1038     ScopedObject error(scope, newReferenceErrorObject(msg));
1039     return throwError(error);
1040 }
1041
1042 ReturnedValue ExecutionEngine::throwReferenceError(const QString &message, const QString &fileName, int line, int column)
1043 {
1044     Scope scope(this);
1045     QString msg = message;
1046     ScopedObject error(scope, newReferenceErrorObject(msg, fileName, line, column));
1047     return throwError(error);
1048 }
1049
1050 ReturnedValue ExecutionEngine::throwRangeError(const QString &message)
1051 {
1052     Scope scope(this);
1053     ScopedObject error(scope, newRangeErrorObject(message));
1054     return throwError(error);
1055 }
1056
1057 ReturnedValue ExecutionEngine::throwRangeError(const Value &value)
1058 {
1059     Scope scope(this);
1060     ScopedString s(scope, value.toString(this));
1061     QString msg = s->toQString() + QStringLiteral(" out of range");
1062     ScopedObject error(scope, newRangeErrorObject(msg));
1063     return throwError(error);
1064 }
1065
1066 ReturnedValue ExecutionEngine::throwURIError(const Value &msg)
1067 {
1068     Scope scope(this);
1069     ScopedObject error(scope, newURIErrorObject(msg));
1070     return throwError(error);
1071 }
1072
1073 ReturnedValue ExecutionEngine::throwUnimplemented(const QString &message)
1074 {
1075     Scope scope(this);
1076     ScopedValue v(scope, newString(QStringLiteral("Unimplemented ") + message));
1077     v = newErrorObject(v);
1078     return throwError(v);
1079 }
1080
1081
1082 QQmlError ExecutionEngine::catchExceptionAsQmlError()
1083 {
1084     QV4::StackTrace trace;
1085     QV4::Scope scope(this);
1086     QV4::ScopedValue exception(scope, catchException(&trace));
1087     QQmlError error;
1088     if (!trace.isEmpty()) {
1089         QV4::StackFrame frame = trace.first();
1090         error.setUrl(QUrl(frame.source));
1091         error.setLine(frame.line);
1092         error.setColumn(frame.column);
1093     }
1094     QV4::Scoped<QV4::ErrorObject> errorObj(scope, exception);
1095     if (!!errorObj && errorObj->asSyntaxError()) {
1096         QV4::ScopedString m(scope, newString(QStringLiteral("message")));
1097         QV4::ScopedValue v(scope, errorObj->get(m));
1098         error.setDescription(v->toQStringNoThrow());
1099     } else
1100         error.setDescription(exception->toQStringNoThrow());
1101     return error;
1102 }
1103
1104 bool ExecutionEngine::recheckCStackLimits()
1105 {
1106     int dummy;
1107 #ifdef Q_OS_WIN
1108     // ### this is only required on windows, where we currently use heuristics to get the stack limit
1109     if (cStackLimit - reinterpret_cast<quintptr>(&dummy) > 128*1024)
1110         // we're more then 128k away from our stack limit, assume the thread has changed, and
1111         // call getStackLimit
1112 #endif
1113     // this can happen after a thread change
1114     cStackLimit = getStackLimit();
1115
1116     return (reinterpret_cast<quintptr>(&dummy) >= cStackLimit);
1117 }
1118
1119
1120 // Variant conversion code
1121
1122 typedef QSet<QV4::Heap::Object *> V4ObjectSet;
1123 static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects);
1124 static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &value);
1125 static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects = 0);
1126 static bool convertToNativeQObject(QV4::ExecutionEngine *e, const QV4::Value &value,
1127                             const QByteArray &targetType,
1128                             void **result);
1129 static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst);
1130 static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVariantMap &vmap);
1131 static QV4::ReturnedValue variantToJS(QV4::ExecutionEngine *v4, const QVariant &value)
1132 {
1133     return v4->metaTypeToJS(value.userType(), value.constData());
1134 }
1135
1136
1137 QVariant ExecutionEngine::toVariant(const Value &value, int typeHint, bool createJSValueForObjects)
1138 {
1139     return ::toVariant(this, value, typeHint, createJSValueForObjects, 0);
1140 }
1141
1142
1143 static QVariant toVariant(QV4::ExecutionEngine *e, const QV4::Value &value, int typeHint, bool createJSValueForObjects, V4ObjectSet *visitedObjects)
1144 {
1145     Q_ASSERT (!value.isEmpty());
1146     QV4::Scope scope(e);
1147
1148     if (const QV4::VariantObject *v = value.as<QV4::VariantObject>())
1149         return v->d()->data;
1150
1151     if (typeHint == QVariant::Bool)
1152         return QVariant(value.toBoolean());
1153
1154     if (typeHint == QMetaType::QJsonValue)
1155         return QVariant::fromValue(QV4::JsonObject::toJsonValue(value));
1156
1157     if (typeHint == qMetaTypeId<QJSValue>())
1158         return QVariant::fromValue(QJSValue(e, value.asReturnedValue()));
1159
1160     if (value.as<Object>()) {
1161         QV4::ScopedObject object(scope, value);
1162         if (typeHint == QMetaType::QJsonObject
1163                    && !value.as<ArrayObject>() && !value.as<FunctionObject>()) {
1164             return QVariant::fromValue(QV4::JsonObject::toJsonObject(object));
1165         } else if (QV4::QObjectWrapper *wrapper = object->as<QV4::QObjectWrapper>()) {
1166             return qVariantFromValue<QObject *>(wrapper->object());
1167         } else if (object->as<QV4::QmlContextWrapper>()) {
1168             return QVariant();
1169         } else if (QV4::QmlTypeWrapper *w = object->as<QV4::QmlTypeWrapper>()) {
1170             return w->toVariant();
1171         } else if (QV4::QQmlValueTypeWrapper *v = object->as<QV4::QQmlValueTypeWrapper>()) {
1172             return v->toVariant();
1173         } else if (QV4::QmlListWrapper *l = object->as<QV4::QmlListWrapper>()) {
1174             return l->toVariant();
1175         } else if (object->isListType())
1176             return QV4::SequencePrototype::toVariant(object);
1177     }
1178
1179     if (value.as<ArrayObject>()) {
1180         QV4::ScopedArrayObject a(scope, value);
1181         if (typeHint == qMetaTypeId<QList<QObject *> >()) {
1182             QList<QObject *> list;
1183             uint length = a->getLength();
1184             QV4::Scoped<QV4::QObjectWrapper> qobjectWrapper(scope);
1185             for (uint ii = 0; ii < length; ++ii) {
1186                 qobjectWrapper = a->getIndexed(ii);
1187                 if (!!qobjectWrapper) {
1188                     list << qobjectWrapper->object();
1189                 } else {
1190                     list << 0;
1191                 }
1192             }
1193
1194             return qVariantFromValue<QList<QObject*> >(list);
1195         } else if (typeHint == QMetaType::QJsonArray) {
1196             return QVariant::fromValue(QV4::JsonObject::toJsonArray(a));
1197         }
1198
1199         bool succeeded = false;
1200         QVariant retn = QV4::SequencePrototype::toVariant(value, typeHint, &succeeded);
1201         if (succeeded)
1202             return retn;
1203     }
1204
1205     if (value.isUndefined())
1206         return QVariant();
1207     if (value.isNull())
1208         return QVariant(QMetaType::VoidStar, (void *)0);
1209     if (value.isBoolean())
1210         return value.booleanValue();
1211     if (value.isInteger())
1212         return value.integerValue();
1213     if (value.isNumber())
1214         return value.asDouble();
1215     if (value.isString())
1216         return value.stringValue()->toQString();
1217     if (const QV4::QQmlLocaleData *ld = value.as<QV4::QQmlLocaleData>())
1218         return ld->d()->locale;
1219     if (const QV4::DateObject *d = value.as<DateObject>())
1220         return d->toQDateTime();
1221     if (const QV4::ArrayBuffer *d = value.as<ArrayBuffer>())
1222         return d->asByteArray();
1223     // NOTE: since we convert QTime to JS Date, round trip will change the variant type (to QDateTime)!
1224
1225     QV4::ScopedObject o(scope, value);
1226     Q_ASSERT(o);
1227
1228     if (QV4::RegExpObject *re = o->as<QV4::RegExpObject>())
1229         return re->toQRegExp();
1230
1231     if (createJSValueForObjects)
1232         return QVariant::fromValue(QJSValue(scope.engine, o->asReturnedValue()));
1233
1234     return objectToVariant(e, o, visitedObjects);
1235 }
1236
1237 static QVariant objectToVariant(QV4::ExecutionEngine *e, const QV4::Object *o, V4ObjectSet *visitedObjects)
1238 {
1239     Q_ASSERT(o);
1240
1241     V4ObjectSet recursionGuardSet;
1242     if (!visitedObjects) {
1243         visitedObjects = &recursionGuardSet;
1244     } else if (visitedObjects->contains(o->d())) {
1245         // Avoid recursion.
1246         // For compatibility with QVariant{List,Map} conversion, we return an
1247         // empty object (and no error is thrown).
1248         if (o->as<ArrayObject>())
1249             return QVariantList();
1250         return QVariantMap();
1251     }
1252     visitedObjects->insert(o->d());
1253
1254     QVariant result;
1255
1256     if (o->as<ArrayObject>()) {
1257         QV4::Scope scope(e);
1258         QV4::ScopedArrayObject a(scope, o->asReturnedValue());
1259         QV4::ScopedValue v(scope);
1260         QVariantList list;
1261
1262         int length = a->getLength();
1263         for (int ii = 0; ii < length; ++ii) {
1264             v = a->getIndexed(ii);
1265             list << ::toVariant(e, v, -1, /*createJSValueForObjects*/false, visitedObjects);
1266         }
1267
1268         result = list;
1269     } else if (!o->as<FunctionObject>()) {
1270         QVariantMap map;
1271         QV4::Scope scope(e);
1272         QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly);
1273         QV4::ScopedValue name(scope);
1274         QV4::ScopedValue val(scope);
1275         while (1) {
1276             name = it.nextPropertyNameAsString(val);
1277             if (name->isNull())
1278                 break;
1279
1280             QString key = name->toQStringNoThrow();
1281             map.insert(key, ::toVariant(e, val, /*type hint*/-1, /*createJSValueForObjects*/false, visitedObjects));
1282         }
1283
1284         result = map;
1285     }
1286
1287     visitedObjects->remove(o->d());
1288     return result;
1289 }
1290
1291 static QV4::ReturnedValue arrayFromVariantList(QV4::ExecutionEngine *e, const QVariantList &list)
1292 {
1293     QV4::Scope scope(e);
1294     QV4::ScopedArrayObject a(scope, e->newArrayObject());
1295     int len = list.count();
1296     a->arrayReserve(len);
1297     QV4::ScopedValue v(scope);
1298     for (int ii = 0; ii < len; ++ii)
1299         a->arrayPut(ii, (v = scope.engine->fromVariant(list.at(ii))));
1300
1301     a->setArrayLengthUnchecked(len);
1302     return a.asReturnedValue();
1303 }
1304
1305 static QV4::ReturnedValue objectFromVariantMap(QV4::ExecutionEngine *e, const QVariantMap &map)
1306 {
1307     QV4::Scope scope(e);
1308     QV4::ScopedObject o(scope, e->newObject());
1309     QV4::ScopedString s(scope);
1310     QV4::ScopedValue v(scope);
1311     for (QVariantMap::const_iterator iter = map.begin(), cend = map.end(); iter != cend; ++iter) {
1312         s = e->newString(iter.key());
1313         uint idx = s->asArrayIndex();
1314         if (idx > 16 && (!o->arrayData() || idx > o->arrayData()->length() * 2))
1315             o->initSparseArray();
1316         o->put(s, (v = e->fromVariant(iter.value())));
1317     }
1318     return o.asReturnedValue();
1319 }
1320
1321 Q_CORE_EXPORT QString qt_regexp_toCanonical(const QString &, QRegExp::PatternSyntax);
1322
1323 QV4::ReturnedValue QV4::ExecutionEngine::fromVariant(const QVariant &variant)
1324 {
1325     int type = variant.userType();
1326     const void *ptr = variant.constData();
1327
1328     if (type < QMetaType::User) {
1329         switch (QMetaType::Type(type)) {
1330             case QMetaType::UnknownType:
1331             case QMetaType::Void:
1332                 return QV4::Encode::undefined();
1333             case QMetaType::VoidStar:
1334                 return QV4::Encode::null();
1335             case QMetaType::Bool:
1336                 return QV4::Encode(*reinterpret_cast<const bool*>(ptr));
1337             case QMetaType::Int:
1338                 return QV4::Encode(*reinterpret_cast<const int*>(ptr));
1339             case QMetaType::UInt:
1340                 return QV4::Encode(*reinterpret_cast<const uint*>(ptr));
1341             case QMetaType::LongLong:
1342                 return QV4::Encode((double)*reinterpret_cast<const qlonglong*>(ptr));
1343             case QMetaType::ULongLong:
1344                 return QV4::Encode((double)*reinterpret_cast<const qulonglong*>(ptr));
1345             case QMetaType::Double:
1346                 return QV4::Encode(*reinterpret_cast<const double*>(ptr));
1347             case QMetaType::QString:
1348                 return newString(*reinterpret_cast<const QString*>(ptr))->asReturnedValue();
1349             case QMetaType::Float:
1350                 return QV4::Encode(*reinterpret_cast<const float*>(ptr));
1351             case QMetaType::Short:
1352                 return QV4::Encode((int)*reinterpret_cast<const short*>(ptr));
1353             case QMetaType::UShort:
1354                 return QV4::Encode((int)*reinterpret_cast<const unsigned short*>(ptr));
1355             case QMetaType::Char:
1356                 return newString(QChar::fromLatin1(*reinterpret_cast<const char *>(ptr)))->asReturnedValue();
1357             case QMetaType::UChar:
1358                 return newString(QChar::fromLatin1(*reinterpret_cast<const unsigned char *>(ptr)))->asReturnedValue();
1359             case QMetaType::QChar:
1360                 return newString(*reinterpret_cast<const QChar *>(ptr))->asReturnedValue();
1361             case QMetaType::QDateTime:
1362                 return QV4::Encode(newDateObject(*reinterpret_cast<const QDateTime *>(ptr)));
1363             case QMetaType::QDate:
1364                 return QV4::Encode(newDateObject(QDateTime(*reinterpret_cast<const QDate *>(ptr))));
1365             case QMetaType::QTime:
1366             return QV4::Encode(newDateObject(QDateTime(QDate(1970,1,1), *reinterpret_cast<const QTime *>(ptr))));
1367             case QMetaType::QRegExp:
1368                 return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(ptr)));
1369             case QMetaType::QObjectStar:
1370                 return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
1371             case QMetaType::QStringList:
1372                 {
1373                 bool succeeded = false;
1374                 QV4::Scope scope(this);
1375                 QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromVariant(this, variant, &succeeded));
1376                 if (succeeded)
1377                     return retn->asReturnedValue();
1378                 return QV4::Encode(newArrayObject(*reinterpret_cast<const QStringList *>(ptr)));
1379                 }
1380             case QMetaType::QVariantList:
1381                 return arrayFromVariantList(this, *reinterpret_cast<const QVariantList *>(ptr));
1382             case QMetaType::QVariantMap:
1383                 return objectFromVariantMap(this, *reinterpret_cast<const QVariantMap *>(ptr));
1384             case QMetaType::QJsonValue:
1385                 return QV4::JsonObject::fromJsonValue(this, *reinterpret_cast<const QJsonValue *>(ptr));
1386             case QMetaType::QJsonObject:
1387                 return QV4::JsonObject::fromJsonObject(this, *reinterpret_cast<const QJsonObject *>(ptr));
1388             case QMetaType::QJsonArray:
1389                 return QV4::JsonObject::fromJsonArray(this, *reinterpret_cast<const QJsonArray *>(ptr));
1390             case QMetaType::QLocale:
1391                 return QQmlLocale::wrap(this, *reinterpret_cast<const QLocale*>(ptr));
1392             default:
1393                 break;
1394         }
1395
1396         if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(type))
1397             return QV4::QQmlValueTypeWrapper::create(this, variant, vtmo, type);
1398     } else {
1399         QV4::Scope scope(this);
1400         if (type == qMetaTypeId<QQmlListReference>()) {
1401             typedef QQmlListReferencePrivate QDLRP;
1402             QDLRP *p = QDLRP::get((QQmlListReference*)const_cast<void *>(ptr));
1403             if (p->object) {
1404                 return QV4::QmlListWrapper::create(scope.engine, p->property, p->propertyType);
1405             } else {
1406                 return QV4::Encode::null();
1407             }
1408         } else if (type == qMetaTypeId<QJSValue>()) {
1409             const QJSValue *value = reinterpret_cast<const QJSValue *>(ptr);
1410             return QJSValuePrivate::convertedToValue(this, *value);
1411         } else if (type == qMetaTypeId<QList<QObject *> >()) {
1412             // XXX Can this be made more by using Array as a prototype and implementing
1413             // directly against QList<QObject*>?
1414             const QList<QObject *> &list = *(const QList<QObject *>*)ptr;
1415             QV4::ScopedArrayObject a(scope, newArrayObject());
1416             a->arrayReserve(list.count());
1417             QV4::ScopedValue v(scope);
1418             for (int ii = 0; ii < list.count(); ++ii)
1419                 a->arrayPut(ii, (v = QV4::QObjectWrapper::wrap(this, list.at(ii))));
1420             a->setArrayLengthUnchecked(list.count());
1421             return a.asReturnedValue();
1422         } else if (QMetaType::typeFlags(type) & QMetaType::PointerToQObject) {
1423             return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(ptr));
1424         }
1425
1426         bool objOk;
1427         QObject *obj = QQmlMetaType::toQObject(variant, &objOk);
1428         if (objOk)
1429             return QV4::QObjectWrapper::wrap(this, obj);
1430
1431         bool succeeded = false;
1432         QV4::ScopedValue retn(scope, QV4::SequencePrototype::fromVariant(this, variant, &succeeded));
1433         if (succeeded)
1434             return retn->asReturnedValue();
1435
1436         if (const QMetaObject *vtmo = QQmlValueTypeFactory::metaObjectForMetaType(type))
1437             return QV4::QQmlValueTypeWrapper::create(this, variant, vtmo, type);
1438     }
1439
1440     // XXX TODO: To be compatible, we still need to handle:
1441     //    + QObjectList
1442     //    + QList<int>
1443
1444     return QV4::Encode(newVariantObject(variant));
1445 }
1446
1447 QVariantMap ExecutionEngine::variantMapFromJS(const Object *o)
1448 {
1449     return objectToVariant(this, o).toMap();
1450 }
1451
1452
1453 // Converts a QVariantList to JS.
1454 // The result is a new Array object with length equal to the length
1455 // of the QVariantList, and the elements being the QVariantList's
1456 // elements converted to JS, recursively.
1457 static QV4::ReturnedValue variantListToJS(QV4::ExecutionEngine *v4, const QVariantList &lst)
1458 {
1459     QV4::Scope scope(v4);
1460     QV4::ScopedArrayObject a(scope, v4->newArrayObject());
1461     a->arrayReserve(lst.size());
1462     QV4::ScopedValue v(scope);
1463     for (int i = 0; i < lst.size(); i++)
1464         a->arrayPut(i, (v = variantToJS(v4, lst.at(i))));
1465     a->setArrayLengthUnchecked(lst.size());
1466     return a.asReturnedValue();
1467 }
1468
1469 // Converts a QVariantMap to JS.
1470 // The result is a new Object object with property names being
1471 // the keys of the QVariantMap, and values being the values of
1472 // the QVariantMap converted to JS, recursively.
1473 static QV4::ReturnedValue variantMapToJS(QV4::ExecutionEngine *v4, const QVariantMap &vmap)
1474 {
1475     QV4::Scope scope(v4);
1476     QV4::ScopedObject o(scope, v4->newObject());
1477     QV4::ScopedString s(scope);
1478     QV4::ScopedValue v(scope);
1479     for (QVariantMap::const_iterator it = vmap.constBegin(), cend = vmap.constEnd(); it != cend; ++it) {
1480         s = v4->newIdentifier(it.key());
1481         v = variantToJS(v4, it.value());
1482         uint idx = s->asArrayIndex();
1483         if (idx < UINT_MAX)
1484             o->arraySet(idx, v);
1485         else
1486             o->insertMember(s, v);
1487     }
1488     return o.asReturnedValue();
1489 }
1490
1491 // Converts the meta-type defined by the given type and data to JS.
1492 // Returns the value if conversion succeeded, an empty handle otherwise.
1493 QV4::ReturnedValue ExecutionEngine::metaTypeToJS(int type, const void *data)
1494 {
1495     Q_ASSERT(data != 0);
1496
1497     // check if it's one of the types we know
1498     switch (QMetaType::Type(type)) {
1499     case QMetaType::UnknownType:
1500     case QMetaType::Void:
1501         return QV4::Encode::undefined();
1502     case QMetaType::VoidStar:
1503         return QV4::Encode::null();
1504     case QMetaType::Bool:
1505         return QV4::Encode(*reinterpret_cast<const bool*>(data));
1506     case QMetaType::Int:
1507         return QV4::Encode(*reinterpret_cast<const int*>(data));
1508     case QMetaType::UInt:
1509         return QV4::Encode(*reinterpret_cast<const uint*>(data));
1510     case QMetaType::LongLong:
1511         return QV4::Encode(double(*reinterpret_cast<const qlonglong*>(data)));
1512     case QMetaType::ULongLong:
1513 #if defined(Q_OS_WIN) && defined(_MSC_FULL_VER) && _MSC_FULL_VER <= 12008804
1514 #pragma message("** NOTE: You need the Visual Studio Processor Pack to compile support for 64bit unsigned integers.")
1515         return QV4::Encode(double((qlonglong)*reinterpret_cast<const qulonglong*>(data)));
1516 #elif defined(Q_CC_MSVC) && !defined(Q_CC_MSVC_NET)
1517         return QV4::Encode(double((qlonglong)*reinterpret_cast<const qulonglong*>(data)));
1518 #else
1519         return QV4::Encode(double(*reinterpret_cast<const qulonglong*>(data)));
1520 #endif
1521     case QMetaType::Double:
1522         return QV4::Encode(*reinterpret_cast<const double*>(data));
1523     case QMetaType::QString:
1524         return newString(*reinterpret_cast<const QString*>(data))->asReturnedValue();
1525     case QMetaType::Float:
1526         return QV4::Encode(*reinterpret_cast<const float*>(data));
1527     case QMetaType::Short:
1528         return QV4::Encode((int)*reinterpret_cast<const short*>(data));
1529     case QMetaType::UShort:
1530         return QV4::Encode((int)*reinterpret_cast<const unsigned short*>(data));
1531     case QMetaType::Char:
1532         return QV4::Encode((int)*reinterpret_cast<const char*>(data));
1533     case QMetaType::UChar:
1534         return QV4::Encode((int)*reinterpret_cast<const unsigned char*>(data));
1535     case QMetaType::QChar:
1536         return QV4::Encode((int)(*reinterpret_cast<const QChar*>(data)).unicode());
1537     case QMetaType::QStringList:
1538         return QV4::Encode(newArrayObject(*reinterpret_cast<const QStringList *>(data)));
1539     case QMetaType::QVariantList:
1540         return variantListToJS(this, *reinterpret_cast<const QVariantList *>(data));
1541     case QMetaType::QVariantMap:
1542         return variantMapToJS(this, *reinterpret_cast<const QVariantMap *>(data));
1543     case QMetaType::QDateTime:
1544         return QV4::Encode(newDateObject(*reinterpret_cast<const QDateTime *>(data)));
1545     case QMetaType::QDate:
1546         return QV4::Encode(newDateObject(QDateTime(*reinterpret_cast<const QDate *>(data))));
1547     case QMetaType::QRegExp:
1548         return QV4::Encode(newRegExpObject(*reinterpret_cast<const QRegExp *>(data)));
1549     case QMetaType::QObjectStar:
1550         return QV4::QObjectWrapper::wrap(this, *reinterpret_cast<QObject* const *>(data));
1551     case QMetaType::QVariant:
1552         return variantToJS(this, *reinterpret_cast<const QVariant*>(data));
1553     case QMetaType::QJsonValue:
1554         return QV4::JsonObject::fromJsonValue(this, *reinterpret_cast<const QJsonValue *>(data));
1555     case QMetaType::QJsonObject:
1556         return QV4::JsonObject::fromJsonObject(this, *reinterpret_cast<const QJsonObject *>(data));
1557     case QMetaType::QJsonArray:
1558         return QV4::JsonObject::fromJsonArray(this, *reinterpret_cast<const QJsonArray *>(data));
1559     default:
1560         if (type == qMetaTypeId<QJSValue>()) {
1561             return QJSValuePrivate::convertedToValue(this, *reinterpret_cast<const QJSValue*>(data));
1562         } else {
1563             QByteArray typeName = QMetaType::typeName(type);
1564             if (typeName.endsWith('*') && !*reinterpret_cast<void* const *>(data)) {
1565                 return QV4::Encode::null();
1566             }
1567             QMetaType mt(type);
1568             if (mt.flags() & QMetaType::IsGadget) {
1569                 Q_ASSERT(mt.metaObject());
1570                 return QV4::QQmlValueTypeWrapper::create(this, QVariant(type, data), mt.metaObject(), type);
1571             }
1572             // Fall back to wrapping in a QVariant.
1573             return QV4::Encode(newVariantObject(QVariant(type, data)));
1574         }
1575     }
1576     Q_UNREACHABLE();
1577     return 0;
1578 }
1579
1580 void ExecutionEngine::assertObjectBelongsToEngine(const Heap::Base &baseObject)
1581 {
1582     Q_ASSERT(!baseObject.vtable()->isObject || static_cast<const Heap::Object&>(baseObject).internalClass->engine == this);
1583     Q_UNUSED(baseObject);
1584 }
1585
1586 // Converts a JS value to a meta-type.
1587 // data must point to a place that can store a value of the given type.
1588 // Returns true if conversion succeeded, false otherwise.
1589 bool ExecutionEngine::metaTypeFromJS(const Value *value, int type, void *data)
1590 {
1591     // check if it's one of the types we know
1592     switch (QMetaType::Type(type)) {
1593     case QMetaType::Bool:
1594         *reinterpret_cast<bool*>(data) = value->toBoolean();
1595         return true;
1596     case QMetaType::Int:
1597         *reinterpret_cast<int*>(data) = value->toInt32();
1598         return true;
1599     case QMetaType::UInt:
1600         *reinterpret_cast<uint*>(data) = value->toUInt32();
1601         return true;
1602     case QMetaType::LongLong:
1603         *reinterpret_cast<qlonglong*>(data) = qlonglong(value->toInteger());
1604         return true;
1605     case QMetaType::ULongLong:
1606         *reinterpret_cast<qulonglong*>(data) = qulonglong(value->toInteger());
1607         return true;
1608     case QMetaType::Double:
1609         *reinterpret_cast<double*>(data) = value->toNumber();
1610         return true;
1611     case QMetaType::QString:
1612         if (value->isUndefined() || value->isNull())
1613             *reinterpret_cast<QString*>(data) = QString();
1614         else
1615             *reinterpret_cast<QString*>(data) = value->toQString();
1616         return true;
1617     case QMetaType::Float:
1618         *reinterpret_cast<float*>(data) = value->toNumber();
1619         return true;
1620     case QMetaType::Short:
1621         *reinterpret_cast<short*>(data) = short(value->toInt32());
1622         return true;
1623     case QMetaType::UShort:
1624         *reinterpret_cast<unsigned short*>(data) = value->toUInt16();
1625         return true;
1626     case QMetaType::Char:
1627         *reinterpret_cast<char*>(data) = char(value->toInt32());
1628         return true;
1629     case QMetaType::UChar:
1630         *reinterpret_cast<unsigned char*>(data) = (unsigned char)(value->toInt32());
1631         return true;
1632     case QMetaType::QChar:
1633         if (value->isString()) {
1634             QString str = value->stringValue()->toQString();
1635             *reinterpret_cast<QChar*>(data) = str.isEmpty() ? QChar() : str.at(0);
1636         } else {
1637             *reinterpret_cast<QChar*>(data) = QChar(ushort(value->toUInt16()));
1638         }
1639         return true;
1640     case QMetaType::QDateTime:
1641         if (const QV4::DateObject *d = value->as<DateObject>()) {
1642             *reinterpret_cast<QDateTime *>(data) = d->toQDateTime();
1643             return true;
1644         } break;
1645     case QMetaType::QDate:
1646         if (const QV4::DateObject *d = value->as<DateObject>()) {
1647             *reinterpret_cast<QDate *>(data) = d->toQDateTime().date();
1648             return true;
1649         } break;
1650     case QMetaType::QRegExp:
1651         if (const QV4::RegExpObject *r = value->as<QV4::RegExpObject>()) {
1652             *reinterpret_cast<QRegExp *>(data) = r->toQRegExp();
1653             return true;
1654         } break;
1655     case QMetaType::QObjectStar: {
1656         const QV4::QObjectWrapper *qobjectWrapper = value->as<QV4::QObjectWrapper>();
1657         if (qobjectWrapper || value->isNull()) {
1658             *reinterpret_cast<QObject* *>(data) = qtObjectFromJS(this, *value);
1659             return true;
1660         } break;
1661     }
1662     case QMetaType::QStringList: {
1663         const QV4::ArrayObject *a = value->as<QV4::ArrayObject>();
1664         if (a) {
1665             *reinterpret_cast<QStringList *>(data) = a->toQStringList();
1666             return true;
1667         }
1668         break;
1669     }
1670     case QMetaType::QVariantList: {
1671         const QV4::ArrayObject *a = value->as<QV4::ArrayObject>();
1672         if (a) {
1673             *reinterpret_cast<QVariantList *>(data) = toVariant(*a, /*typeHint*/-1, /*createJSValueForObjects*/false).toList();
1674             return true;
1675         }
1676         break;
1677     }
1678     case QMetaType::QVariantMap: {
1679         const QV4::Object *o = value->as<QV4::Object>();
1680         if (o) {
1681             *reinterpret_cast<QVariantMap *>(data) = variantMapFromJS(o);
1682             return true;
1683         }
1684         break;
1685     }
1686     case QMetaType::QVariant:
1687         *reinterpret_cast<QVariant*>(data) = toVariant(*value, /*typeHint*/-1, /*createJSValueForObjects*/false);
1688         return true;
1689     case QMetaType::QJsonValue:
1690         *reinterpret_cast<QJsonValue *>(data) = QV4::JsonObject::toJsonValue(*value);
1691         return true;
1692     case QMetaType::QJsonObject: {
1693         *reinterpret_cast<QJsonObject *>(data) = QV4::JsonObject::toJsonObject(value->as<Object>());
1694         return true;
1695     }
1696     case QMetaType::QJsonArray: {
1697         const QV4::ArrayObject *a = value->as<ArrayObject>();
1698         if (a) {
1699             *reinterpret_cast<QJsonArray *>(data) = JsonObject::toJsonArray(a);
1700             return true;
1701         }
1702         break;
1703     }
1704     default:
1705     ;
1706     }
1707
1708     {
1709         const QQmlValueTypeWrapper *vtw = value->as<QQmlValueTypeWrapper>();
1710         if (vtw && vtw->typeId() == type) {
1711             return vtw->toGadget(data);
1712         }
1713     }
1714
1715 #if 0
1716     if (isQtVariant(value)) {
1717         const QVariant &var = variantValue(value);
1718         // ### Enable once constructInPlace() is in qt master.
1719         if (var.userType() == type) {
1720             QMetaType::constructInPlace(type, data, var.constData());
1721             return true;
1722         }
1723         if (var.canConvert(type)) {
1724             QVariant vv = var;
1725             vv.convert(type);
1726             Q_ASSERT(vv.userType() == type);
1727             QMetaType::constructInPlace(type, data, vv.constData());
1728             return true;
1729         }
1730
1731     }
1732 #endif
1733
1734     // Try to use magic; for compatibility with qjsvalue_cast.
1735
1736     QByteArray name = QMetaType::typeName(type);
1737     if (convertToNativeQObject(this, *value, name, reinterpret_cast<void* *>(data)))
1738         return true;
1739     if (value->as<QV4::VariantObject>() && name.endsWith('*')) {
1740         int valueType = QMetaType::type(name.left(name.size()-1));
1741         QVariant &var = value->as<QV4::VariantObject>()->d()->data;
1742         if (valueType == var.userType()) {
1743             // We have T t, T* is requested, so return &t.
1744             *reinterpret_cast<void* *>(data) = var.data();
1745             return true;
1746         } else if (value->isObject()) {
1747             // Look in the prototype chain.
1748             QV4::Scope scope(this);
1749             QV4::ScopedObject proto(scope, value->objectValue()->prototype());
1750             while (proto) {
1751                 bool canCast = false;
1752                 if (QV4::VariantObject *vo = proto->as<QV4::VariantObject>()) {
1753                     const QVariant &v = vo->d()->data;
1754                     canCast = (type == v.userType()) || (valueType && (valueType == v.userType()));
1755                 }
1756                 else if (proto->as<QV4::QObjectWrapper>()) {
1757                     QByteArray className = name.left(name.size()-1);
1758                     QV4::ScopedObject p(scope, proto.getPointer());
1759                     if (QObject *qobject = qtObjectFromJS(this, p))
1760                         canCast = qobject->qt_metacast(className) != 0;
1761                 }
1762                 if (canCast) {
1763                     QByteArray varTypeName = QMetaType::typeName(var.userType());
1764                     if (varTypeName.endsWith('*'))
1765                         *reinterpret_cast<void* *>(data) = *reinterpret_cast<void* *>(var.data());
1766                     else
1767                         *reinterpret_cast<void* *>(data) = var.data();
1768                     return true;
1769                 }
1770                 proto = proto->prototype();
1771             }
1772         }
1773     } else if (value->isNull() && name.endsWith('*')) {
1774         *reinterpret_cast<void* *>(data) = 0;
1775         return true;
1776     } else if (type == qMetaTypeId<QJSValue>()) {
1777         *reinterpret_cast<QJSValue*>(data) = QJSValue(this, value->asReturnedValue());
1778         return true;
1779     }
1780
1781     return false;
1782 }
1783
1784 static bool convertToNativeQObject(QV4::ExecutionEngine *e, const Value &value, const QByteArray &targetType, void **result)
1785 {
1786     if (!targetType.endsWith('*'))
1787         return false;
1788     if (QObject *qobject = qtObjectFromJS(e, value)) {
1789         int start = targetType.startsWith("const ") ? 6 : 0;
1790         QByteArray className = targetType.mid(start, targetType.size()-start-1);
1791         if (void *instance = qobject->qt_metacast(className)) {
1792             *result = instance;
1793             return true;
1794         }
1795     }
1796     return false;
1797 }
1798
1799 static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const Value &value)
1800 {
1801     if (!value.isObject())
1802         return 0;
1803
1804     QV4::Scope scope(engine);
1805     QV4::Scoped<QV4::VariantObject> v(scope, value);
1806
1807     if (v) {
1808         QVariant variant = v->d()->data;
1809         int type = variant.userType();
1810         if (type == QMetaType::QObjectStar)
1811             return *reinterpret_cast<QObject* const *>(variant.constData());
1812     }
1813     QV4::Scoped<QV4::QObjectWrapper> wrapper(scope, value);
1814     if (!wrapper)
1815         return 0;
1816     return wrapper->object();
1817 }
1818
1819
1820 QT_END_NAMESPACE