< prev index next >

src/hotspot/share/prims/unsafe.cpp

Print this page

        

@@ -29,17 +29,23 @@
 #include "classfile/classLoader.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "jfr/jfrEvents.hpp"
 #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.hpp"
 #include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/typeArrayOop.inline.hpp"
+#include "oops/valueArrayKlass.hpp"
+#include "oops/valueArrayOop.hpp"
+#include "oops/valueArrayOop.inline.hpp"
 #include "prims/unsafe.hpp"
 #include "runtime/atomic.hpp"
+#include "runtime/fieldDescriptor.inline.hpp"
 #include "runtime/globals.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/interfaceSupport.inline.hpp"
 #include "runtime/jniHandles.inline.hpp"
 #include "runtime/orderAccess.hpp"

@@ -143,11 +149,10 @@
 }
 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 for accessing memory.
  *

@@ -228,15 +233,15 @@
   void put(T x) {
     if (_obj == NULL) {
       GuardUnsafeAccess guard(_thread);
       RawAccess<>::store(addr(), normalize_for_write(x));
     } else {
+      assert(!_obj->is_value() || _obj->mark()->is_larval_state(), "must be an object instance or a larval value");
       HeapAccess<>::store_at(_obj, _offset, normalize_for_write(x));
     }
   }
 
-
   T get_volatile() {
     if (_obj == NULL) {
       GuardUnsafeAccess guard(_thread);
       volatile T ret = RawAccess<MO_SEQ_CST>::load(addr());
       return normalize_for_read(ret);

@@ -254,10 +259,72 @@
       HeapAccess<MO_SEQ_CST>::store_at(_obj, _offset, 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, ValueKlass* 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_flattened(), "field not flat");
+    } else {
+      if (log_is_enabled(Trace, valuetypes)) {
+        log_trace(valuetypes)("not a field in %s at offset " SIZE_FORMAT_HEX,
+                              p->klass()->external_name(), offset);
+      }
+    }
+  } else if (k->is_valueArray_klass()) {
+    ValueArrayKlass* vak = ValueArrayKlass::cast(k);
+    int index = (offset - vak->array_header_in_bytes()) / vak->element_byte_size();
+    address dest = (address)((valueArrayOop)p)->value_at_addr(index, vak->layout_helper());
+    assert(dest == ((address)p) + offset, "invalid offset");
+  } else {
+    ShouldNotReachHere();
+  }
+#endif // ASSERT
+  if (log_is_enabled(Trace, valuetypes)) {
+    if (k->is_valueArray_klass()) {
+      ValueArrayKlass* vak = ValueArrayKlass::cast(k);
+      int index = (offset - vak->array_header_in_bytes()) / vak->element_byte_size();
+      address dest = (address)((valueArrayOop)p)->value_at_addr(index, vak->layout_helper());
+      log_trace(valuetypes)("%s array type %s index %d element size %d offset " SIZE_FORMAT_HEX " at " INTPTR_FORMAT,
+                            p->klass()->external_name(), vak->external_name(),
+                            index, vak->element_byte_size(), offset, p2i(dest));
+    } else {
+      log_trace(valuetypes)("%s field type %s at offset " SIZE_FORMAT_HEX,
+                            p->klass()->external_name(), vk->external_name(), 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);

@@ -268,13 +335,77 @@
 
 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_value() || p->mark()->is_larval_state(), "must be an object instance or a larval value");
   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));
+  ValueKlass* vk = ValueKlass::cast(k);
+  return vk->first_field_offset();
+} UNSAFE_END
+
+UNSAFE_ENTRY(jboolean, Unsafe_IsFlattenedArray(JNIEnv *env, jobject unsafe, jclass c)) {
+  Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c));
+  return k->is_valueArray_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));
+  ValueKlass* vk = ValueKlass::cast(k);
+  oop v = vk->default_value();
+  return JNIHandles::make_local(env, 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));
+  ValueKlass* vk = ValueKlass::cast(k);
+  assert_and_log_unsafe_value_access(base, offset, vk);
+  Handle base_h(THREAD, base);
+  oop v = vk->allocate_instance(CHECK_NULL); // allocate instance
+  vk->initialize(CHECK_NULL); // If field is a default value, value class might not be initialized yet
+  vk->value_store(((address)(oopDesc*)base_h()) + offset,
+                  vk->data_for_oop(v),
+                  true, true);
+  return JNIHandles::make_local(env, 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));
+  ValueKlass* vk = ValueKlass::cast(k);
+  assert(!base->is_value() || base->mark()->is_larval_state(), "must be an object instance or a larval value");
+  assert_and_log_unsafe_value_access(base, offset, vk);
+  oop v = JNIHandles::resolve(value);
+  vk->value_store(vk->data_for_oop(v),
+                 ((address)(oopDesc*)base) + offset, true, true);
+} UNSAFE_END
+
+UNSAFE_ENTRY(jobject, Unsafe_MakePrivateBuffer(JNIEnv *env, jobject unsafe, jobject value)) {
+  oop v = JNIHandles::resolve_non_null(value);
+  assert(v->is_value(), "must be a value instance");
+  Handle vh(THREAD, v);
+  ValueKlass* vk = ValueKlass::cast(v->klass());
+  instanceOop new_value = vk->allocate_instance(CHECK_NULL);
+  vk->value_store(vk->data_for_oop(vh()), vk->data_for_oop(new_value), true, false);
+  markOop mark = new_value->mark();
+  new_value->set_mark(mark->enter_larval_state());
+  return JNIHandles::make_local(env, 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");
+  markOop mark = v->mark();
+  v->set_mark(mark->exit_larval_state());
+  return JNIHandles::make_local(env, 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(env, v);

@@ -552,10 +683,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_valueArray_klass()) {
+    ValueArrayKlass* vak = ValueArrayKlass::cast(k);
+    ValueKlass* vklass = vak->element_klass();
+    base = vak->array_header_in_bytes();
+    scale = vak->element_byte_size();
   } else {
     ShouldNotReachHere();
   }
 }
 

@@ -1006,22 +1142,30 @@
 
 #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)}
+    {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 "isFlattenedArray", CC "(" CLS ")Z",                     FN_PTR(Unsafe_IsFlattenedArray)},
+    {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),
< prev index next >