< prev index next >

src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java

Print this page

        

@@ -23,10 +23,11 @@
  * questions.
  */
 
 package com.sun.tools.javac.jvm;
 
+import com.sun.tools.javac.code.Types.UniqueType;
 import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant;
 import com.sun.tools.javac.tree.TreeInfo.PosKind;
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
 import com.sun.tools.javac.util.List;

@@ -58,10 +59,11 @@
  *  If you write code that depends on this, you do so at your own risk.
  *  This code and its internal interfaces are subject to change or
  *  deletion without notice.</b>
  */
 public class Gen extends JCTree.Visitor {
+    private static final Object[] NO_STATIC_ARGS = new Object[0];
     protected static final Context.Key<Gen> genKey = new Context.Key<>();
 
     private final Log log;
     private final Symtab syms;
     private final Check chk;

@@ -72,10 +74,11 @@
     private final Name accessDollar;
     private final Types types;
     private final Lower lower;
     private final Annotate annotate;
     private final StringConcat concat;
+    private final TransValues transValues;
 
     /** Format of stackmap tables to be generated. */
     private final Code.StackMapFormat stackMap;
 
     /** A type that serves as the expected type for all method expressions.

@@ -108,10 +111,11 @@
 
         methodType = new MethodType(null, null, null, syms.methodClass);
         accessDollar = names.
             fromString("access" + target.syntheticNameChar());
         lower = Lower.instance(context);
+        transValues = TransValues.instance(context);
 
         Options options = Options.instance(context);
         lineDebugInfo =
             options.isUnset(G_CUSTOM) ||
             options.isSet(G_CUSTOM, "lines");

@@ -251,12 +255,26 @@
     /** Insert a reference to given type in the constant pool,
      *  checking for an array with too many dimensions;
      *  return the reference's index.
      *  @param type   The type for which a reference is inserted.
      */
+    int makeRef(DiagnosticPosition pos, Type type, boolean emitQtype) {
+        checkDimension(pos, type);
+        if (emitQtype) {
+            return poolWriter.putClass(new ConstantPoolQType(type, types));
+        } else {
+            return poolWriter.putClass(type);
+        }
+    }
+
+    /** Insert a reference to given type in the constant pool,
+     *  checking for an array with too many dimensions;
+     *  return the reference's index.
+     *  @param type   The type for which a reference is inserted.
+     */
     int makeRef(DiagnosticPosition pos, Type type) {
-        return poolWriter.putClass(checkDimension(pos, type));
+        return makeRef(pos, type, false);
     }
 
     /** Check if the given type is an array with too many dimensions.
      */
     private Type checkDimension(DiagnosticPosition pos, Type t) {

@@ -964,10 +982,13 @@
                 if (code.isAlive()) {
                     code.statBegin(TreeInfo.endPos(tree.body));
                     if (env.enclMethod == null ||
                         env.enclMethod.sym.type.getReturnType().hasTag(VOID)) {
                         code.emitop0(return_);
+                    } else if (env.enclMethod.sym.isValueFactory()) {
+                        items.makeLocalItem(env.enclMethod.factoryProduct).load();
+                        code.emitop0(areturn);
                     } else {
                         // sometime dead code seems alive (4415991);
                         // generate a small loop instead
                         int startpc = code.entryPoint();
                         CondItem c = items.makeCondItem(goto_);

@@ -1052,10 +1073,77 @@
             code.pendingStackMap = false;
 
             return startpcCrt;
         }
 
+        private void synthesizeValueMethod(JCMethodDecl methodDecl) {
+
+            Name name; List<Type> argTypes; Type resType;
+
+            switch (methodDecl.name.toString()) {
+                case "hashCode":
+                    name = names.hashCode;
+                    argTypes = List.of(methodDecl.sym.owner.type);
+                    resType = methodDecl.restype.type;
+                    break;
+                case "equals":
+                    name = names.equals;
+                    argTypes = List.of(methodDecl.sym.owner.type, syms.objectType);
+                    resType = methodDecl.restype.type;
+                    break;
+                case "toString":
+                    name = names.toString;
+                    argTypes = List.of(methodDecl.sym.owner.type);
+                    resType = methodDecl.restype.type;
+                    break;
+                default:
+                    throw new AssertionError("Unexpected synthetic method body");
+            }
+
+            Type.MethodType indyType = new Type.MethodType(argTypes,
+                    resType,
+                    List.nil(),
+                    syms.methodClass);
+
+            List<Type> bsm_staticArgs = List.of(syms.methodHandleLookupType,
+                                                syms.stringType,
+                                                syms.methodTypeType);
+
+            Symbol bsm = rs.resolveInternalMethod(methodDecl.pos(),
+                    getAttrEnv(),
+                    syms.valueBootstrapMethods,
+                    names.fromString("makeBootstrapMethod"),
+                    bsm_staticArgs,
+                    null);
+
+            Symbol.DynamicMethodSymbol dynSym = new Symbol.DynamicMethodSymbol(name,
+                    syms.noSymbol,
+                    ((MethodSymbol)bsm).asHandle(),
+                    indyType,
+                    List.nil().toArray(new LoadableConstant[0]));
+
+
+            switch (methodDecl.name.toString()) {
+                case "hashCode":
+                    code.emitop0(aload_0);
+                    items.makeDynamicItem(dynSym).invoke();
+                    code.emitop0(ireturn);
+                    return;
+                case "equals":
+                    code.emitop0(aload_0);
+                    code.emitop0(aload_1);
+                    items.makeDynamicItem(dynSym).invoke();
+                    code.emitop0(ireturn);
+                    return;
+                case "toString":
+                    code.emitop0(aload_0);
+                    items.makeDynamicItem(dynSym).invoke();
+                    code.emitop0(areturn);
+                    return;
+            }
+        }
+
     public void visitVarDef(JCVariableDecl tree) {
         VarSymbol v = tree.sym;
         if (tree.init != null) {
             checkStringConstant(tree.init.pos(), v.getConstValue());
             if (v.getConstValue() == null || varDebugInfo) {

@@ -1073,10 +1161,14 @@
 
     public void visitSkip(JCSkip tree) {
     }
 
     public void visitBlock(JCBlock tree) {
+        if ((tree.flags & SYNTHETIC) != 0 && env.tree.hasTag(METHODDEF) && (((JCMethodDecl) env.tree).sym.owner.flags() & VALUE) != 0) {
+            synthesizeValueMethod((JCMethodDecl) env.tree);
+            return;
+        }
         int limit = code.nextreg;
         Env<GenContext> localEnv = env.dup(tree, new GenContext());
         genStats(tree.stats, localEnv);
         // End the scope of all block-local variables in variable info.
         if (!env.tree.hasTag(METHODDEF)) {

@@ -1092,10 +1184,41 @@
 
     public void visitWhileLoop(JCWhileLoop tree) {
         genLoop(tree, tree.body, tree.cond, List.nil(), true);
     }
 
+    public void visitWithField(JCWithField tree) {
+        switch(tree.field.getTag()) {
+            case IDENT:
+                Symbol sym = ((JCIdent) tree.field).sym;
+                items.makeThisItem().load();
+                genExpr(tree.value, tree.field.type).load();
+                sym = binaryQualifier(sym, env.enclClass.type);
+                code.emitop2(withfield, sym, PoolWriter::putMember);
+                result = items.makeStackItem(tree.type);
+                break;
+            case SELECT:
+                JCFieldAccess fieldAccess = (JCFieldAccess) tree.field;
+                sym = TreeInfo.symbol(fieldAccess);
+                // JDK-8207332: To maintain the order of side effects, must compute value ahead of field
+                genExpr(tree.value, tree.field.type).load();
+                genExpr(fieldAccess.selected, fieldAccess.selected.type).load();
+                if (Code.width(tree.field.type) == 2) {
+                    code.emitop0(dup_x2);
+                    code.emitop0(pop);
+                } else {
+                    code.emitop0(swap);
+                }
+                sym = binaryQualifier(sym, fieldAccess.selected.type);
+                code.emitop2(withfield, sym, PoolWriter::putMember);
+                result = items.makeStackItem(tree.type);
+                break;
+            default:
+                Assert.check(false);
+        }
+    }
+
     public void visitForLoop(JCForLoop tree) {
         int limit = code.nextreg;
         genStats(tree.init, env);
         genLoop(tree, tree.body, tree.cond, tree.step, true);
         code.endScopes(limit);

@@ -1936,10 +2059,11 @@
         // the parameters of the constructor's external type (that is,
         // any implicit outer instance appears as first parameter).
         genArgs(tree.args, tree.constructor.externalType(types).getParameterTypes());
 
         items.makeMemberItem(tree.constructor, true).invoke();
+
         result = items.makeStackItem(tree.type);
     }
 
     public void visitNewArray(JCNewArray tree) {
         setTypeAnnotationPositions(tree.pos);

@@ -1974,11 +2098,11 @@
                 log.error(pos, Errors.LimitDimensions);
                 nerrs++;
             }
             int elemcode = Code.arraycode(elemtype);
             if (elemcode == 0 || (elemcode == 1 && ndims == 1)) {
-                code.emitAnewarray(makeRef(pos, elemtype), type);
+                code.emitAnewarray(makeRef(pos, elemtype, types.isValue(elemtype)), type);
             } else if (elemcode == 1) {
                 code.emitMultianewarray(ndims, makeRef(pos, type), type);
             } else {
                 code.emitNewarray(elemcode, type);
             }

@@ -2203,11 +2327,17 @@
         // For basic types, the coerce(...) in genExpr(...) will do
         // the conversion.
         if (!tree.clazz.type.isPrimitive() &&
            !types.isSameType(tree.expr.type, tree.clazz.type) &&
            types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) {
-            code.emitop2(checkcast, checkDimension(tree.pos(), tree.clazz.type), PoolWriter::putClass);
+            checkDimension(tree.pos(), tree.clazz.type);
+            if (types.isValue(tree.clazz.type)) {
+                code.emitop2(checkcast, new ConstantPoolQType(tree.clazz.type, types), PoolWriter::putClass);
+            } else {
+                code.emitop2(checkcast, tree.clazz.type, PoolWriter::putClass);
+            }
+
         }
     }
 
     public void visitWildcard(JCWildcard tree) {
         throw new AssertionError(this.getClass().getName());

@@ -2268,11 +2398,15 @@
 
         if (tree.name == names._class) {
             code.emitLdc((LoadableConstant)checkDimension(tree.pos(), tree.selected.type));
             result = items.makeStackItem(pt);
             return;
-       }
+        } else if (tree.name == names._default) {
+            code.emitop2(defaultvalue, checkDimension(tree.pos(), tree.type), PoolWriter::putClass);
+            result = items.makeStackItem(tree.type);
+            return;
+        }
 
         Symbol ssym = TreeInfo.symbol(tree.selected);
 
         // Are we selecting via super?
         boolean selectSuper =

@@ -2380,10 +2514,11 @@
             this.toplevel = env.toplevel;
             this.endPosTable = toplevel.endPositions;
             /* method normalizeDefs() can add references to external classes into the constant pool
              */
             cdef.defs = normalizeDefs(cdef.defs, c);
+            cdef = transValues.translateTopLevelClass(cdef, make);
             generateReferencesToPrunedTree(c);
             Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
             localEnv.toplevel = env.toplevel;
             localEnv.enclClass = cdef;
 
< prev index next >