8148481: Devirtualize Klass::vtable

Move remainder of vtable related methods to Klass

Reviewed-by: cjplummer, coleenp
This commit is contained in:
Mikael Gerdin 2016-01-19 12:07:32 +01:00
parent 211dc93a85
commit 3cda485fe5
12 changed files with 44 additions and 73 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -168,7 +168,7 @@ CallInfo::CallInfo(Method* resolved_method, Klass* resolved_klass) {
} else if (!resolved_klass->is_interface()) { } else if (!resolved_klass->is_interface()) {
// A default or miranda method. Compute the vtable index. // A default or miranda method. Compute the vtable index.
ResourceMark rm; ResourceMark rm;
klassVtable* vt = InstanceKlass::cast(resolved_klass)->vtable(); klassVtable* vt = resolved_klass->vtable();
index = LinkResolver::vtable_index_of_interface_method(resolved_klass, index = LinkResolver::vtable_index_of_interface_method(resolved_klass,
resolved_method); resolved_method);
assert(index >= 0 , "we should have valid vtable index at this point"); assert(index >= 0 , "we should have valid vtable index at this point");
@ -1227,8 +1227,7 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
resolved_method); resolved_method);
assert(vtable_index >= 0 , "we should have valid vtable index at this point"); assert(vtable_index >= 0 , "we should have valid vtable index at this point");
InstanceKlass* inst = InstanceKlass::cast(recv_klass()); selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index));
selected_method = methodHandle(THREAD, inst->method_at_vtable(vtable_index));
} else { } else {
// at this point we are sure that resolved_method is virtual and not // at this point we are sure that resolved_method is virtual and not
// a default or miranda method; therefore, it must have a valid vtable index. // a default or miranda method; therefore, it must have a valid vtable index.
@ -1243,10 +1242,7 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
assert(resolved_method->can_be_statically_bound(), "cannot override this method"); assert(resolved_method->can_be_statically_bound(), "cannot override this method");
selected_method = resolved_method; selected_method = resolved_method;
} else { } else {
// recv_klass might be an arrayKlassOop but all vtables start at selected_method = methodHandle(THREAD, recv_klass->method_at_vtable(vtable_index));
// the same place. The cast is to avoid virtual call and assertion.
InstanceKlass* inst = (InstanceKlass*)recv_klass();
selected_method = methodHandle(THREAD, inst->method_at_vtable(vtable_index));
} }
} }

View file

@ -655,8 +655,7 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t
vtable_index = LinkResolver::vtable_index_of_interface_method(holder_klass, resolved_method); vtable_index = LinkResolver::vtable_index_of_interface_method(holder_klass, resolved_method);
assert(vtable_index >= 0 , "we should have valid vtable index at this point"); assert(vtable_index >= 0 , "we should have valid vtable index at this point");
InstanceKlass* inst = InstanceKlass::cast(recv_klass); selected_method = recv_klass->method_at_vtable(vtable_index);
selected_method = inst->method_at_vtable(vtable_index);
} else { } else {
// at this point we are sure that resolved_method is virtual and not // at this point we are sure that resolved_method is virtual and not
// a miranda method; therefore, it must have a valid vtable index. // a miranda method; therefore, it must have a valid vtable index.
@ -671,10 +670,7 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t
assert(resolved_method->can_be_statically_bound(), "cannot override this method"); assert(resolved_method->can_be_statically_bound(), "cannot override this method");
selected_method = resolved_method(); selected_method = resolved_method();
} else { } else {
// recv_klass might be an arrayKlassOop but all vtables start at selected_method = recv_klass->method_at_vtable(vtable_index);
// the same place. The cast is to avoid virtual call and assertion.
InstanceKlass* inst = (InstanceKlass*)recv_klass;
selected_method = inst->method_at_vtable(vtable_index);
} }
} }
oop result = CompilerToVM::get_jvmci_method(selected_method, CHECK_NULL); oop result = CompilerToVM::get_jvmci_method(selected_method, CHECK_NULL);

View file

@ -117,19 +117,6 @@ bool ArrayKlass::compute_is_subtype_of(Klass* k) {
|| k == SystemDictionary::Serializable_klass(); || k == SystemDictionary::Serializable_klass();
} }
inline intptr_t* ArrayKlass::start_of_vtable() const {
// all vtables start at the same place, that's why we use InstanceKlass::header_size here
return ((intptr_t*)this) + InstanceKlass::header_size();
}
klassVtable* ArrayKlass::vtable() const {
KlassHandle kh(Thread::current(), this);
return new klassVtable(kh, start_of_vtable(), vtable_length() / vtableEntry::size());
}
objArrayOop ArrayKlass::allocate_arrayArray(int n, int length, TRAPS) { objArrayOop ArrayKlass::allocate_arrayArray(int n, int length, TRAPS) {
if (length < 0) { if (length < 0) {
THROW_0(vmSymbols::java_lang_NegativeArraySizeException()); THROW_0(vmSymbols::java_lang_NegativeArraySizeException());

View file

@ -98,7 +98,6 @@ class ArrayKlass: public Klass {
bool compute_is_subtype_of(Klass* k); bool compute_is_subtype_of(Klass* k);
// Sizing // Sizing
static int header_size() { return sizeof(ArrayKlass)/wordSize; }
static int static_size(int header_size); static int static_size(int header_size);
#if INCLUDE_SERVICES #if INCLUDE_SERVICES
@ -109,12 +108,6 @@ class ArrayKlass: public Klass {
} }
#endif #endif
// Java vtable
klassVtable* vtable() const; // return new klassVtable
protected:
inline intptr_t* start_of_vtable() const;
public:
// Iterators // Iterators
void array_klasses_do(void f(Klass* k)); void array_klasses_do(void f(Klass* k));
void array_klasses_do(void f(Klass* k, TRAPS), TRAPS); void array_klasses_do(void f(Klass* k, TRAPS), TRAPS);

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -394,9 +394,7 @@ Method* ConstantPoolCacheEntry::method_if_resolved(const constantPoolHandle& cpo
int holder_index = cpool->uncached_klass_ref_index_at(constant_pool_index()); int holder_index = cpool->uncached_klass_ref_index_at(constant_pool_index());
if (cpool->tag_at(holder_index).is_klass()) { if (cpool->tag_at(holder_index).is_klass()) {
Klass* klass = cpool->resolved_klass_at(holder_index); Klass* klass = cpool->resolved_klass_at(holder_index);
if (!klass->is_instance_klass()) return klass->method_at_vtable(f2_as_index());
klass = SystemDictionary::Object_klass();
return InstanceKlass::cast(klass)->method_at_vtable(f2_as_index());
} }
} }
break; break;

View file

@ -364,10 +364,6 @@ bool InstanceKlass::should_be_initialized() const {
return !is_initialized(); return !is_initialized();
} }
klassVtable* InstanceKlass::vtable() const {
return new klassVtable(this, start_of_vtable(), vtable_length() / vtableEntry::size());
}
klassItable* InstanceKlass::itable() const { klassItable* InstanceKlass::itable() const {
return new klassItable(instanceKlassHandle(this)); return new klassItable(instanceKlassHandle(this));
} }
@ -2667,6 +2663,10 @@ static void print_vtable(intptr_t* start, int len, outputStream* st) {
} }
} }
static void print_vtable(vtableEntry* start, int len, outputStream* st) {
return print_vtable(reinterpret_cast<intptr_t*>(start), len, st);
}
void InstanceKlass::print_on(outputStream* st) const { void InstanceKlass::print_on(outputStream* st) const {
assert(is_klass(), "must be klass"); assert(is_klass(), "must be klass");
Klass::print_on(st); Klass::print_on(st);

View file

@ -944,12 +944,11 @@ public:
virtual void collect_statistics(KlassSizeStats *sz) const; virtual void collect_statistics(KlassSizeStats *sz) const;
#endif #endif
intptr_t* start_of_vtable() const { return (intptr_t*) ((address)this + in_bytes(vtable_start_offset())); } intptr_t* start_of_itable() const { return (intptr_t*)start_of_vtable() + vtable_length(); }
intptr_t* start_of_itable() const { return start_of_vtable() + vtable_length(); }
int itable_offset_in_words() const { return start_of_itable() - (intptr_t*)this; }
intptr_t* end_of_itable() const { return start_of_itable() + itable_length(); } intptr_t* end_of_itable() const { return start_of_itable() + itable_length(); }
int itable_offset_in_words() const { return start_of_itable() - (intptr_t*)this; }
address static_field_addr(int offset); address static_field_addr(int offset);
OopMapBlock* start_of_nonstatic_oop_maps() const { OopMapBlock* start_of_nonstatic_oop_maps() const {
@ -997,9 +996,7 @@ public:
return !layout_helper_needs_slow_path(layout_helper()); return !layout_helper_needs_slow_path(layout_helper());
} }
// Java vtable/itable // Java itable
klassVtable* vtable() const; // return new klassVtable wrapper
inline Method* method_at_vtable(int index);
klassItable* itable() const; // return new klassItable wrapper klassItable* itable() const; // return new klassItable wrapper
Method* method_at_itable(Klass* holder, int index, TRAPS); Method* method_at_itable(Klass* holder, int index, TRAPS);
@ -1249,17 +1246,6 @@ public:
void oop_verify_on(oop obj, outputStream* st); void oop_verify_on(oop obj, outputStream* st);
}; };
inline Method* InstanceKlass::method_at_vtable(int index) {
#ifndef PRODUCT
assert(index >= 0, "valid vtable index");
if (DebugVtables) {
verify_vtable_index(index);
}
#endif
vtableEntry* ve = (vtableEntry*)start_of_vtable();
return ve[index].method();
}
// for adding methods // for adding methods
// UNSET_IDNUM return means no more ids available // UNSET_IDNUM return means no more ids available
inline u2 InstanceKlass::next_method_idnum() { inline u2 InstanceKlass::next_method_idnum() {

View file

@ -659,6 +659,24 @@ void Klass::oop_verify_on(oop obj, outputStream* st) {
guarantee(obj->klass()->is_klass(), "klass field is not a klass"); guarantee(obj->klass()->is_klass(), "klass field is not a klass");
} }
klassVtable* Klass::vtable() const {
return new klassVtable(this, start_of_vtable(), vtable_length() / vtableEntry::size());
}
vtableEntry* Klass::start_of_vtable() const {
return (vtableEntry*) ((address)this + in_bytes(vtable_start_offset()));
}
Method* Klass::method_at_vtable(int index) {
#ifndef PRODUCT
assert(index >= 0, "valid vtable index");
if (DebugVtables) {
verify_vtable_index(index);
}
#endif
return start_of_vtable()[index].method();
}
ByteSize Klass::vtable_start_offset() { ByteSize Klass::vtable_start_offset() {
return in_ByteSize(InstanceKlass::header_size() * wordSize); return in_ByteSize(InstanceKlass::header_size() * wordSize);
} }

View file

@ -57,6 +57,7 @@ class ParCompactionManager;
class PSPromotionManager; class PSPromotionManager;
class KlassSizeStats; class KlassSizeStats;
class fieldDescriptor; class fieldDescriptor;
class vtableEntry;
class Klass : public Metadata { class Klass : public Metadata {
friend class VMStructs; friend class VMStructs;
@ -377,7 +378,7 @@ protected:
#endif #endif
// vtables // vtables
virtual klassVtable* vtable() const = 0; klassVtable* vtable() const;
int vtable_length() const { return _vtable_len; } int vtable_length() const { return _vtable_len; }
// subclass check // subclass check
@ -443,7 +444,10 @@ protected:
void set_vtable_length(int len) { _vtable_len= len; } void set_vtable_length(int len) { _vtable_len= len; }
vtableEntry* start_of_vtable() const;
public: public:
Method* method_at_vtable(int index);
static ByteSize vtable_start_offset(); static ByteSize vtable_start_offset();
static ByteSize vtable_length_offset() { static ByteSize vtable_length_offset() {
return byte_offset_of(Klass, _vtable_len); return byte_offset_of(Klass, _vtable_len);

View file

@ -1131,11 +1131,7 @@ static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receive
assert(m->valid_vtable_index(), "no valid vtable index"); assert(m->valid_vtable_index(), "no valid vtable index");
int vtbl_index = m->vtable_index(); int vtbl_index = m->vtable_index();
if (vtbl_index != Method::nonvirtual_vtable_index) { if (vtbl_index != Method::nonvirtual_vtable_index) {
Klass* k = h_recv->klass(); selected_method = h_recv->klass()->method_at_vtable(vtbl_index);
// k might be an arrayKlassOop but all vtables start at
// the same place. The cast is to avoid virtual call and assertion.
InstanceKlass *ik = (InstanceKlass*)k;
selected_method = ik->method_at_vtable(vtbl_index);
} else { } else {
// final method // final method
selected_method = m; selected_method = m;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -939,10 +939,7 @@ static oop invoke(instanceKlassHandle klass,
int index = reflected_method->vtable_index(); int index = reflected_method->vtable_index();
method = reflected_method; method = reflected_method;
if (index != Method::nonvirtual_vtable_index) { if (index != Method::nonvirtual_vtable_index) {
// target_klass might be an arrayKlassOop but all vtables start at method = methodHandle(THREAD, target_klass->method_at_vtable(index));
// the same place. The cast is to avoid virtual call and assertion.
InstanceKlass* inst = (InstanceKlass*)target_klass();
method = methodHandle(THREAD, inst->method_at_vtable(index));
} }
if (!method.is_null()) { if (!method.is_null()) {
// Check for abstract methods as well // Check for abstract methods as well

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -461,7 +461,7 @@ extern "C" void blob(CodeBlob* cb) {
extern "C" void dump_vtable(address p) { extern "C" void dump_vtable(address p) {
Command c("dump_vtable"); Command c("dump_vtable");
Klass* k = (Klass*)p; Klass* k = (Klass*)p;
InstanceKlass::cast(k)->vtable()->print(); k->vtable()->print();
} }