duke@435: /* xdono@631: * Copyright 2005-2008 Sun Microsystems, Inc. All Rights Reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * duke@435: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, duke@435: * CA 95054 USA or visit www.sun.com if you need additional information or duke@435: * have any questions. duke@435: * duke@435: */ duke@435: duke@435: define_array(ciObjectArray, ciObject*); duke@435: define_stack(ciObjectList, ciObjectArray); duke@435: duke@435: // This class implements a fast, conservative analysis of effect of methods duke@435: // on the escape state of their arguments. The analysis is at the bytecode duke@435: // level. duke@435: duke@435: class ciMethodBlocks; duke@435: class ciBlock; duke@435: duke@435: class BCEscapeAnalyzer : public ResourceObj { duke@435: private: duke@435: bool _conservative; // If true, return maximally duke@435: // conservative results. duke@435: ciMethod* _method; duke@435: ciMethodData* _methodData; duke@435: int _arg_size; duke@435: duke@435: intStack _stack; duke@435: duke@435: BitMap _arg_local; duke@435: BitMap _arg_stack; duke@435: BitMap _arg_returned; duke@435: BitMap _dirty; kvn@480: enum{ ARG_OFFSET_MAX = 31}; kvn@480: uint *_arg_modified; duke@435: duke@435: bool _return_local; kvn@513: bool _return_allocated; duke@435: bool _allocated_escapes; kvn@480: bool _unknown_modified; duke@435: duke@435: ciObjectList _dependencies; duke@435: duke@435: ciMethodBlocks *_methodBlocks; duke@435: duke@435: BCEscapeAnalyzer* _parent; duke@435: int _level; duke@435: duke@435: class ArgumentMap; duke@435: class StateInfo; duke@435: duke@435: // helper functions duke@435: bool is_argument(int i) { return i >= 0 && i < _arg_size; } duke@435: duke@435: void raw_push(int i) { _stack.push(i); } duke@435: int raw_pop() { return _stack.is_empty() ? -1 : _stack.pop(); } duke@435: void apush(int i) { raw_push(i); } duke@435: void spush() { raw_push(-1); } duke@435: void lpush() { spush(); spush(); } duke@435: int apop() { return raw_pop(); } duke@435: void spop() { assert(_stack.is_empty() || _stack.top() == -1, ""); raw_pop(); } duke@435: void lpop() { spop(); spop(); } duke@435: duke@435: void set_returned(ArgumentMap vars); duke@435: bool is_argument(ArgumentMap vars); duke@435: bool is_arg_stack(ArgumentMap vars); duke@435: void clear_bits(ArgumentMap vars, BitMap &bs); duke@435: void set_method_escape(ArgumentMap vars); duke@435: void set_global_escape(ArgumentMap vars); duke@435: void set_dirty(ArgumentMap vars); kvn@480: void set_modified(ArgumentMap vars, int offs, int size); duke@435: duke@435: bool is_recursive_call(ciMethod* callee); duke@435: void add_dependence(ciKlass *klass, ciMethod *meth); duke@435: void propagate_dependencies(ciMethod *meth); duke@435: void invoke(StateInfo &state, Bytecodes::Code code, ciMethod* target, ciKlass* holder); duke@435: duke@435: void iterate_one_block(ciBlock *blk, StateInfo &state, GrowableArray &successors); duke@435: void iterate_blocks(Arena *); duke@435: void merge_block_states(StateInfo *blockstates, ciBlock *dest, StateInfo *s_state); duke@435: duke@435: // analysis duke@435: void initialize(); duke@435: void clear_escape_info(); duke@435: void compute_escape_info(); duke@435: vmIntrinsics::ID known_intrinsic(); duke@435: bool compute_escape_for_intrinsic(vmIntrinsics::ID iid); duke@435: bool do_analysis(); duke@435: duke@435: void read_escape_info(); duke@435: duke@435: bool contains(uint arg_set1, uint arg_set2); duke@435: duke@435: public: duke@435: BCEscapeAnalyzer(ciMethod* method, BCEscapeAnalyzer* parent = NULL); duke@435: duke@435: // accessors duke@435: ciMethod* method() const { return _method; } duke@435: ciMethodData* methodData() const { return _methodData; } duke@435: BCEscapeAnalyzer* parent() const { return _parent; } duke@435: int level() const { return _level; } duke@435: ciObjectList* dependencies() { return &_dependencies; } duke@435: bool has_dependencies() const { return !_dependencies.is_empty(); } duke@435: duke@435: // retrieval of interprocedural escape information duke@435: duke@435: // The given argument does not escape the callee. duke@435: bool is_arg_local(int i) const { duke@435: return !_conservative && _arg_local.at(i); duke@435: } duke@435: duke@435: // The given argument escapes the callee, but does not become globally duke@435: // reachable. duke@435: bool is_arg_stack(int i) const { duke@435: return !_conservative && _arg_stack.at(i); duke@435: } duke@435: duke@435: // The given argument does not escape globally, and may be returned. duke@435: bool is_arg_returned(int i) const { duke@435: return !_conservative && _arg_returned.at(i); } duke@435: duke@435: // True iff only input arguments are returned. duke@435: bool is_return_local() const { duke@435: return !_conservative && _return_local; duke@435: } duke@435: duke@435: // True iff only newly allocated unescaped objects are returned. duke@435: bool is_return_allocated() const { duke@435: return !_conservative && _return_allocated && !_allocated_escapes; duke@435: } duke@435: kvn@480: // Tracking of argument modification kvn@480: kvn@480: enum {OFFSET_ANY = -1}; kvn@480: bool is_arg_modified(int arg, int offset, int size_in_bytes); kvn@480: void set_arg_modified(int arg, int offset, int size_in_bytes); kvn@480: bool has_non_arg_side_affects() { return _unknown_modified; } kvn@480: duke@435: // Copy dependencies from this analysis into "deps" duke@435: void copy_dependencies(Dependencies *deps); kvn@513: kvn@513: #ifndef PRODUCT kvn@513: // dump escape information kvn@513: void dump(); kvn@513: #endif duke@435: };