rev 17253 : imported patch 8183131.patch
rev 17240 : Dump classes from LambdaFormBuilder is triggered using
MethodHandleStatics.DUMP_CLASS_FILES. Class names are
extended by the LF invoker name (which should be unique)
when debugging (dumping triggers debugging).
rev 17235 : Add support for Q-types to lambda forms
Note: support is optional, and can be enabled using the flag:
-Dvalhalla.enableValueLambdaForms=true

   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 
  87     LambdaFormBuilder(LambdaFormCodeBuilder builder, LambdaForm lambdaForm, MethodType invokerType) {
  88         this.builder = builder;
  89         this.lambdaForm = lambdaForm;
  90         this.invokerType = invokerType;















  91     }
  92 
  93     void generateLambdaFormBody() {
  94         // iterate over the form's names, generating bytecode instructions for each
  95         // start iterating at the first name following the arguments
  96         Name onStack = null;
  97         for (int i = lambdaForm.arity; i < lambdaForm.names.length; i++) {
  98             Name name = lambdaForm.names[i];
  99 
 100             if (onStack != null && onStack.type != V_TYPE) {
 101                 // non-void: actually assign
 102                 builder.store(fromBasicType(onStack.type), onStack.index());
 103             }
 104             onStack = name;  // unless otherwise modified below
 105             MemberName member = name.function.member();
 106             if (InvokerBytecodeGenerator.isStaticallyInvocable(member)) {
 107                 emitStaticInvoke(member, name);
 108             } else {
 109                 emitInvoke(name);
 110             }
 111         }
 112         emitReturn(onStack);
 113     }
 114 
 115     /**
 116      * Emits a return statement from a LF invoker. If required, the result type is cast to the correct return type.
 117      */
 118     private void emitReturn(Name onStack) {
 119         // return statement
 120         Class<?> rclass = invokerType.returnType();
 121         BasicType rtype = lambdaForm.returnType();
 122         assert(rtype == basicType(rclass));  // must agree
 123         if (rtype == V_TYPE) {
 124             // void
 125             builder.return_();
 126             // it doesn't matter what rclass is; the JVM will discard any value
 127         } else {
 128             LambdaForm.Name rn = lambdaForm.names[lambdaForm.result];
 129 
 130             // put return value on the stack if it is not already there
 131             if (rn != onStack) {
 132                 builder.load(lambdaForm.result);
 133             }
 134 
 135             emitImplicitConversion(rtype, rclass, rn);
 136 
 137             // generate actual return statement
 138             builder.return_(fromBasicType(rtype));
 139         }
 140     }
 141 
 142     /**
 143      * Emit an implicit conversion for an argument which must be of the given pclass.
 144      * This is usually a no-op, except when pclass is a subword type or a reference other than Object or an interface.
 145      *
 146      * @param ptype type of value present on stack
 147      * @param pclass type of value required on stack
 148      * @param arg compile-time representation of value on stack (Node, constant) or null if none
 149      */
 150     private void emitImplicitConversion(BasicType ptype, Class<?> pclass, Object arg) {
 151         assert(basicType(pclass) == ptype);  // boxing/unboxing handled by caller
 152         if (pclass == ptype.basicTypeClass() && ptype != L_TYPE)
 153             return;   // nothing to do
 154         switch (ptype) {
 155             case L_TYPE:
 156                 if (VerifyType.isNullConversion(Object.class, pclass, false)) {
 157                     if (PROFILE_LEVEL > 0)
 158                         emitReferenceCast(Object.class, arg);
 159                     return;
 160                 }
 161                 emitReferenceCast(pclass, arg);
 162                 return;
 163             case I_TYPE:
 164                 if (!VerifyType.isNullConversion(int.class, pclass, false))
 165                     builder.conv(fromBasicType(ptype), fromBasicType(BasicType.basicType(pclass)));
 166                 return;
 167             case Q_TYPE:
 168                 if (!MinimalValueTypes_1_0.isValueType(pclass)) {
 169                     builder.vbox(Object.class);
 170                     return;
 171                 }
 172                 assert pclass == arg.getClass();
 173                 return; //assume they are equal
 174         }
 175         throw newInternalError("bad implicit conversion: tc="+ptype+": "+pclass);
 176     }
 177 
 178     private void emitReferenceCast(Class<?> cls, Object arg) {
 179         Name writeBack = null;  // local to write back result
 180         if (arg instanceof Name) {
 181             Name n = (Name) arg;
 182             if (cls.isAssignableFrom(builder.typeOfLocal(n.index())))
 183                 return;  // this cast was already performed
 184             if (lambdaForm.useCount(n) > 1) {
 185                 // This guy gets used more than once.
 186                 writeBack = n;
 187             }
 188         }
 189         if (InvokerBytecodeGenerator.isStaticallyNameable(cls)) {
 190             builder.checkcast(cls);
 191         } else {
 192             builder.ldc(cls)
 193                     .checkcast(Class.class)
 194                     .swap()
 195                     .invokevirtual(Class.class, "cast", LL_SIG, false);
 196             if (Object[].class.isAssignableFrom(cls))
 197                 builder.checkcast(Object[].class);
 198             else if (PROFILE_LEVEL > 0)
 199                 builder.checkcast(Object.class);
 200         }
 201         if (writeBack != null) {
 202             builder.dup().astore(writeBack.index());
 203         }
 204     }
 205 
 206     /**
 207      * Emit an invoke for the given name, using the MemberName directly.
 208      */
 209     void emitStaticInvoke(MemberName member, Name name) {
 210         assert(member.equals(name.function.member()));
 211         Class<?> defc = member.getDeclaringClass();
 212         String mname = member.getName();
 213         String mtype;
 214         byte refKind = member.getReferenceKind();
 215         if (refKind == REF_invokeSpecial) {
 216             // in order to pass the verifier, we need to convert this to invokevirtual in all cases
 217             assert(member.canBeStaticallyBound()) : member;
 218             refKind = REF_invokeVirtual;
 219         }
 220 
 221         assert(!(member.getDeclaringClass().isInterface() && refKind == REF_invokeVirtual));
 222 
 223         // push arguments
 224         emitPushArguments(name);
 225 
 226         // invocation
 227         if (member.isMethod()) {
 228             mtype = member.getMethodType().toMethodDescriptorString();
 229             builder.invoke(invKindFromRefKind(refKind), defc, mname, mtype,
 230                                member.getDeclaringClass().isInterface());
 231         } else {
 232             mtype = MethodType.toFieldDescriptorString(member.getFieldType());
 233             builder.getfield(fieldKindFromRefKind(refKind), defc, mname, mtype);
 234         }
 235         // Issue a type assertion for the result, so we can avoid casts later.
 236         if (name.type == L_TYPE) {
 237             Class<?> rtype = member.getInvocationType().returnType();
 238             assert(!rtype.isPrimitive());
 239         }
 240     }
 241 
 242     /**
 243      * Emit an invoke for the given name.
 244      */
 245     void emitInvoke(Name name) {
 246         //assert(!isLinkerMethodInvoke(name));  // should use the static path for these
 247         if (true) {
 248             // push receiver
 249             MethodHandle target = name.function.resolvedHandle();
 250             assert(target != null) : name.exprString();
 251             builder.ldc(target);
 252             emitReferenceCast(MethodHandle.class, target);
 253         }
 254 
 255         // push arguments
 256         emitPushArguments(name);
 257 
 258         // invocation
 259         MethodType type = name.function.methodType();
 260         builder.invokevirtual(MethodHandle.class, "invokeBasic", type.basicType().toMethodDescriptorString(), false);
 261     }
 262 
 263     private void emitPushArguments(Name args) {
 264         emitPushArguments(args, 0);
 265     }
 266 
 267     private void emitPushArguments(Name args, int start) {
 268         for (int i = start; i < args.arguments.length; i++) {
 269             emitPushArgument(args, i);
 270         }
 271     }
 272 
 273     private void emitPushArgument(Name name, int paramIndex) {
 274         Object arg = name.arguments[paramIndex];
 275         Class<?> ptype = name.function.methodType().parameterType(paramIndex);
 276         emitPushArgument(ptype, arg);
 277     }
 278 
 279     private void emitPushArgument(Class<?> ptype, Object arg) {
 280         BasicType bptype = basicType(ptype);
 281         if (arg instanceof Name) {
 282             Name n = (Name) arg;
 283             builder.load(fromBasicType(n.type), n.index());
 284             emitImplicitConversion(n.type, ptype, n);
 285         } else if ((arg == null || arg instanceof String) && bptype == L_TYPE) {
 286             builder.ldc(arg);
 287         } else {
 288             if (Wrapper.isWrapperType(arg.getClass()) && bptype != L_TYPE) {
 289                 builder.ldc(arg);
 290             } else {
 291                 builder.ldc(arg);
 292                 emitImplicitConversion(L_TYPE, ptype, arg);
 293             }
 294         }
 295     }
 296 
 297     TypeTag fromBasicType(BasicType type) {
 298         switch (type) {
 299             case I_TYPE:  return TypeTag.I;
 300             case J_TYPE:  return TypeTag.J;
 301             case F_TYPE:  return TypeTag.F;
 302             case D_TYPE:  return TypeTag.D;
 303             case L_TYPE:  return TypeTag.A;
 304             case V_TYPE:  return TypeTag.V;
 305             case Q_TYPE:  return TypeTag.Q;
 306             default:
 307                 throw new InternalError("unknown type: " + type);
 308         }
 309     }
 310 
 311     InvocationKind invKindFromRefKind(int refKind) {
 312         switch (refKind) {
 313             case REF_invokeVirtual:      return InvocationKind.INVOKEVIRTUAL;
 314             case REF_invokeStatic:       return InvocationKind.INVOKESTATIC;
 315             case REF_invokeSpecial:      return InvocationKind.INVOKESPECIAL;
 316             case REF_invokeInterface:    return InvocationKind.INVOKEINTERFACE;
 317         }
 318         throw new InternalError("refKind="+refKind);
 319     }
 320 
 321     FieldAccessKind fieldKindFromRefKind(int refKind) {
 322         switch (refKind) {
 323             case REF_getField:
 324             case REF_putField:            return FieldAccessKind.INSTANCE;
 325             case REF_getStatic:
 326             case REF_putStatic:          return FieldAccessKind.STATIC;
 327         }
 328         throw new InternalError("refKind="+refKind);
 329     }
 330 
 331     static class LambdaFormCodeBuilder extends MethodHandleCodeBuilder {
 332         public LambdaFormCodeBuilder(LambdaForm form, MethodBuilder<Class<?>, String, byte[]> methodBuilder) {
 333             super(methodBuilder);
 334             if (form.forceInline) {
 335                 methodBuilder.withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljdk/internal/vm/annotation/ForceInline;");
 336             }
 337             methodBuilder.withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljava/lang/invoke/LambdaForm$Hidden;")
 338                     .withAnnotation(AnnotationsBuilder.Kind.RUNTIME_VISIBLE, "Ljava/lang/invoke/LambdaForm$Compiled;");
 339         }
 340 
 341         Class<?> typeOfLocal(int index) {
 342             return typeHelper.symbol(state.locals.get(index));
 343         }
 344     }
 345 }
--- EOF ---