• 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;
    }
    
  • 相关阅读:
    mybatis 中的稍微复杂些的sql语句
    Why doesn't Genymotion run on Windows 10?
    java.lang.NoSuchMethodError: 属于jar包冲突
    sqlserver修改某列为行号
    手机App开发
    java连接SQLserver
    svn忽略target
    JaxWsDynamicClientFactory弃用了,改成org.codehaus.xfire.client;
    FileDataSource java的文件操作
    解决Navicat无法连接Oracle的问题
  • 原文地址:https://www.cnblogs.com/kelthuzadx/p/15718548.html
Copyright © 2020-2023  润新知