Path: blob/master/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/GenerateOopMap.java
41161 views
/*1* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324package sun.jvm.hotspot.oops;2526import java.io.*;27import java.util.*;28import sun.jvm.hotspot.interpreter.*;29import sun.jvm.hotspot.runtime.*;30import sun.jvm.hotspot.utilities.*;3132/** Minimal port of the VM's oop map generator for interpreted frames */3334public class GenerateOopMap {35interface JumpClosure {36public void process(GenerateOopMap c, int bcpDelta, int[] data);37}3839// Used for debugging this code40private static final boolean DEBUG = false;4142// These two should be removed. But requires som code to be cleaned up43private static final int MAXARGSIZE = 256; // This should be enough44private static final int MAX_LOCAL_VARS = 65536; // 16-bit entry45private static final boolean TraceMonitorMismatch = true;46private static final boolean TraceOopMapRewrites = true;4748// Commonly used constants49static CellTypeState[] epsilonCTS = { CellTypeState.bottom };50static CellTypeState refCTS = CellTypeState.ref;51static CellTypeState valCTS = CellTypeState.value;52static CellTypeState[] vCTS = { CellTypeState.value, CellTypeState.bottom };53static CellTypeState[] rCTS = { CellTypeState.ref, CellTypeState.bottom };54static CellTypeState[] rrCTS = { CellTypeState.ref, CellTypeState.ref, CellTypeState.bottom };55static CellTypeState[] vrCTS = { CellTypeState.value, CellTypeState.ref, CellTypeState.bottom };56static CellTypeState[] vvCTS = { CellTypeState.value, CellTypeState.value, CellTypeState.bottom };57static CellTypeState[] rvrCTS = { CellTypeState.ref, CellTypeState.value, CellTypeState.ref, CellTypeState.bottom };58static CellTypeState[] vvrCTS = { CellTypeState.value, CellTypeState.value, CellTypeState.ref, CellTypeState.bottom };59static CellTypeState[] vvvCTS = { CellTypeState.value, CellTypeState.value, CellTypeState.value, CellTypeState.bottom };60static CellTypeState[] vvvrCTS = { CellTypeState.value, CellTypeState.value, CellTypeState.value, CellTypeState.ref, CellTypeState.bottom };61static CellTypeState[] vvvvCTS = { CellTypeState.value, CellTypeState.value, CellTypeState.value, CellTypeState.value, CellTypeState.bottom };6263/** Specialization of SignatureIterator - compute the effects of a call */64static class ComputeCallStack extends SignatureIterator {65CellTypeStateList _effect;66int _idx;6768void set(CellTypeState state) { _effect.get(_idx++).set(state); }69int length() { return _idx; };7071public void doBool () { set(CellTypeState.value); }72public void doChar () { set(CellTypeState.value); }73public void doFloat () { set(CellTypeState.value); }74public void doByte () { set(CellTypeState.value); }75public void doShort () { set(CellTypeState.value); }76public void doInt () { set(CellTypeState.value); }77public void doVoid () { set(CellTypeState.bottom);}78public void doObject(int begin, int end) { set(CellTypeState.ref); }79public void doArray (int begin, int end) { set(CellTypeState.ref); }8081public void doDouble() { set(CellTypeState.value);82set(CellTypeState.value); }83public void doLong () { set(CellTypeState.value);84set(CellTypeState.value); }8586ComputeCallStack(Symbol signature) {87super(signature);88}8990// Compute methods91int computeForParameters(boolean is_static, CellTypeStateList effect) {92_idx = 0;93_effect = effect;9495if (!is_static) {96effect.get(_idx++).set(CellTypeState.ref);97}9899iterateParameters();100101return length();102};103104int computeForReturntype(CellTypeStateList effect) {105_idx = 0;106_effect = effect;107iterateReturntype();108set(CellTypeState.bottom); // Always terminate with a bottom state, so ppush works109110return length();111}112}113114/** Specialization of SignatureIterator - in order to set up first stack frame */115static class ComputeEntryStack extends SignatureIterator {116CellTypeStateList _effect;117int _idx;118119void set(CellTypeState state) { _effect.get(_idx++).set(state); }120int length() { return _idx; };121122public void doBool () { set(CellTypeState.value); }123public void doChar () { set(CellTypeState.value); }124public void doFloat () { set(CellTypeState.value); }125public void doByte () { set(CellTypeState.value); }126public void doShort () { set(CellTypeState.value); }127public void doInt () { set(CellTypeState.value); }128public void doVoid () { set(CellTypeState.bottom);}129public void doObject(int begin, int end) { set(CellTypeState.makeSlotRef(_idx)); }130public void doArray (int begin, int end) { set(CellTypeState.makeSlotRef(_idx)); }131132public void doDouble() { set(CellTypeState.value);133set(CellTypeState.value); }134public void doLong () { set(CellTypeState.value);135set(CellTypeState.value); }136137ComputeEntryStack(Symbol signature) {138super(signature);139}140141// Compute methods142int computeForParameters(boolean is_static, CellTypeStateList effect) {143_idx = 0;144_effect = effect;145146if (!is_static) {147effect.get(_idx++).set(CellTypeState.makeSlotRef(0));148}149150iterateParameters();151152return length();153};154155int computeForReturntype(CellTypeStateList effect) {156_idx = 0;157_effect = effect;158iterateReturntype();159set(CellTypeState.bottom); // Always terminate with a bottom state, so ppush works160161return length();162}163}164165/** Contains maping between jsr targets and there return addresses.166One-to-many mapping. */167static class RetTableEntry {168private static int _init_nof_jsrs; // Default size of jsrs list169private int _target_bci; // Target PC address of jump (bytecode index)170private List<Integer> _jsrs; // List of return addresses (bytecode index)171private RetTableEntry _next; // Link to next entry172173RetTableEntry(int target, RetTableEntry next) {174_target_bci = target;175_jsrs = new ArrayList<>(_init_nof_jsrs);176_next = next;177}178179// Query180int targetBci() { return _target_bci; }181int nofJsrs() { return _jsrs.size(); }182int jsrs(int i) { return _jsrs.get(i).intValue(); }183184// Update entry185void addJsr (int return_bci) { _jsrs.add(return_bci); }186void addDelta(int bci, int delta) {187if (_target_bci > bci) {188_target_bci += delta;189}190191for (int k = 0; k < nofJsrs(); k++) {192int jsr = jsrs(k);193if (jsr > bci) {194_jsrs.set(k, jsr + delta);195}196}197}198RetTableEntry next() { return _next; }199}200201static class RetTable {202private RetTableEntry _first;203private static int _init_nof_entries;204205private void addJsr(int return_bci, int target_bci) {206RetTableEntry entry = _first;207208// Scan table for entry209for (;(entry != null) && (entry.targetBci() != target_bci); entry = entry.next());210211if (entry == null) {212// Allocate new entry and put in list213entry = new RetTableEntry(target_bci, _first);214_first = entry;215}216217// Now "entry" is set. Make sure that the entry is initialized218// and has room for the new jsr.219entry.addJsr(return_bci);220}221222RetTable() {}223void computeRetTable(Method method) {224BytecodeStream i = new BytecodeStream(method);225int bytecode;226227while( (bytecode = i.next()) >= 0) {228switch (bytecode) {229case Bytecodes._jsr:230addJsr(i.nextBCI(), i.dest());231break;232case Bytecodes._jsr_w:233addJsr(i.nextBCI(), i.dest_w());234break;235}236}237}238void updateRetTable(int bci, int delta) {239RetTableEntry cur = _first;240while(cur != null) {241cur.addDelta(bci, delta);242cur = cur.next();243}244}245RetTableEntry findJsrsForTarget(int targBci) {246RetTableEntry cur = _first;247248while(cur != null) {249if (Assert.ASSERTS_ENABLED) {250Assert.that(cur.targetBci() != -1, "sanity check");251}252if (cur.targetBci() == targBci) {253return cur;254}255cur = cur.next();256}257throw new RuntimeException("Should not reach here");258}259}260261static class BasicBlock {262private boolean _changed; // Reached a fixpoint or not263static final int _dead_basic_block = -2;264// Alive but not yet reached by analysis265static final int _unreached = -1;266// >=0: Alive and has a merged state267268int _bci; // Start of basic block269int _end_bci; // Bci of last instruction in basicblock270int _max_locals; // Determines split between vars and stack271int _max_stack; // Determines split between stack and monitors272CellTypeStateList _state; // State (vars, stack) at entry.273int _stack_top; // -1 indicates bottom stack value.274int _monitor_top; // -1 indicates bottom monitor stack value.275276CellTypeStateList vars() { return _state; }277CellTypeStateList stack() { return _state.subList(_max_locals, _state.size()); }278279boolean changed() { return _changed; }280void setChanged(boolean s) { _changed = s; }281282// Analysis has reached this basicblock283boolean isReachable() { return _stack_top >= 0; }284285// All basicblocks that are unreachable are going to have a _stack_top == _dead_basic_block.286// This info. is setup in a pre-parse before the real abstract interpretation starts.287boolean isDead() { return _stack_top == _dead_basic_block; }288boolean isAlive() { return _stack_top != _dead_basic_block; }289void markAsAlive() {290if (Assert.ASSERTS_ENABLED) {291Assert.that(isDead(), "must be dead");292_stack_top = _unreached;293}294}295}296297//----------------------------------------------------------------------298// Protected routines for GenerateOopMap299//300301// _monitor_top is set to this constant to indicate that a monitor matching302// problem was encountered prior to this point in control flow.303protected static final int bad_monitors = -1;304305// Main variables306Method _method; // The method we are examining307RetTable _rt; // Contains the return address mappings308int _max_locals; // Cached value of no. of locals309int _max_stack; // Cached value of max. stack depth310int _max_monitors; // Cached value of max. monitor stack depth311boolean _has_exceptions; // True, if exceptions exist for method312boolean _got_error; // True, if an error occured during interpretation.313String _error_msg; // Error message. Set if _got_error is true.314// bool _did_rewriting; // was bytecodes rewritten315// bool _did_relocation; // was relocation neccessary316boolean _monitor_safe; // The monitors in this method have been determined317// to be safe.318319// Working Cell type state320int _state_len; // Size of states321CellTypeStateList _state; // list of states322char[] _state_vec_buf; // Buffer used to print a readable version of a state323int _stack_top;324int _monitor_top;325326// Timing and statistics327// static elapsedTimer _total_oopmap_time; // Holds cumulative oopmap generation time328// static long _total_byte_count; // Holds cumulative number of bytes inspected329330// Monitor query logic331int _report_for_exit_bci;332int _matching_enter_bci;333334// Cell type methods335void initState() {336_state_len = _max_locals + _max_stack + _max_monitors;337_state = new CellTypeStateList(_state_len);338_state_vec_buf = new char[Math.max(_max_locals, Math.max(_max_stack, Math.max(_max_monitors, 1)))];339}340void makeContextUninitialized () {341CellTypeStateList vs = vars();342343for (int i = 0; i < _max_locals; i++)344vs.get(i).set(CellTypeState.uninit);345346_stack_top = 0;347_monitor_top = 0;348}349350int methodsigToEffect (Symbol signature, boolean isStatic, CellTypeStateList effect) {351ComputeEntryStack ces = new ComputeEntryStack(signature);352return ces.computeForParameters(isStatic, effect);353}354355boolean mergeStateVectors (CellTypeStateList cts, CellTypeStateList bbts) {356int i;357int len = _max_locals + _stack_top;358boolean change = false;359360for (i = len - 1; i >= 0; i--) {361CellTypeState v = cts.get(i).merge(bbts.get(i), i);362change = change || !v.equal(bbts.get(i));363bbts.get(i).set(v);364}365366if (_max_monitors > 0 && _monitor_top != bad_monitors) {367// If there are no monitors in the program, or there has been368// a monitor matching error before this point in the program,369// then we do not merge in the monitor state.370371int base = _max_locals + _max_stack;372len = base + _monitor_top;373for (i = len - 1; i >= base; i--) {374CellTypeState v = cts.get(i).merge(bbts.get(i), i);375376// Can we prove that, when there has been a change, it will already377// have been detected at this point? That would make this equal378// check here unnecessary.379change = change || !v.equal(bbts.get(i));380bbts.get(i).set(v);381}382}383384return change;385}386387void copyState (CellTypeStateList dst, CellTypeStateList src) {388int len = _max_locals + _stack_top;389for (int i = 0; i < len; i++) {390if (src.get(i).isNonlockReference()) {391dst.get(i).set(CellTypeState.makeSlotRef(i));392} else {393dst.get(i).set(src.get(i));394}395}396if (_max_monitors > 0 && _monitor_top != bad_monitors) {397int base = _max_locals + _max_stack;398len = base + _monitor_top;399for (int i = base; i < len; i++) {400dst.get(i).set(src.get(i));401}402}403}404405void mergeStateIntoBB (BasicBlock bb) {406if (Assert.ASSERTS_ENABLED) {407Assert.that(bb.isAlive(), "merging state into a dead basicblock");408}409410if (_stack_top == bb._stack_top) {411if (_monitor_top == bb._monitor_top) {412if (mergeStateVectors(_state, bb._state)) {413bb.setChanged(true);414}415} else {416if (TraceMonitorMismatch) {417reportMonitorMismatch("monitor stack height merge conflict");418}419// When the monitor stacks are not matched, we set _monitor_top to420// bad_monitors. This signals that, from here on, the monitor stack cannot421// be trusted. In particular, monitorexit bytecodes may throw422// exceptions. We mark this block as changed so that the change423// propagates properly.424bb._monitor_top = bad_monitors;425bb.setChanged(true);426_monitor_safe = false;427}428} else if (!bb.isReachable()) {429// First time we look at this BB430copyState(bb._state, _state);431bb._stack_top = _stack_top;432bb._monitor_top = _monitor_top;433bb.setChanged(true);434} else {435throw new RuntimeException("stack height conflict: " +436_stack_top + " vs. " + bb._stack_top);437}438}439440void mergeState (int bci, int[] data) {441mergeStateIntoBB(getBasicBlockAt(bci));442}443444void setVar (int localNo, CellTypeState cts) {445if (Assert.ASSERTS_ENABLED) {446Assert.that(cts.isReference() || cts.isValue() || cts.isAddress(),447"wrong celltypestate");448}449if (localNo < 0 || localNo > _max_locals) {450throw new RuntimeException("variable write error: r" + localNo);451}452vars().get(localNo).set(cts);453}454455CellTypeState getVar (int localNo) {456if (Assert.ASSERTS_ENABLED) {457Assert.that(localNo < _max_locals + _nof_refval_conflicts, "variable read error");458}459if (localNo < 0 || localNo > _max_locals) {460throw new RuntimeException("variable read error: r" + localNo);461}462return vars().get(localNo).copy();463}464465CellTypeState pop () {466if ( _stack_top <= 0) {467throw new RuntimeException("stack underflow");468}469return stack().get(--_stack_top).copy();470}471472void push (CellTypeState cts) {473if ( _stack_top >= _max_stack) {474if (DEBUG) {475System.err.println("Method: " + method().getName().asString() + method().getSignature().asString() +476" _stack_top: " + _stack_top + " _max_stack: " + _max_stack);477}478throw new RuntimeException("stack overflow");479}480stack().get(_stack_top++).set(cts);481if (DEBUG) {482System.err.println("After push: _stack_top: " + _stack_top +483" _max_stack: " + _max_stack +484" just pushed: " + cts.toChar());485}486}487488CellTypeState monitorPop () {489if (Assert.ASSERTS_ENABLED) {490Assert.that(_monitor_top != bad_monitors, "monitorPop called on error monitor stack");491}492if (_monitor_top == 0) {493// We have detected a pop of an empty monitor stack.494_monitor_safe = false;495_monitor_top = bad_monitors;496497if (TraceMonitorMismatch) {498reportMonitorMismatch("monitor stack underflow");499}500return CellTypeState.ref; // just to keep the analysis going.501}502return monitors().get(--_monitor_top).copy();503}504505void monitorPush (CellTypeState cts) {506if (Assert.ASSERTS_ENABLED) {507Assert.that(_monitor_top != bad_monitors, "monitorPush called on error monitor stack");508}509if (_monitor_top >= _max_monitors) {510// Some monitorenter is being executed more than once.511// This means that the monitor stack cannot be simulated.512_monitor_safe = false;513_monitor_top = bad_monitors;514515if (TraceMonitorMismatch) {516reportMonitorMismatch("monitor stack overflow");517}518return;519}520monitors().get(_monitor_top++).set(cts);521}522523CellTypeStateList vars () { return _state; }524CellTypeStateList stack () { return _state.subList(_max_locals, _state.size()); }525CellTypeStateList monitors() { return _state.subList(_max_locals+_max_stack, _state.size()); }526527void replaceAllCTSMatches (CellTypeState match,528CellTypeState replace) {529int i;530int len = _max_locals + _stack_top;531boolean change = false;532533for (i = len - 1; i >= 0; i--) {534if (match.equal(_state.get(i))) {535_state.get(i).set(replace);536}537}538539if (_monitor_top > 0) {540int base = _max_locals + _max_stack;541len = base + _monitor_top;542for (i = len - 1; i >= base; i--) {543if (match.equal(_state.get(i))) {544_state.get(i).set(replace);545}546}547}548}549550void printStates (PrintStream tty, CellTypeStateList vector, int num) {551for (int i = 0; i < num; i++) {552vector.get(i).print(tty);553}554}555556void printCurrentState (PrintStream tty,557BytecodeStream currentBC,558boolean detailed) {559if (detailed) {560tty.print(" " + currentBC.bci() + " vars = ");561printStates(tty, vars(), _max_locals);562tty.print(" " + Bytecodes.name(currentBC.code()));563switch(currentBC.code()) {564case Bytecodes._invokevirtual:565case Bytecodes._invokespecial:566case Bytecodes._invokestatic:567case Bytecodes._invokeinterface:568case Bytecodes._invokedynamic:569// FIXME: print signature of referenced method (need more570// accessors in ConstantPool and ConstantPoolCache)571int idx = currentBC.hasIndexU4() ? currentBC.getIndexU4() : currentBC.getIndexU2();572tty.print(" idx " + idx);573/*574int idx = currentBC.getIndexU2();575ConstantPool cp = method().getConstants();576int nameAndTypeIdx = cp.name_and_type_ref_index_at(idx);577int signatureIdx = cp.signature_ref_index_at(nameAndTypeIdx);578Symbol* signature = cp.symbol_at(signatureIdx);579tty.print("%s", signature.as_C_string());580*/581}582tty.println();583tty.print(" stack = ");584printStates(tty, stack(), _stack_top);585tty.println();586if (_monitor_top != bad_monitors) {587tty.print(" monitors = ");588printStates(tty, monitors(), _monitor_top);589} else {590tty.print(" [bad monitor stack]");591}592tty.println();593} else {594tty.print(" " + currentBC.bci() + " vars = '" +595stateVecToString(vars(), _max_locals) + "' ");596tty.print(" stack = '" + stateVecToString(stack(), _stack_top) + "' ");597if (_monitor_top != bad_monitors) {598tty.print(" monitors = '" + stateVecToString(monitors(), _monitor_top) + "' \t" +599Bytecodes.name(currentBC.code()));600} else {601tty.print(" [bad monitor stack]");602}603switch(currentBC.code()) {604case Bytecodes._invokevirtual:605case Bytecodes._invokespecial:606case Bytecodes._invokestatic:607case Bytecodes._invokeinterface:608case Bytecodes._invokedynamic:609// FIXME: print signature of referenced method (need more610// accessors in ConstantPool and ConstantPoolCache)611int idx = currentBC.hasIndexU4() ? currentBC.getIndexU4() : currentBC.getIndexU2();612tty.print(" idx " + idx);613/*614int idx = currentBC.getIndexU2();615ConstantPool* cp = method().constants();616int nameAndTypeIdx = cp.name_and_type_ref_index_at(idx);617int signatureIdx = cp.signature_ref_index_at(nameAndTypeIdx);618Symbol* signature = cp.symbol_at(signatureIdx);619tty.print("%s", signature.as_C_string());620*/621}622tty.println();623}624}625626void reportMonitorMismatch (String msg) {627if (Assert.ASSERTS_ENABLED) {628System.err.print(" Monitor mismatch in method ");629method().printValueOn(System.err);630System.err.println(": " + msg);631}632}633634// Basicblock info635BasicBlock[] _basic_blocks; // Array of basicblock info636int _gc_points;637int _bb_count;638BitMap _bb_hdr_bits;639640// Basicblocks methods641void initializeBB () {642_gc_points = 0;643_bb_count = 0;644_bb_hdr_bits = new BitMap((int) _method.getCodeSize());645}646647void markBBHeadersAndCountGCPoints() {648initializeBB();649650boolean fellThrough = false; // False to get first BB marked.651652// First mark all exception handlers as start of a basic-block653if (method().hasExceptionTable()) {654ExceptionTableElement[] excps = method().getExceptionTable();655for(int i = 0; i < excps.length; i++) {656markBB(excps[i].getHandlerPC(), null);657}658}659660// Then iterate through the code661BytecodeStream bcs = new BytecodeStream(_method);662int bytecode;663664while( (bytecode = bcs.next()) >= 0) {665int bci = bcs.bci();666667if (!fellThrough)668markBB(bci, null);669670fellThrough = jumpTargetsDo(bcs,671new JumpClosure() {672public void process(GenerateOopMap c, int bcpDelta, int[] data) {673c.markBB(bcpDelta, data);674}675},676null);677678/* We will also mark successors of jsr's as basic block headers. */679switch (bytecode) {680case Bytecodes._jsr:681if (Assert.ASSERTS_ENABLED) {682Assert.that(!fellThrough, "should not happen");683}684markBB(bci + Bytecodes.lengthFor(bytecode), null);685break;686case Bytecodes._jsr_w:687if (Assert.ASSERTS_ENABLED) {688Assert.that(!fellThrough, "should not happen");689}690markBB(bci + Bytecodes.lengthFor(bytecode), null);691break;692}693694if (possibleGCPoint(bcs))695_gc_points++;696}697}698699boolean isBBHeader (int bci) {700return _bb_hdr_bits.at(bci);701}702703int gcPoints () {704return _gc_points;705}706707int bbCount () {708return _bb_count;709}710711void setBBMarkBit (int bci) {712_bb_hdr_bits.atPut(bci, true);713}714715void clear_bbmark_bit (int bci) {716_bb_hdr_bits.atPut(bci, false);717}718719BasicBlock getBasicBlockAt (int bci) {720BasicBlock bb = getBasicBlockContaining(bci);721if (Assert.ASSERTS_ENABLED) {722Assert.that(bb._bci == bci, "should have found BB");723}724return bb;725}726727BasicBlock getBasicBlockContaining (int bci) {728BasicBlock[] bbs = _basic_blocks;729int lo = 0, hi = _bb_count - 1;730731while (lo <= hi) {732int m = (lo + hi) / 2;733int mbci = bbs[m]._bci;734int nbci;735736if ( m == _bb_count-1) {737if (Assert.ASSERTS_ENABLED) {738Assert.that( bci >= mbci && bci < method().getCodeSize(), "sanity check failed");739}740return bbs[m];741} else {742nbci = bbs[m+1]._bci;743}744745if ( mbci <= bci && bci < nbci) {746return bbs[m];747} else if (mbci < bci) {748lo = m + 1;749} else {750if (Assert.ASSERTS_ENABLED) {751Assert.that(mbci > bci, "sanity check");752}753hi = m - 1;754}755}756757throw new RuntimeException("should have found BB");758}759760void interpBB (BasicBlock bb) {761// We do not want to do anything in case the basic-block has not been initialized. This762// will happen in the case where there is dead-code hang around in a method.763if (Assert.ASSERTS_ENABLED) {764Assert.that(bb.isReachable(), "should be reachable or deadcode exist");765}766restoreState(bb);767768BytecodeStream itr = new BytecodeStream(_method);769770// Set iterator interval to be the current basicblock771int lim_bci = nextBBStartPC(bb);772itr.setInterval(bb._bci, lim_bci);773774if (DEBUG) {775System.err.println("interpBB: method = " + method().getName().asString() +776method().getSignature().asString() +777", BCI interval [" + bb._bci + ", " + lim_bci + ")");778{779System.err.print("Bytecodes:");780for (int i = bb._bci; i < lim_bci; i++) {781System.err.print(" 0x" + Long.toHexString(method().getBytecodeOrBPAt(i)));782}783System.err.println();784}785}786787if (Assert.ASSERTS_ENABLED) {788Assert.that(lim_bci != bb._bci, "must be at least one instruction in a basicblock");789}790itr.next(); // read first instruction791792// Iterates through all bytecodes except the last in a basic block.793// We handle the last one special, since there is controlflow change.794while(itr.nextBCI() < lim_bci && !_got_error) {795if (_has_exceptions || (_monitor_top != 0)) {796// We do not need to interpret the results of exceptional797// continuation from this instruction when the method has no798// exception handlers and the monitor stack is currently799// empty.800doExceptionEdge(itr);801}802interp1(itr);803itr.next();804}805806// Handle last instruction.807if (!_got_error) {808if (Assert.ASSERTS_ENABLED) {809Assert.that(itr.nextBCI() == lim_bci, "must point to end");810}811if (_has_exceptions || (_monitor_top != 0)) {812doExceptionEdge(itr);813}814interp1(itr);815816boolean fall_through = jumpTargetsDo(itr, new JumpClosure() {817public void process(GenerateOopMap c, int bcpDelta, int[] data) {818c.mergeState(bcpDelta, data);819}820}, null);821if (_got_error) return;822823if (itr.code() == Bytecodes._ret) {824if (Assert.ASSERTS_ENABLED) {825Assert.that(!fall_through, "cannot be set if ret instruction");826}827// Automatically handles 'wide' ret indicies828retJumpTargetsDo(itr, new JumpClosure() {829public void process(GenerateOopMap c, int bcpDelta, int[] data) {830c.mergeState(bcpDelta, data);831}832}, itr.getIndex(), null);833} else if (fall_through) {834// Hit end of BB, but the instr. was a fall-through instruction,835// so perform transition as if the BB ended in a "jump".836if (Assert.ASSERTS_ENABLED) {837Assert.that(lim_bci == _basic_blocks[bbIndex(bb) + 1]._bci, "there must be another bb");838}839mergeStateIntoBB(_basic_blocks[bbIndex(bb) + 1]);840}841}842}843844void restoreState (BasicBlock bb) {845for (int i = 0; i < _state_len; i++) {846_state.get(i).set(bb._state.get(i));847}848_stack_top = bb._stack_top;849_monitor_top = bb._monitor_top;850}851852int nextBBStartPC (BasicBlock bb) {853int bbNum = bbIndex(bb) + 1;854if (bbNum == _bb_count)855return (int) method().getCodeSize();856857return _basic_blocks[bbNum]._bci;858}859860void updateBasicBlocks (int bci, int delta) {861BitMap bbBits = new BitMap((int) (_method.getCodeSize() + delta));862for(int k = 0; k < _bb_count; k++) {863if (_basic_blocks[k]._bci > bci) {864_basic_blocks[k]._bci += delta;865_basic_blocks[k]._end_bci += delta;866}867bbBits.atPut(_basic_blocks[k]._bci, true);868}869_bb_hdr_bits = bbBits;870}871872void markBB(int bci, int[] data) {873if (Assert.ASSERTS_ENABLED) {874Assert.that(bci>= 0 && bci < method().getCodeSize(), "index out of bounds");875}876if (isBBHeader(bci))877return;878879// FIXME: remove880// if (TraceNewOopMapGeneration) {881// tty.print_cr("Basicblock#%d begins at: %d", c._bb_count, bci);882// }883setBBMarkBit(bci);884_bb_count++;885}886887// Dead code detection888void markReachableCode() {889final int[] change = new int[1];890change[0] = 1;891892// Mark entry basic block as alive and all exception handlers893_basic_blocks[0].markAsAlive();894if (method().hasExceptionTable()) {895ExceptionTableElement[] excps = method().getExceptionTable();896for(int i = 0; i < excps.length; i ++) {897BasicBlock bb = getBasicBlockAt(excps[i].getHandlerPC());898// If block is not already alive (due to multiple exception handlers to same bb), then899// make it alive900if (bb.isDead())901bb.markAsAlive();902}903}904905BytecodeStream bcs = new BytecodeStream(_method);906907// Iterate through all basic blocks until we reach a fixpoint908while (change[0] != 0) {909change[0] = 0;910911for (int i = 0; i < _bb_count; i++) {912BasicBlock bb = _basic_blocks[i];913if (bb.isAlive()) {914// Position bytecodestream at last bytecode in basicblock915bcs.setStart(bb._end_bci);916bcs.next();917int bytecode = bcs.code();918int bci = bcs.bci();919if (Assert.ASSERTS_ENABLED) {920Assert.that(bci == bb._end_bci, "wrong bci");921}922923boolean fell_through = jumpTargetsDo(bcs, new JumpClosure() {924public void process(GenerateOopMap c, int bciDelta, int[] change) {925c.reachableBasicblock(bciDelta, change);926}927}, change);928929// We will also mark successors of jsr's as alive.930switch (bytecode) {931case Bytecodes._jsr:932case Bytecodes._jsr_w:933if (Assert.ASSERTS_ENABLED) {934Assert.that(!fell_through, "should not happen");935}936reachableBasicblock(bci + Bytecodes.lengthFor(bytecode), change);937break;938}939if (fell_through) {940// Mark successor as alive941if (_basic_blocks[i+1].isDead()) {942_basic_blocks[i+1].markAsAlive();943change[0] = 1;944}945}946}947}948}949}950951void reachableBasicblock (int bci, int[] data) {952if (Assert.ASSERTS_ENABLED) {953Assert.that(bci>= 0 && bci < method().getCodeSize(), "index out of bounds");954}955BasicBlock bb = getBasicBlockAt(bci);956if (bb.isDead()) {957bb.markAsAlive();958data[0] = 1; // Mark basicblock as changed959}960}961962// Interpretation methods (primary)963void doInterpretation () {964// "i" is just for debugging, so we can detect cases where this loop is965// iterated more than once.966int i = 0;967do {968// FIXME: remove969// if (TraceNewOopMapGeneration) {970// tty.print("\n\nIteration #%d of do_interpretation loop, method:\n", i);971// method().print_name(tty);972// tty.print("\n\n");973// }974_conflict = false;975_monitor_safe = true;976// init_state is now called from init_basic_blocks. The length of a977// state vector cannot be determined until we have made a pass through978// the bytecodes counting the possible monitor entries.979if (!_got_error) initBasicBlocks();980if (!_got_error) setupMethodEntryState();981if (!_got_error) interpAll();982if (!_got_error) rewriteRefvalConflicts();983i++;984} while (_conflict && !_got_error);985}986987void initBasicBlocks () {988// Note: Could consider reserving only the needed space for each BB's state989// (entry stack may not be of maximal height for every basic block).990// But cumbersome since we don't know the stack heights yet. (Nor the991// monitor stack heights...)992993_basic_blocks = new BasicBlock[_bb_count];994for (int i = 0; i < _bb_count; i++) {995_basic_blocks[i] = new BasicBlock();996}997998// Make a pass through the bytecodes. Count the number of monitorenters.999// This can be used an upper bound on the monitor stack depth in programs1000// which obey stack discipline with their monitor usage. Initialize the1001// known information about basic blocks.1002BytecodeStream j = new BytecodeStream(_method);1003int bytecode;10041005int bbNo = 0;1006int monitor_count = 0;1007int prev_bci = -1;1008while( (bytecode = j.next()) >= 0) {1009if (j.code() == Bytecodes._monitorenter) {1010monitor_count++;1011}10121013int bci = j.bci();1014if (isBBHeader(bci)) {1015// Initialize the basicblock structure1016BasicBlock bb = _basic_blocks[bbNo];1017bb._bci = bci;1018bb._max_locals = _max_locals;1019bb._max_stack = _max_stack;1020bb.setChanged(false);1021bb._stack_top = BasicBlock._dead_basic_block; // Initialize all basicblocks are dead.1022bb._monitor_top = bad_monitors;10231024if (bbNo > 0) {1025_basic_blocks[bbNo - 1]._end_bci = prev_bci;1026}10271028bbNo++;1029}1030// Remember prevous bci.1031prev_bci = bci;1032}1033// Set1034_basic_blocks[bbNo-1]._end_bci = prev_bci;10351036_max_monitors = monitor_count;10371038// Now that we have a bound on the depth of the monitor stack, we can1039// initialize the CellTypeState-related information.1040initState();10411042// We allocate space for all state-vectors for all basicblocks in one huge chuck.1043// Then in the next part of the code, we set a pointer in each _basic_block that1044// points to each piece.1045CellTypeStateList basicBlockState = new CellTypeStateList(bbNo * _state_len);10461047// Make a pass over the basicblocks and assign their state vectors.1048for (int blockNum=0; blockNum < bbNo; blockNum++) {1049BasicBlock bb = _basic_blocks[blockNum];1050bb._state = basicBlockState.subList(blockNum * _state_len, (blockNum + 1) * _state_len);10511052if (Assert.ASSERTS_ENABLED) {1053if (blockNum + 1 < bbNo) {1054int bc_len = Bytecodes.javaLengthAt(_method, bb._end_bci);1055Assert.that(bb._end_bci + bc_len == _basic_blocks[blockNum + 1]._bci,1056"unmatched bci info in basicblock");1057}1058}1059}1060if (Assert.ASSERTS_ENABLED) {1061BasicBlock bb = _basic_blocks[bbNo-1];1062int bc_len = Bytecodes.javaLengthAt(_method, bb._end_bci);1063Assert.that(bb._end_bci + bc_len == _method.getCodeSize(), "wrong end bci");1064}10651066// Check that the correct number of basicblocks was found1067if (bbNo !=_bb_count) {1068if (bbNo < _bb_count) {1069throw new RuntimeException("jump into the middle of instruction?");1070} else {1071throw new RuntimeException("extra basic blocks - should not happen?");1072}1073}10741075// Mark all alive blocks1076markReachableCode();1077}10781079void setupMethodEntryState () {1080// Initialize all locals to 'uninit' and set stack-height to 01081makeContextUninitialized();10821083// Initialize CellState type of arguments1084methodsigToEffect(method().getSignature(), method().isStatic(), vars());10851086// If some references must be pre-assigned to null, then set that up1087initializeVars();10881089// This is the start state1090mergeStateIntoBB(_basic_blocks[0]);10911092if (Assert.ASSERTS_ENABLED) {1093Assert.that(_basic_blocks[0].changed(), "we are not getting off the ground");1094}1095}10961097void interpAll () {1098boolean change = true;10991100while (change && !_got_error) {1101change = false;1102for (int i = 0; i < _bb_count && !_got_error; i++) {1103BasicBlock bb = _basic_blocks[i];1104if (bb.changed()) {1105if (_got_error) return;1106change = true;1107bb.setChanged(false);1108interpBB(bb);1109}1110}1111}1112}11131114//1115// Interpretation methods (secondary)1116//11171118/** Sets the current state to be the state after executing the1119current instruction, starting in the current state. */1120void interp1 (BytecodeStream itr) {1121if (DEBUG) {1122System.err.println(" - bci " + itr.bci() + " " + itr.code());1123printCurrentState(System.err, itr, false);1124}11251126// if (TraceNewOopMapGeneration) {1127// print_current_state(tty, itr, TraceNewOopMapGenerationDetailed);1128// }11291130// Should we report the results? Result is reported *before* the1131// instruction at the current bci is executed. However, not for1132// calls. For calls we do not want to include the arguments, so we1133// postpone the reporting until they have been popped (in method1134// ppl).1135if (_report_result == true) {1136switch(itr.code()) {1137case Bytecodes._invokevirtual:1138case Bytecodes._invokespecial:1139case Bytecodes._invokestatic:1140case Bytecodes._invokeinterface:1141case Bytecodes._invokedynamic:1142_itr_send = itr;1143_report_result_for_send = true;1144break;1145default:1146fillStackmapForOpcodes(itr, vars(), stack(), _stack_top);1147break;1148}1149}11501151// abstract interpretation of current opcode1152switch(itr.code()) {1153case Bytecodes._nop: break;1154case Bytecodes._goto: break;1155case Bytecodes._goto_w: break;1156case Bytecodes._iinc: break;1157case Bytecodes._return: doReturnMonitorCheck();1158break;11591160case Bytecodes._aconst_null:1161case Bytecodes._new: ppush1(CellTypeState.makeLineRef(itr.bci()));1162break;11631164case Bytecodes._iconst_m1:1165case Bytecodes._iconst_0:1166case Bytecodes._iconst_1:1167case Bytecodes._iconst_2:1168case Bytecodes._iconst_3:1169case Bytecodes._iconst_4:1170case Bytecodes._iconst_5:1171case Bytecodes._fconst_0:1172case Bytecodes._fconst_1:1173case Bytecodes._fconst_2:1174case Bytecodes._bipush:1175case Bytecodes._sipush: ppush1(valCTS); break;11761177case Bytecodes._lconst_0:1178case Bytecodes._lconst_1:1179case Bytecodes._dconst_0:1180case Bytecodes._dconst_1: ppush(vvCTS); break;11811182case Bytecodes._ldc2_w: ppush(vvCTS); break;11831184case Bytecodes._ldc: doLdc(itr.bci()); break;1185case Bytecodes._ldc_w: doLdc(itr.bci()); break;11861187case Bytecodes._iload:1188case Bytecodes._fload: ppload(vCTS, itr.getIndex()); break;11891190case Bytecodes._lload:1191case Bytecodes._dload: ppload(vvCTS,itr.getIndex()); break;11921193case Bytecodes._aload: ppload(rCTS, itr.getIndex()); break;11941195case Bytecodes._iload_0:1196case Bytecodes._fload_0: ppload(vCTS, 0); break;1197case Bytecodes._iload_1:1198case Bytecodes._fload_1: ppload(vCTS, 1); break;1199case Bytecodes._iload_2:1200case Bytecodes._fload_2: ppload(vCTS, 2); break;1201case Bytecodes._iload_3:1202case Bytecodes._fload_3: ppload(vCTS, 3); break;12031204case Bytecodes._lload_0:1205case Bytecodes._dload_0: ppload(vvCTS, 0); break;1206case Bytecodes._lload_1:1207case Bytecodes._dload_1: ppload(vvCTS, 1); break;1208case Bytecodes._lload_2:1209case Bytecodes._dload_2: ppload(vvCTS, 2); break;1210case Bytecodes._lload_3:1211case Bytecodes._dload_3: ppload(vvCTS, 3); break;12121213case Bytecodes._aload_0: ppload(rCTS, 0); break;1214case Bytecodes._aload_1: ppload(rCTS, 1); break;1215case Bytecodes._aload_2: ppload(rCTS, 2); break;1216case Bytecodes._aload_3: ppload(rCTS, 3); break;12171218case Bytecodes._iaload:1219case Bytecodes._faload:1220case Bytecodes._baload:1221case Bytecodes._caload:1222case Bytecodes._saload: pp(vrCTS, vCTS); break;12231224case Bytecodes._laload: pp(vrCTS, vvCTS); break;1225case Bytecodes._daload: pp(vrCTS, vvCTS); break;12261227case Bytecodes._aaload: ppNewRef(vrCTS, itr.bci()); break;12281229case Bytecodes._istore:1230case Bytecodes._fstore: ppstore(vCTS, itr.getIndex()); break;12311232case Bytecodes._lstore:1233case Bytecodes._dstore: ppstore(vvCTS, itr.getIndex()); break;12341235case Bytecodes._astore: doAstore(itr.getIndex()); break;12361237case Bytecodes._istore_0:1238case Bytecodes._fstore_0: ppstore(vCTS, 0); break;1239case Bytecodes._istore_1:1240case Bytecodes._fstore_1: ppstore(vCTS, 1); break;1241case Bytecodes._istore_2:1242case Bytecodes._fstore_2: ppstore(vCTS, 2); break;1243case Bytecodes._istore_3:1244case Bytecodes._fstore_3: ppstore(vCTS, 3); break;12451246case Bytecodes._lstore_0:1247case Bytecodes._dstore_0: ppstore(vvCTS, 0); break;1248case Bytecodes._lstore_1:1249case Bytecodes._dstore_1: ppstore(vvCTS, 1); break;1250case Bytecodes._lstore_2:1251case Bytecodes._dstore_2: ppstore(vvCTS, 2); break;1252case Bytecodes._lstore_3:1253case Bytecodes._dstore_3: ppstore(vvCTS, 3); break;12541255case Bytecodes._astore_0: doAstore(0); break;1256case Bytecodes._astore_1: doAstore(1); break;1257case Bytecodes._astore_2: doAstore(2); break;1258case Bytecodes._astore_3: doAstore(3); break;12591260case Bytecodes._iastore:1261case Bytecodes._fastore:1262case Bytecodes._bastore:1263case Bytecodes._castore:1264case Bytecodes._sastore: ppop(vvrCTS); break;1265case Bytecodes._lastore:1266case Bytecodes._dastore: ppop(vvvrCTS); break;1267case Bytecodes._aastore: ppop(rvrCTS); break;12681269case Bytecodes._pop: ppopAny(1); break;1270case Bytecodes._pop2: ppopAny(2); break;12711272case Bytecodes._dup: ppdupswap(1, "11"); break;1273case Bytecodes._dup_x1: ppdupswap(2, "121"); break;1274case Bytecodes._dup_x2: ppdupswap(3, "1321"); break;1275case Bytecodes._dup2: ppdupswap(2, "2121"); break;1276case Bytecodes._dup2_x1: ppdupswap(3, "21321"); break;1277case Bytecodes._dup2_x2: ppdupswap(4, "214321"); break;1278case Bytecodes._swap: ppdupswap(2, "12"); break;12791280case Bytecodes._iadd:1281case Bytecodes._fadd:1282case Bytecodes._isub:1283case Bytecodes._fsub:1284case Bytecodes._imul:1285case Bytecodes._fmul:1286case Bytecodes._idiv:1287case Bytecodes._fdiv:1288case Bytecodes._irem:1289case Bytecodes._frem:1290case Bytecodes._ishl:1291case Bytecodes._ishr:1292case Bytecodes._iushr:1293case Bytecodes._iand:1294case Bytecodes._ior:1295case Bytecodes._ixor:1296case Bytecodes._l2f:1297case Bytecodes._l2i:1298case Bytecodes._d2f:1299case Bytecodes._d2i:1300case Bytecodes._fcmpl:1301case Bytecodes._fcmpg: pp(vvCTS, vCTS); break;13021303case Bytecodes._ladd:1304case Bytecodes._dadd:1305case Bytecodes._lsub:1306case Bytecodes._dsub:1307case Bytecodes._lmul:1308case Bytecodes._dmul:1309case Bytecodes._ldiv:1310case Bytecodes._ddiv:1311case Bytecodes._lrem:1312case Bytecodes._drem:1313case Bytecodes._land:1314case Bytecodes._lor:1315case Bytecodes._lxor: pp(vvvvCTS, vvCTS); break;13161317case Bytecodes._ineg:1318case Bytecodes._fneg:1319case Bytecodes._i2f:1320case Bytecodes._f2i:1321case Bytecodes._i2c:1322case Bytecodes._i2s:1323case Bytecodes._i2b: pp(vCTS, vCTS); break;13241325case Bytecodes._lneg:1326case Bytecodes._dneg:1327case Bytecodes._l2d:1328case Bytecodes._d2l: pp(vvCTS, vvCTS); break;13291330case Bytecodes._lshl:1331case Bytecodes._lshr:1332case Bytecodes._lushr: pp(vvvCTS, vvCTS); break;13331334case Bytecodes._i2l:1335case Bytecodes._i2d:1336case Bytecodes._f2l:1337case Bytecodes._f2d: pp(vCTS, vvCTS); break;13381339case Bytecodes._lcmp: pp(vvvvCTS, vCTS); break;1340case Bytecodes._dcmpl:1341case Bytecodes._dcmpg: pp(vvvvCTS, vCTS); break;13421343case Bytecodes._ifeq:1344case Bytecodes._ifne:1345case Bytecodes._iflt:1346case Bytecodes._ifge:1347case Bytecodes._ifgt:1348case Bytecodes._ifle:1349case Bytecodes._tableswitch: ppop1(valCTS);1350break;1351case Bytecodes._ireturn:1352case Bytecodes._freturn: doReturnMonitorCheck();1353ppop1(valCTS);1354break;1355case Bytecodes._if_icmpeq:1356case Bytecodes._if_icmpne:1357case Bytecodes._if_icmplt:1358case Bytecodes._if_icmpge:1359case Bytecodes._if_icmpgt:1360case Bytecodes._if_icmple: ppop(vvCTS);1361break;13621363case Bytecodes._lreturn: doReturnMonitorCheck();1364ppop(vvCTS);1365break;13661367case Bytecodes._dreturn: doReturnMonitorCheck();1368ppop(vvCTS);1369break;13701371case Bytecodes._if_acmpeq:1372case Bytecodes._if_acmpne: ppop(rrCTS); break;13731374case Bytecodes._jsr: doJsr(itr.dest()); break;1375case Bytecodes._jsr_w: doJsr(itr.dest_w()); break;13761377case Bytecodes._getstatic: doField(true, true, itr.getIndexU2Cpcache(), itr.bci()); break;1378case Bytecodes._putstatic: doField(false, true, itr.getIndexU2Cpcache(), itr.bci()); break;1379case Bytecodes._getfield: doField(true, false, itr.getIndexU2Cpcache(), itr.bci()); break;1380case Bytecodes._putfield: doField(false, false, itr.getIndexU2Cpcache(), itr.bci()); break;13811382case Bytecodes._invokevirtual:1383case Bytecodes._invokespecial: doMethod(false, false, itr.getIndexU2Cpcache(), itr.bci()); break;1384case Bytecodes._invokestatic: doMethod(true, false, itr.getIndexU2Cpcache(), itr.bci()); break;1385case Bytecodes._invokedynamic: doMethod(true, false, itr.getIndexU4(), itr.bci()); break;1386case Bytecodes._invokeinterface: doMethod(false, true, itr.getIndexU2Cpcache(), itr.bci()); break;1387case Bytecodes._newarray:1388case Bytecodes._anewarray: ppNewRef(vCTS, itr.bci()); break;1389case Bytecodes._checkcast: doCheckcast(); break;1390case Bytecodes._arraylength:1391case Bytecodes._instanceof: pp(rCTS, vCTS); break;1392case Bytecodes._monitorenter: doMonitorenter(itr.bci()); break;1393case Bytecodes._monitorexit: doMonitorexit(itr.bci()); break;13941395case Bytecodes._athrow: // handled by do_exception_edge() BUT ...1396// vlh(apple): doExceptionEdge() does not get1397// called if method has no exception handlers1398if ((!_has_exceptions) && (_monitor_top > 0)) {1399_monitor_safe = false;1400}1401break;14021403case Bytecodes._areturn: doReturnMonitorCheck();1404ppop1(refCTS);1405break;1406case Bytecodes._ifnull:1407case Bytecodes._ifnonnull: ppop1(refCTS); break;1408case Bytecodes._multianewarray: doMultianewarray(itr.codeAt(itr.bci() + 3), itr.bci()); break;14091410case Bytecodes._wide: throw new RuntimeException("Iterator should skip this bytecode");1411case Bytecodes._ret: break;14121413// Java opcodes1414case Bytecodes._fast_aaccess_0: ppNewRef(rCTS, itr.bci()); break; // Pair bytecode for (aload_0, _fast_agetfield)14151416case Bytecodes._fast_iaccess_0: ppush1(valCTS); break; // Pair bytecode for (aload_0, _fast_igetfield)14171418case Bytecodes._fast_igetfield: pp(rCTS, vCTS); break;14191420case Bytecodes._fast_agetfield: ppNewRef(rCTS, itr.bci()); break;14211422case Bytecodes._fast_aload_0: ppload(rCTS, 0); break;14231424case Bytecodes._lookupswitch:1425case Bytecodes._fast_linearswitch:1426case Bytecodes._fast_binaryswitch: ppop1(valCTS); break;14271428default:1429throw new RuntimeException("unexpected opcode: " + itr.code());1430}1431}14321433void doExceptionEdge (BytecodeStream itr) {1434// Only check exception edge, if bytecode can trap1435if (!Bytecodes.canTrap(itr.code())) return;1436switch (itr.code()) {1437case Bytecodes._aload_0:1438case Bytecodes._fast_aload_0:1439// These bytecodes can trap for rewriting. We need to assume that1440// they do not throw exceptions to make the monitor analysis work.1441return;14421443case Bytecodes._ireturn:1444case Bytecodes._lreturn:1445case Bytecodes._freturn:1446case Bytecodes._dreturn:1447case Bytecodes._areturn:1448case Bytecodes._return:1449// If the monitor stack height is not zero when we leave the method,1450// then we are either exiting with a non-empty stack or we have1451// found monitor trouble earlier in our analysis. In either case,1452// assume an exception could be taken here.1453if (_monitor_top == 0) {1454return;1455}1456break;14571458case Bytecodes._monitorexit:1459// If the monitor stack height is bad_monitors, then we have detected a1460// monitor matching problem earlier in the analysis. If the1461// monitor stack height is 0, we are about to pop a monitor1462// off of an empty stack. In either case, the bytecode1463// could throw an exception.1464if (_monitor_top != bad_monitors && _monitor_top != 0) {1465return;1466}1467break;1468}14691470if (_has_exceptions) {1471int bci = itr.bci();1472ExceptionTableElement[] exct = method().getExceptionTable();1473for(int i = 0; i< exct.length; i++) {1474int start_pc = exct[i].getStartPC();1475int end_pc = exct[i].getEndPC();1476int handler_pc = exct[i].getHandlerPC();1477int catch_type = exct[i].getCatchTypeIndex();14781479if (start_pc <= bci && bci < end_pc) {1480BasicBlock excBB = getBasicBlockAt(handler_pc);1481CellTypeStateList excStk = excBB.stack();1482CellTypeStateList cOpStck = stack();1483CellTypeState cOpStck_0 = cOpStck.get(0).copy();1484int cOpStackTop = _stack_top;14851486// Exception stacks are always the same.1487if (Assert.ASSERTS_ENABLED) {1488Assert.that(method().getMaxStack() > 0, "sanity check");1489}14901491// We remembered the size and first element of "cOpStck"1492// above; now we temporarily set them to the appropriate1493// values for an exception handler.1494cOpStck.get(0).set(CellTypeState.makeSlotRef(_max_locals));1495_stack_top = 1;14961497mergeStateIntoBB(excBB);14981499// Now undo the temporary change.1500cOpStck.get(0).set(cOpStck_0);1501_stack_top = cOpStackTop;15021503// If this is a "catch all" handler, then we do not need to1504// consider any additional handlers.1505if (catch_type == 0) {1506return;1507}1508}1509}1510}15111512// It is possible that none of the exception handlers would have caught1513// the exception. In this case, we will exit the method. We must1514// ensure that the monitor stack is empty in this case.1515if (_monitor_top == 0) {1516return;1517}15181519// We pessimistically assume that this exception can escape the1520// method. (It is possible that it will always be caught, but1521// we don't care to analyse the types of the catch clauses.)15221523// We don't set _monitor_top to bad_monitors because there are no successors1524// to this exceptional exit.15251526if (TraceMonitorMismatch && _monitor_safe) {1527// We check _monitor_safe so that we only report the first mismatched1528// exceptional exit.1529reportMonitorMismatch("non-empty monitor stack at exceptional exit");1530}1531_monitor_safe = false;1532}15331534void checkType (CellTypeState expected, CellTypeState actual) {1535if (!expected.equalKind(actual)) {1536throw new RuntimeException("wrong type on stack (found: " +1537actual.toChar() + " expected: " +1538expected.toChar() + ")");1539}1540}15411542void ppstore (CellTypeState[] in, int loc_no) {1543for (int i = 0; i < in.length && !in[i].equal(CellTypeState.bottom); i++) {1544CellTypeState expected = in[i];1545CellTypeState actual = pop();1546checkType(expected, actual);1547if (Assert.ASSERTS_ENABLED) {1548Assert.that(loc_no >= 0, "sanity check");1549}1550setVar(loc_no++, actual);1551}1552}15531554void ppload (CellTypeState[] out, int loc_no) {1555for (int i = 0; i < out.length && !out[i].equal(CellTypeState.bottom); i++) {1556CellTypeState out1 = out[i];1557CellTypeState vcts = getVar(loc_no);1558if (Assert.ASSERTS_ENABLED) {1559Assert.that(out1.canBeReference() || out1.canBeValue(),1560"can only load refs. and values.");1561}1562if (out1.isReference()) {1563if (Assert.ASSERTS_ENABLED) {1564Assert.that(loc_no>=0, "sanity check");1565}1566if (!vcts.isReference()) {1567// We were asked to push a reference, but the type of the1568// variable can be something else1569_conflict = true;1570if (vcts.canBeUninit()) {1571// It is a ref-uninit conflict (at least). If there are other1572// problems, we'll get them in the next round1573addToRefInitSet(loc_no);1574vcts = out1;1575} else {1576// It wasn't a ref-uninit conflict. So must be a1577// ref-val or ref-pc conflict. Split the variable.1578recordRefvalConflict(loc_no);1579vcts = out1;1580}1581push(out1); // recover...1582} else {1583push(vcts); // preserve reference.1584}1585// Otherwise it is a conflict, but one that verification would1586// have caught if illegal. In particular, it can't be a topCTS1587// resulting from mergeing two difference pcCTS's since the verifier1588// would have rejected any use of such a merge.1589} else {1590push(out1); // handle val/init conflict1591}1592loc_no++;1593}1594}15951596void ppush1 (CellTypeState in) {1597if (Assert.ASSERTS_ENABLED) {1598Assert.that(in.isReference() | in.isValue(), "sanity check");1599}1600if (DEBUG) {1601System.err.println(" - pushing " + in.toChar());1602}1603push(in);1604}16051606void ppush (CellTypeState[] in) {1607for (int i = 0; i < in.length && !in[i].equal(CellTypeState.bottom); i++) {1608ppush1(in[i]);1609}1610}16111612void ppush (CellTypeStateList in) {1613for (int i = 0; i < in.size() && !in.get(i).equal(CellTypeState.bottom); i++) {1614ppush1(in.get(i));1615}1616}16171618void ppop1 (CellTypeState out) {1619CellTypeState actual = pop();1620if (DEBUG) {1621System.err.println(" - popping " + actual.toChar() + ", expecting " + out.toChar());1622}1623checkType(out, actual);1624}16251626void ppop (CellTypeState[] out) {1627for (int i = 0; i < out.length && !out[i].equal(CellTypeState.bottom); i++) {1628ppop1(out[i]);1629}1630}16311632void ppopAny (int poplen) {1633if (_stack_top >= poplen) {1634_stack_top -= poplen;1635} else {1636throw new RuntimeException("stack underflow");1637}1638}16391640void pp (CellTypeState[] in, CellTypeState[] out) {1641ppop(in);1642ppush(out);1643}16441645void ppNewRef (CellTypeState[] in, int bci) {1646ppop(in);1647ppush1(CellTypeState.makeLineRef(bci));1648}16491650void ppdupswap (int poplen, String out) {1651CellTypeState[] actual = new CellTypeState[5];1652Assert.that(poplen < 5, "this must be less than length of actual vector");16531654// pop all arguments1655for(int i = 0; i < poplen; i++) actual[i] = pop();16561657// put them back1658for (int i = 0; i < out.length(); i++) {1659char push_ch = out.charAt(i);1660int idx = push_ch - '1';1661if (Assert.ASSERTS_ENABLED) {1662Assert.that(idx >= 0 && idx < poplen, "wrong arguments");1663}1664push(actual[idx]);1665}1666}16671668void doLdc (int bci) {1669BytecodeLoadConstant ldc = BytecodeLoadConstant.at(_method, bci);1670ConstantPool cp = method().getConstants();1671BasicType bt = ldc.resultType();1672CellTypeState cts = (bt == BasicType.T_OBJECT) ? CellTypeState.makeLineRef(bci) : valCTS;1673ppush1(cts);1674}16751676void doAstore (int idx) {1677CellTypeState r_or_p = pop();1678if (!r_or_p.isAddress() && !r_or_p.isReference()) {1679// We actually expected ref or pc, but we only report that we expected a ref. It does not1680// really matter (at least for now)1681throw new RuntimeException("wrong type on stack (found: " +1682r_or_p.toChar() + ", expected: {pr})");1683}1684setVar(idx, r_or_p);1685}16861687void doJsr (int targBCI) {1688push(CellTypeState.makeAddr(targBCI));1689}16901691void doField (boolean is_get, boolean is_static, int idx, int bci) {1692// Dig up signature for field in constant pool1693ConstantPool cp = method().getConstants();1694int nameAndTypeIdx = cp.getNameAndTypeRefIndexAt(idx);1695int signatureIdx = cp.getSignatureRefIndexAt(nameAndTypeIdx);1696Symbol signature = cp.getSymbolAt(signatureIdx);16971698if (DEBUG) {1699System.err.println("doField: signature = " + signature.asString() + ", idx = " + idx +1700", nameAndTypeIdx = " + nameAndTypeIdx + ", signatureIdx = " + signatureIdx + ", bci = " + bci);1701}17021703// Parse signature (espcially simple for fields)1704// The signature is UFT8 encoded, but the first char is always ASCII for signatures.1705char sigch = (char) signature.getByteAt(0);1706CellTypeState[] temp = new CellTypeState[4];1707CellTypeState[] eff = sigcharToEffect(sigch, bci, temp);17081709CellTypeState[] in = new CellTypeState[4];1710CellTypeState[] out;1711int i = 0;17121713if (is_get) {1714out = eff;1715} else {1716out = epsilonCTS;1717i = copyCTS(in, eff);1718}1719if (!is_static) in[i++] = CellTypeState.ref;1720in[i] = CellTypeState.bottom;1721if (Assert.ASSERTS_ENABLED) {1722Assert.that(i<=3, "sanity check");1723}1724pp(in, out);1725}17261727void doMethod (boolean is_static, boolean is_interface, int idx, int bci) {1728// Dig up signature for field in constant pool1729ConstantPool cp = _method.getConstants();1730Symbol signature = cp.getSignatureRefAt(idx);17311732// Parse method signature1733CellTypeStateList out = new CellTypeStateList(4);1734CellTypeStateList in = new CellTypeStateList(MAXARGSIZE+1); // Includes result1735ComputeCallStack cse = new ComputeCallStack(signature);17361737// Compute return type1738int res_length = cse.computeForReturntype(out);17391740// Temporary hack.1741if (out.get(0).equal(CellTypeState.ref) && out.get(1).equal(CellTypeState.bottom)) {1742out.get(0).set(CellTypeState.makeLineRef(bci));1743}17441745if (Assert.ASSERTS_ENABLED) {1746Assert.that(res_length<=4, "max value should be vv");1747}17481749// Compute arguments1750int arg_length = cse.computeForParameters(is_static, in);1751if (Assert.ASSERTS_ENABLED) {1752Assert.that(arg_length<=MAXARGSIZE, "too many locals");1753}17541755// Pop arguments1756for (int i = arg_length - 1; i >= 0; i--) ppop1(in.get(i));// Do args in reverse order.17571758// Report results1759if (_report_result_for_send == true) {1760fillStackmapForOpcodes(_itr_send, vars(), stack(), _stack_top);1761_report_result_for_send = false;1762}17631764// Push return address1765ppush(out);1766}17671768void doMultianewarray (int dims, int bci) {1769if (Assert.ASSERTS_ENABLED) {1770Assert.that(dims >= 1, "sanity check");1771}1772for(int i = dims -1; i >=0; i--) {1773ppop1(valCTS);1774}1775ppush1(CellTypeState.makeLineRef(bci));1776}17771778void doMonitorenter (int bci) {1779CellTypeState actual = pop();1780if (_monitor_top == bad_monitors) {1781return;1782}17831784// Bail out when we get repeated locks on an identical monitor. This case1785// isn't too hard to handle and can be made to work if supporting nested1786// redundant synchronized statements becomes a priority.1787//1788// See also "Note" in do_monitorexit(), below.1789if (actual.isLockReference()) {1790_monitor_top = bad_monitors;1791_monitor_safe = false;17921793if (TraceMonitorMismatch) {1794reportMonitorMismatch("nested redundant lock -- bailout...");1795}1796return;1797}17981799CellTypeState lock = CellTypeState.makeLockRef(bci);1800checkType(refCTS, actual);1801if (!actual.isInfoTop()) {1802replaceAllCTSMatches(actual, lock);1803monitorPush(lock);1804}1805}18061807void doMonitorexit (int bci) {1808CellTypeState actual = pop();1809if (_monitor_top == bad_monitors) {1810return;1811}1812checkType(refCTS, actual);1813CellTypeState expected = monitorPop();1814if (!actual.isLockReference() || !expected.equal(actual)) {1815// The monitor we are exiting is not verifiably the one1816// on the top of our monitor stack. This causes a monitor1817// mismatch.1818_monitor_top = bad_monitors;1819_monitor_safe = false;18201821// We need to mark this basic block as changed so that1822// this monitorexit will be visited again. We need to1823// do this to ensure that we have accounted for the1824// possibility that this bytecode will throw an1825// exception.1826BasicBlock bb = getBasicBlockContaining(bci);1827bb.setChanged(true);1828bb._monitor_top = bad_monitors;18291830if (TraceMonitorMismatch) {1831reportMonitorMismatch("improper monitor pair");1832}1833} else {1834// This code is a fix for the case where we have repeated1835// locking of the same object in straightline code. We clear1836// out the lock when it is popped from the monitor stack1837// and replace it with an unobtrusive reference value that can1838// be locked again.1839//1840// Note: when generateOopMap is fixed to properly handle repeated,1841// nested, redundant locks on the same object, then this1842// fix will need to be removed at that time.1843replaceAllCTSMatches(actual, CellTypeState.makeLineRef(bci));1844}18451846if (_report_for_exit_bci == bci) {1847_matching_enter_bci = expected.getMonitorSource();1848}1849}18501851void doReturnMonitorCheck () {1852if (_monitor_top > 0) {1853// The monitor stack must be empty when we leave the method1854// for the monitors to be properly matched.1855_monitor_safe = false;18561857// Since there are no successors to the *return bytecode, it1858// isn't necessary to set _monitor_top to bad_monitors.18591860if (TraceMonitorMismatch) {1861reportMonitorMismatch("non-empty monitor stack at return");1862}1863}1864}18651866void doCheckcast () {1867CellTypeState actual = pop();1868checkType(refCTS, actual);1869push(actual);1870}18711872CellTypeState[] sigcharToEffect (char sigch, int bci, CellTypeState[] out) {1873// Object and array1874if (sigch=='L' || sigch=='[') {1875out[0] = CellTypeState.makeLineRef(bci);1876out[1] = CellTypeState.bottom;1877return out;1878}1879if (sigch == 'J' || sigch == 'D' ) return vvCTS; // Long and Double1880if (sigch == 'V' ) return epsilonCTS; // Void1881return vCTS; // Otherwise1882}18831884// Copies (optionally bottom/zero terminated) CTS string from "src" into "dst".1885// Does NOT terminate with a bottom. Returns the number of cells copied.1886int copyCTS (CellTypeState[] dst, CellTypeState[] src) {1887int idx = 0;1888for (; idx < src.length && !src[idx].isBottom(); idx++) {1889dst[idx] = src[idx];1890}1891return idx;1892}18931894// Create result set1895boolean _report_result;1896boolean _report_result_for_send; // Unfortunatly, stackmaps for sends are special, so we need some extra1897BytecodeStream _itr_send; // variables to handle them properly.18981899void reportResult () {1900// if (TraceNewOopMapGeneration) tty.print_cr("Report result pass");19011902// We now want to report the result of the parse1903_report_result = true;19041905// Prolog code1906fillStackmapProlog(_gc_points);19071908// Mark everything changed, then do one interpretation pass.1909for (int i = 0; i<_bb_count; i++) {1910if (_basic_blocks[i].isReachable()) {1911_basic_blocks[i].setChanged(true);1912interpBB(_basic_blocks[i]);1913}1914}19151916// Note: Since we are skipping dead-code when we are reporting results, then1917// the no. of encountered gc-points might be fewer than the previously number1918// we have counted. (dead-code is a pain - it should be removed before we get here)1919fillStackmapEpilog();19201921// Report initvars1922fillInitVars(_init_vars);19231924_report_result = false;1925}19261927// Initvars1928List<Integer> _init_vars;19291930void initializeVars () {1931for (int k = 0; k < _init_vars.size(); k++)1932_state.get((_init_vars.get(k)).intValue()).set(CellTypeState.makeSlotRef(k));1933}19341935void addToRefInitSet (int localNo) {1936// if (TraceNewOopMapGeneration)1937// tty.print_cr("Added init vars: %d", localNo);19381939Integer local = localNo;19401941// Is it already in the set?1942if (_init_vars.contains(local))1943return;19441945_init_vars.add(local);1946}19471948// Conflicts rewrite logic1949boolean _conflict; // True, if a conflict occured during interpretation1950int _nof_refval_conflicts; // No. of conflicts that require rewrites1951int[] _new_var_map;19521953void recordRefvalConflict (int varNo) {1954if (Assert.ASSERTS_ENABLED) {1955Assert.that(varNo>=0 && varNo< _max_locals, "index out of range");1956}19571958if (TraceOopMapRewrites) {1959System.err.println("### Conflict detected (local no: " + varNo + ")");1960}19611962if (_new_var_map == null) {1963_new_var_map = new int[_max_locals];1964for (int k = 0; k < _max_locals; k++) _new_var_map[k] = k;1965}19661967if ( _new_var_map[varNo] == varNo) {1968// Check if max. number of locals has been reached1969if (_max_locals + _nof_refval_conflicts >= MAX_LOCAL_VARS) {1970throw new RuntimeException("Rewriting exceeded local variable limit");1971}1972_new_var_map[varNo] = _max_locals + _nof_refval_conflicts;1973_nof_refval_conflicts++;1974}1975}19761977void rewriteRefvalConflicts () {1978if (_nof_refval_conflicts > 0) {1979if (VM.getVM().isDebugging()) {1980throw new RuntimeException("Should not reach here (method rewriting should have been done by the VM already)");1981} else {1982throw new RuntimeException("Method rewriting not yet implemented in Java");1983}1984}1985}1986// Rewriting-related routines are not needed here1987// void rewrite_refval_conflict (int from, int to);1988// bool rewrite_refval_conflict_inst (BytecodeStream *i, int from, int to);1989// bool rewrite_load_or_store (BytecodeStream *i, Bytecodes.Code bc, Bytecodes.Code bc0, unsigned int varNo);19901991// bool expand_current_instr (int bci, int ilen, int newIlen, u_char inst_buffer[]);1992// bool is_astore (BytecodeStream *itr, int *index);1993// bool is_aload (BytecodeStream *itr, int *index);19941995// List of bci's where a return address is on top of the stack1996// GrowableArray<intptr_t> *_ret_adr_tos;19971998// bool stack_top_holds_ret_addr (int bci);1999// void compute_ret_adr_at_TOS ();2000// void update_ret_adr_at_TOS (int bci, int delta);20012002String stateVecToString (CellTypeStateList vec, int len) {2003for (int i = 0; i < len; i++) {2004_state_vec_buf[i] = vec.get(i).toChar();2005}2006return new String(_state_vec_buf, 0, len);2007}20082009// Helper method. Can be used in subclasses to fx. calculate gc_points. If the current instuction2010// is a control transfer, then calls the jmpFct all possible destinations.2011void retJumpTargetsDo (BytecodeStream bcs, JumpClosure closure, int varNo, int[] data) {2012CellTypeState ra = vars().get(varNo);2013if (!ra.isGoodAddress()) {2014throw new RuntimeException("ret returns from two jsr subroutines?");2015}2016int target = ra.getInfo();20172018RetTableEntry rtEnt = _rt.findJsrsForTarget(target);2019int bci = bcs.bci();2020for (int i = 0; i < rtEnt.nofJsrs(); i++) {2021int target_bci = rtEnt.jsrs(i);2022// Make sure a jrtRet does not set the changed bit for dead basicblock.2023BasicBlock jsr_bb = getBasicBlockContaining(target_bci - 1);2024if (Assert.ASSERTS_ENABLED) {2025BasicBlock target_bb = _basic_blocks[1 + bbIndex(jsr_bb)];2026Assert.that(target_bb == getBasicBlockAt(target_bci), "wrong calc. of successor basicblock");2027}2028boolean alive = jsr_bb.isAlive();2029// if (TraceNewOopMapGeneration) {2030// tty.print("pc = %d, ret . %d alive: %s\n", bci, target_bci, alive ? "true" : "false");2031// }2032if (alive) {2033closure.process(this, target_bci, data);2034}2035}2036}20372038/** If the current instruction in "c" has no effect on control flow,2039returns "true". Otherwise, calls "closure.process()" one or2040more times, with "c", an appropriate "pcDelta", and "data" as2041arguments, then returns "false". There is one exception: if the2042current instruction is a "ret", returns "false" without calling2043"jmpFct". Arrangements for tracking the control flow of a "ret"2044must be made externally. */2045boolean jumpTargetsDo (BytecodeStream bcs, JumpClosure closure, int[] data) {2046int bci = bcs.bci();20472048switch (bcs.code()) {2049case Bytecodes._ifeq:2050case Bytecodes._ifne:2051case Bytecodes._iflt:2052case Bytecodes._ifge:2053case Bytecodes._ifgt:2054case Bytecodes._ifle:2055case Bytecodes._if_icmpeq:2056case Bytecodes._if_icmpne:2057case Bytecodes._if_icmplt:2058case Bytecodes._if_icmpge:2059case Bytecodes._if_icmpgt:2060case Bytecodes._if_icmple:2061case Bytecodes._if_acmpeq:2062case Bytecodes._if_acmpne:2063case Bytecodes._ifnull:2064case Bytecodes._ifnonnull:2065closure.process(this, bcs.dest(), data);2066closure.process(this, bci + 3, data);2067break;20682069case Bytecodes._goto:2070closure.process(this, bcs.dest(), data);2071break;2072case Bytecodes._goto_w:2073closure.process(this, bcs.dest_w(), data);2074break;2075case Bytecodes._tableswitch:2076{2077BytecodeTableswitch tableswitch = BytecodeTableswitch.at(bcs);2078int len = tableswitch.length();20792080closure.process(this, bci + tableswitch.defaultOffset(), data); /* Default. jump address */2081while (--len >= 0) {2082closure.process(this, bci + tableswitch.destOffsetAt(len), data);2083}2084break;2085}20862087case Bytecodes._fast_linearswitch: // Java opcodes2088case Bytecodes._fast_binaryswitch: // get_int_table handles conversions2089case Bytecodes._lookupswitch:2090{2091BytecodeLookupswitch lookupswitch = BytecodeLookupswitch.at(bcs);2092int npairs = lookupswitch.numberOfPairs();2093closure.process(this, bci + lookupswitch.defaultOffset(), data); /* Default. */2094while(--npairs >= 0) {2095LookupswitchPair pair = lookupswitch.pairAt(npairs);2096closure.process(this, bci + pair.offset(), data);2097}2098break;2099}2100case Bytecodes._jsr:2101Assert.that(bcs.isWide()==false, "sanity check");2102closure.process(this, bcs.dest(), data);2103break;2104case Bytecodes._jsr_w:2105closure.process(this, bcs.dest_w(), data);2106break;2107case Bytecodes._wide:2108throw new RuntimeException("Should not reach here");2109case Bytecodes._athrow:2110case Bytecodes._ireturn:2111case Bytecodes._lreturn:2112case Bytecodes._freturn:2113case Bytecodes._dreturn:2114case Bytecodes._areturn:2115case Bytecodes._return:2116case Bytecodes._ret:2117break;2118default:2119return true;2120}2121return false;2122}21232124// Monitor matching2125// int fill_out_arrays (int *enter, int *exit, int max);21262127// friend class RelocCallback;21282129//----------------------------------------------------------------------2130// Public routines for GenerateOopMap2131//2132public GenerateOopMap(Method method) {2133// We have to initialize all variables here, that can be queried direcly2134_method = method;2135_max_locals=0;2136_init_vars = null;2137_rt = new RetTable();2138}213921402141// Compute the map.2142public void computeMap() {2143if (DEBUG) {2144System.err.println("*** GenerateOopMap: computing for " +2145method().getMethodHolder().getName().asString() + "." +2146method().getName().asString() +2147method().getSignature().asString());2148}21492150// Initialize values2151_got_error = false;2152_conflict = false;2153_max_locals = (int) method().getMaxLocals();2154_max_stack = (int) method().getMaxStack();2155_has_exceptions = (method().hasExceptionTable());2156_nof_refval_conflicts = 0;2157_init_vars = new ArrayList<>(5); // There are seldom more than 5 init_vars2158_report_result = false;2159_report_result_for_send = false;2160_report_for_exit_bci = -1;2161_new_var_map = null;2162// _ret_adr_tos = new GrowableArray<intptr_t>(5); // 5 seems like a good number;2163// _did_rewriting = false;2164// _did_relocation = false;21652166// FIXME: remove2167/*2168if (TraceNewOopMapGeneration) {2169tty.print("Method name: %s\n", method().name().as_C_string());2170if (Verbose) {2171_method.print_codes();2172tty.print_cr("Exception table:");2173typeArrayOop excps = method().exception_table();2174for(int i = 0; i < excps.length(); i += 4) {2175tty.print_cr("[%d - %d] . %d", excps.int_at(i + 0), excps.int_at(i + 1), excps.int_at(i + 2));2176}2177}2178}2179*/21802181// if no code - do nothing2182// compiler needs info2183if (method().getCodeSize() == 0 || _max_locals + method().getMaxStack() == 0) {2184fillStackmapProlog(0);2185fillStackmapEpilog();2186return;2187}2188// Step 1: Compute all jump targets and their return value2189if (!_got_error)2190_rt.computeRetTable(_method);21912192// Step 2: Find all basic blocks and count GC points2193if (!_got_error)2194markBBHeadersAndCountGCPoints();21952196// Step 3: Calculate stack maps2197if (!_got_error)2198doInterpretation();21992200// Step 4:Return results2201if (!_got_error && reportResults())2202reportResult();22032204if (_got_error) {2205// We could expand this code to throw somekind of exception (e.g., VerifyException). However,2206// an exception thrown in this part of the code is likly to mean that we are executing some2207// illegal bytecodes (that the verifier should have caught if turned on), so we will just exit2208// with a fatal.2209throw new RuntimeException("Illegal bytecode sequence encountered while generating interpreter pointer maps - method should be rejected by verifier.");2210}2211}22122213// Do a callback on fill_stackmap_for_opcodes for basicblock containing bci2214public void resultForBasicblock(int bci) {2215// FIXME: remove2216// if (TraceNewOopMapGeneration) tty.print_cr("Report result pass for basicblock");22172218// We now want to report the result of the parse2219_report_result = true;22202221// Find basicblock and report results2222BasicBlock bb = getBasicBlockContaining(bci);2223if (Assert.ASSERTS_ENABLED) {2224Assert.that(bb.isReachable(), "getting result from unreachable basicblock");2225}2226bb.setChanged(true);2227interpBB(bb);2228}22292230// Query2231public int maxLocals() { return _max_locals; }2232public Method method() { return _method; }22332234// bool did_rewriting() { return _did_rewriting; }2235// bool did_relocation() { return _did_relocation; }22362237// static void print_time();22382239// Monitor query2240public boolean monitorSafe() { return _monitor_safe; }2241// Takes as input the bci of a monitorexit bytecode.2242// Returns the bci of the corresponding monitorenter.2243// Can only be called safely after computeMap() is run.2244public int getMonitorMatch(int bci) {2245if (Assert.ASSERTS_ENABLED) {2246Assert.that(_monitor_safe, "Attempt to match monitor in broken code.");2247}22482249// if (TraceNewOopMapGeneration)2250// tty.print_cr("Report monitor match for bci : %d", bci);22512252// We want to report the line number of the monitorenter.2253_report_for_exit_bci = bci;2254_matching_enter_bci = -1;22552256// Find basicblock and report results2257BasicBlock bb = getBasicBlockContaining(bci);2258if (bb.isReachable()) {2259bb.setChanged(true);2260interpBB(bb);2261_report_for_exit_bci = -1;2262if (Assert.ASSERTS_ENABLED) {2263Assert.that(_matching_enter_bci != -1, "monitor matching invariant");2264}2265}2266return _matching_enter_bci;2267}22682269// Returns a Arena allocated object that contains pairing info.2270// MonitorPairs* get_pairing(Arena *arena);22712272// copies monitor pairing info into area; area_count specifies maximum2273// possible number of monitor pairs2274// int copy_pairing(int pair_count, MonitorPairs* pairs);22752276private int bbIndex(BasicBlock bb) {2277for (int i = 0; i < _basic_blocks.length; i++) {2278if (_basic_blocks[i] == bb) {2279return i;2280}2281}2282throw new RuntimeException("Should have found block");2283}22842285//----------------------------------------------------------------------2286// Specialization methods. Intended use:2287// - possibleGCPoint must return true for every bci for which the2288// stackmaps must be returned2289// - fillStackmapProlog is called just before the result is2290// reported. The arguments tells the estimated number of gc points2291// - fillStackmapForOpcodes is called once for each bytecode index2292// in order (0...code_length-1)2293// - fillStackmapEpilog is called after all results has been2294// reported. Note: Since the algorithm does not report stackmaps for2295// deadcode, fewer gc_points might have been encounted than assumed2296// during the epilog. It is the responsibility of the subclass to2297// count the correct number.2298// - fillInitVars are called once with the result of the init_vars2299// computation2300//2301// All these methods are used during a call to computeMap. Note:2302// None of the return results are valid after computeMap returns,2303// since all values are allocated as resource objects.2304//2305// All virtual method must be implemented in subclasses2306public boolean allowRewrites () { return false; }2307public boolean reportResults () { return true; }2308public boolean reportInitVars () { return true; }2309public boolean possibleGCPoint (BytecodeStream bcs) { throw new RuntimeException("ShouldNotReachHere"); }2310public void fillStackmapProlog (int nofGCPoints) { throw new RuntimeException("ShouldNotReachHere"); }2311public void fillStackmapEpilog () { throw new RuntimeException("ShouldNotReachHere"); }2312public void fillStackmapForOpcodes (BytecodeStream bcs,2313CellTypeStateList vars,2314CellTypeStateList stack,2315int stackTop) { throw new RuntimeException("ShouldNotReachHere"); }2316public void fillInitVars (List<Integer> init_vars) { throw new RuntimeException("ShouldNotReachHere"); }2317}231823192320