--- old/src/hotspot/share/interpreter/interpreterRuntime.cpp 2019-03-11 14:25:58.858355256 +0100 +++ new/src/hotspot/share/interpreter/interpreterRuntime.cpp 2019-03-11 14:25:58.646355259 +0100 @@ -47,6 +47,10 @@ #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" +#include "oops/valueKlass.hpp" +#include "oops/valueArrayKlass.hpp" +#include "oops/valueArrayOop.hpp" +#include "oops/valueArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "prims/nativeLookup.hpp" #include "runtime/atomic.hpp" @@ -69,6 +73,7 @@ #include "utilities/align.hpp" #include "utilities/copy.hpp" #include "utilities/events.hpp" +#include "utilities/globalDefinitions.hpp" #ifdef COMPILER2 #include "opto/runtime.hpp" #endif @@ -253,6 +258,176 @@ thread->set_vm_result(obj); IRT_END +void copy_primitive_argument(intptr_t* addr, Handle instance, int offset, BasicType type) { + switch (type) { + case T_BOOLEAN: + instance()->bool_field_put(offset, (jboolean)*((int*)addr)); + break; + case T_CHAR: + instance()->char_field_put(offset, (jchar) *((int*)addr)); + break; + case T_FLOAT: + instance()->float_field_put(offset, (jfloat)*((float*)addr)); + break; + case T_DOUBLE: + instance()->double_field_put(offset, (jdouble)*((double*)addr)); + break; + case T_BYTE: + instance()->byte_field_put(offset, (jbyte)*((int*)addr)); + break; + case T_SHORT: + instance()->short_field_put(offset, (jshort)*((int*)addr)); + break; + case T_INT: + instance()->int_field_put(offset, (jint)*((int*)addr)); + break; + case T_LONG: + instance()->long_field_put(offset, (jlong)*((long long*)addr)); + break; + case T_OBJECT: + case T_ARRAY: + case T_VALUETYPE: + fatal("Should not be handled with this method"); + break; + default: + fatal("Unsupported BasicType"); + } +} + +IRT_ENTRY(void, InterpreterRuntime::defaultvalue(JavaThread* thread, ConstantPool* pool, int index)) + // Getting the ValueKlass + Klass* k = pool->klass_at(index, CHECK); + assert(k->is_value(), "defaultvalue argument must be the value type class"); + ValueKlass* vklass = ValueKlass::cast(k); + + vklass->initialize(THREAD); + oop res = vklass->default_value(); + thread->set_vm_result(res); +IRT_END + +IRT_ENTRY(int, InterpreterRuntime::withfield(JavaThread* thread, ConstantPoolCache* cp_cache)) + LastFrameAccessor last_frame(thread); + // Getting the ValueKlass + int index = ConstantPool::decode_cpcache_index(last_frame.get_index_u2_cpcache(Bytecodes::_withfield)); + ConstantPoolCacheEntry* cp_entry = cp_cache->entry_at(index); + assert(cp_entry->is_resolved(Bytecodes::_withfield), "Should have been resolved"); + Klass* klass = cp_entry->f1_as_klass(); + assert(klass->is_value(), "withfield only applies to value types"); + ValueKlass* vklass = ValueKlass::cast(klass); + + // Getting Field information + int offset = cp_entry->f2_as_index(); + int field_index = cp_entry->field_index(); + int field_offset = cp_entry->f2_as_offset(); + Symbol* field_signature = vklass->field_signature(field_index); + ResourceMark rm(THREAD); + const char* signature = (const char *) field_signature->as_utf8(); + BasicType field_type = char2type(signature[0]); + + // Getting old value + frame& f = last_frame.get_frame(); + jint tos_idx = f.interpreter_frame_expression_stack_size() - 1; + int vt_offset = type2size[field_type]; + oop old_value = *(oop*)f.interpreter_frame_expression_stack_at(tos_idx - vt_offset); + assert(old_value != NULL && oopDesc::is_oop(old_value) && old_value->is_value(),"Verifying receiver"); + Handle old_value_h(THREAD, old_value); + + // Creating new value by copying the one passed in argument + instanceOop new_value = vklass->allocate_instance( + CHECK_((type2size[field_type]) * AbstractInterpreter::stackElementSize)); + Handle new_value_h = Handle(THREAD, new_value); + int first_offset = vklass->first_field_offset(); + vklass->value_store(vklass->data_for_oop(old_value_h()), + vklass->data_for_oop(new_value_h()), true, false); + + // Updating the field specified in arguments + if (field_type == T_ARRAY || field_type == T_OBJECT) { + oop aoop = *(oop*)f.interpreter_frame_expression_stack_at(tos_idx); + assert(aoop == NULL || oopDesc::is_oop(aoop),"argument must be a reference type"); + new_value_h()->obj_field_put(field_offset, aoop); + } else if (field_type == T_VALUETYPE) { + if (cp_entry->is_flattened()) { + oop vt_oop = *(oop*)f.interpreter_frame_expression_stack_at(tos_idx); + if (vt_oop == NULL) { + THROW_(vmSymbols::java_lang_NullPointerException(), + (type2size[field_type] * AbstractInterpreter::stackElementSize)); + } + assert(vt_oop != NULL && oopDesc::is_oop(vt_oop) && vt_oop->is_value(),"argument must be a value type"); + Klass* field_k = vklass->get_value_field_klass(field_index); + ValueKlass* field_vk = ValueKlass::cast(field_k); + assert(field_vk == vt_oop->klass(), "Must match"); + field_vk->value_store(field_vk->data_for_oop(vt_oop), + ((char*)(oopDesc*)new_value_h()) + field_offset, false, false); + } else { // not flattened + oop voop = *(oop*)f.interpreter_frame_expression_stack_at(tos_idx); + if (voop == NULL && cp_entry->is_flattenable()) { + THROW_(vmSymbols::java_lang_NullPointerException(), + (type2size[field_type] * AbstractInterpreter::stackElementSize)); + } + assert(voop == NULL || oopDesc::is_oop(voop),"checking argument"); + new_value_h()->obj_field_put(field_offset, voop); + } + } else { // not T_OBJECT nor T_ARRAY nor T_VALUETYPE + intptr_t* addr = f.interpreter_frame_expression_stack_at(tos_idx); + copy_primitive_argument(addr, new_value_h, field_offset, field_type); + } + + // returning result + thread->set_vm_result(new_value_h()); + return (type2size[field_type] + type2size[T_OBJECT]) * AbstractInterpreter::stackElementSize; +IRT_END + +IRT_ENTRY(void, InterpreterRuntime::uninitialized_static_value_field(JavaThread* thread, oopDesc* mirror, int index)) + instanceHandle mirror_h(THREAD, (instanceOop)mirror); + InstanceKlass* klass = InstanceKlass::cast(java_lang_Class::as_Klass(mirror)); + int offset = klass->field_offset(index); + Klass* field_k = klass->get_value_field_klass_or_null(index); + assert(field_k != NULL, "Must have been initialized"); + ValueKlass* field_vklass = ValueKlass::cast(field_k); + instanceOop res = (instanceOop)field_vklass->default_value(); + thread->set_vm_result(res); +IRT_END + +IRT_ENTRY(void, InterpreterRuntime::uninitialized_instance_value_field(JavaThread* thread, oopDesc* obj, int index)) + instanceHandle obj_h(THREAD, (instanceOop)obj); + InstanceKlass* klass = InstanceKlass::cast(obj_h()->klass()); + Klass* field_k = klass->get_value_field_klass_or_null(index); + assert(field_k != NULL, "Must have been initialized"); + ValueKlass* field_vklass = ValueKlass::cast(field_k); + assert(field_vklass->is_initialized(), "Must have been initialized at this point"); + instanceOop res = (instanceOop)field_vklass->default_value(); + thread->set_vm_result(res); +IRT_END + +IRT_ENTRY(void, InterpreterRuntime::write_flattened_value(JavaThread* thread, oopDesc* value, int offset, oopDesc* rcv)) + assert(oopDesc::is_oop(value), "Sanity check"); + assert(oopDesc::is_oop(rcv), "Sanity check"); + assert(value->is_value(), "Sanity check"); + + ValueKlass* vklass = ValueKlass::cast(value->klass()); + vklass->value_store(vklass->data_for_oop(value), ((char*)(oopDesc*)rcv) + offset, true, true); +IRT_END + +IRT_ENTRY(void, InterpreterRuntime::read_flattened_field(JavaThread* thread, oopDesc* obj, int index, Klass* field_holder)) + Handle obj_h(THREAD, obj); + + assert(oopDesc::is_oop(obj), "Sanity check"); + + assert(field_holder->is_instance_klass(), "Sanity check"); + InstanceKlass* klass = InstanceKlass::cast(field_holder); + + assert(klass->field_is_flattened(index), "Sanity check"); + + ValueKlass* field_vklass = ValueKlass::cast(klass->get_value_field_klass(index)); + assert(field_vklass->is_initialized(), "Must be initialized at this point"); + + // allocate instance + instanceOop res = field_vklass->allocate_instance(CHECK); + // copy value + field_vklass->value_store(((char*)(oopDesc*)obj_h()) + klass->field_offset(index), + field_vklass->data_for_oop(res), true, true); + thread->set_vm_result(res); +IRT_END IRT_ENTRY(void, InterpreterRuntime::newarray(JavaThread* thread, BasicType type, jint size)) oop obj = oopFactory::new_typeArray(type, size, CHECK); @@ -262,10 +437,40 @@ IRT_ENTRY(void, InterpreterRuntime::anewarray(JavaThread* thread, ConstantPool* pool, int index, jint size)) Klass* klass = pool->klass_at(index, CHECK); - objArrayOop obj = oopFactory::new_objArray(klass, size, CHECK); + if (klass->is_value()) { // Logically creates elements, ensure klass init + klass->initialize(CHECK); + } + arrayOop obj = oopFactory::new_array(klass, size, CHECK); thread->set_vm_result(obj); IRT_END +IRT_ENTRY(void, InterpreterRuntime::value_array_load(JavaThread* thread, arrayOopDesc* array, int index)) + Klass* klass = array->klass(); + assert(klass->is_valueArray_klass(), "expected value array oop"); + + ValueArrayKlass* vaklass = ValueArrayKlass::cast(klass); + ValueKlass* vklass = vaklass->element_klass(); + arrayHandle ah(THREAD, array); + instanceOop value_holder = vklass->allocate_instance(CHECK); + void* src = ((valueArrayOop)ah())->value_at_addr(index, vaklass->layout_helper()); + vklass->value_store(src, vklass->data_for_oop(value_holder), + vaklass->element_byte_size(), true, false); + thread->set_vm_result(value_holder); +IRT_END + +IRT_ENTRY(void, InterpreterRuntime::value_array_store(JavaThread* thread, void* val, arrayOopDesc* array, int index)) + assert(val != NULL, "can't store null into flat array"); + Klass* klass = array->klass(); + assert(klass->is_valueArray_klass(), "expected value array"); + assert(ArrayKlass::cast(klass)->element_klass() == ((oop)val)->klass(), "Store type incorrect"); + + valueArrayOop varray = (valueArrayOop)array; + ValueArrayKlass* vaklass = ValueArrayKlass::cast(klass); + ValueKlass* vklass = vaklass->element_klass(); + const int lh = vaklass->layout_helper(); + vklass->value_store(vklass->data_for_oop((oop)val), varray->value_at_addr(index, lh), + vaklass->element_byte_size(), true, false); +IRT_END IRT_ENTRY(void, InterpreterRuntime::multianewarray(JavaThread* thread, jint* first_size_address)) // We may want to pass in more arguments - could make this slightly faster @@ -277,6 +482,10 @@ assert(klass->is_klass(), "not a class"); assert(nof_dims >= 1, "multianewarray rank must be nonzero"); + if (klass->is_value()) { // Logically creates elements, ensure klass init + klass->initialize(CHECK); + } + // We must create an array of jints to pass to multi_allocate. ResourceMark rm(thread); const int small_dims = 10; @@ -687,8 +896,9 @@ constantPoolHandle pool(thread, last_frame.method()->constants()); methodHandle m(thread, last_frame.method()); bool is_put = (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_nofast_putfield || - bytecode == Bytecodes::_putstatic); + bytecode == Bytecodes::_putstatic || bytecode == Bytecodes::_withfield); bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic); + bool is_value = bytecode == Bytecodes::_withfield; { JvmtiHideSingleStepping jhss(thread); @@ -732,9 +942,15 @@ Bytecodes::Code get_code = (Bytecodes::Code)0; Bytecodes::Code put_code = (Bytecodes::Code)0; if (!uninitialized_static) { - get_code = ((is_static) ? Bytecodes::_getstatic : Bytecodes::_getfield); - if ((is_put && !has_initialized_final_update) || !info.access_flags().is_final()) { - put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield); + if (is_static) { + get_code = Bytecodes::_getstatic; + } else { + get_code = Bytecodes::_getfield; + } + if (is_put && is_value) { + put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_withfield); + } else if ((is_put && !has_initialized_final_update) || !info.access_flags().is_final()) { + put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield); } } @@ -747,6 +963,8 @@ state, info.access_flags().is_final(), info.access_flags().is_volatile(), + info.is_flattened(), + info.is_flattenable(), pool->pool_holder() ); } @@ -857,8 +1075,7 @@ Symbol* signature = call.signature(); receiver = Handle(thread, last_frame.callee_receiver(signature)); - assert(Universe::heap()->is_in_reserved_or_null(receiver()), - "sanity check"); + assert(Universe::heap()->is_in_reserved_or_null(receiver()), "sanity check"); assert(receiver.is_null() || !Universe::heap()->is_in_reserved(receiver->klass()), "sanity check"); @@ -1000,6 +1217,7 @@ case Bytecodes::_putstatic: case Bytecodes::_getfield: case Bytecodes::_putfield: + case Bytecodes::_withfield: resolve_get_put(thread, bytecode); break; case Bytecodes::_invokevirtual: @@ -1264,6 +1482,12 @@ case dtos: sig_type = 'D'; break; default: ShouldNotReachHere(); return; } + + // Both Q-signatures and L-signatures are mapped to atos + if (cp_entry->flag_state() == atos && ik->field_signature(index)->is_Q_signature()) { + sig_type = 'Q'; + } + bool is_static = (obj == NULL); HandleMark hm(thread);