Пример #1
0
void BlockModset::ProcessUpdatedLval(BlockMemory *mcfg, Exp *lval, Exp *kind,
                                     bool consider_assign, bool from_call)
{
  if (!m_modset_list)
    m_modset_list = new Vector<PointValue>();
  if (!m_assign_list)
    m_assign_list = new Vector<GuardAssign>();

  // use the ID from the memory rather than the ID from this modset,
  // as this modset has a temporary ID.
  BlockId *use_id = mcfg->GetId();

  // hold a reference on the lvalue, drop it at exit.
  lval->IncRef();

  goto entry;

  // exit label up here to avoid goofy gcc 'crosses initialization' errors.
 exit:
  lval->DecRef();
  return;

 entry:

  ModsetIncludeVisitor visitor(use_id->Kind(), from_call);

  // use the base buffer if we are updating a terminator.
  if (kind) {
    if (ExpTerminate *nkind = kind->IfTerminate()) {
      // ignore field terminator modsets, these are pretty much useless.
      if (nkind->GetTerminateTest()->IsFld())
        goto exit;

      Exp *new_lval = mcfg->GetBaseBuffer(lval, nkind->GetStrideType());
      lval->DecRef();
      lval = new_lval;
      visitor.buffer = true;
    }
  }

  visitor.SetFoundLval(true);
  lval->DoVisit(&visitor);
  visitor.SetFoundLval(false);

  visitor.rvalue = true;

  if (visitor.excluded)
    goto exit;

  Variable *root = lval->Root();
  if (!root)
    goto exit;

  // argument lvals with zero dereferences are additionally excluded.
  // these updates are local to the current function. also look for updates
  // to 'this' which can come from frontend parse/tcheck errors.
  if (use_id->Kind() == B_Function &&
      (root->Kind() == VK_Arg || root->Kind() == VK_This)) {
    if (lval->DrfCount() == 0)
      goto exit;
  }

  // add to the modset if this is not the function's return value. we don't
  // need to explicitly add the return value as it is special cased by
  // BlockMemory and is always treated as modified.
  if (root->Kind() != VK_Return) {
    lval->IncRef();
    if (kind)
      kind->IncRef();
    AddModset(lval, kind);
  }

  if (!consider_assign)
    goto exit;

  // should only be generating direct assignments for Drf() updates.
  Assert(kind == NULL);

  // don't generate assignments for loop iterations.
  if (use_id->Kind() != B_Function)
    goto exit;

  // don't generate assignments for global variables.
  if (root->IsGlobal())
    goto exit;

  // see if we already have assignments for this lval.
  for (size_t ind = 0; ind < GetAssignCount(); ind++) {
    if (m_assign_list->At(ind).left == lval)
      goto exit;
  }

  PPoint exit_point = mcfg->GetCFG()->GetExitPoint();
  if (!exit_point)
    goto exit;

  // temporary vector to hold assignments. if we find a problem with
  // the assigns (bad lvalue, etc.) we will bail out and clear this list.
  Vector<GuardAssign> assigns;

  GuardExpVector exit_values;
  mcfg->GetValComplete(lval, NULL, exit_point, &exit_values, true);

  // cases we will currently generate assignments for. in all cases
  // the rvalue and guard must be functionally determined from the arguments.
  // 1. one or two possible values for the lval.
  // 2. all values for the lval are constants.

  for (size_t ind = 0; ind < exit_values.Size(); ind++) {
    const GuardExp &val = exit_values[ind];

    if (val.guard->Size() >= ASSIGN_BIT_CUTOFF)
      goto exit;

    if (exit_values.Size() <= 2) {
      if (val.exp->TermCountExceeds(ASSIGN_EXP_CUTOFF))
        goto exit;
    }
    else {
      if (!val.exp->IsInt())
        goto exit;
    }
  }

  for (size_t ind = 0; ind < exit_values.Size(); ind++) {
    const GuardExp &val = exit_values[ind];
    val.exp->DoVisit(&visitor);
    val.guard->DoVisit(&visitor);

    lval->IncRef();
    val.IncRef();
    assigns.PushBack(GuardAssign(lval, val.exp, val.guard));
  }

  if (visitor.excluded) {
    for (size_t ind = 0; ind < assigns.Size(); ind++) {
      const GuardAssign &gasn = assigns[ind];
      gasn.left->DecRef();
      gasn.right->DecRef();
      gasn.guard->DecRef();
    }
  }
  else {
    for (size_t ind = 0; ind < assigns.Size(); ind++) {
      const GuardAssign &gasn = assigns[ind];
      AddAssign(gasn.left, gasn.right, gasn.guard);
    }
  }

  goto exit;
}
Пример #2
0
  void Visit(Exp *exp)
  {
    if (exp->IsVar()) {
      Variable *root = exp->AsVar()->GetVariable();

      // allow global exps when the assign was not generated from a call.
      if (root->IsGlobal() && (!from_call || rvalue))
        return;

      if (kind == B_Function) {
        // only consider exps derived from arguments, 'this' and the return
        // variable. note that we will special case the return var later in the
        // modset as it is automatically handled by BlockMemory, but we don't
        // exclude it here so that we can get exact side effects for it
        // if possible.
        if (root->Kind() != VK_Arg &&
            root->Kind() != VK_This &&
            root->Kind() != VK_Return)
          excluded = exp;

        // watch for taking the address of function arguments and leaving them
        // accessible in the caller. weird!
        if (root->Kind() == VK_Arg && !FoundLval())
          excluded = exp;
      }
      else {
        // only consider exps derived from arguments, 'this' and locals.
        if (root->Kind() != VK_Arg &&
            root->Kind() != VK_This &&
            root->Kind() != VK_Local)
          excluded = exp;
      }

      return;
    }

    if (exp->IsDrf()) {
      if (!FoundLval())
        return;

      if (!rvalue) {
        // limits on the number of dereferences in expressions.
        size_t max_derefs = buffer ? 2 : 1;
        if (exp->DrfCount() > max_derefs)
          excluded = exp;
      }

      return;
    }

    if (exp->IsIndex() && !rvalue) {
      // indexes are allowed only for assignment rvalues.
      excluded = exp;
      return;
    }

    if (exp->IsFld() && exp->FldCount() > 6) {
      // limit on the number of fields in expressions. this cuts off infinite
      // recursion during modset computation when the program does funny casts.
      excluded = exp;
      return;
    }

    if (exp->IsRfld()) {
      // all rfld expressions are excluded. these are usually here because
      // of indirect calls which could operate on a variety of structures
      // (this happens in both C and C++).
      excluded = exp;
      return;
    }

    if (exp->IsClobber() || exp->IsVal()) {
      excluded = exp;
      return;
    }
  }