Exemple #1
0
void MInstrEffects::get(const IRInstruction* inst,
                        const FrameStateMgr& frame,
                        LocalStateHook& hook) {
  // If the base for this instruction is a local address, the helper call might
  // have side effects on the local's value
  auto const base = inst->src(minstrBaseIdx(inst->op()));
  auto const locInstr = base->inst();

  // Right now we require that the address of any affected local is the
  // immediate source of the base tmp.  This isn't actually specified in the ir
  // spec right now but will intend to make it more general soon.
  if (locInstr->op() != LdLocAddr) return;

  auto const locId = locInstr->extra<LdLocAddr>()->locId;
  auto const baseType = frame.localType(locId);

  MInstrEffects effects(inst->op(), baseType.ptr(Ptr::Frame));
  if (effects.baseTypeChanged || effects.baseValChanged) {
    auto const ty = effects.baseType.derefIfPtr();
    if (ty.isBoxed()) {
      hook.setLocalType(locId, Type::BoxedInitCell);
      hook.setBoxedLocalPrediction(locId, ty);
    } else {
      hook.setLocalType(locId, ty);
    }
  }

}
Exemple #2
0
/**
 * This method changes any boxed local into a BoxedInitCell type. It's safe to
 * assume they're init because you can never have a reference to uninit.
 */
void FrameState::dropLocalRefsInnerTypes(LocalStateHook& hook) const {
  walkAllInlinedLocals(
  [&](uint32_t i, unsigned inlineIdx, const LocalState& local) {
    if (local.type.isBoxed()) {
      hook.dropLocalInnerType(i, inlineIdx);
    }
  });
}
Exemple #3
0
/**
 * Called to clear out the tracked local values at a call site.  Calls kill all
 * registers, so we don't want to keep locals in registers across calls. We do
 * continue tracking the types in locals, however.
 */
void FrameState::killLocalsForCall(LocalStateHook& hook,
                                   bool skipThisFrame) const {
  walkAllInlinedLocals(
  [&](uint32_t i, unsigned inlineIdx, const LocalState& local) {
    auto* value = local.value;
    if (!value || value->inst()->is(DefConst)) return;

    hook.killLocalForCall(i, inlineIdx, value);
  },
  skipThisFrame);
}
Exemple #4
0
void FrameState::refineLocalValues(LocalStateHook& hook,
                                   SSATmp* oldVal, SSATmp* newVal) const {
  assert(newVal->inst()->is(CheckType));
  assert(newVal->inst()->src(0) == oldVal);

  for (unsigned i = 0, n = m_locals.size(); i < n; ++i) {
    if (m_locals[i].value == oldVal) {
      hook.refineLocalValue(i, oldVal, newVal);
    }
  }
}
Exemple #5
0
//
// This method updates the tracked values and types of all locals that contain
// oldRef so that they now contain newRef.
// This should only be called for ref/boxed types.
//
void FrameState::updateLocalRefValues(LocalStateHook& hook,
                                      SSATmp* oldRef, SSATmp* newRef) const {
  assert(oldRef->type().isBoxed());
  assert(newRef->type().isBoxed());

  walkAllInlinedLocals(
  [&](uint32_t i, unsigned inlineIdx, const LocalState& local) {
    if (local.value != oldRef) return;

    hook.updateLocalRefValue(i, inlineIdx, oldRef, newRef);
  });
}
Exemple #6
0
void FrameState::refineLocalValues(LocalStateHook& hook,
                                   SSATmp* oldVal, SSATmp* newVal) const {
  assert(newVal->inst()->is(CheckType, AssertType));
  assert(newVal->inst()->src(0) == oldVal);

  walkAllInlinedLocals(
  [&](uint32_t i, unsigned inlineIdx, const LocalState& local) {
    if (local.value == oldVal) {
      hook.refineLocalValue(i, inlineIdx, oldVal, newVal);
    }
  });
}
Exemple #7
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 #8
0
///// Support helpers for getLocalEffects /////
void FrameState::clearLocals(LocalStateHook& hook) const {
  for (unsigned i = 0; i < m_locals.size(); ++i) {
    hook.setLocalValue(i, nullptr);
  }
}
Exemple #9
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);
}