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

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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