Type specialization / recompilation of functions using "arguments"
Axel Faust
axel.faust.g at googlemail.com
Fri Aug 19 14:41:16 UTC 2016
Hello,
in my ongoing project to implement an alternative scripting integration to
the ECM platform Alfresco using Nashorn, I recently ran into a performance
issue due to constructor / function recompilation due to type
specialization, particularly if the constructor / function in question is
accessing the "arguments" object.
I have tried to simplify this with a test and used "jjs
--log=recompile:finest" to run it.
Consider the following script:
function testArguments() { print(JSON.stringify(arguments)); }
// simple call tests
testArguments('test1'); // first access => 2x "parameter type
specialization"
testArguments('test1'); // identical parameter => no recompilation
testArguments('test2'); // identical param type, different value =>
"parameter type specialization"
testArguments('test3'); // identical param type, different value =>
"parameter type specialization"
// iterative call test
for (var i = 0; i < 1000; i++) { testArguments('test' + i); } // identical
param type, different values => only one "parameter type specialization"
Now I don't quite understand why script function "testArguments" needs to
be recompiled on each call with the same parameter type but different
value, and how this is not required when executed within a loop structure.
The latter is interesting on another level, since a test script for my
Alfresco-Nashorn integration is running an array-forEach loop where the
called function is being recompiled on every iteration, while replacing the
for-loop in the test script above with an array-forEach (pre-filled)
behaves exactly the same as the for-loop with only a single recompilation.
Additionally, in the integration test script I even see recompilations for
identical values (in subsequent runs of the same script).
Now having a single recompilation wouldn't be so bad, but continous
recompilation hurts quite a bit. Unfortunately this affects quite a central
piece in my integration project and thus causes significant overhead via
ClassLoader.defineClass, Class.getDeclaredFields and method handle / call
site handling operations that result from the recompilation. Each run of my
integration-specific test script adds ~10 CompiledFunction instances to the
ScriptFunctionData.code list for the same function (all with apparently
identical call site types and invokers, at least judging from
toString-representations). The persistent code cache doesn't seem to be
used at all as RecompilableScriptFunctionData.getBest calls
compileTypeSpecialization in a way that disables its use.
Is this behaviour something that should be considered "expected" or is it a
"real" performance bug? If it is expected, is there a general
recommendation not to use functions that access arguments for
performance-critical code?
(I tested with JDK 8u71 and JDK 9 ea+125 - behaviour is the same except JDK
9 provides deoptimization log output on 1st call)
Regards
Axel Faust
More information about the nashorn-dev
mailing list