meth: add front-end support for JVM implicit methods on MH, Dynamic
authorjrose
Fri Sep 12 20:17:53 2008 -0700 (14 months ago)
changeset 6351c508b0dc1
parent 5d73ab86abbe1
child 73ed731114b29
meth: add front-end support for JVM implicit methods on MH, Dynamic
meth.patch
meth.txt
series
--- a/series Fri Sep 12 20:17:34 2008 -0700
+++ b/series Fri Sep 12 20:17:53 2008 -0700
@@ -1,1 +1,2 @@ quid.patch #-/quid #+jdk7-b
-quid.patch #-/quid #+jdk7-b34
+quid.patch #-/quid
+meth.patch #-/meth
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/meth.patch Fri Sep 12 20:17:53 2008 -0700
@@ -0,0 +1,313 @@
+diff --git a/src/share/classes/com/sun/tools/javac/code/Symtab.java b/src/share/classes/com/sun/tools/javac/code/Symtab.java
+--- a/src/share/classes/com/sun/tools/javac/code/Symtab.java
++++ b/src/share/classes/com/sun/tools/javac/code/Symtab.java
+@@ -120,6 +120,8 @@
+ public final Type stringBuilderType;
+ public final Type cloneableType;
+ public final Type serializableType;
++ public final Type methodHandleType;
++ public final Type dynamicType;
+ public final Type throwableType;
+ public final Type errorType;
+ public final Type illegalArgumentExceptionType;
+@@ -290,6 +292,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;
++ ((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;
+@@ -403,6 +423,8 @@
+ cloneableType = enterClass("java.lang.Cloneable");
+ throwableType = enterClass("java.lang.Throwable");
+ serializableType = enterClass("java.io.Serializable");
++ methodHandleType = enterClass("java.dyn.MethodHandle");
++ dynamicType = enterClass("java.dyn.Dynamic");
+ errorType = enterClass("java.lang.Error");
+ illegalArgumentExceptionType = enterClass("java.lang.IllegalArgumentException");
+ exceptionType = enterClass("java.lang.Exception");
+@@ -439,6 +461,8 @@
+
+ synthesizeEmptyInterfaceIfMissing(cloneableType);
+ synthesizeEmptyInterfaceIfMissing(serializableType);
++ synthesizeMHTypeIfMissing(methodHandleType);
++ synthesizeEmptyInterfaceIfMissing(dynamicType);
+ synthesizeBoxTypeIfMissing(doubleType);
+ synthesizeBoxTypeIfMissing(floatType);
+
+diff --git a/src/share/classes/com/sun/tools/javac/code/Types.java b/src/share/classes/com/sun/tools/javac/code/Types.java
+--- a/src/share/classes/com/sun/tools/javac/code/Types.java
++++ b/src/share/classes/com/sun/tools/javac/code/Types.java
+@@ -874,6 +874,9 @@
+ */
+ public boolean isCastable(Type t, Type s, Warner warn) {
+ if (t == s)
++ return true;
++
++ if (s == syms.dynamicType && (allowBoxing || !s.isPrimitive()))
+ return true;
+
+ if (t.isPrimitive() != s.isPrimitive())
+diff --git a/src/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/share/classes/com/sun/tools/javac/comp/Resolve.java
+--- a/src/share/classes/com/sun/tools/javac/comp/Resolve.java
++++ b/src/share/classes/com/sun/tools/javac/comp/Resolve.java
+@@ -852,6 +852,62 @@
+ 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.
++ * @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 site == syms.dynamicType || (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);
++ MethodType mtype = new MethodType(Type.map(argtypes, implicitArgType),
++ syms.objectType,
++ List.<Type>nil(),
++ syms.methodClass);
++ 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)) {
++ m = sym;
++ break;
++ }
++ }
++ if (m == null) {
++ // create the desired method
++ m = new MethodSymbol(PUBLIC | ABSTRACT, 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 Object
++ argType = syms.objectType;
++ return argType;
++ }
++
+ /** Load toplevel or member class with given fully qualified name and
+ * verify that it is accessible.
+ * @param env The current environment.
+@@ -1226,6 +1282,13 @@
+ sym = findMethod(env, site, name, argtypes, typeargtypes, true,
+ env.info.varArgs=true, false);
+ }
++ if (sym.kind >= AMBIGUOUS &&
++ (site == syms.dynamicType ||
++ (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) {
+ sym = access(sym, pos, site, name, true, argtypes, typeargtypes);
+ }
+diff --git a/src/share/classes/com/sun/tools/javac/jvm/Gen.java b/src/share/classes/com/sun/tools/javac/jvm/Gen.java
+--- a/src/share/classes/com/sun/tools/javac/jvm/Gen.java
++++ b/src/share/classes/com/sun/tools/javac/jvm/Gen.java
+@@ -2057,6 +2057,7 @@
+ // For basic types, the coerce(...) in genExpr(...) will do
+ // the conversion.
+ if (tree.clazz.type.tag > lastBaseTag &&
++ !types.isSameType(tree.clazz.type, syms.dynamicType) &&
+ types.asSuper(tree.expr.type, tree.clazz.type.tsym) == null) {
+ code.emitop2(checkcast, makeRef(tree.pos(), tree.clazz.type));
+ }
+diff --git a/src/share/classes/com/sun/tools/javac/util/Name.java b/src/share/classes/com/sun/tools/javac/util/Name.java
+--- a/src/share/classes/com/sun/tools/javac/util/Name.java
++++ b/src/share/classes/com/sun/tools/javac/util/Name.java
+@@ -437,6 +437,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_Dynamic = fromString("java.dyn.Dynamic");
+ package_info = fromString("package-info");
+ serialVersionUID = fromString("serialVersionUID");
+ ConstantValue = fromString("ConstantValue");
+@@ -478,6 +480,7 @@
+ value = fromString("value");
+ getMessage = fromString("getMessage");
+ getClass = fromString("getClass");
++ invoke = fromString("invoke");
+
+ TYPE = fromString("TYPE");
+ FIELD = fromString("FIELD");
+@@ -571,6 +574,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_Dynamic;
+ public final Name package_info;
+ public final Name ConstantValue;
+ public final Name LineNumberTable;
+@@ -612,6 +617,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;
+diff --git a/test/tools/javac/meth/InvokeDyn.java b/test/tools/javac/meth/InvokeDyn.java
+new file mode 100644
+--- /dev/null
++++ b/test/tools/javac/meth/InvokeDyn.java
+@@ -0,0 +1,55 @@
++/*
++ * 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 0000000
++ * @summary Generate call sites for method handle
++ * @author jrose
++ *
++ * 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>
++ *
++ * @compile InvokeDyn.java
++ */
++
++package meth;
++
++import java.dyn.Dynamic;
++
++public class InvokeDyn {
++ void test() {
++ Object x = "hello";
++ ((Dynamic)x).greet("world", 123);
++ ((Dynamic)x).greet("mundus", 456);
++ ((Dynamic)x).greet("kosmos", 789);
++ ((Dynamic)10.11121).cogitate(3.14);
++ ((Dynamic)null).#"yow: what I mean to say is, please treat this one specially"(null);
++ ((Dynamic)"goodbye").invoke();
++ }
++}
+diff --git a/test/tools/javac/meth/InvokeMH.java b/test/tools/javac/meth/InvokeMH.java
+new file mode 100644
+--- /dev/null
++++ b/test/tools/javac/meth/InvokeMH.java
+@@ -0,0 +1,52 @@
++/*
++ * 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 0000000
++ * @summary Generate call sites for method handle
++ * @author jrose
++ *
++ * 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>
++ *
++ * @run main meth.InvokeMH
++ */
++
++package meth;
++
++import java.dyn.MethodHandle;
++
++public class InvokeMH {
++ void test(MethodHandle mh) {
++ mh.invoke("world", 123);
++ mh.invoke("mundus", 456);
++ mh.invoke("kosmos", 789);
++ mh.invoke();
++ }
++}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/meth.txt Fri Sep 12 20:17:53 2008 -0700
@@ -0,0 +1,36 @@
+0000000: writing libraries in Java for non-Java languages requires method handle invocation
+Summary: javac recognizes implicit methods assigned by JVM to MethodHandle and Dynamic
+
+javac needs to support library development for non-Java langauges
+
+http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6746458
+
+Features:
+- the method java.dyn.MethodHandle.invoke(AAA)Object exists, even if not explicitly found
+- the method java.dyn.Dynamic.zzz(AAA)Object always exists, even if not explicitly found
+- the cast (Dynamic)x always succeeds and generates no code (other than primitive boxing)
+- the signature of the implicit method is obtained by erasing actual argument types
+- null arguments are treated as of Object type
+- no implicit conversions are performed on these calls; use a cast if you want conversion
+
+Examples from the unit test:
+ void test(MethodHandle mh) {
+ mh.invoke("world", 123);
+ ((Dynamic)"hello").greet("world", 123);
+ }
+
+
+Authors:
+- John Rose (Sun)
+
+Tests:
+- unit tests test/tools/javac/meth/*
+
+Incremental testing:
+This does not require a full JDK build.
+
+$ cd .../langtools
+$ hg qpush meth.patch
+$ (cd make; make)
+$ ./dist/bootstrap/bin/javac -d dist test/tools/javac/meth/*.java
+$ javap -c -classpath dist meth.Invoke{Dyn,MH} # observe call sites