// If main trace starts with guards, have them generate a patchable jump // to the anchor trace static void hoistGuardJumps(Trace* trace, IRFactory* irFactory) { Block* guardLabel = nullptr; // Check the beginning of the trace for guards for (Block* block : trace->getBlocks()) { for (IRInstruction& instr : *block) { IRInstruction* inst = &instr; Opcode opc = inst->getOpcode(); if (inst->getTaken() && (opc == LdLoc || opc == LdStack || opc == GuardLoc || opc == GuardStk)) { Block* exitLabel = inst->getTaken(); // Find the GuardFailure's label and confirm this branches there if (!guardLabel && exitLabel->getTrace() != trace) { auto instIter = exitLabel->skipLabel(); // Confirm this is a GuardExit for (auto it = instIter, end = exitLabel->end(); it != end; ++it) { Opcode op = it->getOpcode(); if (op == Marker) { continue; } if (op == ExitGuardFailure) { guardLabel = exitLabel; } // Do not optimize if other instructions are on exit trace break; } } if (exitLabel == guardLabel) { inst->setTCA(kIRDirectGuardActive); continue; } return; // terminate search } if (opc == Marker || opc == DefLabel || opc == DefSP || opc == DefFP || opc == LdStack) { continue; } return; // terminate search } } }
/* * Looks for whether the value in tmp was defined by a load, and if * so, changes that load into a load that guards on the given * type. Returns true if it succeeds. */ static bool hoistGuardToLoad(SSATmp* tmp, Type type) { IRInstruction* inst = tmp->getInstruction(); switch (inst->getOpcode()) { case Mov: case IncRef: { // if inst is an incref or move, then chase down its src if (hoistGuardToLoad(inst->getSrc(0), type)) { // guard was successfully attached to a load instruction // refine the type of this mov/incref // Note: We can also further simplify incref's here if type is not // ref-counted tmp->setType(type); inst->setTypeParam(type); return true; } break; } case LdLoc: case LdStack: case LdMem: case LdProp: case LdRef: case LdClsCns: { if (!inst->getTaken()) { // Not a control flow instruction, so can't give it check semantics break; } Type instType = tmp->getType(); if (instType == Type::Gen || (instType == Type::Cell && !type.isBoxed())) { tmp->setType(type); inst->setTypeParam(type); return true; } break; } default: break; } return false; }