bool MethodComparator::methods_EMCP(methodOop old_method, methodOop new_method) { if (old_method->code_size() != new_method->code_size()) return false; if (check_stack_and_locals_size(old_method, new_method) != 0) { // RC_TRACE macro has an embedded ResourceMark RC_TRACE(0x00800000, ("Methods %s non-comparable with diagnosis %d", old_method->name()->as_C_string(), check_stack_and_locals_size(old_method, new_method))); return false; } _old_cp = old_method->constants(); _new_cp = new_method->constants(); BytecodeStream s_old(old_method); BytecodeStream s_new(new_method); _s_old = &s_old; _s_new = &s_new; _switchable_test = false; Bytecodes::Code c_old, c_new; while ((c_old = s_old.next()) >= 0) { if ((c_new = s_new.next()) < 0 || c_old != c_new) return false; if (! args_same(c_old, c_new)) return false; } return true; }
bool MethodComparator::methods_switchable(methodOop old_method, methodOop new_method, BciMap &bci_map) { if (old_method->code_size() > new_method->code_size()) // Something has definitely been deleted in the new method, compared to the old one. return false; if (! check_stack_and_locals_size(old_method, new_method)) return false; _old_cp = old_method->constants(); _new_cp = new_method->constants(); BytecodeStream s_old(old_method); BytecodeStream s_new(new_method); _s_old = &s_old; _s_new = &s_new; _bci_map = &bci_map; _switchable_test = true; GrowableArray<int> fwd_jmps(16); _fwd_jmps = &fwd_jmps; Bytecodes::Code c_old, c_new; while ((c_old = s_old.next()) >= 0) { if ((c_new = s_new.next()) < 0) return false; if (! (c_old == c_new && args_same(c_old, c_new))) { int old_bci = s_old.bci(); int new_st_bci = s_new.bci(); bool found_match = false; do { c_new = s_new.next(); if (c_new == c_old && args_same(c_old, c_new)) { found_match = true; break; } } while (c_new >= 0); if (! found_match) return false; int new_end_bci = s_new.bci(); bci_map.store_fragment_location(old_bci, new_st_bci, new_end_bci); } } // Now we can test all forward jumps for (int i = 0; i < fwd_jmps.length() / 2; i++) { if (! bci_map.old_and_new_locations_same(fwd_jmps.at(i*2), fwd_jmps.at(i*2+1))) { RC_TRACE(0x00800000, ("Fwd jump miss: old dest = %d, calc new dest = %d, act new dest = %d", fwd_jmps.at(i*2), bci_map.new_bci_for_old(fwd_jmps.at(i*2)), fwd_jmps.at(i*2+1))); return false; } } return true; }
// Simple methods are as good being compiled with C1 as C2. // Determine if a given method is such a case. bool SimpleThresholdPolicy::is_trivial(methodOop method) { if (method->is_accessor()) return true; if (method->code() != NULL) { methodDataOop mdo = method->method_data(); if (mdo != NULL && mdo->num_loops() == 0 && (method->code_size() < 5 || (mdo->num_blocks() < 4) && (method->code_size() < 15))) { return !mdo->would_profile(); } } return false; }
// for hashing into the table static int hash(methodOop method) { // The point here is to try to make something fairly unique // out of the fields we can read without grabbing any locks // since the method may be locked when we need the hash. return ( method->code_size() ^ method->max_stack() ^ method->max_locals() ^ method->size_of_parameters()); }
// Rewrites a method given the index_map information void Rewriter::scan_method(methodOop method, bool reverse) { int nof_jsrs = 0; bool has_monitor_bytecodes = false; { // We cannot tolerate a GC in this block, because we've // cached the bytecodes in 'code_base'. If the methodOop // moves, the bytecodes will also move. No_Safepoint_Verifier nsv; Bytecodes::Code c; // Bytecodes and their length const address code_base = method->code_base(); const int code_length = method->code_size(); int bc_length; for (int bci = 0; bci < code_length; bci += bc_length) { address bcp = code_base + bci; int prefix_length = 0; c = (Bytecodes::Code)(*bcp); // Since we have the code, see if we can get the length // directly. Some more complicated bytecodes will report // a length of zero, meaning we need to make another method // call to calculate the length. bc_length = Bytecodes::length_for(c); if (bc_length == 0) { bc_length = Bytecodes::length_at(method, bcp); // length_at will put us at the bytecode after the one modified // by 'wide'. We don't currently examine any of the bytecodes // modified by wide, but in case we do in the future... if (c == Bytecodes::_wide) { prefix_length = 1; c = (Bytecodes::Code)bcp[1]; } } assert(bc_length != 0, "impossible bytecode length"); switch (c) { case Bytecodes::_lookupswitch : { #ifndef CC_INTERP Bytecode_lookupswitch bc(method, bcp); (*bcp) = ( bc.number_of_pairs() < BinarySwitchThreshold ? Bytecodes::_fast_linearswitch : Bytecodes::_fast_binaryswitch ); #endif break; } case Bytecodes::_fast_linearswitch: case Bytecodes::_fast_binaryswitch: { #ifndef CC_INTERP (*bcp) = Bytecodes::_lookupswitch; #endif break; } case Bytecodes::_getstatic : // fall through case Bytecodes::_putstatic : // fall through case Bytecodes::_getfield : // fall through case Bytecodes::_putfield : // fall through case Bytecodes::_invokevirtual : // fall through case Bytecodes::_invokespecial : // fall through case Bytecodes::_invokestatic : case Bytecodes::_invokeinterface: rewrite_member_reference(bcp, prefix_length+1, reverse); break; case Bytecodes::_invokedynamic: rewrite_invokedynamic(bcp, prefix_length+1, reverse); break; case Bytecodes::_ldc: case Bytecodes::_fast_aldc: maybe_rewrite_ldc(bcp, prefix_length+1, false, reverse); break; case Bytecodes::_ldc_w: case Bytecodes::_fast_aldc_w: maybe_rewrite_ldc(bcp, prefix_length+1, true, reverse); break; case Bytecodes::_jsr : // fall through case Bytecodes::_jsr_w : nof_jsrs++; break; case Bytecodes::_monitorenter : // fall through case Bytecodes::_monitorexit : has_monitor_bytecodes = true; break; } } } // Update access flags if (has_monitor_bytecodes) { method->set_has_monitor_bytecodes(); } // The present of a jsr bytecode implies that the method might potentially // have to be rewritten, so we run the oopMapGenerator on the method if (nof_jsrs > 0) { method->set_has_jsrs(); // Second pass will revisit this method. assert(method->has_jsrs(), "didn't we just set this?"); } }