Exemple #1
0
void local_effects(const FrameStateMgr& frameState,
                   const IRInstruction* inst,
                   LocalStateHook& hook) {
  auto killIterLocals = [&](const std::initializer_list<uint32_t>& ids) {
    for (auto id : ids) {
      hook.setLocalValue(id, nullptr);
    }
  };

  switch (inst->op()) {
    case CallBuiltin:
      if (inst->extra<CallBuiltin>()->destroyLocals) hook.clearLocals();
      break;

    case Call:
    case CallArray:
    case ContEnter:
      {
        auto const callDestroysLocals =
          (inst->is(CallArray) && inst->extra<CallArray>()->destroyLocals) ||
          (inst->is(Call) && inst->extra<Call>()->destroyLocals);
        hook.killLocalsForCall(callDestroysLocals);
      }
      break;

    case StRef:
      hook.updateLocalRefPredictions(inst->src(0), inst->src(1));
      break;

    case StLocNT:
    case StLoc:
      hook.setLocalValue(inst->extra<LocalId>()->locId, inst->src(1));
      break;

    case LdLoc:
      hook.setLocalValue(inst->extra<LdLoc>()->locId, inst->dst());
      break;

    case StLocPseudoMain:
      hook.predictLocalType(inst->extra<LocalId>()->locId,
                            inst->src(1)->type());
      break;

    case AssertLoc:
    case GuardLoc:
    case CheckLoc: {
      auto id = inst->extra<LocalId>()->locId;
      if (inst->marker().func()->isPseudoMain()) {
        hook.predictLocalType(id, inst->typeParam());
      } else {
        hook.refineLocalType(id,
                             inst->typeParam(),
                             TypeSource::makeGuard(inst));
      }
      break;
    }

    case HintLocInner:
      hook.setBoxedLocalPrediction(inst->extra<HintLocInner>()->locId,
                                   inst->typeParam());
      break;

    case CheckType:
    case AssertType:
      hook.refineLocalValues(inst->src(0), inst->dst());
      break;

    case IterInitK:
    case WIterInitK:
      // kill the locals to which this instruction stores iter's key and value
      killIterLocals({inst->extra<IterData>()->keyId,
                      inst->extra<IterData>()->valId});
      break;

    case IterInit:
    case WIterInit:
      // kill the local to which this instruction stores iter's value
      killIterLocals({inst->extra<IterData>()->valId});
      break;

    case IterNextK:
    case WIterNextK:
      // kill the locals to which this instruction stores iter's key and value
      killIterLocals({inst->extra<IterData>()->keyId,
                      inst->extra<IterData>()->valId});
      break;

    case IterNext:
    case WIterNext:
      // kill the local to which this instruction stores iter's value
      killIterLocals({inst->extra<IterData>()->valId});
      break;

    case InterpOne:
    case InterpOneCF: {
      auto const& id = *inst->extra<InterpOneData>();
      assert(!id.smashesAllLocals || id.nChangedLocals == 0);
      if (id.smashesAllLocals || inst->marker().func()->isPseudoMain()) {
        hook.clearLocals();
      } else {
        auto it = id.changedLocals;
        auto const end = it + id.nChangedLocals;
        for (; it != end; ++it) {
          auto& loc = *it;
          // If changing the inner type of a boxed local, also drop the
          // information about inner types for any other boxed locals.
          if (loc.type.isBoxed()) hook.dropLocalRefsInnerTypes();
          hook.setLocalType(loc.id, loc.type);
        }
      }
      break;
    }
    default:
      break;
  }

  if (MInstrEffects::supported(inst)) {
    MInstrEffects::get(inst, frameState, hook);
  }
}
Exemple #2
0
void FrameState::getLocalEffects(const IRInstruction* inst,
                                 LocalStateHook& hook) const {
  auto killIterLocals = [&](const std::initializer_list<uint32_t>& ids) {
    for (auto id : ids) {
      hook.setLocalValue(id, nullptr);
    }
  };

  auto killedCallLocals = false;
  if ((inst->is(CallArray) && inst->extra<CallArrayData>()->destroyLocals) ||
      (inst->is(Call, CallBuiltin) && inst->extra<CallData>()->destroyLocals)) {
    clearLocals(hook);
    killedCallLocals = true;
  }

  switch (inst->op()) {
    case Call:
    case CallArray:
    case ContEnter:
      killLocalsForCall(hook, killedCallLocals);
      break;

    case StRef: {
      SSATmp* newRef = inst->dst();
      SSATmp* prevRef = inst->src(0);
      // update other tracked locals that also contain prevRef
      updateLocalRefValues(hook, prevRef, newRef);
      break;
    }

    case StLocNT:
    case StLoc:
      hook.setLocalValue(inst->extra<LocalId>()->locId, inst->src(1));
      break;

    case LdLoc:
      hook.setLocalValue(inst->extra<LdLoc>()->locId, inst->dst());
      break;

    case AssertLoc:
    case GuardLoc:
    case CheckLoc:
      hook.refineLocalType(inst->extra<LocalId>()->locId, inst->typeParam(),
                           inst->dst());
      break;

    case CheckType:
    case AssertType: {
      SSATmp* newVal = inst->dst();
      SSATmp* oldVal = inst->src(0);
      refineLocalValues(hook, oldVal, newVal);
      break;
    }

    case IterInitK:
    case WIterInitK:
      // kill the locals to which this instruction stores iter's key and value
      killIterLocals({inst->extra<IterData>()->keyId,
                      inst->extra<IterData>()->valId});
      break;

    case IterInit:
    case WIterInit:
      // kill the local to which this instruction stores iter's value
      killIterLocals({inst->extra<IterData>()->valId});
      break;

    case IterNextK:
    case WIterNextK:
      // kill the locals to which this instruction stores iter's key and value
      killIterLocals({inst->extra<IterData>()->keyId,
                      inst->extra<IterData>()->valId});
      break;

    case IterNext:
    case WIterNext:
      // kill the local to which this instruction stores iter's value
      killIterLocals({inst->extra<IterData>()->valId});
      break;

    case InterpOne:
    case InterpOneCF: {
      auto const& id = *inst->extra<InterpOneData>();
      assert(!id.smashesAllLocals || id.nChangedLocals == 0);
      if (id.smashesAllLocals) {
        clearLocals(hook);
      } else {
        auto it = id.changedLocals;
        auto const end = it + id.nChangedLocals;
        for (; it != end; ++it) {
          auto& loc = *it;
          // If changing the inner type of a boxed local, also drop the
          // information about inner types for any other boxed locals.
          if (loc.type.isBoxed()) dropLocalRefsInnerTypes(hook);
          hook.setLocalType(loc.id, loc.type);
        }
      }
      break;
    }
    default:
      break;
  }

  if (MInstrEffects::supported(inst)) MInstrEffects::get(inst, hook);
}