anonk: 6655643: some dynamic languages need stack reification
authorjrose
Tue Apr 15 01:26:22 2008 -0700 (19 months ago)
changeset 2349442ac41d1
parent 10ac4312c0830
child 343e41568eedf
anonk: 6655643: some dynamic languages need stack reification
Summary: first working revision
Reviewed-by: jrose
callcc.patch
series
--- a/series Tue Apr 15 01:22:42 2008 -0700
+++ b/series Tue Apr 15 01:26:22 2008 -0700
@@ -2,4 +2,4 @@ anonk.patch #-/anonk #+jdk7-b25
#meth.patch #-/meth #+jdk7-b25 #-buildable
#indy.patch #-/indy #+jdk7-b25 #-buildable
#inti.patch #-/inti #+jdk7-b25 #-buildable
-#callcc.patch #-/callcc #+jdk7-b25 #-buildable
+callcc.patch #-/callcc #+jdk7-b25 #-testable
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/callcc.patch Tue Apr 15 01:26:22 2008 -0700
@@ -0,0 +1,181 @@
+diff --git a/src/share/classes/sun/misc/Unsafe.java b/src/share/classes/sun/misc/Unsafe.java
+--- a/src/share/classes/sun/misc/Unsafe.java
++++ b/src/share/classes/sun/misc/Unsafe.java
+@@ -856,6 +856,77 @@ public final class Unsafe {
+
+
+ /**
++ * Captures a snapshot of the JVM state, places it into the given exception,
++ * and throws it. The caller may choose to catch it immediately, or let
++ * someone up the call-chain catch it.
++ * <p>
++ * Later on, if the captured JVM state is resumed, the function returns normally,
++ * with whatever value the resumer provides, or (again) throws an exception,
++ * with whatever throwable the resumer provides. This can happen any number of
++ * times. Thus, we distinguish between the initial call to copyStack,
++ * and any number (zero or more) of returns.
++ * <p>
++ * If the context is null, the captured JVM state specifies all frames of
++ * the current thread. Otherwise, the context must correspond to a live
++ * call (in the same thread, not yet returned) to doCopyStackContext.
++ * (Correspondence is determined by reference identity, not Object.equals.)
++ * The captured JVM state then specifies only stack frames which are younger than
++ * that call to doCopyStackContext. It is an error for a resumed computation
++ * to attempt to return to that call to doCopyStackContext.
++ * The context is stored into the supplied CopyStackException, which must
++ * not already have a stored context. (That is, its 'stack' field must be null.)
++ * <p>
++ * Security note: The caller must be privileged, as TBD.
++ * All methods on the stack trace will have an opportunity to
++ * observe the thrown exception, but some may be less-privileged,
++ * and must be prevented from observing the contents of the stack.
++ * <p>
++ * Note: This method must return twice, and so two different execution
++ * paths must be created, either by some sort of data test (e.g., a boolean
++ * or a 2-array with one null element) or by distinguishing normal return
++ * from an exceptional return. This API uses the last option, because
++ * in many use cases (but not all) the copyStack call will be followed by
++ * some sort of suspension of the computation, back to a containing context,
++ * which will only ever be resume by an explicit resumeStack call.
++ */
++ public native Object copyStack(Object context, CopyStackException ex)
++ throws CopyStackException;
++ /**
++ * Resume a captured snapshot of a JVM state, which is suspended at a call
++ * to copyStack. This call returns normally with the given value, or (if the
++ * exception is not null) by immediately throwing the given exception.
++ * <p>
++ * A captured snapshot may be resumed any number of times, with any combination
++ * of normal and abnormal exits, and in any thread (or many threads, concurrently).
++ * <p>
++ * Note that the stack object must be obtained from inside a CopyStackException.
++ * This is not possible unless copyStack and resumeStack agree on which
++ * subclass of CopyStackException they are using, and if that subclass
++ * grants resumeStack access to its internal 'stack' field.
++ */
++ public /*unreached*/ void resumeStack(Object stack, Object value, Throwable exception) {
++ // This stack frame is available for overwriting.
++ // (This may make VM mods easier.)
++ resumeStack0(stack, value, exception);
++ }
++
++ private native long resumeStack0(Object stack, Object value, Throwable exception);
++
++ /**
++ * Establish a context for any nested calls to copyStack.
++ * The context object is arbitrary; often the expression new Object() works well.
++ * The run method is called.
++ * The only interesting use of this context object is as a non-null argument to copyStack.
++ */
++ public native void doCopyStackContext(Object context, Runnable r);
++
++ /** Exception thrown by an initial call to copyStack. */
++ public static class CopyStackException extends RuntimeException {
++ /** The JVM state, in an implementation dependent format. */
++ protected Object stack;
++ }
++
++ /**
+ * Atomically update Java variable to <tt>x</tt> if it is currently
+ * holding <tt>expected</tt>.
+ * @return <tt>true</tt> if successful
+diff --git a/test/java/dyn/Continuations/TestCopyStack.java b/test/java/dyn/Continuations/TestCopyStack.java
+new file mode 100644
+--- /dev/null
++++ b/test/java/dyn/Continuations/TestCopyStack.java
+@@ -0,0 +1,95 @@
++/*
++ * Copyright 2007-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 6655643
++ * @summary TestCopyStack, basic test
++ */
++
++import sun.misc.Unsafe;
++import java.util.*;
++
++class TestCopyStack {
++ static Unsafe unsafe;
++ static {
++ unsafe = Unsafe.getUnsafe();
++ }
++
++ public static class CSE extends Unsafe.CopyStackException {
++ //public String toString() { return "CSE/" + TestCopyStack.toString(stack); }
++ public void resume(Object value) {
++ unsafe.resumeStack(stack, value, null);
++ }
++ Object peekAtStack() { return stack; }
++ }
++
++ static String gammon() {
++ String normally = "";
++ try {
++ System.out.println("ENTER gammon");
++ String res = "gammon+"+spinach();
++ normally = " NORMALLY";
++ return res;
++ } finally {
++ System.out.println("EXIT gammon"+normally);
++ }
++ }
++
++ static String spinach() {
++ String normally = "";
++ try {
++ System.out.println("ENTER spinach");
++ String res = "spinach+"+magic();
++ normally = " NORMALLY";
++ return res;
++ } finally {
++ System.out.println("EXIT spinach"+normally);
++ }
++ }
++
++ static String magic() {
++ CSE cse = new CSE();
++ Object rv = unsafe.copyStack(null, cse);
++ rv = toString(rv);
++ System.out.println("copyStack rv="+rv);
++ return rv.toString();
++ }
++
++ public static void main(String... av) {
++ try {
++ System.out.println(gammon());
++ } catch (CSE cse) {
++ System.out.println("copyStack cse="+cse);
++ System.out.println("copyStack stack="+toString(cse.peekAtStack()));
++ cse.resume("resuming");
++ }
++ }
++
++ static String toString(Object x) {
++ if (x == null) return "null";
++ if (x instanceof Object[])
++ return Arrays.deepToString((Object[])x);
++ return x.toString();
++ }
++}