meth: update test project to do assertion tests
authorjrose
Sat Sep 06 19:40:47 2008 -0700 (14 months ago)
changeset 25e65430d0399f
parent 2431eb9efc095b
child 26bb305998312e
meth: update test project to do assertion tests
meth.proj.patch
--- a/meth.proj.patch Tue Sep 02 00:08:13 2008 -0700
+++ b/meth.proj.patch Sat Sep 06 19:40:47 2008 -0700
@@ -43,7 +43,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/projects/MethodHandle/build.xml
-@@ -0,0 +1,125 @@
+@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
@@ -59,6 +59,22 @@ new file mode 100644
+ <property name="--broken--run.jvmargs" value="-Xbootclasspath/a:${build.classes.dir}:${local.junit.jar}"/>
+
+ <property name="javadoc.includes" value="java/dyn/*.java"/>
++
++ <!--- copy dependency class files straight into the output JAR -->
++ <target name="-post-jar">
++ <jar destfile="${dist.jar}"
++ update="true" compress="true">
++ <zipfileset src="${reference.AnonymousClass.jar}"/>
++ </jar>
++ </target>
++
++ <!--- build a bundle of the tests -->
++ <target name="-post-compile-test">
++ <echo message="make build/test-classes.jar from ${build.test.classes.dir}"/>
++ <jar compress="${jar.compress}" jarfile="${build.dir}/test-classes.jar">
++ <fileset dir="${build.test.classes.dir}"/>
++ </jar>
++ </target>
+
+ <target depends="init" name="-javadoc-build">
+ <mkdir dir="${dist.javadoc.dir}"/>
@@ -198,7 +214,7 @@ new file mode 100644
+excludes=java/dyn/Anonymous*.java,java/dyn/*ConstantPool*.java,jdk/java/dyn/Anonymous*.java
+includes=java/dyn/**,jdk/java/dyn/**
+#includes=**
-+jar.compress=false
++jar.compress=true
+javac.classpath=\
+ ${reference.AnonymousClass.jar}
+# Space-separated list of extra javac options
@@ -280,6 +296,439 @@ new file mode 100644
+ </references>
+ </configuration>
+</project>
+diff --git a/src/share/projects/MethodHandle/test/jdk/java/dyn/InvokeDynamicDemo.java b/src/share/projects/MethodHandle/test/jdk/java/dyn/InvokeDynamicDemo.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/MethodHandle/test/jdk/java/dyn/InvokeDynamicDemo.java
+@@ -0,0 +1,298 @@
++/*
++ * 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. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun 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 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.
++ */
++
++package jdk.java.dyn;
++
++import java.dyn.*;
++
++import java.util.Arrays;
++import java.util.HashMap;
++import java.util.regex.Pattern;
++import org.junit.*;
++//import static org.junit.Assert.*;
++import static jdk.java.dyn.JUnitAssert.*;
++
++public class InvokeDynamicDemo {
++
++ private interface FakeDynamic extends Dynamic {
++ int foo(int x);
++ String bar(String x, int y);
++ }
++
++ public static int myFoo(Object recv, int z) {
++ println("myFoo "+recv+" "+z);
++ return z * 1000000;
++ }
++
++ public static String myBar(Object recv, String x, int y) {
++ println("myBar "+recv+" "+x+" "+y);
++ return "myBar"+Arrays.asList(recv, x, y);
++ }
++
++ static class IDUser implements Runnable {
++ static String options = "FAKE_OPTIONS";
++ static boolean hasOption(String x) {
++ return options.indexOf(x) >= 0;
++ }
++
++ @Override
++ public void run() {
++ useit("baz", "bat", 123);
++ }
++
++ void useit(Object x, Object y, int z) {
++ int fooval = fakeIdentity(x).foo(z);
++ println("foo => "+fooval);
++ assertEquals(myFoo(x, z), fooval);
++ String barval = fakeIdentity(x).bar((String)y, z);
++ println("bar => "+barval);
++ assertEquals(myBar(x, (String)y, z), barval);
++ }
++
++ public // %%% FIXME: findStatic only finds public methods right now
++ static Object bootstrap(CallSite site, Object... args) {
++ println("bootstrap "+site+Arrays.asList(args));
++ // a bootstrap method can be very stupid:
++ if (hasOption("boot-gc"))
++ Runtime.getRuntime().gc();
++ if (hasOption("boot-null"))
++ return null;
++ if (hasOption("boot-bad"))
++ return Arrays.asList(args); // neither a String nor an Integer
++ if (hasOption("boot-string"))
++ return "boot";
++ if (hasOption("boot-int"))
++ return 8007;
++ if (hasOption("boot-throw"))
++ throw new RuntimeException("boot-throw!");
++ // or it can actually look at the call site:
++ Object name = site.name();
++ if (name == "foo") {
++ if (hasOption("boot-con"))
++ return 8007000; // it does not need to set a target...
++ MethodHandle myFoo = MethodHandles.findStatic(InvokeDynamicDemo.class, "myFoo", site.type());
++ println("setTarget myFoo: "+myFoo);
++ site.setTarget(myFoo);
++ return myFoo(args[0], (Integer) args[1]);
++ }
++ if (name == "bar") {
++ if (hasOption("boot-con"))
++ return "boot con!"; // it does not need to set a target...
++ MethodHandle myBar = MethodHandles.findStatic(InvokeDynamicDemo.class, "myBar", site.type());
++ println("setTarget myBar: "+myBar);
++ site.setTarget(myBar);
++ return myBar(args[0], (String) args[1], (Integer) args[2]);
++ }
++ throw new RuntimeException("name not recognized: "+name);
++ }
++
++ static {
++ println("options: "+options);
++ MethodType type = Linkage.BOOTSTRAP_METHOD_TYPE;
++ MethodHandle mh = MethodHandles.findStatic(IDUser.class, "bootstrap", type);
++ if (mh == null)
++ println("missing bootstrap"+type);
++ else
++ println("register bootstrap: "+mh);
++ Linkage.registerBootstrapMethod(IDUser.class, mh);
++ }
++ }
++ static FakeDynamic fakeIdentity(Object x) {
++ return (FakeDynamic)x;
++ }
++ static Object identity(Object x) {
++ return x;
++ }
++
++ static boolean verbose;
++ static void println(String x) {
++ if (verbose) System.out.println(x);
++ }
++
++ @Test public void run() throws Exception { run(new String[0]); }
++
++ public static void run(String... av) throws Exception {
++ final HashMap<String,String> utf8Map = new HashMap<String,String>();
++ utf8Map.put("fakeIdentity", "identity");
++ String objbcn = Object.class.getName().replace('.', '/');
++ String objsig = "L"+objbcn+";";
++ String fdbcn = FakeDynamic.class.getName().replace('.', '/');
++ String rdbcn = Dynamic.class.getName().replace('.', '/');
++ utf8Map.put(fdbcn, rdbcn);
++ String fakesig = "("+objsig+")L"+fdbcn+";";
++ utf8Map.put(fakesig, fakesig.replaceAll(Pattern.quote(fdbcn), objbcn));
++ utf8Map.put("FAKE_OPTIONS", Arrays.asList(av).toString());
++ System.out.println("utf8Map: "+utf8Map);
++ final ConstantPoolPatch patch = new ConstantPoolPatch(IDUser.class);
++ patch.putPatches(utf8Map, null, null, true);
++ if (!utf8Map.isEmpty())
++ throw new AssertionError("Map not empty: "+utf8Map);
++ Class anonk = new AnonymousClassLoader(IDUser.class).loadClass(patch);
++ Object user = anonk.newInstance();
++ System.out.println("Running test on new object "+user);
++ int count = 1;
++ verbose = true;
++ for (String arg : av) {
++ if (arg.startsWith("count-"))
++ count = Integer.parseInt(arg.substring("count-".length(), arg.length()));
++ }
++ if (count != 1) System.out.println("run count: "+count);
++ for (int i = 0; i < count; i++) {
++ if (i > 10) {
++ if (i > count - 10)
++ verbose = true;
++ else if (verbose) {
++ println("...shutting up...");
++ verbose = false;
++ }
++ }
++ ((Runnable)user).run();
++ }
++ }
++
++ // Extra entry point for standalone use. Use as follows:
++ //junit="$NetBeansResources/NetBeans/java2/modules/ext/junit-4.1.jar"
++ //anonk="../AnonymousClass/dist/AnonymousClass.jar"
++ //cpath="$anonk:build/classes:build/test/classes:$junit"
++ //java -Xbootclasspath/p:"$cpath" jdk.java.dyn.MethodHandleBytecodeTest
++ public static void main(String... av) throws Throwable {
++ System.out.println("running ID demo");
++ run(av);
++ //new JUnit4TestAdapter(InvokeDynamicDemo.class).run(null);
++ }
++}
++
++/* --- SAMPLE OUTPUT ---
++--------
++ ./gamma -XX:+{MethodHandles,InvokeDynamic} -Xbootclasspath/p:"$cpath" jdk.java.dyn.InvokeDynamicDemo count-1000
++VM option '+PrintCompilation'
++VM option '+VerifyBeforeGC'
++VM option '+MethodHandles'
++VM option '+InvokeDynamic'
++[Verifying threads permgen tenured generation def new generation remset ref_proc syms strs zone dict hand C-heap ]
++running ID demo
++utf8Map: {fakeIdentity=identity, jdk/java/dyn/InvokeDynamicDemo$FakeDynamic=java/dyn/Dynamic, (Ljava/lang/Object;)Ljdk/java/dyn/InvokeDynamicDemo$FakeDynamic;=(Ljava/lang/Object;)Ljava/lang/Object;, FAKE_OPTIONS=[count-1000]}
++ 1 java.lang.String::charAt (33 bytes)
++ 2 java.lang.String::hashCode (60 bytes)
++Running test on new object jdk.java.dyn.InvokeDynamicDemo$IDUser/29596205@eb7859
++run count: 1000
++reporting bootstrap method to JVM: bootstrap:(java.dyn.CallSite,java.lang.Object...)java.lang.Object
++DynCallSite: CallSite#23491286[foo(java.lang.Object,int)int => null]
++bootstrap CallSite#23491286[foo(java.lang.Object,int)int => null][baz, 123]
++setTarget myFoo: myFoo:(java.lang.Object,int)int
++myFoo baz 123
++foo => 123000000
++DynCallSite: CallSite#21061094[bar(java.lang.Object,java.lang.String,int)java.lang.String => null]
++bootstrap CallSite#21061094[bar(java.lang.Object,java.lang.String,int)java.lang.String => null][baz, bat, 123]
++setTarget myBar: myBar:(java.lang.Object,java.lang.String,int)java.lang.String
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++...shutting up...
++ 3 java.lang.Object::<init> (1 bytes)
++ VerifyBeforeGC:[Verifying threads permgen tenured generation def new generation remset ref_proc syms strs zone dict hand C-heap ]
++--- n java.lang.System::arraycopy (static)
++ 4 java.lang.String::getChars (66 bytes)
++ 5 java.lang.AbstractStringBuilder::append (60 bytes)
++ 6 java.lang.StringBuilder::append (8 bytes)
++ 7 java.lang.Integer::getChars (131 bytes)
++ 8 java.lang.AbstractStringBuilder::stringSizeOfInt (21 bytes)
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++myFoo baz 123
++foo => 123000000
++myBar baz bat 123
++bar => myBar[baz, bat, 123]
++--------
++ * --- */
+diff --git a/src/share/projects/MethodHandle/test/jdk/java/dyn/JUnitAssert.java b/src/share/projects/MethodHandle/test/jdk/java/dyn/JUnitAssert.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/projects/MethodHandle/test/jdk/java/dyn/JUnitAssert.java
+@@ -0,0 +1,125 @@
++/*
++ * 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. Sun designates this
++ * particular file as subject to the "Classpath" exception as provided
++ * by Sun 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 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.
++ */
++
++package jdk.java.dyn;
++
++import java.lang.reflect.InvocationTargetException;
++import java.lang.reflect.Method;
++import java.util.ArrayList;
++import java.util.Arrays;
++import java.util.HashMap;
++import java.util.List;
++
++/**
++ * Local stub for running without junit.jar.
++ * To use, copy this file to your package, and add this to the per-file imports:
++ * <code>
++ * //import static org.junit.Assert.*;
++ * import static whatever.this.package.is.JUnitAssert.*;
++ * </code>
++ * @author jrose
++ */
++class JUnitAssert {
++ static void assertSame(Object expected, Object actual) {
++ Method m = findMethod("assertSame", Object.class, Object.class);
++ if (m != null) {
++ callMethod(m, expected, actual);
++ } else if (expected != actual) {
++ error("not same", expected, actual);
++ }
++ }
++
++ static void assertEquals(Object expected, Object actual) {
++ if (!equals(expected, actual))
++ assertSame(expected, actual);
++ }
++
++ static boolean equals(Object x, Object y) {
++ return (x == y) || (x != null && y != null && x.equals(y));
++ }
++
++ static void error(String message, Object expected, Object actual) {
++ throw new AssertionError(message+": expected ["+expected+"]"+
++ ", but result was ["+actual+"]");
++ }
++
++ /// the rest is brute hackery...
++
++ static final Class<?> JUNIT_ASSERT;
++ static {
++ Class <?> JUNIT_ASSERT_ = null;
++ final String cname = "org.junit.Assert";
++ try {
++ JUNIT_ASSERT_ = Class.forName(cname);
++ } catch (ClassNotFoundException ee) {
++ System.out.println("Using backup methods instead of "+cname);
++ }
++ JUNIT_ASSERT = JUNIT_ASSERT_;
++ }
++
++ static final HashMap<List<Object>, Method> methods
++ = new HashMap<List<Object>, Method>();
++ static final Method NO_METHOD;
++ static {
++ Method noMethod = null;
++ try {
++ noMethod = JUnitAssert.class.getDeclaredMethod("noMethod");
++ } catch (Exception ee) {
++ }
++ NO_METHOD = noMethod;
++ }
++ static private void noMethod() { }
++
++ static Method findMethod(String name, Class<?>... params) {
++ if (JUNIT_ASSERT == null) return null;
++ ArrayList<Object> key = new ArrayList<Object>(Arrays.asList(params));
++ key.add(0, name);
++ Method m = methods.get(key);
++ if (m != null) return (m == NO_METHOD ? null : m);
++ try {
++ m = JUNIT_ASSERT.getMethod(name, params);
++ } catch (NoSuchMethodException ee) {
++ System.out.println("Missing method: "+name+Arrays.asList(params));
++ }
++ methods.put(key, (m == null ? NO_METHOD : m));
++ return m;
++ }
++ static Object callMethod(Method m, Object... params) {
++ Throwable bad;
++ try {
++ return m.invoke(null, params);
++ } catch (InvocationTargetException ite) {
++ Throwable ee = ite.getTargetException();
++ if (ee instanceof RuntimeException)
++ throw (RuntimeException)ee;
++ if (ee instanceof Error)
++ throw (Error)ee;
++ bad = ee;
++ } catch (Exception ee) {
++ bad = ee;
++ }
++ throw new Error("unexpected reflection problem", bad);
++ }
++}
diff --git a/src/share/projects/MethodHandle/test/jdk/java/dyn/MethodHandleBytecodeTest.java b/src/share/projects/MethodHandle/test/jdk/java/dyn/MethodHandleBytecodeTest.java
new file mode 100644
--- /dev/null
@@ -372,7 +821,7 @@ new file mode 100644
new file mode 100644
--- /dev/null
+++ b/src/share/projects/MethodHandle/test/jdk/java/dyn/MethodHandleDemo.java
-@@ -0,0 +1,122 @@
+@@ -0,0 +1,170 @@
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -405,10 +854,43 @@ new file mode 100644
+
+import org.junit.*;
+//import static org.junit.Assert.*;
++import static jdk.java.dyn.JUnitAssert.*;
+
+public class MethodHandleDemo {
++ static String options = "";
++ static boolean hasOption(String x) {
++ return options.indexOf(x) >= 0;
++ }
++ static boolean verbose = true;
++ static void println(Object x) {
++ if (verbose) System.out.println(x);
++ }
+
+ public static void main(String... av) {
++ assertSame("hello", "hello"); // exercise assertion stuff first
++
++ options = java.util.Arrays.asList(av).toString();
++ int count = 1;
++ verbose = true;
++ for (String arg : av) {
++ if (arg.startsWith("count-"))
++ count = Integer.parseInt(arg.substring("count-".length(), arg.length()));
++ }
++ if (count != 1) println("run count: "+count);
++ for (int i = 0; i < count; i++) {
++ if (i > 10) {
++ if (i > count - 10)
++ verbose = true;
++ else if (verbose) {
++ println("...shutting up...");
++ verbose = false;
++ }
++ }
++ test();
++ }
++ }
++
++ static void test() {
+ Class caller = MethodHandleDemo.class;
+ Class returnType = String.class;
+ Class[] signature = {String.class};
@@ -416,59 +898,71 @@ new file mode 100644
+ MethodHandle mh;
+ mh = MethodHandles.findVirtual(Object.class,
+ "toString", MethodType.make(String.class));
-+ System.out.println("calling "+mh);
++ println("calling "+mh);
+ result = (String) MethodHandleInvoker.make(mh.type()).invoke_LL(mh, "foo");
-+ System.out.println(result);
-+ if ((Object)result != "foo")
-+ throw new AssertionError("result = "+result);
++ assertSame("foo", result);
+
+ mh = MethodHandles.findStatic(MethodHandleDemo.class,
+ "test0", MethodType.make(String.class));
-+ System.out.println("calling "+mh);
++ println("calling "+mh);
+ result = (String) MethodHandleInvoker.make(mh.type()).invoke_L(mh);
-+ System.out.println(result);
++ assertEquals("[test0]", result);
+
+ mh = MethodHandles.findStatic(MethodHandleDemo.class,
+ "test1", MethodType.make(String.class, String.class));
-+ System.out.println("calling "+mh);
++ println("calling "+mh);
+ result = (String) MethodHandleInvoker.make(mh.type()).invoke_LL(mh, "X");
-+ System.out.println(result);
++ assertEquals("[test1 X]", result);
+
+ mh = MethodHandles.insertArgument(mh, "Bounderby");
-+ System.out.println("calling bound "+mh);
++ println("calling bound "+mh);
+ result = (String) MethodHandleInvoker.make(mh.type()).invoke_L(mh);
-+ System.out.println(result);
++ assertEquals("[test1 Bounderby]", result);
+
+ mh = MethodHandles.findStatic(MethodHandleDemo.class,
+ "test2", MethodType.make(String.class, String.class, int.class));
-+ System.out.println("calling "+mh);
++ println("calling "+mh);
+ result = (String) MethodHandleInvoker.make(mh.type()).invoke_LLI(mh, "X", 123);
-+ System.out.println(result);
++ assertEquals("[test2 X #123]", result);
++
++ mh = MethodHandles.insertArgument(mh, "Buster");
++ println("calling bound "+mh);
++ result = (String) MethodHandleInvoker.make(mh.type()).invoke_LI(mh, 456);
++ assertEquals("[test2 Buster #456]", result);
+
+ Obj obj = new Obj("X");
+ mh = MethodHandles.findVirtual(I.class,
+ "test1", MethodType.make(String.class));
-+ System.out.println("calling "+mh);
++ println("calling "+mh);
+ result = (String) MethodHandleInvoker.make(mh.type()).invoke_LL(mh, obj);
-+ System.out.println(result);
++ assertEquals("[Obj.test1 X]", result);
+
+ mh = MethodHandles.findVirtual(I.class,
+ "test2", MethodType.make(String.class, int.class));
-+ System.out.println("calling "+mh);
++ println("calling "+mh);
+ result = (String) MethodHandleInvoker.make(mh.type()).invoke_LLI(mh, obj, 123);
-+ System.out.println(result);
++ assertEquals("[Obj.test2 X #123]", result);
++ }
++
++ static void eachCall() {
++ if (hasOption("call-gc"))
++ Runtime.getRuntime().gc();
+ }
+
+ // static methods we make handles for:
+ public static String test0() {
++ eachCall();
+ return "[test0]";
+ }
+
+ public static String test1(String x) {
++ eachCall();
+ return "[test1 " + x + "]";
+ }
+
+ public static String test2(String x, int y) {
++ System.out.println("y == 0x"+Integer.toHexString(y));
++ eachCall();
+ return "[test2 " + x + " #" + y + "]";
+ }
+
@@ -482,9 +976,12 @@ new file mode 100644
+ String x;
+ Obj(String x) { this.x = x; }
+ public String test1() {
++ eachCall();
+ return "[Obj.test1 " + x + "]";
+ }
+ public String test2(int y) {
++ System.out.println("y == 0x"+Integer.toHexString(y));
++ eachCall();
+ return "[Obj.test2 " + x + " #" + y + "]";
+ }
+ }