8178350: klassVtable and klassItable should be ValueObj

Reviewed-by: coleenp
This commit is contained in:
Ioi Lam 2017-04-13 01:56:01 -07:00
parent dd358a3bac
commit 9d5b85daf4
14 changed files with 56 additions and 80 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, 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
@ -218,11 +218,11 @@ extern "C" void bad_compiled_vtable_index(JavaThread* thread, oop receiver, int
HandleMark hm; HandleMark hm;
Klass* klass = receiver->klass(); Klass* klass = receiver->klass();
InstanceKlass* ik = InstanceKlass::cast(klass); InstanceKlass* ik = InstanceKlass::cast(klass);
klassVtable* vt = ik->vtable(); klassVtable vt = ik->vtable();
ik->print(); ik->print();
fatal("bad compiled vtable dispatch: receiver " INTPTR_FORMAT ", " fatal("bad compiled vtable dispatch: receiver " INTPTR_FORMAT ", "
"index %d (vtable length %d)", "index %d (vtable length %d)",
p2i(receiver), index, vt->length()); p2i(receiver), index, vt.length());
} }
#endif // PRODUCT #endif // PRODUCT

View file

@ -150,8 +150,6 @@ CallInfo::CallInfo(Method* resolved_method, Klass* resolved_klass) {
kind = CallInfo::vtable_call; kind = CallInfo::vtable_call;
} 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;
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");
@ -163,7 +161,7 @@ CallInfo::CallInfo(Method* resolved_method, Klass* resolved_klass) {
#ifdef ASSERT #ifdef ASSERT
// Ensure that this is really the case. // Ensure that this is really the case.
Klass* object_klass = SystemDictionary::Object_klass(); Klass* object_klass = SystemDictionary::Object_klass();
Method * object_resolved_method = object_klass->vtable()->method_at(index); Method * object_resolved_method = object_klass->vtable().method_at(index);
assert(object_resolved_method->name() == resolved_method->name(), assert(object_resolved_method->name() == resolved_method->name(),
"Object and interface method names should match at vtable index %d, %s != %s", "Object and interface method names should match at vtable index %d, %s != %s",
index, object_resolved_method->name()->as_C_string(), resolved_method->name()->as_C_string()); index, object_resolved_method->name()->as_C_string(), resolved_method->name()->as_C_string());
@ -400,9 +398,8 @@ int LinkResolver::vtable_index_of_interface_method(Klass* klass,
} }
if (vtable_index == Method::invalid_vtable_index) { if (vtable_index == Method::invalid_vtable_index) {
// get vtable_index for miranda methods // get vtable_index for miranda methods
ResourceMark rm; klassVtable vt = ik->vtable();
klassVtable *vt = ik->vtable(); vtable_index = vt.index_of_miranda(name, signature);
vtable_index = vt->index_of_miranda(name, signature);
} }
return vtable_index; return vtable_index;
} }

View file

@ -526,8 +526,7 @@ void Universe::run_finalizers_on_exit() {
// In case those ever change we use handles for oops // In case those ever change we use handles for oops
void Universe::reinitialize_vtable_of(Klass* ko, TRAPS) { void Universe::reinitialize_vtable_of(Klass* ko, TRAPS) {
// init vtable of k and all subclasses // init vtable of k and all subclasses
klassVtable* vt = ko->vtable(); ko->vtable().initialize_vtable(false, CHECK);
if (vt) vt->initialize_vtable(false, CHECK);
if (ko->is_instance_klass()) { if (ko->is_instance_klass()) {
for (Klass* sk = ko->subklass(); for (Klass* sk = ko->subklass();
sk != NULL; sk != NULL;
@ -539,7 +538,7 @@ void Universe::reinitialize_vtable_of(Klass* ko, TRAPS) {
void initialize_itable_for_klass(Klass* k, TRAPS) { void initialize_itable_for_klass(Klass* k, TRAPS) {
InstanceKlass::cast(k)->itable()->initialize_itable(false, CHECK); InstanceKlass::cast(k)->itable().initialize_itable(false, CHECK);
} }

View file

@ -99,7 +99,7 @@ ArrayKlass::ArrayKlass(Symbol* name) :
void ArrayKlass::complete_create_array_klass(ArrayKlass* k, Klass* super_klass, ModuleEntry* module_entry, TRAPS) { void ArrayKlass::complete_create_array_klass(ArrayKlass* k, Klass* super_klass, ModuleEntry* module_entry, TRAPS) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
k->initialize_supers(super_klass, CHECK); k->initialize_supers(super_klass, CHECK);
k->vtable()->initialize_vtable(false, CHECK); k->vtable().initialize_vtable(false, CHECK);
// During bootstrapping, before java.base is defined, the module_entry may not be present yet. // During bootstrapping, before java.base is defined, the module_entry may not be present yet.
// These classes will be put on a fixup list and their module fields will be patched once // These classes will be put on a fixup list and their module fields will be patched once

View file

@ -373,8 +373,8 @@ bool InstanceKlass::should_be_initialized() const {
return !is_initialized(); return !is_initialized();
} }
klassItable* InstanceKlass::itable() const { klassItable InstanceKlass::itable() const {
return new klassItable(const_cast<InstanceKlass*>(this)); return klassItable(const_cast<InstanceKlass*>(this));
} }
void InstanceKlass::eager_initialize(Thread *thread) { void InstanceKlass::eager_initialize(Thread *thread) {
@ -621,15 +621,14 @@ bool InstanceKlass::link_class_impl(bool throw_verifyerror, TRAPS) {
if (!(is_shared() && if (!(is_shared() &&
loader_data->is_the_null_class_loader_data())) { loader_data->is_the_null_class_loader_data())) {
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
vtable()->initialize_vtable(true, CHECK_false); vtable().initialize_vtable(true, CHECK_false);
itable()->initialize_itable(true, CHECK_false); itable().initialize_itable(true, CHECK_false);
} }
#ifdef ASSERT #ifdef ASSERT
else { else {
ResourceMark rm(THREAD); vtable().verify(tty, true);
vtable()->verify(tty, true);
// In case itable verification is ever added. // In case itable verification is ever added.
// itable()->verify(tty, true); // itable().verify(tty, true);
} }
#endif #endif
set_init_state(linked); set_init_state(linked);
@ -807,8 +806,8 @@ void InstanceKlass::initialize_impl(TRAPS) {
// Step 9 // Step 9
if (!HAS_PENDING_EXCEPTION) { if (!HAS_PENDING_EXCEPTION) {
set_initialization_state_and_notify(fully_initialized, CHECK); set_initialization_state_and_notify(fully_initialized, CHECK);
{ ResourceMark rm(THREAD); {
debug_only(vtable()->verify(tty, true);) debug_only(vtable().verify(tty, true);)
} }
} }
else { else {
@ -2041,8 +2040,8 @@ void InstanceKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handl
// vtables in the shared system dictionary, only the main one. // vtables in the shared system dictionary, only the main one.
// It also redefines the itable too so fix that too. // It also redefines the itable too so fix that too.
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
vtable()->initialize_vtable(false, CHECK); vtable().initialize_vtable(false, CHECK);
itable()->initialize_itable(false, CHECK); itable().initialize_itable(false, CHECK);
} }
// restore constant pool resolved references // restore constant pool resolved references
@ -3212,10 +3211,9 @@ void InstanceKlass::verify_on(outputStream* st) {
// Verify vtables // Verify vtables
if (is_linked()) { if (is_linked()) {
ResourceMark rm;
// $$$ This used to be done only for m/s collections. Doing it // $$$ This used to be done only for m/s collections. Doing it
// always seemed a valid generalization. (DLD -- 6/00) // always seemed a valid generalization. (DLD -- 6/00)
vtable()->verify(st); vtable().verify(st);
} }
// Verify first subklass // Verify first subklass

View file

@ -1127,7 +1127,7 @@ public:
} }
// Java itable // Java itable
klassItable* itable() const; // return new klassItable wrapper klassItable itable() const; // return klassItable wrapper
Method* method_at_itable(Klass* holder, int index, TRAPS); Method* method_at_itable(Klass* holder, int index, TRAPS);
#if INCLUDE_JVMTI #if INCLUDE_JVMTI

View file

@ -696,8 +696,8 @@ 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 { klassVtable Klass::vtable() const {
return new klassVtable(const_cast<Klass*>(this), start_of_vtable(), vtable_length() / vtableEntry::size()); return klassVtable(const_cast<Klass*>(this), start_of_vtable(), vtable_length() / vtableEntry::size());
} }
vtableEntry* Klass::start_of_vtable() const { vtableEntry* Klass::start_of_vtable() const {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, 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
@ -399,7 +399,7 @@ protected:
#endif #endif
// vtables // vtables
klassVtable* vtable() const; klassVtable vtable() const;
int vtable_length() const { return _vtable_len; } int vtable_length() const { return _vtable_len; }
// subclass check // subclass check

View file

@ -136,22 +136,22 @@ int klassVtable::initialize_from_super(Klass* super) {
// methods from super class for shared class, as that was already done // methods from super class for shared class, as that was already done
// during archiving time. However, if Jvmti has redefined a class, // during archiving time. However, if Jvmti has redefined a class,
// copy super class's vtable in case the super class has changed. // copy super class's vtable in case the super class has changed.
return super->vtable()->length(); return super->vtable().length();
} else { } else {
// copy methods from superKlass // copy methods from superKlass
klassVtable* superVtable = super->vtable(); klassVtable superVtable = super->vtable();
assert(superVtable->length() <= _length, "vtable too short"); assert(superVtable.length() <= _length, "vtable too short");
#ifdef ASSERT #ifdef ASSERT
superVtable->verify(tty, true); superVtable.verify(tty, true);
#endif #endif
superVtable->copy_vtable_to(table()); superVtable.copy_vtable_to(table());
if (log_develop_is_enabled(Trace, vtables)) { if (log_develop_is_enabled(Trace, vtables)) {
ResourceMark rm; ResourceMark rm;
log_develop_trace(vtables)("copy vtable from %s to %s size %d", log_develop_trace(vtables)("copy vtable from %s to %s size %d",
super->internal_name(), klass()->internal_name(), super->internal_name(), klass()->internal_name(),
_length); _length);
} }
return superVtable->length(); return superVtable.length();
} }
} }
@ -290,9 +290,9 @@ InstanceKlass* klassVtable::find_transitive_override(InstanceKlass* initialsuper
InstanceKlass* superk = initialsuper; InstanceKlass* superk = initialsuper;
while (superk != NULL && superk->super() != NULL) { while (superk != NULL && superk->super() != NULL) {
InstanceKlass* supersuperklass = InstanceKlass::cast(superk->super()); InstanceKlass* supersuperklass = InstanceKlass::cast(superk->super());
klassVtable* ssVtable = supersuperklass->vtable(); klassVtable ssVtable = supersuperklass->vtable();
if (vtable_index < ssVtable->length()) { if (vtable_index < ssVtable.length()) {
Method* super_method = ssVtable->method_at(vtable_index); Method* super_method = ssVtable.method_at(vtable_index);
#ifndef PRODUCT #ifndef PRODUCT
Symbol* name= target_method()->name(); Symbol* name= target_method()->name();
Symbol* signature = target_method()->signature(); Symbol* signature = target_method()->signature();
@ -445,8 +445,8 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
if (is_preinitialized_vtable()) { if (is_preinitialized_vtable()) {
// If this is a shared class, the vtable is already in the final state (fully // If this is a shared class, the vtable is already in the final state (fully
// initialized). Need to look at the super's vtable. // initialized). Need to look at the super's vtable.
klassVtable* superVtable = super->vtable(); klassVtable superVtable = super->vtable();
super_method = superVtable->method_at(i); super_method = superVtable.method_at(i);
} else { } else {
super_method = method_at(i); super_method = method_at(i);
} }
@ -1249,17 +1249,6 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass
} }
} }
// Update entry for specific Method*
void klassItable::initialize_with_method(Method* m) {
itableMethodEntry* ime = method_entry(0);
for(int i = 0; i < _size_method_table; i++) {
if (ime->method() == m) {
ime->initialize(m);
}
ime++;
}
}
#if INCLUDE_JVMTI #if INCLUDE_JVMTI
// search the itable for uses of either obsolete or EMCP methods // search the itable for uses of either obsolete or EMCP methods
void klassItable::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) { void klassItable::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) {
@ -1488,9 +1477,9 @@ void klassVtable::verify(outputStream* st, bool forced) {
Klass* super = _klass->super(); Klass* super = _klass->super();
if (super != NULL) { if (super != NULL) {
InstanceKlass* sk = InstanceKlass::cast(super); InstanceKlass* sk = InstanceKlass::cast(super);
klassVtable* vt = sk->vtable(); klassVtable vt = sk->vtable();
for (int i = 0; i < vt->length(); i++) { for (int i = 0; i < vt.length(); i++) {
verify_against(st, vt, i); verify_against(st, &vt, i);
} }
} }
} }
@ -1557,8 +1546,7 @@ class VtableStats : AllStatic {
static void do_class(Klass* k) { static void do_class(Klass* k) {
Klass* kl = k; Klass* kl = k;
klassVtable* vt = kl->vtable(); klassVtable vt = kl->vtable();
if (vt == NULL) return;
no_klasses++; no_klasses++;
if (kl->is_instance_klass()) { if (kl->is_instance_klass()) {
no_instance_klasses++; no_instance_klasses++;
@ -1566,9 +1554,9 @@ class VtableStats : AllStatic {
} }
if (kl->is_array_klass()) { if (kl->is_array_klass()) {
no_array_klasses++; no_array_klasses++;
sum_of_array_vtable_len += vt->length(); sum_of_array_vtable_len += vt.length();
} }
sum_of_vtable_len += vt->length(); sum_of_vtable_len += vt.length();
} }
static void compute() { static void compute() {

View file

@ -41,7 +41,7 @@
class vtableEntry; class vtableEntry;
class klassVtable : public ResourceObj { class klassVtable VALUE_OBJ_CLASS_SPEC {
Klass* _klass; // my klass Klass* _klass; // my klass
int _tableOffset; // offset of start of vtable data within klass int _tableOffset; // offset of start of vtable data within klass
int _length; // length of vtable (number of entries) int _length; // length of vtable (number of entries)
@ -288,7 +288,7 @@ class itableMethodEntry VALUE_OBJ_CLASS_SPEC {
// -- vtable for interface 2 --- // -- vtable for interface 2 ---
// ... // ...
// //
class klassItable : public ResourceObj { class klassItable VALUE_OBJ_CLASS_SPEC {
private: private:
InstanceKlass* _klass; // my klass InstanceKlass* _klass; // my klass
int _table_offset; // offset of start of itable data within klass (in words) int _table_offset; // offset of start of itable data within klass (in words)
@ -310,9 +310,6 @@ class klassItable : public ResourceObj {
// Initialization // Initialization
void initialize_itable(bool checkconstraints, TRAPS); void initialize_itable(bool checkconstraints, TRAPS);
// Updates
void initialize_with_method(Method* m);
#if INCLUDE_JVMTI #if INCLUDE_JVMTI
// RedefineClasses() API support: // RedefineClasses() API support:
// if any entry of this itable points to any of old_methods, // if any entry of this itable points to any of old_methods,

View file

@ -1191,7 +1191,6 @@ bool Method::is_overridden_in(Klass* k) const {
} }
assert(ik->is_subclass_of(method_holder()), "should be subklass"); assert(ik->is_subclass_of(method_holder()), "should be subklass");
assert(ik->vtable() != NULL, "vtable should exist");
if (!has_vtable_index()) { if (!has_vtable_index()) {
return false; return false;
} else { } else {

View file

@ -3272,7 +3272,7 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
// If the class being redefined is java.lang.Object, we need to fix all // If the class being redefined is java.lang.Object, we need to fix all
// array class vtables also // array class vtables also
if (k->is_array_klass() && _the_class == SystemDictionary::Object_klass()) { if (k->is_array_klass() && _the_class == SystemDictionary::Object_klass()) {
k->vtable()->adjust_method_entries(the_class, &trace_name_printed); k->vtable().adjust_method_entries(the_class, &trace_name_printed);
} else if (k->is_instance_klass()) { } else if (k->is_instance_klass()) {
HandleMark hm(_thread); HandleMark hm(_thread);
@ -3315,7 +3315,7 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
// ik->vtable() creates a wrapper object; rm cleans it up // ik->vtable() creates a wrapper object; rm cleans it up
ResourceMark rm(_thread); ResourceMark rm(_thread);
ik->vtable()->adjust_method_entries(the_class, &trace_name_printed); ik->vtable().adjust_method_entries(the_class, &trace_name_printed);
ik->adjust_default_methods(the_class, &trace_name_printed); ik->adjust_default_methods(the_class, &trace_name_printed);
} }
@ -3329,10 +3329,8 @@ void VM_RedefineClasses::AdjustCpoolCacheAndVtable::do_klass(Klass* k) {
if (ik->itable_length() > 0 && (_the_class->is_interface() if (ik->itable_length() > 0 && (_the_class->is_interface()
|| _the_class == SystemDictionary::internal_Unsafe_klass() || _the_class == SystemDictionary::internal_Unsafe_klass()
|| ik->is_subclass_of(_the_class))) { || ik->is_subclass_of(_the_class))) {
// ik->itable() creates a wrapper object; rm cleans it up
ResourceMark rm(_thread); ResourceMark rm(_thread);
ik->itable().adjust_method_entries(the_class, &trace_name_printed);
ik->itable()->adjust_method_entries(the_class, &trace_name_printed);
} }
// The constant pools in other classes (other_cp) can refer to // The constant pools in other classes (other_cp) can refer to
@ -3957,8 +3955,8 @@ void VM_RedefineClasses::redefine_single_class(jclass the_jclass,
// compare_and_normalize_class_versions has already checked: // compare_and_normalize_class_versions has already checked:
// - classloaders unchanged, signatures unchanged // - classloaders unchanged, signatures unchanged
// - all instanceKlasses for redefined classes reused & contents updated // - all instanceKlasses for redefined classes reused & contents updated
the_class->vtable()->initialize_vtable(false, THREAD); the_class->vtable().initialize_vtable(false, THREAD);
the_class->itable()->initialize_itable(false, THREAD); the_class->itable().initialize_itable(false, THREAD);
assert(!HAS_PENDING_EXCEPTION || (THREAD->pending_exception()->is_a(SystemDictionary::ThreadDeath_klass())), "redefine exception"); assert(!HAS_PENDING_EXCEPTION || (THREAD->pending_exception()->is_a(SystemDictionary::ThreadDeath_klass())), "redefine exception");
} }
@ -4093,12 +4091,12 @@ void VM_RedefineClasses::CheckClass::do_klass(Klass* k) {
// a vtable should never contain old or obsolete methods // a vtable should never contain old or obsolete methods
ResourceMark rm(_thread); ResourceMark rm(_thread);
if (k->vtable_length() > 0 && if (k->vtable_length() > 0 &&
!k->vtable()->check_no_old_or_obsolete_entries()) { !k->vtable().check_no_old_or_obsolete_entries()) {
if (log_is_enabled(Trace, redefine, class, obsolete, metadata)) { if (log_is_enabled(Trace, redefine, class, obsolete, metadata)) {
log_trace(redefine, class, obsolete, metadata) log_trace(redefine, class, obsolete, metadata)
("klassVtable::check_no_old_or_obsolete_entries failure -- OLD or OBSOLETE method found -- class: %s", ("klassVtable::check_no_old_or_obsolete_entries failure -- OLD or OBSOLETE method found -- class: %s",
k->signature_name()); k->signature_name());
k->vtable()->dump_vtable(); k->vtable().dump_vtable();
} }
no_old_methods = false; no_old_methods = false;
} }
@ -4109,12 +4107,12 @@ void VM_RedefineClasses::CheckClass::do_klass(Klass* k) {
// an itable should never contain old or obsolete methods // an itable should never contain old or obsolete methods
if (ik->itable_length() > 0 && if (ik->itable_length() > 0 &&
!ik->itable()->check_no_old_or_obsolete_entries()) { !ik->itable().check_no_old_or_obsolete_entries()) {
if (log_is_enabled(Trace, redefine, class, obsolete, metadata)) { if (log_is_enabled(Trace, redefine, class, obsolete, metadata)) {
log_trace(redefine, class, obsolete, metadata) log_trace(redefine, class, obsolete, metadata)
("klassItable::check_no_old_or_obsolete_entries failure -- OLD or OBSOLETE method found -- class: %s", ("klassItable::check_no_old_or_obsolete_entries failure -- OLD or OBSOLETE method found -- class: %s",
ik->signature_name()); ik->signature_name());
ik->itable()->dump_itable(); ik->itable().dump_itable();
} }
no_old_methods = false; no_old_methods = false;
} }

View file

@ -218,7 +218,7 @@ oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info, bool int
m_klass_non_interface = SystemDictionary::Object_klass(); m_klass_non_interface = SystemDictionary::Object_klass();
#ifdef ASSERT #ifdef ASSERT
{ ResourceMark rm; { ResourceMark rm;
Method* m2 = m_klass_non_interface->vtable()->method_at(vmindex); Method* m2 = m_klass_non_interface->vtable().method_at(vmindex);
assert(m->name() == m2->name() && m->signature() == m2->signature(), assert(m->name() == m2->name() && m->signature() == m2->signature(),
"at %d, %s != %s", vmindex, "at %d, %s != %s", vmindex,
m->name_and_sig_as_C_string(), m2->name_and_sig_as_C_string()); m->name_and_sig_as_C_string(), m2->name_and_sig_as_C_string());

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1997, 2017, 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
@ -490,7 +490,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;
k->vtable()->print(); k->vtable().print();
} }