1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#ifndef QV4ENGINE_H
4#define QV4ENGINE_H
5
6//
7// W A R N I N G
8// -------------
9//
10// This file is not part of the Qt API. It exists purely as an
11// implementation detail. This header file may change from version to
12// version without notice, or even be removed.
13//
14// We mean it.
15//
16
17#include <private/qintrusivelist_p.h>
18#include <private/qqmldelayedcallqueue_p.h>
19#include <private/qqmlrefcount_p.h>
20#include <private/qv4compileddata_p.h>
21#include <private/qv4context_p.h>
22#include <private/qv4enginebase_p.h>
23#include <private/qv4executablecompilationunit_p.h>
24#include <private/qv4global_p.h>
25#include <private/qv4stacklimits_p.h>
26
27#include <QtCore/qelapsedtimer.h>
28#include <QtCore/qmutex.h>
29#include <QtCore/qprocessordetection.h>
30#include <QtCore/qset.h>
31
32namespace WTF {
33class BumpPointerAllocator;
34class PageAllocation;
35}
36
37#define V4_DEFINE_EXTENSION(dataclass, datafunction) \
38 static inline dataclass *datafunction(QV4::ExecutionEngine *engine) \
39 { \
40 static int extensionId = -1; \
41 if (extensionId == -1) { \
42 QV4::ExecutionEngine::registrationMutex()->lock(); \
43 if (extensionId == -1) \
44 extensionId = QV4::ExecutionEngine::registerExtension(); \
45 QV4::ExecutionEngine::registrationMutex()->unlock(); \
46 } \
47 dataclass *rv = (dataclass *)engine->extensionData(extensionId); \
48 if (!rv) { \
49 rv = new dataclass(engine); \
50 engine->setExtensionData(extensionId, rv); \
51 } \
52 return rv; \
53 } \
54
55
56QT_BEGIN_NAMESPACE
57
58#if QT_CONFIG(qml_network)
59class QNetworkAccessManager;
60
61namespace QV4 {
62struct QObjectMethod;
63namespace detail {
64QNetworkAccessManager *getNetworkAccessManager(ExecutionEngine *engine);
65}
66}
67#else
68namespace QV4 { struct QObjectMethod; }
69#endif // qml_network
70
71// Used to allow a QObject method take and return raw V4 handles without having to expose
72// 48 in the public API.
73// Use like this:
74// class MyClass : public QObject {
75// Q_OBJECT
76// ...
77// Q_INVOKABLE void myMethod(QQmlV4FunctionPtr);
78// };
79// The QQmlV8Function - and consequently the arguments and return value - only remains
80// valid during the call. If the return value isn't set within myMethod(), the will return
81// undefined.
82
83class QQmlV4Function
84{
85public:
86 int length() const { return callData->argc(); }
87 QV4::ReturnedValue operator[](int idx) const { return (idx < callData->argc() ? callData->args[idx].asReturnedValue() : QV4::Encode::undefined()); }
88 void setReturnValue(QV4::ReturnedValue rv) { *retVal = rv; }
89 QV4::ExecutionEngine *v4engine() const { return e; }
90private:
91 friend struct QV4::QObjectMethod;
92 QQmlV4Function();
93 QQmlV4Function(const QQmlV4Function &);
94 QQmlV4Function &operator=(const QQmlV4Function &);
95
96 QQmlV4Function(QV4::CallData *callData, QV4::Value *retVal, QV4::ExecutionEngine *e)
97 : callData(callData), retVal(retVal), e(e)
98 {
99 callData->thisObject = QV4::Encode::undefined();
100 }
101
102 QV4::CallData *callData;
103 QV4::Value *retVal;
104 QV4::ExecutionEngine *e;
105};
106
107class QQmlError;
108class QJSEngine;
109class QQmlEngine;
110class QQmlContextData;
111class QQmlTypeLoader;
112
113namespace QV4 {
114namespace Debugging {
115class Debugger;
116} // namespace Debugging
117namespace Profiling {
118class Profiler;
119} // namespace Profiling
120namespace CompiledData {
121struct CompilationUnit;
122}
123
124namespace Heap {
125struct Module;
126};
127
128struct Function;
129
130namespace Promise {
131class ReactionHandler;
132};
133
134struct Q_QML_EXPORT ExecutionEngine : public EngineBase
135{
136private:
137 friend struct ExecutionContextSaver;
138 friend struct ExecutionContext;
139 friend struct Heap::ExecutionContext;
140public:
141 enum class DiskCache : quint8 {
142 Disabled = 0,
143 AotByteCode = 1 << 0,
144 AotNative = 1 << 1,
145 QmlcRead = 1 << 2,
146 QmlcWrite = 1 << 3,
147 Aot = AotByteCode | AotNative,
148 Qmlc = QmlcRead | QmlcWrite,
149 Enabled = Aot | Qmlc,
150
151 };
152
153 Q_DECLARE_FLAGS(DiskCacheOptions, DiskCache);
154
155 ExecutableAllocator *executableAllocator = nullptr;
156 ExecutableAllocator *regExpAllocator = nullptr;
157
158 WTF::BumpPointerAllocator *bumperPointerAllocator = nullptr; // Used by Yarr Regex engine.
159
160 WTF::PageAllocation *jsStack = nullptr;
161
162 WTF::PageAllocation *gcStack = nullptr;
163
164 QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) {
165 Value *ptr = jsStackTop;
166 jsStackTop = ptr + nValues;
167 return ptr;
168 }
169
170 Function *globalCode = nullptr;
171
172 QJSEngine *jsEngine() const { return publicEngine; }
173 QQmlEngine *qmlEngine() const { return m_qmlEngine; }
174 QJSEngine *publicEngine = nullptr;
175
176 template<typename TypeLoader = QQmlTypeLoader>
177 TypeLoader *typeLoader()
178 {
179 if (m_qmlEngine)
180 return TypeLoader::get(m_qmlEngine);
181 return nullptr;
182 }
183
184 enum JSObjects {
185 RootContext,
186 ScriptContext,
187 IntegerNull, // Has to come after the RootContext to make the context stack safe
188 ObjectProto,
189 SymbolProto,
190 ArrayProto,
191 ArrayProtoValues,
192 PropertyListProto,
193 StringProto,
194 NumberProto,
195 BooleanProto,
196 DateProto,
197 FunctionProto,
198 GeneratorProto,
199 RegExpProto,
200 ErrorProto,
201 EvalErrorProto,
202 RangeErrorProto,
203 ReferenceErrorProto,
204 SyntaxErrorProto,
205 TypeErrorProto,
206 URIErrorProto,
207 PromiseProto,
208 VariantProto,
209 VariantAssociationProto,
210 SequenceProto,
211 SharedArrayBufferProto,
212 ArrayBufferProto,
213 DataViewProto,
214 WeakSetProto,
215 SetProto,
216 WeakMapProto,
217 MapProto,
218 IntrinsicTypedArrayProto,
219 ValueTypeProto,
220 TypeWrapperProto,
221 SignalHandlerProto,
222 IteratorProto,
223 ForInIteratorProto,
224 SetIteratorProto,
225 MapIteratorProto,
226 ArrayIteratorProto,
227 StringIteratorProto,
228 UrlProto,
229 UrlSearchParamsProto,
230
231 Object_Ctor,
232 String_Ctor,
233 Symbol_Ctor,
234 Number_Ctor,
235 Boolean_Ctor,
236 Array_Ctor,
237 Function_Ctor,
238 GeneratorFunction_Ctor,
239 Date_Ctor,
240 RegExp_Ctor,
241 Error_Ctor,
242 EvalError_Ctor,
243 RangeError_Ctor,
244 ReferenceError_Ctor,
245 SyntaxError_Ctor,
246 TypeError_Ctor,
247 URIError_Ctor,
248 SharedArrayBuffer_Ctor,
249 Promise_Ctor,
250 ArrayBuffer_Ctor,
251 DataView_Ctor,
252 WeakSet_Ctor,
253 Set_Ctor,
254 WeakMap_Ctor,
255 Map_Ctor,
256 IntrinsicTypedArray_Ctor,
257 Url_Ctor,
258 UrlSearchParams_Ctor,
259
260 GetSymbolSpecies,
261
262 Eval_Function,
263 GetStack_Function,
264 ThrowerObject,
265 NJSObjects
266 };
267 Value *jsObjects = nullptr;
268 enum { NTypedArrayTypes = 9 }; // == TypedArray::NValues, avoid header dependency
269
270 ExecutionContext *rootContext() const { return reinterpret_cast<ExecutionContext *>(jsObjects + RootContext); }
271 ExecutionContext *scriptContext() const { return reinterpret_cast<ExecutionContext *>(jsObjects + ScriptContext); }
272 void setScriptContext(ReturnedValue c) { jsObjects[ScriptContext] = c; }
273 FunctionObject *objectCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Object_Ctor); }
274 FunctionObject *stringCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + String_Ctor); }
275 FunctionObject *symbolCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Symbol_Ctor); }
276 FunctionObject *numberCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Number_Ctor); }
277 FunctionObject *booleanCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Boolean_Ctor); }
278 FunctionObject *arrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Array_Ctor); }
279 FunctionObject *functionCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Function_Ctor); }
280 FunctionObject *generatorFunctionCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + GeneratorFunction_Ctor); }
281 FunctionObject *dateCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Date_Ctor); }
282 FunctionObject *regExpCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + RegExp_Ctor); }
283 FunctionObject *errorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Error_Ctor); }
284 FunctionObject *evalErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + EvalError_Ctor); }
285 FunctionObject *rangeErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + RangeError_Ctor); }
286 FunctionObject *referenceErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ReferenceError_Ctor); }
287 FunctionObject *syntaxErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + SyntaxError_Ctor); }
288 FunctionObject *typeErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + TypeError_Ctor); }
289 FunctionObject *uRIErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + URIError_Ctor); }
290 FunctionObject *sharedArrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + SharedArrayBuffer_Ctor); }
291 FunctionObject *promiseCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Promise_Ctor); }
292 FunctionObject *arrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ArrayBuffer_Ctor); }
293 FunctionObject *dataViewCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + DataView_Ctor); }
294 FunctionObject *weakSetCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + WeakSet_Ctor); }
295 FunctionObject *setCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Set_Ctor); }
296 FunctionObject *weakMapCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + WeakMap_Ctor); }
297 FunctionObject *mapCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Map_Ctor); }
298 FunctionObject *intrinsicTypedArrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + IntrinsicTypedArray_Ctor); }
299 FunctionObject *urlCtor() const
300 {
301 return reinterpret_cast<FunctionObject *>(jsObjects + Url_Ctor);
302 }
303 FunctionObject *urlSearchParamsCtor() const
304 {
305 return reinterpret_cast<FunctionObject *>(jsObjects + UrlSearchParams_Ctor);
306 }
307 FunctionObject *typedArrayCtors = nullptr;
308
309 FunctionObject *getSymbolSpecies() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetSymbolSpecies); }
310
311 Object *objectPrototype() const { return reinterpret_cast<Object *>(jsObjects + ObjectProto); }
312 Object *symbolPrototype() const { return reinterpret_cast<Object *>(jsObjects + SymbolProto); }
313 Object *arrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayProto); }
314 Object *arrayProtoValues() const { return reinterpret_cast<Object *>(jsObjects + ArrayProtoValues); }
315 Object *propertyListPrototype() const { return reinterpret_cast<Object *>(jsObjects + PropertyListProto); }
316 Object *stringPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringProto); }
317 Object *numberPrototype() const { return reinterpret_cast<Object *>(jsObjects + NumberProto); }
318 Object *booleanPrototype() const { return reinterpret_cast<Object *>(jsObjects + BooleanProto); }
319 Object *datePrototype() const { return reinterpret_cast<Object *>(jsObjects + DateProto); }
320 Object *functionPrototype() const { return reinterpret_cast<Object *>(jsObjects + FunctionProto); }
321 Object *generatorPrototype() const { return reinterpret_cast<Object *>(jsObjects + GeneratorProto); }
322 Object *regExpPrototype() const { return reinterpret_cast<Object *>(jsObjects + RegExpProto); }
323 Object *errorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ErrorProto); }
324 Object *evalErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + EvalErrorProto); }
325 Object *rangeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + RangeErrorProto); }
326 Object *referenceErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ReferenceErrorProto); }
327 Object *syntaxErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SyntaxErrorProto); }
328 Object *typeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeErrorProto); }
329 Object *uRIErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + URIErrorProto); }
330 Object *promisePrototype() const { return reinterpret_cast<Object *>(jsObjects + PromiseProto); }
331 Object *variantPrototype() const { return reinterpret_cast<Object *>(jsObjects + VariantProto); }
332 Object *variantAssociationPrototype() const { return reinterpret_cast<Object *>(jsObjects + VariantAssociationProto); }
333 Object *sequencePrototype() const { return reinterpret_cast<Object *>(jsObjects + SequenceProto); }
334
335 Object *sharedArrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + SharedArrayBufferProto); }
336 Object *arrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayBufferProto); }
337 Object *dataViewPrototype() const { return reinterpret_cast<Object *>(jsObjects + DataViewProto); }
338 Object *weakSetPrototype() const { return reinterpret_cast<Object *>(jsObjects + WeakSetProto); }
339 Object *setPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetProto); }
340 Object *weakMapPrototype() const { return reinterpret_cast<Object *>(jsObjects + WeakMapProto); }
341 Object *mapPrototype() const { return reinterpret_cast<Object *>(jsObjects + MapProto); }
342 Object *intrinsicTypedArrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + IntrinsicTypedArrayProto); }
343 Object *typedArrayPrototype = nullptr;
344
345 Object *valueTypeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + ValueTypeProto); }
346 Object *signalHandlerPrototype() const { return reinterpret_cast<Object *>(jsObjects + SignalHandlerProto); }
347 Object *typeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeWrapperProto); }
348 Object *iteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + IteratorProto); }
349 Object *forInIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ForInIteratorProto); }
350 Object *setIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetIteratorProto); }
351 Object *mapIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + MapIteratorProto); }
352 Object *arrayIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayIteratorProto); }
353 Object *stringIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringIteratorProto); }
354 Object *urlPrototype() const { return reinterpret_cast<Object *>(jsObjects + UrlProto); }
355 Object *urlSearchParamsPrototype() const { return reinterpret_cast<Object *>(jsObjects + UrlSearchParamsProto); }
356
357 EvalFunction *evalFunction() const { return reinterpret_cast<EvalFunction *>(jsObjects + Eval_Function); }
358 FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); }
359 FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); }
360
361#if QT_CONFIG(qml_network)
362 QNetworkAccessManager* (*networkAccessManager)(ExecutionEngine*) = detail::getNetworkAccessManager;
363#endif
364
365 enum JSStrings {
366 String_Empty,
367 String_undefined,
368 String_null,
369 String_true,
370 String_false,
371 String_boolean,
372 String_number,
373 String_string,
374 String_default,
375 String_symbol,
376 String_object,
377 String_function,
378 String_length,
379 String_prototype,
380 String_constructor,
381 String_arguments,
382 String_caller,
383 String_callee,
384 String_this,
385 String___proto__,
386 String_enumerable,
387 String_configurable,
388 String_writable,
389 String_value,
390 String_get,
391 String_set,
392 String_eval,
393 String_uintMax,
394 String_name,
395 String_index,
396 String_input,
397 String_toString,
398 String_toLocaleString,
399 String_destroy,
400 String_valueOf,
401 String_byteLength,
402 String_byteOffset,
403 String_buffer,
404 String_lastIndex,
405 String_next,
406 String_done,
407 String_return,
408 String_throw,
409 String_global,
410 String_ignoreCase,
411 String_multiline,
412 String_unicode,
413 String_sticky,
414 String_source,
415 String_flags,
416
417 NJSStrings
418 };
419 Value *jsStrings = nullptr;
420
421 enum JSSymbols {
422 Symbol_hasInstance,
423 Symbol_isConcatSpreadable,
424 Symbol_iterator,
425 Symbol_match,
426 Symbol_replace,
427 Symbol_search,
428 Symbol_species,
429 Symbol_split,
430 Symbol_toPrimitive,
431 Symbol_toStringTag,
432 Symbol_unscopables,
433 Symbol_revokableProxy,
434 NJSSymbols
435 };
436 Value *jsSymbols = nullptr;
437
438 String *id_empty() const { return reinterpret_cast<String *>(jsStrings + String_Empty); }
439 String *id_undefined() const { return reinterpret_cast<String *>(jsStrings + String_undefined); }
440 String *id_null() const { return reinterpret_cast<String *>(jsStrings + String_null); }
441 String *id_true() const { return reinterpret_cast<String *>(jsStrings + String_true); }
442 String *id_false() const { return reinterpret_cast<String *>(jsStrings + String_false); }
443 String *id_boolean() const { return reinterpret_cast<String *>(jsStrings + String_boolean); }
444 String *id_number() const { return reinterpret_cast<String *>(jsStrings + String_number); }
445 String *id_string() const { return reinterpret_cast<String *>(jsStrings + String_string); }
446 String *id_default() const { return reinterpret_cast<String *>(jsStrings + String_default); }
447 String *id_symbol() const { return reinterpret_cast<String *>(jsStrings + String_symbol); }
448 String *id_object() const { return reinterpret_cast<String *>(jsStrings + String_object); }
449 String *id_function() const { return reinterpret_cast<String *>(jsStrings + String_function); }
450 String *id_length() const { return reinterpret_cast<String *>(jsStrings + String_length); }
451 String *id_prototype() const { return reinterpret_cast<String *>(jsStrings + String_prototype); }
452 String *id_constructor() const { return reinterpret_cast<String *>(jsStrings + String_constructor); }
453 String *id_arguments() const { return reinterpret_cast<String *>(jsStrings + String_arguments); }
454 String *id_caller() const { return reinterpret_cast<String *>(jsStrings + String_caller); }
455 String *id_callee() const { return reinterpret_cast<String *>(jsStrings + String_callee); }
456 String *id_this() const { return reinterpret_cast<String *>(jsStrings + String_this); }
457 String *id___proto__() const { return reinterpret_cast<String *>(jsStrings + String___proto__); }
458 String *id_enumerable() const { return reinterpret_cast<String *>(jsStrings + String_enumerable); }
459 String *id_configurable() const { return reinterpret_cast<String *>(jsStrings + String_configurable); }
460 String *id_writable() const { return reinterpret_cast<String *>(jsStrings + String_writable); }
461 String *id_value() const { return reinterpret_cast<String *>(jsStrings + String_value); }
462 String *id_get() const { return reinterpret_cast<String *>(jsStrings + String_get); }
463 String *id_set() const { return reinterpret_cast<String *>(jsStrings + String_set); }
464 String *id_eval() const { return reinterpret_cast<String *>(jsStrings + String_eval); }
465 String *id_uintMax() const { return reinterpret_cast<String *>(jsStrings + String_uintMax); }
466 String *id_name() const { return reinterpret_cast<String *>(jsStrings + String_name); }
467 String *id_index() const { return reinterpret_cast<String *>(jsStrings + String_index); }
468 String *id_input() const { return reinterpret_cast<String *>(jsStrings + String_input); }
469 String *id_toString() const { return reinterpret_cast<String *>(jsStrings + String_toString); }
470 String *id_toLocaleString() const { return reinterpret_cast<String *>(jsStrings + String_toLocaleString); }
471 String *id_destroy() const { return reinterpret_cast<String *>(jsStrings + String_destroy); }
472 String *id_valueOf() const { return reinterpret_cast<String *>(jsStrings + String_valueOf); }
473 String *id_byteLength() const { return reinterpret_cast<String *>(jsStrings + String_byteLength); }
474 String *id_byteOffset() const { return reinterpret_cast<String *>(jsStrings + String_byteOffset); }
475 String *id_buffer() const { return reinterpret_cast<String *>(jsStrings + String_buffer); }
476 String *id_lastIndex() const { return reinterpret_cast<String *>(jsStrings + String_lastIndex); }
477 String *id_next() const { return reinterpret_cast<String *>(jsStrings + String_next); }
478 String *id_done() const { return reinterpret_cast<String *>(jsStrings + String_done); }
479 String *id_return() const { return reinterpret_cast<String *>(jsStrings + String_return); }
480 String *id_throw() const { return reinterpret_cast<String *>(jsStrings + String_throw); }
481 String *id_global() const { return reinterpret_cast<String *>(jsStrings + String_global); }
482 String *id_ignoreCase() const { return reinterpret_cast<String *>(jsStrings + String_ignoreCase); }
483 String *id_multiline() const { return reinterpret_cast<String *>(jsStrings + String_multiline); }
484 String *id_unicode() const { return reinterpret_cast<String *>(jsStrings + String_unicode); }
485 String *id_sticky() const { return reinterpret_cast<String *>(jsStrings + String_sticky); }
486 String *id_source() const { return reinterpret_cast<String *>(jsStrings + String_source); }
487 String *id_flags() const { return reinterpret_cast<String *>(jsStrings + String_flags); }
488
489 Symbol *symbol_hasInstance() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_hasInstance); }
490 Symbol *symbol_isConcatSpreadable() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_isConcatSpreadable); }
491 Symbol *symbol_iterator() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_iterator); }
492 Symbol *symbol_match() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_match); }
493 Symbol *symbol_replace() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_replace); }
494 Symbol *symbol_search() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_search); }
495 Symbol *symbol_species() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_species); }
496 Symbol *symbol_split() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_split); }
497 Symbol *symbol_toPrimitive() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_toPrimitive); }
498 Symbol *symbol_toStringTag() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_toStringTag); }
499 Symbol *symbol_unscopables() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_unscopables); }
500 Symbol *symbol_revokableProxy() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_revokableProxy); }
501
502 quint32 m_engineId = 0;
503
504 RegExpCache *regExpCache = nullptr;
505
506 // Scarce resources are "exceptionally high cost" QVariant types where allowing the
507 // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other
508 // out-of-resource situations. When such a resource is passed into JavaScript we
509 // add it to the scarceResources list and it is destroyed when we return from the
510 // JavaScript execution that created it. The user can prevent this behavior by
511 // calling preserve() on the object which removes it from this scarceResource list.
512 class ScarceResourceData {
513 public:
514 ScarceResourceData() = default;
515 ScarceResourceData(const QMetaType type, const void *data) : data(type, data) {}
516 QVariant data;
517 QIntrusiveListNode node;
518 };
519 QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources;
520
521 // Normally the JS wrappers for QObjects are stored in the QQmlData/QObjectPrivate,
522 // but any time a QObject is wrapped a second time in another engine, we have to do
523 // bookkeeping.
524 MultiplyWrappedQObjectMap *m_multiplyWrappedQObjects = nullptr;
525#if QT_CONFIG(qml_jit)
526 const bool m_canAllocateExecutableMemory = false;
527#endif
528
529 quintptr protoIdCount = 1;
530
531 ExecutionEngine(QJSEngine *jsEngine = nullptr);
532 ~ExecutionEngine();
533
534#if !QT_CONFIG(qml_debug)
535 QV4::Debugging::Debugger *debugger() const { return nullptr; }
536 QV4::Profiling::Profiler *profiler() const { return nullptr; }
537
538 void setDebugger(Debugging::Debugger *) {}
539 void setProfiler(Profiling::Profiler *) {}
540 static void setPreviewing(bool) {}
541#else
542 QV4::Debugging::Debugger *debugger() const { return m_debugger.data(); }
543 QV4::Profiling::Profiler *profiler() const { return m_profiler.data(); }
544
545 void setDebugger(Debugging::Debugger *debugger);
546 void setProfiler(Profiling::Profiler *profiler);
547 static void setPreviewing(bool enabled);
548#endif // QT_CONFIG(qml_debug)
549
550 // We don't want to #include <private/qv4stackframe_p.h> here, but we still want
551 // currentContext() to be inline. Therefore we shift the requirement to provide the
552 // complete type of CppStackFrame to the caller by making this a template.
553 template<typename StackFrame = CppStackFrame>
554 ExecutionContext *currentContext() const
555 {
556 return static_cast<const StackFrame *>(currentStackFrame)->context();
557 }
558
559 // ensure we always get odd prototype IDs. This helps make marking in QV4::Lookup fast
560 quintptr newProtoId() { return (protoIdCount += 2); }
561
562 Heap::InternalClass *newInternalClass(const VTable *vtable, Object *prototype);
563
564 Heap::Object *newObject();
565 Heap::Object *newObject(Heap::InternalClass *internalClass);
566
567 Heap::String *newString(char16_t c) { return newString(s: QChar(c)); }
568 Heap::String *newString(const QString &s = QString());
569 Heap::String *newIdentifier(const QString &text);
570
571 Heap::Object *newStringObject(const String *string);
572 Heap::Object *newSymbolObject(const Symbol *symbol);
573 Heap::Object *newNumberObject(double value);
574 Heap::Object *newBooleanObject(bool b);
575
576 Heap::ArrayObject *newArrayObject(int count = 0);
577 Heap::ArrayObject *newArrayObject(const Value *values, int length);
578 Heap::ArrayObject *newArrayObject(const QStringList &list);
579 Heap::ArrayObject *newArrayObject(Heap::InternalClass *ic);
580
581 Heap::ArrayBuffer *newArrayBuffer(const QByteArray &array);
582 Heap::ArrayBuffer *newArrayBuffer(size_t length);
583
584 Heap::DateObject *newDateObject(double dateTime);
585 Heap::DateObject *newDateObject(const QDateTime &dateTime);
586 Heap::DateObject *newDateObject(QDate date, Heap::Object *parent, int index, uint flags);
587 Heap::DateObject *newDateObject(QTime time, Heap::Object *parent, int index, uint flags);
588 Heap::DateObject *newDateObject(QDateTime dateTime, Heap::Object *parent, int index, uint flags);
589
590 Heap::RegExpObject *newRegExpObject(const QString &pattern, int flags);
591 Heap::RegExpObject *newRegExpObject(RegExp *re);
592#if QT_CONFIG(regularexpression)
593 Heap::RegExpObject *newRegExpObject(const QRegularExpression &re);
594#endif
595
596 Heap::UrlObject *newUrlObject();
597 Heap::UrlObject *newUrlObject(const QUrl &url);
598 Heap::UrlSearchParamsObject *newUrlSearchParamsObject();
599
600 Heap::Object *newErrorObject(const Value &value);
601 Heap::Object *newErrorObject(const QString &message);
602 Heap::Object *newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column);
603 Heap::Object *newSyntaxErrorObject(const QString &message);
604 Heap::Object *newReferenceErrorObject(const QString &message);
605 Heap::Object *newReferenceErrorObject(const QString &message, const QString &fileName, int line, int column);
606 Heap::Object *newTypeErrorObject(const QString &message);
607 Heap::Object *newRangeErrorObject(const QString &message);
608 Heap::Object *newURIErrorObject(const QString &message);
609 Heap::Object *newURIErrorObject(const Value &message);
610 Heap::Object *newEvalErrorObject(const QString &message);
611
612 Heap::PromiseObject *newPromiseObject();
613 Heap::Object *newPromiseObject(const QV4::FunctionObject *thisObject, const QV4::PromiseCapability *capability);
614 Promise::ReactionHandler *getPromiseReactionHandler();
615
616 Heap::Object *newVariantObject(const QMetaType type, const void *data);
617
618 Heap::Object *newForInIteratorObject(Object *o);
619 Heap::Object *newSetIteratorObject(Object *o);
620 Heap::Object *newMapIteratorObject(Object *o);
621 Heap::Object *newArrayIteratorObject(Object *o);
622
623 static Heap::ExecutionContext *qmlContext(Heap::ExecutionContext *ctx)
624 {
625 Heap::ExecutionContext *outer = ctx->outer;
626
627 if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !outer)
628 return nullptr;
629
630 while (outer && outer->type != Heap::ExecutionContext::Type_GlobalContext) {
631 ctx = outer;
632 outer = ctx->outer;
633 }
634
635 Q_ASSERT(ctx);
636 if (ctx->type != Heap::ExecutionContext::Type_QmlContext)
637 return nullptr;
638
639 return ctx;
640 }
641
642 Heap::QmlContext *qmlContext() const;
643 QObject *qmlScopeObject() const;
644 QQmlRefPointer<QQmlContextData> callingQmlContext() const;
645
646
647 StackTrace stackTrace(int frameLimit = -1) const;
648 QUrl resolvedUrl(const QString &file);
649
650 void markObjects(MarkStack *markStack);
651
652 void initRootContext();
653
654 Heap::InternalClass *newClass(Heap::InternalClass *other);
655
656 StackTrace exceptionStackTrace;
657
658 ReturnedValue throwError(const Value &value);
659 ReturnedValue catchException(StackTrace *trace = nullptr);
660
661 ReturnedValue throwError(const QString &message);
662 ReturnedValue throwSyntaxError(const QString &message);
663 ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int lineNumber, int column);
664 ReturnedValue throwTypeError();
665 ReturnedValue throwTypeError(const QString &message);
666 ReturnedValue throwReferenceError(const Value &value);
667 ReturnedValue throwReferenceError(const QString &name);
668 ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int lineNumber, int column);
669 ReturnedValue throwRangeError(const Value &value);
670 ReturnedValue throwRangeError(const QString &message);
671 ReturnedValue throwURIError(const Value &msg);
672 ReturnedValue throwUnimplemented(const QString &message);
673
674 // Use only inside catch(...) -- will re-throw if no JS exception
675 QQmlError catchExceptionAsQmlError();
676
677 void amendException();
678
679 // variant conversions
680 static QVariant toVariant(
681 const QV4::Value &value, QMetaType typeHint, bool createJSValueForObjectsAndSymbols = true);
682 static QVariant toVariantLossy(const QV4::Value &value);
683 QV4::ReturnedValue fromVariant(const QVariant &);
684 QV4::ReturnedValue fromVariant(
685 const QVariant &variant, Heap::Object *parent, int property, uint flags);
686
687 static QVariantMap variantMapFromJS(const QV4::Object *o);
688 static QVariantHash variantHashFromJS(const QV4::Object *o);
689
690 static bool metaTypeFromJS(const Value &value, QMetaType type, void *data);
691 QV4::ReturnedValue metaTypeToJS(QMetaType type, const void *data);
692
693 int maxJSStackSize() const;
694 int maxGCStackSize() const;
695
696 bool checkStackLimits();
697 int safeForAllocLength(qint64 len64);
698
699 template<typename Jittable>
700 bool canJIT(Jittable *jittable) const
701 {
702#if QT_CONFIG(qml_jit)
703 return m_canAllocateExecutableMemory
704 && jittable->isJittable()
705 && jittable->interpreterCallCount >= s_jitCallCountThreshold;
706#else
707 Q_UNUSED(jittable);
708 return false;
709#endif
710 }
711
712 QV4::ReturnedValue global();
713 void initQmlGlobalObject();
714 void initializeGlobal();
715 void createQtObject();
716
717 void freezeObject(const QV4::Value &value);
718 void lockObject(const QV4::Value &value);
719
720#if QT_CONFIG(qml_xml_http_request)
721 void setupXmlHttpRequestExtension();
722 void *xmlHttpRequestData() const { return m_xmlHttpRequestData; }
723#endif
724
725 void setQmlEngine(QQmlEngine *engine);
726
727 QQmlDelayedCallQueue *delayedCallQueue() { return &m_delayedCallQueue; }
728
729 // used for console.time(), console.timeEnd()
730 void startTimer(const QString &timerName);
731 qint64 stopTimer(const QString &timerName, bool *wasRunning);
732
733 // used for console.count()
734 int consoleCountHelper(const QString &file, quint16 line, quint16 column);
735
736 struct Deletable {
737 virtual ~Deletable() {}
738 };
739
740 static QMutex *registrationMutex();
741 static int registerExtension();
742
743 void setExtensionData(int, Deletable *);
744 Deletable *extensionData(int index) const
745 {
746 if (index < m_extensionData.size())
747 return m_extensionData[index];
748 else
749 return nullptr;
750 }
751
752 double localTZA = 0.0; // local timezone, initialized at startup
753
754 QQmlRefPointer<ExecutableCompilationUnit> compileModule(const QUrl &url);
755 QQmlRefPointer<ExecutableCompilationUnit> compileModule(
756 const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp);
757
758 QQmlRefPointer<ExecutableCompilationUnit> compilationUnitForUrl(const QUrl &url) const;
759
760 QQmlRefPointer<ExecutableCompilationUnit> executableCompilationUnit(
761 QQmlRefPointer<QV4::CompiledData::CompilationUnit> &&unit);
762
763 QQmlRefPointer<ExecutableCompilationUnit> insertCompilationUnit(
764 QQmlRefPointer<QV4::CompiledData::CompilationUnit> &&unit);
765
766 QMultiHash<QUrl, QQmlRefPointer<ExecutableCompilationUnit>> compilationUnits() const
767 {
768 return m_compilationUnits;
769 }
770
771 void trimCompilationUnits();
772 void trimCompilationUnitsForUrl(const QUrl &url);
773
774 using Module = QQmlRefPointer<ExecutableCompilationUnit>;
775
776 Module registerNativeModule(const QUrl &url, const QV4::Value &value);
777 Module moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr) const;
778 Module loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr);
779
780 DiskCacheOptions diskCacheOptions() const;
781
782 void callInContext(QV4::Function *function, QObject *self, QV4::ExecutionContext *ctxt,
783 int argc, void **args, QMetaType *types);
784 QV4::ReturnedValue callInContext(QV4::Function *function, QObject *self,
785 QV4::ExecutionContext *ctxt, int argc, const QV4::Value *argv);
786
787 QV4::ReturnedValue fromData(
788 QMetaType type, const void *ptr,
789 Heap::Object *parent = nullptr, int property = -1, uint flags = 0);
790
791
792 static void setMaxCallDepth(int maxCallDepth) { s_maxCallDepth = maxCallDepth; }
793 static int maxCallDepth() { return s_maxCallDepth; }
794
795 template<typename Value>
796 static QJSPrimitiveValue createPrimitive(const Value &v)
797 {
798 if (v->isUndefined())
799 return QJSPrimitiveValue(QJSPrimitiveUndefined());
800 if (v->isNull())
801 return QJSPrimitiveValue(QJSPrimitiveNull());
802 if (v->isBoolean())
803 return QJSPrimitiveValue(v->toBoolean());
804 if (v->isInteger())
805 return QJSPrimitiveValue(v->integerValue());
806 if (v->isDouble())
807 return QJSPrimitiveValue(v->doubleValue());
808 bool ok;
809 const QString result = v->toQString(&ok);
810 return ok ? QJSPrimitiveValue(result) : QJSPrimitiveValue(QJSPrimitiveUndefined());
811 }
812
813private:
814 template<int Frames>
815 friend struct ExecutionEngineCallDepthRecorder;
816
817 static void initializeStaticMembers();
818
819 bool inStack(const void *current) const
820 {
821#if Q_STACK_GROWTH_DIRECTION > 0
822 return current < cppStackLimit && current >= cppStackBase;
823#else
824 return current > cppStackLimit && current <= cppStackBase;
825#endif
826 }
827
828 bool hasCppStackOverflow()
829 {
830 if (s_maxCallDepth >= 0)
831 return callDepth >= s_maxCallDepth;
832
833 if (inStack(current: currentStackPointer()))
834 return false;
835
836 // Double check the stack limits on failure.
837 // We may have moved to a different thread.
838 const StackProperties stack = stackProperties();
839 cppStackBase = stack.base;
840 cppStackLimit = stack.softLimit;
841 return !inStack(current: currentStackPointer());
842 }
843
844 bool hasJsStackOverflow() const
845 {
846 return jsStackTop > jsStackLimit;
847 }
848
849 bool hasStackOverflow()
850 {
851 return hasJsStackOverflow() || hasCppStackOverflow();
852 }
853
854 static int s_maxCallDepth;
855 static int s_jitCallCountThreshold;
856 static int s_maxJSStackSize;
857 static int s_maxGCStackSize;
858
859#if QT_CONFIG(qml_debug)
860 QScopedPointer<QV4::Debugging::Debugger> m_debugger;
861 QScopedPointer<QV4::Profiling::Profiler> m_profiler;
862#endif
863
864 // used by generated Promise objects to handle 'then' events
865 QScopedPointer<QV4::Promise::ReactionHandler> m_reactionHandler;
866
867#if QT_CONFIG(qml_xml_http_request)
868 void *m_xmlHttpRequestData = nullptr;
869#endif
870
871 QQmlEngine *m_qmlEngine = nullptr;
872
873 QQmlDelayedCallQueue m_delayedCallQueue;
874
875 QElapsedTimer m_time;
876 QHash<QString, qint64> m_startedTimers;
877
878 QHash<QString, quint32> m_consoleCount;
879
880 QVector<Deletable *> m_extensionData;
881
882 QMultiHash<QUrl, QQmlRefPointer<ExecutableCompilationUnit>> m_compilationUnits;
883};
884
885#define CHECK_STACK_LIMITS(v4) \
886 if (v4->checkStackLimits()) \
887 return Encode::undefined(); \
888 ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4);
889
890template<int Frames = 1>
891struct ExecutionEngineCallDepthRecorder
892{
893 ExecutionEngine *ee;
894
895 ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e)
896 {
897 if (ExecutionEngine::s_maxCallDepth >= 0)
898 ee->callDepth += Frames;
899 }
900
901 ~ExecutionEngineCallDepthRecorder()
902 {
903 if (ExecutionEngine::s_maxCallDepth >= 0)
904 ee->callDepth -= Frames;
905 }
906
907 bool hasOverflow() const
908 {
909 return ee->hasCppStackOverflow();
910 }
911};
912
913inline bool ExecutionEngine::checkStackLimits()
914{
915 if (Q_UNLIKELY(hasStackOverflow())) {
916 throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
917 return true;
918 }
919
920 return false;
921}
922
923Q_DECLARE_OPERATORS_FOR_FLAGS(ExecutionEngine::DiskCacheOptions);
924
925} // namespace QV4
926
927QT_END_NAMESPACE
928
929#endif // QV4ENGINE_H
930

source code of qtdeclarative/src/qml/jsruntime/qv4engine_p.h