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 | #if QT_CONFIG(qml_network) |
95 | class QNetworkAccessManager; |
96 | |
97 | namespace QV4 { |
98 | struct QObjectMethod; |
99 | namespace detail { |
100 | QNetworkAccessManager *getNetworkAccessManager(ExecutionEngine *engine); |
101 | } |
102 | } |
103 | #else |
104 | namespace QV4 { struct QObjectMethod; } |
105 | #endif // qml_network |
106 | |
107 | // Used to allow a QObject method take and return raw V4 handles without having to expose |
108 | // 48 in the public API. |
109 | // Use like this: |
110 | // class MyClass : public QObject { |
111 | // Q_OBJECT |
112 | // ... |
113 | // Q_INVOKABLE void myMethod(QQmlV4Function*); |
114 | // }; |
115 | // The QQmlV8Function - and consequently the arguments and return value - only remains |
116 | // valid during the call. If the return value isn't set within myMethod(), the will return |
117 | // undefined. |
118 | |
119 | class QQmlV4Function |
120 | { |
121 | public: |
122 | int length() const { return callData->argc(); } |
123 | QV4::ReturnedValue operator[](int idx) const { return (idx < callData->argc() ? callData->args[idx].asReturnedValue() : QV4::Encode::undefined()); } |
124 | void setReturnValue(QV4::ReturnedValue rv) { *retVal = rv; } |
125 | QV4::ExecutionEngine *v4engine() const { return e; } |
126 | private: |
127 | friend struct QV4::QObjectMethod; |
128 | QQmlV4Function(); |
129 | QQmlV4Function(const QQmlV4Function &); |
130 | QQmlV4Function &operator=(const QQmlV4Function &); |
131 | |
132 | QQmlV4Function(QV4::CallData *callData, QV4::Value *retVal, QV4::ExecutionEngine *e) |
133 | : callData(callData), retVal(retVal), e(e) |
134 | { |
135 | callData->thisObject = QV4::Encode::undefined(); |
136 | } |
137 | |
138 | QV4::CallData *callData; |
139 | QV4::Value *retVal; |
140 | QV4::ExecutionEngine *e; |
141 | }; |
142 | |
143 | class QQmlError; |
144 | class QJSEngine; |
145 | class QQmlEngine; |
146 | class QQmlContextData; |
147 | |
148 | namespace QV4 { |
149 | namespace Debugging { |
150 | class Debugger; |
151 | } // namespace Debugging |
152 | namespace Profiling { |
153 | class Profiler; |
154 | } // namespace Profiling |
155 | namespace CompiledData { |
156 | struct CompilationUnit; |
157 | } |
158 | |
159 | namespace Heap { |
160 | struct Module; |
161 | }; |
162 | |
163 | struct Function; |
164 | |
165 | namespace Promise { |
166 | class ReactionHandler; |
167 | }; |
168 | |
169 | struct Q_QML_EXPORT ExecutionEngine : public EngineBase |
170 | { |
171 | private: |
172 | static qint32 maxCallDepth; |
173 | |
174 | friend struct ExecutionContextSaver; |
175 | friend struct ExecutionContext; |
176 | friend struct Heap::ExecutionContext; |
177 | public: |
178 | ExecutableAllocator *executableAllocator; |
179 | ExecutableAllocator *regExpAllocator; |
180 | |
181 | WTF::BumpPointerAllocator *bumperPointerAllocator; // Used by Yarr Regex engine. |
182 | |
183 | WTF::PageAllocation *jsStack; |
184 | |
185 | WTF::PageAllocation *gcStack; |
186 | |
187 | QML_NEARLY_ALWAYS_INLINE Value *jsAlloca(int nValues) { |
188 | Value *ptr = jsStackTop; |
189 | jsStackTop = ptr + nValues; |
190 | return ptr; |
191 | } |
192 | |
193 | Function *globalCode; |
194 | |
195 | QJSEngine *jsEngine() const { return publicEngine; } |
196 | QQmlEngine *qmlEngine() const { return m_qmlEngine; } |
197 | QJSEngine *publicEngine; |
198 | |
199 | enum JSObjects { |
200 | RootContext, |
201 | ScriptContext, |
202 | IntegerNull, // Has to come after the RootContext to make the context stack safe |
203 | ObjectProto, |
204 | SymbolProto, |
205 | ArrayProto, |
206 | ArrayProtoValues, |
207 | PropertyListProto, |
208 | StringProto, |
209 | NumberProto, |
210 | BooleanProto, |
211 | DateProto, |
212 | FunctionProto, |
213 | GeneratorProto, |
214 | RegExpProto, |
215 | ErrorProto, |
216 | EvalErrorProto, |
217 | RangeErrorProto, |
218 | ReferenceErrorProto, |
219 | SyntaxErrorProto, |
220 | TypeErrorProto, |
221 | URIErrorProto, |
222 | PromiseProto, |
223 | VariantProto, |
224 | #if QT_CONFIG(qml_sequence_object) |
225 | SequenceProto, |
226 | #endif |
227 | SharedArrayBufferProto, |
228 | ArrayBufferProto, |
229 | DataViewProto, |
230 | WeakSetProto, |
231 | SetProto, |
232 | WeakMapProto, |
233 | MapProto, |
234 | IntrinsicTypedArrayProto, |
235 | ValueTypeProto, |
236 | SignalHandlerProto, |
237 | IteratorProto, |
238 | ForInIteratorProto, |
239 | SetIteratorProto, |
240 | MapIteratorProto, |
241 | ArrayIteratorProto, |
242 | StringIteratorProto, |
243 | |
244 | Object_Ctor, |
245 | String_Ctor, |
246 | Symbol_Ctor, |
247 | Number_Ctor, |
248 | Boolean_Ctor, |
249 | Array_Ctor, |
250 | Function_Ctor, |
251 | GeneratorFunction_Ctor, |
252 | Date_Ctor, |
253 | RegExp_Ctor, |
254 | Error_Ctor, |
255 | EvalError_Ctor, |
256 | RangeError_Ctor, |
257 | ReferenceError_Ctor, |
258 | SyntaxError_Ctor, |
259 | TypeError_Ctor, |
260 | URIError_Ctor, |
261 | SharedArrayBuffer_Ctor, |
262 | Promise_Ctor, |
263 | ArrayBuffer_Ctor, |
264 | DataView_Ctor, |
265 | WeakSet_Ctor, |
266 | Set_Ctor, |
267 | WeakMap_Ctor, |
268 | Map_Ctor, |
269 | IntrinsicTypedArray_Ctor, |
270 | |
271 | GetSymbolSpecies, |
272 | |
273 | Eval_Function, |
274 | GetStack_Function, |
275 | ThrowerObject, |
276 | NJSObjects |
277 | }; |
278 | Value *jsObjects; |
279 | enum { NTypedArrayTypes = 9 }; // == TypedArray::NValues, avoid header dependency |
280 | |
281 | ExecutionContext *rootContext() const { return reinterpret_cast<ExecutionContext *>(jsObjects + RootContext); } |
282 | ExecutionContext *scriptContext() const { return reinterpret_cast<ExecutionContext *>(jsObjects + ScriptContext); } |
283 | void setScriptContext(ReturnedValue c) { jsObjects[ScriptContext] = c; } |
284 | FunctionObject *objectCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Object_Ctor); } |
285 | FunctionObject *stringCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + String_Ctor); } |
286 | FunctionObject *symbolCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Symbol_Ctor); } |
287 | FunctionObject *numberCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Number_Ctor); } |
288 | FunctionObject *booleanCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Boolean_Ctor); } |
289 | FunctionObject *arrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Array_Ctor); } |
290 | FunctionObject *functionCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Function_Ctor); } |
291 | FunctionObject *generatorFunctionCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + GeneratorFunction_Ctor); } |
292 | FunctionObject *dateCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Date_Ctor); } |
293 | FunctionObject *regExpCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + RegExp_Ctor); } |
294 | FunctionObject *errorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Error_Ctor); } |
295 | FunctionObject *evalErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + EvalError_Ctor); } |
296 | FunctionObject *rangeErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + RangeError_Ctor); } |
297 | FunctionObject *referenceErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ReferenceError_Ctor); } |
298 | FunctionObject *syntaxErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + SyntaxError_Ctor); } |
299 | FunctionObject *typeErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + TypeError_Ctor); } |
300 | FunctionObject *uRIErrorCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + URIError_Ctor); } |
301 | FunctionObject *sharedArrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + SharedArrayBuffer_Ctor); } |
302 | FunctionObject *promiseCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Promise_Ctor); } |
303 | FunctionObject *arrayBufferCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + ArrayBuffer_Ctor); } |
304 | FunctionObject *dataViewCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + DataView_Ctor); } |
305 | FunctionObject *weakSetCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + WeakSet_Ctor); } |
306 | FunctionObject *setCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Set_Ctor); } |
307 | FunctionObject *weakMapCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + WeakMap_Ctor); } |
308 | FunctionObject *mapCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Map_Ctor); } |
309 | FunctionObject *intrinsicTypedArrayCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + IntrinsicTypedArray_Ctor); } |
310 | FunctionObject *typedArrayCtors; |
311 | |
312 | FunctionObject *getSymbolSpecies() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetSymbolSpecies); } |
313 | |
314 | Object *objectPrototype() const { return reinterpret_cast<Object *>(jsObjects + ObjectProto); } |
315 | Object *symbolPrototype() const { return reinterpret_cast<Object *>(jsObjects + SymbolProto); } |
316 | Object *arrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayProto); } |
317 | Object *arrayProtoValues() const { return reinterpret_cast<Object *>(jsObjects + ArrayProtoValues); } |
318 | Object *propertyListPrototype() const { return reinterpret_cast<Object *>(jsObjects + PropertyListProto); } |
319 | Object *stringPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringProto); } |
320 | Object *numberPrototype() const { return reinterpret_cast<Object *>(jsObjects + NumberProto); } |
321 | Object *booleanPrototype() const { return reinterpret_cast<Object *>(jsObjects + BooleanProto); } |
322 | Object *datePrototype() const { return reinterpret_cast<Object *>(jsObjects + DateProto); } |
323 | Object *functionPrototype() const { return reinterpret_cast<Object *>(jsObjects + FunctionProto); } |
324 | Object *generatorPrototype() const { return reinterpret_cast<Object *>(jsObjects + GeneratorProto); } |
325 | Object *regExpPrototype() const { return reinterpret_cast<Object *>(jsObjects + RegExpProto); } |
326 | Object *errorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ErrorProto); } |
327 | Object *evalErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + EvalErrorProto); } |
328 | Object *rangeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + RangeErrorProto); } |
329 | Object *referenceErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ReferenceErrorProto); } |
330 | Object *syntaxErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SyntaxErrorProto); } |
331 | Object *typeErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + TypeErrorProto); } |
332 | Object *uRIErrorPrototype() const { return reinterpret_cast<Object *>(jsObjects + URIErrorProto); } |
333 | Object *promisePrototype() const { return reinterpret_cast<Object *>(jsObjects + PromiseProto); } |
334 | Object *variantPrototype() const { return reinterpret_cast<Object *>(jsObjects + VariantProto); } |
335 | #if QT_CONFIG(qml_sequence_object) |
336 | Object *sequencePrototype() const { return reinterpret_cast<Object *>(jsObjects + SequenceProto); } |
337 | #endif |
338 | |
339 | Object *sharedArrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + SharedArrayBufferProto); } |
340 | Object *arrayBufferPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayBufferProto); } |
341 | Object *dataViewPrototype() const { return reinterpret_cast<Object *>(jsObjects + DataViewProto); } |
342 | Object *weakSetPrototype() const { return reinterpret_cast<Object *>(jsObjects + WeakSetProto); } |
343 | Object *setPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetProto); } |
344 | Object *weakMapPrototype() const { return reinterpret_cast<Object *>(jsObjects + WeakMapProto); } |
345 | Object *mapPrototype() const { return reinterpret_cast<Object *>(jsObjects + MapProto); } |
346 | Object *intrinsicTypedArrayPrototype() const { return reinterpret_cast<Object *>(jsObjects + IntrinsicTypedArrayProto); } |
347 | Object *typedArrayPrototype; |
348 | |
349 | Object *valueTypeWrapperPrototype() const { return reinterpret_cast<Object *>(jsObjects + ValueTypeProto); } |
350 | Object *signalHandlerPrototype() const { return reinterpret_cast<Object *>(jsObjects + SignalHandlerProto); } |
351 | Object *iteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + IteratorProto); } |
352 | Object *forInIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ForInIteratorProto); } |
353 | Object *setIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + SetIteratorProto); } |
354 | Object *mapIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + MapIteratorProto); } |
355 | Object *arrayIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + ArrayIteratorProto); } |
356 | Object *stringIteratorPrototype() const { return reinterpret_cast<Object *>(jsObjects + StringIteratorProto); } |
357 | |
358 | EvalFunction *evalFunction() const { return reinterpret_cast<EvalFunction *>(jsObjects + Eval_Function); } |
359 | FunctionObject *getStackFunction() const { return reinterpret_cast<FunctionObject *>(jsObjects + GetStack_Function); } |
360 | FunctionObject *thrower() const { return reinterpret_cast<FunctionObject *>(jsObjects + ThrowerObject); } |
361 | |
362 | #if QT_CONFIG(qml_network) |
363 | QNetworkAccessManager* (*networkAccessManager)(ExecutionEngine*) = detail::getNetworkAccessManager; |
364 | #endif |
365 | |
366 | enum JSStrings { |
367 | String_Empty, |
368 | String_undefined, |
369 | String_null, |
370 | String_true, |
371 | String_false, |
372 | String_boolean, |
373 | String_number, |
374 | String_string, |
375 | String_default, |
376 | String_symbol, |
377 | String_object, |
378 | String_function, |
379 | String_length, |
380 | String_prototype, |
381 | String_constructor, |
382 | String_arguments, |
383 | String_caller, |
384 | String_callee, |
385 | String_this, |
386 | String___proto__, |
387 | String_enumerable, |
388 | String_configurable, |
389 | String_writable, |
390 | String_value, |
391 | String_get, |
392 | String_set, |
393 | String_eval, |
394 | String_uintMax, |
395 | String_name, |
396 | String_index, |
397 | String_input, |
398 | String_toString, |
399 | String_toLocaleString, |
400 | String_destroy, |
401 | String_valueOf, |
402 | String_byteLength, |
403 | String_byteOffset, |
404 | String_buffer, |
405 | String_lastIndex, |
406 | String_next, |
407 | String_done, |
408 | String_return, |
409 | String_throw, |
410 | String_global, |
411 | String_ignoreCase, |
412 | String_multiline, |
413 | String_unicode, |
414 | String_sticky, |
415 | String_source, |
416 | String_flags, |
417 | |
418 | NJSStrings |
419 | }; |
420 | Value *jsStrings; |
421 | |
422 | enum JSSymbols { |
423 | Symbol_hasInstance, |
424 | Symbol_isConcatSpreadable, |
425 | Symbol_iterator, |
426 | Symbol_match, |
427 | Symbol_replace, |
428 | Symbol_search, |
429 | Symbol_species, |
430 | Symbol_split, |
431 | Symbol_toPrimitive, |
432 | Symbol_toStringTag, |
433 | Symbol_unscopables, |
434 | Symbol_revokableProxy, |
435 | NJSSymbols |
436 | }; |
437 | Value *jsSymbols; |
438 | |
439 | String *id_empty() const { return reinterpret_cast<String *>(jsStrings + String_Empty); } |
440 | String *id_undefined() const { return reinterpret_cast<String *>(jsStrings + String_undefined); } |
441 | String *id_null() const { return reinterpret_cast<String *>(jsStrings + String_null); } |
442 | String *id_true() const { return reinterpret_cast<String *>(jsStrings + String_true); } |
443 | String *id_false() const { return reinterpret_cast<String *>(jsStrings + String_false); } |
444 | String *id_boolean() const { return reinterpret_cast<String *>(jsStrings + String_boolean); } |
445 | String *id_number() const { return reinterpret_cast<String *>(jsStrings + String_number); } |
446 | String *id_string() const { return reinterpret_cast<String *>(jsStrings + String_string); } |
447 | String *id_default() const { return reinterpret_cast<String *>(jsStrings + String_default); } |
448 | String *id_symbol() const { return reinterpret_cast<String *>(jsStrings + String_symbol); } |
449 | String *id_object() const { return reinterpret_cast<String *>(jsStrings + String_object); } |
450 | String *id_function() const { return reinterpret_cast<String *>(jsStrings + String_function); } |
451 | String *id_length() const { return reinterpret_cast<String *>(jsStrings + String_length); } |
452 | String *id_prototype() const { return reinterpret_cast<String *>(jsStrings + String_prototype); } |
453 | String *id_constructor() const { return reinterpret_cast<String *>(jsStrings + String_constructor); } |
454 | String *id_arguments() const { return reinterpret_cast<String *>(jsStrings + String_arguments); } |
455 | String *id_caller() const { return reinterpret_cast<String *>(jsStrings + String_caller); } |
456 | String *id_callee() const { return reinterpret_cast<String *>(jsStrings + String_callee); } |
457 | String *id_this() const { return reinterpret_cast<String *>(jsStrings + String_this); } |
458 | String *id___proto__() const { return reinterpret_cast<String *>(jsStrings + String___proto__); } |
459 | String *id_enumerable() const { return reinterpret_cast<String *>(jsStrings + String_enumerable); } |
460 | String *id_configurable() const { return reinterpret_cast<String *>(jsStrings + String_configurable); } |
461 | String *id_writable() const { return reinterpret_cast<String *>(jsStrings + String_writable); } |
462 | String *id_value() const { return reinterpret_cast<String *>(jsStrings + String_value); } |
463 | String *id_get() const { return reinterpret_cast<String *>(jsStrings + String_get); } |
464 | String *id_set() const { return reinterpret_cast<String *>(jsStrings + String_set); } |
465 | String *id_eval() const { return reinterpret_cast<String *>(jsStrings + String_eval); } |
466 | String *id_uintMax() const { return reinterpret_cast<String *>(jsStrings + String_uintMax); } |
467 | String *id_name() const { return reinterpret_cast<String *>(jsStrings + String_name); } |
468 | String *id_index() const { return reinterpret_cast<String *>(jsStrings + String_index); } |
469 | String *id_input() const { return reinterpret_cast<String *>(jsStrings + String_input); } |
470 | String *id_toString() const { return reinterpret_cast<String *>(jsStrings + String_toString); } |
471 | String *id_toLocaleString() const { return reinterpret_cast<String *>(jsStrings + String_toLocaleString); } |
472 | String *id_destroy() const { return reinterpret_cast<String *>(jsStrings + String_destroy); } |
473 | String *id_valueOf() const { return reinterpret_cast<String *>(jsStrings + String_valueOf); } |
474 | String *id_byteLength() const { return reinterpret_cast<String *>(jsStrings + String_byteLength); } |
475 | String *id_byteOffset() const { return reinterpret_cast<String *>(jsStrings + String_byteOffset); } |
476 | String *id_buffer() const { return reinterpret_cast<String *>(jsStrings + String_buffer); } |
477 | String *id_lastIndex() const { return reinterpret_cast<String *>(jsStrings + String_lastIndex); } |
478 | String *id_next() const { return reinterpret_cast<String *>(jsStrings + String_next); } |
479 | String *id_done() const { return reinterpret_cast<String *>(jsStrings + String_done); } |
480 | String *id_return() const { return reinterpret_cast<String *>(jsStrings + String_return); } |
481 | String *id_throw() const { return reinterpret_cast<String *>(jsStrings + String_throw); } |
482 | String *id_global() const { return reinterpret_cast<String *>(jsStrings + String_global); } |
483 | String *id_ignoreCase() const { return reinterpret_cast<String *>(jsStrings + String_ignoreCase); } |
484 | String *id_multiline() const { return reinterpret_cast<String *>(jsStrings + String_multiline); } |
485 | String *id_unicode() const { return reinterpret_cast<String *>(jsStrings + String_unicode); } |
486 | String *id_sticky() const { return reinterpret_cast<String *>(jsStrings + String_sticky); } |
487 | String *id_source() const { return reinterpret_cast<String *>(jsStrings + String_source); } |
488 | String *id_flags() const { return reinterpret_cast<String *>(jsStrings + String_flags); } |
489 | |
490 | Symbol *symbol_hasInstance() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_hasInstance); } |
491 | Symbol *symbol_isConcatSpreadable() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_isConcatSpreadable); } |
492 | Symbol *symbol_iterator() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_iterator); } |
493 | Symbol *symbol_match() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_match); } |
494 | Symbol *symbol_replace() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_replace); } |
495 | Symbol *symbol_search() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_search); } |
496 | Symbol *symbol_species() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_species); } |
497 | Symbol *symbol_split() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_split); } |
498 | Symbol *symbol_toPrimitive() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_toPrimitive); } |
499 | Symbol *symbol_toStringTag() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_toStringTag); } |
500 | Symbol *symbol_unscopables() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_unscopables); } |
501 | Symbol *symbol_revokableProxy() const { return reinterpret_cast<Symbol *>(jsSymbols + Symbol_revokableProxy); } |
502 | |
503 | QIntrusiveList<ExecutableCompilationUnit, &ExecutableCompilationUnit::nextCompilationUnit> compilationUnits; |
504 | |
505 | quint32 m_engineId; |
506 | |
507 | RegExpCache *regExpCache; |
508 | |
509 | // Scarce resources are "exceptionally high cost" QVariant types where allowing the |
510 | // normal JavaScript GC to clean them up is likely to lead to out-of-memory or other |
511 | // out-of-resource situations. When such a resource is passed into JavaScript we |
512 | // add it to the scarceResources list and it is destroyed when we return from the |
513 | // JavaScript execution that created it. The user can prevent this behavior by |
514 | // calling preserve() on the object which removes it from this scarceResource list. |
515 | class ScarceResourceData { |
516 | public: |
517 | ScarceResourceData(const QVariant &data = QVariant()) : data(data) {} |
518 | QVariant data; |
519 | QIntrusiveListNode node; |
520 | }; |
521 | QIntrusiveList<ScarceResourceData, &ScarceResourceData::node> scarceResources; |
522 | |
523 | // Normally the JS wrappers for QObjects are stored in the QQmlData/QObjectPrivate, |
524 | // but any time a QObject is wrapped a second time in another engine, we have to do |
525 | // bookkeeping. |
526 | MultiplyWrappedQObjectMap *m_multiplyWrappedQObjects; |
527 | #if QT_CONFIG(qml_jit) |
528 | const bool m_canAllocateExecutableMemory; |
529 | #endif |
530 | |
531 | quintptr protoIdCount = 1; |
532 | |
533 | ExecutionEngine(QJSEngine *jsEngine = nullptr); |
534 | ~ExecutionEngine(); |
535 | |
536 | #if !QT_CONFIG(qml_debug) |
537 | QV4::Debugging::Debugger *debugger() const { return nullptr; } |
538 | QV4::Profiling::Profiler *profiler() const { return nullptr; } |
539 | |
540 | void setDebugger(Debugging::Debugger *) {} |
541 | void setProfiler(Profiling::Profiler *) {} |
542 | #else |
543 | QV4::Debugging::Debugger *debugger() const { return m_debugger.data(); } |
544 | QV4::Profiling::Profiler *profiler() const { return m_profiler.data(); } |
545 | |
546 | void setDebugger(Debugging::Debugger *debugger); |
547 | void setProfiler(Profiling::Profiler *profiler); |
548 | #endif // QT_CONFIG(qml_debug) |
549 | |
550 | ExecutionContext *currentContext() const; |
551 | |
552 | // ensure we always get odd prototype IDs. This helps make marking in QV4::Lookup fast |
553 | quintptr newProtoId() { return (protoIdCount += 2); } |
554 | |
555 | Heap::InternalClass *newInternalClass(const VTable *vtable, Object *prototype); |
556 | |
557 | Heap::Object *newObject(); |
558 | Heap::Object *newObject(Heap::InternalClass *internalClass); |
559 | |
560 | Heap::String *newString(const QString &s = QString()); |
561 | Heap::String *newIdentifier(const QString &text); |
562 | |
563 | Heap::Object *newStringObject(const String *string); |
564 | Heap::Object *newSymbolObject(const Symbol *symbol); |
565 | Heap::Object *newNumberObject(double value); |
566 | Heap::Object *newBooleanObject(bool b); |
567 | |
568 | Heap::ArrayObject *newArrayObject(int count = 0); |
569 | Heap::ArrayObject *newArrayObject(const Value *values, int length); |
570 | Heap::ArrayObject *newArrayObject(const QStringList &list); |
571 | Heap::ArrayObject *newArrayObject(Heap::InternalClass *ic); |
572 | |
573 | Heap::ArrayBuffer *newArrayBuffer(const QByteArray &array); |
574 | Heap::ArrayBuffer *newArrayBuffer(size_t length); |
575 | |
576 | Heap::DateObject *newDateObject(const Value &value); |
577 | Heap::DateObject *newDateObject(const QDateTime &dt); |
578 | Heap::DateObject *newDateObjectFromTime(const QTime &t); |
579 | |
580 | Heap::RegExpObject *newRegExpObject(const QString &pattern, int flags); |
581 | Heap::RegExpObject *newRegExpObject(RegExp *re); |
582 | Heap::RegExpObject *newRegExpObject(const QRegExp &re); |
583 | #if QT_CONFIG(regularexpression) |
584 | Heap::RegExpObject *newRegExpObject(const QRegularExpression &re); |
585 | #endif |
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 QVariant &v); |
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 | Heap::QmlContext *qmlContext() const; |
611 | QObject *qmlScopeObject() const; |
612 | QQmlContextData *callingQmlContext() const; |
613 | |
614 | |
615 | StackTrace stackTrace(int frameLimit = -1) const; |
616 | QUrl resolvedUrl(const QString &file); |
617 | |
618 | void markObjects(MarkStack *markStack); |
619 | |
620 | void initRootContext(); |
621 | |
622 | Heap::InternalClass *newClass(Heap::InternalClass *other); |
623 | |
624 | StackTrace exceptionStackTrace; |
625 | |
626 | ReturnedValue throwError(const Value &value); |
627 | ReturnedValue catchException(StackTrace *trace = nullptr); |
628 | |
629 | ReturnedValue throwError(const QString &message); |
630 | ReturnedValue throwSyntaxError(const QString &message); |
631 | ReturnedValue throwSyntaxError(const QString &message, const QString &fileName, int lineNumber, int column); |
632 | ReturnedValue throwTypeError(); |
633 | ReturnedValue throwTypeError(const QString &message); |
634 | ReturnedValue throwReferenceError(const Value &value); |
635 | ReturnedValue throwReferenceError(const QString &name); |
636 | ReturnedValue throwReferenceError(const QString &value, const QString &fileName, int lineNumber, int column); |
637 | ReturnedValue throwRangeError(const Value &value); |
638 | ReturnedValue throwRangeError(const QString &message); |
639 | ReturnedValue throwURIError(const Value &msg); |
640 | ReturnedValue throwUnimplemented(const QString &message); |
641 | |
642 | // Use only inside catch(...) -- will re-throw if no JS exception |
643 | QQmlError catchExceptionAsQmlError(); |
644 | |
645 | // variant conversions |
646 | QVariant toVariant(const QV4::Value &value, int typeHint, bool createJSValueForObjects = true); |
647 | QV4::ReturnedValue fromVariant(const QVariant &); |
648 | |
649 | QVariantMap variantMapFromJS(const QV4::Object *o); |
650 | |
651 | bool metaTypeFromJS(const Value *value, int type, void *data); |
652 | QV4::ReturnedValue metaTypeToJS(int type, const void *data); |
653 | |
654 | int maxJSStackSize() const; |
655 | int maxGCStackSize() const; |
656 | |
657 | bool checkStackLimits(); |
658 | |
659 | bool canJIT(Function *f = nullptr) |
660 | { |
661 | #if QT_CONFIG(qml_jit) |
662 | if (!m_canAllocateExecutableMemory) |
663 | return false; |
664 | if (f) |
665 | return !f->isGenerator() && f->interpreterCallCount >= jitCallCountThreshold; |
666 | return true; |
667 | #else |
668 | Q_UNUSED(f); |
669 | return false; |
670 | #endif |
671 | } |
672 | |
673 | QV4::ReturnedValue global(); |
674 | void initQmlGlobalObject(); |
675 | void initializeGlobal(); |
676 | |
677 | void freezeObject(const QV4::Value &value); |
678 | |
679 | // Return the list of illegal id names (the names of the properties on the global object) |
680 | const QSet<QString> &illegalNames() const; |
681 | |
682 | #if QT_CONFIG(qml_xml_http_request) |
683 | void *xmlHttpRequestData() const { return m_xmlHttpRequestData; } |
684 | #endif |
685 | |
686 | void setQmlEngine(QQmlEngine *engine); |
687 | |
688 | QQmlDelayedCallQueue *delayedCallQueue() { return &m_delayedCallQueue; } |
689 | |
690 | // used for console.time(), console.timeEnd() |
691 | void startTimer(const QString &timerName); |
692 | qint64 stopTimer(const QString &timerName, bool *wasRunning); |
693 | |
694 | // used for console.count() |
695 | int consoleCountHelper(const QString &file, quint16 line, quint16 column); |
696 | |
697 | struct Deletable { |
698 | virtual ~Deletable() {} |
699 | }; |
700 | |
701 | static QMutex *registrationMutex(); |
702 | static int registerExtension(); |
703 | |
704 | void setExtensionData(int, Deletable *); |
705 | Deletable *extensionData(int index) const |
706 | { |
707 | if (index < m_extensionData.count()) |
708 | return m_extensionData[index]; |
709 | else |
710 | return nullptr; |
711 | } |
712 | |
713 | double localTZA = 0.0; // local timezone, initialized at startup |
714 | |
715 | QQmlRefPointer<ExecutableCompilationUnit> compileModule(const QUrl &url); |
716 | QQmlRefPointer<ExecutableCompilationUnit> compileModule( |
717 | const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp); |
718 | |
719 | mutable QMutex moduleMutex; |
720 | QHash<QUrl, QQmlRefPointer<ExecutableCompilationUnit>> modules; |
721 | void injectModule(const QQmlRefPointer<ExecutableCompilationUnit> &moduleUnit); |
722 | QQmlRefPointer<ExecutableCompilationUnit> moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr) const; |
723 | QQmlRefPointer<ExecutableCompilationUnit> loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr); |
724 | |
725 | private: |
726 | #if QT_CONFIG(qml_debug) |
727 | QScopedPointer<QV4::Debugging::Debugger> m_debugger; |
728 | QScopedPointer<QV4::Profiling::Profiler> m_profiler; |
729 | #endif |
730 | QSet<QString> m_illegalNames; |
731 | int jitCallCountThreshold; |
732 | |
733 | // used by generated Promise objects to handle 'then' events |
734 | QScopedPointer<QV4::Promise::ReactionHandler> m_reactionHandler; |
735 | |
736 | #if QT_CONFIG(qml_xml_http_request) |
737 | void *m_xmlHttpRequestData; |
738 | #endif |
739 | |
740 | QQmlEngine *m_qmlEngine; |
741 | |
742 | QQmlDelayedCallQueue m_delayedCallQueue; |
743 | |
744 | QElapsedTimer m_time; |
745 | QHash<QString, qint64> m_startedTimers; |
746 | |
747 | QHash<QString, quint32> m_consoleCount; |
748 | |
749 | QVector<Deletable *> m_extensionData; |
750 | |
751 | int m_maxJSStackSize = 4 * 1024 * 1024; |
752 | int m_maxGCStackSize = 2 * 1024 * 1024; |
753 | }; |
754 | |
755 | #define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \ |
756 | ExecutionEngineCallDepthRecorder _executionEngineCallDepthRecorder(v4); |
757 | |
758 | struct ExecutionEngineCallDepthRecorder |
759 | { |
760 | ExecutionEngine *ee; |
761 | |
762 | ExecutionEngineCallDepthRecorder(ExecutionEngine *e): ee(e) { ++ee->callDepth; } |
763 | ~ExecutionEngineCallDepthRecorder() { --ee->callDepth; } |
764 | }; |
765 | |
766 | inline bool ExecutionEngine::checkStackLimits() |
767 | { |
768 | if (Q_UNLIKELY((jsStackTop > jsStackLimit) || (callDepth >= maxCallDepth))) { |
769 | throwRangeError(QStringLiteral("Maximum call stack size exceeded." )); |
770 | return true; |
771 | } |
772 | |
773 | return false; |
774 | } |
775 | |
776 | } // namespace QV4 |
777 | |
778 | QT_END_NAMESPACE |
779 | |
780 | #endif // QV4ENGINE_H |
781 | |