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
775 using Module = QQmlRefPointer<ExecutableCompilationUnit>;
776
777 Module registerNativeModule(const QUrl &url, const QV4::Value &value);
778 Module moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr) const;
779 Module loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr);
780
781 DiskCacheOptions diskCacheOptions() const;
782
783 void callInContext(QV4::Function *function, QObject *self, QV4::ExecutionContext *ctxt,
784 int argc, void **args, QMetaType *types);
785 QV4::ReturnedValue callInContext(QV4::Function *function, QObject *self,
786 QV4::ExecutionContext *ctxt, int argc, const QV4::Value *argv);
787
788 QV4::ReturnedValue fromData(
789 QMetaType type, const void *ptr,
790 Heap::Object *parent = nullptr, int property = -1, uint flags = 0);
791
792
793 static void setMaxCallDepth(int maxCallDepth) { s_maxCallDepth = maxCallDepth; }
794 static int maxCallDepth() { return s_maxCallDepth; }
795
796 template<typename Value>
797 static QJSPrimitiveValue createPrimitive(const Value &v)
798 {
799 if (v->isUndefined())
800 return QJSPrimitiveValue(QJSPrimitiveUndefined());
801 if (v->isNull())
802 return QJSPrimitiveValue(QJSPrimitiveNull());
803 if (v->isBoolean())
804 return QJSPrimitiveValue(v->toBoolean());
805 if (v->isInteger())
806 return QJSPrimitiveValue(v->integerValue());
807 if (v->isDouble())
808 return QJSPrimitiveValue(v->doubleValue());
809 bool ok;
810 const QString result = v->toQString(&ok);
811 return ok ? QJSPrimitiveValue(result) : QJSPrimitiveValue(QJSPrimitiveUndefined());
812 }
813
814private:
815 template<int Frames>
816 friend struct ExecutionEngineCallDepthRecorder;
817
818 static void initializeStaticMembers();
819
820 bool inStack(const void *current) const
821 {
822#if Q_STACK_GROWTH_DIRECTION > 0
823 return current < cppStackLimit && current >= cppStackBase;
824#else
825 return current > cppStackLimit && current <= cppStackBase;
826#endif
827 }
828
829 bool hasCppStackOverflow()
830 {
831 if (s_maxCallDepth >= 0)
832 return callDepth >= s_maxCallDepth;
833
834 if (inStack(current: currentStackPointer()))
835 return false;
836
837 // Double check the stack limits on failure.
838 // We may have moved to a different thread.
839 const StackProperties stack = stackProperties();
840 cppStackBase = stack.base;
841 cppStackLimit = stack.softLimit;
842 return !inStack(current: currentStackPointer());
843 }
844
845 bool hasJsStackOverflow() const
846 {
847 return jsStackTop > jsStackLimit;
848 }
849
850 bool hasStackOverflow()
851 {
852 return hasJsStackOverflow() || hasCppStackOverflow();
853 }
854
855 static int s_maxCallDepth;
856 static int s_jitCallCountThreshold;
857 static int s_maxJSStackSize;
858 static int s_maxGCStackSize;
859
860#if QT_CONFIG(qml_debug)
861 QScopedPointer<QV4::Debugging::Debugger> m_debugger;
862 QScopedPointer<QV4::Profiling::Profiler> m_profiler;
863#endif
864 QSet<QString> m_illegalNames;
865
866 // used by generated Promise objects to handle 'then' events
867 QScopedPointer<QV4::Promise::ReactionHandler> m_reactionHandler;
868
869#if QT_CONFIG(qml_xml_http_request)
870 void *m_xmlHttpRequestData;
871#endif
872
873 QQmlEngine *m_qmlEngine;
874
875 QQmlDelayedCallQueue m_delayedCallQueue;
876
877 QElapsedTimer m_time;
878 QHash<QString, qint64> m_startedTimers;
879
880 QHash<QString, quint32> m_consoleCount;
881
882 QVector<Deletable *> m_extensionData;
883
884 QMultiHash<QUrl, QQmlRefPointer<ExecutableCompilationUnit>> m_compilationUnits;
885};
886
887#define CHECK_STACK_LIMITS(v4) \
888 if (v4->checkStackLimits()) \
889 return Encode::undefined(); \
890 ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4);
891
892template<int Frames = 1>
893struct ExecutionEngineCallDepthRecorder
894{
895 ExecutionEngine *ee;
896
897 ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e)
898 {
899 if (ExecutionEngine::s_maxCallDepth >= 0)
900 ee->callDepth += Frames;
901 }
902
903 ~ExecutionEngineCallDepthRecorder()
904 {
905 if (ExecutionEngine::s_maxCallDepth >= 0)
906 ee->callDepth -= Frames;
907 }
908
909 bool hasOverflow() const
910 {
911 return ee->hasCppStackOverflow();
912 }
913};
914
915inline bool ExecutionEngine::checkStackLimits()
916{
917 if (Q_UNLIKELY(hasStackOverflow())) {
918 throwRangeError(QStringLiteral("Maximum call stack size exceeded."));
919 return true;
920 }
921
922 return false;
923}
924
925Q_DECLARE_OPERATORS_FOR_FLAGS(ExecutionEngine::DiskCacheOptions);
926
927} // namespace QV4
928
929QT_END_NAMESPACE
930
931#endif // QV4ENGINE_H
932

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