[plt-scheme] Embedding MzScheme in Java
Matthew,
I finally figured out why I was getting an access violation when
initializing MzScheme within a Java app. The upshot is that MzScheme
assumes Win32 embedding apps have a thread stack size of 1 MB, but
Sun's HotSpot JVM native stack is only a quarter that size. When
MzScheme calculates its stack boundary (in scheme_init_stack_check in
eval.c), like so
scheme_stack_boundary += (STACK_SAFETY_MARGIN - 0x100000);
after initializing scheme_stack_boundary to the scheme stack base, the
result, in the case at hand, is (logically) a negative number because
the Java native stack top is way lower than anticipated when MzScheme
first gets control. Later, when a stack check is performed, an
overflow is erroneously detected because scheme_stack_boundary is
declared an unsigned long and is taken to be in very high memory, way
above any reasonable stack location (remembering the stack grows
downward under Win32).
For my immediate purposes, I've opted for the obvious workaround:
modifying the Java executable "stack reserve" so that the JVM starts
up with a 1 MB native stack, like so
cd $JAVA_HOME/bin
editbin /stack:0x100000 java.exe
editbin /stack:0x100000 javaw.exe
(the later mod for apps which embed Java, like Eclipse).
I'm not really comfortable with that approach, as it means users would
have to tweak their Java executable in order to run MzScheme from a
Java app. Unfortunately, WIN32 provides no way to modify the stack
size at run time, nor even any way to determine its size (except with
SetThreadStackGuarantee on 64-bit machines). I'm aware there are ways
to probe the stack to calculate its extent, but they require
undocumented APIs and are sure to be brittle.
On the MzScheme side, the basic rub is the hard-wired 1 MB stack size
assumption (the 0x100000 term in the calculation of
scheme_stack_boundary). It's not a bad assumption, because WIN32 apps
get a 1 MB stack by default. Java's definitely an odd-ball-out in
that regard, but then any app could start with a non-default stack.
Here are some suggestions, for what they may worth:
1) Provide a variant of scheme_set_stack_base with an argument that
explicitly tells MzScheme what size stack it's dealing with.
2) Mention the potential problem and possible workarounds in
Inside MzScheme. The editbin trick may be the best that can be
done under WIN32 (for apps that can't be rebuilt), but there
are better ways on other platforms.
3) Have scheme_init_stack_check do an immediate check for a stack
overflow, to catch the situation I've just described, and print
out a message indicating the expected stack size is impossible.
If you wish, I'd be happy to put together a patch for this (though I
couldn't get to it til next week or so).
Once again, thanks for your help, and for MzScheme generally.
Randal