Nashorn Project, javascript + java?

Asked

Viewed 138 times

4

I found the approach interesting after studying more deep bytecode instruction Invokedynamic. But I have doubts about design and practical use.

The javac natively will understand the javascript block and will generate the bytecode from that mixed code?

I would like to understand the advantages/disadvantages of using javascript Embedded in java applications. If possible any code snippet and practical demonstration of such use.

  • 1

    Related: http://answall.com/q/71340/132

1 answer

3


After some research, I came to some conclusions regarding my question, they were:

Regarding an example of in encoding java + javascript I could find in a reference of a answer by @Filipegonzagamiranda who was featured in the comments and was a great starting point.

Following I worked on a different example, more advanced, mixing java and javascript:

public class NashornEval {
       public static void main(String... args) {

           ScriptEngineManager manager = new ScriptEngineManager();
           ScriptEngine engine = manager.getEngineByName("nashorn");

           String js;
           js  = "var Thread = java.lang.Thread; \n";
           js += "var map = Array.prototype.map \n";
           js += "var names = [\"corinthians\", \"palmeiras\", \"santos\"]\n";
           js += "var a = map.call(names, function(name) { return name.length() })\n";
           js += "print(a); \n";
           js += "Thread.sleep(5000); \n";
           js += "print(\"finalizado...\");";

           try {
            engine.eval(js);
        } catch (ScriptException e) {
            e.printStackTrace();
        }

        }
}

And it really worked!

11,9,6
(... 5 seg ...)
finalizado...

Perplexed by this example, I ran to analyze the generated bytecode (naively) in search of the invokedynamic instruction and what I got was:

// class version 52.0 (52)
// access flags 0x21
public class NashornEval {

  // compiled from: NashornEval.java

  // access flags 0x1
  public <init>() : void
   L0
    LINENUMBER 7 L0
    ALOAD 0: this
    INVOKESPECIAL Object.<init> () : void
    RETURN
   L1
    LOCALVARIABLE this NashornEval L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x89
  public static transient varargs main(String[]) : void
    TRYCATCHBLOCK L0 L1 L2 ScriptException
   L3
    LINENUMBER 10 L3
    NEW ScriptEngineManager
    DUP
    INVOKESPECIAL ScriptEngineManager.<init> () : void
    ASTORE 1
   L4
    LINENUMBER 11 L4
    ALOAD 1: manager
    LDC "nashorn"
    INVOKEVIRTUAL ScriptEngineManager.getEngineByName (String) : ScriptEngine
    ASTORE 2
   L5
    LINENUMBER 14 L5
    LDC "var Thread = java.lang.Thread; \n"
    ASTORE 3
   L6
    LINENUMBER 15 L6
    NEW StringBuilder
    DUP
    ALOAD 3: js
    INVOKESTATIC String.valueOf (Object) : String
    INVOKESPECIAL StringBuilder.<init> (String) : void
    LDC "var map = Array.prototype.map \n"
    INVOKEVIRTUAL StringBuilder.append (String) : StringBuilder
    INVOKEVIRTUAL StringBuilder.toString () : String
    ASTORE 3: js
   L7
    LINENUMBER 16 L7
    NEW StringBuilder
    DUP
    ALOAD 3: js
    INVOKESTATIC String.valueOf (Object) : String
    INVOKESPECIAL StringBuilder.<init> (String) : void
    LDC "var names = [\"corinthians\", \"palmeiras\", \"santos\"]\n"
    INVOKEVIRTUAL StringBuilder.append (String) : StringBuilder
    INVOKEVIRTUAL StringBuilder.toString () : String
    ASTORE 3: js
   L8
    LINENUMBER 17 L8
    NEW StringBuilder
    DUP
    ALOAD 3: js
    INVOKESTATIC String.valueOf (Object) : String
    INVOKESPECIAL StringBuilder.<init> (String) : void
    LDC "var a = map.call(names, function(name) { return name.length() })\n"
    INVOKEVIRTUAL StringBuilder.append (String) : StringBuilder
    INVOKEVIRTUAL StringBuilder.toString () : String
    ASTORE 3: js
   L9
    LINENUMBER 18 L9
    NEW StringBuilder
    DUP
    ALOAD 3: js
    INVOKESTATIC String.valueOf (Object) : String
    INVOKESPECIAL StringBuilder.<init> (String) : void
    LDC "print(a); \n"
    INVOKEVIRTUAL StringBuilder.append (String) : StringBuilder
    INVOKEVIRTUAL StringBuilder.toString () : String
    ASTORE 3: js
   L10
    LINENUMBER 19 L10
    NEW StringBuilder
    DUP
    ALOAD 3: js
    INVOKESTATIC String.valueOf (Object) : String
    INVOKESPECIAL StringBuilder.<init> (String) : void
    LDC "Thread.sleep(5000); \n"
    INVOKEVIRTUAL StringBuilder.append (String) : StringBuilder
    INVOKEVIRTUAL StringBuilder.toString () : String
    ASTORE 3: js
   L11
    LINENUMBER 20 L11
    NEW StringBuilder
    DUP
    ALOAD 3: js
    INVOKESTATIC String.valueOf (Object) : String
    INVOKESPECIAL StringBuilder.<init> (String) : void
    LDC "print(\"finalizado...\");"
    INVOKEVIRTUAL StringBuilder.append (String) : StringBuilder
    INVOKEVIRTUAL StringBuilder.toString () : String
    ASTORE 3: js
   L0
    LINENUMBER 23 L0
    ALOAD 2: engine
    ALOAD 3: js
    INVOKEINTERFACE ScriptEngine.eval (String) : Object
    POP
   L1
    LINENUMBER 24 L1
    GOTO L12
   L2
   FRAME FULL [String[] ScriptEngineManager ScriptEngine String] [ScriptException]
    ASTORE 4
   L13
    LINENUMBER 25 L13
    ALOAD 4: e
    INVOKEVIRTUAL ScriptException.printStackTrace () : void
   L12
    LINENUMBER 28 L12
   FRAME SAME
    RETURN
   L14
    LOCALVARIABLE args String[] L3 L14 0
    LOCALVARIABLE manager ScriptEngineManager L4 L14 1
    LOCALVARIABLE engine ScriptEngine L5 L14 2
    LOCALVARIABLE js String L6 L14 3
    LOCALVARIABLE e ScriptException L13 L12 4
    MAXSTACK = 3
    MAXLOCALS = 5
}

Soon I was sure the routine that is responsible for the execution of "non-typed language" (Nashorn) o should do so at execution time.

My next step would be to identify it, and where I could get closer was by displaying a process histogram at runtime from the jvm instance responsible for running my Nashorneval example. So I did:

$ jps
40231 Jps
40076 NashornEval
//PID da instancia jvm NashornEval = 40076

And using the jmap:

$ jmap -histo 40076 | grep dynamic
// -histo  imprime o histograma do java object heap
// usei o grep pra restringir meu retorno a um match “dynamic”

And my return was:

  6:         10265         410600  java.lang.invoke.MethodType
   8:         10373         331936  java.lang.invoke.MethodType$ConcurrentWeakInternSet$WeakEntry
  12:          4395         246120  java.lang.invoke.MemberName
  14:          2078         116368  java.lang.invoke.LambdaFormEditor$Transform
  16:          2199          70368  java.lang.invoke.LambdaForm$Name
  18:          1280          57864  [Ljava.lang.invoke.LambdaForm$Name;
  20:          1622          51904  java.lang.invoke.BoundMethodHandle$Species_LL
  21:          1454          46528  java.lang.invoke.DirectMethodHandle
  22:          1384          44288  java.lang.invoke.BoundMethodHandle$Species_L
  38:          1882          30112  java.lang.invoke.LambdaFormEditor
  40:           602          28896  java.lang.invoke.LambdaForm
  46:           396          22176  java.lang.invoke.MethodTypeForm
  50:           865          20760  java.lang.invoke.MethodHandles$Lookup
  51:           606          20720  [Ljava.lang.invoke.MethodHandle;
  57:           238          15232  java.lang.invoke.InvokerBytecodeGenerator
  60:           577          13848  java.lang.invoke.LambdaForm$NamedFunction
  63:           279          13136  [Ljava.lang.invoke.LambdaForm$BasicType;
  74:           211           8440  java.lang.invoke.BoundMethodHandle$Species_L3
  94:            99           4752  java.lang.invoke.LambdaFormBuffer
 101:           126           4032  java.lang.invoke.BoundMethodHandle$Species_LI
 106:            90           3600  java.lang.invoke.BoundMethodHandle$Species_L3I
 111:            62           2976  java.lang.invoke.MethodHandleImpl$CountingWrapper
 114:            66           2640  java.lang.invoke.DirectMethodHandle$Accessor
 118:            61           2440  java.lang.invoke.MethodHandleImpl$AsVarargsCollector
 119:            60           2400  java.lang.invoke.BoundMethodHandle$Species_LILL
 124:            40           1920  java.lang.invoke.BoundMethodHandle$Species_LIL3
 130:            45           1800  java.lang.invoke.BoundMethodHandle$Species_LIL
 133:            69           1656  java.lang.invoke.Invokers
 152:            33           1200  [Ljava.lang.invoke.LambdaFormEditor$Transform;
 171:            20            800  java.lang.invoke.BoundMethodHandle$SpeciesData
 172:            25            800  java.lang.invoke.MethodHandleImpl$IntrinsicMethodHandle
 179:            18            720  [Ljava.lang.invoke.BoundMethodHandle$SpeciesData;
 180:            18            720  java.lang.invoke.BoundMethodHandle$Species_LLI
 191:            27            648  java.lang.invoke.SimpleMethodHandle
 192:            40            640  java.lang.invoke.MutableCallSite
 194:             3            624  [Ljava.lang.invoke.LambdaForm;
 202:            19            600  [Ljava.lang.invoke.LambdaForm$NamedFunction;
 204:             9            576  [Lsun.invoke.util.Wrapper;
 209:            10            560  sun.invoke.util.Wrapper
 210:            23            552  [Ljava.lang.invoke.MutableCallSite;
 211:            23            552  [Ljava.lang.invoke.SwitchPoint;
 224:            11            440  java.lang.invoke.MethodHandleImpl$WrappedMember
 231:            10            400  java.lang.invoke.BoundMethodHandle$Species_LLIL
 255:            14            336  java.lang.invoke.LambdaFormEditor$Transform$Kind
 263:            10            320  java.lang.invoke.DirectMethodHandle$Special
 281:            17            272  sun.invoke.util.ValueConversions$WrapperCache
 282:            11            264  java.lang.invoke.SwitchPoint
 305:             5            200  java.lang.invoke.BoundMethodHandle$Species_L4
 308:             4            192  java.lang.invoke.BoundMethodHandle$Species_L5
 309:             6            192  java.lang.invoke.InvokerBytecodeGenerator$CpPatch
 310:             6            192  java.lang.invoke.LambdaForm$BasicType
 311:             8            192  java.lang.invoke.MethodHandleImpl$Intrinsic
 341:             4            136  [Lsun.invoke.util.ValueConversions$WrapperCache;
 377:             1             96  [Ljava.lang.invoke.MethodType;
 379:             2             96  java.lang.invoke.BoundMethodHandle$Species_L3IL
 418:             1             72  [Ljava.lang.invoke.LambdaFormEditor$Transform$Kind;
 449:             2             64  java.lang.invoke.BoundMethodHandle$Species_D
 523:             1             48  [Ljava.lang.invoke.MethodHandleImpl$Intrinsic;
 532:             1             48  java.lang.invoke.BoundMethodHandle$Species_LLILL
 588:             1             40  [[Ljava.lang.invoke.LambdaForm$Name;
 633:             1             32  java.lang.invoke.BoundMethodHandle$Species_I
 679:             1             24  java.lang.invoke.DirectMethodHandle$EnsureInitialized
 680:             1             24  java.lang.invoke.MethodHandleImpl$4
 681:             1             24  java.lang.invoke.MethodHandleImpl$ArrayAccessor$1
 682:             1             24  java.lang.invoke.MethodType$ConcurrentWeakInternSet
 753:             1             16  java.lang.invoke.MemberName$Factory
 754:             1             16  java.lang.invoke.MethodHandleImpl$2
 755:             1             16  java.lang.invoke.MethodHandleImpl$3

And there it was, the engine nashorn doing the magic:

 192:            40            640  java.lang.invoke.MutableCallSite

Mutablecallsite is a Callsite whose target variable behaves as a common field. An invokedynamic statement is linked to Mutablecallsite delegating all calls to the site’s current target. The dynamic summoner of a callsite mutable also delegates each call to originating target.

I’m still very interested in more complex applications using Ducktyping, but I was pleased for the moment, I hope it helps to clarify the subject for others too.

  • 1

    Awesome!! A question: is there any optimization possible for Invokedynamic? @Reginaldosoares

Browser other questions tagged

You are not signed in. Login or sign up in order to post.