methodOop ConstantPoolCacheEntry::method_if_resolved(constantPoolHandle cpool) { if (is_secondary_entry()) { if (!is_f1_null()) return f2_as_vfinal_method(); return NULL; } // Decode the action of set_method and set_interface_call Bytecodes::Code invoke_code = bytecode_1(); if (invoke_code != (Bytecodes::Code)0) { oop f1 = _f1; if (f1 != NULL) { switch (invoke_code) { case Bytecodes::_invokeinterface: assert(f1->is_klass(), ""); return klassItable::method_for_itable_index(klassOop(f1), f2_as_index()); case Bytecodes::_invokestatic: case Bytecodes::_invokespecial: assert(!has_appendix(), ""); assert(f1->is_method(), ""); return methodOop(f1); } } } invoke_code = bytecode_2(); if (invoke_code != (Bytecodes::Code)0) { switch (invoke_code) { case Bytecodes::_invokevirtual: if (is_vfinal()) { // invokevirtual methodOop m = f2_as_vfinal_method(); assert(m->is_method(), ""); return m; } else { int holder_index = cpool->uncached_klass_ref_index_at(constant_pool_index()); if (cpool->tag_at(holder_index).is_klass()) { klassOop klass = cpool->resolved_klass_at(holder_index); if (!Klass::cast(klass)->oop_is_instance()) klass = SystemDictionary::Object_klass(); return instanceKlass::cast(klass)->method_at_vtable(f2_as_index()); } } break; case Bytecodes::_invokehandle: case Bytecodes::_invokedynamic: return f2_as_vfinal_method(); } } return NULL; }
bool ConstantPoolCacheEntry::is_interesting_method_entry(klassOop k) { if (!is_method_entry()) { // not a method entry so not interesting by default return false; } methodOop m = NULL; if (is_vfinal()) { // virtual and final so _f2 contains method ptr instead of vtable index m = f2_as_vfinal_method(); } else if (is_f1_null()) { // NULL _f1 means this is a virtual entry so also not interesting return false; } else { oop f1 = _f1; // _f1 is volatile if (!f1->is_method()) { // _f1 can also contain a klassOop for an interface return false; } m = f1_as_method(); } assert(m != NULL && m->is_method(), "sanity check"); if (m == NULL || !m->is_method() || m->method_holder() != k) { // robustness for above sanity checks or method is not in // the interesting class return false; } // the method is in the interesting class so the entry is interesting return true; }
// RedefineClasses() API support: // If this ConstantPoolCacheEntry refers to old_method then update it // to refer to new_method. bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method, Method* new_method, bool * trace_name_printed) { if (is_vfinal()) { // virtual and final so _f2 contains method ptr instead of vtable index if (f2_as_vfinal_method() == old_method) { // match old_method so need an update // NOTE: can't use set_f2_as_vfinal_method as it asserts on different values _f2 = (intptr_t)new_method; if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) { if (!(*trace_name_printed)) { // RC_TRACE_MESG macro has an embedded ResourceMark RC_TRACE_MESG(("adjust: name=%s", old_method->method_holder()->external_name())); *trace_name_printed = true; } // RC_TRACE macro has an embedded ResourceMark RC_TRACE(0x00400000, ("cpc vf-entry update: %s(%s)", new_method->name()->as_C_string(), new_method->signature()->as_C_string())); } return true; } // f1() is not used with virtual entries so bail out return false; } if (_f1 == NULL) { // NULL f1() means this is a virtual entry so bail out // We are assuming that the vtable index does not need change. return false; } if (_f1 == old_method) { _f1 = new_method; if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) { if (!(*trace_name_printed)) { // RC_TRACE_MESG macro has an embedded ResourceMark RC_TRACE_MESG(("adjust: name=%s", old_method->method_holder()->external_name())); *trace_name_printed = true; } // RC_TRACE macro has an embedded ResourceMark RC_TRACE(0x00400000, ("cpc entry update: %s(%s)", new_method->name()->as_C_string(), new_method->signature()->as_C_string())); } return true; } return false; }
Method* ConstantPoolCacheEntry::method_if_resolved(constantPoolHandle cpool) { // Decode the action of set_method and set_interface_call Bytecodes::Code invoke_code = bytecode_1(); if (invoke_code != (Bytecodes::Code)0) { Metadata* f1 = f1_ord(); if (f1 != NULL) { switch (invoke_code) { case Bytecodes::_invokeinterface: assert(f1->is_klass(), ""); return klassItable::method_for_itable_index((Klass*)f1, f2_as_index()); case Bytecodes::_invokestatic: case Bytecodes::_invokespecial: assert(!has_appendix(), ""); case Bytecodes::_invokehandle: case Bytecodes::_invokedynamic: assert(f1->is_method(), ""); return (Method*)f1; } } } invoke_code = bytecode_2(); if (invoke_code != (Bytecodes::Code)0) { switch (invoke_code) { case Bytecodes::_invokevirtual: if (is_vfinal()) { // invokevirtual Method* m = f2_as_vfinal_method(); assert(m->is_method(), ""); return m; } else { int holder_index = cpool->uncached_klass_ref_index_at(constant_pool_index()); if (cpool->tag_at(holder_index).is_klass()) { Klass* klass = cpool->resolved_klass_at(holder_index); if (!klass->oop_is_instance()) klass = SystemDictionary::Object_klass(); return InstanceKlass::cast(klass)->method_at_vtable(f2_as_index()); } } break; } } return NULL; }
// RedefineClasses() API support: // If this ConstantPoolCacheEntry refers to old_method then update it // to refer to new_method. bool ConstantPoolCacheEntry::adjust_method_entry(Method* old_method, Method* new_method, bool * trace_name_printed) { if (is_vfinal()) { // virtual and final so _f2 contains method ptr instead of vtable index if (f2_as_vfinal_method() == old_method) { // match old_method so need an update // NOTE: can't use set_f2_as_vfinal_method as it asserts on different values _f2 = (intptr_t)new_method; if (log_is_enabled(Info, redefine, class, update)) { ResourceMark rm; if (!(*trace_name_printed)) { log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name()); *trace_name_printed = true; } log_debug(redefine, class, update, constantpool) ("cpc vf-entry update: %s(%s)", new_method->name()->as_C_string(), new_method->signature()->as_C_string()); } return true; }