callcc: resume works better, stack frame API
authorjrose
Tue Jul 15 00:17:06 2008 -0700 (16 months ago)
changeset 4524d5cf342c5
parent 343e41568eedf
child 5308f0b343095
callcc: resume works better, stack frame API
Contributed-By: Lukas Stadler <lukas.stadler@jku.at>
rebase to jdk7-b30
callcc.patch
series
--- a/callcc.patch Tue Jul 15 00:03:14 2008 -0700
+++ b/callcc.patch Tue Jul 15 00:17:06 2008 -0700
@@ -1,10 +1,136 @@ diff --git a/src/share/classes/sun/misc/
+diff --git a/src/share/classes/javax/stack/Continuation.java b/src/share/classes/javax/stack/Continuation.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/javax/stack/Continuation.java
+@@ -0,0 +1,31 @@
++package javax.stack;
++
++import java.lang.reflect.Method;
++
++/**
++ * Allows to store stack frames so that they can be inspected, modified and reinstated. Any access beyond querying the
++ * stack frame count and the methods poses a potential security risk.
++ *
++ * TODO make this object iterable
++ */
++public class Continuation {
++ private StackFrame[] stackFrames;
++
++ public int getStackFrameCount() {
++ return stackFrames == null ? 0 : stackFrames.length;
++ }
++
++ public Method getMethod(int index) {
++ return stackFrames[index].getMethod();
++ }
++
++ public StackFrame getStackFrame(int index) {
++ // TODO: security check ...
++ return stackFrames[index];
++ }
++
++ public void setStackFrames(StackFrame[] stackFrames) {
++ // TODO: security check
++ this.stackFrames = stackFrames;
++ }
++}
+diff --git a/src/share/classes/javax/stack/StackFrame.java b/src/share/classes/javax/stack/StackFrame.java
+new file mode 100644
+--- /dev/null
++++ b/src/share/classes/javax/stack/StackFrame.java
+@@ -0,0 +1,82 @@
++package javax.stack;
++
++import java.lang.reflect.Method;
++
++/**
++ * Contains the defining state of one stack frame activation. Read access provides access to private data, unverified
++ * write access may allow code to escape security constraints, violate JVM invariants or even break the JVM.
++ *
++ * Data within this object is somewhat packed: the values and objects of local variables and expressions are
++ * sequentially written into valueSlots and objectSlots. After that the monitors are written into objectSlots.
++ */
++public class StackFrame {
++ private Method method;
++ private int bci;
++
++ private boolean[] localIsObject;
++ private boolean[] expressionIsObject;
++ private int[] valueSlots;
++ private Object[] objectSlots;
++
++ public Method getMethod() {
++ return method;
++ }
++
++ public void setMethod(Method method) {
++ this.method = method;
++ }
++
++ public int getBci() {
++ return bci;
++ }
++
++ public void setBci(int bci) {
++ this.bci = bci;
++ }
++
++ public int getLocalCount() {
++ return localIsObject == null ? 0 : localIsObject.length;
++ }
++
++ public int getExpressionCount() {
++ return expressionIsObject == null ? 0 : expressionIsObject.length;
++ }
++
++ public int getMonitorCount() {
++ return (valueSlots == null ? 0 : valueSlots.length) + (objectSlots == null ? 0 : objectSlots.length)
++ - getLocalCount() - getExpressionCount();
++ }
++
++ public int getValueSlot(int index) {
++ return valueSlots[index];
++ }
++
++ public Object getObjectSlot(int index) {
++ return objectSlots[index];
++ }
++
++ public void setValueSlots(int[] valueSlots) {
++ this.valueSlots = valueSlots;
++ }
++
++ public void setObjectSlots(Object[] objectSlots) {
++ this.objectSlots = objectSlots;
++ }
++
++ public boolean localIsObject(int index) {
++ return localIsObject[index];
++ }
++
++ public boolean expressionIsObject(int index) {
++ return expressionIsObject[index];
++ }
++
++ public void setLocalIsObject(boolean[] localIsObject) {
++ this.localIsObject = localIsObject;
++ }
++
++ public void setExpressionIsObject(boolean[] expressionIsObject) {
++ this.expressionIsObject = expressionIsObject;
++ }
++
++}
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 {
-
-
- /**
+@@ -1000,4 +1000,78 @@ public final class Unsafe {
+ * if the load average is unobtainable.
+ */
+ public native int getLoadAverage(double[] loadavg, int nelems);
++
++ // %%%% Experimental:
++ /**
+ * 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.
@@ -53,21 +179,20 @@ diff --git a/src/share/classes/sun/misc/
+ * 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) {
++ public /*unreached*/ long resumeStack(Object context, 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);
++ return resumeStack0(context, stack, value, exception);
++ }
++ private native long resumeStack0(Object context, 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);
++ public void doCopyStackContext(Runnable r, Object context) {
++ r.run();
++ }
+
+ /** Exception thrown by an initial call to copyStack. */
+ public static class CopyStackException extends RuntimeException {
@@ -75,15 +200,14 @@ diff --git a/src/share/classes/sun/misc/
+ 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
++ public native Object copyStackSimple(Object context, javax.stack.Continuation continuation);
++
+ }
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 @@
+@@ -0,0 +1,99 @@
+/*
+ * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -125,7 +249,7 @@ new file mode 100644
+ 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);
++ unsafe.resumeStack(null, stack, value, null);
+ }
+ Object peekAtStack() { return stack; }
+ }
@@ -163,13 +287,17 @@ new file mode 100644
+ }
+
+ 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");
-+ }
++ unsafe.doCopyStackContext(new Runnable() {
++ public void run() {
++ try {
++ System.out.println(gammon());
++ } catch (CSE cse) {
++ System.out.println("copyStack cse="+cse);
++ System.out.println("copyStack stack="+TestCopyStack.toString(cse.peekAtStack()));
++ cse.resume("resuming");
++ }
++ }
++ }, null);
+ }
+
+ static String toString(Object x) {
--- a/series Tue Jul 15 00:03:14 2008 -0700
+++ b/series Tue Jul 15 00:17:06 2008 -0700
@@ -2,4 +2,4 @@ anonk.patch #-/anonk #+jdk7-b
#meth.patch #-/meth #+jdk7-b30 #-buildable
#indy.patch #-/indy #+jdk7-b30 #-buildable
#inti.patch #-/inti #+jdk7-b30 #-buildable
-callcc.patch #-/callcc #+jdk7-b25 #-testable
+callcc.patch #-/callcc #+jdk7-b30 #-testable