< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java

Print this page




   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.comp;
  27 


  28 import java.util.*;
  29 import java.util.Map.Entry;
  30 import java.util.function.Function;
  31 import java.util.stream.Stream;
  32 
  33 import com.sun.source.tree.CaseTree.CaseKind;
  34 import com.sun.tools.javac.code.*;
  35 import com.sun.tools.javac.code.Kinds.KindSelector;
  36 import com.sun.tools.javac.code.Scope.WriteableScope;

  37 import com.sun.tools.javac.jvm.*;

  38 import com.sun.tools.javac.main.Option.PkgInfo;
  39 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  40 import com.sun.tools.javac.tree.*;
  41 import com.sun.tools.javac.util.*;
  42 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  43 import com.sun.tools.javac.util.List;
  44 
  45 import com.sun.tools.javac.code.Symbol.*;
  46 import com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode;
  47 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  48 import com.sun.tools.javac.tree.JCTree.*;
  49 import com.sun.tools.javac.code.Type.*;
  50 
  51 import com.sun.tools.javac.jvm.Target;
  52 import com.sun.tools.javac.tree.EndPosTable;
  53 
  54 import static com.sun.tools.javac.code.Flags.*;
  55 import static com.sun.tools.javac.code.Flags.BLOCK;
  56 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
  57 import static com.sun.tools.javac.code.TypeTag.*;
  58 import static com.sun.tools.javac.code.Kinds.Kind.*;
  59 import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.DEREF;
  60 import static com.sun.tools.javac.jvm.ByteCodes.*;
  61 import com.sun.tools.javac.tree.JCTree.JCBreak;
  62 import com.sun.tools.javac.tree.JCTree.JCCase;
  63 import com.sun.tools.javac.tree.JCTree.JCExpression;
  64 import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
  65 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
  66 import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
  67 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  68 
  69 /** This pass translates away some syntactic sugar: inner classes,
  70  *  class literals, assertions, foreach loops, etc.
  71  *
  72  *  <p><b>This is NOT part of any supported API.
  73  *  If you write code that depends on this, you do so at your own risk.
  74  *  This code and its internal interfaces are subject to change or
  75  *  deletion without notice.</b>
  76  */
  77 public class Lower extends TreeTranslator {
  78     protected static final Context.Key<Lower> lowerKey = new Context.Key<>();
  79 
  80     public static Lower instance(Context context) {
  81         Lower instance = context.get(lowerKey);
  82         if (instance == null)
  83             instance = new Lower(context);
  84         return instance;


 785                 log.error(pos, Errors.CannotGenerateClass(sym.location(), Fragments.SyntheticNameConflict(sym, sym.location())));
 786             }
 787         }
 788     };
 789 
 790     /** Look up a synthetic name in a given scope.
 791      *  @param s            The scope.
 792      *  @param name         The name.
 793      */
 794     private Symbol lookupSynthetic(Name name, Scope s) {
 795         Symbol sym = s.findFirst(name);
 796         return (sym==null || (sym.flags()&SYNTHETIC)==0) ? null : sym;
 797     }
 798 
 799     /** Look up a method in a given scope.
 800      */
 801     private MethodSymbol lookupMethod(DiagnosticPosition pos, Name name, Type qual, List<Type> args) {
 802         return rs.resolveInternalMethod(pos, attrEnv, qual, name, args, List.nil());
 803     }
 804 















 805     /** Anon inner classes are used as access constructor tags.
 806      * accessConstructorTag will use an existing anon class if one is available,
 807      * and synthethise a class (with makeEmptyClass) if one is not available.
 808      * However, there is a small possibility that an existing class will not
 809      * be generated as expected if it is inside a conditional with a constant
 810      * expression. If that is found to be the case, create an empty class tree here.
 811      */
 812     private void checkAccessConstructorTags() {
 813         for (List<ClassSymbol> l = accessConstrTags; l.nonEmpty(); l = l.tail) {
 814             ClassSymbol c = l.head;
 815             if (isTranslatedClassAvailable(c))
 816                 continue;
 817             // Create class definition tree.
 818             JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC,
 819                     c.outermostClass(), c.flatname, false);
 820             swapAccessConstructorTag(c, cdec.sym);
 821             translated.append(cdec);
 822         }
 823     }
 824     // where


2171         ClassSymbol currentClassPrev = currentClass;
2172         MethodSymbol currentMethodSymPrev = currentMethodSym;
2173 
2174         currentClass = tree.sym;
2175         currentMethodSym = null;
2176         attrEnv = typeEnvs.remove(currentClass);
2177         if (attrEnv == null)
2178             attrEnv = prevEnv;
2179 
2180         classdefs.put(currentClass, tree);
2181 
2182         Map<Symbol, Symbol> prevProxies = proxies;
2183         proxies = new HashMap<>(proxies);
2184         List<VarSymbol> prevOuterThisStack = outerThisStack;
2185 
2186         // If this is an enum definition
2187         if ((tree.mods.flags & ENUM) != 0 &&
2188             (types.supertype(currentClass.type).tsym.flags() & ENUM) == 0)
2189             visitEnumDef(tree);
2190 




2191         // If this is a nested class, define a this$n field for
2192         // it and add to proxies.
2193         JCVariableDecl otdef = null;
2194         if (currentClass.hasOuterInstance())
2195             otdef = outerThisDef(tree.pos, currentClass);
2196 
2197         // If this is a local class, define proxies for all its free variables.
2198         List<JCVariableDecl> fvdefs = freevarDefs(
2199             tree.pos, freevars(currentClass), currentClass);
2200 
2201         // Recursively translate superclass, interfaces.
2202         tree.extending = translate(tree.extending);
2203         tree.implementing = translate(tree.implementing);
2204 
2205         if (currentClass.isLocal()) {
2206             ClassSymbol encl = currentClass.owner.enclClass();
2207             if (encl.trans_local == null) {
2208                 encl.trans_local = List.nil();
2209             }
2210             encl.trans_local = encl.trans_local.prepend(currentClass);


2240         }
2241         if (currentClass.hasOuterInstance()) {
2242             tree.defs = tree.defs.prepend(otdef);
2243             enterSynthetic(tree.pos(), otdef.sym, currentClass.members());
2244         }
2245 
2246         proxies = prevProxies;
2247         outerThisStack = prevOuterThisStack;
2248 
2249         // Append translated tree to `translated' queue.
2250         translated.append(tree);
2251 
2252         attrEnv = prevEnv;
2253         currentClass = currentClassPrev;
2254         currentMethodSym = currentMethodSymPrev;
2255 
2256         // Return empty block {} as a placeholder for an inner class.
2257         result = make_at(tree.pos()).Block(SYNTHETIC, List.nil());
2258     }
2259 
















































2260     /** Translate an enum class. */
2261     private void visitEnumDef(JCClassDecl tree) {
2262         make_at(tree.pos());
2263 
2264         // add the supertype, if needed
2265         if (tree.extending == null)
2266             tree.extending = make.Type(types.supertype(tree.type));
2267 
2268         // classOfType adds a cache field to tree.defs
2269         JCExpression e_class = classOfType(tree.sym.type, tree.pos()).
2270             setType(types.erasure(syms.classType));
2271 
2272         // process each enumeration constant, adding implicit constructor parameters
2273         int nextOrdinal = 0;
2274         ListBuffer<JCExpression> values = new ListBuffer<>();
2275         ListBuffer<JCTree> enumDefs = new ListBuffer<>();
2276         ListBuffer<JCTree> otherDefs = new ListBuffer<>();
2277         for (List<JCTree> defs = tree.defs;
2278              defs.nonEmpty();
2279              defs=defs.tail) {


2393         enumDefs.appendList(otherDefs.toList());
2394         tree.defs = enumDefs.toList();
2395     }
2396         // where
2397         private MethodSymbol systemArraycopyMethod;
2398         private boolean useClone() {
2399             try {
2400                 return syms.objectType.tsym.members().findFirst(names.clone) != null;
2401             }
2402             catch (CompletionFailure e) {
2403                 return false;
2404             }
2405         }
2406 
2407     /** Translate an enumeration constant and its initializer. */
2408     private void visitEnumConstantDef(JCVariableDecl var, int ordinal) {
2409         JCNewClass varDef = (JCNewClass)var.init;
2410         varDef.args = varDef.args.
2411             prepend(makeLit(syms.intType, ordinal)).
2412             prepend(makeLit(syms.stringType, var.name.toString()));



































































































































































































































2413     }
2414 
2415     public void visitMethodDef(JCMethodDecl tree) {
2416         if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) {
2417             // Add "String $enum$name, int $enum$ordinal" to the beginning of the
2418             // argument list for each constructor of an enum.
2419             JCVariableDecl nameParam = make_at(tree.pos()).
2420                 Param(names.fromString(target.syntheticNameChar() +
2421                                        "enum" + target.syntheticNameChar() + "name"),
2422                       syms.stringType, tree.sym);
2423             nameParam.mods.flags |= SYNTHETIC; nameParam.sym.flags_field |= SYNTHETIC;
2424             JCVariableDecl ordParam = make.
2425                 Param(names.fromString(target.syntheticNameChar() +
2426                                        "enum" + target.syntheticNameChar() +
2427                                        "ordinal"),
2428                       syms.intType, tree.sym);
2429             ordParam.mods.flags |= SYNTHETIC; ordParam.sym.flags_field |= SYNTHETIC;
2430 
2431             MethodSymbol m = tree.sym;
2432             tree.params = tree.params.prepend(ordParam).prepend(nameParam);




   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.comp;
  27 
  28 import sun.invoke.util.BytecodeName;
  29 
  30 import java.util.*;
  31 import java.util.stream.Collectors;


  32 

  33 import com.sun.tools.javac.code.*;
  34 import com.sun.tools.javac.code.Kinds.KindSelector;
  35 import com.sun.tools.javac.code.Scope.WriteableScope;
  36 import com.sun.tools.javac.comp.Resolve.MethodResolutionContext;
  37 import com.sun.tools.javac.jvm.*;
  38 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
  39 import com.sun.tools.javac.main.Option.PkgInfo;
  40 import com.sun.tools.javac.resources.CompilerProperties.Fragments;
  41 import com.sun.tools.javac.tree.*;
  42 import com.sun.tools.javac.util.*;
  43 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
  44 import com.sun.tools.javac.util.List;
  45 
  46 import com.sun.tools.javac.code.Symbol.*;
  47 import com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode;
  48 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  49 import com.sun.tools.javac.tree.JCTree.*;
  50 import com.sun.tools.javac.code.Type.*;
  51 
  52 import com.sun.tools.javac.jvm.Target;
  53 import com.sun.tools.javac.tree.EndPosTable;
  54 
  55 import static com.sun.tools.javac.code.Flags.*;
  56 import static com.sun.tools.javac.code.Flags.BLOCK;
  57 import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
  58 import static com.sun.tools.javac.code.TypeTag.*;
  59 import static com.sun.tools.javac.code.Kinds.Kind.*;

  60 import static com.sun.tools.javac.jvm.ByteCodes.*;




  61 import static com.sun.tools.javac.tree.JCTree.JCOperatorExpression.OperandPos.LEFT;
  62 import com.sun.tools.javac.tree.JCTree.JCSwitchExpression;
  63 import static com.sun.tools.javac.tree.JCTree.Tag.*;
  64 
  65 /** This pass translates away some syntactic sugar: inner classes,
  66  *  class literals, assertions, foreach loops, etc.
  67  *
  68  *  <p><b>This is NOT part of any supported API.
  69  *  If you write code that depends on this, you do so at your own risk.
  70  *  This code and its internal interfaces are subject to change or
  71  *  deletion without notice.</b>
  72  */
  73 public class Lower extends TreeTranslator {
  74     protected static final Context.Key<Lower> lowerKey = new Context.Key<>();
  75 
  76     public static Lower instance(Context context) {
  77         Lower instance = context.get(lowerKey);
  78         if (instance == null)
  79             instance = new Lower(context);
  80         return instance;


 781                 log.error(pos, Errors.CannotGenerateClass(sym.location(), Fragments.SyntheticNameConflict(sym, sym.location())));
 782             }
 783         }
 784     };
 785 
 786     /** Look up a synthetic name in a given scope.
 787      *  @param s            The scope.
 788      *  @param name         The name.
 789      */
 790     private Symbol lookupSynthetic(Name name, Scope s) {
 791         Symbol sym = s.findFirst(name);
 792         return (sym==null || (sym.flags()&SYNTHETIC)==0) ? null : sym;
 793     }
 794 
 795     /** Look up a method in a given scope.
 796      */
 797     private MethodSymbol lookupMethod(DiagnosticPosition pos, Name name, Type qual, List<Type> args) {
 798         return rs.resolveInternalMethod(pos, attrEnv, qual, name, args, List.nil());
 799     }
 800 
 801     private Symbol findMethodOrFailSilently(
 802             DiagnosticPosition pos,
 803             Env<AttrContext> env,
 804             Type site,
 805             Name name,
 806             List<Type> argtypes,
 807             List<Type> typeargtypes) {
 808         MethodResolutionContext resolveContext = rs.new MethodResolutionContext();
 809         resolveContext.internalResolution = true;
 810         resolveContext.silentFail = true;
 811         Symbol sym = rs.resolveQualifiedMethod(resolveContext, pos, env, site.tsym,
 812                 site, name, argtypes, typeargtypes);
 813         return sym;
 814     }
 815 
 816     /** Anon inner classes are used as access constructor tags.
 817      * accessConstructorTag will use an existing anon class if one is available,
 818      * and synthethise a class (with makeEmptyClass) if one is not available.
 819      * However, there is a small possibility that an existing class will not
 820      * be generated as expected if it is inside a conditional with a constant
 821      * expression. If that is found to be the case, create an empty class tree here.
 822      */
 823     private void checkAccessConstructorTags() {
 824         for (List<ClassSymbol> l = accessConstrTags; l.nonEmpty(); l = l.tail) {
 825             ClassSymbol c = l.head;
 826             if (isTranslatedClassAvailable(c))
 827                 continue;
 828             // Create class definition tree.
 829             JCClassDecl cdec = makeEmptyClass(STATIC | SYNTHETIC,
 830                     c.outermostClass(), c.flatname, false);
 831             swapAccessConstructorTag(c, cdec.sym);
 832             translated.append(cdec);
 833         }
 834     }
 835     // where


2182         ClassSymbol currentClassPrev = currentClass;
2183         MethodSymbol currentMethodSymPrev = currentMethodSym;
2184 
2185         currentClass = tree.sym;
2186         currentMethodSym = null;
2187         attrEnv = typeEnvs.remove(currentClass);
2188         if (attrEnv == null)
2189             attrEnv = prevEnv;
2190 
2191         classdefs.put(currentClass, tree);
2192 
2193         Map<Symbol, Symbol> prevProxies = proxies;
2194         proxies = new HashMap<>(proxies);
2195         List<VarSymbol> prevOuterThisStack = outerThisStack;
2196 
2197         // If this is an enum definition
2198         if ((tree.mods.flags & ENUM) != 0 &&
2199             (types.supertype(currentClass.type).tsym.flags() & ENUM) == 0)
2200             visitEnumDef(tree);
2201 
2202         if ((tree.mods.flags & RECORD) != 0) {
2203             visitRecordDef(tree);
2204         }
2205 
2206         // If this is a nested class, define a this$n field for
2207         // it and add to proxies.
2208         JCVariableDecl otdef = null;
2209         if (currentClass.hasOuterInstance())
2210             otdef = outerThisDef(tree.pos, currentClass);
2211 
2212         // If this is a local class, define proxies for all its free variables.
2213         List<JCVariableDecl> fvdefs = freevarDefs(
2214             tree.pos, freevars(currentClass), currentClass);
2215 
2216         // Recursively translate superclass, interfaces.
2217         tree.extending = translate(tree.extending);
2218         tree.implementing = translate(tree.implementing);
2219 
2220         if (currentClass.isLocal()) {
2221             ClassSymbol encl = currentClass.owner.enclClass();
2222             if (encl.trans_local == null) {
2223                 encl.trans_local = List.nil();
2224             }
2225             encl.trans_local = encl.trans_local.prepend(currentClass);


2255         }
2256         if (currentClass.hasOuterInstance()) {
2257             tree.defs = tree.defs.prepend(otdef);
2258             enterSynthetic(tree.pos(), otdef.sym, currentClass.members());
2259         }
2260 
2261         proxies = prevProxies;
2262         outerThisStack = prevOuterThisStack;
2263 
2264         // Append translated tree to `translated' queue.
2265         translated.append(tree);
2266 
2267         attrEnv = prevEnv;
2268         currentClass = currentClassPrev;
2269         currentMethodSym = currentMethodSymPrev;
2270 
2271         // Return empty block {} as a placeholder for an inner class.
2272         result = make_at(tree.pos()).Block(SYNTHETIC, List.nil());
2273     }
2274 
2275     List<JCTree> accessors(JCClassDecl tree) {
2276         ListBuffer<JCTree> buffer = new ListBuffer<>();
2277         tree.defs.stream()
2278                 .filter(t -> t.hasTag(VARDEF))
2279                 .map(t -> (JCVariableDecl)t)
2280                 .filter(vd -> vd.sym.accessors.nonEmpty())
2281                 .forEach(vd -> {
2282                     for (Pair<Accessors.Kind, MethodSymbol> accessor : vd.sym.accessors) {
2283                         MethodSymbol accessorSym = accessor.snd;
2284                         if ((accessorSym.flags() & Flags.MANDATED) != 0) {
2285                             make_at(tree.pos());
2286                             switch (accessor.fst) {
2287                                 case GET:
2288                                     buffer.add(make.MethodDef(accessorSym, make.Block(0,
2289                                             List.of(make.Return(make.Ident(vd.sym))))));
2290                                     break;
2291                                 case SET:
2292                                     buffer.add(make.MethodDef(accessorSym, make.Block(0,
2293                                             List.of(make.Exec(
2294                                                     make.Assign(make.Ident(vd.sym), make.Ident(accessorSym.params.head))
2295                                                             .setType(vd.sym.type))))));
2296                                     break;
2297                                 default:
2298                                     Assert.error("Cannot get here!");
2299                             }
2300                         }
2301                     }
2302                 });
2303         return buffer.toList();
2304     }
2305 
2306     /* this method looks for explicit accessors to add them to the corresponding field
2307      */
2308     void findUserDefinedAccessors(JCClassDecl tree) {
2309         tree.defs.stream()
2310                 .filter(t -> t.hasTag(VARDEF))
2311                 .map(t -> (JCVariableDecl)t)
2312                 .filter(vd -> (vd.sym.accessors.isEmpty() && !vd.sym.isStatic()))
2313                 .forEach(vd -> {
2314                     MethodSymbol msym = lookupMethod(tree.pos(),
2315                             vd.name,
2316                             tree.sym.type,
2317                             List.nil());
2318                     Assert.check(msym != null, "there has to be a user defined accessor");
2319                     vd.sym.accessors = List.of(new Pair<>(Accessors.Kind.GET, msym));
2320                 });
2321     }
2322 
2323     /** Translate an enum class. */
2324     private void visitEnumDef(JCClassDecl tree) {
2325         make_at(tree.pos());
2326 
2327         // add the supertype, if needed
2328         if (tree.extending == null)
2329             tree.extending = make.Type(types.supertype(tree.type));
2330 
2331         // classOfType adds a cache field to tree.defs
2332         JCExpression e_class = classOfType(tree.sym.type, tree.pos()).
2333             setType(types.erasure(syms.classType));
2334 
2335         // process each enumeration constant, adding implicit constructor parameters
2336         int nextOrdinal = 0;
2337         ListBuffer<JCExpression> values = new ListBuffer<>();
2338         ListBuffer<JCTree> enumDefs = new ListBuffer<>();
2339         ListBuffer<JCTree> otherDefs = new ListBuffer<>();
2340         for (List<JCTree> defs = tree.defs;
2341              defs.nonEmpty();
2342              defs=defs.tail) {


2456         enumDefs.appendList(otherDefs.toList());
2457         tree.defs = enumDefs.toList();
2458     }
2459         // where
2460         private MethodSymbol systemArraycopyMethod;
2461         private boolean useClone() {
2462             try {
2463                 return syms.objectType.tsym.members().findFirst(names.clone) != null;
2464             }
2465             catch (CompletionFailure e) {
2466                 return false;
2467             }
2468         }
2469 
2470     /** Translate an enumeration constant and its initializer. */
2471     private void visitEnumConstantDef(JCVariableDecl var, int ordinal) {
2472         JCNewClass varDef = (JCNewClass)var.init;
2473         varDef.args = varDef.args.
2474             prepend(makeLit(syms.intType, ordinal)).
2475             prepend(makeLit(syms.stringType, var.name.toString()));
2476     }
2477 
2478     /** Translate a record. */
2479     private void visitRecordDef(JCClassDecl tree) {
2480         make_at(tree.pos());
2481         List<VarSymbol> vars = types.recordVars(tree.type);
2482         MethodHandleSymbol[] getterMethHandles = new MethodHandleSymbol[vars.size()];
2483         // for the extractor we use the user provided getter, for the rest we access the field directly
2484         MethodHandleSymbol[] getterMethHandlesForExtractor = new MethodHandleSymbol[vars.size()];
2485         int index = 0;
2486         for (VarSymbol var : vars) {
2487             if (var.owner != tree.sym) {
2488                 var = new VarSymbol(var.flags_field, var.name, var.type, tree.sym);
2489             }
2490             getterMethHandles[index] = var.asMethodHandle(true);
2491             if (!var.accessors.isEmpty()) {
2492                 getterMethHandlesForExtractor[index] = getterMethHandles[index];
2493             } else {
2494                 MethodSymbol msym = lookupMethod(tree, var.name, tree.sym.type, List.nil());
2495                 getterMethHandlesForExtractor[index] = msym.asHandle();
2496             }
2497             index++;
2498         }
2499 
2500         tree.defs = tree.defs.appendList(accessors(tree));
2501         tree.defs = tree.defs.appendList(List.of(
2502                 generateRecordMethod(tree, names.toString, vars, getterMethHandles),
2503                 generateRecordMethod(tree, names.hashCode, vars, getterMethHandles),
2504                 generateRecordMethod(tree, names.equals, vars, getterMethHandles),
2505                 recordExtractor(tree, getterMethHandlesForExtractor),
2506                 recordReadResolve(tree)
2507         ));
2508         findUserDefinedAccessors(tree);
2509     }
2510 
2511     JCTree generateRecordMethod(JCClassDecl tree, Name name, List<VarSymbol> vars, MethodHandleSymbol[] getterMethHandles) {
2512         make_at(tree.pos());
2513         boolean isEquals = name == names.equals;
2514         MethodSymbol msym = lookupMethod(tree.pos(),
2515                 name,
2516                 tree.sym.type,
2517                 isEquals ? List.of(syms.objectType) : List.nil());
2518         if ((msym.flags() & RECORD) != 0) {
2519             Name bootstrapName = names.bootstrap;
2520             LoadableConstant[] staticArgsValues = new LoadableConstant[2 + getterMethHandles.length];
2521             staticArgsValues[0] = (ClassType)tree.sym.type;
2522             String concatNames = vars.stream()
2523                     .map(v -> v.name)
2524                     .collect(Collectors.joining(";", "", ""));
2525             staticArgsValues[1] = LoadableConstant.String(concatNames);
2526             int index = 2;
2527             for (MethodHandleSymbol mho : getterMethHandles) {
2528                 staticArgsValues[index] = mho;
2529                 index++;
2530             }
2531 
2532             List<Type> staticArgTypes = List.of(syms.classType,
2533                     syms.stringType,
2534                     new ArrayType(syms.methodHandleType, syms.arrayClass));
2535 
2536             JCFieldAccess qualifier = makeIndyQualifier(syms.objectMethodBuildersType, tree, msym,
2537                     List.of(syms.methodHandleLookupType,
2538                             syms.stringType,
2539                             syms.typeDescriptorType).appendList(staticArgTypes),
2540                     staticArgsValues, bootstrapName, name, false);
2541 
2542             VarSymbol _this = new VarSymbol(SYNTHETIC, names._this, tree.sym.type, tree.sym);
2543 
2544             JCMethodInvocation proxyCall;
2545             if (!isEquals) {
2546                 proxyCall = make.Apply(List.nil(), qualifier, List.of(make.Ident(_this)));
2547             } else {
2548                 VarSymbol o = msym.params.head;
2549                 o.adr = 0;
2550                 proxyCall = make.Apply(List.nil(), qualifier, List.of(make.Ident(_this), make.Ident(o)));
2551             }
2552             proxyCall.type = qualifier.type;
2553             return make.MethodDef(msym, make.Block(0, List.of(make.Return(proxyCall))));
2554         } else {
2555             return make.Block(SYNTHETIC, List.nil());
2556         }
2557     }
2558 
2559     JCTree recordExtractor(JCClassDecl tree, MethodHandleSymbol[] getterMethHandles) {
2560         make_at(tree.pos());
2561 
2562         // let's generate the name of the extractor method
2563         List<Type> fieldTypes = TreeInfo.types(TreeInfo.recordFields(tree));
2564         String argsTypeSig = '(' + argsTypeSig(fieldTypes) + ')';
2565         String extractorStr = BytecodeName.toBytecodeName("$pattern$" + tree.sym.name + "$" + argsTypeSig);
2566         Name extractorName = names.fromString(extractorStr);
2567 
2568         // let's create the condy now
2569         Name bsmName = names.ofLazyProjection;
2570         List<Type> staticArgTypes = List.of(syms.classType,
2571                 new ArrayType(syms.methodHandleType, syms.arrayClass));
2572         List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
2573                 syms.stringType,
2574                 syms.classType).appendList(staticArgTypes);
2575 
2576         Symbol bsm = rs.resolveInternalMethod(tree, attrEnv, syms.patternHandlesType,
2577                 bsmName, bsm_staticArgs, List.nil());
2578 
2579         LoadableConstant[] staticArgs = new LoadableConstant[1 + getterMethHandles.length];
2580         staticArgs[0] = (ClassType)tree.sym.type;
2581         int index = 1;
2582         for (MethodHandleSymbol mho : getterMethHandles) {
2583             staticArgs[index] = mho;
2584             index++;
2585         }
2586 
2587         Symbol.DynamicVarSymbol dynSym = new Symbol.DynamicVarSymbol(extractorName,
2588                 syms.noSymbol,
2589                 ((MethodSymbol)bsm).asHandle(),
2590                 syms.patternHandleType,
2591                 staticArgs);
2592         JCIdent ident = make.Ident(dynSym);
2593         ident.type = syms.patternHandleType;
2594 
2595         // public PatternHandle extractorName () { return ???; }
2596         MethodType extractorMT = new MethodType(List.nil(), syms.patternHandleType, List.nil(), syms.methodClass);
2597         MethodSymbol extractorSym = new MethodSymbol(
2598                 Flags.PUBLIC | Flags.RECORD | Flags.STATIC,
2599                 extractorName, extractorMT, tree.sym);
2600         tree.sym.members().enter(extractorSym);
2601         return make.MethodDef(extractorSym, make.Block(0, List.of(make.Return(ident))));
2602     }
2603 
2604     JCTree recordReadResolve(JCClassDecl tree) {
2605         make_at(tree.pos());
2606         Symbol msym = findMethodOrFailSilently(
2607                 tree.pos(),
2608                 attrEnv,
2609                 tree.sym.type,
2610                 names.readResolve,
2611                 List.nil(),
2612                 List.nil());
2613         if (!msym.kind.isResolutionError() && (msym.flags() & RECORD) != 0) {
2614             List<JCExpression> args = TreeInfo.recordFields(tree).map(vd -> make.Ident(vd));
2615             return make.MethodDef((MethodSymbol)msym, make.Block(0, List.of(make.Return(makeNewClass(tree.sym.type, args)))));
2616         } else {
2617             return make.Block(SYNTHETIC, List.nil());
2618         }
2619     }
2620 
2621     private String argsTypeSig(List<Type> typeList) {
2622         LowerSignatureGenerator sg = new LowerSignatureGenerator();
2623         sg.assembleSig(typeList);
2624         return sg.toString();
2625     }
2626 
2627     /**
2628      * Signature Generation
2629      */
2630     private class LowerSignatureGenerator extends Types.SignatureGenerator {
2631 
2632         /**
2633          * An output buffer for type signatures.
2634          */
2635         StringBuilder sb = new StringBuilder();
2636 
2637         LowerSignatureGenerator() {
2638             super(types);
2639         }
2640 
2641         @Override
2642         protected void append(char ch) {
2643             sb.append(ch);
2644         }
2645 
2646         @Override
2647         protected void append(byte[] ba) {
2648             sb.append(new String(ba));
2649         }
2650 
2651         @Override
2652         protected void append(Name name) {
2653             sb.append(name.toString());
2654         }
2655 
2656         @Override
2657         public String toString() {
2658             return sb.toString();
2659         }
2660     }
2661 
2662     /**
2663      * Creates an indy qualifier, helpful to be part of an indy invocation
2664      * @param site                the site
2665      * @param tree                a class declaration tree
2666      * @param msym                the method symbol
2667      * @param staticArgTypes      the static argument types
2668      * @param staticArgValues     the static argument values
2669      * @param bootstrapName       the bootstrap name to look for
2670      * @param argName             normally bootstraps receives a method name as second argument, if you want that name
2671      *                            to be different to that of the bootstrap name pass a different name here
2672      * @param isStatic            is it static or not
2673      * @return                    a field access tree
2674      */
2675     JCFieldAccess makeIndyQualifier(
2676             Type site,
2677             JCClassDecl tree,
2678             MethodSymbol msym,
2679             List<Type> staticArgTypes,
2680             LoadableConstant[] staticArgValues,
2681             Name bootstrapName,
2682             Name argName,
2683             boolean isStatic) {
2684         Symbol bsm = rs.resolveInternalMethod(tree.pos(), attrEnv, site,
2685                 bootstrapName, staticArgTypes, List.nil());
2686 
2687         MethodType indyType = msym.type.asMethodType();
2688         indyType = new MethodType(
2689                 isStatic ? List.nil() : indyType.argtypes.prepend(tree.sym.type),
2690                 indyType.restype,
2691                 indyType.thrown,
2692                 syms.methodClass
2693         );
2694         DynamicMethodSymbol dynSym = new DynamicMethodSymbol(argName,
2695                 syms.noSymbol,
2696                 ((MethodSymbol)bsm).asHandle(),
2697                 indyType,
2698                 staticArgValues);
2699         JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), argName);
2700         qualifier.sym = dynSym;
2701         qualifier.type = msym.type.asMethodType().restype;
2702         return qualifier;
2703     }
2704 
2705     public void visitMethodDef(JCMethodDecl tree) {
2706         if (tree.name == names.init && (currentClass.flags_field&ENUM) != 0) {
2707             // Add "String $enum$name, int $enum$ordinal" to the beginning of the
2708             // argument list for each constructor of an enum.
2709             JCVariableDecl nameParam = make_at(tree.pos()).
2710                 Param(names.fromString(target.syntheticNameChar() +
2711                                        "enum" + target.syntheticNameChar() + "name"),
2712                       syms.stringType, tree.sym);
2713             nameParam.mods.flags |= SYNTHETIC; nameParam.sym.flags_field |= SYNTHETIC;
2714             JCVariableDecl ordParam = make.
2715                 Param(names.fromString(target.syntheticNameChar() +
2716                                        "enum" + target.syntheticNameChar() +
2717                                        "ordinal"),
2718                       syms.intType, tree.sym);
2719             ordParam.mods.flags |= SYNTHETIC; ordParam.sym.flags_field |= SYNTHETIC;
2720 
2721             MethodSymbol m = tree.sym;
2722             tree.params = tree.params.prepend(ordParam).prepend(nameParam);


< prev index next >