changeset 267:5bcac54d408b jdk7-b58

Merge
author tbell
date Mon, 04 May 2009 22:16:46 -0700
parents 8a2424db1a14 (current diff) e2722bd43f3a (diff)
children 88bcb6772159 846944dd48a4
files
diffstat 25 files changed, 881 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/tools/classfile/Opcode.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/classfile/Opcode.java	Mon May 04 22:16:46 2009 -0700
@@ -226,7 +226,7 @@
     INVOKESPECIAL(0xb7, CPREF_W),
     INVOKESTATIC(0xb8, CPREF_W),
     INVOKEINTERFACE(0xb9, CPREF_W_UBYTE_ZERO),
-    // unused 0xba
+    INVOKEDYNAMIC(0xba, CPREF_W_UBYTE_ZERO),
     NEW(0xbb, CPREF_W),
     NEWARRAY(0xbc, ATYPE),
     ANEWARRAY(0xbd, CPREF_W),
--- a/src/share/classes/com/sun/tools/javac/code/Symtab.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java	Mon May 04 22:16:46 2009 -0700
@@ -119,6 +119,8 @@
     public final Type stringBuilderType;
     public final Type cloneableType;
     public final Type serializableType;
+    public final Type methodHandleType;
+    public final Type invokeDynamicType;
     public final Type throwableType;
     public final Type errorType;
     public final Type illegalArgumentExceptionType;
@@ -289,6 +291,24 @@
         }
     }
 
+    public void synthesizeMHTypeIfMissing(final Type type) {
+        final Completer completer = type.tsym.completer;
+        if (completer != null) {
+            type.tsym.completer = new Completer() {
+                public void complete(Symbol sym) throws CompletionFailure {
+                    try {
+                        completer.complete(sym);
+                    } catch (CompletionFailure e) {
+                        sym.flags_field |= (PUBLIC | ABSTRACT);
+                        ((ClassType) sym.type).supertype_field = objectType;
+                        // do not bother to create MH.type if not visibly declared
+                        // this sym just accumulates invoke(...) methods
+                    }
+                }
+            };
+        }
+    }
+
     public void synthesizeBoxTypeIfMissing(final Type type) {
         ClassSymbol sym = reader.enterClass(boxedName[type.tag]);
         final Completer completer = sym.completer;
@@ -405,6 +425,8 @@
         cloneableType = enterClass("java.lang.Cloneable");
         throwableType = enterClass("java.lang.Throwable");
         serializableType = enterClass("java.io.Serializable");
+        methodHandleType = enterClass("java.dyn.MethodHandle");
+        invokeDynamicType = enterClass("java.dyn.InvokeDynamic");
         errorType = enterClass("java.lang.Error");
         illegalArgumentExceptionType = enterClass("java.lang.IllegalArgumentException");
         exceptionType = enterClass("java.lang.Exception");
@@ -441,6 +463,8 @@
 
         synthesizeEmptyInterfaceIfMissing(cloneableType);
         synthesizeEmptyInterfaceIfMissing(serializableType);
+        synthesizeMHTypeIfMissing(methodHandleType);
+        synthesizeMHTypeIfMissing(invokeDynamicType);
         synthesizeBoxTypeIfMissing(doubleType);
         synthesizeBoxTypeIfMissing(floatType);
 
--- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Mon May 04 22:16:46 2009 -0700
@@ -118,6 +118,7 @@
         relax = (options.get("-retrofit") != null ||
                  options.get("-relax") != null);
         useBeforeDeclarationWarning = options.get("useBeforeDeclarationWarning") != null;
+        allowInvokedynamic = options.get("invokedynamic") != null;
     }
 
     /** Switch: relax some constraints for retrofit mode.
@@ -149,6 +150,10 @@
      */
     boolean allowAnonOuterThis;
 
+    /** Switch: allow invokedynamic syntax
+     */
+    boolean allowInvokedynamic;
+
     /**
      * Switch: warn about use of variable before declaration?
      * RFE: 6425594
@@ -438,14 +443,22 @@
     }
 
     /** Attribute a type argument list, returning a list of types.
+     *  Caller is responsible for calling checkRefTypes.
      */
-    List<Type> attribTypes(List<JCExpression> trees, Env<AttrContext> env) {
+    List<Type> attribAnyTypes(List<JCExpression> trees, Env<AttrContext> env) {
         ListBuffer<Type> argtypes = new ListBuffer<Type>();
         for (List<JCExpression> l = trees; l.nonEmpty(); l = l.tail)
-            argtypes.append(chk.checkRefType(l.head.pos(), attribType(l.head, env)));
+            argtypes.append(attribType(l.head, env));
         return argtypes.toList();
     }
 
+    /** Attribute a type argument list, returning a list of types.
+     *  Check that all the types are references.
+     */
+    List<Type> attribTypes(List<JCExpression> trees, Env<AttrContext> env) {
+        List<Type> types = attribAnyTypes(trees, env);
+        return chk.checkRefTypes(trees, types);
+    }
 
     /**
      * Attribute type variables (of generic classes or methods).
@@ -1194,6 +1207,7 @@
 
         // The types of the actual method type arguments.
         List<Type> typeargtypes = null;
+        boolean typeargtypesNonRefOK = false;
 
         Name methName = TreeInfo.name(tree.meth);
 
@@ -1281,7 +1295,7 @@
             // Otherwise, we are seeing a regular method call.
             // Attribute the arguments, yielding list of argument types, ...
             argtypes = attribArgs(tree.args, localEnv);
-            typeargtypes = attribTypes(tree.typeargs, localEnv);
+            typeargtypes = attribAnyTypes(tree.typeargs, localEnv);
 
             // ... and attribute the method using as a prototype a methodtype
             // whose formal argument types is exactly the list of actual
@@ -1318,6 +1332,20 @@
                               restype.tsym);
             }
 
+            // as a special case, MethodHandle.<T>invoke(abc) and InvokeDynamic.<T>foo(abc)
+            // has type <T>, and T can be a primitive type.
+            if (tree.meth.getTag() == JCTree.SELECT && !typeargtypes.isEmpty()) {
+              Type selt = ((JCFieldAccess) tree.meth).selected.type;
+              if ((selt == syms.methodHandleType && methName == names.invoke) || selt == syms.invokeDynamicType) {
+                  assert types.isSameType(restype, typeargtypes.head) : mtype;
+                  typeargtypesNonRefOK = true;
+              }
+            }
+
+            if (!typeargtypesNonRefOK) {
+                chk.checkRefTypes(tree.typeargs, typeargtypes);
+            }
+
             // Check that value of resulting type is admissible in the
             // current context.  Also, capture the return type
             result = check(tree, capture(restype), VAL, pkind, pt);
--- a/src/share/classes/com/sun/tools/javac/comp/Check.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Check.java	Mon May 04 22:16:46 2009 -0700
@@ -207,6 +207,12 @@
      *  @param found      The type that was found.
      */
     Type typeTagError(DiagnosticPosition pos, Object required, Object found) {
+        // this error used to be raised by the parser,
+        // but has been delayed to this point:
+        if (found instanceof Type && ((Type)found).tag == VOID) {
+            log.error(pos, "illegal.start.of.type");
+            return syms.errType;
+        }
         log.error(pos, "type.found.req", found, required);
         return types.createErrorType(found instanceof Type ? (Type)found : syms.errType);
     }
@@ -547,6 +553,20 @@
         }
     }
 
+    /** Check that each type is a reference type, i.e. a class, interface or array type
+     *  or a type variable.
+     *  @param trees         Original trees, used for error reporting.
+     *  @param types         The types to be checked.
+     */
+    List<Type> checkRefTypes(List<JCExpression> trees, List<Type> types) {
+        List<JCExpression> tl = trees;
+        for (List<Type> l = types; l.nonEmpty(); l = l.tail) {
+            l.head = checkRefType(tl.head.pos(), l.head);
+            tl = tl.tail;
+        }
+        return types;
+    }
+
     /** Check that type is a null or reference type.
      *  @param pos           Position to be used for error reporting.
      *  @param t             The type to be checked.
--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java	Mon May 04 22:16:46 2009 -0700
@@ -67,6 +67,7 @@
     JCDiagnostic.Factory diags;
     public final boolean boxingEnabled; // = source.allowBoxing();
     public final boolean varargsEnabled; // = source.allowVarargs();
+    public final boolean allowInvokedynamic; // = options.get("invokedynamic");
     private final boolean debugResolve;
 
     public static Resolve instance(Context context) {
@@ -104,6 +105,7 @@
         varargsEnabled = source.allowVarargs();
         Options options = Options.instance(context);
         debugResolve = options.get("debugresolve") != null;
+        allowInvokedynamic = options.get("invokedynamic") != null;
     }
 
     /** error symbols, which are returned when resolution fails
@@ -881,6 +883,79 @@
         return bestSoFar;
     }
 
+    /** Find or create an implicit method of exactly the given type (after erasure).
+     *  Searches in a side table, not the main scope of the site.
+     *  This emulates the lookup process required by JSR 292 in JVM.
+     *  @param env       The current environment.
+     *  @param site      The original type from where the selection
+     *                   takes place.
+     *  @param name      The method's name.
+     *  @param argtypes  The method's value arguments.
+     *  @param typeargtypes The method's type arguments
+     */
+    Symbol findImplicitMethod(Env<AttrContext> env,
+                              Type site,
+                              Name name,
+                              List<Type> argtypes,
+                              List<Type> typeargtypes) {
+        assert allowInvokedynamic;
+        assert site == syms.invokeDynamicType || (site == syms.methodHandleType && name == names.invoke);
+        ClassSymbol c = (ClassSymbol) site.tsym;
+        Scope implicit = c.members().next;
+        if (implicit == null) {
+            c.members().next = implicit = new Scope(c);
+        }
+        Type restype;
+        if (typeargtypes.isEmpty()) {
+            restype = syms.objectType;
+        } else {
+            restype = typeargtypes.head;
+            if (!typeargtypes.tail.isEmpty())
+                return methodNotFound;
+        }
+        List<Type> paramtypes = Type.map(argtypes, implicitArgType);
+        MethodType mtype = new MethodType(paramtypes,
+                                          restype,
+                                          List.<Type>nil(),
+                                          syms.methodClass);
+        int flags = PUBLIC | ABSTRACT;
+        if (site == syms.invokeDynamicType)  flags |= STATIC;
+        Symbol m = null;
+        for (Scope.Entry e = implicit.lookup(name);
+             e.scope != null;
+             e = e.next()) {
+            Symbol sym = e.sym;
+            assert sym.kind == MTH;
+            if (types.isSameType(mtype, sym.type)
+                && (sym.flags() & STATIC) == (flags & STATIC)) {
+                m = sym;
+                break;
+            }
+        }
+        if (m == null) {
+            // create the desired method
+            m = new MethodSymbol(flags, name, mtype, c);
+            implicit.enter(m);
+        }
+        assert argumentsAcceptable(argtypes, types.memberType(site, m).getParameterTypes(),
+                                   false, false, Warner.noWarnings);
+        assert null != instantiate(env, site, m, argtypes, typeargtypes, false, false, Warner.noWarnings);
+        return m;
+    }
+    //where
+        Mapping implicitArgType = new Mapping ("implicitArgType") {
+                public Type apply(Type t) { return implicitArgType(t); }
+            };
+        Type implicitArgType(Type argType) {
+            argType = types.erasure(argType);
+            if (argType.tag == BOT)
+                // nulls type as the marker type Null (which has no instances)
+                // TO DO: figure out how to access java.lang.Null safely, else throw nice error
+                //argType = types.boxedClass(syms.botType).type;
+                argType = types.boxedClass(syms.voidType).type;  // REMOVE
+            return argType;
+        }
+
     /** Load toplevel or member class with given fully qualified name and
      *  verify that it is accessible.
      *  @param env       The current environment.
@@ -1265,6 +1340,14 @@
             methodResolutionCache.put(steps.head, sym);
             steps = steps.tail;
         }
+        if (sym.kind >= AMBIGUOUS &&
+            allowInvokedynamic &&
+            (site == syms.invokeDynamicType ||
+             site == syms.methodHandleType && name == names.invoke)) {
+            // lookup failed; supply an exactly-typed implicit method
+            sym = findImplicitMethod(env, site, name, argtypes, typeargtypes);
+            env.info.varArgs = false;
+        }
         if (sym.kind >= AMBIGUOUS) {//if nothing is found return the 'first' error
             MethodResolutionPhase errPhase =
                     firstErroneousResolutionPhase();
--- a/src/share/classes/com/sun/tools/javac/jvm/ByteCodes.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/jvm/ByteCodes.java	Mon May 04 22:16:46 2009 -0700
@@ -225,7 +225,7 @@
         invokespecial   = 183,
         invokestatic    = 184,
         invokeinterface = 185,
-        // ___unused___ = 186,
+        invokedynamic   = 186,
         new_            = 187,
         newarray        = 188,
         anewarray       = 189,
--- a/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Mon May 04 22:16:46 2009 -0700
@@ -2309,6 +2309,7 @@
                     String binaryName = fileManager.inferBinaryName(currentLoc, fo);
                     String simpleName = binaryName.substring(binaryName.lastIndexOf(".") + 1);
                     if (SourceVersion.isIdentifier(simpleName) ||
+                        fo.getKind() == JavaFileObject.Kind.CLASS ||
                         simpleName.equals("package-info"))
                         includeClassFile(p, fo);
                     break;
--- a/src/share/classes/com/sun/tools/javac/jvm/Code.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/jvm/Code.java	Mon May 04 22:16:46 2009 -0700
@@ -456,6 +456,19 @@
         state.push(mtype.getReturnType());
     }
 
+    /** Emit an invokedynamic instruction.
+     */
+    public void emitInvokedynamic(int desc, Type mtype) {
+        // N.B. this format is under consideration by the JSR 292 EG
+        int argsize = width(mtype.getParameterTypes());
+        emitop(invokedynamic);
+        if (!alive) return;
+        emit2(desc);
+        emit2(0);
+        state.pop(argsize);
+        state.push(mtype.getReturnType());
+    }
+
     /** Emit an opcode with no operand field.
      */
     public void emitop0(int op) {
@@ -2156,7 +2169,7 @@
             mnem[invokespecial] = "invokespecial";
             mnem[invokestatic] = "invokestatic";
             mnem[invokeinterface] = "invokeinterface";
-            // mnem[___unused___] = "___unused___";
+            mnem[invokedynamic] = "invokedynamic";
             mnem[new_] = "new_";
             mnem[newarray] = "newarray";
             mnem[anewarray] = "anewarray";
--- a/src/share/classes/com/sun/tools/javac/jvm/Gen.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/jvm/Gen.java	Mon May 04 22:16:46 2009 -0700
@@ -119,6 +119,7 @@
             : options.get("-g:vars") != null;
         genCrt = options.get("-Xjcov") != null;
         debugCode = options.get("debugcode") != null;
+        allowInvokedynamic = options.get("invokedynamic") != null;
 
         generateIproxies =
             target.requiresIproxy() ||
@@ -155,6 +156,7 @@
     private final boolean varDebugInfo;
     private final boolean genCrt;
     private final boolean debugCode;
+    private final boolean allowInvokedynamic;
 
     /** Default limit of (approximate) size of finalizer to inline.
      *  Zero means always use jsr.  100 or greater means never use
@@ -2140,6 +2142,9 @@
             }
             result = items.
                 makeImmediateItem(sym.type, ((VarSymbol) sym).getConstValue());
+        } else if (allowInvokedynamic && sym.kind == MTH && ssym == syms.invokeDynamicType.tsym) {
+            base.drop();
+            result = items.makeDynamicItem(sym);
         } else {
             if (!accessSuper)
                 sym = binaryQualifier(sym, tree.selected.type);
--- a/src/share/classes/com/sun/tools/javac/jvm/Items.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/jvm/Items.java	Mon May 04 22:16:46 2009 -0700
@@ -139,6 +139,13 @@
         return new StaticItem(member);
     }
 
+    /** Make an item representing a dynamically invoked method.
+     *  @param member   The represented symbol.
+     */
+    Item makeDynamicItem(Symbol member) {
+        return new DynamicItem(member);
+    }
+
     /** Make an item representing an instance variable or method.
      *  @param member       The represented symbol.
      *  @param nonvirtual   Is the reference not virtual? (true for constructors
@@ -457,6 +464,38 @@
         }
     }
 
+    /** An item representing a dynamic call site.
+     */
+    class DynamicItem extends StaticItem {
+        DynamicItem(Symbol member) {
+            super(member);
+            assert member.owner == syms.invokeDynamicType.tsym;
+        }
+
+        Item load() {
+            assert false;
+            return null;
+        }
+
+        void store() {
+            assert false;
+        }
+
+        Item invoke() {
+            // assert target.hasNativeInvokeDynamic();
+            MethodType mtype = (MethodType)member.erasure(types);
+            int rescode = Code.typecode(mtype.restype);
+            ClassFile.NameAndType descr = new ClassFile.NameAndType(member.name, mtype);
+            code.emitInvokedynamic(pool.put(descr), mtype);
+            return stackItem[rescode];
+        }
+
+        public String toString() {
+            return "dynamic(" + member + ")";
+        }
+    }
+
+
     /** An item representing an instance variable or method.
      */
     class MemberItem extends Item {
--- a/src/share/classes/com/sun/tools/javac/jvm/Target.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/jvm/Target.java	Mon May 04 22:16:46 2009 -0700
@@ -253,6 +253,12 @@
         return compareTo(JDK1_5) >= 0;
     }
 
+    /** Does the VM support an invokedynamic instruction?
+     */
+    public boolean hasInvokedynamic() {
+        return compareTo(JDK1_7) >= 0;
+    }
+
     /** Although we may not have support for class literals, should we
      *  avoid initializing the class that the literal refers to?
      *  See 4468823
--- a/src/share/classes/com/sun/tools/javac/main/Main.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/main/Main.java	Mon May 04 22:16:46 2009 -0700
@@ -268,14 +268,19 @@
                     }
                     return null;
                 } else {
-                    options.put("-target", source.requiredTarget().name);
+                    target = source.requiredTarget();
+                    options.put("-target", target.name);
                 }
             } else {
                 if (targetString == null && !source.allowGenerics()) {
-                    options.put("-target", Target.JDK1_4.name);
+                    target = Target.JDK1_4;
+                    options.put("-target", target.name);
                 }
             }
         }
+        if (target.hasInvokedynamic()) {
+            options.put("invokedynamic",  "invokedynamic");
+        }
         return filenames.toList();
     }
     // where
--- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Mon May 04 22:16:46 2009 -0700
@@ -1034,7 +1034,13 @@
                     return illegal(pos);
                 }
             } else {
-                return illegal();
+                // Support the corner case of myMethodHandle.<void>invoke() by passing
+                // a void type (like other primitive types) to the next phase.
+                // The error will be reported in Attr.attribTypes or Attr.visitApply.
+                JCPrimitiveTypeTree ti = to(F.at(pos).TypeIdent(TypeTags.VOID));
+                S.nextToken();
+                return ti;
+                //return illegal();
             }
             break;
         default:
--- a/src/share/classes/com/sun/tools/javac/parser/Scanner.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/parser/Scanner.java	Mon May 04 22:16:46 2009 -0700
@@ -317,7 +317,7 @@
 
     /** Read next character in character or string literal and copy into sbuf.
      */
-    private void scanLitChar() {
+    private void scanLitChar(boolean forBytecodeName) {
         if (ch == '\\') {
             if (buf[bp+1] == '\\' && unicodeConversionBp != bp) {
                 bp++;
@@ -357,6 +357,18 @@
                     putChar('\"'); scanChar(); break;
                 case '\\':
                     putChar('\\'); scanChar(); break;
+                case '|': case ',': case '?': case '%':
+                case '^': case '_': case '{': case '}':
+                case '!': case '-': case '=':
+                    if (forBytecodeName) {
+                        // Accept escape sequences for dangerous bytecode chars.
+                        // This is illegal in normal Java string or character literals.
+                        // Note that the escape sequence itself is passed through.
+                        putChar('\\'); putChar(ch); scanChar();
+                    } else {
+                        lexError(bp, "illegal.esc.char");
+                    }
+                    break;
                 default:
                     lexError(bp, "illegal.esc.char");
                 }
@@ -365,6 +377,24 @@
             putChar(ch); scanChar();
         }
     }
+    private void scanLitChar() {
+        scanLitChar(false);
+    }
+
+    /** Read next character in an exotic name #"foo"
+     */
+    private void scanBytecodeNameChar() {
+        switch (ch) {
+        // reject any "dangerous" char which is illegal somewhere in the JVM spec
+        // cf. http://blogs.sun.com/jrose/entry/symbolic_freedom_in_the_vm
+        case '/': case '.': case ';':  // illegal everywhere
+        case '<': case '>':  // illegal in methods, dangerous in classes
+        case '[':  // illegal in classes
+            lexError(bp, "illegal.bytecode.ident.char", String.valueOf((int)ch));
+            break;
+        }
+        scanLitChar(true);
+    }
 
     /** Read fractional part of hexadecimal floating point number.
      */
@@ -915,6 +945,26 @@
                         lexError(pos, "unclosed.str.lit");
                     }
                     return;
+                case '#':
+                    scanChar();
+                    if (ch == '\"') {
+                        scanChar();
+                        if (ch == '\"')
+                            lexError(pos, "empty.bytecode.ident");
+                        while (ch != '\"' && ch != CR && ch != LF && bp < buflen) {
+                            scanBytecodeNameChar();
+                        }
+                        if (ch == '\"') {
+                            name = names.fromChars(sbuf, 0, sp);
+                            token = IDENTIFIER;  // even if #"int" or #"do"
+                            scanChar();
+                        } else {
+                            lexError(pos, "unclosed.bytecode.ident");
+                        }
+                    } else {
+                        lexError("illegal.char", String.valueOf((int)'#'));
+                    }
+                    return;
                 default:
                     if (isSpecial(ch)) {
                         scanOperator();
--- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon May 04 22:16:46 2009 -0700
@@ -144,6 +144,8 @@
 
 compiler.err.else.without.if=\
     ''else'' without ''if''
+compiler.err.empty.bytecode.ident=\
+    empty bytecode identifier
 compiler.err.empty.char.lit=\
     empty character literal
 compiler.err.encl.class.required=\
@@ -186,6 +188,8 @@
 
 compiler.err.icls.cant.have.static.decl=\
     inner classes cannot have static declarations
+compiler.err.illegal.bytecode.ident.char=\
+    illegal bytecode identifier character: \\{0}
 compiler.err.illegal.char=\
     illegal character: \\{0}
 compiler.err.illegal.char.for.encoding=\
@@ -445,6 +449,8 @@
 compiler.err.types.incompatible.diff.ret=\
     types {0} and {1} are incompatible; both define {2}, but with unrelated return types
 
+compiler.err.unclosed.bytecode.ident=\
+    unclosed bytecode identifier
 compiler.err.unclosed.char.lit=\
     unclosed character literal
 compiler.err.unclosed.comment=\
--- a/src/share/classes/com/sun/tools/javac/util/Names.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javac/util/Names.java	Mon May 04 22:16:46 2009 -0700
@@ -73,6 +73,8 @@
     public final Name java_io_Serializable;
     public final Name serialVersionUID;
     public final Name java_lang_Enum;
+    public final Name java_dyn_MethodHandle;
+    public final Name java_dyn_InvokeDynamic;
     public final Name package_info;
     public final Name ConstantValue;
     public final Name LineNumberTable;
@@ -111,6 +113,7 @@
     public final Name value;
     public final Name getMessage;
     public final Name getClass;
+    public final Name invoke;
     public final Name TYPE;
     public final Name FIELD;
     public final Name METHOD;
@@ -175,6 +178,8 @@
         java_lang_Cloneable = fromString("java.lang.Cloneable");
         java_io_Serializable = fromString("java.io.Serializable");
         java_lang_Enum = fromString("java.lang.Enum");
+        java_dyn_MethodHandle = fromString("java.dyn.MethodHandle");
+        java_dyn_InvokeDynamic = fromString("java.dyn.InvokeDynamic");
         package_info = fromString("package-info");
         serialVersionUID = fromString("serialVersionUID");
         ConstantValue = fromString("ConstantValue");
@@ -216,6 +221,7 @@
         value = fromString("value");
         getMessage = fromString("getMessage");
         getClass = fromString("getClass");
+        invoke = fromString("invoke");
 
         TYPE = fromString("TYPE");
         FIELD = fromString("FIELD");
--- a/src/share/classes/com/sun/tools/javap/ConstantWriter.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/com/sun/tools/javap/ConstantWriter.java	Mon May 04 22:16:46 2009 -0700
@@ -339,7 +339,7 @@
             cp = name.codePointAt(k);
             if ((cc == '/' && !Character.isJavaIdentifierStart(cp))
                     || (cp != '/' && !Character.isJavaIdentifierPart(cp))) {
-                return "\"" + name + "\"";
+                return "\"" + addEscapes(name) + "\"";
             }
             cc = cp;
         }
@@ -347,6 +347,33 @@
         return name;
     }
 
+    /* If name requires escapes, put them in, so it can be a string body. */
+    private static String addEscapes(String name) {
+        String esc = "\\\"\n\t";
+        String rep = "\\\"nt";
+        StringBuilder buf = null;
+        int nextk = 0;
+        int len = name.length();
+        for (int k = 0; k < len; k++) {
+            char cp = name.charAt(k);
+            int n = esc.indexOf(cp);
+            if (n >= 0) {
+                if (buf == null)
+                    buf = new StringBuilder(len * 2);
+                if (nextk < k)
+                    buf.append(name, nextk, k);
+                buf.append('\\');
+                buf.append(rep.charAt(n));
+                nextk = k+1;
+            }
+        }
+        if (buf == null)
+            return name;
+        if (nextk < len)
+            buf.append(name, nextk, len);
+        return buf.toString();
+    }
+
     private ClassWriter classWriter;
     private Options options;
 }
--- a/src/share/classes/sun/tools/javap/JavapPrinter.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/sun/tools/javap/JavapPrinter.java	Mon May 04 22:16:46 2009 -0700
@@ -475,6 +475,13 @@
             return 5;
         }
 
+        case opc_invokedynamic: {
+            int index = getUShort(pc+1);
+            out.print("\t#"+index+"; //");
+            PrintConstant(index);
+            return 5;
+        }
+
         case opc_multianewarray: {
             int index = getUShort(pc+1), dimensions=getUbyte(pc+3);
             out.print("\t#"+index+",  "+dimensions+"; //");
--- a/src/share/classes/sun/tools/javap/RuntimeConstants.java	Thu Apr 30 15:04:50 2009 -0700
+++ b/src/share/classes/sun/tools/javap/RuntimeConstants.java	Mon May 04 22:16:46 2009 -0700
@@ -318,7 +318,7 @@
     public static final int opc_invokespecial            = 183;
     public static final int opc_invokestatic             = 184;
     public static final int opc_invokeinterface          = 185;
-//    public static final int opc_xxxunusedxxx             = 186;
+    public static final int opc_invokedynamic            = 186;
     public static final int opc_new                      = 187;
     public static final int opc_newarray                 = 188;
     public static final int opc_anewarray                = 189;
@@ -549,7 +549,7 @@
         "invokespecial", //     was "invokenonvirtual",
         "invokestatic",
         "invokeinterface",
-        "bytecode 186", //"xxxunusedxxx",
+        "invokedynamic",
         "new",
         "newarray",
         "anewarray",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/meth/InvokeDyn.java	Mon May 04 22:16:46 2009 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6754038
+ * @summary Generate call sites for method handle
+ * @author jrose
+ *
+ * @library ..
+ * @compile -source 7 -target 7 InvokeDyn.java
+ */
+//No: @run main/othervm -XX:+EnableInvokeDynamic meth.InvokeDyn
+
+/*
+ * Standalone testing:
+ * <code>
+ * $ cd $MY_REPO_DIR/langtools
+ * $ (cd make; make)
+ * $ ./dist/bootstrap/bin/javac -d dist test/tools/javac/meth/InvokeDyn.java
+ * $ javap -c -classpath dist meth.InvokeDyn
+ * </code>
+ */
+
+package meth;
+
+import java.dyn.InvokeDynamic;
+
+public class InvokeDyn {
+    void test() {
+        Object x = "hello";
+        InvokeDynamic.greet(x, "world", 123);
+        InvokeDynamic.greet(x, "mundus", 456);
+        InvokeDynamic.greet(x, "kosmos", 789);
+        InvokeDynamic.<String>cogitate(10.11121, 3.14);
+        InvokeDynamic.<void>#"yow: what I mean to say is, please treat this one specially"(null);
+        InvokeDynamic.<int>invoke("goodbye");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/meth/InvokeMH.java	Mon May 04 22:16:46 2009 -0700
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6754038
+ * @summary Generate call sites for method handle
+ * @author jrose
+ *
+ * @compile -source 7 -target 7 InvokeMH.java
+ */
+
+/*
+ * Standalone testing:
+ * <code>
+ * $ cd $MY_REPO_DIR/langtools
+ * $ (cd make; make)
+ * $ ./dist/bootstrap/bin/javac -d dist test/tools/javac/meth/InvokeMH.java
+ * $ javap -c -classpath dist meth.InvokeMH
+ * </code>
+ */
+
+package meth;
+
+import java.dyn.MethodHandle;
+
+public class InvokeMH {
+    void test(MethodHandle mh_SiO,
+              MethodHandle mh_vS,
+              MethodHandle mh_vi,
+              MethodHandle mh_vv) {
+        Object o; String s; int i;  // for return type testing
+
+        // next five must have sig = (String,int)Object
+        mh_SiO.invoke("world", 123);
+        mh_SiO.invoke("mundus", 456);
+        Object k = "kosmos";
+        mh_SiO.invoke((String)k, 789);
+        o = mh_SiO.invoke((String)null, 000);
+        o = mh_SiO.<Object>invoke("arda", -123);
+
+        // sig = ()String
+        s = mh_vS.<String>invoke();
+
+        // sig = ()int
+        i = mh_vi.<int>invoke();
+        o = mh_vi.<int>invoke();
+        //s = mh_vi.<int>invoke(); //BAD
+        mh_vi.<int>invoke();
+
+        // sig = ()void
+        //o = mh_vv.<void>invoke(); //BAD
+        mh_vv.<void>invoke();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/meth/MakeNegTests.sh	Mon May 04 22:16:46 2009 -0700
@@ -0,0 +1,98 @@
+#!/bin/sh
+
+#
+# Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+# @test
+# @bug 6754038
+# @summary Verify correct rejection of strongly typed return values
+# @run shell MakeNegTests.sh
+
+default_template=InvokeMH.java
+javacflags='-source 7 -target 7'
+# the rest of this file is a generic "//BAD"-line tester
+
+: ${TESTSRC=.} ${TESTCLASSES=.}
+javac="${TESTJAVA+${TESTJAVA}/bin/}javac"
+
+verbose=false quiet=false
+
+main() {
+  case "${@-}" in
+  *.java*)
+    for template in "$@"; do
+      expand_and_test "$template"
+    done;;
+  *) expand_and_test "${TESTSRC}/$default_template";;
+  esac
+}
+
+expand_and_test() {
+  template=$1
+  expand "$@"
+  testneg "$@"
+}
+
+expand() {
+  template=$1
+  badlines=` grep -n < "$template" '//BAD' `
+  badcount=` echo "$badlines" | wc -l `
+  [ $badcount -gt 0 ] || { echo "No negative test cases in $template"; exit 1; }
+  $quiet || echo "Expanding $badcount negative test cases from $template:"
+  $quiet || echo "$badlines"
+  badnums=` echo "$badlines" | sed 's/:.*//' `
+  casestem=` getcasestem "$template" `
+  tclassname=` basename "$template" .java `
+  rm -f "$casestem"*.java
+  for badnum in $badnums; do
+    casefile="$casestem"${badnum}.java
+    cclassname=` basename "$casefile" .java `
+    sed < "$template" > "$casefile" "
+      s|@compile|@compile/fail|
+      / @[a-z]/s|@|##|
+      ${badnum}s:^ *[/*]*:    :
+      s/${tclassname}/${cclassname}/g
+    "
+    $verbose && diff -u "$template" "$casefile"
+  done
+}
+
+getcasestem() {
+  echo "$1" | sed 's/\.java$//;s/_BAD[0-9]*$//;s/$/_BAD/'
+}
+
+testneg() {
+  template=$1
+  for casefile in ` getcasestem "$template" `*.java; do
+    $quiet || echo -------- $javac $javacflags "$casefile"
+    $javac $javacflags "$casefile" > "$casefile".errlog 2>&1 && {
+      echo "*** Compilation unexpectedly succeeded:  $casefile"
+      exit 1
+    }
+    $quiet || echo "Compilation failed as expected"
+    $quiet || head ` $verbose || echo -3 ` < "$casefile".errlog
+    rm "$casefile".errlog
+  done
+}
+
+main "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/quid/MakeNegTests.sh	Mon May 04 22:16:46 2009 -0700
@@ -0,0 +1,97 @@
+#!/bin/sh
+
+#
+# Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+# CA 95054 USA or visit www.sun.com if you need additional information or
+# have any questions.
+#
+
+# @test
+# @bug 6746458
+# @summary Verify correct rejection of illegal quoted identifiers.
+# @run shell MakeNegTests.sh
+
+default_template=QuotedIdent.java
+# the rest of this file is a generic "//BAD"-line tester
+
+: ${TESTSRC=.} ${TESTCLASSES=.}
+javac="${TESTJAVA+${TESTJAVA}/bin/}javac"
+
+verbose=false quiet=false
+
+main() {
+  case "${@-}" in
+  *.java*)
+    for template in "$@"; do
+      expand_and_test "$template"
+    done;;
+  *) expand_and_test "${TESTSRC}/$default_template";;
+  esac
+}
+
+expand_and_test() {
+  template=$1
+  expand "$@"
+  testneg "$@"
+}
+
+expand() {
+  template=$1
+  badlines=` grep -n < "$template" '//BAD' `
+  badcount=` echo "$badlines" | wc -l `
+  [ $badcount -gt 0 ] || { echo "No negative test cases in $template"; exit 1; }
+  $quiet || echo "Expanding $badcount negative test cases from $template:"
+  $quiet || echo "$badlines"
+  badnums=` echo "$badlines" | sed 's/:.*//' `
+  casestem=` getcasestem "$template" `
+  tclassname=` basename "$template" .java `
+  rm "$casestem"*.java
+  for badnum in $badnums; do
+    casefile="$casestem"${badnum}.java
+    cclassname=` basename "$casefile" .java `
+    sed < "$template" > "$casefile" "
+      s|@compile|@compile/fail|
+      / @[a-z]/s|@|##|
+      ${badnum}s:^ *[/*]*:    :
+      s/${tclassname}/${cclassname}/g
+    "
+    $verbose && diff -u "$template" "$casefile"
+  done
+}
+
+getcasestem() {
+  echo "$1" | sed 's/\.java$//;s/_BAD[0-9]*$//;s/$/_BAD/'
+}
+
+testneg() {
+  template=$1
+  for casefile in ` getcasestem "$template" `*.java; do
+    $quiet || echo -------- $javac "$casefile"
+    $javac "$casefile" > "$casefile".errlog 2>&1 && {
+      echo "*** Compilation unexpectedly succeeded:  $casefile"
+      exit 1
+    }
+    $quiet || echo "Compilation failed as expected"
+    $quiet || head ` $verbose || echo -3 ` < "$casefile".errlog
+    rm "$casefile".errlog
+  done
+}
+
+main "$@"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/quid/QuotedIdent.java	Mon May 04 22:16:46 2009 -0700
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6746458
+ * @summary Verify correct lexing of quoted identifiers.
+ * @author jrose
+ *
+ * @library ..
+ * @run main quid.QuotedIdent
+ */
+
+/*
+ * Standalone testing:
+ * <code>
+ * $ cd $MY_REPO_DIR/langtools
+ * $ (cd make; make)
+ * $ ./dist/bootstrap/bin/javac -d dist test/tools/javac/quid/QuotedIdent.java
+ * $ java -version  # should print 1.6 or later
+ * $ java -cp dist quid.QuotedIdent
+ * </code>
+ */
+
+package quid;
+
+public class QuotedIdent {
+    static void check(int testid, String have, String expect)
+                throws RuntimeException {
+        if ((have == null && have != expect) ||
+                (have != null && !have.equals(expect))) {
+            String msg =
+                "TEST " + testid + ": HAVE \"" +
+                have + "\" EXPECT \"" + expect + "\"";
+            System.out.println("StringConversion: " + msg);
+            throw new RuntimeException(msg);
+        }
+    }
+
+    // negative tests:
+    //static class #"" { } //BAD empty ident name
+    //static class #"<foo>" { } //BAD bad char in ident name
+    /*static class /*(//BAD ident name interrupted by newline) #"jump:
+    " { } /* uncomment previous line to attempt class w/ bad name */
+
+    static class #"int" extends Number {
+        final int #"int";
+        #"int"(int #"int") {
+            this.#"int" = #"int";
+        }
+        static #"int" valueOf(int #"int") {
+            return new #"int"(#"int");
+        }
+        public int intValue() { return #"int"; }
+        public long longValue() { return #"int"; }
+        public float floatValue() { return #"int"; }
+        public double doubleValue() { return #"int"; }
+        public String toString() { return String.valueOf(#"int"); }
+    }
+
+    class #"*86" {
+        String #"555-1212"() { return "[*86.555-1212]"; }
+    }
+    static#"*86"#"MAKE-*86"() {   // note close spacing
+        return new QuotedIdent().new#"*86"();
+    }
+
+    static String bar() { return "[bar]"; }
+
+    public static void main(String[] args) throws Exception {
+        String s;
+
+        String #"sticky \' wicket" = "wicked ' stick";
+        s = #"sticky ' wicket";
+        check(11, s, "wicked \' stick");
+        check(12, #"s", s);
+        check(13, #"\163", s);
+
+        s = #"QuotedIdent".bar();
+        check(21, s, "[bar]");
+
+        s = #"int".valueOf(123).toString();
+        check(22, s, "123");
+
+        s = #"MAKE-*86"().#"555-1212"();
+        check(23, s, "[*86.555-1212]");
+
+        class#"{{{inmost}}}" { }
+        s = new#"{{{inmost}}}"().getClass().getName();
+        if (!s.endsWith("{{{inmost}}}"))
+            check(24, s, "should end with \"{{{inmost}}}\"");
+
+        s = #"Yog-Shoggoth".#"(nameless ululation)";
+        check(25, s, "Tekeli-li!");
+
+        s = #"int".class.getName();
+        check(31, s, QuotedIdent.class.getName()+"$int");
+
+        Class x86 = Class.forName(QuotedIdent.class.getName()+"$*86");
+        if (x86 != #"*86".class)
+            check(32, "reflected "+x86, "static "+#"*86".class);
+
+        s = (String) x86.getDeclaredMethod("555-1212").invoke(#"MAKE-*86"());
+        check(31, s, "[*86.555-1212]");
+
+        System.out.println("OK");
+    }
+}
+
+interface #"Yog-Shoggoth" {
+    final String #"(nameless ululation)" = "Tekeli-li!";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/tools/javac/quid/QuotedIdent2.java	Mon May 04 22:16:46 2009 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6746458
+ * @summary Verify correct separate compilation of classes with extended identifiers.
+ * @author jrose
+ *
+ * @library ..
+ * @run main quid.QuotedIdent2
+ */
+/*
+ * Standalone testing:
+ * <code>
+ * $ cd $MY_REPO_DIR/langtools
+ * $ (cd make; make)
+ * $ ./dist/bootstrap/bin/javac -d dist test/tools/javac/quid/QuotedIdent.java
+ * $ ./dist/bootstrap/bin/javac -d dist -cp dist test/tools/javac/quid/QuotedIdent2.java
+ * $ java -version  # should print 1.6 or later
+ * $ java -cp dist QuotedIdent2
+ * </code>
+ */
+
+package quid;
+
+import quid.QuotedIdent.*;
+import quid.QuotedIdent.#"*86";
+import static quid.QuotedIdent.#"MAKE-*86";
+
+public class QuotedIdent2 {
+    static void check(int testid, String have, String expect)
+                throws RuntimeException {
+        QuotedIdent.check(testid, have, expect);
+    }
+
+    public static void main(String[] args) throws Exception {
+        String s;
+
+        s = #"int".valueOf(123).toString();
+        check(22, s, "123");
+
+        s = #"MAKE-*86"().#"555-1212"();
+        check(23, s, "[*86.555-1212]");
+
+        s = #"Yog-Shoggoth".#"(nameless ululation)";
+        check(25, s, "Tekeli-li!");
+
+        s = QuotedIdent.#"int".class.getName();
+        check(31, s, QuotedIdent.class.getName()+"$int");
+
+        Class x86 = Class.forName(QuotedIdent.class.getName()+"$*86");
+        if (x86 != #"*86".class)
+            check(32, "reflected "+x86, "static "+#"*86".class);
+
+        s = (String) x86.getDeclaredMethod("555-1212").invoke(QuotedIdent.#"MAKE-*86"());
+        check(31, s, "[*86.555-1212]");
+
+        System.out.println("OK");
+    }
+}