< 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
int cp_index = wide ? last_frame.get_index_u2(Bytecodes::_ldc_w) : last_frame.get_index_u1(Bytecodes::_ldc);
constantTag tag = pool->tag_at(cp_index);
assert (tag.is_unresolved_klass() || tag.is_klass(), "wrong ldc call");
Klass* klass = pool->klass_at(cp_index, CHECK);
- oop java_class = klass->java_mirror();
+ oop java_class = tag.is_Qdescriptor_klass()
+ ? InlineKlass::cast(klass)->val_mirror()
+ : klass->java_mirror();
current->set_vm_result(java_class);
JRT_END
JRT_ENTRY(void, InterpreterRuntime::resolve_ldc(JavaThread* current, Bytecodes::Code bytecode)) {
assert(bytecode == Bytecodes::_ldc ||
JRT_ENTRY(void, InterpreterRuntime::_new(JavaThread* current, ConstantPool* pool, int index))
Klass* k = pool->klass_at(index, CHECK);
InstanceKlass* klass = InstanceKlass::cast(k);
+ if (klass->is_inline_klass()) {
+ THROW(vmSymbols::java_lang_InstantiationError());
+ }
+
// Make sure we are not instantiating an abstract klass
klass->check_valid_for_instantiation(true, CHECK);
// Make sure klass is initialized
klass->initialize(CHECK);
// because the _breakpoint bytecode would be lost.
oop obj = klass->allocate_instance(CHECK);
current->set_vm_result(obj);
JRT_END
+ JRT_ENTRY(void, InterpreterRuntime::aconst_init(JavaThread* current, ConstantPool* pool, int index))
+ // Getting the InlineKlass
+ Klass* k = pool->klass_at(index, CHECK);
+ if (!k->is_inline_klass()) {
+ // inconsistency with 'new' which throws an InstantiationError
+ // in the future, aconst_init will just return null instead of throwing an exception
+ THROW(vmSymbols::java_lang_IncompatibleClassChangeError());
+ }
+ assert(k->is_inline_klass(), "aconst_init argument must be the inline type class");
+ InlineKlass* vklass = InlineKlass::cast(k);
+
+ vklass->initialize(CHECK);
+ oop res = vklass->default_value();
+ current->set_vm_result(res);
+ JRT_END
+
+ JRT_ENTRY(int, InterpreterRuntime::withfield(JavaThread* current, ResolvedFieldEntry* entry, uintptr_t ptr))
+ assert(entry->is_valid(), "Invalid ResolvedFieldEntry");
+ oop obj = nullptr;
+ int recv_offset = type2size[as_BasicType((TosState)entry->tos_state())];
+ assert(frame::interpreter_frame_expression_stack_direction() == -1, "currently is -1 on all platforms");
+ int ret_adj = (recv_offset + type2size[T_OBJECT] )* AbstractInterpreter::stackElementSize;
+ int offset = entry->field_offset();
+ obj = (oopDesc*)(((uintptr_t*)ptr)[recv_offset * Interpreter::stackElementWords]);
+ if (obj == nullptr) {
+ THROW_(vmSymbols::java_lang_NullPointerException(), ret_adj);
+ }
+ assert(oopDesc::is_oop(obj), "Verifying receiver");
+ assert(obj->klass()->is_inline_klass(), "Must have been checked during resolution");
+ instanceHandle old_value_h(THREAD, (instanceOop)obj);
+ oop ref = nullptr;
+ if (entry->tos_state() == atos) {
+ ref = *(oopDesc**)ptr;
+ }
+ Handle ref_h(THREAD, ref);
+ InlineKlass* ik = InlineKlass::cast(old_value_h()->klass());
+ // Ensure that the class is initialized or being initialized
+ // If the class is in error state, the creation of a new value should not be allowed
+ ik->initialize(CHECK_(ret_adj));
+
+ bool can_skip = false;
+ switch(entry->tos_state()) {
+ case ztos:
+ if (old_value_h()->bool_field(offset) == (jboolean)(*(jint*)ptr)) can_skip = true;
+ break;
+ case btos:
+ if (old_value_h()->byte_field(offset) == (jbyte)(*(jint*)ptr)) can_skip = true;
+ break;
+ case ctos:
+ if (old_value_h()->char_field(offset) == (jchar)(*(jint*)ptr)) can_skip = true;
+ break;
+ case stos:
+ if (old_value_h()->short_field(offset) == (jshort)(*(jint*)ptr)) can_skip = true;
+ break;
+ case itos:
+ if (old_value_h()->int_field(offset) == *(jint*)ptr) can_skip = true;
+ break;
+ case ltos:
+ if (old_value_h()->long_field(offset) == *(jlong*)ptr) can_skip = true;
+ break;
+ case ftos:
+ if (memcmp(old_value_h()->field_addr<jfloat>(offset), (jfloat*)ptr, sizeof(jfloat)) == 0) can_skip = true;
+ break;
+ case dtos:
+ if (memcmp(old_value_h()->field_addr<jdouble>(offset), (jdouble*)ptr, sizeof(jdouble)) == 0) can_skip = true;
+ break;
+ case atos:
+ if (!entry->is_flat() && old_value_h()->obj_field(offset) == ref_h()) can_skip = true;
+ break;
+ default:
+ break;
+ }
+ if (can_skip) {
+ current->set_vm_result(old_value_h());
+ return ret_adj;
+ }
+
+ instanceOop new_value = ik->allocate_instance_buffer(CHECK_(ret_adj));
+ Handle new_value_h = Handle(THREAD, new_value);
+ ik->inline_copy_oop_to_new_oop(old_value_h(), new_value_h());
+ switch(entry->tos_state()) {
+ case ztos:
+ new_value_h()->bool_field_put(offset, (jboolean)(*(jint*)ptr));
+ break;
+ case btos:
+ new_value_h()->byte_field_put(offset, (jbyte)(*(jint*)ptr));
+ break;
+ case ctos:
+ new_value_h()->char_field_put(offset, (jchar)(*(jint*)ptr));
+ break;
+ case stos:
+ new_value_h()->short_field_put(offset, (jshort)(*(jint*)ptr));
+ break;
+ case itos:
+ new_value_h()->int_field_put(offset, (*(jint*)ptr));
+ break;
+ case ltos:
+ new_value_h()->long_field_put(offset, *(jlong*)ptr);
+ break;
+ case ftos:
+ new_value_h()->float_field_put(offset, *(jfloat*)ptr);
+ break;
+ case dtos:
+ new_value_h()->double_field_put(offset, *(jdouble*)ptr);
+ break;
+ case atos:
+ {
+ if (entry->is_null_free_inline_type()) {
+ if (!entry->is_flat()) {
+ if (ref_h() == nullptr) {
+ THROW_(vmSymbols::java_lang_NullPointerException(), ret_adj);
+ }
+ new_value_h()->obj_field_put(offset, ref_h());
+ } else {
+ int field_index = entry->field_index();
+ InlineKlass* field_ik = InlineKlass::cast(ik->get_inline_type_field_klass(field_index));
+ field_ik->write_flat_field(new_value_h(), offset, ref_h(), CHECK_(ret_adj));
+ }
+ } else {
+ new_value_h()->obj_field_put(offset, ref_h());
+ }
+ }
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+ current->set_vm_result(new_value_h());
+ return ret_adj;
+ 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, 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
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);
+ bool is_qtype_desc = pool->tag_at(index).is_Qdescriptor_klass();
+ arrayOop obj;
+ if ((!klass->is_array_klass()) && is_qtype_desc) { // Logically creates elements, ensure klass init
+ klass->initialize(CHECK);
+ obj = oopFactory::new_valueArray(klass, size, CHECK);
+ } else {
+ 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 i = last_frame.get_index_u2(Bytecodes::_multianewarray);
+ Klass* klass = constants->klass_at(i, CHECK);
+ bool is_qtype = klass->name()->is_Q_array_signature();
int nof_dims = last_frame.number_of_dimensions();
assert(klass->is_klass(), "not a class");
assert(nof_dims >= 1, "multianewarray rank must be nonzero");
+ if (is_qtype) { // Logically creates elements, ensure klass init
+ klass->initialize(CHECK);
+ }
+
// We must create an array of jints to pass to multi_allocate.
ResourceMark rm(current);
const int small_dims = 10;
jint dim_array[small_dims];
jint *dims = &dim_array[0];
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);
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
fieldDescriptor info;
LastFrameAccessor last_frame(current);
constantPoolHandle pool(current, last_frame.method()->constants());
methodHandle m(current, 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_inline_type = bytecode == Bytecodes::_withfield;
int field_index = last_frame.get_index_u2(bytecode);
{
JvmtiHideSingleStepping jhss(current);
JavaThread* THREAD = current; // For exception macros.
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);
+ if (is_static) {
+ get_code = Bytecodes::_getstatic;
+ } else {
+ get_code = Bytecodes::_getfield;
+ }
+ if (is_put && is_inline_type) {
+ 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);
}
}
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());
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));
}
switch (bytecode) {
case Bytecodes::_getstatic:
case Bytecodes::_putstatic:
case Bytecodes::_getfield:
case Bytecodes::_putfield:
+ case Bytecodes::_withfield:
resolve_get_put(current, bytecode);
break;
case Bytecodes::_invokevirtual:
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
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
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;
}
+
+ // Both Q-signatures and L-signatures are mapped to atos
+ ik->field_is_null_free_inline_type(index);
+ if (entry->tos_state() == atos && ik->field_is_null_free_inline_type(index)) {
+ sig_type = JVM_SIGNATURE_PRIMITIVE_OBJECT;
+ }
+
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 >