Tobias, I agree with your evaluation.
My only concern is that @Stable doesn't work for AtomicReferenceArray,
so JIT doesn't see what is stored in the array. Maybe use a lock instead?
Best regards,
Vladimir Ivanov
On 5/14/14 2:33 PM, Tobias Hartmann wrote:
> Hi Remi,
>> sorry, I accidentally reverted that part.. Here is the correct webrev:
>>http://cr.openjdk.java.net/~anoll/8005873/webrev.01/>> Thanks,
> Tobias
>> On 14.05.2014 12:04, Remi Forax wrote:
>> your patch doesn't work !
>>>> the array is still allocated as an classical array in the constructor.
>>>> cheers,
>> Remi
>>>> Envoyé avec AquaMail pour Android
>>http://www.aqua-mail.com>>>>>> Le 14 mai 2014 11:04:41 Tobias Hartmann <tobias.hartmann at oracle.com> a
>> écrit :
>>>>> Hi,
>>>>>> please review the following patch for bug 8005873.
>>>>>> *Problem*
>>> Bug: https://bugs.openjdk.java.net/browse/JDK-8005873>>>>>> The test creates multiple threads (~500) that repeatedly execute
>>> invokeExact on a method handle referencing a static method. The call
>>> to invokeExact is performed through an optimized inline cache
>>> (CompiledStaticCall) that points to the LambdaForm generated for the
>>> method handle. The IC is first set to interpreted code by
>>> CompiledStaticCall::set_to_interpreted(...) but soon updated to refer
>>> to the compiled version of the lambda form (-Xcomp).
>>>>>> Because tiered compilation is enabled, the VM decides to compile the
>>> LambdaForm at a different level and sets the old version to
>>> not-entrant. The next call through the IC therefore triggers a
>>> re-resolving of the call site finally performing a Java upcall to
>>> java.lang.invoke.MethodHandleNatives::linkMethod(...) (see call
>>> sequence [1]). A *new* LambdaForm is returned and
>>> CompiledStaticCall::set_to_interpreted(...) is executed again to
>>> update the IC. The assert is hit because the callee differs.
>>>>>> The problem is that there are multiple LambdaForms created for the
>>> same invokeExact instruction. Caching in the Java runtime code should
>>> guarantee that only one LambdaForm is created and reused.
>>> Instrumenting Invokers::invokeHandleForm(...) shows that almost all
>>> requests result in a cache miss and return a new LambdaForm.
>>>>>> This behaviour is caused by a race condition in
>>> Invokers::invokeHandleForm(...). Threads may initially see a cache
>>> miss when invoking MethodTypeForm::cachedLambdaForm(...), then create
>>> a new LambdaForm and call MethodTypeForm::setCachedLambdaForm(...) to
>>> update the cache without checking it again. In a high concurrency
>>> setting, this leads to multiple LambdaForms being created for the
>>> same invokeExact instruction because the cache entry is overwritten
>>> by multiple threads.
>>>>>> *Solution*
>>> Webrev: http://cr.openjdk.java.net/~anoll/8005873/webrev.00/>>>>>> An AtomicReferenceArray is used to cache the LambdaForms and
>>> .get(...) and .compareAndSet(...) are used to retrieve and update the
>>> cache entries. This allows only one thread to set the LambdaForm that
>>> is then being used by all instances of the invokeExact.
>>>>>> *Testing*
>>> - Failing test (vm/mlvm/meth/stress/jni/nativeAndMH)
>>> - Nashorn + Octane
>>> - JPRT
>>>>>> Many thanks to Christian Thalinger and Vladimir Ivanov!
>>>>>> Best,
>>> Tobias
>>>>>> [1] Call sequence of reresolving the IC target
>>> SharedRuntime::handle_wrong_method(...)
>>> -> SharedRuntime::reresolve_call_site(...)
>>> -> SharedRuntime::find_callee_method(...)
>>> -> SharedRuntime::find_callee_info_helper(...)
>>> -> LinkResolver::resolve_invoke(...)
>>> -> LinkResolver::resolve_invokehandle(...)
>>> -> LinkResolver::resolve_invokehandle(...)
>>> -> LinkResolver::lookup_polymorphic_method(...)
>>> -> SystemDictionary::find_method_handle_invoker(...)
>>> -> Java upcall to java.lang.invoke.MethodHandleNatives::linkMethod(...)
>>> -> Invokers::methodHandleInvokeLinkerMethod(...)
>>> -> Invokers::invokeHandleForm(...)
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> Backport?
>>>>>