--- old/src/share/vm/interpreter/linkResolver.cpp 2016-06-10 16:47:23.056893795 +0200 +++ new/src/share/vm/interpreter/linkResolver.cpp 2016-06-10 16:47:22.700893785 +0200 @@ -223,6 +223,22 @@ //------------------------------------------------------------------------------------------------------------------------ // 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) { // resolve klass Klass* result = pool->klass_ref_at(index, CHECK); @@ -233,6 +249,7 @@ _signature = pool->signature_ref_at(index); _tag = pool->tag_ref_at(index); _current_klass = KlassHandle(THREAD, pool->pool_holder()); + _current_method = methodHandle(); // Coming from the constant pool always checks access _check_access = true; @@ -577,7 +594,7 @@ 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(); if (pool->has_preresolution() @@ -875,8 +892,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); } @@ -925,9 +942,40 @@ 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()) { + 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 (CheckFinalFieldModifications && + 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 ? "" : ""); + THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), ss.as_string()); + } + } } // initialize resolved_klass if necessary