三个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;
}