# HG changeset patch # User adinn # Date 1554390714 -3600 # Thu Apr 04 16:11:54 2019 +0100 # Node ID 4f3964cbf7cc8c416ea7cbfe241fdc2769592de1 # Parent a7df0de0835abf753598d872c354a4ea1843e358 8221477: Inject os/cpu-specific constants into Unsafe from JVM Summary: Initialize Unsafe os/cpu-specific constants using injection instead of native callouts Reviewed-by: stuefe, coleenp, dholmes diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -218,7 +218,7 @@ void java_lang_String::set_compact_strings(bool value) { CompactStringsFixup fix(value); - InstanceKlass::cast(SystemDictionary::String_klass())->do_local_static_fields(&fix); + SystemDictionary::String_klass()->do_local_static_fields(&fix); } Handle java_lang_String::basic_create(int length, bool is_latin1, TRAPS) { @@ -3991,6 +3991,48 @@ int java_lang_System::out_offset_in_bytes() { return static_out_offset; } int java_lang_System::err_offset_in_bytes() { return static_err_offset; } +// Support for jdk_internal_misc_UnsafeConstants +// +class UnsafeConstantsFixup : public FieldClosure { +private: + int _address_size; + int _page_size; + bool _big_endian; + bool _use_unaligned_access; +public: + UnsafeConstantsFixup() { + // round up values for all static final fields + _address_size = sizeof(void*); + _page_size = os::vm_page_size(); + _big_endian = LITTLE_ENDIAN_ONLY(false) BIG_ENDIAN_ONLY(true); + _use_unaligned_access = UseUnalignedAccesses; + } + + void do_field(fieldDescriptor* fd) { + oop mirror = fd->field_holder()->java_mirror(); + assert(mirror != NULL, "UnsafeConstants must have mirror already"); + assert(fd->field_holder() == SystemDictionary::UnsafeConstants_klass(), "Should be UnsafeConstants"); + assert(fd->is_final(), "fields of UnsafeConstants must be final"); + assert(fd->is_static(), "fields of UnsafeConstants must be static"); + if (fd->name() == vmSymbols::address_size_name()) { + mirror->int_field_put(fd->offset(), _address_size); + } else if (fd->name() == vmSymbols::page_size_name()) { + mirror->int_field_put(fd->offset(), _page_size); + } else if (fd->name() == vmSymbols::big_endian_name()) { + mirror->bool_field_put(fd->offset(), _big_endian); + } else if (fd->name() == vmSymbols::use_unaligned_access_name()) { + mirror->bool_field_put(fd->offset(), _use_unaligned_access); + } else { + assert(false, "unexpected UnsafeConstants field"); + } + } +}; + +void jdk_internal_misc_UnsafeConstants::set_unsafe_constants() { + UnsafeConstantsFixup fixup; + SystemDictionary::UnsafeConstants_klass()->do_local_static_fields(&fixup); +} + int java_lang_Class::_klass_offset; int java_lang_Class::_array_klass_offset; int java_lang_Class::_oop_size_offset; diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -81,6 +81,7 @@ f(java_lang_StackFrameInfo) \ f(java_lang_LiveStackFrameInfo) \ f(java_util_concurrent_locks_AbstractOwnableSynchronizer) \ + f(jdk_internal_misc_UnsafeConstants) \ //end #define BASIC_JAVA_CLASSES_DO(f) \ @@ -1483,6 +1484,15 @@ static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN; }; + // Interface to jdk.internal.misc.UnsafeConsants + +class jdk_internal_misc_UnsafeConstants : AllStatic { + public: + static void set_unsafe_constants(); + static void compute_offsets() { } + static void serialize_offsets(SerializeClosure* f) { } +}; + // Use to declare fields that need to be injected into Java classes // for the JVM to use. The name_index and signature_index are // declared in vmSymbols. The may_be_java flag is used to declare diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -177,6 +177,7 @@ do_klass(AssertionStatusDirectives_klass, java_lang_AssertionStatusDirectives ) \ do_klass(StringBuffer_klass, java_lang_StringBuffer ) \ do_klass(StringBuilder_klass, java_lang_StringBuilder ) \ + do_klass(UnsafeConstants_klass, jdk_internal_misc_UnsafeConstants ) \ do_klass(internal_Unsafe_klass, jdk_internal_misc_Unsafe ) \ do_klass(module_Modules_klass, jdk_internal_module_Modules ) \ \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -446,6 +446,10 @@ template(module_entry_name, "module_entry") \ template(resolved_references_name, "") \ template(init_lock_name, "") \ + template(address_size_name, "ADDRESS_SIZE0") \ + template(page_size_name, "PAGE_SIZE") \ + template(big_endian_name, "BE") \ + template(use_unaligned_access_name, "UNALIGNED_ACCESS") \ \ /* name symbols needed by intrinsics */ \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, template, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) \ @@ -1070,6 +1074,9 @@ do_intrinsic(_updateByteBufferAdler32, java_util_zip_Adler32, updateByteBuffer_A_name, updateByteBuffer_signature, F_SN) \ do_name( updateByteBuffer_A_name, "updateByteBuffer") \ \ + /* support for UnsafeConstants */ \ + do_class(jdk_internal_misc_UnsafeConstants, "jdk/internal/misc/UnsafeConstants") \ + \ /* support for Unsafe */ \ do_class(jdk_internal_misc_Unsafe, "jdk/internal/misc/Unsafe") \ \ diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -292,18 +292,6 @@ return JNIHandles::make_local(env, v); } UNSAFE_END -UNSAFE_LEAF(jboolean, Unsafe_isBigEndian0(JNIEnv *env, jobject unsafe)) { -#ifdef VM_LITTLE_ENDIAN - return false; -#else - return true; -#endif -} UNSAFE_END - -UNSAFE_LEAF(jint, Unsafe_unalignedAccess0(JNIEnv *env, jobject unsafe)) { - return UseUnalignedAccesses; -} UNSAFE_END - #define DEFINE_GETSETOOP(java_type, Type) \ \ UNSAFE_ENTRY(java_type, Unsafe_Get##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \ @@ -446,14 +434,6 @@ ////// Random queries -UNSAFE_LEAF(jint, Unsafe_AddressSize0(JNIEnv *env, jobject unsafe)) { - return sizeof(void*); -} UNSAFE_END - -UNSAFE_LEAF(jint, Unsafe_PageSize()) { - return os::vm_page_size(); -} UNSAFE_END - static jlong find_field_offset(jclass clazz, jstring name, TRAPS) { assert(clazz != NULL, "clazz must not be NULL"); assert(name != NULL, "name must not be NULL"); @@ -1073,8 +1053,6 @@ {CC "ensureClassInitialized0", CC "(" CLS ")V", FN_PTR(Unsafe_EnsureClassInitialized0)}, {CC "arrayBaseOffset0", CC "(" CLS ")I", FN_PTR(Unsafe_ArrayBaseOffset0)}, {CC "arrayIndexScale0", CC "(" CLS ")I", FN_PTR(Unsafe_ArrayIndexScale0)}, - {CC "addressSize0", CC "()I", FN_PTR(Unsafe_AddressSize0)}, - {CC "pageSize", CC "()I", FN_PTR(Unsafe_PageSize)}, {CC "defineClass0", CC "(" DC_Args ")" CLS, FN_PTR(Unsafe_DefineClass0)}, {CC "allocateInstance", CC "(" CLS ")" OBJ, FN_PTR(Unsafe_AllocateInstance)}, @@ -1102,9 +1080,6 @@ {CC "loadFence", CC "()V", FN_PTR(Unsafe_LoadFence)}, {CC "storeFence", CC "()V", FN_PTR(Unsafe_StoreFence)}, {CC "fullFence", CC "()V", FN_PTR(Unsafe_FullFence)}, - - {CC "isBigEndian0", CC "()Z", FN_PTR(Unsafe_isBigEndian0)}, - {CC "unalignedAccess0", CC "()Z", FN_PTR(Unsafe_unalignedAccess0)} }; #undef CC diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -3628,6 +3628,7 @@ initialize_class(vmSymbols::java_lang_Thread(), CHECK); oop thread_object = create_initial_thread(thread_group, main_thread, CHECK); main_thread->set_threadObj(thread_object); + // Set thread status to running since main thread has // been started and running. java_lang_Thread::set_thread_status(thread_object, @@ -3636,6 +3637,15 @@ // The VM creates objects of this class. initialize_class(vmSymbols::java_lang_Module(), CHECK); +#ifdef ASSERT + InstanceKlass *k = SystemDictionary::UnsafeConstants_klass(); + assert(k->is_not_initialized(), "UnsafeConstants should not already be initialized"); +#endif + + // initialize the hardware-specific constants needed by Unsafe + initialize_class(vmSymbols::jdk_internal_misc_UnsafeConstants(), CHECK); + jdk_internal_misc_UnsafeConstants::set_unsafe_constants(); + // The VM preresolves methods to these classes. Make sure that they get initialized initialize_class(vmSymbols::java_lang_reflect_Method(), CHECK); initialize_class(vmSymbols::java_lang_ref_Finalizer(), CHECK); diff --git a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java --- a/src/java.base/share/classes/jdk/internal/misc/Unsafe.java +++ b/src/java.base/share/classes/jdk/internal/misc/Unsafe.java @@ -33,6 +33,7 @@ import java.lang.reflect.Field; import java.security.ProtectionDomain; +import static jdk.internal.misc.UnsafeConstants.*; /** * A collection of methods for performing low-level, unsafe operations. @@ -1166,14 +1167,13 @@ } /** The value of {@code addressSize()} */ - public static final int ADDRESS_SIZE = theUnsafe.addressSize0(); + public static final int ADDRESS_SIZE = ADDRESS_SIZE0; /** * Reports the size in bytes of a native memory page (whatever that is). * This value will always be a power of two. */ - public native int pageSize(); - + public int pageSize() { return PAGE_SIZE; } /// random trusted operations from JNI: @@ -3361,7 +3361,7 @@ * accesses at addresses which are not aligned for the type of the * primitive type being accessed, false otherwise. */ - public final boolean unalignedAccess() { return unalignedAccess; } + public final boolean unalignedAccess() { return UNALIGNED_ACCESS; } /** * Fetches a value at some byte offset into a given Java object. @@ -3603,13 +3603,6 @@ putCharUnaligned(o, offset, convEndian(bigEndian, x)); } - // JVM interface methods - // BE is true iff the native endianness of this platform is big. - private static final boolean BE = theUnsafe.isBigEndian0(); - - // unalignedAccess is true iff this platform can perform unaligned accesses. - private static final boolean unalignedAccess = theUnsafe.unalignedAccess0(); - private static int pickPos(int top, int pos) { return BE ? top - pos : pos; } // These methods construct integers from bytes. The byte ordering @@ -3721,11 +3714,8 @@ private native void ensureClassInitialized0(Class c); private native int arrayBaseOffset0(Class arrayClass); private native int arrayIndexScale0(Class arrayClass); - private native int addressSize0(); private native Class defineAnonymousClass0(Class hostClass, byte[] data, Object[] cpPatches); private native int getLoadAverage0(double[] loadavg, int nelems); - private native boolean unalignedAccess0(); - private native boolean isBigEndian0(); /** diff --git a/src/java.base/share/classes/jdk/internal/misc/UnsafeConstants.java b/src/java.base/share/classes/jdk/internal/misc/UnsafeConstants.java new file mode 100644 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/misc/UnsafeConstants.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2019, Red Hat Inc. 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package jdk.internal.misc; + +/** + * A class used to expose details of the underlying hardware that + * configure the operation of class Unsafe. This class is + * package-private as the only intended client is class Unsafe. + * All fields in this class must be static final constants. + * + * @since 13 + * + * @implNote + * + * The JVM injects hardware-specific values into all the static fields + * of this class during JVM initialization. The static initialization + * block exists to prevent the fields from being considered constant + * variables, so the field values will be not be compiled directly into + * any class that uses them. + */ + +final class UnsafeConstants { + + /** + * This constructor is private because the class is not meant to + * be instantiated. + */ + private UnsafeConstants() {} + + /** + * The size in bytes of a native pointer, as stored via {@link + * #putAddress}. This value will be either 4 or 8. Note that the + * sizes of other primitive types (as stored in native memory + * blocks) is determined fully by their information content. + * + * @implNote + * The actual value for this field is injected by the JVM. + */ + + static final int ADDRESS_SIZE0; + + /** + * The size in bytes of a native memory page (whatever that is). + * This value will always be a power of two. + * + * @implNote + * The actual value for this field is injected by the JVM. + */ + + static final int PAGE_SIZE; + + /** + * Flag whose value is true if and only if the native endianness + * of this platform is big. + * + * @implNote + * The actual value for this field is injected by the JVM. + */ + + static final boolean BE; + + /** + * Flag whose value is true if and only if the platform can + * perform unaligned accesses + * + * @implNote + * The actual value for this field is injected by the JVM. + */ + + static final boolean UNALIGNED_ACCESS; + + static { + ADDRESS_SIZE0 = 0; + PAGE_SIZE = 0; + BE = false; + UNALIGNED_ACCESS = false; + } +} diff --git a/test/jdk/java/lang/reflect/AccessibleObject/CanAccessTest.java b/test/jdk/java/lang/reflect/AccessibleObject/CanAccessTest.java --- a/test/jdk/java/lang/reflect/AccessibleObject/CanAccessTest.java +++ b/test/jdk/java/lang/reflect/AccessibleObject/CanAccessTest.java @@ -94,7 +94,7 @@ * for instance members */ public void testInstanceMethod() throws Exception { - Method m = Unsafe.class.getDeclaredMethod("addressSize0"); + Method m = Unsafe.class.getDeclaredMethod("allocateMemory0", long.class); assertFalse(m.canAccess(INSTANCE)); try {