[CC-ing mlvm-dev with my reply, since your note is of great general
interest. -- John]
On Apr 22, 2008, at 11:22 AM, Lukas Stadler wrote:
Hi!
If you have a login for that wiki, send me your login identifier,
and I'll add you to the author list. ('ChristianWimmer' already
has author access, and every JVM developer should have it, though
I have to enter the names one at a time for now.)
I've created a wikis.sun.com user named "LukasStadler". It would be
great if you could add that account to the author list.
Done this morning... Please feel free to create or edit pages in
HotSpotInternals, especially notes on implementation as you learn
your way around.
Building: Maybe it should be mentioned that the mercurial mq
extension needs to be enabled. It took me a while to figure out
where the "qselect" command comes from...
Thanks; I'll fix it in the README.
Are the continuations really bounded? (Looks like the framework's
main method, as reflected, serves as a boundary token.) What
happens when you try to return from a bounded continuation?
Good question - right now it is silently assumed that the
continuation is reinstated at a correct position (in this case the
stackframes are removed up to and including the main method, and
then the main method is the first stackframe to be installed again)
I suppose when a continuation is resumed all frames up to its bound
should be overwritten.
I thought there was some serialization story there. The source
code mentions a need to setAccessible(true). (Another potential
security challenge, out of many in this work.)
Hm... I don't think that there's a way - Method doesn't implement
Serializable and there's no special code in the
ObjectOutputStream... But it's not that big a problem anyway, I
just don't see why Class is serializable and Method is not.
Here is a guess: There's a security hole if you allow arbitrary
methods to be created from raw bytes with their "accessible" bit set
to true. But the fix would be to do the same security checks that
setAccessible does in the first place.
- Sounds like a reorganization of the code may allow nearly
complete reuse of the deopt blob
I hope so. There are not that many degrees of freedom in
interpreter frames, so it should not need fundamentally new
techniques.
I added an entry point into the deopt_blob that can be passed an
UnrollInfo object (and that doesn't call fetch_unroll_info). It's
only ~10 new lines of code. One problem that I see is that it may
be necessary to remove the stackframe of an inlined method from a
compiled frame to reach the boundary method, which means that the
topmost frame may need to be deoptimized. This might prove, uhm,
interesting. (because it shouldn't return to the Interpreter after
it's done)
That's one reason I made the boundary method be a fixed native method
doCopyStackContext. All those edge cases are easier to control that
way. I don't see (yet) that it's a significant loss of generality.
I also added code to vframeArray and Deoptimization that creates a
vframeArray from a StackSerializer. So far it works like a charm,
although I'm ignoring monitors for now. (I don't really know how to
create or acquire the BasicLock objects for monitors,
ObjectSynchronizer::inflate?)
I don't remember off hand, but I'd look at how the current deopt. or
OSR code does the trick.
I have created Java classes for the stack state (see the attached
files) and I've written native code that performs the stack copy
operation into these objects. I'd like to work with this
representation for the time being. I don't think that this is much
less efficient than the StackSerializer (apart from the obviously
larger memory consumption). Currently I'm writing code to create
the vframeArray from this representation and I'll send you an
overview of all the changes I made as soon as I'm finished with that.
You probably need more random access than the serialized form can
give you. Hmmm... The array-based representation is fine for
prototyping but for production use is too transparent to optimize or
secure. It's not a short term problem. What we need is a sort of
union-type list abstraction that can equally easily store references
and primitives (at least ints; would like IJFD), but without exposing
its internals too much.
interface MachineWordList extends List<Object> {
int size();
byte type(int i);
Object get(int i);
int getInt(int i);
long getLong(int i);
// setters?
void set(int i, Object x);
void setInt(int i, int x);
// arrays?
byte[] typeArray();
Object[] toArray();
int[] toIntArray();
}
But this is a cleanup; you don't have to turn aside from the main work.
Generators: That's an important use case for "small scale"
continuations. Open question: Does the existing design (a
serialized blob of data) give enough visibility to the compiler to
allow it to optimize across continuation invocations (thus
inlining generator patterns)? Probably not, unless the unsafe
copyStack/resumeStack structures are made more stateless and
immutable, so they can be examined by the compiler.
An ImmutableContinuation object, which allows no access to its
contents whatsoever, would fit this purpose, I think. The compiler
could even detect cases where the continuation is used as a
nonlocal return in inlined methods and create no continuation at
all...
Yes, that's the end-to-end optimization that we want for things like
generators.
Great work!
-- John
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;
}
}
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.
*/
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 Stackframe[] getStackframes() {
// TODO: security check ...
return stackframes;
}
public void setStackframes(Stackframe[] stackframes) {
// TODO: security check
this.stackframes = stackframes;
}
}
_______________________________________________
mlvm-dev mailing list
[email protected]
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev