| 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 | |
| 22 | QT_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 | |
| 470 | namespace QV4 { |
| 471 | |
| 472 | namespace CompiledData { |
| 473 | struct CodeOffsetToLineAndStatement; |
| 474 | } |
| 475 | |
| 476 | namespace Moth { |
| 477 | |
| 478 | class StackSlot { |
| 479 | int index; |
| 480 | |
| 481 | public: |
| 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 | |
| 493 | inline bool operator==(const StackSlot &l, const StackSlot &r) { return l.stackSlot() == r.stackSlot(); } |
| 494 | inline 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 | |
| 498 | Q_QML_EXPORT |
| 499 | QString 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>()); |
| 503 | QString dumpBytecode( |
| 504 | const char *bytecode, int len, int nLocals, int nFormals, int startLine = 1, |
| 505 | const QVector<CompiledData::CodeOffsetToLineAndStatement> &lineAndStatementNumberMapping = |
| 506 | QVector<CompiledData::CodeOffsetToLineAndStatement>()); |
| 507 | inline 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 | |
| 516 | union 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 | |
| 618 | struct InstrInfo |
| 619 | { |
| 620 | static const int argumentCount[]; |
| 621 | static int size(Instr::Type type); |
| 622 | }; |
| 623 | |
| 624 | template<int N> |
| 625 | struct InstrMeta { |
| 626 | }; |
| 627 | |
| 628 | QT_WARNING_PUSH |
| 629 | QT_WARNING_DISABLE_GCC("-Wuninitialized" ) |
| 630 | QT_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 | }; |
| 641 | FOR_EACH_MOTH_INSTR_ALL(MOTH_INSTR_META_TEMPLATE); |
| 642 | #undef MOTH_INSTR_META_TEMPLATE |
| 643 | QT_WARNING_POP |
| 644 | |
| 645 | template<int InstrType> |
| 646 | class InstrData : public InstrMeta<InstrType>::DataType |
| 647 | { |
| 648 | }; |
| 649 | |
| 650 | struct Instruction { |
| 651 | #define MOTH_INSTR_DATA_TYPEDEF(I) typedef InstrData<int(Instr::Type::I)> I; |
| 652 | FOR_EACH_MOTH_INSTR_ALL(MOTH_INSTR_DATA_TYPEDEF) |
| 653 | #undef MOTH_INSTR_DATA_TYPEDEF |
| 654 | private: |
| 655 | Instruction(); |
| 656 | }; |
| 657 | |
| 658 | } // namespace Moth |
| 659 | } // namespace QV4 |
| 660 | |
| 661 | QT_END_NAMESPACE |
| 662 | |
| 663 | #endif // QV4INSTR_MOTH_P_H |
| 664 | |