1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 #ifndef QV4ENGINE_H
40 #define QV4ENGINE_H
41 
42 //
43 //  W A R N I N G
44 //  -------------
45 //
46 // This file is not part of the Qt API.  It exists purely as an
47 // implementation detail.  This header file may change from version to
48 // version without notice, or even be removed.
49 //
50 // We mean it.
51 //
52 
53 #include "qv4global_p.h"
54 #include "qv4managed_p.h"
55 #include "qv4context_p.h"
56 #include "qv4stackframe_p.h"
57 #include <private/qintrusivelist_p.h>
58 #include "qv4enginebase_p.h"
59 #include <private/qqmlrefcount_p.h>
60 #include <private/qqmldelayedcallqueue_p.h>
61 #include <QtCore/qelapsedtimer.h>
62 #include <QtCore/qmutex.h>
63 
64 #include "qv4function_p.h"
65 #include <private/qv4compileddata_p.h>
66 #include <private/qv4executablecompilationunit_p.h>
67 
68 namespace WTF {
69 class BumpPointerAllocator;
70 class PageAllocation;
71 }
72 
73 #define V4_DEFINE_EXTENSION(dataclass, datafunction) \
74     static inline dataclass *datafunction(QV4::ExecutionEngine *engine) \
75     { \
76         static int extensionId = -1; \
77         if (extensionId == -1) { \
78             QV4::ExecutionEngine::registrationMutex()->lock(); \
79             if (extensionId == -1) \
80                 extensionId = QV4::ExecutionEngine::registerExtension(); \
81             QV4::ExecutionEngine::registrationMutex()->unlock(); \
82         } \
83         dataclass *rv = (dataclass *)engine->extensionData(extensionId); \
84         if (!rv) { \
85             rv = new dataclass(engine); \
86             engine->setExtensionData(extensionId, rv); \
87         } \
88         return rv; \
89     } \
90 
91 
92 QT_BEGIN_NAMESPACE
93 
94 #if QT_CONFIG(qml_network)
95 class QNetworkAccessManager;
96 
97 namespace QV4 {
98 struct QObjectMethod;
99 namespace detail {
100 QNetworkAccessManager *getNetworkAccessManager(ExecutionEngine *engine);
101 }
102 }
103 #else
104 namespace QV4 { struct QObjectMethod; }
105 #endif // qml_network
106 
107 // Used to allow a QObject method take and return raw V4 handles without having to expose
108 // 48 in the public API.
109 // Use like this:
110 //     class MyClass : public QObject {
111 //         Q_OBJECT
112 //         ...
113 //         Q_INVOKABLE void myMethod(QQmlV4Function*);
114 //     };
115 // The QQmlV8Function - and consequently the arguments and return value - only remains
116 // valid during the call.  If the return value isn't set within myMethod(), the will return
117 // undefined.
118 
119 class QQmlV4Function
120 {
121 public:
length()122     int length() const { return callData->argc(); }
123     QV4::ReturnedValue operator[](int idx) const { return (idx < callData->argc() ? callData->args[idx].asReturnedValue() : QV4::Encode::undefined()); }
setReturnValue(QV4::ReturnedValue rv)124     void setReturnValue(QV4::ReturnedValue rv) { *retVal = rv; }
v4engine()125     QV4::ExecutionEngine *v4engine() const { return e; }
126 private:
127     friend struct QV4::QObjectMethod;
128     QQmlV4Function();
129     QQmlV4Function(const QQmlV4Function &);
130     QQmlV4Function &operator=(const QQmlV4Function &);
131 
QQmlV4Function(QV4::CallData * callData,QV4::Value * retVal,QV4::ExecutionEngine * e)132     QQmlV4Function(QV4::CallData *callData, QV4::Value *retVal, QV4::ExecutionEngine *e)
133         : callData(callData), retVal(retVal), e(e)
134     {
135         callData->thisObject = QV4::Encode::undefined();
136     }
137 
138     QV4::CallData *callData;
139     QV4::Value *retVal;
140     QV4::ExecutionEngine *e;
141 };
142 
143 class QQmlError;
144 class QJSEngine;
145 class QQmlEngine;
146 class QQmlContextData;
147 
148 namespace QV4 {
149 namespace Debugging {
150 class Debugger;
151 } // namespace Debugging
152 namespace Profiling {
153 class Profiler;
154 } // namespace Profiling
155 namespace CompiledData {
156 struct CompilationUnit;
157 }
158 
159 namespace Heap {
160 struct Module;
161 };
162 
163 struct Function;
164 
165 namespace Promise {
166 class ReactionHandler;
167 };
168 
169 struct Q_QML_EXPORT ExecutionEngine : public EngineBase
170 {
171 private:
172     static qint32 maxCallDepth;
173 
174     friend struct ExecutionContextSaver;
175     friend struct ExecutionContext;
176     friend struct Heap::ExecutionContext;
177 public:
178     ExecutableAllocator *executableAllocator;
179     ExecutableAllocator *regExpAllocator;
180 
181     WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine.
182 
183     WTF::PageAllocation *jsStack;
184 
185     WTF::PageAllocation *gcStack;
186 
jsAllocaExecutionEngine187     QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) {
188         Value *ptr = jsStackTop;
189         jsStackTop = ptr + nValues;
190         return ptr;
191     }
192 
193     Function *globalCode;
194 
jsEngineExecutionEngine195     QJSEngine *jsEngine() const { return publicEngine; }
qmlEngineExecutionEngine196     QQmlEngine *qmlEngine() const { return m_qmlEngine; }
197     QJSEngine *publicEngine;
198 
199     enum JSObjects {
200         RootContext,
201         ScriptContext,
202         IntegerNull, // Has to come after the RootContext to make the context stack safe
203         ObjectProto,
204         SymbolProto,
205         ArrayProto,
206         ArrayProtoValues,
207         PropertyListProto,
208         StringProto,
209         NumberProto,
210         BooleanProto,
211         DateProto,
212         FunctionProto,
213         GeneratorProto,
214         RegExpProto,
215         ErrorProto,
216         EvalErrorProto,
217         RangeErrorProto,
218         ReferenceErrorProto,
219         SyntaxErrorProto,
220         TypeErrorProto,
221         URIErrorProto,
222         PromiseProto,
223         VariantProto,
224 #if QT_CONFIG(qml_sequence_object)
225         SequenceProto,
226 #endif
227         SharedArrayBufferProto,
228         ArrayBufferProto,
229         DataViewProto,
230         WeakSetProto,
231         SetProto,
232         WeakMapProto,
233         MapProto,
234         IntrinsicTypedArrayProto,
235         ValueTypeProto,
236         SignalHandlerProto,
237         IteratorProto,
238         ForInIteratorProto,
239         SetIteratorProto,
240         MapIteratorProto,
241         ArrayIteratorProto,
242         StringIteratorProto,
243 
244         Object_Ctor,
245         String_Ctor,
246         Symbol_Ctor,
247         Number_Ctor,
248         Boolean_Ctor,
249         Array_Ctor,
250         Function_Ctor,
251         GeneratorFunction_Ctor,
252         Date_Ctor,
253         RegExp_Ctor,
254         Error_Ctor,
255         EvalError_Ctor,
256         RangeError_Ctor,
257         ReferenceError_Ctor,
258         SyntaxError_Ctor,
259         TypeError_Ctor,
260         URIError_Ctor,
261         SharedArrayBuffer_Ctor,
262         Promise_Ctor,
263         ArrayBuffer_Ctor,
264         DataView_Ctor,
265         WeakSet_Ctor,
266         Set_Ctor,
267         WeakMap_Ctor,
268         Map_Ctor,
269         IntrinsicTypedArray_Ctor,
270 
271         GetSymbolSpecies,
272 
273         Eval_Function,
274         GetStack_Function,
275         ThrowerObject,
276         NJSObjects
277     };
278     Value *jsObjects;
279     enum { NTypedArrayTypes = 9 }; // == TypedArray::NValues, avoid header dependency
280 
rootContextExecutionEngine281     ExecutionContext *rootContext() const { return reinterpret_cast<ExecutionContext *>(jsObjects + RootContext); }
scriptContextExecutionEngine282     ExecutionContext *scriptContext() const { return reinterpret_cast<ExecutionContext *>(jsObjects + ScriptContext); }
setScriptContextExecutionEngine283     void setScriptContext(ReturnedValue c) { jsObjects[ScriptContext] = c; }
objectCtorExecutionEngine284     FunctionObject *objectCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Object_Ctor); }
stringCtorExecutionEngine285     FunctionObject *stringCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + String_Ctor); }
symbolCtorExecutionEngine286     FunctionObject *symbolCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Symbol_Ctor); }
numberCtorExecutionEngine287     FunctionObject *numberCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Number_Ctor); }
booleanCtorExecutionEngine288     FunctionObject *booleanCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Boolean_Ctor); }
arrayCtorExecutionEngine289     FunctionObject *arrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Array_Ctor); }
functionCtorExecutionEngine290     FunctionObject *functionCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Function_Ctor); }
generatorFunctionCtorExecutionEngine291     FunctionObject *generatorFunctionCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + GeneratorFunction_Ctor); }
dateCtorExecutionEngine292     FunctionObject *dateCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Date_Ctor); }
regExpCtorExecutionEngine293     FunctionObject *regExpCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + RegExp_Ctor); }
errorCtorExecutionEngine294     FunctionObject *errorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Error_Ctor); }
evalErrorCtorExecutionEngine295     FunctionObject *evalErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + EvalError_Ctor); }
rangeErrorCtorExecutionEngine296     FunctionObject *rangeErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + RangeError_Ctor); }
referenceErrorCtorExecutionEngine297     FunctionObject *referenceErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ReferenceError_Ctor); }
syntaxErrorCtorExecutionEngine298     FunctionObject *syntaxErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + SyntaxError_Ctor); }
typeErrorCtorExecutionEngine299     FunctionObject *typeErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + TypeError_Ctor); }
uRIErrorCtorExecutionEngine300     FunctionObject *uRIErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + URIError_Ctor); }
sharedArrayBufferCtorExecutionEngine301     FunctionObject *sharedArrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + SharedArrayBuffer_Ctor); }
promiseCtorExecutionEngine302     FunctionObject *promiseCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Promise_Ctor); }
arrayBufferCtorExecutionEngine303     FunctionObject *arrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ArrayBuffer_Ctor); }
dataViewCtorExecutionEngine304     FunctionObject *dataViewCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + DataView_Ctor); }
weakSetCtorExecutionEngine305     FunctionObject *weakSetCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + WeakSet_Ctor); }
setCtorExecutionEngine306     FunctionObject *setCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Set_Ctor); }
weakMapCtorExecutionEngine307     FunctionObject *weakMapCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + WeakMap_Ctor); }
mapCtorExecutionEngine308     FunctionObject *mapCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Map_Ctor); }
intrinsicTypedArrayCtorExecutionEngine309     FunctionObject *intrinsicTypedArrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + IntrinsicTypedArray_Ctor); }
310     FunctionObject *typedArrayCtors;
311 
getSymbolSpeciesExecutionEngine312     FunctionObject *getSymbolSpecies() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetSymbolSpecies); }
313 
objectPrototypeExecutionEngine314     Object *objectPrototype() const { return reinterpret_cast<Object *>(jsObjects + ObjectProto); }
symbolPrototypeExecutionEngine315     Object *symbolPrototype() const { return reinterpret_cast<Object *>(jsObjects + SymbolProto); }
arrayPrototypeExecutionEngine316     Object *arrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayProto); }
arrayProtoValuesExecutionEngine317     Object *arrayProtoValues() const { return reinterpret_cast<Object *>(jsObjects + ArrayProtoValues); }
propertyListPrototypeExecutionEngine318     Object *propertyListPrototype() const { return reinterpret_cast<Object *>(jsObjects + PropertyListProto); }
stringPrototypeExecutionEngine319     Object *stringPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringProto); }
numberPrototypeExecutionEngine320     Object *numberPrototype() const { return reinterpret_cast<Object *>(jsObjects + NumberProto); }
booleanPrototypeExecutionEngine321     Object *booleanPrototype() const { return reinterpret_cast<Object *>(jsObjects + BooleanProto); }
datePrototypeExecutionEngine322     Object *datePrototype() const { return reinterpret_cast<Object *>(jsObjects + DateProto); }
functionPrototypeExecutionEngine323     Object *functionPrototype() const { return reinterpret_cast<Object *>(jsObjects + FunctionProto); }
generatorPrototypeExecutionEngine324     Object *generatorPrototype() const { return reinterpret_cast<Object *>(jsObjects + GeneratorProto); }
regExpPrototypeExecutionEngine325     Object *regExpPrototype() const { return reinterpret_cast<Object *>(jsObjects + RegExpProto); }
errorPrototypeExecutionEngine326     Object *errorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ErrorProto); }
evalErrorPrototypeExecutionEngine327     Object *evalErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + EvalErrorProto); }
rangeErrorPrototypeExecutionEngine328     Object *rangeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + RangeErrorProto); }
referenceErrorPrototypeExecutionEngine329     Object *referenceErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ReferenceErrorProto); }
syntaxErrorPrototypeExecutionEngine330     Object *syntaxErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SyntaxErrorProto); }
typeErrorPrototypeExecutionEngine331     Object *typeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeErrorProto); }
uRIErrorPrototypeExecutionEngine332     Object *uRIErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + URIErrorProto); }
promisePrototypeExecutionEngine333     Object *promisePrototype() const { return reinterpret_cast<Object *>(jsObjects + PromiseProto); }
variantPrototypeExecutionEngine334     Object *variantPrototype() const { return reinterpret_cast<Object *>(jsObjects + VariantProto); }
335 #if QT_CONFIG(qml_sequence_object)
sequencePrototypeExecutionEngine336     Object *sequencePrototype() const { return reinterpret_cast<Object *>(jsObjects + SequenceProto); }
337 #endif
338 
sharedArrayBufferPrototypeExecutionEngine339     Object *sharedArrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + SharedArrayBufferProto); }
arrayBufferPrototypeExecutionEngine340     Object *arrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayBufferProto); }
dataViewPrototypeExecutionEngine341     Object *dataViewPrototype() const { return reinterpret_cast<Object *>(jsObjects + DataViewProto); }
weakSetPrototypeExecutionEngine342     Object *weakSetPrototype() const { return reinterpret_cast<Object *>(jsObjects + WeakSetProto); }
setPrototypeExecutionEngine343     Object *setPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetProto); }
weakMapPrototypeExecutionEngine344     Object *weakMapPrototype() const { return reinterpret_cast<Object *>(jsObjects + WeakMapProto); }
mapPrototypeExecutionEngine345     Object *mapPrototype() const { return reinterpret_cast<Object *>(jsObjects + MapProto); }
intrinsicTypedArrayPrototypeExecutionEngine346     Object *intrinsicTypedArrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + IntrinsicTypedArrayProto); }
347     Object *typedArrayPrototype;
348 
valueTypeWrapperPrototypeExecutionEngine349     Object *valueTypeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + ValueTypeProto); }
signalHandlerPrototypeExecutionEngine350     Object *signalHandlerPrototype() const { return reinterpret_cast<Object *>(jsObjects + SignalHandlerProto); }
iteratorPrototypeExecutionEngine351     Object *iteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + IteratorProto); }
forInIteratorPrototypeExecutionEngine352     Object *forInIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ForInIteratorProto); }
setIteratorPrototypeExecutionEngine353     Object *setIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetIteratorProto); }
mapIteratorPrototypeExecutionEngine354     Object *mapIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + MapIteratorProto); }
arrayIteratorPrototypeExecutionEngine355     Object *arrayIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayIteratorProto); }
stringIteratorPrototypeExecutionEngine356     Object *stringIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringIteratorProto); }
357 
evalFunctionExecutionEngine358     EvalFunction *evalFunction() const { return reinterpret_cast<EvalFunction *>(jsObjects + Eval_Function); }
getStackFunctionExecutionEngine359     FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); }
throwerExecutionEngine360     FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); }
361 
362 #if QT_CONFIG(qml_network)
363     QNetworkAccessManager* (*networkAccessManager)(ExecutionEngine*)  = detail::getNetworkAccessManager;
364 #endif
365 
366     enum JSStrings {
367         String_Empty,
368         String_undefined,
369         String_null,
370         String_true,
371         String_false,
372         String_boolean,
373         String_number,
374         String_string,
375         String_default,
376         String_symbol,
377         String_object,
378         String_function,
379         String_length,
380         String_prototype,
381         String_constructor,
382         String_arguments,
383         String_caller,
384         String_callee,
385         String_this,
386         String___proto__,
387         String_enumerable,
388         String_configurable,
389         String_writable,
390         String_value,
391         String_get,
392         String_set,
393         String_eval,
394         String_uintMax,
395         String_name,
396         String_index,
397         String_input,
398         String_toString,
399         String_toLocaleString,
400         String_destroy,
401         String_valueOf,
402         String_byteLength,
403         String_byteOffset,
404         String_buffer,
405         String_lastIndex,
406         String_next,
407         String_done,
408         String_return,
409         String_throw,
410         String_global,
411         String_ignoreCase,
412         String_multiline,
413         String_unicode,
414         String_sticky,
415         String_source,
416         String_flags,
417 
418         NJSStrings
419     };
420     Value *jsStrings;
421 
422     enum JSSymbols {
423         Symbol_hasInstance,
424         Symbol_isConcatSpreadable,
425         Symbol_iterator,
426         Symbol_match,
427         Symbol_replace,
428         Symbol_search,
429         Symbol_species,
430         Symbol_split,
431         Symbol_toPrimitive,
432         Symbol_toStringTag,
433         Symbol_unscopables,
434         Symbol_revokableProxy,
435         NJSSymbols
436     };
437     Value *jsSymbols;
438 
id_emptyExecutionEngine439     String *id_empty() const { return reinterpret_cast<String *>(jsStrings + String_Empty); }
id_undefinedExecutionEngine440     String *id_undefined() const { return reinterpret_cast<String *>(jsStrings + String_undefined); }
id_nullExecutionEngine441     String *id_null() const { return reinterpret_cast<String *>(jsStrings + String_null); }
id_trueExecutionEngine442     String *id_true() const { return reinterpret_cast<String *>(jsStrings + String_true); }
id_falseExecutionEngine443     String *id_false() const { return reinterpret_cast<String *>(jsStrings + String_false); }
id_booleanExecutionEngine444     String *id_boolean() const { return reinterpret_cast<String *>(jsStrings + String_boolean); }
id_numberExecutionEngine445     String *id_number() const { return reinterpret_cast<String *>(jsStrings + String_number); }
id_stringExecutionEngine446     String *id_string() const { return reinterpret_cast<String *>(jsStrings + String_string); }
id_defaultExecutionEngine447     String *id_default() const { return reinterpret_cast<String *>(jsStrings + String_default); }
id_symbolExecutionEngine448     String *id_symbol() const { return reinterpret_cast<String *>(jsStrings + String_symbol); }
id_objectExecutionEngine449     String *id_object() const { return reinterpret_cast<String *>(jsStrings + String_object); }
id_functionExecutionEngine450     String *id_function() const { return reinterpret_cast<String *>(jsStrings + String_function); }
id_lengthExecutionEngine451     String *id_length() const { return reinterpret_cast<String *>(jsStrings + String_length); }
id_prototypeExecutionEngine452     String *id_prototype() const { return reinterpret_cast<String *>(jsStrings + String_prototype); }
id_constructorExecutionEngine453     String *id_constructor() const { return reinterpret_cast<String *>(jsStrings + String_constructor); }
id_argumentsExecutionEngine454     String *id_arguments() const { return reinterpret_cast<String *>(jsStrings + String_arguments); }
id_callerExecutionEngine455     String *id_caller() const { return reinterpret_cast<String *>(jsStrings + String_caller); }
id_calleeExecutionEngine456     String *id_callee() const { return reinterpret_cast<String *>(jsStrings + String_callee); }
id_thisExecutionEngine457     String *id_this() const { return reinterpret_cast<String *>(jsStrings + String_this); }
id___proto__ExecutionEngine458     String *id___proto__() const { return reinterpret_cast<String *>(jsStrings + String___proto__); }
id_enumerableExecutionEngine459     String *id_enumerable() const { return reinterpret_cast<String *>(jsStrings + String_enumerable); }
id_configurableExecutionEngine460     String *id_configurable() const { return reinterpret_cast<String *>(jsStrings + String_configurable); }
id_writableExecutionEngine461     String *id_writable() const { return reinterpret_cast<String *>(jsStrings + String_writable); }
id_valueExecutionEngine462     String *id_value() const { return reinterpret_cast<String *>(jsStrings + String_value); }
id_getExecutionEngine463     String *id_get() const { return reinterpret_cast<String *>(jsStrings + String_get); }
id_setExecutionEngine464     String *id_set() const { return reinterpret_cast<String *>(jsStrings + String_set); }
id_evalExecutionEngine465     String *id_eval() const { return reinterpret_cast<String *>(jsStrings + String_eval); }
id_uintMaxExecutionEngine466     String *id_uintMax() const { return reinterpret_cast<String *>(jsStrings + String_uintMax); }
id_nameExecutionEngine467     String *id_name() const { return reinterpret_cast<String *>(jsStrings + String_name); }
id_indexExecutionEngine468     String *id_index() const { return reinterpret_cast<String *>(jsStrings + String_index); }
id_inputExecutionEngine469     String *id_input() const { return reinterpret_cast<String *>(jsStrings + String_input); }
id_toStringExecutionEngine470     String *id_toString() const { return reinterpret_cast<String *>(jsStrings + String_toString); }
id_toLocaleStringExecutionEngine471     String *id_toLocaleString() const { return reinterpret_cast<String *>(jsStrings + String_toLocaleString); }
id_destroyExecutionEngine472     String *id_destroy() const { return reinterpret_cast<String *>(jsStrings + String_destroy); }
id_valueOfExecutionEngine473     String *id_valueOf() const { return reinterpret_cast<String *>(jsStrings + String_valueOf); }
id_byteLengthExecutionEngine474     String *id_byteLength() const { return reinterpret_cast<String *>(jsStrings + String_byteLength); }
id_byteOffsetExecutionEngine475     String *id_byteOffset() const { return reinterpret_cast<String *>(jsStrings + String_byteOffset); }
id_bufferExecutionEngine476     String *id_buffer() const { return reinterpret_cast<String *>(jsStrings + String_buffer); }
id_lastIndexExecutionEngine477     String *id_lastIndex() const { return reinterpret_cast<String *>(jsStrings + String_lastIndex); }
id_nextExecutionEngine478     String *id_next() const { return reinterpret_cast<String *>(jsStrings + String_next); }
id_doneExecutionEngine479     String *id_done() const { return reinterpret_cast<String *>(jsStrings + String_done); }
id_returnExecutionEngine480     String *id_return() const { return reinterpret_cast<String *>(jsStrings + String_return); }
id_throwExecutionEngine481     String *id_throw() const { return reinterpret_cast<String *>(jsStrings + String_throw); }
id_globalExecutionEngine482     String *id_global() const { return reinterpret_cast<String *>(jsStrings + String_global); }
id_ignoreCaseExecutionEngine483     String *id_ignoreCase() const { return reinterpret_cast<String *>(jsStrings + String_ignoreCase); }
id_multilineExecutionEngine484     String *id_multiline() const { return reinterpret_cast<String *>(jsStrings + String_multiline); }
id_unicodeExecutionEngine485     String *id_unicode() const { return reinterpret_cast<String *>(jsStrings + String_unicode); }
id_stickyExecutionEngine486     String *id_sticky() const { return reinterpret_cast<String *>(jsStrings + String_sticky); }
id_sourceExecutionEngine487     String *id_source() const { return reinterpret_cast<String *>(jsStrings + String_source); }
id_flagsExecutionEngine488     String *id_flags() const { return reinterpret_cast<String *>(jsStrings + String_flags); }
489 
symbol_hasInstanceExecutionEngine490     Symbol *symbol_hasInstance() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_hasInstance); }
symbol_isConcatSpreadableExecutionEngine491     Symbol *symbol_isConcatSpreadable() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_isConcatSpreadable); }
symbol_iteratorExecutionEngine492     Symbol *symbol_iterator() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_iterator); }
symbol_matchExecutionEngine493     Symbol *symbol_match() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_match); }
symbol_replaceExecutionEngine494     Symbol *symbol_replace() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_replace); }
symbol_searchExecutionEngine495     Symbol *symbol_search() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_search); }
symbol_speciesExecutionEngine496     Symbol *symbol_species() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_species); }
symbol_splitExecutionEngine497     Symbol *symbol_split() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_split); }
symbol_toPrimitiveExecutionEngine498     Symbol *symbol_toPrimitive() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_toPrimitive); }
symbol_toStringTagExecutionEngine499     Symbol *symbol_toStringTag() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_toStringTag); }
symbol_unscopablesExecutionEngine500     Symbol *symbol_unscopables() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_unscopables); }
symbol_revokableProxyExecutionEngine501     Symbol *symbol_revokableProxy() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_revokableProxy); }
502 
503     QIntrusiveList<ExecutableCompilationUnit, &ExecutableCompilationUnit::nextCompilationUnit> compilationUnits;
504 
505     quint32 m_engineId;
506 
507     RegExpCache *regExpCache;
508 
509     // Scarce resources are "exceptionally high cost" QVariant types where allowing the
510     // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other
511     // out-of-resource situations.  When such a resource is passed into JavaScript we
512     // add it to the scarceResources list and it is destroyed when we return from the
513     // JavaScript execution that created it.  The user can prevent this behavior by
514     // calling preserve() on the object which removes it from this scarceResource list.
515     class ScarceResourceData {
516     public:
dataExecutionEngine517         ScarceResourceData(const QVariant &data = QVariant()) : data(data) {}
518         QVariant data;
519         QIntrusiveListNode node;
520     };
521     QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources;
522 
523     // Normally the JS wrappers for QObjects are stored in the QQmlData/QObjectPrivate,
524     // but any time a QObject is wrapped a second time in another engine, we have to do
525     // bookkeeping.
526     MultiplyWrappedQObjectMap *m_multiplyWrappedQObjects;
527 #if QT_CONFIG(qml_jit)
528     const bool m_canAllocateExecutableMemory;
529 #endif
530 
531     quintptr protoIdCount = 1;
532 
533     ExecutionEngine(QJSEngine *jsEngine = nullptr);
534     ~ExecutionEngine();
535 
536 #if !QT_CONFIG(qml_debug)
debuggerExecutionEngine537     QV4::Debugging::Debugger *debugger() const { return nullptr; }
profilerExecutionEngine538     QV4::Profiling::Profiler *profiler() const { return nullptr; }
539 
setDebuggerExecutionEngine540     void setDebugger(Debugging::Debugger *) {}
setProfilerExecutionEngine541     void setProfiler(Profiling::Profiler *) {}
542 #else
debuggerExecutionEngine543     QV4::Debugging::Debugger *debugger() const { return m_debugger.data(); }
profilerExecutionEngine544     QV4::Profiling::Profiler *profiler() const { return m_profiler.data(); }
545 
546     void setDebugger(Debugging::Debugger *debugger);
547     void setProfiler(Profiling::Profiler *profiler);
548 #endif // QT_CONFIG(qml_debug)
549 
550     ExecutionContext *currentContext() const;
551 
552     // ensure we always get odd prototype IDs. This helps make marking in QV4::Lookup fast
newProtoIdExecutionEngine553     quintptr newProtoId() { return (protoIdCount += 2); }
554 
555     Heap::InternalClass *newInternalClass(const VTable *vtable, Object *prototype);
556 
557     Heap::Object *newObject();
558     Heap::Object *newObject(Heap::InternalClass *internalClass);
559 
560     Heap::String *newString(const QString &s = QString());
561     Heap::String *newIdentifier(const QString &text);
562 
563     Heap::Object *newStringObject(const String *string);
564     Heap::Object *newSymbolObject(const Symbol *symbol);
565     Heap::Object *newNumberObject(double value);
566     Heap::Object *newBooleanObject(bool b);
567 
568     Heap::ArrayObject *newArrayObject(int count = 0);
569     Heap::ArrayObject *newArrayObject(const Value *values, int length);
570     Heap::ArrayObject *newArrayObject(const QStringList &list);
571     Heap::ArrayObject *newArrayObject(Heap::InternalClass *ic);
572 
573     Heap::ArrayBuffer *newArrayBuffer(const QByteArray &array);
574     Heap::ArrayBuffer *newArrayBuffer(size_t length);
575 
576     Heap::DateObject *newDateObject(const Value &value);
577     Heap::DateObject *newDateObject(const QDateTime &dt);
578     Heap::DateObject *newDateObjectFromTime(const QTime &t);
579 
580     Heap::RegExpObject *newRegExpObject(const QString &pattern, int flags);
581     Heap::RegExpObject *newRegExpObject(RegExp *re);
582     Heap::RegExpObject *newRegExpObject(const QRegExp &re);
583 #if QT_CONFIG(regularexpression)
584     Heap::RegExpObject *newRegExpObject(const QRegularExpression &re);
585 #endif
586 
587     Heap::Object *newErrorObject(const Value &value);
588     Heap::Object *newErrorObject(const QString &message);
589     Heap::Object *newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column);
590     Heap::Object *newSyntaxErrorObject(const QString &message);
591     Heap::Object *newReferenceErrorObject(const QString &message);
592     Heap::Object *newReferenceErrorObject(const QString &message, const QString &fileName, int line, int column);
593     Heap::Object *newTypeErrorObject(const QString &message);
594     Heap::Object *newRangeErrorObject(const QString &message);
595     Heap::Object *newURIErrorObject(const QString &message);
596     Heap::Object *newURIErrorObject(const Value &message);
597     Heap::Object *newEvalErrorObject(const QString &message);
598 
599     Heap::PromiseObject *newPromiseObject();
600     Heap::Object *newPromiseObject(const QV4::FunctionObject *thisObject, const QV4::PromiseCapability *capability);
601     Promise::ReactionHandler *getPromiseReactionHandler();
602 
603     Heap::Object *newVariantObject(const QVariant &v);
604 
605     Heap::Object *newForInIteratorObject(Object *o);
606     Heap::Object *newSetIteratorObject(Object *o);
607     Heap::Object *newMapIteratorObject(Object *o);
608     Heap::Object *newArrayIteratorObject(Object *o);
609 
610     Heap::QmlContext *qmlContext() const;
611     QObject *qmlScopeObject() const;
612     QQmlContextData *callingQmlContext() const;
613 
614 
615     StackTrace stackTrace(int frameLimit = -1) const;
616     QUrl resolvedUrl(const QString &file);
617 
618     void markObjects(MarkStack *markStack);
619 
620     void initRootContext();
621 
622     Heap::InternalClass *newClass(Heap::InternalClass *other);
623 
624     StackTrace exceptionStackTrace;
625 
626     ReturnedValue throwError(const Value &value);
627     ReturnedValue catchException(StackTrace *trace = nullptr);
628 
629     ReturnedValue throwError(const QString &message);
630     ReturnedValue throwSyntaxError(const QString &message);
631     ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int lineNumber, int column);
632     ReturnedValue throwTypeError();
633     ReturnedValue throwTypeError(const QString &message);
634     ReturnedValue throwReferenceError(const Value &value);
635     ReturnedValue throwReferenceError(const QString &name);
636     ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int lineNumber, int column);
637     ReturnedValue throwRangeError(const Value &value);
638     ReturnedValue throwRangeError(const QString &message);
639     ReturnedValue throwURIError(const Value &msg);
640     ReturnedValue throwUnimplemented(const QString &message);
641 
642     // Use only inside catch(...) -- will re-throw if no JS exception
643     QQmlError catchExceptionAsQmlError();
644 
645     // variant conversions
646     QVariant toVariant(const QV4::Value &value, int typeHint, bool createJSValueForObjects = true);
647     QV4::ReturnedValue fromVariant(const QVariant &);
648 
649     QVariantMap variantMapFromJS(const QV4::Object *o);
650 
651     bool metaTypeFromJS(const Value *value, int type, void *data);
652     QV4::ReturnedValue metaTypeToJS(int type, const void *data);
653 
654     int maxJSStackSize() const;
655     int maxGCStackSize() const;
656 
657     bool checkStackLimits();
658 
659     bool canJIT(Function *f = nullptr)
660     {
661 #if QT_CONFIG(qml_jit)
662         if (!m_canAllocateExecutableMemory)
663             return false;
664         if (f)
665             return !f->isGenerator() && f->interpreterCallCount >= jitCallCountThreshold;
666         return true;
667 #else
668         Q_UNUSED(f);
669         return false;
670 #endif
671     }
672 
673     QV4::ReturnedValue global();
674     void initQmlGlobalObject();
675     void initializeGlobal();
676 
677     void freezeObject(const QV4::Value &value);
678 
679     // Return the list of illegal id names (the names of the properties on the global object)
680     const QSet<QString> &illegalNames() const;
681 
682 #if QT_CONFIG(qml_xml_http_request)
xmlHttpRequestDataExecutionEngine683     void *xmlHttpRequestData() const { return m_xmlHttpRequestData; }
684 #endif
685 
686     void setQmlEngine(QQmlEngine *engine);
687 
delayedCallQueueExecutionEngine688     QQmlDelayedCallQueue *delayedCallQueue() { return &m_delayedCallQueue; }
689 
690     // used for console.time(), console.timeEnd()
691     void startTimer(const QString &timerName);
692     qint64 stopTimer(const QString &timerName, bool *wasRunning);
693 
694     // used for console.count()
695     int consoleCountHelper(const QString &file, quint16 line, quint16 column);
696 
697     struct Deletable {
~DeletableExecutionEngine::Deletable698         virtual ~Deletable() {}
699     };
700 
701     static QMutex *registrationMutex();
702     static int registerExtension();
703 
704     void setExtensionData(int, Deletable *);
extensionDataExecutionEngine705     Deletable *extensionData(int index) const
706     {
707         if (index < m_extensionData.count())
708             return m_extensionData[index];
709         else
710             return nullptr;
711     }
712 
713     double localTZA = 0.0; // local timezone, initialized at startup
714 
715     QQmlRefPointer<ExecutableCompilationUnit> compileModule(const QUrl &url);
716     QQmlRefPointer<ExecutableCompilationUnit> compileModule(
717             const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp);
718 
719     mutable QMutex moduleMutex;
720     QHash<QUrl, QQmlRefPointer<ExecutableCompilationUnit>> modules;
721     void injectModule(const QQmlRefPointer<ExecutableCompilationUnit> &moduleUnit);
722     QQmlRefPointer<ExecutableCompilationUnit> moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr) const;
723     QQmlRefPointer<ExecutableCompilationUnit> loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr);
724 
725 private:
726 #if QT_CONFIG(qml_debug)
727     QScopedPointer<QV4::Debugging::Debugger> m_debugger;
728     QScopedPointer<QV4::Profiling::Profiler> m_profiler;
729 #endif
730     QSet<QString> m_illegalNames;
731     int jitCallCountThreshold;
732 
733     // used by generated Promise objects to handle 'then' events
734     QScopedPointer<QV4::Promise::ReactionHandler> m_reactionHandler;
735 
736 #if QT_CONFIG(qml_xml_http_request)
737     void *m_xmlHttpRequestData;
738 #endif
739 
740     QQmlEngine *m_qmlEngine;
741 
742     QQmlDelayedCallQueue m_delayedCallQueue;
743 
744     QElapsedTimer m_time;
745     QHash<QString, qint64> m_startedTimers;
746 
747     QHash<QString, quint32> m_consoleCount;
748 
749     QVector<Deletable *> m_extensionData;
750 
751     int m_maxJSStackSize = 4 * 1024 * 1024;
752     int m_maxGCStackSize = 2 * 1024 * 1024;
753 };
754 
755 #define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \
756     ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4);
757 
758 struct ExecutionEngineCallDepthRecorder
759 {
760     ExecutionEngine *ee;
761 
ExecutionEngineCallDepthRecorderExecutionEngineCallDepthRecorder762     ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ++ee->callDepth; }
~ExecutionEngineCallDepthRecorderExecutionEngineCallDepthRecorder763     ~ExecutionEngineCallDepthRecorder() { --ee->callDepth; }
764 };
765 
checkStackLimits()766 inline bool ExecutionEngine::checkStackLimits()
767 {
768     if (Q_UNLIKELY((jsStackTop > jsStackLimit) || (callDepth >= maxCallDepth))) {
769         throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
770         return true;
771     }
772 
773     return false;
774 }
775 
776 } // namespace QV4
777 
778 QT_END_NAMESPACE
779 
780 #endif // QV4ENGINE_H
781