mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-15 08:34:30 +02:00
Merge
This commit is contained in:
commit
afef481831
63 changed files with 1020 additions and 744 deletions
|
@ -1213,6 +1213,7 @@ public class CommandProcessor {
|
||||||
}
|
}
|
||||||
HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
|
HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
|
||||||
if (t.countTokens() == 1) {
|
if (t.countTokens() == 1) {
|
||||||
|
String name = t.nextToken();
|
||||||
out.println("intConstant " + name + " " + db.lookupIntConstant(name));
|
out.println("intConstant " + name + " " + db.lookupIntConstant(name));
|
||||||
} else if (t.countTokens() == 0) {
|
} else if (t.countTokens() == 0) {
|
||||||
Iterator i = db.getIntConstants();
|
Iterator i = db.getIntConstants();
|
||||||
|
@ -1235,6 +1236,7 @@ public class CommandProcessor {
|
||||||
}
|
}
|
||||||
HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
|
HotSpotTypeDataBase db = (HotSpotTypeDataBase)agent.getTypeDataBase();
|
||||||
if (t.countTokens() == 1) {
|
if (t.countTokens() == 1) {
|
||||||
|
String name = t.nextToken();
|
||||||
out.println("longConstant " + name + " " + db.lookupLongConstant(name));
|
out.println("longConstant " + name + " " + db.lookupLongConstant(name));
|
||||||
} else if (t.countTokens() == 0) {
|
} else if (t.countTokens() == 0) {
|
||||||
Iterator i = db.getLongConstants();
|
Iterator i = db.getLongConstants();
|
||||||
|
|
|
@ -1724,14 +1724,6 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_different_registers(obj, k_RInfo, klass_RInfo);
|
assert_different_registers(obj, k_RInfo, klass_RInfo);
|
||||||
if (!k->is_loaded()) {
|
|
||||||
klass2reg_with_patching(k_RInfo, op->info_for_patch());
|
|
||||||
} else {
|
|
||||||
#ifdef _LP64
|
|
||||||
__ mov_metadata(k_RInfo, k->constant_encoding());
|
|
||||||
#endif // _LP64
|
|
||||||
}
|
|
||||||
assert(obj != k_RInfo, "must be different");
|
|
||||||
|
|
||||||
__ cmpptr(obj, (int32_t)NULL_WORD);
|
__ cmpptr(obj, (int32_t)NULL_WORD);
|
||||||
if (op->should_profile()) {
|
if (op->should_profile()) {
|
||||||
|
@ -1748,6 +1740,14 @@ void LIR_Assembler::emit_typecheck_helper(LIR_OpTypeCheck *op, Label* success, L
|
||||||
} else {
|
} else {
|
||||||
__ jcc(Assembler::equal, *obj_is_null);
|
__ jcc(Assembler::equal, *obj_is_null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!k->is_loaded()) {
|
||||||
|
klass2reg_with_patching(k_RInfo, op->info_for_patch());
|
||||||
|
} else {
|
||||||
|
#ifdef _LP64
|
||||||
|
__ mov_metadata(k_RInfo, k->constant_encoding());
|
||||||
|
#endif // _LP64
|
||||||
|
}
|
||||||
__ verify_oop(obj);
|
__ verify_oop(obj);
|
||||||
|
|
||||||
if (op->fast_check()) {
|
if (op->fast_check()) {
|
||||||
|
|
|
@ -34,9 +34,9 @@
|
||||||
// Run with +PrintInterpreter to get the VM to print out the size.
|
// Run with +PrintInterpreter to get the VM to print out the size.
|
||||||
// Max size with JVMTI
|
// Max size with JVMTI
|
||||||
#ifdef AMD64
|
#ifdef AMD64
|
||||||
const static int InterpreterCodeSize = 200 * 1024;
|
const static int InterpreterCodeSize = 208 * 1024;
|
||||||
#else
|
#else
|
||||||
const static int InterpreterCodeSize = 168 * 1024;
|
const static int InterpreterCodeSize = 176 * 1024;
|
||||||
#endif // AMD64
|
#endif // AMD64
|
||||||
|
|
||||||
#endif // CPU_X86_VM_TEMPLATEINTERPRETER_X86_HPP
|
#endif // CPU_X86_VM_TEMPLATEINTERPRETER_X86_HPP
|
||||||
|
|
|
@ -4,14 +4,14 @@ It's main purpose is to recreate output similar to
|
||||||
requires a 1.5 JDK to build and simply typing make should build it.
|
requires a 1.5 JDK to build and simply typing make should build it.
|
||||||
|
|
||||||
It produces a jar file, logc.jar, that can be run on the
|
It produces a jar file, logc.jar, that can be run on the
|
||||||
hotspot.log from LogCompilation output like this:
|
HotSpot log (by default, hotspot_pid{pid}.log) from LogCompilation output like this:
|
||||||
|
|
||||||
java -jar logc.jar hotspot.log
|
java -jar logc.jar hotspot_pid1234.log
|
||||||
|
|
||||||
This will produce something like the normal PrintCompilation output.
|
This will produce something like the normal PrintCompilation output.
|
||||||
Adding the -i option with also report inlining like PrintInlining.
|
Adding the -i option with also report inlining like PrintInlining.
|
||||||
|
|
||||||
More information about the LogCompilation output can be found at
|
More information about the LogCompilation output can be found at
|
||||||
|
|
||||||
https://wikis.oracle.com/display/HotSpotInternals/LogCompilation+overview
|
https://wikis.oracle.com/display/HotSpotInternals/LogCompilation+overview
|
||||||
https://wikis.oracle.com/display/HotSpotInternals/PrintCompilation
|
https://wikis.oracle.com/display/HotSpotInternals/PrintCompilation
|
||||||
|
|
|
@ -709,10 +709,10 @@ static Klass* resolve_field_return_klass(methodHandle caller, int bci, TRAPS) {
|
||||||
Bytecodes::Code code = field_access.code();
|
Bytecodes::Code code = field_access.code();
|
||||||
|
|
||||||
// We must load class, initialize class and resolvethe field
|
// We must load class, initialize class and resolvethe field
|
||||||
FieldAccessInfo result; // initialize class if needed
|
fieldDescriptor result; // initialize class if needed
|
||||||
constantPoolHandle constants(THREAD, caller->constants());
|
constantPoolHandle constants(THREAD, caller->constants());
|
||||||
LinkResolver::resolve_field(result, constants, field_access.index(), Bytecodes::java_code(code), false, CHECK_NULL);
|
LinkResolver::resolve_field_access(result, constants, field_access.index(), Bytecodes::java_code(code), CHECK_NULL);
|
||||||
return result.klass()();
|
return result.field_holder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -826,11 +826,11 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
|
||||||
if (stub_id == Runtime1::access_field_patching_id) {
|
if (stub_id == Runtime1::access_field_patching_id) {
|
||||||
|
|
||||||
Bytecode_field field_access(caller_method, bci);
|
Bytecode_field field_access(caller_method, bci);
|
||||||
FieldAccessInfo result; // initialize class if needed
|
fieldDescriptor result; // initialize class if needed
|
||||||
Bytecodes::Code code = field_access.code();
|
Bytecodes::Code code = field_access.code();
|
||||||
constantPoolHandle constants(THREAD, caller_method->constants());
|
constantPoolHandle constants(THREAD, caller_method->constants());
|
||||||
LinkResolver::resolve_field(result, constants, field_access.index(), Bytecodes::java_code(code), false, CHECK);
|
LinkResolver::resolve_field_access(result, constants, field_access.index(), Bytecodes::java_code(code), CHECK);
|
||||||
patch_field_offset = result.field_offset();
|
patch_field_offset = result.offset();
|
||||||
|
|
||||||
// If we're patching a field which is volatile then at compile it
|
// If we're patching a field which is volatile then at compile it
|
||||||
// must not have been know to be volatile, so the generated code
|
// must not have been know to be volatile, so the generated code
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2013, 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
|
||||||
|
@ -75,7 +75,6 @@ ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with_put(NUL
|
||||||
|
|
||||||
assert(klass->get_instanceKlass()->is_linked(), "must be linked before using its constan-pool");
|
assert(klass->get_instanceKlass()->is_linked(), "must be linked before using its constan-pool");
|
||||||
|
|
||||||
_cp_index = index;
|
|
||||||
constantPoolHandle cpool(thread, klass->get_instanceKlass()->constants());
|
constantPoolHandle cpool(thread, klass->get_instanceKlass()->constants());
|
||||||
|
|
||||||
// Get the field's name, signature, and type.
|
// Get the field's name, signature, and type.
|
||||||
|
@ -116,7 +115,7 @@ ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with_put(NUL
|
||||||
// The declared holder of this field may not have been loaded.
|
// The declared holder of this field may not have been loaded.
|
||||||
// Bail out with partial field information.
|
// Bail out with partial field information.
|
||||||
if (!holder_is_accessible) {
|
if (!holder_is_accessible) {
|
||||||
// _cp_index and _type have already been set.
|
// _type has already been set.
|
||||||
// The default values for _flags and _constant_value will suffice.
|
// The default values for _flags and _constant_value will suffice.
|
||||||
// We need values for _holder, _offset, and _is_constant,
|
// We need values for _holder, _offset, and _is_constant,
|
||||||
_holder = declared_holder;
|
_holder = declared_holder;
|
||||||
|
@ -146,8 +145,6 @@ ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with_put(NUL
|
||||||
ciField::ciField(fieldDescriptor *fd): _known_to_link_with_put(NULL), _known_to_link_with_get(NULL) {
|
ciField::ciField(fieldDescriptor *fd): _known_to_link_with_put(NULL), _known_to_link_with_get(NULL) {
|
||||||
ASSERT_IN_VM;
|
ASSERT_IN_VM;
|
||||||
|
|
||||||
_cp_index = -1;
|
|
||||||
|
|
||||||
// Get the field's name, signature, and type.
|
// Get the field's name, signature, and type.
|
||||||
ciEnv* env = CURRENT_ENV;
|
ciEnv* env = CURRENT_ENV;
|
||||||
_name = env->get_symbol(fd->name());
|
_name = env->get_symbol(fd->name());
|
||||||
|
@ -351,12 +348,11 @@ bool ciField::will_link(ciInstanceKlass* accessing_klass,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FieldAccessInfo result;
|
fieldDescriptor result;
|
||||||
constantPoolHandle c_pool(THREAD,
|
LinkResolver::resolve_field(result, _holder->get_instanceKlass(),
|
||||||
accessing_klass->get_instanceKlass()->constants());
|
_name->get_symbol(), _signature->get_symbol(),
|
||||||
LinkResolver::resolve_field(result, c_pool, _cp_index,
|
accessing_klass->get_Klass(), bc, true, false,
|
||||||
Bytecodes::java_code(bc),
|
KILL_COMPILE_ON_FATAL_(false));
|
||||||
true, false, KILL_COMPILE_ON_FATAL_(false));
|
|
||||||
|
|
||||||
// update the hit-cache, unless there is a problem with memory scoping:
|
// update the hit-cache, unless there is a problem with memory scoping:
|
||||||
if (accessing_klass->is_shared() || !is_shared()) {
|
if (accessing_klass->is_shared() || !is_shared()) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2013, 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
|
||||||
|
@ -53,9 +53,6 @@ private:
|
||||||
ciInstanceKlass* _known_to_link_with_get;
|
ciInstanceKlass* _known_to_link_with_get;
|
||||||
ciConstant _constant_value;
|
ciConstant _constant_value;
|
||||||
|
|
||||||
// Used for will_link
|
|
||||||
int _cp_index;
|
|
||||||
|
|
||||||
ciType* compute_type();
|
ciType* compute_type();
|
||||||
ciType* compute_type_impl();
|
ciType* compute_type_impl();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2013, 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
|
||||||
|
@ -522,8 +522,7 @@ ciInstanceKlass::compute_nonstatic_fields_impl(GrowableArray<ciField*>*
|
||||||
|
|
||||||
for (JavaFieldStream fs(k); !fs.done(); fs.next()) {
|
for (JavaFieldStream fs(k); !fs.done(); fs.next()) {
|
||||||
if (fs.access_flags().is_static()) continue;
|
if (fs.access_flags().is_static()) continue;
|
||||||
fieldDescriptor fd;
|
fieldDescriptor& fd = fs.field_descriptor();
|
||||||
fd.initialize(k, fs.index());
|
|
||||||
ciField* field = new (arena) ciField(&fd);
|
ciField* field = new (arena) ciField(&fd);
|
||||||
fields->append(field);
|
fields->append(field);
|
||||||
}
|
}
|
||||||
|
|
|
@ -286,7 +286,10 @@ int ciMethod::itable_index() {
|
||||||
check_is_loaded();
|
check_is_loaded();
|
||||||
assert(holder()->is_linked(), "must be linked");
|
assert(holder()->is_linked(), "must be linked");
|
||||||
VM_ENTRY_MARK;
|
VM_ENTRY_MARK;
|
||||||
return klassItable::compute_itable_index(get_Method());
|
Method* m = get_Method();
|
||||||
|
if (!m->has_itable_index())
|
||||||
|
return Method::nonvirtual_vtable_index;
|
||||||
|
return m->itable_index();
|
||||||
}
|
}
|
||||||
#endif // SHARK
|
#endif // SHARK
|
||||||
|
|
||||||
|
@ -1137,6 +1140,10 @@ bool ciMethod::is_klass_loaded(int refinfo_index, bool must_be_resolved) const {
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// ciMethod::check_call
|
// ciMethod::check_call
|
||||||
bool ciMethod::check_call(int refinfo_index, bool is_static) const {
|
bool ciMethod::check_call(int refinfo_index, bool is_static) const {
|
||||||
|
// This method is used only in C2 from InlineTree::ok_to_inline,
|
||||||
|
// and is only used under -Xcomp or -XX:CompileTheWorld.
|
||||||
|
// It appears to fail when applied to an invokeinterface call site.
|
||||||
|
// FIXME: Remove this method and resolve_method_statically; refactor to use the other LinkResolver entry points.
|
||||||
VM_ENTRY_MARK;
|
VM_ENTRY_MARK;
|
||||||
{
|
{
|
||||||
EXCEPTION_MARK;
|
EXCEPTION_MARK;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2013, 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
|
||||||
|
@ -44,6 +44,7 @@ class ciSymbol : public ciBaseObject {
|
||||||
friend class ciInstanceKlass;
|
friend class ciInstanceKlass;
|
||||||
friend class ciSignature;
|
friend class ciSignature;
|
||||||
friend class ciMethod;
|
friend class ciMethod;
|
||||||
|
friend class ciField;
|
||||||
friend class ciObjArrayKlass;
|
friend class ciObjArrayKlass;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -3995,9 +3995,8 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
|
||||||
this_klass->set_has_final_method();
|
this_klass->set_has_final_method();
|
||||||
}
|
}
|
||||||
this_klass->copy_method_ordering(method_ordering, CHECK_NULL);
|
this_klass->copy_method_ordering(method_ordering, CHECK_NULL);
|
||||||
// The InstanceKlass::_methods_jmethod_ids cache and the
|
// The InstanceKlass::_methods_jmethod_ids cache
|
||||||
// InstanceKlass::_methods_cached_itable_indices cache are
|
// is managed on the assumption that the initial cache
|
||||||
// both managed on the assumption that the initial cache
|
|
||||||
// size is equal to the number of methods in the class. If
|
// size is equal to the number of methods in the class. If
|
||||||
// that changes, then InstanceKlass::idnum_can_increment()
|
// that changes, then InstanceKlass::idnum_can_increment()
|
||||||
// has to be changed accordingly.
|
// has to be changed accordingly.
|
||||||
|
|
|
@ -1319,6 +1319,25 @@ static void clear_pending_exception_if_not_oom(TRAPS) {
|
||||||
// The CHECK at the caller will propagate the exception out
|
// The CHECK at the caller will propagate the exception out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if the given method should be compiled when doing compile-the-world.
|
||||||
|
*
|
||||||
|
* TODO: This should be a private method in a CompileTheWorld class.
|
||||||
|
*/
|
||||||
|
static bool can_be_compiled(methodHandle m, int comp_level) {
|
||||||
|
assert(CompileTheWorld, "must be");
|
||||||
|
|
||||||
|
// It's not valid to compile a native wrapper for MethodHandle methods
|
||||||
|
// that take a MemberName appendix since the bytecode signature is not
|
||||||
|
// correct.
|
||||||
|
vmIntrinsics::ID iid = m->intrinsic_id();
|
||||||
|
if (MethodHandles::is_signature_polymorphic(iid) && MethodHandles::has_member_arg(iid)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CompilationPolicy::can_be_compiled(m, comp_level);
|
||||||
|
}
|
||||||
|
|
||||||
void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
|
void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
|
||||||
int len = (int)strlen(name);
|
int len = (int)strlen(name);
|
||||||
if (len > 6 && strcmp(".class", name + len - 6) == 0) {
|
if (len > 6 && strcmp(".class", name + len - 6) == 0) {
|
||||||
|
@ -1362,8 +1381,7 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
|
||||||
int comp_level = CompilationPolicy::policy()->initial_compile_level();
|
int comp_level = CompilationPolicy::policy()->initial_compile_level();
|
||||||
for (int n = 0; n < k->methods()->length(); n++) {
|
for (int n = 0; n < k->methods()->length(); n++) {
|
||||||
methodHandle m (THREAD, k->methods()->at(n));
|
methodHandle m (THREAD, k->methods()->at(n));
|
||||||
if (CompilationPolicy::can_be_compiled(m, comp_level)) {
|
if (can_be_compiled(m, comp_level)) {
|
||||||
|
|
||||||
if (++_codecache_sweep_counter == CompileTheWorldSafepointInterval) {
|
if (++_codecache_sweep_counter == CompileTheWorldSafepointInterval) {
|
||||||
// Give sweeper a chance to keep up with CTW
|
// Give sweeper a chance to keep up with CTW
|
||||||
VM_ForceSafepoint op;
|
VM_ForceSafepoint op;
|
||||||
|
@ -1375,7 +1393,7 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
|
||||||
methodHandle(), 0, "CTW", THREAD);
|
methodHandle(), 0, "CTW", THREAD);
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
clear_pending_exception_if_not_oom(CHECK);
|
clear_pending_exception_if_not_oom(CHECK);
|
||||||
tty->print_cr("CompileTheWorld (%d) : Skipping method: %s", _compile_the_world_class_counter, m->name()->as_C_string());
|
tty->print_cr("CompileTheWorld (%d) : Skipping method: %s", _compile_the_world_class_counter, m->name_and_sig_as_C_string());
|
||||||
} else {
|
} else {
|
||||||
_compile_the_world_method_counter++;
|
_compile_the_world_method_counter++;
|
||||||
}
|
}
|
||||||
|
@ -1391,11 +1409,13 @@ void ClassLoader::compile_the_world_in(char* name, Handle loader, TRAPS) {
|
||||||
methodHandle(), 0, "CTW", THREAD);
|
methodHandle(), 0, "CTW", THREAD);
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
clear_pending_exception_if_not_oom(CHECK);
|
clear_pending_exception_if_not_oom(CHECK);
|
||||||
tty->print_cr("CompileTheWorld (%d) : Skipping method: %s", _compile_the_world_class_counter, m->name()->as_C_string());
|
tty->print_cr("CompileTheWorld (%d) : Skipping method: %s", _compile_the_world_class_counter, m->name_and_sig_as_C_string());
|
||||||
} else {
|
} else {
|
||||||
_compile_the_world_method_counter++;
|
_compile_the_world_method_counter++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
tty->print_cr("CompileTheWorld (%d) : Skipping method: %s", _compile_the_world_class_counter, m->name_and_sig_as_C_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
nmethod* nm = m->code();
|
nmethod* nm = m->code();
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2013, 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
|
||||||
|
@ -161,31 +161,36 @@ address CompiledIC::stub_address() const {
|
||||||
|
|
||||||
|
|
||||||
void CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecode, TRAPS) {
|
void CompiledIC::set_to_megamorphic(CallInfo* call_info, Bytecodes::Code bytecode, TRAPS) {
|
||||||
methodHandle method = call_info->selected_method();
|
|
||||||
bool is_invoke_interface = (bytecode == Bytecodes::_invokeinterface && !call_info->has_vtable_index());
|
|
||||||
assert(CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
|
assert(CompiledIC_lock->is_locked() || SafepointSynchronize::is_at_safepoint(), "");
|
||||||
assert(!is_optimized(), "cannot set an optimized virtual call to megamorphic");
|
assert(!is_optimized(), "cannot set an optimized virtual call to megamorphic");
|
||||||
assert(is_call_to_compiled() || is_call_to_interpreted(), "going directly to megamorphic?");
|
assert(is_call_to_compiled() || is_call_to_interpreted(), "going directly to megamorphic?");
|
||||||
|
|
||||||
address entry;
|
address entry;
|
||||||
if (is_invoke_interface) {
|
if (call_info->call_kind() == CallInfo::itable_call) {
|
||||||
int index = klassItable::compute_itable_index(call_info->resolved_method()());
|
assert(bytecode == Bytecodes::_invokeinterface, "");
|
||||||
entry = VtableStubs::create_stub(false, index, method());
|
int itable_index = call_info->itable_index();
|
||||||
|
entry = VtableStubs::find_itable_stub(itable_index);
|
||||||
|
#ifdef ASSERT
|
||||||
assert(entry != NULL, "entry not computed");
|
assert(entry != NULL, "entry not computed");
|
||||||
|
int index = call_info->resolved_method()->itable_index();
|
||||||
|
assert(index == itable_index, "CallInfo pre-computes this");
|
||||||
|
#endif //ASSERT
|
||||||
InstanceKlass* k = call_info->resolved_method()->method_holder();
|
InstanceKlass* k = call_info->resolved_method()->method_holder();
|
||||||
assert(k->is_interface(), "sanity check");
|
assert(k->verify_itable_index(itable_index), "sanity check");
|
||||||
InlineCacheBuffer::create_transition_stub(this, k, entry);
|
InlineCacheBuffer::create_transition_stub(this, k, entry);
|
||||||
} else {
|
} else {
|
||||||
// Can be different than method->vtable_index(), due to package-private etc.
|
assert(call_info->call_kind() == CallInfo::vtable_call, "either itable or vtable");
|
||||||
|
// Can be different than selected_method->vtable_index(), due to package-private etc.
|
||||||
int vtable_index = call_info->vtable_index();
|
int vtable_index = call_info->vtable_index();
|
||||||
entry = VtableStubs::create_stub(true, vtable_index, method());
|
assert(call_info->resolved_klass()->verify_vtable_index(vtable_index), "sanity check");
|
||||||
InlineCacheBuffer::create_transition_stub(this, method(), entry);
|
entry = VtableStubs::find_vtable_stub(vtable_index);
|
||||||
|
InlineCacheBuffer::create_transition_stub(this, NULL, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TraceICs) {
|
if (TraceICs) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
tty->print_cr ("IC@" INTPTR_FORMAT ": to megamorphic %s entry: " INTPTR_FORMAT,
|
tty->print_cr ("IC@" INTPTR_FORMAT ": to megamorphic %s entry: " INTPTR_FORMAT,
|
||||||
instruction_address(), method->print_value_string(), entry);
|
instruction_address(), call_info->selected_method()->print_value_string(), entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can't check this anymore. With lazy deopt we could have already
|
// We can't check this anymore. With lazy deopt we could have already
|
||||||
|
|
|
@ -111,7 +111,7 @@ void VtableStubs::initialize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
address VtableStubs::create_stub(bool is_vtable_stub, int vtable_index, Method* method) {
|
address VtableStubs::find_stub(bool is_vtable_stub, int vtable_index) {
|
||||||
assert(vtable_index >= 0, "must be positive");
|
assert(vtable_index >= 0, "must be positive");
|
||||||
|
|
||||||
VtableStub* s = ShareVtableStubs ? lookup(is_vtable_stub, vtable_index) : NULL;
|
VtableStub* s = ShareVtableStubs ? lookup(is_vtable_stub, vtable_index) : NULL;
|
||||||
|
|
|
@ -121,9 +121,11 @@ class VtableStubs : AllStatic {
|
||||||
static VtableStub* lookup (bool is_vtable_stub, int vtable_index);
|
static VtableStub* lookup (bool is_vtable_stub, int vtable_index);
|
||||||
static void enter (bool is_vtable_stub, int vtable_index, VtableStub* s);
|
static void enter (bool is_vtable_stub, int vtable_index, VtableStub* s);
|
||||||
static inline uint hash (bool is_vtable_stub, int vtable_index);
|
static inline uint hash (bool is_vtable_stub, int vtable_index);
|
||||||
|
static address find_stub (bool is_vtable_stub, int vtable_index);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static address create_stub(bool is_vtable_stub, int vtable_index, Method* method); // return the entry point of a stub for this call
|
static address find_vtable_stub(int vtable_index) { return find_stub(true, vtable_index); }
|
||||||
|
static address find_itable_stub(int itable_index) { return find_stub(false, itable_index); }
|
||||||
static bool is_entry_point(address pc); // is pc a vtable stub entry point?
|
static bool is_entry_point(address pc); // is pc a vtable stub entry point?
|
||||||
static bool contains(address pc); // is pc within any stub?
|
static bool contains(address pc); // is pc within any stub?
|
||||||
static VtableStub* stub_containing(address pc); // stub containing pc or NULL
|
static VtableStub* stub_containing(address pc); // stub containing pc or NULL
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
class PtrQueueSet;
|
class PtrQueueSet;
|
||||||
class PtrQueue VALUE_OBJ_CLASS_SPEC {
|
class PtrQueue VALUE_OBJ_CLASS_SPEC {
|
||||||
|
friend class VMStructs;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// The ptr queue set to which this queue belongs.
|
// The ptr queue set to which this queue belongs.
|
||||||
|
|
|
@ -31,7 +31,8 @@
|
||||||
|
|
||||||
#define VM_STRUCTS_G1(nonstatic_field, static_field) \
|
#define VM_STRUCTS_G1(nonstatic_field, static_field) \
|
||||||
\
|
\
|
||||||
static_field(HeapRegion, GrainBytes, size_t) \
|
static_field(HeapRegion, GrainBytes, size_t) \
|
||||||
|
static_field(HeapRegion, LogOfHRGrainBytes, int) \
|
||||||
\
|
\
|
||||||
nonstatic_field(HeapRegionSeq, _regions, HeapRegion**) \
|
nonstatic_field(HeapRegionSeq, _regions, HeapRegion**) \
|
||||||
nonstatic_field(HeapRegionSeq, _length, uint) \
|
nonstatic_field(HeapRegionSeq, _length, uint) \
|
||||||
|
|
|
@ -496,15 +496,15 @@ IRT_END
|
||||||
|
|
||||||
IRT_ENTRY(void, InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecodes::Code bytecode))
|
IRT_ENTRY(void, InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecodes::Code bytecode))
|
||||||
// resolve field
|
// resolve field
|
||||||
FieldAccessInfo info;
|
fieldDescriptor info;
|
||||||
constantPoolHandle pool(thread, method(thread)->constants());
|
constantPoolHandle pool(thread, method(thread)->constants());
|
||||||
bool is_put = (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_putstatic);
|
bool is_put = (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_putstatic);
|
||||||
bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic);
|
bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic);
|
||||||
|
|
||||||
{
|
{
|
||||||
JvmtiHideSingleStepping jhss(thread);
|
JvmtiHideSingleStepping jhss(thread);
|
||||||
LinkResolver::resolve_field(info, pool, get_index_u2_cpcache(thread, bytecode),
|
LinkResolver::resolve_field_access(info, pool, get_index_u2_cpcache(thread, bytecode),
|
||||||
bytecode, false, CHECK);
|
bytecode, CHECK);
|
||||||
} // end JvmtiHideSingleStepping
|
} // end JvmtiHideSingleStepping
|
||||||
|
|
||||||
// check if link resolution caused cpCache to be updated
|
// check if link resolution caused cpCache to be updated
|
||||||
|
@ -524,7 +524,7 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecode
|
||||||
// class is intitialized. This is required so that access to the static
|
// class is intitialized. This is required so that access to the static
|
||||||
// field will call the initialization function every time until the class
|
// field will call the initialization function every time until the class
|
||||||
// is completely initialized ala. in 2.17.5 in JVM Specification.
|
// is completely initialized ala. in 2.17.5 in JVM Specification.
|
||||||
InstanceKlass *klass = InstanceKlass::cast(info.klass()());
|
InstanceKlass* klass = InstanceKlass::cast(info.field_holder());
|
||||||
bool uninitialized_static = ((bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic) &&
|
bool uninitialized_static = ((bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic) &&
|
||||||
!klass->is_initialized());
|
!klass->is_initialized());
|
||||||
Bytecodes::Code get_code = (Bytecodes::Code)0;
|
Bytecodes::Code get_code = (Bytecodes::Code)0;
|
||||||
|
@ -539,9 +539,9 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecode
|
||||||
cache_entry(thread)->set_field(
|
cache_entry(thread)->set_field(
|
||||||
get_code,
|
get_code,
|
||||||
put_code,
|
put_code,
|
||||||
info.klass(),
|
info.field_holder(),
|
||||||
info.field_index(),
|
info.index(),
|
||||||
info.field_offset(),
|
info.offset(),
|
||||||
state,
|
state,
|
||||||
info.access_flags().is_final(),
|
info.access_flags().is_final(),
|
||||||
info.access_flags().is_volatile(),
|
info.access_flags().is_volatile(),
|
||||||
|
@ -686,29 +686,55 @@ IRT_ENTRY(void, InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes
|
||||||
if (already_resolved(thread)) return;
|
if (already_resolved(thread)) return;
|
||||||
|
|
||||||
if (bytecode == Bytecodes::_invokeinterface) {
|
if (bytecode == Bytecodes::_invokeinterface) {
|
||||||
|
|
||||||
if (TraceItables && Verbose) {
|
if (TraceItables && Verbose) {
|
||||||
ResourceMark rm(thread);
|
ResourceMark rm(thread);
|
||||||
tty->print_cr("Resolving: klass: %s to method: %s", info.resolved_klass()->name()->as_C_string(), info.resolved_method()->name()->as_C_string());
|
tty->print_cr("Resolving: klass: %s to method: %s", info.resolved_klass()->name()->as_C_string(), info.resolved_method()->name()->as_C_string());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#ifdef ASSERT
|
||||||
|
if (bytecode == Bytecodes::_invokeinterface) {
|
||||||
if (info.resolved_method()->method_holder() ==
|
if (info.resolved_method()->method_holder() ==
|
||||||
SystemDictionary::Object_klass()) {
|
SystemDictionary::Object_klass()) {
|
||||||
// NOTE: THIS IS A FIX FOR A CORNER CASE in the JVM spec
|
// NOTE: THIS IS A FIX FOR A CORNER CASE in the JVM spec
|
||||||
// (see also cpCacheOop.cpp for details)
|
// (see also CallInfo::set_interface for details)
|
||||||
|
assert(info.call_kind() == CallInfo::vtable_call ||
|
||||||
|
info.call_kind() == CallInfo::direct_call, "");
|
||||||
methodHandle rm = info.resolved_method();
|
methodHandle rm = info.resolved_method();
|
||||||
assert(rm->is_final() || info.has_vtable_index(),
|
assert(rm->is_final() || info.has_vtable_index(),
|
||||||
"should have been set already");
|
"should have been set already");
|
||||||
cache_entry(thread)->set_method(bytecode, rm, info.vtable_index());
|
} else if (!info.resolved_method()->has_itable_index()) {
|
||||||
|
// Resolved something like CharSequence.toString. Use vtable not itable.
|
||||||
|
assert(info.call_kind() != CallInfo::itable_call, "");
|
||||||
} else {
|
} else {
|
||||||
// Setup itable entry
|
// Setup itable entry
|
||||||
int index = klassItable::compute_itable_index(info.resolved_method()());
|
assert(info.call_kind() == CallInfo::itable_call, "");
|
||||||
cache_entry(thread)->set_interface_call(info.resolved_method(), index);
|
int index = info.resolved_method()->itable_index();
|
||||||
|
assert(info.itable_index() == index, "");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cache_entry(thread)->set_method(
|
assert(info.call_kind() == CallInfo::direct_call ||
|
||||||
|
info.call_kind() == CallInfo::vtable_call, "");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
switch (info.call_kind()) {
|
||||||
|
case CallInfo::direct_call:
|
||||||
|
cache_entry(thread)->set_direct_call(
|
||||||
|
bytecode,
|
||||||
|
info.resolved_method());
|
||||||
|
break;
|
||||||
|
case CallInfo::vtable_call:
|
||||||
|
cache_entry(thread)->set_vtable_call(
|
||||||
bytecode,
|
bytecode,
|
||||||
info.resolved_method(),
|
info.resolved_method(),
|
||||||
info.vtable_index());
|
info.vtable_index());
|
||||||
|
break;
|
||||||
|
case CallInfo::itable_call:
|
||||||
|
cache_entry(thread)->set_itable_call(
|
||||||
|
bytecode,
|
||||||
|
info.resolved_method(),
|
||||||
|
info.itable_index());
|
||||||
|
break;
|
||||||
|
default: ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
IRT_END
|
IRT_END
|
||||||
|
|
|
@ -46,19 +46,6 @@
|
||||||
#include "runtime/thread.inline.hpp"
|
#include "runtime/thread.inline.hpp"
|
||||||
#include "runtime/vmThread.hpp"
|
#include "runtime/vmThread.hpp"
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
|
||||||
// Implementation of FieldAccessInfo
|
|
||||||
|
|
||||||
void FieldAccessInfo::set(KlassHandle klass, Symbol* name, int field_index, int field_offset,
|
|
||||||
BasicType field_type, AccessFlags access_flags) {
|
|
||||||
_klass = klass;
|
|
||||||
_name = name;
|
|
||||||
_field_index = field_index;
|
|
||||||
_field_offset = field_offset;
|
|
||||||
_field_type = field_type;
|
|
||||||
_access_flags = access_flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
// Implementation of CallInfo
|
// Implementation of CallInfo
|
||||||
|
@ -66,26 +53,25 @@ BasicType field_type, AccessFlags access_flags) {
|
||||||
|
|
||||||
void CallInfo::set_static(KlassHandle resolved_klass, methodHandle resolved_method, TRAPS) {
|
void CallInfo::set_static(KlassHandle resolved_klass, methodHandle resolved_method, TRAPS) {
|
||||||
int vtable_index = Method::nonvirtual_vtable_index;
|
int vtable_index = Method::nonvirtual_vtable_index;
|
||||||
set_common(resolved_klass, resolved_klass, resolved_method, resolved_method, vtable_index, CHECK);
|
set_common(resolved_klass, resolved_klass, resolved_method, resolved_method, CallInfo::direct_call, vtable_index, CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CallInfo::set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, TRAPS) {
|
void CallInfo::set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int itable_index, TRAPS) {
|
||||||
// This is only called for interface methods. If the resolved_method
|
// This is only called for interface methods. If the resolved_method
|
||||||
// comes from java/lang/Object, it can be the subject of a virtual call, so
|
// comes from java/lang/Object, it can be the subject of a virtual call, so
|
||||||
// we should pick the vtable index from the resolved method.
|
// we should pick the vtable index from the resolved method.
|
||||||
// Other than that case, there is no valid vtable index to specify.
|
// In that case, the caller must call set_virtual instead of set_interface.
|
||||||
int vtable_index = Method::invalid_vtable_index;
|
assert(resolved_method->method_holder()->is_interface(), "");
|
||||||
if (resolved_method->method_holder() == SystemDictionary::Object_klass()) {
|
assert(itable_index == resolved_method()->itable_index(), "");
|
||||||
assert(resolved_method->vtable_index() == selected_method->vtable_index(), "sanity check");
|
set_common(resolved_klass, selected_klass, resolved_method, selected_method, CallInfo::itable_call, itable_index, CHECK);
|
||||||
vtable_index = resolved_method->vtable_index();
|
|
||||||
}
|
|
||||||
set_common(resolved_klass, selected_klass, resolved_method, selected_method, vtable_index, CHECK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallInfo::set_virtual(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS) {
|
void CallInfo::set_virtual(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS) {
|
||||||
assert(vtable_index >= 0 || vtable_index == Method::nonvirtual_vtable_index, "valid index");
|
assert(vtable_index >= 0 || vtable_index == Method::nonvirtual_vtable_index, "valid index");
|
||||||
set_common(resolved_klass, selected_klass, resolved_method, selected_method, vtable_index, CHECK);
|
assert(vtable_index < 0 || !resolved_method->has_vtable_index() || vtable_index == resolved_method->vtable_index(), "");
|
||||||
|
CallKind kind = (vtable_index >= 0 && !resolved_method->can_be_statically_bound() ? CallInfo::vtable_call : CallInfo::direct_call);
|
||||||
|
set_common(resolved_klass, selected_klass, resolved_method, selected_method, kind, vtable_index, CHECK);
|
||||||
assert(!resolved_method->is_compiled_lambda_form(), "these must be handled via an invokehandle call");
|
assert(!resolved_method->is_compiled_lambda_form(), "these must be handled via an invokehandle call");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,20 +84,29 @@ void CallInfo::set_handle(methodHandle resolved_method, Handle resolved_appendix
|
||||||
resolved_method->is_compiled_lambda_form(),
|
resolved_method->is_compiled_lambda_form(),
|
||||||
"linkMethod must return one of these");
|
"linkMethod must return one of these");
|
||||||
int vtable_index = Method::nonvirtual_vtable_index;
|
int vtable_index = Method::nonvirtual_vtable_index;
|
||||||
assert(resolved_method->vtable_index() == vtable_index, "");
|
assert(!resolved_method->has_vtable_index(), "");
|
||||||
set_common(resolved_klass, resolved_klass, resolved_method, resolved_method, vtable_index, CHECK);
|
set_common(resolved_klass, resolved_klass, resolved_method, resolved_method, CallInfo::direct_call, vtable_index, CHECK);
|
||||||
_resolved_appendix = resolved_appendix;
|
_resolved_appendix = resolved_appendix;
|
||||||
_resolved_method_type = resolved_method_type;
|
_resolved_method_type = resolved_method_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index, TRAPS) {
|
void CallInfo::set_common(KlassHandle resolved_klass,
|
||||||
|
KlassHandle selected_klass,
|
||||||
|
methodHandle resolved_method,
|
||||||
|
methodHandle selected_method,
|
||||||
|
CallKind kind,
|
||||||
|
int index,
|
||||||
|
TRAPS) {
|
||||||
assert(resolved_method->signature() == selected_method->signature(), "signatures must correspond");
|
assert(resolved_method->signature() == selected_method->signature(), "signatures must correspond");
|
||||||
_resolved_klass = resolved_klass;
|
_resolved_klass = resolved_klass;
|
||||||
_selected_klass = selected_klass;
|
_selected_klass = selected_klass;
|
||||||
_resolved_method = resolved_method;
|
_resolved_method = resolved_method;
|
||||||
_selected_method = selected_method;
|
_selected_method = selected_method;
|
||||||
_vtable_index = vtable_index;
|
_call_kind = kind;
|
||||||
|
_call_index = index;
|
||||||
_resolved_appendix = Handle();
|
_resolved_appendix = Handle();
|
||||||
|
DEBUG_ONLY(verify()); // verify before making side effects
|
||||||
|
|
||||||
if (CompilationPolicy::must_be_compiled(selected_method)) {
|
if (CompilationPolicy::must_be_compiled(selected_method)) {
|
||||||
// This path is unusual, mostly used by the '-Xcomp' stress test mode.
|
// This path is unusual, mostly used by the '-Xcomp' stress test mode.
|
||||||
|
|
||||||
|
@ -138,6 +133,65 @@ void CallInfo::set_common(KlassHandle resolved_klass, KlassHandle selected_klass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// utility query for unreflecting a method
|
||||||
|
CallInfo::CallInfo(Method* resolved_method, Klass* resolved_klass) {
|
||||||
|
Klass* resolved_method_holder = resolved_method->method_holder();
|
||||||
|
if (resolved_klass == NULL) { // 2nd argument defaults to holder of 1st
|
||||||
|
resolved_klass = resolved_method_holder;
|
||||||
|
}
|
||||||
|
_resolved_klass = resolved_klass;
|
||||||
|
_selected_klass = resolved_klass;
|
||||||
|
_resolved_method = resolved_method;
|
||||||
|
_selected_method = resolved_method;
|
||||||
|
// classify:
|
||||||
|
CallKind kind = CallInfo::unknown_kind;
|
||||||
|
int index = resolved_method->vtable_index();
|
||||||
|
if (resolved_method->can_be_statically_bound()) {
|
||||||
|
kind = CallInfo::direct_call;
|
||||||
|
} else if (!resolved_method_holder->is_interface()) {
|
||||||
|
// 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.
|
||||||
|
ResourceMark rm;
|
||||||
|
klassVtable* vt = InstanceKlass::cast(resolved_klass)->vtable();
|
||||||
|
index = vt->index_of_miranda(resolved_method->name(),
|
||||||
|
resolved_method->signature());
|
||||||
|
kind = CallInfo::vtable_call;
|
||||||
|
} else {
|
||||||
|
// A regular interface call.
|
||||||
|
kind = CallInfo::itable_call;
|
||||||
|
index = resolved_method->itable_index();
|
||||||
|
}
|
||||||
|
assert(index == Method::nonvirtual_vtable_index || index >= 0, err_msg("bad index %d", index));
|
||||||
|
_call_kind = kind;
|
||||||
|
_call_index = index;
|
||||||
|
_resolved_appendix = Handle();
|
||||||
|
DEBUG_ONLY(verify());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
|
void CallInfo::verify() {
|
||||||
|
switch (call_kind()) { // the meaning and allowed value of index depends on kind
|
||||||
|
case CallInfo::direct_call:
|
||||||
|
if (_call_index == Method::nonvirtual_vtable_index) break;
|
||||||
|
// else fall through to check vtable index:
|
||||||
|
case CallInfo::vtable_call:
|
||||||
|
assert(resolved_klass()->verify_vtable_index(_call_index), "");
|
||||||
|
break;
|
||||||
|
case CallInfo::itable_call:
|
||||||
|
assert(resolved_method()->method_holder()->verify_itable_index(_call_index), "");
|
||||||
|
break;
|
||||||
|
case CallInfo::unknown_kind:
|
||||||
|
assert(call_kind() != CallInfo::unknown_kind, "CallInfo must be set");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fatal(err_msg_res("Unexpected call kind %d", call_kind()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //ASSERT
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
// Klass resolution
|
// Klass resolution
|
||||||
|
@ -163,13 +217,6 @@ void LinkResolver::resolve_klass(KlassHandle& result, constantPoolHandle pool, i
|
||||||
result = KlassHandle(THREAD, result_oop);
|
result = KlassHandle(THREAD, result_oop);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinkResolver::resolve_klass_no_update(KlassHandle& result, constantPoolHandle pool, int index, TRAPS) {
|
|
||||||
Klass* result_oop =
|
|
||||||
ConstantPool::klass_ref_at_if_loaded_check(pool, index, CHECK);
|
|
||||||
result = KlassHandle(THREAD, result_oop);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
// Method resolution
|
// Method resolution
|
||||||
//
|
//
|
||||||
|
@ -360,7 +407,12 @@ void LinkResolver::check_method_accessability(KlassHandle ref_klass,
|
||||||
|
|
||||||
void LinkResolver::resolve_method_statically(methodHandle& resolved_method, KlassHandle& resolved_klass,
|
void LinkResolver::resolve_method_statically(methodHandle& resolved_method, KlassHandle& resolved_klass,
|
||||||
Bytecodes::Code code, constantPoolHandle pool, int index, TRAPS) {
|
Bytecodes::Code code, constantPoolHandle pool, int index, TRAPS) {
|
||||||
|
// This method is used only
|
||||||
|
// (1) in C2 from InlineTree::ok_to_inline (via ciMethod::check_call),
|
||||||
|
// and
|
||||||
|
// (2) in Bytecode_invoke::static_target
|
||||||
|
// It appears to fail when applied to an invokeinterface call site.
|
||||||
|
// FIXME: Remove this method and ciMethod::check_call; refactor to use the other LinkResolver entry points.
|
||||||
// resolve klass
|
// resolve klass
|
||||||
if (code == Bytecodes::_invokedynamic) {
|
if (code == Bytecodes::_invokedynamic) {
|
||||||
resolved_klass = SystemDictionary::MethodHandle_klass();
|
resolved_klass = SystemDictionary::MethodHandle_klass();
|
||||||
|
@ -580,45 +632,49 @@ void LinkResolver::check_field_accessability(KlassHandle ref_klass,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle pool, int index, Bytecodes::Code byte, bool check_only, TRAPS) {
|
void LinkResolver::resolve_field_access(fieldDescriptor& result, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS) {
|
||||||
resolve_field(result, pool, index, byte, check_only, true, CHECK);
|
// Load these early in case the resolve of the containing klass fails
|
||||||
|
Symbol* field = pool->name_ref_at(index);
|
||||||
|
Symbol* sig = pool->signature_ref_at(index);
|
||||||
|
|
||||||
|
// resolve specified klass
|
||||||
|
KlassHandle resolved_klass;
|
||||||
|
resolve_klass(resolved_klass, pool, index, CHECK);
|
||||||
|
|
||||||
|
KlassHandle current_klass(THREAD, pool->pool_holder());
|
||||||
|
resolve_field(result, resolved_klass, field, sig, current_klass, byte, true, true, CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle pool, int index, Bytecodes::Code byte, bool check_only, bool update_pool, TRAPS) {
|
void LinkResolver::resolve_field(fieldDescriptor& fd, KlassHandle resolved_klass, Symbol* field, Symbol* sig,
|
||||||
|
KlassHandle current_klass, Bytecodes::Code byte, bool check_access, bool initialize_class,
|
||||||
|
TRAPS) {
|
||||||
assert(byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic ||
|
assert(byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic ||
|
||||||
byte == Bytecodes::_getfield || byte == Bytecodes::_putfield, "bad bytecode");
|
byte == Bytecodes::_getfield || byte == Bytecodes::_putfield ||
|
||||||
|
(byte == Bytecodes::_nop && !check_access), "bad field access bytecode");
|
||||||
|
|
||||||
bool is_static = (byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic);
|
bool is_static = (byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic);
|
||||||
bool is_put = (byte == Bytecodes::_putfield || byte == Bytecodes::_putstatic);
|
bool is_put = (byte == Bytecodes::_putfield || byte == Bytecodes::_putstatic);
|
||||||
|
|
||||||
// resolve specified klass
|
|
||||||
KlassHandle resolved_klass;
|
|
||||||
if (update_pool) {
|
|
||||||
resolve_klass(resolved_klass, pool, index, CHECK);
|
|
||||||
} else {
|
|
||||||
resolve_klass_no_update(resolved_klass, pool, index, CHECK);
|
|
||||||
}
|
|
||||||
// Load these early in case the resolve of the containing klass fails
|
|
||||||
Symbol* field = pool->name_ref_at(index);
|
|
||||||
Symbol* sig = pool->signature_ref_at(index);
|
|
||||||
// Check if there's a resolved klass containing the field
|
// Check if there's a resolved klass containing the field
|
||||||
if( resolved_klass.is_null() ) {
|
if (resolved_klass.is_null()) {
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), field->as_C_string());
|
THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), field->as_C_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve instance field
|
// Resolve instance field
|
||||||
fieldDescriptor fd; // find_field initializes fd if found
|
|
||||||
KlassHandle sel_klass(THREAD, InstanceKlass::cast(resolved_klass())->find_field(field, sig, &fd));
|
KlassHandle sel_klass(THREAD, InstanceKlass::cast(resolved_klass())->find_field(field, sig, &fd));
|
||||||
// check if field exists; i.e., if a klass containing the field def has been selected
|
// check if field exists; i.e., if a klass containing the field def has been selected
|
||||||
if (sel_klass.is_null()){
|
if (sel_klass.is_null()) {
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), field->as_C_string());
|
THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), field->as_C_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!check_access)
|
||||||
|
// Access checking may be turned off when calling from within the VM.
|
||||||
|
return;
|
||||||
|
|
||||||
// check access
|
// check access
|
||||||
KlassHandle ref_klass(THREAD, pool->pool_holder());
|
check_field_accessability(current_klass, resolved_klass, sel_klass, fd, CHECK);
|
||||||
check_field_accessability(ref_klass, resolved_klass, sel_klass, fd, CHECK);
|
|
||||||
|
|
||||||
// check for errors
|
// check for errors
|
||||||
if (is_static != fd.is_static()) {
|
if (is_static != fd.is_static()) {
|
||||||
|
@ -629,7 +685,7 @@ void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle poo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final fields can only be accessed from its own class.
|
// Final fields can only be accessed from its own class.
|
||||||
if (is_put && fd.access_flags().is_final() && sel_klass() != pool->pool_holder()) {
|
if (is_put && fd.access_flags().is_final() && sel_klass() != current_klass()) {
|
||||||
THROW(vmSymbols::java_lang_IllegalAccessError());
|
THROW(vmSymbols::java_lang_IllegalAccessError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,19 +695,18 @@ void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle poo
|
||||||
//
|
//
|
||||||
// note 2: we don't want to force initialization if we are just checking
|
// note 2: we don't want to force initialization if we are just checking
|
||||||
// if the field access is legal; e.g., during compilation
|
// if the field access is legal; e.g., during compilation
|
||||||
if (is_static && !check_only) {
|
if (is_static && initialize_class) {
|
||||||
sel_klass->initialize(CHECK);
|
sel_klass->initialize(CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if (sel_klass() != current_klass()) {
|
||||||
HandleMark hm(THREAD);
|
HandleMark hm(THREAD);
|
||||||
Handle ref_loader (THREAD, InstanceKlass::cast(ref_klass())->class_loader());
|
Handle ref_loader (THREAD, InstanceKlass::cast(current_klass())->class_loader());
|
||||||
Handle sel_loader (THREAD, InstanceKlass::cast(sel_klass())->class_loader());
|
Handle sel_loader (THREAD, InstanceKlass::cast(sel_klass())->class_loader());
|
||||||
Symbol* signature_ref = pool->signature_ref_at(index);
|
|
||||||
{
|
{
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
Symbol* failed_type_symbol =
|
Symbol* failed_type_symbol =
|
||||||
SystemDictionary::check_signature_loaders(signature_ref,
|
SystemDictionary::check_signature_loaders(sig,
|
||||||
ref_loader, sel_loader,
|
ref_loader, sel_loader,
|
||||||
false,
|
false,
|
||||||
CHECK);
|
CHECK);
|
||||||
|
@ -677,9 +732,6 @@ void LinkResolver::resolve_field(FieldAccessInfo& result, constantPoolHandle poo
|
||||||
|
|
||||||
// return information. note that the klass is set to the actual klass containing the
|
// return information. note that the klass is set to the actual klass containing the
|
||||||
// field, otherwise access of static fields in superclasses will not work.
|
// field, otherwise access of static fields in superclasses will not work.
|
||||||
KlassHandle holder (THREAD, fd.field_holder());
|
|
||||||
Symbol* name = fd.name();
|
|
||||||
result.set(holder, name, fd.index(), fd.offset(), fd.field_type(), fd.access_flags());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -906,10 +958,6 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
|
||||||
THROW(vmSymbols::java_lang_NullPointerException());
|
THROW(vmSymbols::java_lang_NullPointerException());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Virtual methods cannot be resolved before its klass has been linked, for otherwise the Method*'s
|
|
||||||
// has not been rewritten, and the vtable initialized.
|
|
||||||
assert(resolved_method->method_holder()->is_linked(), "must be linked");
|
|
||||||
|
|
||||||
// Virtual methods cannot be resolved before its klass has been linked, for otherwise the Method*'s
|
// Virtual methods cannot be resolved before its klass has been linked, for otherwise the Method*'s
|
||||||
// has not been rewritten, and the vtable initialized. Make sure to do this after the nullcheck, since
|
// has not been rewritten, and the vtable initialized. Make sure to do this after the nullcheck, since
|
||||||
// a missing receiver might result in a bogus lookup.
|
// a missing receiver might result in a bogus lookup.
|
||||||
|
@ -920,6 +968,7 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
|
||||||
vtable_index = vtable_index_of_miranda_method(resolved_klass,
|
vtable_index = vtable_index_of_miranda_method(resolved_klass,
|
||||||
resolved_method->name(),
|
resolved_method->name(),
|
||||||
resolved_method->signature(), CHECK);
|
resolved_method->signature(), CHECK);
|
||||||
|
|
||||||
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());
|
InstanceKlass* inst = InstanceKlass::cast(recv_klass());
|
||||||
|
@ -927,6 +976,7 @@ void LinkResolver::runtime_resolve_virtual_method(CallInfo& result,
|
||||||
} 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.
|
||||||
|
assert(!resolved_method->has_itable_index(), "");
|
||||||
vtable_index = resolved_method->vtable_index();
|
vtable_index = resolved_method->vtable_index();
|
||||||
// We could get a negative vtable_index for final methods,
|
// We could get a negative vtable_index for final methods,
|
||||||
// because as an optimization they are they are never put in the vtable,
|
// because as an optimization they are they are never put in the vtable,
|
||||||
|
@ -1006,6 +1056,12 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
|
||||||
lookup_instance_method_in_klasses(sel_method, recv_klass,
|
lookup_instance_method_in_klasses(sel_method, recv_klass,
|
||||||
resolved_method->name(),
|
resolved_method->name(),
|
||||||
resolved_method->signature(), CHECK);
|
resolved_method->signature(), CHECK);
|
||||||
|
if (sel_method.is_null() && !check_null_and_abstract) {
|
||||||
|
// In theory this is a harmless placeholder value, but
|
||||||
|
// in practice leaving in null affects the nsk default method tests.
|
||||||
|
// This needs further study.
|
||||||
|
sel_method = resolved_method;
|
||||||
|
}
|
||||||
// check if method exists
|
// check if method exists
|
||||||
if (sel_method.is_null()) {
|
if (sel_method.is_null()) {
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
|
@ -1046,7 +1102,14 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, methodHand
|
||||||
sel_method->signature()));
|
sel_method->signature()));
|
||||||
}
|
}
|
||||||
// setup result
|
// setup result
|
||||||
result.set_interface(resolved_klass, recv_klass, resolved_method, sel_method, CHECK);
|
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();
|
||||||
|
result.set_interface(resolved_klass, recv_klass, resolved_method, sel_method, itable_index, CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1293,7 +1356,8 @@ void LinkResolver::resolve_invokedynamic(CallInfo& result, constantPoolHandle po
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TraceMethodHandles) {
|
if (TraceMethodHandles) {
|
||||||
tty->print_cr("resolve_invokedynamic #%d %s %s",
|
ResourceMark rm(THREAD);
|
||||||
|
tty->print_cr("resolve_invokedynamic #%d %s %s",
|
||||||
ConstantPool::decode_invokedynamic_index(index),
|
ConstantPool::decode_invokedynamic_index(index),
|
||||||
method_name->as_C_string(), method_signature->as_C_string());
|
method_name->as_C_string(), method_signature->as_C_string());
|
||||||
tty->print(" BSM info: "); bootstrap_specifier->print();
|
tty->print(" BSM info: "); bootstrap_specifier->print();
|
||||||
|
@ -1342,9 +1406,16 @@ void LinkResolver::resolve_dynamic_call(CallInfo& result,
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
|
|
||||||
void FieldAccessInfo::print() {
|
void CallInfo::print() {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
tty->print_cr("Field %s@%d", name()->as_C_string(), field_offset());
|
const char* kindstr = "unknown";
|
||||||
|
switch (_call_kind) {
|
||||||
|
case direct_call: kindstr = "direct"; break;
|
||||||
|
case vtable_call: kindstr = "vtable"; break;
|
||||||
|
case itable_call: kindstr = "itable"; break;
|
||||||
|
}
|
||||||
|
tty->print_cr("Call %s@%d %s", kindstr, _call_index,
|
||||||
|
_resolved_method.is_null() ? "(none)" : _resolved_method->name_and_sig_as_C_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2013, 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
|
||||||
|
@ -30,63 +30,54 @@
|
||||||
|
|
||||||
// All the necessary definitions for run-time link resolution.
|
// All the necessary definitions for run-time link resolution.
|
||||||
|
|
||||||
// LinkInfo & its subclasses provide all the information gathered
|
// CallInfo provides all the information gathered for a particular
|
||||||
// for a particular link after resolving it. A link is any reference
|
// linked call site after resolving it. A link is any reference
|
||||||
// made from within the bytecodes of a method to an object outside of
|
// made from within the bytecodes of a method to an object outside of
|
||||||
// that method. If the info is invalid, the link has not been resolved
|
// that method. If the info is invalid, the link has not been resolved
|
||||||
// successfully.
|
// successfully.
|
||||||
|
|
||||||
class LinkInfo VALUE_OBJ_CLASS_SPEC {
|
class CallInfo VALUE_OBJ_CLASS_SPEC {
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Link information for getfield/putfield & getstatic/putstatic bytecodes.
|
|
||||||
|
|
||||||
class FieldAccessInfo: public LinkInfo {
|
|
||||||
protected:
|
|
||||||
KlassHandle _klass;
|
|
||||||
Symbol* _name;
|
|
||||||
AccessFlags _access_flags;
|
|
||||||
int _field_index; // original index in the klass
|
|
||||||
int _field_offset;
|
|
||||||
BasicType _field_type;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void set(KlassHandle klass, Symbol* name, int field_index, int field_offset,
|
// Ways that a method call might be selected (or not) based on receiver type.
|
||||||
BasicType field_type, AccessFlags access_flags);
|
// Note that an invokevirtual instruction might be linked with no_dispatch,
|
||||||
KlassHandle klass() const { return _klass; }
|
// and an invokeinterface instruction might be linked with any of the three options
|
||||||
Symbol* name() const { return _name; }
|
enum CallKind {
|
||||||
int field_index() const { return _field_index; }
|
direct_call, // jump into resolved_method (must be concrete)
|
||||||
int field_offset() const { return _field_offset; }
|
vtable_call, // select recv.klass.method_at_vtable(index)
|
||||||
BasicType field_type() const { return _field_type; }
|
itable_call, // select recv.klass.method_at_itable(resolved_method.holder, index)
|
||||||
AccessFlags access_flags() const { return _access_flags; }
|
unknown_kind = -1
|
||||||
|
};
|
||||||
// debugging
|
|
||||||
void print() PRODUCT_RETURN;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Link information for all calls.
|
|
||||||
|
|
||||||
class CallInfo: public LinkInfo {
|
|
||||||
private:
|
private:
|
||||||
KlassHandle _resolved_klass; // static receiver klass
|
KlassHandle _resolved_klass; // static receiver klass, resolved from a symbolic reference
|
||||||
KlassHandle _selected_klass; // dynamic receiver class (same as static, or subklass)
|
KlassHandle _selected_klass; // dynamic receiver class (same as static, or subklass)
|
||||||
methodHandle _resolved_method; // static target method
|
methodHandle _resolved_method; // static target method
|
||||||
methodHandle _selected_method; // dynamic (actual) target method
|
methodHandle _selected_method; // dynamic (actual) target method
|
||||||
int _vtable_index; // vtable index of selected method
|
CallKind _call_kind; // kind of call (static(=bytecode static/special +
|
||||||
|
// others inferred), vtable, itable)
|
||||||
|
int _call_index; // vtable or itable index of selected class method (if any)
|
||||||
Handle _resolved_appendix; // extra argument in constant pool (if CPCE::has_appendix)
|
Handle _resolved_appendix; // extra argument in constant pool (if CPCE::has_appendix)
|
||||||
Handle _resolved_method_type; // MethodType (for invokedynamic and invokehandle call sites)
|
Handle _resolved_method_type; // MethodType (for invokedynamic and invokehandle call sites)
|
||||||
|
|
||||||
void set_static( KlassHandle resolved_klass, methodHandle resolved_method , TRAPS);
|
void set_static( KlassHandle resolved_klass, methodHandle resolved_method , TRAPS);
|
||||||
void set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method , TRAPS);
|
void set_interface(KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int itable_index , TRAPS);
|
||||||
void set_virtual( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index , TRAPS);
|
void set_virtual( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index , TRAPS);
|
||||||
void set_handle( methodHandle resolved_method, Handle resolved_appendix, Handle resolved_method_type, TRAPS);
|
void set_handle( methodHandle resolved_method, Handle resolved_appendix, Handle resolved_method_type, TRAPS);
|
||||||
void set_common( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, int vtable_index , TRAPS);
|
void set_common( KlassHandle resolved_klass, KlassHandle selected_klass, methodHandle resolved_method, methodHandle selected_method, CallKind kind, int index, TRAPS);
|
||||||
|
|
||||||
friend class LinkResolver;
|
friend class LinkResolver;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
CallInfo() {
|
||||||
|
#ifndef PRODUCT
|
||||||
|
_call_kind = CallInfo::unknown_kind;
|
||||||
|
_call_index = Method::garbage_vtable_index;
|
||||||
|
#endif //PRODUCT
|
||||||
|
}
|
||||||
|
|
||||||
|
// utility to extract an effective CallInfo from a method and an optional receiver limit
|
||||||
|
// does not queue the method for compilation
|
||||||
|
CallInfo(Method* resolved_method, Klass* resolved_klass = NULL);
|
||||||
|
|
||||||
KlassHandle resolved_klass() const { return _resolved_klass; }
|
KlassHandle resolved_klass() const { return _resolved_klass; }
|
||||||
KlassHandle selected_klass() const { return _selected_klass; }
|
KlassHandle selected_klass() const { return _selected_klass; }
|
||||||
methodHandle resolved_method() const { return _resolved_method; }
|
methodHandle resolved_method() const { return _resolved_method; }
|
||||||
|
@ -95,21 +86,43 @@ class CallInfo: public LinkInfo {
|
||||||
Handle resolved_method_type() const { return _resolved_method_type; }
|
Handle resolved_method_type() const { return _resolved_method_type; }
|
||||||
|
|
||||||
BasicType result_type() const { return selected_method()->result_type(); }
|
BasicType result_type() const { return selected_method()->result_type(); }
|
||||||
bool has_vtable_index() const { return _vtable_index >= 0; }
|
CallKind call_kind() const { return _call_kind; }
|
||||||
bool is_statically_bound() const { return _vtable_index == Method::nonvirtual_vtable_index; }
|
int call_index() const { return _call_index; }
|
||||||
int vtable_index() const {
|
int vtable_index() const {
|
||||||
// Even for interface calls the vtable index could be non-negative.
|
// Even for interface calls the vtable index could be non-negative.
|
||||||
// See CallInfo::set_interface.
|
// See CallInfo::set_interface.
|
||||||
assert(has_vtable_index() || is_statically_bound(), "");
|
assert(has_vtable_index() || is_statically_bound(), "");
|
||||||
return _vtable_index;
|
assert(call_kind() == vtable_call || call_kind() == direct_call, "");
|
||||||
|
// The returned value is < 0 if the call is statically bound.
|
||||||
|
// But, the returned value may be >= 0 even if the kind is direct_call.
|
||||||
|
// It is up to the caller to decide which way to go.
|
||||||
|
return _call_index;
|
||||||
}
|
}
|
||||||
|
int itable_index() const {
|
||||||
|
assert(call_kind() == itable_call, "");
|
||||||
|
// The returned value is always >= 0, a valid itable index.
|
||||||
|
return _call_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// debugging
|
||||||
|
#ifdef ASSERT
|
||||||
|
bool has_vtable_index() const { return _call_index >= 0 && _call_kind != CallInfo::itable_call; }
|
||||||
|
bool is_statically_bound() const { return _call_index == Method::nonvirtual_vtable_index; }
|
||||||
|
#endif //ASSERT
|
||||||
|
void verify() PRODUCT_RETURN;
|
||||||
|
void print() PRODUCT_RETURN;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Link information for getfield/putfield & getstatic/putstatic bytecodes
|
||||||
|
// is represented using a fieldDescriptor.
|
||||||
|
|
||||||
// The LinkResolver is used to resolve constant-pool references at run-time.
|
// The LinkResolver is used to resolve constant-pool references at run-time.
|
||||||
// It does all necessary link-time checks & throws exceptions if necessary.
|
// It does all necessary link-time checks & throws exceptions if necessary.
|
||||||
|
|
||||||
class LinkResolver: AllStatic {
|
class LinkResolver: AllStatic {
|
||||||
|
friend class klassVtable;
|
||||||
|
friend class klassItable;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void lookup_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
|
static void lookup_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
|
||||||
static void lookup_instance_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
|
static void lookup_instance_method_in_klasses (methodHandle& result, KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
|
||||||
|
@ -120,7 +133,6 @@ class LinkResolver: AllStatic {
|
||||||
static int vtable_index_of_miranda_method(KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
|
static int vtable_index_of_miranda_method(KlassHandle klass, Symbol* name, Symbol* signature, TRAPS);
|
||||||
|
|
||||||
static void resolve_klass (KlassHandle& result, constantPoolHandle pool, int index, TRAPS);
|
static void resolve_klass (KlassHandle& result, constantPoolHandle pool, int index, TRAPS);
|
||||||
static void resolve_klass_no_update (KlassHandle& result, constantPoolHandle pool, int index, TRAPS); // no update of constantPool entry
|
|
||||||
|
|
||||||
static void resolve_pool (KlassHandle& resolved_klass, Symbol*& method_name, Symbol*& method_signature, KlassHandle& current_klass, 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);
|
||||||
|
|
||||||
|
@ -148,9 +160,16 @@ class LinkResolver: AllStatic {
|
||||||
Bytecodes::Code code, constantPoolHandle pool, int index, TRAPS);
|
Bytecodes::Code code, constantPoolHandle pool, int index, TRAPS);
|
||||||
|
|
||||||
// runtime/static resolving for fields
|
// runtime/static resolving for fields
|
||||||
static void resolve_field(FieldAccessInfo& result, constantPoolHandle pool, int index, Bytecodes::Code byte, bool check_only, TRAPS);
|
static void resolve_field_access(fieldDescriptor& result, constantPoolHandle pool, int index, Bytecodes::Code byte, TRAPS);
|
||||||
// takes an extra bool argument "update_pool" to decide whether to update the constantPool during klass resolution.
|
static void resolve_field(fieldDescriptor& result, KlassHandle resolved_klass, Symbol* field_name, Symbol* field_signature,
|
||||||
static void resolve_field(FieldAccessInfo& result, constantPoolHandle pool, int index, Bytecodes::Code byte, bool check_only, bool update_pool, TRAPS);
|
KlassHandle current_klass, Bytecodes::Code access_kind, bool check_access, bool initialize_class, TRAPS);
|
||||||
|
|
||||||
|
// source of access_kind codes:
|
||||||
|
static Bytecodes::Code field_access_kind(bool is_static, bool is_put) {
|
||||||
|
return (is_static
|
||||||
|
? (is_put ? Bytecodes::_putstatic : Bytecodes::_getstatic)
|
||||||
|
: (is_put ? Bytecodes::_putfield : Bytecodes::_getfield ));
|
||||||
|
}
|
||||||
|
|
||||||
// runtime resolving:
|
// runtime resolving:
|
||||||
// resolved_klass = specified class (i.e., static receiver class)
|
// resolved_klass = specified class (i.e., static receiver class)
|
||||||
|
|
|
@ -602,7 +602,7 @@ oop Universe::gen_out_of_memory_error(oop default_err) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static intptr_t non_oop_bits = 0;
|
intptr_t Universe::_non_oop_bits = 0;
|
||||||
|
|
||||||
void* Universe::non_oop_word() {
|
void* Universe::non_oop_word() {
|
||||||
// Neither the high bits nor the low bits of this value is allowed
|
// Neither the high bits nor the low bits of this value is allowed
|
||||||
|
@ -616,11 +616,11 @@ void* Universe::non_oop_word() {
|
||||||
// Using the OS-supplied non-memory-address word (usually 0 or -1)
|
// Using the OS-supplied non-memory-address word (usually 0 or -1)
|
||||||
// will take care of the high bits, however many there are.
|
// will take care of the high bits, however many there are.
|
||||||
|
|
||||||
if (non_oop_bits == 0) {
|
if (_non_oop_bits == 0) {
|
||||||
non_oop_bits = (intptr_t)os::non_memory_address_word() | 1;
|
_non_oop_bits = (intptr_t)os::non_memory_address_word() | 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (void*)non_oop_bits;
|
return (void*)_non_oop_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
jint universe_init() {
|
jint universe_init() {
|
||||||
|
|
|
@ -179,6 +179,8 @@ class Universe: AllStatic {
|
||||||
// The particular choice of collected heap.
|
// The particular choice of collected heap.
|
||||||
static CollectedHeap* _collectedHeap;
|
static CollectedHeap* _collectedHeap;
|
||||||
|
|
||||||
|
static intptr_t _non_oop_bits;
|
||||||
|
|
||||||
// For UseCompressedOops.
|
// For UseCompressedOops.
|
||||||
static struct NarrowPtrStruct _narrow_oop;
|
static struct NarrowPtrStruct _narrow_oop;
|
||||||
// For UseCompressedClassPointers.
|
// For UseCompressedClassPointers.
|
||||||
|
|
|
@ -396,32 +396,6 @@ Klass* ConstantPool::klass_ref_at_if_loaded(constantPoolHandle this_oop, int whi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This is an interface for the compiler that allows accessing non-resolved entries
|
|
||||||
// in the constant pool - but still performs the validations tests. Must be used
|
|
||||||
// in a pre-parse of the compiler - to determine what it can do and not do.
|
|
||||||
// Note: We cannot update the ConstantPool from the vm_thread.
|
|
||||||
Klass* ConstantPool::klass_ref_at_if_loaded_check(constantPoolHandle this_oop, int index, TRAPS) {
|
|
||||||
int which = this_oop->klass_ref_index_at(index);
|
|
||||||
CPSlot entry = this_oop->slot_at(which);
|
|
||||||
if (entry.is_resolved()) {
|
|
||||||
assert(entry.get_klass()->is_klass(), "must be");
|
|
||||||
return entry.get_klass();
|
|
||||||
} else {
|
|
||||||
assert(entry.is_unresolved(), "must be either symbol or klass");
|
|
||||||
Symbol* name = entry.get_symbol();
|
|
||||||
oop loader = this_oop->pool_holder()->class_loader();
|
|
||||||
oop protection_domain = this_oop->pool_holder()->protection_domain();
|
|
||||||
Handle h_loader(THREAD, loader);
|
|
||||||
Handle h_prot (THREAD, protection_domain);
|
|
||||||
KlassHandle k(THREAD, SystemDictionary::find(name, h_loader, h_prot, THREAD));
|
|
||||||
|
|
||||||
// Do access check for klasses
|
|
||||||
if( k.not_null() ) verify_constant_pool_resolve(this_oop, k, CHECK_NULL);
|
|
||||||
return k();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Method* ConstantPool::method_at_if_loaded(constantPoolHandle cpool,
|
Method* ConstantPool::method_at_if_loaded(constantPoolHandle cpool,
|
||||||
int which) {
|
int which) {
|
||||||
if (cpool->cache() == NULL) return NULL; // nothing to load yet
|
if (cpool->cache() == NULL) return NULL; // nothing to load yet
|
||||||
|
|
|
@ -730,8 +730,6 @@ class ConstantPool : public Metadata {
|
||||||
static oop method_type_at_if_loaded (constantPoolHandle this_oop, int which);
|
static oop method_type_at_if_loaded (constantPoolHandle this_oop, int which);
|
||||||
static Klass* klass_at_if_loaded (constantPoolHandle this_oop, int which);
|
static Klass* klass_at_if_loaded (constantPoolHandle this_oop, int which);
|
||||||
static Klass* klass_ref_at_if_loaded (constantPoolHandle this_oop, int which);
|
static Klass* klass_ref_at_if_loaded (constantPoolHandle this_oop, int which);
|
||||||
// Same as above - but does LinkResolving.
|
|
||||||
static Klass* klass_ref_at_if_loaded_check(constantPoolHandle this_oop, int which, TRAPS);
|
|
||||||
|
|
||||||
// Routines currently used for annotations (only called by jvm.cpp) but which might be used in the
|
// Routines currently used for annotations (only called by jvm.cpp) but which might be used in the
|
||||||
// future by other Java code. These take constant pool indices rather than
|
// future by other Java code. These take constant pool indices rather than
|
||||||
|
|
|
@ -140,9 +140,10 @@ void ConstantPoolCacheEntry::set_parameter_size(int value) {
|
||||||
err_msg("size must not change: parameter_size=%d, value=%d", parameter_size(), value));
|
err_msg("size must not change: parameter_size=%d, value=%d", parameter_size(), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
|
void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_code,
|
||||||
methodHandle method,
|
methodHandle method,
|
||||||
int vtable_index) {
|
int vtable_index) {
|
||||||
|
bool is_vtable_call = (vtable_index >= 0); // FIXME: split this method on this boolean
|
||||||
assert(method->interpreter_entry() != NULL, "should have been set at this point");
|
assert(method->interpreter_entry() != NULL, "should have been set at this point");
|
||||||
assert(!method->is_obsolete(), "attempt to write obsolete method to cpCache");
|
assert(!method->is_obsolete(), "attempt to write obsolete method to cpCache");
|
||||||
|
|
||||||
|
@ -160,7 +161,8 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
|
||||||
// ...and fall through as if we were handling invokevirtual:
|
// ...and fall through as if we were handling invokevirtual:
|
||||||
case Bytecodes::_invokevirtual:
|
case Bytecodes::_invokevirtual:
|
||||||
{
|
{
|
||||||
if (method->can_be_statically_bound()) {
|
if (!is_vtable_call) {
|
||||||
|
assert(method->can_be_statically_bound(), "");
|
||||||
// set_f2_as_vfinal_method checks if is_vfinal flag is true.
|
// set_f2_as_vfinal_method checks if is_vfinal flag is true.
|
||||||
set_method_flags(as_TosState(method->result_type()),
|
set_method_flags(as_TosState(method->result_type()),
|
||||||
( 1 << is_vfinal_shift) |
|
( 1 << is_vfinal_shift) |
|
||||||
|
@ -169,6 +171,7 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
|
||||||
method()->size_of_parameters());
|
method()->size_of_parameters());
|
||||||
set_f2_as_vfinal_method(method());
|
set_f2_as_vfinal_method(method());
|
||||||
} else {
|
} else {
|
||||||
|
assert(!method->can_be_statically_bound(), "");
|
||||||
assert(vtable_index >= 0, "valid index");
|
assert(vtable_index >= 0, "valid index");
|
||||||
assert(!method->is_final_method(), "sanity");
|
assert(!method->is_final_method(), "sanity");
|
||||||
set_method_flags(as_TosState(method->result_type()),
|
set_method_flags(as_TosState(method->result_type()),
|
||||||
|
@ -182,6 +185,7 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
|
||||||
|
|
||||||
case Bytecodes::_invokespecial:
|
case Bytecodes::_invokespecial:
|
||||||
case Bytecodes::_invokestatic:
|
case Bytecodes::_invokestatic:
|
||||||
|
assert(!is_vtable_call, "");
|
||||||
// Note: Read and preserve the value of the is_vfinal flag on any
|
// Note: Read and preserve the value of the is_vfinal flag on any
|
||||||
// invokevirtual bytecode shared with this constant pool cache entry.
|
// invokevirtual bytecode shared with this constant pool cache entry.
|
||||||
// It is cheap and safe to consult is_vfinal() at all times.
|
// It is cheap and safe to consult is_vfinal() at all times.
|
||||||
|
@ -232,8 +236,22 @@ void ConstantPoolCacheEntry::set_method(Bytecodes::Code invoke_code,
|
||||||
NOT_PRODUCT(verify(tty));
|
NOT_PRODUCT(verify(tty));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConstantPoolCacheEntry::set_direct_call(Bytecodes::Code invoke_code, methodHandle method) {
|
||||||
|
int index = Method::nonvirtual_vtable_index;
|
||||||
|
// index < 0; FIXME: inline and customize set_direct_or_vtable_call
|
||||||
|
set_direct_or_vtable_call(invoke_code, method, index);
|
||||||
|
}
|
||||||
|
|
||||||
void ConstantPoolCacheEntry::set_interface_call(methodHandle method, int index) {
|
void ConstantPoolCacheEntry::set_vtable_call(Bytecodes::Code invoke_code, methodHandle method, int index) {
|
||||||
|
// either the method is a miranda or its holder should accept the given index
|
||||||
|
assert(method->method_holder()->is_interface() || method->method_holder()->verify_vtable_index(index), "");
|
||||||
|
// index >= 0; FIXME: inline and customize set_direct_or_vtable_call
|
||||||
|
set_direct_or_vtable_call(invoke_code, method, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConstantPoolCacheEntry::set_itable_call(Bytecodes::Code invoke_code, methodHandle method, int index) {
|
||||||
|
assert(method->method_holder()->verify_itable_index(index), "");
|
||||||
|
assert(invoke_code == Bytecodes::_invokeinterface, "");
|
||||||
InstanceKlass* interf = method->method_holder();
|
InstanceKlass* interf = method->method_holder();
|
||||||
assert(interf->is_interface(), "must be an interface");
|
assert(interf->is_interface(), "must be an interface");
|
||||||
assert(!method->is_final_method(), "interfaces do not have final methods; cannot link to one here");
|
assert(!method->is_final_method(), "interfaces do not have final methods; cannot link to one here");
|
||||||
|
|
|
@ -219,15 +219,29 @@ class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
|
||||||
Klass* root_klass // needed by the GC to dirty the klass
|
Klass* root_klass // needed by the GC to dirty the klass
|
||||||
);
|
);
|
||||||
|
|
||||||
void set_method( // sets entry to resolved method entry
|
private:
|
||||||
|
void set_direct_or_vtable_call(
|
||||||
Bytecodes::Code invoke_code, // the bytecode used for invoking the method
|
Bytecodes::Code invoke_code, // the bytecode used for invoking the method
|
||||||
methodHandle method, // the method/prototype if any (NULL, otherwise)
|
methodHandle method, // the method/prototype if any (NULL, otherwise)
|
||||||
int vtable_index // the vtable index if any, else negative
|
int vtable_index // the vtable index if any, else negative
|
||||||
);
|
);
|
||||||
|
|
||||||
void set_interface_call(
|
public:
|
||||||
methodHandle method, // Resolved method
|
void set_direct_call( // sets entry to exact concrete method entry
|
||||||
int index // Method index into interface
|
Bytecodes::Code invoke_code, // the bytecode used for invoking the method
|
||||||
|
methodHandle method // the method to call
|
||||||
|
);
|
||||||
|
|
||||||
|
void set_vtable_call( // sets entry to vtable index
|
||||||
|
Bytecodes::Code invoke_code, // the bytecode used for invoking the method
|
||||||
|
methodHandle method, // resolved method which declares the vtable index
|
||||||
|
int vtable_index // the vtable index
|
||||||
|
);
|
||||||
|
|
||||||
|
void set_itable_call(
|
||||||
|
Bytecodes::Code invoke_code, // the bytecode used; must be invokeinterface
|
||||||
|
methodHandle method, // the resolved interface method
|
||||||
|
int itable_index // index into itable for the method
|
||||||
);
|
);
|
||||||
|
|
||||||
void set_method_handle(
|
void set_method_handle(
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2011, 2013, 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
|
||||||
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include "oops/instanceKlass.hpp"
|
#include "oops/instanceKlass.hpp"
|
||||||
#include "oops/fieldInfo.hpp"
|
#include "oops/fieldInfo.hpp"
|
||||||
|
#include "runtime/fieldDescriptor.hpp"
|
||||||
|
|
||||||
// The is the base class for iteration over the fields array
|
// The is the base class for iteration over the fields array
|
||||||
// describing the declared fields in the class. Several subclasses
|
// describing the declared fields in the class. Several subclasses
|
||||||
|
@ -43,8 +44,10 @@ class FieldStreamBase : public StackObj {
|
||||||
int _index;
|
int _index;
|
||||||
int _limit;
|
int _limit;
|
||||||
int _generic_signature_slot;
|
int _generic_signature_slot;
|
||||||
|
fieldDescriptor _fd_buf;
|
||||||
|
|
||||||
FieldInfo* field() const { return FieldInfo::from_field_array(_fields, _index); }
|
FieldInfo* field() const { return FieldInfo::from_field_array(_fields, _index); }
|
||||||
|
InstanceKlass* field_holder() const { return _constants->pool_holder(); }
|
||||||
|
|
||||||
int init_generic_signature_start_slot() {
|
int init_generic_signature_start_slot() {
|
||||||
int length = _fields->length();
|
int length = _fields->length();
|
||||||
|
@ -102,6 +105,7 @@ class FieldStreamBase : public StackObj {
|
||||||
_index = 0;
|
_index = 0;
|
||||||
_limit = klass->java_fields_count();
|
_limit = klass->java_fields_count();
|
||||||
init_generic_signature_start_slot();
|
init_generic_signature_start_slot();
|
||||||
|
assert(klass == field_holder(), "");
|
||||||
}
|
}
|
||||||
FieldStreamBase(instanceKlassHandle klass) {
|
FieldStreamBase(instanceKlassHandle klass) {
|
||||||
_fields = klass->fields();
|
_fields = klass->fields();
|
||||||
|
@ -109,6 +113,7 @@ class FieldStreamBase : public StackObj {
|
||||||
_index = 0;
|
_index = 0;
|
||||||
_limit = klass->java_fields_count();
|
_limit = klass->java_fields_count();
|
||||||
init_generic_signature_start_slot();
|
init_generic_signature_start_slot();
|
||||||
|
assert(klass == field_holder(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessors
|
// accessors
|
||||||
|
@ -180,6 +185,12 @@ class FieldStreamBase : public StackObj {
|
||||||
return field()->contended_group();
|
return field()->contended_group();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bridge to a heavier API:
|
||||||
|
fieldDescriptor& field_descriptor() const {
|
||||||
|
fieldDescriptor& field = const_cast<fieldDescriptor&>(_fd_buf);
|
||||||
|
field.reinitialize(field_holder(), _index);
|
||||||
|
return field;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Iterate over only the internal fields
|
// Iterate over only the internal fields
|
||||||
|
|
|
@ -286,7 +286,6 @@ InstanceKlass::InstanceKlass(int vtable_len,
|
||||||
init_previous_versions();
|
init_previous_versions();
|
||||||
set_generic_signature_index(0);
|
set_generic_signature_index(0);
|
||||||
release_set_methods_jmethod_ids(NULL);
|
release_set_methods_jmethod_ids(NULL);
|
||||||
release_set_methods_cached_itable_indices(NULL);
|
|
||||||
set_annotations(NULL);
|
set_annotations(NULL);
|
||||||
set_jvmti_cached_class_field_map(NULL);
|
set_jvmti_cached_class_field_map(NULL);
|
||||||
set_initial_method_idnum(0);
|
set_initial_method_idnum(0);
|
||||||
|
@ -1149,7 +1148,7 @@ bool InstanceKlass::find_local_field(Symbol* name, Symbol* sig, fieldDescriptor*
|
||||||
Symbol* f_name = fs.name();
|
Symbol* f_name = fs.name();
|
||||||
Symbol* f_sig = fs.signature();
|
Symbol* f_sig = fs.signature();
|
||||||
if (f_name == name && f_sig == sig) {
|
if (f_name == name && f_sig == sig) {
|
||||||
fd->initialize(const_cast<InstanceKlass*>(this), fs.index());
|
fd->reinitialize(const_cast<InstanceKlass*>(this), fs.index());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1218,7 +1217,7 @@ Klass* InstanceKlass::find_field(Symbol* name, Symbol* sig, bool is_static, fiel
|
||||||
bool InstanceKlass::find_local_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const {
|
bool InstanceKlass::find_local_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const {
|
||||||
for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
|
for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
|
||||||
if (fs.offset() == offset) {
|
if (fs.offset() == offset) {
|
||||||
fd->initialize(const_cast<InstanceKlass*>(this), fs.index());
|
fd->reinitialize(const_cast<InstanceKlass*>(this), fs.index());
|
||||||
if (fd->is_static() == is_static) return true;
|
if (fd->is_static() == is_static) return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1251,8 +1250,7 @@ void InstanceKlass::methods_do(void f(Method* method)) {
|
||||||
void InstanceKlass::do_local_static_fields(FieldClosure* cl) {
|
void InstanceKlass::do_local_static_fields(FieldClosure* cl) {
|
||||||
for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
|
for (JavaFieldStream fs(this); !fs.done(); fs.next()) {
|
||||||
if (fs.access_flags().is_static()) {
|
if (fs.access_flags().is_static()) {
|
||||||
fieldDescriptor fd;
|
fieldDescriptor& fd = fs.field_descriptor();
|
||||||
fd.initialize(this, fs.index());
|
|
||||||
cl->do_field(&fd);
|
cl->do_field(&fd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1268,8 +1266,7 @@ void InstanceKlass::do_local_static_fields(void f(fieldDescriptor*, TRAPS), TRAP
|
||||||
void InstanceKlass::do_local_static_fields_impl(instanceKlassHandle this_oop, void f(fieldDescriptor* fd, TRAPS), TRAPS) {
|
void InstanceKlass::do_local_static_fields_impl(instanceKlassHandle this_oop, void f(fieldDescriptor* fd, TRAPS), TRAPS) {
|
||||||
for (JavaFieldStream fs(this_oop()); !fs.done(); fs.next()) {
|
for (JavaFieldStream fs(this_oop()); !fs.done(); fs.next()) {
|
||||||
if (fs.access_flags().is_static()) {
|
if (fs.access_flags().is_static()) {
|
||||||
fieldDescriptor fd;
|
fieldDescriptor& fd = fs.field_descriptor();
|
||||||
fd.initialize(this_oop(), fs.index());
|
|
||||||
f(&fd, CHECK);
|
f(&fd, CHECK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1291,7 +1288,7 @@ void InstanceKlass::do_nonstatic_fields(FieldClosure* cl) {
|
||||||
int* fields_sorted = NEW_C_HEAP_ARRAY(int, 2*(length+1), mtClass);
|
int* fields_sorted = NEW_C_HEAP_ARRAY(int, 2*(length+1), mtClass);
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (int i = 0; i < length; i += 1) {
|
for (int i = 0; i < length; i += 1) {
|
||||||
fd.initialize(this, i);
|
fd.reinitialize(this, i);
|
||||||
if (!fd.is_static()) {
|
if (!fd.is_static()) {
|
||||||
fields_sorted[j + 0] = fd.offset();
|
fields_sorted[j + 0] = fd.offset();
|
||||||
fields_sorted[j + 1] = i;
|
fields_sorted[j + 1] = i;
|
||||||
|
@ -1303,7 +1300,7 @@ void InstanceKlass::do_nonstatic_fields(FieldClosure* cl) {
|
||||||
// _sort_Fn is defined in growableArray.hpp.
|
// _sort_Fn is defined in growableArray.hpp.
|
||||||
qsort(fields_sorted, length/2, 2*sizeof(int), (_sort_Fn)compare_fields_by_offset);
|
qsort(fields_sorted, length/2, 2*sizeof(int), (_sort_Fn)compare_fields_by_offset);
|
||||||
for (int i = 0; i < length; i += 2) {
|
for (int i = 0; i < length; i += 2) {
|
||||||
fd.initialize(this, fields_sorted[i + 1]);
|
fd.reinitialize(this, fields_sorted[i + 1]);
|
||||||
assert(!fd.is_static() && fd.offset() == fields_sorted[i], "only nonstatic fields");
|
assert(!fd.is_static() && fd.offset() == fields_sorted[i], "only nonstatic fields");
|
||||||
cl->do_field(&fd);
|
cl->do_field(&fd);
|
||||||
}
|
}
|
||||||
|
@ -1686,87 +1683,6 @@ jmethodID InstanceKlass::jmethod_id_or_null(Method* method) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Cache an itable index
|
|
||||||
void InstanceKlass::set_cached_itable_index(size_t idnum, int index) {
|
|
||||||
int* indices = methods_cached_itable_indices_acquire();
|
|
||||||
int* to_dealloc_indices = NULL;
|
|
||||||
|
|
||||||
// We use a double-check locking idiom here because this cache is
|
|
||||||
// performance sensitive. In the normal system, this cache only
|
|
||||||
// transitions from NULL to non-NULL which is safe because we use
|
|
||||||
// release_set_methods_cached_itable_indices() to advertise the
|
|
||||||
// new cache. A partially constructed cache should never be seen
|
|
||||||
// by a racing thread. Cache reads and writes proceed without a
|
|
||||||
// lock, but creation of the cache itself requires no leaks so a
|
|
||||||
// lock is generally acquired in that case.
|
|
||||||
//
|
|
||||||
// If the RedefineClasses() API has been used, then this cache can
|
|
||||||
// grow and we'll have transitions from non-NULL to bigger non-NULL.
|
|
||||||
// Cache creation requires no leaks and we require safety between all
|
|
||||||
// cache accesses and freeing of the old cache so a lock is generally
|
|
||||||
// acquired when the RedefineClasses() API has been used.
|
|
||||||
|
|
||||||
if (indices == NULL || idnum_can_increment()) {
|
|
||||||
// we need a cache or the cache can grow
|
|
||||||
MutexLocker ml(JNICachedItableIndex_lock);
|
|
||||||
// reacquire the cache to see if another thread already did the work
|
|
||||||
indices = methods_cached_itable_indices_acquire();
|
|
||||||
size_t length = 0;
|
|
||||||
// cache size is stored in element[0], other elements offset by one
|
|
||||||
if (indices == NULL || (length = (size_t)indices[0]) <= idnum) {
|
|
||||||
size_t size = MAX2(idnum+1, (size_t)idnum_allocated_count());
|
|
||||||
int* new_indices = NEW_C_HEAP_ARRAY(int, size+1, mtClass);
|
|
||||||
new_indices[0] = (int)size;
|
|
||||||
// copy any existing entries
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < length; i++) {
|
|
||||||
new_indices[i+1] = indices[i+1];
|
|
||||||
}
|
|
||||||
// Set all the rest to -1
|
|
||||||
for (i = length; i < size; i++) {
|
|
||||||
new_indices[i+1] = -1;
|
|
||||||
}
|
|
||||||
if (indices != NULL) {
|
|
||||||
// We have an old cache to delete so save it for after we
|
|
||||||
// drop the lock.
|
|
||||||
to_dealloc_indices = indices;
|
|
||||||
}
|
|
||||||
release_set_methods_cached_itable_indices(indices = new_indices);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (idnum_can_increment()) {
|
|
||||||
// this cache can grow so we have to write to it safely
|
|
||||||
indices[idnum+1] = index;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!idnum_can_increment()) {
|
|
||||||
// The cache cannot grow and this JNI itable index value does not
|
|
||||||
// have to be unique like a jmethodID. If there is a race to set it,
|
|
||||||
// it doesn't matter.
|
|
||||||
indices[idnum+1] = index;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (to_dealloc_indices != NULL) {
|
|
||||||
// we allocated a new cache so free the old one
|
|
||||||
FreeHeap(to_dealloc_indices);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Retrieve a cached itable index
|
|
||||||
int InstanceKlass::cached_itable_index(size_t idnum) {
|
|
||||||
int* indices = methods_cached_itable_indices_acquire();
|
|
||||||
if (indices != NULL && ((size_t)indices[0]) > idnum) {
|
|
||||||
// indices exist and are long enough, retrieve possible cached
|
|
||||||
return indices[idnum+1];
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Walk the list of dependent nmethods searching for nmethods which
|
// Walk the list of dependent nmethods searching for nmethods which
|
||||||
// are dependent on the changes that were passed in and mark them for
|
// are dependent on the changes that were passed in and mark them for
|
||||||
|
@ -2326,12 +2242,6 @@ void InstanceKlass::release_C_heap_structures() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int* indices = methods_cached_itable_indices_acquire();
|
|
||||||
if (indices != (int*)NULL) {
|
|
||||||
release_set_methods_cached_itable_indices(NULL);
|
|
||||||
FreeHeap(indices);
|
|
||||||
}
|
|
||||||
|
|
||||||
// release dependencies
|
// release dependencies
|
||||||
nmethodBucket* b = _dependencies;
|
nmethodBucket* b = _dependencies;
|
||||||
_dependencies = NULL;
|
_dependencies = NULL;
|
||||||
|
@ -2782,6 +2692,18 @@ static const char* state_names[] = {
|
||||||
"allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error"
|
"allocated", "loaded", "linked", "being_initialized", "fully_initialized", "initialization_error"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void print_vtable(intptr_t* start, int len, outputStream* st) {
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
intptr_t e = start[i];
|
||||||
|
st->print("%d : " INTPTR_FORMAT, i, e);
|
||||||
|
if (e != 0 && ((Metadata*)e)->is_metaspace_object()) {
|
||||||
|
st->print(" ");
|
||||||
|
((Metadata*)e)->print_value_on(st);
|
||||||
|
}
|
||||||
|
st->cr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
|
@ -2816,7 +2738,7 @@ void InstanceKlass::print_on(outputStream* st) const {
|
||||||
|
|
||||||
st->print(BULLET"arrays: "); array_klasses()->print_value_on_maybe_null(st); st->cr();
|
st->print(BULLET"arrays: "); array_klasses()->print_value_on_maybe_null(st); st->cr();
|
||||||
st->print(BULLET"methods: "); methods()->print_value_on(st); st->cr();
|
st->print(BULLET"methods: "); methods()->print_value_on(st); st->cr();
|
||||||
if (Verbose) {
|
if (Verbose || WizardMode) {
|
||||||
Array<Method*>* method_array = methods();
|
Array<Method*>* method_array = methods();
|
||||||
for(int i = 0; i < method_array->length(); i++) {
|
for(int i = 0; i < method_array->length(); i++) {
|
||||||
st->print("%d : ", i); method_array->at(i)->print_value(); st->cr();
|
st->print("%d : ", i); method_array->at(i)->print_value(); st->cr();
|
||||||
|
@ -2874,7 +2796,9 @@ void InstanceKlass::print_on(outputStream* st) const {
|
||||||
st->print(BULLET"inner classes: "); inner_classes()->print_value_on(st); st->cr();
|
st->print(BULLET"inner classes: "); inner_classes()->print_value_on(st); st->cr();
|
||||||
st->print(BULLET"java mirror: "); java_mirror()->print_value_on(st); st->cr();
|
st->print(BULLET"java mirror: "); java_mirror()->print_value_on(st); st->cr();
|
||||||
st->print(BULLET"vtable length %d (start addr: " INTPTR_FORMAT ")", vtable_length(), start_of_vtable()); st->cr();
|
st->print(BULLET"vtable length %d (start addr: " INTPTR_FORMAT ")", vtable_length(), start_of_vtable()); st->cr();
|
||||||
|
if (vtable_length() > 0 && (Verbose || WizardMode)) print_vtable(start_of_vtable(), vtable_length(), st);
|
||||||
st->print(BULLET"itable length %d (start addr: " INTPTR_FORMAT ")", itable_length(), start_of_itable()); st->cr();
|
st->print(BULLET"itable length %d (start addr: " INTPTR_FORMAT ")", itable_length(), start_of_itable()); st->cr();
|
||||||
|
if (itable_length() > 0 && (Verbose || WizardMode)) print_vtable(start_of_itable(), itable_length(), st);
|
||||||
st->print_cr(BULLET"---- static fields (%d words):", static_field_size());
|
st->print_cr(BULLET"---- static fields (%d words):", static_field_size());
|
||||||
FieldPrinter print_static_field(st);
|
FieldPrinter print_static_field(st);
|
||||||
((InstanceKlass*)this)->do_local_static_fields(&print_static_field);
|
((InstanceKlass*)this)->do_local_static_fields(&print_static_field);
|
||||||
|
@ -2896,6 +2820,7 @@ void InstanceKlass::print_on(outputStream* st) const {
|
||||||
|
|
||||||
void InstanceKlass::print_value_on(outputStream* st) const {
|
void InstanceKlass::print_value_on(outputStream* st) const {
|
||||||
assert(is_klass(), "must be klass");
|
assert(is_klass(), "must be klass");
|
||||||
|
if (Verbose || WizardMode) access_flags().print_on(st);
|
||||||
name()->print_value_on(st);
|
name()->print_value_on(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -245,7 +245,6 @@ class InstanceKlass: public Klass {
|
||||||
MemberNameTable* _member_names; // Member names
|
MemberNameTable* _member_names; // Member names
|
||||||
JNIid* _jni_ids; // First JNI identifier for static fields in this class
|
JNIid* _jni_ids; // First JNI identifier for static fields in this class
|
||||||
jmethodID* _methods_jmethod_ids; // jmethodIDs corresponding to method_idnum, or NULL if none
|
jmethodID* _methods_jmethod_ids; // jmethodIDs corresponding to method_idnum, or NULL if none
|
||||||
int* _methods_cached_itable_indices; // itable_index cache for JNI invoke corresponding to methods idnum, or NULL
|
|
||||||
nmethodBucket* _dependencies; // list of dependent nmethods
|
nmethodBucket* _dependencies; // list of dependent nmethods
|
||||||
nmethod* _osr_nmethods_head; // Head of list of on-stack replacement nmethods for this class
|
nmethod* _osr_nmethods_head; // Head of list of on-stack replacement nmethods for this class
|
||||||
BreakpointInfo* _breakpoints; // bpt lists, managed by Method*
|
BreakpointInfo* _breakpoints; // bpt lists, managed by Method*
|
||||||
|
@ -690,10 +689,6 @@ class InstanceKlass: public Klass {
|
||||||
size_t *length_p, jmethodID* id_p);
|
size_t *length_p, jmethodID* id_p);
|
||||||
jmethodID jmethod_id_or_null(Method* method);
|
jmethodID jmethod_id_or_null(Method* method);
|
||||||
|
|
||||||
// cached itable index support
|
|
||||||
void set_cached_itable_index(size_t idnum, int index);
|
|
||||||
int cached_itable_index(size_t idnum);
|
|
||||||
|
|
||||||
// annotations support
|
// annotations support
|
||||||
Annotations* annotations() const { return _annotations; }
|
Annotations* annotations() const { return _annotations; }
|
||||||
void set_annotations(Annotations* anno) { _annotations = anno; }
|
void set_annotations(Annotations* anno) { _annotations = anno; }
|
||||||
|
@ -994,11 +989,6 @@ private:
|
||||||
void release_set_methods_jmethod_ids(jmethodID* jmeths)
|
void release_set_methods_jmethod_ids(jmethodID* jmeths)
|
||||||
{ OrderAccess::release_store_ptr(&_methods_jmethod_ids, jmeths); }
|
{ OrderAccess::release_store_ptr(&_methods_jmethod_ids, jmeths); }
|
||||||
|
|
||||||
int* methods_cached_itable_indices_acquire() const
|
|
||||||
{ return (int*)OrderAccess::load_ptr_acquire(&_methods_cached_itable_indices); }
|
|
||||||
void release_set_methods_cached_itable_indices(int* indices)
|
|
||||||
{ OrderAccess::release_store_ptr(&_methods_cached_itable_indices, indices); }
|
|
||||||
|
|
||||||
// Lock during initialization
|
// Lock during initialization
|
||||||
public:
|
public:
|
||||||
// Lock for (1) initialization; (2) access to the ConstantPool of this class.
|
// Lock for (1) initialization; (2) access to the ConstantPool of this class.
|
||||||
|
|
|
@ -674,13 +674,23 @@ void Klass::oop_verify_on(oop obj, outputStream* st) {
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
|
|
||||||
void Klass::verify_vtable_index(int i) {
|
bool Klass::verify_vtable_index(int i) {
|
||||||
if (oop_is_instance()) {
|
if (oop_is_instance()) {
|
||||||
assert(i>=0 && i<((InstanceKlass*)this)->vtable_length()/vtableEntry::size(), "index out of bounds");
|
int limit = ((InstanceKlass*)this)->vtable_length()/vtableEntry::size();
|
||||||
|
assert(i >= 0 && i < limit, err_msg("index %d out of bounds %d", i, limit));
|
||||||
} else {
|
} else {
|
||||||
assert(oop_is_array(), "Must be");
|
assert(oop_is_array(), "Must be");
|
||||||
assert(i>=0 && i<((ArrayKlass*)this)->vtable_length()/vtableEntry::size(), "index out of bounds");
|
int limit = ((ArrayKlass*)this)->vtable_length()/vtableEntry::size();
|
||||||
|
assert(i >= 0 && i < limit, err_msg("index %d out of bounds %d", i, limit));
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Klass::verify_itable_index(int i) {
|
||||||
|
assert(oop_is_instance(), "");
|
||||||
|
int method_count = klassItable::method_count_for_interface(this);
|
||||||
|
assert(i >= 0 && i < method_count, "index out of bounds");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -699,7 +699,8 @@ class Klass : public Metadata {
|
||||||
void verify(bool check_dictionary = true) { verify_on(tty, check_dictionary); }
|
void verify(bool check_dictionary = true) { verify_on(tty, check_dictionary); }
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void verify_vtable_index(int index);
|
bool verify_vtable_index(int index);
|
||||||
|
bool verify_itable_index(int index);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
virtual void oop_verify_on(oop obj, outputStream* st);
|
virtual void oop_verify_on(oop obj, outputStream* st);
|
||||||
|
|
|
@ -47,11 +47,12 @@ inline InstanceKlass* klassVtable::ik() const {
|
||||||
|
|
||||||
|
|
||||||
// this function computes the vtable size (including the size needed for miranda
|
// this function computes the vtable size (including the size needed for miranda
|
||||||
// methods) and the number of miranda methods in this class
|
// methods) and the number of miranda methods in this class.
|
||||||
// Note on Miranda methods: Let's say there is a class C that implements
|
// Note on Miranda methods: Let's say there is a class C that implements
|
||||||
// interface I. Let's say there is a method m in I that neither C nor any
|
// interface I, and none of C's superclasses implements I.
|
||||||
// of its super classes implement (i.e there is no method of any access, with
|
// Let's say there is an abstract method m in I that neither C
|
||||||
// the same name and signature as m), then m is a Miranda method which is
|
// nor any of its super classes implement (i.e there is no method of any access,
|
||||||
|
// with the same name and signature as m), then m is a Miranda method which is
|
||||||
// entered as a public abstract method in C's vtable. From then on it should
|
// entered as a public abstract method in C's vtable. From then on it should
|
||||||
// treated as any other public method in C for method over-ride purposes.
|
// treated as any other public method in C for method over-ride purposes.
|
||||||
void klassVtable::compute_vtable_size_and_num_mirandas(
|
void klassVtable::compute_vtable_size_and_num_mirandas(
|
||||||
|
@ -111,10 +112,13 @@ void klassVtable::compute_vtable_size_and_num_mirandas(
|
||||||
}
|
}
|
||||||
|
|
||||||
int klassVtable::index_of(Method* m, int len) const {
|
int klassVtable::index_of(Method* m, int len) const {
|
||||||
assert(m->vtable_index() >= 0, "do not ask this of non-vtable methods");
|
assert(m->has_vtable_index(), "do not ask this of non-vtable methods");
|
||||||
return m->vtable_index();
|
return m->vtable_index();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy super class's vtable to the first part (prefix) of this class's vtable,
|
||||||
|
// and return the number of entries copied. Expects that 'super' is the Java
|
||||||
|
// super class (arrays can have "array" super classes that must be skipped).
|
||||||
int klassVtable::initialize_from_super(KlassHandle super) {
|
int klassVtable::initialize_from_super(KlassHandle super) {
|
||||||
if (super.is_null()) {
|
if (super.is_null()) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -139,14 +143,14 @@ int klassVtable::initialize_from_super(KlassHandle super) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Revised lookup semantics introduced 1.3 (Kestral beta)
|
//
|
||||||
|
// Revised lookup semantics introduced 1.3 (Kestrel beta)
|
||||||
void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
|
void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
|
||||||
|
|
||||||
// Note: Arrays can have intermediate array supers. Use java_super to skip them.
|
// Note: Arrays can have intermediate array supers. Use java_super to skip them.
|
||||||
KlassHandle super (THREAD, klass()->java_super());
|
KlassHandle super (THREAD, klass()->java_super());
|
||||||
int nofNewEntries = 0;
|
int nofNewEntries = 0;
|
||||||
|
|
||||||
|
|
||||||
if (PrintVtables && !klass()->oop_is_array()) {
|
if (PrintVtables && !klass()->oop_is_array()) {
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
tty->print_cr("Initializing: %s", _klass->name()->as_C_string());
|
tty->print_cr("Initializing: %s", _klass->name()->as_C_string());
|
||||||
|
@ -174,8 +178,10 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
|
||||||
int len = methods->length();
|
int len = methods->length();
|
||||||
int initialized = super_vtable_len;
|
int initialized = super_vtable_len;
|
||||||
|
|
||||||
// update_inherited_vtable can stop for gc - ensure using handles
|
// Check each of this class's methods against super;
|
||||||
|
// if override, replace in copy of super vtable, otherwise append to end
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
|
// update_inherited_vtable can stop for gc - ensure using handles
|
||||||
HandleMark hm(THREAD);
|
HandleMark hm(THREAD);
|
||||||
assert(methods->at(i)->is_method(), "must be a Method*");
|
assert(methods->at(i)->is_method(), "must be a Method*");
|
||||||
methodHandle mh(THREAD, methods->at(i));
|
methodHandle mh(THREAD, methods->at(i));
|
||||||
|
@ -189,11 +195,11 @@ void klassVtable::initialize_vtable(bool checkconstraints, TRAPS) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add miranda methods; it will also update the value of initialized
|
// add miranda methods to end of vtable.
|
||||||
fill_in_mirandas(&initialized);
|
initialized = fill_in_mirandas(initialized);
|
||||||
|
|
||||||
// In class hierarchies where the accessibility is not increasing (i.e., going from private ->
|
// In class hierarchies where the accessibility is not increasing (i.e., going from private ->
|
||||||
// package_private -> publicprotected), the vtable might actually be smaller than our initial
|
// package_private -> public/protected), the vtable might actually be smaller than our initial
|
||||||
// calculation.
|
// calculation.
|
||||||
assert(initialized <= _length, "vtable initialization failed");
|
assert(initialized <= _length, "vtable initialization failed");
|
||||||
for(;initialized < _length; initialized++) {
|
for(;initialized < _length; initialized++) {
|
||||||
|
@ -248,14 +254,8 @@ InstanceKlass* klassVtable::find_transitive_override(InstanceKlass* initialsuper
|
||||||
return superk;
|
return superk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Methods that are "effectively" final don't need vtable entries.
|
|
||||||
bool method_is_effectively_final(
|
|
||||||
AccessFlags klass_flags, methodHandle target) {
|
|
||||||
return target->is_final() || klass_flags.is_final() && !target->is_overpass();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update child's copy of super vtable for overrides
|
// Update child's copy of super vtable for overrides
|
||||||
// OR return true if a new vtable entry is required
|
// OR return true if a new vtable entry is required.
|
||||||
// Only called for InstanceKlass's, i.e. not for arrays
|
// Only called for InstanceKlass's, i.e. not for arrays
|
||||||
// If that changed, could not use _klass as handle for klass
|
// If that changed, could not use _klass as handle for klass
|
||||||
bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle target_method, int super_vtable_len,
|
bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle target_method, int super_vtable_len,
|
||||||
|
@ -263,6 +263,7 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
bool allocate_new = true;
|
bool allocate_new = true;
|
||||||
assert(klass->oop_is_instance(), "must be InstanceKlass");
|
assert(klass->oop_is_instance(), "must be InstanceKlass");
|
||||||
|
assert(klass == target_method()->method_holder(), "caller resp.");
|
||||||
|
|
||||||
// Initialize the method's vtable index to "nonvirtual".
|
// Initialize the method's vtable index to "nonvirtual".
|
||||||
// If we allocate a vtable entry, we will update it to a non-negative number.
|
// If we allocate a vtable entry, we will update it to a non-negative number.
|
||||||
|
@ -273,11 +274,17 @@ bool klassVtable::update_inherited_vtable(InstanceKlass* klass, methodHandle tar
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (method_is_effectively_final(klass->access_flags(), target_method)) {
|
if (target_method->is_final_method(klass->access_flags())) {
|
||||||
// a final method never needs a new entry; final methods can be statically
|
// a final method never needs a new entry; final methods can be statically
|
||||||
// resolved and they have to be present in the vtable only if they override
|
// resolved and they have to be present in the vtable only if they override
|
||||||
// a super's method, in which case they re-use its entry
|
// a super's method, in which case they re-use its entry
|
||||||
allocate_new = false;
|
allocate_new = false;
|
||||||
|
} else if (klass->is_interface()) {
|
||||||
|
allocate_new = false; // see note below in needs_new_vtable_entry
|
||||||
|
// An interface never allocates new vtable slots, only inherits old ones.
|
||||||
|
// This method will either be assigned its own itable index later,
|
||||||
|
// or be assigned an inherited vtable index in the loop below.
|
||||||
|
target_method()->set_vtable_index(Method::pending_itable_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// we need a new entry if there is no superclass
|
// we need a new entry if there is no superclass
|
||||||
|
@ -411,8 +418,14 @@ bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
|
||||||
Symbol* classname,
|
Symbol* classname,
|
||||||
AccessFlags class_flags,
|
AccessFlags class_flags,
|
||||||
TRAPS) {
|
TRAPS) {
|
||||||
|
if (class_flags.is_interface()) {
|
||||||
|
// Interfaces do not use vtables, so there is no point to assigning
|
||||||
|
// a vtable index to any of their methods. If we refrain from doing this,
|
||||||
|
// we can use Method::_vtable_index to hold the itable index
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (method_is_effectively_final(class_flags, target_method) ||
|
if (target_method->is_final_method(class_flags) ||
|
||||||
// a final method never needs a new entry; final methods can be statically
|
// a final method never needs a new entry; final methods can be statically
|
||||||
// resolved and they have to be present in the vtable only if they override
|
// resolved and they have to be present in the vtable only if they override
|
||||||
// a super's method, in which case they re-use its entry
|
// a super's method, in which case they re-use its entry
|
||||||
|
@ -500,7 +513,8 @@ int klassVtable::index_of_miranda(Symbol* name, Symbol* signature) {
|
||||||
return Method::invalid_vtable_index;
|
return Method::invalid_vtable_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if an entry is miranda
|
// check if an entry at an index is miranda
|
||||||
|
// requires that method m at entry be declared ("held") by an interface.
|
||||||
bool klassVtable::is_miranda_entry_at(int i) {
|
bool klassVtable::is_miranda_entry_at(int i) {
|
||||||
Method* m = method_at(i);
|
Method* m = method_at(i);
|
||||||
Klass* method_holder = m->method_holder();
|
Klass* method_holder = m->method_holder();
|
||||||
|
@ -516,7 +530,9 @@ bool klassVtable::is_miranda_entry_at(int i) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if a method is a miranda method, given a class's methods table and it's super
|
// check if a method is a miranda method, given a class's methods table and its super
|
||||||
|
// "miranda" means not static, not defined by this class, and not defined
|
||||||
|
// in super unless it is private and therefore inaccessible to this class.
|
||||||
// the caller must make sure that the method belongs to an interface implemented by the class
|
// the caller must make sure that the method belongs to an interface implemented by the class
|
||||||
bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Klass* super) {
|
bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Klass* super) {
|
||||||
if (m->is_static()) {
|
if (m->is_static()) {
|
||||||
|
@ -541,6 +557,14 @@ bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods, Klass* su
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scans current_interface_methods for miranda methods that do not
|
||||||
|
// already appear in new_mirandas and are also not defined-and-non-private
|
||||||
|
// in super (superclass). These mirandas are added to all_mirandas if it is
|
||||||
|
// not null; in addition, those that are not duplicates of miranda methods
|
||||||
|
// inherited by super from its interfaces are added to new_mirandas.
|
||||||
|
// Thus, new_mirandas will be the set of mirandas that this class introduces,
|
||||||
|
// all_mirandas will be the set of all mirandas applicable to this class
|
||||||
|
// including all defined in superclasses.
|
||||||
void klassVtable::add_new_mirandas_to_lists(
|
void klassVtable::add_new_mirandas_to_lists(
|
||||||
GrowableArray<Method*>* new_mirandas, GrowableArray<Method*>* all_mirandas,
|
GrowableArray<Method*>* new_mirandas, GrowableArray<Method*>* all_mirandas,
|
||||||
Array<Method*>* current_interface_methods, Array<Method*>* class_methods,
|
Array<Method*>* current_interface_methods, Array<Method*>* class_methods,
|
||||||
|
@ -599,17 +623,22 @@ void klassVtable::get_mirandas(GrowableArray<Method*>* new_mirandas,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fill in mirandas
|
// Discover miranda methods ("miranda" = "interface abstract, no binding"),
|
||||||
void klassVtable::fill_in_mirandas(int* initialized) {
|
// and append them into the vtable starting at index initialized,
|
||||||
|
// return the new value of initialized.
|
||||||
|
int klassVtable::fill_in_mirandas(int initialized) {
|
||||||
GrowableArray<Method*> mirandas(20);
|
GrowableArray<Method*> mirandas(20);
|
||||||
get_mirandas(&mirandas, NULL, ik()->super(), ik()->methods(),
|
get_mirandas(&mirandas, NULL, ik()->super(), ik()->methods(),
|
||||||
ik()->local_interfaces());
|
ik()->local_interfaces());
|
||||||
for (int i = 0; i < mirandas.length(); i++) {
|
for (int i = 0; i < mirandas.length(); i++) {
|
||||||
put_method_at(mirandas.at(i), *initialized);
|
put_method_at(mirandas.at(i), initialized);
|
||||||
++(*initialized);
|
++initialized;
|
||||||
}
|
}
|
||||||
|
return initialized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy this class's vtable to the vtable beginning at start.
|
||||||
|
// Used to copy superclass vtable to prefix of subclass's vtable.
|
||||||
void klassVtable::copy_vtable_to(vtableEntry* start) {
|
void klassVtable::copy_vtable_to(vtableEntry* start) {
|
||||||
Copy::disjoint_words((HeapWord*)table(), (HeapWord*)start, _length * vtableEntry::size());
|
Copy::disjoint_words((HeapWord*)table(), (HeapWord*)start, _length * vtableEntry::size());
|
||||||
}
|
}
|
||||||
|
@ -723,6 +752,12 @@ static int initialize_count = 0;
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
void klassItable::initialize_itable(bool checkconstraints, TRAPS) {
|
void klassItable::initialize_itable(bool checkconstraints, TRAPS) {
|
||||||
|
if (_klass->is_interface()) {
|
||||||
|
// This needs to go after vtable indexes are assigned but
|
||||||
|
// before implementors need to know the number of itable indexes.
|
||||||
|
assign_itable_indexes_for_interface(_klass());
|
||||||
|
}
|
||||||
|
|
||||||
// Cannot be setup doing bootstrapping, interfaces don't have
|
// Cannot be setup doing bootstrapping, interfaces don't have
|
||||||
// itables, and klass with only ones entry have empty itables
|
// itables, and klass with only ones entry have empty itables
|
||||||
if (Universe::is_bootstrapping() ||
|
if (Universe::is_bootstrapping() ||
|
||||||
|
@ -754,45 +789,89 @@ void klassItable::initialize_itable(bool checkconstraints, TRAPS) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool interface_method_needs_itable_index(Method* m) {
|
||||||
|
if (m->is_static()) return false; // e.g., Stream.empty
|
||||||
|
if (m->is_initializer()) return false; // <init> or <clinit>
|
||||||
|
// If an interface redeclares a method from java.lang.Object,
|
||||||
|
// it should already have a vtable index, don't touch it.
|
||||||
|
// e.g., CharSequence.toString (from initialize_vtable)
|
||||||
|
// if (m->has_vtable_index()) return false; // NO!
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int klassItable::assign_itable_indexes_for_interface(Klass* klass) {
|
||||||
|
// an interface does not have an itable, but its methods need to be numbered
|
||||||
|
if (TraceItables) tty->print_cr("%3d: Initializing itable for interface %s", ++initialize_count,
|
||||||
|
klass->name()->as_C_string());
|
||||||
|
Array<Method*>* methods = InstanceKlass::cast(klass)->methods();
|
||||||
|
int nof_methods = methods->length();
|
||||||
|
int ime_num = 0;
|
||||||
|
for (int i = 0; i < nof_methods; i++) {
|
||||||
|
Method* m = methods->at(i);
|
||||||
|
if (interface_method_needs_itable_index(m)) {
|
||||||
|
assert(!m->is_final_method(), "no final interface methods");
|
||||||
|
// If m is already assigned a vtable index, do not disturb it.
|
||||||
|
if (!m->has_vtable_index()) {
|
||||||
|
assert(m->vtable_index() == Method::pending_itable_index, "set by initialize_vtable");
|
||||||
|
m->set_itable_index(ime_num);
|
||||||
|
// Progress to next itable entry
|
||||||
|
ime_num++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(ime_num == method_count_for_interface(klass), "proper sizing");
|
||||||
|
return ime_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
int klassItable::method_count_for_interface(Klass* interf) {
|
||||||
|
assert(interf->oop_is_instance(), "must be");
|
||||||
|
assert(interf->is_interface(), "must be");
|
||||||
|
Array<Method*>* methods = InstanceKlass::cast(interf)->methods();
|
||||||
|
int nof_methods = methods->length();
|
||||||
|
while (nof_methods > 0) {
|
||||||
|
Method* m = methods->at(nof_methods-1);
|
||||||
|
if (m->has_itable_index()) {
|
||||||
|
int length = m->itable_index() + 1;
|
||||||
|
#ifdef ASSERT
|
||||||
|
while (nof_methods = 0) {
|
||||||
|
m = methods->at(--nof_methods);
|
||||||
|
assert(!m->has_itable_index() || m->itable_index() < length, "");
|
||||||
|
}
|
||||||
|
#endif //ASSERT
|
||||||
|
return length; // return the rightmost itable index, plus one
|
||||||
|
}
|
||||||
|
nof_methods -= 1;
|
||||||
|
}
|
||||||
|
// no methods have itable indexes
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void klassItable::initialize_itable_for_interface(int method_table_offset, KlassHandle interf_h, bool checkconstraints, TRAPS) {
|
void klassItable::initialize_itable_for_interface(int method_table_offset, KlassHandle interf_h, bool checkconstraints, TRAPS) {
|
||||||
Array<Method*>* methods = InstanceKlass::cast(interf_h())->methods();
|
Array<Method*>* methods = InstanceKlass::cast(interf_h())->methods();
|
||||||
int nof_methods = methods->length();
|
int nof_methods = methods->length();
|
||||||
HandleMark hm;
|
HandleMark hm;
|
||||||
KlassHandle klass = _klass;
|
|
||||||
assert(nof_methods > 0, "at least one method must exist for interface to be in vtable");
|
assert(nof_methods > 0, "at least one method must exist for interface to be in vtable");
|
||||||
Handle interface_loader (THREAD, InstanceKlass::cast(interf_h())->class_loader());
|
Handle interface_loader (THREAD, InstanceKlass::cast(interf_h())->class_loader());
|
||||||
int ime_num = 0;
|
|
||||||
|
|
||||||
// Skip first Method* if it is a class initializer
|
int ime_count = method_count_for_interface(interf_h());
|
||||||
int i = methods->at(0)->is_static_initializer() ? 1 : 0;
|
for (int i = 0; i < nof_methods; i++) {
|
||||||
|
|
||||||
// m, method_name, method_signature, klass reset each loop so they
|
|
||||||
// don't need preserving across check_signature_loaders call
|
|
||||||
// methods needs a handle in case of gc from check_signature_loaders
|
|
||||||
for(; i < nof_methods; i++) {
|
|
||||||
Method* m = methods->at(i);
|
Method* m = methods->at(i);
|
||||||
Symbol* method_name = m->name();
|
methodHandle target;
|
||||||
Symbol* method_signature = m->signature();
|
if (m->has_itable_index()) {
|
||||||
|
LinkResolver::lookup_instance_method_in_klasses(target, _klass, m->name(), m->signature(), CHECK);
|
||||||
// This is same code as in Linkresolver::lookup_instance_method_in_klasses
|
|
||||||
Method* target = klass->uncached_lookup_method(method_name, method_signature);
|
|
||||||
while (target != NULL && target->is_static()) {
|
|
||||||
// continue with recursive lookup through the superclass
|
|
||||||
Klass* super = target->method_holder()->super();
|
|
||||||
target = (super == NULL) ? (Method*)NULL : super->uncached_lookup_method(method_name, method_signature);
|
|
||||||
}
|
}
|
||||||
if (target == NULL || !target->is_public() || target->is_abstract()) {
|
if (target == NULL || !target->is_public() || target->is_abstract()) {
|
||||||
// Entry do not resolve. Leave it empty
|
// Entry do not resolve. Leave it empty
|
||||||
} else {
|
} else {
|
||||||
// Entry did resolve, check loader constraints before initializing
|
// Entry did resolve, check loader constraints before initializing
|
||||||
// if checkconstraints requested
|
// if checkconstraints requested
|
||||||
methodHandle target_h (THREAD, target); // preserve across gc
|
|
||||||
if (checkconstraints) {
|
if (checkconstraints) {
|
||||||
Handle method_holder_loader (THREAD, target->method_holder()->class_loader());
|
Handle method_holder_loader (THREAD, target->method_holder()->class_loader());
|
||||||
if (method_holder_loader() != interface_loader()) {
|
if (method_holder_loader() != interface_loader()) {
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
Symbol* failed_type_symbol =
|
Symbol* failed_type_symbol =
|
||||||
SystemDictionary::check_signature_loaders(method_signature,
|
SystemDictionary::check_signature_loaders(m->signature(),
|
||||||
method_holder_loader,
|
method_holder_loader,
|
||||||
interface_loader,
|
interface_loader,
|
||||||
true, CHECK);
|
true, CHECK);
|
||||||
|
@ -803,9 +882,9 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass
|
||||||
"and the class loader (instance of %s) for interface "
|
"and the class loader (instance of %s) for interface "
|
||||||
"%s have different Class objects for the type %s "
|
"%s have different Class objects for the type %s "
|
||||||
"used in the signature";
|
"used in the signature";
|
||||||
char* sig = target_h()->name_and_sig_as_C_string();
|
char* sig = target()->name_and_sig_as_C_string();
|
||||||
const char* loader1 = SystemDictionary::loader_name(method_holder_loader());
|
const char* loader1 = SystemDictionary::loader_name(method_holder_loader());
|
||||||
char* current = klass->name()->as_C_string();
|
char* current = _klass->name()->as_C_string();
|
||||||
const char* loader2 = SystemDictionary::loader_name(interface_loader());
|
const char* loader2 = SystemDictionary::loader_name(interface_loader());
|
||||||
char* iface = InstanceKlass::cast(interf_h())->name()->as_C_string();
|
char* iface = InstanceKlass::cast(interf_h())->name()->as_C_string();
|
||||||
char* failed_type_name = failed_type_symbol->as_C_string();
|
char* failed_type_name = failed_type_symbol->as_C_string();
|
||||||
|
@ -821,10 +900,10 @@ void klassItable::initialize_itable_for_interface(int method_table_offset, Klass
|
||||||
}
|
}
|
||||||
|
|
||||||
// ime may have moved during GC so recalculate address
|
// ime may have moved during GC so recalculate address
|
||||||
itableOffsetEntry::method_entry(_klass(), method_table_offset)[ime_num].initialize(target_h());
|
int ime_num = m->itable_index();
|
||||||
|
assert(ime_num < ime_count, "oob");
|
||||||
|
itableOffsetEntry::method_entry(_klass(), method_table_offset)[ime_num].initialize(target());
|
||||||
}
|
}
|
||||||
// Progress to next entry
|
|
||||||
ime_num++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -913,20 +992,22 @@ class InterfaceVisiterClosure : public StackObj {
|
||||||
virtual void doit(Klass* intf, int method_count) = 0;
|
virtual void doit(Klass* intf, int method_count) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Visit all interfaces with at-least one method (excluding <clinit>)
|
// Visit all interfaces with at least one itable method
|
||||||
void visit_all_interfaces(Array<Klass*>* transitive_intf, InterfaceVisiterClosure *blk) {
|
void visit_all_interfaces(Array<Klass*>* transitive_intf, InterfaceVisiterClosure *blk) {
|
||||||
// Handle array argument
|
// Handle array argument
|
||||||
for(int i = 0; i < transitive_intf->length(); i++) {
|
for(int i = 0; i < transitive_intf->length(); i++) {
|
||||||
Klass* intf = transitive_intf->at(i);
|
Klass* intf = transitive_intf->at(i);
|
||||||
assert(intf->is_interface(), "sanity check");
|
assert(intf->is_interface(), "sanity check");
|
||||||
|
|
||||||
// Find no. of methods excluding a <clinit>
|
// Find no. of itable methods
|
||||||
int method_count = InstanceKlass::cast(intf)->methods()->length();
|
int method_count = 0;
|
||||||
if (method_count > 0) {
|
// method_count = klassItable::method_count_for_interface(intf);
|
||||||
Method* m = InstanceKlass::cast(intf)->methods()->at(0);
|
Array<Method*>* methods = InstanceKlass::cast(intf)->methods();
|
||||||
assert(m != NULL && m->is_method(), "sanity check");
|
if (methods->length() > 0) {
|
||||||
if (m->name() == vmSymbols::object_initializer_name()) {
|
for (int i = methods->length(); --i >= 0; ) {
|
||||||
method_count--;
|
if (interface_method_needs_itable_index(methods->at(i))) {
|
||||||
|
method_count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1024,40 +1105,26 @@ void klassItable::setup_itable_offset_table(instanceKlassHandle klass) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// m must be a method in an interface
|
// inverse to itable_index
|
||||||
int klassItable::compute_itable_index(Method* m) {
|
|
||||||
InstanceKlass* intf = m->method_holder();
|
|
||||||
assert(intf->is_interface(), "sanity check");
|
|
||||||
Array<Method*>* methods = intf->methods();
|
|
||||||
int index = 0;
|
|
||||||
while(methods->at(index) != m) {
|
|
||||||
index++;
|
|
||||||
assert(index < methods->length(), "should find index for resolve_invoke");
|
|
||||||
}
|
|
||||||
// Adjust for <clinit>, which is left out of table if first method
|
|
||||||
if (methods->length() > 0 && methods->at(0)->is_static_initializer()) {
|
|
||||||
index--;
|
|
||||||
}
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// inverse to compute_itable_index
|
|
||||||
Method* klassItable::method_for_itable_index(Klass* intf, int itable_index) {
|
Method* klassItable::method_for_itable_index(Klass* intf, int itable_index) {
|
||||||
assert(InstanceKlass::cast(intf)->is_interface(), "sanity check");
|
assert(InstanceKlass::cast(intf)->is_interface(), "sanity check");
|
||||||
|
assert(intf->verify_itable_index(itable_index), "");
|
||||||
Array<Method*>* methods = InstanceKlass::cast(intf)->methods();
|
Array<Method*>* methods = InstanceKlass::cast(intf)->methods();
|
||||||
|
|
||||||
int index = itable_index;
|
if (itable_index < 0 || itable_index >= method_count_for_interface(intf))
|
||||||
// Adjust for <clinit>, which is left out of table if first method
|
|
||||||
if (methods->length() > 0 && methods->at(0)->is_static_initializer()) {
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itable_index < 0 || index >= methods->length())
|
|
||||||
return NULL; // help caller defend against bad indexes
|
return NULL; // help caller defend against bad indexes
|
||||||
|
|
||||||
|
int index = itable_index;
|
||||||
Method* m = methods->at(index);
|
Method* m = methods->at(index);
|
||||||
assert(compute_itable_index(m) == itable_index, "correct inverse");
|
int index2 = -1;
|
||||||
|
while (!m->has_itable_index() ||
|
||||||
|
(index2 = m->itable_index()) != itable_index) {
|
||||||
|
assert(index2 < itable_index, "monotonic");
|
||||||
|
if (++index == methods->length())
|
||||||
|
return NULL;
|
||||||
|
m = methods->at(index);
|
||||||
|
}
|
||||||
|
assert(m->itable_index() == itable_index, "correct inverse");
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,7 @@ class klassVtable : public ResourceObj {
|
||||||
|
|
||||||
// support for miranda methods
|
// support for miranda methods
|
||||||
bool is_miranda_entry_at(int i);
|
bool is_miranda_entry_at(int i);
|
||||||
void fill_in_mirandas(int* initialized);
|
int fill_in_mirandas(int initialized);
|
||||||
static bool is_miranda(Method* m, Array<Method*>* class_methods, Klass* super);
|
static bool is_miranda(Method* m, Array<Method*>* class_methods, Klass* super);
|
||||||
static void add_new_mirandas_to_lists(
|
static void add_new_mirandas_to_lists(
|
||||||
GrowableArray<Method*>* new_mirandas,
|
GrowableArray<Method*>* new_mirandas,
|
||||||
|
@ -150,6 +150,8 @@ class klassVtable : public ResourceObj {
|
||||||
// from_compiled_code_entry_point -> nmethod entry point
|
// from_compiled_code_entry_point -> nmethod entry point
|
||||||
// from_interpreter_entry_point -> i2cadapter
|
// from_interpreter_entry_point -> i2cadapter
|
||||||
class vtableEntry VALUE_OBJ_CLASS_SPEC {
|
class vtableEntry VALUE_OBJ_CLASS_SPEC {
|
||||||
|
friend class VMStructs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// size in words
|
// size in words
|
||||||
static int size() {
|
static int size() {
|
||||||
|
@ -288,12 +290,12 @@ class klassItable : public ResourceObj {
|
||||||
#endif // INCLUDE_JVMTI
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
// Setup of itable
|
// Setup of itable
|
||||||
|
static int assign_itable_indexes_for_interface(Klass* klass);
|
||||||
|
static int method_count_for_interface(Klass* klass);
|
||||||
static int compute_itable_size(Array<Klass*>* transitive_interfaces);
|
static int compute_itable_size(Array<Klass*>* transitive_interfaces);
|
||||||
static void setup_itable_offset_table(instanceKlassHandle klass);
|
static void setup_itable_offset_table(instanceKlassHandle klass);
|
||||||
|
|
||||||
// Resolving of method to index
|
// Resolving of method to index
|
||||||
static int compute_itable_index(Method* m);
|
|
||||||
// ...and back again:
|
|
||||||
static Method* method_for_itable_index(Klass* klass, int itable_index);
|
static Method* method_for_itable_index(Klass* klass, int itable_index);
|
||||||
|
|
||||||
// Debugging/Statistics
|
// Debugging/Statistics
|
||||||
|
|
|
@ -509,24 +509,31 @@ bool Method::compute_has_loops_flag() {
|
||||||
return _access_flags.has_loops();
|
return _access_flags.has_loops();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Method::is_final_method(AccessFlags class_access_flags) const {
|
||||||
|
// or "does_not_require_vtable_entry"
|
||||||
|
// overpass can occur, is not final (reuses vtable entry)
|
||||||
|
// private methods get vtable entries for backward class compatibility.
|
||||||
|
if (is_overpass()) return false;
|
||||||
|
return is_final() || class_access_flags.is_final();
|
||||||
|
}
|
||||||
|
|
||||||
bool Method::is_final_method() const {
|
bool Method::is_final_method() const {
|
||||||
// %%% Should return true for private methods also,
|
return is_final_method(method_holder()->access_flags());
|
||||||
// since there is no way to override them.
|
|
||||||
return is_final() || method_holder()->is_final();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Method::can_be_statically_bound(AccessFlags class_access_flags) const {
|
||||||
bool Method::is_strict_method() const {
|
if (is_final_method(class_access_flags)) return true;
|
||||||
return is_strict();
|
#ifdef ASSERT
|
||||||
}
|
bool is_nonv = (vtable_index() == nonvirtual_vtable_index);
|
||||||
|
if (class_access_flags.is_interface()) assert(is_nonv == is_static(), err_msg("is_nonv=%s", is_nonv));
|
||||||
|
#endif
|
||||||
bool Method::can_be_statically_bound() const {
|
assert(valid_vtable_index() || valid_itable_index(), "method must be linked before we ask this question");
|
||||||
if (is_final_method()) return true;
|
|
||||||
return vtable_index() == nonvirtual_vtable_index;
|
return vtable_index() == nonvirtual_vtable_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Method::can_be_statically_bound() const {
|
||||||
|
return can_be_statically_bound(method_holder()->access_flags());
|
||||||
|
}
|
||||||
|
|
||||||
bool Method::is_accessor() const {
|
bool Method::is_accessor() const {
|
||||||
if (code_size() != 5) return false;
|
if (code_size() != 5) return false;
|
||||||
|
@ -967,7 +974,7 @@ 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");
|
assert(ik->vtable() != NULL, "vtable should exist");
|
||||||
if (vtable_index() == nonvirtual_vtable_index) {
|
if (!has_vtable_index()) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
Method* vt_m = ik->method_at_vtable(vtable_index());
|
Method* vt_m = ik->method_at_vtable(vtable_index());
|
||||||
|
@ -1959,7 +1966,7 @@ void Method::print_on(outputStream* st) const {
|
||||||
|
|
||||||
void Method::print_value_on(outputStream* st) const {
|
void Method::print_value_on(outputStream* st) const {
|
||||||
assert(is_method(), "must be method");
|
assert(is_method(), "must be method");
|
||||||
st->print_cr(internal_name());
|
st->print(internal_name());
|
||||||
print_address_on(st);
|
print_address_on(st);
|
||||||
st->print(" ");
|
st->print(" ");
|
||||||
name()->print_value_on(st);
|
name()->print_value_on(st);
|
||||||
|
@ -1967,6 +1974,7 @@ void Method::print_value_on(outputStream* st) const {
|
||||||
signature()->print_value_on(st);
|
signature()->print_value_on(st);
|
||||||
st->print(" in ");
|
st->print(" in ");
|
||||||
method_holder()->print_value_on(st);
|
method_holder()->print_value_on(st);
|
||||||
|
if (WizardMode) st->print("#%d", _vtable_index);
|
||||||
if (WizardMode) st->print("[%d,%d]", size_of_parameters(), max_locals());
|
if (WizardMode) st->print("[%d,%d]", size_of_parameters(), max_locals());
|
||||||
if (WizardMode && code() != NULL) st->print(" ((nmethod*)%p)", code());
|
if (WizardMode && code() != NULL) st->print(" ((nmethod*)%p)", code());
|
||||||
}
|
}
|
||||||
|
|
|
@ -448,16 +448,22 @@ class Method : public Metadata {
|
||||||
enum VtableIndexFlag {
|
enum VtableIndexFlag {
|
||||||
// Valid vtable indexes are non-negative (>= 0).
|
// Valid vtable indexes are non-negative (>= 0).
|
||||||
// These few negative values are used as sentinels.
|
// These few negative values are used as sentinels.
|
||||||
highest_unused_vtable_index_value = -5,
|
itable_index_max = -10, // first itable index, growing downward
|
||||||
|
pending_itable_index = -9, // itable index will be assigned
|
||||||
invalid_vtable_index = -4, // distinct from any valid vtable index
|
invalid_vtable_index = -4, // distinct from any valid vtable index
|
||||||
garbage_vtable_index = -3, // not yet linked; no vtable layout yet
|
garbage_vtable_index = -3, // not yet linked; no vtable layout yet
|
||||||
nonvirtual_vtable_index = -2 // there is no need for vtable dispatch
|
nonvirtual_vtable_index = -2 // there is no need for vtable dispatch
|
||||||
// 6330203 Note: Do not use -1, which was overloaded with many meanings.
|
// 6330203 Note: Do not use -1, which was overloaded with many meanings.
|
||||||
};
|
};
|
||||||
DEBUG_ONLY(bool valid_vtable_index() const { return _vtable_index >= nonvirtual_vtable_index; })
|
DEBUG_ONLY(bool valid_vtable_index() const { return _vtable_index >= nonvirtual_vtable_index; })
|
||||||
int vtable_index() const { assert(valid_vtable_index(), "");
|
bool has_vtable_index() const { return _vtable_index >= 0; }
|
||||||
return _vtable_index; }
|
int vtable_index() const { return _vtable_index; }
|
||||||
void set_vtable_index(int index) { _vtable_index = index; }
|
void set_vtable_index(int index) { _vtable_index = index; }
|
||||||
|
DEBUG_ONLY(bool valid_itable_index() const { return _vtable_index <= pending_itable_index; })
|
||||||
|
bool has_itable_index() const { return _vtable_index <= itable_index_max; }
|
||||||
|
int itable_index() const { assert(valid_itable_index(), "");
|
||||||
|
return itable_index_max - _vtable_index; }
|
||||||
|
void set_itable_index(int index) { _vtable_index = itable_index_max - index; assert(valid_itable_index(), ""); }
|
||||||
|
|
||||||
// interpreter entry
|
// interpreter entry
|
||||||
address interpreter_entry() const { return _i2i_entry; }
|
address interpreter_entry() const { return _i2i_entry; }
|
||||||
|
@ -560,10 +566,11 @@ class Method : public Metadata {
|
||||||
|
|
||||||
// checks method and its method holder
|
// checks method and its method holder
|
||||||
bool is_final_method() const;
|
bool is_final_method() const;
|
||||||
bool is_strict_method() const;
|
bool is_final_method(AccessFlags class_access_flags) const;
|
||||||
|
|
||||||
// true if method needs no dynamic dispatch (final and/or no vtable entry)
|
// true if method needs no dynamic dispatch (final and/or no vtable entry)
|
||||||
bool can_be_statically_bound() const;
|
bool can_be_statically_bound() const;
|
||||||
|
bool can_be_statically_bound(AccessFlags class_access_flags) const;
|
||||||
|
|
||||||
// returns true if the method has any backward branches.
|
// returns true if the method has any backward branches.
|
||||||
bool has_loops() {
|
bool has_loops() {
|
||||||
|
@ -740,10 +747,6 @@ class Method : public Metadata {
|
||||||
// so handles are not used to avoid deadlock.
|
// so handles are not used to avoid deadlock.
|
||||||
jmethodID find_jmethod_id_or_null() { return method_holder()->jmethod_id_or_null(this); }
|
jmethodID find_jmethod_id_or_null() { return method_holder()->jmethod_id_or_null(this); }
|
||||||
|
|
||||||
// JNI static invoke cached itable index accessors
|
|
||||||
int cached_itable_index() { return method_holder()->cached_itable_index(method_idnum()); }
|
|
||||||
void set_cached_itable_index(int index) { method_holder()->set_cached_itable_index(method_idnum(), index); }
|
|
||||||
|
|
||||||
// Support for inlining of intrinsic methods
|
// Support for inlining of intrinsic methods
|
||||||
vmIntrinsics::ID intrinsic_id() const { return (vmIntrinsics::ID) _intrinsic_id; }
|
vmIntrinsics::ID intrinsic_id() const { return (vmIntrinsics::ID) _intrinsic_id; }
|
||||||
void set_intrinsic_id(vmIntrinsics::ID id) { _intrinsic_id = (u1) id; }
|
void set_intrinsic_id(vmIntrinsics::ID id) { _intrinsic_id = (u1) id; }
|
||||||
|
|
|
@ -72,6 +72,8 @@ class ProfileData;
|
||||||
//
|
//
|
||||||
// Overlay for generic profiling data.
|
// Overlay for generic profiling data.
|
||||||
class DataLayout VALUE_OBJ_CLASS_SPEC {
|
class DataLayout VALUE_OBJ_CLASS_SPEC {
|
||||||
|
friend class VMStructs;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Every data layout begins with a header. This header
|
// Every data layout begins with a header. This header
|
||||||
// contains a tag, which is used to indicate the size/layout
|
// contains a tag, which is used to indicate the size/layout
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
// in the SymbolTable bucket (the _literal field in HashtableEntry)
|
// in the SymbolTable bucket (the _literal field in HashtableEntry)
|
||||||
// that points to the Symbol. All other stores of a Symbol*
|
// that points to the Symbol. All other stores of a Symbol*
|
||||||
// to a field of a persistent variable (e.g., the _name filed in
|
// to a field of a persistent variable (e.g., the _name filed in
|
||||||
// FieldAccessInfo or _ptr in a CPSlot) is reference counted.
|
// fieldDescriptor or _ptr in a CPSlot) is reference counted.
|
||||||
//
|
//
|
||||||
// 1) The lookup of a "name" in the SymbolTable either creates a Symbol F for
|
// 1) The lookup of a "name" in the SymbolTable either creates a Symbol F for
|
||||||
// "name" and returns a pointer to F or finds a pre-existing Symbol F for
|
// "name" and returns a pointer to F or finds a pre-existing Symbol F for
|
||||||
|
|
|
@ -122,40 +122,23 @@ double LRG::score() const {
|
||||||
return score;
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
LRG_List::LRG_List( uint max ) : _cnt(max), _max(max), _lidxs(NEW_RESOURCE_ARRAY(uint,max)) {
|
|
||||||
memset( _lidxs, 0, sizeof(uint)*max );
|
|
||||||
}
|
|
||||||
|
|
||||||
void LRG_List::extend( uint nidx, uint lidx ) {
|
|
||||||
_nesting.check();
|
|
||||||
if( nidx >= _max ) {
|
|
||||||
uint size = 16;
|
|
||||||
while( size <= nidx ) size <<=1;
|
|
||||||
_lidxs = REALLOC_RESOURCE_ARRAY( uint, _lidxs, _max, size );
|
|
||||||
_max = size;
|
|
||||||
}
|
|
||||||
while( _cnt <= nidx )
|
|
||||||
_lidxs[_cnt++] = 0;
|
|
||||||
_lidxs[nidx] = lidx;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define NUMBUCKS 3
|
#define NUMBUCKS 3
|
||||||
|
|
||||||
// Straight out of Tarjan's union-find algorithm
|
// Straight out of Tarjan's union-find algorithm
|
||||||
uint LiveRangeMap::find_compress(uint lrg) {
|
uint LiveRangeMap::find_compress(uint lrg) {
|
||||||
uint cur = lrg;
|
uint cur = lrg;
|
||||||
uint next = _uf_map[cur];
|
uint next = _uf_map.at(cur);
|
||||||
while (next != cur) { // Scan chain of equivalences
|
while (next != cur) { // Scan chain of equivalences
|
||||||
assert( next < cur, "always union smaller");
|
assert( next < cur, "always union smaller");
|
||||||
cur = next; // until find a fixed-point
|
cur = next; // until find a fixed-point
|
||||||
next = _uf_map[cur];
|
next = _uf_map.at(cur);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Core of union-find algorithm: update chain of
|
// Core of union-find algorithm: update chain of
|
||||||
// equivalences to be equal to the root.
|
// equivalences to be equal to the root.
|
||||||
while (lrg != next) {
|
while (lrg != next) {
|
||||||
uint tmp = _uf_map[lrg];
|
uint tmp = _uf_map.at(lrg);
|
||||||
_uf_map.map(lrg, next);
|
_uf_map.at_put(lrg, next);
|
||||||
lrg = tmp;
|
lrg = tmp;
|
||||||
}
|
}
|
||||||
return lrg;
|
return lrg;
|
||||||
|
@ -165,10 +148,10 @@ uint LiveRangeMap::find_compress(uint lrg) {
|
||||||
void LiveRangeMap::reset_uf_map(uint max_lrg_id) {
|
void LiveRangeMap::reset_uf_map(uint max_lrg_id) {
|
||||||
_max_lrg_id= max_lrg_id;
|
_max_lrg_id= max_lrg_id;
|
||||||
// Force the Union-Find mapping to be at least this large
|
// Force the Union-Find mapping to be at least this large
|
||||||
_uf_map.extend(_max_lrg_id, 0);
|
_uf_map.at_put_grow(_max_lrg_id, 0);
|
||||||
// Initialize it to be the ID mapping.
|
// Initialize it to be the ID mapping.
|
||||||
for (uint i = 0; i < _max_lrg_id; ++i) {
|
for (uint i = 0; i < _max_lrg_id; ++i) {
|
||||||
_uf_map.map(i, i);
|
_uf_map.at_put(i, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,12 +159,12 @@ void LiveRangeMap::reset_uf_map(uint max_lrg_id) {
|
||||||
// the Union-Find mapping after this call.
|
// the Union-Find mapping after this call.
|
||||||
void LiveRangeMap::compress_uf_map_for_nodes() {
|
void LiveRangeMap::compress_uf_map_for_nodes() {
|
||||||
// For all Nodes, compress mapping
|
// For all Nodes, compress mapping
|
||||||
uint unique = _names.Size();
|
uint unique = _names.length();
|
||||||
for (uint i = 0; i < unique; ++i) {
|
for (uint i = 0; i < unique; ++i) {
|
||||||
uint lrg = _names[i];
|
uint lrg = _names.at(i);
|
||||||
uint compressed_lrg = find(lrg);
|
uint compressed_lrg = find(lrg);
|
||||||
if (lrg != compressed_lrg) {
|
if (lrg != compressed_lrg) {
|
||||||
_names.map(i, compressed_lrg);
|
_names.at_put(i, compressed_lrg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -198,11 +181,11 @@ uint LiveRangeMap::find_const(uint lrg) const {
|
||||||
return lrg;
|
return lrg;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint next = _uf_map[lrg];
|
uint next = _uf_map.at(lrg);
|
||||||
while (next != lrg) { // Scan chain of equivalences
|
while (next != lrg) { // Scan chain of equivalences
|
||||||
assert(next < lrg, "always union smaller");
|
assert(next < lrg, "always union smaller");
|
||||||
lrg = next; // until find a fixed-point
|
lrg = next; // until find a fixed-point
|
||||||
next = _uf_map[lrg];
|
next = _uf_map.at(lrg);
|
||||||
}
|
}
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
@ -215,7 +198,7 @@ PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher)
|
||||||
NULL
|
NULL
|
||||||
#endif
|
#endif
|
||||||
)
|
)
|
||||||
, _lrg_map(unique)
|
, _lrg_map(Thread::current()->resource_area(), unique)
|
||||||
, _live(0)
|
, _live(0)
|
||||||
, _spilled_once(Thread::current()->resource_area())
|
, _spilled_once(Thread::current()->resource_area())
|
||||||
, _spilled_twice(Thread::current()->resource_area())
|
, _spilled_twice(Thread::current()->resource_area())
|
||||||
|
@ -692,6 +675,7 @@ void PhaseChaitin::de_ssa() {
|
||||||
_lrg_map.map(n->_idx, rm.is_NotEmpty() ? lr_counter++ : 0);
|
_lrg_map.map(n->_idx, rm.is_NotEmpty() ? lr_counter++ : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the Union-Find mapping to be identity
|
// Reset the Union-Find mapping to be identity
|
||||||
_lrg_map.reset_uf_map(lr_counter);
|
_lrg_map.reset_uf_map(lr_counter);
|
||||||
}
|
}
|
||||||
|
|
|
@ -283,8 +283,8 @@ private:
|
||||||
|
|
||||||
// Straight out of Tarjan's union-find algorithm
|
// Straight out of Tarjan's union-find algorithm
|
||||||
uint find_compress(const Node *node) {
|
uint find_compress(const Node *node) {
|
||||||
uint lrg_id = find_compress(_names[node->_idx]);
|
uint lrg_id = find_compress(_names.at(node->_idx));
|
||||||
_names.map(node->_idx, lrg_id);
|
_names.at_put(node->_idx, lrg_id);
|
||||||
return lrg_id;
|
return lrg_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,40 +305,40 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
uint size() const {
|
uint size() const {
|
||||||
return _names.Size();
|
return _names.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint live_range_id(uint idx) const {
|
uint live_range_id(uint idx) const {
|
||||||
return _names[idx];
|
return _names.at(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint live_range_id(const Node *node) const {
|
uint live_range_id(const Node *node) const {
|
||||||
return _names[node->_idx];
|
return _names.at(node->_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint uf_live_range_id(uint lrg_id) const {
|
uint uf_live_range_id(uint lrg_id) const {
|
||||||
return _uf_map[lrg_id];
|
return _uf_map.at(lrg_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void map(uint idx, uint lrg_id) {
|
void map(uint idx, uint lrg_id) {
|
||||||
_names.map(idx, lrg_id);
|
_names.at_put(idx, lrg_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uf_map(uint dst_lrg_id, uint src_lrg_id) {
|
void uf_map(uint dst_lrg_id, uint src_lrg_id) {
|
||||||
_uf_map.map(dst_lrg_id, src_lrg_id);
|
_uf_map.at_put(dst_lrg_id, src_lrg_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void extend(uint idx, uint lrg_id) {
|
void extend(uint idx, uint lrg_id) {
|
||||||
_names.extend(idx, lrg_id);
|
_names.at_put_grow(idx, lrg_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void uf_extend(uint dst_lrg_id, uint src_lrg_id) {
|
void uf_extend(uint dst_lrg_id, uint src_lrg_id) {
|
||||||
_uf_map.extend(dst_lrg_id, src_lrg_id);
|
_uf_map.at_put_grow(dst_lrg_id, src_lrg_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
LiveRangeMap(uint unique)
|
LiveRangeMap(Arena* arena, uint unique)
|
||||||
: _names(unique)
|
: _names(arena, unique, unique, 0)
|
||||||
, _uf_map(unique)
|
, _uf_map(arena, unique, unique, 0)
|
||||||
, _max_lrg_id(0) {}
|
, _max_lrg_id(0) {}
|
||||||
|
|
||||||
uint find_id( const Node *n ) {
|
uint find_id( const Node *n ) {
|
||||||
|
@ -355,14 +355,14 @@ public:
|
||||||
void compress_uf_map_for_nodes();
|
void compress_uf_map_for_nodes();
|
||||||
|
|
||||||
uint find(uint lidx) {
|
uint find(uint lidx) {
|
||||||
uint uf_lidx = _uf_map[lidx];
|
uint uf_lidx = _uf_map.at(lidx);
|
||||||
return (uf_lidx == lidx) ? uf_lidx : find_compress(lidx);
|
return (uf_lidx == lidx) ? uf_lidx : find_compress(lidx);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert a Node into a Live Range Index - a lidx
|
// Convert a Node into a Live Range Index - a lidx
|
||||||
uint find(const Node *node) {
|
uint find(const Node *node) {
|
||||||
uint lidx = live_range_id(node);
|
uint lidx = live_range_id(node);
|
||||||
uint uf_lidx = _uf_map[lidx];
|
uint uf_lidx = _uf_map.at(lidx);
|
||||||
return (uf_lidx == lidx) ? uf_lidx : find_compress(node);
|
return (uf_lidx == lidx) ? uf_lidx : find_compress(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -371,10 +371,10 @@ public:
|
||||||
|
|
||||||
// Like Find above, but no path compress, so bad asymptotic behavior
|
// Like Find above, but no path compress, so bad asymptotic behavior
|
||||||
uint find_const(const Node *node) const {
|
uint find_const(const Node *node) const {
|
||||||
if(node->_idx >= _names.Size()) {
|
if(node->_idx >= (uint)_names.length()) {
|
||||||
return 0; // not mapped, usual for debug dump
|
return 0; // not mapped, usual for debug dump
|
||||||
}
|
}
|
||||||
return find_const(_names[node->_idx]);
|
return find_const(_names.at(node->_idx));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
|
|
||||||
class LoopTree;
|
class LoopTree;
|
||||||
class LRG;
|
class LRG;
|
||||||
class LRG_List;
|
|
||||||
class Matcher;
|
class Matcher;
|
||||||
class PhaseIFG;
|
class PhaseIFG;
|
||||||
class PhaseCFG;
|
class PhaseCFG;
|
||||||
|
|
|
@ -3734,6 +3734,8 @@ Node* LibraryCallKit::generate_virtual_guard(Node* obj_klass,
|
||||||
RegionNode* slow_region) {
|
RegionNode* slow_region) {
|
||||||
ciMethod* method = callee();
|
ciMethod* method = callee();
|
||||||
int vtable_index = method->vtable_index();
|
int vtable_index = method->vtable_index();
|
||||||
|
assert(vtable_index >= 0 || vtable_index == Method::nonvirtual_vtable_index,
|
||||||
|
err_msg_res("bad index %d", vtable_index));
|
||||||
// Get the Method* out of the appropriate vtable entry.
|
// Get the Method* out of the appropriate vtable entry.
|
||||||
int entry_offset = (InstanceKlass::vtable_start_offset() +
|
int entry_offset = (InstanceKlass::vtable_start_offset() +
|
||||||
vtable_index*vtableEntry::size()) * wordSize +
|
vtable_index*vtableEntry::size()) * wordSize +
|
||||||
|
@ -3784,6 +3786,8 @@ LibraryCallKit::generate_method_call(vmIntrinsics::ID method_id, bool is_virtual
|
||||||
// so the vtable index is fixed.
|
// so the vtable index is fixed.
|
||||||
// No need to use the linkResolver to get it.
|
// No need to use the linkResolver to get it.
|
||||||
vtable_index = method->vtable_index();
|
vtable_index = method->vtable_index();
|
||||||
|
assert(vtable_index >= 0 || vtable_index == Method::nonvirtual_vtable_index,
|
||||||
|
err_msg_res("bad index %d", vtable_index));
|
||||||
}
|
}
|
||||||
slow_call = new(C) CallDynamicJavaNode(tf,
|
slow_call = new(C) CallDynamicJavaNode(tf,
|
||||||
SharedRuntime::get_resolve_virtual_call_stub(),
|
SharedRuntime::get_resolve_virtual_call_stub(),
|
||||||
|
|
|
@ -91,7 +91,7 @@ void PhaseLive::compute(uint maxlrg) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint r = _names[n->_idx];
|
uint r = _names.at(n->_idx);
|
||||||
assert(!def_outside->member(r), "Use of external LRG overlaps the same LRG defined in this block");
|
assert(!def_outside->member(r), "Use of external LRG overlaps the same LRG defined in this block");
|
||||||
def->insert( r );
|
def->insert( r );
|
||||||
use->remove( r );
|
use->remove( r );
|
||||||
|
@ -100,7 +100,7 @@ void PhaseLive::compute(uint maxlrg) {
|
||||||
Node *nk = n->in(k);
|
Node *nk = n->in(k);
|
||||||
uint nkidx = nk->_idx;
|
uint nkidx = nk->_idx;
|
||||||
if (_cfg.get_block_for_node(nk) != block) {
|
if (_cfg.get_block_for_node(nk) != block) {
|
||||||
uint u = _names[nkidx];
|
uint u = _names.at(nkidx);
|
||||||
use->insert(u);
|
use->insert(u);
|
||||||
DEBUG_ONLY(def_outside->insert(u);)
|
DEBUG_ONLY(def_outside->insert(u);)
|
||||||
}
|
}
|
||||||
|
@ -112,7 +112,7 @@ void PhaseLive::compute(uint maxlrg) {
|
||||||
#endif
|
#endif
|
||||||
// Remove anything defined by Phis and the block start instruction
|
// Remove anything defined by Phis and the block start instruction
|
||||||
for (uint k = i; k > 0; k--) {
|
for (uint k = i; k > 0; k--) {
|
||||||
uint r = _names[block->get_node(k - 1)->_idx];
|
uint r = _names.at(block->get_node(k - 1)->_idx);
|
||||||
def->insert(r);
|
def->insert(r);
|
||||||
use->remove(r);
|
use->remove(r);
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ void PhaseLive::compute(uint maxlrg) {
|
||||||
|
|
||||||
// PhiNode uses go in the live-out set of prior blocks.
|
// PhiNode uses go in the live-out set of prior blocks.
|
||||||
for (uint k = i; k > 0; k--) {
|
for (uint k = i; k > 0; k--) {
|
||||||
add_liveout(p, _names[block->get_node(k-1)->in(l)->_idx], first_pass);
|
add_liveout(p, _names.at(block->get_node(k-1)->in(l)->_idx), first_pass);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
freeset(block);
|
freeset(block);
|
||||||
|
@ -256,7 +256,7 @@ void PhaseLive::dump( const Block *b ) const {
|
||||||
tty->print("LiveOut: "); _live[b->_pre_order-1].dump();
|
tty->print("LiveOut: "); _live[b->_pre_order-1].dump();
|
||||||
uint cnt = b->number_of_nodes();
|
uint cnt = b->number_of_nodes();
|
||||||
for( uint i=0; i<cnt; i++ ) {
|
for( uint i=0; i<cnt; i++ ) {
|
||||||
tty->print("L%d/", _names[b->get_node(i)->_idx] );
|
tty->print("L%d/", _names.at(b->get_node(i)->_idx));
|
||||||
b->get_node(i)->dump();
|
b->get_node(i)->dump();
|
||||||
}
|
}
|
||||||
tty->print("\n");
|
tty->print("\n");
|
||||||
|
|
|
@ -40,27 +40,7 @@ class IndexSet;
|
||||||
//------------------------------LRG_List---------------------------------------
|
//------------------------------LRG_List---------------------------------------
|
||||||
// Map Node indices to Live RanGe indices.
|
// Map Node indices to Live RanGe indices.
|
||||||
// Array lookup in the optimized case.
|
// Array lookup in the optimized case.
|
||||||
class LRG_List : public ResourceObj {
|
typedef GrowableArray<uint> LRG_List;
|
||||||
friend class VMStructs;
|
|
||||||
uint _cnt, _max;
|
|
||||||
uint* _lidxs;
|
|
||||||
ReallocMark _nesting; // assertion check for reallocations
|
|
||||||
public:
|
|
||||||
LRG_List( uint max );
|
|
||||||
|
|
||||||
uint lookup( uint nidx ) const {
|
|
||||||
return _lidxs[nidx];
|
|
||||||
}
|
|
||||||
uint operator[] (uint nidx) const { return lookup(nidx); }
|
|
||||||
|
|
||||||
void map( uint nidx, uint lidx ) {
|
|
||||||
assert( nidx < _cnt, "oob" );
|
|
||||||
_lidxs[nidx] = lidx;
|
|
||||||
}
|
|
||||||
void extend( uint nidx, uint lidx );
|
|
||||||
|
|
||||||
uint Size() const { return _cnt; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------PhaseLive--------------------------------------
|
//------------------------------PhaseLive--------------------------------------
|
||||||
// Compute live-in/live-out
|
// Compute live-in/live-out
|
||||||
|
|
|
@ -1336,6 +1336,7 @@ static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receive
|
||||||
if (call_type == JNI_VIRTUAL) {
|
if (call_type == JNI_VIRTUAL) {
|
||||||
// jni_GetMethodID makes sure class is linked and initialized
|
// jni_GetMethodID makes sure class is linked and initialized
|
||||||
// so m should have a valid vtable index.
|
// so m should have a valid vtable index.
|
||||||
|
assert(!m->has_itable_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();
|
Klass* k = h_recv->klass();
|
||||||
|
@ -1355,12 +1356,7 @@ static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receive
|
||||||
// interface call
|
// interface call
|
||||||
KlassHandle h_holder(THREAD, holder);
|
KlassHandle h_holder(THREAD, holder);
|
||||||
|
|
||||||
int itbl_index = m->cached_itable_index();
|
int itbl_index = m->itable_index();
|
||||||
if (itbl_index == -1) {
|
|
||||||
itbl_index = klassItable::compute_itable_index(m);
|
|
||||||
m->set_cached_itable_index(itbl_index);
|
|
||||||
// the above may have grabbed a lock, 'm' and anything non-handlized can't be used again
|
|
||||||
}
|
|
||||||
Klass* k = h_recv->klass();
|
Klass* k = h_recv->klass();
|
||||||
selected_method = InstanceKlass::cast(k)->method_at_itable(h_holder(), itbl_index, CHECK);
|
selected_method = InstanceKlass::cast(k)->method_at_itable(h_holder(), itbl_index, CHECK);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1824,7 +1824,7 @@ JVM_ENTRY(jobjectArray, JVM_GetClassDeclaredFields(JNIEnv *env, jclass ofClass,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!publicOnly || fs.access_flags().is_public()) {
|
if (!publicOnly || fs.access_flags().is_public()) {
|
||||||
fd.initialize(k(), fs.index());
|
fd.reinitialize(k(), fs.index());
|
||||||
oop field = Reflection::new_field(&fd, UseNewReflection, CHECK_NULL);
|
oop field = Reflection::new_field(&fd, UseNewReflection, CHECK_NULL);
|
||||||
result->obj_at_put(out_idx, field);
|
result->obj_at_put(out_idx, field);
|
||||||
++out_idx;
|
++out_idx;
|
||||||
|
|
|
@ -2958,7 +2958,7 @@ void VM_RedefineClasses::check_methods_and_mark_as_obsolete(
|
||||||
for (int i = 0; i < _deleted_methods_length; ++i) {
|
for (int i = 0; i < _deleted_methods_length; ++i) {
|
||||||
Method* old_method = _deleted_methods[i];
|
Method* old_method = _deleted_methods[i];
|
||||||
|
|
||||||
assert(old_method->vtable_index() < 0,
|
assert(!old_method->has_vtable_index(),
|
||||||
"cannot delete methods with vtable entries");;
|
"cannot delete methods with vtable entries");;
|
||||||
|
|
||||||
// Mark all deleted methods as old and obsolete
|
// Mark all deleted methods as old and obsolete
|
||||||
|
|
|
@ -127,25 +127,37 @@ Handle MethodHandles::new_MemberName(TRAPS) {
|
||||||
}
|
}
|
||||||
|
|
||||||
oop MethodHandles::init_MemberName(Handle mname, Handle target) {
|
oop MethodHandles::init_MemberName(Handle mname, Handle target) {
|
||||||
|
// This method is used from java.lang.invoke.MemberName constructors.
|
||||||
|
// It fills in the new MemberName from a java.lang.reflect.Member.
|
||||||
Thread* thread = Thread::current();
|
Thread* thread = Thread::current();
|
||||||
oop target_oop = target();
|
oop target_oop = target();
|
||||||
Klass* target_klass = target_oop->klass();
|
Klass* target_klass = target_oop->klass();
|
||||||
if (target_klass == SystemDictionary::reflect_Field_klass()) {
|
if (target_klass == SystemDictionary::reflect_Field_klass()) {
|
||||||
oop clazz = java_lang_reflect_Field::clazz(target_oop); // fd.field_holder()
|
oop clazz = java_lang_reflect_Field::clazz(target_oop); // fd.field_holder()
|
||||||
int slot = java_lang_reflect_Field::slot(target_oop); // fd.index()
|
int slot = java_lang_reflect_Field::slot(target_oop); // fd.index()
|
||||||
int mods = java_lang_reflect_Field::modifiers(target_oop);
|
|
||||||
oop type = java_lang_reflect_Field::type(target_oop);
|
|
||||||
oop name = java_lang_reflect_Field::name(target_oop);
|
|
||||||
KlassHandle k(thread, java_lang_Class::as_Klass(clazz));
|
KlassHandle k(thread, java_lang_Class::as_Klass(clazz));
|
||||||
intptr_t offset = InstanceKlass::cast(k())->field_offset(slot);
|
if (!k.is_null() && k->oop_is_instance()) {
|
||||||
return init_field_MemberName(mname, k, accessFlags_from(mods), type, name, offset);
|
fieldDescriptor fd(InstanceKlass::cast(k()), slot);
|
||||||
|
oop mname2 = init_field_MemberName(mname, fd);
|
||||||
|
if (mname2 != NULL) {
|
||||||
|
// Since we have the reified name and type handy, add them to the result.
|
||||||
|
if (java_lang_invoke_MemberName::name(mname2) == NULL)
|
||||||
|
java_lang_invoke_MemberName::set_name(mname2, java_lang_reflect_Field::name(target_oop));
|
||||||
|
if (java_lang_invoke_MemberName::type(mname2) == NULL)
|
||||||
|
java_lang_invoke_MemberName::set_type(mname2, java_lang_reflect_Field::type(target_oop));
|
||||||
|
}
|
||||||
|
return mname2;
|
||||||
|
}
|
||||||
} else if (target_klass == SystemDictionary::reflect_Method_klass()) {
|
} else if (target_klass == SystemDictionary::reflect_Method_klass()) {
|
||||||
oop clazz = java_lang_reflect_Method::clazz(target_oop);
|
oop clazz = java_lang_reflect_Method::clazz(target_oop);
|
||||||
int slot = java_lang_reflect_Method::slot(target_oop);
|
int slot = java_lang_reflect_Method::slot(target_oop);
|
||||||
KlassHandle k(thread, java_lang_Class::as_Klass(clazz));
|
KlassHandle k(thread, java_lang_Class::as_Klass(clazz));
|
||||||
if (!k.is_null() && k->oop_is_instance()) {
|
if (!k.is_null() && k->oop_is_instance()) {
|
||||||
Method* m = InstanceKlass::cast(k())->method_with_idnum(slot);
|
Method* m = InstanceKlass::cast(k())->method_with_idnum(slot);
|
||||||
return init_method_MemberName(mname, m, true, k);
|
if (m == NULL || is_signature_polymorphic(m->intrinsic_id()))
|
||||||
|
return NULL; // do not resolve unless there is a concrete signature
|
||||||
|
CallInfo info(m, k());
|
||||||
|
return init_method_MemberName(mname, info);
|
||||||
}
|
}
|
||||||
} else if (target_klass == SystemDictionary::reflect_Constructor_klass()) {
|
} else if (target_klass == SystemDictionary::reflect_Constructor_klass()) {
|
||||||
oop clazz = java_lang_reflect_Constructor::clazz(target_oop);
|
oop clazz = java_lang_reflect_Constructor::clazz(target_oop);
|
||||||
|
@ -153,65 +165,50 @@ oop MethodHandles::init_MemberName(Handle mname, Handle target) {
|
||||||
KlassHandle k(thread, java_lang_Class::as_Klass(clazz));
|
KlassHandle k(thread, java_lang_Class::as_Klass(clazz));
|
||||||
if (!k.is_null() && k->oop_is_instance()) {
|
if (!k.is_null() && k->oop_is_instance()) {
|
||||||
Method* m = InstanceKlass::cast(k())->method_with_idnum(slot);
|
Method* m = InstanceKlass::cast(k())->method_with_idnum(slot);
|
||||||
return init_method_MemberName(mname, m, false, k);
|
if (m == NULL) return NULL;
|
||||||
}
|
CallInfo info(m, k());
|
||||||
} else if (target_klass == SystemDictionary::MemberName_klass()) {
|
return init_method_MemberName(mname, info);
|
||||||
// Note: This only works if the MemberName has already been resolved.
|
|
||||||
oop clazz = java_lang_invoke_MemberName::clazz(target_oop);
|
|
||||||
int flags = java_lang_invoke_MemberName::flags(target_oop);
|
|
||||||
Metadata* vmtarget=java_lang_invoke_MemberName::vmtarget(target_oop);
|
|
||||||
intptr_t vmindex = java_lang_invoke_MemberName::vmindex(target_oop);
|
|
||||||
KlassHandle k(thread, java_lang_Class::as_Klass(clazz));
|
|
||||||
int ref_kind = (flags >> REFERENCE_KIND_SHIFT) & REFERENCE_KIND_MASK;
|
|
||||||
if (vmtarget == NULL) return NULL; // not resolved
|
|
||||||
if ((flags & IS_FIELD) != 0) {
|
|
||||||
assert(vmtarget->is_klass(), "field vmtarget is Klass*");
|
|
||||||
int basic_mods = (ref_kind_is_static(ref_kind) ? JVM_ACC_STATIC : 0);
|
|
||||||
// FIXME: how does k (receiver_limit) contribute?
|
|
||||||
KlassHandle k_vmtarget(thread, (Klass*)vmtarget);
|
|
||||||
return init_field_MemberName(mname, k_vmtarget, accessFlags_from(basic_mods), NULL, NULL, vmindex);
|
|
||||||
} else if ((flags & (IS_METHOD | IS_CONSTRUCTOR)) != 0) {
|
|
||||||
assert(vmtarget->is_method(), "method or constructor vmtarget is Method*");
|
|
||||||
return init_method_MemberName(mname, (Method*)vmtarget, ref_kind_does_dispatch(ref_kind), k);
|
|
||||||
} else {
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
oop MethodHandles::init_method_MemberName(Handle mname, Method* m, bool do_dispatch,
|
oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) {
|
||||||
KlassHandle receiver_limit_h) {
|
assert(info.resolved_appendix().is_null(), "only normal methods here");
|
||||||
Klass* receiver_limit = receiver_limit_h();
|
KlassHandle receiver_limit = info.resolved_klass();
|
||||||
AccessFlags mods = m->access_flags();
|
methodHandle m = info.resolved_method();
|
||||||
int flags = (jushort)( mods.as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS );
|
int flags = (jushort)( m->access_flags().as_short() & JVM_RECOGNIZED_METHOD_MODIFIERS );
|
||||||
int vmindex = Method::nonvirtual_vtable_index; // implies never any dispatch
|
int vmindex = Method::invalid_vtable_index;
|
||||||
Klass* mklass = m->method_holder();
|
|
||||||
if (receiver_limit == NULL)
|
switch (info.call_kind()) {
|
||||||
receiver_limit = mklass;
|
case CallInfo::itable_call:
|
||||||
if (m->is_initializer()) {
|
vmindex = info.itable_index();
|
||||||
flags |= IS_CONSTRUCTOR | (JVM_REF_invokeSpecial << REFERENCE_KIND_SHIFT);
|
// More importantly, the itable index only works with the method holder.
|
||||||
} else if (mods.is_static()) {
|
receiver_limit = m->method_holder();
|
||||||
flags |= IS_METHOD | (JVM_REF_invokeStatic << REFERENCE_KIND_SHIFT);
|
assert(receiver_limit->verify_itable_index(vmindex), "");
|
||||||
} else if (receiver_limit != mklass &&
|
|
||||||
!receiver_limit->is_subtype_of(mklass)) {
|
|
||||||
return NULL; // bad receiver limit
|
|
||||||
} else if (do_dispatch && receiver_limit->is_interface() &&
|
|
||||||
mklass->is_interface()) {
|
|
||||||
flags |= IS_METHOD | (JVM_REF_invokeInterface << REFERENCE_KIND_SHIFT);
|
flags |= IS_METHOD | (JVM_REF_invokeInterface << REFERENCE_KIND_SHIFT);
|
||||||
receiver_limit = mklass; // ignore passed-in limit; interfaces are interconvertible
|
break;
|
||||||
vmindex = klassItable::compute_itable_index(m);
|
|
||||||
} else if (do_dispatch && mklass != receiver_limit && mklass->is_interface()) {
|
case CallInfo::vtable_call:
|
||||||
|
vmindex = info.vtable_index();
|
||||||
flags |= IS_METHOD | (JVM_REF_invokeVirtual << REFERENCE_KIND_SHIFT);
|
flags |= IS_METHOD | (JVM_REF_invokeVirtual << REFERENCE_KIND_SHIFT);
|
||||||
// it is a miranda method, so m->vtable_index is not what we want
|
assert(receiver_limit->is_subtype_of(m->method_holder()), "virtual call must be type-safe");
|
||||||
ResourceMark rm;
|
break;
|
||||||
klassVtable* vt = InstanceKlass::cast(receiver_limit)->vtable();
|
|
||||||
vmindex = vt->index_of_miranda(m->name(), m->signature());
|
case CallInfo::direct_call:
|
||||||
} else if (!do_dispatch || m->can_be_statically_bound()) {
|
vmindex = Method::nonvirtual_vtable_index;
|
||||||
flags |= IS_METHOD | (JVM_REF_invokeSpecial << REFERENCE_KIND_SHIFT);
|
if (m->is_static()) {
|
||||||
} else {
|
flags |= IS_METHOD | (JVM_REF_invokeStatic << REFERENCE_KIND_SHIFT);
|
||||||
flags |= IS_METHOD | (JVM_REF_invokeVirtual << REFERENCE_KIND_SHIFT);
|
} else if (m->is_initializer()) {
|
||||||
vmindex = m->vtable_index();
|
flags |= IS_CONSTRUCTOR | (JVM_REF_invokeSpecial << REFERENCE_KIND_SHIFT);
|
||||||
|
assert(receiver_limit == m->method_holder(), "constructor call must be exactly typed");
|
||||||
|
} else {
|
||||||
|
flags |= IS_METHOD | (JVM_REF_invokeSpecial << REFERENCE_KIND_SHIFT);
|
||||||
|
assert(receiver_limit->is_subtype_of(m->method_holder()), "special call must be type-safe");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: assert(false, "bad CallInfo"); return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// @CallerSensitive annotation detected
|
// @CallerSensitive annotation detected
|
||||||
|
@ -221,7 +218,7 @@ oop MethodHandles::init_method_MemberName(Handle mname, Method* m, bool do_dispa
|
||||||
|
|
||||||
oop mname_oop = mname();
|
oop mname_oop = mname();
|
||||||
java_lang_invoke_MemberName::set_flags( mname_oop, flags);
|
java_lang_invoke_MemberName::set_flags( mname_oop, flags);
|
||||||
java_lang_invoke_MemberName::set_vmtarget(mname_oop, m);
|
java_lang_invoke_MemberName::set_vmtarget(mname_oop, m());
|
||||||
java_lang_invoke_MemberName::set_vmindex( mname_oop, vmindex); // vtable/itable index
|
java_lang_invoke_MemberName::set_vmindex( mname_oop, vmindex); // vtable/itable index
|
||||||
java_lang_invoke_MemberName::set_clazz( mname_oop, receiver_limit->java_mirror());
|
java_lang_invoke_MemberName::set_clazz( mname_oop, receiver_limit->java_mirror());
|
||||||
// Note: name and type can be lazily computed by resolve_MemberName,
|
// Note: name and type can be lazily computed by resolve_MemberName,
|
||||||
|
@ -237,59 +234,19 @@ oop MethodHandles::init_method_MemberName(Handle mname, Method* m, bool do_dispa
|
||||||
return mname();
|
return mname();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle MethodHandles::init_method_MemberName(Handle mname, CallInfo& info, TRAPS) {
|
oop MethodHandles::init_field_MemberName(Handle mname, fieldDescriptor& fd, bool is_setter) {
|
||||||
Handle empty;
|
int flags = (jushort)( fd.access_flags().as_short() & JVM_RECOGNIZED_FIELD_MODIFIERS );
|
||||||
if (info.resolved_appendix().not_null()) {
|
flags |= IS_FIELD | ((fd.is_static() ? JVM_REF_getStatic : JVM_REF_getField) << REFERENCE_KIND_SHIFT);
|
||||||
// The resolved MemberName must not be accompanied by an appendix argument,
|
|
||||||
// since there is no way to bind this value into the MemberName.
|
|
||||||
// Caller is responsible to prevent this from happening.
|
|
||||||
THROW_MSG_(vmSymbols::java_lang_InternalError(), "appendix", empty);
|
|
||||||
}
|
|
||||||
methodHandle m = info.resolved_method();
|
|
||||||
KlassHandle defc = info.resolved_klass();
|
|
||||||
int vmindex = Method::invalid_vtable_index;
|
|
||||||
if (defc->is_interface() && m->method_holder()->is_interface()) {
|
|
||||||
// static interface methods do not reference vtable or itable
|
|
||||||
if (m->is_static()) {
|
|
||||||
vmindex = Method::nonvirtual_vtable_index;
|
|
||||||
}
|
|
||||||
// interface methods invoked via invokespecial also
|
|
||||||
// do not reference vtable or itable.
|
|
||||||
int ref_kind = ((java_lang_invoke_MemberName::flags(mname()) >>
|
|
||||||
REFERENCE_KIND_SHIFT) & REFERENCE_KIND_MASK);
|
|
||||||
if (ref_kind == JVM_REF_invokeSpecial) {
|
|
||||||
vmindex = Method::nonvirtual_vtable_index;
|
|
||||||
}
|
|
||||||
// If neither m is static nor ref_kind is invokespecial,
|
|
||||||
// set it to itable index.
|
|
||||||
if (vmindex == Method::invalid_vtable_index) {
|
|
||||||
// LinkResolver does not report itable indexes! (fix this?)
|
|
||||||
vmindex = klassItable::compute_itable_index(m());
|
|
||||||
}
|
|
||||||
} else if (m->can_be_statically_bound()) {
|
|
||||||
// LinkResolver reports vtable index even for final methods!
|
|
||||||
vmindex = Method::nonvirtual_vtable_index;
|
|
||||||
} else {
|
|
||||||
vmindex = info.vtable_index();
|
|
||||||
}
|
|
||||||
oop res = init_method_MemberName(mname, m(), (vmindex >= 0), defc());
|
|
||||||
assert(res == NULL || (java_lang_invoke_MemberName::vmindex(res) == vmindex), "");
|
|
||||||
return Handle(THREAD, res);
|
|
||||||
}
|
|
||||||
|
|
||||||
oop MethodHandles::init_field_MemberName(Handle mname, KlassHandle field_holder,
|
|
||||||
AccessFlags mods, oop type, oop name,
|
|
||||||
intptr_t offset, bool is_setter) {
|
|
||||||
int flags = (jushort)( mods.as_short() & JVM_RECOGNIZED_FIELD_MODIFIERS );
|
|
||||||
flags |= IS_FIELD | ((mods.is_static() ? JVM_REF_getStatic : JVM_REF_getField) << REFERENCE_KIND_SHIFT);
|
|
||||||
if (is_setter) flags += ((JVM_REF_putField - JVM_REF_getField) << REFERENCE_KIND_SHIFT);
|
if (is_setter) flags += ((JVM_REF_putField - JVM_REF_getField) << REFERENCE_KIND_SHIFT);
|
||||||
Metadata* vmtarget = field_holder();
|
Metadata* vmtarget = fd.field_holder();
|
||||||
int vmindex = offset; // determines the field uniquely when combined with static bit
|
int vmindex = fd.offset(); // determines the field uniquely when combined with static bit
|
||||||
oop mname_oop = mname();
|
oop mname_oop = mname();
|
||||||
java_lang_invoke_MemberName::set_flags(mname_oop, flags);
|
java_lang_invoke_MemberName::set_flags(mname_oop, flags);
|
||||||
java_lang_invoke_MemberName::set_vmtarget(mname_oop, vmtarget);
|
java_lang_invoke_MemberName::set_vmtarget(mname_oop, vmtarget);
|
||||||
java_lang_invoke_MemberName::set_vmindex(mname_oop, vmindex);
|
java_lang_invoke_MemberName::set_vmindex(mname_oop, vmindex);
|
||||||
java_lang_invoke_MemberName::set_clazz(mname_oop, field_holder->java_mirror());
|
java_lang_invoke_MemberName::set_clazz(mname_oop, fd.field_holder()->java_mirror());
|
||||||
|
oop type = field_signature_type_or_null(fd.signature());
|
||||||
|
oop name = field_name_or_null(fd.name());
|
||||||
if (name != NULL)
|
if (name != NULL)
|
||||||
java_lang_invoke_MemberName::set_name(mname_oop, name);
|
java_lang_invoke_MemberName::set_name(mname_oop, name);
|
||||||
if (type != NULL)
|
if (type != NULL)
|
||||||
|
@ -305,19 +262,6 @@ oop MethodHandles::init_field_MemberName(Handle mname, KlassHandle field_holder,
|
||||||
return mname();
|
return mname();
|
||||||
}
|
}
|
||||||
|
|
||||||
Handle MethodHandles::init_field_MemberName(Handle mname, FieldAccessInfo& info, TRAPS) {
|
|
||||||
return Handle();
|
|
||||||
#if 0 // FIXME
|
|
||||||
KlassHandle field_holder = info.klass();
|
|
||||||
intptr_t field_offset = info.field_offset();
|
|
||||||
return init_field_MemberName(mname_oop, field_holder(),
|
|
||||||
info.access_flags(),
|
|
||||||
type, name,
|
|
||||||
field_offset, false /*is_setter*/);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// JVM 2.9 Special Methods:
|
// JVM 2.9 Special Methods:
|
||||||
// A method is signature polymorphic if and only if all of the following conditions hold :
|
// A method is signature polymorphic if and only if all of the following conditions hold :
|
||||||
// * It is declared in the java.lang.invoke.MethodHandle class.
|
// * It is declared in the java.lang.invoke.MethodHandle class.
|
||||||
|
@ -573,12 +517,12 @@ static oop object_java_mirror() {
|
||||||
return SystemDictionary::Object_klass()->java_mirror();
|
return SystemDictionary::Object_klass()->java_mirror();
|
||||||
}
|
}
|
||||||
|
|
||||||
static oop field_name_or_null(Symbol* s) {
|
oop MethodHandles::field_name_or_null(Symbol* s) {
|
||||||
if (s == NULL) return NULL;
|
if (s == NULL) return NULL;
|
||||||
return StringTable::lookup(s);
|
return StringTable::lookup(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
static oop field_signature_type_or_null(Symbol* s) {
|
oop MethodHandles::field_signature_type_or_null(Symbol* s) {
|
||||||
if (s == NULL) return NULL;
|
if (s == NULL) return NULL;
|
||||||
BasicType bt = FieldType::basic_type(s);
|
BasicType bt = FieldType::basic_type(s);
|
||||||
if (is_java_primitive(bt)) {
|
if (is_java_primitive(bt)) {
|
||||||
|
@ -701,7 +645,14 @@ Handle MethodHandles::resolve_MemberName(Handle mname, TRAPS) {
|
||||||
return empty;
|
return empty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return init_method_MemberName(mname, result, THREAD);
|
if (result.resolved_appendix().not_null()) {
|
||||||
|
// The resolved MemberName must not be accompanied by an appendix argument,
|
||||||
|
// since there is no way to bind this value into the MemberName.
|
||||||
|
// Caller is responsible to prevent this from happening.
|
||||||
|
THROW_MSG_(vmSymbols::java_lang_InternalError(), "appendix", empty);
|
||||||
|
}
|
||||||
|
oop mname2 = init_method_MemberName(mname, result);
|
||||||
|
return Handle(THREAD, mname2);
|
||||||
}
|
}
|
||||||
case IS_CONSTRUCTOR:
|
case IS_CONSTRUCTOR:
|
||||||
{
|
{
|
||||||
|
@ -719,22 +670,21 @@ Handle MethodHandles::resolve_MemberName(Handle mname, TRAPS) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(result.is_statically_bound(), "");
|
assert(result.is_statically_bound(), "");
|
||||||
return init_method_MemberName(mname, result, THREAD);
|
oop mname2 = init_method_MemberName(mname, result);
|
||||||
|
return Handle(THREAD, mname2);
|
||||||
}
|
}
|
||||||
case IS_FIELD:
|
case IS_FIELD:
|
||||||
{
|
{
|
||||||
// This is taken from LinkResolver::resolve_field, sans access checks.
|
fieldDescriptor result; // find_field initializes fd if found
|
||||||
fieldDescriptor fd; // find_field initializes fd if found
|
{
|
||||||
KlassHandle sel_klass(THREAD, InstanceKlass::cast(defc())->find_field(name, type, &fd));
|
assert(!HAS_PENDING_EXCEPTION, "");
|
||||||
// check if field exists; i.e., if a klass containing the field def has been selected
|
LinkResolver::resolve_field(result, defc, name, type, KlassHandle(), Bytecodes::_nop, false, false, THREAD);
|
||||||
if (sel_klass.is_null()) return empty; // should not happen
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
oop type = field_signature_type_or_null(fd.signature());
|
return empty;
|
||||||
oop name = field_name_or_null(fd.name());
|
}
|
||||||
bool is_setter = (ref_kind_is_valid(ref_kind) && ref_kind_is_setter(ref_kind));
|
}
|
||||||
mname = Handle(THREAD,
|
oop mname2 = init_field_MemberName(mname, result, ref_kind_is_setter(ref_kind));
|
||||||
init_field_MemberName(mname, sel_klass,
|
return Handle(THREAD, mname2);
|
||||||
fd.access_flags(), type, name, fd.offset(), is_setter));
|
|
||||||
return mname;
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
THROW_MSG_(vmSymbols::java_lang_InternalError(), "unrecognized MemberName format", empty);
|
THROW_MSG_(vmSymbols::java_lang_InternalError(), "unrecognized MemberName format", empty);
|
||||||
|
@ -793,7 +743,6 @@ void MethodHandles::expand_MemberName(Handle mname, int suppress, TRAPS) {
|
||||||
}
|
}
|
||||||
case IS_FIELD:
|
case IS_FIELD:
|
||||||
{
|
{
|
||||||
// This is taken from LinkResolver::resolve_field, sans access checks.
|
|
||||||
assert(vmtarget->is_klass(), "field vmtarget is Klass*");
|
assert(vmtarget->is_klass(), "field vmtarget is Klass*");
|
||||||
if (!((Klass*) vmtarget)->oop_is_instance()) break;
|
if (!((Klass*) vmtarget)->oop_is_instance()) break;
|
||||||
instanceKlassHandle defc(THREAD, (Klass*) vmtarget);
|
instanceKlassHandle defc(THREAD, (Klass*) vmtarget);
|
||||||
|
@ -872,11 +821,7 @@ int MethodHandles::find_MemberNames(KlassHandle k,
|
||||||
Handle result(thread, results->obj_at(rfill++));
|
Handle result(thread, results->obj_at(rfill++));
|
||||||
if (!java_lang_invoke_MemberName::is_instance(result()))
|
if (!java_lang_invoke_MemberName::is_instance(result()))
|
||||||
return -99; // caller bug!
|
return -99; // caller bug!
|
||||||
oop type = field_signature_type_or_null(st.signature());
|
oop saved = MethodHandles::init_field_MemberName(result, st.field_descriptor());
|
||||||
oop name = field_name_or_null(st.name());
|
|
||||||
oop saved = MethodHandles::init_field_MemberName(result, st.klass(),
|
|
||||||
st.access_flags(), type, name,
|
|
||||||
st.offset());
|
|
||||||
if (saved != result())
|
if (saved != result())
|
||||||
results->obj_at_put(rfill-1, saved); // show saved instance to user
|
results->obj_at_put(rfill-1, saved); // show saved instance to user
|
||||||
} else if (++overflow >= overflow_limit) {
|
} else if (++overflow >= overflow_limit) {
|
||||||
|
@ -926,7 +871,8 @@ int MethodHandles::find_MemberNames(KlassHandle k,
|
||||||
Handle result(thread, results->obj_at(rfill++));
|
Handle result(thread, results->obj_at(rfill++));
|
||||||
if (!java_lang_invoke_MemberName::is_instance(result()))
|
if (!java_lang_invoke_MemberName::is_instance(result()))
|
||||||
return -99; // caller bug!
|
return -99; // caller bug!
|
||||||
oop saved = MethodHandles::init_method_MemberName(result, m, true, NULL);
|
CallInfo info(m);
|
||||||
|
oop saved = MethodHandles::init_method_MemberName(result, info);
|
||||||
if (saved != result())
|
if (saved != result())
|
||||||
results->obj_at_put(rfill-1, saved); // show saved instance to user
|
results->obj_at_put(rfill-1, saved); // show saved instance to user
|
||||||
} else if (++overflow >= overflow_limit) {
|
} else if (++overflow >= overflow_limit) {
|
||||||
|
@ -1227,7 +1173,8 @@ JVM_ENTRY(jobject, MHN_getMemberVMInfo(JNIEnv *env, jobject igcls, jobject mname
|
||||||
x = ((Klass*) vmtarget)->java_mirror();
|
x = ((Klass*) vmtarget)->java_mirror();
|
||||||
} else if (vmtarget->is_method()) {
|
} else if (vmtarget->is_method()) {
|
||||||
Handle mname2 = MethodHandles::new_MemberName(CHECK_NULL);
|
Handle mname2 = MethodHandles::new_MemberName(CHECK_NULL);
|
||||||
x = MethodHandles::init_method_MemberName(mname2, (Method*)vmtarget, false, NULL);
|
CallInfo info((Method*)vmtarget);
|
||||||
|
x = MethodHandles::init_method_MemberName(mname2, info);
|
||||||
}
|
}
|
||||||
result->obj_at_put(1, x);
|
result->obj_at_put(1, x);
|
||||||
return JNIHandles::make_local(env, result());
|
return JNIHandles::make_local(env, result());
|
||||||
|
|
|
@ -49,19 +49,18 @@ class MethodHandles: AllStatic {
|
||||||
// Adapters.
|
// Adapters.
|
||||||
static MethodHandlesAdapterBlob* _adapter_code;
|
static MethodHandlesAdapterBlob* _adapter_code;
|
||||||
|
|
||||||
|
// utility functions for reifying names and types
|
||||||
|
static oop field_name_or_null(Symbol* s);
|
||||||
|
static oop field_signature_type_or_null(Symbol* s);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// working with member names
|
// working with member names
|
||||||
static Handle resolve_MemberName(Handle mname, TRAPS); // compute vmtarget/vmindex from name/type
|
static Handle resolve_MemberName(Handle mname, TRAPS); // compute vmtarget/vmindex from name/type
|
||||||
static void expand_MemberName(Handle mname, int suppress, TRAPS); // expand defc/name/type if missing
|
static void expand_MemberName(Handle mname, int suppress, TRAPS); // expand defc/name/type if missing
|
||||||
static Handle new_MemberName(TRAPS); // must be followed by init_MemberName
|
static Handle new_MemberName(TRAPS); // must be followed by init_MemberName
|
||||||
static oop init_MemberName(Handle mname_h, Handle target_h); // compute vmtarget/vmindex from target
|
static oop init_MemberName(Handle mname_h, Handle target_h); // compute vmtarget/vmindex from target
|
||||||
static oop init_method_MemberName(Handle mname_h, Method* m, bool do_dispatch,
|
static oop init_field_MemberName(Handle mname_h, fieldDescriptor& fd, bool is_setter = false);
|
||||||
KlassHandle receiver_limit_h);
|
static oop init_method_MemberName(Handle mname_h, CallInfo& info);
|
||||||
static oop init_field_MemberName(Handle mname_h, KlassHandle field_holder_h,
|
|
||||||
AccessFlags mods, oop type, oop name,
|
|
||||||
intptr_t offset, bool is_setter = false);
|
|
||||||
static Handle init_method_MemberName(Handle mname_h, CallInfo& info, TRAPS);
|
|
||||||
static Handle init_field_MemberName(Handle mname_h, FieldAccessInfo& info, TRAPS);
|
|
||||||
static int method_ref_kind(Method* m, bool do_dispatch_if_possible = true);
|
static int method_ref_kind(Method* m, bool do_dispatch_if_possible = true);
|
||||||
static int find_MemberNames(KlassHandle k, Symbol* name, Symbol* sig,
|
static int find_MemberNames(KlassHandle k, Symbol* name, Symbol* sig,
|
||||||
int mflags, KlassHandle caller,
|
int mflags, KlassHandle caller,
|
||||||
|
|
|
@ -3408,6 +3408,33 @@ static char* get_shared_archive_path() {
|
||||||
return shared_archive_path;
|
return shared_archive_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef PRODUCT
|
||||||
|
// Determine whether LogVMOutput should be implicitly turned on.
|
||||||
|
static bool use_vm_log() {
|
||||||
|
if (LogCompilation || !FLAG_IS_DEFAULT(LogFile) ||
|
||||||
|
PrintCompilation || PrintInlining || PrintDependencies || PrintNativeNMethods ||
|
||||||
|
PrintDebugInfo || PrintRelocations || PrintNMethods || PrintExceptionHandlers ||
|
||||||
|
PrintAssembly || TraceDeoptimization || TraceDependencies ||
|
||||||
|
(VerifyDependencies && FLAG_IS_CMDLINE(VerifyDependencies))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef COMPILER1
|
||||||
|
if (PrintC1Statistics) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif // COMPILER1
|
||||||
|
|
||||||
|
#ifdef COMPILER2
|
||||||
|
if (PrintOptoAssembly || PrintOptoStatistics) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif // COMPILER2
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif // PRODUCT
|
||||||
|
|
||||||
// Parse entry point called from JNI_CreateJavaVM
|
// Parse entry point called from JNI_CreateJavaVM
|
||||||
|
|
||||||
jint Arguments::parse(const JavaVMInitArgs* args) {
|
jint Arguments::parse(const JavaVMInitArgs* args) {
|
||||||
|
@ -3708,7 +3735,13 @@ jint Arguments::apply_ergo() {
|
||||||
NmethodSweepFraction = 1;
|
NmethodSweepFraction = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
if (!LogVMOutput && FLAG_IS_DEFAULT(LogVMOutput)) {
|
||||||
|
if (use_vm_log()) {
|
||||||
|
LogVMOutput = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // PRODUCT
|
||||||
|
|
||||||
if (PrintCommandLineFlags) {
|
if (PrintCommandLineFlags) {
|
||||||
CommandLineFlags::printSetFlags(tty);
|
CommandLineFlags::printSetFlags(tty);
|
||||||
|
|
|
@ -1751,7 +1751,7 @@ int Deoptimization::trap_state_set_recompiled(int trap_state, bool z) {
|
||||||
else return trap_state & ~DS_RECOMPILE_BIT;
|
else return trap_state & ~DS_RECOMPILE_BIT;
|
||||||
}
|
}
|
||||||
//---------------------------format_trap_state---------------------------------
|
//---------------------------format_trap_state---------------------------------
|
||||||
// This is used for debugging and diagnostics, including hotspot.log output.
|
// This is used for debugging and diagnostics, including LogFile output.
|
||||||
const char* Deoptimization::format_trap_state(char* buf, size_t buflen,
|
const char* Deoptimization::format_trap_state(char* buf, size_t buflen,
|
||||||
int trap_state) {
|
int trap_state) {
|
||||||
DeoptReason reason = trap_state_reason(trap_state);
|
DeoptReason reason = trap_state_reason(trap_state);
|
||||||
|
@ -1828,7 +1828,7 @@ const char* Deoptimization::trap_action_name(int action) {
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is used for debugging and diagnostics, including hotspot.log output.
|
// This is used for debugging and diagnostics, including LogFile output.
|
||||||
const char* Deoptimization::format_trap_request(char* buf, size_t buflen,
|
const char* Deoptimization::format_trap_request(char* buf, size_t buflen,
|
||||||
int trap_request) {
|
int trap_request) {
|
||||||
jint unloaded_class_index = trap_request_index(trap_request);
|
jint unloaded_class_index = trap_request_index(trap_request);
|
||||||
|
|
|
@ -97,18 +97,32 @@ oop fieldDescriptor::string_initial_value(TRAPS) const {
|
||||||
return constants()->uncached_string_at(initial_value_index(), CHECK_0);
|
return constants()->uncached_string_at(initial_value_index(), CHECK_0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fieldDescriptor::initialize(InstanceKlass* ik, int index) {
|
void fieldDescriptor::reinitialize(InstanceKlass* ik, int index) {
|
||||||
_cp = ik->constants();
|
if (_cp.is_null() || field_holder() != ik) {
|
||||||
|
_cp = constantPoolHandle(Thread::current(), ik->constants());
|
||||||
|
// _cp should now reference ik's constant pool; i.e., ik is now field_holder.
|
||||||
|
assert(field_holder() == ik, "must be already initialized to this class");
|
||||||
|
}
|
||||||
FieldInfo* f = ik->field(index);
|
FieldInfo* f = ik->field(index);
|
||||||
assert(!f->is_internal(), "regular Java fields only");
|
assert(!f->is_internal(), "regular Java fields only");
|
||||||
|
|
||||||
_access_flags = accessFlags_from(f->access_flags());
|
_access_flags = accessFlags_from(f->access_flags());
|
||||||
guarantee(f->name_index() != 0 && f->signature_index() != 0, "bad constant pool index for fieldDescriptor");
|
guarantee(f->name_index() != 0 && f->signature_index() != 0, "bad constant pool index for fieldDescriptor");
|
||||||
_index = index;
|
_index = index;
|
||||||
|
verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
|
|
||||||
|
void fieldDescriptor::verify() const {
|
||||||
|
if (_cp.is_null()) {
|
||||||
|
assert(_index == badInt, "constructor must be called"); // see constructor
|
||||||
|
} else {
|
||||||
|
assert(_index >= 0, "good index");
|
||||||
|
assert(_index < field_holder()->java_fields_count(), "oob");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void fieldDescriptor::print_on(outputStream* st) const {
|
void fieldDescriptor::print_on(outputStream* st) const {
|
||||||
access_flags().print_on(st);
|
access_flags().print_on(st);
|
||||||
name()->print_value_on(st);
|
name()->print_value_on(st);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2013, 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
|
||||||
|
@ -53,6 +53,13 @@ class fieldDescriptor VALUE_OBJ_CLASS_SPEC {
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
fieldDescriptor() {
|
||||||
|
DEBUG_ONLY(_index = badInt);
|
||||||
|
}
|
||||||
|
fieldDescriptor(InstanceKlass* ik, int index) {
|
||||||
|
DEBUG_ONLY(_index = badInt);
|
||||||
|
reinitialize(ik, index);
|
||||||
|
}
|
||||||
Symbol* name() const {
|
Symbol* name() const {
|
||||||
return field()->name(_cp);
|
return field()->name(_cp);
|
||||||
}
|
}
|
||||||
|
@ -112,12 +119,13 @@ class fieldDescriptor VALUE_OBJ_CLASS_SPEC {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
void initialize(InstanceKlass* ik, int index);
|
void reinitialize(InstanceKlass* ik, int index);
|
||||||
|
|
||||||
// Print
|
// Print
|
||||||
void print() { print_on(tty); }
|
void print() { print_on(tty); }
|
||||||
void print_on(outputStream* st) const PRODUCT_RETURN;
|
void print_on(outputStream* st) const PRODUCT_RETURN;
|
||||||
void print_on_for(outputStream* st, oop obj) PRODUCT_RETURN;
|
void print_on_for(outputStream* st, oop obj) PRODUCT_RETURN;
|
||||||
|
void verify() const PRODUCT_RETURN;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_VM_RUNTIME_FIELDDESCRIPTOR_HPP
|
#endif // SHARE_VM_RUNTIME_FIELDDESCRIPTOR_HPP
|
||||||
|
|
|
@ -880,7 +880,7 @@ class CommandLineFlags {
|
||||||
"stay alive at the expense of JVM performance") \
|
"stay alive at the expense of JVM performance") \
|
||||||
\
|
\
|
||||||
diagnostic(bool, LogCompilation, false, \
|
diagnostic(bool, LogCompilation, false, \
|
||||||
"Log compilation activity in detail to hotspot.log or LogFile") \
|
"Log compilation activity in detail to LogFile") \
|
||||||
\
|
\
|
||||||
product(bool, PrintCompilation, false, \
|
product(bool, PrintCompilation, false, \
|
||||||
"Print compilations") \
|
"Print compilations") \
|
||||||
|
@ -2498,16 +2498,17 @@ class CommandLineFlags {
|
||||||
"Print all VM flags with default values and descriptions and exit")\
|
"Print all VM flags with default values and descriptions and exit")\
|
||||||
\
|
\
|
||||||
diagnostic(bool, SerializeVMOutput, true, \
|
diagnostic(bool, SerializeVMOutput, true, \
|
||||||
"Use a mutex to serialize output to tty and hotspot.log") \
|
"Use a mutex to serialize output to tty and LogFile") \
|
||||||
\
|
\
|
||||||
diagnostic(bool, DisplayVMOutput, true, \
|
diagnostic(bool, DisplayVMOutput, true, \
|
||||||
"Display all VM output on the tty, independently of LogVMOutput") \
|
"Display all VM output on the tty, independently of LogVMOutput") \
|
||||||
\
|
\
|
||||||
diagnostic(bool, LogVMOutput, trueInDebug, \
|
diagnostic(bool, LogVMOutput, false, \
|
||||||
"Save VM output to hotspot.log, or to LogFile") \
|
"Save VM output to LogFile") \
|
||||||
\
|
\
|
||||||
diagnostic(ccstr, LogFile, NULL, \
|
diagnostic(ccstr, LogFile, NULL, \
|
||||||
"If LogVMOutput is on, save VM output to this file [hotspot.log]") \
|
"If LogVMOutput or LogCompilation is on, save VM output to " \
|
||||||
|
"this file [default: ./hotspot_pid%p.log] (%p replaced with pid)") \
|
||||||
\
|
\
|
||||||
product(ccstr, ErrorFile, NULL, \
|
product(ccstr, ErrorFile, NULL, \
|
||||||
"If an error occurs, save the error data to this file " \
|
"If an error occurs, save the error data to this file " \
|
||||||
|
|
|
@ -45,7 +45,6 @@ Mutex* InlineCacheBuffer_lock = NULL;
|
||||||
Mutex* VMStatistic_lock = NULL;
|
Mutex* VMStatistic_lock = NULL;
|
||||||
Mutex* JNIGlobalHandle_lock = NULL;
|
Mutex* JNIGlobalHandle_lock = NULL;
|
||||||
Mutex* JNIHandleBlockFreeList_lock = NULL;
|
Mutex* JNIHandleBlockFreeList_lock = NULL;
|
||||||
Mutex* JNICachedItableIndex_lock = NULL;
|
|
||||||
Mutex* MemberNameTable_lock = NULL;
|
Mutex* MemberNameTable_lock = NULL;
|
||||||
Mutex* JmethodIdCreation_lock = NULL;
|
Mutex* JmethodIdCreation_lock = NULL;
|
||||||
Mutex* JfieldIdCreation_lock = NULL;
|
Mutex* JfieldIdCreation_lock = NULL;
|
||||||
|
@ -253,7 +252,6 @@ void mutex_init() {
|
||||||
}
|
}
|
||||||
def(Heap_lock , Monitor, nonleaf+1, false);
|
def(Heap_lock , Monitor, nonleaf+1, false);
|
||||||
def(JfieldIdCreation_lock , Mutex , nonleaf+1, true ); // jfieldID, Used in VM_Operation
|
def(JfieldIdCreation_lock , Mutex , nonleaf+1, true ); // jfieldID, Used in VM_Operation
|
||||||
def(JNICachedItableIndex_lock , Mutex , nonleaf+1, false); // Used to cache an itable index during JNI invoke
|
|
||||||
def(MemberNameTable_lock , Mutex , nonleaf+1, false); // Used to protect MemberNameTable
|
def(MemberNameTable_lock , Mutex , nonleaf+1, false); // Used to protect MemberNameTable
|
||||||
|
|
||||||
def(CompiledIC_lock , Mutex , nonleaf+2, false); // locks VtableStubs_lock, InlineCacheBuffer_lock
|
def(CompiledIC_lock , Mutex , nonleaf+2, false); // locks VtableStubs_lock, InlineCacheBuffer_lock
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2013, 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
|
||||||
|
@ -50,7 +50,6 @@ extern Mutex* InlineCacheBuffer_lock; // a lock used to guard the Inl
|
||||||
extern Mutex* VMStatistic_lock; // a lock used to guard statistics count increment
|
extern Mutex* VMStatistic_lock; // a lock used to guard statistics count increment
|
||||||
extern Mutex* JNIGlobalHandle_lock; // a lock on creating JNI global handles
|
extern Mutex* JNIGlobalHandle_lock; // a lock on creating JNI global handles
|
||||||
extern Mutex* JNIHandleBlockFreeList_lock; // a lock on the JNI handle block free list
|
extern Mutex* JNIHandleBlockFreeList_lock; // a lock on the JNI handle block free list
|
||||||
extern Mutex* JNICachedItableIndex_lock; // a lock on caching an itable index during JNI invoke
|
|
||||||
extern Mutex* MemberNameTable_lock; // a lock on the MemberNameTable updates
|
extern Mutex* MemberNameTable_lock; // a lock on the MemberNameTable updates
|
||||||
extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers
|
extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers
|
||||||
extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers
|
extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers
|
||||||
|
|
|
@ -91,6 +91,8 @@ const bool ExecMem = true;
|
||||||
typedef void (*java_call_t)(JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread);
|
typedef void (*java_call_t)(JavaValue* value, methodHandle* method, JavaCallArguments* args, Thread* thread);
|
||||||
|
|
||||||
class os: AllStatic {
|
class os: AllStatic {
|
||||||
|
friend class VMStructs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum { page_sizes_max = 9 }; // Size of _page_sizes array (8 plus a sentinel)
|
enum { page_sizes_max = 9 }; // Size of _page_sizes array (8 plus a sentinel)
|
||||||
|
|
||||||
|
|
|
@ -952,7 +952,8 @@ oop Reflection::invoke(instanceKlassHandle klass, methodHandle reflected_method,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if the method can be overridden, we resolve using the vtable index.
|
// if the method can be overridden, we resolve using the vtable index.
|
||||||
int index = reflected_method->vtable_index();
|
assert(!reflected_method->has_itable_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
|
// target_klass might be an arrayKlassOop but all vtables start at
|
||||||
|
|
|
@ -109,6 +109,8 @@ class FieldStream : public KlassStream {
|
||||||
private:
|
private:
|
||||||
int length() const { return _klass->java_fields_count(); }
|
int length() const { return _klass->java_fields_count(); }
|
||||||
|
|
||||||
|
fieldDescriptor _fd_buf;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FieldStream(instanceKlassHandle klass, bool local_only, bool classes_only)
|
FieldStream(instanceKlassHandle klass, bool local_only, bool classes_only)
|
||||||
: KlassStream(klass, local_only, classes_only) {
|
: KlassStream(klass, local_only, classes_only) {
|
||||||
|
@ -134,6 +136,12 @@ class FieldStream : public KlassStream {
|
||||||
int offset() const {
|
int offset() const {
|
||||||
return _klass->field_offset( index() );
|
return _klass->field_offset( index() );
|
||||||
}
|
}
|
||||||
|
// bridge to a heavier API:
|
||||||
|
fieldDescriptor& field_descriptor() const {
|
||||||
|
fieldDescriptor& field = const_cast<fieldDescriptor&>(_fd_buf);
|
||||||
|
field.reinitialize(_klass(), _index);
|
||||||
|
return field;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class FilteredField : public CHeapObj<mtInternal> {
|
class FilteredField : public CHeapObj<mtInternal> {
|
||||||
|
|
|
@ -269,6 +269,7 @@ void NMethodSweeper::sweep_code_cache() {
|
||||||
// the number of nmethods changes during the sweep so the final
|
// the number of nmethods changes during the sweep so the final
|
||||||
// stage must iterate until it there are no more nmethods.
|
// stage must iterate until it there are no more nmethods.
|
||||||
int todo = (CodeCache::nof_nmethods() - _seen) / _invocations;
|
int todo = (CodeCache::nof_nmethods() - _seen) / _invocations;
|
||||||
|
int swept_count = 0;
|
||||||
|
|
||||||
assert(!SafepointSynchronize::is_at_safepoint(), "should not be in safepoint when we get here");
|
assert(!SafepointSynchronize::is_at_safepoint(), "should not be in safepoint when we get here");
|
||||||
assert(!CodeCache_lock->owned_by_self(), "just checking");
|
assert(!CodeCache_lock->owned_by_self(), "just checking");
|
||||||
|
@ -278,6 +279,7 @@ void NMethodSweeper::sweep_code_cache() {
|
||||||
|
|
||||||
// The last invocation iterates until there are no more nmethods
|
// The last invocation iterates until there are no more nmethods
|
||||||
for (int i = 0; (i < todo || _invocations == 1) && _current != NULL; i++) {
|
for (int i = 0; (i < todo || _invocations == 1) && _current != NULL; i++) {
|
||||||
|
swept_count++;
|
||||||
if (SafepointSynchronize::is_synchronizing()) { // Safepoint request
|
if (SafepointSynchronize::is_synchronizing()) { // Safepoint request
|
||||||
if (PrintMethodFlushing && Verbose) {
|
if (PrintMethodFlushing && Verbose) {
|
||||||
tty->print_cr("### Sweep at %d out of %d, invocation: %d, yielding to safepoint", _seen, CodeCache::nof_nmethods(), _invocations);
|
tty->print_cr("### Sweep at %d out of %d, invocation: %d, yielding to safepoint", _seen, CodeCache::nof_nmethods(), _invocations);
|
||||||
|
@ -331,7 +333,7 @@ void NMethodSweeper::sweep_code_cache() {
|
||||||
event.set_endtime(sweep_end_counter);
|
event.set_endtime(sweep_end_counter);
|
||||||
event.set_sweepIndex(_traversals);
|
event.set_sweepIndex(_traversals);
|
||||||
event.set_sweepFractionIndex(NmethodSweepFraction - _invocations + 1);
|
event.set_sweepFractionIndex(NmethodSweepFraction - _invocations + 1);
|
||||||
event.set_sweptCount(todo);
|
event.set_sweptCount(swept_count);
|
||||||
event.set_flushedCount(_flushed_count);
|
event.set_flushedCount(_flushed_count);
|
||||||
event.set_markedCount(_marked_count);
|
event.set_markedCount(_marked_count);
|
||||||
event.set_zombifiedCount(_zombified_count);
|
event.set_zombifiedCount(_zombified_count);
|
||||||
|
|
|
@ -315,7 +315,6 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
nonstatic_field(InstanceKlass, _breakpoints, BreakpointInfo*) \
|
nonstatic_field(InstanceKlass, _breakpoints, BreakpointInfo*) \
|
||||||
nonstatic_field(InstanceKlass, _generic_signature_index, u2) \
|
nonstatic_field(InstanceKlass, _generic_signature_index, u2) \
|
||||||
nonstatic_field(InstanceKlass, _methods_jmethod_ids, jmethodID*) \
|
nonstatic_field(InstanceKlass, _methods_jmethod_ids, jmethodID*) \
|
||||||
nonstatic_field(InstanceKlass, _methods_cached_itable_indices, int*) \
|
|
||||||
volatile_nonstatic_field(InstanceKlass, _idnum_allocated_count, u2) \
|
volatile_nonstatic_field(InstanceKlass, _idnum_allocated_count, u2) \
|
||||||
nonstatic_field(InstanceKlass, _annotations, Annotations*) \
|
nonstatic_field(InstanceKlass, _annotations, Annotations*) \
|
||||||
nonstatic_field(InstanceKlass, _dependencies, nmethodBucket*) \
|
nonstatic_field(InstanceKlass, _dependencies, nmethodBucket*) \
|
||||||
|
@ -330,11 +329,13 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
nonstatic_field(Klass, _java_mirror, oop) \
|
nonstatic_field(Klass, _java_mirror, oop) \
|
||||||
nonstatic_field(Klass, _modifier_flags, jint) \
|
nonstatic_field(Klass, _modifier_flags, jint) \
|
||||||
nonstatic_field(Klass, _super, Klass*) \
|
nonstatic_field(Klass, _super, Klass*) \
|
||||||
|
nonstatic_field(Klass, _subklass, Klass*) \
|
||||||
nonstatic_field(Klass, _layout_helper, jint) \
|
nonstatic_field(Klass, _layout_helper, jint) \
|
||||||
nonstatic_field(Klass, _name, Symbol*) \
|
nonstatic_field(Klass, _name, Symbol*) \
|
||||||
nonstatic_field(Klass, _access_flags, AccessFlags) \
|
nonstatic_field(Klass, _access_flags, AccessFlags) \
|
||||||
nonstatic_field(Klass, _subklass, Klass*) \
|
nonstatic_field(Klass, _prototype_header, markOop) \
|
||||||
nonstatic_field(Klass, _next_sibling, Klass*) \
|
nonstatic_field(Klass, _next_sibling, Klass*) \
|
||||||
|
nonstatic_field(vtableEntry, _method, Method*) \
|
||||||
nonstatic_field(MethodData, _size, int) \
|
nonstatic_field(MethodData, _size, int) \
|
||||||
nonstatic_field(MethodData, _method, Method*) \
|
nonstatic_field(MethodData, _method, Method*) \
|
||||||
nonstatic_field(MethodData, _data_size, int) \
|
nonstatic_field(MethodData, _data_size, int) \
|
||||||
|
@ -342,10 +343,15 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
nonstatic_field(MethodData, _nof_decompiles, uint) \
|
nonstatic_field(MethodData, _nof_decompiles, uint) \
|
||||||
nonstatic_field(MethodData, _nof_overflow_recompiles, uint) \
|
nonstatic_field(MethodData, _nof_overflow_recompiles, uint) \
|
||||||
nonstatic_field(MethodData, _nof_overflow_traps, uint) \
|
nonstatic_field(MethodData, _nof_overflow_traps, uint) \
|
||||||
|
nonstatic_field(MethodData, _trap_hist._array[0], u1) \
|
||||||
nonstatic_field(MethodData, _eflags, intx) \
|
nonstatic_field(MethodData, _eflags, intx) \
|
||||||
nonstatic_field(MethodData, _arg_local, intx) \
|
nonstatic_field(MethodData, _arg_local, intx) \
|
||||||
nonstatic_field(MethodData, _arg_stack, intx) \
|
nonstatic_field(MethodData, _arg_stack, intx) \
|
||||||
nonstatic_field(MethodData, _arg_returned, intx) \
|
nonstatic_field(MethodData, _arg_returned, intx) \
|
||||||
|
nonstatic_field(DataLayout, _header._struct._tag, u1) \
|
||||||
|
nonstatic_field(DataLayout, _header._struct._flags, u1) \
|
||||||
|
nonstatic_field(DataLayout, _header._struct._bci, u2) \
|
||||||
|
nonstatic_field(DataLayout, _cells[0], intptr_t) \
|
||||||
nonstatic_field(MethodCounters, _interpreter_invocation_count, int) \
|
nonstatic_field(MethodCounters, _interpreter_invocation_count, int) \
|
||||||
nonstatic_field(MethodCounters, _interpreter_throwout_count, u2) \
|
nonstatic_field(MethodCounters, _interpreter_throwout_count, u2) \
|
||||||
nonstatic_field(MethodCounters, _number_of_breakpoints, u2) \
|
nonstatic_field(MethodCounters, _number_of_breakpoints, u2) \
|
||||||
|
@ -357,6 +363,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
nonstatic_field(Method, _access_flags, AccessFlags) \
|
nonstatic_field(Method, _access_flags, AccessFlags) \
|
||||||
nonstatic_field(Method, _vtable_index, int) \
|
nonstatic_field(Method, _vtable_index, int) \
|
||||||
nonstatic_field(Method, _method_size, u2) \
|
nonstatic_field(Method, _method_size, u2) \
|
||||||
|
nonstatic_field(Method, _intrinsic_id, u1) \
|
||||||
nonproduct_nonstatic_field(Method, _compiled_invocation_count, int) \
|
nonproduct_nonstatic_field(Method, _compiled_invocation_count, int) \
|
||||||
volatile_nonstatic_field(Method, _code, nmethod*) \
|
volatile_nonstatic_field(Method, _code, nmethod*) \
|
||||||
nonstatic_field(Method, _i2i_entry, address) \
|
nonstatic_field(Method, _i2i_entry, address) \
|
||||||
|
@ -443,12 +450,19 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
static_field(Universe, _bootstrapping, bool) \
|
static_field(Universe, _bootstrapping, bool) \
|
||||||
static_field(Universe, _fully_initialized, bool) \
|
static_field(Universe, _fully_initialized, bool) \
|
||||||
static_field(Universe, _verify_count, int) \
|
static_field(Universe, _verify_count, int) \
|
||||||
|
static_field(Universe, _non_oop_bits, intptr_t) \
|
||||||
static_field(Universe, _narrow_oop._base, address) \
|
static_field(Universe, _narrow_oop._base, address) \
|
||||||
static_field(Universe, _narrow_oop._shift, int) \
|
static_field(Universe, _narrow_oop._shift, int) \
|
||||||
static_field(Universe, _narrow_oop._use_implicit_null_checks, bool) \
|
static_field(Universe, _narrow_oop._use_implicit_null_checks, bool) \
|
||||||
static_field(Universe, _narrow_klass._base, address) \
|
static_field(Universe, _narrow_klass._base, address) \
|
||||||
static_field(Universe, _narrow_klass._shift, int) \
|
static_field(Universe, _narrow_klass._shift, int) \
|
||||||
\
|
\
|
||||||
|
/******/ \
|
||||||
|
/* os */ \
|
||||||
|
/******/ \
|
||||||
|
\
|
||||||
|
static_field(os, _polling_page, address) \
|
||||||
|
\
|
||||||
/**********************************************************************************/ \
|
/**********************************************************************************/ \
|
||||||
/* Generation and Space hierarchies */ \
|
/* Generation and Space hierarchies */ \
|
||||||
/**********************************************************************************/ \
|
/**********************************************************************************/ \
|
||||||
|
@ -456,6 +470,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
unchecked_nonstatic_field(ageTable, sizes, sizeof(ageTable::sizes)) \
|
unchecked_nonstatic_field(ageTable, sizes, sizeof(ageTable::sizes)) \
|
||||||
\
|
\
|
||||||
nonstatic_field(BarrierSet, _max_covered_regions, int) \
|
nonstatic_field(BarrierSet, _max_covered_regions, int) \
|
||||||
|
nonstatic_field(BarrierSet, _kind, BarrierSet::Name) \
|
||||||
nonstatic_field(BlockOffsetTable, _bottom, HeapWord*) \
|
nonstatic_field(BlockOffsetTable, _bottom, HeapWord*) \
|
||||||
nonstatic_field(BlockOffsetTable, _end, HeapWord*) \
|
nonstatic_field(BlockOffsetTable, _end, HeapWord*) \
|
||||||
\
|
\
|
||||||
|
@ -495,6 +510,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
nonstatic_field(CollectedHeap, _barrier_set, BarrierSet*) \
|
nonstatic_field(CollectedHeap, _barrier_set, BarrierSet*) \
|
||||||
nonstatic_field(CollectedHeap, _defer_initial_card_mark, bool) \
|
nonstatic_field(CollectedHeap, _defer_initial_card_mark, bool) \
|
||||||
nonstatic_field(CollectedHeap, _is_gc_active, bool) \
|
nonstatic_field(CollectedHeap, _is_gc_active, bool) \
|
||||||
|
nonstatic_field(CollectedHeap, _total_collections, unsigned int) \
|
||||||
nonstatic_field(CompactibleSpace, _compaction_top, HeapWord*) \
|
nonstatic_field(CompactibleSpace, _compaction_top, HeapWord*) \
|
||||||
nonstatic_field(CompactibleSpace, _first_dead, HeapWord*) \
|
nonstatic_field(CompactibleSpace, _first_dead, HeapWord*) \
|
||||||
nonstatic_field(CompactibleSpace, _end_of_live, HeapWord*) \
|
nonstatic_field(CompactibleSpace, _end_of_live, HeapWord*) \
|
||||||
|
@ -505,7 +521,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
nonstatic_field(ContiguousSpace, _saved_mark_word, HeapWord*) \
|
nonstatic_field(ContiguousSpace, _saved_mark_word, HeapWord*) \
|
||||||
\
|
\
|
||||||
nonstatic_field(DefNewGeneration, _next_gen, Generation*) \
|
nonstatic_field(DefNewGeneration, _next_gen, Generation*) \
|
||||||
nonstatic_field(DefNewGeneration, _tenuring_threshold, uint) \
|
nonstatic_field(DefNewGeneration, _tenuring_threshold, uint) \
|
||||||
nonstatic_field(DefNewGeneration, _age_table, ageTable) \
|
nonstatic_field(DefNewGeneration, _age_table, ageTable) \
|
||||||
nonstatic_field(DefNewGeneration, _eden_space, EdenSpace*) \
|
nonstatic_field(DefNewGeneration, _eden_space, EdenSpace*) \
|
||||||
nonstatic_field(DefNewGeneration, _from_space, ContiguousSpace*) \
|
nonstatic_field(DefNewGeneration, _from_space, ContiguousSpace*) \
|
||||||
|
@ -552,6 +568,11 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
nonstatic_field(ThreadLocalAllocBuffer, _desired_size, size_t) \
|
nonstatic_field(ThreadLocalAllocBuffer, _desired_size, size_t) \
|
||||||
nonstatic_field(ThreadLocalAllocBuffer, _refill_waste_limit, size_t) \
|
nonstatic_field(ThreadLocalAllocBuffer, _refill_waste_limit, size_t) \
|
||||||
static_field(ThreadLocalAllocBuffer, _target_refills, unsigned) \
|
static_field(ThreadLocalAllocBuffer, _target_refills, unsigned) \
|
||||||
|
nonstatic_field(ThreadLocalAllocBuffer, _number_of_refills, unsigned) \
|
||||||
|
nonstatic_field(ThreadLocalAllocBuffer, _fast_refill_waste, unsigned) \
|
||||||
|
nonstatic_field(ThreadLocalAllocBuffer, _slow_refill_waste, unsigned) \
|
||||||
|
nonstatic_field(ThreadLocalAllocBuffer, _gc_waste, unsigned) \
|
||||||
|
nonstatic_field(ThreadLocalAllocBuffer, _slow_allocations, unsigned) \
|
||||||
nonstatic_field(VirtualSpace, _low_boundary, char*) \
|
nonstatic_field(VirtualSpace, _low_boundary, char*) \
|
||||||
nonstatic_field(VirtualSpace, _high_boundary, char*) \
|
nonstatic_field(VirtualSpace, _high_boundary, char*) \
|
||||||
nonstatic_field(VirtualSpace, _low, char*) \
|
nonstatic_field(VirtualSpace, _low, char*) \
|
||||||
|
@ -713,6 +734,13 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
\
|
\
|
||||||
static_field(ClassLoaderDataGraph, _head, ClassLoaderData*) \
|
static_field(ClassLoaderDataGraph, _head, ClassLoaderData*) \
|
||||||
\
|
\
|
||||||
|
/**********/ \
|
||||||
|
/* Arrays */ \
|
||||||
|
/**********/ \
|
||||||
|
\
|
||||||
|
nonstatic_field(Array<Klass*>, _length, int) \
|
||||||
|
nonstatic_field(Array<Klass*>, _data[0], Klass*) \
|
||||||
|
\
|
||||||
/*******************/ \
|
/*******************/ \
|
||||||
/* GrowableArrays */ \
|
/* GrowableArrays */ \
|
||||||
/*******************/ \
|
/*******************/ \
|
||||||
|
@ -720,7 +748,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
nonstatic_field(GenericGrowableArray, _len, int) \
|
nonstatic_field(GenericGrowableArray, _len, int) \
|
||||||
nonstatic_field(GenericGrowableArray, _max, int) \
|
nonstatic_field(GenericGrowableArray, _max, int) \
|
||||||
nonstatic_field(GenericGrowableArray, _arena, Arena*) \
|
nonstatic_field(GenericGrowableArray, _arena, Arena*) \
|
||||||
nonstatic_field(GrowableArray<int>, _data, int*) \
|
nonstatic_field(GrowableArray<int>, _data, int*) \
|
||||||
\
|
\
|
||||||
/********************************/ \
|
/********************************/ \
|
||||||
/* CodeCache (NOTE: incomplete) */ \
|
/* CodeCache (NOTE: incomplete) */ \
|
||||||
|
@ -763,7 +791,20 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
/* StubRoutines (NOTE: incomplete) */ \
|
/* StubRoutines (NOTE: incomplete) */ \
|
||||||
/***********************************/ \
|
/***********************************/ \
|
||||||
\
|
\
|
||||||
|
static_field(StubRoutines, _verify_oop_count, jint) \
|
||||||
static_field(StubRoutines, _call_stub_return_address, address) \
|
static_field(StubRoutines, _call_stub_return_address, address) \
|
||||||
|
static_field(StubRoutines, _aescrypt_encryptBlock, address) \
|
||||||
|
static_field(StubRoutines, _aescrypt_decryptBlock, address) \
|
||||||
|
static_field(StubRoutines, _cipherBlockChaining_encryptAESCrypt, address) \
|
||||||
|
static_field(StubRoutines, _cipherBlockChaining_decryptAESCrypt, address) \
|
||||||
|
static_field(StubRoutines, _updateBytesCRC32, address) \
|
||||||
|
static_field(StubRoutines, _crc_table_adr, address) \
|
||||||
|
\
|
||||||
|
/*****************/ \
|
||||||
|
/* SharedRuntime */ \
|
||||||
|
/*****************/ \
|
||||||
|
\
|
||||||
|
static_field(SharedRuntime, _ic_miss_blob, RuntimeStub*) \
|
||||||
\
|
\
|
||||||
/***************************************/ \
|
/***************************************/ \
|
||||||
/* PcDesc and other compiled code info */ \
|
/* PcDesc and other compiled code info */ \
|
||||||
|
@ -853,6 +894,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
volatile_nonstatic_field(Thread, _suspend_flags, uint32_t) \
|
volatile_nonstatic_field(Thread, _suspend_flags, uint32_t) \
|
||||||
nonstatic_field(Thread, _active_handles, JNIHandleBlock*) \
|
nonstatic_field(Thread, _active_handles, JNIHandleBlock*) \
|
||||||
nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \
|
nonstatic_field(Thread, _tlab, ThreadLocalAllocBuffer) \
|
||||||
|
nonstatic_field(Thread, _allocated_bytes, jlong) \
|
||||||
nonstatic_field(Thread, _current_pending_monitor, ObjectMonitor*) \
|
nonstatic_field(Thread, _current_pending_monitor, ObjectMonitor*) \
|
||||||
nonstatic_field(Thread, _current_pending_monitor_is_from_java, bool) \
|
nonstatic_field(Thread, _current_pending_monitor_is_from_java, bool) \
|
||||||
nonstatic_field(Thread, _current_waiting_monitor, ObjectMonitor*) \
|
nonstatic_field(Thread, _current_waiting_monitor, ObjectMonitor*) \
|
||||||
|
@ -866,6 +908,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
nonstatic_field(JavaThread, _pending_async_exception, oop) \
|
nonstatic_field(JavaThread, _pending_async_exception, oop) \
|
||||||
volatile_nonstatic_field(JavaThread, _exception_oop, oop) \
|
volatile_nonstatic_field(JavaThread, _exception_oop, oop) \
|
||||||
volatile_nonstatic_field(JavaThread, _exception_pc, address) \
|
volatile_nonstatic_field(JavaThread, _exception_pc, address) \
|
||||||
|
volatile_nonstatic_field(JavaThread, _is_method_handle_return, int) \
|
||||||
nonstatic_field(JavaThread, _is_compiling, bool) \
|
nonstatic_field(JavaThread, _is_compiling, bool) \
|
||||||
nonstatic_field(JavaThread, _special_runtime_exit_condition, JavaThread::AsyncRequests) \
|
nonstatic_field(JavaThread, _special_runtime_exit_condition, JavaThread::AsyncRequests) \
|
||||||
nonstatic_field(JavaThread, _saved_exception_pc, address) \
|
nonstatic_field(JavaThread, _saved_exception_pc, address) \
|
||||||
|
@ -875,6 +918,8 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
nonstatic_field(JavaThread, _stack_size, size_t) \
|
nonstatic_field(JavaThread, _stack_size, size_t) \
|
||||||
nonstatic_field(JavaThread, _vframe_array_head, vframeArray*) \
|
nonstatic_field(JavaThread, _vframe_array_head, vframeArray*) \
|
||||||
nonstatic_field(JavaThread, _vframe_array_last, vframeArray*) \
|
nonstatic_field(JavaThread, _vframe_array_last, vframeArray*) \
|
||||||
|
nonstatic_field(JavaThread, _satb_mark_queue, ObjPtrQueue) \
|
||||||
|
nonstatic_field(JavaThread, _dirty_card_queue, DirtyCardQueue) \
|
||||||
nonstatic_field(Thread, _resource_area, ResourceArea*) \
|
nonstatic_field(Thread, _resource_area, ResourceArea*) \
|
||||||
nonstatic_field(CompilerThread, _env, ciEnv*) \
|
nonstatic_field(CompilerThread, _env, ciEnv*) \
|
||||||
\
|
\
|
||||||
|
@ -1187,7 +1232,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
unchecked_nonstatic_field(Array<int>, _data, sizeof(int)) \
|
unchecked_nonstatic_field(Array<int>, _data, sizeof(int)) \
|
||||||
unchecked_nonstatic_field(Array<u1>, _data, sizeof(u1)) \
|
unchecked_nonstatic_field(Array<u1>, _data, sizeof(u1)) \
|
||||||
unchecked_nonstatic_field(Array<u2>, _data, sizeof(u2)) \
|
unchecked_nonstatic_field(Array<u2>, _data, sizeof(u2)) \
|
||||||
unchecked_nonstatic_field(Array<Method*>, _data, sizeof(Method*)) \
|
unchecked_nonstatic_field(Array<Method*>, _data, sizeof(Method*)) \
|
||||||
unchecked_nonstatic_field(Array<Klass*>, _data, sizeof(Klass*)) \
|
unchecked_nonstatic_field(Array<Klass*>, _data, sizeof(Klass*)) \
|
||||||
\
|
\
|
||||||
/*********************************/ \
|
/*********************************/ \
|
||||||
|
@ -1203,7 +1248,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
/* Miscellaneous fields */ \
|
/* Miscellaneous fields */ \
|
||||||
/************************/ \
|
/************************/ \
|
||||||
\
|
\
|
||||||
nonstatic_field(CompileTask, _method, Method*) \
|
nonstatic_field(CompileTask, _method, Method*) \
|
||||||
nonstatic_field(CompileTask, _osr_bci, int) \
|
nonstatic_field(CompileTask, _osr_bci, int) \
|
||||||
nonstatic_field(CompileTask, _comp_level, int) \
|
nonstatic_field(CompileTask, _comp_level, int) \
|
||||||
nonstatic_field(CompileTask, _compile_id, uint) \
|
nonstatic_field(CompileTask, _compile_id, uint) \
|
||||||
|
@ -1217,7 +1262,11 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
\
|
\
|
||||||
nonstatic_field(vframeArrayElement, _frame, frame) \
|
nonstatic_field(vframeArrayElement, _frame, frame) \
|
||||||
nonstatic_field(vframeArrayElement, _bci, int) \
|
nonstatic_field(vframeArrayElement, _bci, int) \
|
||||||
nonstatic_field(vframeArrayElement, _method, Method*) \
|
nonstatic_field(vframeArrayElement, _method, Method*) \
|
||||||
|
\
|
||||||
|
nonstatic_field(PtrQueue, _active, bool) \
|
||||||
|
nonstatic_field(PtrQueue, _buf, void**) \
|
||||||
|
nonstatic_field(PtrQueue, _index, size_t) \
|
||||||
\
|
\
|
||||||
nonstatic_field(AccessFlags, _flags, jint) \
|
nonstatic_field(AccessFlags, _flags, jint) \
|
||||||
nonstatic_field(elapsedTimer, _counter, jlong) \
|
nonstatic_field(elapsedTimer, _counter, jlong) \
|
||||||
|
@ -1363,7 +1412,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
/* MetadataOopDesc hierarchy (NOTE: some missing) */ \
|
/* MetadataOopDesc hierarchy (NOTE: some missing) */ \
|
||||||
/**************************************************/ \
|
/**************************************************/ \
|
||||||
\
|
\
|
||||||
declare_toplevel_type(CompiledICHolder) \
|
declare_toplevel_type(CompiledICHolder) \
|
||||||
declare_toplevel_type(MetaspaceObj) \
|
declare_toplevel_type(MetaspaceObj) \
|
||||||
declare_type(Metadata, MetaspaceObj) \
|
declare_type(Metadata, MetaspaceObj) \
|
||||||
declare_type(Klass, Metadata) \
|
declare_type(Klass, Metadata) \
|
||||||
|
@ -1374,17 +1423,20 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
declare_type(InstanceClassLoaderKlass, InstanceKlass) \
|
declare_type(InstanceClassLoaderKlass, InstanceKlass) \
|
||||||
declare_type(InstanceMirrorKlass, InstanceKlass) \
|
declare_type(InstanceMirrorKlass, InstanceKlass) \
|
||||||
declare_type(InstanceRefKlass, InstanceKlass) \
|
declare_type(InstanceRefKlass, InstanceKlass) \
|
||||||
declare_type(ConstantPool, Metadata) \
|
declare_type(ConstantPool, Metadata) \
|
||||||
declare_type(ConstantPoolCache, MetaspaceObj) \
|
declare_type(ConstantPoolCache, MetaspaceObj) \
|
||||||
declare_type(MethodData, Metadata) \
|
declare_type(MethodData, Metadata) \
|
||||||
declare_type(Method, Metadata) \
|
declare_type(Method, Metadata) \
|
||||||
declare_type(MethodCounters, MetaspaceObj) \
|
declare_type(MethodCounters, MetaspaceObj) \
|
||||||
declare_type(ConstMethod, MetaspaceObj) \
|
declare_type(ConstMethod, MetaspaceObj) \
|
||||||
|
\
|
||||||
|
declare_toplevel_type(vtableEntry) \
|
||||||
\
|
\
|
||||||
declare_toplevel_type(Symbol) \
|
declare_toplevel_type(Symbol) \
|
||||||
declare_toplevel_type(Symbol*) \
|
declare_toplevel_type(Symbol*) \
|
||||||
declare_toplevel_type(volatile Metadata*) \
|
declare_toplevel_type(volatile Metadata*) \
|
||||||
\
|
\
|
||||||
|
declare_toplevel_type(DataLayout) \
|
||||||
declare_toplevel_type(nmethodBucket) \
|
declare_toplevel_type(nmethodBucket) \
|
||||||
\
|
\
|
||||||
/********/ \
|
/********/ \
|
||||||
|
@ -1432,6 +1484,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
declare_type(ModRefBarrierSet, BarrierSet) \
|
declare_type(ModRefBarrierSet, BarrierSet) \
|
||||||
declare_type(CardTableModRefBS, ModRefBarrierSet) \
|
declare_type(CardTableModRefBS, ModRefBarrierSet) \
|
||||||
declare_type(CardTableModRefBSForCTRS, CardTableModRefBS) \
|
declare_type(CardTableModRefBSForCTRS, CardTableModRefBS) \
|
||||||
|
declare_toplevel_type(BarrierSet::Name) \
|
||||||
declare_toplevel_type(GenRemSet) \
|
declare_toplevel_type(GenRemSet) \
|
||||||
declare_type(CardTableRS, GenRemSet) \
|
declare_type(CardTableRS, GenRemSet) \
|
||||||
declare_toplevel_type(BlockOffsetSharedArray) \
|
declare_toplevel_type(BlockOffsetSharedArray) \
|
||||||
|
@ -1450,6 +1503,8 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
declare_toplevel_type(ThreadLocalAllocBuffer) \
|
declare_toplevel_type(ThreadLocalAllocBuffer) \
|
||||||
declare_toplevel_type(VirtualSpace) \
|
declare_toplevel_type(VirtualSpace) \
|
||||||
declare_toplevel_type(WaterMark) \
|
declare_toplevel_type(WaterMark) \
|
||||||
|
declare_toplevel_type(ObjPtrQueue) \
|
||||||
|
declare_toplevel_type(DirtyCardQueue) \
|
||||||
\
|
\
|
||||||
/* Pointers to Garbage Collection types */ \
|
/* Pointers to Garbage Collection types */ \
|
||||||
\
|
\
|
||||||
|
@ -2068,6 +2123,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
declare_toplevel_type(StubQueue*) \
|
declare_toplevel_type(StubQueue*) \
|
||||||
declare_toplevel_type(Thread*) \
|
declare_toplevel_type(Thread*) \
|
||||||
declare_toplevel_type(Universe) \
|
declare_toplevel_type(Universe) \
|
||||||
|
declare_toplevel_type(os) \
|
||||||
declare_toplevel_type(vframeArray) \
|
declare_toplevel_type(vframeArray) \
|
||||||
declare_toplevel_type(vframeArrayElement) \
|
declare_toplevel_type(vframeArrayElement) \
|
||||||
declare_toplevel_type(Annotations*) \
|
declare_toplevel_type(Annotations*) \
|
||||||
|
@ -2076,6 +2132,8 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
/* Miscellaneous types */ \
|
/* Miscellaneous types */ \
|
||||||
/***************/ \
|
/***************/ \
|
||||||
\
|
\
|
||||||
|
declare_toplevel_type(PtrQueue) \
|
||||||
|
\
|
||||||
/* freelist */ \
|
/* freelist */ \
|
||||||
declare_toplevel_type(FreeChunk*) \
|
declare_toplevel_type(FreeChunk*) \
|
||||||
declare_toplevel_type(Metablock*) \
|
declare_toplevel_type(Metablock*) \
|
||||||
|
@ -2106,6 +2164,7 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
/* Useful globals */ \
|
/* Useful globals */ \
|
||||||
/******************/ \
|
/******************/ \
|
||||||
\
|
\
|
||||||
|
declare_preprocessor_constant("ASSERT", DEBUG_ONLY(1) NOT_DEBUG(0)) \
|
||||||
\
|
\
|
||||||
/**************/ \
|
/**************/ \
|
||||||
/* Stack bias */ \
|
/* Stack bias */ \
|
||||||
|
@ -2122,6 +2181,8 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
declare_constant(BytesPerWord) \
|
declare_constant(BytesPerWord) \
|
||||||
declare_constant(BytesPerLong) \
|
declare_constant(BytesPerLong) \
|
||||||
\
|
\
|
||||||
|
declare_constant(LogKlassAlignmentInBytes) \
|
||||||
|
\
|
||||||
/********************************************/ \
|
/********************************************/ \
|
||||||
/* Generation and Space Hierarchy Constants */ \
|
/* Generation and Space Hierarchy Constants */ \
|
||||||
/********************************************/ \
|
/********************************************/ \
|
||||||
|
@ -2130,6 +2191,9 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
\
|
\
|
||||||
declare_constant(BarrierSet::ModRef) \
|
declare_constant(BarrierSet::ModRef) \
|
||||||
declare_constant(BarrierSet::CardTableModRef) \
|
declare_constant(BarrierSet::CardTableModRef) \
|
||||||
|
declare_constant(BarrierSet::CardTableExtension) \
|
||||||
|
declare_constant(BarrierSet::G1SATBCT) \
|
||||||
|
declare_constant(BarrierSet::G1SATBCTLogging) \
|
||||||
declare_constant(BarrierSet::Other) \
|
declare_constant(BarrierSet::Other) \
|
||||||
\
|
\
|
||||||
declare_constant(BlockOffsetSharedArray::LogN) \
|
declare_constant(BlockOffsetSharedArray::LogN) \
|
||||||
|
@ -2248,8 +2312,11 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
declare_constant(Klass::_primary_super_limit) \
|
declare_constant(Klass::_primary_super_limit) \
|
||||||
declare_constant(Klass::_lh_instance_slow_path_bit) \
|
declare_constant(Klass::_lh_instance_slow_path_bit) \
|
||||||
declare_constant(Klass::_lh_log2_element_size_shift) \
|
declare_constant(Klass::_lh_log2_element_size_shift) \
|
||||||
|
declare_constant(Klass::_lh_log2_element_size_mask) \
|
||||||
declare_constant(Klass::_lh_element_type_shift) \
|
declare_constant(Klass::_lh_element_type_shift) \
|
||||||
|
declare_constant(Klass::_lh_element_type_mask) \
|
||||||
declare_constant(Klass::_lh_header_size_shift) \
|
declare_constant(Klass::_lh_header_size_shift) \
|
||||||
|
declare_constant(Klass::_lh_header_size_mask) \
|
||||||
declare_constant(Klass::_lh_array_tag_shift) \
|
declare_constant(Klass::_lh_array_tag_shift) \
|
||||||
declare_constant(Klass::_lh_array_tag_type_value) \
|
declare_constant(Klass::_lh_array_tag_type_value) \
|
||||||
declare_constant(Klass::_lh_array_tag_obj_value) \
|
declare_constant(Klass::_lh_array_tag_obj_value) \
|
||||||
|
@ -2268,6 +2335,12 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
declare_constant(ConstMethod::_has_default_annotations) \
|
declare_constant(ConstMethod::_has_default_annotations) \
|
||||||
declare_constant(ConstMethod::_has_type_annotations) \
|
declare_constant(ConstMethod::_has_type_annotations) \
|
||||||
\
|
\
|
||||||
|
/**************/ \
|
||||||
|
/* DataLayout */ \
|
||||||
|
/**************/ \
|
||||||
|
\
|
||||||
|
declare_constant(DataLayout::cell_size) \
|
||||||
|
\
|
||||||
/*************************************/ \
|
/*************************************/ \
|
||||||
/* InstanceKlass enum */ \
|
/* InstanceKlass enum */ \
|
||||||
/*************************************/ \
|
/*************************************/ \
|
||||||
|
@ -2402,6 +2475,13 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
declare_constant(Deoptimization::Reason_LIMIT) \
|
declare_constant(Deoptimization::Reason_LIMIT) \
|
||||||
declare_constant(Deoptimization::Reason_RECORDED_LIMIT) \
|
declare_constant(Deoptimization::Reason_RECORDED_LIMIT) \
|
||||||
\
|
\
|
||||||
|
declare_constant(Deoptimization::Action_none) \
|
||||||
|
declare_constant(Deoptimization::Action_maybe_recompile) \
|
||||||
|
declare_constant(Deoptimization::Action_reinterpret) \
|
||||||
|
declare_constant(Deoptimization::Action_make_not_entrant) \
|
||||||
|
declare_constant(Deoptimization::Action_make_not_compilable) \
|
||||||
|
declare_constant(Deoptimization::Action_LIMIT) \
|
||||||
|
\
|
||||||
/*********************/ \
|
/*********************/ \
|
||||||
/* Matcher (C2 only) */ \
|
/* Matcher (C2 only) */ \
|
||||||
/*********************/ \
|
/*********************/ \
|
||||||
|
@ -2468,6 +2548,16 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
declare_constant(vmSymbols::FIRST_SID) \
|
declare_constant(vmSymbols::FIRST_SID) \
|
||||||
declare_constant(vmSymbols::SID_LIMIT) \
|
declare_constant(vmSymbols::SID_LIMIT) \
|
||||||
\
|
\
|
||||||
|
/****************/ \
|
||||||
|
/* vmIntrinsics */ \
|
||||||
|
/****************/ \
|
||||||
|
\
|
||||||
|
declare_constant(vmIntrinsics::_invokeBasic) \
|
||||||
|
declare_constant(vmIntrinsics::_linkToVirtual) \
|
||||||
|
declare_constant(vmIntrinsics::_linkToStatic) \
|
||||||
|
declare_constant(vmIntrinsics::_linkToSpecial) \
|
||||||
|
declare_constant(vmIntrinsics::_linkToInterface) \
|
||||||
|
\
|
||||||
/********************************/ \
|
/********************************/ \
|
||||||
/* Calling convention constants */ \
|
/* Calling convention constants */ \
|
||||||
/********************************/ \
|
/********************************/ \
|
||||||
|
@ -2515,6 +2605,8 @@ typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
declare_constant(markOopDesc::biased_lock_bit_in_place) \
|
declare_constant(markOopDesc::biased_lock_bit_in_place) \
|
||||||
declare_constant(markOopDesc::age_mask) \
|
declare_constant(markOopDesc::age_mask) \
|
||||||
declare_constant(markOopDesc::age_mask_in_place) \
|
declare_constant(markOopDesc::age_mask_in_place) \
|
||||||
|
declare_constant(markOopDesc::epoch_mask) \
|
||||||
|
declare_constant(markOopDesc::epoch_mask_in_place) \
|
||||||
declare_constant(markOopDesc::hash_mask) \
|
declare_constant(markOopDesc::hash_mask) \
|
||||||
declare_constant(markOopDesc::hash_mask_in_place) \
|
declare_constant(markOopDesc::hash_mask_in_place) \
|
||||||
declare_constant(markOopDesc::biased_lock_alignment) \
|
declare_constant(markOopDesc::biased_lock_alignment) \
|
||||||
|
|
|
@ -792,7 +792,7 @@ bool defaultStream::has_log_file() {
|
||||||
|
|
||||||
void defaultStream::init_log() {
|
void defaultStream::init_log() {
|
||||||
// %%% Need a MutexLocker?
|
// %%% Need a MutexLocker?
|
||||||
const char* log_name = LogFile != NULL ? LogFile : "hotspot.log";
|
const char* log_name = LogFile != NULL ? LogFile : "hotspot_pid%p.log";
|
||||||
const char* try_name = make_log_name(log_name, NULL);
|
const char* try_name = make_log_name(log_name, NULL);
|
||||||
fileStream* file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name);
|
fileStream* file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name);
|
||||||
if (!file->is_open()) {
|
if (!file->is_open()) {
|
||||||
|
@ -803,14 +803,15 @@ void defaultStream::init_log() {
|
||||||
// Note: This feature is for maintainer use only. No need for L10N.
|
// Note: This feature is for maintainer use only. No need for L10N.
|
||||||
jio_print(warnbuf);
|
jio_print(warnbuf);
|
||||||
FREE_C_HEAP_ARRAY(char, try_name, mtInternal);
|
FREE_C_HEAP_ARRAY(char, try_name, mtInternal);
|
||||||
try_name = make_log_name("hs_pid%p.log", os::get_temp_directory());
|
try_name = make_log_name(log_name, os::get_temp_directory());
|
||||||
jio_snprintf(warnbuf, sizeof(warnbuf),
|
jio_snprintf(warnbuf, sizeof(warnbuf),
|
||||||
"Warning: Forcing option -XX:LogFile=%s\n", try_name);
|
"Warning: Forcing option -XX:LogFile=%s\n", try_name);
|
||||||
jio_print(warnbuf);
|
jio_print(warnbuf);
|
||||||
delete file;
|
delete file;
|
||||||
file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name);
|
file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name);
|
||||||
FREE_C_HEAP_ARRAY(char, try_name, mtInternal);
|
|
||||||
}
|
}
|
||||||
|
FREE_C_HEAP_ARRAY(char, try_name, mtInternal);
|
||||||
|
|
||||||
if (file->is_open()) {
|
if (file->is_open()) {
|
||||||
_log_file = file;
|
_log_file = file;
|
||||||
xmlStream* xs = new(ResourceObj::C_HEAP, mtInternal) xmlStream(file);
|
xmlStream* xs = new(ResourceObj::C_HEAP, mtInternal) xmlStream(file);
|
||||||
|
|
|
@ -48,7 +48,7 @@ public class TestVerifyDuringStartup {
|
||||||
"-XX:+VerifyDuringStartup",
|
"-XX:+VerifyDuringStartup",
|
||||||
"-version"});
|
"-version"});
|
||||||
|
|
||||||
System.out.print("Testing:\n" + JDKToolFinder.getCurrentJDKTool("java"));
|
System.out.print("Testing:\n" + JDKToolFinder.getJDKTool("java"));
|
||||||
for (int i = 0; i < vmOpts.size(); i += 1) {
|
for (int i = 0; i < vmOpts.size(); i += 1) {
|
||||||
System.out.print(" " + vmOpts.get(i));
|
System.out.print(" " + vmOpts.get(i));
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,9 @@
|
||||||
|
|
||||||
package com.oracle.java.testlibrary;
|
package com.oracle.java.testlibrary;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.FileNotFoundException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
public final class JDKToolFinder {
|
public final class JDKToolFinder {
|
||||||
|
|
||||||
|
@ -32,38 +34,73 @@ public final class JDKToolFinder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the full path to an executable in jdk/bin based on System
|
* Returns the full path to an executable in jdk/bin based on System
|
||||||
* property {@code compile.jdk} (set by jtreg test suite)
|
* property {@code test.jdk} or {@code compile.jdk} (both are set by the jtreg test suite)
|
||||||
*
|
*
|
||||||
* @return Full path to an executable in jdk/bin
|
* @return Full path to an executable in jdk/bin
|
||||||
*/
|
*/
|
||||||
public static String getJDKTool(String tool) {
|
public static String getJDKTool(String tool) {
|
||||||
String binPath = System.getProperty("compile.jdk");
|
|
||||||
if (binPath == null) {
|
|
||||||
throw new RuntimeException("System property 'compile.jdk' not set. "
|
|
||||||
+ "This property is normally set by jtreg. "
|
|
||||||
+ "When running test separately, set this property using "
|
|
||||||
+ "'-Dcompile.jdk=/path/to/jdk'.");
|
|
||||||
}
|
|
||||||
binPath += File.separatorChar + "bin" + File.separatorChar + tool;
|
|
||||||
|
|
||||||
return binPath;
|
// First try to find the executable in test.jdk
|
||||||
|
try {
|
||||||
|
return getTool(tool, "test.jdk");
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now see if it's available in compile.jdk
|
||||||
|
try {
|
||||||
|
return getTool(tool, "compile.jdk");
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
throw new RuntimeException("Failed to find " + tool +
|
||||||
|
", looked in test.jdk (" + System.getProperty("test.jdk") +
|
||||||
|
") and compile.jdk (" + System.getProperty("compile.jdk") + ")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the full path to an executable in <current jdk>/bin based
|
* Returns the full path to an executable in jdk/bin based on System
|
||||||
* on System property {@code test.jdk} (set by jtreg test suite)
|
* property {@code compile.jdk}
|
||||||
*
|
*
|
||||||
* @return Full path to an executable in jdk/bin
|
* @return Full path to an executable in jdk/bin
|
||||||
*/
|
*/
|
||||||
public static String getCurrentJDKTool(String tool) {
|
public static String getCompileJDKTool(String tool) {
|
||||||
String binPath = System.getProperty("test.jdk");
|
try {
|
||||||
if (binPath == null) {
|
return getTool(tool, "compile.jdk");
|
||||||
throw new RuntimeException("System property 'test.jdk' not set. "
|
} catch (FileNotFoundException e) {
|
||||||
+ "This property is normally set by jtreg. "
|
throw new RuntimeException(e);
|
||||||
+ "When running test separately, set this property using "
|
|
||||||
+ "'-Dtest.jdk=/path/to/jdk'.");
|
|
||||||
}
|
}
|
||||||
binPath += File.separatorChar + "bin" + File.separatorChar + tool;
|
}
|
||||||
|
|
||||||
return binPath;
|
/**
|
||||||
|
* Returns the full path to an executable in jdk/bin based on System
|
||||||
|
* property {@code test.jdk}
|
||||||
|
*
|
||||||
|
* @return Full path to an executable in jdk/bin
|
||||||
|
*/
|
||||||
|
public static String getTestJDKTool(String tool) {
|
||||||
|
try {
|
||||||
|
return getTool(tool, "test.jdk");
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getTool(String tool, String property) throws FileNotFoundException {
|
||||||
|
String jdkPath = System.getProperty(property);
|
||||||
|
|
||||||
|
if (jdkPath == null) {
|
||||||
|
throw new RuntimeException(
|
||||||
|
"System property '" + property + "' not set. This property is normally set by jtreg. "
|
||||||
|
+ "When running test separately, set this property using '-D" + property + "=/path/to/jdk'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Path toolName = Paths.get("bin", tool + (Platform.isWindows() ? ".exe" : ""));
|
||||||
|
|
||||||
|
Path jdkTool = Paths.get(jdkPath, toolName.toString());
|
||||||
|
if (!jdkTool.toFile().exists()) {
|
||||||
|
throw new FileNotFoundException("Could not find file " + jdkTool.toAbsolutePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
return jdkTool.toAbsolutePath().toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue