--- old/src/hotspot/share/prims/unsafe.cpp 2018-06-27 17:07:07.000000000 -0400 +++ new/src/hotspot/share/prims/unsafe.cpp 2018-06-27 17:07:06.000000000 -0400 @@ -35,6 +35,9 @@ #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/globals.hpp" @@ -223,11 +226,16 @@ } } - void put(T x) { + void put(T x, TRAPS) { if (_obj == NULL) { GuardUnsafeAccess guard(_thread); RawAccess<>::store(addr(), normalize_for_write(x)); } else { + if (EnableValhalla) { + if (_obj->klass()->is_value()) { + THROW(vmSymbols::java_lang_IllegalAccessError()); + } + } HeapAccess<>::store_at(_obj, _offset, normalize_for_write(x)); } } @@ -244,45 +252,204 @@ } } - void put_volatile(T x) { + void put_volatile(T x, TRAPS) { if (_obj == NULL) { GuardUnsafeAccess guard(_thread); RawAccess::store(addr(), normalize_for_write(x)); } else { + if (EnableValhalla) { + if (_obj->klass()->is_value()) { + THROW(vmSymbols::java_lang_IllegalAccessError()); + } + } HeapAccess::store_at(_obj, _offset, normalize_for_write(x)); } } }; +oop read_reference_field(jobject obj, jlong offset, bool is_volatile, TRAPS) { + oop p = JNIHandles::resolve(obj); + assert_field_offset_sane(p, offset); + oop v; + bool read = false; + if (EnableValhalla && p != NULL) { + Klass* k = p->klass(); + if (k->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(k); + fieldDescriptor fd; + bool found = ik->find_field_from_offset((int)offset, false, &fd); + if (found) { + if (fd.is_flattened()) { + ValueKlass* vk = ValueKlass::cast(ik->get_value_field_klass(fd.index())); + bool in_heap; + Handle p_h(THREAD, p); + vk->initialize(CHECK_NULL); // If field is a default value, value class might not be initialized yet + // allocate instance + v = vk->allocate_buffered_or_heap_instance(&in_heap, CHECK_NULL); + // copy value + vk->value_store(((char*)(oopDesc*)p_h()) + ik->field_offset(fd.index()), + vk->data_for_oop(v), in_heap, true); + read = true; + } + } else { + if (ik->is_mirror_instance_klass()) { + Klass* k2 = java_lang_Class::as_Klass(p); + if (k2->is_instance_klass()) { + InstanceKlass* ik2 = InstanceKlass::cast(k2); + bool found = ik2->find_field_from_offset((int)offset, true, &fd); + if (found) { + if (fd.is_flattened()) { + ValueKlass* vk = ValueKlass::cast(ik2->get_value_field_klass(fd.index())); + bool in_heap; + Handle p_h(THREAD, p); + vk->initialize(CHECK_NULL); // If field is a default value, value class might not be initialized yet + // allocate instance + v = vk->allocate_buffered_or_heap_instance(&in_heap, CHECK_NULL); + // copy value + vk->value_store(((char*)(oopDesc*)p_h()) + ik2->field_offset(fd.index()), + vk->data_for_oop(v), in_heap, true); + read = true; + } else if(fd.is_flattenable()) { + if (is_volatile) { + v = HeapAccess::oop_load_at(p, offset); + } else { + v = HeapAccess::oop_load_at(p, offset); + } + if (v == NULL) { + // Uninitialized static flattenable field + ValueKlass* vk = ValueKlass::cast(ik2->get_value_field_klass(fd.index())); + vk->initialize(CHECK_NULL); + v = vk->default_value(); + read = true; + } + } + } + } + } + } + } else if (k->is_valueArray_klass()) { + ValueArrayKlass* vak = ValueArrayKlass::cast(k); + int index = (offset - vak->array_header_in_bytes()) / vak->element_byte_size(); + assert(index >= 0 && index < ((arrayOop)p)->length() , "Sanity check"); + ValueKlass* vklass = vak->element_klass(); + arrayHandle ah(THREAD, (arrayOop)p); + bool in_heap; + v = vklass->allocate_buffered_or_heap_instance(&in_heap, CHECK_NULL); + void* src = ((valueArrayOop)ah())->value_at_addr(index, vak->layout_helper()); + vklass->value_store(src, vklass->data_for_oop(v), + vak->element_byte_size(), in_heap, false); + read = true; + } + } + if (!read) { + if (is_volatile) { + v = HeapAccess::oop_load_at(p, offset); + } else { + v = HeapAccess::oop_load_at(p, offset); + } + } + return v; +} + +void write_reference_field(jobject obj, jlong offset, jobject new_val, bool is_volatile, TRAPS) { + oop p = JNIHandles::resolve(obj); + assert_field_offset_sane(p, offset); + oop v; + bool written = false; + if (EnableValhalla && p != NULL) { + Klass* k = p->klass(); + if (k->is_instance_klass()) { + if (k->is_value()) { + THROW(vmSymbols::java_lang_IllegalAccessError()); + } + InstanceKlass* ik = InstanceKlass::cast(k); + fieldDescriptor fd; + bool found = ik->find_field_from_offset((int)offset, false, &fd); + if (found) { + oop nv = JNIHandles::resolve(new_val); + if (fd.is_flattenable() && nv == NULL) { + THROW(vmSymbols::java_lang_NullPointerException()); + } + if (fd.is_flattened()) { + ValueKlass* vk = ValueKlass::cast(ik->get_value_field_klass(fd.index())); + // copy value + vk->value_store(vk->data_for_oop(nv), + ((char*)(oopDesc*)p) + ik->field_offset(fd.index()), true, true); + written = true; + } + } else { + if (ik->is_mirror_instance_klass()) { + Klass* k2 = java_lang_Class::as_Klass(p); + if (k2->is_instance_klass()) { + InstanceKlass* ik2 = InstanceKlass::cast(k2); + bool found = ik2->find_field_from_offset((int)offset, true, &fd); + if (found) { + oop nv = JNIHandles::resolve(new_val); + if (fd.is_flattenable() && nv == NULL) { + THROW(vmSymbols::java_lang_NullPointerException()); + } + if (fd.is_flattened()) { + ValueKlass* vk = ValueKlass::cast(ik2->get_value_field_klass(fd.index())); + // copy value + vk->value_store(vk->data_for_oop(v), + ((char*)(oopDesc*)p) + ik2->field_offset(fd.index()), + true, true); + written = true; + } + } + } + } + } + } else if (k->is_valueArray_klass()) { + oop nv = JNIHandles::resolve(new_val); + if (nv == NULL) { + THROW(vmSymbols::java_lang_NullPointerException()); + } + ValueArrayKlass* vak = ValueArrayKlass::cast(k); + int index = (offset - vak->array_header_in_bytes()) / vak->element_byte_size(); + assert(index >= 0 && index < ((arrayOop)p)->length() , "Sanity check"); + ValueKlass* vklass = vak->element_klass(); + void* dest = ((valueArrayOop)p)->value_at_addr(index, vak->layout_helper()); + vklass->value_store(vklass->data_for_oop(nv), dest, + vak->element_byte_size(), true, false); + written = true; + } else if (k->is_objArray_klass()) { + ObjArrayKlass* oak = ObjArrayKlass::cast(k); + oop nv = JNIHandles::resolve(new_val); + if (oak->element_klass()->is_value() && nv == NULL) { + THROW(vmSymbols::java_lang_NullPointerException()); + } + } + } + if (!written) { + oop x = JNIHandles::resolve(new_val); + if (is_volatile) { + HeapAccess::oop_store_at(p, offset, x); + } else { + HeapAccess::oop_store_at(p, offset, x); + } + } +} + // 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_GetObject(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { - oop p = JNIHandles::resolve(obj); - assert_field_offset_sane(p, offset); - oop v = HeapAccess::oop_load_at(p, offset); + oop v = read_reference_field(obj, offset, false, CHECK_NULL); return JNIHandles::make_local(env, v); } UNSAFE_END UNSAFE_ENTRY(void, Unsafe_PutObject(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); - HeapAccess::oop_store_at(p, offset, x); + write_reference_field(obj, offset, x_h, false, CHECK); } UNSAFE_END UNSAFE_ENTRY(jobject, Unsafe_GetObjectVolatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { - oop p = JNIHandles::resolve(obj); - assert_field_offset_sane(p, offset); - oop v = HeapAccess::oop_load_at(p, offset); + oop v = read_reference_field(obj, offset, true, CHECK_NULL); return JNIHandles::make_local(env, v); } UNSAFE_END UNSAFE_ENTRY(void, Unsafe_PutObjectVolatile(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); - HeapAccess::oop_store_at(p, offset, x); + write_reference_field(obj, offset, x_h, false, CHECK); } UNSAFE_END UNSAFE_ENTRY(jobject, Unsafe_GetUncompressedObject(JNIEnv *env, jobject unsafe, jlong addr)) { @@ -309,7 +476,7 @@ } UNSAFE_END \ \ UNSAFE_ENTRY(void, Unsafe_Put##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, java_type x)) { \ - MemoryAccess(thread, obj, offset).put(x); \ + MemoryAccess(thread, obj, offset).put(x, CHECK); \ } UNSAFE_END \ \ // END DEFINE_GETSETOOP. @@ -332,7 +499,7 @@ } UNSAFE_END \ \ UNSAFE_ENTRY(void, Unsafe_Put##Type##Volatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, java_type x)) { \ - MemoryAccess(thread, obj, offset).put_volatile(x); \ + MemoryAccess(thread, obj, offset).put_volatile(x, CHECK); \ } UNSAFE_END \ \ // END DEFINE_GETSETOOP_VOLATILE. @@ -572,6 +739,10 @@ 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); + base = vak->array_header_in_bytes(); + scale = vak->element_byte_size(); } else { ShouldNotReachHere(); }