This commit is contained in:
Vladimir Kozlov 2013-11-21 12:30:35 -08:00
commit aabed3781b
1054 changed files with 36891 additions and 14735 deletions

View file

@ -152,11 +152,13 @@ CallInfo::CallInfo(Method* resolved_method, Klass* resolved_klass) {
// Could be an Object method inherited into an interface, but still a vtable call.
kind = CallInfo::vtable_call;
} else if (!resolved_klass->is_interface()) {
// A miranda method. Compute the vtable index.
// A default or miranda method. Compute the vtable index.
ResourceMark rm;
klassVtable* vt = InstanceKlass::cast(resolved_klass)->vtable();
index = vt->index_of_miranda(resolved_method->name(),
resolved_method->signature());
index = LinkResolver::vtable_index_of_interface_method(resolved_klass,
resolved_method);
assert(index >= 0 , "we should have valid vtable index at this point");
kind = CallInfo::vtable_call;
} else if (resolved_method->has_vtable_index()) {
// Can occur if an interface redeclares a method of Object.
@ -279,7 +281,7 @@ void LinkResolver::lookup_instance_method_in_klasses(methodHandle& result, Klass
}
int LinkResolver::vtable_index_of_interface_method(KlassHandle klass,
methodHandle resolved_method, TRAPS) {
methodHandle resolved_method) {
int vtable_index = Method::invalid_vtable_index;
Symbol* name = resolved_method->name();
@ -295,7 +297,7 @@ int LinkResolver::vtable_index_of_interface_method(KlassHandle klass,
}
if (vtable_index == Method::invalid_vtable_index) {
// get vtable_index for miranda methods
ResourceMark rm(THREAD);
ResourceMark rm;
klassVtable *vt = InstanceKlass::cast(klass())->vtable();
vtable_index = vt->index_of_miranda(name, signature);
}
@ -691,7 +693,7 @@ void LinkResolver::resolve_interface_method(methodHandle& resolved_method,
);
resolved_method->access_flags().print_on(tty);
if (resolved_method->is_default_method()) {
tty->print("default");
tty->print("default ");
}
if (resolved_method->is_overpass()) {
tty->print("overpass");
@ -937,7 +939,7 @@ void LinkResolver::linktime_resolve_special_method(methodHandle& resolved_method
);
resolved_method->access_flags().print_on(tty);
if (resolved_method->is_default_method()) {
tty->print("default");
tty->print("default ");
}
if (resolved_method->is_overpass()) {
tty->print("overpass");
@ -1017,7 +1019,7 @@ void LinkResolver::runtime_resolve_special_method(CallInfo& result, methodHandle
);
sel_method->access_flags().print_on(tty);
if (sel_method->is_default_method()) {
tty->print("default");
tty->print("default ");
}
if (sel_method->is_overpass()) {
tty->print("overpass");
@ -1081,7 +1083,7 @@ void LinkResolver::linktime_resolve_virtual_method(methodHandle &resolved_method
);
resolved_method->access_flags().print_on(tty);
if (resolved_method->is_default_method()) {
tty->print("default");
tty->print("default ");
}
if (resolved_method->is_overpass()) {
tty->print("overpass");
@ -1118,7 +1120,7 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
// do lookup based on receiver klass using the vtable index
if (resolved_method->method_holder()->is_interface()) { // miranda method
vtable_index = vtable_index_of_interface_method(resolved_klass,
resolved_method, CHECK);
resolved_method);
assert(vtable_index >= 0 , "we should have valid vtable index at this point");
InstanceKlass* inst = InstanceKlass::cast(recv_klass());
@ -1175,7 +1177,7 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
);
selected_method->access_flags().print_on(tty);
if (selected_method->is_default_method()) {
tty->print("default");
tty->print("default ");
}
if (selected_method->is_overpass()) {
tty->print("overpass");
@ -1268,14 +1270,6 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
sel_method->name(),
sel_method->signature()));
}
// setup result
if (!resolved_method->has_itable_index()) {
int vtable_index = resolved_method->vtable_index();
assert(vtable_index == sel_method->vtable_index(), "sanity check");
result.set_virtual(resolved_klass, recv_klass, resolved_method, sel_method, vtable_index, CHECK);
return;
}
int itable_index = resolved_method()->itable_index();
if (TraceItables && Verbose) {
ResourceMark rm(THREAD);
@ -1289,14 +1283,22 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
);
sel_method->access_flags().print_on(tty);
if (sel_method->is_default_method()) {
tty->print("default");
tty->print("default ");
}
if (sel_method->is_overpass()) {
tty->print("overpass");
}
tty->cr();
}
result.set_interface(resolved_klass, recv_klass, resolved_method, sel_method, itable_index, CHECK);
// setup result
if (!resolved_method->has_itable_index()) {
int vtable_index = resolved_method->vtable_index();
assert(vtable_index == sel_method->vtable_index(), "sanity check");
result.set_virtual(resolved_klass, recv_klass, resolved_method, sel_method, vtable_index, CHECK);
} else {
int itable_index = resolved_method()->itable_index();
result.set_interface(resolved_klass, recv_klass, resolved_method, sel_method, itable_index, CHECK);
}
}

View file

@ -130,7 +130,6 @@ class LinkResolver: AllStatic {
static void lookup_polymorphic_method (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature,
KlassHandle current_klass, Handle *appendix_result_or_null, Handle *method_type_result, TRAPS);
static int vtable_index_of_interface_method(KlassHandle klass, methodHandle resolved_method, TRAPS);
static void resolve_klass (KlassHandle& result, constantPoolHandle pool, int index, TRAPS);
static void resolve_pool (KlassHandle& resolved_klass, Symbol*& method_name, Symbol*& method_signature, KlassHandle& current_klass, constantPoolHandle pool, int index, TRAPS);
@ -186,6 +185,7 @@ class LinkResolver: AllStatic {
static methodHandle resolve_interface_call_or_null(KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass);
static methodHandle resolve_static_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass);
static methodHandle resolve_special_call_or_null (KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass);
static int vtable_index_of_interface_method(KlassHandle klass, methodHandle resolved_method);
// same as above for compile-time resolution; returns vtable_index if current_klass if linked
static int resolve_virtual_vtable_index (KlassHandle receiver_klass, KlassHandle resolved_klass, Symbol* method_name, Symbol* method_signature, KlassHandle current_klass);

View file

@ -70,21 +70,21 @@ void Rewriter::compute_index_maps() {
}
// Unrewrite the bytecodes if an error occurs.
void Rewriter::restore_bytecodes() {
void Rewriter::restore_bytecodes(TRAPS) {
int len = _methods->length();
for (int i = len-1; i >= 0; i--) {
Method* method = _methods->at(i);
scan_method(method, true);
scan_method(method, true, CHECK);
}
}
// Creates a constant pool cache given a CPC map
void Rewriter::make_constant_pool_cache(TRAPS) {
const int length = _cp_cache_map.length();
ClassLoaderData* loader_data = _pool->pool_holder()->class_loader_data();
ConstantPoolCache* cache =
ConstantPoolCache::allocate(loader_data, length, _cp_cache_map,
ConstantPoolCache::allocate(loader_data, _cp_cache_map,
_invokedynamic_cp_cache_map,
_invokedynamic_references_map, CHECK);
// initialize object cache in constant pool
@ -154,6 +154,31 @@ void Rewriter::rewrite_member_reference(address bcp, int offset, bool reverse) {
}
}
// If the constant pool entry for invokespecial is InterfaceMethodref,
// we need to add a separate cpCache entry for its resolution, because it is
// different than the resolution for invokeinterface with InterfaceMethodref.
// These cannot share cpCache entries. It's unclear if all invokespecial to
// InterfaceMethodrefs would resolve to the same thing so a new cpCache entry
// is created for each one. This was added with lambda.
void Rewriter::rewrite_invokespecial(address bcp, int offset, bool reverse, TRAPS) {
static int count = 0;
address p = bcp + offset;
if (!reverse) {
int cp_index = Bytes::get_Java_u2(p);
int cache_index = add_invokespecial_cp_cache_entry(cp_index);
if (cache_index != (int)(jushort) cache_index) {
THROW_MSG(vmSymbols::java_lang_InternalError(),
"This classfile overflows invokespecial for interfaces "
"and cannot be loaded");
}
Bytes::put_native_u2(p, cache_index);
} else {
int cache_index = Bytes::get_native_u2(p);
int cp_index = cp_cache_entry_pool_index(cache_index);
Bytes::put_Java_u2(p, cp_index);
}
}
// Adjust the invocation bytecode for a signature-polymorphic method (MethodHandle.invoke, etc.)
void Rewriter::maybe_rewrite_invokehandle(address opc, int cp_index, int cache_index, bool reverse) {
@ -203,7 +228,7 @@ void Rewriter::rewrite_invokedynamic(address bcp, int offset, bool reverse) {
if (!reverse) {
int cp_index = Bytes::get_Java_u2(p);
int cache_index = add_invokedynamic_cp_cache_entry(cp_index);
add_invokedynamic_resolved_references_entries(cp_index, cache_index);
int resolved_index = add_invokedynamic_resolved_references_entries(cp_index, cache_index);
// Replace the trailing four bytes with a CPC index for the dynamic
// call site. Unlike other CPC entries, there is one per bytecode,
// not just one per distinct CP entry. In other words, the
@ -212,13 +237,20 @@ void Rewriter::rewrite_invokedynamic(address bcp, int offset, bool reverse) {
// all these entries. That is the main reason invokedynamic
// must have a five-byte instruction format. (Of course, other JVM
// implementations can use the bytes for other purposes.)
Bytes::put_native_u4(p, ConstantPool::encode_invokedynamic_index(cache_index));
// Note: We use native_u4 format exclusively for 4-byte indexes.
Bytes::put_native_u4(p, ConstantPool::encode_invokedynamic_index(cache_index));
// add the bcp in case we need to patch this bytecode if we also find a
// invokespecial/InterfaceMethodref in the bytecode stream
_patch_invokedynamic_bcps->push(p);
_patch_invokedynamic_refs->push(resolved_index);
} else {
// callsite index
int cache_index = ConstantPool::decode_invokedynamic_index(
Bytes::get_native_u4(p));
int cp_index = cp_cache_entry_pool_index(cache_index);
// We will reverse the bytecode rewriting _after_ adjusting them.
// Adjust the cache index by offset to the invokedynamic entries in the
// cpCache plus the delta if the invokedynamic bytecodes were adjusted.
cache_index = cp_cache_delta() + _first_iteration_cp_cache_limit;
int cp_index = invokedynamic_cp_cache_entry_pool_index(cache_index);
assert(_pool->tag_at(cp_index).is_invoke_dynamic(), "wrong index");
// zero out 4 bytes
Bytes::put_Java_u4(p, 0);
@ -226,6 +258,34 @@ void Rewriter::rewrite_invokedynamic(address bcp, int offset, bool reverse) {
}
}
void Rewriter::patch_invokedynamic_bytecodes() {
// If the end of the cp_cache is the same as after initializing with the
// cpool, nothing needs to be done. Invokedynamic bytecodes are at the
// correct offsets. ie. no invokespecials added
int delta = cp_cache_delta();
if (delta > 0) {
int length = _patch_invokedynamic_bcps->length();
assert(length == _patch_invokedynamic_refs->length(),
"lengths should match");
for (int i = 0; i < length; i++) {
address p = _patch_invokedynamic_bcps->at(i);
int cache_index = ConstantPool::decode_invokedynamic_index(
Bytes::get_native_u4(p));
Bytes::put_native_u4(p, ConstantPool::encode_invokedynamic_index(cache_index + delta));
// invokedynamic resolved references map also points to cp cache and must
// add delta to each.
int resolved_index = _patch_invokedynamic_refs->at(i);
for (int entry = 0; entry < ConstantPoolCacheEntry::_indy_resolved_references_entries; entry++) {
assert(_invokedynamic_references_map[resolved_index+entry] == cache_index,
"should be the same index");
_invokedynamic_references_map.at_put(resolved_index+entry,
cache_index + delta);
}
}
}
}
// Rewrite some ldc bytecodes to _fast_aldc
void Rewriter::maybe_rewrite_ldc(address bcp, int offset, bool is_wide,
@ -269,7 +329,7 @@ void Rewriter::maybe_rewrite_ldc(address bcp, int offset, bool is_wide,
// Rewrites a method given the index_map information
void Rewriter::scan_method(Method* method, bool reverse) {
void Rewriter::scan_method(Method* method, bool reverse, TRAPS) {
int nof_jsrs = 0;
bool has_monitor_bytecodes = false;
@ -329,12 +389,25 @@ void Rewriter::scan_method(Method* method, bool reverse) {
#endif
break;
}
case Bytecodes::_invokespecial : {
int offset = prefix_length + 1;
address p = bcp + offset;
int cp_index = Bytes::get_Java_u2(p);
// InterfaceMethodref
if (_pool->tag_at(cp_index).is_interface_method()) {
rewrite_invokespecial(bcp, offset, reverse, CHECK);
} else {
rewrite_member_reference(bcp, offset, reverse);
}
break;
}
case Bytecodes::_getstatic : // fall through
case Bytecodes::_putstatic : // fall through
case Bytecodes::_getfield : // fall through
case Bytecodes::_putfield : // fall through
case Bytecodes::_invokevirtual : // fall through
case Bytecodes::_invokespecial : // fall through
case Bytecodes::_invokestatic :
case Bytecodes::_invokeinterface:
case Bytecodes::_invokehandle : // if reverse=true
@ -426,16 +499,21 @@ Rewriter::Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, Array<Me
for (int i = len-1; i >= 0; i--) {
Method* method = _methods->at(i);
scan_method(method);
scan_method(method, false, CHECK); // If you get an error here,
// there is no reversing bytecodes
}
// May have to fix invokedynamic bytecodes if invokestatic/InterfaceMethodref
// entries had to be added.
patch_invokedynamic_bytecodes();
// allocate constant pool cache, now that we've seen all the bytecodes
make_constant_pool_cache(THREAD);
// Restore bytecodes to their unrewritten state if there are exceptions
// rewriting bytecodes or allocating the cpCache
if (HAS_PENDING_EXCEPTION) {
restore_bytecodes();
restore_bytecodes(CATCH);
return;
}
@ -452,7 +530,7 @@ Rewriter::Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, Array<Me
// relocating bytecodes. If some are relocated, that is ok because that
// doesn't affect constant pool to cpCache rewriting.
if (HAS_PENDING_EXCEPTION) {
restore_bytecodes();
restore_bytecodes(CATCH);
return;
}
// Method might have gotten rewritten.

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -46,55 +46,102 @@ class Rewriter: public StackObj {
intArray _method_handle_invokers;
int _resolved_reference_limit;
// For mapping invokedynamic bytecodes, which are discovered during method
// scanning. The invokedynamic entries are added at the end of the cpCache.
// If there are any invokespecial/InterfaceMethodref special case bytecodes,
// these entries are added before invokedynamic entries so that the
// invokespecial bytecode 16 bit index doesn't overflow.
intStack _invokedynamic_cp_cache_map;
// For patching.
GrowableArray<address>* _patch_invokedynamic_bcps;
GrowableArray<int>* _patch_invokedynamic_refs;
void init_maps(int length) {
_cp_map.initialize(length, -1);
// Choose an initial value large enough that we don't get frequent
// calls to grow().
_cp_cache_map.initialize(length / 2);
_cp_cache_map.initialize(length/2);
// Also cache resolved objects, in another different cache.
_reference_map.initialize(length, -1);
_resolved_references_map.initialize(length / 2);
_invokedynamic_references_map.initialize(length / 2);
_resolved_references_map.initialize(length/2);
_invokedynamic_references_map.initialize(length/2);
_resolved_reference_limit = -1;
DEBUG_ONLY(_cp_cache_index_limit = -1);
_first_iteration_cp_cache_limit = -1;
// invokedynamic specific fields
_invokedynamic_cp_cache_map.initialize(length/4);
_patch_invokedynamic_bcps = new GrowableArray<address>(length/4);
_patch_invokedynamic_refs = new GrowableArray<int>(length/4);
}
int _cp_cache_index_limit;
int _first_iteration_cp_cache_limit;
void record_map_limits() {
#ifdef ASSERT
// Record initial size of the two arrays generated for the CP cache:
_cp_cache_index_limit = _cp_cache_map.length();
#endif //ASSERT
// Record initial size of the two arrays generated for the CP cache
// relative to walking the constant pool.
_first_iteration_cp_cache_limit = _cp_cache_map.length();
_resolved_reference_limit = _resolved_references_map.length();
}
int cp_cache_delta() {
// How many cp cache entries were added since recording map limits after
// cp cache initialization?
assert(_first_iteration_cp_cache_limit != -1, "only valid after first iteration");
return _cp_cache_map.length() - _first_iteration_cp_cache_limit;
}
int cp_entry_to_cp_cache(int i) { assert(has_cp_cache(i), "oob"); return _cp_map[i]; }
bool has_cp_cache(int i) { return (uint)i < (uint)_cp_map.length() && _cp_map[i] >= 0; }
int add_map_entry(int cp_index, intArray* cp_map, intStack* cp_cache_map) {
assert(cp_map->at(cp_index) == -1, "not twice on same cp_index");
int cache_index = cp_cache_map->append(cp_index);
cp_map->at_put(cp_index, cache_index);
return cache_index;
}
int add_cp_cache_entry(int cp_index) {
assert(_pool->tag_at(cp_index).value() != JVM_CONSTANT_InvokeDynamic, "use indy version");
assert(_cp_map[cp_index] == -1, "not twice on same cp_index");
assert(_cp_cache_index_limit == -1, "do not add cache entries after first iteration");
int cache_index = _cp_cache_map.append(cp_index);
_cp_map.at_put(cp_index, cache_index);
assert(_first_iteration_cp_cache_limit == -1, "do not add cache entries after first iteration");
int cache_index = add_map_entry(cp_index, &_cp_map, &_cp_cache_map);
assert(cp_entry_to_cp_cache(cp_index) == cache_index, "");
assert(cp_cache_entry_pool_index(cache_index) == cp_index, "");
return cache_index;
}
// add a new CP cache entry beyond the normal cache (for invokedynamic only)
int add_invokedynamic_cp_cache_entry(int cp_index) {
assert(_pool->tag_at(cp_index).value() == JVM_CONSTANT_InvokeDynamic, "use non-indy version");
assert(_cp_map[cp_index] == -1, "do not map from cp_index");
assert(_cp_cache_index_limit >= 0, "add indy cache entries after first iteration");
assert(_first_iteration_cp_cache_limit >= 0, "add indy cache entries after first iteration");
// add to the invokedynamic index map.
int cache_index = _invokedynamic_cp_cache_map.append(cp_index);
// do not update _cp_map, since the mapping is one-to-many
assert(invokedynamic_cp_cache_entry_pool_index(cache_index) == cp_index, "");
// this index starts at one but in the bytecode it's appended to the end.
return cache_index + _first_iteration_cp_cache_limit;
}
int invokedynamic_cp_cache_entry_pool_index(int cache_index) {
int cp_index = _invokedynamic_cp_cache_map[cache_index];
return cp_index;
}
// add a new CP cache entry beyond the normal cache for the special case of
// invokespecial with InterfaceMethodref as cpool operand.
int add_invokespecial_cp_cache_entry(int cp_index) {
assert(_first_iteration_cp_cache_limit >= 0, "add these special cache entries after first iteration");
// Don't add InterfaceMethodref if it already exists at the end.
for (int i = _first_iteration_cp_cache_limit; i < _cp_cache_map.length(); i++) {
if (cp_cache_entry_pool_index(i) == cp_index) {
return i;
}
}
int cache_index = _cp_cache_map.append(cp_index);
assert(cache_index >= _cp_cache_index_limit, "");
assert(cache_index >= _first_iteration_cp_cache_limit, "");
// do not update _cp_map, since the mapping is one-to-many
assert(cp_cache_entry_pool_index(cache_index) == cp_index, "");
return cache_index;
}
// fix duplicated code later
int cp_entry_to_resolved_references(int cp_index) const {
assert(has_entry_in_resolved_references(cp_index), "oob");
return _reference_map[cp_index];
@ -105,10 +152,7 @@ class Rewriter: public StackObj {
// add a new entry to the resolved_references map
int add_resolved_references_entry(int cp_index) {
assert(_reference_map[cp_index] == -1, "not twice on same cp_index");
assert(_resolved_reference_limit == -1, "do not add CP refs after first iteration");
int ref_index = _resolved_references_map.append(cp_index);
_reference_map.at_put(cp_index, ref_index);
int ref_index = add_map_entry(cp_index, &_reference_map, &_resolved_references_map);
assert(cp_entry_to_resolved_references(cp_index) == ref_index, "");
return ref_index;
}
@ -137,7 +181,7 @@ class Rewriter: public StackObj {
// Access the contents of _cp_cache_map to determine CP cache layout.
int cp_cache_entry_pool_index(int cache_index) {
int cp_index = _cp_cache_map[cache_index];
return cp_index;
return cp_index;
}
// All the work goes in here:
@ -145,14 +189,18 @@ class Rewriter: public StackObj {
void compute_index_maps();
void make_constant_pool_cache(TRAPS);
void scan_method(Method* m, bool reverse = false);
void scan_method(Method* m, bool reverse, TRAPS);
void rewrite_Object_init(methodHandle m, TRAPS);
void rewrite_member_reference(address bcp, int offset, bool reverse = false);
void maybe_rewrite_invokehandle(address opc, int cp_index, int cache_index, bool reverse = false);
void rewrite_invokedynamic(address bcp, int offset, bool reverse = false);
void maybe_rewrite_ldc(address bcp, int offset, bool is_wide, bool reverse = false);
void rewrite_member_reference(address bcp, int offset, bool reverse);
void maybe_rewrite_invokehandle(address opc, int cp_index, int cache_index, bool reverse);
void rewrite_invokedynamic(address bcp, int offset, bool reverse);
void maybe_rewrite_ldc(address bcp, int offset, bool is_wide, bool reverse);
void rewrite_invokespecial(address bcp, int offset, bool reverse, TRAPS);
void patch_invokedynamic_bytecodes();
// Revert bytecodes in case of an exception.
void restore_bytecodes();
void restore_bytecodes(TRAPS);
static methodHandle rewrite_jsrs(methodHandle m, TRAPS);
public: