< prev index next >

src/hotspot/share/interpreter/interpreterRuntime.cpp

Print this page
@@ -23,10 +23,11 @@
   */
  
  #include "precompiled.hpp"
  #include "classfile/javaClasses.inline.hpp"
  #include "classfile/symbolTable.hpp"
+ #include "classfile/systemDictionary.hpp"
  #include "classfile/vmClasses.hpp"
  #include "classfile/vmSymbols.hpp"
  #include "code/codeCache.hpp"
  #include "compiler/compilationPolicy.hpp"
  #include "compiler/compileBroker.hpp"

@@ -43,10 +44,13 @@
  #include "memory/oopFactory.hpp"
  #include "memory/resourceArea.hpp"
  #include "memory/universe.hpp"
  #include "oops/constantPool.inline.hpp"
  #include "oops/cpCache.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/methodData.hpp"
  #include "oops/method.inline.hpp"
  #include "oops/objArrayKlass.hpp"

@@ -75,10 +79,11 @@
  #include "runtime/threadCritical.hpp"
  #include "utilities/align.hpp"
  #include "utilities/checkedCast.hpp"
  #include "utilities/copy.hpp"
  #include "utilities/events.hpp"
+ #include "utilities/globalDefinitions.hpp"
  #ifdef COMPILER2
  #include "opto/runtime.hpp"
  #endif
  
  // Helper class to access current interpreter state

@@ -225,30 +230,166 @@
  
    oop obj = klass->allocate_instance(CHECK);
    current->set_vm_result(obj);
  JRT_END
  
+ JRT_ENTRY(void, InterpreterRuntime::uninitialized_static_inline_type_field(JavaThread* current, oopDesc* mirror, ResolvedFieldEntry* entry))
+   // The interpreter tries to access an inline static field that has not been initialized.
+   // This situation can happen in different scenarios:
+   //   1 - if the load or initialization of the field failed during step 8 of
+   //       the initialization of the holder of the field, in this case the access to the field
+   //       must fail
+   //   2 - it can also happen when the initialization of the holder class triggered the initialization of
+   //       another class which accesses this field in its static initializer, in this case the
+   //       access must succeed to allow circularity
+   // The code below tries to load and initialize the field's class again before returning the default value.
+   // If the field was not initialized because of an error, an exception should be thrown.
+   // If the class is being initialized, the default value is returned.
+   assert(entry->is_valid(), "Invalid ResolvedFieldEntry");
+   instanceHandle mirror_h(THREAD, (instanceOop)mirror);
+   InstanceKlass* klass = entry->field_holder();
+   u2 index = entry->field_index();
+   assert(klass == java_lang_Class::as_Klass(mirror), "Not the field holder klass");
+   assert(klass->field_is_null_free_inline_type(index), "Sanity check");
+   if (klass->is_being_initialized() && klass->is_reentrant_initialization(THREAD)) {
+     int offset = klass->field_offset(index);
+     Klass* field_k = klass->get_inline_type_field_klass_or_null(index);
+     if (field_k == nullptr) {
+       field_k = SystemDictionary::resolve_or_fail(klass->field_signature(index)->fundamental_name(THREAD),
+           Handle(THREAD, klass->class_loader()),
+           Handle(THREAD, klass->protection_domain()),
+           true, CHECK);
+       assert(field_k != nullptr, "Should have been loaded or an exception thrown above");
+       if (!field_k->is_inline_klass()) {
+         THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(),
+                   err_msg("class %s expects class %s to be a concrete value class but it is not",
+                   klass->name()->as_C_string(), field_k->external_name()));
+       }
+       InlineLayoutInfo* li = klass->inline_layout_info_adr(index);
+       li->set_klass(InlineKlass::cast(field_k));
+       li->set_kind(LayoutKind::REFERENCE);
+     }
+     field_k->initialize(CHECK);
+     oop defaultvalue = InlineKlass::cast(field_k)->default_value();
+     // It is safe to initialize the static field because 1) the current thread is the initializing thread
+     // and is the only one that can access it, and 2) the field is actually not initialized (i.e. null)
+     // otherwise the JVM should not be executing this code.
+     mirror_h()->obj_field_put(offset, defaultvalue);
+     current->set_vm_result(defaultvalue);
+   } else {
+     assert(klass->is_in_error_state(), "If not initializing, initialization must have failed to get there");
+     ResourceMark rm(THREAD);
+     const char* desc = "Could not initialize class ";
+     const char* className = klass->external_name();
+     size_t msglen = strlen(desc) + strlen(className) + 1;
+     char* message = NEW_RESOURCE_ARRAY(char, msglen);
+     if (nullptr == message) {
+       // Out of memory: can't create detailed error message
+       THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), className);
+     } else {
+       jio_snprintf(message, msglen, "%s%s", desc, className);
+       THROW_MSG(vmSymbols::java_lang_NoClassDefFoundError(), message);
+     }
+   }
+ JRT_END
+ 
+ JRT_ENTRY(void, InterpreterRuntime::read_flat_field(JavaThread* current, oopDesc* obj, ResolvedFieldEntry* entry))
+   assert(oopDesc::is_oop(obj), "Sanity check");
+   Handle obj_h(THREAD, obj);
+ 
+   InstanceKlass* holder = InstanceKlass::cast(entry->field_holder());
+   assert(entry->field_holder()->field_is_flat(entry->field_index()), "Sanity check");
+ 
+   InlineLayoutInfo* layout_info = holder->inline_layout_info_adr(entry->field_index());
+   InlineKlass* field_vklass = layout_info->klass();
+ 
+   oop res = field_vklass->read_flat_field(obj_h(), entry->field_offset(), layout_info->kind(), CHECK);
+   current->set_vm_result(res);
+ JRT_END
+ 
+ JRT_ENTRY(void, InterpreterRuntime::read_nullable_flat_field(JavaThread* current, oopDesc* obj, ResolvedFieldEntry* entry))
+   assert(oopDesc::is_oop(obj), "Sanity check");
+   assert(entry->has_null_marker(), "Otherwise should not get there");
+   Handle obj_h(THREAD, obj);
+ 
+   InstanceKlass* holder = entry->field_holder();
+   int field_index = entry->field_index();
+   InlineLayoutInfo* li= holder->inline_layout_info_adr(field_index);
+ 
+   int nm_offset = li->null_marker_offset();
+   if (obj_h()->byte_field_acquire(nm_offset) == 0) {
+     current->set_vm_result(nullptr);
+   } else {
+     InlineKlass* field_vklass = InlineKlass::cast(li->klass());
+     oop res = field_vklass->read_flat_field(obj_h(), entry->field_offset(), LayoutKind::NULLABLE_ATOMIC_FLAT, CHECK);
+     current->set_vm_result(res);
+   }
+ JRT_END
+ 
+ JRT_ENTRY(void, InterpreterRuntime::write_nullable_flat_field(JavaThread* current, oopDesc* obj, oopDesc* value, ResolvedFieldEntry* entry))
+   assert(oopDesc::is_oop(obj), "Sanity check");
+   Handle obj_h(THREAD, obj);
+   assert(value == nullptr || oopDesc::is_oop(value), "Sanity check");
+   Handle val_h(THREAD, value);
+ 
+   InstanceKlass* holder = entry->field_holder();
+   InlineLayoutInfo* li = holder->inline_layout_info_adr(entry->field_index());
+   InlineKlass* vk = li->klass();
+   assert(li->kind() == LayoutKind::NULLABLE_ATOMIC_FLAT, "Must be");
+   int nm_offset = li->null_marker_offset();
+ 
+   if (val_h() == nullptr) {
+     if(li->klass()->nonstatic_oop_count() == 0) {
+       // No embedded oops, just reset the null marker
+       obj_h()->byte_field_put(nm_offset, (jbyte)0);
+     } else {
+       // Has embedded oops, using the reset value to rewrite all fields to null/zeros
+       assert(li->klass()->null_reset_value()->byte_field(vk->null_marker_offset()) == 0, "reset value must always have a null marker set to 0");
+       vk->inline_copy_oop_to_payload(vk->null_reset_value(), ((char*)(oopDesc*)obj_h()) + entry->field_offset(), li->kind());
+     }
+     return;
+   }
+ 
+   assert(val_h()->klass() == vk, "Must match because flat fields are monomorphic");
+   // The interpreter copies values with a bulk operation
+   // To avoid accidentally setting the null marker to "null" during
+   // the copying, the null marker is set to non zero in the source object
+   if (val_h()->byte_field(vk->null_marker_offset()) == 0) {
+     val_h()->byte_field_put(vk->null_marker_offset(), (jbyte)1);
+   }
+   vk->inline_copy_oop_to_payload(val_h(), ((char*)(oopDesc*)obj_h()) + entry->field_offset(), li->kind());
+ JRT_END
  
  JRT_ENTRY(void, InterpreterRuntime::newarray(JavaThread* current, BasicType type, jint size))
    oop obj = oopFactory::new_typeArray(type, size, CHECK);
    current->set_vm_result(obj);
  JRT_END
  
  
  JRT_ENTRY(void, InterpreterRuntime::anewarray(JavaThread* current, ConstantPool* pool, int index, jint size))
    Klass*    klass = pool->klass_at(index, CHECK);
-   objArrayOop obj = oopFactory::new_objArray(klass, size, CHECK);
+   arrayOop obj = oopFactory::new_objArray(klass, size, CHECK);
    current->set_vm_result(obj);
  JRT_END
  
+ JRT_ENTRY(void, InterpreterRuntime::value_array_load(JavaThread* current, arrayOopDesc* array, int index))
+   flatArrayHandle vah(current, (flatArrayOop)array);
+   oop value_holder = flatArrayOopDesc::value_alloc_copy_from_index(vah, index, CHECK);
+   current->set_vm_result(value_holder);
+ JRT_END
+ 
+ JRT_ENTRY(void, InterpreterRuntime::value_array_store(JavaThread* current, void* val, arrayOopDesc* array, int index))
+   assert(val != nullptr, "can't store null into flat array");
+   ((flatArrayOop)array)->value_copy_to_index(cast_to_oop(val), index, LayoutKind::PAYLOAD); // Non atomic is the only layout currently supported by flat arrays
+ JRT_END
  
  JRT_ENTRY(void, InterpreterRuntime::multianewarray(JavaThread* current, jint* first_size_address))
    // We may want to pass in more arguments - could make this slightly faster
    LastFrameAccessor last_frame(current);
    ConstantPool* constants = last_frame.method()->constants();
-   int          i = last_frame.get_index_u2(Bytecodes::_multianewarray);
-   Klass* klass   = constants->klass_at(i, CHECK);
+   int i = last_frame.get_index_u2(Bytecodes::_multianewarray);
+   Klass* klass = constants->klass_at(i, CHECK);
    int   nof_dims = last_frame.number_of_dimensions();
    assert(klass->is_klass(), "not a class");
    assert(nof_dims >= 1, "multianewarray rank must be nonzero");
  
    // We must create an array of jints to pass to multi_allocate.

@@ -273,10 +414,34 @@
    assert(oopDesc::is_oop(obj), "must be a valid oop");
    assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise");
    InstanceKlass::register_finalizer(instanceOop(obj), CHECK);
  JRT_END
  
+ JRT_ENTRY(jboolean, InterpreterRuntime::is_substitutable(JavaThread* current, oopDesc* aobj, oopDesc* bobj))
+   assert(oopDesc::is_oop(aobj) && oopDesc::is_oop(bobj), "must be valid oops");
+ 
+   Handle ha(THREAD, aobj);
+   Handle hb(THREAD, bobj);
+   JavaValue result(T_BOOLEAN);
+   JavaCallArguments args;
+   args.push_oop(ha);
+   args.push_oop(hb);
+   methodHandle method(current, Universe::is_substitutable_method());
+   method->method_holder()->initialize(CHECK_false); // Ensure class ValueObjectMethods is initialized
+   JavaCalls::call(&result, method, &args, THREAD);
+   if (HAS_PENDING_EXCEPTION) {
+     // Something really bad happened because isSubstitutable() should not throw exceptions
+     // If it is an error, just let it propagate
+     // If it is an exception, wrap it into an InternalError
+     if (!PENDING_EXCEPTION->is_a(vmClasses::Error_klass())) {
+       Handle e(THREAD, PENDING_EXCEPTION);
+       CLEAR_PENDING_EXCEPTION;
+       THROW_MSG_CAUSE_(vmSymbols::java_lang_InternalError(), "Internal error in substitutability test", e, false);
+     }
+   }
+   return result.get_jboolean();
+ JRT_END
  
  // Quicken instance-of and check-cast bytecodes
  JRT_ENTRY(void, InterpreterRuntime::quicken_io_cc(JavaThread* current))
    // Force resolving; quicken the bytecode
    LastFrameAccessor last_frame(current);

@@ -616,10 +781,14 @@
    ResourceMark rm(current);
    methodHandle mh = methodHandle(current, missingMethod);
    LinkResolver::throw_abstract_method_error(mh, recvKlass, THREAD);
  JRT_END
  
+ JRT_ENTRY(void, InterpreterRuntime::throw_InstantiationError(JavaThread* current))
+   THROW(vmSymbols::java_lang_InstantiationError());
+ JRT_END
+ 
  
  JRT_ENTRY(void, InterpreterRuntime::throw_IncompatibleClassChangeError(JavaThread* current))
    THROW(vmSymbols::java_lang_IncompatibleClassChangeError());
  JRT_END
  

@@ -700,18 +869,25 @@
    assert(!(has_initialized_final_update && !info.access_flags().is_final()), "Fields with initialized final updates must be final");
  
    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_static) {
+       get_code = Bytecodes::_getstatic;
+     } else {
+       get_code = Bytecodes::_getfield;
+     }
      if ((is_put && !has_initialized_final_update) || !info.access_flags().is_final()) {
-       put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
+         put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
      }
    }
  
    ResolvedFieldEntry* entry = pool->resolved_field_entry_at(field_index);
-   entry->set_flags(info.access_flags().is_final(), info.access_flags().is_volatile());
+   entry->set_flags(info.access_flags().is_final(), info.access_flags().is_volatile(),
+                    info.is_flat(), info.is_null_free_inline_type(),
+                    info.has_null_marker());
+ 
    entry->fill_in(info.field_holder(), info.offset(),
                   checked_cast<u2>(info.index()), checked_cast<u1>(state),
                   static_cast<u1>(get_code), static_cast<u1>(put_code));
  }
  

@@ -754,16 +930,14 @@
    // Free entry. If it is not cleared, the exception handling code will try to unlock the monitor
    // again at method exit or in the case of an exception.
    elem->set_obj(nullptr);
  JRT_END
  
- 
  JRT_ENTRY(void, InterpreterRuntime::throw_illegal_monitor_state_exception(JavaThread* current))
    THROW(vmSymbols::java_lang_IllegalMonitorStateException());
  JRT_END
  
- 
  JRT_ENTRY(void, InterpreterRuntime::new_illegal_monitor_state_exception(JavaThread* current))
    // Returns an illegal exception to install into the current thread. The
    // pending_exception flag is cleared so normal exception handling does not
    // trigger. Any current installed exception will be overwritten. This
    // method will be called during an exception unwind.

@@ -774,10 +948,25 @@
    current->set_vm_result(nullptr); // clear vm result before continuing (may cause memory leaks and assert failures)
    exception = get_preinitialized_exception(vmClasses::IllegalMonitorStateException_klass(), CATCH);
    current->set_vm_result(exception());
  JRT_END
  
+ JRT_ENTRY(void, InterpreterRuntime::throw_identity_exception(JavaThread* current, oopDesc* obj))
+   Klass* klass = cast_to_oop(obj)->klass();
+   ResourceMark rm(THREAD);
+   const char* desc = "Cannot synchronize on an instance of value class ";
+   const char* className = klass->external_name();
+   size_t msglen = strlen(desc) + strlen(className) + 1;
+   char* message = NEW_RESOURCE_ARRAY(char, msglen);
+   if (nullptr == message) {
+     // Out of memory: can't create detailed error message
+     THROW_MSG(vmSymbols::java_lang_IdentityException(), className);
+   } else {
+     jio_snprintf(message, msglen, "%s%s", desc, className);
+     THROW_MSG(vmSymbols::java_lang_IdentityException(), message);
+   }
+ JRT_END
  
  //------------------------------------------------------------------------------------------------------------------------
  // Invokes
  
  JRT_ENTRY(Bytecodes::Code, InterpreterRuntime::get_original_bytecode_at(JavaThread* current, Method* method, address bcp))

@@ -1166,33 +1355,36 @@
  JRT_END
  
  JRT_ENTRY(void, InterpreterRuntime::post_field_access(JavaThread* current, oopDesc* obj,
                                                        ResolvedFieldEntry *entry))
  
+   assert(entry->is_valid(), "Invalid ResolvedFieldEntry");
    // check the access_flags for the field in the klass
  
    InstanceKlass* ik = entry->field_holder();
    int index = entry->field_index();
    if (!ik->field_status(index).is_access_watched()) return;
  
    bool is_static = (obj == nullptr);
+   bool is_flat = entry->is_flat();
    HandleMark hm(current);
  
    Handle h_obj;
    if (!is_static) {
      // non-static field accessors have an object, but we need a handle
      h_obj = Handle(current, obj);
    }
    InstanceKlass* field_holder = entry->field_holder(); // HERE
-   jfieldID fid = jfieldIDWorkaround::to_jfieldID(field_holder, entry->field_offset(), is_static);
+   jfieldID fid = jfieldIDWorkaround::to_jfieldID(field_holder, entry->field_offset(), is_static, is_flat);
    LastFrameAccessor last_frame(current);
    JvmtiExport::post_field_access(current, last_frame.method(), last_frame.bcp(), field_holder, h_obj, fid);
  JRT_END
  
  JRT_ENTRY(void, InterpreterRuntime::post_field_modification(JavaThread* current, oopDesc* obj,
                                                              ResolvedFieldEntry *entry, jvalue *value))
  
+   assert(entry->is_valid(), "Invalid ResolvedFieldEntry");
    InstanceKlass* ik = entry->field_holder();
  
    // check the access_flags for the field in the klass
    int index = entry->field_index();
    // bail out if field modifications are not watched

@@ -1210,14 +1402,16 @@
      case atos: sig_type = JVM_SIGNATURE_CLASS;   break;
      case ltos: sig_type = JVM_SIGNATURE_LONG;    break;
      case dtos: sig_type = JVM_SIGNATURE_DOUBLE;  break;
      default:  ShouldNotReachHere(); return;
    }
+ 
    bool is_static = (obj == nullptr);
+   bool is_flat = entry->is_flat();
  
    HandleMark hm(current);
-   jfieldID fid = jfieldIDWorkaround::to_jfieldID(ik, entry->field_offset(), is_static);
+   jfieldID fid = jfieldIDWorkaround::to_jfieldID(ik, entry->field_offset(), is_static, is_flat);
    jvalue fvalue;
  #ifdef _LP64
    fvalue = *value;
  #else
    // Long/double values are stored unaligned and also noncontiguously with
< prev index next >