> When I wrote my previous message, I did not understand what was going on
> here. Let me repeat it back to you to see if I understand now.
> Basically, when we attempt to resolve a ur_java_class, we check to see
> if there's a static initializer. If there is, we hang a java_thread
> which will run the static initializers off of the (in process of being
> resolved) java_class. When running invoke (or under some other
> circumstances I haven't run under the debugger to see who calls) or
> getstatic opcodes for a thread, we check to see if this slot in the
> java_thread's corresponding java_class is non-NULL, and, if so, we then
> run the initializer thread to the bitter end.
Right. We can't run the static initializer during resolution
(even if we wanted to) because you hit all sort of nastiness because of
the recursive resolution algorithm.
> It just feels like the potential exists for some
> really weird (and hard to debug) things to happen.
You're definitely right. I hadn't (in my ignorance :)) thought
about that at all. It's very likely a source of Bad Karma. Much better
to treat static initialization as a normal function call. (Which it is,
except that it's the ONLY call made /implicitly/ by the JVM -- everything else,
including the instance initializers, are explicitly called by the
bytecode.) This would involve be /very/ careful with the stack until we
determine if the class we're about to use has been initialized or not --
I'll investigate how far forward we can move the initialization check.
> Does the requesting
> thread get "slept" or "waited" properly, and the Right Thing happen
> later after the bits get loaded?
No. This way of doing things was a hack while I was rewriting
resolution. (and realizing that initializing during resolution was a Bad
Idea.) However, it *should* happen correctly if we treat it as a normal
method call. The other thing being that we need to treat calls to the
static initializer as being synchronized (for obvious reasons), with the
exception that the threads that block on some other thread's synch *don't*
continue with the method call. (Basically, we should implement this as a
wait() operation with the program counter backed off one; when the
notifyAll() op is peformed by the initializing thread, the thread will
re-execute the initializer-causing opcode, which should no longer call the
initializer...) Looking this up in the JVM spec also made me realize that
decaf isn't doing things quite right, because it has to check and make
sure that all superclasses are initialized before the subclass is,
starting from Object and going down. (hooray for stacks:)) That, and it
looks like I might be ignoring the distinction between active and passive
uses of a class, but it's hard to tell. (sigh...)
> (3) Speaking somewhat hypothetically and prematurely, what happens when
> we get real multithreading? Won't we want to pre-empt the static
> initializers?
Yes. See above -- the other reason for synchronizing.
> Well, I agree that you never ever want to leave a thread "in the middle
> of" a bytecode execution. I believe you'd have to back it out all the
> way and wait for a retry. The second part, about pushing a frame on top
> of the current stack, I will have to think about how bad that is (I
> forget what the stack discipline is like, and how the frames get
> popped). I would think it could be kind of like an "interrupt"
> happened, and the interrupt affects the runnability (sp?) of the pending
> opcode (by side effect of resolving the required class), and then just
> goes away and cleans up after itself. However, a debugger might show
> the extra stack stuff on top of the explicitly-called stuff.
We *want* to show that the code being executed is the static
initializer, IMHO -- it would be *very* confusing, otherwise. I think the
best solution here is to put the static init check as far forward as
possible, to minimize the 'unrolling' that needs to take place, push the
static init frame as a normal function call, except that we (don't) adjust
the program counter to point at the initializing bytecode, so that the
initializing bytecode is just run again. Since static initializers don't
return anything, the stack should be fine.
> How do "normal" Java systems/debuggers treat this event (he asked,
> ignorantly)?
No idea. We can ask the japhar/kaffe people :)
-_Quinn
_______________________________________________
Kernel maillist - [EMAIL PROTECTED]
http://jos.org/mailman/listinfo/kernel