Merge
This commit is contained in:
commit
98babf0899
hotspot
src
cpu
jdk.vm.ci/share/classes
jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot
jdk.vm.ci.meta/src/jdk/vm/ci/meta
os
share/vm
c1
classfile
classFileParser.cppclassFileParser.hppclassLoaderData.cppklassFactory.cppklassFactory.hppsystemDictionary.cppsystemDictionary.hppverifier.cpp
code
gc
cms
g1
shared
interpreter
jvmci
logging
oops
opto
prims
runtime
services
test
compiler
codecache
jsr292
jvmci
compilerToVM
jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test
loopopts
unsafe
gc
runtime
RedefineTests
defineAnonClass
testlibrary
@ -2921,6 +2921,26 @@ enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{
|
||||
__ cmp( Rold, O7 );
|
||||
%}
|
||||
|
||||
// raw int cas without using tmp register for compareAndExchange
|
||||
enc_class enc_casi_exch( iRegP mem, iRegL old, iRegL new) %{
|
||||
Register Rmem = reg_to_register_object($mem$$reg);
|
||||
Register Rold = reg_to_register_object($old$$reg);
|
||||
Register Rnew = reg_to_register_object($new$$reg);
|
||||
|
||||
MacroAssembler _masm(&cbuf);
|
||||
__ cas(Rmem, Rold, Rnew);
|
||||
%}
|
||||
|
||||
// 64-bit cas without using tmp register for compareAndExchange
|
||||
enc_class enc_casx_exch( iRegP mem, iRegL old, iRegL new) %{
|
||||
Register Rmem = reg_to_register_object($mem$$reg);
|
||||
Register Rold = reg_to_register_object($old$$reg);
|
||||
Register Rnew = reg_to_register_object($new$$reg);
|
||||
|
||||
MacroAssembler _masm(&cbuf);
|
||||
__ casx(Rmem, Rold, Rnew);
|
||||
%}
|
||||
|
||||
enc_class enc_lflags_ne_to_boolean( iRegI res ) %{
|
||||
Register Rres = reg_to_register_object($res$$reg);
|
||||
|
||||
@ -7105,6 +7125,7 @@ instruct storeLConditional( iRegP mem_ptr, iRegL oldval, g3RegL newval, flagsReg
|
||||
instruct compareAndSwapL_bool(iRegP mem_ptr, iRegL oldval, iRegL newval, iRegI res, o7RegI tmp1, flagsReg ccr ) %{
|
||||
predicate(VM_Version::supports_cx8());
|
||||
match(Set res (CompareAndSwapL mem_ptr (Binary oldval newval)));
|
||||
match(Set res (WeakCompareAndSwapL mem_ptr (Binary oldval newval)));
|
||||
effect( USE mem_ptr, KILL ccr, KILL tmp1);
|
||||
format %{
|
||||
"MOV $newval,O7\n\t"
|
||||
@ -7121,6 +7142,7 @@ instruct compareAndSwapL_bool(iRegP mem_ptr, iRegL oldval, iRegL newval, iRegI r
|
||||
|
||||
instruct compareAndSwapI_bool(iRegP mem_ptr, iRegI oldval, iRegI newval, iRegI res, o7RegI tmp1, flagsReg ccr ) %{
|
||||
match(Set res (CompareAndSwapI mem_ptr (Binary oldval newval)));
|
||||
match(Set res (WeakCompareAndSwapI mem_ptr (Binary oldval newval)));
|
||||
effect( USE mem_ptr, KILL ccr, KILL tmp1);
|
||||
format %{
|
||||
"MOV $newval,O7\n\t"
|
||||
@ -7139,6 +7161,7 @@ instruct compareAndSwapP_bool(iRegP mem_ptr, iRegP oldval, iRegP newval, iRegI r
|
||||
predicate(VM_Version::supports_cx8());
|
||||
#endif
|
||||
match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval)));
|
||||
match(Set res (WeakCompareAndSwapP mem_ptr (Binary oldval newval)));
|
||||
effect( USE mem_ptr, KILL ccr, KILL tmp1);
|
||||
format %{
|
||||
"MOV $newval,O7\n\t"
|
||||
@ -7159,6 +7182,7 @@ instruct compareAndSwapP_bool(iRegP mem_ptr, iRegP oldval, iRegP newval, iRegI r
|
||||
|
||||
instruct compareAndSwapN_bool(iRegP mem_ptr, iRegN oldval, iRegN newval, iRegI res, o7RegI tmp1, flagsReg ccr ) %{
|
||||
match(Set res (CompareAndSwapN mem_ptr (Binary oldval newval)));
|
||||
match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval)));
|
||||
effect( USE mem_ptr, KILL ccr, KILL tmp1);
|
||||
format %{
|
||||
"MOV $newval,O7\n\t"
|
||||
@ -7172,6 +7196,54 @@ instruct compareAndSwapN_bool(iRegP mem_ptr, iRegN oldval, iRegN newval, iRegI r
|
||||
ins_pipe( long_memory_op );
|
||||
%}
|
||||
|
||||
instruct compareAndExchangeI(iRegP mem_ptr, iRegI oldval, iRegI newval)
|
||||
%{
|
||||
match(Set newval (CompareAndExchangeI mem_ptr (Binary oldval newval)));
|
||||
effect( USE mem_ptr );
|
||||
|
||||
format %{
|
||||
"CASA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr] and set $newval=[$mem_ptr]\n\t"
|
||||
%}
|
||||
ins_encode( enc_casi_exch(mem_ptr, oldval, newval) );
|
||||
ins_pipe( long_memory_op );
|
||||
%}
|
||||
|
||||
instruct compareAndExchangeL(iRegP mem_ptr, iRegL oldval, iRegL newval)
|
||||
%{
|
||||
match(Set newval (CompareAndExchangeL mem_ptr (Binary oldval newval)));
|
||||
effect( USE mem_ptr );
|
||||
|
||||
format %{
|
||||
"CASXA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr] and set $newval=[$mem_ptr]\n\t"
|
||||
%}
|
||||
ins_encode( enc_casx_exch(mem_ptr, oldval, newval) );
|
||||
ins_pipe( long_memory_op );
|
||||
%}
|
||||
|
||||
instruct compareAndExchangeP(iRegP mem_ptr, iRegP oldval, iRegP newval)
|
||||
%{
|
||||
match(Set newval (CompareAndExchangeP mem_ptr (Binary oldval newval)));
|
||||
effect( USE mem_ptr );
|
||||
|
||||
format %{
|
||||
"CASXA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr] and set $newval=[$mem_ptr]\n\t"
|
||||
%}
|
||||
ins_encode( enc_casx_exch(mem_ptr, oldval, newval) );
|
||||
ins_pipe( long_memory_op );
|
||||
%}
|
||||
|
||||
instruct compareAndExchangeN(iRegP mem_ptr, iRegN oldval, iRegN newval)
|
||||
%{
|
||||
match(Set newval (CompareAndExchangeN mem_ptr (Binary oldval newval)));
|
||||
effect( USE mem_ptr );
|
||||
|
||||
format %{
|
||||
"CASA [$mem_ptr],$oldval,$newval\t! If $oldval==[$mem_ptr] Then store $newval into [$mem_ptr] and set $newval=[$mem_ptr]\n\t"
|
||||
%}
|
||||
ins_encode( enc_casi_exch(mem_ptr, oldval, newval) );
|
||||
ins_pipe( long_memory_op );
|
||||
%}
|
||||
|
||||
instruct xchgI( memory mem, iRegI newval) %{
|
||||
match(Set newval (GetAndSetI mem newval));
|
||||
format %{ "SWAP [$mem],$newval" %}
|
||||
|
@ -65,10 +65,10 @@ define_pd_global(intx, InlineSmallCode, 1000);
|
||||
#ifdef AMD64
|
||||
// Very large C++ stack frames using solaris-amd64 optimized builds
|
||||
// due to lack of optimization caused by C++ compiler bugs
|
||||
#define DEFAULT_STACK_SHADOW_PAGES (NOT_WIN64(20) WIN64_ONLY(6) DEBUG_ONLY(+2))
|
||||
#define DEFAULT_STACK_SHADOW_PAGES (NOT_WIN64(20) WIN64_ONLY(7) DEBUG_ONLY(+2))
|
||||
// For those clients that do not use write socket, we allow
|
||||
// the min range value to be below that of the default
|
||||
#define MIN_STACK_SHADOW_PAGES (NOT_WIN64(10) WIN64_ONLY(6) DEBUG_ONLY(+2))
|
||||
#define MIN_STACK_SHADOW_PAGES (NOT_WIN64(10) WIN64_ONLY(7) DEBUG_ONLY(+2))
|
||||
#else
|
||||
#define DEFAULT_STACK_SHADOW_PAGES (4 DEBUG_ONLY(+5))
|
||||
#define MIN_STACK_SHADOW_PAGES DEFAULT_STACK_SHADOW_PAGES
|
||||
|
@ -8131,8 +8131,7 @@ void MacroAssembler::has_negatives(Register ary1, Register len,
|
||||
jmp(FALSE_LABEL);
|
||||
|
||||
clear_vector_masking(); // closing of the stub context for programming mask registers
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
movl(result, len); // copy
|
||||
|
||||
if (UseAVX == 2 && UseSSE >= 2) {
|
||||
@ -8169,8 +8168,7 @@ void MacroAssembler::has_negatives(Register ary1, Register len,
|
||||
bind(COMPARE_TAIL); // len is zero
|
||||
movl(len, result);
|
||||
// Fallthru to tail compare
|
||||
}
|
||||
else if (UseSSE42Intrinsics) {
|
||||
} else if (UseSSE42Intrinsics) {
|
||||
// With SSE4.2, use double quad vector compare
|
||||
Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
|
||||
|
||||
@ -10748,7 +10746,10 @@ void MacroAssembler::char_array_compress(Register src, Register dst, Register le
|
||||
// save length for return
|
||||
push(len);
|
||||
|
||||
// 8165287: EVEX version disabled for now, needs to be refactored as
|
||||
// it is returning incorrect results.
|
||||
if ((UseAVX > 2) && // AVX512
|
||||
0 &&
|
||||
VM_Version::supports_avx512vlbw() &&
|
||||
VM_Version::supports_bmi2()) {
|
||||
|
||||
@ -11067,10 +11068,11 @@ void MacroAssembler::byte_array_inflate(Register src, Register dst, Register len
|
||||
|
||||
bind(below_threshold);
|
||||
bind(copy_new_tail);
|
||||
if (UseAVX > 2) {
|
||||
if ((UseAVX > 2) &&
|
||||
VM_Version::supports_avx512vlbw() &&
|
||||
VM_Version::supports_bmi2()) {
|
||||
movl(tmp2, len);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
movl(len, tmp2);
|
||||
}
|
||||
andl(tmp2, 0x00000007);
|
||||
|
@ -366,8 +366,8 @@ final class CompilerToVM {
|
||||
* {@code exactReceiver}.
|
||||
*
|
||||
* @param caller the caller or context type used to perform access checks
|
||||
* @return the link-time resolved method (might be abstract) or {@code 0} if it can not be
|
||||
* linked
|
||||
* @return the link-time resolved method (might be abstract) or {@code null} if it is either a
|
||||
* signature polymorphic method or can not be linked.
|
||||
*/
|
||||
native HotSpotResolvedJavaMethodImpl resolveMethod(HotSpotResolvedObjectTypeImpl exactReceiver, HotSpotResolvedJavaMethodImpl method, HotSpotResolvedObjectTypeImpl caller);
|
||||
|
||||
|
2
hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java
2
hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java
@ -722,7 +722,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
|
||||
/**
|
||||
* Determines if {@code type} contains signature polymorphic methods.
|
||||
*/
|
||||
private static boolean isSignaturePolymorphicHolder(final HotSpotResolvedObjectTypeImpl type) {
|
||||
static boolean isSignaturePolymorphicHolder(final ResolvedJavaType type) {
|
||||
String name = type.getName();
|
||||
if (signaturePolymorphicHolders == null) {
|
||||
signaturePolymorphicHolders = compilerToVM().getSignaturePolymorphicHolders();
|
||||
|
@ -24,6 +24,7 @@ package jdk.vm.ci.hotspot;
|
||||
|
||||
import static java.util.Objects.requireNonNull;
|
||||
import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM;
|
||||
import static jdk.vm.ci.hotspot.HotSpotConstantPool.isSignaturePolymorphicHolder;
|
||||
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
|
||||
import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
|
||||
import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE;
|
||||
@ -426,7 +427,7 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
|
||||
// Methods can only be resolved against concrete types
|
||||
return null;
|
||||
}
|
||||
if (method.isConcrete() && method.getDeclaringClass().equals(this) && method.isPublic()) {
|
||||
if (method.isConcrete() && method.getDeclaringClass().equals(this) && method.isPublic() && !isSignaturePolymorphicHolder(method.getDeclaringClass())) {
|
||||
return method;
|
||||
}
|
||||
if (!method.getDeclaringClass().isAssignableFrom(this)) {
|
||||
|
@ -209,8 +209,8 @@ public interface ResolvedJavaType extends JavaType, ModifiersProvider, Annotated
|
||||
*
|
||||
* @param method the method to select the implementation of
|
||||
* @param callerType the caller or context type used to perform access checks
|
||||
* @return the method that would be selected at runtime (might be abstract) or {@code null} if
|
||||
* it can not be resolved
|
||||
* @return the link-time resolved method (might be abstract) or {@code null} if it is either a
|
||||
* signature polymorphic method or can not be linked.
|
||||
*/
|
||||
ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType);
|
||||
|
||||
|
@ -2875,7 +2875,7 @@ void os::Linux::rebuild_cpu_to_node_map() {
|
||||
// in the library.
|
||||
const size_t BitsPerCLong = sizeof(long) * CHAR_BIT;
|
||||
|
||||
size_t cpu_num = os::active_processor_count();
|
||||
size_t cpu_num = processor_count();
|
||||
size_t cpu_map_size = NCPUS / BitsPerCLong;
|
||||
size_t cpu_map_valid_size =
|
||||
MIN2((cpu_num + BitsPerCLong - 1) / BitsPerCLong, cpu_map_size);
|
||||
|
@ -2504,13 +2504,15 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
|
||||
// It write enables the page immediately after protecting it
|
||||
// so just return.
|
||||
if (exception_code == EXCEPTION_ACCESS_VIOLATION) {
|
||||
JavaThread* thread = (JavaThread*) t;
|
||||
PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord;
|
||||
address addr = (address) exceptionRecord->ExceptionInformation[1];
|
||||
if (os::is_memory_serialize_page(thread, addr)) {
|
||||
// Block current thread until the memory serialize page permission restored.
|
||||
os::block_on_serialize_page_trap();
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
if (t != NULL && t->is_Java_thread()) {
|
||||
JavaThread* thread = (JavaThread*) t;
|
||||
PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord;
|
||||
address addr = (address) exceptionRecord->ExceptionInformation[1];
|
||||
if (os::is_memory_serialize_page(thread, addr)) {
|
||||
// Block current thread until the memory serialize page permission restored.
|
||||
os::block_on_serialize_page_trap();
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2564,7 +2566,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
|
||||
}
|
||||
#endif
|
||||
if (thread->stack_guards_enabled()) {
|
||||
if (_thread_in_Java) {
|
||||
if (in_java) {
|
||||
frame fr;
|
||||
PEXCEPTION_RECORD exceptionRecord = exceptionInfo->ExceptionRecord;
|
||||
address addr = (address) exceptionRecord->ExceptionInformation[1];
|
||||
@ -2576,6 +2578,7 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) {
|
||||
// Yellow zone violation. The o/s has unprotected the first yellow
|
||||
// zone page for us. Note: must call disable_stack_yellow_zone to
|
||||
// update the enabled status, even if the zone contains only one page.
|
||||
assert(thread->thread_state() != _thread_in_vm, "Undersized StackShadowPages");
|
||||
thread->disable_stack_yellow_reserved_zone();
|
||||
// If not in java code, return and hope for the best.
|
||||
return in_java
|
||||
@ -3793,6 +3796,11 @@ void os::win32::initialize_system_info() {
|
||||
GlobalMemoryStatusEx(&ms);
|
||||
_physical_memory = ms.ullTotalPhys;
|
||||
|
||||
if (FLAG_IS_DEFAULT(MaxRAM)) {
|
||||
// Adjust MaxRAM according to the maximum virtual address space available.
|
||||
FLAG_SET_DEFAULT(MaxRAM, MIN2(MaxRAM, (uint64_t) ms.ullTotalVirtual));
|
||||
}
|
||||
|
||||
OSVERSIONINFOEX oi;
|
||||
oi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
||||
GetVersionEx((OSVERSIONINFO*)&oi);
|
||||
|
@ -2410,6 +2410,15 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) {
|
||||
#endif // INCLUDE_ALL_GCS
|
||||
|
||||
if (x->is_volatile() && os::is_MP()) __ membar_acquire();
|
||||
|
||||
/* Normalize boolean value returned by unsafe operation, i.e., value != 0 ? value = true : value false. */
|
||||
if (type == T_BOOLEAN) {
|
||||
LabelObj* equalZeroLabel = new LabelObj();
|
||||
__ cmp(lir_cond_equal, value, 0);
|
||||
__ branch(lir_cond_equal, T_BOOLEAN, equalZeroLabel->label());
|
||||
__ move(LIR_OprFact::intConst(1), value);
|
||||
__ branch_destination(equalZeroLabel->label());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -576,9 +576,8 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
|
||||
// normal bytecode execution.
|
||||
thread->clear_exception_oop_and_pc();
|
||||
|
||||
Handle original_exception(thread, exception());
|
||||
|
||||
continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false);
|
||||
bool recursive_exception = false;
|
||||
continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false, recursive_exception);
|
||||
// If an exception was thrown during exception dispatch, the exception oop may have changed
|
||||
thread->set_exception_oop(exception());
|
||||
thread->set_exception_pc(pc);
|
||||
@ -586,8 +585,9 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
|
||||
// the exception cache is used only by non-implicit exceptions
|
||||
// Update the exception cache only when there didn't happen
|
||||
// another exception during the computation of the compiled
|
||||
// exception handler.
|
||||
if (continuation != NULL && original_exception() == exception()) {
|
||||
// exception handler. Checking for exception oop equality is not
|
||||
// sufficient because some exceptions are pre-allocated and reused.
|
||||
if (continuation != NULL && !recursive_exception) {
|
||||
nm->add_handler_for_exception_and_pc(exception, pc, continuation);
|
||||
}
|
||||
}
|
||||
|
@ -5407,6 +5407,59 @@ void ClassFileParser::fill_instance_klass(InstanceKlass* ik, bool changed_by_loa
|
||||
debug_only(ik->verify();)
|
||||
}
|
||||
|
||||
// For an anonymous class that is in the unnamed package, move it to its host class's
|
||||
// package by prepending its host class's package name to its class name and setting
|
||||
// its _class_name field.
|
||||
void ClassFileParser::prepend_host_package_name(const InstanceKlass* host_klass, TRAPS) {
|
||||
ResourceMark rm(THREAD);
|
||||
assert(strrchr(_class_name->as_C_string(), '/') == NULL,
|
||||
"Anonymous class should not be in a package");
|
||||
const char* host_pkg_name =
|
||||
ClassLoader::package_from_name(host_klass->name()->as_C_string(), NULL);
|
||||
|
||||
if (host_pkg_name != NULL) {
|
||||
size_t host_pkg_len = strlen(host_pkg_name);
|
||||
int class_name_len = _class_name->utf8_length();
|
||||
char* new_anon_name =
|
||||
NEW_RESOURCE_ARRAY(char, host_pkg_len + 1 + class_name_len);
|
||||
// Copy host package name and trailing /.
|
||||
strncpy(new_anon_name, host_pkg_name, host_pkg_len);
|
||||
new_anon_name[host_pkg_len] = '/';
|
||||
// Append anonymous class name. The anonymous class name can contain odd
|
||||
// characters. So, do a strncpy instead of using sprintf("%s...").
|
||||
strncpy(new_anon_name + host_pkg_len + 1, (char *)_class_name->base(), class_name_len);
|
||||
|
||||
// Create a symbol and update the anonymous class name.
|
||||
_class_name = SymbolTable::new_symbol(new_anon_name,
|
||||
(int)host_pkg_len + 1 + class_name_len,
|
||||
CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
// If the host class and the anonymous class are in the same package then do
|
||||
// nothing. If the anonymous class is in the unnamed package then move it to its
|
||||
// host's package. If the classes are in different packages then throw an IAE
|
||||
// exception.
|
||||
void ClassFileParser::fix_anonymous_class_name(TRAPS) {
|
||||
assert(_host_klass != NULL, "Expected an anonymous class");
|
||||
|
||||
const jbyte* anon_last_slash = UTF8::strrchr(_class_name->base(),
|
||||
_class_name->utf8_length(), '/');
|
||||
if (anon_last_slash == NULL) { // Unnamed package
|
||||
prepend_host_package_name(_host_klass, CHECK);
|
||||
} else {
|
||||
if (!InstanceKlass::is_same_class_package(_host_klass->class_loader(),
|
||||
_host_klass->name(),
|
||||
_host_klass->class_loader(),
|
||||
_class_name)) {
|
||||
ResourceMark rm(THREAD);
|
||||
THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
|
||||
err_msg("Host class %s and anonymous class %s are in different packages",
|
||||
_host_klass->name()->as_C_string(), _class_name->as_C_string()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool relax_format_check_for(ClassLoaderData* loader_data) {
|
||||
bool trusted = (loader_data->is_the_null_class_loader_data() ||
|
||||
SystemDictionary::is_platform_class_loader(loader_data->class_loader()));
|
||||
@ -5422,7 +5475,7 @@ ClassFileParser::ClassFileParser(ClassFileStream* stream,
|
||||
Symbol* name,
|
||||
ClassLoaderData* loader_data,
|
||||
Handle protection_domain,
|
||||
const Klass* host_klass,
|
||||
const InstanceKlass* host_klass,
|
||||
GrowableArray<Handle>* cp_patches,
|
||||
Publicity pub_level,
|
||||
TRAPS) :
|
||||
@ -5697,6 +5750,13 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
|
||||
return;
|
||||
}
|
||||
|
||||
// if this is an anonymous class fix up its name if it's in the unnamed
|
||||
// package. Otherwise, throw IAE if it is in a different package than
|
||||
// its host class.
|
||||
if (_host_klass != NULL) {
|
||||
fix_anonymous_class_name(CHECK);
|
||||
}
|
||||
|
||||
// Verification prevents us from creating names with dots in them, this
|
||||
// asserts that that's the case.
|
||||
assert(is_internal_format(_class_name), "external class name format used internally");
|
||||
|
@ -79,7 +79,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
const Symbol* _requested_name;
|
||||
Symbol* _class_name;
|
||||
mutable ClassLoaderData* _loader_data;
|
||||
const Klass* _host_klass;
|
||||
const InstanceKlass* _host_klass;
|
||||
GrowableArray<Handle>* _cp_patches; // overrides for CP entries
|
||||
|
||||
// Metadata created before the instance klass is created. Must be deallocated
|
||||
@ -155,6 +155,9 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
ConstantPool* cp,
|
||||
TRAPS);
|
||||
|
||||
void prepend_host_package_name(const InstanceKlass* host_klass, TRAPS);
|
||||
void fix_anonymous_class_name(TRAPS);
|
||||
|
||||
void fill_instance_klass(InstanceKlass* ik, bool cf_changed_in_CFLH, TRAPS);
|
||||
void set_klass(InstanceKlass* instance);
|
||||
|
||||
@ -474,7 +477,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
Symbol* name,
|
||||
ClassLoaderData* loader_data,
|
||||
Handle protection_domain,
|
||||
const Klass* host_klass,
|
||||
const InstanceKlass* host_klass,
|
||||
GrowableArray<Handle>* cp_patches,
|
||||
Publicity pub_level,
|
||||
TRAPS);
|
||||
@ -500,7 +503,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
bool is_anonymous() const { return _host_klass != NULL; }
|
||||
bool is_interface() const { return _access_flags.is_interface(); }
|
||||
|
||||
const Klass* host_klass() const { return _host_klass; }
|
||||
const InstanceKlass* host_klass() const { return _host_klass; }
|
||||
const GrowableArray<Handle>* cp_patches() const { return _cp_patches; }
|
||||
ClassLoaderData* loader_data() const { return _loader_data; }
|
||||
const Symbol* class_name() const { return _class_name; }
|
||||
|
@ -966,7 +966,7 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure,
|
||||
// Klasses to delete.
|
||||
bool walk_all_metadata = clean_previous_versions &&
|
||||
JvmtiExport::has_redefined_a_class() &&
|
||||
InstanceKlass::has_previous_versions();
|
||||
InstanceKlass::has_previous_versions_and_reset();
|
||||
MetadataOnStackMark md_on_stack(walk_all_metadata);
|
||||
|
||||
// Save previous _unloading pointer for CMS which may add to unloading list before
|
||||
|
@ -94,7 +94,7 @@ instanceKlassHandle KlassFactory::create_from_stream(ClassFileStream* stream,
|
||||
Symbol* name,
|
||||
ClassLoaderData* loader_data,
|
||||
Handle protection_domain,
|
||||
const Klass* host_klass,
|
||||
const InstanceKlass* host_klass,
|
||||
GrowableArray<Handle>* cp_patches,
|
||||
TRAPS) {
|
||||
|
||||
|
@ -72,7 +72,7 @@ class KlassFactory : AllStatic {
|
||||
Symbol* name,
|
||||
ClassLoaderData* loader_data,
|
||||
Handle protection_domain,
|
||||
const Klass* host_klass,
|
||||
const InstanceKlass* host_klass,
|
||||
GrowableArray<Handle>* cp_patches,
|
||||
TRAPS);
|
||||
};
|
||||
|
@ -1027,7 +1027,7 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
ClassFileStream* st,
|
||||
const Klass* host_klass,
|
||||
const InstanceKlass* host_klass,
|
||||
GrowableArray<Handle>* cp_patches,
|
||||
TRAPS) {
|
||||
|
||||
|
@ -299,7 +299,7 @@ public:
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
ClassFileStream* st,
|
||||
const Klass* host_klass,
|
||||
const InstanceKlass* host_klass,
|
||||
GrowableArray<Handle>* cp_patches,
|
||||
TRAPS);
|
||||
|
||||
|
@ -2786,7 +2786,7 @@ void ClassVerifier::verify_invoke_instructions(
|
||||
// direct interface relative to the host class
|
||||
have_imr_indirect = (have_imr_indirect &&
|
||||
!is_same_or_direct_interface(
|
||||
InstanceKlass::cast(current_class()->host_klass()),
|
||||
current_class()->host_klass(),
|
||||
host_klass_type, ref_class_type));
|
||||
}
|
||||
if (!subtype) {
|
||||
|
@ -1305,7 +1305,7 @@ void CodeCache::report_codemem_full(int code_blob_type, bool print) {
|
||||
event.set_entryCount(heap->blob_count());
|
||||
event.set_methodCount(heap->nmethod_count());
|
||||
event.set_adaptorCount(heap->adapter_count());
|
||||
event.set_unallocatedCapacity(heap->unallocated_capacity()/K);
|
||||
event.set_unallocatedCapacity(heap->unallocated_capacity());
|
||||
event.set_fullCount(heap->full_count());
|
||||
event.commit();
|
||||
}
|
||||
|
@ -3511,6 +3511,7 @@ bool CMSCollector::do_marking_mt() {
|
||||
conc_workers()->active_workers(),
|
||||
Threads::number_of_non_daemon_threads());
|
||||
num_workers = conc_workers()->update_active_workers(num_workers);
|
||||
log_info(gc,task)("Using %u workers of %u for marking", num_workers, conc_workers()->total_workers());
|
||||
|
||||
CompactibleFreeListSpace* cms_space = _cmsGen->cmsSpace();
|
||||
|
||||
|
@ -899,6 +899,8 @@ void ParNewGeneration::collect(bool full,
|
||||
workers->active_workers(),
|
||||
Threads::number_of_non_daemon_threads());
|
||||
active_workers = workers->update_active_workers(active_workers);
|
||||
log_info(gc,task)("Using %u workers of %u for evacuation", active_workers, workers->total_workers());
|
||||
|
||||
_old_gen = gch->old_gen();
|
||||
|
||||
// If the next generation is too full to accommodate worst-case promotion
|
||||
|
@ -1332,6 +1332,7 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc,
|
||||
workers()->active_workers(),
|
||||
Threads::number_of_non_daemon_threads());
|
||||
workers()->update_active_workers(n_workers);
|
||||
log_info(gc,task)("Using %u workers of %u to rebuild remembered set", n_workers, workers()->total_workers());
|
||||
|
||||
ParRebuildRSTask rebuild_rs_task(this);
|
||||
workers()->run_task(&rebuild_rs_task);
|
||||
@ -3068,6 +3069,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
|
||||
workers()->active_workers(),
|
||||
Threads::number_of_non_daemon_threads());
|
||||
workers()->update_active_workers(active_workers);
|
||||
log_info(gc,task)("Using %u workers of %u for evacuation", active_workers, workers()->total_workers());
|
||||
|
||||
TraceCollectorStats tcs(g1mm()->incremental_collection_counters());
|
||||
TraceMemoryManagerStats tms(false /* fullGC */, gc_cause());
|
||||
|
@ -1035,6 +1035,8 @@ void G1ConcurrentMark::mark_from_roots() {
|
||||
// worker threads may currently exist and more may not be
|
||||
// available.
|
||||
active_workers = _parallel_workers->update_active_workers(active_workers);
|
||||
log_info(gc, task)("Using %u workers of %u for marking", active_workers, _parallel_workers->total_workers());
|
||||
|
||||
// Parallel task terminator is set in "set_concurrency_and_phase()"
|
||||
set_concurrency_and_phase(active_workers, true /* concurrent */);
|
||||
|
||||
|
@ -162,7 +162,7 @@ class AbstractWorkGang : public CHeapObj<mtInternal> {
|
||||
_active_workers = MIN2(v, _total_workers);
|
||||
add_workers(false /* exit_on_failure */);
|
||||
assert(v != 0, "Trying to set active workers to 0");
|
||||
log_info(gc, task)("GC Workers: using %d out of %d", _active_workers, _total_workers);
|
||||
log_trace(gc, task)("%s: using %d out of %d workers", name(), _active_workers, _total_workers);
|
||||
return _active_workers;
|
||||
}
|
||||
|
||||
|
@ -576,27 +576,39 @@ void InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecodes::Code byt
|
||||
// compute auxiliary field attributes
|
||||
TosState state = as_TosState(info.field_type());
|
||||
|
||||
// Put instructions on final fields are not resolved. This is required so we throw
|
||||
// exceptions at the correct place (when the instruction is actually invoked).
|
||||
// Resolution of put instructions on final fields is delayed. That is required so that
|
||||
// exceptions are thrown at the correct place (when the instruction is actually invoked).
|
||||
// If we do not resolve an instruction in the current pass, leaving the put_code
|
||||
// set to zero will cause the next put instruction to the same field to reresolve.
|
||||
|
||||
// Resolution of put instructions to final instance fields with invalid updates (i.e.,
|
||||
// to final instance fields with updates originating from a method different than <init>)
|
||||
// is inhibited. A putfield instruction targeting an instance final field must throw
|
||||
// an IllegalAccessError if the instruction is not in an instance
|
||||
// initializer method <init>. If resolution were not inhibited, a putfield
|
||||
// in an initializer method could be resolved in the initializer. Subsequent
|
||||
// putfield instructions to the same field would then use cached information.
|
||||
// As a result, those instructions would not pass through the VM. That is,
|
||||
// checks in resolve_field_access() would not be executed for those instructions
|
||||
// and the required IllegalAccessError would not be thrown.
|
||||
//
|
||||
// Also, we need to delay resolving getstatic and putstatic instructions until the
|
||||
// class is initialized. This is required so that access to the static
|
||||
// field will call the initialization function every time until the class
|
||||
// is completely initialized ala. in 2.17.5 in JVM Specification.
|
||||
InstanceKlass* klass = InstanceKlass::cast(info.field_holder());
|
||||
bool uninitialized_static = ((bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic) &&
|
||||
!klass->is_initialized());
|
||||
|
||||
Bytecodes::Code put_code = (Bytecodes::Code)0;
|
||||
if (is_put && !info.access_flags().is_final() && !uninitialized_static) {
|
||||
put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
|
||||
}
|
||||
bool uninitialized_static = is_static && !klass->is_initialized();
|
||||
bool has_initialized_final_update = info.field_holder()->major_version() >= 53 &&
|
||||
info.has_initialized_final_update();
|
||||
assert(!(has_initialized_final_update && !info.access_flags().is_final()), "Fields with initialized final updates must be final");
|
||||
|
||||
Bytecodes::Code get_code = (Bytecodes::Code)0;
|
||||
Bytecodes::Code put_code = (Bytecodes::Code)0;
|
||||
if (!uninitialized_static) {
|
||||
get_code = ((is_static) ? Bytecodes::_getstatic : Bytecodes::_getfield);
|
||||
if ((is_put && !has_initialized_final_update) || !info.access_flags().is_final()) {
|
||||
put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
|
||||
}
|
||||
}
|
||||
|
||||
cp_cache_entry->set_field(
|
||||
|
@ -768,6 +768,11 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t
|
||||
Symbol* h_name = method->name();
|
||||
Symbol* h_signature = method->signature();
|
||||
|
||||
if (MethodHandles::is_signature_polymorphic_method(method())) {
|
||||
// Signature polymorphic methods are already resolved, JVMCI just returns NULL in this case.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass);
|
||||
methodHandle m;
|
||||
// Only do exact lookup if receiver klass has been linked. Otherwise,
|
||||
@ -782,7 +787,7 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t
|
||||
}
|
||||
|
||||
if (m.is_null()) {
|
||||
// Return NULL only if there was a problem with lookup (uninitialized class, etc.)
|
||||
// Return NULL if there was a problem with lookup (uninitialized class, etc.)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -313,13 +313,18 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
|
||||
// normal bytecode execution.
|
||||
thread->clear_exception_oop_and_pc();
|
||||
|
||||
continuation = SharedRuntime::compute_compiled_exc_handler(cm, pc, exception, false, false);
|
||||
bool recursive_exception = false;
|
||||
continuation = SharedRuntime::compute_compiled_exc_handler(cm, pc, exception, false, false, recursive_exception);
|
||||
// If an exception was thrown during exception dispatch, the exception oop may have changed
|
||||
thread->set_exception_oop(exception());
|
||||
thread->set_exception_pc(pc);
|
||||
|
||||
// the exception cache is used only by non-implicit exceptions
|
||||
if (continuation != NULL && !SharedRuntime::deopt_blob()->contains(continuation)) {
|
||||
// Update the exception cache only when there didn't happen
|
||||
// another exception during the computation of the compiled
|
||||
// exception handler. Checking for exception oop equality is not
|
||||
// sufficient because some exceptions are pre-allocated and reused.
|
||||
if (continuation != NULL && !recursive_exception && !SharedRuntime::deopt_blob()->contains(continuation)) {
|
||||
cm->add_handler_for_exception_and_pc(exception, pc, continuation);
|
||||
}
|
||||
}
|
||||
|
@ -385,6 +385,7 @@ bool LogConfiguration::parse_log_arguments(const char* outputstr,
|
||||
const char* decoratorstr,
|
||||
const char* output_options,
|
||||
outputStream* errstream) {
|
||||
assert(errstream != NULL, "errstream can not be NULL");
|
||||
if (outputstr == NULL || strlen(outputstr) == 0) {
|
||||
outputstr = "stdout";
|
||||
}
|
||||
|
@ -3365,88 +3365,119 @@ void InstanceKlass::set_init_state(ClassState state) {
|
||||
|
||||
#if INCLUDE_JVMTI
|
||||
|
||||
// RedefineClasses() support for previous versions:
|
||||
int InstanceKlass::_previous_version_count = 0;
|
||||
// RedefineClasses() support for previous versions
|
||||
|
||||
// Purge previous versions before adding new previous versions of the class.
|
||||
void InstanceKlass::purge_previous_versions(InstanceKlass* ik) {
|
||||
if (ik->previous_versions() != NULL) {
|
||||
// This klass has previous versions so see what we can cleanup
|
||||
// while it is safe to do so.
|
||||
// Globally, there is at least one previous version of a class to walk
|
||||
// during class unloading, which is saved because old methods in the class
|
||||
// are still running. Otherwise the previous version list is cleaned up.
|
||||
bool InstanceKlass::_has_previous_versions = false;
|
||||
|
||||
int deleted_count = 0; // leave debugging breadcrumbs
|
||||
int live_count = 0;
|
||||
ClassLoaderData* loader_data = ik->class_loader_data();
|
||||
assert(loader_data != NULL, "should never be null");
|
||||
// Returns true if there are previous versions of a class for class
|
||||
// unloading only. Also resets the flag to false. purge_previous_version
|
||||
// will set the flag to true if there are any left, i.e., if there's any
|
||||
// work to do for next time. This is to avoid the expensive code cache
|
||||
// walk in CLDG::do_unloading().
|
||||
bool InstanceKlass::has_previous_versions_and_reset() {
|
||||
bool ret = _has_previous_versions;
|
||||
log_trace(redefine, class, iklass, purge)("Class unloading: has_previous_versions = %s",
|
||||
ret ? "true" : "false");
|
||||
_has_previous_versions = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ResourceMark rm;
|
||||
log_trace(redefine, class, iklass, purge)("%s: previous versions", ik->external_name());
|
||||
// Purge previous versions before adding new previous versions of the class and
|
||||
// during class unloading.
|
||||
void InstanceKlass::purge_previous_version_list() {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
|
||||
assert(has_been_redefined(), "Should only be called for main class");
|
||||
|
||||
// previous versions are linked together through the InstanceKlass
|
||||
InstanceKlass* pv_node = ik->previous_versions();
|
||||
InstanceKlass* last = ik;
|
||||
int version = 0;
|
||||
// Quick exit.
|
||||
if (previous_versions() == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check the previous versions list
|
||||
for (; pv_node != NULL; ) {
|
||||
// This klass has previous versions so see what we can cleanup
|
||||
// while it is safe to do so.
|
||||
|
||||
ConstantPool* pvcp = pv_node->constants();
|
||||
assert(pvcp != NULL, "cp ref was unexpectedly cleared");
|
||||
int deleted_count = 0; // leave debugging breadcrumbs
|
||||
int live_count = 0;
|
||||
ClassLoaderData* loader_data = class_loader_data();
|
||||
assert(loader_data != NULL, "should never be null");
|
||||
|
||||
if (!pvcp->on_stack()) {
|
||||
// If the constant pool isn't on stack, none of the methods
|
||||
// are executing. Unlink this previous_version.
|
||||
// The previous version InstanceKlass is on the ClassLoaderData deallocate list
|
||||
// so will be deallocated during the next phase of class unloading.
|
||||
log_trace(redefine, class, iklass, purge)("previous version " INTPTR_FORMAT " is dead", p2i(pv_node));
|
||||
// For debugging purposes.
|
||||
pv_node->set_is_scratch_class();
|
||||
pv_node->class_loader_data()->add_to_deallocate_list(pv_node);
|
||||
pv_node = pv_node->previous_versions();
|
||||
last->link_previous_versions(pv_node);
|
||||
deleted_count++;
|
||||
version++;
|
||||
continue;
|
||||
} else {
|
||||
log_trace(redefine, class, iklass, purge)("previous version " INTPTR_FORMAT " is alive", p2i(pv_node));
|
||||
assert(pvcp->pool_holder() != NULL, "Constant pool with no holder");
|
||||
guarantee (!loader_data->is_unloading(), "unloaded classes can't be on the stack");
|
||||
live_count++;
|
||||
}
|
||||
ResourceMark rm;
|
||||
log_trace(redefine, class, iklass, purge)("%s: previous versions", external_name());
|
||||
|
||||
// At least one method is live in this previous version.
|
||||
// Reset dead EMCP methods not to get breakpoints.
|
||||
// All methods are deallocated when all of the methods for this class are no
|
||||
// longer running.
|
||||
Array<Method*>* method_refs = pv_node->methods();
|
||||
if (method_refs != NULL) {
|
||||
log_trace(redefine, class, iklass, purge)("previous methods length=%d", method_refs->length());
|
||||
for (int j = 0; j < method_refs->length(); j++) {
|
||||
Method* method = method_refs->at(j);
|
||||
// previous versions are linked together through the InstanceKlass
|
||||
InstanceKlass* pv_node = previous_versions();
|
||||
InstanceKlass* last = this;
|
||||
int version = 0;
|
||||
|
||||
if (!method->on_stack()) {
|
||||
// no breakpoints for non-running methods
|
||||
if (method->is_running_emcp()) {
|
||||
method->set_running_emcp(false);
|
||||
}
|
||||
} else {
|
||||
assert (method->is_obsolete() || method->is_running_emcp(),
|
||||
"emcp method cannot run after emcp bit is cleared");
|
||||
log_trace(redefine, class, iklass, purge)
|
||||
("purge: %s(%s): prev method @%d in version @%d is alive",
|
||||
method->name()->as_C_string(), method->signature()->as_C_string(), j, version);
|
||||
// check the previous versions list
|
||||
for (; pv_node != NULL; ) {
|
||||
|
||||
ConstantPool* pvcp = pv_node->constants();
|
||||
assert(pvcp != NULL, "cp ref was unexpectedly cleared");
|
||||
|
||||
if (!pvcp->on_stack()) {
|
||||
// If the constant pool isn't on stack, none of the methods
|
||||
// are executing. Unlink this previous_version.
|
||||
// The previous version InstanceKlass is on the ClassLoaderData deallocate list
|
||||
// so will be deallocated during the next phase of class unloading.
|
||||
log_trace(redefine, class, iklass, purge)
|
||||
("previous version " INTPTR_FORMAT " is dead.", p2i(pv_node));
|
||||
// For debugging purposes.
|
||||
pv_node->set_is_scratch_class();
|
||||
// Unlink from previous version list.
|
||||
assert(pv_node->class_loader_data() == loader_data, "wrong loader_data");
|
||||
InstanceKlass* next = pv_node->previous_versions();
|
||||
pv_node->link_previous_versions(NULL); // point next to NULL
|
||||
last->link_previous_versions(next);
|
||||
// Add to the deallocate list after unlinking
|
||||
loader_data->add_to_deallocate_list(pv_node);
|
||||
pv_node = next;
|
||||
deleted_count++;
|
||||
version++;
|
||||
continue;
|
||||
} else {
|
||||
log_trace(redefine, class, iklass, purge)("previous version " INTPTR_FORMAT " is alive", p2i(pv_node));
|
||||
assert(pvcp->pool_holder() != NULL, "Constant pool with no holder");
|
||||
guarantee (!loader_data->is_unloading(), "unloaded classes can't be on the stack");
|
||||
live_count++;
|
||||
// found a previous version for next time we do class unloading
|
||||
_has_previous_versions = true;
|
||||
}
|
||||
|
||||
// At least one method is live in this previous version.
|
||||
// Reset dead EMCP methods not to get breakpoints.
|
||||
// All methods are deallocated when all of the methods for this class are no
|
||||
// longer running.
|
||||
Array<Method*>* method_refs = pv_node->methods();
|
||||
if (method_refs != NULL) {
|
||||
log_trace(redefine, class, iklass, purge)("previous methods length=%d", method_refs->length());
|
||||
for (int j = 0; j < method_refs->length(); j++) {
|
||||
Method* method = method_refs->at(j);
|
||||
|
||||
if (!method->on_stack()) {
|
||||
// no breakpoints for non-running methods
|
||||
if (method->is_running_emcp()) {
|
||||
method->set_running_emcp(false);
|
||||
}
|
||||
} else {
|
||||
assert (method->is_obsolete() || method->is_running_emcp(),
|
||||
"emcp method cannot run after emcp bit is cleared");
|
||||
log_trace(redefine, class, iklass, purge)
|
||||
("purge: %s(%s): prev method @%d in version @%d is alive",
|
||||
method->name()->as_C_string(), method->signature()->as_C_string(), j, version);
|
||||
}
|
||||
}
|
||||
// next previous version
|
||||
last = pv_node;
|
||||
pv_node = pv_node->previous_versions();
|
||||
version++;
|
||||
}
|
||||
log_trace(redefine, class, iklass, purge)
|
||||
("previous version stats: live=%d, deleted=%d",
|
||||
live_count, deleted_count);
|
||||
// next previous version
|
||||
last = pv_node;
|
||||
pv_node = pv_node->previous_versions();
|
||||
version++;
|
||||
}
|
||||
log_trace(redefine, class, iklass, purge)
|
||||
("previous version stats: live=%d, deleted=%d", live_count, deleted_count);
|
||||
}
|
||||
|
||||
void InstanceKlass::mark_newly_obsolete_methods(Array<Method*>* old_methods,
|
||||
@ -3518,8 +3549,8 @@ void InstanceKlass::add_previous_version(instanceKlassHandle scratch_class,
|
||||
log_trace(redefine, class, iklass, add)
|
||||
("adding previous version ref for %s, EMCP_cnt=%d", scratch_class->external_name(), emcp_method_count);
|
||||
|
||||
// Clean out old previous versions
|
||||
purge_previous_versions(this);
|
||||
// Clean out old previous versions for this class
|
||||
purge_previous_version_list();
|
||||
|
||||
// Mark newly obsolete methods in remaining previous versions. An EMCP method from
|
||||
// a previous redefinition may be made obsolete by this redefinition.
|
||||
@ -3536,8 +3567,6 @@ void InstanceKlass::add_previous_version(instanceKlassHandle scratch_class,
|
||||
// For debugging purposes.
|
||||
scratch_class->set_is_scratch_class();
|
||||
scratch_class->class_loader_data()->add_to_deallocate_list(scratch_class());
|
||||
// Update count for class unloading.
|
||||
_previous_version_count--;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -3565,12 +3594,12 @@ void InstanceKlass::add_previous_version(instanceKlassHandle scratch_class,
|
||||
}
|
||||
|
||||
// Add previous version if any methods are still running.
|
||||
log_trace(redefine, class, iklass, add)("scratch class added; one of its methods is on_stack");
|
||||
// Set has_previous_version flag for processing during class unloading.
|
||||
_has_previous_versions = true;
|
||||
log_trace(redefine, class, iklass, add) ("scratch class added; one of its methods is on_stack.");
|
||||
assert(scratch_class->previous_versions() == NULL, "shouldn't have a previous version");
|
||||
scratch_class->link_previous_versions(previous_versions());
|
||||
link_previous_versions(scratch_class());
|
||||
// Update count for class unloading.
|
||||
_previous_version_count++;
|
||||
} // end add_previous_version()
|
||||
|
||||
#endif // INCLUDE_JVMTI
|
||||
|
@ -619,8 +619,8 @@ class InstanceKlass: public Klass {
|
||||
objArrayOop signers() const;
|
||||
|
||||
// host class
|
||||
Klass* host_klass() const {
|
||||
Klass** hk = (Klass**)adr_host_klass();
|
||||
InstanceKlass* host_klass() const {
|
||||
InstanceKlass** hk = adr_host_klass();
|
||||
if (hk == NULL) {
|
||||
return NULL;
|
||||
} else {
|
||||
@ -628,9 +628,9 @@ class InstanceKlass: public Klass {
|
||||
return *hk;
|
||||
}
|
||||
}
|
||||
void set_host_klass(const Klass* host) {
|
||||
void set_host_klass(const InstanceKlass* host) {
|
||||
assert(is_anonymous(), "not anonymous");
|
||||
const Klass** addr = (const Klass**)adr_host_klass();
|
||||
const InstanceKlass** addr = (const InstanceKlass **)adr_host_klass();
|
||||
assert(addr != NULL, "no reversed space");
|
||||
if (addr != NULL) {
|
||||
*addr = host;
|
||||
@ -709,6 +709,7 @@ class InstanceKlass: public Klass {
|
||||
|
||||
// RedefineClasses() support for previous versions:
|
||||
void add_previous_version(instanceKlassHandle ikh, int emcp_method_count);
|
||||
void purge_previous_version_list();
|
||||
|
||||
InstanceKlass* previous_versions() const { return _previous_versions; }
|
||||
#else
|
||||
@ -768,10 +769,15 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static int _previous_version_count;
|
||||
static bool _has_previous_versions;
|
||||
public:
|
||||
static void purge_previous_versions(InstanceKlass* ik);
|
||||
static bool has_previous_versions() { return _previous_version_count > 0; }
|
||||
static void purge_previous_versions(InstanceKlass* ik) {
|
||||
if (ik->has_been_redefined()) {
|
||||
ik->purge_previous_version_list();
|
||||
}
|
||||
}
|
||||
|
||||
static bool has_previous_versions_and_reset();
|
||||
|
||||
// JVMTI: Support for caching a class file before it is modified by an agent that can do retransformation
|
||||
void set_cached_class_file(JvmtiCachedClassFileData *data) {
|
||||
@ -792,7 +798,7 @@ public:
|
||||
#else // INCLUDE_JVMTI
|
||||
|
||||
static void purge_previous_versions(InstanceKlass* ik) { return; };
|
||||
static bool has_previous_versions() { return false; }
|
||||
static bool has_previous_versions_and_reset() { return false; }
|
||||
|
||||
void set_cached_class_file(JvmtiCachedClassFileData *data) {
|
||||
assert(data == NULL, "unexpected call with JVMTI disabled");
|
||||
@ -1057,13 +1063,13 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
Klass** adr_host_klass() const {
|
||||
InstanceKlass** adr_host_klass() const {
|
||||
if (is_anonymous()) {
|
||||
Klass** adr_impl = adr_implementor();
|
||||
InstanceKlass** adr_impl = (InstanceKlass **)adr_implementor();
|
||||
if (adr_impl != NULL) {
|
||||
return adr_impl + 1;
|
||||
} else {
|
||||
return end_of_nonstatic_oop_maps();
|
||||
return (InstanceKlass **)end_of_nonstatic_oop_maps();
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
|
@ -431,6 +431,12 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive, bool clean_alive
|
||||
if (clean_alive_klasses && current->is_instance_klass()) {
|
||||
InstanceKlass* ik = InstanceKlass::cast(current);
|
||||
ik->clean_weak_instanceklass_links(is_alive);
|
||||
|
||||
// JVMTI RedefineClasses creates previous versions that are not in
|
||||
// the class hierarchy, so process them here.
|
||||
while ((ik = ik->previous_versions()) != NULL) {
|
||||
ik->clean_weak_instanceklass_links(is_alive);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2172,10 +2172,9 @@ Node* GraphKit::record_profiled_receiver_for_speculation(Node* n) {
|
||||
java_bc() == Bytecodes::_instanceof ||
|
||||
java_bc() == Bytecodes::_aastore) {
|
||||
ciProfileData* data = method()->method_data()->bci_to_data(bci());
|
||||
bool maybe_null = data == NULL ? true : data->as_BitData()->null_seen();
|
||||
maybe_null = data == NULL ? true : data->as_BitData()->null_seen();
|
||||
}
|
||||
return record_profile_for_speculation(n, exact_kls, maybe_null);
|
||||
return n;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2475,6 +2475,28 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c
|
||||
// load value
|
||||
switch (type) {
|
||||
case T_BOOLEAN:
|
||||
{
|
||||
// Normalize the value returned by getBoolean in the following cases
|
||||
if (mismatched ||
|
||||
heap_base_oop == top() || // - heap_base_oop is NULL or
|
||||
(can_access_non_heap && alias_type->field() == NULL) // - heap_base_oop is potentially NULL
|
||||
// and the unsafe access is made to large offset
|
||||
// (i.e., larger than the maximum offset necessary for any
|
||||
// field access)
|
||||
) {
|
||||
IdealKit ideal = IdealKit(this);
|
||||
#define __ ideal.
|
||||
IdealVariable normalized_result(ideal);
|
||||
__ declarations_done();
|
||||
__ set(normalized_result, p);
|
||||
__ if_then(p, BoolTest::ne, ideal.ConI(0));
|
||||
__ set(normalized_result, ideal.ConI(1));
|
||||
ideal.end_if();
|
||||
final_sync(ideal);
|
||||
p = __ value(normalized_result);
|
||||
#undef __
|
||||
}
|
||||
}
|
||||
case T_CHAR:
|
||||
case T_BYTE:
|
||||
case T_SHORT:
|
||||
|
@ -1349,17 +1349,23 @@ JRT_ENTRY_NO_ASYNC(address, OptoRuntime::handle_exception_C_helper(JavaThread* t
|
||||
force_unwind ? NULL : nm->handler_for_exception_and_pc(exception, pc);
|
||||
|
||||
if (handler_address == NULL) {
|
||||
Handle original_exception(thread, exception());
|
||||
handler_address = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, force_unwind, true);
|
||||
bool recursive_exception = false;
|
||||
handler_address = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, force_unwind, true, recursive_exception);
|
||||
assert (handler_address != NULL, "must have compiled handler");
|
||||
// Update the exception cache only when the unwind was not forced
|
||||
// and there didn't happen another exception during the computation of the
|
||||
// compiled exception handler.
|
||||
if (!force_unwind && original_exception() == exception()) {
|
||||
// compiled exception handler. Checking for exception oop equality is not
|
||||
// sufficient because some exceptions are pre-allocated and reused.
|
||||
if (!force_unwind && !recursive_exception) {
|
||||
nm->add_handler_for_exception_and_pc(exception,pc,handler_address);
|
||||
}
|
||||
} else {
|
||||
assert(handler_address == SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, force_unwind, true), "Must be the same");
|
||||
#ifdef ASSERT
|
||||
bool recursive_exception = false;
|
||||
address computed_address = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, force_unwind, true, recursive_exception);
|
||||
vmassert(recursive_exception || (handler_address == computed_address), "Handler address inconsistency: " PTR_FORMAT " != " PTR_FORMAT,
|
||||
p2i(handler_address), p2i(computed_address));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -649,18 +649,14 @@ JvmtiEnv::GetErrorName(jvmtiError error, char** name_ptr) {
|
||||
|
||||
jvmtiError
|
||||
JvmtiEnv::SetVerboseFlag(jvmtiVerboseFlag flag, jboolean value) {
|
||||
LogLevelType level = value == 0 ? LogLevel::Off : LogLevel::Info;
|
||||
switch (flag) {
|
||||
case JVMTI_VERBOSE_OTHER:
|
||||
// ignore
|
||||
break;
|
||||
case JVMTI_VERBOSE_CLASS:
|
||||
if (value == 0) {
|
||||
LogConfiguration::parse_log_arguments("stdout", "class+unload=off", NULL, NULL, NULL);
|
||||
LogConfiguration::parse_log_arguments("stdout", "class+load=off", NULL, NULL, NULL);
|
||||
} else {
|
||||
LogConfiguration::parse_log_arguments("stdout", "class+load=info", NULL, NULL, NULL);
|
||||
LogConfiguration::parse_log_arguments("stdout", "class+unload=info", NULL, NULL, NULL);
|
||||
}
|
||||
LogConfiguration::configure_stdout(level, false, LOG_TAGS(class, unload));
|
||||
LogConfiguration::configure_stdout(level, false, LOG_TAGS(class, load));
|
||||
break;
|
||||
case JVMTI_VERBOSE_GC:
|
||||
if (value == 0) {
|
||||
|
@ -150,14 +150,23 @@ class MemoryAccess : StackObj {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T normalize(T x) {
|
||||
T normalize_for_write(T x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
jboolean normalize(jboolean x) {
|
||||
jboolean normalize_for_write(jboolean x) {
|
||||
return x & 1;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T normalize_for_read(T x) {
|
||||
return x;
|
||||
}
|
||||
|
||||
jboolean normalize_for_read(jboolean x) {
|
||||
return x != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to wrap memory accesses in JavaThread::doing_unsafe_access()
|
||||
*/
|
||||
@ -196,7 +205,7 @@ public:
|
||||
|
||||
T* p = (T*)addr();
|
||||
|
||||
T x = *p;
|
||||
T x = normalize_for_read(*p);
|
||||
|
||||
return x;
|
||||
}
|
||||
@ -207,7 +216,7 @@ public:
|
||||
|
||||
T* p = (T*)addr();
|
||||
|
||||
*p = normalize(x);
|
||||
*p = normalize_for_write(x);
|
||||
}
|
||||
|
||||
|
||||
@ -223,7 +232,7 @@ public:
|
||||
|
||||
T x = OrderAccess::load_acquire((volatile T*)p);
|
||||
|
||||
return x;
|
||||
return normalize_for_read(x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -232,7 +241,7 @@ public:
|
||||
|
||||
T* p = (T*)addr();
|
||||
|
||||
OrderAccess::release_store_fence((volatile T*)p, normalize(x));
|
||||
OrderAccess::release_store_fence((volatile T*)p, normalize_for_write(x));
|
||||
}
|
||||
|
||||
|
||||
@ -256,7 +265,7 @@ public:
|
||||
|
||||
jlong* p = (jlong*)addr();
|
||||
|
||||
Atomic::store(normalize(x), p);
|
||||
Atomic::store(normalize_for_write(x), p);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
@ -783,6 +792,7 @@ UNSAFE_ENTRY(jclass, Unsafe_DefineClass0(JNIEnv *env, jobject unsafe, jstring na
|
||||
|
||||
// define a class but do not make it known to the class loader or system dictionary
|
||||
// - host_class: supplies context for linkage, access control, protection domain, and class loader
|
||||
// if host_class is itself anonymous then it is replaced with its host class.
|
||||
// - data: bytes of a class file, a raw memory address (length gives the number of bytes)
|
||||
// - cp_patches: where non-null entries exist, they replace corresponding CP entries in data
|
||||
|
||||
@ -791,8 +801,12 @@ UNSAFE_ENTRY(jclass, Unsafe_DefineClass0(JNIEnv *env, jobject unsafe, jstring na
|
||||
// link to any member of U. Just after U is loaded, the only way to use it is reflectively,
|
||||
// through java.lang.Class methods like Class.newInstance.
|
||||
|
||||
// The package of an anonymous class must either match its host's class's package or be in the
|
||||
// unnamed package. If it is in the unnamed package then it will be put in its host class's
|
||||
// package.
|
||||
//
|
||||
|
||||
// Access checks for linkage sites within U continue to follow the same rules as for named classes.
|
||||
// The package of an anonymous class is given by the package qualifier on the name under which it was loaded.
|
||||
// An anonymous class also has special privileges to access any member of its host class.
|
||||
// This is the main reason why this loading operation is unsafe. The purpose of this is to
|
||||
// allow language implementations to simulate "open classes"; a host class in effect gets
|
||||
@ -874,9 +888,11 @@ Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
|
||||
|
||||
// Primitive types have NULL Klass* fields in their java.lang.Class instances.
|
||||
if (host_klass == NULL) {
|
||||
THROW_0(vmSymbols::java_lang_IllegalArgumentException());
|
||||
THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "Host class is null");
|
||||
}
|
||||
|
||||
assert(host_klass->is_instance_klass(), "Host class must be an instance class");
|
||||
|
||||
const char* host_source = host_klass->external_name();
|
||||
Handle host_loader(THREAD, host_klass->class_loader());
|
||||
Handle host_domain(THREAD, host_klass->protection_domain());
|
||||
@ -907,7 +923,7 @@ Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
|
||||
host_loader,
|
||||
host_domain,
|
||||
&st,
|
||||
host_klass,
|
||||
InstanceKlass::cast(host_klass),
|
||||
cp_patches,
|
||||
CHECK_NULL);
|
||||
if (anonk == NULL) {
|
||||
|
@ -33,8 +33,9 @@
|
||||
#include "gc/shared/referenceProcessor.hpp"
|
||||
#include "gc/shared/taskqueue.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "logging/logTag.hpp"
|
||||
#include "logging/logConfiguration.hpp"
|
||||
#include "logging/logStream.hpp"
|
||||
#include "logging/logTag.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "memory/universe.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
@ -4176,7 +4177,10 @@ bool Arguments::handle_deprecated_print_gc_flags() {
|
||||
if (_gc_log_filename != NULL) {
|
||||
// -Xloggc was used to specify a filename
|
||||
const char* gc_conf = PrintGCDetails ? "gc*" : "gc";
|
||||
return LogConfiguration::parse_log_arguments(_gc_log_filename, gc_conf, NULL, NULL, NULL);
|
||||
|
||||
LogTarget(Error, logging) target;
|
||||
LogStreamCHeap errstream(target);
|
||||
return LogConfiguration::parse_log_arguments(_gc_log_filename, gc_conf, NULL, NULL, &errstream);
|
||||
} else if (PrintGC || PrintGCDetails) {
|
||||
LogConfiguration::configure_stdout(LogLevel::Info, !PrintGCDetails, LOG_TAGS(gc));
|
||||
}
|
||||
|
@ -219,6 +219,9 @@ class ThreadInVMfromJava : public ThreadStateTransition {
|
||||
trans_from_java(_thread_in_vm);
|
||||
}
|
||||
~ThreadInVMfromJava() {
|
||||
if (_thread->stack_yellow_reserved_zone_disabled()) {
|
||||
_thread->enable_stack_yellow_reserved_zone();
|
||||
}
|
||||
trans(_thread_in_vm, _thread_in_Java);
|
||||
// Check for pending. async. exceptions or suspends.
|
||||
if (_thread->has_special_runtime_exit_condition()) _thread->handle_special_runtime_exit_condition();
|
||||
@ -306,6 +309,9 @@ class ThreadInVMfromJavaNoAsyncException : public ThreadStateTransition {
|
||||
trans_from_java(_thread_in_vm);
|
||||
}
|
||||
~ThreadInVMfromJavaNoAsyncException() {
|
||||
if (_thread->stack_yellow_reserved_zone_disabled()) {
|
||||
_thread->enable_stack_yellow_reserved_zone();
|
||||
}
|
||||
trans(_thread_in_vm, _thread_in_Java);
|
||||
// NOTE: We do not check for pending. async. exceptions.
|
||||
// If we did and moved the pending async exception over into the
|
||||
@ -314,6 +320,7 @@ class ThreadInVMfromJavaNoAsyncException : public ThreadStateTransition {
|
||||
// to the _thread_in_vm state. Instead we postpone the handling of
|
||||
// the async exception.
|
||||
|
||||
|
||||
// Check for pending. suspends only.
|
||||
if (_thread->has_special_runtime_exit_condition())
|
||||
_thread->handle_special_runtime_exit_condition(false);
|
||||
|
@ -412,13 +412,13 @@ oop Reflection::array_component_type(oop mirror, TRAPS) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool under_host_klass(const InstanceKlass* ik, const Klass* host_klass) {
|
||||
static bool under_host_klass(const InstanceKlass* ik, const InstanceKlass* host_klass) {
|
||||
DEBUG_ONLY(int inf_loop_check = 1000 * 1000 * 1000);
|
||||
for (;;) {
|
||||
const Klass* hc = (const Klass*)ik->host_klass();
|
||||
const InstanceKlass* hc = ik->host_klass();
|
||||
if (hc == NULL) return false;
|
||||
if (hc == host_klass) return true;
|
||||
ik = InstanceKlass::cast(hc);
|
||||
ik = hc;
|
||||
|
||||
// There's no way to make a host class loop short of patching memory.
|
||||
// Therefore there cannot be a loop here unless there's another bug.
|
||||
@ -436,8 +436,8 @@ static bool can_relax_access_check_for(const Klass* accessor,
|
||||
|
||||
// If either is on the other's host_klass chain, access is OK,
|
||||
// because one is inside the other.
|
||||
if (under_host_klass(accessor_ik, accessee) ||
|
||||
under_host_klass(accessee_ik, accessor))
|
||||
if (under_host_klass(accessor_ik, accessee_ik) ||
|
||||
under_host_klass(accessee_ik, accessor_ik))
|
||||
return true;
|
||||
|
||||
if ((RelaxAccessControlCheck &&
|
||||
|
@ -621,7 +621,7 @@ JRT_END
|
||||
// ret_pc points into caller; we are returning caller's exception handler
|
||||
// for given exception
|
||||
address SharedRuntime::compute_compiled_exc_handler(CompiledMethod* cm, address ret_pc, Handle& exception,
|
||||
bool force_unwind, bool top_frame_only) {
|
||||
bool force_unwind, bool top_frame_only, bool& recursive_exception_occurred) {
|
||||
assert(cm != NULL, "must exist");
|
||||
ResourceMark rm;
|
||||
|
||||
@ -677,6 +677,7 @@ address SharedRuntime::compute_compiled_exc_handler(CompiledMethod* cm, address
|
||||
// BCI of the exception handler which caused the exception to be
|
||||
// thrown (bugs 4307310 and 4546590). Set "exception" reference
|
||||
// argument to ensure that the correct exception is thrown (4870175).
|
||||
recursive_exception_occurred = true;
|
||||
exception = Handle(THREAD, PENDING_EXCEPTION);
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
if (handler_bci >= 0) {
|
||||
|
@ -189,7 +189,7 @@ class SharedRuntime: AllStatic {
|
||||
|
||||
// exception handling and implicit exceptions
|
||||
static address compute_compiled_exc_handler(CompiledMethod* nm, address ret_pc, Handle& exception,
|
||||
bool force_unwind, bool top_frame_only);
|
||||
bool force_unwind, bool top_frame_only, bool& recursive_exception_occurred);
|
||||
enum ImplicitExceptionKind {
|
||||
IMPLICIT_NULL,
|
||||
IMPLICIT_DIVIDE_BY_ZERO,
|
||||
|
@ -183,11 +183,8 @@ size_t ClassLoadingService::compute_class_size(InstanceKlass* k) {
|
||||
bool ClassLoadingService::set_verbose(bool verbose) {
|
||||
MutexLocker m(Management_lock);
|
||||
// verbose will be set to the previous value
|
||||
if (verbose) {
|
||||
LogConfiguration::parse_log_arguments("stdout", "class+load=info", NULL, NULL, NULL);
|
||||
} else {
|
||||
LogConfiguration::parse_log_arguments("stdout", "class+load=off", NULL, NULL, NULL);
|
||||
}
|
||||
LogLevelType level = verbose ? LogLevel::Info : LogLevel::Off;
|
||||
LogConfiguration::configure_stdout(level, false, LOG_TAGS(class, load));
|
||||
reset_trace_class_unloading();
|
||||
return verbose;
|
||||
}
|
||||
@ -196,11 +193,8 @@ bool ClassLoadingService::set_verbose(bool verbose) {
|
||||
void ClassLoadingService::reset_trace_class_unloading() {
|
||||
assert(Management_lock->owned_by_self(), "Must own the Management_lock");
|
||||
bool value = MemoryService::get_verbose() || ClassLoadingService::get_verbose();
|
||||
if (value) {
|
||||
LogConfiguration::parse_log_arguments("stdout", "class+unload=info", NULL, NULL, NULL);
|
||||
} else {
|
||||
LogConfiguration::parse_log_arguments("stdout", "class+unload=off", NULL, NULL, NULL);
|
||||
}
|
||||
LogLevelType level = value ? LogLevel::Info : LogLevel::Off;
|
||||
LogConfiguration::configure_stdout(level, false, LOG_TAGS(class, unload));
|
||||
}
|
||||
|
||||
GrowableArray<KlassHandle>* LoadedClassesEnumerator::_loaded_classes = NULL;
|
||||
|
@ -75,6 +75,7 @@ public class OverflowCodeCacheTest {
|
||||
System.out.printf("type %s%n", type);
|
||||
System.out.println("allocating till possible...");
|
||||
ArrayList<Long> blobs = new ArrayList<>();
|
||||
int compilationActivityMode = -1;
|
||||
try {
|
||||
long addr;
|
||||
int size = (int) (getHeapSize() >> 7);
|
||||
@ -88,13 +89,16 @@ public class OverflowCodeCacheTest {
|
||||
type + " doesn't allow using " + actualType + " when overflow");
|
||||
}
|
||||
}
|
||||
Asserts.assertNotEquals(WHITE_BOX.getCompilationActivityMode(), 1 /* run_compilation*/,
|
||||
"Compilation must be disabled when CodeCache(CodeHeap) overflows");
|
||||
/* now, remember compilationActivityMode to check it later, after freeing, since we
|
||||
possibly have no free cache for futher work */
|
||||
compilationActivityMode = WHITE_BOX.getCompilationActivityMode();
|
||||
} finally {
|
||||
for (Long blob : blobs) {
|
||||
WHITE_BOX.freeCodeBlob(blob);
|
||||
}
|
||||
}
|
||||
Asserts.assertNotEquals(compilationActivityMode, 1 /* run_compilation*/,
|
||||
"Compilation must be disabled when CodeCache(CodeHeap) overflows");
|
||||
}
|
||||
|
||||
private long getHeapSize() {
|
||||
|
@ -62,7 +62,7 @@ import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN;
|
||||
public class CallSiteDepContextTest {
|
||||
static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
static final MethodHandles.Lookup LOOKUP = MethodHandleHelper.IMPL_LOOKUP;
|
||||
static final String CLASS_NAME = "java/lang/invoke/Test";
|
||||
static final String CLASS_NAME = "compiler/jsr292/Test";
|
||||
static final String METHOD_NAME = "m";
|
||||
static final MethodType TYPE = MethodType.methodType(int.class);
|
||||
|
||||
@ -129,8 +129,8 @@ public class CallSiteDepContextTest {
|
||||
}
|
||||
|
||||
public static void testSharedCallSite() throws Throwable {
|
||||
Class<?> cls1 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_1"), null);
|
||||
Class<?> cls2 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("CS_2"), null);
|
||||
Class<?> cls1 = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("CS_1"), null);
|
||||
Class<?> cls2 = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("CS_2"), null);
|
||||
|
||||
MethodHandle[] mhs = new MethodHandle[] {
|
||||
LOOKUP.findStatic(cls1, METHOD_NAME, TYPE),
|
||||
@ -151,7 +151,7 @@ public class CallSiteDepContextTest {
|
||||
execute(1, mh);
|
||||
|
||||
// mcs.context == cls1
|
||||
Class<?> cls1 = UNSAFE.defineAnonymousClass(Object.class, getClassFile("NonBound_1"), null);
|
||||
Class<?> cls1 = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("NonBound_1"), null);
|
||||
MethodHandle mh1 = LOOKUP.findStatic(cls1, METHOD_NAME, TYPE);
|
||||
|
||||
execute(1, mh1);
|
||||
@ -170,8 +170,8 @@ public class CallSiteDepContextTest {
|
||||
mcs = new MutableCallSite(LOOKUP.findStatic(T.class, "f1", TYPE));
|
||||
|
||||
Class<?>[] cls = new Class[] {
|
||||
UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_1" + id), null),
|
||||
UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_2" + id), null),
|
||||
UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("GC_1" + id), null),
|
||||
UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("GC_2" + id), null),
|
||||
};
|
||||
|
||||
MethodHandle[] mhs = new MethodHandle[] {
|
||||
@ -185,7 +185,7 @@ public class CallSiteDepContextTest {
|
||||
execute(1, mhs);
|
||||
|
||||
ref = new PhantomReference<>(cls[0], rq);
|
||||
cls[0] = UNSAFE.defineAnonymousClass(Object.class, getClassFile("GC_3" + id), null);
|
||||
cls[0] = UNSAFE.defineAnonymousClass(CallSiteDepContextTest.class, getClassFile("GC_3" + id), null);
|
||||
mhs[0] = LOOKUP.findStatic(cls[0], METHOD_NAME, TYPE);
|
||||
|
||||
do {
|
||||
|
@ -19,7 +19,6 @@ import java.util.List;
|
||||
* @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
|
||||
* @library /test/lib /
|
||||
* @library ../common/patches
|
||||
* @ignore 8139383
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @modules java.base/jdk.internal.org.objectweb.asm
|
||||
* java.base/jdk.internal.org.objectweb.asm.tree
|
||||
|
@ -25,7 +25,6 @@
|
||||
* @test
|
||||
* @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
|
||||
* @library ../../../../../
|
||||
* @ignore 8161550
|
||||
* @modules java.base/jdk.internal.reflect
|
||||
* jdk.vm.ci/jdk.vm.ci.meta
|
||||
* jdk.vm.ci/jdk.vm.ci.runtime
|
||||
@ -74,11 +73,29 @@ import static org.junit.Assert.assertTrue;
|
||||
/**
|
||||
* Tests for {@link ResolvedJavaType}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class TestResolvedJavaType extends TypeUniverse {
|
||||
private static final Class<? extends Annotation> SIGNATURE_POLYMORPHIC_CLASS = findPolymorphicSignatureClass();
|
||||
|
||||
public TestResolvedJavaType() {
|
||||
}
|
||||
|
||||
private static Class<? extends Annotation> findPolymorphicSignatureClass() {
|
||||
Class<? extends Annotation> signaturePolyAnnotation = null;
|
||||
try {
|
||||
for (Class<?> clazz : TestResolvedJavaType.class.getClassLoader().loadClass("java.lang.invoke.MethodHandle").getDeclaredClasses()) {
|
||||
if (clazz.getName().endsWith("PolymorphicSignature") && Annotation.class.isAssignableFrom(clazz)) {
|
||||
signaturePolyAnnotation = (Class<? extends Annotation>) clazz;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throw new AssertionError("Could not find annotation PolymorphicSignature in java.lang.invoke.MethodHandle", e);
|
||||
}
|
||||
assertNotNull(signaturePolyAnnotation);
|
||||
return signaturePolyAnnotation;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findInstanceFieldWithOffsetTest() {
|
||||
for (Class<?> c : classes) {
|
||||
@ -577,8 +594,14 @@ public class TestResolvedJavaType extends TypeUniverse {
|
||||
for (Method decl : decls) {
|
||||
ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl);
|
||||
if (m.isPublic()) {
|
||||
ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl);
|
||||
assertEquals(m.toString(), i, type.resolveMethod(m, context));
|
||||
ResolvedJavaMethod resolvedmethod = type.resolveMethod(m, context);
|
||||
if (isSignaturePolymorphic(m)) {
|
||||
// Signature polymorphic methods must not be resolved
|
||||
assertNull(resolvedmethod);
|
||||
} else {
|
||||
ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl);
|
||||
assertEquals(m.toString(), i, resolvedmethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -606,8 +629,14 @@ public class TestResolvedJavaType extends TypeUniverse {
|
||||
for (Method decl : decls) {
|
||||
ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl);
|
||||
if (m.isPublic()) {
|
||||
ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl);
|
||||
assertEquals(i, type.resolveConcreteMethod(m, context));
|
||||
ResolvedJavaMethod resolvedMethod = type.resolveConcreteMethod(m, context);
|
||||
if (isSignaturePolymorphic(m)) {
|
||||
// Signature polymorphic methods must not be resolved
|
||||
assertNull(String.format("Got: %s", resolvedMethod), resolvedMethod);
|
||||
} else {
|
||||
ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl);
|
||||
assertEquals(i, resolvedMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -929,4 +958,8 @@ public class TestResolvedJavaType extends TypeUniverse {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isSignaturePolymorphic(ResolvedJavaMethod method) {
|
||||
return method.getAnnotation(SIGNATURE_POLYMORPHIC_CLASS) != null;
|
||||
}
|
||||
}
|
||||
|
@ -22,51 +22,32 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 6869327
|
||||
* @summary Test that C2 flag UseCountedLoopSafepoints ensures a safepoint is kept in a CountedLoop
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @ignore 8146096
|
||||
* @run driver compiler.loopopts.UseCountedLoopSafepoints
|
||||
*/
|
||||
|
||||
package compiler.loopopts;
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.lang.reflect.Method;
|
||||
import sun.hotspot.WhiteBox;
|
||||
import jdk.test.lib.Asserts;
|
||||
import compiler.whitebox.CompilerWhiteBoxTest;
|
||||
|
||||
public class UseCountedLoopSafepoints {
|
||||
private static final AtomicLong _num = new AtomicLong(0);
|
||||
private static final WhiteBox WB = WhiteBox.getWhiteBox();
|
||||
private static final String METHOD_NAME = "testMethod";
|
||||
|
||||
private long accum = 0;
|
||||
|
||||
// Uses the fact that an EnableBiasedLocking vmop will be started
|
||||
// after 500ms, while we are still in the loop. If there is a
|
||||
// safepoint in the counted loop, then we will reach safepoint
|
||||
// very quickly. Otherwise SafepointTimeout will be hit.
|
||||
public static void main (String args[]) throws Exception {
|
||||
if (args.length == 1) {
|
||||
final int loops = Integer.parseInt(args[0]);
|
||||
for (int i = 0; i < loops; i++) {
|
||||
_num.addAndGet(1);
|
||||
}
|
||||
} else {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||
"-XX:+IgnoreUnrecognizedVMOptions",
|
||||
"-XX:-TieredCompilation",
|
||||
"-XX:+UseBiasedLocking",
|
||||
"-XX:BiasedLockingStartupDelay=500",
|
||||
"-XX:+SafepointTimeout",
|
||||
"-XX:SafepointTimeoutDelay=2000",
|
||||
"-XX:+UseCountedLoopSafepoints",
|
||||
UseCountedLoopSafepoints.class.getName(),
|
||||
"2000000000"
|
||||
);
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldNotContain("Timeout detected");
|
||||
output.shouldHaveExitValue(0);
|
||||
new UseCountedLoopSafepoints().testMethod();
|
||||
Method m = UseCountedLoopSafepoints.class.getDeclaredMethod(METHOD_NAME);
|
||||
String directive = "[{ match: \"" + UseCountedLoopSafepoints.class.getName().replace('.', '/')
|
||||
+ "." + METHOD_NAME + "\", " + "BackgroundCompilation: false }]";
|
||||
Asserts.assertTrue(WB.addCompilerDirective(directive) == 1, "Can't add compiler directive");
|
||||
Asserts.assertTrue(WB.enqueueMethodForCompilation(m,
|
||||
CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION), "Can't enqueue method");
|
||||
}
|
||||
|
||||
private void testMethod() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
accum += accum << 5 + accum >> 4 - accum >>> 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
123
hotspot/test/compiler/loopopts/UseCountedLoopSafepointsTest.java
Normal file
123
hotspot/test/compiler/loopopts/UseCountedLoopSafepointsTest.java
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 6869327
|
||||
* @summary Test that C2 flag UseCountedLoopSafepoints ensures a safepoint is kept in a CountedLoop
|
||||
* @library /test/lib /
|
||||
* @requires vm.compMode != "Xint" & vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4)
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @build sun.hotspot.WhiteBox
|
||||
* @run driver ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||
* @run driver compiler.loopopts.UseCountedLoopSafepointsTest
|
||||
*/
|
||||
|
||||
package compiler.loopopts;
|
||||
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
/* Idea of this test is to check if ideal graph has CountedLoopEnd->SafePoint edge in case
|
||||
of UseCountedLoopSafepoint enabled and has no such edge in case it's disabled. Restricting
|
||||
compilation to testMethod only will leave only one counted loop (the one in testedMethod) */
|
||||
public class UseCountedLoopSafepointsTest {
|
||||
|
||||
public static void main (String args[]) {
|
||||
check(true); // check ideal graph with UseCountedLoopSafepoint enabled
|
||||
check(false); // ... and disabled
|
||||
}
|
||||
|
||||
private static void check(boolean enabled) {
|
||||
OutputAnalyzer oa;
|
||||
try {
|
||||
oa = ProcessTools.executeTestJvm("-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.",
|
||||
"-XX:" + (enabled ? "+" : "-") + "UseCountedLoopSafepoints", "-XX:+WhiteBoxAPI",
|
||||
"-XX:-Inline", "-Xbatch", "-XX:+PrintIdeal", "-XX:LoopUnrollLimit=0",
|
||||
"-XX:CompileOnly=" + UseCountedLoopSafepoints.class.getName() + "::testMethod",
|
||||
UseCountedLoopSafepoints.class.getName());
|
||||
} catch (Exception e) {
|
||||
throw new Error("Exception launching child for case enabled=" + enabled + " : " + e, e);
|
||||
}
|
||||
oa.shouldHaveExitValue(0);
|
||||
// parse output in seach of SafePoint and CountedLoopEnd nodes
|
||||
List<Node> safePoints = new ArrayList<>();
|
||||
List<Node> loopEnds = new ArrayList<>();
|
||||
for (String line : oa.getOutput().split("\\n")) {
|
||||
int separatorIndex = line.indexOf("\t===");
|
||||
if (separatorIndex > -1) {
|
||||
String header = line.substring(0, separatorIndex);
|
||||
if (header.endsWith("\tSafePoint")) {
|
||||
safePoints.add(new Node("SafePoint", line));
|
||||
} else if (header.endsWith("\tCountedLoopEnd")) {
|
||||
loopEnds.add(new Node("CountedLoopEnd", line));
|
||||
}
|
||||
}
|
||||
}
|
||||
// now, find CountedLoopEnd -> SafePoint edge
|
||||
boolean found = false;
|
||||
for (Node loopEnd : loopEnds) {
|
||||
found |= loopEnd.to.stream()
|
||||
.filter(id -> nodeListHasElementWithId(safePoints, id))
|
||||
.findAny()
|
||||
.isPresent();
|
||||
}
|
||||
Asserts.assertEQ(enabled, found, "Safepoint " + (found ? "" : "not ") + "found");
|
||||
}
|
||||
|
||||
private static boolean nodeListHasElementWithId(List<Node> list, int id) {
|
||||
return list.stream()
|
||||
.filter(node -> node.id == id)
|
||||
.findAny()
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
private static class Node {
|
||||
public final int id;
|
||||
public final List<Integer> from;
|
||||
public final List<Integer> to;
|
||||
|
||||
public Node(String name, String str) {
|
||||
List<Integer> tmpFrom = new ArrayList<>();
|
||||
List<Integer> tmpTo = new ArrayList<>();
|
||||
// parse string like: " $id $name === $to1 $to2 ... [[ $from1 $from2 ... ]] $anything"
|
||||
// example: 318 SafePoint === 317 1 304 1 1 10 308 [[ 97 74 ]] ...
|
||||
id = Integer.parseInt(str.substring(1, str.indexOf(name)).trim());
|
||||
Arrays.stream(str.substring(str.indexOf("===") + 4, str.indexOf("[[")).trim().split("\\s+"))
|
||||
.map(Integer::parseInt)
|
||||
.forEach(tmpTo::add);
|
||||
Arrays.stream(str.substring(str.indexOf("[[") + 3, str.indexOf("]]")).trim().split("\\s+"))
|
||||
.map(Integer::parseInt)
|
||||
.forEach(tmpFrom::add);
|
||||
this.from = Collections.unmodifiableList(tmpFrom);
|
||||
this.to = Collections.unmodifiableList(tmpTo);
|
||||
}
|
||||
}
|
||||
}
|
92
hotspot/test/compiler/unsafe/UnsafeOffHeapBooleanTest.java
Normal file
92
hotspot/test/compiler/unsafe/UnsafeOffHeapBooleanTest.java
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8161720
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @run main/othervm -Xint UnsafeOffHeapBooleanTest 1
|
||||
* @run main/othervm -XX:+TieredCompilation -XX:TieredStopAtLevel=3 -Xbatch UnsafeOffHeapBooleanTest 20000
|
||||
* @run main/othervm -XX:-TieredCompilation -Xbatch UnsafeOffHeapBooleanTest 20000
|
||||
*/
|
||||
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
public class UnsafeOffHeapBooleanTest {
|
||||
static boolean bool0 = false, bool1 = false, result = false;
|
||||
static Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
static long offHeapMemory;
|
||||
|
||||
public static void test() {
|
||||
// Write two bytes to the off-heap memory location, both
|
||||
// bytes correspond to the boolean value 'true'.
|
||||
UNSAFE.putShort(null, offHeapMemory, (short)0x0204);
|
||||
|
||||
// Read two bytes from the storage allocated above (as booleans).
|
||||
bool0 = UNSAFE.getBoolean(null, offHeapMemory + 0);
|
||||
bool1 = UNSAFE.getBoolean(null, offHeapMemory + 1);
|
||||
result = bool0 & bool1;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("### Test started");
|
||||
|
||||
if (args.length != 1) {
|
||||
throw new RuntimeException("### Test failure: test called with incorrect number of arguments");
|
||||
}
|
||||
|
||||
// Allocate two bytes of storage.
|
||||
offHeapMemory = UNSAFE.allocateMemory(2);
|
||||
|
||||
try {
|
||||
for (int i = 0; i < Integer.parseInt(args[0]); i++) {
|
||||
test();
|
||||
}
|
||||
|
||||
// Check if the two 'true' boolean values were normalized
|
||||
// (i.e., reduced from the range 1...255 to 1).
|
||||
if (!bool0 || !bool1 || !result) {
|
||||
System.out.println("Some of the results below are wrong");
|
||||
System.out.println("bool0 is: " + bool0);
|
||||
System.out.println("bool1 is: " + bool1);
|
||||
System.out.println("bool0 & bool1 is: " + result);
|
||||
System.out.println("===================================");
|
||||
throw new RuntimeException("### Test failed");
|
||||
} else {
|
||||
System.out.println("Test generated correct results");
|
||||
System.out.println("bool0 is: " + bool0);
|
||||
System.out.println("bool1 is: " + bool1);
|
||||
System.out.println("bool0 & bool1 is: " + result);
|
||||
System.out.println("===================================");
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
throw new RuntimeException("### Test failure: test called with incorrectly formatted parameter");
|
||||
}
|
||||
|
||||
UNSAFE.freeMemory(offHeapMemory);
|
||||
|
||||
System.out.println("### Test passed");
|
||||
}
|
||||
}
|
95
hotspot/test/compiler/unsafe/UnsafeOnHeapBooleanTest.java
Normal file
95
hotspot/test/compiler/unsafe/UnsafeOnHeapBooleanTest.java
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8161720
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @run main/othervm -Xint UnsafeOnHeapBooleanTest 1
|
||||
* @run main/othervm -XX:-UseOnStackReplacement -XX:+TieredCompilation -XX:TieredStopAtLevel=3 -Xbatch UnsafeOnHeapBooleanTest 20000
|
||||
* @run main/othervm -XX:-UseOnStackReplacement -XX:-TieredCompilation -Xbatch UnsafeOnHeapBooleanTest 20000
|
||||
*/
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
public class UnsafeOnHeapBooleanTest {
|
||||
static short static_v;
|
||||
static boolean bool0 = false, bool1 = false, result = false;
|
||||
static Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
|
||||
public static void test() {
|
||||
try {
|
||||
// Write two bytes into the static field
|
||||
// UnsafeOnHeapBooleanTest.static_v write two values. Both
|
||||
// bytes correspond to the boolean value 'true'.
|
||||
Field staticVField = UnsafeOnHeapBooleanTest.class.getDeclaredField("static_v");
|
||||
Object base = UNSAFE.staticFieldBase(staticVField);
|
||||
long offset = UNSAFE.staticFieldOffset(staticVField);
|
||||
UNSAFE.putShort(base, offset, (short)0x0204);
|
||||
|
||||
// Read two bytes from the static field
|
||||
// UnsafeOnHeapBooleanTest.static_v (as booleans).
|
||||
bool0 = UNSAFE.getBoolean(base, offset + 0);
|
||||
bool1 = UNSAFE.getBoolean(base, offset + 1);
|
||||
result = bool0 & bool1;
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new RuntimeException("### Test failure: static field UnsafeOnHeapBooleanTest.static_v was not found");
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("### Test started");
|
||||
|
||||
if (args.length != 1) {
|
||||
throw new RuntimeException("### Test failure: test called with incorrect number of arguments");
|
||||
}
|
||||
|
||||
try {
|
||||
for (int i = 0; i < Integer.parseInt(args[0]); i++) {
|
||||
test();
|
||||
}
|
||||
|
||||
// Check if the two 'true' boolean values were normalized
|
||||
// (i.e., reduced from the range 1...255 to 1).
|
||||
if (!bool0 || !bool1 || !result) {
|
||||
System.out.println("Some of the results below are wrong");
|
||||
System.out.println("bool0 is: " + bool0);
|
||||
System.out.println("bool1 is: " + bool1);
|
||||
System.out.println("bool0 & bool1 is: " + result);
|
||||
System.out.println("===================================");
|
||||
throw new RuntimeException("### Test failed");
|
||||
} else {
|
||||
System.out.println("Test generated correct results");
|
||||
System.out.println("bool0 is: " + bool0);
|
||||
System.out.println("bool1 is: " + bool1);
|
||||
System.out.println("bool0 & bool1 is: " + result);
|
||||
System.out.println("===================================");
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
throw new RuntimeException("### Test failure: test called with incorrectly formatted parameter");
|
||||
}
|
||||
|
||||
System.out.println("### Test passed");
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8161720
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xbatch -XX:-TieredCompilation UnsafeSmallOffsetBooleanAccessTest
|
||||
* @run main/othervm -Xbatch UnsafeSmallOffsetBooleanAccessTest
|
||||
*/
|
||||
|
||||
import java.util.Random;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
|
||||
public class UnsafeSmallOffsetBooleanAccessTest {
|
||||
static final Unsafe UNSAFE = Unsafe.getUnsafe();
|
||||
static final long F_OFFSET;
|
||||
static final Random random = new Random();
|
||||
|
||||
static {
|
||||
try {
|
||||
F_OFFSET = UNSAFE.objectFieldOffset(T.class.getDeclaredField("f"));
|
||||
System.out.println("The offset is: " + F_OFFSET);
|
||||
} catch (Exception e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static class T {
|
||||
boolean f;
|
||||
}
|
||||
|
||||
// Always return false in a way that is not obvious to the compiler.
|
||||
public static boolean myRandom() {
|
||||
if (random.nextInt(101) > 134) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean test(T t) {
|
||||
boolean result = false;
|
||||
for (int i = 0; i < 20000; i++) {
|
||||
boolean random = myRandom();
|
||||
// If myRandom() returns false, access t.f.
|
||||
//
|
||||
// If myRandom() returns true, access virtual address
|
||||
// F_OFFSET. That address is most likely not mapped,
|
||||
// therefore the access will most likely cause a
|
||||
// crash. We're not concerned about that, though, because
|
||||
// myRandom() always returns false. However, the C2
|
||||
// compiler avoids normalization of the value returned by
|
||||
// getBoolean in this case.
|
||||
result = UNSAFE.getBoolean(myRandom() ? null : t, F_OFFSET);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
T t = new T();
|
||||
UNSAFE.putBoolean(t, F_OFFSET, true);
|
||||
System.out.println("The result for t is: " + test(t));
|
||||
}
|
||||
}
|
103
hotspot/test/gc/TestNumWorkerOutput.java
Normal file
103
hotspot/test/gc/TestNumWorkerOutput.java
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test TestNumWorkerOutput
|
||||
* @bug 8165292
|
||||
* @summary Check that when PrintGCDetails is enabled, gc,task output is printed only once per collection.
|
||||
* @key gc
|
||||
* @requires vm.gc=="null"
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @library /test/lib
|
||||
* @build sun.hotspot.WhiteBox
|
||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* @run main/othervm -XX:+UseConcMarkSweepGC TestNumWorkerOutput UseConcMarkSweepGC
|
||||
* @run main/othervm -XX:+UseG1GC TestNumWorkerOutput UseG1GC
|
||||
*/
|
||||
|
||||
import sun.hotspot.WhiteBox;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import jdk.test.lib.Platform;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
import static jdk.test.lib.Asserts.*;
|
||||
|
||||
public class TestNumWorkerOutput {
|
||||
|
||||
public static void checkPatternOnce(String pattern, String what) throws Exception {
|
||||
Pattern r = Pattern.compile(pattern);
|
||||
Matcher m = r.matcher(what);
|
||||
|
||||
if (!m.find()) {
|
||||
throw new RuntimeException("Could not find pattern " + pattern + " in output");
|
||||
}
|
||||
if (m.find()) {
|
||||
throw new RuntimeException("Could find pattern " + pattern + " in output more than once");
|
||||
}
|
||||
}
|
||||
|
||||
public static void runTest(String gcArg) throws Exception {
|
||||
final String[] arguments = {
|
||||
"-Xbootclasspath/a:.",
|
||||
"-XX:+UnlockExperimentalVMOptions",
|
||||
"-XX:+UnlockDiagnosticVMOptions",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
"-XX:+" + gcArg,
|
||||
"-Xmx10M",
|
||||
"-XX:+PrintGCDetails",
|
||||
GCTest.class.getName()
|
||||
};
|
||||
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(arguments);
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
|
||||
output.shouldHaveExitValue(0);
|
||||
|
||||
System.out.println(output.getStdout());
|
||||
|
||||
String stdout = output.getStdout();
|
||||
|
||||
checkPatternOnce(".*[info.*].*[gc,task.*].*GC\\(0\\) .*Using \\d+ workers of \\d+ for evacuation.*", stdout);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
runTest(args[0]);
|
||||
}
|
||||
|
||||
static class GCTest {
|
||||
private static final WhiteBox WB = WhiteBox.getWhiteBox();
|
||||
|
||||
public static Object holder;
|
||||
|
||||
public static void main(String [] args) {
|
||||
holder = new byte[100];
|
||||
WB.youngGC();
|
||||
System.out.println(holder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
120
hotspot/test/runtime/RedefineTests/RedefinePreviousVersions.java
Normal file
120
hotspot/test/runtime/RedefineTests/RedefinePreviousVersions.java
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8165246
|
||||
* @summary Test has_previous_versions flag and processing during class unloading.
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @modules java.compiler
|
||||
* java.instrument
|
||||
* jdk.jartool/sun.tools.jar
|
||||
* @run main RedefineClassHelper
|
||||
* @run main/othervm RedefinePreviousVersions test
|
||||
*/
|
||||
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
|
||||
public class RedefinePreviousVersions {
|
||||
|
||||
public static String newB =
|
||||
"class RedefinePreviousVersions$B {" +
|
||||
"}";
|
||||
|
||||
static class B { }
|
||||
|
||||
public static String newRunning =
|
||||
"class RedefinePreviousVersions$Running {" +
|
||||
" public static volatile boolean stop = true;" +
|
||||
" static void localSleep() { }" +
|
||||
" public static void infinite() { }" +
|
||||
"}";
|
||||
|
||||
static class Running {
|
||||
public static volatile boolean stop = false;
|
||||
static void localSleep() {
|
||||
try{
|
||||
Thread.currentThread().sleep(10);//sleep for 10 ms
|
||||
} catch(InterruptedException ie) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void infinite() {
|
||||
while (!stop) { localSleep(); }
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
if (args.length > 0) {
|
||||
|
||||
String jarFile = System.getProperty("test.src") + "/testcase.jar";
|
||||
|
||||
// java -javaagent:redefineagent.jar -Xlog:stuff RedefinePreviousVersions
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( "-javaagent:redefineagent.jar",
|
||||
"-Xlog:redefine+class+iklass+add=trace,redefine+class+iklass+purge=trace",
|
||||
"RedefinePreviousVersions");
|
||||
new OutputAnalyzer(pb.start())
|
||||
.shouldContain("Class unloading: has_previous_versions = false")
|
||||
.shouldContain("Class unloading: has_previous_versions = true")
|
||||
.shouldHaveExitValue(0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Redefine a class and create some garbage
|
||||
// Since there are no methods running, the previous version is never added to the
|
||||
// previous_version_list and the flag _has_previous_versions should stay false
|
||||
RedefineClassHelper.redefineClass(B.class, newB);
|
||||
|
||||
for (int i = 0; i < 10 ; i++) {
|
||||
String s = new String("some garbage");
|
||||
System.gc();
|
||||
}
|
||||
|
||||
// Start a class that has a method running
|
||||
new Thread() {
|
||||
public void run() {
|
||||
Running.infinite();
|
||||
}
|
||||
}.start();
|
||||
|
||||
// Since a method of newRunning is running, this class should be added to the previous_version_list
|
||||
// of Running, and _has_previous_versions should return true at class unloading.
|
||||
RedefineClassHelper.redefineClass(Running.class, newRunning);
|
||||
|
||||
for (int i = 0; i < 10 ; i++) {
|
||||
String s = new String("some garbage");
|
||||
System.gc();
|
||||
}
|
||||
|
||||
// purge should clean everything up, except Xcomp it might not.
|
||||
Running.stop = true;
|
||||
|
||||
for (int i = 0; i < 10 ; i++) {
|
||||
String s = new String("some garbage");
|
||||
System.gc();
|
||||
}
|
||||
}
|
||||
}
|
134
hotspot/test/runtime/defineAnonClass/DefineAnon.java
Normal file
134
hotspot/test/runtime/defineAnonClass/DefineAnon.java
Normal file
@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test DefineAnon
|
||||
* @bug 8058575
|
||||
* @library /testlibrary
|
||||
* @modules java.base/jdk.internal.org.objectweb.asm
|
||||
* java.management
|
||||
* @compile -XDignore.symbol.file=true DefineAnon.java
|
||||
* @run main/othervm p1.DefineAnon
|
||||
*/
|
||||
|
||||
package p1;
|
||||
|
||||
import jdk.internal.org.objectweb.asm.ClassWriter;
|
||||
import jdk.internal.org.objectweb.asm.MethodVisitor;
|
||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||
import sun.misc.Unsafe;
|
||||
|
||||
|
||||
class T {
|
||||
static protected void test0() { System.out.println("test0 (public)"); }
|
||||
static protected void test1() { System.out.println("test1 (protected)"); }
|
||||
static /*package-private*/ void test2() { System.out.println("test2 (package)"); }
|
||||
static private void test3() { System.out.println("test3 (private)"); }
|
||||
}
|
||||
|
||||
public class DefineAnon {
|
||||
|
||||
private static Unsafe getUnsafe() {
|
||||
try {
|
||||
java.lang.reflect.Field singleoneInstanceField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||
singleoneInstanceField.setAccessible(true);
|
||||
return (Unsafe) singleoneInstanceField.get(null);
|
||||
} catch (Throwable ex) {
|
||||
throw new RuntimeException("Was unable to get Unsafe instance.");
|
||||
}
|
||||
}
|
||||
|
||||
static Unsafe UNSAFE = DefineAnon.getUnsafe();
|
||||
|
||||
static Class<?> getAnonClass(Class<?> hostClass, final String className) {
|
||||
final String superName = "java/lang/Object";
|
||||
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS + ClassWriter.COMPUTE_FRAMES);
|
||||
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, className, null, superName, null);
|
||||
|
||||
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC, "test", "()V", null, null);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test0", "()V", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test1", "()V", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test2", "()V", false);
|
||||
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "p1/T", "test3", "()V", false);
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitMaxs(0, 0);
|
||||
mv.visitEnd();
|
||||
|
||||
final byte[] classBytes = cw.toByteArray();
|
||||
Class<?> invokerClass = UNSAFE.defineAnonymousClass(hostClass, classBytes, new Object[0]);
|
||||
UNSAFE.ensureClassInitialized(invokerClass);
|
||||
return invokerClass;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
Throwable fail = null;
|
||||
|
||||
// Anonymous class has the privileges of its host class, so test[0123] should all work.
|
||||
System.out.println("Injecting from the same package (p1):");
|
||||
Class<?> p1cls = getAnonClass(T.class, "p1/AnonClass");
|
||||
try {
|
||||
p1cls.getMethod("test").invoke(null);
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
fail = ex; // throw this to make test fail, since subtest failed
|
||||
}
|
||||
|
||||
// Anonymous class has different package name from host class. Should throw
|
||||
// IllegalArgumentException.
|
||||
System.out.println("Injecting from the wrong package (p2):");
|
||||
try {
|
||||
Class<?> p2cls = getAnonClass(DefineAnon.class, "p2/AnonClass");
|
||||
p2cls.getMethod("test").invoke(null);
|
||||
System.out.println("Failed, did not get expected IllegalArgumentException");
|
||||
} catch (java.lang.IllegalArgumentException e) {
|
||||
if (e.getMessage().contains("Host class p1/DefineAnon and anonymous class p2/AnonClass")) {
|
||||
System.out.println("Got expected IllegalArgumentException: " + e.getMessage());
|
||||
} else {
|
||||
throw new RuntimeException("Unexpected message: " + e.getMessage());
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
fail = ex; // throw this to make test fail, since subtest failed
|
||||
}
|
||||
|
||||
// Inject a class in the unnamed package into p1.T. It should be able
|
||||
// to access all methods in p1.T.
|
||||
System.out.println("Injecting unnamed package into correct host class:");
|
||||
try {
|
||||
Class<?> p3cls = getAnonClass(T.class, "AnonClass");
|
||||
p3cls.getMethod("test").invoke(null);
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
fail = ex; // throw this to make test fail, since subtest failed
|
||||
}
|
||||
|
||||
// Try using an array class as the host class. This should throw IllegalArgumentException.
|
||||
try {
|
||||
Class<?> p3cls = getAnonClass(String[].class, "AnonClass");
|
||||
throw new RuntimeException("Expected IllegalArgumentException not thrown");
|
||||
} catch (IllegalArgumentException ex) {
|
||||
}
|
||||
|
||||
if (fail != null) throw fail; // make test fail, since subtest failed
|
||||
}
|
||||
}
|
91
hotspot/test/runtime/defineAnonClass/NestedUnsafe.java
Normal file
91
hotspot/test/runtime/defineAnonClass/NestedUnsafe.java
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8058575
|
||||
* @summary Creates an anonymous class inside of an anonymous class.
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.compiler
|
||||
* java.management
|
||||
* @run main p.NestedUnsafe
|
||||
*/
|
||||
|
||||
package p;
|
||||
|
||||
import java.security.ProtectionDomain;
|
||||
import java.io.InputStream;
|
||||
import java.lang.*;
|
||||
import jdk.test.lib.*;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.test.lib.unsafe.UnsafeHelper;
|
||||
|
||||
|
||||
// Test that an anonymous class in package 'p' cannot define its own anonymous class
|
||||
// in another package.
|
||||
public class NestedUnsafe {
|
||||
// The String concatenation should create the nested anonymous class.
|
||||
static byte klassbuf[] = InMemoryJavaCompiler.compile("q.TestClass",
|
||||
"package q; " +
|
||||
"public class TestClass { " +
|
||||
" public static void concat(String one, String two) throws Throwable { " +
|
||||
" System.out.println(one + two);" +
|
||||
" } } ");
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
Unsafe unsafe = UnsafeHelper.getUnsafe();
|
||||
|
||||
// The anonymous class calls defineAnonymousClass creating a nested anonymous class.
|
||||
byte klassbuf2[] = InMemoryJavaCompiler.compile("p.TestClass2",
|
||||
"package p; " +
|
||||
"import jdk.internal.misc.Unsafe; " +
|
||||
"public class TestClass2 { " +
|
||||
" public static void doit() throws Throwable { " +
|
||||
" Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe(); " +
|
||||
" Class klass2 = unsafe.defineAnonymousClass(TestClass2.class, p.NestedUnsafe.klassbuf, new Object[0]); " +
|
||||
" unsafe.ensureClassInitialized(klass2); " +
|
||||
" Class[] dArgs = new Class[2]; " +
|
||||
" dArgs[0] = String.class; " +
|
||||
" dArgs[1] = String.class; " +
|
||||
" try { " +
|
||||
" klass2.getMethod(\"concat\", dArgs).invoke(null, \"CC\", \"DD\"); " +
|
||||
" } catch (Throwable ex) { " +
|
||||
" throw new RuntimeException(\"Exception: \" + ex.toString()); " +
|
||||
" } " +
|
||||
"} } ",
|
||||
"--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED");
|
||||
|
||||
Class klass2 = unsafe.defineAnonymousClass(p.NestedUnsafe.class, klassbuf2, new Object[0]);
|
||||
try {
|
||||
klass2.getMethod("doit").invoke(null);
|
||||
throw new RuntimeException("Expected exception not thrown");
|
||||
} catch (Throwable ex) {
|
||||
Throwable iae = ex.getCause();
|
||||
if (!iae.toString().contains(
|
||||
"IllegalArgumentException: Host class p/NestedUnsafe and anonymous class q/TestClass")) {
|
||||
throw new RuntimeException("Exception: " + iae.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
90
hotspot/test/runtime/defineAnonClass/NestedUnsafe2.java
Normal file
90
hotspot/test/runtime/defineAnonClass/NestedUnsafe2.java
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8058575
|
||||
* @summary Creates an anonymous class inside of an anonymous class.
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.compiler
|
||||
* java.management
|
||||
* @run main p.NestedUnsafe2
|
||||
*/
|
||||
|
||||
package p;
|
||||
|
||||
import java.security.ProtectionDomain;
|
||||
import java.io.InputStream;
|
||||
import java.lang.*;
|
||||
import jdk.test.lib.*;
|
||||
import jdk.internal.misc.Unsafe;
|
||||
import jdk.test.lib.unsafe.UnsafeHelper;
|
||||
|
||||
|
||||
// Test that an anonymous class that gets put in its host's package cannot define
|
||||
// an anonymous class in another package.
|
||||
public class NestedUnsafe2 {
|
||||
// The String concatenation should create the nested anonymous class.
|
||||
public static byte klassbuf[] = InMemoryJavaCompiler.compile("q.TestClass",
|
||||
"package q; " +
|
||||
"public class TestClass { " +
|
||||
" public static void concat(String one, String two) throws Throwable { " +
|
||||
" System.out.println(one + two);" +
|
||||
" } } ");
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
Unsafe unsafe = UnsafeHelper.getUnsafe();
|
||||
|
||||
// The anonymous class calls defineAnonymousClass creating a nested anonymous class.
|
||||
byte klassbuf2[] = InMemoryJavaCompiler.compile("TestClass2",
|
||||
"import jdk.internal.misc.Unsafe; " +
|
||||
"public class TestClass2 { " +
|
||||
" public static void doit() throws Throwable { " +
|
||||
" Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe(); " +
|
||||
" Class klass2 = unsafe.defineAnonymousClass(TestClass2.class, p.NestedUnsafe2.klassbuf, new Object[0]); " +
|
||||
" unsafe.ensureClassInitialized(klass2); " +
|
||||
" Class[] dArgs = new Class[2]; " +
|
||||
" dArgs[0] = String.class; " +
|
||||
" dArgs[1] = String.class; " +
|
||||
" try { " +
|
||||
" klass2.getMethod(\"concat\", dArgs).invoke(null, \"CC\", \"DD\"); " +
|
||||
" } catch (Throwable ex) { " +
|
||||
" throw new RuntimeException(\"Exception: \" + ex.toString()); " +
|
||||
" } " +
|
||||
"} } ",
|
||||
"--add-exports=java.base/jdk.internal.misc=ALL-UNNAMED");
|
||||
|
||||
Class klass2 = unsafe.defineAnonymousClass(p.NestedUnsafe2.class, klassbuf2, new Object[0]);
|
||||
try {
|
||||
klass2.getMethod("doit").invoke(null);
|
||||
throw new RuntimeException("Expected exception not thrown");
|
||||
} catch (Throwable ex) {
|
||||
Throwable iae = ex.getCause();
|
||||
if (!iae.toString().contains(
|
||||
"IllegalArgumentException: Host class p/NestedUnsafe2 and anonymous class q/TestClass")) {
|
||||
throw new RuntimeException("Exception: " + iae.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -40,7 +40,7 @@ TESTLIBRARY_DIR = ../../../../test/lib
|
||||
JAVAC = $(JDK_HOME)/bin/javac
|
||||
JAR = $(JDK_HOME)/bin/jar
|
||||
|
||||
SRC_FILES = $(shell find $(SRC_DIR) $(TESTLIBRARY_DIR)/share/classes -name '*.java')
|
||||
SRC_FILES = $(shell find $(SRC_DIR) $(TESTLIBRARY_DIR)/jdk/test/lib -name '*.java')
|
||||
WB_SRC_FILES = $(shell find $(TESTLIBRARY_DIR)/sun/hotspot -name '*.java')
|
||||
|
||||
MAIN_CLASS = sun.hotspot.tools.ctw.CompileTheWorld
|
||||
|
@ -56,7 +56,6 @@ BUILD_DIR = build
|
||||
CLASSES_DIR = $(BUILD_DIR)/classes
|
||||
SRC_DIR = src
|
||||
TEST_DIR = test
|
||||
DRIVER_DIR = $(TESTBASE_DIR)/jdk/test/lib/jittester/jtreg
|
||||
MANIFEST = manifest.mf
|
||||
APPLICATION_ARGS += \
|
||||
--property-file $(PROPERTY_FILE) \
|
||||
@ -118,19 +117,18 @@ cleantmp:
|
||||
@rm filelist
|
||||
@rm -rf $(CLASSES_DIR)
|
||||
|
||||
copytestlibrary: $(DRIVER_DIR)
|
||||
@cp -r src/jdk/test/lib/jittester/jtreg/*.java $(DRIVER_DIR)
|
||||
copytestlibrary: $(TESTBASE_DIR)/jdk/test/lib/jittester/jtreg
|
||||
@cp -r src/jdk/test/lib/jittester/jtreg/*.java $(TESTBASE_DIR)/jdk/test/lib/jittester/jtreg
|
||||
@cp -r $(TESTLIBRARY_SRC_DIR) $(TESTBASE_DIR)/jdk/test/
|
||||
|
||||
testgroup: $(TESTBASE_DIR)
|
||||
@echo 'jittester_all = \\' > $(TESTGROUP_FILE)
|
||||
@echo ' /' >> $(TESTGROUP_FILE)
|
||||
@echo '' >> $(TESTGROUP_FILE)
|
||||
@echo 'main = \\' >> $(TESTGROUP_FILE)
|
||||
@echo ' Test_0.java' >> $(TESTGROUP_FILE)
|
||||
|
||||
testroot: $(TESTBASE_DIR)
|
||||
@echo 'groups=TEST.groups' > $(TESTROOT_FILE)
|
||||
|
||||
$(TESTBASE_DIR) $(DIST_DIR) $(DRIVER_DIR):
|
||||
$(TESTBASE_DIR) $(DIST_DIR) $(TESTBASE_DIR)/jdk/test/lib/jittester/jtreg:
|
||||
$(shell if [ ! -d $@ ]; then mkdir -p $@; fi)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user