mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 07:14:30 +02:00
8148481: Devirtualize Klass::vtable
Move remainder of vtable related methods to Klass Reviewed-by: cjplummer, coleenp
This commit is contained in:
parent
211dc93a85
commit
3cda485fe5
12 changed files with 44 additions and 73 deletions
|
@ -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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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());
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue