< prev index next > src/hotspot/share/interpreter/interpreterRuntime.cpp
Print this page
*/
#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"
#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"
#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
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.
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);
! 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 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.
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);
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
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));
}
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());
+
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));
}
// 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.
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))
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
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
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
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 >