changeset 3518:30469b6d88b6

Summary: Implement semantic checks for value capable classes when run with -XDenableMinimalValueTypes
author sadayapalam
date Mon, 03 Oct 2016 13:09:38 +0530
parents 93beb80dcc65
children a7d38b363cf5
files src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ValueCapableClassAttr.java src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java test/tools/javac/diags/CheckResourceKeys.java test/tools/javac/valhalla/minimalvalues/CheckClone.java test/tools/javac/valhalla/minimalvalues/CheckClone.out test/tools/javac/valhalla/minimalvalues/CheckCyclicMembership.java test/tools/javac/valhalla/minimalvalues/CheckCyclicMembership.out test/tools/javac/valhalla/minimalvalues/CheckEquals.java test/tools/javac/valhalla/minimalvalues/CheckEquals.out test/tools/javac/valhalla/minimalvalues/CheckExtends.java test/tools/javac/valhalla/minimalvalues/CheckExtends.out test/tools/javac/valhalla/minimalvalues/CheckFinal.java test/tools/javac/valhalla/minimalvalues/CheckFinal.out test/tools/javac/valhalla/minimalvalues/CheckFinalize.java test/tools/javac/valhalla/minimalvalues/CheckFinalize.out test/tools/javac/valhalla/minimalvalues/CheckIdentityHash.java test/tools/javac/valhalla/minimalvalues/CheckIdentityHash.out test/tools/javac/valhalla/minimalvalues/CheckIdentityHash01.java test/tools/javac/valhalla/minimalvalues/CheckIdentityHash01.out test/tools/javac/valhalla/minimalvalues/CheckNullAssign.java test/tools/javac/valhalla/minimalvalues/CheckNullAssign.out test/tools/javac/valhalla/minimalvalues/CheckNullCastable.java test/tools/javac/valhalla/minimalvalues/CheckNullCastable.out test/tools/javac/valhalla/minimalvalues/CheckSync.java test/tools/javac/valhalla/minimalvalues/CheckSync.out test/tools/javac/valhalla/minimalvalues/CheckSynchronized.java test/tools/javac/valhalla/minimalvalues/CheckSynchronized.out test/tools/javac/valhalla/minimalvalues/ClassFileReaderTest.java test/tools/javac/valhalla/minimalvalues/ClassFileReaderTest.out test/tools/javac/valhalla/minimalvalues/Point.java
diffstat 34 files changed, 653 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Thu Sep 01 05:07:27 2016 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java	Mon Oct 03 13:09:38 2016 +0530
@@ -228,7 +228,7 @@
      */
     public static final long UNION = 1L<<39;
 
-    // Flag bit (1L << 40) is available.
+    public static final long VALUE_CAPABLE = 1L<<40;
 
     /**
      * Flag that marks an 'effectively final' local variable.
@@ -410,6 +410,7 @@
         ENUM(Flags.ENUM),
         MANDATED(Flags.MANDATED),
         VALUE(Flags.VALUE),
+        VALUECAPABLE(Flags.VALUE_CAPABLE),
         SPECIES(Flags.SPECIES),
         NOOUTERTHIS(Flags.NOOUTERTHIS),
         EXISTS(Flags.EXISTS),
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Thu Sep 01 05:07:27 2016 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Mon Oct 03 13:09:38 2016 +0530
@@ -208,6 +208,7 @@
     public final Type virtualAccess;
     public final Type objectibleDispatch;
     public final Type classConstantFactory;
+    public final Type deriveValueType;
 
     /** The symbol representing the length field of an array.
      */
@@ -287,6 +288,31 @@
         };
     }
 
+    public void synthesizeDeriveValueTypeIfMissing(final Type type) {
+        final Completer completer = type.tsym.completer;
+        type.tsym.completer = new Completer() {
+            public void complete(Symbol sym) throws CompletionFailure {
+                try {
+                    completer.complete(sym);
+                } catch (CompletionFailure e) {
+                    ClassType ctype = (ClassType) type;
+                    sym.flags_field = PUBLIC|ACYCLIC|ANNOTATION|INTERFACE;
+                    sym.erasure_field = ctype;
+                    ((ClassSymbol) sym).members_field = WriteableScope.create(sym);
+                    ctype.typarams_field = List.nil();
+                    ctype.allparams_field = List.nil();
+                    ctype.supertype_field = annotationType;
+                    ctype.interfaces_field = List.nil();
+                }
+            }
+
+            @Override
+            public boolean isTerminal() {
+                return completer.isTerminal();
+            }
+        };
+    }
+
     public void synthesizeJavaLangValueClassIfMissing(final Type type) {
         final Completer completer = type.tsym.completer;
         type.tsym.completer = new Completer() {
@@ -560,11 +586,14 @@
         virtualAccess = enterClass("java.lang.invoke.VirtualAccess");
         objectibleDispatch = enterClass("java.lang.invoke.ObjectibleDispatch");
         classConstantFactory = enterClass("java.lang.invoke.ConstantDynamic");
+        deriveValueType = enterClass("jvm.internal.value.DeriveValueType");
+
         //transitional
         synthesizeEmptyInterfaceIfMissing(varHandleType);
         synthesizeEmptyInterfaceIfMissing(fieldHandleType);
         synthesizeEmptyInterfaceIfMissing(arrayHandleType);
         synthesizeJavaLangValueClassIfMissing(valueClassType);
+        synthesizeDeriveValueTypeIfMissing(deriveValueType);
 
         synthesizeEmptyInterfaceIfMissing(autoCloseableType);
         synthesizeEmptyInterfaceIfMissing(cloneableType);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Sep 01 05:07:27 2016 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Oct 03 13:09:38 2016 +0530
@@ -113,6 +113,8 @@
     final Dependencies dependencies;
     final Annotate annotate;
     final ArgumentAttr argumentAttr;
+    private final ValueCapableClassAttr valueCapableClassAttr;
+    private final boolean enableMinimalValueTypes;
 
     public static Attr instance(Context context) {
         Attr instance = context.get(attrKey);
@@ -148,6 +150,7 @@
         typeEnvs = TypeEnvs.instance(context);
         dependencies = Dependencies.instance(context);
         argumentAttr = ArgumentAttr.instance(context);
+        valueCapableClassAttr = ValueCapableClassAttr.instance(context);
 
         Options options = Options.instance(context);
 
@@ -168,6 +171,7 @@
         unknownTypeInfo = new ResultInfo(KindSelector.TYP, Type.noType);
         unknownTypeExprInfo = new ResultInfo(KindSelector.VAL_TYP, Type.noType);
         recoveryInfo = new RecoveryInfo(deferredAttr.emptyDeferredAttrContext);
+        enableMinimalValueTypes = options.isSet("enableMinimalValueTypes");
     }
 
     /** Switch: support target-typing inference
@@ -4423,6 +4427,11 @@
         try {
             annotate.flush();
             attribClass(c);
+            if (enableMinimalValueTypes) {
+                final Env<AttrContext> env = typeEnvs.get(c);
+                if (env != null)
+                    valueCapableClassAttr.translate(env.tree);
+            }
         } catch (CompletionFailure ex) {
             chk.completionError(pos, ex);
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Thu Sep 01 05:07:27 2016 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Mon Oct 03 13:09:38 2016 +0530
@@ -2256,7 +2256,7 @@
                     JCVariableDecl field = (JCVariableDecl) l.head;
                     if (!field.sym.isStatic()) {
                         Type fieldType = field.sym.type;
-                        if (types.isValue(fieldType)) {
+                        if (types.isValue(fieldType) || (fieldType.tsym.flags() & Flags.VALUE_CAPABLE) != 0) {
                             checkNonCyclicMembership((ClassSymbol) fieldType.tsym, field.pos());
                         }
                     }
@@ -2277,7 +2277,7 @@
                 c.flags_field |= LOCKED;
                 for (Symbol fld : c.members().getSymbols(s -> s.kind == VAR &&
                                                               !s.isStatic() &&
-                                                              types.isValue(s.type), NON_RECURSIVE)) {
+                        (types.isValue(s.type) || (s.type.tsym.flags() & VALUE_CAPABLE) != 0), NON_RECURSIVE)) {
                     checkNonCyclicMembership((ClassSymbol) fld.type.tsym, pos);
                 }
             } finally {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ValueCapableClassAttr.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,267 @@
+/*
+ * 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.  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.comp;
+
+import com.sun.tools.javac.code.*;
+
+import static com.sun.tools.javac.code.Flags.VALUE_CAPABLE;
+import static com.sun.tools.javac.code.Flags.asFlagSet;
+import static com.sun.tools.javac.code.Kinds.Kind.*;
+import com.sun.tools.javac.code.Symbol.MethodSymbol;
+import com.sun.tools.javac.code.Symbol.OperatorSymbol;
+import com.sun.tools.javac.code.Symbol.TypeSymbol;
+import com.sun.tools.javac.jvm.ByteCodes;
+import com.sun.tools.javac.tree.*;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.util.*;
+
+/**
+ * Support for "Minimal Value Types" : Process classes annotated with @DeriveValueType -
+ * All semantic checks are centralized in this place so that we can blow them all away when
+ * moving to "Maximal Value Types".
+ *
+ * see: http://cr.openjdk.java.net/~jrose/values/shady-values.html
+ *
+ */
+
+public class ValueCapableClassAttr extends TreeTranslator {
+
+    protected static final Context.Key<ValueCapableClassAttr> valueCapableClassAttr = new Context.Key<>();
+    private JCMethodDecl currentMethod;
+    private Log log;
+    private Names names;
+    private Symtab syms;
+    private final JCDiagnostic.Factory diags;
+    private final Types types;
+    private final Check chk;
+    private boolean inValue = false;
+
+    public static ValueCapableClassAttr instance(Context context) {
+        ValueCapableClassAttr instance = context.get(valueCapableClassAttr);
+        if (instance == null)
+            instance = new ValueCapableClassAttr(context);
+        return instance;
+    }
+
+    protected ValueCapableClassAttr(Context context) {
+        context.put(valueCapableClassAttr, this);
+        log = Log.instance(context);
+        names = Names.instance(context);
+        syms = Symtab.instance(context);
+        diags = JCDiagnostic.Factory.instance(context);
+        types = Types.instance(context);
+        chk = Check.instance(context);
+    }
+
+    public void visitClassDef(JCClassDecl tree) {
+        boolean oldInValue = inValue;
+        try {
+            inValue = false;
+            for (List<JCAnnotation> al = tree.mods.annotations; !al.isEmpty(); al = al.tail) {
+                JCAnnotation a = al.head;
+                if (a.annotationType.type == syms.deriveValueType && a.args.isEmpty()) {
+                    inValue = true;
+                    tree.sym.flags_field |= VALUE_CAPABLE;
+                    break;
+                }
+            }
+            if (inValue) {
+                if (tree.extending != null) {
+                    log.error(tree.pos(), "value.may.not.extend");
+                }
+                if ((tree.mods.flags & Flags.FINAL) == 0) {
+                    log.error(tree.pos(), "value.must.be.final");
+                }
+                chk.checkNonCyclicMembership(tree);
+            }
+            super.visitClassDef(tree);
+        } finally {
+            inValue = oldInValue;
+        }
+    }
+
+    public void visitMethodDef(JCMethodDecl tree) {
+        JCMethodDecl previousMethod = currentMethod;
+        try {
+            currentMethod = tree;
+            if (tree.sym != null && (tree.sym.owner.flags() & VALUE_CAPABLE) != 0) {
+                if ((tree.sym.flags() & (Flags.SYNCHRONIZED | Flags.STATIC)) == Flags.SYNCHRONIZED) {
+                    log.error(tree.pos(), "mod.not.allowed.here", asFlagSet(Flags.SYNCHRONIZED));
+                }
+                if (tree.sym.attribute(syms.overrideType.tsym) != null) {
+                    MethodSymbol m = tree.sym;
+                    TypeSymbol owner = (TypeSymbol)m.owner;
+                    for (Type sup : types.closure(owner.type)) {
+                        if (sup == owner.type)
+                            continue; // skip "this"
+                        Scope scope = sup.tsym.members();
+                        for (Symbol sym : scope.getSymbolsByName(m.name)) {
+                            if (!sym.isStatic() && m.overrides(sym, owner, types, true)) {
+                                switch (sym.name.toString()) {
+                                    case "hashCode":
+                                    case "equals":
+                                    case "toString":
+                                        break;
+                                    default:
+                                        log.error(tree.pos(), "value.does.not.support", "overriding java.lang.Object's method: " + sym.name.toString());
+                                        break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            super.visitMethodDef(tree);
+        } finally {
+            currentMethod = previousMethod;
+        }
+
+    }
+
+    public void visitVarDef(JCVariableDecl tree) {
+        if (tree.sym != null && tree.sym.owner.kind == TYP && (tree.sym.owner.flags() & VALUE_CAPABLE) != 0) {
+            if ((tree.mods.flags & (Flags.FINAL | Flags.STATIC)) == 0) {
+                log.error(tree.pos(), "value.field.must.be.final");
+            }
+        }
+        if (tree.init != null && tree.init.type != null && tree.init.type.hasTag(TypeTag.BOT)) {
+            if ((tree.vartype.type.tsym.flags() & VALUE_CAPABLE) != 0)
+                log.error(tree.init.pos(), "prob.found.req", diags.fragment("inconvertible.types", syms.botType, tree.vartype.type));
+        }
+        super.visitVarDef(tree);
+    }
+
+    @Override
+    public void visitAssign(JCAssign tree) {
+        if (tree.rhs.type != null && tree.rhs.type.hasTag(TypeTag.BOT)) {
+            Type lType = tree.lhs.type;
+            if (lType != null && (lType.tsym.flags() & VALUE_CAPABLE) != 0) {
+                log.error(tree.rhs.pos(), "prob.found.req", diags.fragment("inconvertible.types", syms.botType, lType));
+            }
+        }
+        super.visitAssign(tree);
+    }
+
+    @Override
+    public void visitReturn(JCReturn tree) {
+        if (currentMethod != null && tree.expr != null && tree.expr.type != null && tree.expr.type.hasTag(TypeTag.BOT)) {
+            if (currentMethod.restype != null && (currentMethod.restype.type.tsym.flags() & VALUE_CAPABLE) != 0) {
+                log.error(tree.expr.pos(), "prob.found.req", diags.fragment("inconvertible.types", syms.botType, currentMethod.restype.type));
+            }
+        }
+        super.visitReturn(tree);
+    }
+
+    @Override
+    public void visitTypeTest(JCInstanceOf tree) {
+        if (tree.expr.type.hasTag(TypeTag.BOT)) {
+            if ((tree.clazz.type.tsym.flags() & VALUE_CAPABLE) != 0) {
+                log.error(tree.expr.pos(), "prob.found.req", diags.fragment("inconvertible.types", syms.botType, tree.clazz.type));
+            }
+        }
+        super.visitTypeTest(tree);
+    }
+
+    @Override
+    public void visitTypeCast(JCTypeCast tree) {
+        if (tree.expr.type != null && tree.expr.type.hasTag(TypeTag.BOT) &&
+                tree.clazz.type != null && (tree.clazz.type.tsym.flags() & VALUE_CAPABLE) != 0) {
+            log.error(tree.expr.pos(), "prob.found.req", diags.fragment("inconvertible.types", syms.botType, tree.clazz.type));
+        }
+        super.visitTypeCast(tree);
+    }
+
+    public void visitBinary(JCBinary tree) {
+        Type left = tree.lhs.type;
+        Type right = tree.rhs.type;
+        Symbol operator = tree.operator;
+
+        if (operator != null && operator.kind == MTH &&
+                left != null && !left.isErroneous() &&
+                right != null && !right.isErroneous()) {
+            int opc = ((OperatorSymbol)operator).opcode;
+            if ((opc == ByteCodes.if_acmpeq || opc == ByteCodes.if_acmpne)) {
+                if ((left.hasTag(TypeTag.BOT) && (right.tsym.flags() & VALUE_CAPABLE) != 0) ||
+                        (right.hasTag(TypeTag.BOT) && (left.tsym.flags() & VALUE_CAPABLE) != 0)) {
+                    log.error(tree.pos(), "incomparable.types", left, right);
+                }
+            }
+            // this is likely to change.
+            if (operator.name.contentEquals("==") || operator.name.contentEquals("!=")) {
+                if ((tree.lhs.type.tsym.flags() & VALUE_CAPABLE) != 0 ||
+                        (tree.rhs.type.tsym.flags() & VALUE_CAPABLE) != 0)
+                    log.error(tree.pos(), "value.does.not.support", tree.operator.name.toString());
+            }
+        }
+        super.visitBinary(tree);
+    }
+
+    @Override
+    public void visitSynchronized(JCSynchronized tree) {
+        if ((tree.lock.type.tsym.flags() & VALUE_CAPABLE) != 0) {
+            log.error(tree.pos(), "type.found.req", tree.lock.type, diags.fragment("type.req.ref"));
+        }
+        super.visitSynchronized(tree);
+    }
+
+    public void visitApply(JCMethodInvocation tree) {
+        final Symbol method = TreeInfo.symbolFor(tree);
+        if (method != null && method.kind != ERR) {
+            if (method.name.contentEquals("identityHashCode") && method.owner.type == syms.systemType) {
+                if ((tree.args.length() == 1) && ((tree.args.head.type.tsym.flags() & VALUE_CAPABLE) != 0))
+                    log.error(tree.pos(), "value.does.not.support", "identityHashCode");
+            }
+
+            if (method.name != names.init && method.name != names.getClass && method.owner.type == syms.objectType) {
+                boolean receiverIsValue = false;
+                switch (tree.meth.getTag()) {
+                    case IDENT:
+                        receiverIsValue = inValue;
+                        break;
+                    case SELECT:
+                        final Symbol symbol = TreeInfo.symbol(((JCFieldAccess)tree.meth).selected);
+                        receiverIsValue = symbol != null &&
+                                (symbol.name == names._super ? inValue : (symbol.type.tsym.flags() & VALUE_CAPABLE) != 0);
+                        break;
+                }
+                if (receiverIsValue) {
+                    log.error(tree.pos(), "value.does.not.support", "calling java.lang.Object's method: " + method.name.toString());
+                }
+            }
+            final List<Type> parameterTypes = method.type.getParameterTypes();
+            for (int i = 0; i < tree.args.size(); i++) {
+                final JCExpression arg = tree.args.get(i);
+                if (arg.type != null && arg.type.hasTag(TypeTag.BOT)) {
+                    Type param = i < parameterTypes.size() ? parameterTypes.get(i) :
+                            types.elemtype(parameterTypes.get(parameterTypes.size() - 1));
+                    if ((param.tsym.flags() & VALUE_CAPABLE) != 0)
+                        log.error(arg.pos(), "prob.found.req", diags.fragment("inconvertible.types", syms.botType, param));
+                }
+            }
+        }
+        super.visitApply(tree);
+    }
+}
\ No newline at end of file
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Thu Sep 01 05:07:27 2016 +0530
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Mon Oct 03 13:09:38 2016 +0530
@@ -1205,6 +1205,8 @@
                         target = proxy;
                     } else if (proxy.type.tsym == syms.repeatableType.tsym) {
                         repeatable = proxy;
+                    } else if (sym.kind == TYP && proxy.type.tsym == syms.deriveValueType.tsym) {
+                        sym.flags_field |= VALUE_CAPABLE;
                     }
 
                     proxies.append(proxy);
--- a/test/tools/javac/diags/CheckResourceKeys.java	Thu Sep 01 05:07:27 2016 +0530
+++ b/test/tools/javac/diags/CheckResourceKeys.java	Mon Oct 03 13:09:38 2016 +0530
@@ -289,7 +289,9 @@
             "count.",
             "illegal.",
             "javac.",
-            "verbose."
+            "verbose.",
+            // annotation for minimal value types.
+            "jvm.internal.value.DeriveValueType"
     ));
 
     /**
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckClone.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,17 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Value types do not support clone
+ *
+ * @compile/fail/ref=CheckClone.out -XDenableMinimalValueTypes -XDrawDiagnostics CheckClone.java
+ */
+@jvm.internal.value.DeriveValueType
+final class CheckClone {
+    @jvm.internal.value.DeriveValueType
+    final class InnerValue {
+        void foo(InnerValue iv) {
+            iv.clone(); // <-- error
+        }
+    }
+    @Override
+    protected Object clone() { return null; } // <-- error
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckClone.out	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,3 @@
+CheckClone.java:12:21: compiler.err.value.does.not.support: calling java.lang.Object's method: clone
+CheckClone.java:16:22: compiler.err.value.does.not.support: overriding java.lang.Object's method: clone
+2 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckCyclicMembership.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,20 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Value types may not declare fields of its own type either directly or indirectly.
+ *
+ * @compile/fail/ref=CheckCyclicMembership.out -XDenableMinimalValueTypes -XDrawDiagnostics CheckCyclicMembership.java
+ */
+@jvm.internal.value.DeriveValueType
+final class CheckCyclicMembership {
+    class InnerRef {
+        CheckCyclicMembership ccm;
+    }
+    @jvm.internal.value.DeriveValueType final class InnerValue {
+        final CheckCyclicMembership ccm = new CheckCyclicMembership(); // Error.
+    }
+    final CheckCyclicMembership ccm = new CheckCyclicMembership(); // Error.
+    final int i = 10;
+    final String s = "blah";
+    final InnerRef ir = new InnerRef(); // OK.
+    final InnerValue iv = new InnerValue(); // Error.
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckCyclicMembership.out	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,4 @@
+CheckCyclicMembership.java:15:33: compiler.err.cyclic.value.type.membership: CheckCyclicMembership
+CheckCyclicMembership.java:19:22: compiler.err.cyclic.value.type.membership: CheckCyclicMembership
+CheckCyclicMembership.java:13:37: compiler.err.cyclic.value.type.membership: CheckCyclicMembership.InnerValue
+3 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckEquals.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,12 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Value types do not support == or !=
+ *
+ * @compile/fail/ref=CheckEquals.out -XDenableMinimalValueTypes -XDrawDiagnostics CheckEquals.java
+ */
+@jvm.internal.value.DeriveValueType
+final class CheckEquals {
+    boolean foo(CheckEquals a, CheckEquals b) {
+        return (a == b) || (a != b);
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckEquals.out	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,3 @@
+CheckEquals.java:10:19: compiler.err.value.does.not.support: ==
+CheckEquals.java:10:31: compiler.err.value.does.not.support: !=
+2 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckExtends.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,9 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Values may not extend
+ *
+ * @compile/fail/ref=CheckExtends.out -XDenableMinimalValueTypes -XDrawDiagnostics CheckExtends.java
+ */
+@jvm.internal.value.DeriveValueType
+final class CheckExtends extends Object {
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckExtends.out	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,2 @@
+CheckExtends.java:8:7: compiler.err.value.may.not.extend
+1 error
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckFinal.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,20 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Value types and their instance fields must be final
+ *
+ * @compile/fail/ref=CheckFinal.out -XDenableMinimalValueTypes -XDrawDiagnostics CheckFinal.java
+ */
+
+@jvm.internal.value.DeriveValueType
+class CheckFinal {  // <- error
+    int x;          // <- error
+    void f(int x) { // <- ok
+        int y;      // <- ok
+        @jvm.internal.value.DeriveValueType
+        final class CheckLocalFinal {
+            int x; // <- error.
+        }
+    }
+    final Object o = new Object() { int i; }; // <- ok
+    static int xs; // OK.
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckFinal.out	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,4 @@
+CheckFinal.java:15:17: compiler.err.value.field.must.be.final
+CheckFinal.java:9:1: compiler.err.value.must.be.final
+CheckFinal.java:10:9: compiler.err.value.field.must.be.final
+3 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckFinalize.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,19 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Value types do not support finalize
+ *
+ * @compile/fail/ref=CheckFinalize.out -XDenableMinimalValueTypes -XDrawDiagnostics CheckFinalize.java
+ */
+@jvm.internal.value.DeriveValueType
+final class CheckFinalize {
+    @Override
+    protected void finalize() {} // <-- error
+
+    @jvm.internal.value.DeriveValueType
+    final class CheckFinalizeInner {}
+
+    void foo(CheckFinalizeInner cfi, CheckFinalize cf) {
+        cfi.finalize();          // Error
+        cf.finalize();           // OK.
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckFinalize.out	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,4 @@
+CheckFinalize.java:16:12: compiler.err.report.access: finalize(), protected, java.lang.Object
+CheckFinalize.java:10:20: compiler.err.value.does.not.support: overriding java.lang.Object's method: finalize
+CheckFinalize.java:16:21: compiler.err.value.does.not.support: calling java.lang.Object's method: finalize
+3 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckIdentityHash.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,19 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Value types do not support identityHashCode
+ *
+ * @compile/fail/ref=CheckIdentityHash.out -XDenableMinimalValueTypes -XDrawDiagnostics CheckIdentityHash.java
+ */
+@jvm.internal.value.DeriveValueType
+final class CheckIdentityHash {
+    int identityHashCode(CheckIdentityHash x) {
+        return 0;
+    }
+    void test(CheckIdentityHash v) {
+        this.identityHashCode(v);      // <- ok
+        System.identityHashCode(v);    // <- error
+        System.identityHashCode(this); // <- error
+        java.lang.System.identityHashCode(v);    // <- error
+        java.lang.System.identityHashCode(this); // <- error
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckIdentityHash.out	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,5 @@
+CheckIdentityHash.java:14:32: compiler.err.value.does.not.support: identityHashCode
+CheckIdentityHash.java:15:32: compiler.err.value.does.not.support: identityHashCode
+CheckIdentityHash.java:16:42: compiler.err.value.does.not.support: identityHashCode
+CheckIdentityHash.java:17:42: compiler.err.value.does.not.support: identityHashCode
+4 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckIdentityHash01.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,26 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Value types do not support identityHashCode
+ *
+ * @compile/fail/ref=CheckIdentityHash01.out -XDenableMinimalValueTypes -XDrawDiagnostics CheckIdentityHash01.java
+ */
+
+import static java.lang.System.*;
+@jvm.internal.value.DeriveValueType
+final class CheckIdentityHash01 {
+    void test(CheckIdentityHash01 v) {
+
+        identityHashCode(v);      // <- error
+        identityHashCode(this);   // <- error
+
+        System system = null;
+        system.identityHashCode(v);      // <- error
+        system.identityHashCode(this);   // <- error
+
+        System.identityHashCode(v);      // <- error
+        System.identityHashCode(this);   // <- error
+
+        java.lang.System.identityHashCode(v);    // <- error
+        java.lang.System.identityHashCode(this); // <- error
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckIdentityHash01.out	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,9 @@
+CheckIdentityHash01.java:13:25: compiler.err.value.does.not.support: identityHashCode
+CheckIdentityHash01.java:14:25: compiler.err.value.does.not.support: identityHashCode
+CheckIdentityHash01.java:17:32: compiler.err.value.does.not.support: identityHashCode
+CheckIdentityHash01.java:18:32: compiler.err.value.does.not.support: identityHashCode
+CheckIdentityHash01.java:20:32: compiler.err.value.does.not.support: identityHashCode
+CheckIdentityHash01.java:21:32: compiler.err.value.does.not.support: identityHashCode
+CheckIdentityHash01.java:23:42: compiler.err.value.does.not.support: identityHashCode
+CheckIdentityHash01.java:24:42: compiler.err.value.does.not.support: identityHashCode
+8 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckNullAssign.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,17 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Assignment of null to value types should be disallowed.
+ *
+ * @compile/fail/ref=CheckNullAssign.out -XDenableMinimalValueTypes -XDrawDiagnostics CheckNullAssign.java
+ */
+@jvm.internal.value.DeriveValueType
+final class CheckNullAssign {
+    CheckNullAssign foo(CheckNullAssign cna) {
+        // All of the below involve subtype/assignability checks and should be rejected.
+        CheckNullAssign cnal = null;
+        cna = null;
+        foo(null);
+        if (null instanceof CheckNullAssign) {}
+        return null;
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckNullAssign.out	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,6 @@
+CheckNullAssign.java:11:32: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: compiler.misc.type.null, CheckNullAssign)
+CheckNullAssign.java:12:15: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: compiler.misc.type.null, CheckNullAssign)
+CheckNullAssign.java:13:13: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: compiler.misc.type.null, CheckNullAssign)
+CheckNullAssign.java:14:13: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: compiler.misc.type.null, CheckNullAssign)
+CheckNullAssign.java:15:16: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: compiler.misc.type.null, CheckNullAssign)
+5 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckNullCastable.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,14 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary null cannot be casted to and compared with value types.
+ *
+ * @compile/fail/ref=CheckNullCastable.out -XDenableMinimalValueTypes -XDrawDiagnostics CheckNullCastable.java
+ */
+@jvm.internal.value.DeriveValueType
+final class CheckNullCastable {
+    void foo(CheckNullCastable cnc) {
+        CheckNullCastable cncl = (CheckNullCastable) null;
+        if (cnc != null) {};
+        if (null != cnc) {};
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckNullCastable.out	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,4 @@
+CheckNullCastable.java:10:54: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: compiler.misc.type.null, CheckNullCastable)
+CheckNullCastable.java:11:17: compiler.err.incomparable.types: CheckNullCastable, compiler.misc.type.null
+CheckNullCastable.java:12:18: compiler.err.incomparable.types: compiler.misc.type.null, CheckNullCastable
+3 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckSync.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,42 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary May not synchronize on value types
+ *
+ * @compile/fail/ref=CheckSync.out -XDenableMinimalValueTypes -XDrawDiagnostics CheckSync.java
+ */
+
+/* Note: ATM, value types do not have jlO in their lineage. So they anyway
+   cannot synchronize using the methods declared on jlO.
+*/
+@jvm.internal.value.DeriveValueType
+public final class CheckSync {
+    @jvm.internal.value.DeriveValueType
+    final class Val {
+
+        void foo() {
+            // All calls below are bad.
+            wait();
+            wait(10);
+            wait(10, 10);
+            notify();
+            notifyAll();
+            finalize();
+            clone();
+        }
+    }
+
+    final Val val = new Val();
+
+    void test() throws InterruptedException {
+        // All calls below are bad.
+        val.wait();
+        val.wait(10);
+        val.wait(new Integer(10));
+        val.wait(new Long(10));
+        val.wait(10L);
+        val.wait(10L, 10);
+        val.wait("Hello");
+        val.notify();
+        val.notifyAll();
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckSync.out	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,17 @@
+CheckSync.java:18:17: compiler.err.value.does.not.support: calling java.lang.Object's method: wait
+CheckSync.java:19:17: compiler.err.value.does.not.support: calling java.lang.Object's method: wait
+CheckSync.java:20:17: compiler.err.value.does.not.support: calling java.lang.Object's method: wait
+CheckSync.java:21:19: compiler.err.value.does.not.support: calling java.lang.Object's method: notify
+CheckSync.java:22:22: compiler.err.value.does.not.support: calling java.lang.Object's method: notifyAll
+CheckSync.java:23:21: compiler.err.value.does.not.support: calling java.lang.Object's method: finalize
+CheckSync.java:24:18: compiler.err.value.does.not.support: calling java.lang.Object's method: clone
+CheckSync.java:38:12: compiler.err.cant.apply.symbols: kindname.method, wait, java.lang.String,{(compiler.misc.inapplicable.method: kindname.method, java.lang.Object, wait(long), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.inconvertible.types: java.lang.String, long))),(compiler.misc.inapplicable.method: kindname.method, java.lang.Object, wait(long,int), (compiler.misc.arg.length.mismatch)),(compiler.misc.inapplicable.method: kindname.method, java.lang.Object, wait(), (compiler.misc.arg.length.mismatch))}
+CheckSync.java:32:17: compiler.err.value.does.not.support: calling java.lang.Object's method: wait
+CheckSync.java:33:17: compiler.err.value.does.not.support: calling java.lang.Object's method: wait
+CheckSync.java:34:17: compiler.err.value.does.not.support: calling java.lang.Object's method: wait
+CheckSync.java:35:17: compiler.err.value.does.not.support: calling java.lang.Object's method: wait
+CheckSync.java:36:17: compiler.err.value.does.not.support: calling java.lang.Object's method: wait
+CheckSync.java:37:17: compiler.err.value.does.not.support: calling java.lang.Object's method: wait
+CheckSync.java:39:19: compiler.err.value.does.not.support: calling java.lang.Object's method: notify
+CheckSync.java:40:22: compiler.err.value.does.not.support: calling java.lang.Object's method: notifyAll
+16 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckSynchronized.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,18 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Check behavior of synzhronized key word on value instances and methods.
+ *
+ * @compile/fail/ref=CheckSynchronized.out -XDenableMinimalValueTypes -XDrawDiagnostics CheckSynchronized.java
+ */
+@jvm.internal.value.DeriveValueType
+final class CheckSynchronized {
+    synchronized void foo() { // <<-- ERROR, no monitor associated with `this'
+    }
+    void goo() {
+        synchronized(this) {} // <<-- ERROR, no monitor associated with `this'
+    }
+    synchronized static void zoo(CheckSynchronized cs) { // OK, static method.
+        synchronized(cs) {    // <<-- ERROR, no monitor associated with value instance.
+        }
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/CheckSynchronized.out	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,4 @@
+CheckSynchronized.java:9:23: compiler.err.mod.not.allowed.here: synchronized
+CheckSynchronized.java:12:9: compiler.err.type.found.req: CheckSynchronized, (compiler.misc.type.req.ref)
+CheckSynchronized.java:15:9: compiler.err.type.found.req: CheckSynchronized, (compiler.misc.type.req.ref)
+3 errors
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/ClassFileReaderTest.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,11 @@
+/*
+ * @test /nodynamiccopyright/
+ * @summary Verify that the class reader flags Value capable classes appropriately.
+ *
+ * @compile Point.java
+ * @compile/fail/ref=ClassFileReaderTest.out -XDenableMinimalValueTypes -XDrawDiagnostics ClassFileReaderTest.java
+ */
+
+public class ClassFileReaderTest {
+    Point point = null;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/ClassFileReaderTest.out	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,2 @@
+ClassFileReaderTest.java:10:19: compiler.err.prob.found.req: (compiler.misc.inconvertible.types: compiler.misc.type.null, Point)
+1 error
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/valhalla/minimalvalues/Point.java	Mon Oct 03 13:09:38 2016 +0530
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+@jvm.internal.value.DeriveValueType
+final class Point {
+    final int x = 0;
+    final int y = 0;
+}
\ No newline at end of file