[9] RFR (S): 8157181: Compilers accept modification of final fields outside initializer methods
Vladimir Ivanov
vladimir.x.ivanov at oracle.com
Fri Jun 10 12:56:53 UTC 2016
http://cr.openjdk.java.net/~zmajo/8157181/webrev.08
I'm fine with enabling the checks only for 9 for now and handle 7 & 8
class files separately.
>> src/share/vm/classfile/verifier.cpp:
>>
>> + void
>> Verifier::detect_invalid_final_field_accesses(instanceKlassHandle
>> klass) {
>>
>> The name is misleading: such accesses are legal according to JVMS-6
>> (and earlier). Maybe something like
>> detect_initialized_final_field_updates?
>>
>> Same for:
>> + bool has_invalid_final_access() const { return
>> access_flags().has_field_invalid_final_access(); }
>> + void set_has_invalid_final_access(const bool value) {
>> + JVM_ACC_FIELD_INVALID_FINAL_ACCESS = 0x00000100,
>>
>
> Yes, that name sounds better and I've updated the code accordingly.
A leftover:
src/share/vm/runtime/fieldDescriptor.hpp:
+ void set_has_invalid_final_access(const bool value) {
>> ---
>> I don't see much benefit in tracking the problematic updates
>> per-methods and not per-class. So, you could do the checks in
>> ClassVerifier::verify_field_instructions [1] and mark the whole class
>> (ClassVerifier::_klass) as containing problematic instructions.
>
> The problematic updates are tracked *per-field* (and not *per-method* or
> * per-class*).
>
> Initially, I had a version that tracked problematic instructions on a
> per-class basis. With that version, once a problematic instruction was
> detected, the whole class was marked as containing problematic
> instructions. As a result, constant folding was disabled for accesses to
> *all* final fields of that class.
>
> Tracking problematic updates on a per-field basis seems to be less
> intrusive. That way we disable folding *only for fields to which
> problematic accesses are made* (and leave constant folding enabled for
> accesses to all other fields). So we can fold some accesses even for
> "misbehaving" classes. I hope that is fine.
>
> Regarding doing checks in verify_field_instructions() [2]: It turns out
> that we have two verifiers, one that is called for
>
> major_version >= STACKMAP_ATTRIBUTE_MAJOR_VERSION
>
> and a second one that is called for
>
> major_version < STACKMAP_ATTRIBUTE_MAJOR_VERSION.
>
> ClassVerifier::verify_field_instructions() is called only for class
> files >= STACKMAP_ATTRIBUTE_MAJOR_VERSION so we need to call
> detect_initialized_final_field_updates() after verification.
>
> But I think it is a good idea to move the check to the linkage phase (as
> you've suggested above).
While browsing the code, I got another idea: what about piggybacking on
Rewriter pass (see Rewriter::scan_method)? It already sets some
per-method properties (e.g., Method::has_monitor_bytecodes()).
I'd like to avoid additional pass over the bytecode, because it can
cause slow downs during class loading (just a precaution - I haven't
measured the impact).
>> ---
>> src/share/vm/interpreter/linkResolver.cpp:
>>
>> THROW(vmSymbols::java_lang_IllegalAccessError());
>>
>> + THROW(vmSymbols::java_lang_IllegalAccessError());
>>
>> Please, add an error message for diagnostic purposes.
>
> OK, I did that.
src/share/vm/interpreter/linkResolver.cpp:
+ if (is_put && fd.access_flags().is_final()) {
+ ResourceMark rm(THREAD);
+ char msg[200];
There's much more convenient way now - stringStream. It takes care of
memory management in resource area for you and provides convenient
utility functions:
ResourceMark rm(THREAD);
stringStream ss;
ss.printf("...", ...);
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), ss.as_string());
---
+ if ((byte == Bytecodes::_putstatic && fd.is_static() &&
!m()->is_static_initializer()) ||
+ ((byte == Bytecodes::_putfield || byte ==
Bytecodes::_nofast_putfield) && !fd.is_static() &&
!m->is_object_initializer())) {
Maybe refactor it to make more readable?
bool is_static_final_update = ...;
bool is_instance_final_update = ...;
if (is_static_final_update || is_instance_final_update) {
...
Otherwise, looks good.
Best regards,
Vladimir Ivanov
More information about the hotspot-compiler-dev
mailing list