0N/A/*
4565N/A * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
1472N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1472N/A * or visit www.oracle.com if you need additional information or have any
1472N/A * questions.
0N/A *
0N/A */
0N/A
1879N/A#include "precompiled.hpp"
1879N/A#include "interpreter/bytecodeStream.hpp"
1879N/A#include "oops/generateOopMap.hpp"
1879N/A#include "oops/oop.inline.hpp"
2062N/A#include "oops/symbol.hpp"
1879N/A#include "runtime/handles.inline.hpp"
1879N/A#include "runtime/java.hpp"
1879N/A#include "runtime/relocator.hpp"
1879N/A#include "utilities/bitMap.inline.hpp"
3932N/A#include "prims/methodHandles.hpp"
1879N/A
0N/A//
0N/A//
0N/A// Compute stack layouts for each instruction in method.
0N/A//
0N/A// Problems:
0N/A// - What to do about jsr with different types of local vars?
0N/A// Need maps that are conditional on jsr path?
0N/A// - Jsr and exceptions should be done more efficiently (the retAddr stuff)
0N/A//
0N/A// Alternative:
0N/A// - Could extend verifier to provide this information.
0N/A// For: one fewer abstract interpreter to maintain. Against: the verifier
0N/A// solves a bigger problem so slower (undesirable to force verification of
0N/A// everything?).
0N/A//
0N/A// Algorithm:
0N/A// Partition bytecodes into basic blocks
0N/A// For each basic block: store entry state (vars, stack). For instructions
0N/A// inside basic blocks we do not store any state (instead we recompute it
0N/A// from state produced by previous instruction).
0N/A//
0N/A// Perform abstract interpretation of bytecodes over this lattice:
0N/A//
0N/A// _--'#'--_
0N/A// / / \ \
0N/A// / / \ \
0N/A// / | | \
0N/A// 'r' 'v' 'p' ' '
0N/A// \ | | /
0N/A// \ \ / /
0N/A// \ \ / /
0N/A// -- '@' --
0N/A//
0N/A// '#' top, result of conflict merge
0N/A// 'r' reference type
0N/A// 'v' value type
0N/A// 'p' pc type for jsr/ret
0N/A// ' ' uninitialized; never occurs on operand stack in Java
0N/A// '@' bottom/unexecuted; initial state each bytecode.
0N/A//
0N/A// Basic block headers are the only merge points. We use this iteration to
0N/A// compute the information:
0N/A//
0N/A// find basic blocks;
0N/A// initialize them with uninitialized state;
0N/A// initialize first BB according to method signature;
0N/A// mark first BB changed
0N/A// while (some BB is changed) do {
0N/A// perform abstract interpration of all bytecodes in BB;
0N/A// merge exit state of BB into entry state of all successor BBs,
0N/A// noting if any of these change;
0N/A// }
0N/A//
0N/A// One additional complication is necessary. The jsr instruction pushes
0N/A// a return PC on the stack (a 'p' type in the abstract interpretation).
0N/A// To be able to process "ret" bytecodes, we keep track of these return
0N/A// PC's in a 'retAddrs' structure in abstract interpreter context (when
0N/A// processing a "ret" bytecodes, it is not sufficient to know that it gets
0N/A// an argument of the right type 'p'; we need to know which address it
0N/A// returns to).
0N/A//
0N/A// (Note this comment is borrowed form the original author of the algorithm)
0N/A
0N/A// ComputeCallStack
0N/A//
0N/A// Specialization of SignatureIterator - compute the effects of a call
0N/A//
0N/Aclass ComputeCallStack : public SignatureIterator {
0N/A CellTypeState *_effect;
0N/A int _idx;
0N/A
0N/A void setup();
0N/A void set(CellTypeState state) { _effect[_idx++] = state; }
0N/A int length() { return _idx; };
0N/A
0N/A virtual void do_bool () { set(CellTypeState::value); };
0N/A virtual void do_char () { set(CellTypeState::value); };
0N/A virtual void do_float () { set(CellTypeState::value); };
0N/A virtual void do_byte () { set(CellTypeState::value); };
0N/A virtual void do_short () { set(CellTypeState::value); };
0N/A virtual void do_int () { set(CellTypeState::value); };
0N/A virtual void do_void () { set(CellTypeState::bottom);};
0N/A virtual void do_object(int begin, int end) { set(CellTypeState::ref); };
0N/A virtual void do_array (int begin, int end) { set(CellTypeState::ref); };
0N/A
0N/A void do_double() { set(CellTypeState::value);
0N/A set(CellTypeState::value); }
0N/A void do_long () { set(CellTypeState::value);
0N/A set(CellTypeState::value); }
0N/A
0N/Apublic:
2062N/A ComputeCallStack(Symbol* signature) : SignatureIterator(signature) {};
0N/A
0N/A // Compute methods
0N/A int compute_for_parameters(bool is_static, CellTypeState *effect) {
0N/A _idx = 0;
0N/A _effect = effect;
0N/A
0N/A if (!is_static)
0N/A effect[_idx++] = CellTypeState::ref;
0N/A
0N/A iterate_parameters();
0N/A
0N/A return length();
0N/A };
0N/A
0N/A int compute_for_returntype(CellTypeState *effect) {
0N/A _idx = 0;
0N/A _effect = effect;
0N/A iterate_returntype();
0N/A set(CellTypeState::bottom); // Always terminate with a bottom state, so ppush works
0N/A
0N/A return length();
0N/A }
0N/A};
0N/A
0N/A//=========================================================================================
0N/A// ComputeEntryStack
0N/A//
0N/A// Specialization of SignatureIterator - in order to set up first stack frame
0N/A//
0N/Aclass ComputeEntryStack : public SignatureIterator {
0N/A CellTypeState *_effect;
0N/A int _idx;
0N/A
0N/A void setup();
0N/A void set(CellTypeState state) { _effect[_idx++] = state; }
0N/A int length() { return _idx; };
0N/A
0N/A virtual void do_bool () { set(CellTypeState::value); };
0N/A virtual void do_char () { set(CellTypeState::value); };
0N/A virtual void do_float () { set(CellTypeState::value); };
0N/A virtual void do_byte () { set(CellTypeState::value); };
0N/A virtual void do_short () { set(CellTypeState::value); };
0N/A virtual void do_int () { set(CellTypeState::value); };
0N/A virtual void do_void () { set(CellTypeState::bottom);};
0N/A virtual void do_object(int begin, int end) { set(CellTypeState::make_slot_ref(_idx)); }
0N/A virtual void do_array (int begin, int end) { set(CellTypeState::make_slot_ref(_idx)); }
0N/A
0N/A void do_double() { set(CellTypeState::value);
0N/A set(CellTypeState::value); }
0N/A void do_long () { set(CellTypeState::value);
0N/A set(CellTypeState::value); }
0N/A
0N/Apublic:
2062N/A ComputeEntryStack(Symbol* signature) : SignatureIterator(signature) {};
0N/A
0N/A // Compute methods
0N/A int compute_for_parameters(bool is_static, CellTypeState *effect) {
0N/A _idx = 0;
0N/A _effect = effect;
0N/A
0N/A if (!is_static)
0N/A effect[_idx++] = CellTypeState::make_slot_ref(0);
0N/A
0N/A iterate_parameters();
0N/A
0N/A return length();
0N/A };
0N/A
0N/A int compute_for_returntype(CellTypeState *effect) {
0N/A _idx = 0;
0N/A _effect = effect;
0N/A iterate_returntype();
0N/A set(CellTypeState::bottom); // Always terminate with a bottom state, so ppush works
0N/A
0N/A return length();
0N/A }
0N/A};
0N/A
0N/A//=====================================================================================
0N/A//
0N/A// Implementation of RetTable/RetTableEntry
0N/A//
0N/A// Contains function to itereate through all bytecodes
0N/A// and find all return entry points
0N/A//
0N/Aint RetTable::_init_nof_entries = 10;
0N/Aint RetTableEntry::_init_nof_jsrs = 5;
0N/A
0N/Avoid RetTableEntry::add_delta(int bci, int delta) {
0N/A if (_target_bci > bci) _target_bci += delta;
0N/A
0N/A for (int k = 0; k < _jsrs->length(); k++) {
0N/A int jsr = _jsrs->at(k);
0N/A if (jsr > bci) _jsrs->at_put(k, jsr+delta);
0N/A }
0N/A}
0N/A
0N/Avoid RetTable::compute_ret_table(methodHandle method) {
0N/A BytecodeStream i(method);
0N/A Bytecodes::Code bytecode;
0N/A
0N/A while( (bytecode = i.next()) >= 0) {
0N/A switch (bytecode) {
0N/A case Bytecodes::_jsr:
0N/A add_jsr(i.next_bci(), i.dest());
0N/A break;
0N/A case Bytecodes::_jsr_w:
0N/A add_jsr(i.next_bci(), i.dest_w());
0N/A break;
0N/A }
0N/A }
0N/A}
0N/A
0N/Avoid RetTable::add_jsr(int return_bci, int target_bci) {
0N/A RetTableEntry* entry = _first;
0N/A
0N/A // Scan table for entry
0N/A for (;entry && entry->target_bci() != target_bci; entry = entry->next());
0N/A
0N/A if (!entry) {
0N/A // Allocate new entry and put in list
0N/A entry = new RetTableEntry(target_bci, _first);
0N/A _first = entry;
0N/A }
0N/A
0N/A // Now "entry" is set. Make sure that the entry is initialized
0N/A // and has room for the new jsr.
0N/A entry->add_jsr(return_bci);
0N/A}
0N/A
0N/ARetTableEntry* RetTable::find_jsrs_for_target(int targBci) {
0N/A RetTableEntry *cur = _first;
0N/A
0N/A while(cur) {
0N/A assert(cur->target_bci() != -1, "sanity check");
0N/A if (cur->target_bci() == targBci) return cur;
0N/A cur = cur->next();
0N/A }
0N/A ShouldNotReachHere();
0N/A return NULL;
0N/A}
0N/A
0N/A// The instruction at bci is changing size by "delta". Update the return map.
0N/Avoid RetTable::update_ret_table(int bci, int delta) {
0N/A RetTableEntry *cur = _first;
0N/A while(cur) {
0N/A cur->add_delta(bci, delta);
0N/A cur = cur->next();
0N/A }
0N/A}
0N/A
0N/A//
0N/A// Celltype state
0N/A//
0N/A
0N/ACellTypeState CellTypeState::bottom = CellTypeState::make_bottom();
0N/ACellTypeState CellTypeState::uninit = CellTypeState::make_any(uninit_value);
0N/ACellTypeState CellTypeState::ref = CellTypeState::make_any(ref_conflict);
0N/ACellTypeState CellTypeState::value = CellTypeState::make_any(val_value);
0N/ACellTypeState CellTypeState::refUninit = CellTypeState::make_any(ref_conflict | uninit_value);
0N/ACellTypeState CellTypeState::top = CellTypeState::make_top();
0N/ACellTypeState CellTypeState::addr = CellTypeState::make_any(addr_conflict);
0N/A
0N/A// Commonly used constants
0N/Astatic CellTypeState epsilonCTS[1] = { CellTypeState::bottom };
0N/Astatic CellTypeState refCTS = CellTypeState::ref;
0N/Astatic CellTypeState valCTS = CellTypeState::value;
0N/Astatic CellTypeState vCTS[2] = { CellTypeState::value, CellTypeState::bottom };
0N/Astatic CellTypeState rCTS[2] = { CellTypeState::ref, CellTypeState::bottom };
0N/Astatic CellTypeState rrCTS[3] = { CellTypeState::ref, CellTypeState::ref, CellTypeState::bottom };
0N/Astatic CellTypeState vrCTS[3] = { CellTypeState::value, CellTypeState::ref, CellTypeState::bottom };
0N/Astatic CellTypeState vvCTS[3] = { CellTypeState::value, CellTypeState::value, CellTypeState::bottom };
0N/Astatic CellTypeState rvrCTS[4] = { CellTypeState::ref, CellTypeState::value, CellTypeState::ref, CellTypeState::bottom };
0N/Astatic CellTypeState vvrCTS[4] = { CellTypeState::value, CellTypeState::value, CellTypeState::ref, CellTypeState::bottom };
0N/Astatic CellTypeState vvvCTS[4] = { CellTypeState::value, CellTypeState::value, CellTypeState::value, CellTypeState::bottom };
0N/Astatic CellTypeState vvvrCTS[5] = { CellTypeState::value, CellTypeState::value, CellTypeState::value, CellTypeState::ref, CellTypeState::bottom };
0N/Astatic CellTypeState vvvvCTS[5] = { CellTypeState::value, CellTypeState::value, CellTypeState::value, CellTypeState::value, CellTypeState::bottom };
0N/A
0N/Achar CellTypeState::to_char() const {
0N/A if (can_be_reference()) {
0N/A if (can_be_value() || can_be_address())
0N/A return '#'; // Conflict that needs to be rewritten
0N/A else
0N/A return 'r';
0N/A } else if (can_be_value())
0N/A return 'v';
0N/A else if (can_be_address())
0N/A return 'p';
0N/A else if (can_be_uninit())
0N/A return ' ';
0N/A else
0N/A return '@';
0N/A}
0N/A
0N/A
0N/A// Print a detailed CellTypeState. Indicate all bits that are set. If
0N/A// the CellTypeState represents an address or a reference, print the
0N/A// value of the additional information.
0N/Avoid CellTypeState::print(outputStream *os) {
0N/A if (can_be_address()) {
0N/A os->print("(p");
0N/A } else {
0N/A os->print("( ");
0N/A }
0N/A if (can_be_reference()) {
0N/A os->print("r");
0N/A } else {
0N/A os->print(" ");
0N/A }
0N/A if (can_be_value()) {
0N/A os->print("v");
0N/A } else {
0N/A os->print(" ");
0N/A }
0N/A if (can_be_uninit()) {
0N/A os->print("u|");
0N/A } else {
0N/A os->print(" |");
0N/A }
0N/A if (is_info_top()) {
0N/A os->print("Top)");
0N/A } else if (is_info_bottom()) {
0N/A os->print("Bot)");
0N/A } else {
0N/A if (is_reference()) {
0N/A int info = get_info();
0N/A int data = info & ~(ref_not_lock_bit | ref_slot_bit);
0N/A if (info & ref_not_lock_bit) {
0N/A // Not a monitor lock reference.
0N/A if (info & ref_slot_bit) {
0N/A // slot
0N/A os->print("slot%d)", data);
0N/A } else {
0N/A // line
0N/A os->print("line%d)", data);
0N/A }
0N/A } else {
0N/A // lock
0N/A os->print("lock%d)", data);
0N/A }
0N/A } else {
0N/A os->print("%d)", get_info());
0N/A }
0N/A }
0N/A}
0N/A
0N/A//
0N/A// Basicblock handling methods
0N/A//
0N/A
0N/Avoid GenerateOopMap ::initialize_bb() {
0N/A _gc_points = 0;
0N/A _bb_count = 0;
342N/A _bb_hdr_bits.clear();
342N/A _bb_hdr_bits.resize(method()->code_size());
0N/A}
0N/A
0N/Avoid GenerateOopMap::bb_mark_fct(GenerateOopMap *c, int bci, int *data) {
0N/A assert(bci>= 0 && bci < c->method()->code_size(), "index out of bounds");
0N/A if (c->is_bb_header(bci))
0N/A return;
0N/A
0N/A if (TraceNewOopMapGeneration) {
0N/A tty->print_cr("Basicblock#%d begins at: %d", c->_bb_count, bci);
0N/A }
0N/A c->set_bbmark_bit(bci);
0N/A c->_bb_count++;
0N/A}
0N/A
0N/A
0N/Avoid GenerateOopMap::mark_bbheaders_and_count_gc_points() {
0N/A initialize_bb();
0N/A
0N/A bool fellThrough = false; // False to get first BB marked.
0N/A
0N/A // First mark all exception handlers as start of a basic-block
3879N/A ExceptionTable excps(method());
3879N/A for(int i = 0; i < excps.length(); i ++) {
3879N/A bb_mark_fct(this, excps.handler_pc(i), NULL);
0N/A }
0N/A
0N/A // Then iterate through the code
0N/A BytecodeStream bcs(_method);
0N/A Bytecodes::Code bytecode;
0N/A
0N/A while( (bytecode = bcs.next()) >= 0) {
0N/A int bci = bcs.bci();
0N/A
0N/A if (!fellThrough)
0N/A bb_mark_fct(this, bci, NULL);
0N/A
0N/A fellThrough = jump_targets_do(&bcs, &GenerateOopMap::bb_mark_fct, NULL);
0N/A
0N/A /* We will also mark successors of jsr's as basic block headers. */
0N/A switch (bytecode) {
0N/A case Bytecodes::_jsr:
0N/A assert(!fellThrough, "should not happen");
0N/A bb_mark_fct(this, bci + Bytecodes::length_for(bytecode), NULL);
0N/A break;
0N/A case Bytecodes::_jsr_w:
0N/A assert(!fellThrough, "should not happen");
0N/A bb_mark_fct(this, bci + Bytecodes::length_for(bytecode), NULL);
0N/A break;
0N/A }
0N/A
0N/A if (possible_gc_point(&bcs))
0N/A _gc_points++;
0N/A }
0N/A}
0N/A
0N/Avoid GenerateOopMap::reachable_basicblock(GenerateOopMap *c, int bci, int *data) {
0N/A assert(bci>= 0 && bci < c->method()->code_size(), "index out of bounds");
0N/A BasicBlock* bb = c->get_basic_block_at(bci);
0N/A if (bb->is_dead()) {
0N/A bb->mark_as_alive();
0N/A *data = 1; // Mark basicblock as changed
0N/A }
0N/A}
0N/A
0N/A
0N/Avoid GenerateOopMap::mark_reachable_code() {
0N/A int change = 1; // int to get function pointers to work
0N/A
0N/A // Mark entry basic block as alive and all exception handlers
0N/A _basic_blocks[0].mark_as_alive();
3879N/A ExceptionTable excps(method());
3879N/A for(int i = 0; i < excps.length(); i++) {
3879N/A BasicBlock *bb = get_basic_block_at(excps.handler_pc(i));
0N/A // If block is not already alive (due to multiple exception handlers to same bb), then
0N/A // make it alive
0N/A if (bb->is_dead()) bb->mark_as_alive();
0N/A }
0N/A
0N/A BytecodeStream bcs(_method);
0N/A
0N/A // Iterate through all basic blocks until we reach a fixpoint
0N/A while (change) {
0N/A change = 0;
0N/A
0N/A for (int i = 0; i < _bb_count; i++) {
0N/A BasicBlock *bb = &_basic_blocks[i];
0N/A if (bb->is_alive()) {
0N/A // Position bytecodestream at last bytecode in basicblock
0N/A bcs.set_start(bb->_end_bci);
0N/A bcs.next();
0N/A Bytecodes::Code bytecode = bcs.code();
0N/A int bci = bcs.bci();
0N/A assert(bci == bb->_end_bci, "wrong bci");
0N/A
0N/A bool fell_through = jump_targets_do(&bcs, &GenerateOopMap::reachable_basicblock, &change);
0N/A
0N/A // We will also mark successors of jsr's as alive.
0N/A switch (bytecode) {
0N/A case Bytecodes::_jsr:
0N/A case Bytecodes::_jsr_w:
0N/A assert(!fell_through, "should not happen");
0N/A reachable_basicblock(this, bci + Bytecodes::length_for(bytecode), &change);
0N/A break;
0N/A }
0N/A if (fell_through) {
0N/A // Mark successor as alive
0N/A if (bb[1].is_dead()) {
0N/A bb[1].mark_as_alive();
0N/A change = 1;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A }
0N/A}
0N/A
0N/A/* If the current instruction in "c" has no effect on control flow,
0N/A returns "true". Otherwise, calls "jmpFct" one or more times, with
0N/A "c", an appropriate "pcDelta", and "data" as arguments, then
0N/A returns "false". There is one exception: if the current
0N/A instruction is a "ret", returns "false" without calling "jmpFct".
0N/A Arrangements for tracking the control flow of a "ret" must be made
0N/A externally. */
0N/Abool GenerateOopMap::jump_targets_do(BytecodeStream *bcs, jmpFct_t jmpFct, int *data) {
0N/A int bci = bcs->bci();
0N/A
0N/A switch (bcs->code()) {
0N/A case Bytecodes::_ifeq:
0N/A case Bytecodes::_ifne:
0N/A case Bytecodes::_iflt:
0N/A case Bytecodes::_ifge:
0N/A case Bytecodes::_ifgt:
0N/A case Bytecodes::_ifle:
0N/A case Bytecodes::_if_icmpeq:
0N/A case Bytecodes::_if_icmpne:
0N/A case Bytecodes::_if_icmplt:
0N/A case Bytecodes::_if_icmpge:
0N/A case Bytecodes::_if_icmpgt:
0N/A case Bytecodes::_if_icmple:
0N/A case Bytecodes::_if_acmpeq:
0N/A case Bytecodes::_if_acmpne:
0N/A case Bytecodes::_ifnull:
0N/A case Bytecodes::_ifnonnull:
0N/A (*jmpFct)(this, bcs->dest(), data);
0N/A (*jmpFct)(this, bci + 3, data);
0N/A break;
0N/A
0N/A case Bytecodes::_goto:
0N/A (*jmpFct)(this, bcs->dest(), data);
0N/A break;
0N/A case Bytecodes::_goto_w:
0N/A (*jmpFct)(this, bcs->dest_w(), data);
0N/A break;
0N/A case Bytecodes::_tableswitch:
2027N/A { Bytecode_tableswitch tableswitch(method(), bcs->bcp());
2027N/A int len = tableswitch.length();
0N/A
2027N/A (*jmpFct)(this, bci + tableswitch.default_offset(), data); /* Default. jump address */
0N/A while (--len >= 0) {
2027N/A (*jmpFct)(this, bci + tableswitch.dest_offset_at(len), data);
0N/A }
0N/A break;
0N/A }
0N/A
0N/A case Bytecodes::_lookupswitch:
2027N/A { Bytecode_lookupswitch lookupswitch(method(), bcs->bcp());
2027N/A int npairs = lookupswitch.number_of_pairs();
2027N/A (*jmpFct)(this, bci + lookupswitch.default_offset(), data); /* Default. */
0N/A while(--npairs >= 0) {
2027N/A LookupswitchPair pair = lookupswitch.pair_at(npairs);
2027N/A (*jmpFct)(this, bci + pair.offset(), data);
0N/A }
0N/A break;
0N/A }
0N/A case Bytecodes::_jsr:
0N/A assert(bcs->is_wide()==false, "sanity check");
0N/A (*jmpFct)(this, bcs->dest(), data);
0N/A
0N/A
0N/A
0N/A break;
0N/A case Bytecodes::_jsr_w:
0N/A (*jmpFct)(this, bcs->dest_w(), data);
0N/A break;
0N/A case Bytecodes::_wide:
0N/A ShouldNotReachHere();
0N/A return true;
0N/A break;
0N/A case Bytecodes::_athrow:
0N/A case Bytecodes::_ireturn:
0N/A case Bytecodes::_lreturn:
0N/A case Bytecodes::_freturn:
0N/A case Bytecodes::_dreturn:
0N/A case Bytecodes::_areturn:
0N/A case Bytecodes::_return:
0N/A case Bytecodes::_ret:
0N/A break;
0N/A default:
0N/A return true;
0N/A }
0N/A return false;
0N/A}
0N/A
0N/A/* Requires "pc" to be the head of a basic block; returns that basic
0N/A block. */
0N/ABasicBlock *GenerateOopMap::get_basic_block_at(int bci) const {
0N/A BasicBlock* bb = get_basic_block_containing(bci);
0N/A assert(bb->_bci == bci, "should have found BB");
0N/A return bb;
0N/A}
0N/A
0N/A// Requires "pc" to be the start of an instruction; returns the basic
0N/A// block containing that instruction. */
0N/ABasicBlock *GenerateOopMap::get_basic_block_containing(int bci) const {
0N/A BasicBlock *bbs = _basic_blocks;
0N/A int lo = 0, hi = _bb_count - 1;
0N/A
0N/A while (lo <= hi) {
0N/A int m = (lo + hi) / 2;
0N/A int mbci = bbs[m]._bci;
0N/A int nbci;
0N/A
0N/A if ( m == _bb_count-1) {
0N/A assert( bci >= mbci && bci < method()->code_size(), "sanity check failed");
0N/A return bbs+m;
0N/A } else {
0N/A nbci = bbs[m+1]._bci;
0N/A }
0N/A
0N/A if ( mbci <= bci && bci < nbci) {
0N/A return bbs+m;
0N/A } else if (mbci < bci) {
0N/A lo = m + 1;
0N/A } else {
0N/A assert(mbci > bci, "sanity check");
0N/A hi = m - 1;
0N/A }
0N/A }
0N/A
0N/A fatal("should have found BB");
0N/A return NULL;
0N/A}
0N/A
0N/Avoid GenerateOopMap::restore_state(BasicBlock *bb)
0N/A{
0N/A memcpy(_state, bb->_state, _state_len*sizeof(CellTypeState));
0N/A _stack_top = bb->_stack_top;
0N/A _monitor_top = bb->_monitor_top;
0N/A}
0N/A
0N/Aint GenerateOopMap::next_bb_start_pc(BasicBlock *bb) {
0N/A int bbNum = bb - _basic_blocks + 1;
0N/A if (bbNum == _bb_count)
0N/A return method()->code_size();
0N/A
0N/A return _basic_blocks[bbNum]._bci;
0N/A}
0N/A
0N/A//
0N/A// CellType handling methods
0N/A//
0N/A
4565N/A// Allocate memory and throw LinkageError if failure.
4565N/A#define ALLOC_RESOURCE_ARRAY(var, type, count) \
4565N/A var = NEW_RESOURCE_ARRAY_RETURN_NULL(type, count); \
4565N/A if (var == NULL) { \
4565N/A report_error("Cannot reserve enough memory to analyze this method"); \
4565N/A return; \
4565N/A }
4565N/A
0N/Avoid GenerateOopMap::init_state() {
0N/A _state_len = _max_locals + _max_stack + _max_monitors;
4565N/A ALLOC_RESOURCE_ARRAY(_state, CellTypeState, _state_len);
0N/A memset(_state, 0, _state_len * sizeof(CellTypeState));
4565N/A int count = MAX3(_max_locals, _max_stack, _max_monitors) + 1/*for null terminator char */;
4565N/A ALLOC_RESOURCE_ARRAY(_state_vec_buf, char, count)
0N/A}
0N/A
0N/Avoid GenerateOopMap::make_context_uninitialized() {
0N/A CellTypeState* vs = vars();
0N/A
0N/A for (int i = 0; i < _max_locals; i++)
0N/A vs[i] = CellTypeState::uninit;
0N/A
0N/A _stack_top = 0;
0N/A _monitor_top = 0;
0N/A}
0N/A
2062N/Aint GenerateOopMap::methodsig_to_effect(Symbol* signature, bool is_static, CellTypeState* effect) {
0N/A ComputeEntryStack ces(signature);
0N/A return ces.compute_for_parameters(is_static, effect);
0N/A}
0N/A
0N/A// Return result of merging cts1 and cts2.
0N/ACellTypeState CellTypeState::merge(CellTypeState cts, int slot) const {
0N/A CellTypeState result;
0N/A
0N/A assert(!is_bottom() && !cts.is_bottom(),
0N/A "merge of bottom values is handled elsewhere");
0N/A
0N/A result._state = _state | cts._state;
0N/A
0N/A // If the top bit is set, we don't need to do any more work.
0N/A if (!result.is_info_top()) {
0N/A assert((result.can_be_address() || result.can_be_reference()),
0N/A "only addresses and references have non-top info");
0N/A
0N/A if (!equal(cts)) {
0N/A // The two values being merged are different. Raise to top.
0N/A if (result.is_reference()) {
0N/A result = CellTypeState::make_slot_ref(slot);
0N/A } else {
0N/A result._state |= info_conflict;
0N/A }
0N/A }
0N/A }
0N/A assert(result.is_valid_state(), "checking that CTS merge maintains legal state");
0N/A
0N/A return result;
0N/A}
0N/A
0N/A// Merge the variable state for locals and stack from cts into bbts.
0N/Abool GenerateOopMap::merge_local_state_vectors(CellTypeState* cts,
0N/A CellTypeState* bbts) {
0N/A int i;
0N/A int len = _max_locals + _stack_top;
0N/A bool change = false;
0N/A
0N/A for (i = len - 1; i >= 0; i--) {
0N/A CellTypeState v = cts[i].merge(bbts[i], i);
0N/A change = change || !v.equal(bbts[i]);
0N/A bbts[i] = v;
0N/A }
0N/A
0N/A return change;
0N/A}
0N/A
0N/A// Merge the monitor stack state from cts into bbts.
0N/Abool GenerateOopMap::merge_monitor_state_vectors(CellTypeState* cts,
0N/A CellTypeState* bbts) {
0N/A bool change = false;
0N/A if (_max_monitors > 0 && _monitor_top != bad_monitors) {
0N/A // If there are no monitors in the program, or there has been
0N/A // a monitor matching error before this point in the program,
0N/A // then we do not merge in the monitor state.
0N/A
0N/A int base = _max_locals + _max_stack;
0N/A int len = base + _monitor_top;
0N/A for (int i = len - 1; i >= base; i--) {
0N/A CellTypeState v = cts[i].merge(bbts[i], i);
0N/A
0N/A // Can we prove that, when there has been a change, it will already
0N/A // have been detected at this point? That would make this equal
0N/A // check here unnecessary.
0N/A change = change || !v.equal(bbts[i]);
0N/A bbts[i] = v;
0N/A }
0N/A }
0N/A
0N/A return change;
0N/A}
0N/A
0N/Avoid GenerateOopMap::copy_state(CellTypeState *dst, CellTypeState *src) {
0N/A int len = _max_locals + _stack_top;
0N/A for (int i = 0; i < len; i++) {
0N/A if (src[i].is_nonlock_reference()) {
0N/A dst[i] = CellTypeState::make_slot_ref(i);
0N/A } else {
0N/A dst[i] = src[i];
0N/A }
0N/A }
0N/A if (_max_monitors > 0 && _monitor_top != bad_monitors) {
0N/A int base = _max_locals + _max_stack;
0N/A len = base + _monitor_top;
0N/A for (int i = base; i < len; i++) {
0N/A dst[i] = src[i];
0N/A }
0N/A }
0N/A}
0N/A
0N/A
0N/A// Merge the states for the current block and the next. As long as a
0N/A// block is reachable the locals and stack must be merged. If the
0N/A// stack heights don't match then this is a verification error and
0N/A// it's impossible to interpret the code. Simultaneously monitor
0N/A// states are being check to see if they nest statically. If monitor
0N/A// depths match up then their states are merged. Otherwise the
0N/A// mismatch is simply recorded and interpretation continues since
0N/A// monitor matching is purely informational and doesn't say anything
0N/A// about the correctness of the code.
0N/Avoid GenerateOopMap::merge_state_into_bb(BasicBlock *bb) {
0N/A assert(bb->is_alive(), "merging state into a dead basicblock");
0N/A
0N/A if (_stack_top == bb->_stack_top) {
0N/A // always merge local state even if monitors don't match.
0N/A if (merge_local_state_vectors(_state, bb->_state)) {
0N/A bb->set_changed(true);
0N/A }
0N/A if (_monitor_top == bb->_monitor_top) {
0N/A // monitors still match so continue merging monitor states.
0N/A if (merge_monitor_state_vectors(_state, bb->_state)) {
0N/A bb->set_changed(true);
0N/A }
0N/A } else {
0N/A if (TraceMonitorMismatch) {
0N/A report_monitor_mismatch("monitor stack height merge conflict");
0N/A }
0N/A // When the monitor stacks are not matched, we set _monitor_top to
0N/A // bad_monitors. This signals that, from here on, the monitor stack cannot
0N/A // be trusted. In particular, monitorexit bytecodes may throw
0N/A // exceptions. We mark this block as changed so that the change
0N/A // propagates properly.
0N/A bb->_monitor_top = bad_monitors;
0N/A bb->set_changed(true);
0N/A _monitor_safe = false;
0N/A }
0N/A } else if (!bb->is_reachable()) {
0N/A // First time we look at this BB
0N/A copy_state(bb->_state, _state);
0N/A bb->_stack_top = _stack_top;
0N/A bb->_monitor_top = _monitor_top;
0N/A bb->set_changed(true);
0N/A } else {
0N/A verify_error("stack height conflict: %d vs. %d", _stack_top, bb->_stack_top);
0N/A }
0N/A}
0N/A
0N/Avoid GenerateOopMap::merge_state(GenerateOopMap *gom, int bci, int* data) {
0N/A gom->merge_state_into_bb(gom->get_basic_block_at(bci));
0N/A}
0N/A
0N/Avoid GenerateOopMap::set_var(int localNo, CellTypeState cts) {
0N/A assert(cts.is_reference() || cts.is_value() || cts.is_address(),
0N/A "wrong celltypestate");
0N/A if (localNo < 0 || localNo > _max_locals) {
0N/A verify_error("variable write error: r%d", localNo);
0N/A return;
0N/A }
0N/A vars()[localNo] = cts;
0N/A}
0N/A
0N/ACellTypeState GenerateOopMap::get_var(int localNo) {
1409N/A assert(localNo < _max_locals + _nof_refval_conflicts, "variable read error");
0N/A if (localNo < 0 || localNo > _max_locals) {
0N/A verify_error("variable read error: r%d", localNo);
0N/A return valCTS; // just to pick something;
0N/A }
0N/A return vars()[localNo];
0N/A}
0N/A
0N/ACellTypeState GenerateOopMap::pop() {
0N/A if ( _stack_top <= 0) {
0N/A verify_error("stack underflow");
0N/A return valCTS; // just to pick something
0N/A }
0N/A return stack()[--_stack_top];
0N/A}
0N/A
0N/Avoid GenerateOopMap::push(CellTypeState cts) {
0N/A if ( _stack_top >= _max_stack) {
0N/A verify_error("stack overflow");
0N/A return;
0N/A }
0N/A stack()[_stack_top++] = cts;
0N/A}
0N/A
0N/ACellTypeState GenerateOopMap::monitor_pop() {
0N/A assert(_monitor_top != bad_monitors, "monitor_pop called on error monitor stack");
0N/A if (_monitor_top == 0) {
0N/A // We have detected a pop of an empty monitor stack.
0N/A _monitor_safe = false;
0N/A _monitor_top = bad_monitors;
0N/A
0N/A if (TraceMonitorMismatch) {
0N/A report_monitor_mismatch("monitor stack underflow");
0N/A }
0N/A return CellTypeState::ref; // just to keep the analysis going.
0N/A }
0N/A return monitors()[--_monitor_top];
0N/A}
0N/A
0N/Avoid GenerateOopMap::monitor_push(CellTypeState cts) {
0N/A assert(_monitor_top != bad_monitors, "monitor_push called on error monitor stack");
0N/A if (_monitor_top >= _max_monitors) {
0N/A // Some monitorenter is being executed more than once.
0N/A // This means that the monitor stack cannot be simulated.
0N/A _monitor_safe = false;
0N/A _monitor_top = bad_monitors;
0N/A
0N/A if (TraceMonitorMismatch) {
0N/A report_monitor_mismatch("monitor stack overflow");
0N/A }
0N/A return;
0N/A }
0N/A monitors()[_monitor_top++] = cts;
0N/A}
0N/A
0N/A//
0N/A// Interpretation handling methods
0N/A//
0N/A
0N/Avoid GenerateOopMap::do_interpretation()
0N/A{
0N/A // "i" is just for debugging, so we can detect cases where this loop is
0N/A // iterated more than once.
0N/A int i = 0;
0N/A do {
0N/A#ifndef PRODUCT
0N/A if (TraceNewOopMapGeneration) {
0N/A tty->print("\n\nIteration #%d of do_interpretation loop, method:\n", i);
0N/A method()->print_name(tty);
0N/A tty->print("\n\n");
0N/A }
0N/A#endif
0N/A _conflict = false;
0N/A _monitor_safe = true;
0N/A // init_state is now called from init_basic_blocks. The length of a
0N/A // state vector cannot be determined until we have made a pass through
0N/A // the bytecodes counting the possible monitor entries.
0N/A if (!_got_error) init_basic_blocks();
0N/A if (!_got_error) setup_method_entry_state();
0N/A if (!_got_error) interp_all();
0N/A if (!_got_error) rewrite_refval_conflicts();
0N/A i++;
0N/A } while (_conflict && !_got_error);
0N/A}
0N/A
0N/Avoid GenerateOopMap::init_basic_blocks() {
0N/A // Note: Could consider reserving only the needed space for each BB's state
0N/A // (entry stack may not be of maximal height for every basic block).
0N/A // But cumbersome since we don't know the stack heights yet. (Nor the
0N/A // monitor stack heights...)
0N/A
4565N/A ALLOC_RESOURCE_ARRAY(_basic_blocks, BasicBlock, _bb_count);
0N/A
0N/A // Make a pass through the bytecodes. Count the number of monitorenters.
0N/A // This can be used an upper bound on the monitor stack depth in programs
0N/A // which obey stack discipline with their monitor usage. Initialize the
0N/A // known information about basic blocks.
0N/A BytecodeStream j(_method);
0N/A Bytecodes::Code bytecode;
0N/A
0N/A int bbNo = 0;
0N/A int monitor_count = 0;
0N/A int prev_bci = -1;
0N/A while( (bytecode = j.next()) >= 0) {
0N/A if (j.code() == Bytecodes::_monitorenter) {
0N/A monitor_count++;
0N/A }
0N/A
0N/A int bci = j.bci();
0N/A if (is_bb_header(bci)) {
0N/A // Initialize the basicblock structure
0N/A BasicBlock *bb = _basic_blocks + bbNo;
0N/A bb->_bci = bci;
0N/A bb->_max_locals = _max_locals;
0N/A bb->_max_stack = _max_stack;
0N/A bb->set_changed(false);
0N/A bb->_stack_top = BasicBlock::_dead_basic_block; // Initialize all basicblocks are dead.
0N/A bb->_monitor_top = bad_monitors;
0N/A
0N/A if (bbNo > 0) {
0N/A _basic_blocks[bbNo - 1]._end_bci = prev_bci;
0N/A }
0N/A
0N/A bbNo++;
0N/A }
0N/A // Remember prevous bci.
0N/A prev_bci = bci;
0N/A }
0N/A // Set
0N/A _basic_blocks[bbNo-1]._end_bci = prev_bci;
0N/A
0N/A
342N/A // Check that the correct number of basicblocks was found
342N/A if (bbNo !=_bb_count) {
342N/A if (bbNo < _bb_count) {
342N/A verify_error("jump into the middle of instruction?");
342N/A return;
342N/A } else {
342N/A verify_error("extra basic blocks - should not happen?");
342N/A return;
342N/A }
342N/A }
Error!

 

There was an error!

null

java.lang.NullPointerException