--- old/src/share/vm/interpreter/linkResolver.cpp 2016-06-02 12:26:07.458263845 +0200 +++ new/src/share/vm/interpreter/linkResolver.cpp 2016-06-02 12:26:07.102263856 +0200 @@ -223,7 +223,7 @@ //------------------------------------------------------------------------------------------------------------------------ // Implementation of LinkInfo -LinkInfo::LinkInfo(const constantPoolHandle& pool, int index, TRAPS) { +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); @@ -232,6 +232,7 @@ _name = pool->name_ref_at(index); _signature = pool->signature_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; @@ -572,11 +573,11 @@ Symbol* method_name = vmSymbols::invoke_name(); Symbol* method_signature = pool->signature_ref_at(index); KlassHandle current_klass(THREAD, pool->pool_holder()); - LinkInfo link_info(resolved_klass, method_name, method_signature, current_klass); + LinkInfo link_info(resolved_klass, method_name, method_signature, current_klass, NULL); return resolve_method(link_info, /*require_methodref*/false, THREAD); } - LinkInfo link_info(pool, index, CHECK_NULL); + LinkInfo link_info(pool, index, NULL, CHECK_NULL); resolved_klass = link_info.resolved_klass(); if (pool->has_preresolution() @@ -857,8 +858,8 @@ } } -void LinkResolver::resolve_field_access(fieldDescriptor& fd, const constantPoolHandle& pool, int index, Bytecodes::Code byte, TRAPS) { - LinkInfo link_info(pool, index, CHECK); +void LinkResolver::resolve_field_access(fieldDescriptor& fd, const constantPoolHandle& pool, int index, const methodHandle& method, Bytecodes::Code byte, TRAPS) { + LinkInfo link_info(pool, index, method, CHECK); resolve_field(fd, link_info, byte, true, CHECK); } @@ -907,9 +908,20 @@ THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), msg); } - // Final fields can only be accessed from its own class. - if (is_put && fd.access_flags().is_final() && sel_klass() != current_klass()) { - THROW(vmSymbols::java_lang_IllegalAccessError()); + // A final field can be modified only + // (1) by methods declared in the class declaring the field and + // (2) by the method (in case of a static field) + // or by the method (in case of an instance field). + if (is_put && fd.access_flags().is_final()) { + methodHandle m = link_info.current_method(); + assert(!m.is_null(), "information about the current method must be available for 'put' bytecodes"); + Symbol* method_name = m->name(); + if (sel_klass() != current_klass() || + (byte == Bytecodes::_putstatic && fd.is_static() && method_name != vmSymbols::class_initializer_name()) || + ((byte == Bytecodes::_putfield || byte == Bytecodes::_nofast_putfield) && !fd.is_static() && method_name != vmSymbols::object_initializer_name()) + ) { + THROW(vmSymbols::java_lang_IllegalAccessError()); + } } // initialize resolved_klass if necessary @@ -956,7 +968,7 @@ resolved_klass->initialize(CHECK); // Use updated LinkInfo (to reresolve with resolved_klass as method_holder?) LinkInfo new_info(resolved_klass, link_info.name(), link_info.signature(), - link_info.current_klass(), link_info.check_access()); + link_info.current_klass(), NULL, link_info.check_access()); resolved_method = linktime_resolve_static_method(new_info, CHECK); } @@ -1482,7 +1494,7 @@ KlassHandle defc = attached_method->method_holder(); Symbol* name = attached_method->name(); Symbol* type = attached_method->signature(); - LinkInfo link_info(defc, name, type, KlassHandle(), /*check_access=*/false); + LinkInfo link_info(defc, name, type, KlassHandle(), NULL, /*check_access=*/false); switch(byte) { case Bytecodes::_invokevirtual: resolve_virtual_call(result, recv, recv->klass(), link_info, @@ -1504,13 +1516,13 @@ } void LinkResolver::resolve_invokestatic(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) { - LinkInfo link_info(pool, index, CHECK); + LinkInfo link_info(pool, index, NULL, CHECK); resolve_static_call(result, link_info, /*initialize_class*/true, CHECK); } void LinkResolver::resolve_invokespecial(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) { - LinkInfo link_info(pool, index, CHECK); + LinkInfo link_info(pool, index, NULL, CHECK); resolve_special_call(result, link_info, CHECK); } @@ -1519,14 +1531,14 @@ const constantPoolHandle& pool, int index, TRAPS) { - LinkInfo link_info(pool, index, CHECK); + LinkInfo link_info(pool, index, NULL, CHECK); KlassHandle recvrKlass (THREAD, recv.is_null() ? (Klass*)NULL : recv->klass()); resolve_virtual_call(result, recv, recvrKlass, link_info, /*check_null_or_abstract*/true, CHECK); } void LinkResolver::resolve_invokeinterface(CallInfo& result, Handle recv, const constantPoolHandle& pool, int index, TRAPS) { - LinkInfo link_info(pool, index, CHECK); + LinkInfo link_info(pool, index, NULL, CHECK); KlassHandle recvrKlass (THREAD, recv.is_null() ? (Klass*)NULL : recv->klass()); resolve_interface_call(result, recv, recvrKlass, link_info, true, CHECK); } @@ -1534,7 +1546,7 @@ void LinkResolver::resolve_invokehandle(CallInfo& result, const constantPoolHandle& pool, int index, TRAPS) { // This guy is reached from InterpreterRuntime::resolve_invokehandle. - LinkInfo link_info(pool, index, CHECK); + LinkInfo link_info(pool, index, NULL, CHECK); if (TraceMethodHandles) { ResourceMark rm(THREAD); tty->print_cr("resolve_invokehandle %s %s", link_info.name()->as_C_string(),