IterTable iterTableFromStream(PC& pc) { IterTable ret; auto const length = decode_iva(pc); for (int32_t i = 0; i < length; ++i) { auto const kind = static_cast<IterKind>(decode_iva(pc)); auto const id = decode_iva(pc); auto const local = (kind == KindOfLIter) ? static_cast<int32_t>(decode_iva(pc)) : kInvalidId; ret.push_back(IterTableEnt{kind, static_cast<int32_t>(id), local}); } return ret; }
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 = decode_iva(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; }
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; }
// Await / Yield opcodes mark a suspend points of async functions and // generators. Execution will resume at this function later after the // opcode. void CmdNext::setupStepSuspend(ActRec* fp, PC pc) { // Yield is followed by the label where execution will continue. auto const op = decode_op(pc); assertx(op == OpAwait || op == OpYield || op == OpYieldK); if (op == OpAwait) { decode_iva(pc); } Offset nextInst = fp->func()->unit()->offsetOf(pc); assertx(nextInst != InvalidAbsoluteOffset); m_stepResumableId = fp; TRACE(2, "CmdNext: patch for resumable step at '%s' offset %d\n", fp->m_func->fullName()->data(), nextInst); m_stepResumable = StepDestination(fp->m_func->unit(), nextInst); }
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(); }
/** * Return the number of successor-edges including fall-through paths but not * implicit exception paths. */ int numSuccs(const PC origPC) { auto pc = origPC; auto const op = decode_op(pc); if ((instrFlags(op) & TF) != 0) { if (isSwitch(op)) { if (op == Op::Switch) { decode_raw<SwitchKind>(pc); // skip bounded flag decode_raw<int64_t>(pc); // skip base } return decode_iva(pc); // vector length } if (isUnconditionalJmp(op) || op == OpIterBreak) return 1; return 0; } if (!instrIsControlFlow(op)) return 1; if (instrJumpOffset(origPC)) return 2; return 1; }
MemberKey decode_member_key(PC& pc, Either<const Unit*, const UnitEmitter*> u) { auto const mcode = static_cast<MemberCode>(decode_byte(pc)); switch (mcode) { case MEC: case MEL: case MPC: case MPL: return MemberKey{mcode, decode_iva(pc)}; case MEI: return MemberKey{mcode, decode_raw<int64_t>(pc)}; case MET: case MPT: case MQT: { auto const id = decode_raw<Id>(pc); auto const str = u.match( [id](const Unit* u) { return u->lookupLitstrId(id); }, [id](const UnitEmitter* ue) { return ue->lookupLitstr(id); } ); return MemberKey{mcode, str}; } case MW: return MemberKey{}; } not_reached(); }
int immSize(PC origPC, int idx) { auto pc = origPC; auto const op = decode_op(pc); assertx(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 || immType(op, idx) == CAR || immType(op, idx) == CAW) { 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 (immType(op, idx) == LAR) { if (idx >= 1) pc += immSize(origPC, 0); if (idx >= 2) pc += immSize(origPC, 1); if (idx >= 3) pc += immSize(origPC, 2); auto start = pc; decode_iva(pc); // first decode_iva(pc); // restCount return pc - start; } 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 if (itype == I32LA) { vecElemSz = sizeof(uint32_t); } else { assertx(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; }