void LoopInvariantCodeMotion::process_block(BlockBegin* block) {
TRACE_VALUE_NUMBERING(tty->print_cr("processing block B%d", block->block_id()));
Instruction* prev = block;
Instruction* cur = block->next();
while (cur != NULL) {
bool cur_invariant = false;
if (cur->as_Constant() != NULL) {
cur_invariant = !cur->can_trap();
} else if (cur->as_ArithmeticOp() != NULL || cur->as_LogicOp() != NULL || cur->as_ShiftOp() != NULL) {
assert(cur->as_Op2() != NULL, "must be Op2");
Op2* op2 = (Op2*)cur;
cur_invariant = !op2->can_trap() && is_invariant(op2->x()) && is_invariant(op2->y());
} else if (cur->as_LoadField() != NULL) {
LoadField* lf = (LoadField*)cur;
cur_invariant = !lf->needs_patching() && !lf->field()->is_volatile() && !_short_loop_optimizer->has_field_store(lf->field()->type()->basic_type()) && is_invariant(lf->obj()) && _insert_is_pred;
} else if (cur->as_ArrayLength() != NULL) {
ArrayLength *length = cur->as_ArrayLength();
cur_invariant = is_invariant(length->array());
} else if (cur->as_LoadIndexed() != NULL) {
LoadIndexed *li = (LoadIndexed *)cur->as_LoadIndexed();
cur_invariant = !_short_loop_optimizer->has_indexed_store(as_BasicType(cur->type())) && is_invariant(li->array()) && is_invariant(li->index()) && _insert_is_pred;
}
if (cur_invariant) {
_gvn->substitute(cur);
if (cur->as_Constant() == NULL) {
cur->pin();
}
Instruction* next = cur->next();
Instruction* in = _insertion_point->next();
_insertion_point = _insertion_point->set_next(cur);
cur->set_next(in);
cur->set_flag(Instruction::DeoptimizeOnException, true);
cur->set_exception_handlers(NULL);
TRACE_VALUE_NUMBERING(tty->print_cr("Instruction %c%d is loop invariant", cur->type()->tchar(), cur->id()));
if (cur->state_before() != NULL) {
cur->set_state_before(_state->copy());
}
if (cur->exception_state() != NULL) {
cur->set_exception_state(_state->copy());
}
cur = prev->set_next(next);
} else {
prev = cur;
cur = cur->next();
}
}
}
bool ShortLoopOptimizer::process(BlockBegin* loop_header) {
TRACE_VALUE_NUMBERING(tty->print_cr("** loop header block"));
_too_complicated_loop = false;
_loop_blocks.clear();
_loop_blocks.append(loop_header);
for (int i = 0; i < _loop_blocks.length(); i++) {
BlockBegin* block = _loop_blocks.at(i);
TRACE_VALUE_NUMBERING(tty->print_cr("processing loop block B%d", block->block_id()));
if (block->is_set(BlockBegin::exception_entry_flag)) {
return false;
}
for (int j = block->number_of_preds() - 1; j >= 0; j--) {
BlockBegin* pred = block->pred_at(j);
if (pred->is_set(BlockBegin::osr_entry_flag)) {
return false;
}
ValueMap* pred_map = value_map_of(pred);
if (pred_map != NULL) {
current_map()->kill_map(pred_map);
} else if (!_loop_blocks.contains(pred)) {
if (_loop_blocks.length() >= ValueMapMaxLoopSize) {
return false;
}
_loop_blocks.append(pred);
}
}
for (Value instr = block->next(); instr != NULL; instr = instr->next()) {
instr->visit(this);
if (_too_complicated_loop) {
return false;
}
}
}
bool optimistic = this->_gvn->compilation()->is_optimistic();
if (UseLoopInvariantCodeMotion && optimistic) {
LoopInvariantCodeMotion code_motion(this, _gvn, loop_header, &_loop_blocks);
}
TRACE_VALUE_NUMBERING(tty->print_cr("** loop successfully optimized"));
return true;
}
GlobalValueNumbering::GlobalValueNumbering(IR* ir)
: _current_map(NULL)
, _value_maps(ir->linear_scan_order()->length(), NULL)
, _compilation(ir->compilation())
{
TRACE_VALUE_NUMBERING(tty->print_cr("****** start of global value numbering"));
ShortLoopOptimizer short_loop_optimizer(this);
BlockList* blocks = ir->linear_scan_order();
int num_blocks = blocks->length();
BlockBegin* start_block = blocks->at(0);
assert(start_block == ir->start() && start_block->number_of_preds() == 0 && start_block->dominator() == NULL, "must be start block");
assert(start_block->next()->as_Base() != NULL && start_block->next()->next() == NULL, "start block must not have instructions");
for_each_state_value(start_block->state(), value,
assert(value->as_Local() != NULL, "only method parameters allowed");
set_processed(value);
);
set_value_map_of(start_block, new ValueMap());
for (int i = 1; i < num_blocks; i++) {
BlockBegin* block = blocks->at(i);
TRACE_VALUE_NUMBERING(tty->print_cr("**** processing block B%d", block->block_id()));
int num_preds = block->number_of_preds();
assert(num_preds > 0, "block must have predecessors");
BlockBegin* dominator = block->dominator();
assert(dominator != NULL, "dominator must exist");
assert(value_map_of(dominator) != NULL, "value map of dominator must exist");
_current_map = new ValueMap(value_map_of(dominator));
if (num_preds == 1 && !block->is_set(BlockBegin::exception_entry_flag)) {
assert(dominator == block->pred_at(0), "dominator must be equal to predecessor");
} else if (block->is_set(BlockBegin::linear_scan_loop_header_flag)) {
if (!short_loop_optimizer.process(block)) {
current_map()->kill_memory();
}
} else {
for (int j = 0; j < num_preds; j++) {
BlockBegin* pred = block->pred_at(j);
ValueMap* pred_map = value_map_of(pred);
if (pred_map != NULL) {
current_map()->kill_map(value_map_of(pred));
} else {
current_map()->kill_memory();
}
}
}
for_each_phi_fun(block, phi,
set_processed(phi);
);
TRACE_VALUE_NUMBERING(tty->print("value map before processing block: "); current_map()->print());
for (Value instr = block->next(); instr != NULL; instr = instr->next()) {
instr->visit(this);
substitute(instr);
}
set_value_map_of(block, current_map());
}
if (_has_substitutions) {
SubstitutionResolver resolver(ir);
}
TRACE_VALUE_NUMBERING(tty->print("****** end of global value numbering. "); ValueMap::print_statistics());
}
void GlobalValueNumbering::substitute(Instruction* instr) {
assert(!instr->has_subst(), "substitution already set");
Value subst = current_map()->find_insert(instr);
if (subst != instr) {
assert(!subst->has_subst(), "can't have a substitution");
TRACE_VALUE_NUMBERING(tty->print_cr("substitution for %d set to %d", instr->id(), subst->id()));
instr->set_subst(subst);
_has_substitutions = true;
}
set_processed(instr);
}
C:\hotspot-69087d08d473\src\share\vm/c1/c1_ValueMap.hpp
#ifndef SHARE_VM_C1_C1_VALUEMAP_HPP
#define SHARE_VM_C1_C1_VALUEMAP_HPP
#include "c1/c1_Instruction.hpp"
#include "c1/c1_ValueSet.hpp"
#include "memory/allocation.hpp"
class ValueMapEntry: public CompilationResourceObj {
private:
intx _hash;
Value _value;
int _nesting;
ValueMapEntry* _next;
public:
ValueMapEntry(intx hash, Value value, int nesting, ValueMapEntry* next)
: _hash(hash)
, _value(value)
, _nesting(nesting)
, _next(next)
{
}
intx hash() { return _hash; }
Value value() { return _value; }
int nesting() { return _nesting; }
ValueMapEntry* next() { return _next; }
void set_next(ValueMapEntry* next) { _next = next; }
};
define_array(ValueMapEntryArray, ValueMapEntry*)
define_stack(ValueMapEntryList, ValueMapEntryArray)
class ValueMap: public CompilationResourceObj {
private:
int _nesting;
ValueMapEntryArray _entries;
ValueSet _killed_values;
int _entry_count;
int nesting() { return _nesting; }
bool is_local_value_numbering() { return _nesting == 0; }
bool is_global_value_numbering() { return _nesting > 0; }
int entry_count() { return _entry_count; }
int size() { return _entries.length(); }
ValueMapEntry* entry_at(int i) { return _entries.at(i); }
int entry_index(intx hash, int n) { return (unsigned int)hash % n; }
int size_threshold() { return size(); }
void kill_value(Value v) { if (is_global_value_numbering()) _killed_values.put(v); }
bool is_killed(Value v) { if (is_global_value_numbering()) return _killed_values.contains(v); else return false; }
void increase_table_size();
#ifndef PRODUCT
static int _number_of_finds;
static int _number_of_hits;
static int _number_of_kills;
#endif // PRODUCT
public:
ValueMap(); // empty value map
ValueMap(ValueMap* old); // value map with increased nesting
Value find_insert(Value x);
void kill_memory();
void kill_field(ciField* field, bool all_offsets);
void kill_array(ValueType* type);
void kill_exception();
void kill_map(ValueMap* map);
void kill_all();
#ifndef PRODUCT
void print();
static void reset_statistics();
static void print_statistics();
#endif
};
define_array(ValueMapArray, ValueMap*)
class ValueNumberingVisitor: public InstructionVisitor {
protected:
virtual void kill_memory() = 0;
virtual void kill_field(ciField* field, bool all_offsets) = 0;
virtual void kill_array(ValueType* type) = 0;
void do_StoreField (StoreField* x) {
if (x->is_init_point() || // putstatic is an initialization point so treat it as a wide kill
x->field()->is_volatile()) {
kill_memory();
} else {
kill_field(x->field(), x->needs_patching());
}
}
void do_StoreIndexed (StoreIndexed* x) { kill_array(x->type()); }
void do_MonitorEnter (MonitorEnter* x) { kill_memory(); }
void do_MonitorExit (MonitorExit* x) { kill_memory(); }
void do_Invoke (Invoke* x) { kill_memory(); }
void do_UnsafePutRaw (UnsafePutRaw* x) { kill_memory(); }
void do_UnsafePutObject(UnsafePutObject* x) { kill_memory(); }
void do_UnsafeGetAndSetObject(UnsafeGetAndSetObject* x) { kill_memory(); }
void do_UnsafeGetRaw (UnsafeGetRaw* x) { /* nothing to do */ }
void do_UnsafeGetObject(UnsafeGetObject* x) {
if (x->is_volatile()) { // the JMM requires this
kill_memory();
}
}
void do_Intrinsic (Intrinsic* x) { if (!x->preserves_state()) kill_memory(); }
void do_Phi (Phi* x) { /* nothing to do */ }
void do_Local (Local* x) { /* nothing to do */ }
void do_Constant (Constant* x) { /* nothing to do */ }
void do_LoadField (LoadField* x) {
if (x->is_init_point() || // getstatic is an initialization point so treat it as a wide kill
x->field()->is_volatile()) { // the JMM requires this
kill_memory();
}
}
void do_ArrayLength (ArrayLength* x) { /* nothing to do */ }
void do_LoadIndexed (LoadIndexed* x) { /* nothing to do */ }
void do_NegateOp (NegateOp* x) { /* nothing to do */ }
void do_ArithmeticOp (ArithmeticOp* x) { /* nothing to do */ }
void do_ShiftOp (ShiftOp* x) { /* nothing to do */ }
void do_LogicOp (LogicOp* x) { /* nothing to do */ }
void do_CompareOp (CompareOp* x) { /* nothing to do */ }
void do_IfOp (IfOp* x) { /* nothing to do */ }
void do_Convert (Convert* x) { /* nothing to do */ }
void do_NullCheck (NullCheck* x) { /* nothing to do */ }
void do_TypeCast (TypeCast* x) { /* nothing to do */ }
void do_NewInstance (NewInstance* x) { /* nothing to do */ }
void do_NewTypeArray (NewTypeArray* x) { /* nothing to do */ }
void do_NewObjectArray (NewObjectArray* x) { /* nothing to do */ }
void do_NewMultiArray (NewMultiArray* x) { /* nothing to do */ }
void do_CheckCast (CheckCast* x) { /* nothing to do */ }
void do_InstanceOf (InstanceOf* x) { /* nothing to do */ }
void do_BlockBegin (BlockBegin* x) { /* nothing to do */ }
void do_Goto (Goto* x) { /* nothing to do */ }
void do_If (If* x) { /* nothing to do */ }
void do_IfInstanceOf (IfInstanceOf* x) { /* nothing to do */ }
void do_TableSwitch (TableSwitch* x) { /* nothing to do */ }
void do_LookupSwitch (LookupSwitch* x) { /* nothing to do */ }
void do_Return (Return* x) { /* nothing to do */ }
void do_Throw (Throw* x) { /* nothing to do */ }
void do_Base (Base* x) { /* nothing to do */ }
void do_OsrEntry (OsrEntry* x) { /* nothing to do */ }
void do_ExceptionObject(ExceptionObject* x) { /* nothing to do */ }
void do_RoundFP (RoundFP* x) { /* nothing to do */ }
void do_UnsafePrefetchRead (UnsafePrefetchRead* x) { /* nothing to do */ }
void do_UnsafePrefetchWrite(UnsafePrefetchWrite* x) { /* nothing to do */ }
void do_ProfileCall (ProfileCall* x) { /* nothing to do */ }
void do_ProfileReturnType (ProfileReturnType* x) { /* nothing to do */ }
void do_ProfileInvoke (ProfileInvoke* x) { /* nothing to do */ };
void do_RuntimeCall (RuntimeCall* x) { /* nothing to do */ };
void do_MemBar (MemBar* x) { /* nothing to do */ };
void do_RangeCheckPredicate(RangeCheckPredicate* x) { /* nothing to do */ };
#ifdef ASSERT
void do_Assert (Assert* x) { /* nothing to do */ };
#endif
};
class ValueNumberingEffects: public ValueNumberingVisitor {
private:
ValueMap* _map;
public:
void kill_memory() { _map->kill_memory(); }
void kill_field(ciField* field, bool all_offsets) { _map->kill_field(field, all_offsets); }
void kill_array(ValueType* type) { _map->kill_array(type); }
ValueNumberingEffects(ValueMap* map): _map(map) {}
};
class GlobalValueNumbering: public ValueNumberingVisitor {
private:
Compilation* _compilation; // compilation data
ValueMap* _current_map; // value map of current block
ValueMapArray _value_maps; // list of value maps for all blocks
ValueSet _processed_values; // marker for instructions that were already processed
bool _has_substitutions; // set to true when substitutions must be resolved
public:
Compilation* compilation() const { return _compilation; }
ValueMap* current_map() { return _current_map; }
ValueMap* value_map_of(BlockBegin* block) { return _value_maps.at(block->linear_scan_number()); }
void set_value_map_of(BlockBegin* block, ValueMap* map) { assert(value_map_of(block) == NULL, ""); _value_maps.at_put(block->linear_scan_number(), map); }
bool is_processed(Value v) { return _processed_values.contains(v); }
void set_processed(Value v) { _processed_values.put(v); }
void kill_memory() { current_map()->kill_memory(); }
void kill_field(ciField* field, bool all_offsets) { current_map()->kill_field(field, all_offsets); }
void kill_array(ValueType* type) { current_map()->kill_array(type); }
GlobalValueNumbering(IR* ir);
void substitute(Instruction* instr); // substitute instruction if it is contained in current value map
};
#endif // SHARE_VM_C1_C1_VALUEMAP_HPP
C:\hotspot-69087d08d473\src\share\vm/c1/c1_ValueSet.cpp
#include "precompiled.hpp"
#include "c1/c1_ValueSet.hpp"
C:\hotspot-69087d08d473\src\share\vm/c1/c1_ValueSet.hpp
#ifndef SHARE_VM_C1_C1_VALUESET_HPP
#define SHARE_VM_C1_C1_VALUESET_HPP
#include "c1/c1_Instruction.hpp"
#include "memory/allocation.hpp"
#include "utilities/bitMap.inline.hpp"
class ValueSet: public CompilationResourceObj {
private:
BitMap _map;
public:
ValueSet();
ValueSet* copy();
bool contains(Value x);
void put (Value x);
void remove (Value x);
bool set_intersect(ValueSet* other);
void set_union(ValueSet* other);
void clear ();
void set_from(ValueSet* other);
bool equals (ValueSet* other);
};
inline ValueSet::ValueSet() : _map(Instruction::number_of_instructions()) {
_map.clear();
}
inline ValueSet* ValueSet::copy() {
ValueSet* res = new ValueSet();
res->_map.set_from(_map);
return res;
}
inline bool ValueSet::contains(Value x) {
return _map.at(x->id());
}
inline void ValueSet::put(Value x) {
_map.set_bit(x->id());
}
inline void ValueSet::remove(Value x) {
_map.clear_bit(x->id());
}
inline bool ValueSet::set_intersect(ValueSet* other) {
return _map.set_intersection_with_result(other->_map);
}
inline void ValueSet::set_union(ValueSet* other) {
_map.set_union(other->_map);
}
inline void ValueSet::clear() {
_map.clear();
}
inline void ValueSet::set_from(ValueSet* other) {
_map.set_from(other->_map);
}
inline bool ValueSet::equals(ValueSet* other) {
return _map.is_same(other->_map);
}
#endif // SHARE_VM_C1_C1_VALUESET_HPP
C:\hotspot-69087d08d473\src\share\vm/c1/c1_ValueStack.cpp
#include "precompiled.hpp"
#include "c1/c1_IR.hpp"
#include "c1/c1_InstructionPrinter.hpp"
#include "c1/c1_ValueStack.hpp"
ValueStack::ValueStack(IRScope* scope, ValueStack* caller_state)
: _scope(scope)
, _caller_state(caller_state)
, _bci(-99)
, _kind(Parsing)
, _locals(scope->method()->max_locals(), NULL)
, _stack(scope->method()->max_stack())
, _locks()
{
verify();
}
ValueStack::ValueStack(ValueStack* copy_from, Kind kind, int bci)
: _scope(copy_from->scope())
, _caller_state(copy_from->caller_state())
, _bci(bci)
, _kind(kind)
, _locals()
, _stack()
, _locks(copy_from->locks_size())
{
assert(kind != EmptyExceptionState || !Compilation::current()->env()->should_retain_local_variables(), "need locals");
if (kind != EmptyExceptionState) {
_locals = Values(copy_from->locals_size());
_locals.appendAll(©_from->_locals);
}
if (kind != ExceptionState && kind != EmptyExceptionState) {
if (kind == Parsing) {
_stack = Values(scope()->method()->max_stack());
} else {
_stack = Values(copy_from->stack_size());
}
_stack.appendAll(©_from->_stack);
}
_locks.appendAll(©_from->_locks);
verify();
}
bool ValueStack::is_same(ValueStack* s) {
if (scope() != s->scope()) return false;
if (caller_state() != s->caller_state()) return false;
if (locals_size() != s->locals_size()) return false;
if (stack_size() != s->stack_size()) return false;
if (locks_size() != s->locks_size()) return false;
int index;
Value value;
for_each_stack_value(this, index, value) {
if (value->type()->tag() != s->stack_at(index)->type()->tag()) return false;
}
for_each_lock_value(this, index, value) {
if (value != s->lock_at(index)) return false;
}
return true;
}
void ValueStack::clear_locals() {
for (int i = _locals.length() - 1; i >= 0; i--) {
_locals.at_put(i, NULL);
}
}
void ValueStack::pin_stack_for_linear_scan() {
for_each_state_value(this, v,
if (v->as_Constant() == NULL && v->as_Local() == NULL) {
v->pin(Instruction::PinStackForStateSplit);
}
);
}
void ValueStack::apply(Values list, ValueVisitor* f) {
for (int i = 0; i < list.length(); i++) {
Value* va = list.adr_at(i);
Value v0 = *va;
if (v0 != NULL && !v0->type()->is_illegal()) {
f->visit(va);
#ifdef ASSERT
Value v1 = *va;
assert(v1->type()->is_illegal() || v0->type()->tag() == v1->type()->tag(), "types must match");
assert(!v1->type()->is_double_word() || list.at(i + 1) == NULL, "hi-word of doubleword value must be NULL");
#endif
if (v0->type()->is_double_word()) i++;
}
}
}
void ValueStack::values_do(ValueVisitor* f) {
ValueStack* state = this;
for_each_state(state) {
apply(state->_locals, f);
apply(state->_stack, f);
apply(state->_locks, f);
}
}
Values* ValueStack::pop_arguments(int argument_size) {
assert(stack_size() >= argument_size, "stack too small or too many arguments");
int base = stack_size() - argument_size;
Values* args = new Values(argument_size);
for (int i = base; i < stack_size();) args->push(stack_at_inc(i));
truncate_stack(base);
return args;
}
int ValueStack::total_locks_size() const {
int num_locks = 0;
const ValueStack* state = this;
for_each_state(state) {
num_locks += state->locks_size();
}
return num_locks;
}
int ValueStack::lock(Value obj) {
_locks.push(obj);
int num_locks = total_locks_size();
scope()->set_min_number_of_locks(num_locks);
return num_locks - 1;
}
int ValueStack::unlock() {
_locks.pop();
return total_locks_size();
}
void ValueStack::setup_phi_for_stack(BlockBegin* b, int index) {
assert(stack_at(index)->as_Phi() == NULL || stack_at(index)->as_Phi()->block() != b, "phi function already created");
ValueType* t = stack_at(index)->type();
Value phi = new Phi(t, b, -index - 1);
_stack[index] = phi;
assert(!t->is_double_word() || _stack.at(index + 1) == NULL, "hi-word of doubleword value must be NULL");
}
void ValueStack::setup_phi_for_local(BlockBegin* b, int index) {
assert(local_at(index)->as_Phi() == NULL || local_at(index)->as_Phi()->block() != b, "phi function already created");
ValueType* t = local_at(index)->type();
Value phi = new Phi(t, b, index);
store_local(index, phi);
}
#ifndef PRODUCT
void ValueStack::print() {
scope()->method()->print_name();
tty->cr();
if (stack_is_empty()) {
tty->print_cr("empty stack");
} else {
InstructionPrinter ip;
for (int i = 0; i < stack_size();) {
Value t = stack_at_inc(i);
tty->print("%2d ", i);
tty->print("%c%d ", t->type()->tchar(), t->id());
ip.print_instr(t);
tty->cr();
}
}
if (!no_active_locks()) {
InstructionPrinter ip;
for (int i = 0; i < locks_size(); i++) {
Value t = lock_at(i);
tty->print("lock %2d ", i);
if (t == NULL) {
tty->print("this");
} else {
tty->print("%c%d ", t->type()->tchar(), t->id());
ip.print_instr(t);
}
tty->cr();
}
}
if (locals_size() > 0) {
InstructionPrinter ip;
for (int i = 0; i < locals_size();) {
Value l = _locals[i];
tty->print("local %d ", i);
if (l == NULL) {
tty->print("null");
i ++;
} else {
tty->print("%c%d ", l->type()->tchar(), l->id());
ip.print_instr(l);
if (l->type()->is_illegal() || l->type()->is_single_word()) i ++; else i += 2;
}
tty->cr();
}
}
if (caller_state() != NULL) {
caller_state()->print();
}
}
void ValueStack::verify() {
assert(scope() != NULL, "scope must exist");
if (caller_state() != NULL) {
assert(caller_state()->scope() == scope()->caller(), "invalid caller scope");
caller_state()->verify();
}
if (kind() == Parsing) {
assert(bci() == -99, "bci not defined during parsing");
} else {
assert(bci() >= -1, "bci out of range");
assert(bci() < scope()->method()->code_size(), "bci out of range");
assert(bci() == SynchronizationEntryBCI || Bytecodes::is_defined(scope()->method()->java_code_at_bci(bci())), "make sure bci points at a real bytecode");
assert(scope()->method()->liveness_at_bci(bci()).is_valid(), "liveness at bci must be valid");
}
int i;
for (i = 0; i < stack_size(); i++) {
Value v = _stack.at(i);
if (v == NULL) {
assert(_stack.at(i - 1)->type()->is_double_word(), "only hi-words are NULL on stack");
} else if (v->type()->is_double_word()) {
assert(_stack.at(i + 1) == NULL, "hi-word must be NULL");
}
}
for (i = 0; i < locals_size(); i++) {
Value v = _locals.at(i);
if (v != NULL && v->type()->is_double_word()) {
assert(_locals.at(i + 1) == NULL, "hi-word must be NULL");
}
}
for_each_state_value(this, v,
assert(v != NULL, "just test if state-iteration succeeds");
);
}
#endif // PRODUCT
C:\hotspot-69087d08d473\src\share\vm/c1/c1_ValueStack.hpp
#ifndef SHARE_VM_C1_C1_VALUESTACK_HPP
#define SHARE_VM_C1_C1_VALUESTACK_HPP
#include "c1/c1_Instruction.hpp"
class ValueStack: public CompilationResourceObj {
public:
enum Kind {
Parsing, // During abstract interpretation in GraphBuilder
CallerState, // Caller state when inlining
StateBefore, // Before before execution of instruction
StateAfter, // After execution of instruction
ExceptionState, // Exception handling of instruction
EmptyExceptionState, // Exception handling of instructions not covered by an xhandler
BlockBeginState // State of BlockBegin instruction with phi functions of this block
};
private:
IRScope* _scope; // the enclosing scope
ValueStack* _caller_state;
int _bci;
Kind _kind;
Values _locals; // the locals
Values _stack; // the expression stack
Values _locks; // the monitor stack (holding the locked values)
Value check(ValueTag tag, Value t) {
assert(tag == t->type()->tag() || tag == objectTag && t->type()->tag() == addressTag, "types must correspond");
return t;
}
Value check(ValueTag tag, Value t, Value h) {
assert(h == NULL, "hi-word of doubleword value must be NULL");
return check(tag, t);
}
static void apply(Values list, ValueVisitor* f);
ValueStack(ValueStack* copy_from, Kind kind, int bci);
public:
ValueStack(IRScope* scope, ValueStack* caller_state);
ValueStack* copy() { return new ValueStack(this, _kind, _bci); }
ValueStack* copy(Kind new_kind, int new_bci) { return new ValueStack(this, new_kind, new_bci); }
ValueStack* copy_for_parsing() { return new ValueStack(this, Parsing, -99); }
void set_caller_state(ValueStack* s) {
assert(kind() == EmptyExceptionState ||
(Compilation::current()->env()->should_retain_local_variables() && kind() == ExceptionState),
"only EmptyExceptionStates can be modified");
_caller_state = s;
}
bool is_same(ValueStack* s); // returns true if this & s's types match (w/o checking locals)
IRScope* scope() const { return _scope; }
ValueStack* caller_state() const { return _caller_state; }
int bci() const { return _bci; }
Kind kind() const { return _kind; }
int locals_size() const { return _locals.length(); }
int stack_size() const { return _stack.length(); }
int locks_size() const { return _locks.length(); }
bool stack_is_empty() const { return _stack.is_empty(); }
bool no_active_locks() const { return _locks.is_empty(); }
int total_locks_size() const;
void clear_locals(); // sets all locals to NULL;
void invalidate_local(int i) {
assert(_locals.at(i)->type()->is_single_word() ||
_locals.at(i + 1) == NULL, "hi-word of doubleword value must be NULL");
_locals.at_put(i, NULL);
}
Value local_at(int i) const {
Value x = _locals.at(i);
assert(x == NULL || x->type()->is_single_word() ||
_locals.at(i + 1) == NULL, "hi-word of doubleword value must be NULL");
return x;
}
void store_local(int i, Value x) {
if (i > 0) {
Value prev = _locals.at(i - 1);
if (prev != NULL && prev->type()->is_double_word()) {
_locals.at_put(i - 1, NULL);
}
}
_locals.at_put(i, x);
if (x->type()->is_double_word()) {
_locals.at_put(i + 1, NULL);
}
}
Value stack_at(int i) const {
Value x = _stack.at(i);
assert(x->type()->is_single_word() ||
_stack.at(i + 1) == NULL, "hi-word of doubleword value must be NULL");
return x;
}
Value stack_at_inc(int& i) const {
Value x = stack_at(i);
i += x->type()->size();
return x;
}
void stack_at_put(int i, Value x) {
_stack.at_put(i, x);
}
void pin_stack_for_linear_scan();
void values_do(ValueVisitor* f);
void truncate_stack(int size) { _stack.trunc_to(size); }
void raw_push(Value t) { _stack.push(t); }
Value raw_pop() { return _stack.pop(); }
void ipush(Value t) { _stack.push(check(intTag , t)); }
void fpush(Value t) { _stack.push(check(floatTag , t)); }
void apush(Value t) { _stack.push(check(objectTag , t)); }
void rpush(Value t) { _stack.push(check(addressTag, t)); }
void lpush(Value t) { _stack.push(check(longTag , t)); _stack.push(NULL); }
void dpush(Value t) { _stack.push(check(doubleTag , t)); _stack.push(NULL); }
void push(ValueType* type, Value t) {
switch (type->tag()) {
case intTag : ipush(t); return;
case longTag : lpush(t); return;
case floatTag : fpush(t); return;
case doubleTag : dpush(t); return;
case objectTag : apush(t); return;
case addressTag: rpush(t); return;
}
ShouldNotReachHere();
}
Value ipop() { return check(intTag , _stack.pop()); }
Value fpop() { return check(floatTag , _stack.pop()); }
Value apop() { return check(objectTag , _stack.pop()); }
Value rpop() { return check(addressTag, _stack.pop()); }
Value lpop() { Value h = _stack.pop(); return check(longTag , _stack.pop(), h); }
Value dpop() { Value h = _stack.pop(); return check(doubleTag, _stack.pop(), h); }
Value pop(ValueType* type) {
switch (type->tag()) {
case intTag : return ipop();
case longTag : return lpop();
case floatTag : return fpop();
case doubleTag : return dpop();
case objectTag : return apop();
case addressTag: return rpop();
}
ShouldNotReachHere();
return NULL;
}
Values* pop_arguments(int argument_size);
int lock (Value obj);
int unlock();
Value lock_at(int i) const { return _locks.at(i); }
void setup_phi_for_stack(BlockBegin* b, int index);
void setup_phi_for_local(BlockBegin* b, int index);
void print() PRODUCT_RETURN;
void verify() PRODUCT_RETURN;
};
#define temp_var3(x) temp__ ## x
#define temp_var2(x) temp_var3(x)
#define temp_var temp_var2(__LINE__)
#define for_each_state(state) \
for (; state != NULL; state = state->caller_state())
#define for_each_local_value(state, index, value) \
int temp_var = state->locals_size(); \
for (index = 0; \
index < temp_var && (value = state->local_at(index), true); \
index += (value == NULL || value->type()->is_illegal() ? 1 : value->type()->size())) \
if (value != NULL)
#define for_each_stack_value(state, index, value) \
int temp_var = state->stack_size(); \
for (index = 0; \
index < temp_var && (value = state->stack_at(index), true); \
index += value->type()->size())
#define for_each_lock_value(state, index, value) \
int temp_var = state->locks_size(); \
for (index = 0; \
index < temp_var && (value = state->lock_at(index), true); \
index++) \
if (value != NULL)
#define for_each_state_value(v_state, v_value, v_code) \
{ \
int cur_index; \
ValueStack* cur_state = v_state; \
Value v_value; \
for_each_state(cur_state) { \
{ \
for_each_local_value(cur_state, cur_index, v_value) { \
v_code; \
} \
} \
{ \
for_each_stack_value(cur_state, cur_index, v_value) { \
v_code; \
} \
} \
} \
}
#define for_each_phi_fun(v_block, v_phi, v_code) \
{ \
int cur_index; \
ValueStack* cur_state = v_block->state(); \
Value value; \
{ \
for_each_stack_value(cur_state, cur_index, value) { \
Phi* v_phi = value->as_Phi(); \
if (v_phi != NULL && v_phi->block() == v_block) { \
v_code; \
} \
} \
} \
{ \
for_each_local_value(cur_state, cur_index, value) { \
Phi* v_phi = value->as_Phi(); \
if (v_phi != NULL && v_phi->block() == v_block) { \
v_code; \
} \
} \
} \
}
#endif // SHARE_VM_C1_C1_VALUESTACK_HPP
C:\hotspot-69087d08d473\src\share\vm/c1/c1_ValueType.cpp
#include "precompiled.hpp"
#include "c1/c1_ValueType.hpp"
#include "ci/ciArray.hpp"
#include "ci/ciInstance.hpp"
#include "ci/ciNullObject.hpp"
VoidType* voidType = NULL;
IntType* intType = NULL;
LongType* longType = NULL;
FloatType* floatType = NULL;
DoubleType* doubleType = NULL;
ObjectType* objectType = NULL;
ArrayType* arrayType = NULL;
InstanceType* instanceType = NULL;
ClassType* classType = NULL;
AddressType* addressType = NULL;
IllegalType* illegalType = NULL;
IntConstant* intZero = NULL;
IntConstant* intOne = NULL;
ObjectConstant* objectNull = NULL;
void ValueType::initialize(Arena* arena) {
voidType = new (arena) VoidType();
intType = new (arena) IntType();
longType = new (arena) LongType();
floatType = new (arena) FloatType();
doubleType = new (arena) DoubleType();
objectType = new (arena) ObjectType();
arrayType = new (arena) ArrayType();
instanceType = new (arena) InstanceType();
classType = new (arena) ClassType();
addressType = new (arena) AddressType();
illegalType = new (arena) IllegalType();
intZero = new (arena) IntConstant(0);
intOne = new (arena) IntConstant(1);
objectNull = new (arena) ObjectConstant(ciNullObject::make());
};
ValueType* ValueType::meet(ValueType* y) const {
assert(tag() == y->tag(), "types must match");
return base();
}
ValueType* ValueType::join(ValueType* y) const {
Unimplemented();
return NULL;
}
ciType* ObjectConstant::exact_type() const {
ciObject* c = constant_value();
return (c != NULL && !c->is_null_object()) ? c->klass() : NULL;
}
ciType* ArrayConstant::exact_type() const {
ciObject* c = constant_value();
return (c != NULL && !c->is_null_object()) ? c->klass() : NULL;
}
ciType* InstanceConstant::exact_type() const {
ciObject* c = constant_value();
return (c != NULL && !c->is_null_object()) ? c->klass() : NULL;
}
ciType* ClassConstant::exact_type() const {
return Compilation::current()->env()->Class_klass();
}
jobject ObjectType::encoding() const {
assert(is_constant(), "must be");
return constant_value()->constant_encoding();
}
bool ObjectType::is_loaded() const {
assert(is_constant(), "must be");
return constant_value()->is_loaded();
}
bool MetadataType::is_loaded() const {
assert(is_constant(), "must be");
return constant_value()->is_loaded();
}
ciObject* ObjectConstant::constant_value() const { return _value; }
ciObject* ArrayConstant::constant_value() const { return _value; }
ciObject* InstanceConstant::constant_value() const { return _value; }
ValueType* as_ValueType(BasicType type) {
switch (type) {
case T_VOID : return voidType;
case T_BYTE : // fall through
case T_CHAR : // fall through
case T_SHORT : // fall through
case T_BOOLEAN: // fall through
case T_INT : return intType;
case T_LONG : return longType;
case T_FLOAT : return floatType;
case T_DOUBLE : return doubleType;
case T_ARRAY : return arrayType;
case T_OBJECT : return objectType;
case T_ADDRESS: return addressType;
case T_ILLEGAL: return illegalType;
}
ShouldNotReachHere();
return illegalType;
}
ValueType* as_ValueType(ciConstant value) {
switch (value.basic_type()) {
case T_BYTE : // fall through
case T_CHAR : // fall through
case T_SHORT : // fall through
case T_BOOLEAN: // fall through
case T_INT : return new IntConstant (value.as_int ());
case T_LONG : return new LongConstant (value.as_long ());
case T_FLOAT : return new FloatConstant (value.as_float ());
case T_DOUBLE : return new DoubleConstant(value.as_double());
case T_ARRAY : // fall through (ciConstant doesn't have an array accessor)
case T_OBJECT : {
ciObject* obj = value.as_object();
if (obj->is_null_object())
return objectNull;
if (obj->is_loaded()) {
if (obj->is_array())
return new ArrayConstant(obj->as_array());
else if (obj->is_instance())
return new InstanceConstant(obj->as_instance());
}
return new ObjectConstant(obj);
}
}
ShouldNotReachHere();
return illegalType;
}
BasicType as_BasicType(ValueType* type) {
switch (type->tag()) {
case voidTag: return T_VOID;
case intTag: return T_INT;
case longTag: return T_LONG;
case floatTag: return T_FLOAT;
case doubleTag: return T_DOUBLE;
case objectTag: return T_OBJECT;
case metaDataTag:return T_METADATA;
case addressTag: return T_ADDRESS;
case illegalTag: return T_ILLEGAL;
}
ShouldNotReachHere();
return T_ILLEGAL;
}
C:\hotspot-69087d08d473\src\share\vm/c1/c1_ValueType.hpp
#ifndef SHARE_VM_C1_C1_VALUETYPE_HPP
#define SHARE_VM_C1_C1_VALUETYPE_HPP
#include "c1/c1_Compilation.hpp"
#include "ci/ciConstant.hpp"
#include "ci/ciMethodData.hpp"
class ValueType;
class VoidType;
class IntType;
class IntConstant;
class IntInterval;
class LongType;
class LongConstant;
class FloatType;
class FloatConstant;
class DoubleType;
class DoubleConstant;
class ObjectType;
class ObjectConstant;
class ArrayType;
class ArrayConstant;
class InstanceType;
class InstanceConstant;
class MetadataType;
class ClassType;
class ClassConstant;
class MethodType;
class MethodConstant;
class MethodDataType;
class MethodDataConstant;
class AddressType;
class AddressConstant;
class IllegalType;
extern VoidType* voidType;
extern IntType* intType;
extern LongType* longType;
extern FloatType* floatType;
extern DoubleType* doubleType;
extern ObjectType* objectType;
extern ArrayType* arrayType;
extern InstanceType* instanceType;
extern ClassType* classType;
extern AddressType* addressType;
extern IllegalType* illegalType;
extern IntConstant* intZero;
extern IntConstant* intOne;
extern ObjectConstant* objectNull;
enum ValueTag {
intTag,
longTag,
floatTag,
doubleTag,
objectTag,
addressTag,
metaDataTag,
number_of_legal_tags,
voidTag = number_of_legal_tags,
illegalTag,
number_of_tags
};
class ValueType: public CompilationResourceObj {
private:
const int _size;
const ValueTag _tag;
ValueType();
protected:
ValueType(ValueTag tag, int size): _tag(tag), _size(size) {}
public:
static void initialize(Arena* arena);
virtual ValueType* base() const = 0; // the 'canonical' type (e.g., intType for an IntConstant)
ValueTag tag() const { return _tag; } // the 'canonical' tag (useful for type matching)
int size() const { // the size of an object of the type in words
assert(_size > -1, "shouldn't be asking for size");
return _size;
}
virtual const char tchar() const = 0; // the type 'character' for printing
virtual const char* name() const = 0; // the type name for printing
virtual bool is_constant() const { return false; }
bool is_void() { return tag() == voidTag; }
bool is_int() { return tag() == intTag; }
bool is_long() { return tag() == longTag; }
bool is_float() { return tag() == floatTag; }
bool is_double() { return tag() == doubleTag; }
bool is_object() { return as_ObjectType() != NULL; }
bool is_array() { return as_ArrayType() != NULL; }
bool is_instance() { return as_InstanceType() != NULL; }
bool is_class() { return as_ClassType() != NULL; }
bool is_method() { return as_MethodType() != NULL; }
bool is_method_data() { return as_MethodDataType() != NULL; }
bool is_address() { return as_AddressType() != NULL; }
bool is_illegal() { return tag() == illegalTag; }
bool is_int_kind() const { return tag() == intTag || tag() == longTag; }
bool is_float_kind() const { return tag() == floatTag || tag() == doubleTag; }
bool is_object_kind() const { return tag() == objectTag; }
bool is_single_word() const { return _size == 1; }
bool is_double_word() const { return _size == 2; }
virtual VoidType* as_VoidType() { return NULL; }
virtual IntType* as_IntType() { return NULL; }
virtual LongType* as_LongType() { return NULL; }
virtual FloatType* as_FloatType() { return NULL; }
virtual DoubleType* as_DoubleType() { return NULL; }
virtual ObjectType* as_ObjectType() { return NULL; }
virtual ArrayType* as_ArrayType() { return NULL; }
virtual InstanceType* as_InstanceType() { return NULL; }
virtual ClassType* as_ClassType() { return NULL; }
virtual MetadataType* as_MetadataType() { return NULL; }
virtual MethodType* as_MethodType() { return NULL; }
virtual MethodDataType* as_MethodDataType() { return NULL; }
virtual AddressType* as_AddressType() { return NULL; }
virtual IllegalType* as_IllegalType() { return NULL; }
virtual IntConstant* as_IntConstant() { return NULL; }
virtual LongConstant* as_LongConstant() { return NULL; }
virtual FloatConstant* as_FloatConstant() { return NULL; }
virtual DoubleConstant* as_DoubleConstant() { return NULL; }
virtual ObjectConstant* as_ObjectConstant() { return NULL; }
virtual InstanceConstant* as_InstanceConstant(){ return NULL; }
virtual ClassConstant* as_ClassConstant() { return NULL; }
virtual MethodConstant* as_MethodConstant() { return NULL; }
virtual MethodDataConstant* as_MethodDataConstant() { return NULL; }
virtual ArrayConstant* as_ArrayConstant() { return NULL; }
virtual AddressConstant* as_AddressConstant() { return NULL; }
ValueType* meet(ValueType* y) const;
ValueType* join(ValueType* y) const;
void print(outputStream* s = tty) { s->print("%s", name()); }
};
class VoidType: public ValueType {
public:
VoidType(): ValueType(voidTag, 0) {}
virtual ValueType* base() const { return voidType; }
virtual const char tchar() const { return 'v'; }
virtual const char* name() const { return "void"; }
virtual VoidType* as_VoidType() { return this; }
};
class IntType: public ValueType {
public:
IntType(): ValueType(intTag, 1) {}
virtual ValueType* base() const { return intType; }
virtual const char tchar() const { return 'i'; }
virtual const char* name() const { return "int"; }
virtual IntType* as_IntType() { return this; }
};
class IntConstant: public IntType {
private:
jint _value;
public:
IntConstant(jint value) { _value = value; }
jint value() const { return _value; }
virtual bool is_constant() const { return true; }
virtual IntConstant* as_IntConstant() { return this; }
};
class IntInterval: public IntType {
private:
jint _beg;
jint _end;
public:
IntInterval(jint beg, jint end) {
assert(beg <= end, "illegal interval");
_beg = beg;
_end = end;
}
jint beg() const { return _beg; }
jint end() const { return _end; }
virtual bool is_interval() const { return true; }
};
class LongType: public ValueType {
public:
LongType(): ValueType(longTag, 2) {}
virtual ValueType* base() const { return longType; }
virtual const char tchar() const { return 'l'; }
virtual const char* name() const { return "long"; }
virtual LongType* as_LongType() { return this; }
};
class LongConstant: public LongType {
private:
jlong _value;
public:
LongConstant(jlong value) { _value = value; }
jlong value() const { return _value; }
virtual bool is_constant() const { return true; }
virtual LongConstant* as_LongConstant() { return this; }
};
class FloatType: public ValueType {
public:
FloatType(): ValueType(floatTag, 1) {}
virtual ValueType* base() const { return floatType; }
virtual const char tchar() const { return 'f'; }
virtual const char* name() const { return "float"; }
virtual FloatType* as_FloatType() { return this; }
};
class FloatConstant: public FloatType {
private:
jfloat _value;
public:
FloatConstant(jfloat value) { _value = value; }
jfloat value() const { return _value; }
virtual bool is_constant() const { return true; }
virtual FloatConstant* as_FloatConstant() { return this; }
};
class DoubleType: public ValueType {
public:
DoubleType(): ValueType(doubleTag, 2) {}
virtual ValueType* base() const { return doubleType; }
virtual const char tchar() const { return 'd'; }
virtual const char* name() const { return "double"; }
virtual DoubleType* as_DoubleType() { return this; }
};
class DoubleConstant: public DoubleType {
private:
jdouble _value;
public:
DoubleConstant(jdouble value) { _value = value; }
jdouble value() const { return _value; }
virtual bool is_constant() const { return true; }
virtual DoubleConstant* as_DoubleConstant() { return this; }
};
class ObjectType: public ValueType {
public:
ObjectType(): ValueType(objectTag, 1) {}
virtual ValueType* base() const { return objectType; }
virtual const char tchar() const { return 'a'; }
virtual const char* name() const { return "object"; }
virtual ObjectType* as_ObjectType() { return this; }
virtual ciObject* constant_value() const { ShouldNotReachHere(); return NULL; }
virtual ciType* exact_type() const { return NULL; }
bool is_loaded() const;
jobject encoding() const;
};
class ObjectConstant: public ObjectType {
private:
ciObject* _value;
public:
ObjectConstant(ciObject* value) { _value = value; }
ciObject* value() const { return _value; }
virtual bool is_constant() const { return true; }
virtual ObjectConstant* as_ObjectConstant() { return this; }
virtual ciObject* constant_value() const;
virtual ciType* exact_type() const;
};
class ArrayType: public ObjectType {
public:
virtual ArrayType* as_ArrayType() { return this; }
};
class ArrayConstant: public ArrayType {
private:
ciArray* _value;
public:
ArrayConstant(ciArray* value) { _value = value; }
ciArray* value() const { return _value; }
virtual bool is_constant() const { return true; }
virtual ArrayConstant* as_ArrayConstant() { return this; }
virtual ciObject* constant_value() const;
virtual ciType* exact_type() const;
};
class InstanceType: public ObjectType {
public:
virtual InstanceType* as_InstanceType() { return this; }
};
class InstanceConstant: public InstanceType {
private:
ciInstance* _value;
public:
InstanceConstant(ciInstance* value) { _value = value; }
ciInstance* value() const { return _value; }
virtual bool is_constant() const { return true; }
virtual InstanceConstant* as_InstanceConstant(){ return this; }
virtual ciObject* constant_value() const;
virtual ciType* exact_type() const;
};
class MetadataType: public ValueType {
public:
MetadataType(): ValueType(metaDataTag, 1) {}
virtual ValueType* base() const { return objectType; }
virtual const char tchar() const { return 'a'; }
virtual const char* name() const { return "object"; }
virtual MetadataType* as_MetadataType() { return this; }
bool is_loaded() const;
jobject encoding() const;
virtual ciMetadata* constant_value() const { ShouldNotReachHere(); return NULL; }
};
class ClassType: public MetadataType {
public:
virtual ClassType* as_ClassType() { return this; }
};
class ClassConstant: public ClassType {
private:
ciInstanceKlass* _value;
public:
ClassConstant(ciInstanceKlass* value) { _value = value; }
ciInstanceKlass* value() const { return _value; }
virtual bool is_constant() const { return true; }
virtual ClassConstant* as_ClassConstant() { return this; }
virtual ciMetadata* constant_value() const { return _value; }
virtual ciType* exact_type() const;
};
class MethodType: public MetadataType {
public:
virtual MethodType* as_MethodType() { return this; }
};
class MethodConstant: public MethodType {
private:
ciMethod* _value;
public:
MethodConstant(ciMethod* value) { _value = value; }
ciMethod* value() const { return _value; }
virtual bool is_constant() const { return true; }
virtual MethodConstant* as_MethodConstant() { return this; }
virtual ciMetadata* constant_value() const { return _value; }
};
class MethodDataType: public MetadataType {
public:
virtual MethodDataType* as_MethodDataType() { return this; }
};
class MethodDataConstant: public MethodDataType {
private:
ciMethodData* _value;
public:
MethodDataConstant(ciMethodData* value) { _value = value; }
ciMethodData* value() const { return _value; }
virtual bool is_constant() const { return true; }
virtual MethodDataConstant* as_MethodDataConstant() { return this; }
virtual ciMetadata* constant_value() const { return _value; }
};
class AddressType: public ValueType {
public:
AddressType(): ValueType(addressTag, 1) {}
virtual ValueType* base() const { return addressType; }
virtual const char tchar() const { return 'r'; }
virtual const char* name() const { return "address"; }
virtual AddressType* as_AddressType() { return this; }
};
class AddressConstant: public AddressType {
private:
jint _value;
public:
AddressConstant(jint value) { _value = value; }
jint value() const { return _value; }
virtual bool is_constant() const { return true; }
virtual AddressConstant* as_AddressConstant() { return this; }
};
class IllegalType: public ValueType {
public:
IllegalType(): ValueType(illegalTag, -1) {}
virtual ValueType* base() const { return illegalType; }
virtual const char tchar() const { return ' '; }
virtual const char* name() const { return "illegal"; }
virtual IllegalType* as_IllegalType() { return this; }
};
ValueType* as_ValueType(BasicType type);
ValueType* as_ValueType(ciConstant value);
BasicType as_BasicType(ValueType* type);
inline ValueType* as_ValueType(ciType* type) { return as_ValueType(type->basic_type()); }
#endif // SHARE_VM_C1_C1_VALUETYPE_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/bcEscapeAnalyzer.cpp
#include "precompiled.hpp"
#include "ci/bcEscapeAnalyzer.hpp"
#include "ci/ciConstant.hpp"
#include "ci/ciField.hpp"
#include "ci/ciMethodBlocks.hpp"
#include "ci/ciStreams.hpp"
#include "interpreter/bytecode.hpp"
#include "utilities/bitMap.inline.hpp"
#ifndef PRODUCT
#define TRACE_BCEA(level, code) \
if (EstimateArgEscape && BCEATraceLevel >= level) { \
code; \
}
#else
#define TRACE_BCEA(level, code)
#endif
class BCEscapeAnalyzer::ArgumentMap {
uint _bits;
enum {MAXBIT = 29,
ALLOCATED = 1,
UNKNOWN = 2};
uint int_to_bit(uint e) const {
if (e > MAXBIT)
e = MAXBIT;
return (1 << (e + 2));
}
public:
ArgumentMap() { _bits = 0;}
void set_bits(uint bits) { _bits = bits;}
uint get_bits() const { return _bits;}
void clear() { _bits = 0;}
void set_all() { _bits = ~0u; }
bool is_empty() const { return _bits == 0; }
bool contains(uint var) const { return (_bits & int_to_bit(var)) != 0; }
bool is_singleton(uint var) const { return (_bits == int_to_bit(var)); }
bool contains_unknown() const { return (_bits & UNKNOWN) != 0; }
bool contains_allocated() const { return (_bits & ALLOCATED) != 0; }
bool contains_vars() const { return (_bits & (((1 << MAXBIT) -1) << 2)) != 0; }
void set(uint var) { _bits = int_to_bit(var); }
void add(uint var) { _bits |= int_to_bit(var); }
void add_unknown() { _bits = UNKNOWN; }
void add_allocated() { _bits = ALLOCATED; }
void set_union(const ArgumentMap &am) { _bits |= am._bits; }
void set_intersect(const ArgumentMap &am) { _bits |= am._bits; }
void set_difference(const ArgumentMap &am) { _bits &= ~am._bits; }
void operator=(const ArgumentMap &am) { _bits = am._bits; }
bool operator==(const ArgumentMap &am) { return _bits == am._bits; }
bool operator!=(const ArgumentMap &am) { return _bits != am._bits; }
};
class BCEscapeAnalyzer::StateInfo {
public:
ArgumentMap *_vars;
ArgumentMap *_stack;
int _stack_height;
int _max_stack;
bool _initialized;
ArgumentMap empty_map;
StateInfo() {
empty_map.clear();
}
ArgumentMap raw_pop() { guarantee(_stack_height > 0, "stack underflow"); return _stack[--_stack_height]; }
ArgumentMap apop() { return raw_pop(); }
void spop() { raw_pop(); }
void lpop() { spop(); spop(); }
void raw_push(ArgumentMap i) { guarantee(_stack_height < _max_stack, "stack overflow"); _stack[_stack_height++] = i; }
void apush(ArgumentMap i) { raw_push(i); }
void spush() { raw_push(empty_map); }
void lpush() { spush(); spush(); }
};
void BCEscapeAnalyzer::set_returned(ArgumentMap vars) {
for (int i = 0; i < _arg_size; i++) {
if (vars.contains(i))
_arg_returned.set(i);
}
_return_local = _return_local && !(vars.contains_unknown() || vars.contains_allocated());
_return_allocated = _return_allocated && vars.contains_allocated() && !(vars.contains_unknown() || vars.contains_vars());
}
bool BCEscapeAnalyzer::is_argument(ArgumentMap vars) {
for (int i = 0; i < _arg_size; i++) {
if (vars.contains(i))
return true;
}
return false;
}
bool BCEscapeAnalyzer::is_arg_stack(ArgumentMap vars){
if (_conservative)
return true;
for (int i = 0; i < _arg_size; i++) {
if (vars.contains(i) && _arg_stack.test(i))
return true;
}
return false;
}
bool BCEscapeAnalyzer::returns_all(ArgumentMap vars) {
for (int i = 0; i < _arg_size; i++) {
if (vars.contains(i) && !_arg_returned.test(i)) {
return false;
}
}
return true;
}
void BCEscapeAnalyzer::clear_bits(ArgumentMap vars, VectorSet &bm) {
for (int i = 0; i < _arg_size; i++) {
if (vars.contains(i)) {
bm >>= i;
}
}
}
void BCEscapeAnalyzer::set_method_escape(ArgumentMap vars) {
clear_bits(vars, _arg_local);
if (vars.contains_allocated()) {
_allocated_escapes = true;
}
}
void BCEscapeAnalyzer::set_global_escape(ArgumentMap vars, bool merge) {
clear_bits(vars, _arg_local);
clear_bits(vars, _arg_stack);
if (vars.contains_allocated())
_allocated_escapes = true;
if (merge && !vars.is_empty()) {
if (vars.contains_unknown() || vars.contains_allocated()) {
_return_local = false;
}
if (vars.contains_unknown() || vars.contains_vars()) {
_return_allocated = false;
}
if (_return_local && vars.contains_vars() && !returns_all(vars)) {
_return_local = false;
}
}
}
void BCEscapeAnalyzer::set_dirty(ArgumentMap vars) {
clear_bits(vars, _dirty);
}
void BCEscapeAnalyzer::set_modified(ArgumentMap vars, int offs, int size) {
for (int i = 0; i < _arg_size; i++) {
if (vars.contains(i)) {
set_arg_modified(i, offs, size);
}
}
if (vars.contains_unknown())
_unknown_modified = true;
}
bool BCEscapeAnalyzer::is_recursive_call(ciMethod* callee) {
for (BCEscapeAnalyzer* scope = this; scope != NULL; scope = scope->_parent) {
if (scope->method() == callee) {
return true;
}
}
return false;
}
bool BCEscapeAnalyzer::is_arg_modified(int arg, int offset, int size_in_bytes) {
if (offset == OFFSET_ANY)
return _arg_modified[arg] != 0;
assert(arg >= 0 && arg < _arg_size, "must be an argument.");
bool modified = false;
int l = offset / HeapWordSize;
int h = round_to(offset + size_in_bytes, HeapWordSize) / HeapWordSize;
if (l > ARG_OFFSET_MAX)
l = ARG_OFFSET_MAX;
if (h > ARG_OFFSET_MAX+1)
h = ARG_OFFSET_MAX + 1;
for (int i = l; i < h; i++) {
modified = modified || (_arg_modified[arg] & (1 << i)) != 0;
}
return modified;
}
void BCEscapeAnalyzer::set_arg_modified(int arg, int offset, int size_in_bytes) {
if (offset == OFFSET_ANY) {
_arg_modified[arg] = (uint) -1;
return;
}
assert(arg >= 0 && arg < _arg_size, "must be an argument.");
int l = offset / HeapWordSize;
int h = round_to(offset + size_in_bytes, HeapWordSize) / HeapWordSize;
if (l > ARG_OFFSET_MAX)
l = ARG_OFFSET_MAX;
if (h > ARG_OFFSET_MAX+1)
h = ARG_OFFSET_MAX + 1;
for (int i = l; i < h; i++) {
_arg_modified[arg] |= (1 << i);
}
}
void BCEscapeAnalyzer::invoke(StateInfo &state, Bytecodes::Code code, ciMethod* target, ciKlass* holder) {
int i;
ciInstanceKlass* klass = target->holder();
ciInstanceKlass* calling_klass = method()->holder();
ciInstanceKlass* callee_holder = ciEnv::get_instance_klass_for_declared_method_holder(holder);
ciInstanceKlass* actual_recv = callee_holder;
if (target->is_loaded() && !target->is_abstract() && target->can_be_statically_bound()) {
switch (code) {
case Bytecodes::_invokevirtual:
code = Bytecodes::_invokespecial;
break;
case Bytecodes::_invokehandle:
code = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokespecial;
break;
}
}
int arg_size = target->invoke_arg_size(code);
int arg_base = MAX2(state._stack_height - arg_size, 0);
bool directly_recursive = (method() == target) &&
(code != Bytecodes::_invokevirtual || target->is_final_method() || state._stack[arg_base] .is_empty());
bool skip_callee = true;
for (i = state._stack_height - 1; i >= arg_base && skip_callee; i--) {
ArgumentMap arg = state._stack[i];
skip_callee = !is_argument(arg) || !is_arg_stack(arg) || (directly_recursive && arg.is_singleton(i - arg_base));
}
if (code == Bytecodes::_invokedynamic) {
skip_callee = true;
}
if (skip_callee) {
TRACE_BCEA(3, tty->print_cr("[EA] skipping method %s::%s", holder->name()->as_utf8(), target->name()->as_utf8()));
for (i = 0; i < arg_size; i++) {
set_method_escape(state.raw_pop());
}
_unknown_modified = true; // assume the worst since we don't analyze the called method
return;
}
ciMethod* inline_target = NULL;
if (target->is_loaded() && klass->is_loaded()
&& (klass->is_initialized() || klass->is_interface() && target->holder()->is_initialized())
&& target->is_loaded()) {
if (code == Bytecodes::_invokestatic
|| code == Bytecodes::_invokespecial
|| code == Bytecodes::_invokevirtual && target->is_final_method()) {
inline_target = target;
} else {
inline_target = target->find_monomorphic_target(calling_klass, callee_holder, actual_recv);
}
}
if (inline_target != NULL && !is_recursive_call(inline_target)) {
BCEscapeAnalyzer analyzer(inline_target, this);
bool must_record_dependencies = false;
for (i = arg_size - 1; i >= 0; i--) {
ArgumentMap arg = state.raw_pop();
bool allocated = arg.contains_allocated();
if (!(is_argument(arg) || allocated))
continue;
for (int j = 0; j < _arg_size; j++) {
if (arg.contains(j)) {
_arg_modified[j] |= analyzer._arg_modified[i];
}
}
if (!(is_arg_stack(arg) || allocated)) {
} else if (analyzer.is_arg_stack(i) && !analyzer.is_arg_returned(i)) {
set_method_escape(arg);
must_record_dependencies = true;
} else {
set_global_escape(arg);
}
}
_unknown_modified = _unknown_modified || analyzer.has_non_arg_side_affects();
if (must_record_dependencies) {
if (code == Bytecodes::_invokeinterface || code == Bytecodes::_invokevirtual && !target->is_final_method()) {
_dependencies.append(actual_recv);
_dependencies.append(inline_target);
}
_dependencies.appendAll(analyzer.dependencies());
}
} else {
TRACE_BCEA(1, tty->print_cr("[EA] virtual method %s is not monomorphic.",
target->name()->as_utf8()));
for (i = 0; i < arg_size; i++) {
ArgumentMap arg = state.raw_pop();
if (!is_argument(arg))
continue;
set_modified(arg, OFFSET_ANY, type2size[T_INT]*HeapWordSize);
set_global_escape(arg);
}
_unknown_modified = true; // assume the worst since we don't know the called method
}
}
bool BCEscapeAnalyzer::contains(uint arg_set1, uint arg_set2) {
return ((~arg_set1) | arg_set2) == 0;
}
void BCEscapeAnalyzer::iterate_one_block(ciBlock *blk, StateInfo &state, GrowableArray<ciBlock *> &successors) {
blk->set_processed();
ciBytecodeStream s(method());
int limit_bci = blk->limit_bci();
bool fall_through = false;
ArgumentMap allocated_obj;
allocated_obj.add_allocated();
ArgumentMap unknown_obj;
unknown_obj.add_unknown();
ArgumentMap empty_map;
s.reset_to_bci(blk->start_bci());
while (s.next() != ciBytecodeStream::EOBC() && s.cur_bci() < limit_bci) {
fall_through = true;
switch (s.cur_bc()) {
case Bytecodes::_nop:
break;
case Bytecodes::_aconst_null:
state.apush(unknown_obj);
break;
case Bytecodes::_iconst_m1:
case Bytecodes::_iconst_0:
case Bytecodes::_iconst_1:
case Bytecodes::_iconst_2:
case Bytecodes::_iconst_3:
case Bytecodes::_iconst_4:
case Bytecodes::_iconst_5:
case Bytecodes::_fconst_0:
case Bytecodes::_fconst_1:
case Bytecodes::_fconst_2:
case Bytecodes::_bipush:
case Bytecodes::_sipush:
state.spush();
break;
case Bytecodes::_lconst_0:
case Bytecodes::_lconst_1:
case Bytecodes::_dconst_0:
case Bytecodes::_dconst_1:
state.lpush();
break;
case Bytecodes::_ldc:
case Bytecodes::_ldc_w:
case Bytecodes::_ldc2_w:
{
int index = s.get_constant_pool_index();
constantTag tag = s.get_constant_pool_tag(index);
if (tag.is_long() || tag.is_double()) {
state.lpush();
} else if (tag.basic_type() == T_OBJECT) {
state.apush(unknown_obj);
} else {
state.spush();
}
break;
}
case Bytecodes::_aload:
state.apush(state._vars[s.get_index()]);
break;
case Bytecodes::_iload:
case Bytecodes::_fload:
case Bytecodes::_iload_0:
case Bytecodes::_iload_1:
case Bytecodes::_iload_2:
case Bytecodes::_iload_3:
case Bytecodes::_fload_0:
case Bytecodes::_fload_1:
case Bytecodes::_fload_2:
case Bytecodes::_fload_3:
state.spush();
break;
case Bytecodes::_lload:
case Bytecodes::_dload:
case Bytecodes::_lload_0:
case Bytecodes::_lload_1:
case Bytecodes::_lload_2:
case Bytecodes::_lload_3:
case Bytecodes::_dload_0:
case Bytecodes::_dload_1:
case Bytecodes::_dload_2:
case Bytecodes::_dload_3:
state.lpush();
break;
case Bytecodes::_aload_0:
state.apush(state._vars[0]);
break;
case Bytecodes::_aload_1:
state.apush(state._vars[1]);
break;
case Bytecodes::_aload_2:
state.apush(state._vars[2]);
break;
case Bytecodes::_aload_3:
state.apush(state._vars[3]);
break;
case Bytecodes::_iaload:
case Bytecodes::_faload:
case Bytecodes::_baload:
case Bytecodes::_caload:
case Bytecodes::_saload:
state.spop();
set_method_escape(state.apop());
state.spush();
break;
case Bytecodes::_laload:
case Bytecodes::_daload:
state.spop();
set_method_escape(state.apop());
state.lpush();
break;
case Bytecodes::_aaload:
{ state.spop();
ArgumentMap array = state.apop();
set_method_escape(array);
state.apush(unknown_obj);
set_dirty(array);
}
break;
case Bytecodes::_istore:
case Bytecodes::_fstore:
case Bytecodes::_istore_0:
case Bytecodes::_istore_1:
case Bytecodes::_istore_2:
case Bytecodes::_istore_3:
case Bytecodes::_fstore_0:
case Bytecodes::_fstore_1:
case Bytecodes::_fstore_2:
case Bytecodes::_fstore_3:
state.spop();
break;
case Bytecodes::_lstore:
case Bytecodes::_dstore:
case Bytecodes::_lstore_0:
case Bytecodes::_lstore_1:
case Bytecodes::_lstore_2:
case Bytecodes::_lstore_3:
case Bytecodes::_dstore_0:
case Bytecodes::_dstore_1:
case Bytecodes::_dstore_2:
case Bytecodes::_dstore_3:
state.lpop();
break;
case Bytecodes::_astore:
state._vars[s.get_index()] = state.apop();
break;
case Bytecodes::_astore_0:
state._vars[0] = state.apop();
break;
case Bytecodes::_astore_1:
state._vars[1] = state.apop();
break;
case Bytecodes::_astore_2:
state._vars[2] = state.apop();
break;
case Bytecodes::_astore_3:
state._vars[3] = state.apop();
break;
case Bytecodes::_iastore:
case Bytecodes::_fastore:
case Bytecodes::_bastore:
case Bytecodes::_castore:
case Bytecodes::_sastore:
{
state.spop();
state.spop();
ArgumentMap arr = state.apop();
set_method_escape(arr);
set_modified(arr, OFFSET_ANY, type2size[T_INT]*HeapWordSize);
break;
}
case Bytecodes::_lastore:
case Bytecodes::_dastore:
{
state.lpop();
state.spop();
ArgumentMap arr = state.apop();
set_method_escape(arr);
set_modified(arr, OFFSET_ANY, type2size[T_LONG]*HeapWordSize);
break;
}
case Bytecodes::_aastore:
{
set_global_escape(state.apop());
state.spop();
ArgumentMap arr = state.apop();
set_modified(arr, OFFSET_ANY, type2size[T_OBJECT]*HeapWordSize);
break;
}
case Bytecodes::_pop:
state.raw_pop();
break;
case Bytecodes::_pop2:
state.raw_pop();
state.raw_pop();
break;
case Bytecodes::_dup:
{ ArgumentMap w1 = state.raw_pop();
state.raw_push(w1);
state.raw_push(w1);
}
break;
case Bytecodes::_dup_x1:
{ ArgumentMap w1 = state.raw_pop();
ArgumentMap w2 = state.raw_pop();
state.raw_push(w1);
state.raw_push(w2);
state.raw_push(w1);
}
break;
case Bytecodes::_dup_x2:
{ ArgumentMap w1 = state.raw_pop();
ArgumentMap w2 = state.raw_pop();
ArgumentMap w3 = state.raw_pop();
state.raw_push(w1);
state.raw_push(w3);
state.raw_push(w2);
state.raw_push(w1);
}
break;
case Bytecodes::_dup2:
{ ArgumentMap w1 = state.raw_pop();
ArgumentMap w2 = state.raw_pop();
state.raw_push(w2);
state.raw_push(w1);
state.raw_push(w2);
state.raw_push(w1);
}
break;
case Bytecodes::_dup2_x1:
{ ArgumentMap w1 = state.raw_pop();
ArgumentMap w2 = state.raw_pop();
ArgumentMap w3 = state.raw_pop();
state.raw_push(w2);
state.raw_push(w1);
state.raw_push(w3);
state.raw_push(w2);
state.raw_push(w1);
}
break;
case Bytecodes::_dup2_x2:
{ ArgumentMap w1 = state.raw_pop();
ArgumentMap w2 = state.raw_pop();
ArgumentMap w3 = state.raw_pop();
ArgumentMap w4 = state.raw_pop();
state.raw_push(w2);
state.raw_push(w1);
state.raw_push(w4);
state.raw_push(w3);
state.raw_push(w2);
state.raw_push(w1);
}
break;
case Bytecodes::_swap:
{ ArgumentMap w1 = state.raw_pop();
ArgumentMap w2 = state.raw_pop();
state.raw_push(w1);
state.raw_push(w2);
}
break;
case Bytecodes::_iadd:
case Bytecodes::_fadd:
case Bytecodes::_isub:
case Bytecodes::_fsub:
case Bytecodes::_imul:
case Bytecodes::_fmul:
case Bytecodes::_idiv:
case Bytecodes::_fdiv:
case Bytecodes::_irem:
case Bytecodes::_frem:
case Bytecodes::_iand:
case Bytecodes::_ior:
case Bytecodes::_ixor:
state.spop();
state.spop();
state.spush();
break;
case Bytecodes::_ladd:
case Bytecodes::_dadd:
case Bytecodes::_lsub:
case Bytecodes::_dsub:
case Bytecodes::_lmul:
case Bytecodes::_dmul:
case Bytecodes::_ldiv:
case Bytecodes::_ddiv:
case Bytecodes::_lrem:
case Bytecodes::_drem:
case Bytecodes::_land:
case Bytecodes::_lor:
case Bytecodes::_lxor:
state.lpop();
state.lpop();
state.lpush();
break;
case Bytecodes::_ishl:
case Bytecodes::_ishr:
case Bytecodes::_iushr:
state.spop();
state.spop();
state.spush();
break;
case Bytecodes::_lshl:
case Bytecodes::_lshr:
case Bytecodes::_lushr:
state.spop();
state.lpop();
state.lpush();
break;
case Bytecodes::_ineg:
case Bytecodes::_fneg:
state.spop();
state.spush();
break;
case Bytecodes::_lneg:
case Bytecodes::_dneg:
state.lpop();
state.lpush();
break;
case Bytecodes::_iinc:
break;
case Bytecodes::_i2l:
case Bytecodes::_i2d:
case Bytecodes::_f2l:
case Bytecodes::_f2d:
state.spop();
state.lpush();
break;
case Bytecodes::_i2f:
case Bytecodes::_f2i:
state.spop();
state.spush();
break;
case Bytecodes::_l2i:
case Bytecodes::_l2f:
case Bytecodes::_d2i:
case Bytecodes::_d2f:
state.lpop();
state.spush();
break;
case Bytecodes::_l2d:
case Bytecodes::_d2l:
state.lpop();
state.lpush();
break;
case Bytecodes::_i2b:
case Bytecodes::_i2c:
case Bytecodes::_i2s:
state.spop();
state.spush();
break;
case Bytecodes::_lcmp:
case Bytecodes::_dcmpl:
case Bytecodes::_dcmpg:
state.lpop();
state.lpop();
state.spush();
break;
case Bytecodes::_fcmpl:
case Bytecodes::_fcmpg:
state.spop();
state.spop();
state.spush();
break;
case Bytecodes::_ifeq:
case Bytecodes::_ifne:
case Bytecodes::_iflt:
case Bytecodes::_ifge:
case Bytecodes::_ifgt:
case Bytecodes::_ifle:
{
state.spop();
int dest_bci = s.get_dest();
assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");
assert(s.next_bci() == limit_bci, "branch must end block");
successors.push(_methodBlocks->block_containing(dest_bci));
break;
}
case Bytecodes::_if_icmpeq:
case Bytecodes::_if_icmpne:
case Bytecodes::_if_icmplt:
case Bytecodes::_if_icmpge:
case Bytecodes::_if_icmpgt:
case Bytecodes::_if_icmple:
{
state.spop();
state.spop();
int dest_bci = s.get_dest();
assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");
assert(s.next_bci() == limit_bci, "branch must end block");
successors.push(_methodBlocks->block_containing(dest_bci));
break;
}
case Bytecodes::_if_acmpeq:
case Bytecodes::_if_acmpne:
{
set_method_escape(state.apop());
set_method_escape(state.apop());
int dest_bci = s.get_dest();
assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");
assert(s.next_bci() == limit_bci, "branch must end block");
successors.push(_methodBlocks->block_containing(dest_bci));
break;
}
case Bytecodes::_goto:
{
int dest_bci = s.get_dest();
assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");
assert(s.next_bci() == limit_bci, "branch must end block");
successors.push(_methodBlocks->block_containing(dest_bci));
fall_through = false;
break;
}
case Bytecodes::_jsr:
{
int dest_bci = s.get_dest();
assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");
assert(s.next_bci() == limit_bci, "branch must end block");
state.apush(empty_map);
successors.push(_methodBlocks->block_containing(dest_bci));
fall_through = false;
break;
}
case Bytecodes::_ret:
assert(s.next_bci() == limit_bci, "branch must end block");
fall_through = false;
break;
case Bytecodes::_return:
assert(s.next_bci() == limit_bci, "return must end block");
fall_through = false;
break;
case Bytecodes::_tableswitch:
{
state.spop();
Bytecode_tableswitch sw(&s);
int len = sw.length();
int dest_bci;
for (int i = 0; i < len; i++) {
dest_bci = s.cur_bci() + sw.dest_offset_at(i);
assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");
successors.push(_methodBlocks->block_containing(dest_bci));
}
dest_bci = s.cur_bci() + sw.default_offset();
assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");
successors.push(_methodBlocks->block_containing(dest_bci));
assert(s.next_bci() == limit_bci, "branch must end block");
fall_through = false;
break;
}
case Bytecodes::_lookupswitch:
{
state.spop();
Bytecode_lookupswitch sw(&s);
int len = sw.number_of_pairs();
int dest_bci;
for (int i = 0; i < len; i++) {
dest_bci = s.cur_bci() + sw.pair_at(i).offset();
assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");
successors.push(_methodBlocks->block_containing(dest_bci));
}
dest_bci = s.cur_bci() + sw.default_offset();
assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");
successors.push(_methodBlocks->block_containing(dest_bci));
fall_through = false;
break;
}
case Bytecodes::_ireturn:
case Bytecodes::_freturn:
state.spop();
fall_through = false;
break;
case Bytecodes::_lreturn:
case Bytecodes::_dreturn:
state.lpop();
fall_through = false;
break;
case Bytecodes::_areturn:
set_returned(state.apop());
fall_through = false;
break;
case Bytecodes::_getstatic:
case Bytecodes::_getfield:
{ bool ignored_will_link;
ciField* field = s.get_field(ignored_will_link);
BasicType field_type = field->type()->basic_type();
if (s.cur_bc() != Bytecodes::_getstatic) {
set_method_escape(state.apop());
}
if (field_type == T_OBJECT || field_type == T_ARRAY) {
state.apush(unknown_obj);
} else if (type2size[field_type] == 1) {
state.spush();
} else {
state.lpush();
}
}
break;
case Bytecodes::_putstatic:
case Bytecodes::_putfield:
{ bool will_link;
ciField* field = s.get_field(will_link);
BasicType field_type = field->type()->basic_type();
if (field_type == T_OBJECT || field_type == T_ARRAY) {
set_global_escape(state.apop());
} else if (type2size[field_type] == 1) {
state.spop();
} else {
state.lpop();
}
if (s.cur_bc() != Bytecodes::_putstatic) {
ArgumentMap p = state.apop();
set_method_escape(p);
set_modified(p, will_link ? field->offset() : OFFSET_ANY, type2size[field_type]*HeapWordSize);
}
}
break;
case Bytecodes::_invokevirtual:
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
case Bytecodes::_invokedynamic:
case Bytecodes::_invokeinterface:
{ bool ignored_will_link;
ciSignature* declared_signature = NULL;
ciMethod* target = s.get_method(ignored_will_link, &declared_signature);
ciKlass* holder = s.get_declared_method_holder();
assert(declared_signature != NULL, "cannot be null");
if (s.has_appendix()) {
state.apush(unknown_obj);
}
invoke(state, s.cur_bc_raw(), target, holder);
ciType* return_type = declared_signature->return_type();
if (!return_type->is_primitive_type()) {
state.apush(unknown_obj);
} else if (return_type->is_one_word()) {
state.spush();
} else if (return_type->is_two_word()) {
state.lpush();
}
}
break;
case Bytecodes::_new:
state.apush(allocated_obj);
break;
case Bytecodes::_newarray:
case Bytecodes::_anewarray:
state.spop();
state.apush(allocated_obj);
break;
case Bytecodes::_multianewarray:
{ int i = s.cur_bcp()[3];
while (i-- > 0) state.spop();
state.apush(allocated_obj);
}
break;
case Bytecodes::_arraylength:
set_method_escape(state.apop());
state.spush();
break;
case Bytecodes::_athrow:
set_global_escape(state.apop());
fall_through = false;
break;
case Bytecodes::_checkcast:
{ ArgumentMap obj = state.apop();
set_method_escape(obj);
state.apush(obj);
}
break;
case Bytecodes::_instanceof:
set_method_escape(state.apop());
state.spush();
break;
case Bytecodes::_monitorenter:
case Bytecodes::_monitorexit:
state.apop();
break;
case Bytecodes::_wide:
ShouldNotReachHere();
break;
case Bytecodes::_ifnull:
case Bytecodes::_ifnonnull:
{
set_method_escape(state.apop());
int dest_bci = s.get_dest();
assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");
assert(s.next_bci() == limit_bci, "branch must end block");
successors.push(_methodBlocks->block_containing(dest_bci));
break;
}
case Bytecodes::_goto_w:
{
int dest_bci = s.get_far_dest();
assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");
assert(s.next_bci() == limit_bci, "branch must end block");
successors.push(_methodBlocks->block_containing(dest_bci));
fall_through = false;
break;
}
case Bytecodes::_jsr_w:
{
int dest_bci = s.get_far_dest();
assert(_methodBlocks->is_block_start(dest_bci), "branch destination must start a block");
assert(s.next_bci() == limit_bci, "branch must end block");
state.apush(empty_map);
successors.push(_methodBlocks->block_containing(dest_bci));
fall_through = false;
break;
}
case Bytecodes::_breakpoint:
break;
default:
ShouldNotReachHere();
break;
}
}
if (fall_through) {
int fall_through_bci = s.cur_bci();
if (fall_through_bci < _method->code_size()) {
assert(_methodBlocks->is_block_start(fall_through_bci), "must fall through to block start.");
successors.push(_methodBlocks->block_containing(fall_through_bci));
}
}
}
void BCEscapeAnalyzer::merge_block_states(StateInfo *blockstates, ciBlock *dest, StateInfo *s_state) {
StateInfo *d_state = blockstates + dest->index();
int nlocals = _method->max_locals();
if (dest->is_handler())
return;
if (!d_state->_initialized ) {
for (int i = 0; i < nlocals; i++) {
d_state->_vars[i] = s_state->_vars[i];
}
for (int i = 0; i < s_state->_stack_height; i++) {
d_state->_stack[i] = s_state->_stack[i];
}
d_state->_stack_height = s_state->_stack_height;
d_state->_max_stack = s_state->_max_stack;
d_state->_initialized = true;
} else if (!dest->processed()) {
assert(d_state->_stack_height == s_state->_stack_height, "computed stack heights must match");
for (int i = 0; i < nlocals; i++) {
d_state->_vars[i].set_union(s_state->_vars[i]);
}
for (int i = 0; i < s_state->_stack_height; i++) {
d_state->_stack[i].set_union(s_state->_stack[i]);
}
} else {
assert(d_state->_stack_height == s_state->_stack_height, "computed stack heights must match");
ArgumentMap extra_vars;
for (int i = 0; i < nlocals; i++) {
ArgumentMap t;
t = s_state->_vars[i];
t.set_difference(d_state->_vars[i]);
extra_vars.set_union(t);
}
for (int i = 0; i < s_state->_stack_height; i++) {
ArgumentMap t;
t.clear();
t = s_state->_stack[i];
t.set_difference(d_state->_stack[i]);
extra_vars.set_union(t);
}
set_global_escape(extra_vars, true);
}
}
void BCEscapeAnalyzer::iterate_blocks(Arena *arena) {
int numblocks = _methodBlocks->num_blocks();
int stkSize = _method->max_stack();
int numLocals = _method->max_locals();
StateInfo state;
int datacount = (numblocks + 1) * (stkSize + numLocals);
int datasize = datacount * sizeof(ArgumentMap);
StateInfo *blockstates = (StateInfo *) arena->Amalloc(numblocks * sizeof(StateInfo));
ArgumentMap *statedata = (ArgumentMap *) arena->Amalloc(datasize);
for (int i = 0; i < datacount; i++) ::new ((void*)&statedata[i]) ArgumentMap();
ArgumentMap *dp = statedata;
state._vars = dp;
dp += numLocals;
state._stack = dp;
dp += stkSize;
state._initialized = false;
state._max_stack = stkSize;
for (int i = 0; i < numblocks; i++) {
blockstates[i]._vars = dp;
dp += numLocals;
blockstates[i]._stack = dp;
dp += stkSize;
blockstates[i]._initialized = false;
blockstates[i]._stack_height = 0;
blockstates[i]._max_stack = stkSize;
}
GrowableArray<ciBlock *> worklist(arena, numblocks / 4, 0, NULL);
GrowableArray<ciBlock *> successors(arena, 4, 0, NULL);
_methodBlocks->clear_processed();
ArgumentMap allVars; // all oop arguments to method
ciSignature* sig = method()->signature();
int j = 0;
ciBlock* first_blk = _methodBlocks->block_containing(0);
int fb_i = first_blk->index();
if (!method()->is_static()) {
blockstates[fb_i]._vars[j].set(j);
allVars.add(j);
j++;
}
for (int i = 0; i < sig->count(); i++) {
ciType* t = sig->type_at(i);
if (!t->is_primitive_type()) {
blockstates[fb_i]._vars[j].set(j);
allVars.add(j);
}
j += t->size();
}
blockstates[fb_i]._initialized = true;
assert(j == _arg_size, "just checking");
ArgumentMap unknown_map;
unknown_map.add_unknown();
worklist.push(first_blk);
while(worklist.length() > 0) {
ciBlock *blk = worklist.pop();
StateInfo *blkState = blockstates + blk->index();
if (blk->is_handler() || blk->is_ret_target()) {
for (int i = 0; i < numLocals; i++) {
state._vars[i] = allVars;
}
if (blk->is_handler()) {
state._stack_height = 1;
} else {
state._stack_height = blkState->_stack_height;
}
for (int i = 0; i < state._stack_height; i++) {
state._stack[i] = allVars;
}
} else {
for (int i = 0; i < numLocals; i++) {
state._vars[i] = blkState->_vars[i];
}
for (int i = 0; i < blkState->_stack_height; i++) {
state._stack[i] = blkState->_stack[i];
}
state._stack_height = blkState->_stack_height;
}
iterate_one_block(blk, state, successors);
if (blk->has_handler()) {
DEBUG_ONLY(int handler_count = 0;)
int blk_start = blk->start_bci();
int blk_end = blk->limit_bci();
for (int i = 0; i < numblocks; i++) {
ciBlock *b = _methodBlocks->block(i);
if (b->is_handler()) {
int ex_start = b->ex_start_bci();
int ex_end = b->ex_limit_bci();
if ((ex_start >= blk_start && ex_start < blk_end) ||
(ex_end > blk_start && ex_end <= blk_end)) {
successors.push(b);
}
DEBUG_ONLY(handler_count++;)
}
}
assert(handler_count > 0, "must find at least one handler");
}
while(successors.length() > 0) {
ciBlock *succ = successors.pop();
merge_block_states(blockstates, succ, &state);
if (!succ->processed())
worklist.push(succ);
}
}
}
void BCEscapeAnalyzer::do_analysis() {
Arena* arena = CURRENT_ENV->arena();
_methodBlocks = _method->get_method_blocks();
iterate_blocks(arena);
}
vmIntrinsics::ID BCEscapeAnalyzer::known_intrinsic() {
vmIntrinsics::ID iid = method()->intrinsic_id();
if (iid == vmIntrinsics::_getClass ||
iid == vmIntrinsics::_fillInStackTrace ||
iid == vmIntrinsics::_hashCode) {
return iid;
} else {
return vmIntrinsics::_none;
}
}
void BCEscapeAnalyzer::compute_escape_for_intrinsic(vmIntrinsics::ID iid) {
ArgumentMap arg;
arg.clear();
switch (iid) {
case vmIntrinsics::_getClass:
_return_local = false;
_return_allocated = false;
break;
case vmIntrinsics::_fillInStackTrace:
arg.set(0); // 'this'
set_returned(arg);
break;
case vmIntrinsics::_hashCode:
break;
default:
assert(false, "unexpected intrinsic");
}
}
void BCEscapeAnalyzer::initialize() {
int i;
methodData()->clear_escape_info();
ciSignature* sig = method()->signature();
int j = 0;
if (!method()->is_static()) {
_arg_local.set(0);
_arg_stack.set(0);
j++;
}
for (i = 0; i < sig->count(); i++) {
ciType* t = sig->type_at(i);
if (!t->is_primitive_type()) {
_arg_local.set(j);
_arg_stack.set(j);
}
j += t->size();
}
assert(j == _arg_size, "just checking");
ciType *rt = _method->return_type();
if (rt->is_primitive_type()) {
_return_local = false;
_return_allocated = false;
} else {
_return_local = true;
_return_allocated = true;
}
_allocated_escapes = false;
_unknown_modified = false;
}
void BCEscapeAnalyzer::clear_escape_info() {
ciSignature* sig = method()->signature();
int arg_count = sig->count();
ArgumentMap var;
if (!method()->is_static()) {
arg_count++; // allow for "this"
}
for (int i = 0; i < arg_count; i++) {
set_arg_modified(i, OFFSET_ANY, 4);
var.clear();
var.set(i);
set_modified(var, OFFSET_ANY, 4);
set_global_escape(var);
}
_arg_local.Clear();
_arg_stack.Clear();
_arg_returned.Clear();
_return_local = false;
_return_allocated = false;
_allocated_escapes = true;
_unknown_modified = true;
}
void BCEscapeAnalyzer::compute_escape_info() {
int i;
assert(!methodData()->has_escape_info(), "do not overwrite escape info");
vmIntrinsics::ID iid = known_intrinsic();
if (iid == vmIntrinsics::_none && (method()->is_abstract() || method()->is_native() || !method()->holder()->is_initialized()
|| _level > MaxBCEAEstimateLevel
|| method()->code_size() > MaxBCEAEstimateSize)) {
if (BCEATraceLevel >= 1) {
tty->print("Skipping method because: ");
if (method()->is_abstract())
tty->print_cr("method is abstract.");
else if (method()->is_native())
tty->print_cr("method is native.");
else if (!method()->holder()->is_initialized())
tty->print_cr("class of method is not initialized.");
else if (_level > MaxBCEAEstimateLevel)
tty->print_cr("level (%d) exceeds MaxBCEAEstimateLevel (%d).",
_level, (int) MaxBCEAEstimateLevel);
else if (method()->code_size() > MaxBCEAEstimateSize)
tty->print_cr("code size (%d) exceeds MaxBCEAEstimateSize (%d).",
method()->code_size(), (int) MaxBCEAEstimateSize);
else
ShouldNotReachHere();
}
clear_escape_info();
return;
}
if (BCEATraceLevel >= 1) {
tty->print("[EA] estimating escape information for");
if (iid != vmIntrinsics::_none)
tty->print(" intrinsic");
method()->print_short_name();
tty->print_cr(" (%d bytes)", method()->code_size());
}
initialize();
if (_arg_local.Size() == 0 && !_return_allocated) {
clear_escape_info();
methodData()->set_eflag(MethodData::allocated_escapes);
methodData()->set_eflag(MethodData::unknown_modified);
methodData()->set_eflag(MethodData::estimated);
return;
}
if (iid != vmIntrinsics::_none)
compute_escape_for_intrinsic(iid);
else {
do_analysis();
}
if (!has_dependencies() && !methodData()->is_empty()) {
for (i = 0; i < _arg_size; i++) {
if (_arg_local.test(i)) {
assert(_arg_stack.test(i), "inconsistent escape info");
methodData()->set_arg_local(i);
methodData()->set_arg_stack(i);
} else if (_arg_stack.test(i)) {
methodData()->set_arg_stack(i);
}
if (_arg_returned.test(i)) {
methodData()->set_arg_returned(i);
}
methodData()->set_arg_modified(i, _arg_modified[i]);
}
if (_return_local) {
methodData()->set_eflag(MethodData::return_local);
}
if (_return_allocated) {
methodData()->set_eflag(MethodData::return_allocated);
}
if (_allocated_escapes) {
methodData()->set_eflag(MethodData::allocated_escapes);
}
if (_unknown_modified) {
methodData()->set_eflag(MethodData::unknown_modified);
}
methodData()->set_eflag(MethodData::estimated);
}
}
void BCEscapeAnalyzer::read_escape_info() {
assert(methodData()->has_escape_info(), "no escape info available");
for (int i = 0; i < _arg_size; i++) {
if (methodData()->is_arg_local(i))
_arg_local.set(i);
if (methodData()->is_arg_stack(i))
_arg_stack.set(i);
if (methodData()->is_arg_returned(i))
_arg_returned.set(i);
_arg_modified[i] = methodData()->arg_modified(i);
}
_return_local = methodData()->eflag_set(MethodData::return_local);
_return_allocated = methodData()->eflag_set(MethodData::return_allocated);
_allocated_escapes = methodData()->eflag_set(MethodData::allocated_escapes);
_unknown_modified = methodData()->eflag_set(MethodData::unknown_modified);
}
#ifndef PRODUCT
void BCEscapeAnalyzer::dump() {
tty->print("[EA] estimated escape information for");
method()->print_short_name();
tty->print_cr(has_dependencies() ? " (not stored)" : "");
tty->print(" non-escaping args: ");
_arg_local.print_on(tty);
tty->print(" stack-allocatable args: ");
_arg_stack.print_on(tty);
if (_return_local) {
tty->print(" returned args: ");
_arg_returned.print_on(tty);
} else if (is_return_allocated()) {
tty->print_cr(" return allocated value");
} else {
tty->print_cr(" return non-local value");
}
tty->print(" modified args: ");
for (int i = 0; i < _arg_size; i++) {
if (_arg_modified[i] == 0)
tty->print(" 0");
else
tty->print(" 0x%x", _arg_modified[i]);
}
tty->cr();
tty->print(" flags: ");
if (_return_allocated)
tty->print(" return_allocated");
if (_allocated_escapes)
tty->print(" allocated_escapes");
if (_unknown_modified)
tty->print(" unknown_modified");
tty->cr();
}
#endif
BCEscapeAnalyzer::BCEscapeAnalyzer(ciMethod* method, BCEscapeAnalyzer* parent)
: _conservative(method == NULL || !EstimateArgEscape)
, _arena(CURRENT_ENV->arena())
, _method(method)
, _methodData(method ? method->method_data() : NULL)
, _arg_size(method ? method->arg_size() : 0)
, _arg_local(_arena)
, _arg_stack(_arena)
, _arg_returned(_arena)
, _dirty(_arena)
, _return_local(false)
, _return_allocated(false)
, _allocated_escapes(false)
, _unknown_modified(false)
, _dependencies(_arena, 4, 0, NULL)
, _parent(parent)
, _level(parent == NULL ? 0 : parent->level() + 1) {
if (!_conservative) {
_arg_local.Clear();
_arg_stack.Clear();
_arg_returned.Clear();
_dirty.Clear();
Arena* arena = CURRENT_ENV->arena();
_arg_modified = (uint *) arena->Amalloc(_arg_size * sizeof(uint));
Copy::zero_to_bytes(_arg_modified, _arg_size * sizeof(uint));
if (methodData() == NULL)
return;
bool printit = _method->should_print_assembly();
if (methodData()->has_escape_info()) {
TRACE_BCEA(2, tty->print_cr("[EA] Reading previous results for %s.%s",
method->holder()->name()->as_utf8(),
method->name()->as_utf8()));
read_escape_info();
} else {
TRACE_BCEA(2, tty->print_cr("[EA] computing results for %s.%s",
method->holder()->name()->as_utf8(),
method->name()->as_utf8()));
compute_escape_info();
methodData()->update_escape_info();
}
#ifndef PRODUCT
if (BCEATraceLevel >= 3) {
dump();
}
#endif
}
}
void BCEscapeAnalyzer::copy_dependencies(Dependencies *deps) {
if (ciEnv::current()->jvmti_can_hotswap_or_post_breakpoint()) {
deps->assert_evol_method(method());
}
for (int i = 0; i < _dependencies.length(); i+=2) {
ciKlass *k = _dependencies.at(i)->as_klass();
ciMethod *m = _dependencies.at(i+1)->as_method();
deps->assert_unique_concrete_method(k, m);
}
}
C:\hotspot-69087d08d473\src\share\vm/ci/bcEscapeAnalyzer.hpp
#ifndef SHARE_VM_CI_BCESCAPEANALYZER_HPP
#define SHARE_VM_CI_BCESCAPEANALYZER_HPP
#ifdef COMPILER2
#include "ci/ciObject.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciMethodData.hpp"
#include "code/dependencies.hpp"
#include "libadt/vectset.hpp"
#include "memory/allocation.hpp"
#include "utilities/growableArray.hpp"
#endif
class ciMethodBlocks;
class ciBlock;
class BCEscapeAnalyzer : public ResourceObj {
private:
Arena* _arena; // ciEnv arena
bool _conservative; // If true, return maximally
ciMethod* _method;
ciMethodData* _methodData;
int _arg_size;
VectorSet _arg_local;
VectorSet _arg_stack;
VectorSet _arg_returned;
VectorSet _dirty;
enum{ ARG_OFFSET_MAX = 31};
uint *_arg_modified;
bool _return_local;
bool _return_allocated;
bool _allocated_escapes;
bool _unknown_modified;
GrowableArray<ciMetadata *> _dependencies;
ciMethodBlocks *_methodBlocks;
BCEscapeAnalyzer* _parent;
int _level;
public:
class ArgumentMap;
class StateInfo;
private:
bool is_argument(int i) { return i >= 0 && i < _arg_size; }
void set_returned(ArgumentMap vars);
bool is_argument(ArgumentMap vars);
bool is_arg_stack(ArgumentMap vars);
bool returns_all(ArgumentMap vars);
void clear_bits(ArgumentMap vars, VectorSet &bs);
void set_method_escape(ArgumentMap vars);
void set_global_escape(ArgumentMap vars, bool merge = false);
void set_dirty(ArgumentMap vars);
void set_modified(ArgumentMap vars, int offs, int size);
bool is_recursive_call(ciMethod* callee);
void add_dependence(ciKlass *klass, ciMethod *meth);
void propagate_dependencies(ciMethod *meth);
void invoke(StateInfo &state, Bytecodes::Code code, ciMethod* target, ciKlass* holder);
void iterate_one_block(ciBlock *blk, StateInfo &state, GrowableArray<ciBlock *> &successors);
void iterate_blocks(Arena *);
void merge_block_states(StateInfo *blockstates, ciBlock *dest, StateInfo *s_state);
void initialize();
void clear_escape_info();
void compute_escape_info();
vmIntrinsics::ID known_intrinsic();
void compute_escape_for_intrinsic(vmIntrinsics::ID iid);
void do_analysis();
void read_escape_info();
bool contains(uint arg_set1, uint arg_set2);
public:
BCEscapeAnalyzer(ciMethod* method, BCEscapeAnalyzer* parent = NULL);
ciMethod* method() const { return _method; }
ciMethodData* methodData() const { return _methodData; }
BCEscapeAnalyzer* parent() const { return _parent; }
int level() const { return _level; }
GrowableArray<ciMetadata *>* dependencies() { return &_dependencies; }
bool has_dependencies() const { return !_dependencies.is_empty(); }
bool is_arg_local(int i) const {
return !_conservative && _arg_local.test(i);
}
bool is_arg_stack(int i) const {
return !_conservative && _arg_stack.test(i);
}
bool is_arg_returned(int i) const {
return !_conservative && _arg_returned.test(i); }
bool is_return_local() const {
return !_conservative && _return_local;
}
bool is_return_allocated() const {
return !_conservative && _return_allocated && !_allocated_escapes;
}
enum {OFFSET_ANY = -1};
bool is_arg_modified(int arg, int offset, int size_in_bytes);
void set_arg_modified(int arg, int offset, int size_in_bytes);
bool has_non_arg_side_affects() { return _unknown_modified; }
void copy_dependencies(Dependencies *deps);
#ifndef PRODUCT
void dump();
#endif
};
#endif // SHARE_VM_CI_BCESCAPEANALYZER_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciArray.cpp
#include "precompiled.hpp"
#include "ci/ciArray.hpp"
#include "ci/ciArrayKlass.hpp"
#include "ci/ciConstant.hpp"
#include "ci/ciKlass.hpp"
#include "ci/ciUtilities.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/typeArrayOop.hpp"
static BasicType fixup_element_type(BasicType bt) {
if (bt == T_ARRAY) return T_OBJECT;
if (bt == T_BOOLEAN) return T_BYTE;
return bt;
}
ciConstant ciArray::element_value_impl(BasicType elembt,
arrayOop ary,
int index) {
if (ary == NULL)
return ciConstant();
assert(ary->is_array(), "");
if (index < 0 || index >= ary->length())
return ciConstant();
ArrayKlass* ak = (ArrayKlass*) ary->klass();
BasicType abt = ak->element_type();
if (fixup_element_type(elembt) !=
fixup_element_type(abt))
return ciConstant();
switch (elembt) {
case T_ARRAY:
case T_OBJECT:
{
assert(ary->is_objArray(), "");
objArrayOop objary = (objArrayOop) ary;
oop elem = objary->obj_at(index);
ciEnv* env = CURRENT_ENV;
ciObject* box = env->get_object(elem);
return ciConstant(T_OBJECT, box);
}
}
assert(ary->is_typeArray(), "");
typeArrayOop tary = (typeArrayOop) ary;
jint value = 0;
switch (elembt) {
case T_LONG: return ciConstant(tary->long_at(index));
case T_FLOAT: return ciConstant(tary->float_at(index));
case T_DOUBLE: return ciConstant(tary->double_at(index));
default: return ciConstant();
case T_BYTE: value = tary->byte_at(index); break;
case T_BOOLEAN: value = tary->byte_at(index) & 1; break;
case T_SHORT: value = tary->short_at(index); break;
case T_CHAR: value = tary->char_at(index); break;
case T_INT: value = tary->int_at(index); break;
}
return ciConstant(elembt, value);
}
ciConstant ciArray::element_value(int index) {
BasicType elembt = element_basic_type();
GUARDED_VM_ENTRY(
return element_value_impl(elembt, get_arrayOop(), index);
)
}
ciConstant ciArray::element_value_by_offset(intptr_t element_offset) {
BasicType elembt = element_basic_type();
intptr_t shift = exact_log2(type2aelembytes(elembt));
intptr_t header = arrayOopDesc::base_offset_in_bytes(elembt);
intptr_t index = (element_offset - header) >> shift;
intptr_t offset = header + ((intptr_t)index << shift);
if (offset != element_offset || index != (jint)index)
return ciConstant();
return element_value((jint) index);
}
void ciArray::print_impl(outputStream* st) {
st->print(" length=%d type=", length());
klass()->print(st);
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciArray.hpp
#ifndef SHARE_VM_CI_CIARRAY_HPP
#define SHARE_VM_CI_CIARRAY_HPP
#include "ci/ciArrayKlass.hpp"
#include "ci/ciConstant.hpp"
#include "ci/ciObject.hpp"
#include "oops/arrayOop.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/typeArrayOop.hpp"
class ciArray : public ciObject {
private:
int _length;
protected:
ciArray( arrayHandle h_a) : ciObject(h_a), _length(h_a()->length()) {}
ciArray( objArrayHandle h_a) : ciObject(h_a), _length(h_a()->length()) {}
ciArray(typeArrayHandle h_a) : ciObject(h_a), _length(h_a()->length()) {}
ciArray(ciKlass* klass, int len) : ciObject(klass), _length(len) {}
arrayOop get_arrayOop() const { return (arrayOop)get_oop(); }
const char* type_string() { return "ciArray"; }
void print_impl(outputStream* st);
ciConstant element_value_impl(BasicType elembt, arrayOop ary, int index);
public:
int length() { return _length; }
ciArrayKlass* array_type() { return klass()->as_array_klass(); }
ciType* element_type() { return array_type()->element_type(); }
BasicType element_basic_type() { return element_type()->basic_type(); }
ciConstant element_value(int index);
ciConstant element_value_by_offset(intptr_t element_offset);
bool is_array() { return true; }
bool is_java_object() { return true; }
};
#endif // SHARE_VM_CI_CIARRAY_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciArrayKlass.cpp
#include "precompiled.hpp"
#include "ci/ciArrayKlass.hpp"
#include "ci/ciObjArrayKlass.hpp"
#include "ci/ciTypeArrayKlass.hpp"
#include "ci/ciUtilities.hpp"
ciArrayKlass::ciArrayKlass(KlassHandle h_k) : ciKlass(h_k) {
assert(get_Klass()->oop_is_array(), "wrong type");
_dimension = get_ArrayKlass()->dimension();
}
ciArrayKlass::ciArrayKlass(ciSymbol* name, int dimension, BasicType bt)
: ciKlass(name, bt) {
_dimension = dimension;
}
ciType* ciArrayKlass::element_type() {
if (is_type_array_klass()) {
return ciType::make(as_type_array_klass()->element_type());
} else {
return as_obj_array_klass()->element_klass()->as_klass();
}
}
ciType* ciArrayKlass::base_element_type() {
if (is_type_array_klass()) {
return ciType::make(as_type_array_klass()->element_type());
} else {
ciKlass* ek = as_obj_array_klass()->base_element_klass();
if (ek->is_type_array_klass()) {
return ciType::make(ek->as_type_array_klass()->element_type());
}
return ek;
}
}
bool ciArrayKlass::is_leaf_type() {
if (is_type_array_klass()) {
return true;
} else {
return as_obj_array_klass()->base_element_klass()->is_leaf_type();
}
}
ciArrayKlass* ciArrayKlass::make(ciType* element_type) {
if (element_type->is_primitive_type()) {
return ciTypeArrayKlass::make(element_type->basic_type());
} else {
return ciObjArrayKlass::make(element_type->as_klass());
}
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciArrayKlass.hpp
#ifndef SHARE_VM_CI_CIARRAYKLASS_HPP
#define SHARE_VM_CI_CIARRAYKLASS_HPP
#include "ci/ciKlass.hpp"
class ciArrayKlass : public ciKlass {
CI_PACKAGE_ACCESS
private:
jint _dimension;
protected:
ciArrayKlass(KlassHandle h_k);
ciArrayKlass(ciSymbol* name, int dimension, BasicType bt);
ArrayKlass* get_ArrayKlass() {
return (ArrayKlass*)get_Klass();
}
const char* type_string() { return "ciArrayKlass"; }
public:
jint dimension() { return _dimension; }
ciType* element_type(); // JLS calls this the "component type"
ciType* base_element_type(); // JLS calls this the "element type"
bool is_leaf_type(); // No subtypes of this array type.
ciInstance* component_mirror() {
return element_type()->java_mirror();
}
bool is_array_klass() const { return true; }
bool is_java_klass() const { return true; }
static ciArrayKlass* make(ciType* element_type);
};
#endif // SHARE_VM_CI_CIARRAYKLASS_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciBaseObject.cpp
#include "precompiled.hpp"
#include "ci/ciBaseObject.hpp"
#include "ci/ciUtilities.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "oops/oop.inline2.hpp"
void ciBaseObject::set_ident(uint id) {
assert((_ident >> FLAG_BITS) == 0, "must only initialize once");
assert( id < ((uint)1 << (BitsPerInt-FLAG_BITS)), "id too big");
_ident = _ident + (id << FLAG_BITS);
}
uint ciBaseObject::ident() {
uint id = _ident >> FLAG_BITS;
assert(id != 0, "must be initialized");
return id;
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciBaseObject.hpp
#ifndef SHARE_VM_CI_CIBASEOBJECT_HPP
#define SHARE_VM_CI_CIBASEOBJECT_HPP
#include "ci/ciClassList.hpp"
#include "memory/allocation.hpp"
#include "runtime/handles.hpp"
#include "runtime/jniHandles.hpp"
class ciBaseObject : public ResourceObj {
CI_PACKAGE_ACCESS
friend class ciEnv;
protected:
uint _ident;
enum { FLAG_BITS = 1 };
enum {
SCAVENGABLE_FLAG = 1
};
protected:
ciBaseObject(): _ident(0) {}
virtual const char* type_string() { return "ciBaseObject"; }
void set_ident(uint id);
public:
uint ident();
virtual bool is_symbol() const { return false; }
virtual bool is_object() const { return false; }
virtual bool is_metadata() const { return false; }
ciSymbol* as_symbol() {
assert(is_symbol(), "must be");
return (ciSymbol*)this;
}
ciObject* as_object() {
assert(is_object(), "must be");
return (ciObject*)this;
}
ciMetadata* as_metadata() {
assert(is_metadata(), "must be");
return (ciMetadata*)this;
}
};
#endif // SHARE_VM_CI_CIBASEOBJECT_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciCallProfile.hpp
#ifndef SHARE_VM_CI_CICALLPROFILE_HPP
#define SHARE_VM_CI_CICALLPROFILE_HPP
#include "ci/ciClassList.hpp"
#include "memory/allocation.hpp"
class ciCallProfile : StackObj {
private:
friend class ciMethod;
friend class ciMethodHandle;
enum { MorphismLimit = 2 }; // Max call site's morphism we care about
int _limit; // number of receivers have been determined
int _morphism; // determined call site's morphism
int _count; // # times has this call been executed
int _receiver_count[MorphismLimit + 1]; // # times receivers have been seen
ciMethod* _method[MorphismLimit + 1]; // receivers methods
ciKlass* _receiver[MorphismLimit + 1]; // receivers (exact)
ciCallProfile() {
_limit = 0;
_morphism = 0;
_count = -1;
_receiver_count[0] = -1;
_method[0] = NULL;
_receiver[0] = NULL;
}
void add_receiver(ciKlass* receiver, int receiver_count);
public:
bool has_receiver(int i) const { return _limit > i; }
int morphism() const { return _morphism; }
int count() const { return _count; }
int receiver_count(int i) {
assert(i < _limit, "out of Call Profile MorphismLimit");
return _receiver_count[i];
}
float receiver_prob(int i) {
assert(i < _limit, "out of Call Profile MorphismLimit");
return (float)_receiver_count[i]/(float)_count;
}
ciMethod* method(int i) {
assert(i < _limit, "out of Call Profile MorphismLimit");
return _method[i];
}
ciKlass* receiver(int i) {
assert(i < _limit, "out of Call Profile MorphismLimit");
return _receiver[i];
}
ciCallProfile rescale(double scale) {
assert(scale >= 0 && scale <= 1.0, "out of range");
ciCallProfile call = *this;
call._count = (int)(call._count * scale);
for (int i = 0; i < _morphism; i++) {
call._receiver_count[i] = (int)(call._receiver_count[i] * scale);
}
return call;
}
};
#endif // SHARE_VM_CI_CICALLPROFILE_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciCallSite.cpp
#include "precompiled.hpp"
#include "ci/ciCallSite.hpp"
#include "ci/ciUtilities.hpp"
bool ciCallSite::is_constant_call_site() {
return klass()->is_subclass_of(CURRENT_ENV->ConstantCallSite_klass());
}
bool ciCallSite::is_mutable_call_site() {
return klass()->is_subclass_of(CURRENT_ENV->MutableCallSite_klass());
}
bool ciCallSite::is_volatile_call_site() {
return klass()->is_subclass_of(CURRENT_ENV->VolatileCallSite_klass());
}
ciMethodHandle* ciCallSite::get_target() const {
VM_ENTRY_MARK;
oop method_handle_oop = java_lang_invoke_CallSite::target(get_oop());
return CURRENT_ENV->get_object(method_handle_oop)->as_method_handle();
}
void ciCallSite::print() {
Unimplemented();
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciCallSite.hpp
#ifndef SHARE_VM_CI_CICALLSITE_HPP
#define SHARE_VM_CI_CICALLSITE_HPP
#include "ci/ciInstance.hpp"
class ciCallSite : public ciInstance {
public:
ciCallSite(instanceHandle h_i) : ciInstance(h_i) {}
bool is_call_site() const { return true; }
bool is_constant_call_site();
bool is_mutable_call_site();
bool is_volatile_call_site();
ciMethodHandle* get_target() const;
void print();
};
#endif // SHARE_VM_CI_CICALLSITE_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciClassList.hpp
#ifndef SHARE_VM_CI_CICLASSLIST_HPP
#define SHARE_VM_CI_CICLASSLIST_HPP
class ciEnv;
class ciObjectFactory;
class ciConstantPoolCache;
class ciField;
class ciConstant;
class ciFlags;
class ciExceptionHandler;
class ciCallProfile;
class ciSignature;
class ciBytecodeStream;
class ciSignatureStream;
class ciExceptionHandlerStream;
class ciTypeFlow;
class ciBaseObject;
class ciObject;
class ciNullObject;
class ciInstance;
class ciCallSite;
class ciMemberName;
class ciMethodHandle;
class ciMethodType;
class ciArray;
class ciObjArray;
class ciTypeArray;
class ciSymbol;
class ciMetadata;
class ciMethod;
class ciMethodData;
class ciReceiverTypeData; // part of ciMethodData
class ciType;
class ciReturnAddress;
class ciKlass;
class ciInstanceKlass;
class ciArrayKlass;
class ciObjArrayKlass;
class ciTypeArrayKlass;
#define CI_PACKAGE_ACCESS \
friend class ciObjectFactory; \
friend class VMStructs;
#define CI_PACKAGE_ACCESS_TO \
friend class ciObjectFactory; \
friend class VMStructs; \
friend class ciCallSite; \
friend class ciConstantPoolCache; \
friend class ciField; \
friend class ciConstant; \
friend class ciFlags; \
friend class ciExceptionHandler; \
friend class ciCallProfile; \
friend class ciSignature; \
friend class ciBytecodeStream; \
friend class ciSignatureStream; \
friend class ciExceptionHandlerStream; \
friend class ciObject; \
friend class ciNullObject; \
friend class ciInstance; \
friend class ciMemberName; \
friend class ciMethod; \
friend class ciMethodData; \
friend class ciMethodHandle; \
friend class ciMethodType; \
friend class ciReceiverTypeData; \
friend class ciTypeEntries; \
friend class ciSpeculativeTrapData; \
friend class ciSymbol; \
friend class ciArray; \
friend class ciObjArray; \
friend class ciMetadata; \
friend class ciReplay; \
friend class ciTypeArray; \
friend class ciType; \
friend class ciReturnAddress; \
friend class ciKlass; \
friend class ciInstanceKlass; \
friend class ciArrayKlass; \
friend class ciObjArrayKlass; \
friend class ciTypeArrayKlass; \
#endif // SHARE_VM_CI_CICLASSLIST_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciConstant.cpp
#include "precompiled.hpp"
#include "ci/ciConstant.hpp"
#include "ci/ciUtilities.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
void ciConstant::print() {
tty->print("<ciConstant type=%s value=",
basictype_to_str(basic_type()));
switch (basic_type()) {
case T_BOOLEAN:
tty->print("%s", bool_to_str(_value._int != 0));
break;
case T_CHAR:
case T_BYTE:
case T_SHORT:
case T_INT:
tty->print("%d", _value._int);
break;
case T_LONG:
tty->print(INT64_FORMAT, (int64_t)(_value._long));
break;
case T_FLOAT:
tty->print("%f", _value._float);
break;
case T_DOUBLE:
tty->print("%lf", _value._double);
break;
case T_OBJECT:
case T_ARRAY:
_value._object->print();
break;
default:
tty->print("ILLEGAL");
break;
}
tty->print(">");
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciConstant.hpp
#ifndef SHARE_VM_CI_CICONSTANT_HPP
#define SHARE_VM_CI_CICONSTANT_HPP
#include "ci/ciClassList.hpp"
#include "ci/ciNullObject.hpp"
class ciConstant VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
private:
friend class ciEnv;
friend class ciField;
BasicType _type;
union {
jint _int;
jlong _long;
jfloat _float;
jdouble _double;
ciObject* _object;
} _value;
public:
ciConstant() {
_type = T_ILLEGAL; _value._long = -1;
}
ciConstant(BasicType type, jint value) {
assert(type != T_LONG && type != T_DOUBLE && type != T_FLOAT,
"using the wrong ciConstant constructor");
_type = type; _value._int = value;
}
ciConstant(jlong value) {
_type = T_LONG; _value._long = value;
}
ciConstant(jfloat value) {
_type = T_FLOAT; _value._float = value;
}
ciConstant(jdouble value) {
_type = T_DOUBLE; _value._double = value;
}
ciConstant(BasicType type, ciObject* p) {
_type = type; _value._object = p;
}
BasicType basic_type() const { return _type; }
jboolean as_boolean() {
assert(basic_type() == T_BOOLEAN, "wrong type");
return (jboolean)_value._int;
}
jchar as_char() {
assert(basic_type() == T_CHAR, "wrong type");
return (jchar)_value._int;
}
jbyte as_byte() {
assert(basic_type() == T_BYTE, "wrong type");
return (jbyte)_value._int;
}
jshort as_short() {
assert(basic_type() == T_SHORT, "wrong type");
return (jshort)_value._int;
}
jint as_int() {
assert(basic_type() == T_BOOLEAN || basic_type() == T_CHAR ||
basic_type() == T_BYTE || basic_type() == T_SHORT ||
basic_type() == T_INT, "wrong type");
return _value._int;
}
jlong as_long() {
assert(basic_type() == T_LONG, "wrong type");
return _value._long;
}
jfloat as_float() {
assert(basic_type() == T_FLOAT, "wrong type");
return _value._float;
}
jdouble as_double() {
assert(basic_type() == T_DOUBLE, "wrong type");
return _value._double;
}
ciObject* as_object() const {
assert(basic_type() == T_OBJECT || basic_type() == T_ARRAY, "wrong type");
return _value._object;
}
bool is_null_or_zero() const {
if (!is_java_primitive(basic_type())) {
return as_object()->is_null_object();
} else if (type2size[basic_type()] == 1) {
return (_value._int == 0);
} else if (type2size[basic_type()] == 2) {
return (_value._long == 0);
} else {
return false;
}
}
void print();
};
#endif // SHARE_VM_CI_CICONSTANT_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciConstantPoolCache.cpp
#include "precompiled.hpp"
#include "ci/ciConstantPoolCache.hpp"
#include "ci/ciUtilities.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
ciConstantPoolCache::ciConstantPoolCache(Arena* arena,
int expected_size) {
_elements =
new (arena) GrowableArray<void*>(arena, expected_size, 0, 0);
_keys = new (arena) GrowableArray<intptr_t>(arena, expected_size, 0, 0);
}
void* ciConstantPoolCache::get(int index) {
ASSERT_IN_VM;
int pos = find(index);
if (pos >= _keys->length() ||
_keys->at(pos) != index) {
return NULL;
}
return _elements->at(pos);
}
int ciConstantPoolCache::find(int key) {
int min = 0;
int max = _keys->length()-1;
while (max >= min) {
int mid = (max + min) / 2;
int value = _keys->at(mid);
if (value < key) {
min = mid + 1;
} else if (value > key) {
max = mid - 1;
} else {
return mid;
}
}
return min;
}
void ciConstantPoolCache::insert(int index, void* elem) {
int i;
int pos = find(index);
for (i = _keys->length()-1; i >= pos; i--) {
_keys->at_put_grow(i+1, _keys->at(i));
_elements->at_put_grow(i+1, _elements->at(i));
}
_keys->at_put_grow(pos, index);
_elements->at_put_grow(pos, elem);
}
void ciConstantPoolCache::print() {
Unimplemented();
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciConstantPoolCache.hpp
#ifndef SHARE_VM_CI_CICONSTANTPOOLCACHE_HPP
#define SHARE_VM_CI_CICONSTANTPOOLCACHE_HPP
#include "memory/resourceArea.hpp"
#include "utilities/growableArray.hpp"
class ciConstantPoolCache : public ResourceObj {
private:
GrowableArray<intptr_t>* _keys;
GrowableArray<void*>* _elements;
int find(int index);
public:
ciConstantPoolCache(Arena* arena, int expected_size);
void* get(int index);
void insert(int index, void* element);
void print();
};
#endif // SHARE_VM_CI_CICONSTANTPOOLCACHE_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciEnv.cpp
#include "precompiled.hpp"
#include "ci/ciConstant.hpp"
#include "ci/ciEnv.hpp"
#include "ci/ciField.hpp"
#include "ci/ciInstance.hpp"
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciNullObject.hpp"
#include "ci/ciReplay.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/scopeDesc.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/compileLog.hpp"
#include "compiler/compilerOracle.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "interpreter/linkResolver.hpp"
#include "jfr/jfrEvents.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/oopFactory.hpp"
#include "memory/universe.inline.hpp"
#include "oops/methodData.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/oop.inline.hpp"
#include "oops/oop.inline2.hpp"
#include "prims/jvmtiExport.hpp"
#include "runtime/init.hpp"
#include "runtime/reflection.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/thread.inline.hpp"
#include "utilities/dtrace.hpp"
#include "utilities/macros.hpp"
#ifdef COMPILER1
#include "c1/c1_Runtime1.hpp"
#endif
#ifdef COMPILER2
#include "opto/runtime.hpp"
#endif
ciObject* ciEnv::_null_object_instance;
#define WK_KLASS_DEFN(name, ignore_s, ignore_o) ciInstanceKlass* ciEnv::_##name = NULL;
WK_KLASSES_DO(WK_KLASS_DEFN)
#undef WK_KLASS_DEFN
ciSymbol* ciEnv::_unloaded_cisymbol = NULL;
ciInstanceKlass* ciEnv::_unloaded_ciinstance_klass = NULL;
ciObjArrayKlass* ciEnv::_unloaded_ciobjarrayklass = NULL;
jobject ciEnv::_ArrayIndexOutOfBoundsException_handle = NULL;
jobject ciEnv::_ArrayStoreException_handle = NULL;
jobject ciEnv::_ClassCastException_handle = NULL;
#ifndef PRODUCT
static bool firstEnv = true;
#endif /* PRODUCT */
ciEnv::ciEnv(CompileTask* task, int system_dictionary_modification_counter)
: _ciEnv_arena(mtCompiler) {
VM_ENTRY_MARK;
thread->set_env(this);
assert(ciEnv::current() == this, "sanity");
_oop_recorder = NULL;
_debug_info = NULL;
_dependencies = NULL;
_failure_reason = NULL;
_compilable = MethodCompilable;
_break_at_compile = false;
_compiler_data = NULL;
#ifndef PRODUCT
assert(!firstEnv, "not initialized properly");
#endif /* !PRODUCT */
_system_dictionary_modification_counter = system_dictionary_modification_counter;
_num_inlined_bytecodes = 0;
assert(task == NULL || thread->task() == task, "sanity");
_task = task;
_log = NULL;
_name_buffer = NULL;
_name_buffer_len = 0;
_arena = &_ciEnv_arena;
_factory = new (_arena) ciObjectFactory(_arena, 128);
assert(Universe::is_fully_initialized(), "should be complete");
oop o = Universe::null_ptr_exception_instance();
assert(o != NULL, "should have been initialized");
_NullPointerException_instance = get_object(o)->as_instance();
o = Universe::arithmetic_exception_instance();
assert(o != NULL, "should have been initialized");
_ArithmeticException_instance = get_object(o)->as_instance();
_ArrayIndexOutOfBoundsException_instance = NULL;
_ArrayStoreException_instance = NULL;
_ClassCastException_instance = NULL;
_the_null_string = NULL;
_the_min_jint_string = NULL;
_jvmti_can_hotswap_or_post_breakpoint = false;
_jvmti_can_access_local_variables = false;
_jvmti_can_post_on_exceptions = false;
_jvmti_can_pop_frame = false;
}
ciEnv::ciEnv(Arena* arena) : _ciEnv_arena(mtCompiler) {
ASSERT_IN_VM;
CompilerThread* current_thread = CompilerThread::current();
assert(current_thread->env() == NULL, "must be");
current_thread->set_env(this);
assert(ciEnv::current() == this, "sanity");
_oop_recorder = NULL;
_debug_info = NULL;
_dependencies = NULL;
_failure_reason = NULL;
_compilable = MethodCompilable_never;
_break_at_compile = false;
_compiler_data = NULL;
#ifndef PRODUCT
assert(firstEnv, "must be first");
firstEnv = false;
#endif /* !PRODUCT */
_system_dictionary_modification_counter = 0;
_num_inlined_bytecodes = 0;
_task = NULL;
_log = NULL;
_name_buffer = NULL;
_name_buffer_len = 0;
_arena = arena;
_factory = new (_arena) ciObjectFactory(_arena, 128);
assert(Universe::is_fully_initialized(), "must be");
_NullPointerException_instance = NULL;
_ArithmeticException_instance = NULL;
_ArrayIndexOutOfBoundsException_instance = NULL;
_ArrayStoreException_instance = NULL;
_ClassCastException_instance = NULL;
_the_null_string = NULL;
_the_min_jint_string = NULL;
_jvmti_can_hotswap_or_post_breakpoint = false;
_jvmti_can_access_local_variables = false;
_jvmti_can_post_on_exceptions = false;
_jvmti_can_pop_frame = false;
}
ciEnv::~ciEnv() {
CompilerThread* current_thread = CompilerThread::current();
_factory->remove_symbols();
GUARDED_VM_ENTRY(current_thread->set_env(NULL);)
}
void ciEnv::cache_jvmti_state() {
VM_ENTRY_MARK;
MutexLocker mu(JvmtiThreadState_lock);
_jvmti_can_hotswap_or_post_breakpoint = JvmtiExport::can_hotswap_or_post_breakpoint();
_jvmti_can_access_local_variables = JvmtiExport::can_access_local_variables();
_jvmti_can_post_on_exceptions = JvmtiExport::can_post_on_exceptions();
_jvmti_can_pop_frame = JvmtiExport::can_pop_frame();
}
bool ciEnv::should_retain_local_variables() const {
return _jvmti_can_access_local_variables || _jvmti_can_pop_frame;
}
bool ciEnv::jvmti_state_changed() const {
if (!_jvmti_can_access_local_variables &&
JvmtiExport::can_access_local_variables()) {
return true;
}
if (!_jvmti_can_hotswap_or_post_breakpoint &&
JvmtiExport::can_hotswap_or_post_breakpoint()) {
return true;
}
if (!_jvmti_can_post_on_exceptions &&
JvmtiExport::can_post_on_exceptions()) {
return true;
}
if (!_jvmti_can_pop_frame &&
JvmtiExport::can_pop_frame()) {
return true;
}
return false;
}
void ciEnv::cache_dtrace_flags() {
_dtrace_extended_probes = ExtendedDTraceProbes;
if (_dtrace_extended_probes) {
_dtrace_monitor_probes = true;
_dtrace_method_probes = true;
_dtrace_alloc_probes = true;
} else {
_dtrace_monitor_probes = DTraceMonitorProbes;
_dtrace_method_probes = DTraceMethodProbes;
_dtrace_alloc_probes = DTraceAllocProbes;
}
}
ciInstance* ciEnv::get_or_create_exception(jobject& handle, Symbol* name) {
VM_ENTRY_MARK;
if (handle == NULL) {
Klass* k = SystemDictionary::find(name, Handle(), Handle(), THREAD);
jobject objh = NULL;
if (!HAS_PENDING_EXCEPTION && k != NULL) {
oop obj = InstanceKlass::cast(k)->allocate_instance(THREAD);
if (!HAS_PENDING_EXCEPTION)
objh = JNIHandles::make_global(obj);
}
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
} else {
handle = objh;
}
}
oop obj = JNIHandles::resolve(handle);
return obj == NULL? NULL: get_object(obj)->as_instance();
}
ciInstance* ciEnv::ArrayIndexOutOfBoundsException_instance() {
if (_ArrayIndexOutOfBoundsException_instance == NULL) {
_ArrayIndexOutOfBoundsException_instance
= get_or_create_exception(_ArrayIndexOutOfBoundsException_handle,
vmSymbols::java_lang_ArrayIndexOutOfBoundsException());
}
return _ArrayIndexOutOfBoundsException_instance;
}
ciInstance* ciEnv::ArrayStoreException_instance() {
if (_ArrayStoreException_instance == NULL) {
_ArrayStoreException_instance
= get_or_create_exception(_ArrayStoreException_handle,
vmSymbols::java_lang_ArrayStoreException());
}
return _ArrayStoreException_instance;
}
ciInstance* ciEnv::ClassCastException_instance() {
if (_ClassCastException_instance == NULL) {
_ClassCastException_instance
= get_or_create_exception(_ClassCastException_handle,
vmSymbols::java_lang_ClassCastException());
}
return _ClassCastException_instance;
}
ciInstance* ciEnv::the_null_string() {
if (_the_null_string == NULL) {
VM_ENTRY_MARK;
_the_null_string = get_object(Universe::the_null_string())->as_instance();
}
return _the_null_string;
}
ciInstance* ciEnv::the_min_jint_string() {
if (_the_min_jint_string == NULL) {
VM_ENTRY_MARK;
_the_min_jint_string = get_object(Universe::the_min_jint_string())->as_instance();
}
return _the_min_jint_string;
}
ciMethod* ciEnv::get_method_from_handle(Method* method) {
VM_ENTRY_MARK;
return get_metadata(method)->as_method();
}
int ciEnv::array_element_offset_in_bytes(ciArray* a_h, ciObject* o_h) {
VM_ENTRY_MARK;
objArrayOop a = (objArrayOop)a_h->get_oop();
assert(a->is_objArray(), "");
int length = a->length();
oop o = o_h->get_oop();
for (int i = 0; i < length; i++) {
if (a->obj_at(i) == o) return i;
}
return -1;
}
bool ciEnv::check_klass_accessibility(ciKlass* accessing_klass,
Klass* resolved_klass) {
if (accessing_klass == NULL || !accessing_klass->is_loaded()) {
return true;
}
if (accessing_klass->is_obj_array_klass()) {
accessing_klass = accessing_klass->as_obj_array_klass()->base_element_klass();
}
if (!accessing_klass->is_instance_klass()) {
return true;
}
if (resolved_klass->oop_is_objArray()) {
resolved_klass = ObjArrayKlass::cast(resolved_klass)->bottom_klass();
}
if (resolved_klass->oop_is_instance()) {
return Reflection::verify_class_access(accessing_klass->get_Klass(),
resolved_klass,
true);
}
return true;
}
ciKlass* ciEnv::get_klass_by_name_impl(ciKlass* accessing_klass,
constantPoolHandle cpool,
ciSymbol* name,
bool require_local) {
ASSERT_IN_VM;
EXCEPTION_CONTEXT;
Symbol* sym = name->get_symbol();
if (sym->byte_at(0) == 'L' &&
sym->byte_at(sym->utf8_length()-1) == ';') {
TempNewSymbol strippedsym = SymbolTable::new_symbol(sym->as_utf8()+1,
sym->utf8_length()-2,
KILL_COMPILE_ON_FATAL_(_unloaded_ciinstance_klass));
ciSymbol* strippedname = get_symbol(strippedsym);
return get_klass_by_name_impl(accessing_klass, cpool, strippedname, require_local);
}
ciKlass* unloaded_klass = check_get_unloaded_klass(accessing_klass, name);
if (unloaded_klass != NULL) {
if (require_local) return NULL;
return unloaded_klass;
}
Handle loader(THREAD, (oop)NULL);
Handle domain(THREAD, (oop)NULL);
if (accessing_klass != NULL) {
loader = Handle(THREAD, accessing_klass->loader());
domain = Handle(THREAD, accessing_klass->protection_domain());
}
ciKlass* fail_type;
if (sym->byte_at(0) == '[') {
fail_type = _unloaded_ciobjarrayklass;
} else {
fail_type = _unloaded_ciinstance_klass;
}
KlassHandle found_klass;
{
ttyUnlocker ttyul; // release tty lock to avoid ordering problems
MutexLocker ml(Compile_lock);
Klass* kls;
if (!require_local) {
kls = SystemDictionary::find_constrained_instance_or_array_klass(sym, loader,
KILL_COMPILE_ON_FATAL_(fail_type));
} else {
kls = SystemDictionary::find_instance_or_array_klass(sym, loader, domain,
KILL_COMPILE_ON_FATAL_(fail_type));
}
found_klass = KlassHandle(THREAD, kls);
}
if (sym->byte_at(0) == '[' &&
(sym->byte_at(1) == '[' || sym->byte_at(1) == 'L')) {
TempNewSymbol elem_sym = SymbolTable::new_symbol(sym->as_utf8()+1,
sym->utf8_length()-1,
KILL_COMPILE_ON_FATAL_(fail_type));
ciKlass* elem_klass =
get_klass_by_name_impl(accessing_klass,
cpool,
get_symbol(elem_sym),
require_local);
if (elem_klass != NULL && elem_klass->is_loaded()) {
return ciObjArrayKlass::make_impl(elem_klass);
}
}
if (found_klass() == NULL && !cpool.is_null() && cpool->has_preresolution()) {
for (int i = cpool->length() - 1; i >= 1; i--) {
if (cpool->tag_at(i).is_klass()) {
Klass* kls = cpool->resolved_klass_at(i);
if (kls->name() == sym) {
found_klass = KlassHandle(THREAD, kls);
break;
}
}
}
}
if (found_klass() != NULL) {
return get_klass(found_klass());
}
if (require_local) return NULL;
return get_unloaded_klass(accessing_klass, name);
}
ciKlass* ciEnv::get_klass_by_name(ciKlass* accessing_klass,
ciSymbol* klass_name,
bool require_local) {
GUARDED_VM_ENTRY(return get_klass_by_name_impl(accessing_klass,
constantPoolHandle(),
klass_name,
require_local);)
}
ciKlass* ciEnv::get_klass_by_index_impl(constantPoolHandle cpool,
int index,
bool& is_accessible,
ciInstanceKlass* accessor) {
EXCEPTION_CONTEXT;
KlassHandle klass; // = NULL;
Symbol* klass_name = NULL;
if (cpool->tag_at(index).is_symbol()) {
klass_name = cpool->symbol_at(index);
} else {
klass = KlassHandle(THREAD, ConstantPool::klass_at_if_loaded(cpool, index));
if (klass.is_null()) {
{
MonitorLockerEx ml(cpool->lock());
constantTag tag = cpool->tag_at(index);
if (tag.is_klass()) {
klass = KlassHandle(THREAD, cpool->resolved_klass_at(index));
} else {
assert(cpool->tag_at(index).is_unresolved_klass(), "wrong tag");
klass_name = cpool->unresolved_klass_at(index);
}
}
}
}
if (klass.is_null()) {
ciKlass* k = get_klass_by_name_impl(accessor,
cpool,
get_symbol(klass_name),
false);
if (!k->is_loaded()) {
is_accessible = false;
} else if (k->loader() != accessor->loader() &&
get_klass_by_name_impl(accessor, cpool, k->name(), true) == NULL) {
is_accessible = false;
} else {
is_accessible = check_klass_accessibility(accessor, k->get_Klass());
}
return k;
}
ciSymbol* name = get_symbol(klass()->name());
ciKlass* unloaded_klass = check_get_unloaded_klass(accessor, name);
if (unloaded_klass != NULL) {
is_accessible = false;
return unloaded_klass;
}
is_accessible = true;
return get_klass(klass());
}
ciKlass* ciEnv::get_klass_by_index(constantPoolHandle cpool,
int index,
bool& is_accessible,
ciInstanceKlass* accessor) {
GUARDED_VM_ENTRY(return get_klass_by_index_impl(cpool, index, is_accessible, accessor);)
}
ciConstant ciEnv::get_constant_by_index_impl(constantPoolHandle cpool,
int pool_index, int cache_index,
ciInstanceKlass* accessor) {
bool ignore_will_link;
EXCEPTION_CONTEXT;
int index = pool_index;
if (cache_index >= 0) {
assert(index < 0, "only one kind of index at a time");
oop obj = cpool->resolved_references()->obj_at(cache_index);
if (obj != NULL) {
ciObject* ciobj = get_object(obj);
if (ciobj->is_array()) {
return ciConstant(T_ARRAY, ciobj);
} else {
assert(ciobj->is_instance(), "should be an instance");
return ciConstant(T_OBJECT, ciobj);
}
}
index = cpool->object_to_cp_index(cache_index);
}
constantTag tag = cpool->tag_at(index);
if (tag.is_int()) {
return ciConstant(T_INT, (jint)cpool->int_at(index));
} else if (tag.is_long()) {
return ciConstant((jlong)cpool->long_at(index));
} else if (tag.is_float()) {
return ciConstant((jfloat)cpool->float_at(index));
} else if (tag.is_double()) {
return ciConstant((jdouble)cpool->double_at(index));
} else if (tag.is_string()) {
oop string = NULL;
assert(cache_index >= 0, "should have a cache index");
if (cpool->is_pseudo_string_at(index)) {
string = cpool->pseudo_string_at(index, cache_index);
} else {
string = cpool->string_at(index, cache_index, THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
record_out_of_memory_failure();
return ciConstant();
}
}
ciObject* constant = get_object(string);
if (constant->is_array()) {
return ciConstant(T_ARRAY, constant);
} else {
assert (constant->is_instance(), "must be an instance, or not? ");
return ciConstant(T_OBJECT, constant);
}
} else if (tag.is_klass() || tag.is_unresolved_klass()) {
ciKlass* klass = get_klass_by_index_impl(cpool, index, ignore_will_link, accessor);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
record_out_of_memory_failure();
return ciConstant();
}
assert (klass->is_instance_klass() || klass->is_array_klass(),
"must be an instance or array klass ");
return ciConstant(T_OBJECT, klass->java_mirror());
} else if (tag.is_method_type()) {
ciSymbol* signature = get_symbol(cpool->method_type_signature_at(index));
ciObject* ciobj = get_unloaded_method_type_constant(signature);
return ciConstant(T_OBJECT, ciobj);
} else if (tag.is_method_handle()) {
int ref_kind = cpool->method_handle_ref_kind_at(index);
int callee_index = cpool->method_handle_klass_index_at(index);
ciKlass* callee = get_klass_by_index_impl(cpool, callee_index, ignore_will_link, accessor);
ciSymbol* name = get_symbol(cpool->method_handle_name_ref_at(index));
ciSymbol* signature = get_symbol(cpool->method_handle_signature_ref_at(index));
ciObject* ciobj = get_unloaded_method_handle_constant(callee, name, signature, ref_kind);
return ciConstant(T_OBJECT, ciobj);
} else {
ShouldNotReachHere();
return ciConstant();
}
}
ciConstant ciEnv::get_constant_by_index(constantPoolHandle cpool,
int pool_index, int cache_index,
ciInstanceKlass* accessor) {
GUARDED_VM_ENTRY(return get_constant_by_index_impl(cpool, pool_index, cache_index, accessor);)
}
ciField* ciEnv::get_field_by_index_impl(ciInstanceKlass* accessor,
int index) {
ciConstantPoolCache* cache = accessor->field_cache();
if (cache == NULL) {
ciField* field = new (arena()) ciField(accessor, index);
return field;
} else {
ciField* field = (ciField*)cache->get(index);
if (field == NULL) {
field = new (arena()) ciField(accessor, index);
cache->insert(index, field);
}
return field;
}
}
ciField* ciEnv::get_field_by_index(ciInstanceKlass* accessor,
int index) {
GUARDED_VM_ENTRY(return get_field_by_index_impl(accessor, index);)
}
Method* ciEnv::lookup_method(InstanceKlass* accessor,
InstanceKlass* holder,
Symbol* name,
Symbol* sig,
Bytecodes::Code bc) {
EXCEPTION_CONTEXT;
KlassHandle h_accessor(THREAD, accessor);
KlassHandle h_holder(THREAD, holder);
LinkResolver::check_klass_accessability(h_accessor, h_holder, KILL_COMPILE_ON_FATAL_(NULL));
methodHandle dest_method;
switch (bc) {
case Bytecodes::_invokestatic:
dest_method =
LinkResolver::resolve_static_call_or_null(h_holder, name, sig, h_accessor);
break;
case Bytecodes::_invokespecial:
dest_method =
LinkResolver::resolve_special_call_or_null(h_holder, name, sig, h_accessor);
break;
case Bytecodes::_invokeinterface:
dest_method =
LinkResolver::linktime_resolve_interface_method_or_null(h_holder, name, sig,
h_accessor, true);
break;
case Bytecodes::_invokevirtual:
dest_method =
LinkResolver::linktime_resolve_virtual_method_or_null(h_holder, name, sig,
h_accessor, true);
break;
default: ShouldNotReachHere();
}
return dest_method();
}
ciMethod* ciEnv::get_method_by_index_impl(constantPoolHandle cpool,
int index, Bytecodes::Code bc,
ciInstanceKlass* accessor) {
if (bc == Bytecodes::_invokedynamic) {
ConstantPoolCacheEntry* cpce = cpool->invokedynamic_cp_cache_entry_at(index);
bool is_resolved = !cpce->is_f1_null();
if (is_resolved) {
Method* adapter = cpce->f1_as_method();
return get_method(adapter);
}
ciInstanceKlass* holder = get_instance_klass(SystemDictionary::MethodHandle_klass());
ciSymbol* name = ciSymbol::invokeBasic_name();
ciSymbol* signature = get_symbol(cpool->signature_ref_at(index));
return get_unloaded_method(holder, name, signature, accessor);
} else {
const int holder_index = cpool->klass_ref_index_at(index);
bool holder_is_accessible;
ciKlass* holder = get_klass_by_index_impl(cpool, holder_index, holder_is_accessible, accessor);
ciInstanceKlass* declared_holder = get_instance_klass_for_declared_method_holder(holder);
Symbol* name_sym = cpool->name_ref_at(index);
Symbol* sig_sym = cpool->signature_ref_at(index);
if (cpool->has_preresolution()
|| (holder == ciEnv::MethodHandle_klass() &&
MethodHandles::is_signature_polymorphic_name(holder->get_Klass(), name_sym))) {
switch (bc) {
case Bytecodes::_invokevirtual:
case Bytecodes::_invokeinterface:
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
{
Method* m = ConstantPool::method_at_if_loaded(cpool, index);
if (m != NULL) {
return get_method(m);
}
}
break;
}
}
if (holder_is_accessible) { // Our declared holder is loaded.
InstanceKlass* lookup = declared_holder->get_instanceKlass();
Method* m = lookup_method(accessor->get_instanceKlass(), lookup, name_sym, sig_sym, bc);
if (m != NULL &&
(bc == Bytecodes::_invokestatic
? m->method_holder()->is_not_initialized()
: !m->method_holder()->is_loaded())) {
m = NULL;
}
#ifdef ASSERT
if (m != NULL && ReplayCompiles && !ciReplay::is_loaded(m)) {
m = NULL;
}
#endif
if (m != NULL) {
return get_method(m);
}
}
ciSymbol* name = get_symbol(name_sym);
ciSymbol* signature = get_symbol(sig_sym);
return get_unloaded_method(declared_holder, name, signature, accessor);
}
}
ciInstanceKlass* ciEnv::get_instance_klass_for_declared_method_holder(ciKlass* method_holder) {
guarantee(method_holder != NULL, "no method holder");
if (method_holder->is_instance_klass()) {
return method_holder->as_instance_klass();
} else if (method_holder->is_array_klass()) {
return current()->Object_klass();
} else {
ShouldNotReachHere();
}
return NULL;
}
ciMethod* ciEnv::get_method_by_index(constantPoolHandle cpool,
int index, Bytecodes::Code bc,
ciInstanceKlass* accessor) {
GUARDED_VM_ENTRY(return get_method_by_index_impl(cpool, index, bc, accessor);)
}
char *ciEnv::name_buffer(int req_len) {
if (_name_buffer_len < req_len) {
if (_name_buffer == NULL) {
_name_buffer = (char*)arena()->Amalloc(sizeof(char)*req_len);
_name_buffer_len = req_len;
} else {
_name_buffer =
(char*)arena()->Arealloc(_name_buffer, _name_buffer_len, req_len);
_name_buffer_len = req_len;
}
}
return _name_buffer;
}
bool ciEnv::is_in_vm() {
return JavaThread::current()->thread_state() == _thread_in_vm;
}
bool ciEnv::system_dictionary_modification_counter_changed() {
return _system_dictionary_modification_counter != SystemDictionary::number_of_modifications();
}
void ciEnv::validate_compile_task_dependencies(ciMethod* target) {
if (failing()) return; // no need for further checks
for (Dependencies::DepStream deps(dependencies()); deps.next(); ) {
if (deps.is_klass_type()) continue; // skip klass dependencies
Klass* witness = deps.check_dependency();
if (witness != NULL) {
record_failure("invalid non-klass dependency");
return;
}
}
bool counter_changed = system_dictionary_modification_counter_changed();
bool verify_deps = trueInDebug;
if (!counter_changed && !verify_deps) return;
int klass_violations = 0;
for (Dependencies::DepStream deps(dependencies()); deps.next(); ) {
if (!deps.is_klass_type()) continue; // skip non-klass dependencies
Klass* witness = deps.check_dependency();
if (witness != NULL) {
klass_violations++;
if (!counter_changed) {
deps.print_dependency(witness);
} else if (xtty == NULL) {
break;
}
}
}
if (klass_violations != 0) {
#ifdef ASSERT
if (!counter_changed && !PrintCompilation) {
_task->print_line();
}
#endif
assert(counter_changed, "failed dependencies, but counter didn't change");
record_failure("concurrent class loading");
}
}
void ciEnv::register_method(ciMethod* target,
int entry_bci,
CodeOffsets* offsets,
int orig_pc_offset,
CodeBuffer* code_buffer,
int frame_words,
OopMapSet* oop_map_set,
ExceptionHandlerTable* handler_table,
ImplicitExceptionTable* inc_table,
AbstractCompiler* compiler,
int comp_level,
bool has_unsafe_access,
bool has_wide_vectors,
RTMState rtm_state) {
VM_ENTRY_MARK;
nmethod* nm = NULL;
{
MutexLocker locker(MethodCompileQueue_lock, THREAD);
MutexLocker ml(Compile_lock);
No_Safepoint_Verifier nsv;
if (!failing() && jvmti_state_changed()) {
record_failure("Jvmti state change invalidated dependencies");
}
if (!failing() &&
( (!dtrace_extended_probes() && ExtendedDTraceProbes) ||
(!dtrace_method_probes() && DTraceMethodProbes) ||
(!dtrace_alloc_probes() && DTraceAllocProbes) )) {
record_failure("DTrace flags change invalidated dependencies");
}
if (!failing()) {
if (log() != NULL) {
dependencies()->log_all_dependencies();
}
dependencies()->encode_content_bytes();
validate_compile_task_dependencies(target);
}
methodHandle method(THREAD, target->get_Method());
#if INCLUDE_RTM_OPT
if (!failing() && (rtm_state != NoRTM) &&
(method()->method_data() != NULL) &&
(method()->method_data()->rtm_state() != rtm_state)) {
record_failure("RTM state change invalidated rtm code");
}
#endif
if (failing()) {
MethodData* mdo = method()->method_data();
if (mdo != NULL) {
mdo->inc_decompile_count();
}
code_buffer->free_blob();
return;
}
assert(offsets->value(CodeOffsets::Deopt) != -1, "must have deopt entry");
assert(offsets->value(CodeOffsets::Exceptions) != -1, "must have exception entry");
nm = nmethod::new_nmethod(method,
compile_id(),
entry_bci,
offsets,
orig_pc_offset,
debug_info(), dependencies(), code_buffer,
frame_words, oop_map_set,
handler_table, inc_table,
compiler, comp_level);
code_buffer->free_blob();
if (nm != NULL) {
nm->set_has_unsafe_access(has_unsafe_access);
nm->set_has_wide_vectors(has_wide_vectors);
#if INCLUDE_RTM_OPT
nm->set_rtm_state(rtm_state);
#endif
if (task() != NULL) {
task()->set_code(nm);
}
if (entry_bci == InvocationEntryBci) {
if (TieredCompilation) {
nmethod* old = method->code();
if (TraceMethodReplacement && old != NULL) {
ResourceMark rm;
char *method_name = method->name_and_sig_as_C_string();
tty->print_cr("Replacing method %s", method_name);
}
if (old != NULL) {
old->make_not_entrant();
}
}
if (TraceNMethodInstalls) {
ResourceMark rm;
char *method_name = method->name_and_sig_as_C_string();
ttyLocker ttyl;
tty->print_cr("Installing method (%d) %s ",
comp_level,
method_name);
}
method->set_code(method, nm);
} else {
if (TraceNMethodInstalls) {
ResourceMark rm;
char *method_name = method->name_and_sig_as_C_string();
ttyLocker ttyl;
tty->print_cr("Installing osr method (%d) %s @ %d",
comp_level,
method_name,
entry_bci);
}
method->method_holder()->add_osr_nmethod(nm);
}
}
} // safepoints are allowed again
if (nm != NULL) {
nm->post_compiled_method_load_event();
} else {
record_failure("code cache is full");
CompileBroker::handle_full_code_cache();
}
}
ciKlass* ciEnv::find_system_klass(ciSymbol* klass_name) {
VM_ENTRY_MARK;
return get_klass_by_name_impl(NULL, constantPoolHandle(), klass_name, false);
}
int ciEnv::comp_level() {
if (task() == NULL) return CompLevel_highest_tier;
return task()->comp_level();
}
uint ciEnv::compile_id() {
if (task() == NULL) return 0;
return task()->compile_id();
}
void ciEnv::notice_inlined_method(ciMethod* method) {
_num_inlined_bytecodes += method->code_size_for_inlining();
}
int ciEnv::num_inlined_bytecodes() const {
return _num_inlined_bytecodes;
}
void ciEnv::record_failure(const char* reason) {
if (_failure_reason == NULL) {
_failure_reason = reason;
}
}
void ciEnv::record_method_not_compilable(const char* reason, bool all_tiers) {
int new_compilable =
all_tiers ? MethodCompilable_never : MethodCompilable_not_at_tier ;
if (new_compilable > _compilable) {
if (log() != NULL) {
if (all_tiers) {
log()->elem("method_not_compilable");
} else {
log()->elem("method_not_compilable_at_tier level='%d'",
current()->task()->comp_level());
}
}
_compilable = new_compilable;
_failure_reason = NULL;
record_failure(reason);
}
}
void ciEnv::record_out_of_memory_failure() {
record_method_not_compilable("out of memory");
}
ciInstance* ciEnv::unloaded_ciinstance() {
GUARDED_VM_ENTRY(return _factory->get_unloaded_object_constant();)
}
void ciEnv::dump_compile_data(outputStream* out) {
CompileTask* task = this->task();
Method* method = task->method();
int entry_bci = task->osr_bci();
int comp_level = task->comp_level();
out->print("compile %s %s %s %d %d",
method->klass_name()->as_quoted_ascii(),
method->name()->as_quoted_ascii(),
method->signature()->as_quoted_ascii(),
entry_bci, comp_level);
if (compiler_data() != NULL) {
if (is_c2_compile(comp_level)) { // C2 or Shark
#ifdef COMPILER2
((Compile*)compiler_data())->dump_inline_data(out);
#endif
} else if (is_c1_compile(comp_level)) { // C1
#ifdef COMPILER1
((Compilation*)compiler_data())->dump_inline_data(out);
#endif
}
}
out->cr();
}
void ciEnv::dump_replay_data_unsafe(outputStream* out) {
ResourceMark rm;
#if INCLUDE_JVMTI
out->print_cr("JvmtiExport can_access_local_variables %d", _jvmti_can_access_local_variables);
out->print_cr("JvmtiExport can_hotswap_or_post_breakpoint %d", _jvmti_can_hotswap_or_post_breakpoint);
out->print_cr("JvmtiExport can_post_on_exceptions %d", _jvmti_can_post_on_exceptions);
#endif // INCLUDE_JVMTI
GrowableArray<ciMetadata*>* objects = _factory->get_ci_metadata();
out->print_cr("# %d ciObject found", objects->length());
for (int i = 0; i < objects->length(); i++) {
objects->at(i)->dump_replay_data(out);
}
dump_compile_data(out);
out->flush();
}
void ciEnv::dump_replay_data(outputStream* out) {
GUARDED_VM_ENTRY(
MutexLocker ml(Compile_lock);
dump_replay_data_unsafe(out);
)
}
void ciEnv::dump_replay_data(int compile_id) {
static char buffer[O_BUFLEN];
int ret = jio_snprintf(buffer, O_BUFLEN, "replay_pid%p_compid%d.log", os::current_process_id(), compile_id);
if (ret > 0) {
int fd = open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd != -1) {
FILE* replay_data_file = os::open(fd, "w");
if (replay_data_file != NULL) {
fileStream replay_data_stream(replay_data_file, /*need_close=*/true);
dump_replay_data(&replay_data_stream);
tty->print_cr("# Compiler replay data is saved as: %s", buffer);
} else {
tty->print_cr("# Can't open file to dump replay data.");
}
}
}
}
void ciEnv::dump_inline_data(int compile_id) {
static char buffer[O_BUFLEN];
int ret = jio_snprintf(buffer, O_BUFLEN, "inline_pid%p_compid%d.log", os::current_process_id(), compile_id);
if (ret > 0) {
int fd = open(buffer, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd != -1) {
FILE* inline_data_file = os::open(fd, "w");
if (inline_data_file != NULL) {
fileStream replay_data_stream(inline_data_file, /*need_close=*/true);
GUARDED_VM_ENTRY(
MutexLocker ml(Compile_lock);
dump_compile_data(&replay_data_stream);
)
replay_data_stream.flush();
tty->print("# Compiler inline data is saved as: ");
tty->print_cr("%s", buffer);
} else {
tty->print_cr("# Can't open file to dump inline data.");
}
}
}
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciEnv.hpp
#ifndef SHARE_VM_CI_CIENV_HPP
#define SHARE_VM_CI_CIENV_HPP
#include "ci/ciClassList.hpp"
#include "ci/ciObjectFactory.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/debugInfoRec.hpp"
#include "code/dependencies.hpp"
#include "code/exceptionHandlerTable.hpp"
#include "compiler/oopMap.hpp"
#include "runtime/thread.hpp"
class CompileTask;
class ciEnv : StackObj {
CI_PACKAGE_ACCESS_TO
friend class CompileBroker;
friend class Dependencies; // for get_object, during logging
private:
Arena* _arena; // Alias for _ciEnv_arena except in init_shared_objects()
Arena _ciEnv_arena;
int _system_dictionary_modification_counter;
ciObjectFactory* _factory;
OopRecorder* _oop_recorder;
DebugInformationRecorder* _debug_info;
Dependencies* _dependencies;
const char* _failure_reason;
int _compilable;
bool _break_at_compile;
int _num_inlined_bytecodes;
CompileTask* _task; // faster access to CompilerThread::task
CompileLog* _log; // faster access to CompilerThread::log
void* _compiler_data; // compiler-specific stuff, if any
char* _name_buffer;
int _name_buffer_len;
bool _jvmti_can_hotswap_or_post_breakpoint;
bool _jvmti_can_access_local_variables;
bool _jvmti_can_post_on_exceptions;
bool _jvmti_can_pop_frame;
bool _dtrace_extended_probes;
bool _dtrace_monitor_probes;
bool _dtrace_method_probes;
bool _dtrace_alloc_probes;
static ciObject* _null_object_instance;
#define WK_KLASS_DECL(name, ignore_s, ignore_o) static ciInstanceKlass* _##name;
WK_KLASSES_DO(WK_KLASS_DECL)
#undef WK_KLASS_DECL
static ciSymbol* _unloaded_cisymbol;
static ciInstanceKlass* _unloaded_ciinstance_klass;
static ciObjArrayKlass* _unloaded_ciobjarrayklass;
static jobject _ArrayIndexOutOfBoundsException_handle;
static jobject _ArrayStoreException_handle;
static jobject _ClassCastException_handle;
ciInstance* _NullPointerException_instance;
ciInstance* _ArithmeticException_instance;
ciInstance* _ArrayIndexOutOfBoundsException_instance;
ciInstance* _ArrayStoreException_instance;
ciInstance* _ClassCastException_instance;
ciInstance* _the_null_string; // The Java string "null"
ciInstance* _the_min_jint_string; // The Java string "-2147483648"
ciKlass* get_klass_by_name(ciKlass* accessing_klass,
ciSymbol* klass_name,
bool require_local);
ciKlass* get_klass_by_index(constantPoolHandle cpool,
int klass_index,
bool& is_accessible,
ciInstanceKlass* loading_klass);
ciConstant get_constant_by_index(constantPoolHandle cpool,
int pool_index, int cache_index,
ciInstanceKlass* accessor);
ciField* get_field_by_index(ciInstanceKlass* loading_klass,
int field_index);
ciMethod* get_method_by_index(constantPoolHandle cpool,
int method_index, Bytecodes::Code bc,
ciInstanceKlass* loading_klass);
ciKlass* get_klass_by_name_impl(ciKlass* accessing_klass,
constantPoolHandle cpool,
ciSymbol* klass_name,
bool require_local);
ciKlass* get_klass_by_index_impl(constantPoolHandle cpool,
int klass_index,
bool& is_accessible,
ciInstanceKlass* loading_klass);
ciConstant get_constant_by_index_impl(constantPoolHandle cpool,
int pool_index, int cache_index,
ciInstanceKlass* loading_klass);
ciField* get_field_by_index_impl(ciInstanceKlass* loading_klass,
int field_index);
ciMethod* get_method_by_index_impl(constantPoolHandle cpool,
int method_index, Bytecodes::Code bc,
ciInstanceKlass* loading_klass);
bool check_klass_accessibility(ciKlass* accessing_klass,
Klass* resolved_klass);
Method* lookup_method(InstanceKlass* accessor,
InstanceKlass* holder,
Symbol* name,
Symbol* sig,
Bytecodes::Code bc);
ciObject* get_object(oop o) {
if (o == NULL) {
return _null_object_instance;
} else {
return _factory->get(o);
}
}
ciSymbol* get_symbol(Symbol* o) {
if (o == NULL) {
ShouldNotReachHere();
return NULL;
} else {
return _factory->get_symbol(o);
}
}
ciMetadata* get_metadata(Metadata* o) {
if (o == NULL) {
return NULL;
} else {
return _factory->get_metadata(o);
}
}
void ensure_metadata_alive(ciMetadata* m) {
_factory->ensure_metadata_alive(m);
}
ciInstance* get_instance(oop o) {
if (o == NULL) return NULL;
return get_object(o)->as_instance();
}
ciObjArrayKlass* get_obj_array_klass(Klass* o) {
if (o == NULL) return NULL;
return get_metadata(o)->as_obj_array_klass();
}
ciTypeArrayKlass* get_type_array_klass(Klass* o) {
if (o == NULL) return NULL;
return get_metadata(o)->as_type_array_klass();
}
ciKlass* get_klass(Klass* o) {
if (o == NULL) return NULL;
return get_metadata(o)->as_klass();
}
ciInstanceKlass* get_instance_klass(Klass* o) {
if (o == NULL) return NULL;
return get_metadata(o)->as_instance_klass();
}
ciMethod* get_method(Method* o) {
if (o == NULL) return NULL;
return get_metadata(o)->as_method();
}
ciMethodData* get_method_data(MethodData* o) {
if (o == NULL) return NULL;
return get_metadata(o)->as_method_data();
}
ciMethod* get_method_from_handle(Method* method);
ciInstance* get_or_create_exception(jobject& handle, Symbol* name);
ciMethod* get_unloaded_method(ciInstanceKlass* holder,
ciSymbol* name,
ciSymbol* signature,
ciInstanceKlass* accessor) {
return _factory->get_unloaded_method(holder, name, signature, accessor);
}
ciKlass* get_unloaded_klass(ciKlass* accessing_klass,
ciSymbol* name) {
return _factory->get_unloaded_klass(accessing_klass, name, true);
}
ciInstance* get_unloaded_klass_mirror(ciKlass* type) {
return _factory->get_unloaded_klass_mirror(type);
}
ciInstance* get_unloaded_method_handle_constant(ciKlass* holder,
ciSymbol* name,
ciSymbol* signature,
int ref_kind) {
return _factory->get_unloaded_method_handle_constant(holder, name, signature, ref_kind);
}
ciInstance* get_unloaded_method_type_constant(ciSymbol* signature) {
return _factory->get_unloaded_method_type_constant(signature);
}
ciKlass *check_get_unloaded_klass(ciKlass* accessing_klass, ciSymbol* name) {
return _factory->get_unloaded_klass(accessing_klass, name, false);
}
ciReturnAddress* get_return_address(int bci) {
return _factory->get_return_address(bci);
}
ciMethodData* get_empty_methodData() {
return _factory->get_empty_methodData();
}
char* name_buffer(int req_len);
static bool is_in_vm();
void validate_compile_task_dependencies(ciMethod* target);
public:
enum {
MethodCompilable,
MethodCompilable_not_at_tier,
MethodCompilable_never
};
ciEnv(CompileTask* task, int system_dictionary_modification_counter);
ciEnv(Arena* arena);
~ciEnv();
OopRecorder* oop_recorder() { return _oop_recorder; }
void set_oop_recorder(OopRecorder* r) { _oop_recorder = r; }
DebugInformationRecorder* debug_info() { return _debug_info; }
void set_debug_info(DebugInformationRecorder* i) { _debug_info = i; }
Dependencies* dependencies() { return _dependencies; }
void set_dependencies(Dependencies* d) { _dependencies = d; }
bool failing() { return _failure_reason != NULL; }
const char* failure_reason() { return _failure_reason; }
int compilable() { return _compilable; }
const char* retry_message() const {
switch (_compilable) {
case ciEnv::MethodCompilable_not_at_tier:
return "retry at different tier";
case ciEnv::MethodCompilable_never:
return "not retryable";
case ciEnv::MethodCompilable:
return NULL;
default:
ShouldNotReachHere();
return NULL;
}
}
bool break_at_compile() { return _break_at_compile; }
void set_break_at_compile(bool z) { _break_at_compile = z; }
void cache_jvmti_state();
bool jvmti_state_changed() const;
bool should_retain_local_variables() const;
bool jvmti_can_hotswap_or_post_breakpoint() const { return _jvmti_can_hotswap_or_post_breakpoint; }
bool jvmti_can_post_on_exceptions() const { return _jvmti_can_post_on_exceptions; }
void cache_dtrace_flags();
bool dtrace_extended_probes() const { return _dtrace_extended_probes; }
bool dtrace_monitor_probes() const { return _dtrace_monitor_probes; }
bool dtrace_method_probes() const { return _dtrace_method_probes; }
bool dtrace_alloc_probes() const { return _dtrace_alloc_probes; }
CompileTask* task() { return _task; }
int comp_level(); // task()->comp_level()
uint compile_id(); // task()->compile_id()
void register_method(ciMethod* target,
int entry_bci,
CodeOffsets* offsets,
int orig_pc_offset,
CodeBuffer* code_buffer,
int frame_words,
OopMapSet* oop_map_set,
ExceptionHandlerTable* handler_table,
ImplicitExceptionTable* inc_table,
AbstractCompiler* compiler,
int comp_level,
bool has_unsafe_access,
bool has_wide_vectors,
RTMState rtm_state = NoRTM);
#define WK_KLASS_FUNC(name, ignore_s, ignore_o) \
ciInstanceKlass* name() { \
return _##name;\
}
WK_KLASSES_DO(WK_KLASS_FUNC)
#undef WK_KLASS_FUNC
ciInstance* NullPointerException_instance() {
assert(_NullPointerException_instance != NULL, "initialization problem");
return _NullPointerException_instance;
}
ciInstance* ArithmeticException_instance() {
assert(_ArithmeticException_instance != NULL, "initialization problem");
return _ArithmeticException_instance;
}
ciInstance* ArrayIndexOutOfBoundsException_instance();
ciInstance* ArrayStoreException_instance();
ciInstance* ClassCastException_instance();
ciInstance* the_null_string();
ciInstance* the_min_jint_string();
static ciSymbol* unloaded_cisymbol() {
return _unloaded_cisymbol;
}
static ciObjArrayKlass* unloaded_ciobjarrayklass() {
return _unloaded_ciobjarrayklass;
}
static ciInstanceKlass* unloaded_ciinstance_klass() {
return _unloaded_ciinstance_klass;
}
ciInstance* unloaded_ciinstance();
ciKlass* find_system_klass(ciSymbol* klass_name);
static ciInstanceKlass* get_instance_klass_for_declared_method_holder(ciKlass* klass);
int array_element_offset_in_bytes(ciArray* a, ciObject* o);
Arena* arena() { return _arena; }
static ciEnv* current() { return CompilerThread::current()->env(); }
static ciEnv* current(CompilerThread *thread) { return thread->env(); }
void* compiler_data() { return _compiler_data; }
void set_compiler_data(void* x) { _compiler_data = x; }
void notice_inlined_method(ciMethod* method);
int num_inlined_bytecodes() const;
CompileLog* log() { return _log; }
void set_log(CompileLog* log) { _log = log; }
bool system_dictionary_modification_counter_changed();
void record_failure(const char* reason);
void record_method_not_compilable(const char* reason, bool all_tiers = true);
void record_out_of_memory_failure();
void metadata_do(void f(Metadata*)) { _factory->metadata_do(f); }
void dump_replay_data(int compile_id);
void dump_inline_data(int compile_id);
void dump_replay_data(outputStream* out);
void dump_replay_data_unsafe(outputStream* out);
void dump_compile_data(outputStream* out);
};
#endif // SHARE_VM_CI_CIENV_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciExceptionHandler.cpp
#include "precompiled.hpp"
#include "ci/ciExceptionHandler.hpp"
#include "ci/ciUtilities.hpp"
ciInstanceKlass* ciExceptionHandler::catch_klass() {
VM_ENTRY_MARK;
assert(!is_catch_all(), "bad index");
if (_catch_klass == NULL) {
bool will_link;
assert(_loading_klass->get_instanceKlass()->is_linked(), "must be linked before accessing constant pool");
constantPoolHandle cpool(_loading_klass->get_instanceKlass()->constants());
ciKlass* k = CURRENT_ENV->get_klass_by_index(cpool,
_catch_klass_index,
will_link,
_loading_klass);
if (!will_link && k->is_loaded()) {
GUARDED_VM_ENTRY(
k = CURRENT_ENV->get_unloaded_klass(_loading_klass, k->name());
)
}
_catch_klass = k->as_instance_klass();
}
return _catch_klass;
}
void ciExceptionHandler::print() {
tty->print("<ciExceptionHandler start=%d limit=%d"
" handler_bci=%d ex_klass_index=%d",
start(), limit(), handler_bci(), catch_klass_index());
if (_catch_klass != NULL) {
tty->print(" ex_klass=");
_catch_klass->print();
}
tty->print(">");
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciExceptionHandler.hpp
#ifndef SHARE_VM_CI_CIEXCEPTIONHANDLER_HPP
#define SHARE_VM_CI_CIEXCEPTIONHANDLER_HPP
#include "ci/ciClassList.hpp"
#include "ci/ciInstanceKlass.hpp"
class ciExceptionHandler : public ResourceObj {
private:
friend class ciMethod;
ciInstanceKlass* _loading_klass;
int _start;
int _limit;
int _handler_bci;
int _catch_klass_index;
ciInstanceKlass* _catch_klass;
public:
ciExceptionHandler(ciInstanceKlass* loading_klass,
int start, int limit,
int handler_bci, int klass_index) {
_loading_klass = loading_klass;
_start = start;
_limit = limit;
_handler_bci = handler_bci;
_catch_klass_index = klass_index;
_catch_klass = NULL;
}
int start() { return _start; }
int limit() { return _limit; }
int handler_bci() { return _handler_bci; }
int catch_klass_index() { return _catch_klass_index; }
ciInstanceKlass* catch_klass();
bool is_catch_all() { return catch_klass_index() == 0; }
bool is_in_range(int bci) {
return start() <= bci && bci < limit();
}
bool catches(ciInstanceKlass *exc) {
return is_catch_all() || exc->is_subtype_of(catch_klass());
}
bool is_rethrow() { return handler_bci() == -1; }
void print();
};
#endif // SHARE_VM_CI_CIEXCEPTIONHANDLER_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciField.cpp
#include "precompiled.hpp"
#include "ci/ciField.hpp"
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/systemDictionary.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "interpreter/linkResolver.hpp"
#include "memory/universe.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/oop.inline2.hpp"
#include "runtime/fieldDescriptor.hpp"
ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with_put(NULL), _known_to_link_with_get(NULL) {
ASSERT_IN_VM;
CompilerThread *thread = CompilerThread::current();
assert(ciObjectFactory::is_initialized(), "not a shared field");
assert(klass->get_instanceKlass()->is_linked(), "must be linked before using its constan-pool");
constantPoolHandle cpool(thread, klass->get_instanceKlass()->constants());
Symbol* name = cpool->name_ref_at(index);
_name = ciEnv::current(thread)->get_symbol(name);
int nt_index = cpool->name_and_type_ref_index_at(index);
int sig_index = cpool->signature_ref_index_at(nt_index);
Symbol* signature = cpool->symbol_at(sig_index);
_signature = ciEnv::current(thread)->get_symbol(signature);
BasicType field_type = FieldType::basic_type(signature);
if (field_type == T_OBJECT || field_type == T_ARRAY) {
bool ignore;
_type = ciEnv::current(thread)->get_klass_by_index(cpool, sig_index, ignore, klass);
} else {
_type = ciType::make(field_type);
}
_name = (ciSymbol*)ciEnv::current(thread)->get_symbol(name);
int holder_index = cpool->klass_ref_index_at(index);
bool holder_is_accessible;
ciInstanceKlass* declared_holder =
ciEnv::current(thread)->get_klass_by_index(cpool, holder_index,
holder_is_accessible,
klass)->as_instance_klass();
if (!holder_is_accessible) {
_holder = declared_holder;
_offset = -1;
_is_constant = false;
return;
}
InstanceKlass* loaded_decl_holder = declared_holder->get_instanceKlass();
fieldDescriptor field_desc;
Klass* canonical_holder =
loaded_decl_holder->find_field(name, signature, &field_desc);
if (canonical_holder == NULL) {
_holder = declared_holder;
_offset = -1;
_is_constant = false;
return;
}
if (!Reflection::verify_field_access(klass->get_Klass(), declared_holder->get_Klass(), canonical_holder, field_desc.access_flags(), true)) {
_holder = declared_holder;
_offset = -1;
_is_constant = false;
return;
}
assert(canonical_holder == field_desc.field_holder(), "just checking");
initialize_from(&field_desc);
}
ciField::ciField(fieldDescriptor *fd): _known_to_link_with_put(NULL), _known_to_link_with_get(NULL) {
ASSERT_IN_VM;
ciEnv* env = CURRENT_ENV;
_name = env->get_symbol(fd->name());
_signature = env->get_symbol(fd->signature());
BasicType field_type = fd->field_type();
if (field_type == T_OBJECT || field_type == T_ARRAY) {
_type = NULL; // must call compute_type on first access
} else {
_type = ciType::make(field_type);
}
initialize_from(fd);
assert(is_shared() || ciObjectFactory::is_initialized(),
"bootstrap classes must not create & cache unshared fields");
}
static bool trust_final_non_static_fields(ciInstanceKlass* holder) {
if (holder == NULL)
return false;
if (holder->name() == ciSymbol::java_lang_System())
return false;
if (holder->is_in_package("java/lang/invoke") || holder->is_in_package("sun/invoke"))
return true;
if (holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicIntegerFieldUpdater_Impl() ||
holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicLongFieldUpdater_CASUpdater() ||
holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicLongFieldUpdater_LockedUpdater() ||
holder->name() == ciSymbol::java_util_concurrent_atomic_AtomicReferenceFieldUpdater_Impl()) {
return true;
}
return TrustFinalNonStaticFields;
}
void ciField::initialize_from(fieldDescriptor* fd) {
_flags = ciFlags(fd->access_flags());
_offset = fd->offset();
_holder = CURRENT_ENV->get_instance_klass(fd->field_holder());
bool is_final = this->is_final();
bool is_stable = FoldStableValues && this->is_stable();
if (_holder->is_initialized() && ((is_final && !has_initialized_final_update()) || is_stable)) {
if (!this->is_static()) {
if (is_stable || trust_final_non_static_fields(_holder)) {
_is_constant = true;
return;
}
_is_constant = false;
return;
}
KlassHandle k = _holder->get_Klass();
assert( SystemDictionary::System_klass() != NULL, "Check once per vm");
if( k() == SystemDictionary::System_klass() ) {
if( _offset == java_lang_System::in_offset_in_bytes() ||
_offset == java_lang_System::out_offset_in_bytes() ||
_offset == java_lang_System::err_offset_in_bytes() ) {
_is_constant = false;
return;
}
}
Handle mirror = k->java_mirror();
switch(type()->basic_type()) {
case T_BYTE:
_constant_value = ciConstant(type()->basic_type(), mirror->byte_field(_offset));
break;
case T_CHAR:
_constant_value = ciConstant(type()->basic_type(), mirror->char_field(_offset));
break;
case T_SHORT:
_constant_value = ciConstant(type()->basic_type(), mirror->short_field(_offset));
break;
case T_BOOLEAN:
_constant_value = ciConstant(type()->basic_type(), mirror->bool_field(_offset));
break;
case T_INT:
_constant_value = ciConstant(type()->basic_type(), mirror->int_field(_offset));
break;
case T_FLOAT:
_constant_value = ciConstant(mirror->float_field(_offset));
break;
case T_DOUBLE:
_constant_value = ciConstant(mirror->double_field(_offset));
break;
case T_LONG:
_constant_value = ciConstant(mirror->long_field(_offset));
break;
case T_OBJECT:
case T_ARRAY:
{
oop o = mirror->obj_field(_offset);
if (o == NULL) {
_constant_value = ciConstant(type()->basic_type(), ciNullObject::make());
} else {
_constant_value = ciConstant(type()->basic_type(), CURRENT_ENV->get_object(o));
assert(_constant_value.as_object() == CURRENT_ENV->get_object(o), "check interning");
}
}
}
if (is_stable && _constant_value.is_null_or_zero()) {
_is_constant = false;
} else {
_is_constant = true;
}
} else {
_is_constant = false;
}
}
ciType* ciField::compute_type() {
GUARDED_VM_ENTRY(return compute_type_impl();)
}
ciType* ciField::compute_type_impl() {
ciKlass* type = CURRENT_ENV->get_klass_by_name_impl(_holder, constantPoolHandle(), _signature, false);
if (!type->is_primitive_type() && is_shared()) {
bool type_is_also_shared = false;
if (type->is_type_array_klass()) {
type_is_also_shared = true; // int[] etc. are explicitly bootstrapped
} else if (type->is_instance_klass()) {
type_is_also_shared = type->as_instance_klass()->is_shared();
} else {
type_is_also_shared = !ciObjectFactory::is_initialized();
}
if (!type_is_also_shared)
return type; // Bummer.
}
_type = type;
return type;
}
bool ciField::will_link(ciInstanceKlass* accessing_klass,
Bytecodes::Code bc) {
VM_ENTRY_MARK;
assert(bc == Bytecodes::_getstatic || bc == Bytecodes::_putstatic ||
bc == Bytecodes::_getfield || bc == Bytecodes::_putfield,
"unexpected bytecode");
if (_offset == -1) {
return false;
}
bool is_static = (bc == Bytecodes::_getstatic || bc == Bytecodes::_putstatic);
if (is_static != this->is_static()) {
return false;
}
bool is_put = (bc == Bytecodes::_putfield || bc == Bytecodes::_putstatic);
if (is_put) {
if (_known_to_link_with_put == accessing_klass) {
return true;
}
} else {
if (_known_to_link_with_get == accessing_klass) {
return true;
}
}
fieldDescriptor result;
LinkResolver::resolve_field(result, _holder->get_instanceKlass(),
_name->get_symbol(), _signature->get_symbol(),
accessing_klass->get_Klass(), bc, true, false,
KILL_COMPILE_ON_FATAL_(false));
if (accessing_klass->is_shared() || !is_shared()) {
if (is_put) {
_known_to_link_with_put = accessing_klass;
} else {
_known_to_link_with_get = accessing_klass;
}
}
return true;
}
void ciField::print() {
tty->print("<ciField name=");
_holder->print_name();
tty->print(".");
_name->print_symbol();
tty->print(" signature=");
_signature->print_symbol();
tty->print(" offset=%d type=", _offset);
if (_type != NULL)
_type->print_name();
else
tty->print("(reference)");
tty->print(" flags=%04x", flags().as_int());
tty->print(" is_constant=%s", bool_to_str(_is_constant));
if (_is_constant && is_static()) {
tty->print(" constant_value=");
_constant_value.print();
}
tty->print(">");
}
void ciField::print_name_on(outputStream* st) {
name()->print_symbol_on(st);
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciField.hpp
#ifndef SHARE_VM_CI_CIFIELD_HPP
#define SHARE_VM_CI_CIFIELD_HPP
#include "ci/ciClassList.hpp"
#include "ci/ciConstant.hpp"
#include "ci/ciFlags.hpp"
#include "ci/ciInstance.hpp"
class ciField : public ResourceObj {
CI_PACKAGE_ACCESS
friend class ciEnv;
friend class ciInstanceKlass;
friend class NonStaticFieldFiller;
private:
ciFlags _flags;
ciInstanceKlass* _holder;
ciSymbol* _name;
ciSymbol* _signature;
ciType* _type;
int _offset;
bool _is_constant;
ciInstanceKlass* _known_to_link_with_put;
ciInstanceKlass* _known_to_link_with_get;
ciConstant _constant_value;
ciType* compute_type();
ciType* compute_type_impl();
ciField(ciInstanceKlass* klass, int index);
ciField(fieldDescriptor* fd);
void initialize_from(fieldDescriptor* fd);
public:
ciFlags flags() { return _flags; }
ciInstanceKlass* holder() { return _holder; }
ciSymbol* name() { return _name; }
ciSymbol* signature() { return _signature; }
ciType* type() { return (_type == NULL) ? compute_type() : _type; }
BasicType layout_type() { return type2field[(_type == NULL) ? T_OBJECT : _type->basic_type()]; }
int size_in_bytes() { return type2aelembytes(layout_type()); }
int offset() {
assert(_offset >= 1, "illegal call to offset()");
return _offset;
}
int offset_in_bytes() {
return offset();
}
bool is_shared() {
return _holder->is_shared() && !is_static();
}
bool is_constant() { return _is_constant; }
ciConstant constant_value() {
assert(is_static() && is_constant(), "illegal call to constant_value()");
return _constant_value;
}
ciConstant constant_value_of(ciObject* object) {
assert(!is_static() && is_constant(), "only if field is non-static constant");
assert(object->is_instance(), "must be instance");
return object->as_instance()->field_value(this);
}
bool will_link(ciInstanceKlass* accessing_klass,
Bytecodes::Code bc);
bool is_public () { return flags().is_public(); }
bool is_private () { return flags().is_private(); }
bool is_protected () { return flags().is_protected(); }
bool is_static () { return flags().is_static(); }
bool is_final () { return flags().is_final(); }
bool is_stable () { return flags().is_stable(); }
bool is_volatile () { return flags().is_volatile(); }
bool is_transient () { return flags().is_transient(); }
bool has_initialized_final_update() { return flags().has_initialized_final_update(); }
bool is_call_site_target() {
ciInstanceKlass* callsite_klass = CURRENT_ENV->CallSite_klass();
if (callsite_klass == NULL)
return false;
return (holder()->is_subclass_of(callsite_klass) && (name() == ciSymbol::target_name()));
}
void print();
void print_name_on(outputStream* st);
};
#endif // SHARE_VM_CI_CIFIELD_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciFlags.cpp
#include "precompiled.hpp"
#include "ci/ciFlags.hpp"
void ciFlags::print_klass_flags(outputStream* st) {
if (is_public()) {
st->print("public");
} else {
st->print("DEFAULT_ACCESS");
}
if (is_final()) {
st->print(",final");
}
if (is_super()) {
st->print(",super");
}
if (is_interface()) {
st->print(",interface");
}
if (is_abstract()) {
st->print(",abstract");
}
}
void ciFlags::print_member_flags(outputStream* st) {
if (is_public()) {
st->print("public");
} else if (is_private()) {
st->print("private");
} else if (is_protected()) {
st->print("protected");
} else {
st->print("DEFAULT_ACCESS");
}
if (is_static()) {
st->print(",static");
}
if (is_final()) {
st->print(",final");
}
if (is_synchronized()) {
st->print(",synchronized");
}
if (is_volatile()) {
st->print(",volatile");
}
if (is_transient()) {
st->print(",transient");
}
if (is_native()) {
st->print(",native");
}
if (is_abstract()) {
st->print(",abstract");
}
if (is_strict()) {
st->print(",strict");
}
}
void ciFlags::print(outputStream* st) {
st->print(" flags=%x", _flags);
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciFlags.hpp
#ifndef SHARE_VM_CI_CIFLAGS_HPP
#define SHARE_VM_CI_CIFLAGS_HPP
#include "ci/ciClassList.hpp"
#include "memory/allocation.hpp"
#include "prims/jvm.h"
#include "utilities/accessFlags.hpp"
class ciFlags VALUE_OBJ_CLASS_SPEC {
private:
friend class ciInstanceKlass;
friend class ciField;
friend class ciMethod;
jint _flags;
ciFlags() { _flags = 0; }
ciFlags(AccessFlags flags) { _flags = flags.as_int(); }
public:
bool is_public () const { return (_flags & JVM_ACC_PUBLIC ) != 0; }
bool is_private () const { return (_flags & JVM_ACC_PRIVATE ) != 0; }
bool is_protected () const { return (_flags & JVM_ACC_PROTECTED ) != 0; }
bool is_static () const { return (_flags & JVM_ACC_STATIC ) != 0; }
bool is_final () const { return (_flags & JVM_ACC_FINAL ) != 0; }
bool is_synchronized () const { return (_flags & JVM_ACC_SYNCHRONIZED ) != 0; }
bool is_super () const { return (_flags & JVM_ACC_SUPER ) != 0; }
bool is_volatile () const { return (_flags & JVM_ACC_VOLATILE ) != 0; }
bool is_transient () const { return (_flags & JVM_ACC_TRANSIENT ) != 0; }
bool is_native () const { return (_flags & JVM_ACC_NATIVE ) != 0; }
bool is_interface () const { return (_flags & JVM_ACC_INTERFACE ) != 0; }
bool is_abstract () const { return (_flags & JVM_ACC_ABSTRACT ) != 0; }
bool is_strict () const { return (_flags & JVM_ACC_STRICT ) != 0; }
bool is_stable () const { return (_flags & JVM_ACC_FIELD_STABLE ) != 0; }
bool has_initialized_final_update() const { return (_flags & JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE) != 0; };
jint as_int() { return _flags; }
void print_klass_flags(outputStream* st = tty);
void print_member_flags(outputStream* st = tty);
void print(outputStream* st = tty);
};
#endif // SHARE_VM_CI_CIFLAGS_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciInstance.cpp
#include "precompiled.hpp"
#include "ci/ciConstant.hpp"
#include "ci/ciField.hpp"
#include "ci/ciInstance.hpp"
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/systemDictionary.hpp"
#include "oops/oop.inline.hpp"
ciType* ciInstance::java_mirror_type() {
VM_ENTRY_MARK;
oop m = get_oop();
if (m == NULL || m->klass() != SystemDictionary::Class_klass()) {
return NULL;
}
if (java_lang_Class::is_primitive(m)) {
return ciType::make(java_lang_Class::primitive_type(m));
} else {
Klass* k = java_lang_Class::as_Klass(m);
assert(k != NULL, "");
return CURRENT_THREAD_ENV->get_klass(k);
}
}
ciConstant ciInstance::field_value(ciField* field) {
assert(is_loaded(), "invalid access - must be loaded");
assert(field->holder()->is_loaded(), "invalid access - holder must be loaded");
assert(klass()->is_subclass_of(field->holder()), "invalid access - must be subclass");
VM_ENTRY_MARK;
ciConstant result;
Handle obj = get_oop();
assert(!obj.is_null(), "bad oop");
BasicType field_btype = field->type()->basic_type();
int offset = field->offset();
switch(field_btype) {
case T_BYTE:
return ciConstant(field_btype, obj->byte_field(offset));
break;
case T_CHAR:
return ciConstant(field_btype, obj->char_field(offset));
break;
case T_SHORT:
return ciConstant(field_btype, obj->short_field(offset));
break;
case T_BOOLEAN:
return ciConstant(field_btype, obj->bool_field(offset));
break;
case T_INT:
return ciConstant(field_btype, obj->int_field(offset));
break;
case T_FLOAT:
return ciConstant(obj->float_field(offset));
break;
case T_DOUBLE:
return ciConstant(obj->double_field(offset));
break;
case T_LONG:
return ciConstant(obj->long_field(offset));
break;
case T_OBJECT:
case T_ARRAY:
{
oop o = obj->obj_field(offset);
if (o == NULL) {
return ciConstant(field_btype, ciNullObject::make());
} else {
return ciConstant(field_btype, CURRENT_ENV->get_object(o));
}
}
}
ShouldNotReachHere();
return ciConstant();
}
ciConstant ciInstance::field_value_by_offset(int field_offset) {
ciInstanceKlass* ik = klass()->as_instance_klass();
ciField* field = ik->get_field_by_offset(field_offset, false);
if (field == NULL)
return ciConstant(); // T_ILLEGAL
return field_value(field);
}
void ciInstance::print_impl(outputStream* st) {
st->print(" type=");
klass()->print(st);
}
ciKlass* ciInstance::java_lang_Class_klass() {
VM_ENTRY_MARK;
return CURRENT_ENV->get_metadata(java_lang_Class::as_Klass(get_oop()))->as_klass();
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciInstance.hpp
#ifndef SHARE_VM_CI_CIINSTANCE_HPP
#define SHARE_VM_CI_CIINSTANCE_HPP
#include "ci/ciObject.hpp"
#include "oops/instanceOop.hpp"
class ciInstance : public ciObject {
CI_PACKAGE_ACCESS
protected:
ciInstance(instanceHandle h_i) : ciObject(h_i) {
assert(h_i()->is_instance(), "wrong type");
}
ciInstance(ciKlass* klass) : ciObject(klass) {}
instanceOop get_instanceOop() { return (instanceOop)get_oop(); }
const char* type_string() { return "ciInstance"; }
void print_impl(outputStream* st);
public:
ciType* java_mirror_type();
bool is_instance() { return true; }
bool is_java_object() { return true; }
ciConstant field_value(ciField* field);
ciConstant field_value_by_offset(int field_offset);
ciKlass* java_lang_Class_klass();
};
#endif // SHARE_VM_CI_CIINSTANCE_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciInstanceKlass.cpp
#include "precompiled.hpp"
#include "ci/ciField.hpp"
#include "ci/ciInstance.hpp"
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/systemDictionary.hpp"
#include "memory/allocation.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/fieldStreams.hpp"
#include "runtime/fieldDescriptor.hpp"
ciInstanceKlass::ciInstanceKlass(KlassHandle h_k) :
ciKlass(h_k), _non_static_fields(NULL)
{
assert(get_Klass()->oop_is_instance(), "wrong type");
assert(get_instanceKlass()->is_loaded(), "must be at least loaded");
InstanceKlass* ik = get_instanceKlass();
AccessFlags access_flags = ik->access_flags();
_flags = ciFlags(access_flags);
_has_finalizer = access_flags.has_finalizer();
_has_subklass = ik->subklass() != NULL;
_init_state = ik->init_state();
_nonstatic_field_size = ik->nonstatic_field_size();
_has_nonstatic_fields = ik->has_nonstatic_fields();
_has_default_methods = ik->has_default_methods();
_is_anonymous = ik->is_anonymous();
_nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields:
_implementor = NULL; // we will fill these lazily
Thread *thread = Thread::current();
if (ciObjectFactory::is_initialized()) {
_loader = JNIHandles::make_local(thread, ik->class_loader());
_protection_domain = JNIHandles::make_local(thread,
ik->protection_domain());
_is_shared = false;
} else {
Handle h_loader(thread, ik->class_loader());
Handle h_protection_domain(thread, ik->protection_domain());
_loader = JNIHandles::make_global(h_loader);
_protection_domain = JNIHandles::make_global(h_protection_domain);
_is_shared = true;
}
_super = NULL;
_java_mirror = NULL;
if (is_shared()) {
if (h_k() != SystemDictionary::Object_klass()) {
super();
}
}
_field_cache = NULL;
}
ciInstanceKlass::ciInstanceKlass(ciSymbol* name,
jobject loader, jobject protection_domain)
: ciKlass(name, T_OBJECT)
{
assert(name->byte_at(0) != '[', "not an instance klass");
_init_state = (InstanceKlass::ClassState)0;
_nonstatic_field_size = -1;
_has_nonstatic_fields = false;
_nonstatic_fields = NULL;
_is_anonymous = false;
_loader = loader;
_protection_domain = protection_domain;
_is_shared = false;
_super = NULL;
_java_mirror = NULL;
_field_cache = NULL;
}
void ciInstanceKlass::compute_shared_init_state() {
GUARDED_VM_ENTRY(
InstanceKlass* ik = get_instanceKlass();
_init_state = ik->init_state();
)
}
bool ciInstanceKlass::compute_shared_has_subklass() {
GUARDED_VM_ENTRY(
InstanceKlass* ik = get_instanceKlass();
_has_subklass = ik->subklass() != NULL;
return _has_subklass;
)
}
oop ciInstanceKlass::loader() {
ASSERT_IN_VM;
return JNIHandles::resolve(_loader);
}
jobject ciInstanceKlass::loader_handle() {
return _loader;
}
oop ciInstanceKlass::protection_domain() {
ASSERT_IN_VM;
return JNIHandles::resolve(_protection_domain);
}
jobject ciInstanceKlass::protection_domain_handle() {
return _protection_domain;
}
ciConstantPoolCache* ciInstanceKlass::field_cache() {
if (is_shared()) {
return NULL;
}
if (_field_cache == NULL) {
assert(!is_java_lang_Object(), "Object has no fields");
Arena* arena = CURRENT_ENV->arena();
_field_cache = new (arena) ciConstantPoolCache(arena, 5);
}
return _field_cache;
}
ciInstanceKlass* ciInstanceKlass::get_canonical_holder(int offset) {
#ifdef ASSERT
if (!(offset >= 0 && offset < layout_helper())) {
tty->print("*** get_canonical_holder(%d) on ", offset);
this->print();
tty->print_cr(" ***");
};
assert(offset >= 0 && offset < layout_helper(), "offset must be tame");
#endif
if (offset < instanceOopDesc::base_offset_in_bytes()) {
return CURRENT_ENV->Object_klass();
}
ciInstanceKlass* self = this;
for (;;) {
assert(self->is_loaded(), "must be loaded to have size");
ciInstanceKlass* super = self->super();
if (super == NULL || super->nof_nonstatic_fields() == 0 ||
!super->contains_field_offset(offset)) {
return self;
} else {
self = super; // return super->get_canonical_holder(offset)
}
}
}
bool ciInstanceKlass::is_java_lang_Object() const {
return equals(CURRENT_ENV->Object_klass());
}
bool ciInstanceKlass::uses_default_loader() const {
return _loader == NULL;
}
BasicType ciInstanceKlass::box_klass_type() const {
if (uses_default_loader() && is_loaded()) {
return SystemDictionary::box_klass_type(get_Klass());
} else {
return T_OBJECT;
}
}
bool ciInstanceKlass::is_box_klass() const {
return is_java_primitive(box_klass_type());
}
bool ciInstanceKlass::is_boxed_value_offset(int offset) const {
BasicType bt = box_klass_type();
return is_java_primitive(bt) &&
(offset == java_lang_boxing_object::value_offset_in_bytes(bt));
}
bool ciInstanceKlass::is_in_package(const char* packagename, int len) {
if (!uses_default_loader())
return false;
GUARDED_VM_ENTRY(
return is_in_package_impl(packagename, len);
)
}
bool ciInstanceKlass::is_in_package_impl(const char* packagename, int len) {
ASSERT_IN_VM;
if (packagename[len - 1] == '/')
len--;
if (!name()->starts_with(packagename, len))
return false;
if ((len + 1) > name()->utf8_length())
return false;
if ((char) name()->byte_at(len) != '/')
return false;
if (name()->index_of_at(len+1, "/", 1) >= 0)
return false;
return true;
}
void ciInstanceKlass::print_impl(outputStream* st) {
ciKlass::print_impl(st);
GUARDED_VM_ENTRY(st->print(" loader=" INTPTR_FORMAT, p2i((address)loader()));)
if (is_loaded()) {
st->print(" loaded=true initialized=%s finalized=%s subklass=%s size=%d flags=",
bool_to_str(is_initialized()),
bool_to_str(has_finalizer()),
bool_to_str(has_subklass()),
layout_helper());
_flags.print_klass_flags();
if (_super) {
st->print(" super=");
_super->print_name();
}
if (_java_mirror) {
st->print(" mirror=PRESENT");
}
} else {
st->print(" loaded=false");
}
}
ciInstanceKlass* ciInstanceKlass::super() {
assert(is_loaded(), "must be loaded");
if (_super == NULL && !is_java_lang_Object()) {
GUARDED_VM_ENTRY(
Klass* super_klass = get_instanceKlass()->super();
_super = CURRENT_ENV->get_instance_klass(super_klass);
)
}
return _super;
}
ciInstance* ciInstanceKlass::java_mirror() {
if (is_shared()) {
return ciKlass::java_mirror();
}
if (_java_mirror == NULL) {
_java_mirror = ciKlass::java_mirror();
}
return _java_mirror;
}
ciInstanceKlass* ciInstanceKlass::unique_concrete_subklass() {
if (!is_loaded()) return NULL; // No change if class is not loaded
if (!is_abstract()) return NULL; // Only applies to abstract classes.
if (!has_subklass()) return NULL; // Must have at least one subklass.
VM_ENTRY_MARK;
InstanceKlass* ik = get_instanceKlass();
Klass* up = ik->up_cast_abstract();
assert(up->oop_is_instance(), "must be InstanceKlass");
if (ik == up) {
return NULL;
}
return CURRENT_THREAD_ENV->get_instance_klass(up);
}
bool ciInstanceKlass::has_finalizable_subclass() {
if (!is_loaded()) return true;
VM_ENTRY_MARK;
return Dependencies::find_finalizable_subclass(get_instanceKlass()) != NULL;
}
ciField* ciInstanceKlass::get_field_by_offset(int field_offset, bool is_static) {
if (!is_static) {
for (int i = 0, len = nof_nonstatic_fields(); i < len; i++) {
ciField* field = _nonstatic_fields->at(i);
int field_off = field->offset_in_bytes();
if (field_off == field_offset)
return field;
if (field_off > field_offset)
break;
}
return NULL;
}
VM_ENTRY_MARK;
InstanceKlass* k = get_instanceKlass();
fieldDescriptor fd;
if (!k->find_field_from_offset(field_offset, is_static, &fd)) {
return NULL;
}
ciField* field = new (CURRENT_THREAD_ENV->arena()) ciField(&fd);
return field;
}
ciField* ciInstanceKlass::get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static) {
VM_ENTRY_MARK;
InstanceKlass* k = get_instanceKlass();
fieldDescriptor fd;
Klass* def = k->find_field(name->get_symbol(), signature->get_symbol(), is_static, &fd);
if (def == NULL) {
return NULL;
}
ciField* field = new (CURRENT_THREAD_ENV->arena()) ciField(&fd);
return field;
}
class NonStaticFieldFiller: public FieldClosure {
GrowableArray<ciField*>* _arr;
ciEnv* _curEnv;
public:
NonStaticFieldFiller(ciEnv* curEnv, GrowableArray<ciField*>* arr) :
_curEnv(curEnv), _arr(arr)
{}
void do_field(fieldDescriptor* fd) {
ciField* field = new (_curEnv->arena()) ciField(fd);
_arr->append(field);
}
};
GrowableArray<ciField*>* ciInstanceKlass::non_static_fields() {
if (_non_static_fields == NULL) {
VM_ENTRY_MARK;
ciEnv* curEnv = ciEnv::current();
InstanceKlass* ik = get_instanceKlass();
int max_n_fields = ik->java_fields_count();
Arena* arena = curEnv->arena();
_non_static_fields =
new (arena) GrowableArray<ciField*>(arena, max_n_fields, 0, NULL);
NonStaticFieldFiller filler(curEnv, _non_static_fields);
ik->do_nonstatic_fields(&filler);
}
return _non_static_fields;
}
static int sort_field_by_offset(ciField** a, ciField** b) {
return (*a)->offset_in_bytes() - (*b)->offset_in_bytes();
}
int ciInstanceKlass::compute_nonstatic_fields() {
assert(is_loaded(), "must be loaded");
if (_nonstatic_fields != NULL)
return _nonstatic_fields->length();
if (!has_nonstatic_fields()) {
Arena* arena = CURRENT_ENV->arena();
_nonstatic_fields = new (arena) GrowableArray<ciField*>(arena, 0, 0, NULL);
return 0;
}
assert(!is_java_lang_Object(), "bootstrap OK");
int fsize = nonstatic_field_size() * heapOopSize;
ciInstanceKlass* super = this->super();
GrowableArray<ciField*>* super_fields = NULL;
if (super != NULL && super->has_nonstatic_fields()) {
int super_fsize = super->nonstatic_field_size() * heapOopSize;
int super_flen = super->nof_nonstatic_fields();
super_fields = super->_nonstatic_fields;
assert(super_flen == 0 || super_fields != NULL, "first get nof_fields");
if (fsize == super_fsize) {
_nonstatic_fields = super_fields;
return super_fields->length();
}
}
GrowableArray<ciField*>* fields = NULL;
GUARDED_VM_ENTRY({
fields = compute_nonstatic_fields_impl(super_fields);
});
if (fields == NULL) {
_nonstatic_fields = super_fields;
return super_fields->length();
}
int flen = fields->length();
fields->sort(sort_field_by_offset);
_nonstatic_fields = fields;
return flen;
}
GrowableArray<ciField*>*
ciInstanceKlass::compute_nonstatic_fields_impl(GrowableArray<ciField*>*
super_fields) {
ASSERT_IN_VM;
Arena* arena = CURRENT_ENV->arena();
int flen = 0;
GrowableArray<ciField*>* fields = NULL;
InstanceKlass* k = get_instanceKlass();
for (JavaFieldStream fs(k); !fs.done(); fs.next()) {
if (fs.access_flags().is_static()) continue;
flen += 1;
}
if (flen == 0) {
return NULL; // return nothing if none are locally declared
}
if (super_fields != NULL) {
flen += super_fields->length();
}
fields = new (arena) GrowableArray<ciField*>(arena, flen, 0, NULL);
if (super_fields != NULL) {
fields->appendAll(super_fields);
}
for (JavaFieldStream fs(k); !fs.done(); fs.next()) {
if (fs.access_flags().is_static()) continue;
fieldDescriptor& fd = fs.field_descriptor();
ciField* field = new (arena) ciField(&fd);
fields->append(field);
}
assert(fields->length() == flen, "sanity");
return fields;
}
ciMethod* ciInstanceKlass::find_method(ciSymbol* name, ciSymbol* signature) {
VM_ENTRY_MARK;
InstanceKlass* k = get_instanceKlass();
Symbol* name_sym = name->get_symbol();
Symbol* sig_sym= signature->get_symbol();
Method* m = k->find_method(name_sym, sig_sym);
if (m == NULL) return NULL;
return CURRENT_THREAD_ENV->get_method(m);
}
bool ciInstanceKlass::is_leaf_type() {
assert(is_loaded(), "must be loaded");
if (is_shared()) {
return is_final(); // approximately correct
} else {
return !_has_subklass && (nof_implementors() == 0);
}
}
ciInstanceKlass* ciInstanceKlass::implementor() {
ciInstanceKlass* impl = _implementor;
if (impl == NULL) {
{
VM_ENTRY_MARK;
Klass* k = get_instanceKlass()->implementor();
if (k != NULL) {
if (k == get_instanceKlass()) {
impl = this;
} else {
impl = CURRENT_THREAD_ENV->get_instance_klass(k);
}
}
}
if (!is_shared()) {
_implementor = impl;
}
}
return impl;
}
ciInstanceKlass* ciInstanceKlass::host_klass() {
assert(is_loaded(), "must be loaded");
if (is_anonymous()) {
VM_ENTRY_MARK
Klass* host_klass = get_instanceKlass()->host_klass();
return CURRENT_ENV->get_instance_klass(host_klass);
}
return NULL;
}
class StaticFinalFieldPrinter : public FieldClosure {
outputStream* _out;
const char* _holder;
public:
StaticFinalFieldPrinter(outputStream* out, const char* holder) :
_out(out),
_holder(holder) {
}
void do_field(fieldDescriptor* fd) {
if (fd->is_final() && !fd->has_initial_value()) {
ResourceMark rm;
oop mirror = fd->field_holder()->java_mirror();
_out->print("staticfield %s %s %s ", _holder, fd->name()->as_quoted_ascii(), fd->signature()->as_quoted_ascii());
switch (fd->field_type()) {
case T_BYTE: _out->print_cr("%d", mirror->byte_field(fd->offset())); break;
case T_BOOLEAN: _out->print_cr("%d", mirror->bool_field(fd->offset())); break;
case T_SHORT: _out->print_cr("%d", mirror->short_field(fd->offset())); break;
case T_CHAR: _out->print_cr("%d", mirror->char_field(fd->offset())); break;
case T_INT: _out->print_cr("%d", mirror->int_field(fd->offset())); break;
case T_LONG: _out->print_cr(INT64_FORMAT, (int64_t)(mirror->long_field(fd->offset()))); break;
case T_FLOAT: {
float f = mirror->float_field(fd->offset());
_out->print_cr("%d", *(int*)&f);
break;
}
case T_DOUBLE: {
double d = mirror->double_field(fd->offset());
_out->print_cr(INT64_FORMAT, *(int64_t*)&d);
break;
}
case T_ARRAY: {
oop value = mirror->obj_field_acquire(fd->offset());
if (value == NULL) {
_out->print_cr("null");
} else {
typeArrayOop ta = (typeArrayOop)value;
_out->print("%d", ta->length());
if (value->is_objArray()) {
objArrayOop oa = (objArrayOop)value;
const char* klass_name = value->klass()->name()->as_quoted_ascii();
_out->print(" %s", klass_name);
}
_out->cr();
}
break;
}
case T_OBJECT: {
oop value = mirror->obj_field_acquire(fd->offset());
if (value == NULL) {
_out->print_cr("null");
} else if (value->is_instance()) {
if (value->is_a(SystemDictionary::String_klass())) {
_out->print("\"");
_out->print_raw(java_lang_String::as_quoted_ascii(value));
_out->print_cr("\"");
} else {
const char* klass_name = value->klass()->name()->as_quoted_ascii();
_out->print_cr("%s", klass_name);
}
} else {
ShouldNotReachHere();
}
break;
}
default:
ShouldNotReachHere();
}
}
}
};
void ciInstanceKlass::dump_replay_data(outputStream* out) {
ResourceMark rm;
InstanceKlass* ik = get_instanceKlass();
ConstantPool* cp = ik->constants();
Klass* sub = ik->subklass();
while (sub != NULL) {
if (sub->oop_is_instance()) {
out->print_cr("instanceKlass %s", sub->name()->as_quoted_ascii());
}
sub = sub->next_sibling();
}
out->print("ciInstanceKlass %s %d %d %d", ik->name()->as_quoted_ascii(),
is_linked(), is_initialized(), cp->length());
for (int index = 1; index < cp->length(); index++) {
out->print(" %d", cp->tags()->at(index));
}
out->cr();
if (is_initialized()) {
StaticFinalFieldPrinter sffp(out, ik->name()->as_quoted_ascii());
ik->do_local_static_fields(&sffp);
}
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciInstanceKlass.hpp
#ifndef SHARE_VM_CI_CIINSTANCEKLASS_HPP
#define SHARE_VM_CI_CIINSTANCEKLASS_HPP
#include "ci/ciConstantPoolCache.hpp"
#include "ci/ciFlags.hpp"
#include "ci/ciKlass.hpp"
#include "ci/ciSymbol.hpp"
class ciInstanceKlass : public ciKlass {
CI_PACKAGE_ACCESS
friend class ciBytecodeStream;
friend class ciEnv;
friend class ciExceptionHandler;
friend class ciMethod;
friend class ciField;
private:
jobject _loader;
jobject _protection_domain;
InstanceKlass::ClassState _init_state; // state of class
bool _is_shared;
bool _has_finalizer;
bool _has_subklass;
bool _has_nonstatic_fields;
bool _has_default_methods;
bool _is_anonymous;
ciFlags _flags;
jint _nonstatic_field_size;
jint _nonstatic_oop_map_size;
ciInstanceKlass* _super;
ciInstance* _java_mirror;
ciConstantPoolCache* _field_cache; // cached map index->field
GrowableArray<ciField*>* _nonstatic_fields;
ciInstanceKlass* _implementor;
GrowableArray<ciField*>* _non_static_fields;
protected:
ciInstanceKlass(KlassHandle h_k);
ciInstanceKlass(ciSymbol* name, jobject loader, jobject protection_domain);
InstanceKlass* get_instanceKlass() const {
return (InstanceKlass*)get_Klass();
}
oop loader();
jobject loader_handle();
oop protection_domain();
jobject protection_domain_handle();
const char* type_string() { return "ciInstanceKlass"; }
bool is_in_package_impl(const char* packagename, int len);
void print_impl(outputStream* st);
ciConstantPoolCache* field_cache();
bool is_shared() { return _is_shared; }
void compute_shared_init_state();
bool compute_shared_has_subklass();
int compute_nonstatic_fields();
GrowableArray<ciField*>* compute_nonstatic_fields_impl(GrowableArray<ciField*>* super_fields);
void update_if_shared(InstanceKlass::ClassState expected) {
if (_is_shared && _init_state != expected) {
if (is_loaded()) compute_shared_init_state();
}
}
public:
bool is_initialized() {
update_if_shared(InstanceKlass::fully_initialized);
return _init_state == InstanceKlass::fully_initialized;
}
bool is_being_initialized() {
update_if_shared(InstanceKlass::being_initialized);
return _init_state == InstanceKlass::being_initialized;
}
bool is_linked() {
update_if_shared(InstanceKlass::linked);
return _init_state >= InstanceKlass::linked;
}
ciFlags flags() {
assert(is_loaded(), "must be loaded");
return _flags;
}
bool has_finalizer() {
assert(is_loaded(), "must be loaded");
return _has_finalizer; }
bool has_subklass() {
assert(is_loaded(), "must be loaded");
if (_is_shared && !_has_subklass) {
if (flags().is_final()) {
return false;
} else {
return compute_shared_has_subklass();
}
}
return _has_subklass;
}
jint size_helper() {
return (Klass::layout_helper_size_in_bytes(layout_helper())
>> LogHeapWordSize);
}
jint nonstatic_field_size() {
assert(is_loaded(), "must be loaded");
return _nonstatic_field_size; }
jint has_nonstatic_fields() {
assert(is_loaded(), "must be loaded");
return _has_nonstatic_fields; }
jint nonstatic_oop_map_size() {
assert(is_loaded(), "must be loaded");
return _nonstatic_oop_map_size; }
ciInstanceKlass* super();
jint nof_implementors() {
ciInstanceKlass* impl;
assert(is_loaded(), "must be loaded");
impl = implementor();
if (impl == NULL) {
return 0;
} else if (impl != this) {
return 1;
} else {
return 2;
}
}
bool has_default_methods() {
assert(is_loaded(), "must be loaded");
return _has_default_methods;
}
bool is_anonymous() {
return _is_anonymous;
}
ciInstanceKlass* get_canonical_holder(int offset);
ciField* get_field_by_offset(int field_offset, bool is_static);
ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static);
GrowableArray<ciField*>* non_static_fields();
int nof_nonstatic_fields() {
if (_nonstatic_fields == NULL)
return compute_nonstatic_fields();
else
return _nonstatic_fields->length();
}
ciField* nonstatic_field_at(int i) {
assert(_nonstatic_fields != NULL, "");
return _nonstatic_fields->at(i);
}
ciInstanceKlass* unique_concrete_subklass();
bool has_finalizable_subclass();
bool contains_field_offset(int offset) {
return instanceOopDesc::contains_field_offset(offset, nonstatic_field_size());
}
ciInstance* java_mirror();
bool is_public () { return flags().is_public(); }
bool is_final () { return flags().is_final(); }
bool is_super () { return flags().is_super(); }
bool is_interface () { return flags().is_interface(); }
bool is_abstract () { return flags().is_abstract(); }
ciMethod* find_method(ciSymbol* name, ciSymbol* signature);
bool is_leaf_type();
ciInstanceKlass* implementor();
bool uses_default_loader() const;
bool is_java_lang_Object() const;
BasicType box_klass_type() const;
bool is_box_klass() const;
bool is_boxed_value_offset(int offset) const;
bool is_in_package(const char* packagename) {
return is_in_package(packagename, (int) strlen(packagename));
}
bool is_in_package(const char* packagename, int len);
bool is_instance_klass() const { return true; }
bool is_java_klass() const { return true; }
virtual ciKlass* exact_klass() {
if (is_loaded() && is_final() && !is_interface()) {
return this;
}
return NULL;
}
ciInstanceKlass* host_klass();
virtual void dump_replay_data(outputStream* out);
};
#endif // SHARE_VM_CI_CIINSTANCEKLASS_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciKlass.cpp
#include "precompiled.hpp"
#include "ci/ciKlass.hpp"
#include "ci/ciSymbol.hpp"
#include "ci/ciUtilities.hpp"
#include "oops/oop.inline.hpp"
ciKlass::ciKlass(KlassHandle h_k) : ciType(h_k) {
assert(get_Klass()->is_klass(), "wrong type");
Klass* k = get_Klass();
_layout_helper = k->layout_helper();
Symbol* klass_name = k->name();
assert(klass_name != NULL, "wrong ciKlass constructor");
_name = CURRENT_ENV->get_symbol(klass_name);
}
ciKlass::ciKlass(KlassHandle h_k, ciSymbol* name) : ciType(h_k) {
assert(get_Klass()->is_klass(), "wrong type");
_name = name;
_layout_helper = Klass::_lh_neutral_value;
}
ciKlass::ciKlass(ciSymbol* name, BasicType bt) : ciType(bt) {
_name = name;
_layout_helper = Klass::_lh_neutral_value;
}
bool ciKlass::is_subtype_of(ciKlass* that) {
assert(this->is_loaded(), err_msg("must be loaded: %s", this->name()->as_quoted_ascii()));
assert(that->is_loaded(), err_msg("must be loaded: %s", that->name()->as_quoted_ascii()));
if (this == that) {
return true;
}
VM_ENTRY_MARK;
Klass* this_klass = get_Klass();
Klass* that_klass = that->get_Klass();
bool result = this_klass->is_subtype_of(that_klass);
return result;
}
bool ciKlass::is_subclass_of(ciKlass* that) {
assert(this->is_loaded(), err_msg("must be loaded: %s", this->name()->as_quoted_ascii()));
assert(that->is_loaded(), err_msg("must be loaded: %s", that->name()->as_quoted_ascii()));
VM_ENTRY_MARK;
Klass* this_klass = get_Klass();
Klass* that_klass = that->get_Klass();
bool result = this_klass->is_subclass_of(that_klass);
return result;
}
juint ciKlass::super_depth() {
assert(is_loaded(), "must be loaded");
VM_ENTRY_MARK;
Klass* this_klass = get_Klass();
return this_klass->super_depth();
}
juint ciKlass::super_check_offset() {
assert(is_loaded(), "must be loaded");
VM_ENTRY_MARK;
Klass* this_klass = get_Klass();
return this_klass->super_check_offset();
}
ciKlass* ciKlass::super_of_depth(juint i) {
assert(is_loaded(), "must be loaded");
VM_ENTRY_MARK;
Klass* this_klass = get_Klass();
Klass* super = this_klass->primary_super_of_depth(i);
return (super != NULL) ? CURRENT_THREAD_ENV->get_klass(super) : NULL;
}
bool ciKlass::can_be_primary_super() {
assert(is_loaded(), "must be loaded");
VM_ENTRY_MARK;
Klass* this_klass = get_Klass();
return this_klass->can_be_primary_super();
}
ciKlass*
ciKlass::least_common_ancestor(ciKlass* that) {
assert(is_loaded() && that->is_loaded(), "must be loaded");
if (this == that) {
return this;
}
VM_ENTRY_MARK;
Klass* this_klass = get_Klass();
Klass* that_klass = that->get_Klass();
Klass* lca = this_klass->LCA(that_klass);
if (lca == that_klass) {
return that;
}
if (this_klass == lca) {
return this;
}
ciKlass* result =
CURRENT_THREAD_ENV->get_klass(lca);
return result;
}
ciKlass* ciKlass::find_klass(ciSymbol* klass_name) {
assert(is_loaded(), "cannot find_klass through an unloaded klass");
return CURRENT_ENV->get_klass_by_name(this,
klass_name, false);
}
ciInstance* ciKlass::java_mirror() {
GUARDED_VM_ENTRY(
if (!is_loaded())
return ciEnv::current()->get_unloaded_klass_mirror(this);
oop java_mirror = get_Klass()->java_mirror();
return CURRENT_ENV->get_instance(java_mirror);
)
}
jint ciKlass::modifier_flags() {
assert(is_loaded(), "not loaded");
GUARDED_VM_ENTRY(
return get_Klass()->modifier_flags();
)
}
jint ciKlass::access_flags() {
assert(is_loaded(), "not loaded");
GUARDED_VM_ENTRY(
return get_Klass()->access_flags().as_int();
)
}
void ciKlass::print_impl(outputStream* st) {
st->print(" name=");
print_name_on(st);
}
void ciKlass::print_name_on(outputStream* st) {
name()->print_symbol_on(st);
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciKlass.hpp
#ifndef SHARE_VM_CI_CIKLASS_HPP
#define SHARE_VM_CI_CIKLASS_HPP
#include "ci/ciType.hpp"
class ciKlass : public ciType {
CI_PACKAGE_ACCESS
friend class ciEnv;
friend class ciField;
friend class ciMethod;
friend class ciMethodData;
friend class ciObjArrayKlass;
friend class ciReceiverTypeData;
private:
ciSymbol* _name;
jint _layout_helper;
protected:
ciKlass(KlassHandle k_h, ciSymbol* name);
ciKlass(ciSymbol* name, BasicType bt);
Klass* get_Klass() const {
Klass* k = (Klass*)_metadata;
assert(k != NULL, "illegal use of unloaded klass");
return k;
}
virtual oop loader() { return NULL; }
virtual jobject loader_handle() { return NULL; }
virtual oop protection_domain() { return NULL; }
virtual jobject protection_domain_handle() { return NULL; }
const char* type_string() { return "ciKlass"; }
void print_impl(outputStream* st);
public:
ciKlass(KlassHandle k_h);
ciSymbol* name() const { return _name; }
jint layout_helper() { return _layout_helper; }
bool is_subtype_of(ciKlass* klass);
bool is_subclass_of(ciKlass* klass);
juint super_depth();
juint super_check_offset();
ciKlass* super_of_depth(juint i);
bool can_be_primary_super();
static juint primary_super_limit() { return Klass::primary_super_limit(); }
virtual bool is_java_lang_Object() const { return false; }
ciKlass* least_common_ancestor(ciKlass* k);
virtual bool is_interface() {
return false;
}
virtual bool is_abstract() {
return false;
}
virtual bool is_leaf_type() {
return false;
}
ciKlass* find_klass(ciSymbol* klass_name);
ciInstance* java_mirror();
jint modifier_flags();
jint access_flags();
bool is_klass() const { return true; }
virtual ciKlass* exact_klass() = 0;
void print_name_on(outputStream* st);
};
#endif // SHARE_VM_CI_CIKLASS_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciMemberName.cpp
#include "precompiled.hpp"
#include "ci/ciClassList.hpp"
#include "ci/ciMemberName.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/javaClasses.hpp"
ciMethod* ciMemberName::get_vmtarget() const {
VM_ENTRY_MARK;
Metadata* vmtarget = java_lang_invoke_MemberName::vmtarget(get_oop());
if (vmtarget->is_method())
return CURRENT_ENV->get_method((Method*) vmtarget);
assert(false, "");
return NULL;
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciMemberName.hpp
#ifndef SHARE_VM_CI_CIMEMBERNAME_HPP
#define SHARE_VM_CI_CIMEMBERNAME_HPP
#include "ci/ciCallProfile.hpp"
#include "ci/ciInstance.hpp"
class ciMemberName : public ciInstance {
public:
ciMemberName(instanceHandle h_i) : ciInstance(h_i) {}
bool is_member_name() const { return true; }
ciMethod* get_vmtarget() const;
};
#endif // SHARE_VM_CI_CIMEMBERNAME_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciMetadata.cpp
#include "precompiled.hpp"
#include "ci/ciObject.hpp"
#include "ci/ciUtilities.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "oops/oop.inline2.hpp"
void ciMetadata::print(outputStream* st) {
st->print("<%s", type_string());
GUARDED_VM_ENTRY(print_impl(st);)
st->print(" ident=%d address=" INTPTR_FORMAT ">", ident(), p2i((address)this));
}
void ciMetadata::print_metadata(outputStream* st) {
if (!is_loaded()) {
st->print_cr("UNLOADED");
} else {
GUARDED_VM_ENTRY(_metadata->print_on(st);)
}
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciMetadata.hpp
#ifndef SHARE_VM_CI_CIMETADATA_HPP
#define SHARE_VM_CI_CIMETADATA_HPP
#include "ci/ciBaseObject.hpp"
#include "ci/ciClassList.hpp"
#include "memory/allocation.hpp"
#include "runtime/handles.hpp"
#include "runtime/jniHandles.hpp"
class ciMetadata: public ciBaseObject {
CI_PACKAGE_ACCESS
friend class ciEnv;
protected:
Metadata* _metadata;
ciMetadata(): _metadata(NULL) {}
ciMetadata(Metadata* o): _metadata(o) {}
virtual bool is_classless() const { return false; }
public:
bool is_loaded() const { return _metadata != NULL || is_classless(); }
virtual bool is_metadata() const { return true; }
virtual bool is_type() const { return false; }
virtual bool is_cpcache() const { return false; }
virtual bool is_return_address() const { return false; }
virtual bool is_method() const { return false; }
virtual bool is_method_data() const { return false; }
virtual bool is_klass() const { return false; }
virtual bool is_instance_klass() const { return false; }
virtual bool is_array_klass() const { return false; }
virtual bool is_obj_array_klass() const { return false; }
virtual bool is_type_array_klass() const { return false; }
virtual void dump_replay_data(outputStream* st) { /* do nothing */ }
ciMethod* as_method() {
assert(is_method(), "bad cast");
return (ciMethod*)this;
}
ciMethodData* as_method_data() {
assert(is_method_data(), "bad cast");
return (ciMethodData*)this;
}
ciSymbol* as_symbol() {
assert(is_symbol(), "bad cast");
return (ciSymbol*)this;
}
ciType* as_type() {
assert(is_type(), "bad cast");
return (ciType*)this;
}
ciReturnAddress* as_return_address() {
assert(is_return_address(), "bad cast");
return (ciReturnAddress*)this;
}
ciKlass* as_klass() {
assert(is_klass(), "bad cast");
return (ciKlass*)this;
}
ciInstanceKlass* as_instance_klass() {
assert(is_instance_klass(), "bad cast");
return (ciInstanceKlass*)this;
}
ciArrayKlass* as_array_klass() {
assert(is_array_klass(), "bad cast");
return (ciArrayKlass*)this;
}
ciObjArrayKlass* as_obj_array_klass() {
assert(is_obj_array_klass(), "bad cast");
return (ciObjArrayKlass*)this;
}
ciTypeArrayKlass* as_type_array_klass() {
assert(is_type_array_klass(), "bad cast");
return (ciTypeArrayKlass*)this;
}
Metadata* constant_encoding() { return _metadata; }
bool equals(ciMetadata* obj) const { return (this == obj); }
int hash() { return ident() * 31; } // ???
void print(outputStream* st);
virtual void print_impl(outputStream* st) {}
virtual const char* type_string() { return "ciMetadata"; }
void print() { print(tty); }
void print_metadata(outputStream* st = tty);
};
#endif // SHARE_VM_CI_CIMETADATA_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciMethod.cpp
#include "precompiled.hpp"
#include "ci/ciCallProfile.hpp"
#include "ci/ciExceptionHandler.hpp"
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciMethodBlocks.hpp"
#include "ci/ciMethodData.hpp"
#include "ci/ciStreams.hpp"
#include "ci/ciSymbol.hpp"
#include "ci/ciReplay.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/systemDictionary.hpp"
#include "compiler/abstractCompiler.hpp"
#include "compiler/compilerOracle.hpp"
#include "compiler/methodLiveness.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/linkResolver.hpp"
#include "interpreter/oopMapCache.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "oops/generateOopMap.hpp"
#include "oops/oop.inline.hpp"
#include "prims/nativeLookup.hpp"
#include "runtime/deoptimization.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/xmlstream.hpp"
#ifdef COMPILER2
#include "ci/bcEscapeAnalyzer.hpp"
#include "ci/ciTypeFlow.hpp"
#include "oops/method.hpp"
#endif
#ifdef SHARK
#include "ci/ciTypeFlow.hpp"
#include "oops/method.hpp"
#endif
ciMethod::ciMethod(methodHandle h_m, ciInstanceKlass* holder) :
ciMetadata(h_m()),
_holder(holder)
{
assert(h_m() != NULL, "no null method");
_flags = ciFlags(h_m()->access_flags());
_max_stack = h_m()->max_stack();
_max_locals = h_m()->max_locals();
_code_size = h_m()->code_size();
_intrinsic_id = h_m()->intrinsic_id();
_handler_count = h_m()->exception_table_length();
_size_of_parameters = h_m()->size_of_parameters();
_uses_monitors = h_m()->access_flags().has_monitor_bytecodes();
_balanced_monitors = !_uses_monitors || h_m()->access_flags().is_monitor_matching();
_is_c1_compilable = !h_m()->is_not_c1_compilable();
_is_c2_compilable = !h_m()->is_not_c2_compilable();
_code = NULL;
_exception_handlers = NULL;
_liveness = NULL;
_method_blocks = NULL;
#if defined(COMPILER2) || defined(SHARK)
_flow = NULL;
_bcea = NULL;
#endif // COMPILER2 || SHARK
ciEnv *env = CURRENT_ENV;
if (env->jvmti_can_hotswap_or_post_breakpoint() && can_be_compiled()) {
MutexLocker locker(Compile_lock);
if (Dependencies::check_evol_method(h_m()) != NULL) {
_is_c1_compilable = false;
_is_c2_compilable = false;
}
} else {
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
}
if (h_m()->method_holder()->is_linked()) {
_can_be_statically_bound = h_m()->can_be_statically_bound();
} else {
_can_be_statically_bound = false;
}
if (!_can_be_statically_bound && h_m()->is_private())
_can_be_statically_bound = true;
if (_can_be_statically_bound && h_m()->is_abstract())
_can_be_statically_bound = false;
_name = env->get_symbol(h_m()->name());
ciSymbol* sig_symbol = env->get_symbol(h_m()->signature());
constantPoolHandle cpool = h_m()->constants();
_signature = new (env->arena()) ciSignature(_holder, cpool, sig_symbol);
_method_data = NULL;
if (ProfileInterpreter || TieredCompilation) {
int invcnt = h_m()->interpreter_invocation_count();
_interpreter_invocation_count = invcnt < 0 ? max_jint : invcnt ;
_interpreter_throwout_count = h_m()->interpreter_throwout_count();
} else {
_interpreter_invocation_count = 0;
_interpreter_throwout_count = 0;
}
if (_interpreter_invocation_count == 0)
_interpreter_invocation_count = 1;
_instructions_size = -1;
#ifdef ASSERT
if (ReplayCompiles) {
ciReplay::initialize(this);
}
#endif
}
ciMethod::ciMethod(ciInstanceKlass* holder,
ciSymbol* name,
ciSymbol* signature,
ciInstanceKlass* accessor) :
ciMetadata((Metadata*)NULL),
_name( name),
_holder( holder),
_intrinsic_id( vmIntrinsics::_none),
_liveness( NULL),
_can_be_statically_bound(false),
_method_blocks( NULL),
_method_data( NULL)
#if defined(COMPILER2) || defined(SHARK)
,
_flow( NULL),
_bcea( NULL),
_instructions_size(-1)
#endif // COMPILER2 || SHARK
{
_signature = new (CURRENT_ENV->arena()) ciSignature(accessor, constantPoolHandle(), signature);
}
void ciMethod::load_code() {
VM_ENTRY_MARK;
assert(is_loaded(), "only loaded methods have code");
Method* me = get_Method();
Arena* arena = CURRENT_THREAD_ENV->arena();
_code = (address)arena->Amalloc(code_size());
memcpy(_code, me->code_base(), code_size());
if (me->number_of_breakpoints() > 0) {
BreakpointInfo* bp = me->method_holder()->breakpoints();
for (; bp != NULL; bp = bp->next()) {
if (bp->match(me)) {
code_at_put(bp->bci(), bp->orig_bytecode());
}
}
}
ExceptionTable exc_table(me);
_exception_handlers =
(ciExceptionHandler**)arena->Amalloc(sizeof(ciExceptionHandler*)
if (_handler_count > 0) {
for (int i=0; i<_handler_count; i++) {
_exception_handlers[i] = new (arena) ciExceptionHandler(
holder(),
}
}
_exception_handlers[_handler_count] =
new (arena) ciExceptionHandler(holder(), 0, code_size(), -1, 0);
if (CIPrintMethodCodes) {
print_codes();
}
}
bool ciMethod::has_linenumber_table() const {
check_is_loaded();
VM_ENTRY_MARK;
return get_Method()->has_linenumber_table();
}
u_char* ciMethod::compressed_linenumber_table() const {
check_is_loaded();
VM_ENTRY_MARK;
return get_Method()->compressed_linenumber_table();
}
int ciMethod::line_number_from_bci(int bci) const {
check_is_loaded();
VM_ENTRY_MARK;
return get_Method()->line_number_from_bci(bci);
}
int ciMethod::vtable_index() {
check_is_loaded();
assert(holder()->is_linked(), "must be linked");
VM_ENTRY_MARK;
return get_Method()->vtable_index();
}
#ifdef SHARK
int ciMethod::itable_index() {
check_is_loaded();
assert(holder()->is_linked(), "must be linked");
VM_ENTRY_MARK;
Method* m = get_Method();
if (!m->has_itable_index())
return Method::nonvirtual_vtable_index;
return m->itable_index();
}
#endif // SHARK
address ciMethod::native_entry() {
check_is_loaded();
assert(flags().is_native(), "must be native method");
VM_ENTRY_MARK;
Method* method = get_Method();
address entry = method->native_function();
assert(entry != NULL, "must be valid entry point");
return entry;
}
address ciMethod::interpreter_entry() {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
return Interpreter::entry_for_method(mh);
}
bool ciMethod::has_balanced_monitors() {
check_is_loaded();
if (_balanced_monitors) return true;
VM_ENTRY_MARK;
methodHandle method(THREAD, get_Method());
assert(method->has_monitor_bytecodes(), "should have checked this");
if (method->guaranteed_monitor_matching()) {
_balanced_monitors = true;
return true;
}
{
EXCEPTION_MARK;
ResourceMark rm(THREAD);
GeneratePairingInfo gpi(method);
gpi.compute_map(CATCH);
if (!gpi.monitor_safe()) {
return false;
}
method->set_guaranteed_monitor_matching();
_balanced_monitors = true;
}
return true;
}
ciTypeFlow* ciMethod::get_flow_analysis() {
#if defined(COMPILER2) || defined(SHARK)
if (_flow == NULL) {
ciEnv* env = CURRENT_ENV;
_flow = new (env->arena()) ciTypeFlow(env, this);
_flow->do_flow();
}
return _flow;
#else // COMPILER2 || SHARK
ShouldNotReachHere();
return NULL;
#endif // COMPILER2 || SHARK
}
ciTypeFlow* ciMethod::get_osr_flow_analysis(int osr_bci) {
#if defined(COMPILER2) || defined(SHARK)
assert(osr_bci >= 0, "must supply valid OSR entry point");
ciEnv* env = CURRENT_ENV;
ciTypeFlow* flow = new (env->arena()) ciTypeFlow(env, this, osr_bci);
flow->do_flow();
return flow;
#else // COMPILER2 || SHARK
ShouldNotReachHere();
return NULL;
#endif // COMPILER2 || SHARK
}
MethodLivenessResult ciMethod::raw_liveness_at_bci(int bci) {
check_is_loaded();
if (_liveness == NULL) {
Arena* arena = CURRENT_ENV->arena();
_liveness = new (arena) MethodLiveness(arena, this);
_liveness->compute_liveness();
}
return _liveness->get_liveness_at(bci);
}
MethodLivenessResult ciMethod::liveness_at_bci(int bci) {
MethodLivenessResult result = raw_liveness_at_bci(bci);
if (CURRENT_ENV->should_retain_local_variables() || DeoptimizeALot || CompileTheWorld) {
result.at_put_range(0, result.size(), true);
}
return result;
}
BitMap ciMethod::live_local_oops_at_bci(int bci) {
VM_ENTRY_MARK;
InterpreterOopMap mask;
OopMapCache::compute_one_oop_map(get_Method(), bci, &mask);
int mask_size = max_locals();
BitMap result(mask_size);
result.clear();
int i;
for (i = 0; i < mask_size ; i++ ) {
if (mask.is_oop(i)) result.set_bit(i);
}
return result;
}
#ifdef COMPILER1
const BitMap ciMethod::bci_block_start() {
check_is_loaded();
if (_liveness == NULL) {
Arena* arena = CURRENT_ENV->arena();
_liveness = new (arena) MethodLiveness(arena, this);
_liveness->compute_liveness();
}
return _liveness->get_bci_block_start();
}
#endif // COMPILER1
ciCallProfile ciMethod::call_profile_at_bci(int bci) {
ResourceMark rm;
ciCallProfile result;
if (method_data() != NULL && method_data()->is_mature()) {
ciProfileData* data = method_data()->bci_to_data(bci);
if (data != NULL && data->is_CounterData()) {
int count = data->as_CounterData()->count();
if (!data->is_ReceiverTypeData()) {
result._receiver_count[0] = 0; // that's a definite zero
} else { // ReceiverTypeData is a subclass of CounterData
ciReceiverTypeData* call = (ciReceiverTypeData*)data->as_ReceiverTypeData();
int receivers_count_total = 0;
int morphism = 0;
for (uint i = 0; i < call->row_limit(); i++) {
ciKlass* receiver = call->receiver(i);
if (receiver == NULL) continue;
morphism++;
}
int epsilon = 0;
if (TieredCompilation && ProfileInterpreter) {
if (morphism == 1 && count > 0) {
epsilon = count;
count = 0;
}
}
for (uint i = 0; i < call->row_limit(); i++) {
ciKlass* receiver = call->receiver(i);
if (receiver == NULL) continue;
int rcount = call->receiver_count(i) + epsilon;
if (rcount == 0) rcount = 1; // Should be valid value
receivers_count_total += rcount;
result.add_receiver(receiver, rcount);
}
if (morphism > 0 && morphism == result._limit) {
if ((morphism < ciCallProfile::MorphismLimit) ||
(morphism == ciCallProfile::MorphismLimit && count == 0)) {
#ifdef ASSERT
if (count > 0) {
this->print_short_name(tty);
tty->print_cr(" @ bci:%d", bci);
this->print_codes();
assert(false, "this call site should not be polymorphic");
}
#endif
result._morphism = morphism;
}
}
if (count >= 0) {
count += receivers_count_total;
}
}
result._count = count;
}
}
return result;
}
void ciCallProfile::add_receiver(ciKlass* receiver, int receiver_count) {
int i = _limit;
for (; i > 0 && receiver_count > _receiver_count[i-1]; i--) {
_receiver[i] = _receiver[i-1];
_receiver_count[i] = _receiver_count[i-1];
}
_receiver[i] = receiver;
_receiver_count[i] = receiver_count;
if (_limit < MorphismLimit) _limit++;
}
void ciMethod::assert_virtual_call_type_ok(int bci) {
assert(java_code_at_bci(bci) == Bytecodes::_invokevirtual ||
java_code_at_bci(bci) == Bytecodes::_invokeinterface, err_msg("unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci))));
}
void ciMethod::assert_call_type_ok(int bci) {
assert(java_code_at_bci(bci) == Bytecodes::_invokestatic ||
java_code_at_bci(bci) == Bytecodes::_invokespecial ||
java_code_at_bci(bci) == Bytecodes::_invokedynamic, err_msg("unexpected bytecode %s", Bytecodes::name(java_code_at_bci(bci))));
}
ciKlass* ciMethod::argument_profiled_type(int bci, int i) {
if (MethodData::profile_parameters() && method_data() != NULL && method_data()->is_mature()) {
ciProfileData* data = method_data()->bci_to_data(bci);
if (data != NULL) {
if (data->is_VirtualCallTypeData()) {
assert_virtual_call_type_ok(bci);
ciVirtualCallTypeData* call = (ciVirtualCallTypeData*)data->as_VirtualCallTypeData();
if (i >= call->number_of_arguments()) {
return NULL;
}
ciKlass* type = call->valid_argument_type(i);
if (type != NULL && !call->argument_maybe_null(i)) {
return type;
}
} else if (data->is_CallTypeData()) {
assert_call_type_ok(bci);
ciCallTypeData* call = (ciCallTypeData*)data->as_CallTypeData();
if (i >= call->number_of_arguments()) {
return NULL;
}
ciKlass* type = call->valid_argument_type(i);
if (type != NULL && !call->argument_maybe_null(i)) {
return type;
}
}
}
}
return NULL;
}
sssssssss9
最新推荐文章于 2024-08-01 15:05:06 发布