1 /*
   2  * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  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 jdk.experimental.bytecode.AnnotationsBuilder;
  29 import jdk.experimental.bytecode.MacroCodeBuilder.FieldAccessKind;
  30 import jdk.experimental.bytecode.MacroCodeBuilder.InvocationKind;
  31 import jdk.experimental.bytecode.MethodBuilder;
  32 import jdk.experimental.bytecode.TypeTag;
  33 import jdk.experimental.value.MethodHandleBuilder;
  34 import sun.invoke.util.VerifyType;
  35 import sun.invoke.util.Wrapper;
  36 import valhalla.shady.MinimalValueTypes_1_0;
  37 
  38 import java.lang.invoke.LambdaForm.BasicType;
  39 import java.lang.invoke.LambdaForm.Name;
  40 import java.lang.invoke.MethodHandles.Lookup;
  41 
  42 import static java.lang.invoke.LambdaForm.BasicType.L_TYPE;
  43 import static java.lang.invoke.LambdaForm.BasicType.V_TYPE;
  44 import static java.lang.invoke.LambdaForm.BasicType.basicType;
  45 import static java.lang.invoke.MethodHandleNatives.Constants.REF_getField;
  46 import static java.lang.invoke.MethodHandleNatives.Constants.REF_getStatic;
  47 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeInterface;
  48 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeSpecial;
  49 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeStatic;
  50 import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeVirtual;
  51 import static java.lang.invoke.MethodHandleNatives.Constants.REF_putField;
  52 import static java.lang.invoke.MethodHandleNatives.Constants.REF_putStatic;
  53 import static java.lang.invoke.MethodHandleStatics.PROFILE_LEVEL;
  54 import static java.lang.invoke.MethodHandleStatics.newInternalError;
  55 
  56 /**
  57  * Utility class for spinning classfiles associated with lambda forms.
  58  */
  59 class LambdaFormBuilder extends MethodHandleBuilder {
  60 
  61     private static final String OBJ     = "java/lang/Object";
  62     private static final String CLASS_PREFIX   = "java/lang/invoke/LambdaForm$Value$";
  63     private static final String DEFAULT_CLASS  = "MH";
  64     private static final String LL_SIG  = "(L" + OBJ + ";)L" + OBJ + ";";
  65 
  66     static MemberName generateCustomizedCode(LambdaForm form, MethodType invokerType) {
  67         String invokerName = form.lambdaName();
  68         int p = invokerName.indexOf('.');
  69         boolean overrideNames = p != -1;
  70         String methodName = overrideNames ? invokerName.substring(p + 1) : invokerName;
  71         String className = overrideNames ?
  72                 CLASS_PREFIX + invokerName.substring(0, p) :
  73                 CLASS_PREFIX + DEFAULT_CLASS;
  74         if (MinimalValueTypes_1_0.DUMP_CLASS_FILES) {
  75             // When DUMP_CLASS_FILES is true methodName will have a unique id
  76             className = className + "_" + methodName;
  77         }
  78         return MethodHandleBuilder.loadCode(Lookup.IMPL_LOOKUP.in(LambdaForm.class), className, methodName, invokerType.toMethodDescriptorString(),
  79                 M -> new LambdaFormCodeBuilder(form, M), clazz -> InvokerBytecodeGenerator.resolveInvokerMember(clazz, methodName, invokerType),
  80                 C -> new LambdaFormBuilder(C, form, invokerType).generateLambdaFormBody());
  81     }
  82 
  83     LambdaFormCodeBuilder builder;
  84     LambdaForm lambdaForm;
  85     MethodType invokerType;
  86     int maxLocals;
  87     int[] localsMap;
  88 
  89     LambdaFormBuilder(LambdaFormCodeBuilder builder, LambdaForm lambdaForm, MethodType invokerType) {
  90         this.builder = builder;
  91         this.lambdaForm = lambdaForm;
  92         this.invokerType = invokerType;
  93         this.maxLocals = lambdaForm.names.length;
  94         this.localsMap = computeLocalsMap(lambdaForm);
  95     }
  96 
  97     static int[] computeLocalsMap(LambdaForm lform) {
  98         int localsMapSize = lform.names.length;
  99         int[] localsMap = new int[localsMapSize+1]; // last entry of localsMap is count of allocated local slots
 100         for (int i = 0, index = 0; i < localsMap.length; i++) {
 101             localsMap[i] = index;
 102             if (i < lform.names.length) {
 103                 BasicType type = lform.names[i].type();
 104                 index += type.basicTypeSlots();
 105             }
 106         }
 107         return localsMap;
 108     }
 109 
 110     void generateLambdaFormBody() {
 111         // iterate over the form's names, generating bytecode instructions for each
 112         // start iterating at the first name following the arguments
 113         Name onStack = null;
 114         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
 115             Name name = lambdaForm.names[i];
 116 
 117             if (onStack != null && onStack.type != V_TYPE) {
 118                 // non-void: actually assign
 119                 builder.store(fromBasicType(onStack.type), localsMap[onStack.index()]);
 120             }
 121             onStack = name;  // unless otherwise modified below
 122             MemberName member = name.function.member();
 123             if (InvokerBytecodeGenerator.isStaticallyInvocable(member)) {
 124                 emitStaticInvoke(member, name);
 125             } else {
 126                 emitInvoke(name);
 127             }
 128         }
 129         emitReturn(onStack);
 130     }
 131 
 132     /**
 133      * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
 134      */
 135     private void emitReturn(Name onStack) {
 136         // return statement
 137         Class<?> rclass = invokerType.returnType();
 138         BasicType rtype = lambdaForm.returnType();
 139         assert(rtype == basicType(rclass));  // must agree
 140         if (rtype == V_TYPE) {
 141             // void
 142             builder.return_();
 143             // it doesn't matter what rclass is; the JVM will discard any value
 144         } else {
 145             LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
 146 
 147             // put return value on the stack if it is not already there
 148             if (rn != onStack) {
 149                 builder.load(localsMap[lambdaForm.result]);
 150             }
 151 
 152             emitImplicitConversion(rtype, rclass, rn);
 153 
 154             // generate actual return statement
 155             builder.return_(fromBasicType(rtype));
 156         }
 157     }
 158 
 159     /**
 160      * Emit an implicit conversion for an argument which must be of the given pclass.
 161      * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface.
 162      *
 163      * @param ptype type of value present on stack
 164      * @param pclass type of value required on stack
 165      * @param arg compile-time representation of value on stack (Node, constant) or null if none
 166      */
 167     private void emitImplicitConversion(BasicType ptype, Class<?> pclass, Object arg) {
 168         assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
 169         if (pclass == ptype.basicTypeClass() && ptype != L_TYPE)
 170             return;   // nothing to do
 171         switch (ptype) {
 172             case L_TYPE:
 173                 if (VerifyType.isNullConversion(Object.class, pclass, false)) {
 174                     if (PROFILE_LEVEL > 0)
 175                         emitReferenceCast(Object.class, arg);
 176                     return;
 177                 }
 178                 emitReferenceCast(pclass, arg);
 179                 return;
 180             case I_TYPE:
 181                 if (!VerifyType.isNullConversion(int.class, pclass, false))
 182                     builder.conv(fromBasicType(ptype), fromBasicType(BasicType.basicType(pclass)));
 183                 return;
 184             case Q_TYPE:
 185                 if (!MinimalValueTypes_1_0.isValueType(pclass)) {
 186                     builder.vbox(Object.class);
 187                     return;
 188                 }
 189                 assert pclass == arg.getClass();
 190                 return; //assume they are equal
 191         }
 192         throw newInternalError("bad implicit conversion: tc="+ptype+": "+pclass);
 193     }
 194 
 195     private void emitReferenceCast(Class<?> cls, Object arg) {
 196         Name writeBack = null;  // local to write back result
 197         if (arg instanceof Name) {
 198             Name n = (Name) arg;
 199             if (cls.isAssignableFrom(builder.typeOfLocal(localsMap[n.index()])))
 200                 return;  // this cast was already performed
 201             if (lambdaForm.useCount(n) > 1) {
 202                 // This guy gets used more than once.
 203                 writeBack = n;
 204             }
 205         }
 206         if (InvokerBytecodeGenerator.isStaticallyNameable(cls)) {
 207             builder.checkcast(cls);
 208         } else {
 209             builder.ldc(cls)
 210                     .checkcast(Class.class)
 211                     .swap()
 212                     .invokevirtual(Class.class, "cast", LL_SIG, false);
 213             if (Object[].class.isAssignableFrom(cls))
 214                 builder.checkcast(Object[].class);
 215             else if (PROFILE_LEVEL > 0)
 216                 builder.checkcast(Object.class);
 217         }
 218         if (writeBack != null) {
 219             builder.dup().astore(localsMap[writeBack.index()]);
 220         }
 221     }
 222 
 223     /**
 224      * Emit an invoke for the given name, using the MemberName directly.
 225      */
 226     void emitStaticInvoke(MemberName member, Name name) {
 227         assert(member.equals(name.function.member()));
 228         Class<?> defc = member.getDeclaringClass();
 229         String mname = member.getName();
 230         String mtype;
 231         byte refKind = member.getReferenceKind();
 232         if (refKind == REF_invokeSpecial) {
 233             // in order to pass the verifier, we need to convert this to invokevirtual in all cases
 234             assert(member.canBeStaticallyBound()) : member;
 235             refKind = REF_invokeVirtual;
 236         }
 237 
 238         assert(!(member.getDeclaringClass().isInterface() && refKind == REF_invokeVirtual));
 239 
 240         // push arguments
 241         emitPushArguments(name);
 242 
 243         // invocation
 244         if (member.isMethod()) {
 245             mtype = member.getMethodType().toMethodDescriptorString();
 246             builder.invoke(invKindFromRefKind(refKind), defc, mname, mtype,
 247                                member.getDeclaringClass().isInterface());
 248         } else {
 249             mtype = MethodType.toFieldDescriptorString(member.getFieldType());
 250             builder.getfield(fieldKindFromRefKind(refKind), defc, mname, mtype);
 251         }
 252         // Issue a type assertion for the result, so we can avoid casts later.
 253         if (name.type == L_TYPE) {
 254             Class<?> rtype = member.getInvocationType().returnType();
 255             assert(!rtype.isPrimitive());
 256         }
 257     }
 258 
 259     /**
 260      * Emit an invoke for the given name.
 261      */
 262     void emitInvoke(Name name) {
 263         //assert(!isLinkerMethodInvoke(name));  // should use the static path for these
 264         if (true) {
 265             // push receiver
 266             MethodHandle target = name.function.resolvedHandle();
 267             assert(target != null) : name.exprString();
 268             builder.ldc(target);
 269             emitReferenceCast(MethodHandle.class, target);
 270         }
 271 
 272         // push arguments
 273         emitPushArguments(name);
 274 
 275         // invocation
 276         MethodType type = name.function.methodType();
 277         builder.invokevirtual(MethodHandle.class, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
 278     }
 279 
 280     private void emitPushArguments(Name args) {
 281         emitPushArguments(args, 0);
 282     }
 283 
 284     private void emitPushArguments(Name args, int start) {
 285         for (int i = start; i < args.arguments.length; i++) {
 286             emitPushArgument(args, i);
 287         }
 288     }
 289 
 290     private void emitPushArgument(Name name, int paramIndex) {
 291         Object arg = name.arguments[paramIndex];
 292         Class<?> ptype = name.function.methodType().parameterType(paramIndex);
 293         emitPushArgument(ptype, arg);
 294     }
 295 
 296     private void emitPushArgument(Class<?> ptype, Object arg) {
 297         BasicType bptype = basicType(ptype);
 298         if (arg instanceof Name) {
 299             Name n = (Name) arg;
 300             builder.load(fromBasicType(n.type), localsMap[n.index()]);
 301             emitImplicitConversion(n.type, ptype, n);
 302         } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
 303             builder.ldc(arg);
 304         } else {
 305             if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
 306                 builder.ldc(arg);
 307             } else {
 308                 builder.ldc(arg);
 309                 emitImplicitConversion(L_TYPE, ptype, arg);
 310             }
 311         }
 312     }
 313 
 314     TypeTag fromBasicType(BasicType type) {
 315         switch (type) {
 316             case I_TYPE:  return TypeTag.I;
 317             case J_TYPE:  return TypeTag.J;
 318             case F_TYPE:  return TypeTag.F;
 319             case D_TYPE:  return TypeTag.D;
 320             case L_TYPE:  return TypeTag.A;
 321             case V_TYPE:  return TypeTag.V;
 322             case Q_TYPE:  return TypeTag.Q;
 323             default:
 324                 throw new InternalError("unknown type: " + type);
 325         }
 326     }
 327 
 328     InvocationKind invKindFromRefKind(int refKind) {
 329         switch (refKind) {
 330             case REF_invokeVirtual:      return InvocationKind.INVOKEVIRTUAL;
 331             case REF_invokeStatic:       return InvocationKind.INVOKESTATIC;
 332             case REF_invokeSpecial:      return InvocationKind.INVOKESPECIAL;
 333             case REF_invokeInterface:    return InvocationKind.INVOKEINTERFACE;
 334         }
 335         throw new InternalError("refKind="+refKind);
 336     }
 337 
 338     FieldAccessKind fieldKindFromRefKind(int refKind) {
 339         switch (refKind) {
 340             case REF_getField:
 341             case REF_putField:            return FieldAccessKind.INSTANCE;
 342             case REF_getStatic:
 343             case REF_putStatic:          return FieldAccessKind.STATIC;
 344         }
 345         throw new InternalError("refKind="+refKind);
 346     }
 347 
 348     static class LambdaFormCodeBuilder extends MethodHandleCodeBuilder {
 349         public LambdaFormCodeBuilder(LambdaForm form, MethodBuilder<Class<?>, String, byte[]> methodBuilder) {
 350             super(methodBuilder);
 351             if (form.forceInline) {
 352                 methodBuilder.withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljdk/internal/vm/annotation/ForceInline;");
 353             }
 354             methodBuilder.withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljava/lang/invoke/LambdaForm$Hidden;")
 355                     .withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljava/lang/invoke/LambdaForm$Compiled;");
 356         }
 357 
 358         Class<?> typeOfLocal(int index) {
 359             return typeHelper.symbol(state.locals.get(index));
 360         }
 361     }
 362 }