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 com.sun.tools.javac.util;
  27 
  28 import java.lang.reflect.Array;
  29 
  30 import java.lang.reflect.InvocationTargetException;
  31 import java.lang.reflect.Method;
  32 import java.lang.reflect.Modifier;
  33 import java.nio.charset.Charset;
  34 import java.util.Optional;
  35 
  36 import com.sun.tools.javac.code.Flags;
  37 import com.sun.tools.javac.code.Kinds.Kind;
  38 import com.sun.tools.javac.code.Scope.WriteableScope;
  39 import com.sun.tools.javac.code.Symbol;
  40 import com.sun.tools.javac.code.Symbol.ClassSymbol;
  41 import com.sun.tools.javac.code.Symbol.CompletionFailure;
  42 import com.sun.tools.javac.code.Symbol.DynamicVarSymbol;
  43 import com.sun.tools.javac.code.Symbol.MethodSymbol;
  44 import com.sun.tools.javac.code.Symbol.ModuleSymbol;
  45 import com.sun.tools.javac.code.Symbol.VarSymbol;
  46 import com.sun.tools.javac.code.Symtab;
  47 import com.sun.tools.javac.code.Type;
  48 import com.sun.tools.javac.code.Type.ArrayType;
  49 import com.sun.tools.javac.code.Type.ClassType;
  50 import com.sun.tools.javac.code.Type.MethodType;
  51 import com.sun.tools.javac.code.TypeTag;
  52 import com.sun.tools.javac.code.Types;
  53 import com.sun.tools.javac.comp.AttrContext;
  54 import com.sun.tools.javac.comp.ConstablesVisitor;
  55 import com.sun.tools.javac.comp.Env;
  56 import com.sun.tools.javac.comp.Resolve;
  57 import com.sun.tools.javac.comp.Resolve.*;
  58 import com.sun.tools.javac.jvm.ClassFile;
  59 import com.sun.tools.javac.jvm.Pool;
  60 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  61 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
  62 import com.sun.tools.javac.tree.JCTree;
  63 import com.sun.tools.javac.tree.JCTree.JCExpression;
  64 import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
  65 import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
  66 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
  67 import com.sun.tools.javac.tree.TreeInfo;
  68 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  69 
  70 import static com.sun.tools.javac.code.Flags.INTERFACE;
  71 import static com.sun.tools.javac.code.Flags.STATIC;
  72 import static com.sun.tools.javac.code.TypeTag.ARRAY;
  73 import static com.sun.tools.javac.tree.JCTree.Tag.SELECT;
  74 
  75 /** This class is a support tool to parse a method descriptor and obtain a list of the types
  76  *  represented in it.
  77  *
  78  *  <p><b>This is NOT part of any supported API.
  79  *  If you write code that depends on this, you do so at your own risk.
  80  *  This code and its internal interfaces are subject to change or
  81  *  deletion without notice.</b>
  82  */
  83 public class Constables {
  84 
  85     protected static final Context.Key<Constables> constablesKey = new Context.Key<>();
  86 
  87     public static Constables instance(Context context) {
  88         Constables instance = context.get(constablesKey);
  89         if (instance == null)
  90             instance = new Constables(context);
  91         return instance;
  92     }
  93 
  94     public Constables(Context context) {
  95         context.put(constablesKey, this);
  96         types = Types.instance(context);
  97         names = Names.instance(context);
  98         syms = Symtab.instance(context);
  99         rs = Resolve.instance(context);
 100         log = Log.instance(context);
 101         constablesVisitor = ConstablesVisitor.instance(context);
 102         try {
 103             directMethodHandleRefClass = Class.forName("java.lang.constant.DirectMethodHandleDesc", false, null);
 104             methodTypeRefClass = Class.forName("java.lang.constant.MethodTypeDesc", false, null);
 105             classRefClass = Class.forName("java.lang.constant.ClassDesc", false, null);
 106             constantRefClass = Class.forName("java.lang.constant.ConstantDesc", false, null);
 107             constableClass = Class.forName("java.lang.constant.Constable", false, null);
 108             dynamicCallsiteRefClass = Class.forName("java.lang.constant.DynamicCallSiteDesc", false, null);
 109             dynamicConstantClass = Class.forName("java.lang.constant.DynamicConstantDesc", false, null);
 110             symRefs = Class.forName("java.lang.constant.ConstantDescs", false, null);
 111         } catch (ClassNotFoundException ex) {
 112             directMethodHandleRefClass = null;
 113             methodTypeRefClass = null;
 114             constableClass = null;
 115             constantRefClass = null;
 116             classRefClass = null;
 117             dynamicCallsiteRefClass = null;
 118             dynamicConstantClass = null;
 119             symRefs = null;
 120         }
 121     }
 122 
 123     private final Types types;
 124     private final Names names;
 125     private final Symtab syms;
 126     private final Resolve rs;
 127     private final Log log;
 128     private ModuleSymbol currentModule;
 129     private final ConstablesVisitor constablesVisitor;
 130 
 131     /** The unread portion of the currently read type is
 132      *  signature[sigp..siglimit-1].
 133      */
 134     byte[] signature;
 135     int sigp;
 136     int siglimit;
 137     boolean sigEnterPhase = false;
 138     byte[] signatureBuffer;
 139     int sbp;
 140 
 141     /** Convert signature to type, where signature is a byte array segment.
 142      */
 143     public Type descriptorToType(String descriptor, ModuleSymbol currentModule, boolean methodDescriptor) {
 144         byte[] sig = descriptor.getBytes(Charset.forName("UTF-8"));
 145         signature = sig;
 146         sigp = 0;
 147         siglimit = sig.length - 1;
 148         sbp = 0;
 149         signatureBuffer = new byte[sig.length];
 150         this.currentModule = currentModule;
 151         try {
 152             if (methodDescriptor) {
 153                 return internalMethodDescriptorToType();
 154             } else { // type descriptor
 155                 return sigToType();
 156             }
 157         } catch (AssertionError ae) {
 158             return Type.noType;
 159         }
 160     }
 161 
 162     private Type internalMethodDescriptorToType() {
 163         if (signature[sigp] != '(') {
 164             throw new AssertionError("bad descriptor");
 165         }
 166         sigp++;
 167         List<Type> argtypes = sigToTypes(')');
 168         Type restype = sigToType();
 169         return new MethodType(argtypes,
 170                               restype,
 171                               List.nil(),
 172                               syms.methodClass);
 173     }
 174 
 175     /** Convert signature to type, where signature is implicit.
 176      */
 177     Type sigToType() {
 178         switch ((char) signature[sigp]) {
 179         case 'B':
 180             sigp++;
 181             return syms.byteType;
 182         case 'C':
 183             sigp++;
 184             return syms.charType;
 185         case 'D':
 186             sigp++;
 187             return syms.doubleType;
 188         case 'F':
 189             sigp++;
 190             return syms.floatType;
 191         case 'I':
 192             sigp++;
 193             return syms.intType;
 194         case 'J':
 195             sigp++;
 196             return syms.longType;
 197         case 'L':
 198             {
 199                 Type t = classSigToType();
 200                 if (sigp < siglimit && signature[sigp] == '.') {
 201                     throw new AssertionError("deprecated inner class signature syntax");
 202                 }
 203                 return t;
 204             }
 205         case 'S':
 206             sigp++;
 207             return syms.shortType;
 208         case 'V':
 209             sigp++;
 210             return syms.voidType;
 211         case 'Z':
 212             sigp++;
 213             return syms.booleanType;
 214         case '[':
 215             sigp++;
 216             return new ArrayType(sigToType(), syms.arrayClass);
 217         default:
 218             throw new AssertionError("bad descriptor");
 219         }
 220     }
 221 
 222     /** Convert class signature to type, where signature is implicit.
 223      */
 224     Type classSigToType() {
 225         if (signature[sigp] != 'L') {
 226             throw new AssertionError("bad descriptor");
 227         }
 228         sigp++;
 229         Type outer = Type.noType;
 230         int startSbp = sbp;
 231 
 232         while (true) {
 233             final byte c = signature[sigp++];
 234             switch (c) {
 235 
 236             case ';': {         // end
 237                 ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
 238                                                          startSbp,
 239                                                          sbp - startSbp));
 240 
 241                 try {
 242                     return (outer == Type.noType) ?
 243                             t.erasure(types) :
 244                         new ClassType(outer, List.<Type>nil(), t);
 245                 } finally {
 246                     sbp = startSbp;
 247                 }
 248             }
 249             case '.':
 250                 //we have seen an enclosing non-generic class
 251                 if (outer != Type.noType) {
 252                     ClassSymbol t = enterClass(names.fromUtf(signatureBuffer,
 253                                                  startSbp,
 254                                                  sbp - startSbp));
 255                     outer = new ClassType(outer, List.<Type>nil(), t);
 256                 }
 257                 signatureBuffer[sbp++] = (byte)'$';
 258                 continue;
 259             case '/':
 260                 signatureBuffer[sbp++] = (byte)'.';
 261                 continue;
 262             default:
 263                 signatureBuffer[sbp++] = c;
 264                 continue;
 265             }
 266         }
 267     }
 268 
 269     ClassSymbol enterClass(Name name) {
 270         return syms.enterClass(currentModule, name);
 271     }
 272 
 273     /** Convert (implicit) signature to list of types
 274      *  until `terminator' is encountered.
 275      */
 276     List<Type> sigToTypes(char terminator) {
 277         List<Type> head = List.of(null);
 278         List<Type> tail = head;
 279         while (signature[sigp] != terminator)
 280             tail = tail.setTail(List.of(sigToType()));
 281         sigp++;
 282         return head.tail;
 283     }
 284 
 285     public Optional<DynamicVarSymbol> getDynamicFieldSymbol(JCTree tree, Object constant, Env<AttrContext> attrEnv) {
 286         if (constant != null) {
 287             if (!canMakeItToConstantValue(tree.type) &&
 288                 constableClass.isInstance(constant)) {
 289                 Optional<?> optional = ((Optional<?>)invokeMethodReflectively(constableClass, constant, "describeConstable"));
 290                 if (!optional.isPresent()) {
 291                     return Optional.empty();
 292                 }
 293                 constant = optional.get();
 294                 // now this should be a condy that the compiler can understand
 295                 // a Pool.ConstantDynamic
 296                 Object condyOb = convertConstant(tree, attrEnv, constant, attrEnv.enclClass.sym.packge().modle);
 297                 if (condyOb instanceof Pool.DynamicVariable) {
 298                     Pool.DynamicVariable condy = (Pool.DynamicVariable)condyOb;
 299                     DynamicVarSymbol dynSym = new DynamicVarSymbol(condy.name,
 300                             syms.noSymbol,
 301                             condy.bsm.refKind,
 302                             (MethodSymbol)condy.bsm.refSym,
 303                             condy.type,
 304                             condy.staticArgs());
 305                     return Optional.of(dynSym);
 306                 }
 307             }
 308         }
 309         return Optional.empty();
 310     }
 311 
 312     public Object convertConstant(JCTree tree, Env<AttrContext> attrEnv, Object constant, ModuleSymbol currentModule) {
 313         return convertConstant(tree, attrEnv, constant, currentModule, false);
 314     }
 315 
 316     public Object convertConstant(JCTree tree, Env<AttrContext> attrEnv, Object constant, ModuleSymbol currentModule, boolean bsmArg) {
 317         if (directMethodHandleRefClass.isInstance(constant)) {
 318             String name = (String)invokeMethodReflectively(directMethodHandleRefClass, constant, "methodName");
 319             int refKind = (int)invokeMethodReflectively(directMethodHandleRefClass, constant, "refKind");
 320             Object owner = invokeMethodReflectively(directMethodHandleRefClass, constant, "owner");
 321             String ownerDescriptor = (String)invokeMethodReflectively(classRefClass, owner, "descriptorString");
 322             Type ownerType = descriptorToType(ownerDescriptor, currentModule, false);
 323             Object mtConstant = invokeMethodReflectively(directMethodHandleRefClass, constant, "methodType");
 324             String methodTypeDesc = (String)invokeMethodReflectively(methodTypeRefClass, mtConstant, "descriptorString");
 325             MethodType mType = (MethodType)descriptorToType(methodTypeDesc, currentModule, true);
 326             // this method generates fake symbols as needed
 327             Pair<Symbol, Boolean> refSymbolPair = getReferenceSymbol(tree, refKind, ownerType.tsym, name, mType);
 328             boolean ownerFound = true;
 329             try {
 330                 refSymbolPair.fst.owner.complete();
 331             } catch (CompletionFailure ex) {
 332                 log.warning(tree, Warnings.ClassNotFound(refSymbolPair.fst.owner));
 333                 ownerFound = false;
 334             }
 335             if (ownerFound) {
 336                 ownerType = refSymbolPair.fst.owner.type;
 337                 checkIfMemberExists(tree, attrEnv, names.fromString(name), ownerType, mType.argtypes, refKind, refSymbolPair.snd);
 338             }
 339             Pool.MethodHandle mHandle = new Pool.MethodHandle(refKind, refSymbolPair.fst, types,
 340                     new Pool.MethodHandle.DumbMethodHandleCheckHelper(refKind, refSymbolPair.fst));
 341             return mHandle;
 342         } else if (methodTypeRefClass.isInstance(constant)) {
 343             String descriptor = (String)invokeMethodReflectively(methodTypeRefClass, constant, "descriptorString");
 344             return types.erasure(descriptorToType(descriptor, currentModule, true));
 345         } else if (classRefClass.isInstance(constant)) {
 346             String descriptor = (String)invokeMethodReflectively(classRefClass, constant, "descriptorString");
 347             if (descriptor.length() == 1) {
 348                 Object BSM_PRIMITIVE_CLASS = getFieldValueReflectively(symRefs, null, "BSM_PRIMITIVE_CLASS");
 349                 Pool.MethodHandle methodHandle = (Pool.MethodHandle)convertConstant(tree, attrEnv,
 350                         BSM_PRIMITIVE_CLASS, currentModule);
 351                 return new Pool.DynamicVariable(names.fromString(descriptor), methodHandle, new Object[0], types, syms);
 352             }
 353             Type type = descriptorToType(descriptor, currentModule, false);
 354             Symbol symToLoad;
 355             if (!type.hasTag(ARRAY)) {
 356                 symToLoad = type.tsym;
 357             } else {
 358                 Type elt = type;
 359                 while (elt.hasTag(ARRAY)) {
 360                     elt = ((ArrayType)elt).elemtype;
 361                 }
 362                 symToLoad = elt.tsym;
 363             }
 364             try {
 365                 symToLoad.complete();
 366             } catch (CompletionFailure ex) {
 367                 log.warning(tree, Warnings.ClassNotFound(symToLoad));
 368             }
 369             return type.hasTag(ARRAY) ? type : type.tsym;
 370         } else if (dynamicConstantClass.isInstance(constant)) {
 371             Object classRef =
 372                     invokeMethodReflectively(dynamicConstantClass, constant, "constantType");
 373             String descriptor = (String)invokeMethodReflectively(classRefClass, classRef, "descriptorString");
 374             Type type = descriptorToType(descriptor, attrEnv.enclClass.sym.packge().modle, false);
 375             String name = (String)invokeMethodReflectively(dynamicConstantClass, constant, "constantName");
 376             Object mh = invokeMethodReflectively(dynamicConstantClass, constant, "bootstrapMethod");
 377             Pool.MethodHandle methodHandle = (Pool.MethodHandle)convertConstant(tree, attrEnv, mh, currentModule);
 378             Object[] args = (Object[])invokeMethodReflectively(dynamicConstantClass, constant, "bootstrapArgs");
 379             Object[] convertedArgs = convertConstants(tree, attrEnv, args, currentModule, true);
 380             return new Pool.DynamicVariable(names.fromString(name), methodHandle, type, convertedArgs, types, syms);
 381         }
 382         return constant;
 383     }
 384     // where
 385         private ClassSymbol boxedClass(String descriptor) {
 386             switch (descriptor) {
 387                 case "I": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.INT.ordinal()]);
 388                 case "J": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.LONG.ordinal()]);
 389                 case "S": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.SHORT.ordinal()]);
 390                 case "B": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.BYTE.ordinal()]);
 391                 case "C": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.CHAR.ordinal()]);
 392                 case "F": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.FLOAT.ordinal()]);
 393                 case "D": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.DOUBLE.ordinal()]);
 394                 case "Z": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.BOOLEAN.ordinal()]);
 395                 case "V": return syms.enterClass(syms.java_base, syms.boxedName[TypeTag.VOID.ordinal()]);
 396                 default:
 397                     throw new AssertionError("invalid primitive descriptor " + descriptor);
 398             }
 399         }
 400 
 401         private void checkIfMemberExists(DiagnosticPosition pos, Env<AttrContext> attrEnv, Name name, Type qual, List<Type> args, int refKind, boolean warned) {
 402             Symbol refSym = resolveConstableMethod(pos, attrEnv, qual, name, args, List.nil());
 403             if (refSym.kind.isResolutionError()) {
 404                 try {
 405                     refSym = rs.resolveInternalField(pos, attrEnv, qual, name);
 406                 } catch (Throwable t) {
 407                     if (!warned) {
 408                         // don't double warn
 409                         log.warning(pos, Warnings.MemberNotFoundAtClass(name,
 410                                 (qual.tsym.flags_field & INTERFACE) == 0 ? "class" : "interface", qual.tsym));
 411                     }
 412                     return;
 413                 }
 414             }
 415             Pool.MethodHandle.WarnMethodHandleCheckHelper mhCheckHelper = new Pool.MethodHandle.WarnMethodHandleCheckHelper(log, pos, refKind, refSym);
 416             mhCheckHelper.check();
 417         }
 418 
 419         public Symbol resolveConstableMethod(DiagnosticPosition pos, Env<AttrContext> env,
 420                                     Type site, Name name,
 421                                     List<Type> argtypes,
 422                                     List<Type> typeargtypes) {
 423             MethodResolutionContext resolveContext = rs.new MethodResolutionContext();
 424             resolveContext.internalResolution = true;
 425             resolveContext.silentFail = true;
 426             Symbol sym = rs.resolveQualifiedMethod(resolveContext, pos, env, site.tsym,
 427                     site, name, argtypes, typeargtypes);
 428             return sym;
 429         }
 430 
 431     public Object[] convertConstants(JCTree tree, Env<AttrContext> attrEnv, Object[] constants, ModuleSymbol currentModule, boolean bsmArgs) {
 432         if (constants == null || constants.length == 0) {
 433             return constants;
 434         }
 435         Object[] result = new Object[constants.length];
 436         int i = 0;
 437         for (Object constant : constants) {
 438             result[i] = convertConstant(tree, attrEnv, constant, currentModule, bsmArgs);
 439             i++;
 440         }
 441         return result;
 442     }
 443 
 444     public Class<?> directMethodHandleRefClass;
 445     public Class<?> methodTypeRefClass;
 446     public Class<?> classRefClass;
 447     public Class<?> constableClass;
 448     public Class<?> constantRefClass;
 449     public Class<?> dynamicCallsiteRefClass;
 450     public Class<?> dynamicConstantClass;
 451     public Class<?> symRefs;
 452 
 453     public boolean canMakeItToConstantValue(Type t) {
 454         return t.isPrimitive() || t.tsym == syms.stringType.tsym;
 455     }
 456 
 457     public boolean skipCodeGeneration(JCVariableDecl tree) {
 458         if (tree.init != null) {
 459             VarSymbol v = tree.sym;
 460             Object constant = v.getConstValue();
 461             boolean canMakeItToConstant = canMakeItToConstantValue(v.type);
 462             return (constant != null &&
 463                 (canMakeItToConstant ||
 464                     constantRefClass.isInstance(constant) ||
 465                     dynamicCallsiteRefClass.isInstance(constant)) &&
 466                 v.isLocal() &&
 467                 v.owner.kind == Kind.MTH &&
 468                 (v.isFinal() || v.isEffectivelyFinal()));
 469         }
 470         return false;
 471     }
 472 
 473     boolean canHaveInterfaceOwner(int refKind) {
 474         switch (refKind) {
 475             case ClassFile.REF_invokeStatic:
 476             case ClassFile.REF_invokeSpecial:
 477             case ClassFile.REF_invokeInterface:
 478             case ClassFile.REF_getStatic:
 479             case ClassFile.REF_putStatic:
 480                 return true;
 481             default:
 482                 return false;
 483         }
 484     }
 485 
 486     String refKindToString(int refKind) {
 487         switch (refKind) {
 488             case ClassFile.REF_newInvokeSpecial :
 489                 return "REF_newInvokeSpecial";
 490             case ClassFile.REF_invokeVirtual:
 491                 return "REF_invokeVirtual";
 492             case ClassFile.REF_invokeStatic:
 493                 return "REF_invokeStatic";
 494             case ClassFile.REF_invokeSpecial:
 495                 return "REF_invokeSpecial";
 496             case ClassFile.REF_invokeInterface:
 497                 return "REF_invokeInterface";
 498             case ClassFile.REF_putField:
 499                 return "REF_putField";
 500             case ClassFile.REF_putStatic:
 501                 return "REF_putStatic";
 502             case ClassFile.REF_getField:
 503                 return "REF_getField";
 504             case ClassFile.REF_getStatic:
 505                 return "REF_getStatic";
 506             default:
 507                 throw new AssertionError("invalid refKind value " + refKind);
 508         }
 509     }
 510 
 511     boolean checkMethodTypeShape(JCTree tree, int refKind, MethodType methodType) {
 512         boolean error;
 513         switch (refKind) {
 514             case ClassFile.REF_newInvokeSpecial :
 515                 error = !methodType.restype.hasTag(TypeTag.VOID);
 516                 break;
 517             case ClassFile.REF_invokeVirtual:
 518             case ClassFile.REF_invokeStatic:
 519             case ClassFile.REF_invokeSpecial:
 520             case ClassFile.REF_invokeInterface:
 521                 error = false;
 522                 break;
 523             case ClassFile.REF_putField:
 524                 error = methodType.argtypes.size() != 2 || !methodType.restype.hasTag(TypeTag.VOID);
 525                 break;
 526             case ClassFile.REF_putStatic:
 527                 error = methodType.argtypes.size() != 1 || !methodType.restype.hasTag(TypeTag.VOID);
 528                 break;
 529             case ClassFile.REF_getField:
 530                 error = methodType.argtypes.size() != 1 || methodType.restype.hasTag(TypeTag.VOID);
 531                 break;
 532             case ClassFile.REF_getStatic:
 533                 error = methodType.argtypes.size() > 0 || methodType.restype.hasTag(TypeTag.VOID);
 534                 break;
 535             default:
 536                 throw new AssertionError("invalid refKind value " + refKind);
 537         }
 538         if (error) {
 539             log.error(tree, Errors.BadMethodTypeShape(methodType, refKindToString(refKind)));
 540         }
 541         if (methodType.argtypes.stream().filter(t -> t.hasTag(TypeTag.VOID)).findAny().isPresent()) {
 542             log.error(tree, Errors.BadMethodTypeShapeArgWithTypeVoid(methodType));
 543         }
 544         return !error;
 545     }
 546 
 547     private Pair<Symbol, Boolean> getReferenceSymbol(JCTree tree, int refKind, Symbol owner, String name, MethodType methodType) {
 548         if (!checkMethodTypeShape(tree, refKind, methodType)) {
 549             return new Pair<>(syms.noSymbol, false);
 550         }
 551         long flags = refKind == ClassFile.REF_getStatic ||
 552                 refKind == ClassFile.REF_putStatic ||
 553                 refKind == ClassFile.REF_invokeStatic ? STATIC : 0;
 554         flags |= Flags.PUBLIC;
 555         Name symbolName = refKind == ClassFile.REF_newInvokeSpecial ? names.init : names.fromString(name);
 556         boolean canHaveInterfaceOwner = canHaveInterfaceOwner(refKind);
 557         switch (refKind) {
 558             case ClassFile.REF_newInvokeSpecial :
 559             case ClassFile.REF_invokeVirtual:
 560             case ClassFile.REF_invokeStatic:
 561             case ClassFile.REF_invokeSpecial:
 562             case ClassFile.REF_invokeInterface:
 563                 if (refKind == ClassFile.REF_invokeInterface && (owner.flags_field & INTERFACE) == 0) {
 564                     Symbol result = generateMethodSymbolHelper(owner, symbolName, methodType, flags, true);
 565                     log.warning(tree, Warnings.MemberNotFoundAtClass(symbolName, "interface", result.owner));
 566                     return new Pair<>(result, true);
 567                 }
 568                 if (!canHaveInterfaceOwner && (owner.flags_field & INTERFACE) != 0) {
 569                     Symbol result = generateMethodSymbolHelper(owner, symbolName, methodType, flags, false);
 570                     log.warning(tree, Warnings.MemberNotFoundAtClass(symbolName, "class", result.owner));
 571                     return new Pair<>(result, true);
 572                 }
 573                 return new Pair<>(new MethodSymbol(flags, symbolName, methodType, owner), false);
 574             case ClassFile.REF_putField:
 575                 if ((owner.flags_field & INTERFACE) != 0) {
 576                     Symbol result = new VarSymbol(flags, symbolName, methodType.restype, owner);
 577                     log.warning(tree, Warnings.MemberNotFoundAtClass(symbolName, "class", result.owner));
 578                     return new Pair<>(result, true);
 579                 }
 580                 return new Pair<>(new VarSymbol(flags, symbolName, methodType.argtypes.tail.head, owner), false);
 581             case ClassFile.REF_putStatic:
 582                 return new Pair<>(new VarSymbol(flags, symbolName, methodType.argtypes.head, owner), false);
 583             case ClassFile.REF_getField:
 584             case ClassFile.REF_getStatic:
 585                 if (refKind == ClassFile.REF_getField && (owner.flags_field & INTERFACE) != 0) {
 586                     Symbol result = new VarSymbol(flags, symbolName, methodType.restype, owner);
 587                     log.warning(tree, Warnings.MemberNotFoundAtClass(symbolName, "class", result.owner));
 588                     return new Pair<>(result, true);
 589                 }
 590                 return new Pair<>(new VarSymbol(flags, symbolName, methodType.restype, owner), false);
 591             default:
 592                 throw new AssertionError("invalid refKind value " + refKind);
 593         }
 594     }
 595 
 596     private Symbol generateMethodSymbolHelper(
 597             Symbol owner,
 598             Name symbolName,
 599             MethodType methodType,
 600             long flags,
 601             final boolean shouldBeInterface) {
 602         Symbol newMS = new MethodSymbol(flags, symbolName, methodType, owner) {
 603             @Override
 604             public boolean isOwnerAnInterface() {
 605                 return shouldBeInterface;
 606             }
 607         };
 608         return newMS;
 609     }
 610 
 611     private Symbol generateVarSymbolHelper(
 612             Symbol owner,
 613             Name symbolName,
 614             MethodType methodType,
 615             long flags) {
 616         Symbol newVS = new VarSymbol(flags, symbolName, methodType.restype, owner);
 617         return newVS;
 618     }
 619 
 620     public Object invokeMethodReflectively(
 621             Class<?> hostClass,
 622             Object instance,
 623             String methodName) {
 624         return invokeMethodReflectively(hostClass, instance, methodName, new Class<?>[0], new Object[0]);
 625     }
 626 
 627     public Object invokeMethodReflectively(
 628             Class<?> hostClass,
 629             Object instance,
 630             String methodName,
 631             Class<?>[] argumentTypes,
 632             Object[] arguments) {
 633         Method theMethod;
 634         try {
 635             theMethod = hostClass.getMethod(methodName, argumentTypes);
 636             return theMethod.invoke(instance, arguments);
 637         } catch (NoSuchMethodException |
 638                 SecurityException |
 639                 IllegalAccessException |
 640                 IllegalArgumentException |
 641                 InvocationTargetException ex) {
 642             Throwable e = (ex.getCause() == null) ? ex : ex.getCause();
 643             String msg = e.getLocalizedMessage();
 644             if (msg == null)
 645                 msg = e.toString();
 646             log.error(Errors.ReflectiveError(methodName, hostClass.getCanonicalName(), msg));
 647             e.printStackTrace(System.err);
 648         }
 649         return null;
 650     }
 651 
 652     public boolean isIntrinsicsIndy(JCTree tree) {
 653         return isIntrinsicsIndy(TreeInfo.symbol(tree));
 654     }
 655 
 656     public boolean isIntrinsicsIndy(Symbol msym) {
 657         return (msym != null &&
 658                 msym.owner != null &&
 659                 msym.owner.type != null &&
 660                 msym.owner.type.tsym == syms.intrinsicsType.tsym &&
 661                 msym.name == names.invokedynamic);
 662     }
 663 
 664     public boolean isIntrinsicsLDCInvocation(Symbol msym) {
 665         return (msym != null &&
 666                 msym.owner != null &&
 667                 msym.owner.type != null &&
 668                 msym.owner.type.tsym == syms.intrinsicsType.tsym &&
 669                 msym.name == names.ldc);
 670     }
 671 
 672     /* This method doesnt verify that the annotated field is static it is assumed that
 673      * it has to be
 674      */
 675     public Object foldTrackableField(final JCTree tree, final Env<AttrContext> env) {
 676         Symbol sym = TreeInfo.symbol(tree);
 677         boolean trackableConstant = isFoldable(sym);
 678         if (trackableConstant) {
 679             String className = sym.owner.type.tsym.flatName().toString();
 680             try {
 681                 Class<?> constablesClass = Class.forName(className, false, null);
 682                 MemberKind mKind = getMemberKind(constablesClass, sym.name.toString());
 683                 if (mKind == MemberKind.METHOD) {
 684                     // we are in the middle of a method invocation bail out
 685                     return null;
 686                 }
 687                 return getFieldValueReflectively(constablesClass, null, sym.name.toString());
 688             } catch (ClassNotFoundException ex) {
 689                 log.error(tree, Errors.ReflectiveError(sym.name.toString(), className, ex.getCause().getLocalizedMessage()));
 690             }
 691         }
 692         return null;
 693     }
 694 
 695     Object getFieldValueReflectively(Class<?> hostClass, Object instance, String fieldName) {
 696         try {
 697             return hostClass.getField(fieldName).get(instance);
 698         } catch (NoSuchFieldException | IllegalAccessException ex) {
 699             Throwable e = (ex.getCause() == null) ? ex : ex.getCause();
 700             String msg = e.getLocalizedMessage();
 701             if (msg == null)
 702                 msg = e.toString();
 703             log.error(Errors.ReflectiveError(fieldName, hostClass.getCanonicalName(), msg));
 704             e.printStackTrace(System.err);
 705         }
 706         return null;
 707     }
 708 
 709     enum MemberKind {
 710         FIELD,
 711         METHOD
 712     }
 713 
 714     MemberKind getMemberKind(Class<?> aClass, String name) {
 715         try {
 716             aClass.getField(name);
 717             return MemberKind.FIELD;
 718         } catch (NoSuchFieldException ex) {
 719             return MemberKind.METHOD;
 720         }
 721     }
 722 
 723     protected boolean isFoldable(Symbol msym) {
 724         return msym.attribute(syms.foldableType.tsym) != null &&
 725                 msym.packge().modle == syms.java_base;
 726     }
 727 
 728     public Object foldMethodInvocation(final JCMethodInvocation tree, final Env<AttrContext> env) {
 729         Symbol msym = TreeInfo.symbol(tree.meth);
 730         Object constant = null;
 731         boolean trackableConstant = isFoldable(msym);
 732         boolean isLDC = msym.owner.type.tsym == syms.intrinsicsType.tsym && msym.name == names.ldc;
 733         if (trackableConstant || isLDC) {
 734             List<Object> constantArgumentValues = extractAllConstansOrNone(tree.args);
 735             boolean allConstants = tree.args.isEmpty() == constantArgumentValues.isEmpty();
 736             if (allConstants) {
 737                 if (trackableConstant) {
 738                     constant = invokeConstablesMethod(tree, env, constantArgumentValues);
 739                 } else if (isLDC) {
 740                     constant = constantArgumentValues.head;
 741                 }
 742             }
 743             if (constant != null) {
 744                 return constant;
 745             }
 746         }
 747         return null;
 748     }
 749 
 750     public List<Object> extractAllConstansOrNone(List<JCExpression> args) {
 751         ListBuffer<Object> constantArgumentValues = new ListBuffer<>();
 752         for (JCExpression arg: args) {
 753             Object argConstant = arg.type.constValue();
 754             if (argConstant != null) {
 755                 constantArgumentValues.add(argConstant);
 756             } else {
 757                 argConstant = constablesVisitor.elementToConstantMap.get(arg) != null ?
 758                         constablesVisitor.elementToConstantMap.get(arg) :
 759                         constablesVisitor.elementToConstantMap.get(TreeInfo.symbol(arg));
 760                 if (argConstant != null) {
 761                     constantArgumentValues.add(argConstant);
 762                 } else {
 763                     return List.nil();
 764                 }
 765             }
 766         }
 767         return constantArgumentValues.toList();
 768     }
 769 
 770     // where
 771         Object invokeConstablesMethod(
 772                 final JCMethodInvocation tree,
 773                 final Env<AttrContext> env,
 774                 List<Object> constantArgumentValues) {
 775             String className = "";
 776             Name methodName = names.empty;
 777             try {
 778                 Symbol msym = TreeInfo.symbol(tree.meth);
 779                 JCTree qualifierTree = (tree.meth.hasTag(SELECT))
 780                     ? ((JCFieldAccess) tree.meth).selected
 781                     : null;
 782                 Object instance = constablesVisitor.elementToConstantMap.get(qualifierTree);
 783                 className = msym.owner.type.tsym.flatName().toString();
 784                 methodName = msym.name;
 785                 Class<?> constablesClass = Class.forName(className, false, null);
 786                 MethodType mt = msym.type.asMethodType();
 787                 java.util.List<Class<?>> argumentTypes =
 788                         mt.argtypes.stream().map(t -> getClassForType(t)).collect(List.collector());
 789                 Method theMethod = constablesClass.getDeclaredMethod(methodName.toString(),
 790                         argumentTypes.toArray(new Class<?>[argumentTypes.size()]));
 791                 int modifiers = theMethod.getModifiers();
 792                 Object[] args = boxArgs(
 793                         mt.argtypes,
 794                         constantArgumentValues,
 795                         tree.varargsElement);
 796                 if ((modifiers & Modifier.STATIC) == 0) {
 797                     return (instance != null) ? theMethod.invoke(instance, args) : null;
 798                 }
 799                 return theMethod.invoke(null, args);
 800             } catch (ClassNotFoundException |
 801                     SecurityException |
 802                     NoSuchMethodException |
 803                     IllegalAccessException |
 804                     IllegalArgumentException |
 805                     InvocationTargetException ex) {
 806                 if (ex.getCause() != null && ex.getCause().getLocalizedMessage() != null) {
 807                     log.error(tree, Errors.ReflectiveError(methodName.toString(), className, ex.getCause().getLocalizedMessage()));
 808                 } else {
 809                     log.error(tree, Errors.ReflectiveError(methodName.toString(), className, ex.toString()));
 810                 }
 811 
 812                 return null;
 813             }
 814         }
 815 
 816         Class<?> getClassForType(Type t) {
 817             try {
 818                 if (t.isPrimitiveOrVoid()) {
 819                     return t.getTag().theClass;
 820                 } else {
 821                     return Class.forName(getFlatName(t), false, null);
 822                 }
 823             } catch (ClassNotFoundException ex) {
 824                 return null;
 825             }
 826         }
 827 
 828         String getFlatName(Type t) {
 829             String flatName = t.tsym.flatName().toString();
 830             if (t.hasTag(ARRAY)) {
 831                 flatName = "";
 832                 while (t.hasTag(ARRAY)) {
 833                     ArrayType at = (ArrayType)t;
 834                     flatName += "[";
 835                     t = at.elemtype;
 836                 }
 837                 flatName += "L" + t.tsym.flatName().toString() + ';';
 838             }
 839             return flatName;
 840         }
 841 
 842         Object[] boxArgs(List<Type> parameters, List<Object> _args, Type varargsElement) {
 843             java.util.List<Object> result = new java.util.ArrayList<>();
 844             List<Object> args = _args;
 845             if (parameters.isEmpty()) return new Object[0];
 846             while (parameters.tail.nonEmpty()) {
 847                 result.add(args.head);
 848                 args = args.tail;
 849                 parameters = parameters.tail;
 850             }
 851             if (varargsElement != null) {
 852                 java.util.List<Object> elems = new java.util.ArrayList<>();
 853                 while (args.nonEmpty()) {
 854                     elems.add(args.head);
 855                     args = args.tail;
 856                 }
 857                 Class<?> arrayClass = null;
 858                 try {
 859                     arrayClass = Class.forName(getFlatName(varargsElement), false, null);
 860                 } catch (ClassNotFoundException ex) {}
 861                 Object arr = Array.newInstance(arrayClass, elems.size());
 862                 for (int i = 0; i < elems.size(); i++) {
 863                     Array.set(arr, i, elems.get(i));
 864                 }
 865                 result.add(arr);
 866             } else {
 867                 if (args.length() != 1) throw new AssertionError(args);
 868                 result.add(args.head);
 869             }
 870             return result.toArray();
 871         }
 872 }