C2 Build IR

三个parse\d.cpp文件

c2有parse1.cpp parse2.cpp parse3.cpp,咋一看很乱,实际上代码非常清晰,parse1.cpp是指解析的最外层(而不是第一步),比如解析我们先从基本块开始,do_one_block,这就在parse1.cpp。然后具体到基本块里面的字节码,do_one_bytecode,这个就是parse2.cpp,然后有些字节码比如get_field,multianewarray这些的IR构造比较复杂,进一步放到parse3.cpp。所以,123它们是层层递进,而不是解析顺序,了解这一点,后面找代码可以快速定位,虽然没啥卵用。

P.S. 巨复杂的invokestatic/virtual等字节码的IR构造不在2也不在3,是直接新建了个doCall.cpp文件

P.P.S. 一般复杂的checkcast instanceof new也是在新文件parseHelper.cpp里面

P.P.P.S. 不过话又说回来,2和3界限是比较模糊的,有些很复杂的字节码的IR构造也是放到2里面,也许可以refactor一下,放到3里面去。

P.P.P.P.S. monitorenter和monitorexit的IR构造是放到了locknode.cpp里面

一句话总结就是,真乱真烂。。

解析过程中,一些研究过的内容。。。

数组访问,如果index确定小于数组size,执行RCE

/------------------------------array_addressing-------------------------------
// Pull array and index from the stack.  Compute pointer-to-element.
Node* Parse::array_addressing(BasicType type, int vals, const Type*& elemtype) {
  Node *idx   = peek(0+vals);   // Get from stack without popping
  Node *ary   = peek(1+vals);   // in case of exception

  // Null check the array base, with correct stack contents
  ary = null_check(ary, T_ARRAY);
  // Compile-time detect of null-exception?
  if (stopped())  return top();

  const TypeAryPtr* arytype  = _gvn.type(ary)->is_aryptr();
  const TypeInt*    sizetype = arytype->size();
  elemtype = arytype->elem();

  if (UseUniqueSubclasses) {
    const Type* el = elemtype->make_ptr();
    if (el && el->isa_instptr()) {
      const TypeInstPtr* toop = el->is_instptr();
      if (toop->klass()->as_instance_klass()->unique_concrete_subklass()) {
        // If we load from "AbstractClass[]" we must see "ConcreteSubClass".
        const Type* subklass = Type::get_const_type(toop->klass());
        elemtype = subklass->join_speculative(el);
      }
    }
  }

  // Check for big class initializers with all constant offsets
  // feeding into a known-size array.
  const TypeInt* idxtype = _gvn.type(idx)->is_int();
  // See if the highest idx value is less than the lowest array bound,
  // and if the idx value cannot be negative:
  bool need_range_check = true;
  if (idxtype->_hi < sizetype->_lo && idxtype->_lo >= 0) {
    need_range_check = false;
    if (C->log() != NULL)   C->log()->elem("observe that='!need_range_check'");
  }

  ciKlass * arytype_klass = arytype->klass();
  if ((arytype_klass != NULL) && (!arytype_klass->is_loaded())) {
    // Only fails for some -Xcomp runs
    // The class is unloaded.  We have to run this bytecode in the interpreter.
    uncommon_trap(Deoptimization::Reason_unloaded,
                  Deoptimization::Action_reinterpret,
                  arytype->klass(), "!loaded array");
    return top();
  }

  // Do the range check
  if (GenerateRangeChecks && need_range_check) {
    Node* tst;
    if (sizetype->_hi <= 0) {
      // The greatest array bound is negative, so we can conclude that we're
      // compiling unreachable code, but the unsigned compare trick used below
      // only works with non-negative lengths.  Instead, hack "tst" to be zero so
      // the uncommon_trap path will always be taken.
      tst = _gvn.intcon(0);
    } else {
      // Range is constant in array-oop, so we can use the original state of mem
      Node* len = load_array_length(ary);

      // Test length vs index (standard trick using unsigned compare)
      Node* chk = _gvn.transform( new CmpUNode(idx, len) );
      BoolTest::mask btest = BoolTest::lt;
      tst = _gvn.transform( new BoolNode(chk, btest) );
    }
    RangeCheckNode* rc = new RangeCheckNode(control(), tst, PROB_MAX, COUNT_UNKNOWN);
    _gvn.set_type(rc, rc->Value(&_gvn));
    if (!tst->is_Con()) {
      record_for_igvn(rc);
    }
    set_control(_gvn.transform(new IfTrueNode(rc)));
    // Branch to failure if out of bounds
    {
      PreserveJVMState pjvms(this);
      set_control(_gvn.transform(new IfFalseNode(rc)));
      if (C->allow_range_check_smearing()) {
        // Do not use builtin_throw, since range checks are sometimes
        // made more stringent by an optimistic transformation.
        // This creates "tentative" range checks at this point,
        // which are not guaranteed to throw exceptions.
        // See IfNode::Ideal, is_range_check, adjust_check.
        uncommon_trap(Deoptimization::Reason_range_check,
                      Deoptimization::Action_make_not_entrant,
                      NULL, "range_check");
      } else {
        // If we have already recompiled with the range-check-widening
        // heroic optimization turned off, then we must really be throwing
        // range check exceptions.
        builtin_throw(Deoptimization::Reason_range_check, idx);
      }
    }
  }
  // Check for always knowing you are throwing a range-check exception
  if (stopped())  return top();

  // Make array address computation control dependent to prevent it
  // from floating above the range check during loop optimizations.
  Node* ptr = array_element_address(ary, idx, type, sizetype, control());
  assert(ptr != top(), "top should go hand-in-hand with stopped");

  return ptr;
}
原文地址:https://www.cnblogs.com/kelthuzadx/p/15718548.html