Nashorn Bug..

June 18, 2014

 

Excited as anyone would be of a newer, performant, cleaner engine Nashorn was something to look forward. Nice to play with moving on from Rhino. But one bug that is annoying and would love to get a fix for fast is its handling of large hierarchy of classes / or large number of methods in the Java class a script calls into. A hack works.. but need better way forward / affirmation on this..

“Step two translates the AST/IR into byte code via the ASM library. ASM emits the actual byte codes to form a script class”

load(‘nashorn:mozilla_compat.js’

 importPackage(my.own.package.name) 

          new MyClass().invokeAnyMethod()  // method on its super class which is Abstract

In this the MySuperClass has invokeAnyMethod() defined viz: MySuperClass should be having a hierarchy of classes that put together have say 6000+ methods.  (The #invokeAnyMethod() then has statements that invokes a method(s) on its super classes, a simple method that returns “hello world” or simple calc on its immediate attributes does not suffice )

In the

JavaAdapterBytecodeGenerator.<init> ( constructor ) .. it does the following:

     gatherMethods(superClass); // this reaps all the methods of the super class MySuperClass of 6000+ methods..

     gatherMethods(interfaces);

..

     generateConstructors(); which in turn invokes the following:

 

private void generateOverridingConstructor(final Constructor<?> ctor, final boolean fromFunction) {

… //this has a loop through all the methods gathered..

for (final MethodInfo mi : methodInfos) {

… which goes on to emit the code bytecodes for the firstMethod of the ClassWriter ( cw ) property

with iteration over 6000+ methods it easily exceeds the 64K bytecode limit of JDK VM method byte code size..

which then gloriously fails as:

 

java.lang.RuntimeException: Method code too large!

            at jdk.internal.org.objectweb.asm.MethodWriter.getSize(MethodWriter.java:2065)

           at jdk.internal.org.objectweb.asm.ClassWriter.toByteArray(ClassWriter.java:837)

           at jdk.nashorn.internal.runtime.linker.JavaAdapterBytecodeGenerator.createAdapterClassLoader(JavaAdapterBytecodeGenerator.java:264)

*******  Hack in at :

public static TypeBasedGuardingDynamicLinker getLinkerForClass(Class<?> clazz) {

   return linkers.get(clazz); // need to check on why NashornBeansLinker for specific cases..

}

// If it returns a NashornBeansLinker that then goes through the chain to dump the ClassWrter creates an issue, for simple methods it returns a BeanLinker and runs fine..  maybe nice to get a hang of it here..

private static GuardedInvocation getSamTypeConverter(final Class<?> sourceType, final Class<?> targetType) throws Exception {

// If source type is more generic than ScriptFunction class, we’ll need to use a guard

final boolean isSourceTypeGeneric = sourceType.isAssignableFrom(ScriptFunction.class); // make this false for such cases… and it works fine.. for the basic tests..

 

 * I have not as yet plumbed as much of the Nashorn logic in this.. why dig through and create a ClassWriter byte code cache (NashornAdaptor to the super class ) when it can probably make a proxy for the Java object and simply let the message be invoked as normal Java method and marshal the result back as per Nashorn semantics.. I am sure there are good reasons, need to plumb it thoroughly before I comprehend it..

*  Now the other concern is org.objectweb.asm.** is used in other packages viz: Groovy / Spring.. et als as asm.xxx.jar  now will this create a conflict is also to be plumbed and ensure classpath loaders honor the segregation properly Groovy still uses a very old asm 4.0 jar.