ciKlass* ciMethod::return_profiled_type(int bci) {
if (MethodData::profile_return() && 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();
ciKlass* type = call->valid_return_type();
if (type != NULL && !call->return_maybe_null()) {
return type;
}
} else if (data->is_CallTypeData()) {
assert_call_type_ok(bci);
ciCallTypeData* call = (ciCallTypeData*)data->as_CallTypeData();
ciKlass* type = call->valid_return_type();
if (type != NULL && !call->return_maybe_null()) {
return type;
}
}
}
}
return NULL;
}
ciKlass* ciMethod::parameter_profiled_type(int i) {
if (MethodData::profile_parameters() && method_data() != NULL && method_data()->is_mature()) {
ciParametersTypeData* parameters = method_data()->parameters_type_data();
if (parameters != NULL && i < parameters->number_of_parameters()) {
ciKlass* type = parameters->valid_parameter_type(i);
if (type != NULL && !parameters->parameter_maybe_null(i)) {
return type;
}
}
}
return NULL;
}
ciMethod* ciMethod::find_monomorphic_target(ciInstanceKlass* caller,
ciInstanceKlass* callee_holder,
ciInstanceKlass* actual_recv,
bool check_access) {
check_is_loaded();
if (actual_recv->is_interface()) {
return NULL;
}
ciMethod* root_m = resolve_invoke(caller, actual_recv, check_access);
if (root_m == NULL) {
return NULL;
}
assert(!root_m->is_abstract(), "resolve_invoke promise");
if (root_m->can_be_statically_bound()) {
return root_m;
}
if (actual_recv->is_leaf_type() && actual_recv == root_m->holder()) {
return root_m;
}
if (!UseCHA) return NULL;
VM_ENTRY_MARK;
if (root_m->get_Method()->is_default_method()) {
return NULL;
}
methodHandle target;
{
MutexLocker locker(Compile_lock);
Klass* context = actual_recv->get_Klass();
target = Dependencies::find_unique_concrete_method(context,
root_m->get_Method());
}
#ifndef PRODUCT
if (TraceDependencies && target() != NULL && target() != root_m->get_Method()) {
tty->print("found a non-root unique target method");
tty->print_cr(" context = %s", InstanceKlass::cast(actual_recv->get_Klass())->external_name());
tty->print(" method = ");
target->print_short_name(tty);
tty->cr();
}
#endif //PRODUCT
if (target() == NULL) {
return NULL;
}
if (target() == root_m->get_Method()) {
return root_m;
}
if (!root_m->is_public() &&
!root_m->is_protected()) {
return NULL;
}
return CURRENT_THREAD_ENV->get_method(target());
}
ciMethod* ciMethod::resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, bool check_access) {
check_is_loaded();
VM_ENTRY_MARK;
KlassHandle caller_klass (THREAD, caller->get_Klass());
KlassHandle h_recv (THREAD, exact_receiver->get_Klass());
KlassHandle h_resolved (THREAD, holder()->get_Klass());
Symbol* h_name = name()->get_symbol();
Symbol* h_signature = signature()->get_symbol();
methodHandle m;
if (h_recv->oop_is_array()
||
InstanceKlass::cast(h_recv())->is_linked() && !exact_receiver->is_interface()) {
if (holder()->is_interface()) {
m = LinkResolver::resolve_interface_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass, check_access);
} else {
m = LinkResolver::resolve_virtual_call_or_null(h_recv, h_resolved, h_name, h_signature, caller_klass, check_access);
}
}
if (m.is_null()) {
return NULL;
}
ciMethod* result = this;
if (m() != get_Method()) {
result = CURRENT_THREAD_ENV->get_method(m());
}
if (result->is_abstract()) {
return NULL;
} else {
return result;
}
}
int ciMethod::resolve_vtable_index(ciKlass* caller, ciKlass* receiver) {
check_is_loaded();
int vtable_index = Method::invalid_vtable_index;
if (!receiver->is_interface()
&& (!receiver->is_instance_klass() ||
receiver->as_instance_klass()->is_linked())) {
VM_ENTRY_MARK;
KlassHandle caller_klass (THREAD, caller->get_Klass());
KlassHandle h_recv (THREAD, receiver->get_Klass());
Symbol* h_name = name()->get_symbol();
Symbol* h_signature = signature()->get_symbol();
vtable_index = LinkResolver::resolve_virtual_vtable_index(h_recv, h_recv, h_name, h_signature, caller_klass);
if (vtable_index == Method::nonvirtual_vtable_index) {
vtable_index = Method::invalid_vtable_index;
}
}
return vtable_index;
}
int ciMethod::interpreter_call_site_count(int bci) {
if (method_data() != NULL) {
ResourceMark rm;
ciProfileData* data = method_data()->bci_to_data(bci);
if (data != NULL && data->is_CounterData()) {
return scale_count(data->as_CounterData()->count());
}
}
return -1; // unknown
}
ciField* ciMethod::get_field_at_bci(int bci, bool &will_link) {
ciBytecodeStream iter(this);
iter.reset_to_bci(bci);
iter.next();
return iter.get_field(will_link);
}
ciMethod* ciMethod::get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature) {
ciBytecodeStream iter(this);
iter.reset_to_bci(bci);
iter.next();
return iter.get_method(will_link, declared_signature);
}
int ciMethod::scale_count(int count, float prof_factor) {
if (count > 0 && method_data() != NULL) {
int counter_life;
int method_life = interpreter_invocation_count();
if (TieredCompilation) {
counter_life = MAX2(method_data()->invocation_count(), method_data()->backedge_count());
} else {
int current_mileage = method_data()->current_mileage();
int creation_mileage = method_data()->creation_mileage();
counter_life = current_mileage - creation_mileage;
}
if (counter_life > method_life)
counter_life = method_life;
if (0 < counter_life && counter_life <= method_life) {
count = (int)((double)count * prof_factor * method_life / counter_life + 0.5);
count = (count > 0) ? count : 1;
}
}
return count;
}
bool ciMethod::is_ignored_by_security_stack_walk() const {
check_is_loaded();
VM_ENTRY_MARK;
return get_Method()->is_ignored_by_security_stack_walk();
}
bool ciMethod::is_method_handle_intrinsic() const {
vmIntrinsics::ID iid = _intrinsic_id; // do not check if loaded
return (MethodHandles::is_signature_polymorphic(iid) &&
MethodHandles::is_signature_polymorphic_intrinsic(iid));
}
bool ciMethod::is_compiled_lambda_form() const {
vmIntrinsics::ID iid = _intrinsic_id; // do not check if loaded
return iid == vmIntrinsics::_compiledLambdaForm;
}
bool ciMethod::is_object_initializer() const {
return name() == ciSymbol::object_initializer_name();
}
bool ciMethod::has_member_arg() const {
vmIntrinsics::ID iid = _intrinsic_id; // do not check if loaded
return (MethodHandles::is_signature_polymorphic(iid) &&
MethodHandles::has_member_arg(iid));
}
bool ciMethod::ensure_method_data(methodHandle h_m) {
EXCEPTION_CONTEXT;
if (is_native() || is_abstract() || h_m()->is_accessor()) {
return true;
}
if (h_m()->method_data() == NULL) {
Method::build_interpreter_method_data(h_m, THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
}
}
if (h_m()->method_data() != NULL) {
_method_data = CURRENT_ENV->get_method_data(h_m()->method_data());
_method_data->load_data();
return true;
} else {
_method_data = CURRENT_ENV->get_empty_methodData();
return false;
}
}
bool ciMethod::ensure_method_data() {
bool result = true;
if (_method_data == NULL || _method_data->is_empty()) {
GUARDED_VM_ENTRY({
result = ensure_method_data(get_Method());
});
}
return result;
}
ciMethodData* ciMethod::method_data() {
if (_method_data != NULL) {
return _method_data;
}
VM_ENTRY_MARK;
ciEnv* env = CURRENT_ENV;
Thread* my_thread = JavaThread::current();
methodHandle h_m(my_thread, get_Method());
if (h_m()->method_data() != NULL) {
_method_data = CURRENT_ENV->get_method_data(h_m()->method_data());
_method_data->load_data();
} else {
_method_data = CURRENT_ENV->get_empty_methodData();
}
return _method_data;
}
ciMethodData* ciMethod::method_data_or_null() {
ciMethodData *md = method_data();
if (md->is_empty()) {
return NULL;
}
return md;
}
MethodCounters* ciMethod::ensure_method_counters() {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
MethodCounters* method_counters = mh->get_method_counters(CHECK_NULL);
return method_counters;
}
bool ciMethod::should_exclude() {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
bool ignore;
return CompilerOracle::should_exclude(mh, ignore);
}
bool ciMethod::should_inline() {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
return CompilerOracle::should_inline(mh);
}
bool ciMethod::should_not_inline() {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
return CompilerOracle::should_not_inline(mh);
}
bool ciMethod::should_print_assembly() {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
return CompilerOracle::should_print(mh);
}
bool ciMethod::break_at_execute() {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
return CompilerOracle::should_break_at(mh);
}
bool ciMethod::has_option(const char* option) {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
return CompilerOracle::has_option_string(mh, option);
}
template<typename T>
bool ciMethod::has_option_value(const char* option, T& value) {
check_is_loaded();
VM_ENTRY_MARK;
methodHandle mh(THREAD, get_Method());
return CompilerOracle::has_option_value(mh, option, value);
}
template bool ciMethod::has_option_value<intx>(const char* option, intx& value);
template bool ciMethod::has_option_value<uintx>(const char* option, uintx& value);
template bool ciMethod::has_option_value<bool>(const char* option, bool& value);
template bool ciMethod::has_option_value<ccstr>(const char* option, ccstr& value);
bool ciMethod::can_be_compiled() {
check_is_loaded();
ciEnv* env = CURRENT_ENV;
if (is_c1_compile(env->comp_level())) {
return _is_c1_compilable;
}
return _is_c2_compilable;
}
void ciMethod::set_not_compilable(const char* reason) {
check_is_loaded();
VM_ENTRY_MARK;
ciEnv* env = CURRENT_ENV;
if (is_c1_compile(env->comp_level())) {
_is_c1_compilable = false;
} else {
_is_c2_compilable = false;
}
get_Method()->set_not_compilable(env->comp_level(), true, reason);
}
bool ciMethod::can_be_osr_compiled(int entry_bci) {
check_is_loaded();
VM_ENTRY_MARK;
ciEnv* env = CURRENT_ENV;
return !get_Method()->is_not_osr_compilable(env->comp_level());
}
bool ciMethod::has_compiled_code() {
return instructions_size() > 0;
}
int ciMethod::comp_level() {
check_is_loaded();
VM_ENTRY_MARK;
nmethod* nm = get_Method()->code();
if (nm != NULL) return nm->comp_level();
return 0;
}
int ciMethod::highest_osr_comp_level() {
check_is_loaded();
VM_ENTRY_MARK;
return get_Method()->highest_osr_comp_level();
}
int ciMethod::code_size_for_inlining() {
check_is_loaded();
if (get_Method()->force_inline()) {
return 1;
}
return code_size();
}
int ciMethod::instructions_size() {
if (_instructions_size == -1) {
GUARDED_VM_ENTRY(
nmethod* code = get_Method()->code();
if (code != NULL && (code->comp_level() == CompLevel_full_optimization)) {
_instructions_size = code->insts_end() - code->verified_entry_point();
} else {
_instructions_size = 0;
}
);
}
return _instructions_size;
}
void ciMethod::log_nmethod_identity(xmlStream* log) {
GUARDED_VM_ENTRY(
nmethod* code = get_Method()->code();
if (code != NULL) {
code->log_identity(log);
}
)
}
bool ciMethod::is_not_reached(int bci) {
check_is_loaded();
VM_ENTRY_MARK;
return Interpreter::is_not_reached(
methodHandle(THREAD, get_Method()), bci);
}
bool ciMethod::was_executed_more_than(int times) {
VM_ENTRY_MARK;
return get_Method()->was_executed_more_than(times);
}
bool ciMethod::has_unloaded_classes_in_signature() {
VM_ENTRY_MARK;
{
EXCEPTION_MARK;
methodHandle m(THREAD, get_Method());
bool has_unloaded = Method::has_unloaded_classes_in_signature(m, (JavaThread *)THREAD);
if( HAS_PENDING_EXCEPTION ) {
CLEAR_PENDING_EXCEPTION;
return true; // Declare that we may have unloaded classes
}
return has_unloaded;
}
}
bool ciMethod::is_klass_loaded(int refinfo_index, bool must_be_resolved) const {
VM_ENTRY_MARK;
return get_Method()->is_klass_loaded(refinfo_index, must_be_resolved);
}
bool ciMethod::check_call(int refinfo_index, bool is_static) const {
VM_ENTRY_MARK;
{
EXCEPTION_MARK;
HandleMark hm(THREAD);
constantPoolHandle pool (THREAD, get_Method()->constants());
methodHandle spec_method;
KlassHandle spec_klass;
Bytecodes::Code code = (is_static ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual);
LinkResolver::resolve_method_statically(spec_method, spec_klass, code, pool, refinfo_index, THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
return false;
} else {
return (spec_method->is_static() == is_static);
}
}
return false;
}
void ciMethod::print_codes_on(outputStream* st) {
check_is_loaded();
GUARDED_VM_ENTRY(get_Method()->print_codes_on(st);)
}
#define FETCH_FLAG_FROM_VM(flag_accessor) { \
check_is_loaded(); \
VM_ENTRY_MARK; \
return get_Method()->flag_accessor(); \
}
bool ciMethod::is_empty_method() const { FETCH_FLAG_FROM_VM(is_empty_method); }
bool ciMethod::is_vanilla_constructor() const { FETCH_FLAG_FROM_VM(is_vanilla_constructor); }
bool ciMethod::has_loops () const { FETCH_FLAG_FROM_VM(has_loops); }
bool ciMethod::has_jsrs () const { FETCH_FLAG_FROM_VM(has_jsrs); }
bool ciMethod::is_accessor () const { FETCH_FLAG_FROM_VM(is_accessor); }
bool ciMethod::is_initializer () const { FETCH_FLAG_FROM_VM(is_initializer); }
bool ciMethod::is_boxing_method() const {
if (holder()->is_box_klass()) {
switch (intrinsic_id()) {
case vmIntrinsics::_Boolean_valueOf:
case vmIntrinsics::_Byte_valueOf:
case vmIntrinsics::_Character_valueOf:
case vmIntrinsics::_Short_valueOf:
case vmIntrinsics::_Integer_valueOf:
case vmIntrinsics::_Long_valueOf:
case vmIntrinsics::_Float_valueOf:
case vmIntrinsics::_Double_valueOf:
return true;
default:
return false;
}
}
return false;
}
bool ciMethod::is_unboxing_method() const {
if (holder()->is_box_klass()) {
switch (intrinsic_id()) {
case vmIntrinsics::_booleanValue:
case vmIntrinsics::_byteValue:
case vmIntrinsics::_charValue:
case vmIntrinsics::_shortValue:
case vmIntrinsics::_intValue:
case vmIntrinsics::_longValue:
case vmIntrinsics::_floatValue:
case vmIntrinsics::_doubleValue:
return true;
default:
return false;
}
}
return false;
}
BCEscapeAnalyzer *ciMethod::get_bcea() {
#ifdef COMPILER2
if (_bcea == NULL) {
_bcea = new (CURRENT_ENV->arena()) BCEscapeAnalyzer(this, NULL);
}
return _bcea;
#else // COMPILER2
ShouldNotReachHere();
return NULL;
#endif // COMPILER2
}
ciMethodBlocks *ciMethod::get_method_blocks() {
Arena *arena = CURRENT_ENV->arena();
if (_method_blocks == NULL) {
_method_blocks = new (arena) ciMethodBlocks(arena, this);
}
return _method_blocks;
}
#undef FETCH_FLAG_FROM_VM
void ciMethod::dump_name_as_ascii(outputStream* st) {
Method* method = get_Method();
st->print("%s %s %s",
method->klass_name()->as_quoted_ascii(),
method->name()->as_quoted_ascii(),
method->signature()->as_quoted_ascii());
}
void ciMethod::dump_replay_data(outputStream* st) {
ResourceMark rm;
Method* method = get_Method();
MethodCounters* mcs = method->method_counters();
st->print("ciMethod ");
dump_name_as_ascii(st);
st->print_cr(" %d %d %d %d %d",
mcs == NULL ? 0 : mcs->invocation_counter()->raw_counter(),
mcs == NULL ? 0 : mcs->backedge_counter()->raw_counter(),
interpreter_invocation_count(),
interpreter_throwout_count(),
_instructions_size);
}
void ciMethod::print_codes_on(int from, int to, outputStream* st) {
check_is_loaded();
GUARDED_VM_ENTRY(get_Method()->print_codes_on(from, to, st);)
}
void ciMethod::print_name(outputStream* st) {
check_is_loaded();
GUARDED_VM_ENTRY(get_Method()->print_name(st);)
}
void ciMethod::print_short_name(outputStream* st) {
if (is_loaded()) {
GUARDED_VM_ENTRY(get_Method()->print_short_name(st););
} else {
holder()->print_name_on(st);
st->print("::");
name()->print_symbol_on(st);
if (WizardMode)
signature()->as_symbol()->print_symbol_on(st);
}
}
void ciMethod::print_impl(outputStream* st) {
ciMetadata::print_impl(st);
st->print(" name=");
name()->print_symbol_on(st);
st->print(" holder=");
holder()->print_name_on(st);
st->print(" signature=");
signature()->as_symbol()->print_symbol_on(st);
if (is_loaded()) {
st->print(" loaded=true");
st->print(" arg_size=%d", arg_size());
st->print(" flags=");
flags().print_member_flags(st);
} else {
st->print(" loaded=false");
}
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciMethod.hpp
#ifndef SHARE_VM_CI_CIMETHOD_HPP
#define SHARE_VM_CI_CIMETHOD_HPP
#include "ci/ciFlags.hpp"
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciObject.hpp"
#include "ci/ciSignature.hpp"
#include "compiler/methodLiveness.hpp"
#include "prims/methodHandles.hpp"
#include "utilities/bitMap.hpp"
class ciMethodBlocks;
class MethodLiveness;
class BitMap;
class Arena;
class BCEscapeAnalyzer;
class ciMethod : public ciMetadata {
friend class CompileBroker;
CI_PACKAGE_ACCESS
friend class ciEnv;
friend class ciExceptionHandlerStream;
friend class ciBytecodeStream;
friend class ciMethodHandle;
friend class ciReplay;
private:
ciFlags _flags;
ciSymbol* _name;
ciInstanceKlass* _holder;
ciSignature* _signature;
ciMethodData* _method_data;
ciMethodBlocks* _method_blocks;
int _code_size;
int _max_stack;
int _max_locals;
vmIntrinsics::ID _intrinsic_id;
int _handler_count;
int _interpreter_invocation_count;
int _interpreter_throwout_count;
int _instructions_size;
int _size_of_parameters;
bool _uses_monitors;
bool _balanced_monitors;
bool _is_c1_compilable;
bool _is_c2_compilable;
bool _can_be_statically_bound;
address _code;
ciExceptionHandler** _exception_handlers;
MethodLiveness* _liveness;
#if defined(COMPILER2) || defined(SHARK)
ciTypeFlow* _flow;
BCEscapeAnalyzer* _bcea;
#endif
ciMethod(methodHandle h_m, ciInstanceKlass* holder);
ciMethod(ciInstanceKlass* holder, ciSymbol* name, ciSymbol* signature, ciInstanceKlass* accessor);
oop loader() const { return _holder->loader(); }
const char* type_string() { return "ciMethod"; }
void print_impl(outputStream* st);
void load_code();
void check_is_loaded() const { assert(is_loaded(), "not loaded"); }
bool ensure_method_data(methodHandle h_m);
void code_at_put(int bci, Bytecodes::Code code) {
Bytecodes::check(code);
assert(0 <= bci && bci < code_size(), "valid bci");
address bcp = _code + bci;
}
void assert_virtual_call_type_ok(int bci);
void assert_call_type_ok(int bci);
public:
ciFlags flags() const { check_is_loaded(); return _flags; }
ciSymbol* name() const { return _name; }
ciInstanceKlass* holder() const { return _holder; }
ciMethodData* method_data();
ciMethodData* method_data_or_null();
ciSignature* signature() const { return _signature; }
ciType* return_type() const { return _signature->return_type(); }
int arg_size_no_receiver() const { return _signature->size(); }
int arg_size() const {
check_is_loaded();
return _signature->size() + (_flags.is_static() ? 0 : 1);
}
int invoke_arg_size(Bytecodes::Code code) const {
if (is_loaded()) {
return arg_size();
} else {
int arg_size = _signature->size();
if (code != Bytecodes::_invokestatic &&
code != Bytecodes::_invokedynamic) {
arg_size++;
}
return arg_size;
}
}
Method* get_Method() const {
Method* m = (Method*)_metadata;
assert(m != NULL, "illegal use of unloaded method");
return m;
}
address code() { if (_code == NULL) load_code(); return _code; }
int code_size() const { check_is_loaded(); return _code_size; }
int max_stack() const { check_is_loaded(); return _max_stack; }
int max_locals() const { check_is_loaded(); return _max_locals; }
vmIntrinsics::ID intrinsic_id() const { check_is_loaded(); return _intrinsic_id; }
bool has_exception_handlers() const { check_is_loaded(); return _handler_count > 0; }
int exception_table_length() const { check_is_loaded(); return _handler_count; }
int interpreter_invocation_count() const { check_is_loaded(); return _interpreter_invocation_count; }
int interpreter_throwout_count() const { check_is_loaded(); return _interpreter_throwout_count; }
int size_of_parameters() const { check_is_loaded(); return _size_of_parameters; }
int code_size_for_inlining();
bool caller_sensitive() const { return get_Method()->caller_sensitive(); }
bool force_inline() const { return get_Method()->force_inline(); }
bool dont_inline() const { return get_Method()->dont_inline(); }
int comp_level();
int highest_osr_comp_level();
Bytecodes::Code java_code_at_bci(int bci) {
address bcp = code() + bci;
return Bytecodes::java_code_at(NULL, bcp);
}
Bytecodes::Code raw_code_at_bci(int bci) {
address bcp = code() + bci;
return Bytecodes::code_at(NULL, bcp);
}
BCEscapeAnalyzer *get_bcea();
ciMethodBlocks *get_method_blocks();
bool has_linenumber_table() const; // length unknown until decompression
u_char* compressed_linenumber_table() const; // not preserved by gc
int line_number_from_bci(int bci) const;
int vtable_index();
#ifdef SHARK
int itable_index();
#endif // SHARK
address native_entry();
address interpreter_entry();
bool has_monitor_bytecodes() const { return _uses_monitors; }
bool has_balanced_monitors();
MethodLivenessResult raw_liveness_at_bci(int bci);
MethodLivenessResult liveness_at_bci(int bci);
BitMap live_local_oops_at_bci(int bci);
#ifdef COMPILER1
const BitMap bci_block_start();
#endif
ciTypeFlow* get_flow_analysis();
ciTypeFlow* get_osr_flow_analysis(int osr_bci); // alternate entry point
ciCallProfile call_profile_at_bci(int bci);
int interpreter_call_site_count(int bci);
ciKlass* argument_profiled_type(int bci, int i);
ciKlass* parameter_profiled_type(int i);
ciKlass* return_profiled_type(int bci);
ciField* get_field_at_bci( int bci, bool &will_link);
ciMethod* get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature);
ciSignature* get_declared_signature_at_bci(int bci) {
bool ignored_will_link;
ciSignature* declared_signature;
get_method_at_bci(bci, ignored_will_link, &declared_signature);
assert(declared_signature != NULL, "cannot be null");
return declared_signature;
}
ciMethod* get_method_at_bci(int bci) {
bool ignored_will_link;
ciSignature* ignored_declared_signature;
return get_method_at_bci(bci, ignored_will_link, &ignored_declared_signature);
}
ciMethod* find_monomorphic_target(ciInstanceKlass* caller,
ciInstanceKlass* callee_holder,
ciInstanceKlass* actual_receiver,
bool check_access = true);
ciMethod* resolve_invoke(ciKlass* caller, ciKlass* exact_receiver, bool check_access = true);
int resolve_vtable_index(ciKlass* caller, ciKlass* receiver);
bool should_exclude();
bool should_inline();
bool should_not_inline();
bool should_print_assembly();
bool break_at_execute();
bool has_option(const char *option);
template<typename T>
bool has_option_value(const char* option, T& value);
bool can_be_compiled();
bool can_be_osr_compiled(int entry_bci);
void set_not_compilable(const char* reason = NULL);
bool has_compiled_code();
void log_nmethod_identity(xmlStream* log);
bool is_not_reached(int bci);
bool was_executed_more_than(int times);
bool has_unloaded_classes_in_signature();
bool is_klass_loaded(int refinfo_index, bool must_be_resolved) const;
bool check_call(int refinfo_index, bool is_static) const;
bool ensure_method_data(); // make sure it exists in the VM also
MethodCounters* ensure_method_counters();
int instructions_size();
int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC
bool is_ignored_by_security_stack_walk() const;
bool is_method_handle_intrinsic() const;
bool is_compiled_lambda_form() const;
bool has_member_arg() const;
bool is_method() const { return true; }
bool is_public () const { return flags().is_public(); }
bool is_private () const { return flags().is_private(); }
bool is_protected () const { return flags().is_protected(); }
bool is_static () const { return flags().is_static(); }
bool is_final () const { return flags().is_final(); }
bool is_synchronized() const { return flags().is_synchronized(); }
bool is_native () const { return flags().is_native(); }
bool is_interface () const { return flags().is_interface(); }
bool is_abstract () const { return flags().is_abstract(); }
bool is_strict () const { return flags().is_strict(); }
bool is_empty_method() const;
bool is_vanilla_constructor() const;
bool is_final_method() const { return is_final() || holder()->is_final(); }
bool has_loops () const;
bool has_jsrs () const;
bool is_accessor () const;
bool is_initializer () const;
bool can_be_statically_bound() const { return _can_be_statically_bound; }
bool is_boxing_method() const;
bool is_unboxing_method() const;
bool is_object_initializer() const;
void dump_name_as_ascii(outputStream* st);
void dump_replay_data(outputStream* st);
void print_codes_on(outputStream* st);
void print_codes() {
print_codes_on(tty);
}
void print_codes_on(int from, int to, outputStream* st);
void print_name(outputStream* st = tty);
void print_short_name(outputStream* st = tty);
};
#endif // SHARE_VM_CI_CIMETHOD_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciMethodBlocks.cpp
#include "precompiled.hpp"
#include "ci/ciMethodBlocks.hpp"
#include "ci/ciStreams.hpp"
#include "interpreter/bytecode.hpp"
#include "utilities/copy.hpp"
ciBlock *ciMethodBlocks::block_containing(int bci) {
ciBlock *blk = _bci_to_block[bci];
return blk;
}
bool ciMethodBlocks::is_block_start(int bci) {
assert(bci >=0 && bci < _code_size, "valid bytecode range");
ciBlock *b = _bci_to_block[bci];
assert(b != NULL, "must have block for bytecode");
return b->start_bci() == bci;
}
ciBlock *ciMethodBlocks::split_block_at(int bci) {
ciBlock *former_block = block_containing(bci);
ciBlock *new_block = new(_arena) ciBlock(_method, _num_blocks++, former_block->start_bci());
_blocks->append(new_block);
assert(former_block != NULL, "must not be NULL");
new_block->set_limit_bci(bci);
former_block->set_start_bci(bci);
for (int pos=bci-1; pos >= 0; pos--) {
ciBlock *current_block = block_containing(pos);
if (current_block == former_block) {
_bci_to_block[pos] = new_block;
} else if (current_block == NULL) {
continue;
} else {
break;
}
}
if (former_block->is_handler()) {
int ex_start = former_block->ex_start_bci();
int ex_end = former_block->ex_limit_bci();
new_block->set_exception_range(ex_start, ex_end);
former_block->clear_exception_handler();
}
return former_block;
}
ciBlock *ciMethodBlocks::make_block_at(int bci) {
ciBlock *cb = block_containing(bci);
if (cb == NULL ) {
ciBlock *nb = new(_arena) ciBlock(_method, _num_blocks++, bci);
_blocks->append(nb);
_bci_to_block[bci] = nb;
return nb;
} else if (cb->start_bci() == bci) {
return cb;
} else {
return split_block_at(bci);
}
}
ciBlock *ciMethodBlocks::make_dummy_block() {
ciBlock *dum = new(_arena) ciBlock(_method, -1, 0);
return dum;
}
void ciMethodBlocks::do_analysis() {
ciBytecodeStream s(_method);
ciBlock *cur_block = block_containing(0);
int limit_bci = _method->code_size();
while (s.next() != ciBytecodeStream::EOBC()) {
int bci = s.cur_bci();
assert(cur_block != NULL, "must always have a current block");
ciBlock *new_block = block_containing(bci);
if (new_block == NULL || new_block == cur_block) {
_bci_to_block[bci] = cur_block;
} else {
cur_block->set_limit_bci(bci);
cur_block = new_block;
}
switch (s.cur_bc()) {
case Bytecodes::_ifeq :
case Bytecodes::_ifne :
case Bytecodes::_iflt :
case Bytecodes::_ifge :
case Bytecodes::_ifgt :
case Bytecodes::_ifle :
case Bytecodes::_if_icmpeq :
case Bytecodes::_if_icmpne :
case Bytecodes::_if_icmplt :
case Bytecodes::_if_icmpge :
case Bytecodes::_if_icmpgt :
case Bytecodes::_if_icmple :
case Bytecodes::_if_acmpeq :
case Bytecodes::_if_acmpne :
case Bytecodes::_ifnull :
case Bytecodes::_ifnonnull :
{
cur_block->set_control_bci(bci);
ciBlock *fall_through = make_block_at(s.next_bci());
int dest_bci = s.get_dest();
ciBlock *dest = make_block_at(dest_bci);
break;
}
case Bytecodes::_goto :
{
cur_block->set_control_bci(bci);
if (s.next_bci() < limit_bci) {
(void) make_block_at(s.next_bci());
}
int dest_bci = s.get_dest();
ciBlock *dest = make_block_at(dest_bci);
break;
}
case Bytecodes::_jsr :
{
cur_block->set_control_bci(bci);
ciBlock *ret = make_block_at(s.next_bci());
int dest_bci = s.get_dest();
ciBlock *dest = make_block_at(dest_bci);
break;
}
case Bytecodes::_tableswitch :
{
cur_block->set_control_bci(bci);
Bytecode_tableswitch sw(&s);
int len = sw.length();
ciBlock *dest;
int dest_bci;
for (int i = 0; i < len; i++) {
dest_bci = s.cur_bci() + sw.dest_offset_at(i);
dest = make_block_at(dest_bci);
}
dest_bci = s.cur_bci() + sw.default_offset();
make_block_at(dest_bci);
if (s.next_bci() < limit_bci) {
dest = make_block_at(s.next_bci());
}
}
break;
case Bytecodes::_lookupswitch:
{
cur_block->set_control_bci(bci);
Bytecode_lookupswitch sw(&s);
int len = sw.number_of_pairs();
ciBlock *dest;
int dest_bci;
for (int i = 0; i < len; i++) {
dest_bci = s.cur_bci() + sw.pair_at(i).offset();
dest = make_block_at(dest_bci);
}
dest_bci = s.cur_bci() + sw.default_offset();
dest = make_block_at(dest_bci);
if (s.next_bci() < limit_bci) {
dest = make_block_at(s.next_bci());
}
}
break;
case Bytecodes::_goto_w :
{
cur_block->set_control_bci(bci);
if (s.next_bci() < limit_bci) {
(void) make_block_at(s.next_bci());
}
int dest_bci = s.get_far_dest();
ciBlock *dest = make_block_at(dest_bci);
break;
}
case Bytecodes::_jsr_w :
{
cur_block->set_control_bci(bci);
ciBlock *ret = make_block_at(s.next_bci());
int dest_bci = s.get_far_dest();
ciBlock *dest = make_block_at(dest_bci);
break;
}
case Bytecodes::_athrow :
cur_block->set_may_throw();
case Bytecodes::_ret :
case Bytecodes::_ireturn :
case Bytecodes::_lreturn :
case Bytecodes::_freturn :
case Bytecodes::_dreturn :
case Bytecodes::_areturn :
case Bytecodes::_return :
cur_block->set_control_bci(bci);
if (s.next_bci() < limit_bci) {
(void) make_block_at(s.next_bci());
}
break;
}
}
cur_block->set_limit_bci(limit_bci);
}
ciMethodBlocks::ciMethodBlocks(Arena *arena, ciMethod *meth): _method(meth),
_arena(arena), _num_blocks(0), _code_size(meth->code_size()) {
int block_estimate = _code_size / 8;
_blocks = new(_arena) GrowableArray<ciBlock *>(_arena, block_estimate, 0, NULL);
int b2bsize = _code_size * sizeof(ciBlock **);
_bci_to_block = (ciBlock **) arena->Amalloc(b2bsize);
Copy::zero_to_words((HeapWord*) _bci_to_block, b2bsize / sizeof(HeapWord));
ciBlock *b = new(arena) ciBlock(_method, _num_blocks++, 0);
_blocks->append(b);
_bci_to_block[0] = b;
if (meth->has_exception_handlers()) {
for(ciExceptionHandlerStream str(meth); !str.is_done(); str.next()) {
ciExceptionHandler* handler = str.handler();
ciBlock *eb = make_block_at(handler->handler_bci());
int ex_start = handler->start();
int ex_end = handler->limit();
(void) make_block_at(ex_start);
if (ex_end < _code_size)
(void) make_block_at(ex_end);
if (eb->is_handler()) {
int old_ex_start = eb->ex_start_bci();
int old_ex_end = eb->ex_limit_bci();
if (ex_start > old_ex_start)
ex_start = old_ex_start;
if (ex_end < old_ex_end)
ex_end = old_ex_end;
eb->clear_exception_handler(); // Reset exception information
}
eb->set_exception_range(ex_start, ex_end);
}
}
do_analysis();
if (meth->has_exception_handlers()) {
for(ciExceptionHandlerStream str(meth); !str.is_done(); str.next()) {
ciExceptionHandler* handler = str.handler();
int ex_start = handler->start();
int ex_end = handler->limit();
int bci = ex_start;
while (bci < ex_end) {
ciBlock *b = block_containing(bci);
b->set_has_handler();
bci = b->limit_bci();
}
}
}
}
void ciMethodBlocks::clear_processed() {
for (int i = 0; i < _blocks->length(); i++)
_blocks->at(i)->clear_processed();
}
#ifndef PRODUCT
void ciMethodBlocks::dump() {
tty->print("---- blocks for method: ");
_method->print();
tty->cr();
for (int i = 0; i < _blocks->length(); i++) {
tty->print(" B%d: ", i); _blocks->at(i)->dump();
}
}
#endif
ciBlock::ciBlock(ciMethod *method, int index, int start_bci) :
#ifndef PRODUCT
_method(method),
#endif
_idx(index), _flags(0), _start_bci(start_bci), _limit_bci(-1), _control_bci(fall_through_bci),
_ex_start_bci(-1), _ex_limit_bci(-1) {
}
void ciBlock::set_exception_range(int start_bci, int limit_bci) {
assert(limit_bci >= start_bci, "valid range");
assert(!is_handler() && _ex_start_bci == -1 && _ex_limit_bci == -1, "must not be handler");
_ex_start_bci = start_bci;
_ex_limit_bci = limit_bci;
set_handler();
}
#ifndef PRODUCT
static const char *flagnames[] = {
"Processed",
"Handler",
"MayThrow",
"Jsr",
"Ret",
"RetTarget",
"HasHandler",
};
void ciBlock::dump() {
tty->print(" [%d .. %d), {", _start_bci, _limit_bci);
for (int i = 0; i < 8; i++) {
if ((_flags & (1 << i)) != 0) {
tty->print(" %s", flagnames[i]);
}
}
tty->print(" ]");
if (is_handler())
tty->print(" handles(%d..%d)", _ex_start_bci, _ex_limit_bci);
tty->cr();
}
void ciBlock::print_on(outputStream* st) const {
st->print_cr("--------------------------------------------------------");
st->print ("ciBlock [%d - %d) control : ", start_bci(), limit_bci());
if (control_bci() == fall_through_bci) {
st->print_cr("%d:fall through", limit_bci());
} else {
st->print_cr("%d:%s", control_bci(),
Bytecodes::name(method()->java_code_at_bci(control_bci())));
}
if (Verbose || WizardMode) {
method()->print_codes_on(start_bci(), limit_bci(), st);
}
}
#endif
C:\hotspot-69087d08d473\src\share\vm/ci/ciMethodBlocks.hpp
#ifndef SHARE_VM_CI_CIMETHODBLOCKS_HPP
#define SHARE_VM_CI_CIMETHODBLOCKS_HPP
#include "ci/ciMethod.hpp"
#include "memory/resourceArea.hpp"
#include "utilities/growableArray.hpp"
class ciBlock;
typedef short ciBlockIndex;
class ciMethodBlocks : public ResourceObj {
private:
ciMethod *_method;
Arena *_arena;
GrowableArray<ciBlock *> *_blocks;
ciBlock **_bci_to_block;
int _num_blocks;
int _code_size;
void do_analysis();
public:
ciMethodBlocks(Arena *arena, ciMethod *meth);
ciBlock *block_containing(int bci);
ciBlock *block(int index) { return _blocks->at(index); }
ciBlock *make_block_at(int bci);
ciBlock *split_block_at(int bci);
bool is_block_start(int bci);
int num_blocks() { return _num_blocks;}
void clear_processed();
ciBlock *make_dummy_block(); // a block not associated with a bci
#ifndef PRODUCT
void dump();
#endif
};
class ciBlock : public ResourceObj {
private:
int _idx;
int _start_bci;
int _limit_bci;
int _control_bci;
uint _flags;
int _ex_start_bci;
int _ex_limit_bci;
#ifndef PRODUCT
ciMethod *_method;
#endif
enum {
Processed = (1 << 0),
Handler = (1 << 1),
MayThrow = (1 << 2),
DoesJsr = (1 << 3),
DoesRet = (1 << 4),
RetTarget = (1 << 5),
HasHandler = (1 << 6)
};
public:
enum {
fall_through_bci = -1
};
ciBlock(ciMethod *method, int index, int start_bci);
int start_bci() const { return _start_bci; }
int limit_bci() const { return _limit_bci; }
int control_bci() const { return _control_bci; }
int index() const { return _idx; }
void set_start_bci(int bci) { _start_bci = bci; }
void set_limit_bci(int bci) { _limit_bci = bci; }
void set_control_bci(int bci) { _control_bci = bci;}
void set_exception_range(int start_bci, int limit_bci);
int ex_start_bci() const { return _ex_start_bci; }
int ex_limit_bci() const { return _ex_limit_bci; }
bool contains(int bci) const { return start_bci() <= bci && bci < limit_bci(); }
bool processed() const { return (_flags & Processed) != 0; }
bool is_handler() const { return (_flags & Handler) != 0; }
bool may_throw() const { return (_flags & MayThrow) != 0; }
bool does_jsr() const { return (_flags & DoesJsr) != 0; }
bool does_ret() const { return (_flags & DoesRet) != 0; }
bool has_handler() const { return (_flags & HasHandler) != 0; }
bool is_ret_target() const { return (_flags & RetTarget) != 0; }
void set_processed() { _flags |= Processed; }
void clear_processed() { _flags &= ~Processed; }
void set_handler() { _flags |= Handler; }
void set_may_throw() { _flags |= MayThrow; }
void set_does_jsr() { _flags |= DoesJsr; }
void clear_does_jsr() { _flags &= ~DoesJsr; }
void set_does_ret() { _flags |= DoesRet; }
void clear_does_ret() { _flags &= ~DoesRet; }
void set_is_ret_target() { _flags |= RetTarget; }
void set_has_handler() { _flags |= HasHandler; }
void clear_exception_handler() { _flags &= ~Handler; _ex_start_bci = -1; _ex_limit_bci = -1; }
#ifndef PRODUCT
ciMethod *method() const { return _method; }
void dump();
void print_on(outputStream* st) const PRODUCT_RETURN;
#endif
};
#endif // SHARE_VM_CI_CIMETHODBLOCKS_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciMethodData.cpp
#include "precompiled.hpp"
#include "ci/ciMetadata.hpp"
#include "ci/ciMethodData.hpp"
#include "ci/ciReplay.hpp"
#include "ci/ciUtilities.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/deoptimization.hpp"
#include "utilities/copy.hpp"
ciMethodData::ciMethodData(MethodData* md) : ciMetadata(md) {
assert(md != NULL, "no null method data");
Copy::zero_to_words((HeapWord*) &_orig, sizeof(_orig) / sizeof(HeapWord));
_data = NULL;
_data_size = 0;
_extra_data_size = 0;
_current_mileage = 0;
_invocation_counter = 0;
_backedge_counter = 0;
_state = empty_state;
_saw_free_extra_data = false;
_hint_di = first_di();
_eflags = _arg_local = _arg_stack = _arg_returned = 0;
_parameters = NULL;
}
ciMethodData::ciMethodData() : ciMetadata(NULL) {
Copy::zero_to_words((HeapWord*) &_orig, sizeof(_orig) / sizeof(HeapWord));
_data = NULL;
_data_size = 0;
_extra_data_size = 0;
_current_mileage = 0;
_invocation_counter = 0;
_backedge_counter = 0;
_state = empty_state;
_saw_free_extra_data = false;
_hint_di = first_di();
_eflags = _arg_local = _arg_stack = _arg_returned = 0;
_parameters = NULL;
}
void ciMethodData::load_extra_data() {
MethodData* mdo = get_MethodData();
DataLayout* dp_src = mdo->extra_data_base();
DataLayout* end_src = mdo->extra_data_limit();
DataLayout* dp_dst = extra_data_base();
for (;; dp_src = MethodData::next_extra(dp_src), dp_dst = MethodData::next_extra(dp_dst)) {
assert(dp_src < end_src, "moved past end of extra data");
switch(dp_dst->tag()) {
case DataLayout::speculative_trap_data_tag: {
ciSpeculativeTrapData* data_dst = new ciSpeculativeTrapData(dp_dst);
SpeculativeTrapData* data_src = new SpeculativeTrapData(dp_src);
data_dst->translate_from(data_src);
break;
}
case DataLayout::bit_data_tag:
break;
case DataLayout::no_tag:
case DataLayout::arg_info_data_tag:
return;
default:
fatal(err_msg("bad tag = %d", dp_dst->tag()));
}
}
}
void ciMethodData::load_data() {
MethodData* mdo = get_MethodData();
if (mdo == NULL) {
return;
}
Copy::disjoint_words_atomic((HeapWord*) mdo,
(HeapWord*) &_orig,
sizeof(_orig) / HeapWordSize);
Arena* arena = CURRENT_ENV->arena();
_data_size = mdo->data_size();
_extra_data_size = mdo->extra_data_size();
int total_size = _data_size + _extra_data_size;
_data = (intptr_t *) arena->Amalloc(total_size);
Copy::disjoint_words_atomic((HeapWord*) mdo->data_base(),
(HeapWord*) _data,
total_size / HeapWordSize);
ResourceMark rm;
ciProfileData* ci_data = first_data();
ProfileData* data = mdo->first_data();
while (is_valid(ci_data)) {
ci_data->translate_from(data);
ci_data = next_data(ci_data);
data = mdo->next_data(data);
}
if (mdo->parameters_type_data() != NULL) {
_parameters = data_layout_at(mdo->parameters_type_data_di());
ciParametersTypeData* parameters = new ciParametersTypeData(_parameters);
parameters->translate_from(mdo->parameters_type_data());
}
load_extra_data();
_current_mileage = MethodData::mileage_of(mdo->method());
_invocation_counter = mdo->invocation_count();
_backedge_counter = mdo->backedge_count();
_state = mdo->is_mature()? mature_state: immature_state;
_eflags = mdo->eflags();
_arg_local = mdo->arg_local();
_arg_stack = mdo->arg_stack();
_arg_returned = mdo->arg_returned();
#ifndef PRODUCT
if (ReplayCompiles) {
ciReplay::initialize(this);
}
#endif
}
void ciReceiverTypeData::translate_receiver_data_from(const ProfileData* data) {
for (uint row = 0; row < row_limit(); row++) {
Klass* k = data->as_ReceiverTypeData()->receiver(row);
if (k != NULL) {
ciKlass* klass = CURRENT_ENV->get_klass(k);
CURRENT_ENV->ensure_metadata_alive(klass);
set_receiver(row, klass);
}
}
}
void ciTypeStackSlotEntries::translate_type_data_from(const TypeStackSlotEntries* entries) {
for (int i = 0; i < _number_of_entries; i++) {
intptr_t k = entries->type(i);
TypeStackSlotEntries::set_type(i, translate_klass(k));
}
}
void ciReturnTypeEntry::translate_type_data_from(const ReturnTypeEntry* ret) {
intptr_t k = ret->type();
set_type(translate_klass(k));
}
void ciSpeculativeTrapData::translate_from(const ProfileData* data) {
Method* m = data->as_SpeculativeTrapData()->method();
ciMethod* ci_m = CURRENT_ENV->get_method(m);
CURRENT_ENV->ensure_metadata_alive(ci_m);
set_method(ci_m);
}
ciProfileData* ciMethodData::data_at(int data_index) {
if (out_of_bounds(data_index)) {
return NULL;
}
DataLayout* data_layout = data_layout_at(data_index);
switch (data_layout->tag()) {
case DataLayout::no_tag:
default:
ShouldNotReachHere();
return NULL;
case DataLayout::bit_data_tag:
return new ciBitData(data_layout);
case DataLayout::counter_data_tag:
return new ciCounterData(data_layout);
case DataLayout::jump_data_tag:
return new ciJumpData(data_layout);
case DataLayout::receiver_type_data_tag:
return new ciReceiverTypeData(data_layout);
case DataLayout::virtual_call_data_tag:
return new ciVirtualCallData(data_layout);
case DataLayout::ret_data_tag:
return new ciRetData(data_layout);
case DataLayout::branch_data_tag:
return new ciBranchData(data_layout);
case DataLayout::multi_branch_data_tag:
return new ciMultiBranchData(data_layout);
case DataLayout::arg_info_data_tag:
return new ciArgInfoData(data_layout);
case DataLayout::call_type_data_tag:
return new ciCallTypeData(data_layout);
case DataLayout::virtual_call_type_data_tag:
return new ciVirtualCallTypeData(data_layout);
case DataLayout::parameters_type_data_tag:
return new ciParametersTypeData(data_layout);
};
}
ciProfileData* ciMethodData::next_data(ciProfileData* current) {
int current_index = dp_to_di(current->dp());
int next_index = current_index + current->size_in_bytes();
ciProfileData* next = data_at(next_index);
return next;
}
ciProfileData* ciMethodData::bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots) {
DataLayout* dp = data_layout_at(data_size());
DataLayout* end = data_layout_at(data_size() + extra_data_size());
two_free_slots = false;
for (;dp < end; dp = MethodData::next_extra(dp)) {
switch(dp->tag()) {
case DataLayout::no_tag:
_saw_free_extra_data = true; // observed an empty slot (common case)
two_free_slots = (MethodData::next_extra(dp)->tag() == DataLayout::no_tag);
return NULL;
case DataLayout::arg_info_data_tag:
return NULL; // ArgInfoData is at the end of extra data section.
case DataLayout::bit_data_tag:
if (m == NULL && dp->bci() == bci) {
return new ciBitData(dp);
}
break;
case DataLayout::speculative_trap_data_tag: {
ciSpeculativeTrapData* data = new ciSpeculativeTrapData(dp);
if (m != NULL && data->method() == m && dp->bci() == bci) {
return data;
}
break;
}
default:
fatal(err_msg("bad tag = %d", dp->tag()));
}
}
return NULL;
}
ciProfileData* ciMethodData::bci_to_data(int bci, ciMethod* m) {
if (m == NULL) {
ciProfileData* data = data_before(bci);
for ( ; is_valid(data); data = next_data(data)) {
if (data->bci() == bci) {
set_hint_di(dp_to_di(data->dp()));
return data;
} else if (data->bci() > bci) {
break;
}
}
}
bool two_free_slots = false;
ciProfileData* result = bci_to_extra_data(bci, m, two_free_slots);
if (result != NULL) {
return result;
}
if (m != NULL && !two_free_slots) {
return bci_to_data(bci, NULL);
}
return NULL;
}
int ciMethodData::has_trap_at(ciProfileData* data, int reason) {
typedef Deoptimization::DeoptReason DR_t;
int per_bc_reason
= Deoptimization::reason_recorded_per_bytecode_if_any((DR_t) reason);
if (trap_count(reason) == 0) {
return 0;
} else if (per_bc_reason == Deoptimization::Reason_none) {
return -1;
} else if (data == NULL) {
if (_saw_free_extra_data)
return 0; // Q.E.D.
else
return -1; // bail with a conservative answer
} else {
return Deoptimization::trap_state_has_reason(data->trap_state(), per_bc_reason);
}
}
int ciMethodData::trap_recompiled_at(ciProfileData* data) {
if (data == NULL) {
return (_saw_free_extra_data? 0: -1); // (see previous method)
} else {
return Deoptimization::trap_state_is_recompiled(data->trap_state())? 1: 0;
}
}
void ciMethodData::clear_escape_info() {
VM_ENTRY_MARK;
MethodData* mdo = get_MethodData();
if (mdo != NULL) {
mdo->clear_escape_info();
ArgInfoData *aid = arg_info();
int arg_count = (aid == NULL) ? 0 : aid->number_of_args();
for (int i = 0; i < arg_count; i++) {
set_arg_modified(i, 0);
}
}
_eflags = _arg_local = _arg_stack = _arg_returned = 0;
}
void ciMethodData::update_escape_info() {
VM_ENTRY_MARK;
MethodData* mdo = get_MethodData();
if ( mdo != NULL) {
mdo->set_eflags(_eflags);
mdo->set_arg_local(_arg_local);
mdo->set_arg_stack(_arg_stack);
mdo->set_arg_returned(_arg_returned);
int arg_count = mdo->method()->size_of_parameters();
for (int i = 0; i < arg_count; i++) {
mdo->set_arg_modified(i, arg_modified(i));
}
}
}
void ciMethodData::set_compilation_stats(short loops, short blocks) {
VM_ENTRY_MARK;
MethodData* mdo = get_MethodData();
if (mdo != NULL) {
mdo->set_num_loops(loops);
mdo->set_num_blocks(blocks);
}
}
void ciMethodData::set_would_profile(bool p) {
VM_ENTRY_MARK;
MethodData* mdo = get_MethodData();
if (mdo != NULL) {
mdo->set_would_profile(p);
}
}
void ciMethodData::set_argument_type(int bci, int i, ciKlass* k) {
VM_ENTRY_MARK;
MethodData* mdo = get_MethodData();
if (mdo != NULL) {
ProfileData* data = mdo->bci_to_data(bci);
if (data != NULL) {
if (data->is_CallTypeData()) {
data->as_CallTypeData()->set_argument_type(i, k->get_Klass());
} else {
assert(data->is_VirtualCallTypeData(), "no arguments!");
data->as_VirtualCallTypeData()->set_argument_type(i, k->get_Klass());
}
}
}
}
void ciMethodData::set_parameter_type(int i, ciKlass* k) {
VM_ENTRY_MARK;
MethodData* mdo = get_MethodData();
if (mdo != NULL) {
mdo->parameters_type_data()->set_type(i, k->get_Klass());
}
}
void ciMethodData::set_return_type(int bci, ciKlass* k) {
VM_ENTRY_MARK;
MethodData* mdo = get_MethodData();
if (mdo != NULL) {
ProfileData* data = mdo->bci_to_data(bci);
if (data != NULL) {
if (data->is_CallTypeData()) {
data->as_CallTypeData()->set_return_type(k->get_Klass());
} else {
assert(data->is_VirtualCallTypeData(), "no arguments!");
data->as_VirtualCallTypeData()->set_return_type(k->get_Klass());
}
}
}
}
bool ciMethodData::has_escape_info() {
return eflag_set(MethodData::estimated);
}
void ciMethodData::set_eflag(MethodData::EscapeFlag f) {
set_bits(_eflags, f);
}
void ciMethodData::clear_eflag(MethodData::EscapeFlag f) {
clear_bits(_eflags, f);
}
bool ciMethodData::eflag_set(MethodData::EscapeFlag f) const {
return mask_bits(_eflags, f) != 0;
}
void ciMethodData::set_arg_local(int i) {
set_nth_bit(_arg_local, i);
}
void ciMethodData::set_arg_stack(int i) {
set_nth_bit(_arg_stack, i);
}
void ciMethodData::set_arg_returned(int i) {
set_nth_bit(_arg_returned, i);
}
void ciMethodData::set_arg_modified(int arg, uint val) {
ArgInfoData *aid = arg_info();
if (aid == NULL)
return;
assert(arg >= 0 && arg < aid->number_of_args(), "valid argument number");
aid->set_arg_modified(arg, val);
}
bool ciMethodData::is_arg_local(int i) const {
return is_set_nth_bit(_arg_local, i);
}
bool ciMethodData::is_arg_stack(int i) const {
return is_set_nth_bit(_arg_stack, i);
}
bool ciMethodData::is_arg_returned(int i) const {
return is_set_nth_bit(_arg_returned, i);
}
uint ciMethodData::arg_modified(int arg) const {
ArgInfoData *aid = arg_info();
if (aid == NULL)
return 0;
assert(arg >= 0 && arg < aid->number_of_args(), "valid argument number");
return aid->arg_modified(arg);
}
ByteSize ciMethodData::offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data) {
ByteSize data_offset = MethodData::data_offset();
int cell_offset = dp_to_di(data->dp());
int offset = in_bytes(data_offset) + cell_offset + in_bytes(slot_offset_in_data);
return in_ByteSize(offset);
}
ciArgInfoData *ciMethodData::arg_info() const {
DataLayout* dp = data_layout_at(data_size());
DataLayout* end = data_layout_at(data_size() + extra_data_size());
for (; dp < end; dp = MethodData::next_extra(dp)) {
if (dp->tag() == DataLayout::arg_info_data_tag)
return new ciArgInfoData(dp);
}
return NULL;
}
void ciMethodData::print_impl(outputStream* st) {
ciMetadata::print_impl(st);
}
void ciMethodData::dump_replay_data(outputStream* out) {
ResourceMark rm;
MethodData* mdo = get_MethodData();
Method* method = mdo->method();
Klass* holder = method->method_holder();
out->print("ciMethodData %s %s %s %d %d",
holder->name()->as_quoted_ascii(),
method->name()->as_quoted_ascii(),
method->signature()->as_quoted_ascii(),
_state,
current_mileage());
unsigned char* orig = (unsigned char*)&_orig;
int length = sizeof(_orig);
out->print(" orig %d", length);
for (int i = 0; i < length; i++) {
out->print(" %d", orig[i]);
}
int elements = data_size() / sizeof(intptr_t);
out->print(" data %d", elements);
for (int i = 0; i < elements; i++) {
#ifdef _LP64
out->print(" 0x%" FORMAT64_MODIFIER "x", data()[i]);
#else
out->print(" 0x%x", data()[i]);
#endif
}
int count = 0;
for (int round = 0; round < 2; round++) {
if (round == 1) out->print(" oops %d", count);
ProfileData* pdata = first_data();
for ( ; is_valid(pdata); pdata = next_data(pdata)) {
if (pdata->is_ReceiverTypeData()) {
ciReceiverTypeData* vdata = (ciReceiverTypeData*)pdata;
for (uint i = 0; i < vdata->row_limit(); i++) {
ciKlass* k = vdata->receiver(i);
if (k != NULL) {
if (round == 0) {
count++;
} else {
out->print(" %d %s", (int)(dp_to_di(vdata->dp() + in_bytes(vdata->receiver_offset(i))) / sizeof(intptr_t)), k->name()->as_quoted_ascii());
}
}
}
} else if (pdata->is_VirtualCallData()) {
ciVirtualCallData* vdata = (ciVirtualCallData*)pdata;
for (uint i = 0; i < vdata->row_limit(); i++) {
ciKlass* k = vdata->receiver(i);
if (k != NULL) {
if (round == 0) {
count++;
} else {
out->print(" %d %s", (int)(dp_to_di(vdata->dp() + in_bytes(vdata->receiver_offset(i))) / sizeof(intptr_t)), k->name()->as_quoted_ascii());
}
}
}
}
}
}
out->cr();
}
#ifndef PRODUCT
void ciMethodData::print() {
print_data_on(tty);
}
void ciMethodData::print_data_on(outputStream* st) {
ResourceMark rm;
ciProfileData* data;
for (data = first_data(); is_valid(data); data = next_data(data)) {
st->print("%d", dp_to_di(data->dp()));
st->fill_to(6);
data->print_data_on(st);
}
st->print_cr("--- Extra data:");
DataLayout* dp = data_layout_at(data_size());
DataLayout* end = data_layout_at(data_size() + extra_data_size());
for (;; dp = MethodData::next_extra(dp)) {
assert(dp < end, "moved past end of extra data");
switch (dp->tag()) {
case DataLayout::no_tag:
continue;
case DataLayout::bit_data_tag:
data = new BitData(dp);
break;
case DataLayout::arg_info_data_tag:
data = new ciArgInfoData(dp);
dp = end; // ArgInfoData is at the end of extra data section.
break;
default:
fatal(err_msg("unexpected tag %d", dp->tag()));
}
st->print("%d", dp_to_di(data->dp()));
st->fill_to(6);
data->print_data_on(st);
if (dp >= end) return;
}
}
void ciTypeEntries::print_ciklass(outputStream* st, intptr_t k) {
if (TypeEntries::is_type_none(k)) {
st->print("none");
} else if (TypeEntries::is_type_unknown(k)) {
st->print("unknown");
} else {
valid_ciklass(k)->print_name_on(st);
}
if (TypeEntries::was_null_seen(k)) {
st->print(" (null seen)");
}
}
void ciTypeStackSlotEntries::print_data_on(outputStream* st) const {
for (int i = 0; i < _number_of_entries; i++) {
_pd->tab(st);
st->print("%d: stack (%u) ", i, stack_slot(i));
print_ciklass(st, type(i));
st->cr();
}
}
void ciReturnTypeEntry::print_data_on(outputStream* st) const {
_pd->tab(st);
st->print("ret ");
print_ciklass(st, type());
st->cr();
}
void ciCallTypeData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "ciCallTypeData", extra);
if (has_arguments()) {
tab(st, true);
st->print("argument types");
args()->print_data_on(st);
}
if (has_return()) {
tab(st, true);
st->print("return type");
ret()->print_data_on(st);
}
}
void ciReceiverTypeData::print_receiver_data_on(outputStream* st) const {
uint row;
int entries = 0;
for (row = 0; row < row_limit(); row++) {
if (receiver(row) != NULL) entries++;
}
st->print_cr("count(%u) entries(%u)", count(), entries);
for (row = 0; row < row_limit(); row++) {
if (receiver(row) != NULL) {
tab(st);
receiver(row)->print_name_on(st);
st->print_cr("(%u)", receiver_count(row));
}
}
}
void ciReceiverTypeData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "ciReceiverTypeData", extra);
print_receiver_data_on(st);
}
void ciVirtualCallData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "ciVirtualCallData", extra);
rtd_super()->print_receiver_data_on(st);
}
void ciVirtualCallTypeData::print_data_on(outputStream* st, const char* extra) const {
print_shared(st, "ciVirtualCallTypeData", extra);
rtd_super()->print_receiver_data_on(st);
if (has_arguments()) {
tab(st, true);
st->print("argument types");
args()->print_data_on(st);
}
if (has_return()) {
tab(st, true);
st->print("return type");
ret()->print_data_on(st);
}
}
void ciParametersTypeData::print_data_on(outputStream* st, const char* extra) const {
st->print_cr("ciParametersTypeData");
parameters()->print_data_on(st);
}
void ciSpeculativeTrapData::print_data_on(outputStream* st, const char* extra) const {
st->print_cr("ciSpeculativeTrapData");
tab(st);
method()->print_short_name(st);
st->cr();
}
#endif
C:\hotspot-69087d08d473\src\share\vm/ci/ciMethodData.hpp
#ifndef SHARE_VM_CI_CIMETHODDATA_HPP
#define SHARE_VM_CI_CIMETHODDATA_HPP
#include "ci/ciClassList.hpp"
#include "ci/ciKlass.hpp"
#include "ci/ciObject.hpp"
#include "ci/ciUtilities.hpp"
#include "oops/methodData.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/deoptimization.hpp"
class ciBitData;
class ciCounterData;
class ciJumpData;
class ciReceiverTypeData;
class ciRetData;
class ciBranchData;
class ciArrayData;
class ciMultiBranchData;
class ciArgInfoData;
class ciCallTypeData;
class ciVirtualCallTypeData;
class ciParametersTypeData;
class ciSpeculativeTrapData;;
typedef ProfileData ciProfileData;
class ciBitData : public BitData {
public:
ciBitData(DataLayout* layout) : BitData(layout) {};
};
class ciCounterData : public CounterData {
public:
ciCounterData(DataLayout* layout) : CounterData(layout) {};
};
class ciJumpData : public JumpData {
public:
ciJumpData(DataLayout* layout) : JumpData(layout) {};
};
class ciTypeEntries {
protected:
static intptr_t translate_klass(intptr_t k) {
Klass* v = TypeEntries::valid_klass(k);
if (v != NULL) {
ciKlass* klass = CURRENT_ENV->get_klass(v);
CURRENT_ENV->ensure_metadata_alive(klass);
return with_status(klass, k);
}
return with_status(NULL, k);
}
public:
static ciKlass* valid_ciklass(intptr_t k) {
if (!TypeEntries::is_type_none(k) &&
!TypeEntries::is_type_unknown(k)) {
ciKlass* res = (ciKlass*)TypeEntries::klass_part(k);
assert(res != NULL, "invalid");
return res;
} else {
return NULL;
}
}
static intptr_t with_status(ciKlass* k, intptr_t in) {
return TypeEntries::with_status((intptr_t)k, in);
}
#ifndef PRODUCT
static void print_ciklass(outputStream* st, intptr_t k);
#endif
};
class ciTypeStackSlotEntries : public TypeStackSlotEntries, ciTypeEntries {
public:
void translate_type_data_from(const TypeStackSlotEntries* args);
ciKlass* valid_type(int i) const {
return valid_ciklass(type(i));
}
bool maybe_null(int i) const {
return was_null_seen(type(i));
}
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
#endif
};
class ciReturnTypeEntry : public ReturnTypeEntry, ciTypeEntries {
public:
void translate_type_data_from(const ReturnTypeEntry* ret);
ciKlass* valid_type() const {
return valid_ciklass(type());
}
bool maybe_null() const {
return was_null_seen(type());
}
#ifndef PRODUCT
void print_data_on(outputStream* st) const;
#endif
};
class ciCallTypeData : public CallTypeData {
public:
ciCallTypeData(DataLayout* layout) : CallTypeData(layout) {}
ciTypeStackSlotEntries* args() const { return (ciTypeStackSlotEntries*)CallTypeData::args(); }
ciReturnTypeEntry* ret() const { return (ciReturnTypeEntry*)CallTypeData::ret(); }
void translate_from(const ProfileData* data) {
if (has_arguments()) {
args()->translate_type_data_from(data->as_CallTypeData()->args());
}
if (has_return()) {
ret()->translate_type_data_from(data->as_CallTypeData()->ret());
}
}
intptr_t argument_type(int i) const {
assert(has_arguments(), "no arg type profiling data");
return args()->type(i);
}
ciKlass* valid_argument_type(int i) const {
assert(has_arguments(), "no arg type profiling data");
return args()->valid_type(i);
}
intptr_t return_type() const {
assert(has_return(), "no ret type profiling data");
return ret()->type();
}
ciKlass* valid_return_type() const {
assert(has_return(), "no ret type profiling data");
return ret()->valid_type();
}
bool argument_maybe_null(int i) const {
return args()->maybe_null(i);
}
bool return_maybe_null() const {
return ret()->maybe_null();
}
#ifndef PRODUCT
void print_data_on(outputStream* st, const char* extra) const;
#endif
};
class ciReceiverTypeData : public ReceiverTypeData {
public:
ciReceiverTypeData(DataLayout* layout) : ReceiverTypeData(layout) {};
void set_receiver(uint row, ciKlass* recv) {
assert((uint)row < row_limit(), "oob");
set_intptr_at(receiver0_offset + row * receiver_type_row_cell_count,
(intptr_t) recv);
}
ciKlass* receiver(uint row) const {
assert((uint)row < row_limit(), "oob");
ciKlass* recv = (ciKlass*)intptr_at(receiver0_offset + row * receiver_type_row_cell_count);
assert(recv == NULL || recv->is_klass(), "wrong type");
return recv;
}
virtual void translate_from(const ProfileData* data) {
translate_receiver_data_from(data);
}
void translate_receiver_data_from(const ProfileData* data);
#ifndef PRODUCT
void print_data_on(outputStream* st, const char* extra) const;
void print_receiver_data_on(outputStream* st) const;
#endif
};
class ciVirtualCallData : public VirtualCallData {
ciReceiverTypeData* rtd_super() const { return (ciReceiverTypeData*) this; }
public:
ciVirtualCallData(DataLayout* layout) : VirtualCallData(layout) {};
void set_receiver(uint row, ciKlass* recv) {
rtd_super()->set_receiver(row, recv);
}
ciKlass* receiver(uint row) {
return rtd_super()->receiver(row);
}
virtual void translate_from(const ProfileData* data) {
rtd_super()->translate_receiver_data_from(data);
}
#ifndef PRODUCT
void print_data_on(outputStream* st, const char* extra) const;
#endif
};
class ciVirtualCallTypeData : public VirtualCallTypeData {
private:
ciReceiverTypeData* rtd_super() const { return (ciReceiverTypeData*) this; }
public:
ciVirtualCallTypeData(DataLayout* layout) : VirtualCallTypeData(layout) {}
void set_receiver(uint row, ciKlass* recv) {
rtd_super()->set_receiver(row, recv);
}
ciKlass* receiver(uint row) const {
return rtd_super()->receiver(row);
}
ciTypeStackSlotEntries* args() const { return (ciTypeStackSlotEntries*)VirtualCallTypeData::args(); }
ciReturnTypeEntry* ret() const { return (ciReturnTypeEntry*)VirtualCallTypeData::ret(); }
virtual void translate_from(const ProfileData* data) {
rtd_super()->translate_receiver_data_from(data);
if (has_arguments()) {
args()->translate_type_data_from(data->as_VirtualCallTypeData()->args());
}
if (has_return()) {
ret()->translate_type_data_from(data->as_VirtualCallTypeData()->ret());
}
}
intptr_t argument_type(int i) const {
assert(has_arguments(), "no arg type profiling data");
return args()->type(i);
}
ciKlass* valid_argument_type(int i) const {
assert(has_arguments(), "no arg type profiling data");
return args()->valid_type(i);
}
intptr_t return_type() const {
assert(has_return(), "no ret type profiling data");
return ret()->type();
}
ciKlass* valid_return_type() const {
assert(has_return(), "no ret type profiling data");
return ret()->valid_type();
}
bool argument_maybe_null(int i) const {
return args()->maybe_null(i);
}
bool return_maybe_null() const {
return ret()->maybe_null();
}
#ifndef PRODUCT
void print_data_on(outputStream* st, const char* extra) const;
#endif
};
class ciRetData : public RetData {
public:
ciRetData(DataLayout* layout) : RetData(layout) {};
};
class ciBranchData : public BranchData {
public:
ciBranchData(DataLayout* layout) : BranchData(layout) {};
};
class ciArrayData : public ArrayData {
public:
ciArrayData(DataLayout* layout) : ArrayData(layout) {};
};
class ciMultiBranchData : public MultiBranchData {
public:
ciMultiBranchData(DataLayout* layout) : MultiBranchData(layout) {};
};
class ciArgInfoData : public ArgInfoData {
public:
ciArgInfoData(DataLayout* layout) : ArgInfoData(layout) {};
};
class ciParametersTypeData : public ParametersTypeData {
public:
ciParametersTypeData(DataLayout* layout) : ParametersTypeData(layout) {}
virtual void translate_from(const ProfileData* data) {
parameters()->translate_type_data_from(data->as_ParametersTypeData()->parameters());
}
ciTypeStackSlotEntries* parameters() const { return (ciTypeStackSlotEntries*)ParametersTypeData::parameters(); }
ciKlass* valid_parameter_type(int i) const {
return parameters()->valid_type(i);
}
bool parameter_maybe_null(int i) const {
return parameters()->maybe_null(i);
}
#ifndef PRODUCT
void print_data_on(outputStream* st, const char* extra) const;
#endif
};
class ciSpeculativeTrapData : public SpeculativeTrapData {
public:
ciSpeculativeTrapData(DataLayout* layout) : SpeculativeTrapData(layout) {}
virtual void translate_from(const ProfileData* data);
ciMethod* method() const {
return (ciMethod*)intptr_at(method_offset);
}
void set_method(ciMethod* m) {
set_intptr_at(method_offset, (intptr_t)m);
}
#ifndef PRODUCT
void print_data_on(outputStream* st, const char* extra) const;
#endif
};
class ciMethodData : public ciMetadata {
CI_PACKAGE_ACCESS
friend class ciReplay;
private:
int _data_size;
int _extra_data_size;
intptr_t* _data;
int _hint_di;
enum { empty_state, immature_state, mature_state };
u_char _state;
u_char _saw_free_extra_data;
intx _eflags; // flags on escape information
intx _arg_local; // bit set of non-escaping arguments
intx _arg_stack; // bit set of stack-allocatable arguments
intx _arg_returned; // bit set of returned arguments
int _current_mileage;
int _invocation_counter;
int _backedge_counter;
MethodData _orig;
DataLayout* _parameters;
ciMethodData(MethodData* md);
ciMethodData();
int data_size() const { return _data_size; }
int extra_data_size() const { return _extra_data_size; }
intptr_t * data() const { return _data; }
MethodData* get_MethodData() const {
return (MethodData*)_metadata;
}
const char* type_string() { return "ciMethodData"; }
void print_impl(outputStream* st);
DataLayout* data_layout_at(int data_index) const {
assert(data_index % sizeof(intptr_t) == 0, "unaligned");
return (DataLayout*) (((address)_data) + data_index);
}
bool out_of_bounds(int data_index) {
return data_index >= data_size();
}
int hint_di() const { return _hint_di; }
void set_hint_di(int di) {
assert(!out_of_bounds(di), "hint_di out of bounds");
_hint_di = di;
}
ciProfileData* data_before(int bci) {
if (data_size() == 0)
return NULL;
int hint = hint_di();
if (data_layout_at(hint)->bci() <= bci)
return data_at(hint);
return first_data();
}
int first_di() { return 0; }
ciArgInfoData *arg_info() const;
address data_base() const {
return (address) _data;
}
DataLayout* limit_data_position() const {
return (DataLayout*)((address)data_base() + _data_size);
}
void load_extra_data();
ciProfileData* bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots);
public:
bool is_method_data() const { return true; }
bool is_empty() { return _state == empty_state; }
bool is_mature() { return _state == mature_state; }
int creation_mileage() { return _orig.creation_mileage(); }
int current_mileage() { return _current_mileage; }
int invocation_count() { return _invocation_counter; }
int backedge_count() { return _backedge_counter; }
#if INCLUDE_RTM_OPT
int rtm_state() {
if (is_empty()) {
return NoRTM;
} else {
return get_MethodData()->rtm_state();
}
}
#endif
void set_would_profile(bool p);
void set_compilation_stats(short loops, short blocks);
void set_argument_type(int bci, int i, ciKlass* k);
void set_parameter_type(int i, ciKlass* k);
void set_return_type(int bci, ciKlass* k);
void load_data();
int dp_to_di(address dp) {
return dp - ((address)_data);
}
ciProfileData* data_at(int data_index);
ciProfileData* first_data() { return data_at(first_di()); }
ciProfileData* next_data(ciProfileData* current);
bool is_valid(ciProfileData* current) { return current != NULL; }
DataLayout* extra_data_base() const { return limit_data_position(); }
ciProfileData* bci_to_data(int bci, ciMethod* m = NULL);
uint overflow_trap_count() const {
return _orig.overflow_trap_count();
}
uint overflow_recompile_count() const {
return _orig.overflow_recompile_count();
}
uint decompile_count() const {
return _orig.decompile_count();
}
uint trap_count(int reason) const {
return _orig.trap_count(reason);
}
uint trap_reason_limit() const { return _orig.trap_reason_limit(); }
uint trap_count_limit() const { return _orig.trap_count_limit(); }
int has_trap_at(ciProfileData* data, int reason);
int has_trap_at(int bci, ciMethod* m, int reason) {
assert((m != NULL) == Deoptimization::reason_is_speculate(reason), "inconsistent method/reason");
return has_trap_at(bci_to_data(bci, m), reason);
}
int trap_recompiled_at(ciProfileData* data);
int trap_recompiled_at(int bci, ciMethod* m) {
return trap_recompiled_at(bci_to_data(bci, m));
}
void clear_escape_info();
bool has_escape_info();
void update_escape_info();
void set_eflag(MethodData::EscapeFlag f);
void clear_eflag(MethodData::EscapeFlag f);
bool eflag_set(MethodData::EscapeFlag f) const;
void set_arg_local(int i);
void set_arg_stack(int i);
void set_arg_returned(int i);
void set_arg_modified(int arg, uint val);
bool is_arg_local(int i) const;
bool is_arg_stack(int i) const;
bool is_arg_returned(int i) const;
uint arg_modified(int arg) const;
ciParametersTypeData* parameters_type_data() const {
return _parameters != NULL ? new ciParametersTypeData(_parameters) : NULL;
}
ByteSize offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data);
int byte_offset_of_slot(ciProfileData* data, ByteSize slot_offset_in_data) { return in_bytes(offset_of_slot(data, slot_offset_in_data)); }
#ifndef PRODUCT
void print();
void print_data_on(outputStream* st);
#endif
void dump_replay_data(outputStream* out);
};
#endif // SHARE_VM_CI_CIMETHODDATA_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciMethodHandle.cpp
#include "precompiled.hpp"
#include "ci/ciClassList.hpp"
#include "ci/ciMethodHandle.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/javaClasses.hpp"
ciMethod* ciMethodHandle::get_vmtarget() const {
VM_ENTRY_MARK;
oop form_oop = java_lang_invoke_MethodHandle::form(get_oop());
oop vmentry_oop = java_lang_invoke_LambdaForm::vmentry(form_oop);
Metadata* vmtarget = java_lang_invoke_MemberName::vmtarget(vmentry_oop);
if (vmtarget->is_method())
return CURRENT_ENV->get_method((Method*) vmtarget);
assert(false, "");
return NULL;
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciMethodHandle.hpp
#ifndef SHARE_VM_CI_CIMETHODHANDLE_HPP
#define SHARE_VM_CI_CIMETHODHANDLE_HPP
#include "ci/ciClassList.hpp"
#include "ci/ciInstance.hpp"
class ciMethodHandle : public ciInstance {
public:
ciMethodHandle(instanceHandle h_i) : ciInstance(h_i) {}
bool is_method_handle() const { return true; }
ciMethod* get_vmtarget() const;
};
#endif // SHARE_VM_CI_CIMETHODHANDLE_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciMethodType.hpp
#ifndef SHARE_VM_CI_CIMETHODTYPE_HPP
#define SHARE_VM_CI_CIMETHODTYPE_HPP
#include "ci/ciInstance.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/javaClasses.hpp"
class ciMethodType : public ciInstance {
private:
ciType* class_to_citype(oop klass_oop) const {
if (java_lang_Class::is_primitive(klass_oop)) {
BasicType bt = java_lang_Class::primitive_type(klass_oop);
return ciType::make(bt);
} else {
Klass* k = java_lang_Class::as_Klass(klass_oop);
return CURRENT_ENV->get_klass(k);
}
}
public:
ciMethodType(instanceHandle h_i) : ciInstance(h_i) {}
bool is_method_type() const { return true; }
ciType* rtype() const {
GUARDED_VM_ENTRY(
oop rtype = java_lang_invoke_MethodType::rtype(get_oop());
return class_to_citype(rtype);
)
}
int ptype_count() const {
GUARDED_VM_ENTRY(return java_lang_invoke_MethodType::ptype_count(get_oop());)
}
int ptype_slot_count() const {
GUARDED_VM_ENTRY(return java_lang_invoke_MethodType::ptype_slot_count(get_oop());)
}
ciType* ptype_at(int index) const {
GUARDED_VM_ENTRY(
oop ptype = java_lang_invoke_MethodType::ptype(get_oop(), index);
return class_to_citype(ptype);
)
}
};
#endif // SHARE_VM_CI_CIMETHODTYPE_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciNullObject.cpp
#include "precompiled.hpp"
#include "ci/ciNullObject.hpp"
void ciNullObject::print_impl(outputStream* st) {
ciObject::print_impl(st);
st->print(" unique");
}
ciNullObject* ciNullObject::make() {
return CURRENT_ENV->_null_object_instance->as_null_object();
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciNullObject.hpp
#ifndef SHARE_VM_CI_CINULLOBJECT_HPP
#define SHARE_VM_CI_CINULLOBJECT_HPP
#include "ci/ciClassList.hpp"
#include "ci/ciObject.hpp"
#include "ci/ciUtilities.hpp"
class ciNullObject : public ciObject {
CI_PACKAGE_ACCESS
private:
ciNullObject() : ciObject() {}
const char* type_string() { return "ciNullObject"; }
void print_impl(outputStream* st);
public:
bool is_java_object() { return true; }
bool is_null_object() const { return true; }
bool is_classless() const { return true; }
static ciNullObject* make();
};
#endif // SHARE_VM_CI_CINULLOBJECT_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciObjArray.cpp
#include "precompiled.hpp"
#include "ci/ciNullObject.hpp"
#include "ci/ciObjArray.hpp"
#include "ci/ciUtilities.hpp"
#include "oops/objArrayOop.hpp"
ciObject* ciObjArray::obj_at(int index) {
VM_ENTRY_MARK;
objArrayOop array = get_objArrayOop();
if (index < 0 || index >= array->length()) return NULL;
oop o = array->obj_at(index);
if (o == NULL) {
return ciNullObject::make();
} else {
return CURRENT_ENV->get_object(o);
}
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciObjArray.hpp
#ifndef SHARE_VM_CI_CIOBJARRAY_HPP
#define SHARE_VM_CI_CIOBJARRAY_HPP
#include "ci/ciArray.hpp"
#include "ci/ciClassList.hpp"
#include "oops/objArrayOop.hpp"
class ciObjArray : public ciArray {
CI_PACKAGE_ACCESS
protected:
ciObjArray(objArrayHandle h_o) : ciArray(h_o) {}
ciObjArray(ciKlass* klass, int len) : ciArray(klass, len) {}
objArrayOop get_objArrayOop() {
return (objArrayOop)get_oop();
}
const char* type_string() { return "ciObjArray"; }
public:
bool is_obj_array() { return true; }
ciObject* obj_at(int index);
};
#endif // SHARE_VM_CI_CIOBJARRAY_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciObjArrayKlass.cpp
#include "precompiled.hpp"
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciObjArrayKlass.hpp"
#include "ci/ciSymbol.hpp"
#include "ci/ciUtilities.hpp"
#include "oops/objArrayKlass.hpp"
ciObjArrayKlass::ciObjArrayKlass(KlassHandle h_k) : ciArrayKlass(h_k) {
assert(get_Klass()->oop_is_objArray(), "wrong type");
Klass* element_Klass = get_ObjArrayKlass()->bottom_klass();
_base_element_klass = CURRENT_ENV->get_klass(element_Klass);
assert(_base_element_klass->is_instance_klass() ||
_base_element_klass->is_type_array_klass(), "bad base klass");
if (dimension() == 1) {
_element_klass = _base_element_klass;
} else {
_element_klass = NULL;
}
if (!ciObjectFactory::is_initialized()) {
assert(_element_klass->is_java_lang_Object(), "only arrays of object are shared");
}
}
ciObjArrayKlass::ciObjArrayKlass(ciSymbol* array_name,
ciKlass* base_element_klass,
int dimension)
: ciArrayKlass(array_name,
dimension, T_OBJECT) {
_base_element_klass = base_element_klass;
assert(_base_element_klass->is_instance_klass() ||
_base_element_klass->is_type_array_klass(), "bad base klass");
if (dimension == 1) {
_element_klass = base_element_klass;
} else {
_element_klass = NULL;
}
}
ciKlass* ciObjArrayKlass::element_klass() {
if (_element_klass == NULL) {
assert(dimension() > 1, "_element_klass should not be NULL");
if (is_loaded()) {
VM_ENTRY_MARK;
Klass* element_Klass = get_ObjArrayKlass()->element_klass();
_element_klass = CURRENT_THREAD_ENV->get_klass(element_Klass);
} else {
VM_ENTRY_MARK;
_element_klass = CURRENT_THREAD_ENV->get_klass_by_name_impl(
this,
constantPoolHandle(),
construct_array_name(base_element_klass()->name(),
dimension() - 1),
false);
}
}
return _element_klass;
}
ciSymbol* ciObjArrayKlass::construct_array_name(ciSymbol* element_name,
int dimension) {
EXCEPTION_CONTEXT;
int element_len = element_name->utf8_length();
Symbol* base_name_sym = element_name->get_symbol();
char* name;
if (base_name_sym->byte_at(0) == '[' ||
(base_name_sym->byte_at(0) == 'L' && // watch package name 'Lxx'
base_name_sym->byte_at(element_len-1) == ';')) {
int new_len = element_len + dimension + 1; // for the ['s and '\0'
name = CURRENT_THREAD_ENV->name_buffer(new_len);
int pos = 0;
for ( ; pos < dimension; pos++) {
name[pos] = '[';
}
strncpy(name+pos, (char*)element_name->base(), element_len);
name[new_len-1] = '\0';
} else {
int new_len = 3 // for L, ;, and '\0'
+ dimension // for ['s
+ element_len;
name = CURRENT_THREAD_ENV->name_buffer(new_len);
int pos = 0;
for ( ; pos < dimension; pos++) {
name[pos] = '[';
}
name[pos++] = 'L';
strncpy(name+pos, (char*)element_name->base(), element_len);
name[new_len-2] = ';';
name[new_len-1] = '\0';
}
return ciSymbol::make(name);
}
ciObjArrayKlass* ciObjArrayKlass::make_impl(ciKlass* element_klass) {
if (element_klass->is_loaded()) {
EXCEPTION_CONTEXT;
Klass* array = element_klass->get_Klass()->array_klass(THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
CURRENT_THREAD_ENV->record_out_of_memory_failure();
return ciEnv::unloaded_ciobjarrayklass();
}
return CURRENT_THREAD_ENV->get_obj_array_klass(array);
}
ciSymbol* array_name = construct_array_name(element_klass->name(), 1);
if (array_name == ciEnv::unloaded_cisymbol()) {
return ciEnv::unloaded_ciobjarrayklass();
}
return
CURRENT_ENV->get_unloaded_klass(element_klass, array_name)
->as_obj_array_klass();
}
ciObjArrayKlass* ciObjArrayKlass::make(ciKlass* element_klass) {
GUARDED_VM_ENTRY(return make_impl(element_klass);)
}
ciKlass* ciObjArrayKlass::exact_klass() {
ciType* base = base_element_type();
if (base->is_instance_klass()) {
ciInstanceKlass* ik = base->as_instance_klass();
if (ik->exact_klass() != NULL) {
return this;
}
} else if (base->is_primitive_type()) {
return this;
}
return NULL;
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciObjArrayKlass.hpp
#ifndef SHARE_VM_CI_CIOBJARRAYKLASS_HPP
#define SHARE_VM_CI_CIOBJARRAYKLASS_HPP
#include "ci/ciArrayKlass.hpp"
class ciObjArrayKlass : public ciArrayKlass {
CI_PACKAGE_ACCESS
friend class ciEnv;
private:
ciKlass* _element_klass;
ciKlass* _base_element_klass;
protected:
ciObjArrayKlass(KlassHandle h_k);
ciObjArrayKlass(ciSymbol* array_name,
ciKlass* base_element_klass,
int dimension);
ObjArrayKlass* get_ObjArrayKlass() {
return (ObjArrayKlass*)get_Klass();
}
static ciObjArrayKlass* make_impl(ciKlass* element_klass);
static ciSymbol* construct_array_name(ciSymbol* element_name,
int dimension);
const char* type_string() { return "ciObjArrayKlass"; }
oop loader() { return _base_element_klass->loader(); }
jobject loader_handle() { return _base_element_klass->loader_handle(); }
oop protection_domain() { return _base_element_klass->protection_domain(); }
jobject protection_domain_handle() { return _base_element_klass->protection_domain_handle(); }
public:
ciKlass* element_klass();
ciKlass* base_element_klass() { return _base_element_klass; }
bool is_obj_array_klass() const { return true; }
static ciObjArrayKlass* make(ciKlass* element_klass);
virtual ciKlass* exact_klass();
};
#endif // SHARE_VM_CI_CIOBJARRAYKLASS_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciObject.cpp
#include "precompiled.hpp"
#include "ci/ciObject.hpp"
#include "ci/ciUtilities.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "oops/oop.inline2.hpp"
ciObject::ciObject(oop o) {
ASSERT_IN_VM;
if (ciObjectFactory::is_initialized()) {
_handle = JNIHandles::make_local(o);
} else {
_handle = JNIHandles::make_global(o);
}
_klass = NULL;
init_flags_from(o);
}
ciObject::ciObject(Handle h) {
ASSERT_IN_VM;
if (ciObjectFactory::is_initialized()) {
_handle = JNIHandles::make_local(h());
} else {
_handle = JNIHandles::make_global(h);
}
_klass = NULL;
init_flags_from(h());
}
ciObject::ciObject(ciKlass* klass) {
ASSERT_IN_VM;
assert(klass != NULL, "must supply klass");
_handle = NULL;
_klass = klass;
}
ciObject::ciObject() {
ASSERT_IN_VM;
_handle = NULL;
_klass = NULL;
}
ciKlass* ciObject::klass() {
if (_klass == NULL) {
if (_handle == NULL) {
assert(is_null_object(), "must be null object");
ShouldNotReachHere();
return NULL;
}
GUARDED_VM_ENTRY(
oop o = get_oop();
_klass = CURRENT_ENV->get_klass(o->klass());
);
}
return _klass;
}
bool ciObject::equals(ciObject* obj) {
return (this == obj);
}
int ciObject::hash() {
return ident() * 31;
}
jobject ciObject::constant_encoding() {
assert(is_null_object() || handle() != NULL, "cannot embed null pointer");
assert(can_be_constant(), "oop must be NULL or perm");
return handle();
}
bool ciObject::can_be_constant() {
if (ScavengeRootsInCode >= 1) return true; // now everybody can encode as a constant
return handle() == NULL;
}
bool ciObject::should_be_constant() {
if (ScavengeRootsInCode >= 2) return true; // force everybody to be a constant
if (is_null_object()) return true;
ciEnv* env = CURRENT_ENV;
if (klass() == env->String_klass() || klass() == env->Class_klass()) {
return true;
}
if (EnableInvokeDynamic &&
(klass()->is_subclass_of(env->MethodHandle_klass()) ||
klass()->is_subclass_of(env->CallSite_klass()))) {
assert(ScavengeRootsInCode >= 1, "must be");
return true;
}
return handle() == NULL;
}
void ciObject::init_flags_from(oop x) {
int flags = 0;
if (x != NULL) {
assert(Universe::heap()->is_in_reserved(x), "must be");
if (x->is_scavengable())
flags |= SCAVENGABLE_FLAG;
}
_ident |= flags;
}
void ciObject::print(outputStream* st) {
st->print("<%s", type_string());
GUARDED_VM_ENTRY(print_impl(st);)
st->print(" ident=%d %s address=" INTPTR_FORMAT ">", ident(),
is_scavengable() ? "SCAVENGABLE" : "",
p2i((address)this));
}
void ciObject::print_oop(outputStream* st) {
if (is_null_object()) {
st->print_cr("NULL");
} else if (!is_loaded()) {
st->print_cr("UNLOADED");
} else {
GUARDED_VM_ENTRY(get_oop()->print_on(st);)
}
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciObject.hpp
#ifndef SHARE_VM_CI_CIOBJECT_HPP
#define SHARE_VM_CI_CIOBJECT_HPP
#include "ci/ciBaseObject.hpp"
#include "ci/ciClassList.hpp"
#include "memory/allocation.hpp"
#include "runtime/handles.hpp"
#include "runtime/jniHandles.hpp"
class ciObject : public ciBaseObject {
CI_PACKAGE_ACCESS
friend class ciEnv;
private:
jobject _handle;
ciKlass* _klass;
protected:
ciObject();
ciObject(oop o);
ciObject(Handle h);
ciObject(ciKlass* klass);
jobject handle() const { return _handle; }
oop get_oop() const {
assert(_handle != NULL, "null oop");
return JNIHandles::resolve_non_null(_handle);
}
void init_flags_from(oop x);
virtual void print_impl(outputStream* st) {}
virtual const char* type_string() { return "ciObject"; }
public:
ciKlass* klass();
bool equals(ciObject* obj);
int hash();
bool can_be_constant();
bool should_be_constant();
bool is_scavengable() { return (_ident & SCAVENGABLE_FLAG) != 0; }
jobject constant_encoding();
virtual bool is_object() const { return true; }
virtual bool is_null_object() const { return false; }
virtual bool is_call_site() const { return false; }
virtual bool is_cpcache() const { return false; }
virtual bool is_instance() { return false; }
virtual bool is_member_name() const { return false; }
virtual bool is_method_handle() const { return false; }
virtual bool is_method_type() const { return false; }
virtual bool is_array() { return false; }
virtual bool is_obj_array() { return false; }
virtual bool is_type_array() { return false; }
virtual bool is_classless() const { return false; }
virtual void dump_replay_data(outputStream* st) { /* do nothing */ }
bool is_loaded() const {
return handle() != NULL || is_classless();
}
ciNullObject* as_null_object() {
assert(is_null_object(), "bad cast");
return (ciNullObject*)this;
}
ciCallSite* as_call_site() {
assert(is_call_site(), "bad cast");
return (ciCallSite*)this;
}
ciInstance* as_instance() {
assert(is_instance(), "bad cast");
return (ciInstance*)this;
}
ciMemberName* as_member_name() {
assert(is_member_name(), "bad cast");
return (ciMemberName*)this;
}
ciMethodHandle* as_method_handle() {
assert(is_method_handle(), "bad cast");
return (ciMethodHandle*)this;
}
ciMethodType* as_method_type() {
assert(is_method_type(), "bad cast");
return (ciMethodType*)this;
}
ciArray* as_array() {
assert(is_array(), "bad cast");
return (ciArray*)this;
}
ciObjArray* as_obj_array() {
assert(is_obj_array(), "bad cast");
return (ciObjArray*)this;
}
ciTypeArray* as_type_array() {
assert(is_type_array(), "bad cast");
return (ciTypeArray*)this;
}
void print(outputStream* st);
void print() { print(tty); } // GDB cannot handle default arguments
void print_oop(outputStream* st = tty);
};
#endif // SHARE_VM_CI_CIOBJECT_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciObjectFactory.cpp
#include "precompiled.hpp"
#include "ci/ciCallSite.hpp"
#include "ci/ciInstance.hpp"
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciMemberName.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciMethodData.hpp"
#include "ci/ciMethodHandle.hpp"
#include "ci/ciMethodType.hpp"
#include "ci/ciNullObject.hpp"
#include "ci/ciObjArray.hpp"
#include "ci/ciObjArrayKlass.hpp"
#include "ci/ciObject.hpp"
#include "ci/ciObjectFactory.hpp"
#include "ci/ciSymbol.hpp"
#include "ci/ciTypeArray.hpp"
#include "ci/ciTypeArrayKlass.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/systemDictionary.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/oop.inline2.hpp"
#include "runtime/fieldType.hpp"
#if INCLUDE_ALL_GCS
# include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
#endif
GrowableArray<ciMetadata*>* ciObjectFactory::_shared_ci_metadata = NULL;
ciSymbol* ciObjectFactory::_shared_ci_symbols[vmSymbols::SID_LIMIT];
int ciObjectFactory::_shared_ident_limit = 0;
volatile bool ciObjectFactory::_initialized = false;
ciObjectFactory::ciObjectFactory(Arena* arena,
int expected_size) {
for (int i = 0; i < NON_PERM_BUCKETS; i++) {
_non_perm_bucket[i] = NULL;
}
_non_perm_count = 0;
_next_ident = _shared_ident_limit;
_arena = arena;
_ci_metadata = new (arena) GrowableArray<ciMetadata*>(arena, expected_size, 0, NULL);
if (_shared_ci_metadata != NULL) {
_ci_metadata->appendAll(_shared_ci_metadata);
}
_unloaded_methods = new (arena) GrowableArray<ciMethod*>(arena, 4, 0, NULL);
_unloaded_klasses = new (arena) GrowableArray<ciKlass*>(arena, 8, 0, NULL);
_unloaded_instances = new (arena) GrowableArray<ciInstance*>(arena, 4, 0, NULL);
_return_addresses =
new (arena) GrowableArray<ciReturnAddress*>(arena, 8, 0, NULL);
_symbols = new (arena) GrowableArray<ciSymbol*>(arena, 100, 0, NULL);
}
void ciObjectFactory::initialize() {
ASSERT_IN_VM;
JavaThread* thread = JavaThread::current();
HandleMark handle_mark(thread);
Arena* arena = new (mtCompiler) Arena(mtCompiler);
ciEnv initial(arena);
ciEnv* env = ciEnv::current();
env->_factory->init_shared_objects();
_initialized = true;
}
void ciObjectFactory::init_shared_objects() {
_next_ident = 1; // start numbering CI objects at 1
{
int i;
for (i = vmSymbols::FIRST_SID; i < vmSymbols::SID_LIMIT; i++) {
Symbol* vmsym = vmSymbols::symbol_at((vmSymbols::SID) i);
assert(vmSymbols::find_sid(vmsym) == i, "1-1 mapping");
ciSymbol* sym = new (_arena) ciSymbol(vmsym, (vmSymbols::SID) i);
init_ident_of(sym);
_shared_ci_symbols[i] = sym;
}
#ifdef ASSERT
for (i = vmSymbols::FIRST_SID; i < vmSymbols::SID_LIMIT; i++) {
Symbol* vmsym = vmSymbols::symbol_at((vmSymbols::SID) i);
ciSymbol* sym = vm_symbol_at((vmSymbols::SID) i);
assert(sym->get_symbol() == vmsym, "oop must match");
}
assert(ciSymbol::void_class_signature()->get_symbol() == vmSymbols::void_class_signature(), "spot check");
#endif
}
_ci_metadata = new (_arena) GrowableArray<ciMetadata*>(_arena, 64, 0, NULL);
for (int i = T_BOOLEAN; i <= T_CONFLICT; i++) {
BasicType t = (BasicType)i;
if (type2name(t) != NULL && t != T_OBJECT && t != T_ARRAY && t != T_NARROWOOP && t != T_NARROWKLASS) {
ciType::_basic_types[t] = new (_arena) ciType(t);
init_ident_of(ciType::_basic_types[t]);
}
}
ciEnv::_null_object_instance = new (_arena) ciNullObject();
init_ident_of(ciEnv::_null_object_instance);
#define WK_KLASS_DEFN(name, ignore_s, opt) \
if (SystemDictionary::name() != NULL) \
ciEnv::_##name = get_metadata(SystemDictionary::name())->as_instance_klass();
WK_KLASSES_DO(WK_KLASS_DEFN)
#undef WK_KLASS_DEFN
for (int len = -1; len != _ci_metadata->length(); ) {
len = _ci_metadata->length();
for (int i2 = 0; i2 < len; i2++) {
ciMetadata* obj = _ci_metadata->at(i2);
assert (obj->is_metadata(), "what else would it be?");
if (obj->is_loaded() && obj->is_instance_klass()) {
obj->as_instance_klass()->compute_nonstatic_fields();
}
}
}
ciEnv::_unloaded_cisymbol = ciObjectFactory::get_symbol(vmSymbols::dummy_symbol());
ciEnv::_unloaded_ciinstance_klass = new (_arena) ciInstanceKlass(ciEnv::_unloaded_cisymbol, NULL, NULL);
init_ident_of(ciEnv::_unloaded_ciinstance_klass);
ciEnv::_unloaded_ciobjarrayklass = new (_arena) ciObjArrayKlass(ciEnv::_unloaded_cisymbol, ciEnv::_unloaded_ciinstance_klass, 1);
init_ident_of(ciEnv::_unloaded_ciobjarrayklass);
assert(ciEnv::_unloaded_ciobjarrayklass->is_obj_array_klass(), "just checking");
get_metadata(Universe::boolArrayKlassObj());
get_metadata(Universe::charArrayKlassObj());
get_metadata(Universe::singleArrayKlassObj());
get_metadata(Universe::doubleArrayKlassObj());
get_metadata(Universe::byteArrayKlassObj());
get_metadata(Universe::shortArrayKlassObj());
get_metadata(Universe::intArrayKlassObj());
get_metadata(Universe::longArrayKlassObj());
assert(_non_perm_count == 0, "no shared non-perm objects");
_shared_ident_limit = _next_ident;
_shared_ci_metadata = _ci_metadata;
}
ciSymbol* ciObjectFactory::get_symbol(Symbol* key) {
vmSymbols::SID sid = vmSymbols::find_sid(key);
if (sid != vmSymbols::NO_SID) {
return vm_symbol_at(sid);
}
assert(vmSymbols::find_sid(key) == vmSymbols::NO_SID, "");
ciSymbol* s = new (arena()) ciSymbol(key, vmSymbols::NO_SID);
_symbols->push(s);
return s;
}
void ciObjectFactory::remove_symbols() {
for (int i = 0; i < _symbols->length(); i++) {
ciSymbol* s = _symbols->at(i);
s->get_symbol()->decrement_refcount();
}
}
ciObject* ciObjectFactory::get(oop key) {
ASSERT_IN_VM;
assert(Universe::heap()->is_in_reserved(key), "must be");
NonPermObject* &bucket = find_non_perm(key);
if (bucket != NULL) {
return bucket->object();
}
Handle keyHandle(key);
ciObject* new_object = create_new_object(keyHandle());
assert(keyHandle() == new_object->get_oop(), "must be properly recorded");
init_ident_of(new_object);
assert(Universe::heap()->is_in_reserved(new_object->get_oop()), "must be");
insert_non_perm(bucket, keyHandle(), new_object);
return new_object;
}
ciMetadata* ciObjectFactory::get_metadata(Metadata* key) {
ASSERT_IN_VM;
#ifdef ASSERT
if (CIObjectFactoryVerify) {
Metadata* last = NULL;
for (int j = 0; j< _ci_metadata->length(); j++) {
Metadata* o = _ci_metadata->at(j)->constant_encoding();
assert(last < o, "out of order");
last = o;
}
}
#endif // ASSERT
int len = _ci_metadata->length();
int index = find(key, _ci_metadata);
#ifdef ASSERT
if (CIObjectFactoryVerify) {
for (int i=0; i<_ci_metadata->length(); i++) {
if (_ci_metadata->at(i)->constant_encoding() == key) {
assert(index == i, " bad lookup");
}
}
}
#endif
if (!is_found_at(index, key, _ci_metadata)) {
ciMetadata* new_object = create_new_metadata(key);
init_ident_of(new_object);
assert(new_object->is_metadata(), "must be");
if (len != _ci_metadata->length()) {
index = find(key, _ci_metadata);
}
assert(!is_found_at(index, key, _ci_metadata), "no double insert");
insert(index, new_object, _ci_metadata);
return new_object;
}
return _ci_metadata->at(index)->as_metadata();
}
ciObject* ciObjectFactory::create_new_object(oop o) {
EXCEPTION_CONTEXT;
if (o->is_instance()) {
instanceHandle h_i(THREAD, (instanceOop)o);
if (java_lang_invoke_CallSite::is_instance(o))
return new (arena()) ciCallSite(h_i);
else if (java_lang_invoke_MemberName::is_instance(o))
return new (arena()) ciMemberName(h_i);
else if (java_lang_invoke_MethodHandle::is_instance(o))
return new (arena()) ciMethodHandle(h_i);
else if (java_lang_invoke_MethodType::is_instance(o))
return new (arena()) ciMethodType(h_i);
else
return new (arena()) ciInstance(h_i);
} else if (o->is_objArray()) {
objArrayHandle h_oa(THREAD, (objArrayOop)o);
return new (arena()) ciObjArray(h_oa);
} else if (o->is_typeArray()) {
typeArrayHandle h_ta(THREAD, (typeArrayOop)o);
return new (arena()) ciTypeArray(h_ta);
}
ShouldNotReachHere();
return NULL;
}
ciMetadata* ciObjectFactory::create_new_metadata(Metadata* o) {
EXCEPTION_CONTEXT;
if (_initialized && o->is_klass()) {
Klass* holder = ((Klass*)o);
if (holder->oop_is_instance() && InstanceKlass::cast(holder)->is_anonymous()) {
ciObject* h = get(holder->klass_holder());
}
}
if (o->is_klass()) {
KlassHandle h_k(THREAD, (Klass*)o);
Klass* k = (Klass*)o;
if (k->oop_is_instance()) {
return new (arena()) ciInstanceKlass(h_k);
} else if (k->oop_is_objArray()) {
return new (arena()) ciObjArrayKlass(h_k);
} else if (k->oop_is_typeArray()) {
return new (arena()) ciTypeArrayKlass(h_k);
}
} else if (o->is_method()) {
methodHandle h_m(THREAD, (Method*)o);
ciEnv *env = CURRENT_THREAD_ENV;
ciInstanceKlass* holder = env->get_instance_klass(h_m()->method_holder());
return new (arena()) ciMethod(h_m, holder);
} else if (o->is_methodData()) {
methodHandle h_m(THREAD, ((MethodData*)o)->method());
return new (arena()) ciMethodData((MethodData*)o);
}
ShouldNotReachHere();
return NULL;
}
void ciObjectFactory::ensure_metadata_alive(ciMetadata* m) {
ASSERT_IN_VM; // We're handling raw oops here.
#if INCLUDE_ALL_GCS
if (!UseG1GC) {
return;
}
Klass* metadata_owner_klass;
if (m->is_klass()) {
metadata_owner_klass = m->as_klass()->get_Klass();
} else if (m->is_method()) {
metadata_owner_klass = m->as_method()->get_Method()->constants()->pool_holder();
} else {
fatal("Not implemented for other types of metadata");
return;
}
oop metadata_holder = metadata_owner_klass->klass_holder();
if (metadata_holder != NULL) {
G1SATBCardTableModRefBS::enqueue(metadata_holder);
}
#endif
}
ciMethod* ciObjectFactory::get_unloaded_method(ciInstanceKlass* holder,
ciSymbol* name,
ciSymbol* signature,
ciInstanceKlass* accessor) {
ciSignature* that = NULL;
for (int i = 0; i < _unloaded_methods->length(); i++) {
ciMethod* entry = _unloaded_methods->at(i);
if (entry->holder()->equals(holder) &&
entry->name()->equals(name) &&
entry->signature()->as_symbol()->equals(signature)) {
if (entry->signature()->accessing_klass() == accessor) {
return entry;
} else {
if (that == NULL) that = new (arena()) ciSignature(accessor, constantPoolHandle(), signature);
if (entry->signature()->equals(that)) {
return entry;
}
}
}
}
ciMethod* new_method = new (arena()) ciMethod(holder, name, signature, accessor);
init_ident_of(new_method);
_unloaded_methods->append(new_method);
return new_method;
}
ciKlass* ciObjectFactory::get_unloaded_klass(ciKlass* accessing_klass,
ciSymbol* name,
bool create_if_not_found) {
EXCEPTION_CONTEXT;
oop loader = NULL;
oop domain = NULL;
if (accessing_klass != NULL) {
loader = accessing_klass->loader();
domain = accessing_klass->protection_domain();
}
for (int i=0; i<_unloaded_klasses->length(); i++) {
ciKlass* entry = _unloaded_klasses->at(i);
if (entry->name()->equals(name) &&
entry->loader() == loader &&
entry->protection_domain() == domain) {
return entry;
}
}
if (!create_if_not_found)
return NULL;
ciKlass* new_klass = NULL;
if (name->byte_at(0) == '[') {
FieldArrayInfo fd;
BasicType element_type = FieldType::get_array_info(name->get_symbol(),
fd, THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
CURRENT_THREAD_ENV->record_out_of_memory_failure();
return ciEnv::_unloaded_ciobjarrayklass;
}
int dimension = fd.dimension();
assert(element_type != T_ARRAY, "unsuccessful decomposition");
ciKlass* element_klass = NULL;
if (element_type == T_OBJECT) {
ciEnv *env = CURRENT_THREAD_ENV;
ciSymbol* ci_name = env->get_symbol(fd.object_key());
element_klass =
env->get_klass_by_name(accessing_klass, ci_name, false)->as_instance_klass();
} else {
assert(dimension > 1, "one dimensional type arrays are always loaded.");
dimension--;
element_klass = ciTypeArrayKlass::make(element_type);
}
new_klass = new (arena()) ciObjArrayKlass(name, element_klass, dimension);
} else {
jobject loader_handle = NULL;
jobject domain_handle = NULL;
if (accessing_klass != NULL) {
loader_handle = accessing_klass->loader_handle();
domain_handle = accessing_klass->protection_domain_handle();
}
new_klass = new (arena()) ciInstanceKlass(name, loader_handle, domain_handle);
}
init_ident_of(new_klass);
_unloaded_klasses->append(new_klass);
return new_klass;
}
ciInstance* ciObjectFactory::get_unloaded_instance(ciInstanceKlass* instance_klass) {
for (int i=0; i<_unloaded_instances->length(); i++) {
ciInstance* entry = _unloaded_instances->at(i);
if (entry->klass()->equals(instance_klass)) {
return entry;
}
}
ciInstance* new_instance = new (arena()) ciInstance(instance_klass);
init_ident_of(new_instance);
_unloaded_instances->append(new_instance);
assert(!new_instance->is_loaded(), "");
assert(new_instance->klass() == instance_klass, "");
return new_instance;
}
ciInstance* ciObjectFactory::get_unloaded_klass_mirror(ciKlass* type) {
assert(ciEnv::_Class_klass != NULL, "");
return get_unloaded_instance(ciEnv::_Class_klass->as_instance_klass());
}
ciInstance* ciObjectFactory::get_unloaded_method_handle_constant(ciKlass* holder,
ciSymbol* name,
ciSymbol* signature,
int ref_kind) {
if (ciEnv::_MethodHandle_klass == NULL) return NULL;
return get_unloaded_instance(ciEnv::_MethodHandle_klass->as_instance_klass());
}
ciInstance* ciObjectFactory::get_unloaded_method_type_constant(ciSymbol* signature) {
if (ciEnv::_MethodType_klass == NULL) return NULL;
return get_unloaded_instance(ciEnv::_MethodType_klass->as_instance_klass());
}
ciInstance* ciObjectFactory::get_unloaded_object_constant() {
if (ciEnv::_Object_klass == NULL) return NULL;
return get_unloaded_instance(ciEnv::_Object_klass->as_instance_klass());
}
ciMethodData* ciObjectFactory::get_empty_methodData() {
ciMethodData* new_methodData = new (arena()) ciMethodData();
init_ident_of(new_methodData);
return new_methodData;
}
ciReturnAddress* ciObjectFactory::get_return_address(int bci) {
for (int i=0; i<_return_addresses->length(); i++) {
ciReturnAddress* entry = _return_addresses->at(i);
if (entry->bci() == bci) {
return entry;
}
}
ciReturnAddress* new_ret_addr = new (arena()) ciReturnAddress(bci);
init_ident_of(new_ret_addr);
_return_addresses->append(new_ret_addr);
return new_ret_addr;
}
void ciObjectFactory::init_ident_of(ciBaseObject* obj) {
obj->set_ident(_next_ident++);
}
int ciObjectFactory::find(Metadata* key, GrowableArray<ciMetadata*>* objects) {
int min = 0;
int max = objects->length()-1;
while (max >= min) {
int mid = (max + min) / 2;
Metadata* value = objects->at(mid)->constant_encoding();
if (value < key) {
min = mid + 1;
} else if (value > key) {
max = mid - 1;
} else {
return mid;
}
}
return min;
}
bool ciObjectFactory::is_found_at(int index, Metadata* key, GrowableArray<ciMetadata*>* objects) {
return (index < objects->length() &&
objects->at(index)->constant_encoding() == key);
}
void ciObjectFactory::insert(int index, ciMetadata* obj, GrowableArray<ciMetadata*>* objects) {
int len = objects->length();
if (len == index) {
objects->append(obj);
} else {
objects->append(objects->at(len-1));
int pos;
for (pos = len-2; pos >= index; pos--) {
objects->at_put(pos+1,objects->at(pos));
}
objects->at_put(index, obj);
}
}
static ciObjectFactory::NonPermObject* emptyBucket = NULL;
ciObjectFactory::NonPermObject* &ciObjectFactory::find_non_perm(oop key) {
assert(Universe::heap()->is_in_reserved(key), "must be");
ciMetadata* klass = get_metadata(key->klass());
NonPermObject* *bp = &_non_perm_bucket[(unsigned) klass->hash() % NON_PERM_BUCKETS];
for (NonPermObject* p; (p = (*bp)) != NULL; bp = &p->next()) {
if (is_equal(p, key)) break;
}
return (*bp);
}
inline ciObjectFactory::NonPermObject::NonPermObject(ciObjectFactory::NonPermObject* &bucket, oop key, ciObject* object) {
assert(ciObjectFactory::is_initialized(), "");
_object = object;
_next = bucket;
bucket = this;
}
void ciObjectFactory::insert_non_perm(ciObjectFactory::NonPermObject* &where, oop key, ciObject* obj) {
assert(Universe::heap()->is_in_reserved_or_null(key), "must be");
assert(&where != &emptyBucket, "must not try to fill empty bucket");
NonPermObject* p = new (arena()) NonPermObject(where, key, obj);
assert(where == p && is_equal(p, key) && p->object() == obj, "entry must match");
assert(find_non_perm(key) == p, "must find the same spot");
++_non_perm_count;
}
ciSymbol* ciObjectFactory::vm_symbol_at(int index) {
assert(index >= vmSymbols::FIRST_SID && index < vmSymbols::SID_LIMIT, "oob");
return _shared_ci_symbols[index];
}
void ciObjectFactory::metadata_do(void f(Metadata*)) {
if (_ci_metadata == NULL) return;
for (int j = 0; j< _ci_metadata->length(); j++) {
Metadata* o = _ci_metadata->at(j)->constant_encoding();
f(o);
}
}
void ciObjectFactory::print_contents_impl() {
int len = _ci_metadata->length();
tty->print_cr("ciObjectFactory (%d) meta data contents:", len);
for (int i=0; i<len; i++) {
_ci_metadata->at(i)->print();
tty->cr();
}
}
void ciObjectFactory::print_contents() {
print();
tty->cr();
GUARDED_VM_ENTRY(print_contents_impl();)
}
void ciObjectFactory::print() {
tty->print("<ciObjectFactory oops=%d metadata=%d unloaded_methods=%d unloaded_instances=%d unloaded_klasses=%d>",
_non_perm_count, _ci_metadata->length(), _unloaded_methods->length(),
_unloaded_instances->length(),
_unloaded_klasses->length());
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciObjectFactory.hpp
#ifndef SHARE_VM_CI_CIOBJECTFACTORY_HPP
#define SHARE_VM_CI_CIOBJECTFACTORY_HPP
#include "ci/ciClassList.hpp"
#include "ci/ciObject.hpp"
#include "utilities/growableArray.hpp"
class ciObjectFactory : public ResourceObj {
friend class VMStructs;
friend class ciEnv;
private:
static volatile bool _initialized;
static GrowableArray<ciMetadata*>* _shared_ci_metadata;
static ciSymbol* _shared_ci_symbols[];
static int _shared_ident_limit;
Arena* _arena;
GrowableArray<ciMetadata*>* _ci_metadata;
GrowableArray<ciMethod*>* _unloaded_methods;
GrowableArray<ciKlass*>* _unloaded_klasses;
GrowableArray<ciInstance*>* _unloaded_instances;
GrowableArray<ciReturnAddress*>* _return_addresses;
GrowableArray<ciSymbol*>* _symbols; // keep list of symbols created
int _next_ident;
public:
struct NonPermObject : public ResourceObj {
ciObject* _object;
NonPermObject* _next;
inline NonPermObject(NonPermObject* &bucket, oop key, ciObject* object);
ciObject* object() { return _object; }
NonPermObject* &next() { return _next; }
};
private:
enum { NON_PERM_BUCKETS = 61 };
NonPermObject* _non_perm_bucket[NON_PERM_BUCKETS];
int _non_perm_count;
int find(Metadata* key, GrowableArray<ciMetadata*>* objects);
bool is_found_at(int index, Metadata* key, GrowableArray<ciMetadata*>* objects);
void insert(int index, ciMetadata* obj, GrowableArray<ciMetadata*>* objects);
ciObject* create_new_object(oop o);
ciMetadata* create_new_metadata(Metadata* o);
void ensure_metadata_alive(ciMetadata* m);
static bool is_equal(NonPermObject* p, oop key) {
return p->object()->get_oop() == key;
}
NonPermObject* &find_non_perm(oop key);
void insert_non_perm(NonPermObject* &where, oop key, ciObject* obj);
void init_ident_of(ciBaseObject* obj);
Arena* arena() { return _arena; }
void print_contents_impl();
ciInstance* get_unloaded_instance(ciInstanceKlass* klass);
public:
static bool is_initialized() { return _initialized; }
static void initialize();
void init_shared_objects();
void remove_symbols();
ciObjectFactory(Arena* arena, int expected_size);
ciObject* get(oop key);
ciMetadata* get_metadata(Metadata* key);
ciSymbol* get_symbol(Symbol* key);
static ciSymbol* vm_symbol_at(int index);
ciMethod* get_unloaded_method(ciInstanceKlass* holder,
ciSymbol* name,
ciSymbol* signature,
ciInstanceKlass* accessor);
ciKlass* get_unloaded_klass(ciKlass* accessing_klass,
ciSymbol* name,
bool create_if_not_found);
ciInstance* get_unloaded_klass_mirror(ciKlass* type);
ciInstance* get_unloaded_method_handle_constant(ciKlass* holder,
ciSymbol* name,
ciSymbol* signature,
int ref_kind);
ciInstance* get_unloaded_method_type_constant(ciSymbol* signature);
ciInstance* get_unloaded_object_constant();
ciMethodData* get_empty_methodData();
ciReturnAddress* get_return_address(int bci);
GrowableArray<ciMetadata*>* get_ci_metadata() const { return _ci_metadata; }
void metadata_do(void f(Metadata*));
void print_contents();
void print();
};
#endif // SHARE_VM_CI_CIOBJECTFACTORY_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciReplay.cpp
#include "precompiled.hpp"
#include "ci/ciMethodData.hpp"
#include "ci/ciReplay.hpp"
#include "ci/ciSymbol.hpp"
#include "ci/ciKlass.hpp"
#include "ci/ciUtilities.hpp"
#include "compiler/compileBroker.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "utilities/copy.hpp"
#include "utilities/macros.hpp"
#ifndef PRODUCT
typedef struct _ciMethodDataRecord {
const char* _klass_name;
const char* _method_name;
const char* _signature;
int _state;
int _current_mileage;
intptr_t* _data;
char* _orig_data;
jobject* _oops_handles;
int* _oops_offsets;
int _data_length;
int _orig_data_length;
int _oops_length;
} ciMethodDataRecord;
typedef struct _ciMethodRecord {
const char* _klass_name;
const char* _method_name;
const char* _signature;
int _instructions_size;
int _interpreter_invocation_count;
int _interpreter_throwout_count;
int _invocation_counter;
int _backedge_counter;
} ciMethodRecord;
typedef struct _ciInlineRecord {
const char* _klass_name;
const char* _method_name;
const char* _signature;
int _inline_depth;
int _inline_bci;
} ciInlineRecord;
class CompileReplay;
static CompileReplay* replay_state;
class CompileReplay : public StackObj {
private:
FILE* _stream;
Thread* _thread;
Handle _protection_domain;
Handle _loader;
GrowableArray<ciMethodRecord*> _ci_method_records;
GrowableArray<ciMethodDataRecord*> _ci_method_data_records;
GrowableArray<ciInlineRecord*>* _ci_inline_records;
const char* _error_message;
char* _bufptr;
char* _buffer;
int _buffer_length;
int _buffer_pos;
ciKlass* _iklass;
Method* _imethod;
int _entry_bci;
int _comp_level;
public:
CompileReplay(const char* filename, TRAPS) {
_thread = THREAD;
_loader = Handle(_thread, SystemDictionary::java_system_loader());
_protection_domain = Handle();
_stream = fopen(filename, "rt");
if (_stream == NULL) {
fprintf(stderr, "ERROR: Can't open replay file %s\n", filename);
}
_ci_inline_records = NULL;
_error_message = NULL;
_buffer_length = 32;
_buffer = NEW_RESOURCE_ARRAY(char, _buffer_length);
_bufptr = _buffer;
_buffer_pos = 0;
_imethod = NULL;
_iklass = NULL;
_entry_bci = 0;
_comp_level = 0;
test();
}
~CompileReplay() {
if (_stream != NULL) fclose(_stream);
}
void test() {
strcpy(_buffer, "1 2 foo 4 bar 0x9 \"this is it\"");
_bufptr = _buffer;
assert(parse_int("test") == 1, "what");
assert(parse_int("test") == 2, "what");
assert(strcmp(parse_string(), "foo") == 0, "what");
assert(parse_int("test") == 4, "what");
assert(strcmp(parse_string(), "bar") == 0, "what");
assert(parse_intptr_t("test") == 9, "what");
assert(strcmp(parse_quoted_string(), "this is it") == 0, "what");
}
bool had_error() {
return _error_message != NULL || _thread->has_pending_exception();
}
bool can_replay() {
return !(_stream == NULL || had_error());
}
void report_error(const char* msg) {
_error_message = msg;
for (int i = 0; i < _buffer_pos; i++) {
if (_buffer[i] == '\0') _buffer[i] = ' ';
}
}
int parse_int(const char* label) {
if (had_error()) {
return 0;
}
int v = 0;
int read;
if (sscanf(_bufptr, "%i%n", &v, &read) != 1) {
report_error(label);
} else {
_bufptr += read;
}
return v;
}
intptr_t parse_intptr_t(const char* label) {
if (had_error()) {
return 0;
}
intptr_t v = 0;
int read;
if (sscanf(_bufptr, INTPTR_FORMAT "%n", &v, &read) != 1) {
report_error(label);
} else {
_bufptr += read;
}
return v;
}
void skip_ws() {
while (*_bufptr == ' ' || *_bufptr == '\t') {
_bufptr++;
}
}
char* scan_and_terminate(char delim) {
char* str = _bufptr;
while (*_bufptr != delim && *_bufptr != '\0') {
_bufptr++;
}
if (*_bufptr != '\0') {
}
if (_bufptr == str) {
return NULL;
}
return str;
}
char* parse_string() {
if (had_error()) return NULL;
skip_ws();
return scan_and_terminate(' ');
}
char* parse_quoted_string() {
if (had_error()) return NULL;
skip_ws();
if (*_bufptr == '"') {
_bufptr++;
return scan_and_terminate('"');
} else {
return scan_and_terminate(' ');
}
}
const char* parse_escaped_string() {
char* result = parse_quoted_string();
if (result != NULL) {
unescape_string(result);
}
return result;
}
bool parse_tag_and_count(const char* tag, int& length) {
const char* t = parse_string();
if (t == NULL) {
return false;
}
if (strcmp(tag, t) != 0) {
report_error(tag);
return false;
}
length = parse_int("parse_tag_and_count");
return !had_error();
}
char* parse_data(const char* tag, int& length) {
if (!parse_tag_and_count(tag, length)) {
return NULL;
}
char * result = NEW_RESOURCE_ARRAY(char, length);
for (int i = 0; i < length; i++) {
int val = parse_int("data");
result[i] = val;
}
return result;
}
intptr_t* parse_intptr_data(const char* tag, int& length) {
if (!parse_tag_and_count(tag, length)) {
return NULL;
}
intptr_t* result = NEW_RESOURCE_ARRAY(intptr_t, length);
for (int i = 0; i < length; i++) {
skip_ws();
intptr_t val = parse_intptr_t("data");
result[i] = val;
}
return result;
}
Symbol* parse_symbol(TRAPS) {
const char* str = parse_escaped_string();
if (str != NULL) {
Symbol* sym = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL);
return sym;
}
return NULL;
}
Klass* parse_klass(TRAPS) {
const char* str = parse_escaped_string();
Symbol* klass_name = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL);
if (klass_name != NULL) {
Klass* k = NULL;
if (_iklass != NULL) {
k = (Klass*)_iklass->find_klass(ciSymbol::make(klass_name->as_C_string()))->constant_encoding();
} else {
k = SystemDictionary::resolve_or_fail(klass_name, _loader, _protection_domain, true, THREAD);
}
if (HAS_PENDING_EXCEPTION) {
oop throwable = PENDING_EXCEPTION;
java_lang_Throwable::print(throwable, tty);
tty->cr();
report_error(str);
return NULL;
}
return k;
}
return NULL;
}
Klass* resolve_klass(const char* klass, TRAPS) {
Symbol* klass_name = SymbolTable::lookup(klass, (int)strlen(klass), CHECK_NULL);
return SystemDictionary::resolve_or_fail(klass_name, _loader, _protection_domain, true, THREAD);
}
Method* parse_method(TRAPS) {
InstanceKlass* k = (InstanceKlass*)parse_klass(CHECK_NULL);
Symbol* method_name = parse_symbol(CHECK_NULL);
Symbol* method_signature = parse_symbol(CHECK_NULL);
Method* m = k->find_method(method_name, method_signature);
if (m == NULL) {
report_error("Can't find method");
}
return m;
}
int get_line(int c) {
while(c != EOF) {
if (_buffer_pos + 1 >= _buffer_length) {
int new_length = _buffer_length * 2;
_buffer = REALLOC_RESOURCE_ARRAY(char, _buffer, _buffer_length, new_length);
_buffer_length = new_length;
}
if (c == '\n') {
c = getc(_stream); // get next char
break;
} else if (c == '\r') {
} else {
_buffer[_buffer_pos++] = c;
}
c = getc(_stream);
}
_buffer[_buffer_pos] = '\0'; // NL or EOF
_buffer_pos = 0;
_bufptr = _buffer;
return c;
}
void process(TRAPS) {
int line_no = 1;
int c = getc(_stream);
while(c != EOF) {
c = get_line(c);
process_command(THREAD);
if (had_error()) {
tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message);
if (ReplayIgnoreInitErrors) {
CLEAR_PENDING_EXCEPTION;
_error_message = NULL;
} else {
return;
}
}
line_no++;
}
}
void process_command(TRAPS) {
char* cmd = parse_string();
if (cmd == NULL) {
return;
}
if (strcmp("#", cmd) == 0) {
} else if (strcmp("compile", cmd) == 0) {
process_compile(CHECK);
} else if (strcmp("ciMethod", cmd) == 0) {
process_ciMethod(CHECK);
} else if (strcmp("ciMethodData", cmd) == 0) {
process_ciMethodData(CHECK);
} else if (strcmp("staticfield", cmd) == 0) {
process_staticfield(CHECK);
} else if (strcmp("ciInstanceKlass", cmd) == 0) {
process_ciInstanceKlass(CHECK);
} else if (strcmp("instanceKlass", cmd) == 0) {
process_instanceKlass(CHECK);
#if INCLUDE_JVMTI
} else if (strcmp("JvmtiExport", cmd) == 0) {
process_JvmtiExport(CHECK);
#endif // INCLUDE_JVMTI
} else {
report_error("unknown command");
}
}
bool is_valid_comp_level(int comp_level) {
const int msg_len = 256;
char* msg = NULL;
if (!is_compile(comp_level)) {
msg = NEW_RESOURCE_ARRAY(char, msg_len);
jio_snprintf(msg, msg_len, "%d isn't compilation level", comp_level);
} else if (!TieredCompilation && (comp_level != CompLevel_highest_tier)) {
msg = NEW_RESOURCE_ARRAY(char, msg_len);
switch (comp_level) {
case CompLevel_simple:
jio_snprintf(msg, msg_len, "compilation level %d requires Client VM or TieredCompilation", comp_level);
break;
case CompLevel_full_optimization:
jio_snprintf(msg, msg_len, "compilation level %d requires Server VM", comp_level);
break;
default:
jio_snprintf(msg, msg_len, "compilation level %d requires TieredCompilation", comp_level);
}
}
if (msg != NULL) {
report_error(msg);
return false;
}
return true;
}
void* process_inline(ciMethod* imethod, Method* m, int entry_bci, int comp_level, TRAPS) {
_imethod = m;
_iklass = imethod->holder();
_entry_bci = entry_bci;
_comp_level = comp_level;
int line_no = 1;
int c = getc(_stream);
while(c != EOF) {
c = get_line(c);
char* cmd = parse_string();
if (cmd == NULL || strcmp("compile", cmd) != 0) {
return NULL;
}
process_compile(CHECK_NULL);
if (had_error()) {
tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message);
tty->print_cr("%s", _buffer);
return NULL;
}
if (_ci_inline_records != NULL && _ci_inline_records->length() > 0) {
return _ci_inline_records;
}
line_no++;
}
return NULL;
}
void process_compile(TRAPS) {
Method* method = parse_method(CHECK);
if (had_error()) return;
int entry_bci = parse_int("entry_bci");
const char* comp_level_label = "comp_level";
int comp_level = parse_int(comp_level_label);
if (had_error() && (error_message() == comp_level_label)) {
comp_level = CompLevel_full_optimization;
}
if (!is_valid_comp_level(comp_level)) {
return;
}
if (_imethod != NULL) {
if (entry_bci != _entry_bci || comp_level != _comp_level) {
return;
}
const char* iklass_name = _imethod->method_holder()->name()->as_utf8();
const char* imethod_name = _imethod->name()->as_utf8();
const char* isignature = _imethod->signature()->as_utf8();
const char* klass_name = method->method_holder()->name()->as_utf8();
const char* method_name = method->name()->as_utf8();
const char* signature = method->signature()->as_utf8();
if (strcmp(iklass_name, klass_name) != 0 ||
strcmp(imethod_name, method_name) != 0 ||
strcmp(isignature, signature) != 0) {
return;
}
}
int inline_count = 0;
if (parse_tag_and_count("inline", inline_count)) {
_ci_inline_records = new GrowableArray<ciInlineRecord*>();
for (int i = 0; i < inline_count; i++) {
int depth = parse_int("inline_depth");
int bci = parse_int("inline_bci");
if (had_error()) {
break;
}
Method* inl_method = parse_method(CHECK);
if (had_error()) {
break;
}
new_ciInlineRecord(inl_method, bci, depth);
}
}
if (_imethod != NULL) {
return; // Replay Inlining
}
Klass* k = method->method_holder();
((InstanceKlass*)k)->initialize(THREAD);
if (HAS_PENDING_EXCEPTION) {
oop throwable = PENDING_EXCEPTION;
java_lang_Throwable::print(throwable, tty);
tty->cr();
if (ReplayIgnoreInitErrors) {
CLEAR_PENDING_EXCEPTION;
((InstanceKlass*)k)->set_init_state(InstanceKlass::fully_initialized);
} else {
return;
}
}
nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, comp_level, true) : method->code();
if (nm != NULL) {
nm->make_not_entrant();
}
replay_state = this;
CompileBroker::compile_method(method, entry_bci, comp_level,
methodHandle(), 0, "replay", THREAD);
replay_state = NULL;
reset();
}
void process_ciMethod(TRAPS) {
Method* method = parse_method(CHECK);
if (had_error()) return;
ciMethodRecord* rec = new_ciMethod(method);
rec->_invocation_counter = parse_int("invocation_counter");
rec->_backedge_counter = parse_int("backedge_counter");
rec->_interpreter_invocation_count = parse_int("interpreter_invocation_count");
rec->_interpreter_throwout_count = parse_int("interpreter_throwout_count");
rec->_instructions_size = parse_int("instructions_size");
}
void process_ciMethodData(TRAPS) {
Method* method = parse_method(CHECK);
if (had_error()) return;
if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) {
return;
}
method->method_holder()->link_class(CHECK);
{
MutexLocker ml(MethodData_lock, THREAD);
if (method->method_data() == NULL) {
ClassLoaderData* loader_data = method->method_holder()->class_loader_data();
MethodData* method_data = MethodData::allocate(loader_data, method, CHECK);
method->set_method_data(method_data);
}
}
ciMethodDataRecord* rec = new_ciMethodData(method);
rec->_state = parse_int("state");
rec->_current_mileage = parse_int("current_mileage");
rec->_orig_data = parse_data("orig", rec->_orig_data_length);
if (rec->_orig_data == NULL) {
return;
}
rec->_data = parse_intptr_data("data", rec->_data_length);
if (rec->_data == NULL) {
return;
}
if (!parse_tag_and_count("oops", rec->_oops_length)) {
return;
}
rec->_oops_handles = NEW_RESOURCE_ARRAY(jobject, rec->_oops_length);
rec->_oops_offsets = NEW_RESOURCE_ARRAY(int, rec->_oops_length);
for (int i = 0; i < rec->_oops_length; i++) {
int offset = parse_int("offset");
if (had_error()) {
return;
}
Klass* k = parse_klass(CHECK);
rec->_oops_offsets[i] = offset;
KlassHandle *kh = NEW_C_HEAP_OBJ(KlassHandle, mtCompiler);
::new ((void*)kh) KlassHandle(THREAD, k);
rec->_oops_handles[i] = (jobject)kh;
}
}
void process_instanceKlass(TRAPS) {
Klass* k = parse_klass(CHECK);
}
void process_ciInstanceKlass(TRAPS) {
InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK);
int is_linked = parse_int("is_linked");
int is_initialized = parse_int("is_initialized");
int length = parse_int("length");
if (is_initialized) {
k->initialize(THREAD);
if (HAS_PENDING_EXCEPTION) {
oop throwable = PENDING_EXCEPTION;
java_lang_Throwable::print(throwable, tty);
tty->cr();
if (ReplayIgnoreInitErrors) {
CLEAR_PENDING_EXCEPTION;
k->set_init_state(InstanceKlass::fully_initialized);
} else {
return;
}
}
} else if (is_linked) {
k->link_class(CHECK);
}
ConstantPool* cp = k->constants();
if (length != cp->length()) {
report_error("constant pool length mismatch: wrong class files?");
return;
}
int parsed_two_word = 0;
for (int i = 1; i < length; i++) {
int tag = parse_int("tag");
if (had_error()) {
return;
}
switch (cp->tag_at(i).value()) {
case JVM_CONSTANT_UnresolvedClass: {
if (tag == JVM_CONSTANT_Class) {
tty->print_cr("Resolving klass %s at %d", cp->unresolved_klass_at(i)->as_utf8(), i);
Klass* k = cp->klass_at(i, CHECK);
}
break;
}
case JVM_CONSTANT_Long:
case JVM_CONSTANT_Double:
parsed_two_word = i + 1;
case JVM_CONSTANT_ClassIndex:
case JVM_CONSTANT_StringIndex:
case JVM_CONSTANT_String:
case JVM_CONSTANT_UnresolvedClassInError:
case JVM_CONSTANT_Fieldref:
case JVM_CONSTANT_Methodref:
case JVM_CONSTANT_InterfaceMethodref:
case JVM_CONSTANT_NameAndType:
case JVM_CONSTANT_Utf8:
case JVM_CONSTANT_Integer:
case JVM_CONSTANT_Float:
case JVM_CONSTANT_MethodHandle:
case JVM_CONSTANT_MethodType:
case JVM_CONSTANT_InvokeDynamic:
if (tag != cp->tag_at(i).value()) {
report_error("tag mismatch: wrong class files?");
return;
}
break;
case JVM_CONSTANT_Class:
if (tag == JVM_CONSTANT_Class) {
} else if (tag == JVM_CONSTANT_UnresolvedClass) {
tty->print_cr("Warning: entry was unresolved in the replay data");
} else {
report_error("Unexpected tag");
return;
}
break;
case 0:
if (parsed_two_word == i) continue;
default:
fatal(err_msg_res("Unexpected tag: %d", cp->tag_at(i).value()));
break;
}
}
}
void process_staticfield(TRAPS) {
InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK);
if (ReplaySuppressInitializers == 0 ||
ReplaySuppressInitializers == 2 && k->class_loader() == NULL) {
return;
}
assert(k->is_initialized(), "must be");
const char* field_name = parse_escaped_string();;
const char* field_signature = parse_string();
fieldDescriptor fd;
Symbol* name = SymbolTable::lookup(field_name, (int)strlen(field_name), CHECK);
Symbol* sig = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK);
if (!k->find_local_field(name, sig, &fd) ||
!fd.is_static() ||
fd.has_initial_value()) {
report_error(field_name);
return;
}
oop java_mirror = k->java_mirror();
if (field_signature[0] == '[') {
int length = parse_int("array length");
oop value = NULL;
if (field_signature[1] == '[') {
ArrayKlass* kelem = (ArrayKlass *)parse_klass(CHECK);
int rank = 0;
while (field_signature[rank] == '[') {
rank++;
}
int* dims = NEW_RESOURCE_ARRAY(int, rank);
dims[0] = length;
for (int i = 1; i < rank; i++) {
dims[i] = 1; // These aren't relevant to the compiler
}
value = kelem->multi_allocate(rank, dims, CHECK);
} else {
if (strcmp(field_signature, "[B") == 0) {
value = oopFactory::new_byteArray(length, CHECK);
} else if (strcmp(field_signature, "[Z") == 0) {
value = oopFactory::new_boolArray(length, CHECK);
} else if (strcmp(field_signature, "[C") == 0) {
value = oopFactory::new_charArray(length, CHECK);
} else if (strcmp(field_signature, "[S") == 0) {
value = oopFactory::new_shortArray(length, CHECK);
} else if (strcmp(field_signature, "[F") == 0) {
value = oopFactory::new_singleArray(length, CHECK);
} else if (strcmp(field_signature, "[D") == 0) {
value = oopFactory::new_doubleArray(length, CHECK);
} else if (strcmp(field_signature, "[I") == 0) {
value = oopFactory::new_intArray(length, CHECK);
} else if (strcmp(field_signature, "[J") == 0) {
value = oopFactory::new_longArray(length, CHECK);
} else if (field_signature[0] == '[' && field_signature[1] == 'L') {
KlassHandle kelem = resolve_klass(field_signature + 1, CHECK);
value = oopFactory::new_objArray(kelem(), length, CHECK);
} else {
report_error("unhandled array staticfield");
}
}
java_mirror->obj_field_put(fd.offset(), value);
} else {
const char* string_value = parse_escaped_string();
if (strcmp(field_signature, "I") == 0) {
int value = atoi(string_value);
java_mirror->int_field_put(fd.offset(), value);
} else if (strcmp(field_signature, "B") == 0) {
int value = atoi(string_value);
java_mirror->byte_field_put(fd.offset(), value);
} else if (strcmp(field_signature, "C") == 0) {
int value = atoi(string_value);
java_mirror->char_field_put(fd.offset(), value);
} else if (strcmp(field_signature, "S") == 0) {
int value = atoi(string_value);
java_mirror->short_field_put(fd.offset(), value);
} else if (strcmp(field_signature, "Z") == 0) {
int value = atol(string_value);
java_mirror->bool_field_put(fd.offset(), value);
} else if (strcmp(field_signature, "J") == 0) {
jlong value;
if (sscanf(string_value, JLONG_FORMAT, &value) != 1) {
fprintf(stderr, "Error parsing long: %s\n", string_value);
return;
}
java_mirror->long_field_put(fd.offset(), value);
} else if (strcmp(field_signature, "F") == 0) {
float value = atof(string_value);
java_mirror->float_field_put(fd.offset(), value);
} else if (strcmp(field_signature, "D") == 0) {
double value = atof(string_value);
java_mirror->double_field_put(fd.offset(), value);
} else if (strcmp(field_signature, "Ljava/lang/String;") == 0) {
Handle value = java_lang_String::create_from_str(string_value, CHECK);
java_mirror->obj_field_put(fd.offset(), value());
} else if (field_signature[0] == 'L') {
Symbol* klass_name = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK);
KlassHandle kelem = resolve_klass(field_signature, CHECK);
oop value = ((InstanceKlass*)kelem())->allocate_instance(CHECK);
java_mirror->obj_field_put(fd.offset(), value);
} else {
report_error("unhandled staticfield");
}
}
}
#if INCLUDE_JVMTI
void process_JvmtiExport(TRAPS) {
const char* field = parse_string();
bool value = parse_int("JvmtiExport flag") != 0;
if (strcmp(field, "can_access_local_variables") == 0) {
JvmtiExport::set_can_access_local_variables(value);
} else if (strcmp(field, "can_hotswap_or_post_breakpoint") == 0) {
JvmtiExport::set_can_hotswap_or_post_breakpoint(value);
} else if (strcmp(field, "can_post_on_exceptions") == 0) {
JvmtiExport::set_can_post_on_exceptions(value);
} else {
report_error("Unrecognized JvmtiExport directive");
}
}
#endif // INCLUDE_JVMTI
ciMethodRecord* new_ciMethod(Method* method) {
ciMethodRecord* rec = NEW_RESOURCE_OBJ(ciMethodRecord);
rec->_klass_name = method->method_holder()->name()->as_utf8();
rec->_method_name = method->name()->as_utf8();
rec->_signature = method->signature()->as_utf8();
_ci_method_records.append(rec);
return rec;
}
ciMethodRecord* find_ciMethodRecord(Method* method) {
const char* klass_name = method->method_holder()->name()->as_utf8();
const char* method_name = method->name()->as_utf8();
const char* signature = method->signature()->as_utf8();
for (int i = 0; i < _ci_method_records.length(); i++) {
ciMethodRecord* rec = _ci_method_records.at(i);
if (strcmp(rec->_klass_name, klass_name) == 0 &&
strcmp(rec->_method_name, method_name) == 0 &&
strcmp(rec->_signature, signature) == 0) {
return rec;
}
}
return NULL;
}
ciMethodDataRecord* new_ciMethodData(Method* method) {
ciMethodDataRecord* rec = NEW_RESOURCE_OBJ(ciMethodDataRecord);
rec->_klass_name = method->method_holder()->name()->as_utf8();
rec->_method_name = method->name()->as_utf8();
rec->_signature = method->signature()->as_utf8();
_ci_method_data_records.append(rec);
return rec;
}
ciMethodDataRecord* find_ciMethodDataRecord(Method* method) {
const char* klass_name = method->method_holder()->name()->as_utf8();
const char* method_name = method->name()->as_utf8();
const char* signature = method->signature()->as_utf8();
for (int i = 0; i < _ci_method_data_records.length(); i++) {
ciMethodDataRecord* rec = _ci_method_data_records.at(i);
if (strcmp(rec->_klass_name, klass_name) == 0 &&
strcmp(rec->_method_name, method_name) == 0 &&
strcmp(rec->_signature, signature) == 0) {
return rec;
}
}
return NULL;
}
ciInlineRecord* new_ciInlineRecord(Method* method, int bci, int depth) {
ciInlineRecord* rec = NEW_RESOURCE_OBJ(ciInlineRecord);
rec->_klass_name = method->method_holder()->name()->as_utf8();
rec->_method_name = method->name()->as_utf8();
rec->_signature = method->signature()->as_utf8();
rec->_inline_bci = bci;
rec->_inline_depth = depth;
_ci_inline_records->append(rec);
return rec;
}
ciInlineRecord* find_ciInlineRecord(Method* method, int bci, int depth) {
if (_ci_inline_records != NULL) {
return find_ciInlineRecord(_ci_inline_records, method, bci, depth);
}
return NULL;
}
static ciInlineRecord* find_ciInlineRecord(GrowableArray<ciInlineRecord*>* records,
Method* method, int bci, int depth) {
if (records != NULL) {
const char* klass_name = method->method_holder()->name()->as_utf8();
const char* method_name = method->name()->as_utf8();
const char* signature = method->signature()->as_utf8();
for (int i = 0; i < records->length(); i++) {
ciInlineRecord* rec = records->at(i);
if ((rec->_inline_bci == bci) &&
(rec->_inline_depth == depth) &&
(strcmp(rec->_klass_name, klass_name) == 0) &&
(strcmp(rec->_method_name, method_name) == 0) &&
(strcmp(rec->_signature, signature) == 0)) {
return rec;
}
}
}
return NULL;
}
const char* error_message() {
return _error_message;
}
void reset() {
_error_message = NULL;
_ci_method_records.clear();
_ci_method_data_records.clear();
}
static void unescape_string(char* value) {
char* from = value;
char* to = value;
while (*from != '\0') {
if (*from != '\\') {
} else {
switch (from[1]) {
case 'u': {
from += 2;
jchar value=0;
for (int i=0; i<4; i++) {
char c = *from++;
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
value = (value << 4) + c - '0';
break;
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
value = (value << 4) + 10 + c - 'a';
break;
case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F':
value = (value << 4) + 10 + c - 'A';
break;
default:
ShouldNotReachHere();
}
}
UNICODE::convert_to_utf8(&value, 1, to);
to++;
break;
}
case 't': *to++ = '\t'; from += 2; break;
case 'n': *to++ = '\n'; from += 2; break;
case 'r': *to++ = '\r'; from += 2; break;
case 'f': *to++ = '\f'; from += 2; break;
default:
ShouldNotReachHere();
}
}
}
}
};
void ciReplay::replay(TRAPS) {
int exit_code = replay_impl(THREAD);
Threads::destroy_vm();
vm_exit(exit_code);
}
void* ciReplay::load_inline_data(ciMethod* method, int entry_bci, int comp_level) {
if (FLAG_IS_DEFAULT(InlineDataFile)) {
tty->print_cr("ERROR: no inline replay data file specified (use -XX:InlineDataFile=inline_pid12345.txt).");
return NULL;
}
VM_ENTRY_MARK;
CompileReplay rp(InlineDataFile, THREAD);
if (!rp.can_replay()) {
tty->print_cr("ciReplay: !rp.can_replay()");
return NULL;
}
void* data = rp.process_inline(method, method->get_Method(), entry_bci, comp_level, THREAD);
if (HAS_PENDING_EXCEPTION) {
oop throwable = PENDING_EXCEPTION;
CLEAR_PENDING_EXCEPTION;
java_lang_Throwable::print(throwable, tty);
tty->cr();
java_lang_Throwable::print_stack_trace(throwable, tty);
tty->cr();
return NULL;
}
if (rp.had_error()) {
tty->print_cr("ciReplay: Failed on %s", rp.error_message());
return NULL;
}
return data;
}
int ciReplay::replay_impl(TRAPS) {
HandleMark hm;
ResourceMark rm;
BackgroundCompilation = false;
if (ReplaySuppressInitializers > 2) {
ReplaySuppressInitializers = 1;
}
if (FLAG_IS_DEFAULT(ReplayDataFile)) {
tty->print_cr("ERROR: no compiler replay data file specified (use -XX:ReplayDataFile=replay_pid12345.txt).");
return 1;
}
CompileReplay rp(ReplayDataFile, THREAD);
int exit_code = 0;
if (rp.can_replay()) {
rp.process(THREAD);
} else {
exit_code = 1;
return exit_code;
}
if (HAS_PENDING_EXCEPTION) {
oop throwable = PENDING_EXCEPTION;
CLEAR_PENDING_EXCEPTION;
java_lang_Throwable::print(throwable, tty);
tty->cr();
java_lang_Throwable::print_stack_trace(throwable, tty);
tty->cr();
exit_code = 2;
}
if (rp.had_error()) {
tty->print_cr("Failed on %s", rp.error_message());
exit_code = 1;
}
return exit_code;
}
void ciReplay::initialize(ciMethodData* m) {
if (replay_state == NULL) {
return;
}
ASSERT_IN_VM;
ResourceMark rm;
Method* method = m->get_MethodData()->method();
ciMethodDataRecord* rec = replay_state->find_ciMethodDataRecord(method);
if (rec == NULL) {
tty->print_cr("Warning: requesting ciMethodData record for method with no data: ");
method->print_name(tty);
tty->cr();
} else {
m->_state = rec->_state;
m->_current_mileage = rec->_current_mileage;
if (rec->_data_length != 0) {
assert(m->_data_size == rec->_data_length * (int)sizeof(rec->_data[0]), "must agree");
ciEnv* env = ciEnv::current();
for (int i = 0; i < rec->_oops_length; i++) {
KlassHandle *h = (KlassHandle *)rec->_oops_handles[i];
env->get_metadata((*h)());
}
#ifdef _LP64
Copy::conjoint_jlongs_atomic((jlong *)rec->_data, (jlong *)m->_data, rec->_data_length);
#else
Copy::conjoint_jints_atomic((jint *)rec->_data, (jint *)m->_data, rec->_data_length);
#endif
}
Copy::conjoint_jbytes(rec->_orig_data, (char*)&m->_orig, rec->_orig_data_length);
}
}
bool ciReplay::should_not_inline(ciMethod* method) {
if (replay_state == NULL) {
return false;
}
VM_ENTRY_MARK;
return replay_state->find_ciMethodRecord(method->get_Method()) == NULL;
}
bool ciReplay::should_inline(void* data, ciMethod* method, int bci, int inline_depth) {
if (data != NULL) {
GrowableArray<ciInlineRecord*>* records = (GrowableArray<ciInlineRecord*>*)data;
VM_ENTRY_MARK;
return CompileReplay::find_ciInlineRecord(records, method->get_Method(), bci, inline_depth) != NULL;
} else if (replay_state != NULL) {
VM_ENTRY_MARK;
return replay_state->find_ciInlineRecord(method->get_Method(), bci, inline_depth) != NULL;
}
return false;
}
bool ciReplay::should_not_inline(void* data, ciMethod* method, int bci, int inline_depth) {
if (data != NULL) {
GrowableArray<ciInlineRecord*>* records = (GrowableArray<ciInlineRecord*>*)data;
VM_ENTRY_MARK;
return CompileReplay::find_ciInlineRecord(records, method->get_Method(), bci, inline_depth) == NULL;
} else if (replay_state != NULL) {
VM_ENTRY_MARK;
return replay_state->find_ciInlineRecord(method->get_Method(), bci, inline_depth) == NULL;
}
return false;
}
void ciReplay::initialize(ciMethod* m) {
if (replay_state == NULL) {
return;
}
ASSERT_IN_VM;
ResourceMark rm;
Method* method = m->get_Method();
ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
if (rec == NULL) {
tty->print_cr("Warning: requesting ciMethod record for method with no data: ");
method->print_name(tty);
tty->cr();
} else {
EXCEPTION_CONTEXT;
m->_instructions_size = -1;
m->_interpreter_invocation_count = rec->_interpreter_invocation_count;
m->_interpreter_throwout_count = rec->_interpreter_throwout_count;
MethodCounters* mcs = method->get_method_counters(CHECK_AND_CLEAR);
guarantee(mcs != NULL, "method counters allocation failed");
mcs->invocation_counter()->_counter = rec->_invocation_counter;
mcs->backedge_counter()->_counter = rec->_backedge_counter;
}
}
bool ciReplay::is_loaded(Method* method) {
if (replay_state == NULL) {
return true;
}
ASSERT_IN_VM;
ResourceMark rm;
ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
return rec != NULL;
}
#endif // PRODUCT
C:\hotspot-69087d08d473\src\share\vm/ci/ciReplay.hpp
#ifndef SHARE_VM_CI_CIREPLAY_HPP
#define SHARE_VM_CI_CIREPLAY_HPP
#include "ci/ciMethod.hpp"
class ciReplay {
CI_PACKAGE_ACCESS
#ifndef PRODUCT
private:
static int replay_impl(TRAPS);
public:
static void replay(TRAPS);
static void* load_inline_data(ciMethod* method, int entry_bci, int comp_level);
static void initialize(ciMethodData* method);
static void initialize(ciMethod* method);
static bool is_loaded(Method* method);
static bool is_loaded(Klass* klass);
static bool should_not_inline(ciMethod* method);
static bool should_inline(void* data, ciMethod* method, int bci, int inline_depth);
static bool should_not_inline(void* data, ciMethod* method, int bci, int inline_depth);
#endif
};
#endif // SHARE_VM_CI_CIREPLAY_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciSignature.cpp
#include "precompiled.hpp"
#include "ci/ciMethodType.hpp"
#include "ci/ciSignature.hpp"
#include "ci/ciUtilities.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/signature.hpp"
ciSignature::ciSignature(ciKlass* accessing_klass, constantPoolHandle cpool, ciSymbol* symbol) {
ASSERT_IN_VM;
EXCEPTION_CONTEXT;
_accessing_klass = accessing_klass;
_symbol = symbol;
ciEnv* env = CURRENT_ENV;
Arena* arena = env->arena();
_types = new (arena) GrowableArray<ciType*>(arena, 8, 0, NULL);
int size = 0;
int count = 0;
ResourceMark rm(THREAD);
Symbol* sh = symbol->get_symbol();
SignatureStream ss(sh);
for (; ; ss.next()) {
ciType* type;
if (!ss.is_object()) {
type = ciType::make(ss.type());
} else {
Symbol* name = ss.as_symbol(THREAD);
if (HAS_PENDING_EXCEPTION) {
type = ss.is_array() ? (ciType*)ciEnv::unloaded_ciobjarrayklass()
: (ciType*)ciEnv::unloaded_ciinstance_klass();
env->record_out_of_memory_failure();
CLEAR_PENDING_EXCEPTION;
} else {
ciSymbol* klass_name = env->get_symbol(name);
type = env->get_klass_by_name_impl(_accessing_klass, cpool, klass_name, false);
}
}
_types->append(type);
if (ss.at_return_type()) {
break;
}
size += type->size();
count++;
}
_size = size;
_count = count;
}
ciSignature::ciSignature(ciKlass* accessing_klass, ciSymbol* symbol, ciMethodType* method_type) :
_symbol(symbol),
_accessing_klass(accessing_klass),
_size( method_type->ptype_slot_count()),
_count(method_type->ptype_count())
{
ASSERT_IN_VM;
EXCEPTION_CONTEXT;
Arena* arena = CURRENT_ENV->arena();
_types = new (arena) GrowableArray<ciType*>(arena, _count + 1, 0, NULL);
for (int i = 0; i < _count; i++) {
_types->append(method_type->ptype_at(i));
}
_types->append(method_type->rtype());
}
ciType* ciSignature::return_type() const {
return _types->at(_count);
}
ciType* ciSignature::type_at(int index) const {
assert(index < _count, "out of bounds");
return _types->at(index);
}
bool ciSignature::equals(ciSignature* that) {
if (!this->as_symbol()->equals(that->as_symbol())) return false;
for (int i = 0; i < _count; i++) {
if (this->type_at(i) != that->type_at(i)) return false;
}
if (this->return_type() != that->return_type()) return false;
return true;
}
void ciSignature::print_signature() {
_symbol->print_symbol();
}
void ciSignature::print() {
tty->print("<ciSignature symbol=");
print_signature();
tty->print(" accessing_klass=");
_accessing_klass->print();
tty->print(" address=" INTPTR_FORMAT ">", p2i((address)this));
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciSignature.hpp
#ifndef SHARE_VM_CI_CISIGNATURE_HPP
#define SHARE_VM_CI_CISIGNATURE_HPP
#include "ci/ciClassList.hpp"
#include "ci/ciSymbol.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/growableArray.hpp"
class ciSignature : public ResourceObj {
private:
ciSymbol* _symbol;
ciKlass* _accessing_klass;
GrowableArray<ciType*>* _types;
int _size; // number of stack slots required for arguments
int _count; // number of parameter types in the signature
friend class ciMethod;
friend class ciBytecodeStream;
friend class ciObjectFactory;
ciSignature(ciKlass* accessing_klass, constantPoolHandle cpool, ciSymbol* signature);
ciSignature(ciKlass* accessing_klass, ciSymbol* signature, ciMethodType* method_type);
void get_all_klasses();
Symbol* get_symbol() const { return _symbol->get_symbol(); }
public:
ciSymbol* as_symbol() const { return _symbol; }
ciKlass* accessing_klass() const { return _accessing_klass; }
ciType* return_type() const;
ciType* type_at(int index) const;
int size() const { return _size; }
int count() const { return _count; }
int arg_size_for_bc(Bytecodes::Code bc) { return size() + (Bytecodes::has_receiver(bc) ? 1 : 0); }
bool equals(ciSignature* that);
void print_signature();
void print();
};
#endif // SHARE_VM_CI_CISIGNATURE_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciStreams.cpp
#include "precompiled.hpp"
#include "ci/ciCallSite.hpp"
#include "ci/ciConstant.hpp"
#include "ci/ciField.hpp"
#include "ci/ciStreams.hpp"
#include "ci/ciUtilities.hpp"
int ciExceptionHandlerStream::count() {
int save_pos = _pos;
int save_end = _end;
int count = 0;
_pos = -1;
_end = _method->_handler_count;
next();
while (!is_done()) {
count++;
next();
}
_pos = save_pos;
_end = save_end;
return count;
}
int ciExceptionHandlerStream::count_remaining() {
int save_pos = _pos;
int save_end = _end;
int count = 0;
while (!is_done()) {
count++;
next();
}
_pos = save_pos;
_end = save_end;
return count;
}
Bytecodes::Code ciBytecodeStream::next_wide_or_table(Bytecodes::Code bc) {
switch (bc) { // Check for special bytecode handling
case Bytecodes::_wide:
assert(Bytecodes::Code(_pc[0]) == Bytecodes::_wide, "");
bc = Bytecodes::java_code(_raw_bc = (Bytecodes::Code)_pc[1]);
assert(Bytecodes::wide_length_for(bc) > 2, "must make progress");
_pc += Bytecodes::wide_length_for(bc);
_was_wide = _pc; // Flag last wide bytecode found
assert(is_wide(), "accessor works right");
break;
case Bytecodes::_lookupswitch:
_pc++; // Skip wide bytecode
_pc += (_start-_pc)&3; // Word align
_table_base = (jint*)_pc; // Capture for later usage
_pc = (address)&_table_base[2+ 2*Bytes::get_Java_u4((address)&_table_base[1])];
break;
case Bytecodes::_tableswitch: {
_pc++; // Skip wide bytecode
_pc += (_start-_pc)&3; // Word align
_table_base = (jint*)_pc; // Capture for later usage
int lo = Bytes::get_Java_u4((address)&_table_base[1]);// Low bound
int hi = Bytes::get_Java_u4((address)&_table_base[2]);// High bound
int len = hi - lo + 1; // Dense table size
_pc = (address)&_table_base[3+len]; // Skip past table
break;
}
default:
fatal("unhandled bytecode");
}
return bc;
}
void ciBytecodeStream::reset_to_bci( int bci ) {
_bc_start=_was_wide=0;
_pc = _start+bci;
}
void ciBytecodeStream::force_bci(int bci) {
if (bci < 0) {
reset_to_bci(0);
_bc_start = _start + bci;
_bc = EOBC();
} else {
reset_to_bci(bci);
next();
}
}
int ciBytecodeStream::get_klass_index() const {
switch(cur_bc()) {
case Bytecodes::_ldc:
return get_index_u1();
case Bytecodes::_ldc_w:
case Bytecodes::_ldc2_w:
case Bytecodes::_checkcast:
case Bytecodes::_instanceof:
case Bytecodes::_anewarray:
case Bytecodes::_multianewarray:
case Bytecodes::_new:
case Bytecodes::_newarray:
return get_index_u2();
default:
ShouldNotReachHere();
return 0;
}
}
ciKlass* ciBytecodeStream::get_klass(bool& will_link) {
VM_ENTRY_MARK;
constantPoolHandle cpool(_method->get_Method()->constants());
return CURRENT_ENV->get_klass_by_index(cpool, get_klass_index(), will_link, _holder);
}
int ciBytecodeStream::get_constant_raw_index() const {
switch (cur_bc()) {
case Bytecodes::_ldc:
return get_index_u1();
case Bytecodes::_ldc_w:
case Bytecodes::_ldc2_w:
return get_index_u2();
default:
ShouldNotReachHere();
return 0;
}
}
int ciBytecodeStream::get_constant_pool_index() const {
int index = get_constant_raw_index();
if (has_cache_index()) {
VM_ENTRY_MARK;
constantPoolHandle cpool(_method->get_Method()->constants());
return cpool->object_to_cp_index(index);
}
return index;
}
int ciBytecodeStream::get_constant_cache_index() const {
return has_cache_index() ? get_constant_raw_index() : -1;
}
ciConstant ciBytecodeStream::get_constant() {
int pool_index = get_constant_raw_index();
int cache_index = -1;
if (has_cache_index()) {
cache_index = pool_index;
pool_index = -1;
}
VM_ENTRY_MARK;
constantPoolHandle cpool(_method->get_Method()->constants());
return CURRENT_ENV->get_constant_by_index(cpool, pool_index, cache_index, _holder);
}
constantTag ciBytecodeStream::get_constant_pool_tag(int index) const {
VM_ENTRY_MARK;
return _method->get_Method()->constants()->tag_at(index);
}
int ciBytecodeStream::get_field_index() {
assert(cur_bc() == Bytecodes::_getfield ||
cur_bc() == Bytecodes::_putfield ||
cur_bc() == Bytecodes::_getstatic ||
cur_bc() == Bytecodes::_putstatic, "wrong bc");
return get_index_u2_cpcache();
}
ciField* ciBytecodeStream::get_field(bool& will_link) {
ciField* f = CURRENT_ENV->get_field_by_index(_holder, get_field_index());
will_link = f->will_link(_holder, _bc);
return f;
}
ciInstanceKlass* ciBytecodeStream::get_declared_field_holder() {
VM_ENTRY_MARK;
constantPoolHandle cpool(_method->get_Method()->constants());
int holder_index = get_field_holder_index();
bool ignore;
return CURRENT_ENV->get_klass_by_index(cpool, holder_index, ignore, _holder)
->as_instance_klass();
}
int ciBytecodeStream::get_field_holder_index() {
GUARDED_VM_ENTRY(
ConstantPool* cpool = _holder->get_instanceKlass()->constants();
return cpool->klass_ref_index_at(get_field_index());
)
}
int ciBytecodeStream::get_field_signature_index() {
VM_ENTRY_MARK;
ConstantPool* cpool = _holder->get_instanceKlass()->constants();
int nt_index = cpool->name_and_type_ref_index_at(get_field_index());
return cpool->signature_ref_index_at(nt_index);
}
int ciBytecodeStream::get_method_index() {
#ifdef ASSERT
switch (cur_bc()) {
case Bytecodes::_invokeinterface:
case Bytecodes::_invokevirtual:
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
case Bytecodes::_invokedynamic:
break;
default:
ShouldNotReachHere();
}
#endif
if (has_index_u4())
return get_index_u4(); // invokedynamic
return get_index_u2_cpcache();
}
ciMethod* ciBytecodeStream::get_method(bool& will_link, ciSignature* *declared_signature_result) {
VM_ENTRY_MARK;
ciEnv* env = CURRENT_ENV;
constantPoolHandle cpool(THREAD, _method->get_Method()->constants());
ciMethod* m = env->get_method_by_index(cpool, get_method_index(), cur_bc(), _holder);
will_link = m->is_loaded();
if (has_method_type()) {
ciSymbol* sig_sym = env->get_symbol(cpool->symbol_at(get_method_signature_index(cpool)));
ciKlass* pool_holder = env->get_klass(cpool->pool_holder());
ciMethodType* method_type = get_method_type();
ciSignature* declared_signature = new (env->arena()) ciSignature(pool_holder, sig_sym, method_type);
(*declared_signature_result) = declared_signature;
} else {
(*declared_signature_result) = m->signature();
}
return m;
}
bool ciBytecodeStream::has_appendix() {
VM_ENTRY_MARK;
constantPoolHandle cpool(_method->get_Method()->constants());
return ConstantPool::has_appendix_at_if_loaded(cpool, get_method_index());
}
ciObject* ciBytecodeStream::get_appendix() {
VM_ENTRY_MARK;
constantPoolHandle cpool(_method->get_Method()->constants());
oop appendix_oop = ConstantPool::appendix_at_if_loaded(cpool, get_method_index());
return CURRENT_ENV->get_object(appendix_oop);
}
bool ciBytecodeStream::has_method_type() {
GUARDED_VM_ENTRY(
constantPoolHandle cpool(_method->get_Method()->constants());
return ConstantPool::has_method_type_at_if_loaded(cpool, get_method_index());
)
}
ciMethodType* ciBytecodeStream::get_method_type() {
GUARDED_VM_ENTRY(
constantPoolHandle cpool(_method->get_Method()->constants());
oop method_type_oop = ConstantPool::method_type_at_if_loaded(cpool, get_method_index());
return CURRENT_ENV->get_object(method_type_oop)->as_method_type();
)
}
ciKlass* ciBytecodeStream::get_declared_method_holder() {
VM_ENTRY_MARK;
constantPoolHandle cpool(_method->get_Method()->constants());
bool ignore;
if (cur_bc() == Bytecodes::_invokedynamic)
return CURRENT_ENV->get_klass_by_name(_holder, ciSymbol::java_lang_invoke_MethodHandle(), false);
return CURRENT_ENV->get_klass_by_index(cpool, get_method_holder_index(), ignore, _holder);
}
int ciBytecodeStream::get_method_holder_index() {
ConstantPool* cpool = _method->get_Method()->constants();
return cpool->klass_ref_index_at(get_method_index());
}
int ciBytecodeStream::get_method_signature_index(const constantPoolHandle& cpool) {
GUARDED_VM_ENTRY(
const int method_index = get_method_index();
const int name_and_type_index = cpool->name_and_type_ref_index_at(method_index);
return cpool->signature_ref_index_at(name_and_type_index);
)
}
ciObjArray* ciBytecodeStream::get_resolved_references() {
VM_ENTRY_MARK;
ConstantPool* cpool = _holder->get_instanceKlass()->constants();
return CURRENT_ENV->get_object(cpool->resolved_references())->as_obj_array();
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciStreams.hpp
#ifndef SHARE_VM_CI_CISTREAMS_HPP
#define SHARE_VM_CI_CISTREAMS_HPP
#include "ci/ciClassList.hpp"
#include "ci/ciExceptionHandler.hpp"
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciMethod.hpp"
#include "interpreter/bytecode.hpp"
class ciBytecodeStream : StackObj {
private:
Bytecodes::Code next_wide_or_table(Bytecodes::Code); // Handle _wide & complicated inline table
static Bytecodes::Code check_java(Bytecodes::Code c) {
assert(Bytecodes::is_java_code(c), "should not return _fast bytecodes");
return c;
}
static Bytecodes::Code check_defined(Bytecodes::Code c) {
assert(Bytecodes::is_defined(c), "");
return c;
}
ciMethod* _method; // the method
ciInstanceKlass* _holder;
address _bc_start; // Start of current bytecode for table
address _was_wide; // Address past last wide bytecode
jint* _table_base; // Aligned start of last table or switch
address _start; // Start of bytecodes
address _end; // Past end of bytecodes
address _pc; // Current PC
Bytecodes::Code _bc; // Current bytecode
Bytecodes::Code _raw_bc; // Current bytecode, raw form
void reset( address base, unsigned int size ) {
_bc_start =_was_wide = 0;
_start = _pc = base; _end = base + size;
}
void assert_wide(bool require_wide) const {
if (require_wide)
{ assert(is_wide(), "must be a wide instruction"); }
else { assert(!is_wide(), "must not be a wide instruction"); }
}
Bytecode bytecode() const { return Bytecode(this, _bc_start); }
Bytecode next_bytecode() const { return Bytecode(this, _pc); }
public:
static Bytecodes::Code EOBC() {
return Bytecodes::_illegal;
}
ciBytecodeStream(ciMethod* m) {
reset_to_method(m);
}
ciBytecodeStream() {
reset_to_method(NULL);
}
ciMethod* method() const { return _method; }
void reset_to_method(ciMethod* m) {
_method = m;
if (m == NULL) {
_holder = NULL;
reset(NULL, 0);
} else {
_holder = m->holder();
reset(m->code(), m->code_size());
}
}
void reset_to_bci( int bci );
void force_bci(int bci);
void set_max_bci( int max ) {
_end = _start + max;
}
address cur_bcp() const { return _bc_start; } // Returns bcp to current instruction
int next_bci() const { return _pc - _start; }
int cur_bci() const { return _bc_start - _start; }
int instruction_size() const { return _pc - _bc_start; }
Bytecodes::Code cur_bc() const{ return check_java(_bc); }
Bytecodes::Code cur_bc_raw() const { return check_defined(_raw_bc); }
Bytecodes::Code next_bc() { return Bytecodes::java_code((Bytecodes::Code)* _pc); }
Bytecodes::Code next() {
_bc_start = _pc; // Capture start of bc
if( _pc >= _end ) return EOBC(); // End-Of-Bytecodes
_bc = Bytecodes::java_code(_raw_bc = (Bytecodes::Code)*_pc);
int csize = Bytecodes::length_for(_bc); // Expected size
_pc += csize; // Bump PC past bytecode
if (csize == 0) {
_bc = next_wide_or_table(_bc);
}
return check_java(_bc);
}
bool is_wide() const { return ( _pc == _was_wide ); }
bool has_cache_index() const { return Bytecodes::uses_cp_cache(cur_bc_raw()); }
bool has_optional_appendix() { return Bytecodes::has_optional_appendix(cur_bc_raw()); }
int get_index_u1() const {
return bytecode().get_index_u1(cur_bc_raw());
}
int get_index_u1_cpcache() const {
return bytecode().get_index_u1_cpcache(cur_bc_raw());
}
int get_index() const {
assert(!has_cache_index(), "else use cpcache variant");
return (_pc == _was_wide) // was widened?
? get_index_u2(true) // yes, return wide index
: get_index_u1(); // no, return narrow index
}
int get_index_u2(bool is_wide = false) const {
return bytecode().get_index_u2(cur_bc_raw(), is_wide);
}
int get_index_u2_cpcache() const {
return bytecode().get_index_u2_cpcache(cur_bc_raw());
}
int get_index_u4() const {
return bytecode().get_index_u4(cur_bc_raw());
}
bool has_index_u4() const {
return bytecode().has_index_u4(cur_bc_raw());
}
int get_dimensions() const { return *(unsigned char*)(_pc-1); }
int get_constant_u1() const { return bytecode().get_constant_u1(instruction_size()-1, cur_bc_raw()); }
int get_constant_u2(bool is_wide = false) const { return bytecode().get_constant_u2(instruction_size()-2, cur_bc_raw(), is_wide); }
int get_iinc_con() const {return (_pc==_was_wide) ? (jshort) get_constant_u2(true) : (jbyte) get_constant_u1();}
int get_dest() const {
return cur_bci() + bytecode().get_offset_s2(cur_bc_raw());
}
int next_get_dest() const {
assert(_pc < _end, "");
return next_bci() + next_bytecode().get_offset_s2(Bytecodes::_ifeq);
}
int get_far_dest() const {
return cur_bci() + bytecode().get_offset_s4(cur_bc_raw());
}
int get_int_table( int index ) const {
return Bytes::get_Java_u4((address)&_table_base[index]); }
int get_tableswitch_length() { return get_int_table(2)-get_int_table(1)+1; }
int get_dest_table( int index ) const {
return cur_bci() + get_int_table(index); }
int get_constant_raw_index() const;
int get_constant_pool_index() const;
int get_constant_cache_index() const;
int get_field_index();
int get_method_index();
ciKlass* get_klass(bool& will_link);
int get_klass_index() const;
ciConstant get_constant();
constantTag get_constant_pool_tag(int index) const;
bool is_unresolved_klass() const {
constantTag tag = get_constant_pool_tag(get_klass_index());
return tag.is_unresolved_klass();
}
ciField* get_field(bool& will_link);
ciInstanceKlass* get_declared_field_holder();
int get_field_holder_index();
int get_field_signature_index();
ciMethod* get_method(bool& will_link, ciSignature* *declared_signature_result);
bool has_appendix();
ciObject* get_appendix();
bool has_method_type();
ciMethodType* get_method_type();
ciKlass* get_declared_method_holder();
int get_method_holder_index();
int get_method_signature_index(const constantPoolHandle& cpool);
ciObjArray* get_resolved_references();
};
class ciSignatureStream : public StackObj {
private:
ciSignature* _sig;
int _pos;
ciKlass* _holder;
public:
ciSignatureStream(ciSignature* signature, ciKlass* holder = NULL) {
_sig = signature;
_pos = 0;
_holder = holder;
}
bool at_return_type() { return _pos == _sig->count(); }
bool is_done() { return _pos > _sig->count(); }
void next() {
if (_pos <= _sig->count()) {
_pos++;
}
}
ciType* type() {
if (at_return_type()) {
return _sig->return_type();
} else {
return _sig->type_at(_pos);
}
}
ciKlass* next_klass() {
ciKlass* sig_k;
if (_holder != NULL) {
sig_k = _holder;
_holder = NULL;
} else {
while (!type()->is_klass()) {
next();
}
assert(!at_return_type(), "passed end of signature");
sig_k = type()->as_klass();
next();
}
return sig_k;
}
};
class ciExceptionHandlerStream : public StackObj {
private:
ciMethod* _method;
int _pos;
int _end;
ciInstanceKlass* _exception_klass;
int _bci;
bool _is_exact;
public:
ciExceptionHandlerStream(ciMethod* method) {
_method = method;
_method->code();
_pos = 0;
_end = _method->_handler_count;
_exception_klass = NULL;
_bci = -1;
_is_exact = false;
}
ciExceptionHandlerStream(ciMethod* method, int bci,
ciInstanceKlass* exception_klass = NULL,
bool is_exact = false) {
_method = method;
_method->code();
_pos = -1;
_end = _method->_handler_count + 1; // include the rethrow handler
_exception_klass = (exception_klass != NULL && exception_klass->is_loaded()
? exception_klass
: NULL);
_bci = bci;
assert(_bci >= 0, "bci out of range");
_is_exact = is_exact;
next();
}
int count();
int count_remaining();
bool is_done() {
return (_pos >= _end);
}
void next() {
_pos++;
if (_bci != -1) {
while (!is_done()) {
ciExceptionHandler* handler = _method->_exception_handlers[_pos];
if (handler->is_in_range(_bci)) {
if (handler->is_catch_all()) {
_end = _pos+1;
return;
} else if (_exception_klass == NULL || !handler->catch_klass()->is_loaded()) {
return;
} else if (_exception_klass->is_subtype_of(handler->catch_klass())) {
_end = _pos+1;
return;
} else if (!_is_exact &&
handler->catch_klass()->is_subtype_of(_exception_klass)) {
return;
}
}
_pos++;
}
} else {
return;
}
}
ciExceptionHandler* handler() {
return _method->_exception_handlers[_pos];
}
};
Bytecode::Bytecode(const ciBytecodeStream* stream, address bcp): _bcp(bcp != NULL ? bcp : stream->cur_bcp()), _code(Bytecodes::code_at(NULL, addr_at(0))) {}
Bytecode_lookupswitch::Bytecode_lookupswitch(const ciBytecodeStream* stream): Bytecode(stream) { verify(); }
Bytecode_tableswitch::Bytecode_tableswitch(const ciBytecodeStream* stream): Bytecode(stream) { verify(); }
#endif // SHARE_VM_CI_CISTREAMS_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciSymbol.cpp
#include "precompiled.hpp"
#include "ci/ciSymbol.hpp"
#include "ci/ciUtilities.hpp"
#include "memory/oopFactory.hpp"
ciSymbol::ciSymbol(Symbol* s, vmSymbols::SID sid)
: _symbol(s), _sid(sid)
{
assert(_symbol != NULL, "adding null symbol");
_symbol->increment_refcount(); // increment ref count
assert(sid_ok(), "must be in vmSymbols");
}
ciSymbol::ciSymbol(Symbol* s)
: _symbol(s), _sid(vmSymbols::NO_SID)
{
assert(_symbol != NULL, "adding null symbol");
_symbol->increment_refcount(); // increment ref count
assert(sid_ok(), "must not be in vmSymbols");
}
const char* ciSymbol::as_utf8() {
VM_QUICK_ENTRY_MARK;
Symbol* s = get_symbol();
return s->as_utf8();
}
const char* ciSymbol::as_quoted_ascii() {
GUARDED_VM_QUICK_ENTRY(return get_symbol()->as_quoted_ascii();)
}
const jbyte* ciSymbol::base() {
GUARDED_VM_ENTRY(return get_symbol()->base();)
}
int ciSymbol::byte_at(int i) {
GUARDED_VM_ENTRY(return get_symbol()->byte_at(i);)
}
bool ciSymbol::starts_with(const char* prefix, int len) const {
GUARDED_VM_ENTRY(return get_symbol()->starts_with(prefix, len);)
}
bool ciSymbol::is_signature_polymorphic_name() const {
GUARDED_VM_ENTRY(return MethodHandles::is_signature_polymorphic_name(get_symbol());)
}
int ciSymbol::index_of_at(int i, const char* str, int len) const {
GUARDED_VM_ENTRY(return get_symbol()->index_of_at(i, str, len);)
}
int ciSymbol::utf8_length() {
GUARDED_VM_ENTRY(return get_symbol()->utf8_length();)
}
void ciSymbol::print_impl(outputStream* st) {
st->print(" value=");
print_symbol_on(st);
}
void ciSymbol::print_symbol_on(outputStream *st) {
GUARDED_VM_ENTRY(get_symbol()->print_symbol_on(st);)
}
ciSymbol* ciSymbol::make_impl(const char* s) {
EXCEPTION_CONTEXT;
TempNewSymbol sym = SymbolTable::new_symbol(s, THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
CURRENT_THREAD_ENV->record_out_of_memory_failure();
return ciEnv::_unloaded_cisymbol;
}
return CURRENT_THREAD_ENV->get_symbol(sym);
}
ciSymbol* ciSymbol::make(const char* s) {
GUARDED_VM_ENTRY(return make_impl(s);)
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciSymbol.hpp
#ifndef SHARE_VM_CI_CISYMBOL_HPP
#define SHARE_VM_CI_CISYMBOL_HPP
#include "ci/ciBaseObject.hpp"
#include "ci/ciObject.hpp"
#include "ci/ciObjectFactory.hpp"
#include "classfile/vmSymbols.hpp"
#include "oops/symbol.hpp"
class ciSymbol : public ciBaseObject {
Symbol* _symbol;
CI_PACKAGE_ACCESS
friend class ciEnv;
friend class ciInstanceKlass;
friend class ciSignature;
friend class ciMethod;
friend class ciField;
friend class ciObjArrayKlass;
private:
const vmSymbols::SID _sid;
DEBUG_ONLY( bool sid_ok() { return vmSymbols::find_sid(get_symbol()) == _sid; } )
ciSymbol(Symbol* s); // normal case, for symbols not mentioned in vmSymbols
ciSymbol(Symbol* s, vmSymbols::SID sid); // for use with vmSymbols
Symbol* get_symbol() const { return _symbol; }
const char* type_string() { return "ciSymbol"; }
void print_impl(outputStream* st);
const jbyte* base();
static ciSymbol* make_impl(const char* s);
public:
vmSymbols::SID sid() const { return _sid; }
const char* as_utf8();
int utf8_length();
const char* as_quoted_ascii();
int byte_at(int i);
bool starts_with(const char* prefix, int len) const;
int index_of_at(int i, const char* str, int len) const;
void print_symbol_on(outputStream* st);
void print_symbol() {
print_symbol_on(tty);
}
static ciSymbol* make(const char* s);
#define CI_SYMBOL_DECLARE(name, ignore_def) \
static ciSymbol* name() { return ciObjectFactory::vm_symbol_at(vmSymbols::VM_SYMBOL_ENUM_NAME(name)); }
VM_SYMBOLS_DO(CI_SYMBOL_DECLARE, CI_SYMBOL_DECLARE)
#undef CI_SYMBOL_DECLARE
void print() {
_symbol->print();
}
virtual bool is_symbol() const { return true; }
bool equals(ciSymbol* obj) { return this->_symbol == obj->get_symbol(); }
bool is_signature_polymorphic_name() const;
};
#endif // SHARE_VM_CI_CISYMBOL_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciType.cpp
#include "precompiled.hpp"
#include "ci/ciEnv.hpp"
#include "ci/ciType.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/systemDictionary.hpp"
#include "oops/oop.inline.hpp"
ciType* ciType::_basic_types[T_CONFLICT+1];
ciType::ciType(BasicType basic_type) : ciMetadata() {
assert(basic_type >= T_BOOLEAN && basic_type <= T_CONFLICT, "range check");
_basic_type = basic_type;
}
ciType::ciType(KlassHandle k) : ciMetadata(k()) {
_basic_type = k()->oop_is_array() ? T_ARRAY : T_OBJECT;
}
bool ciType::is_subtype_of(ciType* type) {
if (this == type) return true;
if (is_klass() && type->is_klass())
return this->as_klass()->is_subtype_of(type->as_klass());
return false;
}
const char* ciType::name() {
if (is_primitive_type()) {
return type2name(basic_type());
} else {
assert(is_klass(), "must be");
return as_klass()->name()->as_utf8();
}
}
void ciType::print_impl(outputStream* st) {
st->print(" type=");
print_name_on(st);
}
void ciType::print_name_on(outputStream* st) {
ResourceMark rm;
st->print("%s", name());
}
ciInstance* ciType::java_mirror() {
VM_ENTRY_MARK;
return CURRENT_THREAD_ENV->get_instance(Universe::java_mirror(basic_type()));
}
ciKlass* ciType::box_klass() {
if (!is_primitive_type()) return this->as_klass(); // reference types are "self boxing"
if (basic_type() == T_VOID) return NULL;
VM_ENTRY_MARK;
return CURRENT_THREAD_ENV->get_instance_klass(SystemDictionary::box_klass(basic_type()));
}
ciType* ciType::make(BasicType t) {
assert((uint)t < T_CONFLICT+1, "range check");
if (t == T_OBJECT) return ciEnv::_Object_klass; // java/lang/Object
assert(_basic_types[t] != NULL, "domain check");
return _basic_types[t];
}
ciReturnAddress::ciReturnAddress(int bci) : ciType(T_ADDRESS) {
assert(0 <= bci, "bci cannot be negative");
_bci = bci;
}
void ciReturnAddress::print_impl(outputStream* st) {
st->print(" bci=%d", _bci);
}
ciReturnAddress* ciReturnAddress::make(int bci) {
GUARDED_VM_ENTRY(return CURRENT_ENV->get_return_address(bci);)
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciType.hpp
#ifndef SHARE_VM_CI_CITYPE_HPP
#define SHARE_VM_CI_CITYPE_HPP
#include "ci/ciMetadata.hpp"
class ciType : public ciMetadata {
CI_PACKAGE_ACCESS
friend class ciKlass;
friend class ciReturnAddress;
private:
BasicType _basic_type;
ciType(BasicType t); // for primitive and unloaded types
ciType(KlassHandle k); // for subclasses (reference types)
const char* type_string() { return "ciType"; }
void print_impl(outputStream* st);
static ciType* _basic_types[T_CONFLICT+1];
public:
BasicType basic_type() const { return _basic_type; }
bool is_subtype_of(ciType* type);
virtual ciInstance* java_mirror();
ciKlass* box_klass();
bool is_primitive_type() const { return basic_type() != T_OBJECT && basic_type() != T_ARRAY; }
int size() const { return type2size[basic_type()]; }
bool is_void() const { return basic_type() == T_VOID; }
bool is_one_word() const { return size() == 1; }
bool is_two_word() const { return size() == 2; }
bool is_type() const { return true; }
bool is_classless() const { return is_primitive_type(); }
const char* name();
virtual void print_name_on(outputStream* st);
void print_name() {
print_name_on(tty);
}
static ciType* make(BasicType t);
};
class ciReturnAddress : public ciType {
CI_PACKAGE_ACCESS
private:
int _bci;
ciReturnAddress(int bci);
const char* type_string() { return "ciReturnAddress"; }
void print_impl(outputStream* st);
public:
bool is_return_address() const { return true; }
int bci() { return _bci; }
static ciReturnAddress* make(int bci);
};
#endif // SHARE_VM_CI_CITYPE_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciTypeArray.cpp
#include "precompiled.hpp"
#include "ci/ciTypeArray.hpp"
#include "ci/ciUtilities.hpp"
jchar ciTypeArray::char_at(int index) {
VM_ENTRY_MARK;
assert(index >= 0 && index < length(), "out of range");
jchar c = get_typeArrayOop()->char_at(index);
#ifdef ASSERT
jchar d = element_value(index).as_char();
assert(c == d, "");
#endif //ASSERT
return c;
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciTypeArray.hpp
#ifndef SHARE_VM_CI_CITYPEARRAY_HPP
#define SHARE_VM_CI_CITYPEARRAY_HPP
#include "ci/ciArray.hpp"
#include "ci/ciClassList.hpp"
#include "oops/typeArrayOop.hpp"
class ciTypeArray : public ciArray {
CI_PACKAGE_ACCESS
protected:
ciTypeArray(typeArrayHandle h_t) : ciArray(h_t) {}
ciTypeArray(ciKlass* klass, int len) : ciArray(klass, len) {}
typeArrayOop get_typeArrayOop() {
return (typeArrayOop)get_oop();
}
const char* type_string() { return "ciTypeArray"; }
public:
bool is_type_array() { return true; }
jchar char_at(int index);
};
#endif // SHARE_VM_CI_CITYPEARRAY_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciTypeArrayKlass.cpp
#include "precompiled.hpp"
#include "ci/ciTypeArrayKlass.hpp"
#include "ci/ciUtilities.hpp"
ciTypeArrayKlass::ciTypeArrayKlass(KlassHandle h_k) : ciArrayKlass(h_k) {
assert(get_Klass()->oop_is_typeArray(), "wrong type");
assert(element_type() == get_TypeArrayKlass()->element_type(), "");
}
ciTypeArrayKlass* ciTypeArrayKlass::make_impl(BasicType t) {
Klass* k = Universe::typeArrayKlassObj(t);
return CURRENT_ENV->get_type_array_klass(k);
}
ciTypeArrayKlass* ciTypeArrayKlass::make(BasicType t) {
GUARDED_VM_ENTRY(return make_impl(t);)
}
C:\hotspot-69087d08d473\src\share\vm/ci/ciTypeArrayKlass.hpp
#ifndef SHARE_VM_CI_CITYPEARRAYKLASS_HPP
#define SHARE_VM_CI_CITYPEARRAYKLASS_HPP
#include "ci/ciArrayKlass.hpp"
class ciTypeArrayKlass : public ciArrayKlass {
CI_PACKAGE_ACCESS
protected:
ciTypeArrayKlass(KlassHandle h_k);
TypeArrayKlass* get_TypeArrayKlass() {
return (TypeArrayKlass*)get_Klass();
}
const char* type_string() { return "ciTypeArrayKlass"; }
static ciTypeArrayKlass* make_impl(BasicType type);
public:
BasicType element_type() {
return Klass::layout_helper_element_type(layout_helper());
}
bool is_type_array_klass() const { return true; }
static ciTypeArrayKlass* make(BasicType type);
virtual ciKlass* exact_klass() {
return this;
}
};
#endif // SHARE_VM_CI_CITYPEARRAYKLASS_HPP
C:\hotspot-69087d08d473\src\share\vm/ci/ciTypeFlow.cpp
#include "precompiled.hpp"
#include "ci/ciConstant.hpp"
#include "ci/ciField.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciMethodData.hpp"
#include "ci/ciObjArrayKlass.hpp"
#include "ci/ciStreams.hpp"
#include "ci/ciTypeArrayKlass.hpp"
#include "ci/ciTypeFlow.hpp"
#include "compiler/compileLog.hpp"
#include "interpreter/bytecode.hpp"
#include "interpreter/bytecodes.hpp"
#include "memory/allocation.inline.hpp"
#include "opto/compile.hpp"
#include "opto/node.hpp"
#include "runtime/deoptimization.hpp"
#include "utilities/growableArray.hpp"
ciTypeFlow::JsrSet::JsrSet(Arena* arena, int default_len) {
if (arena != NULL) {
_set = new (arena) GrowableArray<JsrRecord*>(arena, default_len, 0, NULL);
} else {
_set = new GrowableArray<JsrRecord*>(4, 0, NULL, false);
}
}
void ciTypeFlow::JsrSet::copy_into(JsrSet* jsrs) {
int len = size();
jsrs->_set->clear();
for (int i = 0; i < len; i++) {
jsrs->_set->append(_set->at(i));
}
}
bool ciTypeFlow::JsrSet::is_compatible_with(JsrSet* other) {
int size1 = size();
int size2 = other->size();
if (size2 == 0) {
return true;
} else if (size1 != size2) {
return false;
} else {
for (int i = 0; i < size1; i++) {
JsrRecord* record1 = record_at(i);
JsrRecord* record2 = other->record_at(i);
if (record1->entry_address() != record2->entry_address() ||
record1->return_address() != record2->return_address()) {
return false;
}
}
return true;
}
#if 0
int pos1 = 0;
int pos2 = 0;
int size1 = size();
int size2 = other->size();
while (pos1 < size1 && pos2 < size2) {
JsrRecord* record1 = record_at(pos1);
JsrRecord* record2 = other->record_at(pos2);
int entry1 = record1->entry_address();
int entry2 = record2->entry_address();
if (entry1 < entry2) {
pos1++;
} else if (entry1 > entry2) {
pos2++;
} else {
if (record1->return_address() == record2->return_address()) {
pos1++;
pos2++;
} else {
return false;
}
}
}
return true;
#endif
}
void ciTypeFlow::JsrSet::insert_jsr_record(JsrRecord* record) {
int len = size();
int entry = record->entry_address();
int pos = 0;
for ( ; pos < len; pos++) {
JsrRecord* current = record_at(pos);
if (entry == current->entry_address()) {
_set->at_put(pos, record);
assert(size() == len, "must be same size");
return;
} else if (entry < current->entry_address()) {
break;
}
}
JsrRecord* swap = record;
JsrRecord* temp = NULL;
for ( ; pos < len; pos++) {
temp = _set->at(pos);
_set->at_put(pos, swap);
swap = temp;
}
_set->append(swap);
assert(size() == len+1, "must be larger");
}
void ciTypeFlow::JsrSet::remove_jsr_record(int return_address) {
int len = size();
for (int i = 0; i < len; i++) {
if (record_at(i)->return_address() == return_address) {
for (int j = i+1; j < len ; j++) {
_set->at_put(j-1, _set->at(j));
}
_set->trunc_to(len-1);
assert(size() == len-1, "must be smaller");
return;
}
}
assert(false, "verify: returning from invalid subroutine");
}
void ciTypeFlow::JsrSet::apply_control(ciTypeFlow* analyzer,
ciBytecodeStream* str,
ciTypeFlow::StateVector* state) {
Bytecodes::Code code = str->cur_bc();
if (code == Bytecodes::_jsr) {
JsrRecord* record =
analyzer->make_jsr_record(str->get_dest(), str->next_bci());
insert_jsr_record(record);
} else if (code == Bytecodes::_jsr_w) {
JsrRecord* record =
analyzer->make_jsr_record(str->get_far_dest(), str->next_bci());
insert_jsr_record(record);
} else if (code == Bytecodes::_ret) {
Cell local = state->local(str->get_index());
ciType* return_address = state->type_at(local);
assert(return_address->is_return_address(), "verify: wrong type");
if (size() == 0) {
analyzer->record_failure("OSR in finally clause");
return;
}
remove_jsr_record(return_address->as_return_address()->bci());
}
}
#ifndef PRODUCT
void ciTypeFlow::JsrSet::print_on(outputStream* st) const {
st->print("{ ");
int num_elements = size();
if (num_elements > 0) {
int i = 0;
for( ; i < num_elements - 1; i++) {
_set->at(i)->print_on(st);
st->print(", ");
}
_set->at(i)->print_on(st);
st->print(" ");
}
st->print("}");
}
#endif
ciType* ciTypeFlow::StateVector::type_meet_internal(ciType* t1, ciType* t2, ciTypeFlow* analyzer) {
assert(t1 != t2, "checked in caller");
if (t1->equals(top_type())) {
return t2;
} else if (t2->equals(top_type())) {
return t1;
} else if (t1->is_primitive_type() || t2->is_primitive_type()) {
if (t1->equals(null_type())) {
if (!t2->is_primitive_type() || t2->equals(null_type())) {
return t2;
}
} else if (t2->equals(null_type())) {
if (!t1->is_primitive_type()) {
return t1;
}
}
return bottom_type();
} else {
ciKlass* object_klass = analyzer->env()->Object_klass();
ciKlass* k1 = t1->as_klass();
ciKlass* k2 = t2->as_klass();
if (k1->equals(object_klass) || k2->equals(object_klass)) {
return object_klass;
} else if (!k1->is_loaded() || !k2->is_loaded()) {
return object_klass;
} else if (k1->is_interface() != k2->is_interface()) {
return object_klass;
} else if (k1->is_array_klass() || k2->is_array_klass()) {
if (k1->is_obj_array_klass() && k2->is_obj_array_klass()) {
ciKlass* elem1 = k1->as_obj_array_klass()->element_klass();
ciKlass* elem2 = k2->as_obj_array_klass()->element_klass();
ciKlass* elem = type_meet_internal(elem1, elem2, analyzer)->as_klass();
if (elem == elem1) {
assert(k1 == ciObjArrayKlass::make(elem), "shortcut is OK");
return k1;
} else if (elem == elem2) {
assert(k2 == ciObjArrayKlass::make(elem), "shortcut is OK");
return k2;
} else {
return ciObjArrayKlass::make(elem);
}
} else {
return object_klass;
}
} else {
assert(k1->is_instance_klass(), "previous cases handle non-instances");
assert(k2->is_instance_klass(), "previous cases handle non-instances");
return k1->least_common_ancestor(k2);
}
}
}
ciTypeFlow::StateVector::StateVector(ciTypeFlow* analyzer) {
_outer = analyzer;
_stack_size = -1;
_monitor_count = -1;
int max_cells = analyzer->max_cells();
_types = (ciType**)analyzer->arena()->Amalloc(sizeof(ciType*) * max_cells);
for (int i=0; i<max_cells; i++) {
_types[i] = top_type();
}
_trap_bci = -1;
_trap_index = 0;
_def_locals.clear();
}
const ciTypeFlow::StateVector* ciTypeFlow::get_start_state() {
StateVector* state = new StateVector(this);
if (is_osr_flow()) {
ciTypeFlow* non_osr_flow = method()->get_flow_analysis();
if (non_osr_flow->failing()) {
record_failure(non_osr_flow->failure_reason());
return NULL;
}
JsrSet* jsrs = new JsrSet(NULL, 16);
Block* non_osr_block = non_osr_flow->existing_block_at(start_bci(), jsrs);
if (non_osr_block == NULL) {
record_failure("cannot reach OSR point");
return NULL;
}
non_osr_block->copy_state_into(state);
int non_osr_start = non_osr_block->start();
if (non_osr_start != start_bci()) {
if (CITraceTypeFlow) {
tty->print_cr(">> Interpreting pre-OSR block %d:", non_osr_start);
}
Block* block = block_at(non_osr_start, jsrs);
assert(block->limit() == start_bci(), "must flow forward to start");
flow_block(block, state, jsrs);
}
return state;
}
state->set_stack_size(-max_locals());
if (!method()->is_static()) {
state->push(method()->holder());
assert(state->tos() == state->local(0), "");
}
for (ciSignatureStream str(method()->signature());
!str.at_return_type();
str.next()) {
state->push_translate(str.type());
}
Cell cell = state->next_cell(state->tos());
state->set_stack_size(0);
int limit = state->limit_cell();
for (; cell < limit; cell = state->next_cell(cell)) {
state->set_type_at(cell, state->bottom_type());
}
state->set_monitor_count(method()->is_synchronized() ? 1 : 0);
return state;
}
void ciTypeFlow::StateVector::copy_into(ciTypeFlow::StateVector* copy)
const {
copy->set_stack_size(stack_size());
copy->set_monitor_count(monitor_count());
Cell limit = limit_cell();
for (Cell c = start_cell(); c < limit; c = next_cell(c)) {
copy->set_type_at(c, type_at(c));
}
}
bool ciTypeFlow::StateVector::meet(const ciTypeFlow::StateVector* incoming) {
if (monitor_count() == -1) {
set_monitor_count(incoming->monitor_count());
}
assert(monitor_count() == incoming->monitor_count(), "monitors must match");
if (stack_size() == -1) {
set_stack_size(incoming->stack_size());
Cell limit = limit_cell();
#ifdef ASSERT
{ for (Cell c = start_cell(); c < limit; c = next_cell(c)) {
assert(type_at(c) == top_type(), "");
} }
#endif
for (Cell c = start_cell(); c < limit; c = next_cell(c)) {
set_type_at(c, incoming->type_at(c));
}
return true; // it is always different the first time
}
#ifdef ASSERT
if (stack_size() != incoming->stack_size()) {
_outer->method()->print_codes();
tty->print_cr("!!!! Stack size conflict");
tty->print_cr("Current state:");
print_on(tty);
tty->print_cr("Incoming state:");
((StateVector*)incoming)->print_on(tty);
}
#endif
assert(stack_size() == incoming->stack_size(), "sanity");
bool different = false;
Cell limit = limit_cell();
for (Cell c = start_cell(); c < limit; c = next_cell(c)) {
ciType* t1 = type_at(c);
ciType* t2 = incoming->type_at(c);
if (!t1->equals(t2)) {
ciType* new_type = type_meet(t1, t2);
if (!t1->equals(new_type)) {
set_type_at(c, new_type);
different = true;
}
}
}
return different;
}
bool ciTypeFlow::StateVector::meet_exception(ciInstanceKlass* exc,
const ciTypeFlow::StateVector* incoming) {
if (monitor_count() == -1) {
set_monitor_count(incoming->monitor_count());
}
assert(monitor_count() == incoming->monitor_count(), "monitors must match");
if (stack_size() == -1) {
set_stack_size(1);
}
assert(stack_size() == 1, "must have one-element stack");
bool different = false;
Cell limit = local(_outer->max_locals()-1);
for (Cell c = start_cell(); c <= limit; c = next_cell(c)) {
ciType* t1 = type_at(c);
ciType* t2 = incoming->type_at(c);
if (!t1->equals(t2)) {
ciType* new_type = type_meet(t1, t2);
if (!t1->equals(new_type)) {
set_type_at(c, new_type);
different = true;
}
}
}
ciType* tos_type = type_at_tos();
if (!tos_type->equals(exc)) {
ciType* new_type = type_meet(tos_type, exc);
if (!tos_type->equals(new_type)) {
set_type_at_tos(new_type);
different = true;
}
}
return different;
}
void ciTypeFlow::StateVector::push_translate(ciType* type) {
BasicType basic_type = type->basic_type();
if (basic_type == T_BOOLEAN || basic_type == T_CHAR ||
basic_type == T_BYTE || basic_type == T_SHORT) {
push_int();
} else {
push(type);
if (type->is_two_word()) {
push(half_type(type));
}
}
}
void ciTypeFlow::StateVector::do_aaload(ciBytecodeStream* str) {
pop_int();
ciObjArrayKlass* array_klass = pop_objArray();
if (array_klass == NULL) {
push(null_type());
return;
}
if (!array_klass->is_loaded()) {
trap(str, array_klass,
Deoptimization::make_trap_request
(Deoptimization::Reason_unloaded,
Deoptimization::Action_reinterpret));
return;
}
ciKlass* element_klass = array_klass->element_klass();
if (!element_klass->is_loaded() && element_klass->is_instance_klass()) {
Untested("unloaded array element class in ciTypeFlow");
trap(str, element_klass,
Deoptimization::make_trap_request
(Deoptimization::Reason_unloaded,
Deoptimization::Action_reinterpret));
} else {
push_object(element_klass);
}
}
void ciTypeFlow::StateVector::do_checkcast(ciBytecodeStream* str) {
bool will_link;
ciKlass* klass = str->get_klass(will_link);
if (!will_link) {
pop_object();
do_null_assert(klass);
} else {
pop_object();
push_object(klass);
}
}
void ciTypeFlow::StateVector::do_getfield(ciBytecodeStream* str) {
pop_object();
do_getstatic(str);
}
void ciTypeFlow::StateVector::do_getstatic(ciBytecodeStream* str) {
bool will_link;
ciField* field = str->get_field(will_link);
if (!will_link) {
trap(str, field->holder(), str->get_field_holder_index());
} else {
ciType* field_type = field->type();
if (!field_type->is_loaded()) {
do_null_assert(field_type->as_klass());
} else {
push_translate(field_type);
}
}
}
void ciTypeFlow::StateVector::do_invoke(ciBytecodeStream* str,
bool has_receiver) {
bool will_link;
ciSignature* declared_signature = NULL;
ciMethod* callee = str->get_method(will_link, &declared_signature);
assert(declared_signature != NULL, "cannot be null");
if (!will_link) {
if (str->cur_bc() == Bytecodes::_invokedynamic) {
trap(str, NULL,
Deoptimization::make_trap_request
(Deoptimization::Reason_uninitialized,
Deoptimization::Action_reinterpret));
} else {
ciKlass* unloaded_holder = callee->holder();
trap(str, unloaded_holder, str->get_method_holder_index());
}
} else {
ciSignatureStream sigstr(declared_signature);
const int arg_size = declared_signature->size();
const int stack_base = stack_size() - arg_size;
int i = 0;
for( ; !sigstr.at_return_type(); sigstr.next()) {
ciType* type = sigstr.type();
ciType* stack_type = type_at(stack(stack_base + i++));
if (type->is_two_word()) {
ciType* stack_type2 = type_at(stack(stack_base + i++));
assert(stack_type2->equals(half_type(type)), "must be 2nd half");
}
}
assert(arg_size == i, "must match");
for (int j = 0; j < arg_size; j++) {
pop();
}
if (has_receiver) {
pop_object();
}
assert(!sigstr.is_done(), "must have return type");
ciType* return_type = sigstr.type();
if (!return_type->is_void()) {
if (!return_type->is_loaded()) {
do_null_assert(return_type->as_klass());
} else {
push_translate(return_type);
}
}
}
}
void ciTypeFlow::StateVector::do_jsr(ciBytecodeStream* str) {
push(ciReturnAddress::make(str->next_bci()));
}
void ciTypeFlow::StateVector::do_ldc(ciBytecodeStream* str) {
ciConstant con = str->get_constant();
BasicType basic_type = con.basic_type();
if (basic_type == T_ILLEGAL) {
push_null();
outer()->record_failure("ldc did not link");
return;
}
if (basic_type == T_OBJECT || basic_type == T_ARRAY) {
ciObject* obj = con.as_object();
if (obj->is_null_object()) {
push_null();
} else {
assert(obj->is_instance() || obj->is_array(), "must be java_mirror of klass");
push_object(obj->klass());
}
} else {
push_translate(ciType::make(basic_type));
}
}
void ciTypeFlow::StateVector::do_multianewarray(ciBytecodeStream* str) {
int dimensions = str->get_dimensions();
bool will_link;
ciArrayKlass* array_klass = str->get_klass(will_link)->as_array_klass();
if (!will_link) {
trap(str, array_klass, str->get_klass_index());
} else {
for (int i = 0; i < dimensions; i++) {
pop_int();
}
push_object(array_klass);
}
}
void ciTypeFlow::StateVector::do_new(ciBytecodeStream* str) {
bool will_link;
ciKlass* klass = str->get_klass(will_link);
if (!will_link || str->is_unresolved_klass()) {
trap(str, klass, str->get_klass_index());
} else {
push_object(klass);
}
}
void ciTypeFlow::StateVector::do_newarray(ciBytecodeStream* str) {
pop_int();
ciKlass* klass = ciTypeArrayKlass::make((BasicType)str->get_index());
push_object(klass);
}
void ciTypeFlow::StateVector::do_putfield(ciBytecodeStream* str) {
do_putstatic(str);
if (_trap_bci != -1) return; // unloaded field holder, etc.
pop_object();
}
void ciTypeFlow::StateVector::do_putstatic(ciBytecodeStream* str) {
bool will_link;
ciField* field = str->get_field(will_link);
if (!will_link) {
trap(str, field->holder(), str->get_field_holder_index());
} else {
ciType* field_type = field->type();
ciType* type = pop_value();
if (field_type->is_two_word()) {
ciType* type2 = pop_value();
assert(type2->is_two_word(), "must be 2nd half");
assert(type == half_type(type2), "must be 2nd half");
}
}
}
void ciTypeFlow::StateVector::do_ret(ciBytecodeStream* str) {
Cell index = local(str->get_index());
ciType* address = type_at(index);
assert(address->is_return_address(), "bad return address");
set_type_at(index, bottom_type());
}
void ciTypeFlow::StateVector::trap(ciBytecodeStream* str, ciKlass* klass, int index) {
_trap_bci = str->cur_bci();
_trap_index = index;
CompileLog* log = outer()->env()->log();
if (log != NULL) {
int mid = log->identify(outer()->method());
int kid = (klass == NULL)? -1: log->identify(klass);
log->begin_elem("uncommon_trap method='%d' bci='%d'", mid, str->cur_bci());
char buf[100];
log->print(" %s", Deoptimization::format_trap_request(buf, sizeof(buf),
index));
if (kid >= 0)
log->print(" klass='%d'", kid);
log->end_elem();
}
}
void ciTypeFlow::StateVector::do_null_assert(ciKlass* unloaded_klass) {
if (unloaded_klass->is_loaded()) {
push_object(unloaded_klass);
} else {
push_null();
}
}
bool ciTypeFlow::StateVector::apply_one_bytecode(ciBytecodeStream* str) {
_trap_bci = -1;
_trap_index = 0;
if (CITraceTypeFlow) {
tty->print_cr(">> Interpreting bytecode %d:%s", str->cur_bci(),
Bytecodes::name(str->cur_bc()));
}
switch(str->cur_bc()) {
case Bytecodes::_aaload: do_aaload(str); break;
case Bytecodes::_aastore:
{
pop_object();
pop_int();
pop_objArray();
break;
}
case Bytecodes::_aconst_null:
{
push_null();
break;
}
case Bytecodes::_aload: load_local_object(str->get_index()); break;
case Bytecodes::_aload_0: load_local_object(0); break;
case Bytecodes::_aload_1: load_local_object(1); break;
case Bytecodes::_aload_2: load_local_object(2); break;
case Bytecodes::_aload_3: load_local_object(3); break;
case Bytecodes::_anewarray:
{
pop_int();
bool will_link;
ciKlass* element_klass = str->get_klass(will_link);
if (!will_link) {
trap(str, element_klass, str->get_klass_index());
} else {
push_object(ciObjArrayKlass::make(element_klass));
}
break;
}
case Bytecodes::_areturn:
case Bytecodes::_ifnonnull:
case Bytecodes::_ifnull:
{
pop_object();
break;
}
case Bytecodes::_monitorenter:
{
pop_object();
set_monitor_count(monitor_count() + 1);
break;
}
case Bytecodes::_monitorexit:
{
pop_object();
assert(monitor_count() > 0, "must be a monitor to exit from");
set_monitor_count(monitor_count() - 1);
break;
}
case Bytecodes::_arraylength:
{
pop_array();
push_int();
break;
}
case Bytecodes::_astore: store_local_object(str->get_index()); break;
case Bytecodes::_astore_0: store_local_object(0); break;
case Bytecodes::_astore_1: store_local_object(1); break;
case Bytecodes::_astore_2: store_local_object(2); break;
case Bytecodes::_astore_3: store_local_object(3); break;
case Bytecodes::_athrow:
{
NEEDS_CLEANUP;
pop_object();
break;
}
case Bytecodes::_baload:
case Bytecodes::_caload:
case Bytecodes::_iaload:
case Bytecodes::_saload:
{
pop_int();
ciTypeArrayKlass* array_klass = pop_typeArray();
push_int();
break;
}
case Bytecodes::_bastore:
case Bytecodes::_castore:
case Bytecodes::_iastore:
case Bytecodes::_sastore:
{
pop_int();
pop_int();
pop_typeArray();
break;
}
case Bytecodes::_bipush:
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::_sipush:
{
push_int();
break;
}
case Bytecodes::_checkcast: do_checkcast(str); break;
case Bytecodes::_d2f:
{
pop_double();
push_float();
break;
}
case Bytecodes::_d2i:
{
pop_double();
push_int();
break;
}
case Bytecodes::_d2l:
{
pop_double();
push_long();
break;
}
case Bytecodes::_dadd:
case Bytecodes::_ddiv:
case Bytecodes::_dmul:
case Bytecodes::_drem:
case Bytecodes::_dsub:
{
pop_double();
pop_double();
push_double();
break;
}
case Bytecodes::_daload:
{
pop_int();
ciTypeArrayKlass* array_klass = pop_typeArray();
push_double();
break;
}
case Bytecodes::_dastore:
{
pop_double();
pop_int();
pop_typeArray();
break;
}
case Bytecodes::_dcmpg:
case Bytecodes::_dcmpl:
{
pop_double();
pop_double();
push_int();
break;
}
case Bytecodes::_dconst_0:
case Bytecodes::_dconst_1:
{
push_double();
break;
}
case Bytecodes::_dload: load_local_double(str->get_index()); break;
case Bytecodes::_dload_0: load_local_double(0); break;
case Bytecodes::_dload_1: load_local_double(1); break;
case Bytecodes::_dload_2: load_local_double(2); break;
case Bytecodes::_dload_3: load_local_double(3); break;
case Bytecodes::_dneg:
{
pop_double();
push_double();
break;
}
case Bytecodes::_dreturn:
{
pop_double();
break;
}
case Bytecodes::_dstore: store_local_double(str->get_index()); break;
case Bytecodes::_dstore_0: store_local_double(0); break;
case Bytecodes::_dstore_1: store_local_double(1); break;
case Bytecodes::_dstore_2: store_local_double(2); break;
case Bytecodes::_dstore_3: store_local_double(3); break;
case Bytecodes::_dup:
{
push(type_at_tos());
break;
}
case Bytecodes::_dup_x1:
{
ciType* value1 = pop_value();
ciType* value2 = pop_value();
push(value1);
push(value2);
push(value1);
break;
}
case Bytecodes::_dup_x2:
{
ciType* value1 = pop_value();
ciType* value2 = pop_value();
ciType* value3 = pop_value();
push(value1);
push(value3);
push(value2);
push(value1);
break;
}
case Bytecodes::_dup2:
{
ciType* value1 = pop_value();
ciType* value2 = pop_value();
push(value2);
push(value1);
push(value2);
push(value1);
break;
}
case Bytecodes::_dup2_x1:
{
ciType* value1 = pop_value();
ciType* value2 = pop_value();
ciType* value3 = pop_value();
push(value2);
push(value1);
push(value3);
push(value2);
push(value1);
break;
}
case Bytecodes::_dup2_x2:
{
ciType* value1 = pop_value();
ciType* value2 = pop_value();
ciType* value3 = pop_value();
ciType* value4 = pop_value();
push(value2);
push(value1);
push(value4);
push(value3);
push(value2);
push(value1);
break;
}
case Bytecodes::_f2d:
{
pop_float();
push_double();
break;
}
case Bytecodes::_f2i:
{
pop_float();
push_int();
break;
}
case Bytecodes::_f2l:
{
pop_float();
push_long();
break;
}
case Bytecodes::_fadd:
case Bytecodes::_fdiv:
case Bytecodes::_fmul:
case Bytecodes::_frem:
case Bytecodes::_fsub:
{
pop_float();
pop_float();
push_float();
break;
}
case Bytecodes::_faload:
{
pop_int();
ciTypeArrayKlass* array_klass = pop_typeArray();
push_float();
break;
}
case Bytecodes::_fastore:
{
pop_float();
pop_int();
ciTypeArrayKlass* array_klass = pop_typeArray();
break;
}
case Bytecodes::_fcmpg:
case Bytecodes::_fcmpl:
{
pop_float();
pop_float();
push_int();
break;
}
case Bytecodes::_fconst_0:
case Bytecodes::_fconst_1:
case Bytecodes::_fconst_2:
{
push_float();
break;
}
case Bytecodes::_fload: load_local_float(str->get_index()); break;
case Bytecodes::_fload_0: load_local_float(0); break;
case Bytecodes::_fload_1: load_local_float(1); break;
case Bytecodes::_fload_2: load_local_float(2); break;
case Bytecodes::_fload_3: load_local_float(3); break;
case Bytecodes::_fneg:
{
pop_float();
push_float();
break;
}
case Bytecodes::_freturn:
{
pop_float();
break;
}
case Bytecodes::_fstore: store_local_float(str->get_index()); break;
case Bytecodes::_fstore_0: store_local_float(0); break;
case Bytecodes::_fstore_1: store_local_float(1); break;
case Bytecodes::_fstore_2: store_local_float(2); break;
case Bytecodes::_fstore_3: store_local_float(3); break;
case Bytecodes::_getfield: do_getfield(str); break;
case Bytecodes::_getstatic: do_getstatic(str); break;
case Bytecodes::_goto:
case Bytecodes::_goto_w:
case Bytecodes::_nop:
case Bytecodes::_return:
{
break;
}
case Bytecodes::_i2b:
case Bytecodes::_i2c:
case Bytecodes::_i2s:
case Bytecodes::_ineg:
{
pop_int();
push_int();
break;
}
case Bytecodes::_i2d:
{
pop_int();
push_double();
break;
}
case Bytecodes::_i2f:
{
pop_int();
push_float();
break;
}
case Bytecodes::_i2l:
{
pop_int();
push_long();
break;
}
case Bytecodes::_iadd:
case Bytecodes::_iand:
case Bytecodes::_idiv:
case Bytecodes::_imul:
case Bytecodes::_ior:
case Bytecodes::_irem:
case Bytecodes::_ishl:
case Bytecodes::_ishr:
case Bytecodes::_isub:
case Bytecodes::_iushr:
case Bytecodes::_ixor:
{
pop_int();
pop_int();
push_int();
break;
}
case Bytecodes::_if_acmpeq:
case Bytecodes::_if_acmpne:
{
pop_object();
pop_object();
break;
}
case Bytecodes::_if_icmpeq:
case Bytecodes::_if_icmpge:
case Bytecodes::_if_icmpgt:
case Bytecodes::_if_icmple:
case Bytecodes::_if_icmplt:
case Bytecodes::_if_icmpne:
{
pop_int();
pop_int();
break;
}
case Bytecodes::_ifeq:
case Bytecodes::_ifle:
case Bytecodes::_iflt:
case Bytecodes::_ifge:
case Bytecodes::_ifgt:
case Bytecodes::_ifne:
case Bytecodes::_ireturn:
case Bytecodes::_lookupswitch:
case Bytecodes::_tableswitch:
{
pop_int();
break;
}
case Bytecodes::_iinc:
{
int lnum = str->get_index();
check_int(local(lnum));
store_to_local(lnum);
break;
}
case Bytecodes::_iload: load_local_int(str->get_index()); break;
case Bytecodes::_iload_0: load_local_int(0); break;
case Bytecodes::_iload_1: load_local_int(1); break;
case Bytecodes::_iload_2: load_local_int(2); break;
case Bytecodes::_iload_3: load_local_int(3); break;
case Bytecodes::_instanceof:
{
do_checkcast(str);
pop_object();
push_int();
break;
}
case Bytecodes::_invokeinterface: do_invoke(str, true); break;
case Bytecodes::_invokespecial: do_invoke(str, true); break;
case Bytecodes::_invokestatic: do_invoke(str, false); break;
case Bytecodes::_invokevirtual: do_invoke(str, true); break;
case Bytecodes::_invokedynamic: do_invoke(str, false); break;
case Bytecodes::_istore: store_local_int(str->get_index()); break;
case Bytecodes::_istore_0: store_local_int(0); break;
case Bytecodes::_istore_1: store_local_int(1); break;
case Bytecodes::_istore_2: store_local_int(2); break;
case Bytecodes::_istore_3: store_local_int(3); break;
case Bytecodes::_jsr:
case Bytecodes::_jsr_w: do_jsr(str); break;
case Bytecodes::_l2d:
{
pop_long();
push_double();
break;
}
case Bytecodes::_l2f:
{
pop_long();
push_float();
break;
}
case Bytecodes::_l2i:
{
pop_long();
push_int();
break;
}
case Bytecodes::_ladd:
case Bytecodes::_land:
case Bytecodes::_ldiv:
case Bytecodes::_lmul:
case Bytecodes::_lor:
case Bytecodes::_lrem:
case Bytecodes::_lsub:
case Bytecodes::_lxor:
{
pop_long();
pop_long();
push_long();
break;
}
case Bytecodes::_laload:
{
pop_int();
ciTypeArrayKlass* array_klass = pop_typeArray();
push_long();
break;
}
case Bytecodes::_lastore:
{
pop_long();
pop_int();
pop_typeArray();
break;
}
case Bytecodes::_lcmp:
{
pop_long();
pop_long();
push_int();
break;
}
case Bytecodes::_lconst_0:
case Bytecodes::_lconst_1:
{
push_long();
break;
}
case Bytecodes::_ldc:
case Bytecodes::_ldc_w:
case Bytecodes::_ldc2_w:
{
do_ldc(str);
break;
}
case Bytecodes::_lload: load_local_long(str->get_index()); break;
case Bytecodes::_lload_0: load_local_long(0); break;
case Bytecodes::_lload_1: load_local_long(1); break;
case Bytecodes::_lload_2: load_local_long(2); break;
case Bytecodes::_lload_3: load_local_long(3); break;
case Bytecodes::_lneg:
{
pop_long();
push_long();
break;
}
case Bytecodes::_lreturn:
{
pop_long();
break;
}
case Bytecodes::_lshl:
case Bytecodes::_lshr:
case Bytecodes::_lushr:
{
pop_int();
pop_long();
push_long();
break;
}
case Bytecodes::_lstore: store_local_long(str->get_index()); break;
case Bytecodes::_lstore_0: store_local_long(0); break;
case Bytecodes::_lstore_1: store_local_long(1); break;
case Bytecodes::_lstore_2: store_local_long(2); break;
case Bytecodes::_lstore_3: store_local_long(3); break;
case Bytecodes::_multianewarray: do_multianewarray(str); break;
case Bytecodes::_new: do_new(str); break;
case Bytecodes::_newarray: do_newarray(str); break;
case Bytecodes::_pop:
{
pop();
break;
}
case Bytecodes::_pop2:
{
pop();
pop();
break;
}
case Bytecodes::_putfield: do_putfield(str); break;
case Bytecodes::_putstatic: do_putstatic(str); break;
case Bytecodes::_ret: do_ret(str); break;
case Bytecodes::_swap:
{
ciType* value1 = pop_value();
ciType* value2 = pop_value();
push(value1);
push(value2);
break;
}
case Bytecodes::_wide:
default:
{
ShouldNotReachHere();
break;
}
}
if (CITraceTypeFlow) {
print_on(tty);
}
return (_trap_bci != -1);
}
#ifndef PRODUCT
void ciTypeFlow::StateVector::print_cell_on(outputStream* st, Cell c) const {
ciType* type = type_at(c);
if (type == top_type()) {
st->print("top");
} else if (type == bottom_type()) {
st->print("bottom");
} else if (type == null_type()) {
st->print("null");
} else if (type == long2_type()) {
st->print("long2");
} else if (type == double2_type()) {
st->print("double2");
} else if (is_int(type)) {
st->print("int");
} else if (is_long(type)) {
st->print("long");
} else if (is_float(type)) {
st->print("float");
} else if (is_double(type)) {
st->print("double");
} else if (type->is_return_address()) {
st->print("address(%d)", type->as_return_address()->bci());
} else {
if (type->is_klass()) {
type->as_klass()->name()->print_symbol_on(st);
} else {
st->print("UNEXPECTED TYPE");
type->print();
}
}
}
void ciTypeFlow::StateVector::print_on(outputStream* st) const {
int num_locals = _outer->max_locals();
int num_stack = stack_size();
int num_monitors = monitor_count();
st->print_cr(" State : locals %d, stack %d, monitors %d", num_locals, num_stack, num_monitors);
if (num_stack >= 0) {
int i;
for (i = 0; i < num_locals; i++) {
st->print(" local %2d : ", i);
print_cell_on(st, local(i));
st->cr();
}
for (i = 0; i < num_stack; i++) {
st->print(" stack %2d : ", i);
print_cell_on(st, stack(i));
st->cr();
}
}
}
#endif
void ciTypeFlow::SuccIter::next() {
int succ_ct = _pred->successors()->length();
int next = _index + 1;
if (next < succ_ct) {
_index = next;
_succ = _pred->successors()->at(next);
return;
}
for (int i = next - succ_ct; i < _pred->exceptions()->length(); i++) {
ciInstanceKlass* exception_klass = _pred->exc_klasses()->at(i);
if (exception_klass->is_loaded()) {
_index = next;
_succ = _pred->exceptions()->at(i);
return;
}
next++;
}
_index = -1;
_succ = NULL;
}
void ciTypeFlow::SuccIter::set_succ(Block* succ) {
int succ_ct = _pred->successors()->length();
if (_index < succ_ct) {
_pred->successors()->at_put(_index, succ);
} else {
int idx = _index - succ_ct;
_pred->exceptions()->at_put(idx, succ);
}
}
ciTypeFlow::Block::Block(ciTypeFlow* outer,
ciBlock *ciblk,
ciTypeFlow::JsrSet* jsrs) {
_ciblock = ciblk;
_exceptions = NULL;
_exc_klasses = NULL;
_successors = NULL;
_state = new (outer->arena()) StateVector(outer);
JsrSet* new_jsrs =
new (outer->arena()) JsrSet(outer->arena(), jsrs->size());
jsrs->copy_into(new_jsrs);
_jsrs = new_jsrs;
_next = NULL;
_on_work_list = false;
_backedge_copy = false;
_has_monitorenter = false;
_trap_bci = -1;
_trap_index = 0;
df_init();
if (CITraceTypeFlow) {
tty->print_cr(">> Created new block");
print_on(tty);
}
assert(this->outer() == outer, "outer link set up");
assert(!outer->have_block_count(), "must not have mapped blocks yet");
}
void ciTypeFlow::Block::df_init() {
_pre_order = -1; assert(!has_pre_order(), "");
_post_order = -1; assert(!has_post_order(), "");
_loop = NULL;
_irreducible_entry = false;
_rpo_next = NULL;
}
GrowableArray<ciTypeFlow::Block*>*
ciTypeFlow::Block::successors(ciBytecodeStream* str,
ciTypeFlow::StateVector* state,
ciTypeFlow::JsrSet* jsrs) {
if (_successors == NULL) {
if (CITraceTypeFlow) {
tty->print(">> Computing successors for block ");
print_value_on(tty);
tty->cr();
}
ciTypeFlow* analyzer = outer();
Arena* arena = analyzer->arena();
Block* block = NULL;
bool has_successor = !has_trap() &&
(control() != ciBlock::fall_through_bci || limit() < analyzer->code_size());
if (!has_successor) {
_successors =
new (arena) GrowableArray<Block*>(arena, 1, 0, NULL);
} else if (control() == ciBlock::fall_through_bci) {
assert(str->cur_bci() == limit(), "bad block end");
_successors =
new (arena) GrowableArray<Block*>(arena, 1, 0, NULL);
Block* block = analyzer->block_at(limit(), _jsrs);
assert(_successors->length() == FALL_THROUGH, "");
_successors->append(block);
} else {
int current_bci = str->cur_bci();
int next_bci = str->next_bci();
int branch_bci = -1;
Block* target = NULL;
assert(str->next_bci() == limit(), "bad block end");
switch (str->cur_bc()) {
case Bytecodes::_ifeq: case Bytecodes::_ifne:
case Bytecodes::_iflt: case Bytecodes::_ifge:
case Bytecodes::_ifgt: case Bytecodes::_ifle:
case Bytecodes::_if_icmpeq: case Bytecodes::_if_icmpne:
case Bytecodes::_if_icmplt: case Bytecodes::_if_icmpge:
case Bytecodes::_if_icmpgt: case Bytecodes::_if_icmple:
case Bytecodes::_if_acmpeq: case Bytecodes::_if_acmpne:
case Bytecodes::_ifnull: case Bytecodes::_ifnonnull:
branch_bci = str->get_dest();
_successors =
new (arena) GrowableArray<Block*>(arena, 2, 0, NULL);
assert(_successors->length() == IF_NOT_TAKEN, "");
_successors->append(analyzer->block_at(next_bci, jsrs));
assert(_successors->length() == IF_TAKEN, "");
_successors->append(analyzer->block_at(branch_bci, jsrs));
break;
case Bytecodes::_goto:
branch_bci = str->get_dest();
_successors =
new (arena) GrowableArray<Block*>(arena, 1, 0, NULL);
assert(_successors->length() == GOTO_TARGET, "");
_successors->append(analyzer->block_at(branch_bci, jsrs));
break;
case Bytecodes::_jsr:
branch_bci = str->get_dest();
_successors =
new (arena) GrowableArray<Block*>(arena, 1, 0, NULL);
assert(_successors->length() == GOTO_TARGET, "");
_successors->append(analyzer->block_at(branch_bci, jsrs));
break;
case Bytecodes::_goto_w:
case Bytecodes::_jsr_w:
_successors =
new (arena) GrowableArray<Block*>(arena, 1, 0, NULL);
assert(_successors->length() == GOTO_TARGET, "");
_successors->append(analyzer->block_at(str->get_far_dest(), jsrs));
break;
case Bytecodes::_tableswitch: {
Bytecode_tableswitch tableswitch(str);
int len = tableswitch.length();
_successors =
new (arena) GrowableArray<Block*>(arena, len+1, 0, NULL);
int bci = current_bci + tableswitch.default_offset();
Block* block = analyzer->block_at(bci, jsrs);
assert(_successors->length() == SWITCH_DEFAULT, "");
_successors->append(block);
while (--len >= 0) {
int bci = current_bci + tableswitch.dest_offset_at(len);
block = analyzer->block_at(bci, jsrs);
assert(_successors->length() >= SWITCH_CASES, "");
_successors->append_if_missing(block);
}
break;
}
sssssss10
最新推荐文章于 2024-08-02 10:57:17 发布