Request for review, 6766644: Redefinition of compiled method fails with assertion "Can not load classes with the Compiler thread"
David Holmes
David.Holmes at oracle.com
Tue Feb 1 15:38:08 PST 2011
Keith McGuigan said the following on 02/01/11 23:11:
> On Jan 31, 2011, at 9:20 PM, David Holmes wrote:
>> As per your other email NULL check is pointless as "new" will never
>> return null but will instead call vm_exit_out_of_memory to abort the
>> VM - which is exactly my point. I don't believe that a failure to
>> allocate in this code should be considered a fatal error for the VM.
>
> I agree, there may be situations where memory allocation failures should
> be considered non-fatal, and the Hotspot allocation routines should
> offer some support for that. However, it's not clear to me that the
> various specifications we adhere to have "escape-clause" situations
> where events can be dropped or features scaled back when/if we run into
> memory constraints. They should, no doubt, but I don't recall seeing
> anything like that at the present. It's a can of worms that is probably
> worth opening up, but it's a bigger issue than this bugfix.
Given our allocation routines leave a lot to be desired we should strive
to avoid the need for dynamic allocation as it introduces new abort
points. A program that runs fine today may abort with this fix due to
additional C-Heap usage.
>> I don't understand why we would have to allocate the event objects in
>> C-heap, all we want is a link field so that they can form their own
>> queue without the need for wrapper Nodes.
>>
>> 447 class JvmtiDeferredEvent VALUE_OBJ_CLASS_SPEC {
>> 448 friend class JvmtiDeferredEventQueue;
>> 449 private:
>> JvmtiDeferredEvent _next; // for chaining events together
>> public:
>> JvmtiDeferredEvent next() { return _next; }
>> void set_next(JvmtiDeferredEvent e) {
>> assert(_next == NULL, "overwriting linked event!");
>> _next = e;
>> }
>>
>> Further this would allow you to dequeue all the events at once instead
>> of the service thread going through pulling them off one at a time.
>
> That code doesn't work in C++. You can't have a type contain itself.
Okay my bad they were supposed to be pointer types (it is a linked-list
after all!)
> How big would it be? I suppose what you're suggesting is the Java
> semantics where the '_next' field is a reference/pointer. If so, you've
> just described the 'QueueNode' class. Could I collapse the definitions
> and have just one instead of both JvmtiDeferredEvent and QueueNode?
> Sure, but I see value in having them separate. For one, you can have
> different allocation schemes - QueueNodes go into the C-heap and
> JvmtiDeferredEvents can be value objects. Another reason is to
> separately encapsulate two different concepts that aren't necessarily
> related (list functionality and event specification).
The point is to avoid the need to dynamically allocate the QueueNodes.
If the elements to be queued are self-linking then you don't need the
extra wrapper objects. Take a look at VM_Operations as an example of
self-linking objects.
It also makes it easy to return a list of events for batch processing,
if you chose - ala VM_Operations again.
> And regardless of where you put the link, the event specification has to
> be allocated in the C-heap ...
I don't care about where the events are allocated, that is a totally
different issue. The point is to avoid the need to allocate nodes.
> Batching is a separate issue altogether. The existing code could be
> written to batch-process events using the existing classes.
Yes but I think the batching is simpler if the events themselves are linked.
>>>> 988 if (_queue_head == NULL) {
>>>> 989 // Just in case this happens in product; it shouldn't be
>>>> let's not crash
>>>> 990 return JvmtiDeferredEvent();
>>>> 991 }
>>>>
>>>> doesn't look right. Are we returning a stack allocated instance
>>>> here? (There's also a typo in the comment.)
>>> Yes, we're returning a stack-allocated instance, which returns to the
>>> caller as a temp and is copied into a local variable there. I'll fix
>>> the comment.
>>
>> It isn't "legal" to return a stack-allocated object from a method. I
>> expect we'll get away with it but still ...
>>
>> Couldn't you just allocate a static instance to use in this case?
>
> There's nothing wrong with returning an object by value.
Sorry I was thinking this was returning a pointer. So this is utilizing
C++ copy-semantics to make a valid copy in the caller when the method
returns. Still seems an odd construct to me but I assume C++ deals with
it correctly.
>> Now it seems that flush_queue is also called by the service thread,
>> but I can't see where from?
>
> It's not called directly, but it could happen if a user's JVMTI
> compiled-method-load/unload event handler method calls JVMTI's
> GenerateEvents(), so we need to code defensively here to prevent any
> inadvertent self-deadlocks.
Ok.
>> I'm a little concerned about all the locking/unlocking that seems to
>> happen; and the fact that there are potentially a lot of spurious
>> notifications. ...
>
> The enqueue code does not know the state of the service thread (nor
> should it have to), so it will always have to send a notification to
> wake it up if it's sleeping (even if the events are batched) And all the
> waiting code loops checking for conditions, so a spurious notification
> ought to be harmless.
enqueue() is not an issue for notifications, it has to do them. The
spurious wakeups are only a performance concern, not a correctness one.
> There is a single notifyAll that occurs when flushing is complete. This
> is implemented by the flush pseudo-event. (see JvmtiDeferredEvent::post()).
But this is a notifyAll per flush-event, which was my point. And
combined with the single-event per iteration processing you do get a lot
of locking/unlocking (due to the need to unlock when calling event.post()).
> No doubt this could be restructured a number of different ways, but this
> way is rather straightforward (easy to analyze) and appears correct.
> The possibility to batch-process the events in the future is there if we
> need it for some reason, but I don't see a need for it at the moment.
My mental model for much of this was the vm-operations queue and the
batch processing we do there. But if events are sparse then this is not
an immediate issue.
David
> --
> - Keith
More information about the serviceability-dev
mailing list