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