mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8157181: Compilers accept modification of final fields outside initializer methods
Track initialized final field updates; disable constant folding if an update is detected. Enforce final field update rules introduced by JVMS-7 (but only for JDK 9). Reviewed-by: vlivanov, dnsimon, forax, never, kvn, coleenp
This commit is contained in:
parent
2ade029123
commit
cdc436922a
32 changed files with 284 additions and 75 deletions
|
@ -267,8 +267,9 @@ final class CompilerToVM {
|
||||||
native HotSpotResolvedObjectTypeImpl resolveTypeInPool(HotSpotConstantPool constantPool, int cpi) throws LinkageError;
|
native HotSpotResolvedObjectTypeImpl resolveTypeInPool(HotSpotConstantPool constantPool, int cpi) throws LinkageError;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up and attempts to resolve the {@code JVM_CONSTANT_Field} entry at index {@code cpi} in
|
* Looks up and attempts to resolve the {@code JVM_CONSTANT_Field} entry for at index {@code cpi} in
|
||||||
* {@code constantPool}. The values returned in {@code info} are:
|
* {@code constantPool}. For some opcodes, checks are performed that require the {@code method}
|
||||||
|
* that contains {@code opcode} to be specified. The values returned in {@code info} are:
|
||||||
*
|
*
|
||||||
* <pre>
|
* <pre>
|
||||||
* [(int) flags, // only valid if field is resolved
|
* [(int) flags, // only valid if field is resolved
|
||||||
|
@ -281,7 +282,7 @@ final class CompilerToVM {
|
||||||
* @param info an array in which the details of the field are returned
|
* @param info an array in which the details of the field are returned
|
||||||
* @return the type defining the field if resolution is successful, 0 otherwise
|
* @return the type defining the field if resolution is successful, 0 otherwise
|
||||||
*/
|
*/
|
||||||
native HotSpotResolvedObjectTypeImpl resolveFieldInPool(HotSpotConstantPool constantPool, int cpi, byte opcode, long[] info);
|
native HotSpotResolvedObjectTypeImpl resolveFieldInPool(HotSpotConstantPool constantPool, int cpi, HotSpotResolvedJavaMethodImpl method, byte opcode, long[] info);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts {@code cpci} from an index into the cache for {@code constantPool} to an index
|
* Converts {@code cpci} from an index into the cache for {@code constantPool} to an index
|
||||||
|
|
|
@ -587,7 +587,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JavaField lookupField(int cpi, int opcode) {
|
public JavaField lookupField(int cpi, ResolvedJavaMethod method, int opcode) {
|
||||||
final int index = rawIndexToConstantPoolIndex(cpi, opcode);
|
final int index = rawIndexToConstantPoolIndex(cpi, opcode);
|
||||||
final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index);
|
final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index);
|
||||||
final int nameIndex = getNameRefIndexAt(nameAndTypeIndex);
|
final int nameIndex = getNameRefIndexAt(nameAndTypeIndex);
|
||||||
|
@ -603,7 +603,7 @@ final class HotSpotConstantPool implements ConstantPool, MetaspaceWrapperObject
|
||||||
long[] info = new long[2];
|
long[] info = new long[2];
|
||||||
HotSpotResolvedObjectTypeImpl resolvedHolder;
|
HotSpotResolvedObjectTypeImpl resolvedHolder;
|
||||||
try {
|
try {
|
||||||
resolvedHolder = compilerToVM().resolveFieldInPool(this, index, (byte) opcode, info);
|
resolvedHolder = compilerToVM().resolveFieldInPool(this, index, (HotSpotResolvedJavaMethodImpl) method, (byte) opcode, info);
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
/*
|
/*
|
||||||
* If there was an exception resolving the field we give up and return an unresolved
|
* If there was an exception resolving the field we give up and return an unresolved
|
||||||
|
|
|
@ -48,16 +48,18 @@ public interface ConstantPool {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up a reference to a field. If {@code opcode} is non-negative, then resolution checks
|
* Looks up a reference to a field. If {@code opcode} is non-negative, then resolution checks
|
||||||
* specific to the bytecode it denotes are performed if the field is already resolved. Should
|
* specific to the bytecode it denotes are performed if the field is already resolved. Checks
|
||||||
|
* for some bytecodes require the method that contains the bytecode to be specified. Should
|
||||||
* any of these checks fail, an unresolved field reference is returned.
|
* any of these checks fail, an unresolved field reference is returned.
|
||||||
*
|
*
|
||||||
* @param cpi the constant pool index
|
* @param cpi the constant pool index
|
||||||
* @param opcode the opcode of the instruction for which the lookup is being performed or
|
* @param opcode the opcode of the instruction for which the lookup is being performed or
|
||||||
* {@code -1}
|
* {@code -1}
|
||||||
|
* @param method the method for which the lookup is being performed
|
||||||
* @return a reference to the field at {@code cpi} in this pool
|
* @return a reference to the field at {@code cpi} in this pool
|
||||||
* @throws ClassFormatError if the entry at {@code cpi} is not a field
|
* @throws ClassFormatError if the entry at {@code cpi} is not a field
|
||||||
*/
|
*/
|
||||||
JavaField lookupField(int cpi, int opcode);
|
JavaField lookupField(int cpi, ResolvedJavaMethod method, int opcode);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up a reference to a method. If {@code opcode} is non-negative, then resolution checks
|
* Looks up a reference to a method. If {@code opcode} is non-negative, then resolution checks
|
||||||
|
|
|
@ -1600,7 +1600,7 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
|
||||||
ValueType* type = as_ValueType(field_type);
|
ValueType* type = as_ValueType(field_type);
|
||||||
// call will_link again to determine if the field is valid.
|
// call will_link again to determine if the field is valid.
|
||||||
const bool needs_patching = !holder->is_loaded() ||
|
const bool needs_patching = !holder->is_loaded() ||
|
||||||
!field->will_link(method()->holder(), code) ||
|
!field->will_link(method(), code) ||
|
||||||
PatchALot;
|
PatchALot;
|
||||||
|
|
||||||
ValueStack* state_before = NULL;
|
ValueStack* state_before = NULL;
|
||||||
|
|
|
@ -759,10 +759,10 @@ static Klass* resolve_field_return_klass(methodHandle caller, int bci, TRAPS) {
|
||||||
// This can be static or non-static field access
|
// This can be static or non-static field access
|
||||||
Bytecodes::Code code = field_access.code();
|
Bytecodes::Code code = field_access.code();
|
||||||
|
|
||||||
// We must load class, initialize class and resolvethe field
|
// We must load class, initialize class and resolve the field
|
||||||
fieldDescriptor result; // initialize class if needed
|
fieldDescriptor result; // initialize class if needed
|
||||||
constantPoolHandle constants(THREAD, caller->constants());
|
constantPoolHandle constants(THREAD, caller->constants());
|
||||||
LinkResolver::resolve_field_access(result, constants, field_access.index(), Bytecodes::java_code(code), CHECK_NULL);
|
LinkResolver::resolve_field_access(result, constants, field_access.index(), caller, Bytecodes::java_code(code), CHECK_NULL);
|
||||||
return result.field_holder();
|
return result.field_holder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -879,7 +879,7 @@ JRT_ENTRY(void, Runtime1::patch_code(JavaThread* thread, Runtime1::StubID stub_i
|
||||||
fieldDescriptor result; // initialize class if needed
|
fieldDescriptor result; // initialize class if needed
|
||||||
Bytecodes::Code code = field_access.code();
|
Bytecodes::Code code = field_access.code();
|
||||||
constantPoolHandle constants(THREAD, caller_method->constants());
|
constantPoolHandle constants(THREAD, caller_method->constants());
|
||||||
LinkResolver::resolve_field_access(result, constants, field_access.index(), Bytecodes::java_code(code), CHECK);
|
LinkResolver::resolve_field_access(result, constants, field_access.index(), caller_method, Bytecodes::java_code(code), CHECK);
|
||||||
patch_field_offset = result.offset();
|
patch_field_offset = result.offset();
|
||||||
|
|
||||||
// If we're patching a field which is volatile then at compile it
|
// If we're patching a field which is volatile then at compile it
|
||||||
|
|
|
@ -66,7 +66,8 @@
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// ciField::ciField
|
// ciField::ciField
|
||||||
ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with_put(NULL), _known_to_link_with_get(NULL) {
|
ciField::ciField(ciInstanceKlass* klass, int index) :
|
||||||
|
_known_to_link_with_put(NULL), _known_to_link_with_get(NULL) {
|
||||||
ASSERT_IN_VM;
|
ASSERT_IN_VM;
|
||||||
CompilerThread *thread = CompilerThread::current();
|
CompilerThread *thread = CompilerThread::current();
|
||||||
|
|
||||||
|
@ -173,7 +174,8 @@ ciField::ciField(ciInstanceKlass* klass, int index): _known_to_link_with_put(NUL
|
||||||
initialize_from(&field_desc);
|
initialize_from(&field_desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
ciField::ciField(fieldDescriptor *fd): _known_to_link_with_put(NULL), _known_to_link_with_get(NULL) {
|
ciField::ciField(fieldDescriptor *fd) :
|
||||||
|
_known_to_link_with_put(NULL), _known_to_link_with_get(NULL) {
|
||||||
ASSERT_IN_VM;
|
ASSERT_IN_VM;
|
||||||
|
|
||||||
// Get the field's name, signature, and type.
|
// Get the field's name, signature, and type.
|
||||||
|
@ -237,7 +239,7 @@ void ciField::initialize_from(fieldDescriptor* fd) {
|
||||||
// Check to see if the field is constant.
|
// Check to see if the field is constant.
|
||||||
Klass* k = _holder->get_Klass();
|
Klass* k = _holder->get_Klass();
|
||||||
bool is_stable_field = FoldStableValues && is_stable();
|
bool is_stable_field = FoldStableValues && is_stable();
|
||||||
if (is_final() || is_stable_field) {
|
if ((is_final() && !has_initialized_final_update()) || is_stable_field) {
|
||||||
if (is_static()) {
|
if (is_static()) {
|
||||||
// This field just may be constant. The only case where it will
|
// This field just may be constant. The only case where it will
|
||||||
// not be constant is when the field is a *special* static & final field
|
// not be constant is when the field is a *special* static & final field
|
||||||
|
@ -265,6 +267,7 @@ void ciField::initialize_from(fieldDescriptor* fd) {
|
||||||
assert(SystemDictionary::CallSite_klass() != NULL, "should be already initialized");
|
assert(SystemDictionary::CallSite_klass() != NULL, "should be already initialized");
|
||||||
if (k == SystemDictionary::CallSite_klass() &&
|
if (k == SystemDictionary::CallSite_klass() &&
|
||||||
_offset == java_lang_invoke_CallSite::target_offset_in_bytes()) {
|
_offset == java_lang_invoke_CallSite::target_offset_in_bytes()) {
|
||||||
|
assert(!has_initialized_final_update(), "CallSite is not supposed to have writes to final fields outside initializers");
|
||||||
_is_constant = true;
|
_is_constant = true;
|
||||||
} else {
|
} else {
|
||||||
// Non-final & non-stable fields are not constants.
|
// Non-final & non-stable fields are not constants.
|
||||||
|
@ -340,7 +343,7 @@ ciType* ciField::compute_type_impl() {
|
||||||
//
|
//
|
||||||
// Can a specific access to this field be made without causing
|
// Can a specific access to this field be made without causing
|
||||||
// link errors?
|
// link errors?
|
||||||
bool ciField::will_link(ciInstanceKlass* accessing_klass,
|
bool ciField::will_link(ciMethod* accessing_method,
|
||||||
Bytecodes::Code bc) {
|
Bytecodes::Code bc) {
|
||||||
VM_ENTRY_MARK;
|
VM_ENTRY_MARK;
|
||||||
assert(bc == Bytecodes::_getstatic || bc == Bytecodes::_putstatic ||
|
assert(bc == Bytecodes::_getstatic || bc == Bytecodes::_putstatic ||
|
||||||
|
@ -363,27 +366,27 @@ bool ciField::will_link(ciInstanceKlass* accessing_klass,
|
||||||
// Get and put can have different accessibility rules
|
// Get and put can have different accessibility rules
|
||||||
bool is_put = (bc == Bytecodes::_putfield || bc == Bytecodes::_putstatic);
|
bool is_put = (bc == Bytecodes::_putfield || bc == Bytecodes::_putstatic);
|
||||||
if (is_put) {
|
if (is_put) {
|
||||||
if (_known_to_link_with_put == accessing_klass) {
|
if (_known_to_link_with_put == accessing_method) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (_known_to_link_with_get == accessing_klass) {
|
if (_known_to_link_with_get == accessing_method->holder()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkInfo link_info(_holder->get_instanceKlass(),
|
LinkInfo link_info(_holder->get_instanceKlass(),
|
||||||
_name->get_symbol(), _signature->get_symbol(),
|
_name->get_symbol(), _signature->get_symbol(),
|
||||||
accessing_klass->get_Klass());
|
accessing_method->get_Method());
|
||||||
fieldDescriptor result;
|
fieldDescriptor result;
|
||||||
LinkResolver::resolve_field(result, link_info, bc, false, KILL_COMPILE_ON_FATAL_(false));
|
LinkResolver::resolve_field(result, link_info, bc, false, KILL_COMPILE_ON_FATAL_(false));
|
||||||
|
|
||||||
// update the hit-cache, unless there is a problem with memory scoping:
|
// update the hit-cache, unless there is a problem with memory scoping:
|
||||||
if (accessing_klass->is_shared() || !is_shared()) {
|
if (accessing_method->holder()->is_shared() || !is_shared()) {
|
||||||
if (is_put) {
|
if (is_put) {
|
||||||
_known_to_link_with_put = accessing_klass;
|
_known_to_link_with_put = accessing_method;
|
||||||
} else {
|
} else {
|
||||||
_known_to_link_with_get = accessing_klass;
|
_known_to_link_with_get = accessing_method->holder();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,7 +48,7 @@ private:
|
||||||
ciType* _type;
|
ciType* _type;
|
||||||
int _offset;
|
int _offset;
|
||||||
bool _is_constant;
|
bool _is_constant;
|
||||||
ciInstanceKlass* _known_to_link_with_put;
|
ciMethod* _known_to_link_with_put;
|
||||||
ciInstanceKlass* _known_to_link_with_get;
|
ciInstanceKlass* _known_to_link_with_get;
|
||||||
ciConstant _constant_value;
|
ciConstant _constant_value;
|
||||||
|
|
||||||
|
@ -131,8 +131,12 @@ public:
|
||||||
// non-constant fields. These are java.lang.System.in
|
// non-constant fields. These are java.lang.System.in
|
||||||
// and java.lang.System.out. Abomination.
|
// and java.lang.System.out. Abomination.
|
||||||
//
|
//
|
||||||
// A field is also considered constant if it is marked @Stable
|
// A field is also considered constant if
|
||||||
// and is non-null (or non-zero, if a primitive).
|
// - it is marked @Stable and is non-null (or non-zero, if a primitive) or
|
||||||
|
// - it is trusted or
|
||||||
|
// - it is the target field of a CallSite object.
|
||||||
|
//
|
||||||
|
// See ciField::initialize_from() for more details.
|
||||||
//
|
//
|
||||||
// A user should also check the field value (constant_value().is_valid()), since
|
// A user should also check the field value (constant_value().is_valid()), since
|
||||||
// constant fields of non-initialized classes don't have values yet.
|
// constant fields of non-initialized classes don't have values yet.
|
||||||
|
@ -150,25 +154,28 @@ public:
|
||||||
ciConstant constant_value_of(ciObject* object);
|
ciConstant constant_value_of(ciObject* object);
|
||||||
|
|
||||||
// Check for link time errors. Accessing a field from a
|
// Check for link time errors. Accessing a field from a
|
||||||
// certain class via a certain bytecode may or may not be legal.
|
// certain method via a certain bytecode may or may not be legal.
|
||||||
// This call checks to see if an exception may be raised by
|
// This call checks to see if an exception may be raised by
|
||||||
// an access of this field.
|
// an access of this field.
|
||||||
//
|
//
|
||||||
// Usage note: if the same field is accessed multiple times
|
// Usage note: if the same field is accessed multiple times
|
||||||
// in the same compilation, will_link will need to be checked
|
// in the same compilation, will_link will need to be checked
|
||||||
// at each point of access.
|
// at each point of access.
|
||||||
bool will_link(ciInstanceKlass* accessing_klass,
|
bool will_link(ciMethod* accessing_method,
|
||||||
Bytecodes::Code bc);
|
Bytecodes::Code bc);
|
||||||
|
|
||||||
// Java access flags
|
// Java access flags
|
||||||
bool is_public () const { return flags().is_public(); }
|
bool is_public () const { return flags().is_public(); }
|
||||||
bool is_private () const { return flags().is_private(); }
|
bool is_private () const { return flags().is_private(); }
|
||||||
bool is_protected () const { return flags().is_protected(); }
|
bool is_protected () const { return flags().is_protected(); }
|
||||||
bool is_static () const { return flags().is_static(); }
|
bool is_static () const { return flags().is_static(); }
|
||||||
bool is_final () const { return flags().is_final(); }
|
bool is_final () const { return flags().is_final(); }
|
||||||
bool is_stable () const { return flags().is_stable(); }
|
bool is_stable () const { return flags().is_stable(); }
|
||||||
bool is_volatile () const { return flags().is_volatile(); }
|
bool is_volatile () const { return flags().is_volatile(); }
|
||||||
bool is_transient () const { return flags().is_transient(); }
|
bool is_transient () const { return flags().is_transient(); }
|
||||||
|
// The field is modified outside of instance initializer methods
|
||||||
|
// (or class/initializer methods if the field is static).
|
||||||
|
bool has_initialized_final_update() const { return flags().has_initialized_final_update(); }
|
||||||
|
|
||||||
bool is_call_site_target() {
|
bool is_call_site_target() {
|
||||||
ciInstanceKlass* callsite_klass = CURRENT_ENV->CallSite_klass();
|
ciInstanceKlass* callsite_klass = CURRENT_ENV->CallSite_klass();
|
||||||
|
|
|
@ -47,20 +47,25 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Java access flags
|
// Java access flags
|
||||||
bool is_public () const { return (_flags & JVM_ACC_PUBLIC ) != 0; }
|
bool is_public () const { return (_flags & JVM_ACC_PUBLIC ) != 0; }
|
||||||
bool is_private () const { return (_flags & JVM_ACC_PRIVATE ) != 0; }
|
bool is_private () const { return (_flags & JVM_ACC_PRIVATE ) != 0; }
|
||||||
bool is_protected () const { return (_flags & JVM_ACC_PROTECTED ) != 0; }
|
bool is_protected () const { return (_flags & JVM_ACC_PROTECTED ) != 0; }
|
||||||
bool is_static () const { return (_flags & JVM_ACC_STATIC ) != 0; }
|
bool is_static () const { return (_flags & JVM_ACC_STATIC ) != 0; }
|
||||||
bool is_final () const { return (_flags & JVM_ACC_FINAL ) != 0; }
|
bool is_final () const { return (_flags & JVM_ACC_FINAL ) != 0; }
|
||||||
bool is_synchronized() const { return (_flags & JVM_ACC_SYNCHRONIZED) != 0; }
|
bool is_synchronized () const { return (_flags & JVM_ACC_SYNCHRONIZED ) != 0; }
|
||||||
bool is_super () const { return (_flags & JVM_ACC_SUPER ) != 0; }
|
bool is_super () const { return (_flags & JVM_ACC_SUPER ) != 0; }
|
||||||
bool is_volatile () const { return (_flags & JVM_ACC_VOLATILE ) != 0; }
|
bool is_volatile () const { return (_flags & JVM_ACC_VOLATILE ) != 0; }
|
||||||
bool is_transient () const { return (_flags & JVM_ACC_TRANSIENT ) != 0; }
|
bool is_transient () const { return (_flags & JVM_ACC_TRANSIENT ) != 0; }
|
||||||
bool is_native () const { return (_flags & JVM_ACC_NATIVE ) != 0; }
|
bool is_native () const { return (_flags & JVM_ACC_NATIVE ) != 0; }
|
||||||
bool is_interface () const { return (_flags & JVM_ACC_INTERFACE ) != 0; }
|
bool is_interface () const { return (_flags & JVM_ACC_INTERFACE ) != 0; }
|
||||||
bool is_abstract () const { return (_flags & JVM_ACC_ABSTRACT ) != 0; }
|
bool is_abstract () const { return (_flags & JVM_ACC_ABSTRACT ) != 0; }
|
||||||
bool is_strict () const { return (_flags & JVM_ACC_STRICT ) != 0; }
|
bool is_strict () const { return (_flags & JVM_ACC_STRICT ) != 0; }
|
||||||
bool is_stable () const { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
|
bool is_stable () const { return (_flags & JVM_ACC_FIELD_STABLE ) != 0; }
|
||||||
|
// In case the current object represents a field, return true if
|
||||||
|
// the field is modified outside of instance initializer methods
|
||||||
|
// (or class/initializer methods if the field is static) and false
|
||||||
|
// otherwise.
|
||||||
|
bool has_initialized_final_update() const { return (_flags & JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE) != 0; };
|
||||||
|
|
||||||
// Conversion
|
// Conversion
|
||||||
jint as_int() { return _flags; }
|
jint as_int() { return _flags; }
|
||||||
|
|
|
@ -278,7 +278,7 @@ int ciBytecodeStream::get_field_index() {
|
||||||
// or put_static, get the referenced field.
|
// or put_static, get the referenced field.
|
||||||
ciField* ciBytecodeStream::get_field(bool& will_link) {
|
ciField* ciBytecodeStream::get_field(bool& will_link) {
|
||||||
ciField* f = CURRENT_ENV->get_field_by_index(_holder, get_field_index());
|
ciField* f = CURRENT_ENV->get_field_by_index(_holder, get_field_index());
|
||||||
will_link = f->will_link(_holder, _bc);
|
will_link = f->will_link(_method, _bc);
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -558,6 +558,7 @@ void InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecodes::Code byt
|
||||||
// resolve field
|
// resolve field
|
||||||
fieldDescriptor info;
|
fieldDescriptor info;
|
||||||
constantPoolHandle pool(thread, method(thread)->constants());
|
constantPoolHandle pool(thread, method(thread)->constants());
|
||||||
|
methodHandle m(thread, method(thread));
|
||||||
bool is_put = (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_nofast_putfield ||
|
bool is_put = (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_nofast_putfield ||
|
||||||
bytecode == Bytecodes::_putstatic);
|
bytecode == Bytecodes::_putstatic);
|
||||||
bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic);
|
bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic);
|
||||||
|
@ -565,7 +566,7 @@ void InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecodes::Code byt
|
||||||
{
|
{
|
||||||
JvmtiHideSingleStepping jhss(thread);
|
JvmtiHideSingleStepping jhss(thread);
|
||||||
LinkResolver::resolve_field_access(info, pool, get_index_u2_cpcache(thread, bytecode),
|
LinkResolver::resolve_field_access(info, pool, get_index_u2_cpcache(thread, bytecode),
|
||||||
bytecode, CHECK);
|
m, bytecode, CHECK);
|
||||||
} // end JvmtiHideSingleStepping
|
} // end JvmtiHideSingleStepping
|
||||||
|
|
||||||
// check if link resolution caused cpCache to be updated
|
// check if link resolution caused cpCache to be updated
|
||||||
|
|
|
@ -223,6 +223,22 @@ void CallInfo::print() {
|
||||||
//------------------------------------------------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------------------------------------------------
|
||||||
// Implementation of LinkInfo
|
// Implementation of LinkInfo
|
||||||
|
|
||||||
|
LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, methodHandle current_method, TRAPS) {
|
||||||
|
// resolve klass
|
||||||
|
Klass* result = pool->klass_ref_at(index, CHECK);
|
||||||
|
_resolved_klass = KlassHandle(THREAD, result);
|
||||||
|
|
||||||
|
// Get name, signature, and static klass
|
||||||
|
_name = pool->name_ref_at(index);
|
||||||
|
_signature = pool->signature_ref_at(index);
|
||||||
|
_tag = pool->tag_ref_at(index);
|
||||||
|
_current_klass = KlassHandle(THREAD, pool->pool_holder());
|
||||||
|
_current_method = current_method;
|
||||||
|
|
||||||
|
// Coming from the constant pool always checks access
|
||||||
|
_check_access = true;
|
||||||
|
}
|
||||||
|
|
||||||
LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, TRAPS) {
|
LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, TRAPS) {
|
||||||
// resolve klass
|
// resolve klass
|
||||||
Klass* result = pool->klass_ref_at(index, CHECK);
|
Klass* result = pool->klass_ref_at(index, CHECK);
|
||||||
|
@ -233,6 +249,7 @@ LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, TRAPS) {
|
||||||
_signature = pool->signature_ref_at(index);
|
_signature = pool->signature_ref_at(index);
|
||||||
_tag = pool->tag_ref_at(index);
|
_tag = pool->tag_ref_at(index);
|
||||||
_current_klass = KlassHandle(THREAD, pool->pool_holder());
|
_current_klass = KlassHandle(THREAD, pool->pool_holder());
|
||||||
|
_current_method = methodHandle();
|
||||||
|
|
||||||
// Coming from the constant pool always checks access
|
// Coming from the constant pool always checks access
|
||||||
_check_access = true;
|
_check_access = true;
|
||||||
|
@ -577,7 +594,7 @@ methodHandle LinkResolver::resolve_method_statically(Bytecodes::Code code,
|
||||||
return resolve_method(link_info, code, THREAD);
|
return resolve_method(link_info, code, THREAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkInfo link_info(pool, index, CHECK_NULL);
|
LinkInfo link_info(pool, index, methodHandle(), CHECK_NULL);
|
||||||
resolved_klass = link_info.resolved_klass();
|
resolved_klass = link_info.resolved_klass();
|
||||||
|
|
||||||
if (pool->has_preresolution()
|
if (pool->has_preresolution()
|
||||||
|
@ -875,8 +892,8 @@ void LinkResolver::check_field_accessability(KlassHandle ref_klass,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinkResolver::resolve_field_access(fieldDescriptor& fd, const constantPoolHandle& pool, int index, Bytecodes::Code byte, TRAPS) {
|
void LinkResolver::resolve_field_access(fieldDescriptor& fd, const constantPoolHandle& pool, int index, const methodHandle& method, Bytecodes::Code byte, TRAPS) {
|
||||||
LinkInfo link_info(pool, index, CHECK);
|
LinkInfo link_info(pool, index, method, CHECK);
|
||||||
resolve_field(fd, link_info, byte, true, CHECK);
|
resolve_field(fd, link_info, byte, true, CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -925,9 +942,39 @@ void LinkResolver::resolve_field(fieldDescriptor& fd,
|
||||||
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), msg);
|
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final fields can only be accessed from its own class.
|
// A final field can be modified only
|
||||||
if (is_put && fd.access_flags().is_final() && sel_klass() != current_klass()) {
|
// (1) by methods declared in the class declaring the field and
|
||||||
THROW(vmSymbols::java_lang_IllegalAccessError());
|
// (2) by the <clinit> method (in case of a static field)
|
||||||
|
// or by the <init> method (in case of an instance field).
|
||||||
|
if (is_put && fd.access_flags().is_final()) {
|
||||||
|
ResourceMark rm(THREAD);
|
||||||
|
stringStream ss;
|
||||||
|
|
||||||
|
if (sel_klass() != current_klass()) {
|
||||||
|
ss.print("Update to %s final field %s.%s attempted from a different class (%s) than the field's declaring class",
|
||||||
|
is_static ? "static" : "non-static", resolved_klass()->external_name(), fd.name()->as_C_string(),
|
||||||
|
current_klass()->external_name());
|
||||||
|
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), ss.as_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd.constants()->pool_holder()->major_version() >= 53) {
|
||||||
|
methodHandle m = link_info.current_method();
|
||||||
|
assert(!m.is_null(), "information about the current method must be available for 'put' bytecodes");
|
||||||
|
bool is_initialized_static_final_update = (byte == Bytecodes::_putstatic &&
|
||||||
|
fd.is_static() &&
|
||||||
|
!m()->is_static_initializer());
|
||||||
|
bool is_initialized_instance_final_update = ((byte == Bytecodes::_putfield || byte == Bytecodes::_nofast_putfield) &&
|
||||||
|
!fd.is_static() &&
|
||||||
|
!m->is_object_initializer());
|
||||||
|
|
||||||
|
if (is_initialized_static_final_update || is_initialized_instance_final_update) {
|
||||||
|
ss.print("Update to %s final field %s.%s attempted from a different method (%s) than the initializer method %s ",
|
||||||
|
is_static ? "static" : "non-static", resolved_klass()->external_name(), fd.name()->as_C_string(),
|
||||||
|
current_klass()->external_name(),
|
||||||
|
is_static ? "<clinit>" : "<init>");
|
||||||
|
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), ss.as_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize resolved_klass if necessary
|
// initialize resolved_klass if necessary
|
||||||
|
|
|
@ -131,19 +131,23 @@ class CallInfo : public StackObj {
|
||||||
// resolved_klass = specified class (i.e., static receiver class)
|
// resolved_klass = specified class (i.e., static receiver class)
|
||||||
// current_klass = sending method holder (i.e., class containing the method
|
// current_klass = sending method holder (i.e., class containing the method
|
||||||
// containing the call being resolved)
|
// containing the call being resolved)
|
||||||
|
// current_method = sending method (relevant for field resolution)
|
||||||
class LinkInfo : public StackObj {
|
class LinkInfo : public StackObj {
|
||||||
Symbol* _name; // extracted from JVM_CONSTANT_NameAndType
|
Symbol* _name; // extracted from JVM_CONSTANT_NameAndType
|
||||||
Symbol* _signature;
|
Symbol* _signature;
|
||||||
KlassHandle _resolved_klass; // class that the constant pool entry points to
|
KlassHandle _resolved_klass; // class that the constant pool entry points to
|
||||||
KlassHandle _current_klass; // class that owns the constant pool
|
KlassHandle _current_klass; // class that owns the constant pool
|
||||||
|
methodHandle _current_method; // sending method
|
||||||
bool _check_access;
|
bool _check_access;
|
||||||
constantTag _tag;
|
constantTag _tag;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum AccessCheck {
|
enum AccessCheck {
|
||||||
needs_access_check,
|
needs_access_check,
|
||||||
skip_access_check
|
skip_access_check
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LinkInfo(const constantPoolHandle& pool, int index, methodHandle current_method, TRAPS);
|
||||||
LinkInfo(const constantPoolHandle& pool, int index, TRAPS);
|
LinkInfo(const constantPoolHandle& pool, int index, TRAPS);
|
||||||
|
|
||||||
// Condensed information from other call sites within the vm.
|
// Condensed information from other call sites within the vm.
|
||||||
|
@ -151,13 +155,20 @@ class LinkInfo : public StackObj {
|
||||||
AccessCheck check_access = needs_access_check,
|
AccessCheck check_access = needs_access_check,
|
||||||
constantTag tag = JVM_CONSTANT_Invalid) :
|
constantTag tag = JVM_CONSTANT_Invalid) :
|
||||||
_resolved_klass(resolved_klass),
|
_resolved_klass(resolved_klass),
|
||||||
_name(name), _signature(signature), _current_klass(current_klass),
|
_name(name), _signature(signature), _current_klass(current_klass), _current_method(NULL),
|
||||||
|
_check_access(check_access == needs_access_check), _tag(tag) {}
|
||||||
|
|
||||||
|
LinkInfo(KlassHandle resolved_klass, Symbol* name, Symbol* signature, methodHandle current_method,
|
||||||
|
AccessCheck check_access = needs_access_check,
|
||||||
|
constantTag tag = JVM_CONSTANT_Invalid) :
|
||||||
|
_resolved_klass(resolved_klass),
|
||||||
|
_name(name), _signature(signature), _current_klass(current_method->method_holder()), _current_method(current_method),
|
||||||
_check_access(check_access == needs_access_check), _tag(tag) {}
|
_check_access(check_access == needs_access_check), _tag(tag) {}
|
||||||
|
|
||||||
// Case where we just find the method and don't check access against the current class
|
// Case where we just find the method and don't check access against the current class
|
||||||
LinkInfo(KlassHandle resolved_klass, Symbol*name, Symbol* signature) :
|
LinkInfo(KlassHandle resolved_klass, Symbol*name, Symbol* signature) :
|
||||||
_resolved_klass(resolved_klass),
|
_resolved_klass(resolved_klass),
|
||||||
_name(name), _signature(signature), _current_klass(NULL),
|
_name(name), _signature(signature), _current_klass(NULL), _current_method(NULL),
|
||||||
_check_access(false), _tag(JVM_CONSTANT_Invalid) {}
|
_check_access(false), _tag(JVM_CONSTANT_Invalid) {}
|
||||||
|
|
||||||
// accessors
|
// accessors
|
||||||
|
@ -165,6 +176,7 @@ class LinkInfo : public StackObj {
|
||||||
Symbol* signature() const { return _signature; }
|
Symbol* signature() const { return _signature; }
|
||||||
KlassHandle resolved_klass() const { return _resolved_klass; }
|
KlassHandle resolved_klass() const { return _resolved_klass; }
|
||||||
KlassHandle current_klass() const { return _current_klass; }
|
KlassHandle current_klass() const { return _current_klass; }
|
||||||
|
methodHandle current_method() const { return _current_method; }
|
||||||
constantTag tag() const { return _tag; }
|
constantTag tag() const { return _tag; }
|
||||||
bool check_access() const { return _check_access; }
|
bool check_access() const { return _check_access; }
|
||||||
char* method_string() const;
|
char* method_string() const;
|
||||||
|
@ -266,7 +278,9 @@ class LinkResolver: AllStatic {
|
||||||
|
|
||||||
static void resolve_field_access(fieldDescriptor& result,
|
static void resolve_field_access(fieldDescriptor& result,
|
||||||
const constantPoolHandle& pool,
|
const constantPoolHandle& pool,
|
||||||
int index, Bytecodes::Code byte, TRAPS);
|
int index,
|
||||||
|
const methodHandle& method,
|
||||||
|
Bytecodes::Code byte, TRAPS);
|
||||||
static void resolve_field(fieldDescriptor& result, const LinkInfo& link_info,
|
static void resolve_field(fieldDescriptor& result, const LinkInfo& link_info,
|
||||||
Bytecodes::Code access_kind,
|
Bytecodes::Code access_kind,
|
||||||
bool initialize_class, TRAPS);
|
bool initialize_class, TRAPS);
|
||||||
|
|
|
@ -406,10 +406,45 @@ void Rewriter::scan_method(Method* method, bool reverse, bool* invokespecial_err
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case Bytecodes::_putstatic :
|
||||||
|
case Bytecodes::_putfield : {
|
||||||
|
if (!reverse) {
|
||||||
|
// Check if any final field of the class given as parameter is modified
|
||||||
|
// outside of initializer methods of the class. Fields that are modified
|
||||||
|
// are marked with a flag. For marked fields, the compilers do not perform
|
||||||
|
// constant folding (as the field can be changed after initialization).
|
||||||
|
//
|
||||||
|
// The check is performed after verification and only if verification has
|
||||||
|
// succeeded. Therefore, the class is guaranteed to be well-formed.
|
||||||
|
InstanceKlass* klass = method->method_holder();
|
||||||
|
u2 bc_index = Bytes::get_Java_u2(bcp + prefix_length + 1);
|
||||||
|
constantPoolHandle cp(method->constants());
|
||||||
|
Symbol* field_name = cp->name_ref_at(bc_index);
|
||||||
|
Symbol* field_sig = cp->signature_ref_at(bc_index);
|
||||||
|
Symbol* ref_class_name = cp->klass_name_at(cp->klass_ref_index_at(bc_index));
|
||||||
|
|
||||||
|
if (klass->name() == ref_class_name) {
|
||||||
|
fieldDescriptor fd;
|
||||||
|
klass->find_field(field_name, field_sig, &fd);
|
||||||
|
if (fd.access_flags().is_final()) {
|
||||||
|
if (fd.access_flags().is_static()) {
|
||||||
|
assert(c == Bytecodes::_putstatic, "must be putstatic");
|
||||||
|
if (!method->is_static_initializer()) {
|
||||||
|
fd.set_has_initialized_final_update(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(c == Bytecodes::_putfield, "must be putfield");
|
||||||
|
if (!method->is_object_initializer()) {
|
||||||
|
fd.set_has_initialized_final_update(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fall through
|
||||||
case Bytecodes::_getstatic : // fall through
|
case Bytecodes::_getstatic : // fall through
|
||||||
case Bytecodes::_putstatic : // fall through
|
|
||||||
case Bytecodes::_getfield : // fall through
|
case Bytecodes::_getfield : // fall through
|
||||||
case Bytecodes::_putfield : // fall through
|
|
||||||
case Bytecodes::_invokevirtual : // fall through
|
case Bytecodes::_invokevirtual : // fall through
|
||||||
case Bytecodes::_invokestatic :
|
case Bytecodes::_invokestatic :
|
||||||
case Bytecodes::_invokeinterface:
|
case Bytecodes::_invokeinterface:
|
||||||
|
|
|
@ -621,12 +621,12 @@ C2V_VMENTRY(jint, constantPoolRemapInstructionOperandFromCache, (JNIEnv*, jobjec
|
||||||
return cp->remap_instruction_operand_from_cache(index);
|
return cp->remap_instruction_operand_from_cache(index);
|
||||||
C2V_END
|
C2V_END
|
||||||
|
|
||||||
C2V_VMENTRY(jobject, resolveFieldInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index, jbyte opcode, jlongArray info_handle))
|
C2V_VMENTRY(jobject, resolveFieldInPool, (JNIEnv*, jobject, jobject jvmci_constant_pool, jint index, jobject jvmci_method, jbyte opcode, jlongArray info_handle))
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool);
|
constantPoolHandle cp = CompilerToVM::asConstantPool(jvmci_constant_pool);
|
||||||
Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF);
|
Bytecodes::Code code = (Bytecodes::Code)(((int) opcode) & 0xFF);
|
||||||
fieldDescriptor fd;
|
fieldDescriptor fd;
|
||||||
LinkInfo link_info(cp, index, CHECK_0);
|
LinkInfo link_info(cp, index, (jvmci_method != NULL) ? CompilerToVM::asMethod(jvmci_method) : NULL, CHECK_0);
|
||||||
LinkResolver::resolve_field(fd, link_info, Bytecodes::java_code(code), false, CHECK_0);
|
LinkResolver::resolve_field(fd, link_info, Bytecodes::java_code(code), false, CHECK_0);
|
||||||
typeArrayOop info = (typeArrayOop) JNIHandles::resolve(info_handle);
|
typeArrayOop info = (typeArrayOop) JNIHandles::resolve(info_handle);
|
||||||
assert(info != NULL && info->length() == 2, "must be");
|
assert(info != NULL && info->length() == 2, "must be");
|
||||||
|
@ -1438,7 +1438,7 @@ JNINativeMethod CompilerToVM::methods[] = {
|
||||||
{CC "resolveConstantInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECT, FN_PTR(resolveConstantInPool)},
|
{CC "resolveConstantInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECT, FN_PTR(resolveConstantInPool)},
|
||||||
{CC "resolvePossiblyCachedConstantInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECT, FN_PTR(resolvePossiblyCachedConstantInPool)},
|
{CC "resolvePossiblyCachedConstantInPool", CC "(" HS_CONSTANT_POOL "I)" OBJECT, FN_PTR(resolvePossiblyCachedConstantInPool)},
|
||||||
{CC "resolveTypeInPool", CC "(" HS_CONSTANT_POOL "I)" HS_RESOLVED_KLASS, FN_PTR(resolveTypeInPool)},
|
{CC "resolveTypeInPool", CC "(" HS_CONSTANT_POOL "I)" HS_RESOLVED_KLASS, FN_PTR(resolveTypeInPool)},
|
||||||
{CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL "IB[J)" HS_RESOLVED_KLASS, FN_PTR(resolveFieldInPool)},
|
{CC "resolveFieldInPool", CC "(" HS_CONSTANT_POOL "I" HS_RESOLVED_METHOD "B[J)" HS_RESOLVED_KLASS, FN_PTR(resolveFieldInPool)},
|
||||||
{CC "resolveInvokeDynamicInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeDynamicInPool)},
|
{CC "resolveInvokeDynamicInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeDynamicInPool)},
|
||||||
{CC "resolveInvokeHandleInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeHandleInPool)},
|
{CC "resolveInvokeHandleInPool", CC "(" HS_CONSTANT_POOL "I)V", FN_PTR(resolveInvokeHandleInPool)},
|
||||||
{CC "resolveMethod", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_METHOD HS_RESOLVED_KLASS ")" HS_RESOLVED_METHOD, FN_PTR(resolveMethod)},
|
{CC "resolveMethod", CC "(" HS_RESOLVED_KLASS HS_RESOLVED_METHOD HS_RESOLVED_KLASS ")" HS_RESOLVED_METHOD, FN_PTR(resolveMethod)},
|
||||||
|
|
|
@ -627,7 +627,7 @@ bool Method::is_constant_getter() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Method::is_initializer() const {
|
bool Method::is_initializer() const {
|
||||||
return name() == vmSymbols::object_initializer_name() || is_static_initializer();
|
return is_object_initializer() || is_static_initializer();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Method::has_valid_initializer_flags() const {
|
bool Method::has_valid_initializer_flags() const {
|
||||||
|
@ -643,6 +643,9 @@ bool Method::is_static_initializer() const {
|
||||||
has_valid_initializer_flags();
|
has_valid_initializer_flags();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Method::is_object_initializer() const {
|
||||||
|
return name() == vmSymbols::object_initializer_name();
|
||||||
|
}
|
||||||
|
|
||||||
objArrayHandle Method::resolved_checked_exceptions_impl(Method* method, TRAPS) {
|
objArrayHandle Method::resolved_checked_exceptions_impl(Method* method, TRAPS) {
|
||||||
int length = method->checked_exceptions_length();
|
int length = method->checked_exceptions_length();
|
||||||
|
|
|
@ -638,6 +638,9 @@ class Method : public Metadata {
|
||||||
// valid static initializer flags.
|
// valid static initializer flags.
|
||||||
bool is_static_initializer() const;
|
bool is_static_initializer() const;
|
||||||
|
|
||||||
|
// returns true if the method name is <init>
|
||||||
|
bool is_object_initializer() const;
|
||||||
|
|
||||||
// compiled code support
|
// compiled code support
|
||||||
// NOTE: code() is inherently racy as deopt can be clearing code
|
// NOTE: code() is inherently racy as deopt can be clearing code
|
||||||
// simultaneously. Use with caution.
|
// simultaneously. Use with caution.
|
||||||
|
|
|
@ -109,7 +109,7 @@ void Parse::do_field_access(bool is_get, bool is_field) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(field->will_link(method()->holder(), bc()), "getfield: typeflow responsibility");
|
assert(field->will_link(method(), bc()), "getfield: typeflow responsibility");
|
||||||
|
|
||||||
// Note: We do not check for an unloaded field type here any more.
|
// Note: We do not check for an unloaded field type here any more.
|
||||||
|
|
||||||
|
|
|
@ -106,6 +106,7 @@ class fieldDescriptor VALUE_OBJ_CLASS_SPEC {
|
||||||
bool is_field_access_watched() const { return access_flags().is_field_access_watched(); }
|
bool is_field_access_watched() const { return access_flags().is_field_access_watched(); }
|
||||||
bool is_field_modification_watched() const
|
bool is_field_modification_watched() const
|
||||||
{ return access_flags().is_field_modification_watched(); }
|
{ return access_flags().is_field_modification_watched(); }
|
||||||
|
bool has_initialized_final_update() const { return access_flags().has_field_initialized_final_update(); }
|
||||||
bool has_generic_signature() const { return access_flags().field_has_generic_signature(); }
|
bool has_generic_signature() const { return access_flags().field_has_generic_signature(); }
|
||||||
|
|
||||||
void set_is_field_access_watched(const bool value) {
|
void set_is_field_access_watched(const bool value) {
|
||||||
|
@ -118,6 +119,11 @@ class fieldDescriptor VALUE_OBJ_CLASS_SPEC {
|
||||||
update_klass_field_access_flag();
|
update_klass_field_access_flag();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_has_initialized_final_update(const bool value) {
|
||||||
|
_access_flags.set_has_field_initialized_final_update(value);
|
||||||
|
update_klass_field_access_flag();
|
||||||
|
}
|
||||||
|
|
||||||
// Initialization
|
// Initialization
|
||||||
void reinitialize(InstanceKlass* ik, int index);
|
void reinitialize(InstanceKlass* ik, int index);
|
||||||
|
|
||||||
|
|
|
@ -77,11 +77,12 @@ enum {
|
||||||
// These bits must not conflict with any other field-related access flags
|
// These bits must not conflict with any other field-related access flags
|
||||||
// (e.g., ACC_ENUM).
|
// (e.g., ACC_ENUM).
|
||||||
// Note that the class-related ACC_ANNOTATION bit conflicts with these flags.
|
// Note that the class-related ACC_ANNOTATION bit conflicts with these flags.
|
||||||
JVM_ACC_FIELD_ACCESS_WATCHED = 0x00002000, // field access is watched by JVMTI
|
JVM_ACC_FIELD_ACCESS_WATCHED = 0x00002000, // field access is watched by JVMTI
|
||||||
JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000, // field modification is watched by JVMTI
|
JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000, // field modification is watched by JVMTI
|
||||||
JVM_ACC_FIELD_INTERNAL = 0x00000400, // internal field, same as JVM_ACC_ABSTRACT
|
JVM_ACC_FIELD_INTERNAL = 0x00000400, // internal field, same as JVM_ACC_ABSTRACT
|
||||||
JVM_ACC_FIELD_STABLE = 0x00000020, // @Stable field, same as JVM_ACC_SYNCHRONIZED
|
JVM_ACC_FIELD_STABLE = 0x00000020, // @Stable field, same as JVM_ACC_SYNCHRONIZED and JVM_ACC_SUPER
|
||||||
JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x00000800, // field has generic signature
|
JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE = 0x00000100, // (static) final field updated outside (class) initializer, same as JVM_ACC_NATIVE
|
||||||
|
JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x00000800, // field has generic signature
|
||||||
|
|
||||||
JVM_ACC_FIELD_INTERNAL_FLAGS = JVM_ACC_FIELD_ACCESS_WATCHED |
|
JVM_ACC_FIELD_INTERNAL_FLAGS = JVM_ACC_FIELD_ACCESS_WATCHED |
|
||||||
JVM_ACC_FIELD_MODIFICATION_WATCHED |
|
JVM_ACC_FIELD_MODIFICATION_WATCHED |
|
||||||
|
@ -154,6 +155,8 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC {
|
||||||
bool is_field_access_watched() const { return (_flags & JVM_ACC_FIELD_ACCESS_WATCHED) != 0; }
|
bool is_field_access_watched() const { return (_flags & JVM_ACC_FIELD_ACCESS_WATCHED) != 0; }
|
||||||
bool is_field_modification_watched() const
|
bool is_field_modification_watched() const
|
||||||
{ return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; }
|
{ return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; }
|
||||||
|
bool has_field_initialized_final_update() const
|
||||||
|
{ return (_flags & JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE) != 0; }
|
||||||
bool on_stack() const { return (_flags & JVM_ACC_ON_STACK) != 0; }
|
bool on_stack() const { return (_flags & JVM_ACC_ON_STACK) != 0; }
|
||||||
bool is_internal() const { return (_flags & JVM_ACC_FIELD_INTERNAL) != 0; }
|
bool is_internal() const { return (_flags & JVM_ACC_FIELD_INTERNAL) != 0; }
|
||||||
bool is_stable() const { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
|
bool is_stable() const { return (_flags & JVM_ACC_FIELD_STABLE) != 0; }
|
||||||
|
@ -232,6 +235,15 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC {
|
||||||
atomic_clear_bits(JVM_ACC_FIELD_MODIFICATION_WATCHED);
|
atomic_clear_bits(JVM_ACC_FIELD_MODIFICATION_WATCHED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_has_field_initialized_final_update(const bool value) {
|
||||||
|
if (value) {
|
||||||
|
atomic_set_bits(JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE);
|
||||||
|
} else {
|
||||||
|
atomic_clear_bits(JVM_ACC_FIELD_INITIALIZED_FINAL_UPDATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void set_field_has_generic_signature()
|
void set_field_has_generic_signature()
|
||||||
{
|
{
|
||||||
atomic_set_bits(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE);
|
atomic_set_bits(JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE);
|
||||||
|
|
|
@ -124,8 +124,8 @@ public class CompilerToVMHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static HotSpotResolvedObjectType resolveFieldInPool(
|
public static HotSpotResolvedObjectType resolveFieldInPool(
|
||||||
ConstantPool constantPool, int cpi, byte opcode, long[] info) {
|
ConstantPool constantPool, int cpi, ResolvedJavaMethod method, byte opcode, long[] info) {
|
||||||
return CTVM.resolveFieldInPool((HotSpotConstantPool) constantPool, cpi, opcode, info);
|
return CTVM.resolveFieldInPool((HotSpotConstantPool) constantPool, cpi, (HotSpotResolvedJavaMethodImpl) method, opcode, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int constantPoolRemapInstructionOperandFromCache(
|
public static int constantPoolRemapInstructionOperandFromCache(
|
||||||
|
|
|
@ -27,6 +27,7 @@ package compiler.jvmci.compilerToVM;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
|
import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
|
||||||
|
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||||
import sun.hotspot.WhiteBox;
|
import sun.hotspot.WhiteBox;
|
||||||
import jdk.internal.reflect.ConstantPool;
|
import jdk.internal.reflect.ConstantPool;
|
||||||
import jdk.internal.reflect.ConstantPool.Tag;
|
import jdk.internal.reflect.ConstantPool.Tag;
|
||||||
|
@ -184,13 +185,24 @@ public class ConstantPoolTestCase {
|
||||||
public final String klass;
|
public final String klass;
|
||||||
public final String name;
|
public final String name;
|
||||||
public final String type;
|
public final String type;
|
||||||
|
public final ResolvedJavaMethod[] methods;
|
||||||
public final byte[] opcodes;
|
public final byte[] opcodes;
|
||||||
public final long accFlags;
|
public final long accFlags;
|
||||||
|
|
||||||
public TestedCPEntry(String klass, String name, String type, byte[] opcodes, long accFlags) {
|
public TestedCPEntry(String klass, String name, String type, byte[] opcodes, long accFlags) {
|
||||||
|
this(klass, name, type, null, opcodes, accFlags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TestedCPEntry(String klass, String name, String type, ResolvedJavaMethod[] methods, byte[] opcodes, long accFlags) {
|
||||||
this.klass = klass;
|
this.klass = klass;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.type = type;
|
this.type = type;
|
||||||
|
if (methods != null) {
|
||||||
|
this.methods = new ResolvedJavaMethod[methods.length];
|
||||||
|
System.arraycopy(methods, 0, this.methods, 0, methods.length);
|
||||||
|
} else {
|
||||||
|
this.methods = null;
|
||||||
|
}
|
||||||
if (opcodes != null) {
|
if (opcodes != null) {
|
||||||
this.opcodes = new byte[opcodes.length];
|
this.opcodes = new byte[opcodes.length];
|
||||||
System.arraycopy(opcodes, 0, this.opcodes, 0, opcodes.length);
|
System.arraycopy(opcodes, 0, this.opcodes, 0, opcodes.length);
|
||||||
|
|
|
@ -31,6 +31,10 @@ import static compiler.jvmci.compilerToVM.ConstantPoolTestCase.ConstantTypes.*;
|
||||||
import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry;
|
import compiler.jvmci.compilerToVM.ConstantPoolTestCase.TestedCPEntry;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import jdk.vm.ci.meta.MetaAccessProvider;
|
||||||
|
import jdk.vm.ci.meta.ResolvedJavaMethod;
|
||||||
|
import jdk.vm.ci.meta.ResolvedJavaType;
|
||||||
|
import jdk.vm.ci.runtime.JVMCI;
|
||||||
import jdk.internal.misc.SharedSecrets;
|
import jdk.internal.misc.SharedSecrets;
|
||||||
import jdk.internal.org.objectweb.asm.Opcodes;
|
import jdk.internal.org.objectweb.asm.Opcodes;
|
||||||
import sun.hotspot.WhiteBox;
|
import sun.hotspot.WhiteBox;
|
||||||
|
@ -44,6 +48,7 @@ import jdk.internal.reflect.ConstantPool.Tag;
|
||||||
public class ConstantPoolTestsHelper {
|
public class ConstantPoolTestsHelper {
|
||||||
|
|
||||||
public static final int NO_CP_CACHE_PRESENT = Integer.MAX_VALUE;
|
public static final int NO_CP_CACHE_PRESENT = Integer.MAX_VALUE;
|
||||||
|
private static final MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
|
||||||
|
|
||||||
public enum DummyClasses {
|
public enum DummyClasses {
|
||||||
DUMMY_CLASS(MultipleImplementer2.class, CP_MAP_FOR_CLASS),
|
DUMMY_CLASS(MultipleImplementer2.class, CP_MAP_FOR_CLASS),
|
||||||
|
@ -76,6 +81,45 @@ public class ConstantPoolTestsHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtain a resolved Java method declared by a given type.
|
||||||
|
*
|
||||||
|
* @param type the declaring type
|
||||||
|
* @param the method's name
|
||||||
|
*
|
||||||
|
* Currently, the lookup is based only on the method's name
|
||||||
|
* but not on the method's signature (i.e., the first method
|
||||||
|
* with a matching name declared on {@code type} is returned).
|
||||||
|
*/
|
||||||
|
private static ResolvedJavaMethod getMethod(ResolvedJavaType type, String methodName) {
|
||||||
|
if (methodName.equals("<clinit>")) {
|
||||||
|
return type.getClassInitializer();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (methodName.equals("<init>")) {
|
||||||
|
ResolvedJavaMethod[] initializers = type.getDeclaredConstructors();
|
||||||
|
if (initializers.length >= 0) {
|
||||||
|
return initializers[0];
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ResolvedJavaMethod method : type.getDeclaredMethods()) {
|
||||||
|
if (method.getName().equals(methodName)) {
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ResolvedJavaType getType(Class<?> clazz) {
|
||||||
|
ResolvedJavaType type = metaAccess.lookupJavaType(clazz);
|
||||||
|
type.initialize();
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
private static final Map<ConstantTypes, TestedCPEntry[]> CP_MAP_FOR_CLASS = new HashMap<>();
|
private static final Map<ConstantTypes, TestedCPEntry[]> CP_MAP_FOR_CLASS = new HashMap<>();
|
||||||
static {
|
static {
|
||||||
CP_MAP_FOR_CLASS.put(CONSTANT_CLASS,
|
CP_MAP_FOR_CLASS.put(CONSTANT_CLASS,
|
||||||
|
@ -141,6 +185,7 @@ public class ConstantPoolTestsHelper {
|
||||||
new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2",
|
new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2",
|
||||||
"objectField",
|
"objectField",
|
||||||
"Ljava/lang/Object;",
|
"Ljava/lang/Object;",
|
||||||
|
new ResolvedJavaMethod[] { getMethod(getType(MultipleImplementer2.class), "<init>"), null },
|
||||||
new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD},
|
new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD},
|
||||||
Opcodes.ACC_FINAL),
|
Opcodes.ACC_FINAL),
|
||||||
new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2",
|
new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementer2",
|
||||||
|
@ -296,6 +341,7 @@ public class ConstantPoolTestsHelper {
|
||||||
new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer",
|
new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer",
|
||||||
"objectField",
|
"objectField",
|
||||||
"Ljava/lang/Object;",
|
"Ljava/lang/Object;",
|
||||||
|
new ResolvedJavaMethod[] { getMethod(getType(MultipleAbstractImplementer.class), "<init>"), null },
|
||||||
new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD},
|
new byte[] {(byte) Opcodes.PUTFIELD | (byte) Opcodes.GETFIELD},
|
||||||
Opcodes.ACC_FINAL),
|
Opcodes.ACC_FINAL),
|
||||||
new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer",
|
new TestedCPEntry("compiler/jvmci/common/testcases/MultipleAbstractImplementer",
|
||||||
|
@ -401,6 +447,7 @@ public class ConstantPoolTestsHelper {
|
||||||
new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface",
|
new TestedCPEntry("compiler/jvmci/common/testcases/MultipleImplementersInterface",
|
||||||
"OBJECT_CONSTANT",
|
"OBJECT_CONSTANT",
|
||||||
"Ljava/lang/Object;",
|
"Ljava/lang/Object;",
|
||||||
|
new ResolvedJavaMethod[] { getMethod(getType(MultipleImplementersInterface.class), "<clinit>"), null },
|
||||||
new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC},
|
new byte[] {(byte) Opcodes.PUTSTATIC, (byte) Opcodes.GETSTATIC},
|
||||||
Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_PUBLIC),
|
Opcodes.ACC_STATIC | Opcodes.ACC_FINAL | Opcodes.ACC_PUBLIC),
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
* java.base/jdk.internal.org.objectweb.asm
|
* java.base/jdk.internal.org.objectweb.asm
|
||||||
* java.base/jdk.internal.org.objectweb.asm.tree
|
* java.base/jdk.internal.org.objectweb.asm.tree
|
||||||
* jdk.vm.ci/jdk.vm.ci.hotspot
|
* jdk.vm.ci/jdk.vm.ci.hotspot
|
||||||
|
* jdk.vm.ci/jdk.vm.ci.runtime
|
||||||
* jdk.vm.ci/jdk.vm.ci.meta
|
* jdk.vm.ci/jdk.vm.ci.meta
|
||||||
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
||||||
* @build sun.hotspot.WhiteBox
|
* @build sun.hotspot.WhiteBox
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
* java.base/jdk.internal.org.objectweb.asm
|
* java.base/jdk.internal.org.objectweb.asm
|
||||||
* java.base/jdk.internal.org.objectweb.asm.tree
|
* java.base/jdk.internal.org.objectweb.asm.tree
|
||||||
* jdk.vm.ci/jdk.vm.ci.hotspot
|
* jdk.vm.ci/jdk.vm.ci.hotspot
|
||||||
|
* jdk.vm.ci/jdk.vm.ci.runtime
|
||||||
* jdk.vm.ci/jdk.vm.ci.meta
|
* jdk.vm.ci/jdk.vm.ci.meta
|
||||||
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
||||||
* @build sun.hotspot.WhiteBox
|
* @build sun.hotspot.WhiteBox
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
* java.base/jdk.internal.org.objectweb.asm.tree
|
* java.base/jdk.internal.org.objectweb.asm.tree
|
||||||
* jdk.vm.ci/jdk.vm.ci.hotspot
|
* jdk.vm.ci/jdk.vm.ci.hotspot
|
||||||
* jdk.vm.ci/jdk.vm.ci.meta
|
* jdk.vm.ci/jdk.vm.ci.meta
|
||||||
|
* jdk.vm.ci/jdk.vm.ci.runtime
|
||||||
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
||||||
* @build sun.hotspot.WhiteBox
|
* @build sun.hotspot.WhiteBox
|
||||||
* compiler.jvmci.compilerToVM.LookupMethodInPoolTest
|
* compiler.jvmci.compilerToVM.LookupMethodInPoolTest
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
* java.base/jdk.internal.org.objectweb.asm
|
* java.base/jdk.internal.org.objectweb.asm
|
||||||
* java.base/jdk.internal.org.objectweb.asm.tree
|
* java.base/jdk.internal.org.objectweb.asm.tree
|
||||||
* jdk.vm.ci/jdk.vm.ci.hotspot
|
* jdk.vm.ci/jdk.vm.ci.hotspot
|
||||||
|
* jdk.vm.ci/jdk.vm.ci.runtime
|
||||||
* jdk.vm.ci/jdk.vm.ci.meta
|
* jdk.vm.ci/jdk.vm.ci.meta
|
||||||
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
||||||
* @build sun.hotspot.WhiteBox
|
* @build sun.hotspot.WhiteBox
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
* java.base/jdk.internal.org.objectweb.asm
|
* java.base/jdk.internal.org.objectweb.asm
|
||||||
* java.base/jdk.internal.org.objectweb.asm.tree
|
* java.base/jdk.internal.org.objectweb.asm.tree
|
||||||
* jdk.vm.ci/jdk.vm.ci.hotspot
|
* jdk.vm.ci/jdk.vm.ci.hotspot
|
||||||
|
* jdk.vm.ci/jdk.vm.ci.runtime
|
||||||
* jdk.vm.ci/jdk.vm.ci.meta
|
* jdk.vm.ci/jdk.vm.ci.meta
|
||||||
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
||||||
* @build sun.hotspot.WhiteBox
|
* @build sun.hotspot.WhiteBox
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
* java.base/jdk.internal.org.objectweb.asm
|
* java.base/jdk.internal.org.objectweb.asm
|
||||||
* java.base/jdk.internal.org.objectweb.asm.tree
|
* java.base/jdk.internal.org.objectweb.asm.tree
|
||||||
* jdk.vm.ci/jdk.vm.ci.hotspot
|
* jdk.vm.ci/jdk.vm.ci.hotspot
|
||||||
|
* jdk.vm.ci/jdk.vm.ci.runtime
|
||||||
* jdk.vm.ci/jdk.vm.ci.meta
|
* jdk.vm.ci/jdk.vm.ci.meta
|
||||||
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
||||||
* @build sun.hotspot.WhiteBox
|
* @build sun.hotspot.WhiteBox
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
* java.base/jdk.internal.reflect
|
* java.base/jdk.internal.reflect
|
||||||
* java.base/jdk.internal.org.objectweb.asm
|
* java.base/jdk.internal.org.objectweb.asm
|
||||||
* jdk.vm.ci/jdk.vm.ci.hotspot
|
* jdk.vm.ci/jdk.vm.ci.hotspot
|
||||||
|
* jdk.vm.ci/jdk.vm.ci.runtime
|
||||||
* jdk.vm.ci/jdk.vm.ci.meta
|
* jdk.vm.ci/jdk.vm.ci.meta
|
||||||
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
||||||
* @build sun.hotspot.WhiteBox
|
* @build sun.hotspot.WhiteBox
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
* java.base/jdk.internal.org.objectweb.asm.tree
|
* java.base/jdk.internal.org.objectweb.asm.tree
|
||||||
* jdk.vm.ci/jdk.vm.ci.hotspot
|
* jdk.vm.ci/jdk.vm.ci.hotspot
|
||||||
* jdk.vm.ci/jdk.vm.ci.meta
|
* jdk.vm.ci/jdk.vm.ci.meta
|
||||||
|
* jdk.vm.ci/jdk.vm.ci.runtime
|
||||||
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
||||||
* @build sun.hotspot.WhiteBox
|
* @build sun.hotspot.WhiteBox
|
||||||
* compiler.jvmci.compilerToVM.ResolveFieldInPoolTest
|
* compiler.jvmci.compilerToVM.ResolveFieldInPoolTest
|
||||||
|
@ -107,6 +108,7 @@ public class ResolveFieldInPoolTest {
|
||||||
HotSpotResolvedObjectType fieldToVerify
|
HotSpotResolvedObjectType fieldToVerify
|
||||||
= CompilerToVMHelper.resolveFieldInPool(constantPoolCTVM,
|
= CompilerToVMHelper.resolveFieldInPool(constantPoolCTVM,
|
||||||
index,
|
index,
|
||||||
|
entry.methods == null ? null : entry.methods[j],
|
||||||
entry.opcodes[j],
|
entry.opcodes[j],
|
||||||
info);
|
info);
|
||||||
String msg = String.format("Object returned by resolveFieldInPool method"
|
String msg = String.format("Object returned by resolveFieldInPool method"
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
* java.base/jdk.internal.org.objectweb.asm
|
* java.base/jdk.internal.org.objectweb.asm
|
||||||
* java.base/jdk.internal.org.objectweb.asm.tree
|
* java.base/jdk.internal.org.objectweb.asm.tree
|
||||||
* jdk.vm.ci/jdk.vm.ci.hotspot
|
* jdk.vm.ci/jdk.vm.ci.hotspot
|
||||||
|
* jdk.vm.ci/jdk.vm.ci.runtime
|
||||||
* jdk.vm.ci/jdk.vm.ci.meta
|
* jdk.vm.ci/jdk.vm.ci.meta
|
||||||
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
||||||
* @build sun.hotspot.WhiteBox
|
* @build sun.hotspot.WhiteBox
|
||||||
|
|
|
@ -33,6 +33,7 @@
|
||||||
* java.base/jdk.internal.reflect
|
* java.base/jdk.internal.reflect
|
||||||
* java.base/jdk.internal.org.objectweb.asm
|
* java.base/jdk.internal.org.objectweb.asm
|
||||||
* jdk.vm.ci/jdk.vm.ci.hotspot
|
* jdk.vm.ci/jdk.vm.ci.hotspot
|
||||||
|
* jdk.vm.ci/jdk.vm.ci.runtime
|
||||||
* jdk.vm.ci/jdk.vm.ci.meta
|
* jdk.vm.ci/jdk.vm.ci.meta
|
||||||
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
* @build jdk.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper
|
||||||
* @build sun.hotspot.WhiteBox
|
* @build sun.hotspot.WhiteBox
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue