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 | |
33 | namespace WTF { |
34 | class BumpPointerAllocator; |
35 | class 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 | |
57 | QT_BEGIN_NAMESPACE |
58 | |
59 | #if QT_CONFIG(qml_network) |
60 | class QNetworkAccessManager; |
61 | |
62 | namespace QV4 { |
63 | struct QObjectMethod; |
64 | namespace detail { |
65 | QNetworkAccessManager *getNetworkAccessManager(ExecutionEngine *engine); |
66 | } |
67 | } |
68 | #else |
69 | namespace 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 | |
84 | class QQmlV4Function |
85 | { |
86 | public: |
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; } |
91 | private: |
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 | |
108 | class QQmlError; |
109 | class QJSEngine; |
110 | class QQmlEngine; |
111 | class QQmlContextData; |
112 | |
113 | namespace QV4 { |
114 | namespace Debugging { |
115 | class Debugger; |
116 | } // namespace Debugging |
117 | namespace Profiling { |
118 | class Profiler; |
119 | } // namespace Profiling |
120 | namespace CompiledData { |
121 | struct CompilationUnit; |
122 | } |
123 | |
124 | namespace Heap { |
125 | struct Module; |
126 | }; |
127 | |
128 | struct Function; |
129 | |
130 | namespace Promise { |
131 | class ReactionHandler; |
132 | }; |
133 | |
134 | struct Q_QML_EXPORT ExecutionEngine : public EngineBase |
135 | { |
136 | private: |
137 | friend struct ExecutionContextSaver; |
138 | friend struct ExecutionContext; |
139 | friend struct Heap::ExecutionContext; |
140 | public: |
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 | |
793 | private: |
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 | |
878 | template<int Frames = 1> |
879 | struct 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 | |
901 | inline 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 | |
911 | Q_DECLARE_OPERATORS_FOR_FLAGS(ExecutionEngine::DiskCacheOptions); |
912 | |
913 | } // namespace QV4 |
914 | |
915 | QT_END_NAMESPACE |
916 | |
917 | #endif // QV4ENGINE_H |
918 | |