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

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