< prev index next >

src/hotspot/share/interpreter/linkResolver.cpp

Print this page

        

@@ -943,15 +943,17 @@
                                  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();
 

@@ -985,30 +987,42 @@
 
     // 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()) {
       ResourceMark rm(THREAD);
       stringStream ss;
 
       if (sel_klass != current_klass) {
+      // 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_value() &&
+          current_klass->is_instance_klass()) {
+        are_nestmates = InstanceKlass::cast(link_info.current_klass())->has_nestmate_access_to(
+                                                        InstanceKlass::cast(sel_klass), THREAD);
+      }
+      if (!are_nestmates) {
         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());
+                  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());
+                                                   !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) {
           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(),
                    m()->name()->as_C_string(),

@@ -1122,10 +1136,12 @@
   } 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());

@@ -1195,11 +1211,11 @@
   // 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
< prev index next >