src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File jdk Sdiff src/share/classes/java/lang/invoke

src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java

Print this page
rev 10092 : 8037209: Improvements and cleanups to bytecode assembly for lambda forms
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com
rev 10093 : 8038261: JSR292: cache and reuse typed array accessors
Reviewed-by: vlivanov, ?
Contributed-by: john.r.rose@oracle.com


  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 
  28 import java.io.*;
  29 import java.util.*;
  30 import java.lang.reflect.Modifier;
  31 
  32 import jdk.internal.org.objectweb.asm.*;
  33 
  34 import static java.lang.invoke.LambdaForm.*;
  35 import static java.lang.invoke.LambdaForm.BasicType.*;
  36 import static java.lang.invoke.MethodHandleStatics.*;
  37 import static java.lang.invoke.MethodHandleNatives.Constants.*;

  38 import sun.invoke.util.ValueConversions;
  39 import sun.invoke.util.VerifyAccess;
  40 import sun.invoke.util.VerifyType;
  41 import sun.invoke.util.Wrapper;
  42 import sun.reflect.misc.ReflectUtil;
  43 
  44 /**
  45  * Code generation backend for LambdaForm.
  46  * <p>
  47  * @author John Rose, JSR 292 EG
  48  */
  49 class InvokerBytecodeGenerator {
  50     /** Define class names for convenience. */
  51     private static final String MH      = "java/lang/invoke/MethodHandle";
  52     private static final String MHI     = "java/lang/invoke/MethodHandleImpl";
  53     private static final String LF      = "java/lang/invoke/LambdaForm";
  54     private static final String LFN     = "java/lang/invoke/LambdaForm$Name";
  55     private static final String CLS     = "java/lang/Class";
  56     private static final String OBJ     = "java/lang/Object";
  57     private static final String OBJARY  = "[Ljava/lang/Object;";


 410     private void emitStoreInsn(BasicType type, int index) {
 411         int opcode = storeInsnOpcode(type);
 412         mv.visitVarInsn(opcode, localsMap[index]);
 413     }
 414 
 415     private int storeInsnOpcode(BasicType type) throws InternalError {
 416         switch (type) {
 417             case I_TYPE: return Opcodes.ISTORE;
 418             case J_TYPE: return Opcodes.LSTORE;
 419             case F_TYPE: return Opcodes.FSTORE;
 420             case D_TYPE: return Opcodes.DSTORE;
 421             case L_TYPE: return Opcodes.ASTORE;
 422             default:
 423                 throw new InternalError("unknown type: " + type);
 424         }
 425     }
 426     private void emitAstoreInsn(int index) {
 427         emitStoreInsn(L_TYPE, index);
 428     }
 429 


































 430     private void freeFrameLocal(int oldFrameLocal) {
 431         int i = indexForFrameLocal(oldFrameLocal);
 432         if (i < 0)  return;
 433         BasicType type = localTypes[i];
 434         int newFrameLocal = makeLocalTemp(type);
 435         mv.visitVarInsn(loadInsnOpcode(type), oldFrameLocal);
 436         mv.visitVarInsn(storeInsnOpcode(type), newFrameLocal);
 437         assert(localsMap[i] == oldFrameLocal);
 438         localsMap[i] = newFrameLocal;
 439         assert(indexForFrameLocal(oldFrameLocal) < 0);
 440     }
 441     private int indexForFrameLocal(int frameLocal) {
 442         for (int i = 0; i < localsMap.length; i++) {
 443             if (localsMap[i] == frameLocal && localTypes[i] != V_TYPE)
 444                 return i;
 445         }
 446         return -1;
 447     }
 448     private int makeLocalTemp(BasicType type) {
 449         int frameLocal = localsMap[localsMap.length - 1];


 599 
 600         // iterate over the form's names, generating bytecode instructions for each
 601         // start iterating at the first name following the arguments
 602         Name onStack = null;
 603         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
 604             Name name = lambdaForm.names[i];
 605             MemberName member = name.function.member();
 606             Class<?> rtype = name.function.methodType().returnType();
 607 
 608             emitStoreResult(onStack);
 609             onStack = name;  // unless otherwise modified below
 610 
 611             if (isSelectAlternative(i)) {
 612                 onStack = emitSelectAlternative(name, lambdaForm.names[i + 1]);
 613                 i++;  // skip MH.invokeBasic of the selectAlternative result
 614             } else if (isGuardWithCatch(i)) {
 615                 onStack = emitGuardWithCatch(i);
 616                 i = i+2; // Jump to the end of GWC idiom
 617             } else if (isNewArray(rtype, name)) {
 618                 emitNewArray(rtype, name);




 619             } else if (isStaticallyInvocable(member)) {
 620                 emitStaticInvoke(name);
 621             } else {
 622                 emitInvoke(name);
 623             }
 624         }
 625 
 626         // return statement
 627         emitReturn(onStack);
 628 
 629         classFileEpilogue();
 630         bogusMethod(lambdaForm);
 631 
 632         final byte[] classFile = cw.toByteArray();
 633         maybeDump(className, classFile);
 634         return classFile;
 635     }
 636 





























 637     /**
 638      * Emit an invoke for the given name.
 639      */
 640     void emitInvoke(Name name) {
 641         assert(!isLinkerMethodInvoke(name));  // should use the static path for these
 642         if (true) {
 643             // push receiver
 644             MethodHandle target = name.function.resolvedHandle;
 645             assert(target != null) : name.exprString();
 646             mv.visitLdcInsn(constantPlaceholder(target));
 647             emitReferenceCast(MethodHandle.class, target);
 648         } else {
 649             // load receiver
 650             emitAloadInsn(0);
 651             emitReferenceCast(MethodHandle.class, null);
 652             mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
 653             mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
 654             // TODO more to come
 655         }
 656 


 824     }
 825 
 826     static boolean isArrayBuilder(MethodHandle fn) {
 827         if (fn == null)
 828             return false;
 829         MethodType mtype = fn.type();
 830         Class<?> rtype = mtype.returnType();
 831         Class<?> arrayElementType = rtype.getComponentType();
 832         if (arrayElementType == null)
 833             return false;
 834         List<Class<?>> ptypes = mtype.parameterList();
 835         int size = ptypes.size();
 836         if (!ptypes.equals(Collections.nCopies(size, arrayElementType)))
 837             return false;
 838         // Assume varargsArray caches pointers.
 839         if (fn != ValueConversions.varargsArray(rtype, size))
 840             return false;
 841         return true;
 842     }
 843 





 844     /**
 845      * Check if MemberName is a call to a method named {@code name} in class {@code declaredClass}.
 846      */
 847     private boolean memberRefersTo(MemberName member, Class<?> declaringClass, String name) {
 848         return member != null &&
 849                member.getDeclaringClass() == declaringClass &&
 850                member.getName().equals(name);
 851     }
 852     private boolean nameRefersTo(Name name, Class<?> declaringClass, String methodName) {
 853         return name.function != null &&
 854                memberRefersTo(name.function.member(), declaringClass, methodName);
 855     }
 856 
 857     /**
 858      * Check if MemberName is a call to MethodHandle.invokeBasic.
 859      */
 860     private boolean isInvokeBasic(Name name) {
 861         if (name.function == null)
 862             return false;
 863         if (name.arguments.length < 1)




  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang.invoke;
  27 
  28 import java.io.*;
  29 import java.util.*;
  30 import java.lang.reflect.Modifier;
  31 
  32 import jdk.internal.org.objectweb.asm.*;
  33 
  34 import static java.lang.invoke.LambdaForm.*;
  35 import static java.lang.invoke.LambdaForm.BasicType.*;
  36 import static java.lang.invoke.MethodHandleStatics.*;
  37 import static java.lang.invoke.MethodHandleNatives.Constants.*;
  38 import java.lang.invoke.MethodHandleImpl.ArrayAccessor;
  39 import sun.invoke.util.ValueConversions;
  40 import sun.invoke.util.VerifyAccess;
  41 import sun.invoke.util.VerifyType;
  42 import sun.invoke.util.Wrapper;
  43 import sun.reflect.misc.ReflectUtil;
  44 
  45 /**
  46  * Code generation backend for LambdaForm.
  47  * <p>
  48  * @author John Rose, JSR 292 EG
  49  */
  50 class InvokerBytecodeGenerator {
  51     /** Define class names for convenience. */
  52     private static final String MH      = "java/lang/invoke/MethodHandle";
  53     private static final String MHI     = "java/lang/invoke/MethodHandleImpl";
  54     private static final String LF      = "java/lang/invoke/LambdaForm";
  55     private static final String LFN     = "java/lang/invoke/LambdaForm$Name";
  56     private static final String CLS     = "java/lang/Class";
  57     private static final String OBJ     = "java/lang/Object";
  58     private static final String OBJARY  = "[Ljava/lang/Object;";


 411     private void emitStoreInsn(BasicType type, int index) {
 412         int opcode = storeInsnOpcode(type);
 413         mv.visitVarInsn(opcode, localsMap[index]);
 414     }
 415 
 416     private int storeInsnOpcode(BasicType type) throws InternalError {
 417         switch (type) {
 418             case I_TYPE: return Opcodes.ISTORE;
 419             case J_TYPE: return Opcodes.LSTORE;
 420             case F_TYPE: return Opcodes.FSTORE;
 421             case D_TYPE: return Opcodes.DSTORE;
 422             case L_TYPE: return Opcodes.ASTORE;
 423             default:
 424                 throw new InternalError("unknown type: " + type);
 425         }
 426     }
 427     private void emitAstoreInsn(int index) {
 428         emitStoreInsn(L_TYPE, index);
 429     }
 430 
 431     private byte arrayTypeCode(Wrapper elementType) {
 432         switch (elementType) {
 433             case BOOLEAN: return Opcodes.T_BOOLEAN;
 434             case BYTE:    return Opcodes.T_BYTE;
 435             case CHAR:    return Opcodes.T_CHAR;
 436             case SHORT:   return Opcodes.T_SHORT;
 437             case INT:     return Opcodes.T_INT;
 438             case LONG:    return Opcodes.T_LONG;
 439             case FLOAT:   return Opcodes.T_FLOAT;
 440             case DOUBLE:  return Opcodes.T_DOUBLE;
 441             case OBJECT:  return 0; // in place of Opcodes.T_OBJECT
 442             default:      throw new InternalError();
 443         }
 444     }
 445 
 446     private int arrayInsnOpcode(byte tcode, int aaop) throws InternalError {
 447         assert(aaop == Opcodes.AASTORE || aaop == Opcodes.AALOAD);
 448         int xas;
 449         switch (tcode) {
 450             case Opcodes.T_BOOLEAN: xas = Opcodes.BASTORE; break;
 451             case Opcodes.T_BYTE:    xas = Opcodes.BASTORE; break;
 452             case Opcodes.T_CHAR:    xas = Opcodes.CASTORE; break;
 453             case Opcodes.T_SHORT:   xas = Opcodes.SASTORE; break;
 454             case Opcodes.T_INT:     xas = Opcodes.IASTORE; break;
 455             case Opcodes.T_LONG:    xas = Opcodes.LASTORE; break;
 456             case Opcodes.T_FLOAT:   xas = Opcodes.FASTORE; break;
 457             case Opcodes.T_DOUBLE:  xas = Opcodes.DASTORE; break;
 458             case 0:                 xas = Opcodes.AASTORE; break;
 459             default:      throw new InternalError();
 460         }
 461         return xas - Opcodes.AASTORE + aaop;
 462     }
 463 
 464 
 465     private void freeFrameLocal(int oldFrameLocal) {
 466         int i = indexForFrameLocal(oldFrameLocal);
 467         if (i < 0)  return;
 468         BasicType type = localTypes[i];
 469         int newFrameLocal = makeLocalTemp(type);
 470         mv.visitVarInsn(loadInsnOpcode(type), oldFrameLocal);
 471         mv.visitVarInsn(storeInsnOpcode(type), newFrameLocal);
 472         assert(localsMap[i] == oldFrameLocal);
 473         localsMap[i] = newFrameLocal;
 474         assert(indexForFrameLocal(oldFrameLocal) < 0);
 475     }
 476     private int indexForFrameLocal(int frameLocal) {
 477         for (int i = 0; i < localsMap.length; i++) {
 478             if (localsMap[i] == frameLocal && localTypes[i] != V_TYPE)
 479                 return i;
 480         }
 481         return -1;
 482     }
 483     private int makeLocalTemp(BasicType type) {
 484         int frameLocal = localsMap[localsMap.length - 1];


 634 
 635         // iterate over the form's names, generating bytecode instructions for each
 636         // start iterating at the first name following the arguments
 637         Name onStack = null;
 638         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
 639             Name name = lambdaForm.names[i];
 640             MemberName member = name.function.member();
 641             Class<?> rtype = name.function.methodType().returnType();
 642 
 643             emitStoreResult(onStack);
 644             onStack = name;  // unless otherwise modified below
 645 
 646             if (isSelectAlternative(i)) {
 647                 onStack = emitSelectAlternative(name, lambdaForm.names[i + 1]);
 648                 i++;  // skip MH.invokeBasic of the selectAlternative result
 649             } else if (isGuardWithCatch(i)) {
 650                 onStack = emitGuardWithCatch(i);
 651                 i = i+2; // Jump to the end of GWC idiom
 652             } else if (isNewArray(rtype, name)) {
 653                 emitNewArray(rtype, name);
 654             } else if (isArrayLoad(member)) {
 655                 emitArrayLoad(name);
 656             } else if (isArrayStore(member)) {
 657                 emitArrayStore(name);
 658             } else if (isStaticallyInvocable(member)) {
 659                 emitStaticInvoke(name);
 660             } else {
 661                 emitInvoke(name);
 662             }
 663         }
 664 
 665         // return statement
 666         emitReturn(onStack);
 667 
 668         classFileEpilogue();
 669         bogusMethod(lambdaForm);
 670 
 671         final byte[] classFile = cw.toByteArray();
 672         maybeDump(className, classFile);
 673         return classFile;
 674     }
 675 
 676     boolean isArrayLoad(MemberName member) {
 677         return  member != null &&
 678                 member.getDeclaringClass() == ArrayAccessor.class &&
 679                 member.getName() != null &&
 680                 member.getName().startsWith("getElement");
 681     }
 682 
 683     boolean isArrayStore(MemberName member) {
 684         return  member != null &&
 685                 member.getDeclaringClass() == ArrayAccessor.class &&
 686                 member.getName() != null &&
 687                 member.getName().startsWith("setElement");
 688     }
 689 
 690     void emitArrayLoad(Name name)  { emitArrayOp(name, Opcodes.AALOAD);  }
 691     void emitArrayStore(Name name) { emitArrayOp(name, Opcodes.AASTORE); }
 692 
 693     void emitArrayOp(Name name, int arrayOpcode) {
 694         assert arrayOpcode == Opcodes.AALOAD || arrayOpcode == Opcodes.AASTORE;
 695         Class<?> elementType = name.function.methodType().parameterType(0).getComponentType();
 696         assert elementType != null;
 697         emitPushArguments(name);
 698         if (elementType.isPrimitive()) {
 699             Wrapper w = Wrapper.forPrimitiveType(elementType);
 700             arrayOpcode = arrayInsnOpcode(arrayTypeCode(w), arrayOpcode);
 701         }
 702         mv.visitInsn(arrayOpcode);
 703     }
 704 
 705     /**
 706      * Emit an invoke for the given name.
 707      */
 708     void emitInvoke(Name name) {
 709         assert(!isLinkerMethodInvoke(name));  // should use the static path for these
 710         if (true) {
 711             // push receiver
 712             MethodHandle target = name.function.resolvedHandle;
 713             assert(target != null) : name.exprString();
 714             mv.visitLdcInsn(constantPlaceholder(target));
 715             emitReferenceCast(MethodHandle.class, target);
 716         } else {
 717             // load receiver
 718             emitAloadInsn(0);
 719             emitReferenceCast(MethodHandle.class, null);
 720             mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG);
 721             mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG);
 722             // TODO more to come
 723         }
 724 


 892     }
 893 
 894     static boolean isArrayBuilder(MethodHandle fn) {
 895         if (fn == null)
 896             return false;
 897         MethodType mtype = fn.type();
 898         Class<?> rtype = mtype.returnType();
 899         Class<?> arrayElementType = rtype.getComponentType();
 900         if (arrayElementType == null)
 901             return false;
 902         List<Class<?>> ptypes = mtype.parameterList();
 903         int size = ptypes.size();
 904         if (!ptypes.equals(Collections.nCopies(size, arrayElementType)))
 905             return false;
 906         // Assume varargsArray caches pointers.
 907         if (fn != ValueConversions.varargsArray(rtype, size))
 908             return false;
 909         return true;
 910     }
 911 
 912     static boolean match(MemberName member, MethodHandle fn) {
 913         if (member == null || fn == null)  return false;
 914         return member.equals(fn.internalMemberName());
 915     }
 916 
 917     /**
 918      * Check if MemberName is a call to a method named {@code name} in class {@code declaredClass}.
 919      */
 920     private boolean memberRefersTo(MemberName member, Class<?> declaringClass, String name) {
 921         return member != null &&
 922                member.getDeclaringClass() == declaringClass &&
 923                member.getName().equals(name);
 924     }
 925     private boolean nameRefersTo(Name name, Class<?> declaringClass, String methodName) {
 926         return name.function != null &&
 927                memberRefersTo(name.function.member(), declaringClass, methodName);
 928     }
 929 
 930     /**
 931      * Check if MemberName is a call to MethodHandle.invokeBasic.
 932      */
 933     private boolean isInvokeBasic(Name name) {
 934         if (name.function == null)
 935             return false;
 936         if (name.arguments.length < 1)


src/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File