--- a/hotspot/src/cpu/sparc/vm/sparc.ad Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad Thu Sep 08 23:43:45 2016 -0400
@@ -2921,6 +2921,26 @@
__ 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 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 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 @@
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 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 @@
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" %}
--- a/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/cpu/x86/vm/macroAssembler_x86.cpp Thu Sep 08 23:43:45 2016 -0400
@@ -8131,8 +8131,7 @@
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 @@
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 @@
// 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 @@
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);
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java Thu Sep 08 23:43:45 2016 -0400
@@ -366,8 +366,8 @@
* {@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);
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java Thu Sep 08 23:43:45 2016 -0400
@@ -722,7 +722,7 @@
/**
* 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();
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java Thu Sep 08 23:43:45 2016 -0400
@@ -24,6 +24,7 @@
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 @@
// 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)) {
--- a/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaType.java Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/jdk.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaType.java Thu Sep 08 23:43:45 2016 -0400
@@ -209,8 +209,8 @@
*
* @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);
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Thu Sep 08 23:43:45 2016 -0400
@@ -2410,6 +2410,15 @@
#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());
+ }
}
--- a/hotspot/src/share/vm/c1/c1_Runtime1.cpp Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/share/vm/c1/c1_Runtime1.cpp Thu Sep 08 23:43:45 2016 -0400
@@ -576,9 +576,8 @@
// 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 @@
// 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);
}
}
--- a/hotspot/src/share/vm/code/codeCache.cpp Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/share/vm/code/codeCache.cpp Thu Sep 08 23:43:45 2016 -0400
@@ -1305,7 +1305,7 @@
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();
}
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Thu Sep 08 23:43:45 2016 -0400
@@ -576,27 +576,39 @@
// 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(
--- a/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/share/vm/jvmci/jvmciCompilerToVM.cpp Thu Sep 08 23:43:45 2016 -0400
@@ -768,6 +768,11 @@
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 @@
}
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;
}
--- a/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/share/vm/jvmci/jvmciRuntime.cpp Thu Sep 08 23:43:45 2016 -0400
@@ -313,13 +313,18 @@
// 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);
}
}
--- a/hotspot/src/share/vm/oops/klass.cpp Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/share/vm/oops/klass.cpp Thu Sep 08 23:43:45 2016 -0400
@@ -431,6 +431,12 @@
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);
+ }
}
}
}
--- a/hotspot/src/share/vm/opto/graphKit.cpp Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/share/vm/opto/graphKit.cpp Thu Sep 08 23:43:45 2016 -0400
@@ -2172,10 +2172,9 @@
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;
}
/**
--- a/hotspot/src/share/vm/opto/library_call.cpp Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/share/vm/opto/library_call.cpp Thu Sep 08 23:43:45 2016 -0400
@@ -2475,6 +2475,28 @@
// 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:
--- a/hotspot/src/share/vm/opto/runtime.cpp Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/share/vm/opto/runtime.cpp Thu Sep 08 23:43:45 2016 -0400
@@ -1349,17 +1349,23 @@
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
}
}
--- a/hotspot/src/share/vm/prims/unsafe.cpp Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/share/vm/prims/unsafe.cpp Thu Sep 08 23:43:45 2016 -0400
@@ -150,14 +150,23 @@
}
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 @@
T* p = (T*)addr();
- T x = *p;
+ T x = normalize_for_read(*p);
return x;
}
@@ -207,7 +216,7 @@
T* p = (T*)addr();
- *p = normalize(x);
+ *p = normalize_for_write(x);
}
@@ -223,7 +232,7 @@
T x = OrderAccess::load_acquire((volatile T*)p);
- return x;
+ return normalize_for_read(x);
}
template <typename T>
@@ -232,7 +241,7 @@
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 @@
jlong* p = (jlong*)addr();
- Atomic::store(normalize(x), p);
+ Atomic::store(normalize_for_write(x), p);
}
#endif
};
--- a/hotspot/src/share/vm/runtime/sharedRuntime.cpp Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.cpp Thu Sep 08 23:43:45 2016 -0400
@@ -621,7 +621,7 @@
// 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 @@
// 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) {
--- a/hotspot/src/share/vm/runtime/sharedRuntime.hpp Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/src/share/vm/runtime/sharedRuntime.hpp Thu Sep 08 23:43:45 2016 -0400
@@ -189,7 +189,7 @@
// 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,
--- a/hotspot/test/compiler/codecache/OverflowCodeCacheTest.java Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/test/compiler/codecache/OverflowCodeCacheTest.java Thu Sep 08 23:43:45 2016 -0400
@@ -75,6 +75,7 @@
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 @@
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() {
--- a/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/test/compiler/jvmci/compilerToVM/ExecuteInstalledCodeTest.java Thu Sep 08 23:43:45 2016 -0400
@@ -19,7 +19,6 @@
* @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
--- a/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/test/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaType.java Thu Sep 08 23:43:45 2016 -0400
@@ -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 @@
/**
* 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 @@
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 @@
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 @@
}
}
}
+
+ private static boolean isSignaturePolymorphic(ResolvedJavaMethod method) {
+ return method.getAnnotation(SIGNATURE_POLYMORPHIC_CLASS) != null;
+ }
}
--- a/hotspot/test/compiler/loopopts/UseCountedLoopSafepoints.java Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/test/compiler/loopopts/UseCountedLoopSafepoints.java Thu Sep 08 23:43:45 2016 -0400
@@ -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";
- // 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.
+ private long accum = 0;
+
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;
}
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/loopopts/UseCountedLoopSafepointsTest.java Thu Sep 08 23:43:45 2016 -0400
@@ -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);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/unsafe/UnsafeOffHeapBooleanTest.java Thu Sep 08 23:43:45 2016 -0400
@@ -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");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/unsafe/UnsafeOnHeapBooleanTest.java Thu Sep 08 23:43:45 2016 -0400
@@ -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");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/unsafe/UnsafeSmallOffsetBooleanAccessTest.java Thu Sep 08 23:43:45 2016 -0400
@@ -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));
+ }
+}
--- a/hotspot/test/testlibrary/ctw/Makefile Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/test/testlibrary/ctw/Makefile Thu Sep 08 23:43:45 2016 -0400
@@ -40,7 +40,7 @@
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
--- a/hotspot/test/testlibrary/jittester/Makefile Fri Sep 02 16:45:16 2016 +0200
+++ b/hotspot/test/testlibrary/jittester/Makefile Thu Sep 08 23:43:45 2016 -0400
@@ -56,7 +56,6 @@
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 @@
@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)