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 | |
40 | #ifndef QV4INSTR_MOTH_P_H |
41 | #define QV4INSTR_MOTH_P_H |
42 | |
43 | // |
44 | // W A R N I N G |
45 | // ------------- |
46 | // |
47 | // This file is not part of the Qt API. It exists purely as an |
48 | // implementation detail. This header file may change from version to |
49 | // version without notice, or even be removed. |
50 | // |
51 | // We mean it. |
52 | // |
53 | |
54 | #include <private/qv4staticvalue_p.h> |
55 | #include <private/qv4compileddata_p.h> // for CompiledData::CodeOffsetToLine used by the dumper |
56 | #include <qendian.h> |
57 | |
58 | QT_BEGIN_NAMESPACE |
59 | |
60 | #define INSTRUCTION(op, name, nargs, ...) \ |
61 | op##_INSTRUCTION(name, nargs, __VA_ARGS__) |
62 | |
63 | /* for all jump instructions, the offset has to come last, to simplify the job of the bytecode generator */ |
64 | #define INSTR_Nop(op) INSTRUCTION(op, Nop, 0) |
65 | #define INSTR_Ret(op) INSTRUCTION(op, Ret, 0) |
66 | #define INSTR_Debug(op) INSTRUCTION(op, Debug, 0) |
67 | #define INSTR_LoadConst(op) INSTRUCTION(op, LoadConst, 1, index) |
68 | #define INSTR_LoadZero(op) INSTRUCTION(op, LoadZero, 0) |
69 | #define INSTR_LoadTrue(op) INSTRUCTION(op, LoadTrue, 0) |
70 | #define INSTR_LoadFalse(op) INSTRUCTION(op, LoadFalse, 0) |
71 | #define INSTR_LoadNull(op) INSTRUCTION(op, LoadNull, 0) |
72 | #define INSTR_LoadUndefined(op) INSTRUCTION(op, LoadUndefined, 0) |
73 | #define INSTR_LoadInt(op) INSTRUCTION(op, LoadInt, 1, value) |
74 | #define INSTR_MoveConst(op) INSTRUCTION(op, MoveConst, 2, constIndex, destTemp) |
75 | #define INSTR_LoadReg(op) INSTRUCTION(op, LoadReg, 1, reg) |
76 | #define INSTR_StoreReg(op) INSTRUCTION(op, StoreReg, 1, reg) |
77 | #define INSTR_MoveReg(op) INSTRUCTION(op, MoveReg, 2, srcReg, destReg) |
78 | #define INSTR_LoadImport(op) INSTRUCTION(op, LoadImport, 1, index) |
79 | #define INSTR_LoadLocal(op) INSTRUCTION(op, LoadLocal, 1, index) |
80 | #define INSTR_StoreLocal(op) INSTRUCTION(op, StoreLocal, 1, index) |
81 | #define INSTR_LoadScopedLocal(op) INSTRUCTION(op, LoadScopedLocal, 2, scope, index) |
82 | #define INSTR_StoreScopedLocal(op) INSTRUCTION(op, StoreScopedLocal, 2, scope, index) |
83 | #define INSTR_LoadRuntimeString(op) INSTRUCTION(op, LoadRuntimeString, 1, stringId) |
84 | #define INSTR_MoveRegExp(op) INSTRUCTION(op, MoveRegExp, 2, regExpId, destReg) |
85 | #define INSTR_LoadClosure(op) INSTRUCTION(op, LoadClosure, 1, value) |
86 | #define INSTR_LoadName(op) INSTRUCTION(op, LoadName, 1, name) |
87 | #define INSTR_LoadGlobalLookup(op) INSTRUCTION(op, LoadGlobalLookup, 1, index) |
88 | #define INSTR_LoadQmlContextPropertyLookup(op) INSTRUCTION(op, LoadQmlContextPropertyLookup, 1, index) |
89 | #define INSTR_StoreNameSloppy(op) INSTRUCTION(op, StoreNameSloppy, 1, name) |
90 | #define INSTR_StoreNameStrict(op) INSTRUCTION(op, StoreNameStrict, 1, name) |
91 | #define INSTR_LoadProperty(op) INSTRUCTION(op, LoadProperty, 1, name) |
92 | #define INSTR_GetLookup(op) INSTRUCTION(op, GetLookup, 1, index) |
93 | #define INSTR_LoadIdObject(op) INSTRUCTION(op, LoadIdObject, 2, index, base) |
94 | #define INSTR_Yield(op) INSTRUCTION(op, Yield, 0) |
95 | #define INSTR_YieldStar(op) INSTRUCTION(op, YieldStar, 0) |
96 | #define INSTR_Resume(op) INSTRUCTION(op, Resume, 1, offset) |
97 | #define INSTR_IteratorNextForYieldStar(op) INSTRUCTION(op, IteratorNextForYieldStar, 2, iterator, object) |
98 | #define INSTR_StoreProperty(op) INSTRUCTION(op, StoreProperty, 2, name, base) |
99 | #define INSTR_SetLookup(op) INSTRUCTION(op, SetLookup, 2, index, base) |
100 | #define INSTR_LoadSuperProperty(op) INSTRUCTION(op, LoadSuperProperty, 1, property) |
101 | #define INSTR_StoreSuperProperty(op) INSTRUCTION(op, StoreSuperProperty, 1, property) |
102 | #define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 1, base) |
103 | #define INSTR_StoreElement(op) INSTRUCTION(op, StoreElement, 2, base, index) |
104 | #define INSTR_CallValue(op) INSTRUCTION(op, CallValue, 3, name, argc, argv) |
105 | #define INSTR_CallWithReceiver(op) INSTRUCTION(op, CallWithReceiver, 4, name, thisObject, argc, argv) |
106 | #define INSTR_CallProperty(op) INSTRUCTION(op, CallProperty, 4, name, base, argc, argv) |
107 | #define INSTR_CallPropertyLookup(op) INSTRUCTION(op, CallPropertyLookup, 4, lookupIndex, base, argc, argv) |
108 | #define INSTR_CallElement(op) INSTRUCTION(op, CallElement, 4, base, index, argc, argv) |
109 | #define INSTR_CallName(op) INSTRUCTION(op, CallName, 3, name, argc, argv) |
110 | #define INSTR_CallPossiblyDirectEval(op) INSTRUCTION(op, CallPossiblyDirectEval, 2, argc, argv) |
111 | #define INSTR_CallGlobalLookup(op) INSTRUCTION(op, CallGlobalLookup, 3, index, argc, argv) |
112 | #define INSTR_CallQmlContextPropertyLookup(op) INSTRUCTION(op, CallQmlContextPropertyLookup, 3, index, argc, argv) |
113 | #define INSTR_CallWithSpread(op) INSTRUCTION(op, CallWithSpread, 4, func, thisObject, argc, argv) |
114 | #define INSTR_Construct(op) INSTRUCTION(op, Construct, 3, func, argc, argv) |
115 | #define INSTR_ConstructWithSpread(op) INSTRUCTION(op, ConstructWithSpread, 3, func, argc, argv) |
116 | #define INSTR_SetUnwindHandler(op) INSTRUCTION(op, SetUnwindHandler, 1, offset) |
117 | #define INSTR_UnwindDispatch(op) INSTRUCTION(op, UnwindDispatch, 0) |
118 | #define INSTR_UnwindToLabel(op) INSTRUCTION(op, UnwindToLabel, 2, level, offset) |
119 | #define INSTR_DeadTemporalZoneCheck(op) INSTRUCTION(op, DeadTemporalZoneCheck, 1, name) |
120 | #define INSTR_ThrowException(op) INSTRUCTION(op, ThrowException, 0) |
121 | #define INSTR_GetException(op) INSTRUCTION(op, GetException, 0) |
122 | #define INSTR_SetException(op) INSTRUCTION(op, SetException, 0) |
123 | #define INSTR_CreateCallContext(op) INSTRUCTION(op, CreateCallContext, 0) |
124 | #define INSTR_PushCatchContext(op) INSTRUCTION(op, PushCatchContext, 2, index, name) |
125 | #define INSTR_PushWithContext(op) INSTRUCTION(op, PushWithContext, 0) |
126 | #define INSTR_PushBlockContext(op) INSTRUCTION(op, PushBlockContext, 1, index) |
127 | #define INSTR_CloneBlockContext(op) INSTRUCTION(op, CloneBlockContext, 0) |
128 | #define INSTR_PushScriptContext(op) INSTRUCTION(op, PushScriptContext, 1, index) |
129 | #define INSTR_PopScriptContext(op) INSTRUCTION(op, PopScriptContext, 0) |
130 | #define INSTR_PopContext(op) INSTRUCTION(op, PopContext, 0) |
131 | #define INSTR_GetIterator(op) INSTRUCTION(op, GetIterator, 1, iterator) |
132 | #define INSTR_IteratorNext(op) INSTRUCTION(op, IteratorNext, 2, value, done) |
133 | #define INSTR_IteratorClose(op) INSTRUCTION(op, IteratorClose, 1, done) |
134 | #define INSTR_DestructureRestElement(op) INSTRUCTION(op, DestructureRestElement, 0) |
135 | #define INSTR_DeleteProperty(op) INSTRUCTION(op, DeleteProperty, 2, base, index) |
136 | #define INSTR_DeleteName(op) INSTRUCTION(op, DeleteName, 1, name) |
137 | #define INSTR_TypeofName(op) INSTRUCTION(op, TypeofName, 1, name) |
138 | #define INSTR_TypeofValue(op) INSTRUCTION(op, TypeofValue, 0) |
139 | #define INSTR_DeclareVar(op) INSTRUCTION(op, DeclareVar, 2, varName, isDeletable) |
140 | #define INSTR_DefineArray(op) INSTRUCTION(op, DefineArray, 2, argc, args) |
141 | #define INSTR_DefineObjectLiteral(op) INSTRUCTION(op, DefineObjectLiteral, 3, internalClassId, argc, args) |
142 | #define INSTR_CreateClass(op) INSTRUCTION(op, CreateClass, 3, classIndex, heritage, computedNames) |
143 | #define INSTR_CreateMappedArgumentsObject(op) INSTRUCTION(op, CreateMappedArgumentsObject, 0) |
144 | #define INSTR_CreateUnmappedArgumentsObject(op) INSTRUCTION(op, CreateUnmappedArgumentsObject, 0) |
145 | #define INSTR_CreateRestParameter(op) INSTRUCTION(op, CreateRestParameter, 1, argIndex) |
146 | #define INSTR_ConvertThisToObject(op) INSTRUCTION(op, ConvertThisToObject, 0) |
147 | #define INSTR_LoadSuperConstructor(op) INSTRUCTION(op, LoadSuperConstructor, 0) |
148 | #define INSTR_ToObject(op) INSTRUCTION(op, ToObject, 0) |
149 | #define INSTR_Jump(op) INSTRUCTION(op, Jump, 1, offset) |
150 | #define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 1, offset) |
151 | #define INSTR_JumpFalse(op) INSTRUCTION(op, JumpFalse, 1, offset) |
152 | #define INSTR_JumpNotUndefined(op) INSTRUCTION(op, JumpNotUndefined, 1, offset) |
153 | #define INSTR_JumpNoException(op) INSTRUCTION(op, JumpNoException, 1, offset) |
154 | #define INSTR_CheckException(op) INSTRUCTION(op, CheckException, 0) |
155 | #define INSTR_CmpEqNull(op) INSTRUCTION(op, CmpEqNull, 0) |
156 | #define INSTR_CmpNeNull(op) INSTRUCTION(op, CmpNeNull, 0) |
157 | #define INSTR_CmpEqInt(op) INSTRUCTION(op, CmpEqInt, 1, lhs) |
158 | #define INSTR_CmpNeInt(op) INSTRUCTION(op, CmpNeInt, 1, lhs) |
159 | #define INSTR_CmpEq(op) INSTRUCTION(op, CmpEq, 1, lhs) |
160 | #define INSTR_CmpNe(op) INSTRUCTION(op, CmpNe, 1, lhs) |
161 | #define INSTR_CmpGt(op) INSTRUCTION(op, CmpGt, 1, lhs) |
162 | #define INSTR_CmpGe(op) INSTRUCTION(op, CmpGe, 1, lhs) |
163 | #define INSTR_CmpLt(op) INSTRUCTION(op, CmpLt, 1, lhs) |
164 | #define INSTR_CmpLe(op) INSTRUCTION(op, CmpLe, 1, lhs) |
165 | #define INSTR_CmpStrictEqual(op) INSTRUCTION(op, CmpStrictEqual, 1, lhs) |
166 | #define INSTR_CmpStrictNotEqual(op) INSTRUCTION(op, CmpStrictNotEqual, 1, lhs) |
167 | #define INSTR_CmpIn(op) INSTRUCTION(op, CmpIn, 1, lhs) |
168 | #define INSTR_CmpInstanceOf(op) INSTRUCTION(op, CmpInstanceOf, 1, lhs) |
169 | #define INSTR_UNot(op) INSTRUCTION(op, UNot, 0) |
170 | #define INSTR_UPlus(op) INSTRUCTION(op, UPlus, 0) |
171 | #define INSTR_UMinus(op) INSTRUCTION(op, UMinus, 0) |
172 | #define INSTR_UCompl(op) INSTRUCTION(op, UCompl, 0) |
173 | #define INSTR_Increment(op) INSTRUCTION(op, Increment, 0) |
174 | #define INSTR_Decrement(op) INSTRUCTION(op, Decrement, 0) |
175 | #define INSTR_Add(op) INSTRUCTION(op, Add, 1, lhs) |
176 | #define INSTR_BitAnd(op) INSTRUCTION(op, BitAnd, 1, lhs) |
177 | #define INSTR_BitOr(op) INSTRUCTION(op, BitOr, 1, lhs) |
178 | #define INSTR_BitXor(op) INSTRUCTION(op, BitXor, 1, lhs) |
179 | #define INSTR_UShr(op) INSTRUCTION(op, UShr, 1, lhs) |
180 | #define INSTR_Shr(op) INSTRUCTION(op, Shr, 1, lhs) |
181 | #define INSTR_Shl(op) INSTRUCTION(op, Shl, 1, lhs) |
182 | #define INSTR_BitAndConst(op) INSTRUCTION(op, BitAndConst, 1, rhs) |
183 | #define INSTR_BitOrConst(op) INSTRUCTION(op, BitOrConst, 1, rhs) |
184 | #define INSTR_BitXorConst(op) INSTRUCTION(op, BitXorConst, 1, rhs) |
185 | #define INSTR_UShrConst(op) INSTRUCTION(op, UShrConst, 1, rhs) |
186 | #define INSTR_ShrConst(op) INSTRUCTION(op, ShrConst, 1, rhs) |
187 | #define INSTR_ShlConst(op) INSTRUCTION(op, ShlConst, 1, rhs) |
188 | #define INSTR_Exp(op) INSTRUCTION(op, Exp, 1, lhs) |
189 | #define INSTR_Mul(op) INSTRUCTION(op, Mul, 1, lhs) |
190 | #define INSTR_Div(op) INSTRUCTION(op, Div, 1, lhs) |
191 | #define INSTR_Mod(op) INSTRUCTION(op, Mod, 1, lhs) |
192 | #define INSTR_Sub(op) INSTRUCTION(op, Sub, 1, lhs) |
193 | #define INSTR_LoadQmlImportedScripts(op) INSTRUCTION(op, LoadQmlImportedScripts, 1, result) |
194 | #define INSTR_InitializeBlockDeadTemporalZone(op) INSTRUCTION(op, InitializeBlockDeadTemporalZone, 2, firstReg, count) |
195 | #define INSTR_ThrowOnNullOrUndefined(op) INSTRUCTION(op, ThrowOnNullOrUndefined, 0) |
196 | #define INSTR_GetTemplateObject(op) INSTRUCTION(op, GetTemplateObject, 1, index) |
197 | #define INSTR_TailCall(op) INSTRUCTION(op, TailCall, 4, func, thisObject, argc, argv) |
198 | |
199 | #define FOR_EACH_MOTH_INSTR_ALL(F) \ |
200 | F(Nop) \ |
201 | FOR_EACH_MOTH_INSTR(F) |
202 | |
203 | #define FOR_EACH_MOTH_INSTR(F) \ |
204 | F(Ret) \ |
205 | F(LoadConst) \ |
206 | F(LoadZero) \ |
207 | F(LoadTrue) \ |
208 | F(LoadFalse) \ |
209 | F(LoadNull) \ |
210 | F(LoadUndefined) \ |
211 | F(LoadInt) \ |
212 | F(LoadRuntimeString) \ |
213 | F(MoveConst) \ |
214 | F(LoadReg) \ |
215 | F(StoreReg) \ |
216 | F(MoveReg) \ |
217 | F(LoadImport) \ |
218 | F(LoadLocal) \ |
219 | F(StoreLocal) \ |
220 | F(LoadScopedLocal) \ |
221 | F(StoreScopedLocal) \ |
222 | F(MoveRegExp) \ |
223 | F(LoadClosure) \ |
224 | F(LoadName) \ |
225 | F(LoadGlobalLookup) \ |
226 | F(LoadQmlContextPropertyLookup) \ |
227 | F(StoreNameSloppy) \ |
228 | F(StoreNameStrict) \ |
229 | F(LoadElement) \ |
230 | F(StoreElement) \ |
231 | F(LoadProperty) \ |
232 | F(GetLookup) \ |
233 | F(StoreProperty) \ |
234 | F(SetLookup) \ |
235 | F(LoadSuperProperty) \ |
236 | F(StoreSuperProperty) \ |
237 | F(ConvertThisToObject) \ |
238 | F(ToObject) \ |
239 | F(Jump) \ |
240 | F(JumpTrue) \ |
241 | F(JumpFalse) \ |
242 | F(JumpNoException) \ |
243 | F(JumpNotUndefined) \ |
244 | F(CheckException) \ |
245 | F(CmpEqNull) \ |
246 | F(CmpNeNull) \ |
247 | F(CmpEqInt) \ |
248 | F(CmpNeInt) \ |
249 | F(CmpEq) \ |
250 | F(CmpNe) \ |
251 | F(CmpGt) \ |
252 | F(CmpGe) \ |
253 | F(CmpLt) \ |
254 | F(CmpLe) \ |
255 | F(CmpStrictEqual) \ |
256 | F(CmpStrictNotEqual) \ |
257 | F(CmpIn) \ |
258 | F(CmpInstanceOf) \ |
259 | F(UNot) \ |
260 | F(UPlus) \ |
261 | F(UMinus) \ |
262 | F(UCompl) \ |
263 | F(Increment) \ |
264 | F(Decrement) \ |
265 | F(Add) \ |
266 | F(BitAnd) \ |
267 | F(BitOr) \ |
268 | F(BitXor) \ |
269 | F(UShr) \ |
270 | F(Shr) \ |
271 | F(Shl) \ |
272 | F(BitAndConst) \ |
273 | F(BitOrConst) \ |
274 | F(BitXorConst) \ |
275 | F(UShrConst) \ |
276 | F(ShrConst) \ |
277 | F(ShlConst) \ |
278 | F(Exp) \ |
279 | F(Mul) \ |
280 | F(Div) \ |
281 | F(Mod) \ |
282 | F(Sub) \ |
283 | F(CallValue) \ |
284 | F(CallWithReceiver) \ |
285 | F(CallProperty) \ |
286 | F(CallPropertyLookup) \ |
287 | F(CallElement) \ |
288 | F(CallName) \ |
289 | F(CallPossiblyDirectEval) \ |
290 | F(CallGlobalLookup) \ |
291 | F(CallQmlContextPropertyLookup) \ |
292 | F(CallWithSpread) \ |
293 | F(Construct) \ |
294 | F(ConstructWithSpread) \ |
295 | F(SetUnwindHandler) \ |
296 | F(UnwindDispatch) \ |
297 | F(UnwindToLabel) \ |
298 | F(DeadTemporalZoneCheck) \ |
299 | F(ThrowException) \ |
300 | F(GetException) \ |
301 | F(SetException) \ |
302 | F(CreateCallContext) \ |
303 | F(PushCatchContext) \ |
304 | F(PushWithContext) \ |
305 | F(PushBlockContext) \ |
306 | F(CloneBlockContext) \ |
307 | F(PopContext) \ |
308 | F(GetIterator) \ |
309 | F(IteratorNext) \ |
310 | F(IteratorClose) \ |
311 | F(DestructureRestElement) \ |
312 | F(DeleteProperty) \ |
313 | F(DeleteName) \ |
314 | F(TypeofName) \ |
315 | F(TypeofValue) \ |
316 | F(DeclareVar) \ |
317 | F(DefineArray) \ |
318 | F(DefineObjectLiteral) \ |
319 | F(CreateMappedArgumentsObject) \ |
320 | F(CreateUnmappedArgumentsObject) \ |
321 | F(CreateRestParameter) \ |
322 | F(Yield) \ |
323 | F(YieldStar) \ |
324 | F(Resume) \ |
325 | F(IteratorNextForYieldStar) \ |
326 | F(CreateClass) \ |
327 | F(LoadSuperConstructor) \ |
328 | F(PushScriptContext) \ |
329 | F(PopScriptContext) \ |
330 | F(InitializeBlockDeadTemporalZone) \ |
331 | F(ThrowOnNullOrUndefined) \ |
332 | F(GetTemplateObject) \ |
333 | F(TailCall) \ |
334 | F(Debug) \ |
335 | |
336 | #define MOTH_NUM_INSTRUCTIONS() (static_cast<int>(Moth::Instr::Type::Debug_Wide) + 1) |
337 | |
338 | #if defined(Q_CC_GNU) |
339 | #if defined(Q_CC_INTEL) |
340 | // icc before version 1200 doesn't support computed goto, and at least up to version 18.0.0 the |
341 | // current use results in an internal compiler error. We could enable this if/when it gets fixed |
342 | // in a later version. |
343 | # elif defined(Q_OS_WASM) && !defined(__asmjs) |
344 | // Upstream llvm does not support computed goto for the wasm target, unlike the 'fastcomp' llvm fork |
345 | // shipped with the emscripten SDK. Disable computed goto usage for non-fastcomp llvm on Wasm. |
346 | #else |
347 | # define MOTH_COMPUTED_GOTO |
348 | #endif |
349 | #endif |
350 | |
351 | #define MOTH_INSTR_ALIGN_MASK (Q_ALIGNOF(QV4::Moth::Instr) - 1) |
352 | |
353 | #define MOTH_INSTR_ENUM(I) I, I##_Wide, |
354 | #define MOTH_INSTR_SIZE(I) (sizeof(QV4::Moth::Instr::instr_##I)) |
355 | |
356 | #define MOTH_EXPAND_FOR_MSVC(x) x |
357 | #define MOTH_DEFINE_ARGS(nargs, ...) \ |
358 | MOTH_EXPAND_FOR_MSVC(MOTH_DEFINE_ARGS##nargs(__VA_ARGS__)) |
359 | |
360 | #define MOTH_DEFINE_ARGS0() |
361 | #define MOTH_DEFINE_ARGS1(arg) \ |
362 | int arg; |
363 | #define MOTH_DEFINE_ARGS2(arg1, arg2) \ |
364 | int arg1; \ |
365 | int arg2; |
366 | #define MOTH_DEFINE_ARGS3(arg1, arg2, arg3) \ |
367 | int arg1; \ |
368 | int arg2; \ |
369 | int arg3; |
370 | #define MOTH_DEFINE_ARGS4(arg1, arg2, arg3, arg4) \ |
371 | int arg1; \ |
372 | int arg2; \ |
373 | int arg3; \ |
374 | int arg4; |
375 | #define MOTH_DEFINE_ARGS5(arg1, arg2, arg3, arg4, arg5) \ |
376 | int arg1; \ |
377 | int arg2; \ |
378 | int arg3; \ |
379 | int arg4; \ |
380 | int arg5; |
381 | |
382 | #define MOTH_COLLECT_ENUMS(instr) \ |
383 | INSTR_##instr(MOTH_GET_ENUM) |
384 | #define MOTH_GET_ENUM_INSTRUCTION(name, ...) \ |
385 | name, |
386 | |
387 | #define MOTH_EMIT_STRUCTS(instr) \ |
388 | INSTR_##instr(MOTH_EMIT_STRUCT) |
389 | #define MOTH_EMIT_STRUCT_INSTRUCTION(name, nargs, ...) \ |
390 | struct instr_##name { \ |
391 | MOTH_DEFINE_ARGS(nargs, __VA_ARGS__) \ |
392 | }; |
393 | |
394 | #define MOTH_EMIT_INSTR_MEMBERS(instr) \ |
395 | INSTR_##instr(MOTH_EMIT_INSTR_MEMBER) |
396 | #define MOTH_EMIT_INSTR_MEMBER_INSTRUCTION(name, nargs, ...) \ |
397 | instr_##name name; |
398 | |
399 | #define MOTH_COLLECT_NARGS(instr) \ |
400 | INSTR_##instr(MOTH_COLLECT_ARG_COUNT) |
401 | #define MOTH_COLLECT_ARG_COUNT_INSTRUCTION(name, nargs, ...) \ |
402 | nargs, nargs, |
403 | |
404 | #define MOTH_DECODE_ARG(arg, type, nargs, offset) \ |
405 | arg = qFromLittleEndian<type>(qFromUnaligned<type>(reinterpret_cast<const type *>(code) - nargs + offset)); |
406 | #define MOTH_ADJUST_CODE(type, nargs) \ |
407 | code += static_cast<quintptr>(nargs*sizeof(type) + 1) |
408 | |
409 | #define MOTH_DECODE_INSTRUCTION(name, nargs, ...) \ |
410 | MOTH_DEFINE_ARGS(nargs, __VA_ARGS__) \ |
411 | op_int_##name: \ |
412 | MOTH_ADJUST_CODE(int, nargs); \ |
413 | MOTH_DECODE_ARGS(name, int, nargs, __VA_ARGS__) \ |
414 | goto op_main_##name; \ |
415 | op_byte_##name: \ |
416 | MOTH_ADJUST_CODE(qint8, nargs); \ |
417 | MOTH_DECODE_ARGS(name, qint8, nargs, __VA_ARGS__) \ |
418 | op_main_##name: \ |
419 | ; \ |
420 | |
421 | #define MOTH_DECODE_WITH_BASE_INSTRUCTION(name, nargs, ...) \ |
422 | MOTH_DEFINE_ARGS(nargs, __VA_ARGS__) \ |
423 | const char *base_ptr; \ |
424 | op_int_##name: \ |
425 | base_ptr = code; \ |
426 | MOTH_ADJUST_CODE(int, nargs); \ |
427 | MOTH_DECODE_ARGS(name, int, nargs, __VA_ARGS__) \ |
428 | goto op_main_##name; \ |
429 | op_byte_##name: \ |
430 | base_ptr = code; \ |
431 | MOTH_ADJUST_CODE(qint8, nargs); \ |
432 | MOTH_DECODE_ARGS(name, qint8, nargs, __VA_ARGS__) \ |
433 | op_main_##name: \ |
434 | ; \ |
435 | |
436 | #define MOTH_DECODE_ARGS(name, type, nargs, ...) \ |
437 | MOTH_EXPAND_FOR_MSVC(MOTH_DECODE_ARGS##nargs(name, type, nargs, __VA_ARGS__)) |
438 | |
439 | #define MOTH_DECODE_ARGS0(name, type, nargs, dummy) |
440 | #define MOTH_DECODE_ARGS1(name, type, nargs, arg) \ |
441 | MOTH_DECODE_ARG(arg, type, nargs, 0); |
442 | #define MOTH_DECODE_ARGS2(name, type, nargs, arg1, arg2) \ |
443 | MOTH_DECODE_ARGS1(name, type, nargs, arg1); \ |
444 | MOTH_DECODE_ARG(arg2, type, nargs, 1); |
445 | #define MOTH_DECODE_ARGS3(name, type, nargs, arg1, arg2, arg3) \ |
446 | MOTH_DECODE_ARGS2(name, type, nargs, arg1, arg2); \ |
447 | MOTH_DECODE_ARG(arg3, type, nargs, 2); |
448 | #define MOTH_DECODE_ARGS4(name, type, nargs, arg1, arg2, arg3, arg4) \ |
449 | MOTH_DECODE_ARGS3(name, type, nargs, arg1, arg2, arg3); \ |
450 | MOTH_DECODE_ARG(arg4, type, nargs, 3); |
451 | #define MOTH_DECODE_ARGS5(name, type, nargs, arg1, arg2, arg3, arg4, arg5) \ |
452 | MOTH_DECODE_ARGS4(name, type, nargs, arg1, arg2, arg3, arg4); \ |
453 | MOTH_DECODE_ARG(arg5, type, nargs, 4); |
454 | |
455 | #ifdef MOTH_COMPUTED_GOTO |
456 | /* collect jump labels */ |
457 | #define COLLECT_LABELS(instr) \ |
458 | INSTR_##instr(GET_LABEL) \ |
459 | INSTR_##instr(GET_LABEL_WIDE) |
460 | #define GET_LABEL_INSTRUCTION(name, ...) \ |
461 | &&op_byte_##name, |
462 | #define GET_LABEL_WIDE_INSTRUCTION(name, ...) \ |
463 | &&op_int_##name, |
464 | |
465 | #define MOTH_JUMP_TABLE \ |
466 | static const void *jumpTable[] = { \ |
467 | FOR_EACH_MOTH_INSTR_ALL(COLLECT_LABELS) \ |
468 | }; |
469 | |
470 | #define MOTH_DISPATCH_SINGLE() \ |
471 | goto *jumpTable[*reinterpret_cast<const uchar *>(code)]; |
472 | |
473 | #define MOTH_DISPATCH() \ |
474 | MOTH_DISPATCH_SINGLE() \ |
475 | op_byte_Nop: \ |
476 | ++code; \ |
477 | MOTH_DISPATCH_SINGLE() \ |
478 | op_int_Nop: /* wide prefix */ \ |
479 | ++code; \ |
480 | goto *jumpTable[0x100 | *reinterpret_cast<const uchar *>(code)]; |
481 | #else |
482 | #define MOTH_JUMP_TABLE |
483 | |
484 | #define MOTH_INSTR_CASE_AND_JUMP(instr) \ |
485 | INSTR_##instr(GET_CASE_AND_JUMP) \ |
486 | INSTR_##instr(GET_CASE_AND_JUMP_WIDE) |
487 | #define GET_CASE_AND_JUMP_INSTRUCTION(name, ...) \ |
488 | case Instr::Type::name: goto op_byte_##name; |
489 | #define GET_CASE_AND_JUMP_WIDE_INSTRUCTION(name, ...) \ |
490 | case Instr::Type::name##_Wide: goto op_int_##name; |
491 | |
492 | #define MOTH_DISPATCH() \ |
493 | Instr::Type type = Instr::Type(static_cast<uchar>(*code)); \ |
494 | dispatch: \ |
495 | switch (type) { \ |
496 | case Instr::Type::Nop: \ |
497 | ++code; \ |
498 | type = Instr::Type(static_cast<uchar>(*code)); \ |
499 | goto dispatch; \ |
500 | case Instr::Type::Nop_Wide: /* wide prefix */ \ |
501 | ++code; \ |
502 | type = Instr::Type(0x100 | static_cast<uchar>(*code)); \ |
503 | goto dispatch; \ |
504 | FOR_EACH_MOTH_INSTR(MOTH_INSTR_CASE_AND_JUMP) \ |
505 | } |
506 | #endif |
507 | |
508 | namespace QV4 { |
509 | |
510 | namespace CompiledData { |
511 | struct CodeOffsetToLine; |
512 | } |
513 | |
514 | namespace Moth { |
515 | |
516 | class StackSlot { |
517 | int index; |
518 | |
519 | public: |
520 | static StackSlot createRegister(int index) { |
521 | Q_ASSERT(index >= 0); |
522 | StackSlot t; |
523 | t.index = index; |
524 | return t; |
525 | } |
526 | |
527 | int stackSlot() const { return index; } |
528 | operator int() const { return index; } |
529 | }; |
530 | |
531 | inline bool operator==(const StackSlot &l, const StackSlot &r) { return l.stackSlot() == r.stackSlot(); } |
532 | inline bool operator!=(const StackSlot &l, const StackSlot &r) { return l.stackSlot() != r.stackSlot(); } |
533 | |
534 | // When making changes to the instructions, make sure to bump QV4_DATA_STRUCTURE_VERSION in qv4compileddata_p.h |
535 | |
536 | void dumpBytecode(const char *bytecode, int len, int nLocals, int nFormals, int startLine = 1, |
537 | const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping = QVector<CompiledData::CodeOffsetToLine>()); |
538 | inline void dumpBytecode(const QByteArray &bytecode, int nLocals, int nFormals, int startLine = 1, |
539 | const QVector<CompiledData::CodeOffsetToLine> &lineNumberMapping = QVector<CompiledData::CodeOffsetToLine>()) { |
540 | dumpBytecode(bytecode: bytecode.constData(), len: bytecode.length(), nLocals, nFormals, startLine, lineNumberMapping); |
541 | } |
542 | |
543 | union Instr |
544 | { |
545 | enum class Type { |
546 | FOR_EACH_MOTH_INSTR_ALL(MOTH_INSTR_ENUM) |
547 | }; |
548 | |
549 | static Type wideInstructionType(Type t) { return Type(int(t) | 1); } |
550 | static Type narrowInstructionType(Type t) { return Type(int(t) & ~1); } |
551 | static bool isWide(Type t) { return int(t) & 1; } |
552 | static bool isNarrow(Type t) { return !(int(t) & 1); } |
553 | static int encodedLength(Type t) { return int(t) >= 256 ? 2 : 1; } |
554 | |
555 | static Type unpack(const uchar *c) { if (c[0] == 0x1) return Type(0x100 + c[1]); return Type(c[0]); } |
556 | static uchar *pack(uchar *c, Type t) { |
557 | if (uint(t) >= 256) { |
558 | c[0] = 0x1; |
559 | c[1] = uint(t) &0xff; |
560 | return c + 2; |
561 | } |
562 | c[0] = uchar(uint(t)); |
563 | return c + 1; |
564 | } |
565 | |
566 | FOR_EACH_MOTH_INSTR_ALL(MOTH_EMIT_STRUCTS) |
567 | |
568 | FOR_EACH_MOTH_INSTR_ALL(MOTH_EMIT_INSTR_MEMBERS) |
569 | |
570 | int argumentsAsInts[4]; |
571 | }; |
572 | |
573 | struct InstrInfo |
574 | { |
575 | static const int argumentCount[]; |
576 | static int size(Instr::Type type); |
577 | }; |
578 | |
579 | template<int N> |
580 | struct InstrMeta { |
581 | }; |
582 | |
583 | QT_WARNING_PUSH |
584 | QT_WARNING_DISABLE_GCC("-Wuninitialized" ) |
585 | QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized" ) |
586 | #define MOTH_INSTR_META_TEMPLATE(I) \ |
587 | template<> struct InstrMeta<int(Instr::Type::I)> { \ |
588 | enum { Size = MOTH_INSTR_SIZE(I) }; \ |
589 | typedef Instr::instr_##I DataType; \ |
590 | static const DataType &data(const Instr &instr) { return instr.I; } \ |
591 | static void setData(Instr &instr, const DataType &v) \ |
592 | { memcpy(reinterpret_cast<char *>(&instr.I), \ |
593 | reinterpret_cast<const char *>(&v), \ |
594 | Size); } \ |
595 | }; |
596 | FOR_EACH_MOTH_INSTR_ALL(MOTH_INSTR_META_TEMPLATE); |
597 | #undef MOTH_INSTR_META_TEMPLATE |
598 | QT_WARNING_POP |
599 | |
600 | template<int InstrType> |
601 | class InstrData : public InstrMeta<InstrType>::DataType |
602 | { |
603 | }; |
604 | |
605 | struct Instruction { |
606 | #define MOTH_INSTR_DATA_TYPEDEF(I) typedef InstrData<int(Instr::Type::I)> I; |
607 | FOR_EACH_MOTH_INSTR_ALL(MOTH_INSTR_DATA_TYPEDEF) |
608 | #undef MOTH_INSTR_DATA_TYPEDEF |
609 | private: |
610 | Instruction(); |
611 | }; |
612 | |
613 | } // namespace Moth |
614 | } // namespace QV4 |
615 | |
616 | QT_END_NAMESPACE |
617 | |
618 | #endif // QV4INSTR_MOTH_P_H |
619 | |