< prev index next > src/hotspot/share/interpreter/linkResolver.cpp
Print this page
const LinkInfo& link_info,
Bytecodes::Code byte, bool initialize_class,
TRAPS) {
assert(byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic ||
byte == Bytecodes::_getfield || byte == Bytecodes::_putfield ||
+ byte == Bytecodes::_withfield ||
byte == Bytecodes::_nofast_getfield || byte == Bytecodes::_nofast_putfield ||
(byte == Bytecodes::_nop && !link_info.check_access()), "bad field access bytecode");
bool is_static = (byte == Bytecodes::_getstatic || byte == Bytecodes::_putstatic);
- bool is_put = (byte == Bytecodes::_putfield || byte == Bytecodes::_putstatic || byte == Bytecodes::_nofast_putfield);
+ bool is_put = (byte == Bytecodes::_putfield || byte == Bytecodes::_putstatic ||
+ byte == Bytecodes::_nofast_putfield || byte == Bytecodes::_withfield);
// Check if there's a resolved klass containing the field
Klass* resolved_klass = link_info.resolved_klass();
Symbol* field = link_info.name();
Symbol* sig = link_info.signature();
+
+ if (byte == Bytecodes::_withfield && !resolved_klass->is_inline_klass()) {
+ ResourceMark rm(THREAD);
+ char msg[200];
+ jio_snprintf(msg, sizeof(msg), "Bytecode withfield cannot be used on identity class %s", resolved_klass->external_name());
+ THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), msg);
+ }
+
+ if (is_put && !is_static && byte != Bytecodes::_withfield && resolved_klass->is_inline_klass()) {
+ ResourceMark rm(THREAD);
+ char msg[200];
+ jio_snprintf(msg, sizeof(msg), "Bytecode putfield cannot be used on primitive class %s", resolved_klass->external_name());
+ THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), msg);
+ }
+
// Resolve instance field
Klass* sel_klass = resolved_klass->find_field(field, sig, &fd);
// check if field exists; i.e., if a klass containing the field def has been selected
if (sel_klass == nullptr) {
ResourceMark rm(THREAD);
// A final field can be modified only
// (1) by methods declared in the class declaring the field and
// (2) by the <clinit> method (in case of a static field)
// or by the <init> method (in case of an instance field).
+ // (3) by withfield when field is in a value type and the
+ // selected class and current class are nest mates.
if (is_put && fd.access_flags().is_final()) {
if (sel_klass != current_klass) {
- ResourceMark rm(THREAD);
- stringStream ss;
- 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 byte code is a withfield check if they are nestmates.
+ bool are_nestmates = false;
+ if (sel_klass->is_instance_klass() &&
+ InstanceKlass::cast(sel_klass)->is_inline_klass() &&
+ current_klass->is_instance_klass()) {
+ are_nestmates = InstanceKlass::cast(current_klass)->has_nestmate_access_to(InstanceKlass::cast(sel_klass), THREAD);
+ }
+ if (!are_nestmates) {
+ ResourceMark rm(THREAD);
+ stringStream ss;
+ 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) {
Method* m = link_info.current_method();
assert(m != nullptr, "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());
+ !m->is_class_initializer());
bool is_initialized_instance_final_update = ((byte == Bytecodes::_putfield || byte == Bytecodes::_nofast_putfield) &&
!fd.is_static() &&
- !m->is_object_initializer());
+ !m->is_object_constructor());
if (is_initialized_static_final_update || is_initialized_instance_final_update) {
ResourceMark rm(THREAD);
stringStream ss;
ss.print("Update to %s final field %s.%s attempted from a different method (%s) than the initializer method %s ",
} else {
resolved_method = resolve_interface_method(link_info, Bytecodes::_invokespecial, CHECK_NULL);
}
// check if method name is <init>, that it is found in same klass as static type
+ // Since this method is never inherited from a super, any appearance here under
+ // the wrong class would be an error.
if (resolved_method->name() == vmSymbols::object_initializer_name() &&
resolved_method->method_holder() != resolved_klass) {
ResourceMark rm(THREAD);
stringStream ss;
ss.print("%s: method '", resolved_klass->external_name());
// Invokespecial for a superinterface, resolved method is selected method,
// no checks for shadowing
methodHandle sel_method(THREAD, resolved_method());
if (link_info.check_access() &&
- // check if the method is not <init>
+ // check if the method is not <init>, which is never inherited
resolved_method->name() != vmSymbols::object_initializer_name()) {
Klass* current_klass = link_info.current_klass();
// Check if the class of the resolved_klass is a superclass
}
return;
}
void LinkResolver::resolve_invoke(CallInfo& result, Handle& recv,
- const methodHandle& attached_method,
- Bytecodes::Code byte, TRAPS) {
+ const methodHandle& attached_method,
+ Bytecodes::Code byte, bool check_null_and_abstract, TRAPS) {
Klass* defc = attached_method->method_holder();
Symbol* name = attached_method->name();
Symbol* type = attached_method->signature();
LinkInfo link_info(defc, name, type);
+ Klass* recv_klass = recv.is_null() ? defc : recv->klass();
switch(byte) {
case Bytecodes::_invokevirtual:
- resolve_virtual_call(result, recv, recv->klass(), link_info,
- /*check_null_and_abstract=*/true, CHECK);
+ resolve_virtual_call(result, recv, recv_klass, link_info,
+ check_null_and_abstract, CHECK);
break;
case Bytecodes::_invokeinterface:
- resolve_interface_call(result, recv, recv->klass(), link_info,
- /*check_null_and_abstract=*/true, CHECK);
+ resolve_interface_call(result, recv, recv_klass, link_info,
+ check_null_and_abstract, CHECK);
break;
case Bytecodes::_invokestatic:
resolve_static_call(result, link_info, /*initialize_class=*/false, CHECK);
break;
case Bytecodes::_invokespecial:
< prev index next >