答复: 答复: 答复: HotSpot and IBM's J9 behave quite differently when processing monitorenters and monitorexits
陈雨亭
chenyt at cs.sjtu.edu.cn
Thu May 18 06:02:44 UTC 2017
I agree. There may be a typo when an exception needs to be thrown,:)
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.monitorenter
Yuting
-----邮件原件-----
发件人: David Holmes [mailto:david.holmes at oracle.com]
发送时间: 2017年5月17日 22:29
收件人: chenyt <chenyt at cs.sjtu.edu.cn>
抄送: hotspot-runtime-dev at openjdk.java.net
主题: Re: 答复: 答复: HotSpot and IBM's J9 behave quite differently when processing monitorenters and monitorexits
Is this any different from what you previously reported??
Sorry I'm having a hard time tracking the scenarios. As far as I can tell there are two cases:
- new'd but uninitialized objectref
This should be a verification error in which case runtime behaviour is unspecified.
- null reference
This should throw NullPointerException, and as per last email the interpreter explicitly has a null check, so I don't know why this wouldn't throw.
David
On 18/05/2017 3:15 PM, chenyt wrote:
> Hi, David,
>
> I tested the next Jimple programs (let one object under monitoring be
> null) using J9 and HotSpot. I did not see NullPointerException here
> (the specification does tell me so). Am I wrong again? Hope the next
> two cases will help check.
>
> (1) case 1: HotSpot: IllegalMonitorStateException J9: NullPointerException
> r0 := @this: Search;
> r1 := @parameter0: java.lang.String[];
> r2 = null;
> entermonitor r0;
> entermonitor r2;
> exitmonitor r2;
> exitmonitor r0;
> (2) case 2: HotSpot: IllegalMonitorStateException J9: VerifyError
> r1 := @parameter0: java.lang.String[];
> r2 = new Search;
> entermonitor r0;
> entermonitor r2;
> r2=null;
> exitmonitor r2;
> exitmonitor r0;
> It is very interesting that I can still find some unexpected behaviors
> here.
>
> Wishes,
> Yuting
>
>
> On Thu, 18 May 2017 14:57:03 +1000, David Holmes wrote:
>> On 18/05/2017 2:18 PM, 陈雨亭 wrote:
>>> Hi, David,
>>>
>>> I still did not catch why it happens... I just read the
>>> specification and wrote some tests in order to understand some
>>> paragraphs better, and then had questions.
>>>
>>> Will the HotSpot's verifier detect such kind of uninitialized
>>> monitored objects in future?
>>
>> I have filed a bug so this can be examined more closely.
>>
>> https://bugs.openjdk.java.net/browse/JDK-8180581
>>
>> Thanks,
>> David
>>
>>> Regards,
>>> Yuting
>>>
>>> -----邮件原件-----
>>> 发件人: David Holmes [mailto:david.holmes at oracle.com]
>>> 发送时间: 2017年5月17日 20:23
>>> 收件人: 陈雨亭 <chenyt at cs.sjtu.edu.cn>;
>>> hotspot-runtime-dev at openjdk.java.net
>>> 主题: Re: 答复: HotSpot and IBM's J9 behave quite differently when
>>> processing monitorenters and monitorexits
>>>
>>> One correction ...
>>>
>>> On 18/05/2017 10:29 AM, David Holmes wrote:
>>>> On 18/05/2017 8:12 AM, 陈雨亭 wrote:
>>>>> Thank you, David. I have seen from the specification that
>>>>> structured locking enforcement is optional. The second and the
>>>>> third ones are cases of structured/nested lockings. Will
>>>>> non-nested locking sequences raise deadlocks? Of course it is a
>>>>> different topic, while it might be better if it can be kicked out
>>>>> earlier from the specification/JVM.
>>>>
>>>> Non-nested locking doesn't necessarily lead to deadlocks - you just
>>>> need a different locking order for that (even if properly nested).
>>>> There are locking patterns that rely on the ability to lock and
>>>> unlock in different order ie chained-locking for walking
>>>> linked-lists
>>>> A->B->C->D:
>>>> - lock A, lock B, unlock A, lock C, unlock B, lock D, unlock C ...
>>>>
>>>> The VM spec allows a little flexibility in how the monitor
>>>> bytecodes can be used compared to the Java programming language.
>>>> That's not something that will change.
>>>>
>>>>> The first example is still a problem. It seems that HotSpot allows
>>>>> to monitor a pure object reference without initialized (Is it
>>>>> true? How can this checking be omitted?). J9 reports a verifyerror as follows.
>>>>>
>>>>> Exception in thread "main" java.lang.VerifyError: JVMVRFY012 stack
>>>>> shape inconsistent; class=Search,
>>>>> method=main([Ljava/lang/String;)V,
>>>>> pc=6 Exception Details:
>>>>> Location:
>>>>> Search.main([Ljava/lang/String;)V @6: JBmonitorenter
>>>>> Reason:
>>>>> Type 'uninitialized' (current frame, stack[1]) is not
>>>>> assignable to 'java/lang/Object'
>>>>> Current Frame:
>>>>> bci: @6
>>>>> flags: { }
>>>>> locals: { 'Search', '[Ljava/lang/String;' }
>>>>> stack: { 'uninitialized', 'uninitialized' }
>>>>> at T.main(T.java:4)
>>>>
>>>> Yes I think this may be a bug in hotspot. The type-checking for the
>>>> monitor bytecodes requires a matching type of reference on the
>>>> operand stack - but "uninitialized" does not match Object, as J9
>>>> reports. But I'm not an expert on this aspect of verification so I
>>>> may not be interpreting it correctly.
>>>>
>>>> More below ...
>>>>
>>>>> -----邮件原件-----
>>>>> 发件人: David Holmes [mailto:david.holmes at oracle.com]
>>>>> 发送时间: 2017年5月17日 14:41
>>>>> 收件人: 陈雨亭 <chenyt at cs.sjtu.edu.cn>;
>>>>> hotspot-runtime-dev at openjdk.java.net
>>>>> 主题: Re: HotSpot and IBM's J9 behave quite differently when
>>>>> processing monitorenters and monitorexits
>>>>>
>>>>> Hi,
>>>>> On 18/05/2017 7:23 AM, 陈雨亭 wrote:
>>>>>> Am I wrong?
>>>>>
>>>>> I will look at each situation in detail when I get a chance but
>>>>> structured locking enforcement is optional. Also balancing the
>>>>> number of locks and unlocks in a frame does not mean they can't be
>>>>> locked and unlocked in a non-nested fashion - just that by the end
>>>>> the number of unlocks matches the number of locks.
>>>>>
>>>>> BTW the way you respond to these emails, as if having a
>>>>> conversation with yourself, makes it difficult to respond as we
>>>>> can't readily see what is the new email and what is the original.
>>>>>
>>>>> Cheers,
>>>>> David
>>>>>
>>>>>> The byte code for main() in case 1 is as follows. The strange
>>>>>> thing is that NullPointerException is also not thrown at runtime.
>>>>
>>>> That is strange as it does for the normal obvious case of using
>>>> synchronized(o) when o is null.
>>>
>>> Ah - it isn't null it just an object for which the constructor has
>>> not been run. The runtime can't tell the difference between a
>>> pointer to a valid initialized object, and a pointer to an
>>> uninitialized chunk of memory.
>>>
>>>>>>
>>>>>> public void main(java.lang.String[]) throws java.lang.Exception;
>>>>>> descriptor: ([Ljava/lang/String;)V
>>>>>> flags: ACC_PUBLIC
>>>>>> Code:
>>>>>> stack=3, locals=2, args_size=2
>>>>>> 0: new #2 // class Search
>>>
>>> This allocated an object - hence no null reference. But this is what
>>> verification should have complained about.
>>>
>>> David
>>> -----
>>>
>>>>>> 3: dup
>>>>>> 4: aload_0
>>>>>> 5: monitorenter
>>>>>> 6: monitorenter
>>>>>> 7: monitorexit
>>>>>> 8: aload_0
>>>>>> 9: monitorexit
>>>>>> 10: return
>>>>>> Exceptions:
>>>>>> throws java.lang.Exception
>>>>>>
>>>>>> 主题: HotSpot and IBM's J9 behave quite differently when processing
>>>>>> monitorenters and monitorexits
>>>>>>
>>>>>> I have tested several programs (in Jimple) and found that HotSpot
>>>>>> and
>>>>>> J9 match monitorenters and monitorexits quite differently.
>>>>>> Verifiers should play more important roles here.
>>>>
>>>> The job of the verifier is to establish some basic guarantees for
>>>> the JVM to then operate under. The verifier plays no role in
>>>> checking how monitorenter/exit are used in combination, only that
>>>> each individual bytecode meets some basic type constraints.
>>>>
>>>>>>
>>>>>> (1) Test the next program (r2 is not initizlied) on HotSpot and J9.
>>>>>> J9 throw out a verifier error, while HotSpot does not. It seems
>>>>>> that HotSpot's verifier forgets to check whether a monitored
>>>>>> object is initialized.
>>>>>>
>>>>>> public class Search extends java.lang.Object { public void <init>()
>>>>>> {
>>>>>> Search r0;
>>>>>> r0 := @this: Search;
>>>>>> specialinvoke r0.<java.lang.Object: void <init>()>();
>>>>>> return;
>>>>>> }
>>>>>> public void main(java.lang.String[]) throws java.lang.Exception
>>>>>> {
>>>>>> Search r0;
>>>>>> Search r2;
>>>>>> java.lang.String[] r1;
>>>>>> r0 := @this: Search;
>>>>>> r1 := @parameter0: java.lang.String[];
>>>>>> r2 = new Search;
>>>>>>
>>>>>> entermonitor r2;
>>>>>> entermonitor r0;
>>>>>> exitmonitor r2;
>>>>>> exitmonitor r0;
>>>>>> return;
>>>>>> }
>>>>>> }
>>>>
>>>> Verification was covered above.
>>>>
>>>>>>
>>>>>> (2) Test the next program on HotSpot and J9, and both do not
>>>>>> report any errors. However, I guess the order in the program
>>>>>> (entermonitor r2; => entermonitor r0; => exitmonitor r2; =>
>>>>>> exitmonitor r0;) violates the situation of "structured locking"
>>>>>> (Structured locking is the situation when, during a method
>>>>>> invocation, every exit on a given monitor matches a preceding
>>>>>> entry on that monitor, see the specification
>>>>>>
>>>>>> https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.
>>>>>>
>>>>>> 11.10)
>>>>>> ?
>>>>
>>>> No it doesn't violate structured locking as the number of enters
>>>> and exits match, and there is always an enter before an exit.
>>>>
>>>>>> Actually, the words (every exit on a given monitor matches a
>>>>>> preceding entry on that monitor) are not quite clear as for me.
>>>>>> Otherwise the first rule (The number of monitor entries performed
>>>>>> by T on M during a method invocation must equal the number of
>>>>>> monitor exits performed by T on M during the method invocation
>>>>>> whether the method invocation completes normally or abruptly.) is sufficient.
>>>>
>>>> The number of enters and exits must not only match/balance, but
>>>> there must be an enter before a corresponding exit.
>>>>
>>>>>>
>>>>>> public class Search extends java.lang.Object {
>>>>>>
>>>>>> public void <init>()
>>>>>> {
>>>>>> Search r0;
>>>>>> r0 := @this: Search;
>>>>>> specialinvoke r0.<java.lang.Object: void <init>()>();
>>>>>> return;
>>>>>> }
>>>>>>
>>>>>> public void main(java.lang.String[]) throws java.lang.Exception
>>>>>> {
>>>>>> Search r0;
>>>>>> Search r2;
>>>>>> java.lang.String[] r1;
>>>>>> r0 := @this: Search;
>>>>>> r1 := @parameter0: java.lang.String[];
>>>>>> r2 = new Search;
>>>>>> specialinvoke r2.<Search: void <init>()>();
>>>>>> entermonitor r2;
>>>>>> entermonitor r0;
>>>>>> exitmonitor r2;
>>>>>> exitmonitor r0;
>>>>>> return;
>>>>>> }
>>>>>> }
>>>>>>
>>>>>> (3) The next program enters monitor in <init> and exits it in main().
>>>>>> HotSpot throws a runtime exception, while J9 does not. Should
>>>>>> this program be rejected by the verifiers?
>>>>
>>>> No this does not violate any verification rules. The runtime
>>>> behaviour depends on whether structured locking is enforced or
>>>> not.(Even in hotspot there can be differences between interpreted and jitted code).
>>>>
>>>> Hope that helps clarify things.
>>>>
>>>> David
>>>> -----
>>>>
>>>>>>
>>>>>> public class Search extends java.lang.Object {
>>>>>>
>>>>>> public void <init>()
>>>>>> {
>>>>>> Search r0;
>>>>>> r0 := @this: Search;
>>>>>> specialinvoke r0.<java.lang.Object: void <init>()>();
>>>>>> entermonitor r0;
>>>>
More information about the hotspot-runtime-dev
mailing list