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

source code of qtdeclarative/src/qml/compiler/qv4instr_moth_p.h