ArgUnion getImm(const PC origPC, int idx, const Unit* unit) { auto pc = origPC; auto const op = decode_op(pc); assertx(idx >= 0 && idx < numImmediates(op)); ArgUnion retval; retval.u_NA = 0; int cursor = 0; for (cursor = 0; cursor < idx; cursor++) { // Advance over this immediate. pc += immSize(immType(op, cursor), pc); } always_assert(cursor == idx); auto const type = immType(op, idx); if (type == IVA || type == LA || type == IA || type == CAR || type == CAW) { retval.u_IVA = decode_iva(pc); } else if (type == KA) { assertx(unit != nullptr); retval.u_KA = decode_member_key(pc, unit); } else if (type == LAR) { retval.u_LAR = decodeLocalRange(pc); } else if (type == FCA) { retval.u_FCA = decodeFCallArgs(pc); } else if (type == RATA) { assertx(unit != nullptr); retval.u_RATA = decodeRAT(unit, pc); } else if (!argTypeIsVector(type)) { memcpy(&retval.bytes, pc, immSize(type, pc)); } always_assert(numImmediates(op) > idx); return retval; }
ArgUnion getImm(PC const origPC, int idx, const Unit* unit) { auto pc = origPC; auto const UNUSED op = decode_op(pc); assert(idx >= 0 && idx < numImmediates(op)); ArgUnion retval; retval.u_NA = 0; int cursor = 0; for (cursor = 0; cursor < idx; cursor++) { // Advance over this immediate. pc += immSize(origPC, cursor); } always_assert(cursor == idx); auto const type = immType(op, idx); if (type == IVA || type == LA || type == IA) { retval.u_IVA = decodeVariableSizeImm(&pc); } else if (type == KA) { assert(unit != nullptr); retval.u_KA = decode_member_key(pc, unit); } else if (!immIsVector(op, cursor)) { always_assert(type != RATA); // Decode RATAs with a different function. memcpy(&retval.bytes, pc, immSize(origPC, idx)); } always_assert(numImmediates(op) > idx); return retval; }
bool hasImmVector(Opcode opcode) { const int num = numImmediates(opcode); for (int i = 0; i < num; ++i) { if (immIsVector(opcode, i)) return true; } return false; }
ArgType immType(const Op opcode, int idx) { assertx(isValidOpcode(opcode)); assertx(idx >= 0 && idx < numImmediates(opcode)); always_assert(idx < kMaxHhbcImms); // No opcodes have more than 5 immediates static const int8_t argTypes[][kMaxHhbcImms] = { #define NA {-1, -1, -1, -1, -1}, #define ONE(a) { a, -1, -1, -1, -1}, #define TWO(a, b) { a, b, -1, -1, -1}, #define THREE(a, b, c) { a, b, c, -1, -1}, #define FOUR(a, b, c, d) { a, b, c, d, -1}, #define FIVE(a, b, c, d, e) { a, b, c, d, e}, #define OA(x) OA #define O(name, imm, unusedPop, unusedPush, unusedFlags) imm OPCODES #undef O #undef OA #undef NA #undef ONE #undef TWO #undef THREE #undef FOUR #undef FIVE }; auto opInt = size_t(opcode); return (ArgType)argTypes[opInt][idx]; }
bool hasIterTable(Op opcode) { auto const num = numImmediates(opcode); for (int i = 0; i < num; ++i) { if (immType(opcode, i) == ILA) return true; } return false; }
bool hasMVector(Op op) { auto const num = numImmediates(op); for (int i = 0; i < num; ++i) { if (immType(op, i) == MA) return true; } return false; }
int instrLen(const Opcode* opcode) { int len = 1; int nImm = numImmediates(*opcode); for (int i = 0; i < nImm; i++) { len += immSize(opcode, i); } return len; }
int instrLen(PC const origPC) { auto pc = origPC; auto op = decode_op(pc); int nImm = numImmediates(op); for (int i = 0; i < nImm; i++) { pc += immSize(origPC, i); } return pc - origPC; }
IterTable getIterTable(PC opcode) { auto const op = peek_op(opcode); auto const numImm = numImmediates(op); for (int k = 0; k < numImm; ++k) { auto const type = immType(op, k); if (type != ILA) continue; auto ptr = reinterpret_cast<PC>(getImmPtr(opcode, k)); return iterTableFromStream(ptr); } not_reached(); }
ArgUnion getImm(const Opcode* opcode, int idx) { const Opcode* p = opcode + 1; assert(idx >= 0 && idx < numImmediates(*opcode)); ArgUnion retval; retval.u_NA = 0; int cursor = 0; for (cursor = 0; cursor < idx; cursor++) { // Advance over this immediate. p += immSize(opcode, cursor); } always_assert(cursor == idx); ArgType type = immType(*opcode, idx); if (type == IVA || type == HA || type == IA) { retval.u_IVA = decodeVariableSizeImm(&p); } else if (!immIsVector(*opcode, cursor)) { memcpy(&retval.bytes, p, immSize(opcode, idx)); } always_assert(numImmediates(*opcode) > idx); return retval; }
ArgUnion getImm(const Op* opcode, int idx) { const Op* p = opcode + 1; assert(idx >= 0 && idx < numImmediates(*opcode)); ArgUnion retval; retval.u_NA = 0; int cursor = 0; for (cursor = 0; cursor < idx; cursor++) { // Advance over this immediate. p += immSize(opcode, cursor); } always_assert(cursor == idx); auto const type = immType(*opcode, idx); if (type == IVA || type == LA || type == IA) { retval.u_IVA = decodeVariableSizeImm((const uint8_t**)&p); } else if (!immIsVector(*opcode, cursor)) { always_assert(type != RATA); // Decode RATAs with a different function. memcpy(&retval.bytes, p, immSize(opcode, idx)); } always_assert(numImmediates(*opcode) > idx); return retval; }
ImmVector getImmVector(PC opcode) { auto const op = peek_op(opcode); int numImm = numImmediates(op); for (int k = 0; k < numImm; ++k) { ArgType t = immType(op, k); if (t == BLA || t == SLA || t == I32LA || t == BLLA || t == VSA) { PC vp = getImmPtr(opcode, k)->bytes; auto const size = decode_iva(vp); return ImmVector(vp, size, t == VSA ? size : 0); } } not_reached(); }
int immSize(const Op* opcode, int idx) { assert(idx >= 0 && idx < numImmediates(*opcode)); always_assert(idx < 4); // No opcodes have more than four immediates static const int8_t argTypeToSizes[] = { #define ARGTYPE(nm, type) sizeof(type), #define ARGTYPEVEC(nm, type) 0, ARGTYPES #undef ARGTYPE #undef ARGTYPEVEC }; if (immType(*opcode, idx) == IVA || immType(*opcode, idx) == LA || immType(*opcode, idx) == IA) { intptr_t offset = 1; if (idx >= 1) offset += immSize(opcode, 0); if (idx >= 2) offset += immSize(opcode, 1); if (idx >= 3) offset += immSize(opcode, 2); // variable size unsigned char imm = *(unsigned char*)(opcode + offset); // Low order bit set => 4-byte. return (imm & 0x1 ? sizeof(int32_t) : sizeof(unsigned char)); } else if (immIsVector(*opcode, idx)) { intptr_t offset = 1; if (idx >= 1) offset += immSize(opcode, 0); if (idx >= 2) offset += immSize(opcode, 1); if (idx >= 3) offset += immSize(opcode, 2); int prefixes, vecElemSz; auto itype = immType(*opcode, idx); if (itype == MA) { prefixes = 2; vecElemSz = sizeof(uint8_t); } else if (itype == BLA) { prefixes = 1; vecElemSz = sizeof(Offset); } else if (itype == ILA) { prefixes = 1; vecElemSz = 2 * sizeof(uint32_t); } else { assert(itype == SLA); prefixes = 1; vecElemSz = sizeof(StrVecItem); } return prefixes * sizeof(int32_t) + vecElemSz * *(int32_t*)((int8_t*)opcode + offset); } else { ArgType type = immType(*opcode, idx); return (type >= 0) ? argTypeToSizes[type] : 0; } }
ImmVector getImmVector(const Opcode* opcode) { int numImm = numImmediates(*opcode); for (int k = 0; k < numImm; ++k) { ArgType t = immType(*opcode, k); if (t == MA) { void* vp = getImmPtr(opcode, k); return ImmVector::createFromStream( static_cast<const uint8_t*>(vp)); } else if (t == BLA || t == SLA) { void* vp = getImmPtr(opcode, k); return ImmVector::createFromStream( static_cast<const int32_t*>(vp)); } } NOT_REACHED(); }
ImmVector getImmVector(PC opcode) { auto const op = peek_op(opcode); int numImm = numImmediates(op); for (int k = 0; k < numImm; ++k) { ArgType t = immType(op, k); if (t == BLA || t == SLA || t == ILA || t == I32LA) { void* vp = getImmPtr(opcode, k); return ImmVector::createFromStream( static_cast<const int32_t*>(vp) ); } if (t == VSA) { const int32_t* vp = (int32_t*)getImmPtr(opcode, k); return ImmVector(reinterpret_cast<const uint8_t*>(vp + 1), vp[0], vp[0]); } } not_reached(); }
int immSize(PC origPC, int idx) { auto pc = origPC; auto const op = decode_op(pc); assert(idx >= 0 && idx < numImmediates(op)); always_assert(idx < 4); // No origPCs have more than four immediates static const int8_t argTypeToSizes[] = { #define ARGTYPE(nm, type) sizeof(type), #define ARGTYPEVEC(nm, type) 0, ARGTYPES #undef ARGTYPE #undef ARGTYPEVEC }; if (immType(op, idx) == IVA || immType(op, idx) == LA || immType(op, idx) == IA) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); auto const imm = decode_raw<uint8_t>(pc); // Low order bit set => 4-byte. return (imm & 0x1 ? sizeof(int32_t) : sizeof(unsigned char)); } if (immType(op, idx) == RATA) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); return encodedRATSize(pc); } if (immIsVector(op, idx)) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); int prefixes, vecElemSz; auto itype = immType(op, idx); if (itype == MA) { prefixes = 2; vecElemSz = sizeof(uint8_t); } else if (itype == BLA) { prefixes = 1; vecElemSz = sizeof(Offset); } else if (itype == ILA) { prefixes = 1; vecElemSz = 2 * sizeof(uint32_t); } else if (itype == VSA) { prefixes = 1; vecElemSz = sizeof(Id); } else { assert(itype == SLA); prefixes = 1; vecElemSz = sizeof(StrVecItem); } return prefixes * sizeof(int32_t) + vecElemSz * decode_raw<int32_t>(pc); } ArgType type = immType(op, idx); return (type >= 0) ? argTypeToSizes[type] : 0; }
ArgType immType(const Op opcode, int idx) { assert(isValidOpcode(opcode)); assert(idx >= 0 && idx < numImmediates(opcode)); always_assert(idx < 4); // No opcodes have more than four immediates static const int8_t arg0Types[] = { #define NA -1, #define ONE(a) a, #define TWO(a, b) a, #define THREE(a, b, c) a, #define FOUR(a, b, c, d) a, #define OA(x) OA #define O(name, imm, unusedPop, unusedPush, unusedFlags) imm OPCODES // re-using definition of O below. #undef OA #undef NA #undef ONE #undef TWO #undef THREE #undef FOUR }; static const int8_t arg1Types[] = { #define NA -1, #define ONE(a) -1, #define TWO(a, b) b, #define THREE(a, b, c) b, #define FOUR(a, b, c, d) b, #define OA(x) OA OPCODES // re-using definition of O below. #undef OA #undef NA #undef ONE #undef TWO #undef THREE #undef FOUR }; static const int8_t arg2Types[] = { #define NA -1, #define ONE(a) -1, #define TWO(a, b) -1, #define THREE(a, b, c) c, #define FOUR(a, b, c, d) c, #define OA(x) OA OPCODES #undef OA #undef NA #undef ONE #undef TWO #undef THREE #undef FOUR }; static const int8_t arg3Types[] = { #define NA -1, #define ONE(a) -1, #define TWO(a, b) -1, #define THREE(a, b, c) -1, #define FOUR(a, b, c, d) d, #define OA(x) OA OPCODES #undef OA #undef O #undef NA #undef ONE #undef TWO #undef THREE #undef FOUR }; auto opInt = uint8_t(opcode); switch (idx) { case 0: return (ArgType)arg0Types[opInt]; case 1: return (ArgType)arg1Types[opInt]; case 2: return (ArgType)arg2Types[opInt]; case 3: return (ArgType)arg3Types[opInt]; default: assert(false); return (ArgType)-1; } }
int immSize(PC origPC, int idx) { auto pc = origPC; auto const op = decode_op(pc); assert(idx >= 0 && idx < numImmediates(op)); always_assert(idx < 4); // No origPCs have more than four immediates static const int8_t argTypeToSizes[] = { #define ARGTYPE(nm, type) sizeof(type), #define ARGTYPEVEC(nm, type) 0, ARGTYPES #undef ARGTYPE #undef ARGTYPEVEC }; if (immType(op, idx) == IVA || immType(op, idx) == LA || immType(op, idx) == IA) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); return encoded_iva_size(decode_raw<uint8_t>(pc)); } if (immType(op, idx) == KA) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); switch (decode_raw<MemberCode>(pc)) { case MW: return 1; case MEL: case MPL: case MEC: case MPC: return 1 + encoded_iva_size(decode_raw<uint8_t>(pc)); case MEI: return 1 + sizeof(int64_t); case MET: case MPT: case MQT: return 1 + sizeof(Id); } not_reached(); } if (immType(op, idx) == RATA) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); return encodedRATSize(pc); } if (immIsVector(op, idx)) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); int vecElemSz; auto itype = immType(op, idx); if (itype == BLA) { vecElemSz = sizeof(Offset); } else if (itype == ILA) { vecElemSz = 2 * sizeof(uint32_t); } else if (itype == VSA) { vecElemSz = sizeof(Id); } else { assert(itype == SLA); vecElemSz = sizeof(StrVecItem); } return sizeof(int32_t) + vecElemSz * decode_raw<int32_t>(pc); } ArgType type = immType(op, idx); return (type >= 0) ? argTypeToSizes[type] : 0; }