< prev index next >

src/hotspot/share/prims/unsafe.cpp

Print this page
*** 32,19 ***
--- 32,25 ---
  #include "jfr/jfrEvents.hpp"
  #include "jni.h"
  #include "jvm.h"
  #include "memory/allocation.inline.hpp"
  #include "memory/resourceArea.hpp"
+ #include "logging/log.hpp"
+ #include "logging/logStream.hpp"
  #include "oops/access.inline.hpp"
  #include "oops/fieldStreams.inline.hpp"
+ #include "oops/flatArrayKlass.hpp"
+ #include "oops/flatArrayOop.inline.hpp"
+ #include "oops/inlineKlass.inline.hpp"
  #include "oops/instanceKlass.inline.hpp"
  #include "oops/klass.inline.hpp"
  #include "oops/objArrayOop.inline.hpp"
  #include "oops/oop.inline.hpp"
  #include "oops/typeArrayOop.inline.hpp"
  #include "prims/jvmtiExport.hpp"
  #include "prims/unsafe.hpp"
+ #include "runtime/fieldDescriptor.inline.hpp"
  #include "runtime/globals.hpp"
  #include "runtime/handles.inline.hpp"
  #include "runtime/interfaceSupport.inline.hpp"
  #include "runtime/javaThread.inline.hpp"
  #include "runtime/jniHandles.inline.hpp"

*** 167,11 ***
  }
  jlong Unsafe_field_offset_from_byte_offset(jlong byte_offset) {
    return byte_offset;
  }
  
- 
  ///// Data read/writes on the Java heap and in native (off-heap) memory
  
  /**
   * Helper class to wrap memory accesses in JavaThread::doing_unsafe_access()
   */
--- 173,10 ---

*** 246,14 ***
    // we use this method at some places for writing to 0 e.g. to cause a crash;
    // ubsan does not know that this is the desired behavior
    ATTRIBUTE_NO_UBSAN
    void put(T x) {
      GuardUnsafeAccess guard(_thread);
      *addr() = normalize_for_write(x);
    }
  
- 
    T get_volatile() {
      GuardUnsafeAccess guard(_thread);
      volatile T ret = RawAccess<MO_SEQ_CST>::load(addr());
      return normalize_for_read(ret);
    }
--- 251,14 ---
    // we use this method at some places for writing to 0 e.g. to cause a crash;
    // ubsan does not know that this is the desired behavior
    ATTRIBUTE_NO_UBSAN
    void put(T x) {
      GuardUnsafeAccess guard(_thread);
+     assert(_obj == nullptr || !_obj->is_inline_type() || _obj->mark().is_larval_state(), "must be an object instance or a larval inline type");
      *addr() = normalize_for_write(x);
    }
  
    T get_volatile() {
      GuardUnsafeAccess guard(_thread);
      volatile T ret = RawAccess<MO_SEQ_CST>::load(addr());
      return normalize_for_read(ret);
    }

*** 262,10 ***
--- 267,72 ---
      GuardUnsafeAccess guard(_thread);
      RawAccess<MO_SEQ_CST>::store(addr(), normalize_for_write(x));
    }
  };
  
+ #ifdef ASSERT
+ /*
+  * Get the field descriptor of the field of the given object at the given offset.
+  */
+ static bool get_field_descriptor(oop p, jlong offset, fieldDescriptor* fd) {
+   bool found = false;
+   Klass* k = p->klass();
+   if (k->is_instance_klass()) {
+     InstanceKlass* ik = InstanceKlass::cast(k);
+     found = ik->find_field_from_offset((int)offset, false, fd);
+     if (!found && ik->is_mirror_instance_klass()) {
+       Klass* k2 = java_lang_Class::as_Klass(p);
+       if (k2->is_instance_klass()) {
+         ik = InstanceKlass::cast(k2);
+         found = ik->find_field_from_offset((int)offset, true, fd);
+       }
+     }
+   }
+   return found;
+ }
+ #endif // ASSERT
+ 
+ static void assert_and_log_unsafe_value_access(oop p, jlong offset, InlineKlass* vk) {
+   Klass* k = p->klass();
+ #ifdef ASSERT
+   if (k->is_instance_klass()) {
+     assert_field_offset_sane(p, offset);
+     fieldDescriptor fd;
+     bool found = get_field_descriptor(p, offset, &fd);
+     if (found) {
+       assert(found, "value field not found");
+       assert(fd.is_flat(), "field not flat");
+     } else {
+       if (log_is_enabled(Trace, valuetypes)) {
+         log_trace(valuetypes)("not a field in %s at offset " UINT64_FORMAT_X,
+                               p->klass()->external_name(), (uint64_t)offset);
+       }
+     }
+   } else if (k->is_flatArray_klass()) {
+     FlatArrayKlass* vak = FlatArrayKlass::cast(k);
+     int index = (offset - vak->array_header_in_bytes()) / vak->element_byte_size();
+     address dest = (address)((flatArrayOop)p)->value_at_addr(index, vak->layout_helper());
+     assert(dest == (cast_from_oop<address>(p) + offset), "invalid offset");
+   } else {
+     ShouldNotReachHere();
+   }
+ #endif // ASSERT
+   if (log_is_enabled(Trace, valuetypes)) {
+     if (k->is_flatArray_klass()) {
+       FlatArrayKlass* vak = FlatArrayKlass::cast(k);
+       int index = (offset - vak->array_header_in_bytes()) / vak->element_byte_size();
+       address dest = (address)((flatArrayOop)p)->value_at_addr(index, vak->layout_helper());
+       log_trace(valuetypes)("%s array type %s index %d element size %d offset " UINT64_FORMAT_X " at " INTPTR_FORMAT,
+                             p->klass()->external_name(), vak->external_name(),
+                             index, vak->element_byte_size(), (uint64_t)offset, p2i(dest));
+     } else {
+       log_trace(valuetypes)("%s field type %s at offset " UINT64_FORMAT_X,
+                             p->klass()->external_name(), vk->external_name(), (uint64_t)offset);
+     }
+   }
+ }
+ 
  // These functions allow a null base pointer with an arbitrary address.
  // But if the base pointer is non-null, the offset should make some sense.
  // That is, it should be in the range [0, MAX_OBJECT_SIZE].
  UNSAFE_ENTRY(jobject, Unsafe_GetReference(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) {
    oop p = JNIHandles::resolve(obj);

*** 276,13 ***
--- 343,93 ---
  
  UNSAFE_ENTRY(void, Unsafe_PutReference(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jobject x_h)) {
    oop x = JNIHandles::resolve(x_h);
    oop p = JNIHandles::resolve(obj);
    assert_field_offset_sane(p, offset);
+   assert(!p->is_inline_type() || p->mark().is_larval_state(), "must be an object instance or a larval inline type");
    HeapAccess<ON_UNKNOWN_OOP_REF>::oop_store_at(p, offset, x);
  } UNSAFE_END
  
+ UNSAFE_ENTRY(jlong, Unsafe_ValueHeaderSize(JNIEnv *env, jobject unsafe, jclass c)) {
+   Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c));
+   InlineKlass* vk = InlineKlass::cast(k);
+   return vk->first_field_offset();
+ } UNSAFE_END
+ 
+ UNSAFE_ENTRY(jboolean, Unsafe_IsFlatField(JNIEnv *env, jobject unsafe, jobject o)) {
+   oop f = JNIHandles::resolve_non_null(o);
+   Klass* k = java_lang_Class::as_Klass(java_lang_reflect_Field::clazz(f));
+   int slot = java_lang_reflect_Field::slot(f);
+   return InstanceKlass::cast(k)->field_is_flat(slot);
+ } UNSAFE_END
+ 
+ UNSAFE_ENTRY(jboolean, Unsafe_HasNullMarker(JNIEnv *env, jobject unsage, jobject o)) {
+   oop f = JNIHandles::resolve_non_null(o);
+   Klass* k = java_lang_Class::as_Klass(java_lang_reflect_Field::clazz(f));
+   int slot = java_lang_reflect_Field::slot(f);
+   return InstanceKlass::cast(k)->field_has_null_marker(slot);
+ } UNSAFE_END
+ 
+ UNSAFE_ENTRY(jint, Unsafe_NullMarkerOffset(JNIEnv *env, jobject unsage, jobject o)) {
+   oop f = JNIHandles::resolve_non_null(o);
+   Klass* k = java_lang_Class::as_Klass(java_lang_reflect_Field::clazz(f));
+   int slot = java_lang_reflect_Field::slot(f);
+   fatal("Not supported yet");
+ } UNSAFE_END
+ 
+ UNSAFE_ENTRY(jboolean, Unsafe_IsFlatArray(JNIEnv *env, jobject unsafe, jclass c)) {
+   Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c));
+   return k->is_flatArray_klass();
+ } UNSAFE_END
+ 
+ UNSAFE_ENTRY(jobject, Unsafe_UninitializedDefaultValue(JNIEnv *env, jobject unsafe, jclass vc)) {
+   Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(vc));
+   InlineKlass* vk = InlineKlass::cast(k);
+   oop v = vk->default_value();
+   return JNIHandles::make_local(THREAD, v);
+ } UNSAFE_END
+ 
+ UNSAFE_ENTRY(jobject, Unsafe_GetValue(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jclass vc)) {
+   oop base = JNIHandles::resolve(obj);
+   Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(vc));
+   InlineKlass* vk = InlineKlass::cast(k);
+   assert_and_log_unsafe_value_access(base, offset, vk);
+   Handle base_h(THREAD, base);
+   oop v = vk->read_flat_field(base_h(), offset, LayoutKind::PAYLOAD, CHECK_NULL);  // TODO FIXME Hard coded layout kind to make the code compile, Unsafe must be upgraded to handle correct layout kind
+   return JNIHandles::make_local(THREAD, v);
+ } UNSAFE_END
+ 
+ UNSAFE_ENTRY(void, Unsafe_PutValue(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jclass vc, jobject value)) {
+   oop base = JNIHandles::resolve(obj);
+   Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(vc));
+   InlineKlass* vk = InlineKlass::cast(k);
+   assert(!base->is_inline_type() || base->mark().is_larval_state(), "must be an object instance or a larval inline type");
+   assert_and_log_unsafe_value_access(base, offset, vk);
+   oop v = JNIHandles::resolve(value);
+   vk->write_flat_field(base, offset, v, true /*null free*/, LayoutKind::PAYLOAD, CHECK);  // TODO FIXME Hard coded layout kind to make the code compile, Unsafe must be upgraded to handle correct layout kind
+ } UNSAFE_END
+ 
+ UNSAFE_ENTRY(jobject, Unsafe_MakePrivateBuffer(JNIEnv *env, jobject unsafe, jobject value)) {
+   oop v = JNIHandles::resolve_non_null(value);
+   assert(v->is_inline_type(), "must be an inline type instance");
+   Handle vh(THREAD, v);
+   InlineKlass* vk = InlineKlass::cast(v->klass());
+   instanceOop new_value = vk->allocate_instance_buffer(CHECK_NULL);
+   vk->inline_copy_oop_to_new_oop(vh(), new_value, LayoutKind::PAYLOAD);  // FIXME temporary hack for the transition
+   markWord mark = new_value->mark();
+   new_value->set_mark(mark.enter_larval_state());
+   return JNIHandles::make_local(THREAD, new_value);
+ } UNSAFE_END
+ 
+ UNSAFE_ENTRY(jobject, Unsafe_FinishPrivateBuffer(JNIEnv *env, jobject unsafe, jobject value)) {
+   oop v = JNIHandles::resolve(value);
+   assert(v->mark().is_larval_state(), "must be a larval value");
+   markWord mark = v->mark();
+   v->set_mark(mark.exit_larval_state());
+   return JNIHandles::make_local(THREAD, v);
+ } UNSAFE_END
+ 
  UNSAFE_ENTRY(jobject, Unsafe_GetReferenceVolatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) {
    oop p = JNIHandles::resolve(obj);
    assert_field_offset_sane(p, offset);
    oop v = HeapAccess<MO_SEQ_CST | ON_UNKNOWN_OOP_REF>::oop_load_at(p, offset);
    return JNIHandles::make_local(THREAD, v);

*** 599,10 ***
--- 746,15 ---
    } else if (k->is_typeArray_klass()) {
      TypeArrayKlass* tak = TypeArrayKlass::cast(k);
      base  = tak->array_header_in_bytes();
      assert(base == arrayOopDesc::base_offset_in_bytes(tak->element_type()), "array_header_size semantics ok");
      scale = (1 << tak->log2_element_size());
+   } else if (k->is_flatArray_klass()) {
+     FlatArrayKlass* vak = FlatArrayKlass::cast(k);
+     InlineKlass* vklass = vak->element_klass();
+     base = vak->array_header_in_bytes();
+     scale = vak->element_byte_size();
    } else {
      ShouldNotReachHere();
    }
  }
  

*** 634,10 ***
--- 786,16 ---
    // but requires it to be linear in byte offset.
    return field_offset_from_byte_offset(scale) - field_offset_from_byte_offset(0);
  } UNSAFE_END
  
  
+ UNSAFE_ENTRY(jlong, Unsafe_GetObjectSize0(JNIEnv* env, jobject o, jobject obj))
+   oop p = JNIHandles::resolve(obj);
+   return p->size() * HeapWordSize;
+ UNSAFE_END
+ 
+ 
  static inline void throw_new(JNIEnv *env, const char *ename) {
    jclass cls = env->FindClass(ename);
    if (env->ExceptionCheck()) {
      env->ExceptionClear();
      tty->print_cr("Unsafe: cannot throw %s because FindClass has failed", ename);

*** 853,22 ***
  
  #define CC (char*)  /*cast a literal from (const char*)*/
  #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
  
  #define DECLARE_GETPUTOOP(Type, Desc) \
!     {CC "get" #Type,      CC "(" OBJ "J)" #Desc,       FN_PTR(Unsafe_Get##Type)}, \
!     {CC "put" #Type,      CC "(" OBJ "J" #Desc ")V",   FN_PTR(Unsafe_Put##Type)}, \
!     {CC "get" #Type "Volatile",      CC "(" OBJ "J)" #Desc,       FN_PTR(Unsafe_Get##Type##Volatile)}, \
!     {CC "put" #Type "Volatile",      CC "(" OBJ "J" #Desc ")V",   FN_PTR(Unsafe_Put##Type##Volatile)}
  
  
  static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = {
      {CC "getReference",         CC "(" OBJ "J)" OBJ "",   FN_PTR(Unsafe_GetReference)},
      {CC "putReference",         CC "(" OBJ "J" OBJ ")V",  FN_PTR(Unsafe_PutReference)},
      {CC "getReferenceVolatile", CC "(" OBJ "J)" OBJ,      FN_PTR(Unsafe_GetReferenceVolatile)},
      {CC "putReferenceVolatile", CC "(" OBJ "J" OBJ ")V",  FN_PTR(Unsafe_PutReferenceVolatile)},
  
      {CC "getUncompressedObject", CC "(" ADR ")" OBJ,  FN_PTR(Unsafe_GetUncompressedObject)},
  
      DECLARE_GETPUTOOP(Boolean, Z),
      DECLARE_GETPUTOOP(Byte, B),
      DECLARE_GETPUTOOP(Short, S),
--- 1011,33 ---
  
  #define CC (char*)  /*cast a literal from (const char*)*/
  #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
  
  #define DECLARE_GETPUTOOP(Type, Desc) \
!     {CC "get"  #Type,      CC "(" OBJ "J)" #Desc,                 FN_PTR(Unsafe_Get##Type)}, \
!     {CC "put"  #Type,      CC "(" OBJ "J" #Desc ")V",             FN_PTR(Unsafe_Put##Type)}, \
!     {CC "get"  #Type "Volatile",      CC "(" OBJ "J)" #Desc,      FN_PTR(Unsafe_Get##Type##Volatile)}, \
!     {CC "put"  #Type "Volatile",      CC "(" OBJ "J" #Desc ")V",  FN_PTR(Unsafe_Put##Type##Volatile)}
  
  
  static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = {
      {CC "getReference",         CC "(" OBJ "J)" OBJ "",   FN_PTR(Unsafe_GetReference)},
      {CC "putReference",         CC "(" OBJ "J" OBJ ")V",  FN_PTR(Unsafe_PutReference)},
      {CC "getReferenceVolatile", CC "(" OBJ "J)" OBJ,      FN_PTR(Unsafe_GetReferenceVolatile)},
      {CC "putReferenceVolatile", CC "(" OBJ "J" OBJ ")V",  FN_PTR(Unsafe_PutReferenceVolatile)},
  
+     {CC "isFlatArray", CC "(" CLS ")Z",                   FN_PTR(Unsafe_IsFlatArray)},
+     {CC "isFlatField0", CC "(" OBJ ")Z",                  FN_PTR(Unsafe_IsFlatField)},
+     {CC "hasNullMarker0"   , CC "(" OBJ ")Z",                    FN_PTR(Unsafe_HasNullMarker)},
+     {CC "nullMarkerOffset0", CC "(" OBJ ")I",                    FN_PTR(Unsafe_NullMarkerOffset)},
+     {CC "getValue",         CC "(" OBJ "J" CLS ")" OBJ,   FN_PTR(Unsafe_GetValue)},
+     {CC "putValue",         CC "(" OBJ "J" CLS OBJ ")V",  FN_PTR(Unsafe_PutValue)},
+     {CC "uninitializedDefaultValue", CC "(" CLS ")" OBJ,  FN_PTR(Unsafe_UninitializedDefaultValue)},
+     {CC "makePrivateBuffer",     CC "(" OBJ ")" OBJ,      FN_PTR(Unsafe_MakePrivateBuffer)},
+     {CC "finishPrivateBuffer",   CC "(" OBJ ")" OBJ,      FN_PTR(Unsafe_FinishPrivateBuffer)},
+     {CC "valueHeaderSize",       CC "(" CLS ")J",         FN_PTR(Unsafe_ValueHeaderSize)},
+ 
      {CC "getUncompressedObject", CC "(" ADR ")" OBJ,  FN_PTR(Unsafe_GetUncompressedObject)},
  
      DECLARE_GETPUTOOP(Boolean, Z),
      DECLARE_GETPUTOOP(Byte, B),
      DECLARE_GETPUTOOP(Short, S),

*** 887,10 ***
--- 1056,11 ---
      {CC "staticFieldOffset0", CC "(" FLD ")J",           FN_PTR(Unsafe_StaticFieldOffset0)},
      {CC "staticFieldBase0",   CC "(" FLD ")" OBJ,        FN_PTR(Unsafe_StaticFieldBase0)},
      {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 "getObjectSize0",     CC "(Ljava/lang/Object;)J", FN_PTR(Unsafe_GetObjectSize0)},
  
      {CC "defineClass0",       CC "(" DC_Args ")" CLS,    FN_PTR(Unsafe_DefineClass0)},
      {CC "allocateInstance",   CC "(" CLS ")" OBJ,        FN_PTR(Unsafe_AllocateInstance)},
      {CC "throwException",     CC "(" THR ")V",           FN_PTR(Unsafe_ThrowException)},
      {CC "compareAndSetReference",CC "(" OBJ "J" OBJ "" OBJ ")Z", FN_PTR(Unsafe_CompareAndSetReference)},
< prev index next >