This commit is contained in:
Dean Long 2016-09-08 23:43:45 -04:00
commit 45204fc0bf
29 changed files with 660 additions and 101 deletions

View file

@ -2921,6 +2921,26 @@ enc_class Fast_Unlock(iRegP oop, iRegP box, o7RegP scratch, iRegP scratch2) %{
__ cmp( Rold, O7 ); __ 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 ) %{ enc_class enc_lflags_ne_to_boolean( iRegI res ) %{
Register Rres = reg_to_register_object($res$$reg); 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 ) %{ instruct compareAndSwapL_bool(iRegP mem_ptr, iRegL oldval, iRegL newval, iRegI res, o7RegI tmp1, flagsReg ccr ) %{
predicate(VM_Version::supports_cx8()); predicate(VM_Version::supports_cx8());
match(Set res (CompareAndSwapL mem_ptr (Binary oldval newval))); 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); effect( USE mem_ptr, KILL ccr, KILL tmp1);
format %{ format %{
"MOV $newval,O7\n\t" "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 ) %{ 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 (CompareAndSwapI mem_ptr (Binary oldval newval)));
match(Set res (WeakCompareAndSwapI mem_ptr (Binary oldval newval)));
effect( USE mem_ptr, KILL ccr, KILL tmp1); effect( USE mem_ptr, KILL ccr, KILL tmp1);
format %{ format %{
"MOV $newval,O7\n\t" "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()); predicate(VM_Version::supports_cx8());
#endif #endif
match(Set res (CompareAndSwapP mem_ptr (Binary oldval newval))); 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); effect( USE mem_ptr, KILL ccr, KILL tmp1);
format %{ format %{
"MOV $newval,O7\n\t" "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 ) %{ 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 (CompareAndSwapN mem_ptr (Binary oldval newval)));
match(Set res (WeakCompareAndSwapN mem_ptr (Binary oldval newval)));
effect( USE mem_ptr, KILL ccr, KILL tmp1); effect( USE mem_ptr, KILL ccr, KILL tmp1);
format %{ format %{
"MOV $newval,O7\n\t" "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 ); 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) %{ instruct xchgI( memory mem, iRegI newval) %{
match(Set newval (GetAndSetI mem newval)); match(Set newval (GetAndSetI mem newval));
format %{ "SWAP [$mem],$newval" %} format %{ "SWAP [$mem],$newval" %}

View file

@ -8131,8 +8131,7 @@ void MacroAssembler::has_negatives(Register ary1, Register len,
jmp(FALSE_LABEL); jmp(FALSE_LABEL);
clear_vector_masking(); // closing of the stub context for programming mask registers clear_vector_masking(); // closing of the stub context for programming mask registers
} } else {
else {
movl(result, len); // copy movl(result, len); // copy
if (UseAVX == 2 && UseSSE >= 2) { if (UseAVX == 2 && UseSSE >= 2) {
@ -8169,8 +8168,7 @@ void MacroAssembler::has_negatives(Register ary1, Register len,
bind(COMPARE_TAIL); // len is zero bind(COMPARE_TAIL); // len is zero
movl(len, result); movl(len, result);
// Fallthru to tail compare // Fallthru to tail compare
} } else if (UseSSE42Intrinsics) {
else if (UseSSE42Intrinsics) {
// With SSE4.2, use double quad vector compare // With SSE4.2, use double quad vector compare
Label COMPARE_WIDE_VECTORS, COMPARE_TAIL; 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 // save length for return
push(len); push(len);
// 8165287: EVEX version disabled for now, needs to be refactored as
// it is returning incorrect results.
if ((UseAVX > 2) && // AVX512 if ((UseAVX > 2) && // AVX512
0 &&
VM_Version::supports_avx512vlbw() && VM_Version::supports_avx512vlbw() &&
VM_Version::supports_bmi2()) { VM_Version::supports_bmi2()) {
@ -11067,10 +11068,11 @@ void MacroAssembler::byte_array_inflate(Register src, Register dst, Register len
bind(below_threshold); bind(below_threshold);
bind(copy_new_tail); bind(copy_new_tail);
if (UseAVX > 2) { if ((UseAVX > 2) &&
VM_Version::supports_avx512vlbw() &&
VM_Version::supports_bmi2()) {
movl(tmp2, len); movl(tmp2, len);
} } else {
else {
movl(len, tmp2); movl(len, tmp2);
} }
andl(tmp2, 0x00000007); andl(tmp2, 0x00000007);

View file

@ -366,8 +366,8 @@ final class CompilerToVM {
* {@code exactReceiver}. * {@code exactReceiver}.
* *
* @param caller the caller or context type used to perform access checks * @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 * @return the link-time resolved method (might be abstract) or {@code null} if it is either a
* linked * signature polymorphic method or can not be linked.
*/ */
native HotSpotResolvedJavaMethodImpl resolveMethod(HotSpotResolvedObjectTypeImpl exactReceiver, HotSpotResolvedJavaMethodImpl method, HotSpotResolvedObjectTypeImpl caller); native HotSpotResolvedJavaMethodImpl resolveMethod(HotSpotResolvedObjectTypeImpl exactReceiver, HotSpotResolvedJavaMethodImpl method, HotSpotResolvedObjectTypeImpl caller);

View file

@ -722,7 +722,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
/** /**
* Determines if {@code type} contains signature polymorphic methods. * 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(); String name = type.getName();
if (signaturePolymorphicHolders == null) { if (signaturePolymorphicHolders == null) {
signaturePolymorphicHolders = compilerToVM().getSignaturePolymorphicHolders(); signaturePolymorphicHolders = compilerToVM().getSignaturePolymorphicHolders();

View file

@ -24,6 +24,7 @@ package jdk.vm.ci.hotspot;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static jdk.vm.ci.hotspot.CompilerToVM.compilerToVM; 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.HotSpotJVMCIRuntime.runtime;
import static jdk.vm.ci.hotspot.HotSpotVMConfig.config; import static jdk.vm.ci.hotspot.HotSpotVMConfig.config;
import static jdk.vm.ci.hotspot.UnsafeAccess.UNSAFE; 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 // Methods can only be resolved against concrete types
return null; 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; return method;
} }
if (!method.getDeclaringClass().isAssignableFrom(this)) { if (!method.getDeclaringClass().isAssignableFrom(this)) {

View file

@ -209,8 +209,8 @@ public interface ResolvedJavaType extends JavaType, ModifiersProvider, Annotated
* *
* @param method the method to select the implementation of * @param method the method to select the implementation of
* @param callerType the caller or context type used to perform access checks * @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 * @return the link-time resolved method (might be abstract) or {@code null} if it is either a
* it can not be resolved * signature polymorphic method or can not be linked.
*/ */
ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType); ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType);

View file

@ -2410,6 +2410,15 @@ void LIRGenerator::do_UnsafeGetObject(UnsafeGetObject* x) {
#endif // INCLUDE_ALL_GCS #endif // INCLUDE_ALL_GCS
if (x->is_volatile() && os::is_MP()) __ membar_acquire(); 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());
}
} }

View file

@ -576,9 +576,8 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
// normal bytecode execution. // normal bytecode execution.
thread->clear_exception_oop_and_pc(); thread->clear_exception_oop_and_pc();
Handle original_exception(thread, exception()); bool recursive_exception = false;
continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false, recursive_exception);
continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false);
// If an exception was thrown during exception dispatch, the exception oop may have changed // If an exception was thrown during exception dispatch, the exception oop may have changed
thread->set_exception_oop(exception()); thread->set_exception_oop(exception());
thread->set_exception_pc(pc); 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 // the exception cache is used only by non-implicit exceptions
// Update the exception cache only when there didn't happen // Update the exception cache only when there didn't happen
// another exception during the computation of the compiled // another exception during the computation of the compiled
// exception handler. // exception handler. Checking for exception oop equality is not
if (continuation != NULL && original_exception() == exception()) { // sufficient because some exceptions are pre-allocated and reused.
if (continuation != NULL && !recursive_exception) {
nm->add_handler_for_exception_and_pc(exception, pc, continuation); nm->add_handler_for_exception_and_pc(exception, pc, continuation);
} }
} }

View file

@ -1305,7 +1305,7 @@ void CodeCache::report_codemem_full(int code_blob_type, bool print) {
event.set_entryCount(heap->blob_count()); event.set_entryCount(heap->blob_count());
event.set_methodCount(heap->nmethod_count()); event.set_methodCount(heap->nmethod_count());
event.set_adaptorCount(heap->adapter_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.set_fullCount(heap->full_count());
event.commit(); event.commit();
} }

View file

@ -576,27 +576,39 @@ void InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecodes::Code byt
// compute auxiliary field attributes // compute auxiliary field attributes
TosState state = as_TosState(info.field_type()); TosState state = as_TosState(info.field_type());
// Put instructions on final fields are not resolved. This is required so we throw // Resolution of put instructions on final fields is delayed. That is required so that
// exceptions at the correct place (when the instruction is actually invoked). // 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 // 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. // 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 // Also, we need to delay resolving getstatic and putstatic instructions until the
// class is initialized. This is required so that access to the static // class is initialized. This is required so that access to the static
// field will call the initialization function every time until the class // field will call the initialization function every time until the class
// is completely initialized ala. in 2.17.5 in JVM Specification. // is completely initialized ala. in 2.17.5 in JVM Specification.
InstanceKlass* klass = InstanceKlass::cast(info.field_holder()); InstanceKlass* klass = InstanceKlass::cast(info.field_holder());
bool uninitialized_static = ((bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic) && bool uninitialized_static = is_static && !klass->is_initialized();
!klass->is_initialized()); bool has_initialized_final_update = info.field_holder()->major_version() >= 53 &&
info.has_initialized_final_update();
Bytecodes::Code put_code = (Bytecodes::Code)0; assert(!(has_initialized_final_update && !info.access_flags().is_final()), "Fields with initialized final updates must be final");
if (is_put && !info.access_flags().is_final() && !uninitialized_static) {
put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
}
Bytecodes::Code get_code = (Bytecodes::Code)0; Bytecodes::Code get_code = (Bytecodes::Code)0;
Bytecodes::Code put_code = (Bytecodes::Code)0;
if (!uninitialized_static) { if (!uninitialized_static) {
get_code = ((is_static) ? Bytecodes::_getstatic : Bytecodes::_getfield); 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( cp_cache_entry->set_field(

View file

@ -768,6 +768,11 @@ C2V_VMENTRY(jobject, resolveMethod, (JNIEnv *, jobject, jobject receiver_jvmci_t
Symbol* h_name = method->name(); Symbol* h_name = method->name();
Symbol* h_signature = method->signature(); 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); LinkInfo link_info(h_resolved, h_name, h_signature, caller_klass);
methodHandle m; methodHandle m;
// Only do exact lookup if receiver klass has been linked. Otherwise, // 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()) { 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; return NULL;
} }

View file

@ -313,13 +313,18 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* t
// normal bytecode execution. // normal bytecode execution.
thread->clear_exception_oop_and_pc(); 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 // If an exception was thrown during exception dispatch, the exception oop may have changed
thread->set_exception_oop(exception()); thread->set_exception_oop(exception());
thread->set_exception_pc(pc); thread->set_exception_pc(pc);
// the exception cache is used only by non-implicit exceptions // 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); cm->add_handler_for_exception_and_pc(exception, pc, continuation);
} }
} }

View file

@ -431,6 +431,12 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive, bool clean_alive
if (clean_alive_klasses && current->is_instance_klass()) { if (clean_alive_klasses && current->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(current); InstanceKlass* ik = InstanceKlass::cast(current);
ik->clean_weak_instanceklass_links(is_alive); 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);
}
} }
} }
} }

View file

@ -2172,10 +2172,9 @@ Node* GraphKit::record_profiled_receiver_for_speculation(Node* n) {
java_bc() == Bytecodes::_instanceof || java_bc() == Bytecodes::_instanceof ||
java_bc() == Bytecodes::_aastore) { java_bc() == Bytecodes::_aastore) {
ciProfileData* data = method()->method_data()->bci_to_data(bci()); 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 record_profile_for_speculation(n, exact_kls, maybe_null);
return n;
} }
/** /**

View file

@ -2475,6 +2475,28 @@ bool LibraryCallKit::inline_unsafe_access(bool is_store, const BasicType type, c
// load value // load value
switch (type) { switch (type) {
case T_BOOLEAN: 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_CHAR:
case T_BYTE: case T_BYTE:
case T_SHORT: case T_SHORT:

View file

@ -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); force_unwind ? NULL : nm->handler_for_exception_and_pc(exception, pc);
if (handler_address == NULL) { if (handler_address == NULL) {
Handle original_exception(thread, exception()); bool recursive_exception = false;
handler_address = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, force_unwind, true); handler_address = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, force_unwind, true, recursive_exception);
assert (handler_address != NULL, "must have compiled handler"); assert (handler_address != NULL, "must have compiled handler");
// Update the exception cache only when the unwind was not forced // Update the exception cache only when the unwind was not forced
// and there didn't happen another exception during the computation of the // and there didn't happen another exception during the computation of the
// compiled exception handler. // compiled exception handler. Checking for exception oop equality is not
if (!force_unwind && original_exception() == exception()) { // 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); nm->add_handler_for_exception_and_pc(exception,pc,handler_address);
} }
} else { } 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
} }
} }

View file

@ -150,14 +150,23 @@ class MemoryAccess : StackObj {
} }
template <typename T> template <typename T>
T normalize(T x) { T normalize_for_write(T x) {
return x; return x;
} }
jboolean normalize(jboolean x) { jboolean normalize_for_write(jboolean x) {
return x & 1; 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() * Helper class to wrap memory accesses in JavaThread::doing_unsafe_access()
*/ */
@ -196,7 +205,7 @@ public:
T* p = (T*)addr(); T* p = (T*)addr();
T x = *p; T x = normalize_for_read(*p);
return x; return x;
} }
@ -207,7 +216,7 @@ public:
T* p = (T*)addr(); 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); T x = OrderAccess::load_acquire((volatile T*)p);
return x; return normalize_for_read(x);
} }
template <typename T> template <typename T>
@ -232,7 +241,7 @@ public:
T* p = (T*)addr(); 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(); jlong* p = (jlong*)addr();
Atomic::store(normalize(x), p); Atomic::store(normalize_for_write(x), p);
} }
#endif #endif
}; };

View file

@ -621,7 +621,7 @@ JRT_END
// ret_pc points into caller; we are returning caller's exception handler // ret_pc points into caller; we are returning caller's exception handler
// for given exception // for given exception
address SharedRuntime::compute_compiled_exc_handler(CompiledMethod* cm, address ret_pc, Handle& 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"); assert(cm != NULL, "must exist");
ResourceMark rm; 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 // BCI of the exception handler which caused the exception to be
// thrown (bugs 4307310 and 4546590). Set "exception" reference // thrown (bugs 4307310 and 4546590). Set "exception" reference
// argument to ensure that the correct exception is thrown (4870175). // argument to ensure that the correct exception is thrown (4870175).
recursive_exception_occurred = true;
exception = Handle(THREAD, PENDING_EXCEPTION); exception = Handle(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION; CLEAR_PENDING_EXCEPTION;
if (handler_bci >= 0) { if (handler_bci >= 0) {

View file

@ -189,7 +189,7 @@ class SharedRuntime: AllStatic {
// exception handling and implicit exceptions // exception handling and implicit exceptions
static address compute_compiled_exc_handler(CompiledMethod* nm, address ret_pc, Handle& exception, 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 { enum ImplicitExceptionKind {
IMPLICIT_NULL, IMPLICIT_NULL,
IMPLICIT_DIVIDE_BY_ZERO, IMPLICIT_DIVIDE_BY_ZERO,

View file

@ -75,6 +75,7 @@ public class OverflowCodeCacheTest {
System.out.printf("type %s%n", type); System.out.printf("type %s%n", type);
System.out.println("allocating till possible..."); System.out.println("allocating till possible...");
ArrayList<Long> blobs = new ArrayList<>(); ArrayList<Long> blobs = new ArrayList<>();
int compilationActivityMode = -1;
try { try {
long addr; long addr;
int size = (int) (getHeapSize() >> 7); int size = (int) (getHeapSize() >> 7);
@ -88,13 +89,16 @@ public class OverflowCodeCacheTest {
type + " doesn't allow using " + actualType + " when overflow"); type + " doesn't allow using " + actualType + " when overflow");
} }
} }
Asserts.assertNotEquals(WHITE_BOX.getCompilationActivityMode(), 1 /* run_compilation*/, /* now, remember compilationActivityMode to check it later, after freeing, since we
"Compilation must be disabled when CodeCache(CodeHeap) overflows"); possibly have no free cache for futher work */
compilationActivityMode = WHITE_BOX.getCompilationActivityMode();
} finally { } finally {
for (Long blob : blobs) { for (Long blob : blobs) {
WHITE_BOX.freeCodeBlob(blob); WHITE_BOX.freeCodeBlob(blob);
} }
} }
Asserts.assertNotEquals(compilationActivityMode, 1 /* run_compilation*/,
"Compilation must be disabled when CodeCache(CodeHeap) overflows");
} }
private long getHeapSize() { private long getHeapSize() {

View file

@ -19,7 +19,6 @@ import java.util.List;
* @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64") * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
* @library /test/lib / * @library /test/lib /
* @library ../common/patches * @library ../common/patches
* @ignore 8139383
* @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.misc
* @modules java.base/jdk.internal.org.objectweb.asm * @modules java.base/jdk.internal.org.objectweb.asm
* java.base/jdk.internal.org.objectweb.asm.tree * java.base/jdk.internal.org.objectweb.asm.tree

View file

@ -25,7 +25,6 @@
* @test * @test
* @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64") * @requires (vm.simpleArch == "x64" | vm.simpleArch == "sparcv9" | vm.simpleArch == "aarch64")
* @library ../../../../../ * @library ../../../../../
* @ignore 8161550
* @modules java.base/jdk.internal.reflect * @modules java.base/jdk.internal.reflect
* jdk.vm.ci/jdk.vm.ci.meta * jdk.vm.ci/jdk.vm.ci.meta
* jdk.vm.ci/jdk.vm.ci.runtime * jdk.vm.ci/jdk.vm.ci.runtime
@ -74,11 +73,29 @@ import static org.junit.Assert.assertTrue;
/** /**
* Tests for {@link ResolvedJavaType}. * Tests for {@link ResolvedJavaType}.
*/ */
@SuppressWarnings("unchecked")
public class TestResolvedJavaType extends TypeUniverse { public class TestResolvedJavaType extends TypeUniverse {
private static final Class<? extends Annotation> SIGNATURE_POLYMORPHIC_CLASS = findPolymorphicSignatureClass();
public TestResolvedJavaType() { 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 @Test
public void findInstanceFieldWithOffsetTest() { public void findInstanceFieldWithOffsetTest() {
for (Class<?> c : classes) { for (Class<?> c : classes) {
@ -577,8 +594,14 @@ public class TestResolvedJavaType extends TypeUniverse {
for (Method decl : decls) { for (Method decl : decls) {
ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl); ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl);
if (m.isPublic()) { if (m.isPublic()) {
ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl); ResolvedJavaMethod resolvedmethod = type.resolveMethod(m, context);
assertEquals(m.toString(), i, 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) { for (Method decl : decls) {
ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl); ResolvedJavaMethod m = metaAccess.lookupJavaMethod(decl);
if (m.isPublic()) { if (m.isPublic()) {
ResolvedJavaMethod i = metaAccess.lookupJavaMethod(impl); ResolvedJavaMethod resolvedMethod = type.resolveConcreteMethod(m, context);
assertEquals(i, 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;
}
} }

View file

@ -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; package compiler.loopopts;
import jdk.test.lib.process.OutputAnalyzer; import java.lang.reflect.Method;
import jdk.test.lib.process.ProcessTools; import sun.hotspot.WhiteBox;
import jdk.test.lib.Asserts;
import java.util.concurrent.atomic.AtomicLong; import compiler.whitebox.CompilerWhiteBoxTest;
public class UseCountedLoopSafepoints { 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 { public static void main (String args[]) throws Exception {
if (args.length == 1) { new UseCountedLoopSafepoints().testMethod();
final int loops = Integer.parseInt(args[0]); Method m = UseCountedLoopSafepoints.class.getDeclaredMethod(METHOD_NAME);
for (int i = 0; i < loops; i++) { String directive = "[{ match: \"" + UseCountedLoopSafepoints.class.getName().replace('.', '/')
_num.addAndGet(1); + "." + METHOD_NAME + "\", " + "BackgroundCompilation: false }]";
} Asserts.assertTrue(WB.addCompilerDirective(directive) == 1, "Can't add compiler directive");
} else { Asserts.assertTrue(WB.enqueueMethodForCompilation(m,
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION), "Can't enqueue method");
"-XX:+IgnoreUnrecognizedVMOptions", }
"-XX:-TieredCompilation",
"-XX:+UseBiasedLocking", private void testMethod() {
"-XX:BiasedLockingStartupDelay=500", for (int i = 0; i < 100; i++) {
"-XX:+SafepointTimeout", accum += accum << 5 + accum >> 4 - accum >>> 5;
"-XX:SafepointTimeoutDelay=2000",
"-XX:+UseCountedLoopSafepoints",
UseCountedLoopSafepoints.class.getName(),
"2000000000"
);
OutputAnalyzer output = new OutputAnalyzer(pb.start());
output.shouldNotContain("Timeout detected");
output.shouldHaveExitValue(0);
} }
} }
} }

View 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);
}
}
}

View 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");
}
}

View 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");
}
}

View file

@ -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));
}
}

View file

@ -40,7 +40,7 @@ TESTLIBRARY_DIR = ../../../../test/lib
JAVAC = $(JDK_HOME)/bin/javac JAVAC = $(JDK_HOME)/bin/javac
JAR = $(JDK_HOME)/bin/jar 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') WB_SRC_FILES = $(shell find $(TESTLIBRARY_DIR)/sun/hotspot -name '*.java')
MAIN_CLASS = sun.hotspot.tools.ctw.CompileTheWorld MAIN_CLASS = sun.hotspot.tools.ctw.CompileTheWorld

View file

@ -56,7 +56,6 @@ BUILD_DIR = build
CLASSES_DIR = $(BUILD_DIR)/classes CLASSES_DIR = $(BUILD_DIR)/classes
SRC_DIR = src SRC_DIR = src
TEST_DIR = test TEST_DIR = test
DRIVER_DIR = $(TESTBASE_DIR)/jdk/test/lib/jittester/jtreg
MANIFEST = manifest.mf MANIFEST = manifest.mf
APPLICATION_ARGS += \ APPLICATION_ARGS += \
--property-file $(PROPERTY_FILE) \ --property-file $(PROPERTY_FILE) \
@ -118,19 +117,18 @@ cleantmp:
@rm filelist @rm filelist
@rm -rf $(CLASSES_DIR) @rm -rf $(CLASSES_DIR)
copytestlibrary: $(DRIVER_DIR) copytestlibrary: $(TESTBASE_DIR)/jdk/test/lib/jittester/jtreg
@cp -r src/jdk/test/lib/jittester/jtreg/*.java $(DRIVER_DIR) @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) testgroup: $(TESTBASE_DIR)
@echo 'jittester_all = \\' > $(TESTGROUP_FILE) @echo 'jittester_all = \\' > $(TESTGROUP_FILE)
@echo ' /' >> $(TESTGROUP_FILE) @echo ' /' >> $(TESTGROUP_FILE)
@echo '' >> $(TESTGROUP_FILE) @echo '' >> $(TESTGROUP_FILE)
@echo 'main = \\' >> $(TESTGROUP_FILE)
@echo ' Test_0.java' >> $(TESTGROUP_FILE)
testroot: $(TESTBASE_DIR) testroot: $(TESTBASE_DIR)
@echo 'groups=TEST.groups' > $(TESTROOT_FILE) @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) $(shell if [ ! -d $@ ]; then mkdir -p $@; fi)