1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQml module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | #ifndef QV4ENGINE_H |
40 | #define QV4ENGINE_H |
41 | |
42 | // |
43 | // W A R N I N G |
44 | // ------------- |
45 | // |
46 | // This file is not part of the Qt API. It exists purely as an |
47 | // implementation detail. This header file may change from version to |
48 | // version without notice, or even be removed. |
49 | // |
50 | // We mean it. |
51 | // |
52 | |
53 | #include "qv4global_p.h" |
54 | #include "qv4managed_p.h" |
55 | #include "qv4context_p.h" |
56 | #include "qv4stackframe_p.h" |
57 | #include <private/qintrusivelist_p.h> |
58 | #include "qv4enginebase_p.h" |
59 | #include <private/qqmlrefcount_p.h> |
60 | #include <private/qqmldelayedcallqueue_p.h> |
61 | #include <QtCore/qelapsedtimer.h> |
62 | #include <QtCore/qmutex.h> |
63 | |
64 | #include "qv4function_p.h" |
65 | #include <private/qv4compileddata_p.h> |
66 | #include <private/qv4executablecompilationunit_p.h> |
67 | |
68 | namespace WTF { |
69 | class BumpPointerAllocator; |
70 | class PageAllocation; |
71 | } |
72 | |
73 | #define V4_DEFINE_EXTENSION(dataclass, datafunction) \ |
74 | static inline dataclass *datafunction(QV4::ExecutionEngine *engine) \ |
75 | { \ |
76 | static int extensionId = -1; \ |
77 | if (extensionId == -1) { \ |
78 | QV4::ExecutionEngine::registrationMutex()->lock(); \ |
79 | if (extensionId == -1) \ |
80 | extensionId = QV4::ExecutionEngine::registerExtension(); \ |
81 | QV4::ExecutionEngine::registrationMutex()->unlock(); \ |
82 | } \ |
83 | dataclass *rv = (dataclass *)engine->extensionData(extensionId); \ |
84 | if (!rv) { \ |
85 | rv = new dataclass(engine); \ |
86 | engine->setExtensionData(extensionId, rv); \ |
87 | } \ |
88 | return rv; \ |
89 | } \ |
90 | |
91 | |
92 | QT_BEGIN_NAMESPACE |
93 | |
94 | namespace QV4 { struct QObjectMethod; } |
95 | |
96 | // Used to allow a QObject method take and return raw V4 handles without having to expose |
97 | // 48 in the public API. |
98 | // Use like this: |
99 | // class MyClass : public QObject { |
100 | // Q_OBJECT |
101 | // ... |
102 | // Q_INVOKABLE void myMethod(QQmlV4Function*); |
103 | // }; |
104 | // The QQmlV8Function - and consequently the arguments and return value - only remains |
105 | // valid during the call. If the return value isn't set within myMethod(), the will return |
106 | // undefined. |
107 | |
108 | class QQmlV4Function |
109 | { |
110 | public: |
111 | int length() const { return callData->argc(); } |
112 | QV4::ReturnedValue operator[](int idx) const { return (idx < callData->argc() ? callData->args[idx].asReturnedValue() : QV4::Encode::undefined()); } |
113 | void setReturnValue(QV4::ReturnedValue rv) { *retVal = rv; } |
114 | QV4::ExecutionEngine *v4engine() const { return e; } |
115 | private: |
116 | friend struct QV4::QObjectMethod; |
117 | QQmlV4Function(); |
118 | QQmlV4Function(const QQmlV4Function &); |
119 | QQmlV4Function &operator=(const QQmlV4Function &); |
120 | |
121 | QQmlV4Function(QV4::CallData *callData, QV4::Value *retVal, QV4::ExecutionEngine *e) |
122 | : callData(callData), retVal(retVal), e(e) |
123 | { |
124 | callData->thisObject = QV4::Encode::undefined(); |
125 | } |
126 | |
127 | QV4::CallData *callData; |
128 | QV4::Value *retVal; |
129 | QV4::ExecutionEngine *e; |
130 | }; |
131 | |
132 | class QQmlError; |
133 | class QJSEngine; |
134 | class QQmlEngine; |
135 | class QQmlContextData; |
136 | |
137 | namespace QV4 { |
138 | namespace Debugging { |
139 | class Debugger; |
140 | } // namespace Debugging |
141 | namespace Profiling { |
142 | class Profiler; |
143 | } // namespace Profiling |
144 | namespace CompiledData { |
145 | struct CompilationUnit; |
146 | } |
147 | |
148 | namespace Heap { |
149 | struct Module; |
150 | }; |
151 | |
152 | struct Function; |
153 | |
154 | namespace Promise { |
155 | class ReactionHandler; |
156 | }; |
157 | |
158 | struct Q_QML_EXPORT ExecutionEngine : public EngineBase |
159 | { |
160 | private: |
161 | static qint32 maxCallDepth; |
162 | |
163 | friend struct ExecutionContextSaver; |
164 | friend struct ExecutionContext; |
165 | friend struct Heap::ExecutionContext; |
166 | public: |
167 | ExecutableAllocator *executableAllocator; |
168 | ExecutableAllocator *regExpAllocator; |
169 | |
170 | WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine. |
171 | |
172 | WTF::PageAllocation *jsStack; |
173 | |
174 | WTF::PageAllocation *gcStack; |
175 | |
176 | QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) { |
177 | Value *ptr = jsStackTop; |
178 | jsStackTop = ptr + nValues; |
179 | return ptr; |
180 | } |
181 | |
182 | Function *globalCode; |
183 | |
184 | QJSEngine *jsEngine() const { return publicEngine; } |
185 | QQmlEngine *qmlEngine() const { return m_qmlEngine; } |
186 | QJSEngine *publicEngine; |
187 | |
188 | enum JSObjects { |
189 | RootContext, |
190 | ScriptContext, |
191 | IntegerNull, // Has to come after the RootContext to make the context stack safe |
192 | ObjectProto, |
193 | SymbolProto, |
194 | ArrayProto, |
195 | ArrayProtoValues, |
196 | PropertyListProto, |
197 | StringProto, |
198 | NumberProto, |
199 | BooleanProto, |
200 | DateProto, |
201 | FunctionProto, |
202 | GeneratorProto, |
203 | RegExpProto, |
204 | ErrorProto, |
205 | EvalErrorProto, |
206 | RangeErrorProto, |
207 | ReferenceErrorProto, |
208 | SyntaxErrorProto, |
209 | TypeErrorProto, |
210 | URIErrorProto, |
211 | PromiseProto, |
212 | VariantProto, |
213 | #if QT_CONFIG(qml_sequence_object) |
214 | SequenceProto, |
215 | #endif |
216 | SharedArrayBufferProto, |
217 | ArrayBufferProto, |
218 | DataViewProto, |
219 | WeakSetProto, |
220 | SetProto, |
221 | WeakMapProto, |
222 | MapProto, |
223 | IntrinsicTypedArrayProto, |
224 | ValueTypeProto, |
225 | SignalHandlerProto, |
226 | IteratorProto, |
227 | ForInIteratorProto, |
228 | SetIteratorProto, |
229 | MapIteratorProto, |
230 | ArrayIteratorProto, |
231 | StringIteratorProto, |
232 | |
233 | Object_Ctor, |
234 | String_Ctor, |
235 | Symbol_Ctor, |
236 | Number_Ctor, |
237 | Boolean_Ctor, |
238 | Array_Ctor, |
239 | Function_Ctor, |
240 | GeneratorFunction_Ctor, |
241 | Date_Ctor, |
242 | RegExp_Ctor, |
243 | Error_Ctor, |
244 | EvalError_Ctor, |
245 | RangeError_Ctor, |
246 | ReferenceError_Ctor, |
247 | SyntaxError_Ctor, |
248 | TypeError_Ctor, |
249 | URIError_Ctor, |
250 | SharedArrayBuffer_Ctor, |
251 | Promise_Ctor, |
252 | ArrayBuffer_Ctor, |
253 | DataView_Ctor, |
254 | WeakSet_Ctor, |
255 | Set_Ctor, |
256 | WeakMap_Ctor, |
257 | Map_Ctor, |
258 | IntrinsicTypedArray_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 *typedArrayCtors; |
300 | |
301 | FunctionObject *getSymbolSpecies() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetSymbolSpecies); } |
302 | |
303 | Object *objectPrototype() const { return reinterpret_cast<Object *>(jsObjects + ObjectProto); } |
304 | Object *symbolPrototype() const { return reinterpret_cast<Object *>(jsObjects + SymbolProto); } |
305 | Object *arrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayProto); } |
306 | Object *arrayProtoValues() const { return reinterpret_cast<Object *>(jsObjects + ArrayProtoValues); } |
307 | Object *propertyListPrototype() const { return reinterpret_cast<Object *>(jsObjects + PropertyListProto); } |
308 | Object *stringPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringProto); } |
309 | Object *numberPrototype() const { return reinterpret_cast<Object *>(jsObjects + NumberProto); } |
310 | Object *booleanPrototype() const { return reinterpret_cast<Object *>(jsObjects + BooleanProto); } |
311 | Object *datePrototype() const { return reinterpret_cast<Object *>(jsObjects + DateProto); } |
312 | Object *functionPrototype() const { return reinterpret_cast<Object *>(jsObjects + FunctionProto); } |
313 | Object *generatorPrototype() const { return reinterpret_cast<Object *>(jsObjects + GeneratorProto); } |
314 | Object *regExpPrototype() const { return reinterpret_cast<Object *>(jsObjects + RegExpProto); } |
315 | Object *errorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ErrorProto); } |
316 | Object *evalErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + EvalErrorProto); } |
317 | Object *rangeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + RangeErrorProto); } |
318 | Object *referenceErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ReferenceErrorProto); } |
319 | Object *syntaxErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SyntaxErrorProto); } |
320 | Object *typeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeErrorProto); } |
321 | Object *uRIErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + URIErrorProto); } |
322 | Object *promisePrototype() const { return reinterpret_cast<Object *>(jsObjects + PromiseProto); } |
323 | Object *variantPrototype() const { return reinterpret_cast<Object *>(jsObjects + VariantProto); } |
324 | #if QT_CONFIG(qml_sequence_object) |
325 | Object *sequencePrototype() const { return reinterpret_cast<Object *>(jsObjects + SequenceProto); } |
326 | #endif |
327 | |
328 | Object *sharedArrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + SharedArrayBufferProto); } |
329 | Object *arrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayBufferProto); } |
330 | Object *dataViewPrototype() const { return reinterpret_cast<Object *>(jsObjects + DataViewProto); } |
331 | Object *weakSetPrototype() const { return reinterpret_cast<Object *>(jsObjects + WeakSetProto); } |
332 | Object *setPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetProto); } |
333 | Object *weakMapPrototype() const { return reinterpret_cast<Object *>(jsObjects + WeakMapProto); } |
334 | Object *mapPrototype() const { return reinterpret_cast<Object *>(jsObjects + MapProto); } |
335 | Object *intrinsicTypedArrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + IntrinsicTypedArrayProto); } |
336 | Object *typedArrayPrototype; |
337 | |
338 | Object *valueTypeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + ValueTypeProto); } |
339 | Object *signalHandlerPrototype() const { return reinterpret_cast<Object *>(jsObjects + SignalHandlerProto); } |
340 | Object *iteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + IteratorProto); } |
341 | Object *forInIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ForInIteratorProto); } |
342 | Object *setIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetIteratorProto); } |
343 | Object *mapIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + MapIteratorProto); } |
344 | Object *arrayIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayIteratorProto); } |
345 | Object *stringIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringIteratorProto); } |
346 | |
347 | EvalFunction *evalFunction() const { return reinterpret_cast<EvalFunction *>(jsObjects + Eval_Function); } |
348 | FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); } |
349 | FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); } |
350 | |
351 | enum JSStrings { |
352 | String_Empty, |
353 | String_undefined, |
354 | String_null, |
355 | String_true, |
356 | String_false, |
357 | String_boolean, |
358 | String_number, |
359 | String_string, |
360 | String_default, |
361 | String_symbol, |
362 | String_object, |
363 | String_function, |
364 | String_length, |
365 | String_prototype, |
366 | String_constructor, |
367 | String_arguments, |
368 | String_caller, |
369 | String_callee, |
370 | String_this, |
371 | String___proto__, |
372 | String_enumerable, |
373 | String_configurable, |
374 | String_writable, |
375 | String_value, |
376 | String_get, |
377 | String_set, |
378 | String_eval, |
379 | String_uintMax, |
380 | String_name, |
381 | String_index, |
382 | String_input, |
383 | String_toString, |
384 | String_toLocaleString, |
385 | String_destroy, |
386 | String_valueOf, |
387 | String_byteLength, |
388 | String_byteOffset, |
389 | String_buffer, |
390 | String_lastIndex, |
391 | String_next, |
392 | String_done, |
393 | String_return, |
394 | String_throw, |
395 | String_global, |
396 | String_ignoreCase, |
397 | String_multiline, |
398 | String_unicode, |
399 | String_sticky, |
400 | String_source, |
401 | String_flags, |
402 | |
403 | NJSStrings |
404 | }; |
405 | Value *jsStrings; |
406 | |
407 | enum JSSymbols { |
408 | Symbol_hasInstance, |
409 | Symbol_isConcatSpreadable, |
410 | Symbol_iterator, |
411 | Symbol_match, |
412 | Symbol_replace, |
413 | Symbol_search, |
414 | Symbol_species, |
415 | Symbol_split, |
416 | Symbol_toPrimitive, |
417 | Symbol_toStringTag, |
418 | Symbol_unscopables, |
419 | Symbol_revokableProxy, |
420 | NJSSymbols |
421 | }; |
422 | Value *jsSymbols; |
423 | |
424 | String *id_empty() const { return reinterpret_cast<String *>(jsStrings + String_Empty); } |
425 | String *id_undefined() const { return reinterpret_cast<String *>(jsStrings + String_undefined); } |
426 | String *id_null() const { return reinterpret_cast<String *>(jsStrings + String_null); } |
427 | String *id_true() const { return reinterpret_cast<String *>(jsStrings + String_true); } |
428 | String *id_false() const { return reinterpret_cast<String *>(jsStrings + String_false); } |
429 | String *id_boolean() const { return reinterpret_cast<String *>(jsStrings + String_boolean); } |
430 | String *id_number() const { return reinterpret_cast<String *>(jsStrings + String_number); } |
431 | String *id_string() const { return reinterpret_cast<String *>(jsStrings + String_string); } |
432 | String *id_default() const { return reinterpret_cast<String *>(jsStrings + String_default); } |
433 | String *id_symbol() const { return reinterpret_cast<String *>(jsStrings + String_symbol); } |
434 | String *id_object() const { return reinterpret_cast<String *>(jsStrings + String_object); } |
435 | String *id_function() const { return reinterpret_cast<String *>(jsStrings + String_function); } |
436 | String *id_length() const { return reinterpret_cast<String *>(jsStrings + String_length); } |
437 | String *id_prototype() const { return reinterpret_cast<String *>(jsStrings + String_prototype); } |
438 | String *id_constructor() const { return reinterpret_cast<String *>(jsStrings + String_constructor); } |
439 | String *id_arguments() const { return reinterpret_cast<String *>(jsStrings + String_arguments); } |
440 | String *id_caller() const { return reinterpret_cast<String *>(jsStrings + String_caller); } |
441 | String *id_callee() const { return reinterpret_cast<String *>(jsStrings + String_callee); } |
442 | String *id_this() const { return reinterpret_cast<String *>(jsStrings + String_this); } |
443 | String *id___proto__() const { return reinterpret_cast<String *>(jsStrings + String___proto__); } |
444 | String *id_enumerable() const { return reinterpret_cast<String *>(jsStrings + String_enumerable); } |
445 | String *id_configurable() const { return reinterpret_cast<String *>(jsStrings + String_configurable); } |
446 | String *id_writable() const { return reinterpret_cast<String *>(jsStrings + String_writable); } |
447 | String *id_value() const { return reinterpret_cast<String *>(jsStrings + String_value); } |
448 | String *id_get() const { return reinterpret_cast<String *>(jsStrings + String_get); } |
449 | String *id_set() const { return reinterpret_cast<String *>(jsStrings + String_set); } |
450 | String *id_eval() const { return reinterpret_cast<String *>(jsStrings + String_eval); } |
451 | String *id_uintMax() const { return reinterpret_cast<String *>(jsStrings + String_uintMax); } |
452 | String *id_name() const { return reinterpret_cast<String *>(jsStrings + String_name); } |
453 | String *id_index() const { return reinterpret_cast<String *>(jsStrings + String_index); } |
454 | String *id_input() const { return reinterpret_cast<String *>(jsStrings + String_input); } |
455 | String *id_toString() const { return reinterpret_cast<String *>(jsStrings + String_toString); } |
456 | String *id_toLocaleString() const { return reinterpret_cast<String *>(jsStrings + String_toLocaleString); } |
457 | String *id_destroy() const { return reinterpret_cast<String *>(jsStrings + String_destroy); } |
458 | String *id_valueOf() const { return reinterpret_cast<String *>(jsStrings + String_valueOf); } |
459 | String *id_byteLength() const { return reinterpret_cast<String *>(jsStrings + String_byteLength); } |
460 | String *id_byteOffset() const { return reinterpret_cast<String *>(jsStrings + String_byteOffset); } |
461 | String *id_buffer() const { return reinterpret_cast<String *>(jsStrings + String_buffer); } |
462 | String *id_lastIndex() const { return reinterpret_cast<String *>(jsStrings + String_lastIndex); } |
463 | String *id_next() const { return reinterpret_cast<String *>(jsStrings + String_next); } |
464 | String *id_done() const { return reinterpret_cast<String *>(jsStrings + String_done); } |
465 | String *id_return() const { return reinterpret_cast<String *>(jsStrings + String_return); } |
466 | String *id_throw() const { return reinterpret_cast<String *>(jsStrings + String_throw); } |
467 | String *id_global() const { return reinterpret_cast<String *>(jsStrings + String_global); } |
468 | String *id_ignoreCase() const { return reinterpret_cast<String *>(jsStrings + String_ignoreCase); } |
469 | String *id_multiline() const { return reinterpret_cast<String *>(jsStrings + String_multiline); } |
470 | String *id_unicode() const { return reinterpret_cast<String *>(jsStrings + String_unicode); } |
471 | String *id_sticky() const { return reinterpret_cast<String *>(jsStrings + String_sticky); } |
472 | String *id_source() const { return reinterpret_cast<String *>(jsStrings + String_source); } |
473 | String *id_flags() const { return reinterpret_cast<String *>(jsStrings + String_flags); } |
474 | |
475 | Symbol *symbol_hasInstance() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_hasInstance); } |
476 | Symbol *symbol_isConcatSpreadable() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_isConcatSpreadable); } |
477 | Symbol *symbol_iterator() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_iterator); } |
478 | Symbol *symbol_match() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_match); } |
479 | Symbol *symbol_replace() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_replace); } |
480 | Symbol *symbol_search() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_search); } |
481 | Symbol *symbol_species() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_species); } |
482 | Symbol *symbol_split() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_split); } |
483 | Symbol *symbol_toPrimitive() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_toPrimitive); } |
484 | Symbol *symbol_toStringTag() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_toStringTag); } |
485 | Symbol *symbol_unscopables() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_unscopables); } |
486 | Symbol *symbol_revokableProxy() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_revokableProxy); } |
487 | |
488 | QIntrusiveList<ExecutableCompilationUnit, &ExecutableCompilationUnit::nextCompilationUnit> compilationUnits; |
489 | |
490 | quint32 m_engineId; |
491 | |
492 | RegExpCache *regExpCache; |
493 | |
494 | // Scarce resources are "exceptionally high cost" QVariant types where allowing the |
495 | // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other |
496 | // out-of-resource situations. When such a resource is passed into JavaScript we |
497 | // add it to the scarceResources list and it is destroyed when we return from the |
498 | // JavaScript execution that created it. The user can prevent this behavior by |
499 | // calling preserve() on the object which removes it from this scarceResource list. |
500 | class ScarceResourceData { |
501 | public: |
502 | ScarceResourceData(const QVariant &data = QVariant()) : data(data) {} |
503 | QVariant data; |
504 | QIntrusiveListNode node; |
505 | }; |
506 | QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources; |
507 | |
508 | // Normally the JS wrappers for QObjects are stored in the QQmlData/QObjectPrivate, |
509 | // but any time a QObject is wrapped a second time in another engine, we have to do |
510 | // bookkeeping. |
511 | MultiplyWrappedQObjectMap *m_multiplyWrappedQObjects; |
512 | #if QT_CONFIG(qml_jit) |
513 | const bool m_canAllocateExecutableMemory; |
514 | #endif |
515 | |
516 | quintptr protoIdCount = 1; |
517 | |
518 | ExecutionEngine(QJSEngine *jsEngine = nullptr); |
519 | ~ExecutionEngine(); |
520 | |
521 | #if !QT_CONFIG(qml_debug) |
522 | QV4::Debugging::Debugger *debugger() const { return nullptr; } |
523 | QV4::Profiling::Profiler *profiler() const { return nullptr; } |
524 | |
525 | void setDebugger(Debugging::Debugger *) {} |
526 | void setProfiler(Profiling::Profiler *) {} |
527 | #else |
528 | QV4::Debugging::Debugger *debugger() const { return m_debugger.data(); } |
529 | QV4::Profiling::Profiler *profiler() const { return m_profiler.data(); } |
530 | |
531 | void setDebugger(Debugging::Debugger *debugger); |
532 | void setProfiler(Profiling::Profiler *profiler); |
533 | #endif // QT_CONFIG(qml_debug) |
534 | |
535 | ExecutionContext *currentContext() const; |
536 | |
537 | // ensure we always get odd prototype IDs. This helps make marking in QV4::Lookup fast |
538 | quintptr newProtoId() { return (protoIdCount += 2); } |
539 | |
540 | Heap::InternalClass *newInternalClass(const VTable *vtable, Object *prototype); |
541 | |
542 | Heap::Object *newObject(); |
543 | Heap::Object *newObject(Heap::InternalClass *internalClass); |
544 | |
545 | Heap::String *newString(const QString &s = QString()); |
546 | Heap::String *newIdentifier(const QString &text); |
547 | |
548 | Heap::Object *newStringObject(const String *string); |
549 | Heap::Object *newSymbolObject(const Symbol *symbol); |
550 | Heap::Object *newNumberObject(double value); |
551 | Heap::Object *newBooleanObject(bool b); |
552 | |
553 | Heap::ArrayObject *newArrayObject(int count = 0); |
554 | Heap::ArrayObject *newArrayObject(const Value *values, int length); |
555 | Heap::ArrayObject *newArrayObject(const QStringList &list); |
556 | Heap::ArrayObject *newArrayObject(Heap::InternalClass *ic); |
557 | |
558 | Heap::ArrayBuffer *newArrayBuffer(const QByteArray &array); |
559 | Heap::ArrayBuffer *newArrayBuffer(size_t length); |
560 | |
561 | Heap::DateObject *newDateObject(const Value &value); |
562 | Heap::DateObject *newDateObject(const QDateTime &dt); |
563 | Heap::DateObject *newDateObjectFromTime(const QTime &t); |
564 | |
565 | Heap::RegExpObject *newRegExpObject(const QString &pattern, int flags); |
566 | Heap::RegExpObject *newRegExpObject(RegExp *re); |
567 | Heap::RegExpObject *newRegExpObject(const QRegExp &re); |
568 | #if QT_CONFIG(regularexpression) |
569 | Heap::RegExpObject *newRegExpObject(const QRegularExpression &re); |
570 | #endif |
571 | |
572 | Heap::Object *newErrorObject(const Value &value); |
573 | Heap::Object *newErrorObject(const QString &message); |
574 | Heap::Object *newSyntaxErrorObject(const QString &message, const QString &fileName, int line, int column); |
575 | Heap::Object *newSyntaxErrorObject(const QString &message); |
576 | Heap::Object *newReferenceErrorObject(const QString &message); |
577 | Heap::Object *newReferenceErrorObject(const QString &message, const QString &fileName, int line, int column); |
578 | Heap::Object *newTypeErrorObject(const QString &message); |
579 | Heap::Object *newRangeErrorObject(const QString &message); |
580 | Heap::Object *newURIErrorObject(const QString &message); |
581 | Heap::Object *newURIErrorObject(const Value &message); |
582 | Heap::Object *newEvalErrorObject(const QString &message); |
583 | |
584 | Heap::PromiseObject *newPromiseObject(); |
585 | Heap::Object *newPromiseObject(const QV4::FunctionObject *thisObject, const QV4::PromiseCapability *capability); |
586 | Promise::ReactionHandler *getPromiseReactionHandler(); |
587 | |
588 | Heap::Object *newVariantObject(const QVariant &v); |
589 | |
590 | Heap::Object *newForInIteratorObject(Object *o); |
591 | Heap::Object *newSetIteratorObject(Object *o); |
592 | Heap::Object *newMapIteratorObject(Object *o); |
593 | Heap::Object *newArrayIteratorObject(Object *o); |
594 | |
595 | Heap::QmlContext *qmlContext() const; |
596 | QObject *qmlScopeObject() const; |
597 | QQmlContextData *callingQmlContext() const; |
598 | |
599 | |
600 | StackTrace stackTrace(int frameLimit = -1) const; |
601 | QUrl resolvedUrl(const QString &file); |
602 | |
603 | void markObjects(MarkStack *markStack); |
604 | |
605 | void initRootContext(); |
606 | |
607 | Heap::InternalClass *newClass(Heap::InternalClass *other); |
608 | |
609 | StackTrace exceptionStackTrace; |
610 | |
611 | ReturnedValue throwError(const Value &value); |
612 | ReturnedValue catchException(StackTrace *trace = nullptr); |
613 | |
614 | ReturnedValue throwError(const QString &message); |
615 | ReturnedValue throwSyntaxError(const QString &message); |
616 | ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int lineNumber, int column); |
617 | ReturnedValue throwTypeError(); |
618 | ReturnedValue throwTypeError(const QString &message); |
619 | ReturnedValue throwReferenceError(const Value &value); |
620 | ReturnedValue throwReferenceError(const QString &name); |
621 | ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int lineNumber, int column); |
622 | ReturnedValue throwRangeError(const Value &value); |
623 | ReturnedValue throwRangeError(const QString &message); |
624 | ReturnedValue throwURIError(const Value &msg); |
625 | ReturnedValue throwUnimplemented(const QString &message); |
626 | |
627 | // Use only inside catch(...) -- will re-throw if no JS exception |
628 | QQmlError catchExceptionAsQmlError(); |
629 | |
630 | // variant conversions |
631 | QVariant toVariant(const QV4::Value &value, int typeHint, bool createJSValueForObjects = true); |
632 | QV4::ReturnedValue fromVariant(const QVariant &); |
633 | |
634 | QVariantMap variantMapFromJS(const QV4::Object *o); |
635 | |
636 | bool metaTypeFromJS(const Value *value, int type, void *data); |
637 | QV4::ReturnedValue metaTypeToJS(int type, const void *data); |
638 | |
639 | int maxJSStackSize() const; |
640 | int maxGCStackSize() const; |
641 | |
642 | bool checkStackLimits(); |
643 | |
644 | bool canJIT(Function *f = nullptr) |
645 | { |
646 | #if QT_CONFIG(qml_jit) |
647 | if (!m_canAllocateExecutableMemory) |
648 | return false; |
649 | if (f) |
650 | return !f->isGenerator() && f->interpreterCallCount >= jitCallCountThreshold; |
651 | return true; |
652 | #else |
653 | Q_UNUSED(f); |
654 | return false; |
655 | #endif |
656 | } |
657 | |
658 | QV4::ReturnedValue global(); |
659 | void initQmlGlobalObject(); |
660 | void initializeGlobal(); |
661 | |
662 | void freezeObject(const QV4::Value &value); |
663 | |
664 | // Return the list of illegal id names (the names of the properties on the global object) |
665 | const QSet<QString> &illegalNames() const; |
666 | |
667 | #if QT_CONFIG(qml_xml_http_request) |
668 | void *xmlHttpRequestData() const { return m_xmlHttpRequestData; } |
669 | #endif |
670 | |
671 | void setQmlEngine(QQmlEngine *engine); |
672 | |
673 | QQmlDelayedCallQueue *delayedCallQueue() { return &m_delayedCallQueue; } |
674 | |
675 | // used for console.time(), console.timeEnd() |
676 | void startTimer(const QString &timerName); |
677 | qint64 stopTimer(const QString &timerName, bool *wasRunning); |
678 | |
679 | // used for console.count() |
680 | int consoleCountHelper(const QString &file, quint16 line, quint16 column); |
681 | |
682 | struct Deletable { |
683 | virtual ~Deletable() {} |
684 | }; |
685 | |
686 | static QMutex *registrationMutex(); |
687 | static int registerExtension(); |
688 | |
689 | void setExtensionData(int, Deletable *); |
690 | Deletable *extensionData(int index) const |
691 | { |
692 | if (index < m_extensionData.count()) |
693 | return m_extensionData[index]; |
694 | else |
695 | return nullptr; |
696 | } |
697 | |
698 | double localTZA = 0.0; // local timezone, initialized at startup |
699 | |
700 | QQmlRefPointer<ExecutableCompilationUnit> compileModule(const QUrl &url); |
701 | QQmlRefPointer<ExecutableCompilationUnit> compileModule( |
702 | const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp); |
703 | |
704 | mutable QMutex moduleMutex; |
705 | QHash<QUrl, QQmlRefPointer<ExecutableCompilationUnit>> modules; |
706 | void injectModule(const QQmlRefPointer<ExecutableCompilationUnit> &moduleUnit); |
707 | QQmlRefPointer<ExecutableCompilationUnit> moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr) const; |
708 | QQmlRefPointer<ExecutableCompilationUnit> loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr); |
709 | |
710 | private: |
711 | #if QT_CONFIG(qml_debug) |
712 | QScopedPointer<QV4::Debugging::Debugger> m_debugger; |
713 | QScopedPointer<QV4::Profiling::Profiler> m_profiler; |
714 | #endif |
715 | QSet<QString> m_illegalNames; |
716 | int jitCallCountThreshold; |
717 | |
718 | // used by generated Promise objects to handle 'then' events |
719 | QScopedPointer<QV4::Promise::ReactionHandler> m_reactionHandler; |
720 | |
721 | #if QT_CONFIG(qml_xml_http_request) |
722 | void *m_xmlHttpRequestData; |
723 | #endif |
724 | |
725 | QQmlEngine *m_qmlEngine; |
726 | |
727 | QQmlDelayedCallQueue m_delayedCallQueue; |
728 | |
729 | QElapsedTimer m_time; |
730 | QHash<QString, qint64> m_startedTimers; |
731 | |
732 | QHash<QString, quint32> m_consoleCount; |
733 | |
734 | QVector<Deletable *> m_extensionData; |
735 | |
736 | int m_maxJSStackSize = 4 * 1024 * 1024; |
737 | int m_maxGCStackSize = 2 * 1024 * 1024; |
738 | }; |
739 | |
740 | #define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \ |
741 | ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4); |
742 | |
743 | struct ExecutionEngineCallDepthRecorder |
744 | { |
745 | ExecutionEngine *ee; |
746 | |
747 | ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ++ee->callDepth; } |
748 | ~ExecutionEngineCallDepthRecorder() { --ee->callDepth; } |
749 | }; |
750 | |
751 | inline bool ExecutionEngine::checkStackLimits() |
752 | { |
753 | if (Q_UNLIKELY((jsStackTop > jsStackLimit) || (callDepth >= maxCallDepth))) { |
754 | throwRangeError(QStringLiteral("Maximum call stack size exceeded." )); |
755 | return true; |
756 | } |
757 | |
758 | return false; |
759 | } |
760 | |
761 | } // namespace QV4 |
762 | |
763 | QT_END_NAMESPACE |
764 | |
765 | #endif // QV4ENGINE_H |
766 | |