changeset 3522:a82751a8e69b

Enhancement: Add support for alternate mode of value creation using __MakeDefault
author sadayapalam
date Fri, 25 Nov 2016 13:10:35 +0530
parents ef0142d1ab9a
children ce7460995ffc
files src/java.compiler/share/classes/javax/lang/model/element/Modifier.java src/jdk.compiler/share/classes/com/sun/source/tree/NewClassTree.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ByteCodes.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java src/jdk.jdeps/share/classes/com/sun/tools/classfile/Opcode.java src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java test/tools/javac/diags/examples.not-yet.txt test/tools/javac/valhalla/values/CheckMakeDefault.java test/tools/javac/valhalla/values/CheckMakeDefault.out test/tools/javac/valhalla/values/CheckStaticValueFactory.java test/tools/javac/valhalla/values/CheckStaticValueFactory.out test/tools/javac/valhalla/values/ValueCreationTest.java
diffstat 23 files changed, 421 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/java.compiler/share/classes/javax/lang/model/element/Modifier.java	Fri Nov 25 13:10:35 2016 +0530
@@ -59,11 +59,17 @@
      */
      DEFAULT,
     /**
-     * The modifier {@code default}
+     * The modifier {@code __ByValue}
      * @since 1.9
      */
      VALUE,
     /**
+     * The modifier {@code __ValueFactory}
+     * @since 1.9
+     */
+    STATICVALUEFACTORY,
+
+    /**
      * The modifier {@code species static}
      * @since 1.9
      */
--- a/src/jdk.compiler/share/classes/com/sun/source/tree/NewClassTree.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/source/tree/NewClassTree.java	Fri Nov 25 13:10:35 2016 +0530
@@ -49,6 +49,20 @@
  * @since 1.6
  */
 public interface NewClassTree extends ExpressionTree {
+
+    /**
+     * There are three kinds of new class trees: (i) references (new String("Foo"))
+     * (ii) values (__Make Point(10, 20)) (iii) default values (__MakeDefault Point())
+     */
+    public enum CreationMode {
+        /** enum constant for reference creation. */
+        NEW,
+        /** enum constant for value creation. */
+        VALUE,
+        /** enum constant for default value creation. */
+        DEFAULT_VALUE,
+    }
+
     /**
      * Returns the enclosing expression, or {@code null} if none.
      * @return the enclosing expression
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Fri Nov 25 13:10:35 2016 +0530
@@ -91,7 +91,7 @@
     /** Flag that marks attribute interfaces, added in classfile v49.0. */
     public static final int ANNOTATION   = 1<<13;
 
-    /** Flag to mark value factory methods. */
+    /** Flag to mark value factory methods. (vminit methods as opposed to static value factory methods) */
     public static final int VALUEFACTORY = 1<<13;
 
     /** An enumeration type or an enumeration constant, added in
@@ -129,6 +129,11 @@
      */
     public static final int HASINIT          = 1<<18;
 
+    /** Flag is set for a method symbol that acts as a static factory method for a value type
+     *  (contrast with vminit methods flagged as STATICVALUEFACTORY)
+     */
+    public static final int STATICVALUEFACTORY = 1<<19;
+
     /** Flag is set for compiler-generated anonymous method symbols
      *  that `own' an initializer block.
      */
@@ -333,14 +338,14 @@
         InterfaceVarImplicitFlags     = FINAL | STATIC | PUBLIC;
 
     public static final long
-        ExtendedStandardFlags       = (long)StandardFlags | DEFAULT | VALUE | SPECIES,
+        ExtendedStandardFlags       = (long)StandardFlags | DEFAULT | VALUE | SPECIES | STATICVALUEFACTORY,
         MemberClassFlags      = LocalClassFlags | INTERFACE | AccessFlags,
         VarFlags              = AccessFlags | FINAL | STATIC |
                                 VOLATILE | TRANSIENT | ENUM | SPECIES,
         ConstructorFlags      = AccessFlags,
         InterfaceMethodFlags  = ABSTRACT | PUBLIC | PRIVATE | STATIC | STRICTFP | DEFAULT | SPECIES,
         MethodFlags           = AccessFlags | ABSTRACT | STATIC | NATIVE |
-                                SYNCHRONIZED | FINAL | STRICTFP | VALUEFACTORY | SPECIES,
+                                SYNCHRONIZED | FINAL | STRICTFP | VALUEFACTORY | SPECIES | STATICVALUEFACTORY,
         ModifierFlags               = ((long)StandardFlags & ~INTERFACE) | DEFAULT | VALUE | SPECIES,
         LocalVarFlags               = FINAL | PARAMETER,
         ReceiverParamFlags          = PARAMETER;
@@ -365,6 +370,7 @@
             if (0 != (flags & STRICTFP))  modifiers.add(Modifier.STRICTFP);
             if (0 != (flags & DEFAULT))   modifiers.add(Modifier.DEFAULT);
             if (0 != (flags & VALUE))     modifiers.add(Modifier.VALUE);
+            if (0 != (flags & STATICVALUEFACTORY))     modifiers.add(Modifier.STATICVALUEFACTORY);
             modifiers = Collections.unmodifiableSet(modifiers);
             modifierSets.put(flags, modifiers);
         }
@@ -406,6 +412,7 @@
         ANNOTATION(Flags.ANNOTATION),
         DEPRECATED(Flags.DEPRECATED),
         HASINIT(Flags.HASINIT),
+        STATICVALUEFACTORY(Flags.STATICVALUEFACTORY),
         BLOCK(Flags.BLOCK),
         ENUM(Flags.ENUM),
         MANDATED(Flags.MANDATED),
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Fri Nov 25 13:10:35 2016 +0530
@@ -33,6 +33,7 @@
 import com.sun.source.tree.IdentifierTree;
 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
 import com.sun.source.tree.MemberSelectTree;
+import com.sun.source.tree.NewClassTree.CreationMode;
 import com.sun.source.tree.TreeVisitor;
 import com.sun.source.util.SimpleTreeVisitor;
 import com.sun.tools.javac.code.*;
@@ -297,7 +298,19 @@
             if (v.isResourceVariable()) { //TWR resource
                 log.error(pos, "try.resource.may.not.be.assigned", v);
             } else {
-                log.error(pos, "cant.assign.val.to.final.var", v);
+                boolean complain = true;
+                /* Allow updates to blank final fields inside value factories.
+                   This really results in copy on write and not mutation of the
+                   final field
+                */
+                if (v.getKind() == ElementKind.FIELD && (v.flags() & HASINIT) == 0) {
+                    if (env.enclMethod != null && (env.enclMethod.mods.flags & STATICVALUEFACTORY) != 0) {
+                        if (v.owner == env.enclMethod.sym.owner)
+                            complain = false;
+                    }
+                }
+                if (complain)
+                    log.error(pos, "cant.assign.val.to.final.var", v);
             }
         }
     }
@@ -2134,7 +2147,8 @@
                  ((JCVariableDecl) env.tree).init != tree))
                 log.error(tree.pos(), "enum.cant.be.instantiated");
 
-            if (types.isValue(clazztype) != tree.isValue) {
+            if ((tree.creationMode == CreationMode.NEW && types.isValue(clazztype)) ||
+                    tree.creationMode == CreationMode.VALUE && !types.isValue(clazztype)) {
                 log.error(tree.pos(), Errors.GarbledValueReferenceInstantiation);
             }
             boolean isSpeculativeDiamondInferenceRound = TreeInfo.isDiamond(tree) &&
@@ -2237,6 +2251,22 @@
                         tree.constructorType = instantiatedContext.asInstType(tree.constructorType);
                     });
         }
+        if (tree.creationMode == CreationMode.DEFAULT_VALUE) {
+            if (tree.constructor != null && tree.constructor.isConstructor()) {
+                final List<Type> parameterTypes = tree.constructorType.getParameterTypes();
+                if (!parameterTypes.isEmpty()) {
+                    log.error(tree.pos, "invalid.arguments.to.make.default");
+                }
+                if (!types.isValue(TreeInfo.symbol(tree.clazz).type)) {
+                    log.error(tree.pos, "make.default.with.nonvalue");
+                } else if (env.enclMethod != null && env.enclMethod.sym.owner != TreeInfo.symbol(tree.clazz)) {
+                    log.error(tree.pos, "make.default.with.wrong.value.type", TreeInfo.symbol(tree.clazz));
+                }
+            }
+            if (env.enclMethod != null && (env.enclMethod.mods.flags & STATICVALUEFACTORY) == 0) {
+                log.error(tree.pos, "make.default.in.nonfactory");
+            }
+        }
         chk.validate(tree.typeargs, localEnv);
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java	Fri Nov 25 13:10:35 2016 +0530
@@ -146,7 +146,7 @@
                         return make.at(t.pos).NewClass(encl, typeargs, clazz, args, def);
                     } else {
                         final JCNewClass newClass = (JCNewClass) super.visitNewClass(node, p);
-                        newClass.isValue = t.isValue;
+                        newClass.creationMode = t.creationMode;
                         return newClass;
                     }
                 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Fri Nov 25 13:10:35 2016 +0530
@@ -38,6 +38,8 @@
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.tree.JCTree.*;
 
+import javax.lang.model.element.ElementKind;
+
 import static com.sun.tools.javac.code.Flags.*;
 import static com.sun.tools.javac.code.Flags.BLOCK;
 import static com.sun.tools.javac.code.Kinds.Kind.*;
@@ -1489,6 +1491,7 @@
         }
 
         private boolean isInitialConstructor = false;
+        private JCMethodDecl enclMethod = null;
 
         @Override
         protected void markDead() {
@@ -1574,7 +1577,15 @@
                 }
                 inits.incl(sym.adr);
             } else if ((sym.flags() & FINAL) != 0) {
-                log.error(pos, "var.might.already.be.assigned", sym);
+                boolean complain = true;
+                if (sym.getKind() == ElementKind.FIELD && (sym.flags() & HASINIT) == 0) {
+                    if (enclMethod != null && (enclMethod.mods.flags & STATICVALUEFACTORY) != 0) {
+                        if (sym.owner == enclMethod.sym.owner)
+                            complain = false;
+                    }
+                }
+                if (complain)
+                    log.error(pos, "var.might.already.be.assigned", sym);
             }
         }
         //where
@@ -1815,8 +1826,10 @@
 
                 Assert.check(pendingExits.isEmpty());
                 boolean lastInitialConstructor = isInitialConstructor;
+                JCMethodDecl lastEnclMethod = enclMethod;
                 try {
                     isInitialConstructor = TreeInfo.isInitialConstructor(tree);
+                    enclMethod = tree;
 
                     if (!isInitialConstructor) {
                         firstadr = nextadr;
@@ -1872,6 +1885,7 @@
                     firstadr = firstadrPrev;
                     returnadr = returnadrPrev;
                     isInitialConstructor = lastInitialConstructor;
+                    enclMethod = lastEnclMethod;
                 }
             } finally {
                 lint = lintPrev;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Fri Nov 25 13:10:35 2016 +0530
@@ -243,6 +243,15 @@
         if (wcc.hasConcrete && m.enclClass().isInterface()) {
             m.enclClass().flags_field |= DEFAULT;
         }
+        if ((tree.mods.flags & STATICVALUEFACTORY) != 0) {
+            if ((tree.mods.flags & STATIC) == 0) {
+                log.error(tree.pos(), "value.factory.must.be.static");
+            }
+            final Type returnType = m.getReturnType();
+            if (returnType != null && returnType.tsym != m.owner) {
+                log.error(tree.restype != null ? tree.restype.pos() : tree.pos(), "type.found.req", returnType.tsym, m.owner);
+            }
+        }
     }
 
     class WhereClauseChecker extends TreeScanner {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ByteCodes.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ByteCodes.java	Fri Nov 25 13:10:35 2016 +0530
@@ -258,7 +258,10 @@
 
         invokedirect   =  213,
 
-        ByteCodeCount   = 214;
+        vdefault       =  214,
+        vwithfield     =  215,
+
+        ByteCodeCount   = 216;
 
     /** Virtual instruction codes; used for constant folding.
      */
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Code.java	Fri Nov 25 13:10:35 2016 +0530
@@ -1293,6 +1293,9 @@
         case putstatic:
             state.pop(memberForPool(od).externalType(types));
             break;
+        case vdefault:
+            state.push(classForPool(od));
+            break;
         case vnew:
         case new_:
             Type t = classForPool(od);
@@ -1324,6 +1327,9 @@
         case goto_:
             markDead();
             break;
+        case vwithfield:
+            state.pop(memberForPool(od).externalType(types));
+            break;
         case putfield:
             state.pop(memberForPool(od).externalType(types));
             state.pop(1); // object ref
@@ -2768,6 +2774,8 @@
             mnem[vgetfield] = "vgetfield";
             mnem[typed] = "typed";
             mnem[invokedirect] = "invokedirect";
+            mnem[vdefault] = "vdefault";
+            mnem[vwithfield] = "vwithfield";
         }
     }
 }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Fri Nov 25 13:10:35 2016 +0530
@@ -27,6 +27,7 @@
 
 import java.util.function.Predicate;
 
+import com.sun.source.tree.NewClassTree.CreationMode;
 import com.sun.tools.javac.code.Dynamic.DynamicConstant;
 import com.sun.tools.javac.code.Types.TypeVarContext;
 import com.sun.tools.javac.comp.Resolve.StaticLevel;
@@ -2058,11 +2059,17 @@
         Type newType = tree.type;
 
         if (types.isValue(newType)) {
-            // For values, the creation sequence is simpler: push all arguments, then emit vnew.
-            // Abuse the constructor signature to determine the arguments.
-            List<Type> parameterTypes = tree.constructor.externalType(types).getParameterTypes();
-            genArgs(tree.args, parameterTypes);
-            code.emitVnew(newType, makeRef(tree.pos(), tree.type, parameterTypes), Code.width(parameterTypes));
+            if (tree.creationMode == CreationMode.DEFAULT_VALUE) {
+                Assert.check(tree.constructorType.getParameterTypes().isEmpty());
+                code.emitop2(vdefault, makeRef(tree.pos(), newType));
+            } else {
+                // For values, the creation sequence is simpler: push all arguments, then emit vnew.
+                // Abuse the constructor signature to determine the arguments.
+                Assert.check(tree.creationMode == CreationMode.VALUE);
+                List<Type> parameterTypes = tree.constructor.externalType(types).getParameterTypes();
+                genArgs(tree.args, parameterTypes);
+                code.emitVnew(newType, makeRef(tree.pos(), tree.type, parameterTypes), Code.width(parameterTypes));
+            }
         } else {
             code.emitop2(new_, makeRef(tree.pos(), newType));
             code.emitop0(dup);
@@ -2540,11 +2547,18 @@
                     code.emitop0(arraylength);
                     result = items.makeStackItem(syms.intType);
                 } else {
+                    boolean requireCopyOnWrite = false;
+                    if (sym.kind == VAR && (sym.flags() & FINAL) != 0) {
+                        if ((env.enclMethod.mods.flags & STATICVALUEFACTORY) != 0) {
+                            if (sym.owner == env.enclClass.sym)
+                                requireCopyOnWrite = true;
+                        }
+                    }
                     result = sym.kind == MTH ?
                             items.makeMethodItem(sym,
                                        (sym.flags() & PRIVATE) != 0 ||
                                        selectSuper || accessSuper, types.isValue(tree.selected.type)) :
-                            items.makeFieldItem(rcv, sym);
+                            items.makeFieldItem(rcv, sym, requireCopyOnWrite ? base : null);
                 }
             }
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Items.java	Fri Nov 25 13:10:35 2016 +0530
@@ -197,10 +197,19 @@
     /** Make an item representing an instance variable.
      *  @param rcvItem      The receiver item
      *  @param member       The represented symbol.
+     *  @param baseToCopyOnWrite Updates to fields imply copy on write to this receiver
+     */
+    Item makeFieldItem(Item rcvItem, Symbol member, Item baseToCopyOnWrite) {
+        Item i = baseToCopyOnWrite != null ? new CopyOnWriteFieldItem(baseToCopyOnWrite, member) : new FieldItem(member);
+        return wrapIfNeeded(i, i, Item::isAny, Item::originalType);
+    }
+
+    /** Make an item representing an instance variable.
+     *  @param rcvItem      The receiver item
+     *  @param member       The represented symbol.
      */
     Item makeFieldItem(Item rcvItem, Symbol member) {
-        Item i = new FieldItem(member);
-        return wrapIfNeeded(i, i, Item::isAny, Item::originalType);
+        return makeFieldItem(rcvItem, member, null);
     }
 
     /** Make an item representing a literal.
@@ -996,6 +1005,21 @@
         }
     }
 
+    class CopyOnWriteFieldItem extends FieldItem {
+
+        Item rcvItem;
+
+        CopyOnWriteFieldItem(Item rcvItem, Symbol member) {
+            super(member);
+            this.rcvItem = rcvItem;
+        }
+
+        void store() {
+            code.emitop2(vwithfield, pool.putSymbol(member));
+            rcvItem.store();
+        }
+    }
+
     class MethodItem extends MemberItem {
 
         /** Flag that determines whether or not access is virtual.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Nov 25 13:10:35 2016 +0530
@@ -30,6 +30,7 @@
 
 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
 
+import com.sun.source.tree.NewClassTree.CreationMode;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Flags.Flag;
 import com.sun.tools.javac.parser.Tokens.*;
@@ -407,6 +408,7 @@
                 case SUPER:
                 case NEW:
                 case VNEW:
+                case VDEFAULT:
                     if (stopAtStatement)
                         return;
                     break;
@@ -1197,13 +1199,14 @@
             break;
         case NEW:
         case VNEW:
+        case VDEFAULT:
             if (typeArgs != null) return illegal();
             if ((mode & EXPR) != 0) {
                 mode = EXPR;
-                boolean isValue = token.kind == VNEW;
+                CreationMode creationMode = getCreationMode(token);
                 nextToken();
                 if (token.kind == LT) typeArgs = typeArguments(false);
-                t = creator(pos, isValue, typeArgs);
+                t = creator(pos, creationMode, typeArgs);
                 typeArgs = null;
             } else return illegal();
             break;
@@ -1323,13 +1326,14 @@
                                 break loop;
                             case NEW:
                             case VNEW:
+                            case VDEFAULT:
                                 if (typeArgs != null) return illegal();
                                 mode = EXPR;
                                 int pos1 = token.pos;
-                                boolean isValue = token.kind == VNEW;
+                                CreationMode creationMode = getCreationMode(token);
                                 nextToken();
                                 if (token.kind == LT) typeArgs = typeArguments(false);
-                                t = innerCreator(pos1, isValue, typeArgs, t);
+                                t = innerCreator(pos1, creationMode, typeArgs, t);
                                 typeArgs = null;
                                 break loop;
                             }
@@ -1372,6 +1376,7 @@
                                     !peekToken(LT) &&
                                     !peekToken(NEW) &&
                                     !peekToken(VNEW) &&
+                                    !peekToken(VDEFAULT) &&
                                     !peekToken(SUPER)) {
                                 int selPos = token.pos;
                                 nextToken();
@@ -1435,6 +1440,11 @@
         return term3Rest(mode, t, typeArgs);
     }
 
+    private CreationMode getCreationMode(Token token) {
+        return token.kind == NEW ? CreationMode.NEW :
+                                        token.kind == VNEW ? CreationMode.VALUE : CreationMode.DEFAULT_VALUE;
+    }
+
     JCExpression term3Rest(int prevMode, JCExpression t, List<JCExpression> typeArgs) {
         if (typeArgs != null) illegal();
         while (true) {
@@ -1481,14 +1491,14 @@
                     nextToken();
                     t = arguments(typeArgs, t);
                     typeArgs = null;
-                } else if ((token.kind == NEW || token.kind == VNEW) && (mode & EXPR) != 0) {
+                } else if ((token.kind == NEW || token.kind == VNEW || token.kind == VDEFAULT) && (mode & EXPR) != 0) {
                     if (typeArgs != null) return illegal();
                     mode = EXPR;
                     int pos2 = token.pos;
-                    boolean isValue = token.kind == VNEW;
+                    CreationMode creationMode = getCreationMode(token);
                     nextToken();
                     if (token.kind == LT) typeArgs = typeArguments(false);
-                    t = innerCreator(pos2, isValue, typeArgs, t);
+                    t = innerCreator(pos2, creationMode, typeArgs, t);
                     typeArgs = null;
                 } else {
                     List<JCAnnotation> tyannos = null;
@@ -1651,7 +1661,7 @@
                         case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
                         case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
                         case TRUE: case FALSE: case NULL:
-                        case NEW: case VNEW: case IDENTIFIER: case ASSERT: case ENUM: case UNDERSCORE: case ANY:
+                        case NEW: case VNEW: case VDEFAULT: case IDENTIFIER: case ASSERT: case ENUM: case UNDERSCORE: case ANY:
                         case BYTE: case SHORT: case CHAR: case INT:
                         case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
                             return ParensResult.CAST;
@@ -2091,7 +2101,7 @@
         }
         Name refName;
         ReferenceMode refMode;
-        if (token.kind == NEW || token.kind == VNEW) {
+        if (token.kind == NEW || token.kind == VNEW || token.kind == VDEFAULT) {
             refMode = ReferenceMode.NEW; // TODO(Srikanth): What is the right thing to do here ?
             refName = names.init;
             nextToken();
@@ -2104,7 +2114,7 @@
 
     /** Creator = [Annotations] Qualident [TypeArguments] ( ArrayCreatorRest | ClassCreatorRest )
      */
-    JCExpression creator(int newpos, boolean isValue, List<JCExpression> typeArgs) {
+    JCExpression creator(int newpos, CreationMode creationMode, List<JCExpression> typeArgs) {
         List<JCAnnotation> newAnnotations = typeAnnotationsOpt();
 
         switch (token.kind) {
@@ -2178,7 +2188,7 @@
             }
             return e;
         } else if (token.kind == LPAREN) {
-            JCNewClass newClass = classCreatorRest(newpos, isValue, null, typeArgs, t);
+            JCNewClass newClass = classCreatorRest(newpos, creationMode, null, typeArgs, t);
             if (newClass.def != null) {
                 assert newClass.def.mods.annotations.isEmpty();
                 if (newAnnotations.nonEmpty()) {
@@ -2207,7 +2217,7 @@
 
     /** InnerCreator = [Annotations] Ident [TypeArguments] ClassCreatorRest
      */
-    JCExpression innerCreator(int newpos, boolean isValue, List<JCExpression> typeArgs, JCExpression encl) {
+    JCExpression innerCreator(int newpos, CreationMode creationMode, List<JCExpression> typeArgs, JCExpression encl) {
         List<JCAnnotation> newAnnotations = typeAnnotationsOpt();
 
         JCExpression t = toP(F.at(token.pos).Ident(ident()));
@@ -2221,7 +2231,7 @@
             t = typeArguments(t, true);
             mode = oldmode;
         }
-        return classCreatorRest(newpos, isValue, encl, typeArgs, t);
+        return classCreatorRest(newpos, creationMode, encl, typeArgs, t);
     }
 
     /** ArrayCreatorRest = [Annotations] "[" ( "]" BracketsOpt ArrayInitializer
@@ -2289,7 +2299,7 @@
     /** ClassCreatorRest = Arguments [ClassBody]
      */
     JCNewClass classCreatorRest(int newpos,
-                                boolean isValue,
+                                CreationMode creationMode,
                                   JCExpression encl,
                                   List<JCExpression> typeArgs,
                                   JCExpression t)
@@ -2303,7 +2313,7 @@
             body = toP(F.at(pos).AnonymousClassDef(mods, defs));
         }
         JCNewClass newClass = toP(F.at(newpos).NewClass(encl, typeArgs, t, args, body));
-        newClass.isValue = isValue;
+        newClass.creationMode = creationMode;
         return newClass;
     }
 
@@ -2877,6 +2887,7 @@
             case MONKEYS_AT  : flag = Flags.ANNOTATION; break;
             case DEFAULT     : checkDefaultMethods(); flag = Flags.DEFAULT; break;
             case VALUE       : flag = Flags.VALUE; break;
+            case STATICVALUEFACTORY: flag = Flags.STATICVALUEFACTORY; break;
             case SPECIES     : flag = Flags.SPECIES; break;
             case ERROR       : flag = 0; nextToken(); break;
             default: break loop;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/Tokens.java	Fri Nov 25 13:10:35 2016 +0530
@@ -165,10 +165,12 @@
         TRANSIENT("transient"),
         TRY("try"),
         VALUE("__ByValue"),
+        STATICVALUEFACTORY("__ValueFactory"),
         SPECIES("__species"),
         WHEREREF("__WhereRef"),
         WHEREVAL("__WhereVal"),
         VNEW("__Make"),
+        VDEFAULT("__MakeDefault"),
         VOID("void", Tag.NAMED),
         VOLATILE("volatile"),
         WHILE("while"),
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Fri Nov 25 13:10:35 2016 +0530
@@ -187,6 +187,22 @@
 compiler.err.cant.apply.symbols=\
     no suitable {0} found for {1}({2})
 
+compiler.err.value.factory.must.be.static=\
+    Value factory must be a static method
+
+compiler.err.invalid.arguments.to.make.default=\
+    Superfluous arguments to default value creation
+
+compiler.err.make.default.in.nonfactory=\
+    Illegal attempt to create a default value outside of value factory
+
+compiler.err.make.default.with.nonvalue=\
+    Default value creation requires a value type
+
+# 0: symbol
+compiler.err.make.default.with.wrong.value.type=\
+    This value factory cannot create values of type {0}
+
 # 0: symbol kind, 1: name, 2: list of type or message segment, 3: list of type or message segment, 4: symbol kind, 5: type, 6: message segment
 compiler.misc.cant.apply.symbol=\
     {0} {1} in {4} {5} cannot be applied to given types\n\
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Fri Nov 25 13:10:35 2016 +0530
@@ -1642,7 +1642,7 @@
         public JCExpression clazz;
         public List<JCExpression> args;
         public JCClassDecl def;
-        public boolean isValue;    // <- temporary
+        public CreationMode creationMode;    // <- temporary
         public Symbol constructor;
         public Type varargsElement;
         public Type constructorType;
@@ -1658,7 +1658,7 @@
             this.clazz = clazz;
             this.args = args;
             this.def = def;
-            this.isValue = false;    // <- temporary
+            this.creationMode = CreationMode.NEW;    // <- temporary
         }
         @Override
         public void accept(Visitor v) { v.visitNewClass(this); }
--- a/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Opcode.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/classfile/Opcode.java	Fri Nov 25 13:10:35 2016 +0530
@@ -257,6 +257,9 @@
 
     INVOKEDIRECT(213, CPREF_W),
 
+    VDEFAULT(214, CPREF_W),
+    VWITHFIELD(215, CPREF_W),
+
     // impdep 0xfe: PicoJava nonpriv
     // impdep 0xff: Picojava priv
 
--- a/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Mon Nov 07 18:38:36 2016 +0000
+++ b/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Fri Nov 25 13:10:35 2016 +0530
@@ -191,10 +191,12 @@
         UNDERSCORE(TokenKind.UNDERSCORE, XERRO),  //  _
         ANY(TokenKind.ANY, XEXPR1|XDECL1|XTERM),  //  "any"
         VALUE(TokenKind.VALUE, XEXPR1|XDECL1|XTERM),  //  "__ByValue"
+        VALUEFACTORY(TokenKind.STATICVALUEFACTORY, XDECL1),  //  "__ValueFactory" (a la public)
         SPECIES_STATIC(TokenKind.SPECIES, XEXPR1|XDECL1|XTERM),  //  "__SpeciesStatic"
         WHEREREF(TokenKind.WHEREREF, XEXPR1|XDECL1|XTERM),  //  "__WhereRef"
         WHEREVAL(TokenKind.WHEREVAL, XEXPR1|XDECL1|XTERM),  //  "__WhereVal"
         VNEW(TokenKind.VNEW, XEXPR1|XDECL1|XTERM),  //  "__Make"
+        VDEFAULT(TokenKind.VDEFAULT, XEXPR1|XDECL1|XTERM),  //  "__MakeDefault" a la __Make
         CLASS(TokenKind.CLASS, XEXPR|XDECL1|XTERM),  //  class decl and .class
         MONKEYS_AT(TokenKind.MONKEYS_AT, XEXPR|XDECL1),  //  @
         IMPORT(TokenKind.IMPORT, XDECL1|XSTART),  //  import -- consider declaration
--- a/test/tools/javac/diags/examples.not-yet.txt	Mon Nov 07 18:38:36 2016 +0000
+++ b/test/tools/javac/diags/examples.not-yet.txt	Fri Nov 25 13:10:35 2016 +0530
@@ -111,3 +111,8 @@
 compiler.misc.bad.class.file                            # class file is malformed
 compiler.misc.bad.const.pool.entry                      # constant pool entry has wrong type
 compiler.misc.bad.const.pool.index                      # constant pool entry has wrong index
+compiler.err.invalid.arguments.to.make.default          # Valhalla experimental features
+compiler.err.make.default.in.nonfactory                 # Valhalla experimental features
+compiler.err.make.default.with.nonvalue                 # Valhalla experimental features
+compiler.err.make.default.with.wrong.value.type         # Valhalla experimental features
+compiler.err.value.factory.must.be.static               # Valhalla experimental features
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/values/CheckMakeDefault.java	Fri Nov 25 13:10:35 2016 +0530
@@ -0,0 +1,40 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Check various semantic constraints on value creation via __MakeDefault
+ *
+ * @compile/fail/ref=CheckMakeDefault.out -XDrawDiagnostics CheckMakeDefault.java
+ */
+__ByValue final class Point {
+
+    static final class Sinner {
+        __ValueFactory static Sinner make() {
+            return __MakeDefault Sinner(); // NO: Sinner is not a value class.
+        }
+    }
+
+    __ByValue static final class SinnerValue {
+        __ValueFactory static SinnerValue make() {
+            return __MakeDefault SinnerValue(); // OK.
+        }
+    }
+
+    final int x;
+    final int y;
+
+    Point() {}
+    Point (int x, int y) {}
+
+    Point badFactory(int x, int y) {
+        return __MakeDefault Point(); // NO: Value created in a non-factory.
+    }
+
+    __ValueFactory static Point make(int x, int y) {
+       Point p = __MakeDefault Point(10, 20); // NO arguments to default value creation
+       String s = __MakeDefault String(); // NO: String cannot be produced in this factory.
+       __MakeDefault SinnerValue(); // NO: Wrong factory.
+       p = __MakeDefault Point();
+       p.x = x;
+       p.y = y;
+       return p;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/values/CheckMakeDefault.out	Fri Nov 25 13:10:35 2016 +0530
@@ -0,0 +1,6 @@
+CheckMakeDefault.java:11:20: compiler.err.make.default.with.nonvalue
+CheckMakeDefault.java:28:16: compiler.err.make.default.in.nonfactory
+CheckMakeDefault.java:32:18: compiler.err.invalid.arguments.to.make.default
+CheckMakeDefault.java:33:19: compiler.err.make.default.with.nonvalue
+CheckMakeDefault.java:34:8: compiler.err.make.default.with.wrong.value.type: Point.SinnerValue
+5 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/values/CheckStaticValueFactory.java	Fri Nov 25 13:10:35 2016 +0530
@@ -0,0 +1,53 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Check various semantic constraints on static value factory method
+ *
+ * @compile/fail/ref=CheckStaticValueFactory.out -XDrawDiagnostics CheckStaticValueFactory.java
+ */
+__ByValue __ValueFactory final class Point { // NO: A type cannot be __ValueFactory
+
+    static class Sinner {
+        final int x;
+    }
+
+    interface I {
+        default __ValueFactory I foo() { // No: an interface method cannot be value factory
+            return null;
+        }
+    }
+
+    __ValueFactory final int x; // NO: A field cannot be value factory
+
+    final int y;
+    final int z = 0;
+
+    __ValueFactory Point() { // NO: A constructor cannot be value factory
+    }
+
+    __ValueFactory Point badFactory(int x, int y) { // No: factory must be a static method
+        return __MakeDefault Point();
+    }
+
+    __ValueFactory static String makeString(int x, int y) { // NO: bad return type for factory
+        String s = __MakeDefault String(); // NO: String is not a value type
+        return s;
+    }
+
+    __ValueFactory static Point make(int x, int y, int z) {
+       Point p = __MakeDefault Point();
+       p.x = x; // OK: allow update to blank final field via copy on write`
+       p.y = y; // OK: allow update to blank final field via copy on write`
+       p.z = z; // !OK, do not allow update to a non blank final even in a value factory.
+       Sinner s = new Sinner();
+       s.x = 10; // NO: No write to final field.
+       return p;
+    }
+
+    static Point nonFactory(int x, int y, int z) {
+       Point p = __MakeDefault Point(); // NO: cannot create default value in non-factory
+       p.x = x; // Error: No write to final field.
+       p.y = y; // Error: No write to final field.
+       p.z = z; // Error: No write to final field.
+       return p;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/values/CheckStaticValueFactory.out	Fri Nov 25 13:10:35 2016 +0530
@@ -0,0 +1,14 @@
+CheckStaticValueFactory.java:7:32: compiler.err.mod.not.allowed.here: staticvaluefactory
+CheckStaticValueFactory.java:19:30: compiler.err.mod.not.allowed.here: staticvaluefactory
+CheckStaticValueFactory.java:24:20: compiler.err.mod.not.allowed.here: staticvaluefactory
+CheckStaticValueFactory.java:27:26: compiler.err.value.factory.must.be.static
+CheckStaticValueFactory.java:31:27: compiler.err.type.found.req: java.lang.String, Point
+CheckStaticValueFactory.java:14:34: compiler.err.mod.not.allowed.here: staticvaluefactory
+CheckStaticValueFactory.java:32:20: compiler.err.make.default.with.nonvalue
+CheckStaticValueFactory.java:40:9: compiler.err.cant.assign.val.to.final.var: z
+CheckStaticValueFactory.java:42:9: compiler.err.cant.assign.val.to.final.var: x
+CheckStaticValueFactory.java:47:18: compiler.err.make.default.in.nonfactory
+CheckStaticValueFactory.java:48:9: compiler.err.cant.assign.val.to.final.var: x
+CheckStaticValueFactory.java:49:9: compiler.err.cant.assign.val.to.final.var: y
+CheckStaticValueFactory.java:50:9: compiler.err.cant.assign.val.to.final.var: z
+13 errors
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/values/ValueCreationTest.java	Fri Nov 25 13:10:35 2016 +0530
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016, 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
+ * @summary Check code generation for value creation ops
+ * @compile ValueCreationTest.java
+ * @run main ValueCreationTest
+ * @modules jdk.compiler
+ */
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.nio.file.Paths;
+
+public class ValueCreationTest {
+
+    __ByValue
+    static final class Point {
+
+        final int x;
+        final int y;
+
+        Point () {
+            x = 10;
+            y = 10;
+        }
+
+        __ValueFactory static Point makePoint(int x, int y) {
+           Point p = __MakeDefault Point();
+           p.x = x;
+           p.y = y;
+           return p;
+        }
+
+        public static void main(String [] args) {
+            Point p = makePoint(10, 20);
+        }
+    }
+
+    public static void main(String[] args) {
+        new ValueCreationTest().run();
+    }
+
+    void run() {
+        String [] params = new String [] { "-v",
+                                            Paths.get(System.getProperty("test.classes"),
+                                                "ValueCreationTest$Point.class").toString() };
+        runCheck(params, new String [] {
+
+           "0: vdefault      #10                 // class ValueCreationTest$Point",
+           "3: vstore        2",
+           "5: vload         2",
+           "7: iload_0",
+           "8: vwithfield    #15                 // Field x:I",
+           "11: vstore        2",
+           "13: vload         2",
+           "15: iload_1",
+           "16: vwithfield    #18                 // Field y:I",
+           "19: vstore        2",
+           "21: vload         2",
+           "23: vreturn",
+         });
+
+     }
+
+     void runCheck(String [] params, String [] expectedOut) {
+        StringWriter s;
+        String out;
+
+        try (PrintWriter pw = new PrintWriter(s = new StringWriter())) {
+            com.sun.tools.javap.Main.run(params, pw);
+            out = s.toString();
+        }
+        int errors = 0;
+        for (String eo: expectedOut) {
+            if (!out.contains(eo)) {
+                System.err.println("Match not found for string: " + eo);
+                errors++;
+            }
+        }
+         if (errors > 0) {
+             throw new AssertionError("Unexpected javap output: " + out);
+         }
+    }
+}