6964458: Reimplement class meta-data storage to use native memory

Remove PermGen, allocate meta-data in metaspace linked to class loaders, rewrite GC walking, rewrite and rename metadata to be C++ classes

Co-authored-by: Stefan Karlsson <stefan.karlsson@oracle.com>
Co-authored-by: Mikael Gerdin <mikael.gerdin@oracle.com>
Co-authored-by: Tom Rodriguez <tom.rodriguez@oracle.com>
Reviewed-by: jmasa, stefank, never, coleenp, kvn, brutisso, mgerdin, dholmes, jrose, twisti, roland
This commit is contained in:
Jon Masamitsu 2012-09-01 13:25:18 -04:00 committed by Coleen Phillimore
parent 36eee7c8c8
commit 5c58d27aac
853 changed files with 26124 additions and 82956 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, 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
@ -27,6 +27,7 @@
#include "interpreter/interpreter.hpp"
#include "interpreter/rewriter.hpp"
#include "memory/gcLocker.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "oops/generateOopMap.hpp"
@ -41,7 +42,7 @@
// Marks entries in CP which require additional processing.
void Rewriter::compute_index_maps() {
const int length = _pool->length();
init_cp_map(length);
init_maps(length);
bool saw_mh_symbol = false;
for (int i = 0; i < length; i++) {
int tag = _pool->tag_at(i).value();
@ -49,10 +50,13 @@ void Rewriter::compute_index_maps() {
case JVM_CONSTANT_InterfaceMethodref:
case JVM_CONSTANT_Fieldref : // fall through
case JVM_CONSTANT_Methodref : // fall through
add_cp_cache_entry(i);
break;
case JVM_CONSTANT_String:
case JVM_CONSTANT_Object:
case JVM_CONSTANT_MethodHandle : // fall through
case JVM_CONSTANT_MethodType : // fall through
case JVM_CONSTANT_InvokeDynamic : // fall through
add_cp_cache_entry(i);
add_resolved_references_entry(i);
break;
case JVM_CONSTANT_Utf8:
if (_pool->symbol_at(i) == vmSymbols::java_lang_invoke_MethodHandle())
@ -61,6 +65,9 @@ void Rewriter::compute_index_maps() {
}
}
// Record limits of resolved reference map for constant pool cache indices
record_map_limits();
guarantee((int)_cp_cache_map.length()-1 <= (int)((u2)-1),
"all cp cache indexes fit in a u2");
@ -73,7 +80,7 @@ void Rewriter::restore_bytecodes() {
int len = _methods->length();
for (int i = len-1; i >= 0; i--) {
methodOop method = (methodOop)_methods->obj_at(i);
Method* method = _methods->at(i);
scan_method(method, true);
}
}
@ -81,10 +88,17 @@ void Rewriter::restore_bytecodes() {
// Creates a constant pool cache given a CPC map
void Rewriter::make_constant_pool_cache(TRAPS) {
const int length = _cp_cache_map.length();
constantPoolCacheOop cache =
oopFactory::new_constantPoolCache(length, CHECK);
ClassLoaderData* loader_data = _pool->pool_holder()->class_loader_data();
ConstantPoolCache* cache =
ConstantPoolCache::allocate(loader_data, length, CHECK);
// initialize object cache in constant pool
_pool->initialize_resolved_references(loader_data, _resolved_references_map,
_resolved_reference_limit,
CHECK);
No_Safepoint_Verifier nsv;
cache->initialize(_cp_cache_map);
cache->initialize(_cp_cache_map, _invokedynamic_references_map);
_pool->set_cache(cache);
cache->set_constant_pool(_pool());
}
@ -138,19 +152,19 @@ void Rewriter::rewrite_member_reference(address bcp, int offset, bool reverse) {
int cache_index = cp_entry_to_cp_cache(cp_index);
Bytes::put_native_u2(p, cache_index);
if (!_method_handle_invokers.is_empty())
maybe_rewrite_invokehandle(p - 1, cp_index, reverse);
maybe_rewrite_invokehandle(p - 1, cp_index, cache_index, reverse);
} else {
int cache_index = Bytes::get_native_u2(p);
int pool_index = cp_cache_entry_pool_index(cache_index);
Bytes::put_Java_u2(p, pool_index);
if (!_method_handle_invokers.is_empty())
maybe_rewrite_invokehandle(p - 1, pool_index, reverse);
maybe_rewrite_invokehandle(p - 1, pool_index, cache_index, reverse);
}
}
// Adjust the invocation bytecode for a signature-polymorphic method (MethodHandle.invoke, etc.)
void Rewriter::maybe_rewrite_invokehandle(address opc, int cp_index, bool reverse) {
void Rewriter::maybe_rewrite_invokehandle(address opc, int cp_index, int cache_index, bool reverse) {
if (!reverse) {
if ((*opc) == (u1)Bytecodes::_invokevirtual ||
// allow invokespecial as an alias, although it would be very odd:
@ -163,10 +177,13 @@ void Rewriter::maybe_rewrite_invokehandle(address opc, int cp_index, bool revers
if (status == 0) {
if (_pool->klass_ref_at_noresolve(cp_index) == vmSymbols::java_lang_invoke_MethodHandle() &&
MethodHandles::is_signature_polymorphic_name(SystemDictionary::MethodHandle_klass(),
_pool->name_ref_at(cp_index)))
_pool->name_ref_at(cp_index))) {
// we may need a resolved_refs entry for the appendix
add_invokedynamic_resolved_references_entry(cp_index, cache_index);
status = +1;
else
} else {
status = -1;
}
_method_handle_invokers[cp_index] = status;
}
// We use a special internal bytecode for such methods (if non-static).
@ -193,9 +210,8 @@ void Rewriter::rewrite_invokedynamic(address bcp, int offset, bool reverse) {
assert(p[-1] == Bytecodes::_invokedynamic, "not invokedynamic bytecode");
if (!reverse) {
int cp_index = Bytes::get_Java_u2(p);
int cpc = maybe_add_cp_cache_entry(cp_index); // add lazily
int cpc2 = add_secondary_cp_cache_entry(cpc);
int cache_index = add_invokedynamic_cp_cache_entry(cp_index);
add_invokedynamic_resolved_references_entry(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
@ -204,17 +220,17 @@ 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, constantPoolCacheOopDesc::encode_secondary_index(cpc2));
Bytes::put_native_u4(p, ConstantPool::encode_invokedynamic_index(cache_index));
// Note: We use native_u4 format exclusively for 4-byte indexes.
} else {
int cache_index = constantPoolCacheOopDesc::decode_secondary_index(
// callsite index
int cache_index = ConstantPool::decode_invokedynamic_index(
Bytes::get_native_u4(p));
int secondary_index = cp_cache_secondary_entry_main_index(cache_index);
int pool_index = cp_cache_entry_pool_index(secondary_index);
assert(_pool->tag_at(pool_index).is_invoke_dynamic(), "wrong index");
int cp_index = 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);
Bytes::put_Java_u2(p, pool_index);
Bytes::put_Java_u2(p, cp_index);
}
}
@ -227,16 +243,16 @@ void Rewriter::maybe_rewrite_ldc(address bcp, int offset, bool is_wide,
address p = bcp + offset;
int cp_index = is_wide ? Bytes::get_Java_u2(p) : (u1)(*p);
constantTag tag = _pool->tag_at(cp_index).value();
if (tag.is_method_handle() || tag.is_method_type()) {
int cache_index = cp_entry_to_cp_cache(cp_index);
if (tag.is_method_handle() || tag.is_method_type() || tag.is_string() || tag.is_object()) {
int ref_index = cp_entry_to_resolved_references(cp_index);
if (is_wide) {
(*bcp) = Bytecodes::_fast_aldc_w;
assert(cache_index == (u2)cache_index, "index overflow");
Bytes::put_native_u2(p, cache_index);
assert(ref_index == (u2)ref_index, "index overflow");
Bytes::put_native_u2(p, ref_index);
} else {
(*bcp) = Bytecodes::_fast_aldc;
assert(cache_index == (u1)cache_index, "index overflow");
(*p) = (u1)cache_index;
assert(ref_index == (u1)ref_index, "index overflow");
(*p) = (u1)ref_index;
}
}
} else {
@ -244,8 +260,8 @@ void Rewriter::maybe_rewrite_ldc(address bcp, int offset, bool is_wide,
(is_wide ? Bytecodes::_fast_aldc_w : Bytecodes::_fast_aldc);
if ((*bcp) == rewritten_bc) {
address p = bcp + offset;
int cache_index = is_wide ? Bytes::get_native_u2(p) : (u1)(*p);
int pool_index = cp_cache_entry_pool_index(cache_index);
int ref_index = is_wide ? Bytes::get_native_u2(p) : (u1)(*p);
int pool_index = resolved_references_entry_to_pool_index(ref_index);
if (is_wide) {
(*bcp) = Bytecodes::_ldc_w;
assert(pool_index == (u2)pool_index, "index overflow");
@ -261,14 +277,14 @@ void Rewriter::maybe_rewrite_ldc(address bcp, int offset, bool is_wide,
// Rewrites a method given the index_map information
void Rewriter::scan_method(methodOop method, bool reverse) {
void Rewriter::scan_method(Method* method, bool reverse) {
int nof_jsrs = 0;
bool has_monitor_bytecodes = false;
{
// We cannot tolerate a GC in this block, because we've
// cached the bytecodes in 'code_base'. If the methodOop
// cached the bytecodes in 'code_base'. If the Method*
// moves, the bytecodes will also move.
No_Safepoint_Verifier nsv;
Bytecodes::Code c;
@ -371,16 +387,6 @@ methodHandle Rewriter::rewrite_jsrs(methodHandle method, TRAPS) {
ResolveOopMapConflicts romc(method);
methodHandle original_method = method;
method = romc.do_potential_rewrite(CHECK_(methodHandle()));
if (method() != original_method()) {
// Insert invalid bytecode into original methodOop and set
// interpreter entrypoint, so that a executing this method
// will manifest itself in an easy recognizable form.
address bcp = original_method->bcp_from(0);
*bcp = (u1)Bytecodes::_shouldnotreachhere;
int kind = Interpreter::method_kind(original_method);
original_method->set_interpreter_kind(kind);
}
// Update monitor matching info.
if (romc.monitor_safe()) {
method->set_guaranteed_monitor_matching();
@ -396,28 +402,28 @@ void Rewriter::rewrite(instanceKlassHandle klass, TRAPS) {
}
void Rewriter::rewrite(instanceKlassHandle klass, constantPoolHandle cpool, objArrayHandle methods, TRAPS) {
void Rewriter::rewrite(instanceKlassHandle klass, constantPoolHandle cpool, Array<Method*>* methods, TRAPS) {
ResourceMark rm(THREAD);
Rewriter rw(klass, cpool, methods, CHECK);
// (That's all, folks.)
}
Rewriter::Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, objArrayHandle methods, TRAPS)
Rewriter::Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, Array<Method*>* methods, TRAPS)
: _klass(klass),
_pool(cpool),
_methods(methods)
{
assert(_pool->cache() == NULL, "constant pool cache must not be set yet");
// determine index maps for methodOop rewriting
// determine index maps for Method* rewriting
compute_index_maps();
if (RegisterFinalizersAtInit && _klass->name() == vmSymbols::java_lang_Object()) {
bool did_rewrite = false;
int i = _methods->length();
while (i-- > 0) {
methodOop method = (methodOop)_methods->obj_at(i);
Method* method = _methods->at(i);
if (method->intrinsic_id() == vmIntrinsics::_Object_init) {
// rewrite the return bytecodes of Object.<init> to register the
// object for finalization if needed.
@ -434,7 +440,7 @@ Rewriter::Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, objArray
int len = _methods->length();
for (int i = len-1; i >= 0; i--) {
methodOop method = (methodOop)_methods->obj_at(i);
Method* method = _methods->at(i);
scan_method(method);
}
@ -455,20 +461,19 @@ Rewriter::Rewriter(instanceKlassHandle klass, constantPoolHandle cpool, objArray
// Link and check jvmti dependencies while we're iterating over the methods.
// JSR292 code calls with a different set of methods, so two entry points.
void Rewriter::relocate_and_link(instanceKlassHandle this_oop, TRAPS) {
objArrayHandle methods(THREAD, this_oop->methods());
relocate_and_link(this_oop, methods, THREAD);
relocate_and_link(this_oop, this_oop->methods(), THREAD);
}
void Rewriter::relocate_and_link(instanceKlassHandle this_oop,
objArrayHandle methods, TRAPS) {
Array<Method*>* methods, TRAPS) {
int len = methods->length();
for (int i = len-1; i >= 0; i--) {
methodHandle m(THREAD, (methodOop)methods->obj_at(i));
methodHandle m(THREAD, methods->at(i));
if (m->has_jsrs()) {
m = rewrite_jsrs(m, CHECK);
// Method might have gotten rewritten.
methods->obj_at_put(i, m());
methods->at_put(i, m());
}
// Set up method entry points for compiler and interpreter .
@ -481,7 +486,7 @@ void Rewriter::relocate_and_link(instanceKlassHandle this_oop,
for (int j = i; j >= 0 && j >= i-4; j--) {
if ((++nmc % 1000) == 0) tty->print_cr("Have run MethodComparator %d times...", nmc);
bool z = MethodComparator::methods_EMCP(m(),
(methodOop)methods->obj_at(j));
methods->at(j));
if (j == i && !z) {
tty->print("MethodComparator FAIL: "); m->print(); m->print_codes();
assert(z, "method must compare equal to itself");