changeset 51256:5d5382d7200c lworld

8198749: lworld: Translation of value constructors in classic constructor notation Reviewed-by: mcimadamore
author sadayapalam
date Thu, 12 Jul 2018 16:37:53 +0530
parents 44e73ab2123d
children 00caa4e605cf
files src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/TransValues.java src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java test/langtools/tools/javac/failover/CheckAttributedTree.java test/langtools/tools/javac/valhalla/lworld-values/ConstantPropagationTest.java test/langtools/tools/javac/valhalla/lworld-values/CtorChain.java test/langtools/tools/javac/valhalla/lworld-values/InnerValueNew.java test/langtools/tools/javac/valhalla/lworld-values/LocalValueNew.java test/langtools/tools/javac/valhalla/lworld-values/QualifiedSuperCtor.java test/langtools/tools/javac/valhalla/lworld-values/QualifiedThisTest.java test/langtools/tools/javac/valhalla/lworld-values/ValueConstructorRef.java test/langtools/tools/javac/valhalla/lworld-values/ValueCreationTest.java test/langtools/tools/javac/valhalla/lworld-values/ValueNewReadWrite.java test/langtools/tools/javac/valhalla/lworld-values/ValueTypesAttributeTest.java test/langtools/tools/javac/valhalla/lworld-values/WithFieldOfExplicitSelector.java test/langtools/tools/javac/valhalla/lworld-values/WithFieldOfImplicitThis.java
diffstat 20 files changed, 808 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Thu Jul 12 09:16:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java	Thu Jul 12 16:37:53 2018 +0530
@@ -426,6 +426,12 @@
         return name == name.table.names.init;
     }
 
+    /** Is this symbol a value factory?
+     */
+    public boolean isValueFactory() {
+        return name == name.table.names.makeValue;
+    }
+
     /** The fully qualified name of this symbol.
      *  This is the same as the symbol's name except for class symbols,
      *  which are handled separately.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Jul 12 09:16:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Jul 12 16:37:53 2018 +0530
@@ -164,6 +164,7 @@
         useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
         allowGenericsOverValues = options.isSet("allowGenericsOverValues");
         allowEmptyValues = options.isSet("allowEmptyValues");
+        allowValueConstructors = options.isUnset("disallowValueConstructors");
 
         statInfo = new ResultInfo(KindSelector.NIL, Type.noType);
         varAssignmentInfo = new ResultInfo(KindSelector.ASG, Type.noType);
@@ -211,6 +212,10 @@
     boolean allowEmptyValues;
 
     /**
+     * Switch: Allow value types instantiation via new and classic constructor notation ?
+     */
+    boolean allowValueConstructors;
+    /**
      * Switch: allow strings in switch?
      */
     boolean allowStringsInSwitch;
@@ -2297,7 +2302,8 @@
                 log.error(tree.pos(), Errors.EnumCantBeInstantiated);
 
             if (tree.creationMode == CreationMode.NEW && types.isValue(clazztype)) {
-                log.error(tree.pos(), Errors.GarbledValueReferenceInstantiation);
+                if (!allowValueConstructors)
+                    log.error(tree.pos(), Errors.GarbledValueReferenceInstantiation);
             }
 
             boolean isSpeculativeDiamondInferenceRound = TreeInfo.isDiamond(tree) &&
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Thu Jul 12 09:16:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java	Thu Jul 12 16:37:53 2018 +0530
@@ -2393,7 +2393,7 @@
                         !receiverAccessible() ||
                         (tree.getMode() == ReferenceMode.NEW &&
                           tree.kind != ReferenceKind.ARRAY_CTOR &&
-                          (tree.sym.owner.isLocal() || tree.sym.owner.isInner()));
+                          (tree.sym.owner.isLocal() || tree.sym.owner.isInner() || tree.sym.owner.isValue()));
             }
 
             Type generatedRefSig() {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Thu Jul 12 09:16:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Thu Jul 12 16:37:53 2018 +0530
@@ -75,6 +75,7 @@
     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;
@@ -116,6 +117,7 @@
         accessDollar = names.
             fromString("access" + target.syntheticNameChar());
         lower = Lower.instance(context);
+        transValues = TransValues.instance(context);
 
         Options options = Options.instance(context);
         lineDebugInfo =
@@ -919,6 +921,9 @@
                     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
@@ -2300,6 +2305,7 @@
             /* 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, pool);
             Env<GenContext> localEnv = new Env<>(cdef, new GenContext());
             localEnv.toplevel = env.toplevel;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/TransValues.java	Thu Jul 12 16:37:53 2018 +0530
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.tools.javac.jvm;
+
+import com.sun.source.tree.NewClassTree.CreationMode;
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Scope.LookupKind;
+import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type.MethodType;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.JCTree.JCAssign;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
+import com.sun.tools.javac.tree.JCTree.JCFieldAccess;
+import com.sun.tools.javac.tree.JCTree.JCIdent;
+import com.sun.tools.javac.tree.JCTree.JCMethodDecl;
+import com.sun.tools.javac.tree.JCTree.JCMethodInvocation;
+import com.sun.tools.javac.tree.JCTree.JCNewClass;
+import com.sun.tools.javac.tree.JCTree.JCReturn;
+import com.sun.tools.javac.tree.JCTree.JCStatement;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.TreeTranslator;
+import com.sun.tools.javac.util.Assert;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Names;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static com.sun.tools.javac.code.Kinds.Kind.MTH;
+import static com.sun.tools.javac.code.Kinds.Kind.VAR;
+import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
+import static com.sun.tools.javac.tree.JCTree.Tag.EXEC;
+import static com.sun.tools.javac.tree.JCTree.Tag.IDENT;
+
+/**
+ * This pass translates value constructors into static factory methods and patches up constructor
+ * calls to become invocations of those static factory methods.
+ *
+ * We get commissioned as a subpass of Gen. Constructor trees undergo plenty of change in Lower
+ * (enclosing instance injection, captured locals ...) and in Gen (instance field initialization,
+ * see normalizeDefs) and so it is most effective to wait until things reach a quiescent state
+ * before undertaking the tinkering that we do.
+ *
+ * See https://bugs.openjdk.java.net/browse/JDK-8198749 for the kind of transformations we do.
+ *
+ */
+public class TransValues extends TreeTranslator {
+
+    protected static final Context.Key<TransValues> transValuesKey = new Context.Key<>();
+
+    private Symtab syms;
+    private TreeMaker make;
+    private Types types;
+    private Names names;
+
+    // class currently undergoing translation.
+    private JCClassDecl currentClass;
+
+    // method currently undergoing translation.
+    private JCMethodDecl currentMethod;
+
+    // list of factories synthesized so far.
+    private List<JCTree> staticFactories;
+
+    // Map from constructor symbols to factory symbols.
+    private Map<MethodSymbol, MethodSymbol> init2factory = new HashMap<>();
+
+    public static TransValues instance(Context context) {
+        TransValues instance = context.get(transValuesKey);
+        if (instance == null)
+            instance = new TransValues(context);
+        return instance;
+    }
+
+    protected TransValues(Context context) {
+        context.put(transValuesKey, this);
+        syms = Symtab.instance(context);
+        make = TreeMaker.instance(context);
+        types = Types.instance(context);
+        names = Names.instance(context);
+    }
+
+    public JCClassDecl translateTopLevelClass(JCClassDecl classDecl, TreeMaker make) {
+        try {
+            this.make = make;
+            translate(classDecl);
+        } finally {
+            // note that recursive invocations of this method fail hard
+            this.make = null;
+        }
+        init2factory = new HashMap<>();
+        return classDecl;
+    }
+
+    @Override
+    public void visitClassDef(JCClassDecl classDecl) {
+        JCClassDecl previousClass = currentClass;
+        List<JCTree> previousFactories = staticFactories;
+        staticFactories = List.nil();
+        currentClass = classDecl;
+        try {
+            super.visitClassDef(classDecl);
+            classDecl.defs = classDecl.defs.appendList(staticFactories);
+            staticFactories = List.nil();
+        }
+        finally {
+            currentClass = previousClass;
+            staticFactories = previousFactories;
+        }
+    }
+
+    @Override
+    public void visitMethodDef(JCMethodDecl tree) {
+        JCMethodDecl previousMethod = currentMethod;
+        currentMethod = tree;
+        try {
+            if (constructingValue()) {
+
+                /* Mutate this value constructor into an equivalent static value factory, leaving in place
+                   a dummy constructor. (A placeholder constructor is still required so that Attr and
+                   other earlier pipeline stages will see the required constructors to bind any reference
+                   style instantiations to.)
+
+                   The verifier ensures that the `new' bytecode can never be used with a value class, so
+                   constructor body can be essentially wiped out except for a call that chains to super
+                   constructor. (The latter is mandated by the verifier.)
+                */
+
+                make.at(tree.pos());
+                JCExpressionStatement exec = chainedConstructorCall(tree);
+                Assert.check(exec != null && TreeInfo.isSelfCall(exec));
+                JCMethodInvocation call = (JCMethodInvocation) exec.expr;
+
+                /* Unlike the reference construction sequence where `this' is allocated ahead of time and
+                   is passed as an argument into the <init> method, a value factory must allocate the value
+                   instance that forms the `product' by itself. We do that by injecting a prologue here.
+                */
+                VarSymbol product = currentMethod.factoryProduct = new VarSymbol(0, names.dollarValue, currentClass.sym.type, currentMethod.sym); // TODO: owner needs rewiring
+                JCExpression rhs;
+
+                final Name name = TreeInfo.name(call.meth);
+                MethodSymbol symbol = (MethodSymbol)TreeInfo.symbol(call.meth);
+                if (names._super.equals(name)) { // "initial" constructor.
+                    // Synthesize code to allocate factory "product" via: V $this = __MakeDefault V();
+                    Assert.check(symbol.owner == syms.objectType.tsym);
+                    Assert.check(symbol.type.getParameterTypes().size() == 0);
+                    MethodSymbol ctor = getDefaultConstructor(currentClass.sym);
+                    JCNewClass newClass = (JCNewClass) make.Create(ctor, List.nil(), CreationMode.DEFAULT_VALUE);
+                    newClass.constructorType = ctor.type;
+                    rhs = newClass;
+                } else {
+                    // This must be a chained call of form `this(args)'; Mutate it into a factory invocation i.e V $this = V.$makeValue$(args);
+                    Assert.check(TreeInfo.name(TreeInfo.firstConstructorCall(tree).meth) == names._this);
+                    MethodSymbol factory = getValueFactory(symbol);
+                    final JCIdent ident = make.Ident(factory);
+                    rhs = make.App(ident, call.args);
+                    ((JCMethodInvocation)rhs).varargsElement = call.varargsElement;
+                }
+
+                /* The value product allocation prologue must precede any synthetic inits !!!
+                   as these may reference `this' which gets pre-allocated for references but
+                   not for values.
+                */
+                JCStatement prologue = make.VarDef(product, rhs);
+                tree.body.stats = tree.body.stats.prepend(prologue).diff(List.of(exec));
+                tree.body = translate(tree.body);
+
+                /* We may need an epilogue that returns the value product, but we can't eagerly insert
+                   a return here, since we don't know much about control flow here. Gen#genMethod
+                   will insert a return of the factory product if control does reach the end and would
+                   "fall off the cliff" otherwise.
+                */
+
+                /* Create a factory method declaration and pass on ownership of the translated ctor body
+                   to it, wiping out the ctor body itself.
+                */
+                MethodSymbol factorySym = getValueFactory(tree.sym);
+                JCMethodDecl factoryMethod = make.MethodDef(make.Modifiers(tree.mods.flags | Flags.SYNTHETIC | Flags.STATIC, tree.mods.annotations),
+                        factorySym.name,
+                        make.Type(factorySym.type.getReturnType()),
+                        tree.typarams,
+                        null,
+                        tree.params,
+                        tree.thrown,
+                        tree.body,
+                        null);
+                factoryMethod.sym = factorySym;
+                factoryMethod.setType(factorySym.type);
+                factoryMethod.factoryProduct = product;
+                staticFactories = staticFactories.append(factoryMethod);
+                currentClass.sym.members().enter(factorySym);
+
+                // wipe out the body of the ctor and insert just a super call.
+                MethodSymbol jlOCtor = getDefaultConstructor(syms.objectType.tsym);
+                JCExpression meth = make.Ident(names._super).setType(jlOCtor.type);
+                TreeInfo.setSymbol(meth, jlOCtor);
+
+                final JCExpressionStatement superCall = make.Exec(make.Apply(null, meth, List.nil()).setType(syms.voidType));
+                tree.body = make.at(tree.body).Block(0, List.of(superCall));
+                result = tree;
+                return;
+            }
+            super.visitMethodDef(tree);
+        } finally {
+            currentMethod = previousMethod;
+        }
+    }
+
+    @Override
+    public void visitReturn(JCReturn tree) {
+        if (constructingValue()) {
+            result = make.Return(make.Ident(currentMethod.factoryProduct));
+        } else {
+            super.visitReturn(tree);
+        }
+    }
+
+    /* Note: 1. Assignop does not call for any translation, since value instance fields are final and
+       so cannot be AssignedOped. 2. Any redundantly qualified this would have been lowered already.
+    */
+    @Override
+    public void visitAssign(JCAssign tree) {
+        if (constructingValue()) {
+            Symbol symbol = null;
+            switch(tree.lhs.getTag()) {
+                case IDENT:
+                    symbol = ((JCIdent)tree.lhs).sym;
+                    break;
+                case SELECT:
+                    JCFieldAccess fieldAccess = (JCFieldAccess) tree.lhs;
+                    if (fieldAccess.selected.hasTag(IDENT) && ((JCIdent)fieldAccess.selected).name == names._this) {
+                        symbol = fieldAccess.sym;
+                    }
+                    break;
+                default:
+                    break;
+            }
+            if (isInstanceFieldAccess(symbol)) {
+                final JCIdent facHandle = make.Ident(currentMethod.factoryProduct);
+                result = make.Assign(facHandle, make.WithField(make.Select(facHandle, symbol), translate(tree.rhs)).setType(currentClass.type)).setType(currentClass.type);
+                return;
+            }
+        }
+        super.visitAssign(tree);
+    }
+
+    @Override
+    public void visitIdent(JCIdent ident) {
+        if (constructingValue()) {
+            Symbol symbol = ident.sym;
+            if (isInstanceFieldAccess(symbol)) {
+                final JCIdent facHandle = make.Ident(currentMethod.factoryProduct);
+                result = make.Select(facHandle, symbol);
+                return;
+            }
+        }
+        super.visitIdent(ident);
+    }
+
+    @Override
+    public void visitSelect(JCFieldAccess fieldAccess) {
+        if (constructingValue()) { // Qualified this would have been lowered already.
+            if (fieldAccess.selected.hasTag(IDENT) && ((JCIdent)fieldAccess.selected).name == names._this) {
+                Symbol symbol = fieldAccess.sym;
+                if (isInstanceFieldAccess(symbol)) {
+                    final JCIdent facHandle = make.Ident(currentMethod.factoryProduct);
+                    result = make.Select(facHandle, symbol);
+                    return;
+                }
+            }
+        }
+        super.visitSelect(fieldAccess);
+    }
+
+    // Translate a reference style instance creation attempt on a value type to a static factory call.
+    @Override
+    public void visitNewClass(JCNewClass tree) {
+        if (tree.creationMode == CreationMode.NEW && types.isValue(tree.clazz.type)) {
+            tree.encl = translate(tree.encl);
+            tree.args = translate(tree.args);
+            Assert.check(tree.def == null);
+            MethodSymbol sFactory = getValueFactory((MethodSymbol) tree.constructor);
+            make.at(tree.pos());
+            JCExpression meth = tree.encl == null ? make.Ident(sFactory): make.Select(tree.encl, sFactory); // TODO: tree.encl must have been folded already into a synth argument and nullified
+            meth.type = types.erasure(meth.type);
+            final JCMethodInvocation apply = make.Apply(tree.typeargs, meth, tree.args);
+            apply.varargsElement = tree.varargsElement;
+            apply.type = meth.type.getReturnType();
+            result = apply;
+            return;
+        }
+        super.visitNewClass(tree);
+    }
+
+    // Utility methods ...
+    private boolean constructingValue() {
+        return currentClass != null && (currentClass.sym.flags() & Flags.VALUE) != 0 && currentMethod != null && currentMethod.sym.isConstructor();
+    }
+
+    private boolean isInstanceFieldAccess(Symbol symbol) {
+        return symbol != null && symbol.kind == VAR && symbol.owner == currentClass.sym && !symbol.isStatic();
+    }
+
+    private MethodSymbol getValueFactory(MethodSymbol init) {
+        Assert.check(init.name.equals(names.init));
+        Assert.check(types.isValue(init.owner.type));
+        MethodSymbol factory = init2factory.get(init);
+        if (factory != null)
+            return factory;
+
+        final WriteableScope classScope = init.owner.members();
+        Assert.check(classScope.includes(init, LookupKind.NON_RECURSIVE));
+
+        MethodType factoryType = new MethodType(init.externalType(types).getParameterTypes(), // init.externalType to account for synthetics.
+                                                init.owner.type,
+                                                init.type.getThrownTypes(),
+                                                init.owner.type.tsym);
+        factory = new MethodSymbol(init.flags_field | Flags.STATIC | Flags.SYNTHETIC,
+                                        names.makeValue,
+                                        factoryType,
+                                        init.owner);
+        factory.setAttributes(init);
+        init2factory.put(init, factory);
+        return factory;
+    }
+
+    /** Return the *statement* in the constructor that `chains' to another constructor call either
+     *  in the same class or its superclass. One MUST exist except for jlO, though may be buried
+     *  under synthetic initializations.
+     */
+    private JCExpressionStatement chainedConstructorCall(JCMethodDecl md) {
+        if (md.name == names.init && md.body != null) {
+            for (JCStatement statement : md.body.stats) {
+                if (statement.hasTag(EXEC)) {
+                    JCExpressionStatement exec = (JCExpressionStatement)statement;
+                    if (exec.expr.hasTag(APPLY)) {
+                        JCMethodInvocation apply = (JCMethodInvocation)exec.expr;
+                        Name name = TreeInfo.name(apply.meth);
+                        if (name == names._super || name == names._this)
+                            return exec;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    private MethodSymbol getDefaultConstructor(Symbol klass) {
+        for (Symbol method : klass.members().getSymbolsByName(names.init, s->s.kind == MTH && s.type.getParameterTypes().size() == 0, LookupKind.NON_RECURSIVE)) {
+            return (MethodSymbol) method;
+        }
+        // class defines a non-nullary but no nullary constructor, fabricate a symbol.
+        MethodType dctorType = new MethodType(List.nil(),
+                klass.type,
+                List.nil(),
+                klass.type.tsym);
+        return new MethodSymbol(Flags.PUBLIC,
+                names.init,
+                dctorType,
+                klass);
+    }
+}
\ No newline at end of file
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Thu Jul 12 09:16:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Thu Jul 12 16:37:53 2018 +0530
@@ -842,6 +842,9 @@
         public JCExpression defaultValue;
         /** method symbol */
         public MethodSymbol sym;
+        /** nascent value that evolves into the return value for a value factory */
+        public VarSymbol factoryProduct;
+
         protected JCMethodDecl(JCModifiers mods,
                             Name name,
                             JCExpression restype,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Thu Jul 12 09:16:54 2018 +0200
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Thu Jul 12 16:37:53 2018 +0530
@@ -206,6 +206,10 @@
     public final Name makeConcat;
     public final Name makeConcatWithConstants;
 
+    // values
+    public final Name makeValue;
+    public final Name dollarValue;
+
     public final Name.Table table;
 
     public Names(Context context) {
@@ -370,6 +374,11 @@
         // string concat
         makeConcat = fromString("makeConcat");
         makeConcatWithConstants = fromString("makeConcatWithConstants");
+
+        // value types
+        makeValue = fromString("$makeValue$");
+        dollarValue = fromString("$value");
+
     }
 
     protected Name.Table createTable(Options options) {
--- a/test/langtools/tools/javac/failover/CheckAttributedTree.java	Thu Jul 12 09:16:54 2018 +0200
+++ b/test/langtools/tools/javac/failover/CheckAttributedTree.java	Thu Jul 12 16:37:53 2018 +0530
@@ -405,7 +405,7 @@
                         that.hasTag(CLASSDEF);
             }
 
-            private final List<String> excludedFields = Arrays.asList("varargsElement", "targetType");
+            private final List<String> excludedFields = Arrays.asList("varargsElement", "targetType", "factoryProduct");
 
             void check(boolean ok, String label, Info self) {
                 if (!ok) {
--- a/test/langtools/tools/javac/valhalla/lworld-values/ConstantPropagationTest.java	Thu Jul 12 09:16:54 2018 +0200
+++ b/test/langtools/tools/javac/valhalla/lworld-values/ConstantPropagationTest.java	Thu Jul 12 16:37:53 2018 +0530
@@ -56,15 +56,7 @@
         runCheck(params, new String [] {
 
          "ConstantValue: int 8888",
-         "0: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;",
          "3: sipush        8888",
-         "6: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V",
-         "9: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;",
-         "12: aload_0",
-         "13: getfield      #2                  // Field ifif:I",
-        "16: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V",
-        "19: return",
-           
          }, new String [] {
          "ConstantValue: int 9999"
          });
@@ -96,4 +88,4 @@
              throw new AssertionError("Unexpected javap output: " + out);
         }
     }
-}
\ No newline at end of file
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/valhalla/lworld-values/CtorChain.java	Thu Jul 12 16:37:53 2018 +0530
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8198749
+ * @summary Test value instatiation using new/ctors by chaining constructors.
+ * @run main/othervm -XX:+EnableValhalla CtorChain
+ */
+
+public __ByValue class CtorChain {
+    int x1, x2, x3, x4, x5;
+    CtorChain() {
+        this(10);
+    }
+    CtorChain(int a) {
+        this(a, 20);
+    }
+    CtorChain(int a, int b) {
+        this(a, b, 30);
+    }
+    CtorChain(int a, int b, int c) {
+        this(a, b, c, 40);
+    }
+    CtorChain(int a, int b, int c, int d) {
+        this(a, b, c, d, 50);
+    }
+    CtorChain(int a, int b, int c, int d, int e) {
+        this.x1 = a;
+        this.x2 = b;
+        this.x3 = c;
+        this.x4 = d;
+        this.x5 = e;
+        return;
+    }
+
+    public static void main(String [] args) {
+        String o = new CtorChain().toString();
+        if (!o.equals("[value class CtorChain, 10, 20, 30, 40, 50]"))
+            throw new AssertionError("Broken");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/valhalla/lworld-values/InnerValueNew.java	Thu Jul 12 16:37:53 2018 +0530
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8198749
+ * @summary Test value instatiation using new/ctors.
+ * @run main/othervm -XX:+EnableValhalla InnerValueNew
+ */
+
+
+public class InnerValueNew {
+    final __ByValue class Y {
+        final int x;
+        final int p = 123456;
+        Y() {
+            this(123400);
+        }
+
+        Y(int x) {
+            this.x = x;
+        }
+    }
+    public static void main(String[] args) {
+        Y y1 = new InnerValueNew().new Y();
+        Y y2 = new InnerValueNew().new Y(56);
+        if (y2.x + y1.x != y1.p)
+           throw new AssertionError("Broken");
+        if (y2.x + y1.x != y2.p)
+           throw new AssertionError("Broken");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/valhalla/lworld-values/LocalValueNew.java	Thu Jul 12 16:37:53 2018 +0530
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8198749
+ * @summary Test value instatiation using new/ctors.
+ * @run main/othervm -XX:+EnableValhalla LocalValueNew
+ */
+
+
+public class LocalValueNew {
+    int xf = 1234;
+    void foo() {
+        int xl = 10; int yl = 20;
+        final __ByValue class Y {
+            final int x;
+            final int p = 123456;
+            Y() {
+                this(123400);
+            }
+
+            Y(int x) {
+                this.x = x;
+            }
+            void goo() {
+                if (xf + xl + yl + this.x + this.p != 223485)
+                    throw new AssertionError("Broken");
+            }
+        }
+
+        new Y(98765).goo();
+    }
+    public static void main(String[] args) {
+        new LocalValueNew().foo();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/valhalla/lworld-values/QualifiedSuperCtor.java	Thu Jul 12 16:37:53 2018 +0530
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8198749
+ * @summary Test value instatiation using new/ctors.
+ * @run main/othervm -XX:+EnableValhalla QualifiedSuperCtor
+ */
+
+__ByValue class A {
+    int x = 1000000;
+    class Inner { 
+        String aDotThis;
+        Inner() {
+            aDotThis = A.this.toString();
+        }
+
+        String getADotThis() {
+            return aDotThis;
+        }
+    }
+}
+
+public class QualifiedSuperCtor extends A.Inner {
+    QualifiedSuperCtor(A encl) {
+        encl.super();
+    }
+
+    public static void main(String [] args) {
+        if (!new QualifiedSuperCtor(new A()).getADotThis().equals("[value class A, 1000000]"))
+            throw new AssertionError("Broken");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/valhalla/lworld-values/QualifiedThisTest.java	Thu Jul 12 16:37:53 2018 +0530
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8198749
+ * @summary Test that qualified this based access to instance fields works ok.
+ * @run main/othervm -XX:+EnableValhalla QualifiedThisTest
+ */
+
+public __ByValue  class QualifiedThisTest {
+
+    final int x;
+    final int y;
+
+    final int thrice_x_plus_thrice_y;
+
+    QualifiedThisTest(int xp, int yp) {
+        this.y = yp;
+        this.x = xp;
+        thrice_x_plus_thrice_y = x + this.x + QualifiedThisTest.this.x + y + this.y + QualifiedThisTest.this.y;
+    }
+
+    public static void main(String [] args) {
+        int v;
+        if ((v = new QualifiedThisTest(1234, 10).thrice_x_plus_thrice_y) != 3732)
+            throw new AssertionError("Broken" + v);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/valhalla/lworld-values/ValueConstructorRef.java	Thu Jul 12 16:37:53 2018 +0530
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8198749
+ * @summary Test that qualified this based access to instance fields works ok.
+ * @compile -XDallowGenericsOverValues ValueConstructorRef.java
+ * @run main/othervm -XX:+EnableValhalla ValueConstructorRef
+ */
+
+import java.util.function.Supplier;
+
+public __ByValue class ValueConstructorRef {
+
+    final int x;
+    final int y;
+
+    ValueConstructorRef() {
+    	x = 1234;
+    	y = 5678;
+    }
+    
+    public static void main(String [] args) {   
+    	Supplier<ValueConstructorRef> sx = ValueConstructorRef::new;
+    	ValueConstructorRef x = sx.get();
+        if (!x.toString().equals("[value class ValueConstructorRef, 1234, 5678]"))
+            throw new AssertionError(x);
+    }
+}
--- a/test/langtools/tools/javac/valhalla/lworld-values/ValueCreationTest.java	Thu Jul 12 09:16:54 2018 +0200
+++ b/test/langtools/tools/javac/valhalla/lworld-values/ValueCreationTest.java	Thu Jul 12 16:37:53 2018 +0530
@@ -68,15 +68,15 @@
                                                 "ValueCreationTest$Point.class").toString() };
         runCheck(params, new String [] {
 
-         "0: defaultvalue  #4                  // class ValueCreationTest$Point",
+         "0: defaultvalue  #2                  // class ValueCreationTest$Point",
          "3: astore_2",
          "4: aload_2",
          "5: iload_0",
-         "6: withfield     #2                  // Field x:I",
+         "6: withfield     #3                  // Field x:I",
          "9: astore_2",
         "10: aload_2",
         "11: iload_1",
-        "12: withfield     #3                  // Field y:I",
+        "12: withfield     #4                  // Field y:I",
         "15: areturn"
            
          });
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/langtools/tools/javac/valhalla/lworld-values/ValueNewReadWrite.java	Thu Jul 12 16:37:53 2018 +0530
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8198749
+ * @summary Test value instatiation using new/ctors.
+ * @run main/othervm -XX:+EnableValhalla ValueNewReadWrite
+ */
+
+public __ByValue class ValueNewReadWrite {
+
+    int y = 10;
+    int twice_x_plus_y;
+    int x;
+
+    ValueNewReadWrite(int x) {
+        this.x = x;
+        twice_x_plus_y = 2 * this.x + y;;
+    }
+
+    public static void main(String [] args) {
+        if (new ValueNewReadWrite(1234).twice_x_plus_y != 2478)
+            throw new AssertionError("Broken");
+    }
+}
--- a/test/langtools/tools/javac/valhalla/lworld-values/ValueTypesAttributeTest.java	Thu Jul 12 09:16:54 2018 +0200
+++ b/test/langtools/tools/javac/valhalla/lworld-values/ValueTypesAttributeTest.java	Thu Jul 12 16:37:53 2018 +0530
@@ -70,7 +70,7 @@
          "ValueTypes:",
          "#36;                                    // value class V4",
          "#24;                                    // value class V2",
-         "#7;                                     // value class ValueTypesAttributeTest$X",
+         "#6;                                     // value class ValueTypesAttributeTest$X",
          "#10;                                    // value class V1",
          "#27;                                    // value class V3",
          "#41;                                    // value class V5",
--- a/test/langtools/tools/javac/valhalla/lworld-values/WithFieldOfExplicitSelector.java	Thu Jul 12 09:16:54 2018 +0200
+++ b/test/langtools/tools/javac/valhalla/lworld-values/WithFieldOfExplicitSelector.java	Thu Jul 12 16:37:53 2018 +0530
@@ -63,12 +63,12 @@
 
          "0: aload_0",
          "1: iload_1",
-         "2: withfield     #3                  // Field i:I",
+         "2: withfield     #2                  // Field i:I",
          "5: astore_3",
          "6: aload_3",
          "7: aload_2",
-        "8: invokevirtual #4                  // Method java/lang/Integer.intValue:()I",
-        "11: withfield     #3                  // Field i:I",
+        "8: invokevirtual #3                  // Method java/lang/Integer.intValue:()I",
+        "11: withfield     #2                  // Field i:I",
         "14: astore_3",
         "15: aload_3",
         "16: areturn"
--- a/test/langtools/tools/javac/valhalla/lworld-values/WithFieldOfImplicitThis.java	Thu Jul 12 09:16:54 2018 +0200
+++ b/test/langtools/tools/javac/valhalla/lworld-values/WithFieldOfImplicitThis.java	Thu Jul 12 16:37:53 2018 +0530
@@ -62,7 +62,7 @@
                                                 "WithFieldOfImplicitThis$X.class").toString() };
         runCheck(params, new String [] {
 
-         "0: defaultvalue  #4                  // class WithFieldOfImplicitThis$X",
+         "0: defaultvalue  #2                  // class WithFieldOfImplicitThis$X",
          "3: astore_3",
          "4: aload_0",
          "5: iload_2",
@@ -70,7 +70,7 @@
          "9: astore_3",
         "10: aload_0",
         "11: aload_1",
-        "12: invokevirtual #5                  // Method java/lang/Integer.intValue:()I",
+        "12: invokevirtual #4                  // Method java/lang/Integer.intValue:()I",
         "15: withfield     #3                  // Field x:I",
         "18: astore_3",
         "19: aload_3",