2015-06-16 13 views
6


Sto provando ad avere Java 8 Nashorn con sorgente completa (non strumentato). Come forse saprai, utilizza Nasgen per modificare le classi. L'output viene spedito in JRE/lib/ext/nashorn.jar.Codice Java da compilare in MethodHandle in Costante Pool


Sulla smontare l'uscita, utilizzando javap:

0: aload_0 
1: ldc   #24     // String Function 
3: ldc   #31     // MethodHandle invokestatic jdk/nashorn/internal/objects/NativeFunction.function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction; 
5: getstatic  #22     // Field $nasgenmap$:Ljdk/nashorn/internal/runtime/PropertyMap; 
8: aconst_null 
9: invokespecial #34     // Method jdk/nashorn/internal/objects/ScriptFunctionImpl."<init>":(Ljava/lang/String;Ljava/lang/invoke/MethodHandle;Ljdk/nashorn/internal/runtime/PropertyMap;[Ljdk/nashorn/internal/runtime/Specialization;)V 

che potrebbe essere erroneamente scritto come

super("Function", NativeFunction.function, $nasgenmap$, (Specialization[]) null); 

, che dovrebbe chiamare il costruttore eccellente con la firma:

ScriptFunctionImpl(String, MethodHandle, PropertyMap, Specialization[]) { } 



Il mio problema è il secondo parametro NativeFunction.function, che non ho potuto avere una fonte compilabile, per generare la stessa MethodHandle in piscina costante,

#31 = MethodHandle  #6:#30   // invokestatic jdk/nashorn/internal/objects/NativeFunction.function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction; 

Quella parte della strumentazione è stato fatto da ASM, chiamando lo MethodVisitor.visitLdcInsn.

Quindi, c'è un modo per costruire un tale handle di metodo dal sorgente Java, oppure questa è una funzionalità che può essere eseguita solo a livello di codice byte?

L'uscita javap completa:

$javap -c -v NativeFunction$Constructor.class 

    Last modified Apr 10, 2015; size 1161 bytes 
    MD5 checksum dcae2f54643befc519a45e9ac9bc4781 
final class jdk.nashorn.internal.objects.NativeFunction$Constructor extends jdk.nashorn.internal.objects.ScriptFunctionImpl 
    minor version: 0 
    major version: 51 
    flags: ACC_FINAL 
Constant pool: 
    #1 = Utf8    jdk/nashorn/internal/objects/NativeFunction$Constructor 
    #2 = Class    #1    // jdk/nashorn/internal/objects/NativeFunction$Constructor 
    #3 = Utf8    jdk/nashorn/internal/objects/ScriptFunctionImpl 
    #4 = Class    #3    // jdk/nashorn/internal/objects/ScriptFunctionImpl 
    #5 = Utf8    $nasgenmap$ 
    #6 = Utf8    Ljdk/nashorn/internal/runtime/PropertyMap; 
    #7 = Utf8    <clinit> 
    #8 = Utf8    ()V 
    #9 = Utf8    java/util/ArrayList 
    #10 = Class    #9    // java/util/ArrayList 
    #11 = Utf8    <init> 
    #12 = Utf8    (I)V 
    #13 = NameAndType  #11:#12  // "<init>":(I)V 
    #14 = Methodref   #10.#13  // java/util/ArrayList."<init>":(I)V 
    #15 = Utf8    jdk/nashorn/internal/runtime/PropertyMap 
    #16 = Class    #15   // jdk/nashorn/internal/runtime/PropertyMap 
    #17 = Utf8    newMap 
    #18 = Utf8    (Ljava/util/Collection;)Ljdk/nashorn/internal/runtime/PropertyMap; 
    #19 = NameAndType  #17:#18  // newMap:(Ljava/util/Collection;)Ljdk/nashorn/internal/runtime/PropertyMap; 
    #20 = Methodref   #16.#19  // jdk/nashorn/internal/runtime/PropertyMap.newMap:(Ljava/util/Collection;)Ljdk/nashorn/internal/runtime/PropertyMap; 
    #21 = NameAndType  #5:#6   // $nasgenmap$:Ljdk/nashorn/internal/runtime/PropertyMap; 
    #22 = Fieldref   #2.#21   // jdk/nashorn/internal/objects/NativeFunction$Constructor.$nasgenmap$:Ljdk/nashorn/internal/runtime/PropertyMap; 
    #23 = Utf8    Function 
    #24 = String    #23   // Function 
    #25 = Utf8    jdk/nashorn/internal/objects/NativeFunction 
    #26 = Class    #25   // jdk/nashorn/internal/objects/NativeFunction 
    #27 = Utf8    function 
    #28 = Utf8    (ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction; 
    #29 = NameAndType  #27:#28  // function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction; 
    #30 = Methodref   #26.#29  // jdk/nashorn/internal/objects/NativeFunction.function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction; 
    #31 = MethodHandle  #6:#30   // invokestatic jdk/nashorn/internal/objects/NativeFunction.function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction; 
    #32 = Utf8    (Ljava/lang/String;Ljava/lang/invoke/MethodHandle;Ljdk/nashorn/internal/runtime/PropertyMap;[Ljdk/nashorn/internal/runtime/Specialization;)V 
    #33 = NameAndType  #11:#32  // "<init>":(Ljava/lang/String;Ljava/lang/invoke/MethodHandle;Ljdk/nashorn/internal/runtime/PropertyMap;[Ljdk/nashorn/internal/runtime/Specialization;)V 
    #34 = Methodref   #4.#33   // jdk/nashorn/internal/objects/ScriptFunctionImpl."<init>":(Ljava/lang/String;Ljava/lang/invoke/MethodHandle;Ljdk/nashorn/internal/runtime/PropertyMap;[Ljdk/nashorn/internal/runtime/Specialization;)V 
    #35 = Utf8    jdk/nashorn/internal/objects/NativeFunction$Prototype 
    #36 = Class    #35   // jdk/nashorn/internal/objects/NativeFunction$Prototype 
    #37 = NameAndType  #11:#8   // "<init>":()V 
    #38 = Methodref   #36.#37  // jdk/nashorn/internal/objects/NativeFunction$Prototype."<init>":()V 
    #39 = Utf8    jdk/nashorn/internal/objects/PrototypeObject 
    #40 = Class    #39   // jdk/nashorn/internal/objects/PrototypeObject 
    #41 = Utf8    setConstructor 
    #42 = Utf8    (Ljava/lang/Object;Ljava/lang/Object;)V 
    #43 = NameAndType  #41:#42  // setConstructor:(Ljava/lang/Object;Ljava/lang/Object;)V 
    #44 = Methodref   #40.#43  // jdk/nashorn/internal/objects/PrototypeObject.setConstructor:(Ljava/lang/Object;Ljava/lang/Object;)V 
    #45 = Utf8    jdk/nashorn/internal/runtime/ScriptFunction 
    #46 = Class    #45   // jdk/nashorn/internal/runtime/ScriptFunction 
    #47 = Utf8    setPrototype 
    #48 = Utf8    (Ljava/lang/Object;)V 
    #49 = NameAndType  #47:#48  // setPrototype:(Ljava/lang/Object;)V 
    #50 = Methodref   #46.#49  // jdk/nashorn/internal/runtime/ScriptFunction.setPrototype:(Ljava/lang/Object;)V 
    #51 = Utf8    setArity 
    #52 = NameAndType  #51:#12  // setArity:(I)V 
    #53 = Methodref   #46.#52  // jdk/nashorn/internal/runtime/ScriptFunction.setArity:(I)V 
    #54 = Utf8    Code 
{ 
    public static {}; 
    flags: ACC_PUBLIC, ACC_STATIC 
    Code: 
     stack=3, locals=0, args_size=0 
     0: new   #10     // class java/util/ArrayList 
     3: dup 
     4: iconst_1 
     5: invokespecial #14     // Method java/util/ArrayList."<init>":(I)V 
     8: invokestatic #20     // Method jdk/nashorn/internal/runtime/PropertyMap.newMap:(Ljava/util/Collection;)Ljdk/nashorn 
/internal/runtime/PropertyMap; 
     11: putstatic  #22     // Field $nasgenmap$:Ljdk/nashorn/internal/runtime/PropertyMap; 
     14: return 

    jdk.nashorn.internal.objects.NativeFunction$Constructor(); 
    flags: 
    Code: 
     stack=5, locals=1, args_size=1 
     0: aload_0 
     1: ldc   #24     // String Function 
     3: ldc   #31     // MethodHandle invokestatic jdk/nashorn/internal/objects/NativeFunction.function:(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction; 
     5: getstatic  #22     // Field $nasgenmap$:Ljdk/nashorn/internal/runtime/PropertyMap; 
     8: aconst_null 
     9: invokespecial #34     // Method jdk/nashorn/internal/objects/ScriptFunctionImpl."<init>":(Ljava/lang/String;Ljava/lang/invoke/MethodHandle;Ljdk/nashorn/internal/runtime/PropertyMap;[Ljdk/nashorn/internal/runtime/Specialization;)V 
     12: aload_0 
     13: new   #36     // class jdk/nashorn/internal/objects/NativeFunction$Prototype 
     16: dup 
     17: invokespecial #38     // Method jdk/nashorn/internal/objects/NativeFunction$Prototype."<init>":()V 
     20: dup 
     21: aload_0 
     22: invokestatic #44     // Method jdk/nashorn/internal/objects/PrototypeObject.setConstructor:(Ljava/lang/Object;Ljava/lang/Object;)V 
     25: invokevirtual #50     // Method jdk/nashorn/internal/runtime/ScriptFunction.setPrototype:(Ljava/lang/Object;)V 
     28: aload_0 
     29: iconst_1 
     30: invokevirtual #53     // Method jdk/nashorn/internal/runtime/ScriptFunction.setArity:(I)V 
     33: return 
} 
+3

È probabilmente solo il codice byte. Ci sono molte cose che altri linguaggi JVM fanno che Java non può, ed è una questione di specifiche del linguaggio, non di ciò che i codici byte sono in grado. di. – markspace

+2

L'unica funzione in linguaggio Java che conosco che utilizza l'opcode 'invokespecial' è lambdas. Oltre a questo è principalmente usato per linguaggi dinamici (come Javascript) in esecuzione su JVM. Non so se questo aiuta. – biziclop

+0

Questo doveva essere "invocato dinamico", ovviamente. – biziclop

risposta

6

Non v'è alcun costrutto del linguaggio Java per produrre un'istruzione ldc caricamento di un MethodHandle. Ancora, è possibile creare un equivalente maniglia con un costrutto più complicata:

MethodHandles.lookup().findStatic(
    jdk.nashorn.internal.objects.NativeFunction.class, "function", 
    MethodType.fromMethodDescriptorString(
    "(ZLjava/lang/Object;[Ljava/lang/Object;)Ljdk/nashorn/internal/runtime/ScriptFunction;", 
    null)) 

Non solo questo è più complicato di una singola istruzione ldc bytecode, si è costretti anche a che fare con le eccezioni controllate NoSuchMethodException e IllegalAccessException (o il loro antenato comune ReflectiveOperationException).

Si può incapsulare l'operazione in un metodo come

private static MethodHandle MH_NativeFunction_function() { 
    try { 
    return MethodHandles.lookup().findStatic(
     jdk.nashorn.internal.objects.NativeFunction.class, "function", 
     MethodType.fromMethodDescriptorString("(ZLjava/lang/Object;[Ljava/lang/Object;)" 
     + "Ljdk/nashorn/internal/runtime/ScriptFunction;", null)); 
    } catch(ReflectiveOperationException ex) { 
     throw new AssertionError(ex); 
    } 
} 

e chiamarlo in te costruttore come

super("Function", MH_NativeFunction_function(), $nasgenmap$, (Specialization[]) null); 

il vantaggio di questo approccio è che è possibile utilizzare Indify per convertire l'invocazione MH_NativeFunction_function() di nuovo a un'istruzione ldc che carica il MethodHandle dal pool costante.

Problemi correlati