代码拉取完成,页面将自动刷新
同步操作将从 src-openEuler/openjdk-1.8.0 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
Date: Wed, 7 Jun 2023 18:07:31 +0800
Subject: [PATCH 18/59] 8130832: Extend the WhiteBox API to provide information about the availability of compiler intrinsics
Bug url: https://bugs.openjdk.org/browse/JDK-8130832
---
hotspot/src/share/vm/c1/c1_Compiler.cpp | 160 +++++++
hotspot/src/share/vm/c1/c1_Compiler.hpp | 13 +
hotspot/src/share/vm/c1/c1_GraphBuilder.cpp | 420 ++++++------------
hotspot/src/share/vm/c1/c1_GraphBuilder.hpp | 12 +-
hotspot/src/share/vm/classfile/vmSymbols.cpp | 326 ++++++++++++++
hotspot/src/share/vm/classfile/vmSymbols.hpp | 20 +
.../share/vm/compiler/abstractCompiler.hpp | 53 +++
hotspot/src/share/vm/opto/c2compiler.cpp | 347 +++++++++++++++
hotspot/src/share/vm/opto/c2compiler.hpp | 20 +
hotspot/src/share/vm/opto/library_call.cpp | 326 +-------------
hotspot/src/share/vm/prims/whitebox.cpp | 20 +
.../intrinsics/IntrinsicAvailableTest.java | 126 ++++++
.../mathexact/sanity/IntrinsicBase.java | 30 +-
.../mathexact/sanity/MathIntrinsic.java | 81 ++++
14 files changed, 1349 insertions(+), 605 deletions(-)
create mode 100644 hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java
diff --git a/hotspot/src/share/vm/c1/c1_Compiler.cpp b/hotspot/src/share/vm/c1/c1_Compiler.cpp
index 8fd7bec66..599986278 100644
--- a/hotspot/src/share/vm/c1/c1_Compiler.cpp
+++ b/hotspot/src/share/vm/c1/c1_Compiler.cpp
@@ -93,6 +93,162 @@ BufferBlob* Compiler::init_buffer_blob() {
return buffer_blob;
}
+bool Compiler::is_intrinsic_supported(methodHandle method) {
+ vmIntrinsics::ID id = method->intrinsic_id();
+ assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
+
+ if (method->is_synchronized()) {
+ // C1 does not support intrinsification of synchronized methods.
+ return false;
+ }
+
+ switch (id) {
+ case vmIntrinsics::_compareAndSwapLong:
+ if (!VM_Version::supports_cx8()) return false;
+ break;
+ case vmIntrinsics::_getAndAddInt:
+ if (!VM_Version::supports_atomic_getadd4()) return false;
+ break;
+ case vmIntrinsics::_getAndAddLong:
+ if (!VM_Version::supports_atomic_getadd8()) return false;
+ break;
+ case vmIntrinsics::_getAndSetInt:
+ if (!VM_Version::supports_atomic_getset4()) return false;
+ break;
+ case vmIntrinsics::_getAndSetLong:
+ if (!VM_Version::supports_atomic_getset8()) return false;
+ break;
+ case vmIntrinsics::_getAndSetObject:
+#ifdef _LP64
+ if (!UseCompressedOops && !VM_Version::supports_atomic_getset8()) return false;
+ if (UseCompressedOops && !VM_Version::supports_atomic_getset4()) return false;
+#else
+ if (!VM_Version::supports_atomic_getset4()) return false;
+#endif
+ break;
+ case vmIntrinsics::_arraycopy:
+ case vmIntrinsics::_currentTimeMillis:
+ case vmIntrinsics::_nanoTime:
+ case vmIntrinsics::_Reference_get:
+ // Use the intrinsic version of Reference.get() so that the value in
+ // the referent field can be registered by the G1 pre-barrier code.
+ // Also to prevent commoning reads from this field across safepoint
+ // since GC can change its value.
+ case vmIntrinsics::_loadFence:
+ case vmIntrinsics::_storeFence:
+ case vmIntrinsics::_fullFence:
+ case vmIntrinsics::_floatToRawIntBits:
+ case vmIntrinsics::_intBitsToFloat:
+ case vmIntrinsics::_doubleToRawLongBits:
+ case vmIntrinsics::_longBitsToDouble:
+ case vmIntrinsics::_getClass:
+ case vmIntrinsics::_isInstance:
+ case vmIntrinsics::_currentThread:
+ case vmIntrinsics::_dabs:
+ case vmIntrinsics::_dsqrt:
+ case vmIntrinsics::_dsin:
+ case vmIntrinsics::_dcos:
+ case vmIntrinsics::_dtan:
+ case vmIntrinsics::_dlog:
+ case vmIntrinsics::_dlog10:
+ case vmIntrinsics::_dexp:
+ case vmIntrinsics::_dpow:
+ case vmIntrinsics::_getObject:
+ case vmIntrinsics::_getBoolean:
+ case vmIntrinsics::_getByte:
+ case vmIntrinsics::_getShort:
+ case vmIntrinsics::_getChar:
+ case vmIntrinsics::_getInt:
+ case vmIntrinsics::_getLong:
+ case vmIntrinsics::_getFloat:
+ case vmIntrinsics::_getDouble:
+ case vmIntrinsics::_putObject:
+ case vmIntrinsics::_putBoolean:
+ case vmIntrinsics::_putByte:
+ case vmIntrinsics::_putShort:
+ case vmIntrinsics::_putChar:
+ case vmIntrinsics::_putInt:
+ case vmIntrinsics::_putLong:
+ case vmIntrinsics::_putFloat:
+ case vmIntrinsics::_putDouble:
+ case vmIntrinsics::_getObjectVolatile:
+ case vmIntrinsics::_getBooleanVolatile:
+ case vmIntrinsics::_getByteVolatile:
+ case vmIntrinsics::_getShortVolatile:
+ case vmIntrinsics::_getCharVolatile:
+ case vmIntrinsics::_getIntVolatile:
+ case vmIntrinsics::_getLongVolatile:
+ case vmIntrinsics::_getFloatVolatile:
+ case vmIntrinsics::_getDoubleVolatile:
+ case vmIntrinsics::_putObjectVolatile:
+ case vmIntrinsics::_putBooleanVolatile:
+ case vmIntrinsics::_putByteVolatile:
+ case vmIntrinsics::_putShortVolatile:
+ case vmIntrinsics::_putCharVolatile:
+ case vmIntrinsics::_putIntVolatile:
+ case vmIntrinsics::_putLongVolatile:
+ case vmIntrinsics::_putFloatVolatile:
+ case vmIntrinsics::_putDoubleVolatile:
+ case vmIntrinsics::_getByte_raw:
+ case vmIntrinsics::_getShort_raw:
+ case vmIntrinsics::_getChar_raw:
+ case vmIntrinsics::_getInt_raw:
+ case vmIntrinsics::_getLong_raw:
+ case vmIntrinsics::_getFloat_raw:
+ case vmIntrinsics::_getDouble_raw:
+ case vmIntrinsics::_putByte_raw:
+ case vmIntrinsics::_putShort_raw:
+ case vmIntrinsics::_putChar_raw:
+ case vmIntrinsics::_putInt_raw:
+ case vmIntrinsics::_putLong_raw:
+ case vmIntrinsics::_putFloat_raw:
+ case vmIntrinsics::_putDouble_raw:
+ case vmIntrinsics::_prefetchRead:
+ case vmIntrinsics::_prefetchWrite:
+ case vmIntrinsics::_prefetchReadStatic:
+ case vmIntrinsics::_prefetchWriteStatic:
+ case vmIntrinsics::_putOrderedObject:
+ case vmIntrinsics::_putOrderedInt:
+ case vmIntrinsics::_putOrderedLong:
+ case vmIntrinsics::_checkIndex:
+ case vmIntrinsics::_updateCRC32:
+ case vmIntrinsics::_updateBytesCRC32:
+ case vmIntrinsics::_updateByteBufferCRC32:
+ case vmIntrinsics::_dgemm_dgemm:
+ case vmIntrinsics::_dgemv_dgemv:
+ case vmIntrinsics::_compareAndSwapInt:
+ case vmIntrinsics::_compareAndSwapObject:
+#ifdef JFR_HAVE_INTRINSICS
+ case vmIntrinsics::_getClassId:
+ case vmIntrinsics::_getEventWriter:
+ case vmIntrinsics::_counterTime:
+#endif
+ break;
+ default:
+ return false; // Intrinsics not on the previous list are not available.
+ }
+
+ return true;
+}
+
+bool Compiler::is_intrinsic_disabled_by_flag(methodHandle method) {
+ vmIntrinsics::ID id = method->intrinsic_id();
+ assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
+
+ if (vmIntrinsics::is_disabled_by_flags(id)) {
+ return true;
+ }
+
+ if (!InlineNatives && id != vmIntrinsics::_Reference_get) {
+ return true;
+ }
+
+ if (!InlineClassNatives && id == vmIntrinsics::_getClass) {
+ return true;
+ }
+
+ return false;
+}
void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci) {
BufferBlob* buffer_blob = CompilerThread::current()->get_buffer_blob();
@@ -111,3 +267,7 @@ void Compiler::compile_method(ciEnv* env, ciMethod* method, int entry_bci) {
void Compiler::print_timers() {
Compilation::print_timers();
}
+
+bool Compiler::is_intrinsic_available(methodHandle method, methodHandle /* compilation_context */) {
+ return is_intrinsic_supported(method) && !is_intrinsic_disabled_by_flag(method);
+}
diff --git a/hotspot/src/share/vm/c1/c1_Compiler.hpp b/hotspot/src/share/vm/c1/c1_Compiler.hpp
index 8c645e658..8383a64a3 100644
--- a/hotspot/src/share/vm/c1/c1_Compiler.hpp
+++ b/hotspot/src/share/vm/c1/c1_Compiler.hpp
@@ -56,6 +56,19 @@ class Compiler: public AbstractCompiler {
// Print compilation timers and statistics
virtual void print_timers();
+
+ // Check the availability of an intrinsic for 'method' given a compilation context.
+ // The compilation context is needed to support per-method usage of the
+ // DisableIntrinsic flag. However, as C1 ignores the DisableIntrinsic flag, it
+ // ignores the compilation context.
+ virtual bool is_intrinsic_available(methodHandle method, methodHandle compilation_context);
+
+ // Check if the C1 compiler supports an intrinsic for 'method'.
+ virtual bool is_intrinsic_supported(methodHandle method);
+
+ // Processing of command-line flags specific to the C1 compiler.
+ virtual bool is_intrinsic_disabled_by_flag(methodHandle method);
+
};
#endif // SHARE_VM_C1_C1_COMPILER_HPP
diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
index 5ae34702d..eb8ffe5e5 100644
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp
@@ -3457,238 +3457,81 @@ const char* GraphBuilder::should_not_inline(ciMethod* callee) const {
}
-bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
- if (callee->is_synchronized()) {
- // We don't currently support any synchronized intrinsics
- return false;
- }
-
- // callee seems like a good candidate
- // determine id
+void GraphBuilder::build_graph_for_intrinsic(ciMethod* callee) {
vmIntrinsics::ID id = callee->intrinsic_id();
- if (!InlineNatives && id != vmIntrinsics::_Reference_get) {
- // InlineNatives does not control Reference.get
- INLINE_BAILOUT("intrinsic method inlining disabled");
+ assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
+
+ // Some intrinsics need special IR nodes.
+ switch(id) {
+ case vmIntrinsics::_getObject : append_unsafe_get_obj(callee, T_OBJECT, false); return;
+ case vmIntrinsics::_getBoolean : append_unsafe_get_obj(callee, T_BOOLEAN, false); return;
+ case vmIntrinsics::_getByte : append_unsafe_get_obj(callee, T_BYTE, false); return;
+ case vmIntrinsics::_getShort : append_unsafe_get_obj(callee, T_SHORT, false); return;
+ case vmIntrinsics::_getChar : append_unsafe_get_obj(callee, T_CHAR, false); return;
+ case vmIntrinsics::_getInt : append_unsafe_get_obj(callee, T_INT, false); return;
+ case vmIntrinsics::_getLong : append_unsafe_get_obj(callee, T_LONG, false); return;
+ case vmIntrinsics::_getFloat : append_unsafe_get_obj(callee, T_FLOAT, false); return;
+ case vmIntrinsics::_getDouble : append_unsafe_get_obj(callee, T_DOUBLE, false); return;
+ case vmIntrinsics::_putObject : append_unsafe_put_obj(callee, T_OBJECT, false); return;
+ case vmIntrinsics::_putBoolean : append_unsafe_put_obj(callee, T_BOOLEAN, false); return;
+ case vmIntrinsics::_putByte : append_unsafe_put_obj(callee, T_BYTE, false); return;
+ case vmIntrinsics::_putShort : append_unsafe_put_obj(callee, T_SHORT, false); return;
+ case vmIntrinsics::_putChar : append_unsafe_put_obj(callee, T_CHAR, false); return;
+ case vmIntrinsics::_putInt : append_unsafe_put_obj(callee, T_INT, false); return;
+ case vmIntrinsics::_putLong : append_unsafe_put_obj(callee, T_LONG, false); return;
+ case vmIntrinsics::_putFloat : append_unsafe_put_obj(callee, T_FLOAT, false); return;
+ case vmIntrinsics::_putDouble : append_unsafe_put_obj(callee, T_DOUBLE, false); return;
+ case vmIntrinsics::_getObjectVolatile : append_unsafe_get_obj(callee, T_OBJECT, true); return;
+ case vmIntrinsics::_getBooleanVolatile : append_unsafe_get_obj(callee, T_BOOLEAN, true); return;
+ case vmIntrinsics::_getByteVolatile : append_unsafe_get_obj(callee, T_BYTE, true); return;
+ case vmIntrinsics::_getShortVolatile : append_unsafe_get_obj(callee, T_SHORT, true); return;
+ case vmIntrinsics::_getCharVolatile : append_unsafe_get_obj(callee, T_CHAR, true); return;
+ case vmIntrinsics::_getIntVolatile : append_unsafe_get_obj(callee, T_INT, true); return;
+ case vmIntrinsics::_getLongVolatile : append_unsafe_get_obj(callee, T_LONG, true); return;
+ case vmIntrinsics::_getFloatVolatile : append_unsafe_get_obj(callee, T_FLOAT, true); return;
+ case vmIntrinsics::_getDoubleVolatile : append_unsafe_get_obj(callee, T_DOUBLE, true); return;
+ case vmIntrinsics::_putObjectVolatile : append_unsafe_put_obj(callee, T_OBJECT, true); return;
+ case vmIntrinsics::_putBooleanVolatile : append_unsafe_put_obj(callee, T_BOOLEAN, true); return;
+ case vmIntrinsics::_putByteVolatile : append_unsafe_put_obj(callee, T_BYTE, true); return;
+ case vmIntrinsics::_putShortVolatile : append_unsafe_put_obj(callee, T_SHORT, true); return;
+ case vmIntrinsics::_putCharVolatile : append_unsafe_put_obj(callee, T_CHAR, true); return;
+ case vmIntrinsics::_putIntVolatile : append_unsafe_put_obj(callee, T_INT, true); return;
+ case vmIntrinsics::_putLongVolatile : append_unsafe_put_obj(callee, T_LONG, true); return;
+ case vmIntrinsics::_putFloatVolatile : append_unsafe_put_obj(callee, T_FLOAT, true); return;
+ case vmIntrinsics::_putDoubleVolatile : append_unsafe_put_obj(callee, T_DOUBLE, true); return;
+ case vmIntrinsics::_getByte_raw : append_unsafe_get_raw(callee, T_BYTE ); return;
+ case vmIntrinsics::_getShort_raw : append_unsafe_get_raw(callee, T_SHORT ); return;
+ case vmIntrinsics::_getChar_raw : append_unsafe_get_raw(callee, T_CHAR ); return;
+ case vmIntrinsics::_getInt_raw : append_unsafe_get_raw(callee, T_INT ); return;
+ case vmIntrinsics::_getLong_raw : append_unsafe_get_raw(callee, T_LONG ); return;
+ case vmIntrinsics::_getFloat_raw : append_unsafe_get_raw(callee, T_FLOAT ); return;
+ case vmIntrinsics::_getDouble_raw : append_unsafe_get_raw(callee, T_DOUBLE); return;
+ case vmIntrinsics::_putByte_raw : append_unsafe_put_raw(callee, T_BYTE ); return;
+ case vmIntrinsics::_putShort_raw : append_unsafe_put_raw(callee, T_SHORT ); return;
+ case vmIntrinsics::_putChar_raw : append_unsafe_put_raw(callee, T_CHAR ); return;
+ case vmIntrinsics::_putInt_raw : append_unsafe_put_raw(callee, T_INT ); return;
+ case vmIntrinsics::_putLong_raw : append_unsafe_put_raw(callee, T_LONG ); return;
+ case vmIntrinsics::_putFloat_raw : append_unsafe_put_raw(callee, T_FLOAT ); return;
+ case vmIntrinsics::_putDouble_raw : append_unsafe_put_raw(callee, T_DOUBLE); return;
+ case vmIntrinsics::_prefetchRead : append_unsafe_prefetch(callee, false, false); return;
+ case vmIntrinsics::_prefetchWrite : append_unsafe_prefetch(callee, false, true ); return;
+ case vmIntrinsics::_prefetchReadStatic : append_unsafe_prefetch(callee, true, false); return;
+ case vmIntrinsics::_prefetchWriteStatic: append_unsafe_prefetch(callee, true, true ); return;
+ case vmIntrinsics::_putOrderedObject : append_unsafe_put_obj(callee, T_OBJECT, true); return;
+ case vmIntrinsics::_putOrderedInt : append_unsafe_put_obj(callee, T_INT, true); return;
+ case vmIntrinsics::_putOrderedLong : append_unsafe_put_obj(callee, T_LONG, true); return;
+ case vmIntrinsics::_compareAndSwapLong:
+ case vmIntrinsics::_compareAndSwapInt:
+ case vmIntrinsics::_compareAndSwapObject: append_unsafe_CAS(callee); return;
+ case vmIntrinsics::_getAndAddInt:
+ case vmIntrinsics::_getAndAddLong : append_unsafe_get_and_set_obj(callee, true); return;
+ case vmIntrinsics::_getAndSetInt :
+ case vmIntrinsics::_getAndSetLong :
+ case vmIntrinsics::_getAndSetObject : append_unsafe_get_and_set_obj(callee, false); return;
+ default:
+ break;
}
- bool preserves_state = false;
- bool cantrap = true;
- switch (id) {
- case vmIntrinsics::_arraycopy:
- if (!InlineArrayCopy) return false;
- break;
-
-#ifdef JFR_HAVE_INTRINSICS
-#if defined(_LP64) || !defined(TRACE_ID_CLASS_SHIFT)
- case vmIntrinsics::_getClassId:
- preserves_state = false;
- cantrap = false;
- break;
-#endif
-
- case vmIntrinsics::_getEventWriter:
- preserves_state = false;
- cantrap = true;
- break;
-
- case vmIntrinsics::_counterTime:
- preserves_state = true;
- cantrap = false;
- break;
-#endif
- case vmIntrinsics::_currentTimeMillis:
- case vmIntrinsics::_nanoTime:
- preserves_state = true;
- cantrap = false;
- break;
-
- case vmIntrinsics::_floatToRawIntBits :
- case vmIntrinsics::_intBitsToFloat :
- case vmIntrinsics::_doubleToRawLongBits :
- case vmIntrinsics::_longBitsToDouble :
- if (!InlineMathNatives) return false;
- preserves_state = true;
- cantrap = false;
- break;
-
- case vmIntrinsics::_getClass :
- case vmIntrinsics::_isInstance :
- case vmIntrinsics::_isPrimitive :
- if (!InlineClassNatives) return false;
- preserves_state = true;
- break;
-
- case vmIntrinsics::_currentThread :
- if (!InlineThreadNatives) return false;
- preserves_state = true;
- cantrap = false;
- break;
-
- case vmIntrinsics::_dabs : // fall through
- case vmIntrinsics::_dsqrt : // fall through
- case vmIntrinsics::_dsin : // fall through
- case vmIntrinsics::_dcos : // fall through
- case vmIntrinsics::_dtan : // fall through
- case vmIntrinsics::_dlog : // fall through
- case vmIntrinsics::_dlog10 : // fall through
- case vmIntrinsics::_dexp : // fall through
- case vmIntrinsics::_dpow : // fall through
- if (!InlineMathNatives) return false;
- cantrap = false;
- preserves_state = true;
- break;
-
- // Use special nodes for Unsafe instructions so we can more easily
- // perform an address-mode optimization on the raw variants
- case vmIntrinsics::_getObject : return append_unsafe_get_obj(callee, T_OBJECT, false);
- case vmIntrinsics::_getBoolean: return append_unsafe_get_obj(callee, T_BOOLEAN, false);
- case vmIntrinsics::_getByte : return append_unsafe_get_obj(callee, T_BYTE, false);
- case vmIntrinsics::_getShort : return append_unsafe_get_obj(callee, T_SHORT, false);
- case vmIntrinsics::_getChar : return append_unsafe_get_obj(callee, T_CHAR, false);
- case vmIntrinsics::_getInt : return append_unsafe_get_obj(callee, T_INT, false);
- case vmIntrinsics::_getLong : return append_unsafe_get_obj(callee, T_LONG, false);
- case vmIntrinsics::_getFloat : return append_unsafe_get_obj(callee, T_FLOAT, false);
- case vmIntrinsics::_getDouble : return append_unsafe_get_obj(callee, T_DOUBLE, false);
-
- case vmIntrinsics::_putObject : return append_unsafe_put_obj(callee, T_OBJECT, false);
- case vmIntrinsics::_putBoolean: return append_unsafe_put_obj(callee, T_BOOLEAN, false);
- case vmIntrinsics::_putByte : return append_unsafe_put_obj(callee, T_BYTE, false);
- case vmIntrinsics::_putShort : return append_unsafe_put_obj(callee, T_SHORT, false);
- case vmIntrinsics::_putChar : return append_unsafe_put_obj(callee, T_CHAR, false);
- case vmIntrinsics::_putInt : return append_unsafe_put_obj(callee, T_INT, false);
- case vmIntrinsics::_putLong : return append_unsafe_put_obj(callee, T_LONG, false);
- case vmIntrinsics::_putFloat : return append_unsafe_put_obj(callee, T_FLOAT, false);
- case vmIntrinsics::_putDouble : return append_unsafe_put_obj(callee, T_DOUBLE, false);
-
- case vmIntrinsics::_getObjectVolatile : return append_unsafe_get_obj(callee, T_OBJECT, true);
- case vmIntrinsics::_getBooleanVolatile: return append_unsafe_get_obj(callee, T_BOOLEAN, true);
- case vmIntrinsics::_getByteVolatile : return append_unsafe_get_obj(callee, T_BYTE, true);
- case vmIntrinsics::_getShortVolatile : return append_unsafe_get_obj(callee, T_SHORT, true);
- case vmIntrinsics::_getCharVolatile : return append_unsafe_get_obj(callee, T_CHAR, true);
- case vmIntrinsics::_getIntVolatile : return append_unsafe_get_obj(callee, T_INT, true);
- case vmIntrinsics::_getLongVolatile : return append_unsafe_get_obj(callee, T_LONG, true);
- case vmIntrinsics::_getFloatVolatile : return append_unsafe_get_obj(callee, T_FLOAT, true);
- case vmIntrinsics::_getDoubleVolatile : return append_unsafe_get_obj(callee, T_DOUBLE, true);
-
- case vmIntrinsics::_putObjectVolatile : return append_unsafe_put_obj(callee, T_OBJECT, true);
- case vmIntrinsics::_putBooleanVolatile: return append_unsafe_put_obj(callee, T_BOOLEAN, true);
- case vmIntrinsics::_putByteVolatile : return append_unsafe_put_obj(callee, T_BYTE, true);
- case vmIntrinsics::_putShortVolatile : return append_unsafe_put_obj(callee, T_SHORT, true);
- case vmIntrinsics::_putCharVolatile : return append_unsafe_put_obj(callee, T_CHAR, true);
- case vmIntrinsics::_putIntVolatile : return append_unsafe_put_obj(callee, T_INT, true);
- case vmIntrinsics::_putLongVolatile : return append_unsafe_put_obj(callee, T_LONG, true);
- case vmIntrinsics::_putFloatVolatile : return append_unsafe_put_obj(callee, T_FLOAT, true);
- case vmIntrinsics::_putDoubleVolatile : return append_unsafe_put_obj(callee, T_DOUBLE, true);
-
- case vmIntrinsics::_getByte_raw : return append_unsafe_get_raw(callee, T_BYTE);
- case vmIntrinsics::_getShort_raw : return append_unsafe_get_raw(callee, T_SHORT);
- case vmIntrinsics::_getChar_raw : return append_unsafe_get_raw(callee, T_CHAR);
- case vmIntrinsics::_getInt_raw : return append_unsafe_get_raw(callee, T_INT);
- case vmIntrinsics::_getLong_raw : return append_unsafe_get_raw(callee, T_LONG);
- case vmIntrinsics::_getFloat_raw : return append_unsafe_get_raw(callee, T_FLOAT);
- case vmIntrinsics::_getDouble_raw : return append_unsafe_get_raw(callee, T_DOUBLE);
-
- case vmIntrinsics::_putByte_raw : return append_unsafe_put_raw(callee, T_BYTE);
- case vmIntrinsics::_putShort_raw : return append_unsafe_put_raw(callee, T_SHORT);
- case vmIntrinsics::_putChar_raw : return append_unsafe_put_raw(callee, T_CHAR);
- case vmIntrinsics::_putInt_raw : return append_unsafe_put_raw(callee, T_INT);
- case vmIntrinsics::_putLong_raw : return append_unsafe_put_raw(callee, T_LONG);
- case vmIntrinsics::_putFloat_raw : return append_unsafe_put_raw(callee, T_FLOAT);
- case vmIntrinsics::_putDouble_raw : return append_unsafe_put_raw(callee, T_DOUBLE);
-
- case vmIntrinsics::_prefetchRead : return append_unsafe_prefetch(callee, false, false);
- case vmIntrinsics::_prefetchWrite : return append_unsafe_prefetch(callee, false, true);
- case vmIntrinsics::_prefetchReadStatic : return append_unsafe_prefetch(callee, true, false);
- case vmIntrinsics::_prefetchWriteStatic : return append_unsafe_prefetch(callee, true, true);
-
- case vmIntrinsics::_checkIndex :
- if (!InlineNIOCheckIndex) return false;
- preserves_state = true;
- break;
- case vmIntrinsics::_putOrderedObject : return append_unsafe_put_obj(callee, T_OBJECT, true);
- case vmIntrinsics::_putOrderedInt : return append_unsafe_put_obj(callee, T_INT, true);
- case vmIntrinsics::_putOrderedLong : return append_unsafe_put_obj(callee, T_LONG, true);
-
- case vmIntrinsics::_compareAndSwapLong:
- if (!VM_Version::supports_cx8()) return false;
- // fall through
- case vmIntrinsics::_compareAndSwapInt:
- case vmIntrinsics::_compareAndSwapObject:
- append_unsafe_CAS(callee);
- return true;
-
- case vmIntrinsics::_getAndAddInt:
- if (!VM_Version::supports_atomic_getadd4()) {
- return false;
- }
- return append_unsafe_get_and_set_obj(callee, true);
- case vmIntrinsics::_getAndAddLong:
- if (!VM_Version::supports_atomic_getadd8()) {
- return false;
- }
- return append_unsafe_get_and_set_obj(callee, true);
- case vmIntrinsics::_getAndSetInt:
- if (!VM_Version::supports_atomic_getset4()) {
- return false;
- }
- return append_unsafe_get_and_set_obj(callee, false);
- case vmIntrinsics::_getAndSetLong:
- if (!VM_Version::supports_atomic_getset8()) {
- return false;
- }
- return append_unsafe_get_and_set_obj(callee, false);
- case vmIntrinsics::_getAndSetObject:
-#ifdef _LP64
- if (!UseCompressedOops && !VM_Version::supports_atomic_getset8()) {
- return false;
- }
- if (UseCompressedOops && !VM_Version::supports_atomic_getset4()) {
- return false;
- }
-#else
- if (!VM_Version::supports_atomic_getset4()) {
- return false;
- }
-#endif
- return append_unsafe_get_and_set_obj(callee, false);
-
- case vmIntrinsics::_Reference_get:
- // Use the intrinsic version of Reference.get() so that the value in
- // the referent field can be registered by the G1 pre-barrier code.
- // Also to prevent commoning reads from this field across safepoint
- // since GC can change its value.
- preserves_state = true;
- break;
-
- case vmIntrinsics::_updateCRC32:
- case vmIntrinsics::_updateBytesCRC32:
- case vmIntrinsics::_updateByteBufferCRC32:
- if (!UseCRC32Intrinsics) return false;
- cantrap = false;
- preserves_state = true;
- break;
-
- case vmIntrinsics::_loadFence :
- case vmIntrinsics::_storeFence:
- case vmIntrinsics::_fullFence :
- break;
-
- case vmIntrinsics::_dgemm_dgemm:
- if (!UseF2jBLASIntrinsics || (StubRoutines::dgemmDgemm() == NULL)) {
- return false;
- }
- cantrap = false;
- preserves_state = true;
- break;
-
- case vmIntrinsics::_dgemv_dgemv:
- if (!UseF2jBLASIntrinsics || (StubRoutines::dgemvDgemv() == NULL)) return false;
- cantrap = false;
- preserves_state = true;
- break;
-
- default : return false; // do not inline
- }
// create intrinsic node
const bool has_receiver = !callee->is_static();
ValueType* result_type = as_ValueType(callee->return_type());
@@ -3713,8 +3556,10 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
}
}
- Intrinsic* result = new Intrinsic(result_type, id, args, has_receiver, state_before,
- preserves_state, cantrap);
+ Intrinsic* result = new Intrinsic(result_type, callee->intrinsic_id(),
+ args, has_receiver, state_before,
+ vmIntrinsics::preserves_state(id),
+ vmIntrinsics::can_trap(id));
// append instruction & push result
Value value = append_split(result);
if (result_type != voidType) push(result_type, value);
@@ -3722,8 +3567,22 @@ bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
if (callee != method() && profile_return() && result_type->is_object_kind()) {
profile_return_type(result, callee);
}
+}
- // done
+bool GraphBuilder::try_inline_intrinsics(ciMethod* callee) {
+ // For calling is_intrinsic_available we need to transition to
+ // the '_thread_in_vm' state because is_intrinsic_available()
+ // does not accesses critical VM-internal data.
+ if (!_compilation->compiler()->is_intrinsic_available(callee->get_Method(), NULL)) {
+ if (!InlineNatives) {
+ // Return false and also set message that the inlining of
+ // intrinsics has been disabled in general.
+ INLINE_BAILOUT("intrinsic method inlining disabled");
+ } else {
+ return false;
+ }
+ }
+ build_graph_for_intrinsic(callee);
return true;
}
@@ -4323,63 +4182,51 @@ void GraphBuilder::pop_scope_for_jsr() {
_scope_data = scope_data()->parent();
}
-bool GraphBuilder::append_unsafe_get_obj(ciMethod* callee, BasicType t, bool is_volatile) {
- if (InlineUnsafeOps) {
- Values* args = state()->pop_arguments(callee->arg_size());
- null_check(args->at(0));
- Instruction* offset = args->at(2);
+void GraphBuilder::append_unsafe_get_obj(ciMethod* callee, BasicType t, bool is_volatile) {
+ Values* args = state()->pop_arguments(callee->arg_size());
+ null_check(args->at(0));
+ Instruction* offset = args->at(2);
#ifndef _LP64
- offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT)));
+ offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT)));
#endif
- Instruction* op = append(new UnsafeGetObject(t, args->at(1), offset, is_volatile));
- push(op->type(), op);
- compilation()->set_has_unsafe_access(true);
- }
- return InlineUnsafeOps;
+ Instruction* op = append(new UnsafeGetObject(t, args->at(1), offset, is_volatile));
+ push(op->type(), op);
+ compilation()->set_has_unsafe_access(true);
}
-bool GraphBuilder::append_unsafe_put_obj(ciMethod* callee, BasicType t, bool is_volatile) {
- if (InlineUnsafeOps) {
- Values* args = state()->pop_arguments(callee->arg_size());
- null_check(args->at(0));
- Instruction* offset = args->at(2);
+void GraphBuilder::append_unsafe_put_obj(ciMethod* callee, BasicType t, bool is_volatile) {
+ Values* args = state()->pop_arguments(callee->arg_size());
+ null_check(args->at(0));
+ Instruction* offset = args->at(2);
#ifndef _LP64
- offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT)));
+ offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT)));
#endif
- Value val = args->at(3);
- if (t == T_BOOLEAN) {
- Value mask = append(new Constant(new IntConstant(1)));
- val = append(new LogicOp(Bytecodes::_iand, val, mask));
- }
- Instruction* op = append(new UnsafePutObject(t, args->at(1), offset, val, is_volatile));
- compilation()->set_has_unsafe_access(true);
- kill_all();
+ Value val = args->at(3);
+ if (t == T_BOOLEAN) {
+ Value mask = append(new Constant(new IntConstant(1)));
+ val = append(new LogicOp(Bytecodes::_iand, val, mask));
}
- return InlineUnsafeOps;
+ Instruction* op = append(new UnsafePutObject(t, args->at(1), offset, val, is_volatile));
+ compilation()->set_has_unsafe_access(true);
+ kill_all();
}
-bool GraphBuilder::append_unsafe_get_raw(ciMethod* callee, BasicType t) {
- if (InlineUnsafeOps) {
- Values* args = state()->pop_arguments(callee->arg_size());
- null_check(args->at(0));
- Instruction* op = append(new UnsafeGetRaw(t, args->at(1), false));
- push(op->type(), op);
- compilation()->set_has_unsafe_access(true);
- }
- return InlineUnsafeOps;
+void GraphBuilder::append_unsafe_get_raw(ciMethod* callee, BasicType t) {
+ Values* args = state()->pop_arguments(callee->arg_size());
+ null_check(args->at(0));
+ Instruction* op = append(new UnsafeGetRaw(t, args->at(1), false));
+ push(op->type(), op);
+ compilation()->set_has_unsafe_access(true);
}
-bool GraphBuilder::append_unsafe_put_raw(ciMethod* callee, BasicType t) {
- if (InlineUnsafeOps) {
- Values* args = state()->pop_arguments(callee->arg_size());
- null_check(args->at(0));
- Instruction* op = append(new UnsafePutRaw(t, args->at(1), args->at(2)));
- compilation()->set_has_unsafe_access(true);
- }
- return InlineUnsafeOps;
+void GraphBuilder::append_unsafe_put_raw(ciMethod* callee, BasicType t) {
+ Values* args = state()->pop_arguments(callee->arg_size());
+ null_check(args->at(0));
+ Instruction* op = append(new UnsafePutRaw(t, args->at(1), args->at(2)));
+ compilation()->set_has_unsafe_access(true);
}
@@ -4495,21 +4342,18 @@ void GraphBuilder::print_inlining(ciMethod* callee, const char* msg, bool succes
}
}
-bool GraphBuilder::append_unsafe_get_and_set_obj(ciMethod* callee, bool is_add) {
- if (InlineUnsafeOps) {
- Values* args = state()->pop_arguments(callee->arg_size());
- BasicType t = callee->return_type()->basic_type();
- null_check(args->at(0));
- Instruction* offset = args->at(2);
+void GraphBuilder::append_unsafe_get_and_set_obj(ciMethod* callee, bool is_add) {
+ Values* args = state()->pop_arguments(callee->arg_size());
+ BasicType t = callee->return_type()->basic_type();
+ null_check(args->at(0));
+ Instruction* offset = args->at(2);
#ifndef _LP64
- offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT)));
+ offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT)));
#endif
- Instruction* op = append(new UnsafeGetAndSetObject(t, args->at(1), offset, args->at(3), is_add));
- compilation()->set_has_unsafe_access(true);
- kill_all();
- push(op->type(), op);
- }
- return InlineUnsafeOps;
+ Instruction* op = append(new UnsafeGetAndSetObject(t, args->at(1), offset, args->at(3), is_add));
+ compilation()->set_has_unsafe_access(true);
+ kill_all();
+ push(op->type(), op);
}
#ifndef PRODUCT
diff --git a/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp b/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp
index 2caf6142e..4896985c8 100644
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp
+++ b/hotspot/src/share/vm/c1/c1_GraphBuilder.hpp
@@ -339,6 +339,8 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
void inline_sync_entry(Value lock, BlockBegin* sync_handler);
void fill_sync_handler(Value lock, BlockBegin* sync_handler, bool default_handler = false);
+ void build_graph_for_intrinsic(ciMethod* callee);
+
// inliners
bool try_inline( ciMethod* callee, bool holder_known, Bytecodes::Code bc = Bytecodes::_illegal, Value receiver = NULL);
bool try_inline_intrinsics(ciMethod* callee);
@@ -364,13 +366,13 @@ class GraphBuilder VALUE_OBJ_CLASS_SPEC {
void pop_scope();
void pop_scope_for_jsr();
- bool append_unsafe_get_obj(ciMethod* callee, BasicType t, bool is_volatile);
- bool append_unsafe_put_obj(ciMethod* callee, BasicType t, bool is_volatile);
- bool append_unsafe_get_raw(ciMethod* callee, BasicType t);
- bool append_unsafe_put_raw(ciMethod* callee, BasicType t);
+ void append_unsafe_get_obj(ciMethod* callee, BasicType t, bool is_volatile);
+ void append_unsafe_put_obj(ciMethod* callee, BasicType t, bool is_volatile);
+ void append_unsafe_get_raw(ciMethod* callee, BasicType t);
+ void append_unsafe_put_raw(ciMethod* callee, BasicType t);
bool append_unsafe_prefetch(ciMethod* callee, bool is_store, bool is_static);
void append_unsafe_CAS(ciMethod* callee);
- bool append_unsafe_get_and_set_obj(ciMethod* callee, bool is_add);
+ void append_unsafe_get_and_set_obj(ciMethod* callee, bool is_add);
void print_inlining(ciMethod* callee, const char* msg = NULL, bool success = true);
diff --git a/hotspot/src/share/vm/classfile/vmSymbols.cpp b/hotspot/src/share/vm/classfile/vmSymbols.cpp
index 34514022a..9633e4609 100644
--- a/hotspot/src/share/vm/classfile/vmSymbols.cpp
+++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp
@@ -335,12 +335,338 @@ bool vmIntrinsics::should_be_pinned(vmIntrinsics::ID id) {
case vmIntrinsics::_nanoTime:
case vmIntrinsics::_dgemm_dgemm:
case vmIntrinsics::_dgemv_dgemv:
+ case vmIntrinsics::_f2jblas_ddot:
return true;
default:
return false;
}
}
+bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) {
+ assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
+ switch(id) {
+#ifdef JFR_HAVE_INTRINSICS
+ case vmIntrinsics::_counterTime:
+#endif
+ case vmIntrinsics::_currentTimeMillis:
+ case vmIntrinsics::_nanoTime:
+ case vmIntrinsics::_floatToRawIntBits:
+ case vmIntrinsics::_intBitsToFloat:
+ case vmIntrinsics::_doubleToRawLongBits:
+ case vmIntrinsics::_longBitsToDouble:
+ case vmIntrinsics::_getClass:
+ case vmIntrinsics::_isInstance:
+ case vmIntrinsics::_isPrimitive:
+ case vmIntrinsics::_currentThread:
+ case vmIntrinsics::_dabs:
+ case vmIntrinsics::_dsqrt:
+ case vmIntrinsics::_dsin:
+ case vmIntrinsics::_dcos:
+ case vmIntrinsics::_dtan:
+ case vmIntrinsics::_dlog:
+ case vmIntrinsics::_dlog10:
+ case vmIntrinsics::_dexp:
+ case vmIntrinsics::_dpow:
+ case vmIntrinsics::_checkIndex:
+ case vmIntrinsics::_Reference_get:
+ case vmIntrinsics::_updateCRC32:
+ case vmIntrinsics::_updateBytesCRC32:
+ case vmIntrinsics::_updateByteBufferCRC32:
+ case vmIntrinsics::_dgemm_dgemm:
+ case vmIntrinsics::_dgemv_dgemv:
+ case vmIntrinsics::_f2jblas_ddot:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool vmIntrinsics::can_trap(vmIntrinsics::ID id) {
+ assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
+ switch(id) {
+#ifdef JFR_HAVE_INTRINSICS
+ case vmIntrinsics::_getClassId:
+ case vmIntrinsics::_counterTime:
+#endif
+ case vmIntrinsics::_currentTimeMillis:
+ case vmIntrinsics::_nanoTime:
+ case vmIntrinsics::_floatToRawIntBits:
+ case vmIntrinsics::_intBitsToFloat:
+ case vmIntrinsics::_doubleToRawLongBits:
+ case vmIntrinsics::_longBitsToDouble:
+ case vmIntrinsics::_currentThread:
+ case vmIntrinsics::_dabs:
+ case vmIntrinsics::_dsqrt:
+ case vmIntrinsics::_dsin:
+ case vmIntrinsics::_dcos:
+ case vmIntrinsics::_dtan:
+ case vmIntrinsics::_dlog:
+ case vmIntrinsics::_dlog10:
+ case vmIntrinsics::_dexp:
+ case vmIntrinsics::_dpow:
+ case vmIntrinsics::_updateCRC32:
+ case vmIntrinsics::_updateBytesCRC32:
+ case vmIntrinsics::_updateByteBufferCRC32:
+ case vmIntrinsics::_dgemm_dgemm:
+ case vmIntrinsics::_dgemv_dgemv:
+ case vmIntrinsics::_f2jblas_ddot:
+ return false;
+ default:
+ return true;
+ }
+}
+
+bool vmIntrinsics::does_virtual_dispatch(vmIntrinsics::ID id) {
+ assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
+ switch(id) {
+ case vmIntrinsics::_hashCode:
+ case vmIntrinsics::_clone:
+ return true;
+ default:
+ return false;
+ }
+}
+
+int vmIntrinsics::predicates_needed(vmIntrinsics::ID id) {
+ assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
+ switch (id) {
+ case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt:
+ case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
+ case vmIntrinsics::_counterMode_AESCrypt:
+ return 1;
+ case vmIntrinsics::_digestBase_implCompressMB:
+ return 3;
+ default:
+ return 0;
+ }
+}
+
+bool vmIntrinsics::is_disabled_by_flags(vmIntrinsics::ID id) {
+ assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
+ switch (id) {
+ case vmIntrinsics::_isInstance:
+ case vmIntrinsics::_isAssignableFrom:
+ case vmIntrinsics::_getModifiers:
+ case vmIntrinsics::_isInterface:
+ case vmIntrinsics::_isArray:
+ case vmIntrinsics::_isPrimitive:
+ case vmIntrinsics::_getSuperclass:
+ case vmIntrinsics::_getLength:
+ case vmIntrinsics::_newArray:
+ if (!InlineClassNatives) return true;
+ break;
+ case vmIntrinsics::_currentThread:
+ case vmIntrinsics::_isInterrupted:
+ if (!InlineThreadNatives) return true;
+ break;
+ case vmIntrinsics::_floatToRawIntBits:
+ case vmIntrinsics::_intBitsToFloat:
+ case vmIntrinsics::_doubleToRawLongBits:
+ case vmIntrinsics::_longBitsToDouble:
+ case vmIntrinsics::_dabs:
+ case vmIntrinsics::_dsqrt:
+ case vmIntrinsics::_dsin:
+ case vmIntrinsics::_dcos:
+ case vmIntrinsics::_dtan:
+ case vmIntrinsics::_dlog:
+ case vmIntrinsics::_dexp:
+ case vmIntrinsics::_dpow:
+ case vmIntrinsics::_dlog10:
+ case vmIntrinsics::_datan2:
+ case vmIntrinsics::_min:
+ case vmIntrinsics::_max:
+ case vmIntrinsics::_floatToIntBits:
+ case vmIntrinsics::_doubleToLongBits:
+ if (!InlineMathNatives) return true;
+ break;
+ case vmIntrinsics::_arraycopy:
+ if (!InlineArrayCopy) return true;
+ break;
+ case vmIntrinsics::_updateCRC32:
+ case vmIntrinsics::_updateBytesCRC32:
+ case vmIntrinsics::_updateByteBufferCRC32:
+ if (!UseCRC32Intrinsics) return true;
+ break;
+ case vmIntrinsics::_dgemm_dgemm:
+ if (!UseF2jBLASIntrinsics || (StubRoutines::dgemmDgemm() == NULL)) return true;
+ break;
+ case vmIntrinsics::_dgemv_dgemv:
+ if (!UseF2jBLASIntrinsics || (StubRoutines::dgemvDgemv() == NULL)) return true;
+ break;
+ case vmIntrinsics::_getObject:
+ case vmIntrinsics::_getBoolean:
+ case vmIntrinsics::_getByte:
+ case vmIntrinsics::_getShort:
+ case vmIntrinsics::_getChar:
+ case vmIntrinsics::_getInt:
+ case vmIntrinsics::_getLong:
+ case vmIntrinsics::_getFloat:
+ case vmIntrinsics::_getDouble:
+ case vmIntrinsics::_putObject:
+ case vmIntrinsics::_putBoolean:
+ case vmIntrinsics::_putByte:
+ case vmIntrinsics::_putShort:
+ case vmIntrinsics::_putChar:
+ case vmIntrinsics::_putInt:
+ case vmIntrinsics::_putLong:
+ case vmIntrinsics::_putFloat:
+ case vmIntrinsics::_putDouble:
+ case vmIntrinsics::_getObjectVolatile:
+ case vmIntrinsics::_getBooleanVolatile:
+ case vmIntrinsics::_getByteVolatile:
+ case vmIntrinsics::_getShortVolatile:
+ case vmIntrinsics::_getCharVolatile:
+ case vmIntrinsics::_getIntVolatile:
+ case vmIntrinsics::_getLongVolatile:
+ case vmIntrinsics::_getFloatVolatile:
+ case vmIntrinsics::_getDoubleVolatile:
+ case vmIntrinsics::_putObjectVolatile:
+ case vmIntrinsics::_putBooleanVolatile:
+ case vmIntrinsics::_putByteVolatile:
+ case vmIntrinsics::_putShortVolatile:
+ case vmIntrinsics::_putCharVolatile:
+ case vmIntrinsics::_putIntVolatile:
+ case vmIntrinsics::_putLongVolatile:
+ case vmIntrinsics::_putFloatVolatile:
+ case vmIntrinsics::_putDoubleVolatile:
+ case vmIntrinsics::_getByte_raw:
+ case vmIntrinsics::_getShort_raw:
+ case vmIntrinsics::_getChar_raw:
+ case vmIntrinsics::_getInt_raw:
+ case vmIntrinsics::_getLong_raw:
+ case vmIntrinsics::_getFloat_raw:
+ case vmIntrinsics::_getDouble_raw:
+ case vmIntrinsics::_putByte_raw:
+ case vmIntrinsics::_putShort_raw:
+ case vmIntrinsics::_putChar_raw:
+ case vmIntrinsics::_putInt_raw:
+ case vmIntrinsics::_putLong_raw:
+ case vmIntrinsics::_putFloat_raw:
+ case vmIntrinsics::_putDouble_raw:
+ case vmIntrinsics::_prefetchRead:
+ case vmIntrinsics::_prefetchWrite:
+ case vmIntrinsics::_prefetchReadStatic:
+ case vmIntrinsics::_prefetchWriteStatic:
+ case vmIntrinsics::_putOrderedObject:
+ case vmIntrinsics::_putOrderedLong:
+ case vmIntrinsics::_putOrderedInt:
+ case vmIntrinsics::_getAndAddInt:
+ case vmIntrinsics::_getAndAddLong:
+ case vmIntrinsics::_getAndSetInt:
+ case vmIntrinsics::_getAndSetLong:
+ case vmIntrinsics::_getAndSetObject:
+ if (!InlineUnsafeOps) return true;
+ break;
+ case vmIntrinsics::_allocateInstance:
+ case vmIntrinsics::_getAddress_raw:
+ case vmIntrinsics::_putAddress_raw:
+ if (!InlineUnsafeOps) return true;
+ break;
+ case vmIntrinsics::_hashCode:
+ if (!InlineObjectHash) return true;
+ break;
+ case vmIntrinsics::_aescrypt_encryptBlock:
+ case vmIntrinsics::_aescrypt_decryptBlock:
+ if (!UseAESIntrinsics) return true;
+ break;
+ case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt:
+ case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
+ if (!UseAESIntrinsics) return true;
+ break;
+ case vmIntrinsics::_counterMode_AESCrypt:
+ if (!UseAESCTRIntrinsics) {
+ return true;
+ }
+ break;
+ case vmIntrinsics::_sha_implCompress:
+ if (!UseSHA1Intrinsics) return true;
+ break;
+ case vmIntrinsics::_sha2_implCompress:
+ if (!UseSHA256Intrinsics) return true;
+ break;
+ case vmIntrinsics::_sha5_implCompress:
+ if (!UseSHA512Intrinsics) return true;
+ break;
+ case vmIntrinsics::_digestBase_implCompressMB:
+ if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) return true;
+ break;
+ case vmIntrinsics::_ghash_processBlocks:
+ if (!UseGHASHIntrinsics) return true;
+ break;
+ case vmIntrinsics::_copyMemory:
+ if (!InlineArrayCopy || !InlineUnsafeOps) return true;
+ break;
+#ifdef COMPILER1
+ case vmIntrinsics::_checkIndex:
+ if (!InlineNIOCheckIndex) return true;
+ break;
+#endif // COMPILER1
+#ifdef COMPILER2
+ case vmIntrinsics::_clone:
+ case vmIntrinsics::_copyOf:
+ case vmIntrinsics::_copyOfRange:
+ // These intrinsics use both the objectcopy and the arraycopy
+ // intrinsic mechanism.
+ if (!InlineObjectCopy || !InlineArrayCopy) return true;
+ break;
+ case vmIntrinsics::_compareTo:
+ if (!SpecialStringCompareTo) return true;
+ break;
+ case vmIntrinsics::_indexOf:
+ if (!SpecialStringIndexOf) return true;
+ break;
+ case vmIntrinsics::_equals:
+ if (!SpecialStringEquals) return true;
+ break;
+ case vmIntrinsics::_equalsC:
+ if (!SpecialArraysEquals) return true;
+ break;
+ case vmIntrinsics::_encodeISOArray:
+ if (!SpecialEncodeISOArray) return true;
+ break;
+ case vmIntrinsics::_getCallerClass:
+ if (!InlineReflectionGetCallerClass) return true;
+ break;
+ case vmIntrinsics::_multiplyToLen:
+ if (!UseMultiplyToLenIntrinsic) return true;
+ break;
+ case vmIntrinsics::_squareToLen:
+ if (!UseSquareToLenIntrinsic) return true;
+ break;
+ case vmIntrinsics::_mulAdd:
+ if (!UseMulAddIntrinsic) return true;
+ break;
+ case vmIntrinsics::_montgomeryMultiply:
+ if (!UseMontgomeryMultiplyIntrinsic) return true;
+ break;
+ case vmIntrinsics::_montgomerySquare:
+ if (!UseMontgomerySquareIntrinsic) return true;
+ break;
+ case vmIntrinsics::_addExactI:
+ case vmIntrinsics::_addExactL:
+ case vmIntrinsics::_decrementExactI:
+ case vmIntrinsics::_decrementExactL:
+ case vmIntrinsics::_incrementExactI:
+ case vmIntrinsics::_incrementExactL:
+ case vmIntrinsics::_multiplyExactI:
+ case vmIntrinsics::_multiplyExactL:
+ case vmIntrinsics::_negateExactI:
+ case vmIntrinsics::_negateExactL:
+ case vmIntrinsics::_subtractExactI:
+ case vmIntrinsics::_subtractExactL:
+ if (!UseMathExactIntrinsics || !InlineMathNatives) return true;
+ break;
+ case vmIntrinsics::_f2jblas_ddot:
+ if (!UseF2jBLASIntrinsics || (StubRoutines::ddotF2jBLAS() == NULL)) return true;
+ break;
+#endif // COMPILER2
+ default:
+ return false;
+ }
+
+ return false;
+}
+
#define VM_INTRINSIC_INITIALIZE(id, klass, name, sig, flags) #id "\0"
static const char* vm_intrinsic_name_bodies =
VM_INTRINSICS_DO(VM_INTRINSIC_INITIALIZE,
diff --git a/hotspot/src/share/vm/classfile/vmSymbols.hpp b/hotspot/src/share/vm/classfile/vmSymbols.hpp
index af7b83e28..242660259 100644
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp
@@ -1339,6 +1339,26 @@ public:
static ID for_raw_conversion(BasicType src, BasicType dest);
static bool should_be_pinned(vmIntrinsics::ID id);
+
+ // The methods below provide information related to compiling intrinsics.
+
+ // (1) Information needed by the C1 compiler.
+
+ static bool preserves_state(vmIntrinsics::ID id);
+ static bool can_trap(vmIntrinsics::ID id);
+
+ // (2) Information needed by the C2 compiler.
+
+ // Returns true if the intrinsic for method 'method' will perform a virtual dispatch.
+ static bool does_virtual_dispatch(vmIntrinsics::ID id);
+ // A return value larger than 0 indicates that the intrinsic for method
+ // 'method' requires predicated logic.
+ static int predicates_needed(vmIntrinsics::ID id);
+
+ // Returns true if an intrinsic is disabled by command-line flags and
+ // false otherwise. Implements functionality common to the C1
+ // and the C2 compiler.
+ static bool is_disabled_by_flags(vmIntrinsics::ID id);
};
#endif // SHARE_VM_CLASSFILE_VMSYMBOLS_HPP
diff --git a/hotspot/src/share/vm/compiler/abstractCompiler.hpp b/hotspot/src/share/vm/compiler/abstractCompiler.hpp
index 11aea60a2..2f94b626b 100644
--- a/hotspot/src/share/vm/compiler/abstractCompiler.hpp
+++ b/hotspot/src/share/vm/compiler/abstractCompiler.hpp
@@ -54,6 +54,59 @@ class AbstractCompiler : public CHeapObj<mtCompiler> {
virtual bool supports_native() { return true; }
virtual bool supports_osr () { return true; }
virtual bool can_compile_method(methodHandle method) { return true; }
+
+ // Determine if the current compiler provides an intrinsic
+ // for method 'method'. An intrinsic is available if:
+ // - the intrinsic is enabled (by using the appropriate command-line flag) and
+ // - the platform on which the VM is running supports the intrinsic
+ // (i.e., the platform provides the instructions necessary for the compiler
+ // to generate the intrinsic code).
+ //
+ // The second parameter, 'compilation_context', is needed to implement functionality
+ // related to the DisableIntrinsic command-line flag. The DisableIntrinsic flag can
+ // be used to prohibit the C2 compiler (but not the C1 compiler) to use an intrinsic.
+ // There are three ways to disable an intrinsic using the DisableIntrinsic flag:
+ //
+ // (1) -XX:DisableIntrinsic=_hashCode,_getClass
+ // Disables intrinsification of _hashCode and _getClass globally
+ // (i.e., the intrinsified version the methods will not be used at all).
+ // (2) -XX:CompileCommand=option,aClass::aMethod,ccstr,DisableIntrinsic,_hashCode
+ // Disables intrinsification of _hashCode if it is called from
+ // aClass::aMethod (but not for any other call site of _hashCode)
+ // (3) -XX:CompileCommand=option,java.lang.ref.Reference::get,ccstr,DisableIntrinsic,_Reference_get
+ // Some methods are not compiled by C2. Instead, the C2 compiler
+ // returns directly the intrinsified version of these methods.
+ // The command above forces C2 to compile _Reference_get, but
+ // allows using the intrinsified version of _Reference_get at all
+ // other call sites.
+ //
+ // From the modes above, (1) disable intrinsics globally, (2) and (3)
+ // disable intrinsics on a per-method basis. In cases (2) and (3) the
+ // compilation context is aClass::aMethod and java.lang.ref.Reference::get,
+ // respectively.
+ virtual bool is_intrinsic_available(methodHandle /* method */, methodHandle /* compilation_context */) {
+ return false;
+ }
+
+ // Determines if an intrinsic is supported by the compiler, that is,
+ // the compiler provides the instructions necessary to generate
+ // the intrinsic code for method 'method'.
+ //
+ // The 'is_intrinsic_supported' method is a white list, that is,
+ // by default no intrinsics are supported by a compiler except
+ // the ones listed in the method. Overriding methods should conform
+ // to this behavior.
+ virtual bool is_intrinsic_supported(methodHandle /* method */) {
+ return false;
+ }
+
+ // Implements compiler-specific processing of command-line flags.
+ // Processing of command-line flags common to all compilers is implemented
+ // in vmIntrinsicss::is_disabled_by_flag.
+ virtual bool is_intrinsic_disabled_by_flag(methodHandle /* method */) {
+ return false;
+ }
+
#if defined(TIERED) || ( !defined(COMPILER1) && !defined(COMPILER2) && !defined(SHARK))
virtual bool is_c1 () { return false; }
virtual bool is_c2 () { return false; }
diff --git a/hotspot/src/share/vm/opto/c2compiler.cpp b/hotspot/src/share/vm/opto/c2compiler.cpp
index 137f49600..64de417f6 100644
--- a/hotspot/src/share/vm/opto/c2compiler.cpp
+++ b/hotspot/src/share/vm/opto/c2compiler.cpp
@@ -165,3 +165,350 @@ void C2Compiler::compile_method(ciEnv* env, ciMethod* target, int entry_bci) {
void C2Compiler::print_timers() {
// do nothing
}
+
+bool C2Compiler::is_intrinsic_available(methodHandle method, methodHandle compilation_context) {
+ // Assume a non-virtual dispatch. A virtual dispatch is
+ // possible for only a limited set of available intrinsics whereas
+ // a non-virtual dispatch is possible for all available intrinsics.
+ return is_intrinsic_supported(method, false) &&
+ !is_intrinsic_disabled_by_flag(method, compilation_context);
+}
+
+bool C2Compiler::is_intrinsic_supported(methodHandle method, bool is_virtual) {
+ vmIntrinsics::ID id = method->intrinsic_id();
+ assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
+
+ if (id < vmIntrinsics::FIRST_ID || id >= vmIntrinsics::LAST_COMPILER_INLINE) {
+ return false;
+ }
+
+ // Only Object.hashCode and Object.clone intrinsics implement also a virtual
+ // dispatch because calling both methods is expensive but both methods are
+ // frequently overridden. All other intrinsics implement only a non-virtual
+ // dispatch.
+ if (is_virtual) {
+ switch (id) {
+ case vmIntrinsics::_hashCode:
+ case vmIntrinsics::_clone:
+ break;
+ default:
+ return false;
+ }
+ }
+
+ switch (id) {
+ case vmIntrinsics::_compareTo:
+ if (!Matcher::match_rule_supported(Op_StrComp)) return false;
+ break;
+ case vmIntrinsics::_equals:
+ if (!Matcher::match_rule_supported(Op_StrEquals)) return false;
+ break;
+ case vmIntrinsics::_equalsC:
+ if (!Matcher::match_rule_supported(Op_AryEq)) return false;
+ break;
+ case vmIntrinsics::_copyMemory:
+ if (StubRoutines::unsafe_arraycopy() == NULL) return false;
+ break;
+ case vmIntrinsics::_encodeISOArray:
+ if (!Matcher::match_rule_supported(Op_EncodeISOArray)) return false;
+ break;
+ case vmIntrinsics::_bitCount_i:
+ if (!Matcher::match_rule_supported(Op_PopCountI)) return false;
+ break;
+ case vmIntrinsics::_bitCount_l:
+ if (!Matcher::match_rule_supported(Op_PopCountL)) return false;
+ break;
+ case vmIntrinsics::_numberOfLeadingZeros_i:
+ if (!Matcher::match_rule_supported(Op_CountLeadingZerosI)) return false;
+ break;
+ case vmIntrinsics::_numberOfLeadingZeros_l:
+ if (!Matcher::match_rule_supported(Op_CountLeadingZerosL)) return false;
+ break;
+ case vmIntrinsics::_numberOfTrailingZeros_i:
+ if (!Matcher::match_rule_supported(Op_CountTrailingZerosI)) return false;
+ break;
+ case vmIntrinsics::_numberOfTrailingZeros_l:
+ if (!Matcher::match_rule_supported(Op_CountTrailingZerosL)) return false;
+ break;
+ case vmIntrinsics::_reverseBytes_c:
+ if (!Matcher::match_rule_supported(Op_ReverseBytesUS)) return false;
+ break;
+ case vmIntrinsics::_reverseBytes_s:
+ if (!Matcher::match_rule_supported(Op_ReverseBytesS)) return false;
+ break;
+ case vmIntrinsics::_reverseBytes_i:
+ if (!Matcher::match_rule_supported(Op_ReverseBytesI)) return false;
+ break;
+ case vmIntrinsics::_reverseBytes_l:
+ if (!Matcher::match_rule_supported(Op_ReverseBytesL)) return false;
+ break;
+ case vmIntrinsics::_compareAndSwapObject:
+#ifdef _LP64
+ if (!UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndSwapP)) return false;
+#endif
+ break;
+ case vmIntrinsics::_compareAndSwapLong:
+ if (!Matcher::match_rule_supported(Op_CompareAndSwapL)) return false;
+ break;
+ case vmIntrinsics::_getAndAddInt:
+ if (!Matcher::match_rule_supported(Op_GetAndAddI)) return false;
+ break;
+ case vmIntrinsics::_getAndAddLong:
+ if (!Matcher::match_rule_supported(Op_GetAndAddL)) return false;
+ break;
+ case vmIntrinsics::_getAndSetInt:
+ if (!Matcher::match_rule_supported(Op_GetAndSetI)) return false;
+ break;
+ case vmIntrinsics::_getAndSetLong:
+ if (!Matcher::match_rule_supported(Op_GetAndSetL)) return false;
+ break;
+ case vmIntrinsics::_getAndSetObject:
+#ifdef _LP64
+ if (!UseCompressedOops && !Matcher::match_rule_supported(Op_GetAndSetP)) return false;
+ if (UseCompressedOops && !Matcher::match_rule_supported(Op_GetAndSetN)) return false;
+ break;
+#else
+ if (!Matcher::match_rule_supported(Op_GetAndSetP)) return false;
+ break;
+#endif
+ case vmIntrinsics::_incrementExactI:
+ case vmIntrinsics::_addExactI:
+ if (!Matcher::match_rule_supported(Op_OverflowAddI)) return false;
+ break;
+ case vmIntrinsics::_incrementExactL:
+ case vmIntrinsics::_addExactL:
+ if (!Matcher::match_rule_supported(Op_OverflowAddL)) return false;
+ break;
+ case vmIntrinsics::_decrementExactI:
+ case vmIntrinsics::_subtractExactI:
+ if (!Matcher::match_rule_supported(Op_OverflowSubI)) return false;
+ break;
+ case vmIntrinsics::_decrementExactL:
+ case vmIntrinsics::_subtractExactL:
+ if (!Matcher::match_rule_supported(Op_OverflowSubL)) return false;
+ break;
+ case vmIntrinsics::_negateExactI:
+ if (!Matcher::match_rule_supported(Op_OverflowSubI)) return false;
+ break;
+ case vmIntrinsics::_negateExactL:
+ if (!Matcher::match_rule_supported(Op_OverflowSubL)) return false;
+ break;
+ case vmIntrinsics::_multiplyExactI:
+ if (!Matcher::match_rule_supported(Op_OverflowMulI)) return false;
+ break;
+ case vmIntrinsics::_multiplyExactL:
+ if (!Matcher::match_rule_supported(Op_OverflowMulL)) return false;
+ break;
+ case vmIntrinsics::_getCallerClass:
+ if (SystemDictionary::reflect_CallerSensitive_klass() == NULL) return false;
+ break;
+ case vmIntrinsics::_hashCode:
+ case vmIntrinsics::_identityHashCode:
+ case vmIntrinsics::_getClass:
+ case vmIntrinsics::_dsin:
+ case vmIntrinsics::_dcos:
+ case vmIntrinsics::_dtan:
+ case vmIntrinsics::_dabs:
+ case vmIntrinsics::_datan2:
+ case vmIntrinsics::_dsqrt:
+ case vmIntrinsics::_dexp:
+ case vmIntrinsics::_dlog:
+ case vmIntrinsics::_dlog10:
+ case vmIntrinsics::_dpow:
+ case vmIntrinsics::_min:
+ case vmIntrinsics::_max:
+ case vmIntrinsics::_arraycopy:
+ case vmIntrinsics::_indexOf:
+ case vmIntrinsics::_getObject:
+ case vmIntrinsics::_getBoolean:
+ case vmIntrinsics::_getByte:
+ case vmIntrinsics::_getShort:
+ case vmIntrinsics::_getChar:
+ case vmIntrinsics::_getInt:
+ case vmIntrinsics::_getLong:
+ case vmIntrinsics::_getFloat:
+ case vmIntrinsics::_getDouble:
+ case vmIntrinsics::_putObject:
+ case vmIntrinsics::_putBoolean:
+ case vmIntrinsics::_putByte:
+ case vmIntrinsics::_putShort:
+ case vmIntrinsics::_putChar:
+ case vmIntrinsics::_putInt:
+ case vmIntrinsics::_putLong:
+ case vmIntrinsics::_putFloat:
+ case vmIntrinsics::_putDouble:
+ case vmIntrinsics::_getByte_raw:
+ case vmIntrinsics::_getShort_raw:
+ case vmIntrinsics::_getChar_raw:
+ case vmIntrinsics::_getInt_raw:
+ case vmIntrinsics::_getLong_raw:
+ case vmIntrinsics::_getFloat_raw:
+ case vmIntrinsics::_getDouble_raw:
+ case vmIntrinsics::_getAddress_raw:
+ case vmIntrinsics::_putByte_raw:
+ case vmIntrinsics::_putShort_raw:
+ case vmIntrinsics::_putChar_raw:
+ case vmIntrinsics::_putInt_raw:
+ case vmIntrinsics::_putLong_raw:
+ case vmIntrinsics::_putFloat_raw:
+ case vmIntrinsics::_putDouble_raw:
+ case vmIntrinsics::_putAddress_raw:
+ case vmIntrinsics::_prefetchRead:
+ case vmIntrinsics::_prefetchWrite:
+ case vmIntrinsics::_prefetchReadStatic:
+ case vmIntrinsics::_prefetchWriteStatic:
+ case vmIntrinsics::_getObjectVolatile:
+ case vmIntrinsics::_getBooleanVolatile:
+ case vmIntrinsics::_getByteVolatile:
+ case vmIntrinsics::_getShortVolatile:
+ case vmIntrinsics::_getCharVolatile:
+ case vmIntrinsics::_getIntVolatile:
+ case vmIntrinsics::_getLongVolatile:
+ case vmIntrinsics::_getFloatVolatile:
+ case vmIntrinsics::_getDoubleVolatile:
+ case vmIntrinsics::_putObjectVolatile:
+ case vmIntrinsics::_putBooleanVolatile:
+ case vmIntrinsics::_putByteVolatile:
+ case vmIntrinsics::_putShortVolatile:
+ case vmIntrinsics::_putCharVolatile:
+ case vmIntrinsics::_putIntVolatile:
+ case vmIntrinsics::_putLongVolatile:
+ case vmIntrinsics::_putFloatVolatile:
+ case vmIntrinsics::_putDoubleVolatile:
+ case vmIntrinsics::_compareAndSwapInt:
+ case vmIntrinsics::_putOrderedObject:
+ case vmIntrinsics::_putOrderedInt:
+ case vmIntrinsics::_putOrderedLong:
+ case vmIntrinsics::_loadFence:
+ case vmIntrinsics::_storeFence:
+ case vmIntrinsics::_fullFence:
+ case vmIntrinsics::_currentThread:
+ case vmIntrinsics::_isInterrupted:
+#ifdef JFR_HAVE_INTRINSICS
+ case vmIntrinsics::_getClassId:
+ case vmIntrinsics::_getEventWriter:
+ case vmIntrinsics::_counterTime:
+#endif
+ case vmIntrinsics::_currentTimeMillis:
+ case vmIntrinsics::_nanoTime:
+ case vmIntrinsics::_allocateInstance:
+ case vmIntrinsics::_newArray:
+ case vmIntrinsics::_getLength:
+ case vmIntrinsics::_copyOf:
+ case vmIntrinsics::_copyOfRange:
+ case vmIntrinsics::_clone:
+ case vmIntrinsics::_isAssignableFrom:
+ case vmIntrinsics::_isInstance:
+ case vmIntrinsics::_getModifiers:
+ case vmIntrinsics::_isInterface:
+ case vmIntrinsics::_isArray:
+ case vmIntrinsics::_isPrimitive:
+ case vmIntrinsics::_getSuperclass:
+ case vmIntrinsics::_getClassAccessFlags:
+ case vmIntrinsics::_floatToRawIntBits:
+ case vmIntrinsics::_floatToIntBits:
+ case vmIntrinsics::_intBitsToFloat:
+ case vmIntrinsics::_doubleToRawLongBits:
+ case vmIntrinsics::_doubleToLongBits:
+ case vmIntrinsics::_longBitsToDouble:
+ case vmIntrinsics::_Reference_get:
+ case vmIntrinsics::_aescrypt_encryptBlock:
+ case vmIntrinsics::_aescrypt_decryptBlock:
+ case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt:
+ case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
+ case vmIntrinsics::_counterMode_AESCrypt:
+ case vmIntrinsics::_sha_implCompress:
+ case vmIntrinsics::_sha2_implCompress:
+ case vmIntrinsics::_sha5_implCompress:
+ case vmIntrinsics::_digestBase_implCompressMB:
+ case vmIntrinsics::_multiplyToLen:
+ case vmIntrinsics::_squareToLen:
+ case vmIntrinsics::_mulAdd:
+ case vmIntrinsics::_montgomeryMultiply:
+ case vmIntrinsics::_montgomerySquare:
+ case vmIntrinsics::_ghash_processBlocks:
+ case vmIntrinsics::_updateCRC32:
+ case vmIntrinsics::_updateBytesCRC32:
+ case vmIntrinsics::_updateByteBufferCRC32:
+ case vmIntrinsics::_profileBoolean:
+ case vmIntrinsics::_dgemm_dgemm:
+ case vmIntrinsics::_dgemv_dgemv:
+ case vmIntrinsics::_f2jblas_ddot:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool C2Compiler::is_intrinsic_disabled_by_flag(methodHandle method, methodHandle compilation_context) {
+ vmIntrinsics::ID id = method->intrinsic_id();
+ assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
+
+ if (vmIntrinsics::is_disabled_by_flags(method->intrinsic_id())) {
+ return true;
+ }
+
+ // Check if the intrinsic corresponding to 'method' has been disabled on
+ // the command line by using the DisableIntrinsic flag (either globally
+ // or on a per-method level, see src/share/vm/compiler/abstractCompiler.hpp
+ // for details).
+ // Usually, the compilation context is the caller of the method 'method'.
+ // The only case when for a non-recursive method 'method' the compilation context
+ // is not the caller of the 'method' (but it is the method itself) is
+ // java.lang.ref.Referene::get.
+ // For java.lang.ref.Reference::get, the intrinsic version is used
+ // instead of the C2-compiled version so that the value in the referent
+ // field can be registered by the G1 pre-barrier code. The intrinsified
+ // version of Reference::get also adds a memory barrier to prevent
+ // commoning reads from the referent field across safepoint since GC
+ // can change the referent field's value. See Compile::Compile()
+ // in src/share/vm/opto/compile.cpp for more details.
+ ccstr disable_intr = NULL;
+ if ((DisableIntrinsic[0] != '\0' && strstr(DisableIntrinsic, vmIntrinsics::name_at(id)) != NULL) ||
+ (!compilation_context.is_null() &&
+ CompilerOracle::has_option_value(compilation_context, "DisableIntrinsic", disable_intr) &&
+ strstr(disable_intr, vmIntrinsics::name_at(id)) != NULL)
+ ) {
+ return true;
+ }
+
+ // -XX:-InlineNatives disables nearly all intrinsics except the ones listed in
+ // the following switch statement.
+ if (!InlineNatives) {
+ switch (id) {
+ case vmIntrinsics::_indexOf:
+ case vmIntrinsics::_compareTo:
+ case vmIntrinsics::_equals:
+ case vmIntrinsics::_equalsC:
+ case vmIntrinsics::_getAndAddInt:
+ case vmIntrinsics::_getAndAddLong:
+ case vmIntrinsics::_getAndSetInt:
+ case vmIntrinsics::_getAndSetLong:
+ case vmIntrinsics::_getAndSetObject:
+ case vmIntrinsics::_loadFence:
+ case vmIntrinsics::_storeFence:
+ case vmIntrinsics::_fullFence:
+ case vmIntrinsics::_Reference_get:
+ break;
+ default:
+ return true;
+ }
+ }
+
+ if (!InlineUnsafeOps) {
+ switch (id) {
+ case vmIntrinsics::_loadFence:
+ case vmIntrinsics::_storeFence:
+ case vmIntrinsics::_fullFence:
+ case vmIntrinsics::_compareAndSwapObject:
+ case vmIntrinsics::_compareAndSwapLong:
+ case vmIntrinsics::_compareAndSwapInt:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ return false;
+}
diff --git a/hotspot/src/share/vm/opto/c2compiler.hpp b/hotspot/src/share/vm/opto/c2compiler.hpp
index c1449bc34..8854f1593 100644
--- a/hotspot/src/share/vm/opto/c2compiler.hpp
+++ b/hotspot/src/share/vm/opto/c2compiler.hpp
@@ -53,6 +53,26 @@ public:
// Print compilation timers and statistics
void print_timers();
+
+ // Check the availability of an intrinsic for 'method' given a compilation context.
+ virtual bool is_intrinsic_available(methodHandle method, methodHandle compilation_context);
+
+ // Return true if the intrinsification of a method supported by the compiler
+ // assuming a non-virtual dispatch. Return false otherwise.
+ virtual bool is_intrinsic_supported(methodHandle method) {
+ return is_intrinsic_supported(method, false);
+ }
+
+ // Check if the compiler supports an intrinsic for 'method' given the
+ // the dispatch mode specified by the 'is_virtual' parameter.
+ virtual bool is_intrinsic_supported(methodHandle method, bool is_virtual);
+
+ // Processing of command-line flags specific to the C2 compiler.
+ virtual bool is_intrinsic_disabled_by_flag(methodHandle method) {
+ return is_intrinsic_disabled_by_flag(method, NULL);
+ }
+
+ virtual bool is_intrinsic_disabled_by_flag(methodHandle method, methodHandle compilation_context);
};
#endif // SHARE_VM_OPTO_C2COMPILER_HPP
diff --git a/hotspot/src/share/vm/opto/library_call.cpp b/hotspot/src/share/vm/opto/library_call.cpp
index 2add82dd1..9ba5201f0 100644
--- a/hotspot/src/share/vm/opto/library_call.cpp
+++ b/hotspot/src/share/vm/opto/library_call.cpp
@@ -30,6 +30,7 @@
#include "jfr/support/jfrIntrinsics.hpp"
#include "oops/objArrayKlass.hpp"
#include "opto/addnode.hpp"
+#include "opto/c2compiler.hpp"
#include "opto/callGenerator.hpp"
#include "opto/cfgnode.hpp"
#include "opto/connode.hpp"
@@ -346,322 +347,35 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
vmIntrinsics::ID id = m->intrinsic_id();
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
- ccstr disable_intr = NULL;
-
- if ((DisableIntrinsic[0] != '\0'
- && strstr(DisableIntrinsic, vmIntrinsics::name_at(id)) != NULL) ||
- (method_has_option_value("DisableIntrinsic", disable_intr)
- && strstr(disable_intr, vmIntrinsics::name_at(id)) != NULL)) {
- // disabled by a user request on the command line:
- // example: -XX:DisableIntrinsic=_hashCode,_getClass
- return NULL;
- }
-
if (!m->is_loaded()) {
- // do not attempt to inline unloaded methods
+ // Do not attempt to inline unloaded methods.
return NULL;
}
- // Only a few intrinsics implement a virtual dispatch.
- // They are expensive calls which are also frequently overridden.
- if (is_virtual) {
- switch (id) {
- case vmIntrinsics::_hashCode:
- case vmIntrinsics::_clone:
- // OK, Object.hashCode and Object.clone intrinsics come in both flavors
- break;
- default:
- return NULL;
- }
- }
+ C2Compiler* compiler = (C2Compiler*)CompileBroker::compiler(CompLevel_full_optimization);
+ bool is_available = false;
- // -XX:-InlineNatives disables nearly all intrinsics:
- if (!InlineNatives) {
- switch (id) {
- case vmIntrinsics::_indexOf:
- case vmIntrinsics::_compareTo:
- case vmIntrinsics::_equals:
- case vmIntrinsics::_equalsC:
- case vmIntrinsics::_getAndAddInt:
- case vmIntrinsics::_getAndAddLong:
- case vmIntrinsics::_getAndSetInt:
- case vmIntrinsics::_getAndSetLong:
- case vmIntrinsics::_getAndSetObject:
- case vmIntrinsics::_loadFence:
- case vmIntrinsics::_storeFence:
- case vmIntrinsics::_fullFence:
- break; // InlineNatives does not control String.compareTo
- case vmIntrinsics::_Reference_get:
- break; // InlineNatives does not control Reference.get
- default:
- return NULL;
- }
+ {
+ // For calling is_intrinsic_supported and is_intrinsic_disabled_by_flag
+ // the compiler must transition to '_thread_in_vm' state because both
+ // methods access VM-internal data.
+ VM_ENTRY_MARK;
+ methodHandle mh(THREAD, m->get_Method());
+ methodHandle ct(THREAD, method()->get_Method());
+ is_available = compiler->is_intrinsic_supported(mh, is_virtual) &&
+ !compiler->is_intrinsic_disabled_by_flag(mh, ct);
}
- int predicates = 0;
- bool does_virtual_dispatch = false;
-
- switch (id) {
- case vmIntrinsics::_compareTo:
- if (!SpecialStringCompareTo) return NULL;
- if (!Matcher::match_rule_supported(Op_StrComp)) return NULL;
- break;
- case vmIntrinsics::_indexOf:
- if (!SpecialStringIndexOf) return NULL;
- break;
- case vmIntrinsics::_equals:
- if (!SpecialStringEquals) return NULL;
- if (!Matcher::match_rule_supported(Op_StrEquals)) return NULL;
- break;
- case vmIntrinsics::_equalsC:
- if (!SpecialArraysEquals) return NULL;
- if (!Matcher::match_rule_supported(Op_AryEq)) return NULL;
- break;
- case vmIntrinsics::_arraycopy:
- if (!InlineArrayCopy) return NULL;
- break;
- case vmIntrinsics::_copyMemory:
- if (StubRoutines::unsafe_arraycopy() == NULL) return NULL;
- if (!InlineArrayCopy) return NULL;
- break;
- case vmIntrinsics::_hashCode:
- if (!InlineObjectHash) return NULL;
- does_virtual_dispatch = true;
- break;
- case vmIntrinsics::_clone:
- does_virtual_dispatch = true;
- case vmIntrinsics::_copyOf:
- case vmIntrinsics::_copyOfRange:
- if (!InlineObjectCopy) return NULL;
- // These also use the arraycopy intrinsic mechanism:
- if (!InlineArrayCopy) return NULL;
- break;
- case vmIntrinsics::_encodeISOArray:
- if (!SpecialEncodeISOArray) return NULL;
- if (!Matcher::match_rule_supported(Op_EncodeISOArray)) return NULL;
- break;
- case vmIntrinsics::_checkIndex:
- // We do not intrinsify this. The optimizer does fine with it.
- return NULL;
-
- case vmIntrinsics::_getCallerClass:
- if (!UseNewReflection) return NULL;
- if (!InlineReflectionGetCallerClass) return NULL;
- if (SystemDictionary::reflect_CallerSensitive_klass() == NULL) return NULL;
- break;
-
- case vmIntrinsics::_bitCount_i:
- if (!Matcher::match_rule_supported(Op_PopCountI)) return NULL;
- break;
-
- case vmIntrinsics::_bitCount_l:
- if (!Matcher::match_rule_supported(Op_PopCountL)) return NULL;
- break;
-
- case vmIntrinsics::_numberOfLeadingZeros_i:
- if (!Matcher::match_rule_supported(Op_CountLeadingZerosI)) return NULL;
- break;
-
- case vmIntrinsics::_numberOfLeadingZeros_l:
- if (!Matcher::match_rule_supported(Op_CountLeadingZerosL)) return NULL;
- break;
-
- case vmIntrinsics::_numberOfTrailingZeros_i:
- if (!Matcher::match_rule_supported(Op_CountTrailingZerosI)) return NULL;
- break;
-
- case vmIntrinsics::_numberOfTrailingZeros_l:
- if (!Matcher::match_rule_supported(Op_CountTrailingZerosL)) return NULL;
- break;
-
- case vmIntrinsics::_reverseBytes_c:
- if (!Matcher::match_rule_supported(Op_ReverseBytesUS)) return NULL;
- break;
- case vmIntrinsics::_reverseBytes_s:
- if (!Matcher::match_rule_supported(Op_ReverseBytesS)) return NULL;
- break;
- case vmIntrinsics::_reverseBytes_i:
- if (!Matcher::match_rule_supported(Op_ReverseBytesI)) return NULL;
- break;
- case vmIntrinsics::_reverseBytes_l:
- if (!Matcher::match_rule_supported(Op_ReverseBytesL)) return NULL;
- break;
-
- case vmIntrinsics::_Reference_get:
- // Use the intrinsic version of Reference.get() so that the value in
- // the referent field can be registered by the G1 pre-barrier code.
- // Also add memory barrier to prevent commoning reads from this field
- // across safepoint since GC can change it value.
- break;
-
- case vmIntrinsics::_compareAndSwapObject:
-#ifdef _LP64
- if (!UseCompressedOops && !Matcher::match_rule_supported(Op_CompareAndSwapP)) return NULL;
-#endif
- break;
-
- case vmIntrinsics::_compareAndSwapLong:
- if (!Matcher::match_rule_supported(Op_CompareAndSwapL)) return NULL;
- break;
-
- case vmIntrinsics::_getAndAddInt:
- if (!Matcher::match_rule_supported(Op_GetAndAddI)) return NULL;
- break;
-
- case vmIntrinsics::_getAndAddLong:
- if (!Matcher::match_rule_supported(Op_GetAndAddL)) return NULL;
- break;
-
- case vmIntrinsics::_getAndSetInt:
- if (!Matcher::match_rule_supported(Op_GetAndSetI)) return NULL;
- break;
-
- case vmIntrinsics::_getAndSetLong:
- if (!Matcher::match_rule_supported(Op_GetAndSetL)) return NULL;
- break;
-
- case vmIntrinsics::_getAndSetObject:
-#ifdef _LP64
- if (!UseCompressedOops && !Matcher::match_rule_supported(Op_GetAndSetP)) return NULL;
- if (UseCompressedOops && !Matcher::match_rule_supported(Op_GetAndSetN)) return NULL;
- break;
-#else
- if (!Matcher::match_rule_supported(Op_GetAndSetP)) return NULL;
- break;
-#endif
-
- case vmIntrinsics::_aescrypt_encryptBlock:
- case vmIntrinsics::_aescrypt_decryptBlock:
- if (!UseAESIntrinsics) return NULL;
- break;
-
- case vmIntrinsics::_multiplyToLen:
- if (!UseMultiplyToLenIntrinsic) return NULL;
- break;
-
- case vmIntrinsics::_squareToLen:
- if (!UseSquareToLenIntrinsic) return NULL;
- break;
-
- case vmIntrinsics::_mulAdd:
- if (!UseMulAddIntrinsic) return NULL;
- break;
-
- case vmIntrinsics::_montgomeryMultiply:
- if (!UseMontgomeryMultiplyIntrinsic) return NULL;
- break;
- case vmIntrinsics::_montgomerySquare:
- if (!UseMontgomerySquareIntrinsic) return NULL;
- break;
-
- case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt:
- case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
- if (!UseAESIntrinsics) return NULL;
- // these two require the predicated logic
- predicates = 1;
- break;
-
- case vmIntrinsics::_counterMode_AESCrypt:
- if (!UseAESCTRIntrinsics) {
- return NULL;
- }
- predicates = 1;
- break;
-
- case vmIntrinsics::_sha_implCompress:
- if (!UseSHA1Intrinsics) return NULL;
- break;
-
- case vmIntrinsics::_sha2_implCompress:
- if (!UseSHA256Intrinsics) return NULL;
- break;
-
- case vmIntrinsics::_sha5_implCompress:
- if (!UseSHA512Intrinsics) return NULL;
- break;
-
- case vmIntrinsics::_digestBase_implCompressMB:
- if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) return NULL;
- predicates = 3;
- break;
-
- case vmIntrinsics::_ghash_processBlocks:
- if (!UseGHASHIntrinsics) return NULL;
- break;
-
- case vmIntrinsics::_updateCRC32:
- case vmIntrinsics::_updateBytesCRC32:
- case vmIntrinsics::_updateByteBufferCRC32:
- if (!UseCRC32Intrinsics) return NULL;
- break;
-
- case vmIntrinsics::_f2jblas_ddot:
- case vmIntrinsics::_dgemm_dgemm:
- case vmIntrinsics::_dgemv_dgemv:
- if (!UseF2jBLASIntrinsics) return NULL;
- break;
-
- case vmIntrinsics::_incrementExactI:
- case vmIntrinsics::_addExactI:
- if (!Matcher::match_rule_supported(Op_OverflowAddI) || !UseMathExactIntrinsics) return NULL;
- break;
- case vmIntrinsics::_incrementExactL:
- case vmIntrinsics::_addExactL:
- if (!Matcher::match_rule_supported(Op_OverflowAddL) || !UseMathExactIntrinsics) return NULL;
- break;
- case vmIntrinsics::_decrementExactI:
- case vmIntrinsics::_subtractExactI:
- if (!Matcher::match_rule_supported(Op_OverflowSubI) || !UseMathExactIntrinsics) return NULL;
- break;
- case vmIntrinsics::_decrementExactL:
- case vmIntrinsics::_subtractExactL:
- if (!Matcher::match_rule_supported(Op_OverflowSubL) || !UseMathExactIntrinsics) return NULL;
- break;
- case vmIntrinsics::_negateExactI:
- if (!Matcher::match_rule_supported(Op_OverflowSubI) || !UseMathExactIntrinsics) return NULL;
- break;
- case vmIntrinsics::_negateExactL:
- if (!Matcher::match_rule_supported(Op_OverflowSubL) || !UseMathExactIntrinsics) return NULL;
- break;
- case vmIntrinsics::_multiplyExactI:
- if (!Matcher::match_rule_supported(Op_OverflowMulI) || !UseMathExactIntrinsics) return NULL;
- break;
- case vmIntrinsics::_multiplyExactL:
- if (!Matcher::match_rule_supported(Op_OverflowMulL) || !UseMathExactIntrinsics) return NULL;
- break;
-
- default:
+ if (is_available) {
assert(id <= vmIntrinsics::LAST_COMPILER_INLINE, "caller responsibility");
assert(id != vmIntrinsics::_Object_init && id != vmIntrinsics::_invoke, "enum out of order?");
- break;
- }
-
- // -XX:-InlineClassNatives disables natives from the Class class.
- // The flag applies to all reflective calls, notably Array.newArray
- // (visible to Java programmers as Array.newInstance).
- if (m->holder()->name() == ciSymbol::java_lang_Class() ||
- m->holder()->name() == ciSymbol::java_lang_reflect_Array()) {
- if (!InlineClassNatives) return NULL;
- }
-
- // -XX:-InlineThreadNatives disables natives from the Thread class.
- if (m->holder()->name() == ciSymbol::java_lang_Thread()) {
- if (!InlineThreadNatives) return NULL;
- }
-
- // -XX:-InlineMathNatives disables natives from the Math,Float and Double classes.
- if (m->holder()->name() == ciSymbol::java_lang_Math() ||
- m->holder()->name() == ciSymbol::java_lang_Float() ||
- m->holder()->name() == ciSymbol::java_lang_Double()) {
- if (!InlineMathNatives) return NULL;
- }
-
- // -XX:-InlineUnsafeOps disables natives from the Unsafe class.
- if (m->holder()->name() == ciSymbol::sun_misc_Unsafe()) {
- if (!InlineUnsafeOps) return NULL;
+ return new LibraryIntrinsic(m, is_virtual,
+ vmIntrinsics::predicates_needed(id),
+ vmIntrinsics::does_virtual_dispatch(id),
+ (vmIntrinsics::ID) id);
+ } else {
+ return NULL;
}
-
- return new LibraryIntrinsic(m, is_virtual, predicates, does_virtual_dispatch, (vmIntrinsics::ID) id);
}
//----------------------register_library_intrinsics-----------------------
diff --git a/hotspot/src/share/vm/prims/whitebox.cpp b/hotspot/src/share/vm/prims/whitebox.cpp
index 482bf6a62..16af34e34 100644
--- a/hotspot/src/share/vm/prims/whitebox.cpp
+++ b/hotspot/src/share/vm/prims/whitebox.cpp
@@ -559,6 +559,24 @@ WB_ENTRY(jboolean, WB_IsMethodQueuedForCompilation(JNIEnv* env, jobject o, jobje
return mh->queued_for_compilation();
WB_END
+WB_ENTRY(jboolean, WB_IsIntrinsicAvailable(JNIEnv* env, jobject /* o */, jobject method, jobject compilation_context, jint compLevel))
+ if (compLevel < CompLevel_none || compLevel > CompLevel_highest_tier) {
+ return false; // Intrinsic is not available on a non-existent compilation level.
+ }
+ jmethodID method_id, compilation_context_id;
+ method_id = reflected_method_to_jmid(thread, env, method);
+ CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
+ methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(method_id));
+ if (compilation_context != NULL) {
+ compilation_context_id = reflected_method_to_jmid(thread, env, compilation_context);
+ CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
+ methodHandle cch(THREAD, Method::checked_resolve_jmethod_id(compilation_context_id));
+ return CompileBroker::compiler(compLevel)->is_intrinsic_available(mh, cch);
+ } else {
+ return CompileBroker::compiler(compLevel)->is_intrinsic_available(mh, NULL);
+ }
+WB_END
+
WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject method, jboolean is_osr))
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
CHECK_JNI_EXCEPTION_(env, CompLevel_none);
@@ -1341,6 +1359,8 @@ static JNINativeMethod methods[] = {
(void*)&WB_IsMethodCompilable},
{CC"isMethodQueuedForCompilation",
CC"(Ljava/lang/reflect/Executable;)Z", (void*)&WB_IsMethodQueuedForCompilation},
+ {CC"isIntrinsicAvailable0", CC"(Ljava/lang/reflect/Executable;Ljava/lang/reflect/Executable;I)Z",
+ (void*)&WB_IsIntrinsicAvailable},
{CC"makeMethodNotCompilable",
CC"(Ljava/lang/reflect/Executable;IZ)V", (void*)&WB_MakeMethodNotCompilable},
{CC"testSetDontInlineMethod",
diff --git a/hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java b/hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java
new file mode 100644
index 000000000..1a5475403
--- /dev/null
+++ b/hotspot/test/compiler/intrinsics/IntrinsicAvailableTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2015, 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.
+ */
+import java.lang.reflect.Executable;
+import java.util.concurrent.Callable;
+import java.util.Objects;
+/*
+ * @test
+ * @bug 8130832
+ * @library /testlibrary /../../test/lib /compiler/whitebox /compiler/testlibrary
+ * @build IntrinsicAvailableTest
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:.
+ * -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI
+ * -XX:+UseCRC32Intrinsics
+ * IntrinsicAvailableTest
+ * @run main/othervm -Xbootclasspath/a:.
+ * -XX:+UnlockDiagnosticVMOptions
+ * -XX:+WhiteBoxAPI
+ * -XX:-UseCRC32Intrinsics
+ * IntrinsicAvailableTest
+ */
+public class IntrinsicAvailableTest extends CompilerWhiteBoxTest {
+ protected String VMName;
+
+ public IntrinsicAvailableTest(IntrinsicAvailableTestTestCase testCase) {
+ super(testCase);
+ VMName = System.getProperty("java.vm.name");
+ }
+
+ public static class IntrinsicAvailableTestTestCase implements TestCase {
+
+ public String name() {
+ return "IntrinsicAvailableTestTestCase";
+ }
+
+ public Executable getExecutable() {
+ // Using a single method to test the
+ // WhiteBox.isIntrinsicAvailable(Executable method, int compLevel)
+ // call for the compilation level corresponding to both the C1 and C2
+ // compiler keeps the current test simple.
+ //
+ // The tested method is java.util.zip.CRC32.update(int, int) because
+ // both C1 and C2 define an intrinsic for the method and
+ // the UseCRC32Intrinsics flag can be used to enable/disable
+ // intrinsification of the method in both product and fastdebug
+ // builds.
+ try {
+ return Class.forName("java.util.zip.CRC32").getDeclaredMethod("update", int.class, int.class);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("Test bug, method unavailable. " + e);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Test bug, class unavailable. " + e);
+ }
+ }
+
+ public Callable<Integer> getCallable() {
+ return null;
+ }
+
+ public boolean isOsr() {
+ return false;
+ }
+
+ }
+
+ protected void checkIntrinsicForCompilationLevel(Executable method, int compLevel) throws Exception {
+ boolean intrinsicEnabled = Boolean.valueOf(getVMOption("UseCRC32Intrinsics"));
+ boolean intrinsicAvailable = WHITE_BOX.isIntrinsicAvailable(method,
+ compLevel);
+
+ String intrinsicEnabledMessage = intrinsicEnabled ? "enabled" : "disabled";
+ String intrinsicAvailableMessage = intrinsicAvailable ? "available" : "not available";
+
+ if (intrinsicEnabled == intrinsicAvailable) {
+ System.out.println("Expected result: intrinsic for java.util.zip.CRC32.update() is " +
+ intrinsicEnabledMessage + " and intrinsic is " + intrinsicAvailableMessage +
+ " at compilation level " + compLevel);
+ } else {
+ throw new RuntimeException("Unexpected result: intrinsic for java.util.zip.CRC32.update() is " +
+ intrinsicEnabledMessage + " but intrinsic is " + intrinsicAvailableMessage +
+ " at compilation level " + compLevel);
+ }
+ }
+
+ protected boolean isServerVM() {
+ return VMName.toLowerCase().contains("server");
+ }
+
+ public void test() throws Exception {
+ Executable intrinsicMethod = testCase.getExecutable();
+ if (isServerVM()) {
+ if (TIERED_COMPILATION) {
+ checkIntrinsicForCompilationLevel(intrinsicMethod, COMP_LEVEL_SIMPLE);
+ }
+ checkIntrinsicForCompilationLevel(intrinsicMethod, COMP_LEVEL_FULL_OPTIMIZATION);
+ } else {
+ checkIntrinsicForCompilationLevel(intrinsicMethod, COMP_LEVEL_SIMPLE);
+ }
+ }
+
+ public static void main(String args[]) throws Exception {
+ new IntrinsicAvailableTest(new IntrinsicAvailableTestTestCase()).test();
+ }
+}
diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java
index bdc39962f..a258140b1 100644
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java
@@ -67,7 +67,7 @@ public abstract class IntrinsicBase extends CompilerWhiteBoxTest {
compileAtLevel(CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
}
- if (!isIntrinsicSupported()) {
+ if (!isIntrinsicAvailable()) {
expectedIntrinsicCount = 0;
}
break;
@@ -114,7 +114,11 @@ public abstract class IntrinsicBase extends CompilerWhiteBoxTest {
}
}
- protected abstract boolean isIntrinsicSupported();
+ // An intrinsic is available if:
+ // - the intrinsic is enabled (by using the appropriate command-line flag) and
+ // - the intrinsic is supported by the VM (i.e., the platform on which the VM is
+ // running provides the instructions necessary for the VM to generate the intrinsic).
+ protected abstract boolean isIntrinsicAvailable();
protected abstract String getIntrinsicId();
@@ -123,13 +127,20 @@ public abstract class IntrinsicBase extends CompilerWhiteBoxTest {
}
static class IntTest extends IntrinsicBase {
+
+ protected boolean isIntrinsicAvailable; // The tested intrinsic is available on the current platform.
+
protected IntTest(MathIntrinsic.IntIntrinsic testCase) {
super(testCase);
+ // Only the C2 compiler intrinsifies exact math methods
+ // so check if the intrinsics are available with C2.
+ isIntrinsicAvailable = WHITE_BOX.isIntrinsicAvailable(testCase.getTestMethod(),
+ COMP_LEVEL_FULL_OPTIMIZATION);
}
@Override
- protected boolean isIntrinsicSupported() {
- return isServerVM() && Boolean.valueOf(useMathExactIntrinsics) && (Platform.isX86() || Platform.isX64() || Platform.isAArch64());
+ protected boolean isIntrinsicAvailable() {
+ return isIntrinsicAvailable;
}
@Override
@@ -139,13 +150,20 @@ public abstract class IntrinsicBase extends CompilerWhiteBoxTest {
}
static class LongTest extends IntrinsicBase {
+
+ protected boolean isIntrinsicAvailable; // The tested intrinsic is available on the current platform.
+
protected LongTest(MathIntrinsic.LongIntrinsic testCase) {
super(testCase);
+ // Only the C2 compiler intrinsifies exact math methods
+ // so check if the intrinsics are available with C2.
+ isIntrinsicAvailable = WHITE_BOX.isIntrinsicAvailable(testCase.getTestMethod(),
+ COMP_LEVEL_FULL_OPTIMIZATION);
}
@Override
- protected boolean isIntrinsicSupported() {
- return isServerVM() && Boolean.valueOf(useMathExactIntrinsics) && (Platform.isX64() || Platform.isAArch64());
+ protected boolean isIntrinsicAvailable() {
+ return isIntrinsicAvailable;
}
@Override
diff --git a/hotspot/test/compiler/intrinsics/mathexact/sanity/MathIntrinsic.java b/hotspot/test/compiler/intrinsics/mathexact/sanity/MathIntrinsic.java
index 99039f9a7..b967bd4b0 100644
--- a/hotspot/test/compiler/intrinsics/mathexact/sanity/MathIntrinsic.java
+++ b/hotspot/test/compiler/intrinsics/mathexact/sanity/MathIntrinsic.java
@@ -28,36 +28,65 @@ public class MathIntrinsic {
enum IntIntrinsic implements CompilerWhiteBoxTest.TestCase {
Add {
+ @Override
+ Executable testMethod() throws NoSuchMethodException, ClassNotFoundException {
+ return Class.forName("java.lang.Math").getDeclaredMethod("addExact", int.class, int.class);
+ }
+
@Override
Object execMathMethod() {
return intR = Math.addExact(int1, int2);
}
},
Subtract {
+ @Override
+ Executable testMethod() throws NoSuchMethodException, ClassNotFoundException {
+ return Class.forName("java.lang.Math").getDeclaredMethod("subtractExact", int.class, int.class);
+ }
@Override
Object execMathMethod() {
return intR = Math.subtractExact(int1, int2);
}
},
Multiply {
+ @Override
+ Executable testMethod() throws NoSuchMethodException, ClassNotFoundException {
+ return Class.forName("java.lang.Math").getDeclaredMethod("multiplyExact", int.class, int.class);
+ }
+
@Override
Object execMathMethod() {
return intR = Math.multiplyExact(int1, int2);
}
},
Increment {
+ @Override
+ Executable testMethod() throws NoSuchMethodException, ClassNotFoundException {
+ return Class.forName("java.lang.Math").getDeclaredMethod("incrementExact", int.class);
+ }
+
@Override
Object execMathMethod() {
return intR = Math.incrementExact(int1);
}
},
Decrement {
+ @Override
+ Executable testMethod() throws NoSuchMethodException, ClassNotFoundException {
+ return Class.forName("java.lang.Math").getDeclaredMethod("decrementExact", int.class);
+ }
+
@Override
Object execMathMethod() {
return intR = Math.decrementExact(int1);
}
},
Negate {
+ @Override
+ Executable testMethod() throws NoSuchMethodException, ClassNotFoundException {
+ return Class.forName("java.lang.Math").getDeclaredMethod("negateExact", int.class);
+ }
+
@Override
Object execMathMethod() {
return intR = Math.negateExact(int1);
@@ -67,8 +96,19 @@ public class MathIntrinsic {
protected int int2;
protected int intR;
+ abstract Executable testMethod() throws NoSuchMethodException, ClassNotFoundException;
abstract Object execMathMethod();
+ public Executable getTestMethod() {
+ try {
+ return testMethod();
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("Test bug, no such method: " + e);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Test bug, no such class: " + e);
+ }
+ }
+
@Override
public Executable getExecutable() {
try {
@@ -92,36 +132,66 @@ public class MathIntrinsic {
enum LongIntrinsic implements CompilerWhiteBoxTest.TestCase {
Add {
+ @Override
+ Executable testMethod() throws NoSuchMethodException, ClassNotFoundException {
+ return Class.forName("java.lang.Math").getDeclaredMethod("addExact", long.class, long.class);
+ }
+
@Override
Object execMathMethod() {
return longR = Math.addExact(long1, long2);
}
},
Subtract {
+ @Override
+ Executable testMethod() throws NoSuchMethodException, ClassNotFoundException {
+ return Class.forName("java.lang.Math").getDeclaredMethod("subtractExact", long.class, long.class);
+ }
+
@Override
Object execMathMethod() {
return longR = Math.subtractExact(long1, long2);
}
},
Multiply {
+ @Override
+ Executable testMethod() throws NoSuchMethodException, ClassNotFoundException {
+ return Class.forName("java.lang.Math").getDeclaredMethod("multiplyExact", long.class, long.class);
+ }
+
@Override
Object execMathMethod() {
return longR = Math.multiplyExact(long1, long2);
}
},
Increment {
+ @Override
+ Executable testMethod() throws NoSuchMethodException, ClassNotFoundException {
+ return Class.forName("java.lang.Math").getDeclaredMethod("incrementExact", long.class);
+ }
+
@Override
Object execMathMethod() {
return longR = Math.incrementExact(long1);
}
},
Decrement {
+ @Override
+ Executable testMethod() throws NoSuchMethodException, ClassNotFoundException {
+ return Class.forName("java.lang.Math").getDeclaredMethod("decrementExact", long.class);
+ }
+
@Override
Object execMathMethod() {
return longR = Math.decrementExact(long1);
}
},
Negate {
+ @Override
+ Executable testMethod() throws NoSuchMethodException, ClassNotFoundException {
+ return Class.forName("java.lang.Math").getDeclaredMethod("negateExact", long.class);
+ }
+
@Override
Object execMathMethod() {
return longR = Math.negateExact(long1);
@@ -131,8 +201,19 @@ public class MathIntrinsic {
protected long long2;
protected long longR;
+ abstract Executable testMethod() throws NoSuchMethodException, ClassNotFoundException;
abstract Object execMathMethod();
+ public Executable getTestMethod() {
+ try {
+ return testMethod();
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("Test bug, no such method: " + e);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Test bug, no such class: " + e);
+ }
+ }
+
@Override
public Executable getExecutable() {
try {
--
2.22.0
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。