< 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

*** 239,30 ***
    //       because the _breakpoint bytecode would be lost.
    oop obj = klass->allocate_instance(CHECK);
    current->set_vm_result(obj);
  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);
    current->set_vm_result(obj);
  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   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.
--- 244,164 ---
    //       because the _breakpoint bytecode would be lost.
    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_init_thread(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");
+       klass->set_inline_type_field_klass(index, InlineKlass::cast(field_k));
+     }
+     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, 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_flat(index), "Sanity check");
+ 
+   InlineKlass* field_vklass = InlineKlass::cast(klass->get_inline_type_field_klass(index));
+ 
+   oop res = field_vklass->read_flat_field(obj_h(), klass->field_offset(index), CHECK);
+   current->set_vm_result(res);
+ JRT_END
+ 
+ // The protocol to read a nullable flat field is:
+ // Step 1: read the null marker with an load_acquire barrier to ensure that
+ //         reordered loads won't try to load the value before the null marker is read
+ // Step 2: if the null marker value is zero, the field's value is null
+ //         otherwise the flat field value can be read like a regular flat field
+ 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* ik = InstanceKlass::cast(obj_h()->klass());
+   int field_index = entry->field_index();
+   int nm_offset = ik->null_marker_offsets_array()->at(field_index);
+   if (obj_h()->byte_field_acquire(nm_offset) == 0) {
+     current->set_vm_result(nullptr);
+   } else {
+     InlineKlass* field_vklass = InlineKlass::cast(ik->get_inline_type_field_klass(field_index));
+     oop res = field_vklass->read_flat_field(obj_h(), ik->field_offset(field_index), CHECK);
+     current->set_vm_result(res);
+   }
+ JRT_END
+ 
+ // The protocol to write a nullable flat field is:
+ // If the new field value is null, just write zero to the null marker
+ // Otherwise:
+ // Step 1: write the field value like a regular flat field
+ // Step 2: have a memory barrier to ensure that the whole value content is visible
+ // Step 3: update the null marker to a non zero value
+ 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* ik = InstanceKlass::cast(obj_h()->klass());
+   int nm_offset = ik->null_marker_offsets_array()->at(entry->field_index());
+   if (val_h() == nullptr) {
+     obj_h()->byte_field_put(nm_offset, (jbyte)0);
+     return;
+   }
+   InlineKlass* vk = InlineKlass::cast(val_h()->klass());
+   if (entry->has_internal_null_marker()) {
+     // The interpreter copies values with a bulk operation
+     // To avoid accidently 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->get_internal_null_marker_offset()) == 0) {
+       val_h()->byte_field_put(vk->get_internal_null_marker_offset(), (jbyte)1);
+     }
+     vk->write_non_null_flat_field(obj_h(), entry->field_offset(), val_h());
+   } else {
+     vk->write_non_null_flat_field(obj_h(), entry->field_offset(), val_h());
+     OrderAccess::release();
+     obj_h()->byte_field_put(nm_offset, (jbyte)1);
+   }
+ 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);
!   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);
+ 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   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.

*** 287,10 ***
--- 426,33 ---
    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());
+   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);

*** 630,10 ***
--- 792,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
  

*** 710,18 ***
    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_put && !has_initialized_final_update) || !info.access_flags().is_final()) {
!       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->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));
  }
  
--- 876,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) {
!     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);
      }
    }
  
    ResolvedFieldEntry* entry = pool->resolved_field_entry_at(field_index);
!   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(), info.has_internal_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));
  }
  

*** 782,16 ***
    // 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.
--- 955,14 ---

*** 802,10 ***
--- 973,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))

*** 1161,33 ***
  JRT_END
  
  JRT_ENTRY(void, InterpreterRuntime::post_field_access(JavaThread* current, oopDesc* obj,
                                                        ResolvedFieldEntry *entry))
  
    // 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);
    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);
    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))
  
    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
--- 1347,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, 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

*** 1205,14 ***
      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);
  
    HandleMark hm(current);
!   jfieldID fid = jfieldIDWorkaround::to_jfieldID(ik, entry->field_offset(), is_static);
    jvalue fvalue;
  #ifdef _LP64
    fvalue = *value;
  #else
    // Long/double values are stored unaligned and also noncontiguously with
--- 1394,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, is_flat);
    jvalue fvalue;
  #ifdef _LP64
    fvalue = *value;
  #else
    // Long/double values are stored unaligned and also noncontiguously with
< prev index next >