void emitIterBreak(IRGS& env, Offset relOffset, const ImmVector& iv) { for (int iterIndex = 0; iterIndex < iv.size(); iterIndex += 2) { IterKind iterKind = (IterKind)iv.vec32()[iterIndex]; Id iterId = iv.vec32()[iterIndex + 1]; switch (iterKind) { case KindOfIter: gen(env, IterFree, IterId(iterId), fp(env)); break; case KindOfMIter: gen(env, MIterFree, IterId(iterId), fp(env)); break; case KindOfCIter: gen(env, CIterFree, IterId(iterId), fp(env)); break; } } jmpImpl(env, bcOff(env) + relOffset); }
void emitIterBreak(IRGS& env, const ImmVector& iv, Offset relOffset) { always_assert(env.currentNormalizedInstruction->endsRegion); for (int iterIndex = 0; iterIndex < iv.size(); iterIndex += 2) { IterKind iterKind = (IterKind)iv.vec32()[iterIndex]; Id iterId = iv.vec32()[iterIndex + 1]; switch (iterKind) { case KindOfIter: gen(env, IterFree, IterId(iterId), fp(env)); break; case KindOfMIter: gen(env, MIterFree, IterId(iterId), fp(env)); break; case KindOfCIter: gen(env, CIterFree, IterId(iterId), fp(env)); break; } } // Would need to change this if we support not ending regions on this: gen(env, Jmp, makeExit(env, bcOff(env) + relOffset)); }
void emitNewStructArray(HTS& env, const ImmVector& immVec) { auto const numArgs = immVec.size(); auto const ids = immVec.vec32(); // The NewPackedArray opcode's helper needs array values passed to it // via the stack. We use spillStack() to flush the eval stack and // obtain a pointer to the topmost item; if over-flushing becomes // a problem then we should refactor the NewPackedArray opcode to // take its values directly as SSA operands. spillStack(env); NewStructData extra; extra.offset = offsetFromSP(env, 0); extra.numKeys = numArgs; extra.keys = new (env.unit.arena()) StringData*[numArgs]; for (auto i = size_t{0}; i < numArgs; ++i) { extra.keys[i] = curUnit(env)->lookupLitstrId(ids[i]); } discard(env, numArgs); push(env, gen(env, NewStructArray, extra, sp(env))); }
void emitSwitch(HTS& env, const ImmVector& iv, int64_t base, int32_t bounded) { int nTargets = bounded ? iv.size() - 2 : iv.size(); SSATmp* const switchVal = popC(env); Type type = switchVal->type(); assert(IMPLIES(!(type <= Type::Int), bounded)); assert(IMPLIES(bounded, iv.size() > 2)); SSATmp* index; SSATmp* ssabase = cns(env, base); SSATmp* ssatargets = cns(env, nTargets); Offset defaultOff = bcOff(env) + iv.vec32()[iv.size() - 1]; Offset zeroOff = 0; if (base <= 0 && (base + nTargets) > 0) { zeroOff = bcOff(env) + iv.vec32()[0 - base]; } else { zeroOff = defaultOff; } if (type <= Type::Null) { gen(env, Jmp, makeExit(env, zeroOff)); return; } if (type <= Type::Bool) { Offset nonZeroOff = bcOff(env) + iv.vec32()[iv.size() - 2]; gen(env, JmpNZero, makeExit(env, nonZeroOff), switchVal); gen(env, Jmp, makeExit(env, zeroOff)); return; } if (type <= Type::Int) { // No special treatment needed index = switchVal; } else if (type <= Type::Dbl) { // switch(Double|String|Obj)Helper do bounds-checking for us, so // we need to make sure the default case is in the jump table, // and don't emit our own bounds-checking code bounded = false; index = gen(env, LdSwitchDblIndex, switchVal, ssabase, ssatargets); } else if (type <= Type::Str) { bounded = false; index = gen(env, LdSwitchStrIndex, switchVal, ssabase, ssatargets); } else if (type <= Type::Obj) { // switchObjHelper can throw exceptions and reenter the VM so we use the // catch block here. bounded = false; index = gen(env, LdSwitchObjIndex, switchVal, ssabase, ssatargets); } else if (type <= Type::Arr) { gen(env, DecRef, switchVal); gen(env, Jmp, makeExit(env, defaultOff)); return; } else { PUNT(Switch-UnknownType); } std::vector<Offset> targets(iv.size()); for (int i = 0; i < iv.size(); i++) { targets[i] = bcOff(env) + iv.vec32()[i]; } JmpSwitchData data; data.base = base; data.bounded = bounded; data.cases = iv.size(); data.defaultOff = defaultOff; data.targets = &targets[0]; spillStack(env); gen(env, AdjustSP, StackOffset { offsetFromSP(env, 0) }, sp(env)); gen(env, JmpSwitchDest, data, index, sp(env)); }