449 private: |
449 private: |
450 typedef enum { |
450 typedef enum { |
451 TYPE_NONE, |
451 TYPE_NONE, |
452 TYPE_COMPILED_METHOD_LOAD, |
452 TYPE_COMPILED_METHOD_LOAD, |
453 TYPE_COMPILED_METHOD_UNLOAD, |
453 TYPE_COMPILED_METHOD_UNLOAD, |
454 TYPE_FLUSH // pseudo-event used to implement flush_queue() |
454 TYPE_DYNAMIC_CODE_GENERATED |
455 } Type; |
455 } Type; |
456 |
456 |
457 Type _type; |
457 Type _type; |
458 union { |
458 union { |
459 nmethod* compiled_method_load; |
459 nmethod* compiled_method_load; |
460 struct { |
460 struct { |
461 jmethodID method_id; |
461 jmethodID method_id; |
462 const void* code_begin; |
462 const void* code_begin; |
463 } compiled_method_unload; |
463 } compiled_method_unload; |
464 int* flush_state_addr; |
464 struct { |
|
465 const char* name; |
|
466 const void* code_begin; |
|
467 const void* code_end; |
|
468 } dynamic_code_generated; |
465 } _event_data; |
469 } _event_data; |
466 |
470 |
467 JvmtiDeferredEvent(Type t) : _type(t) {} |
471 JvmtiDeferredEvent(Type t) : _type(t) {} |
468 |
|
469 void set_compiled_method_load(nmethod* nm) { |
|
470 assert(_type == TYPE_COMPILED_METHOD_LOAD, "must be"); |
|
471 _event_data.compiled_method_load = nm; |
|
472 } |
|
473 |
|
474 nmethod* compiled_method_load() const { |
|
475 assert(_type == TYPE_COMPILED_METHOD_LOAD, "must be"); |
|
476 return _event_data.compiled_method_load; |
|
477 } |
|
478 |
|
479 void set_compiled_method_unload(jmethodID id, const void* code) { |
|
480 assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be"); |
|
481 _event_data.compiled_method_unload.method_id = id; |
|
482 _event_data.compiled_method_unload.code_begin = code; |
|
483 } |
|
484 |
|
485 jmethodID compiled_method_unload_method_id() const { |
|
486 assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be"); |
|
487 return _event_data.compiled_method_unload.method_id; |
|
488 } |
|
489 |
|
490 const void* compiled_method_unload_code_begin() const { |
|
491 assert(_type == TYPE_COMPILED_METHOD_UNLOAD, "must be"); |
|
492 return _event_data.compiled_method_unload.code_begin; |
|
493 } |
|
494 |
|
495 bool is_flush_event() const { return _type == TYPE_FLUSH; } |
|
496 |
|
497 int* flush_state_addr() const { |
|
498 assert(is_flush_event(), "must be"); |
|
499 return _event_data.flush_state_addr; |
|
500 } |
|
501 |
|
502 void set_flush_state_addr(int* flag) { |
|
503 assert(is_flush_event(), "must be"); |
|
504 _event_data.flush_state_addr = flag; |
|
505 } |
|
506 |
472 |
507 public: |
473 public: |
508 |
474 |
509 JvmtiDeferredEvent() : _type(TYPE_NONE) {} |
475 JvmtiDeferredEvent() : _type(TYPE_NONE) {} |
510 |
476 |
511 // Factory methods |
477 // Factory methods |
512 static JvmtiDeferredEvent compiled_method_load_event(nmethod* nm) |
478 static JvmtiDeferredEvent compiled_method_load_event(nmethod* nm) |
513 KERNEL_RETURN_(JvmtiDeferredEvent()); |
479 KERNEL_RETURN_(JvmtiDeferredEvent()); |
514 static JvmtiDeferredEvent compiled_method_unload_event( |
480 static JvmtiDeferredEvent compiled_method_unload_event( |
515 jmethodID id, const void* code) KERNEL_RETURN_(JvmtiDeferredEvent()); |
481 jmethodID id, const void* code) KERNEL_RETURN_(JvmtiDeferredEvent()); |
|
482 static JvmtiDeferredEvent dynamic_code_generated_event( |
|
483 const char* name, const void* begin, const void* end) |
|
484 KERNEL_RETURN_(JvmtiDeferredEvent()); |
516 |
485 |
517 // Actually posts the event. |
486 // Actually posts the event. |
518 void post() KERNEL_RETURN; |
487 void post() KERNEL_RETURN; |
519 }; |
488 }; |
520 |
489 |
546 static volatile QueueNode* _pending_list; // Uses CAS for read/update |
515 static volatile QueueNode* _pending_list; // Uses CAS for read/update |
547 |
516 |
548 // Transfers events from the _pending_list to the _queue. |
517 // Transfers events from the _pending_list to the _queue. |
549 static void process_pending_events() KERNEL_RETURN; |
518 static void process_pending_events() KERNEL_RETURN; |
550 |
519 |
551 static void flush_complete(int* flush_state) KERNEL_RETURN; |
|
552 |
|
553 public: |
520 public: |
554 // Must be holding Service_lock when calling these |
521 // Must be holding Service_lock when calling these |
555 static bool has_events() KERNEL_RETURN_(false); |
522 static bool has_events() KERNEL_RETURN_(false); |
556 static void enqueue(const JvmtiDeferredEvent& event) KERNEL_RETURN; |
523 static void enqueue(const JvmtiDeferredEvent& event) KERNEL_RETURN; |
557 static JvmtiDeferredEvent dequeue() KERNEL_RETURN_(JvmtiDeferredEvent()); |
524 static JvmtiDeferredEvent dequeue() KERNEL_RETURN_(JvmtiDeferredEvent()); |
558 |
|
559 // This call blocks until all events enqueued prior to this call |
|
560 // have been posted. The Service_lock is acquired and waited upon. |
|
561 // |
|
562 // Implemented by creating a "flush" event and placing it in the queue. |
|
563 // When the flush event is "posted" it will call flush_complete(), which |
|
564 // will release the caller. |
|
565 // |
|
566 // Can be called by any thread (maybe even the service thread itself). |
|
567 // Not necessary for the caller to be a JavaThread. |
|
568 static void flush_queue(Thread* current) KERNEL_RETURN; |
|
569 |
525 |
570 // Used to enqueue events without using a lock, for times (such as during |
526 // Used to enqueue events without using a lock, for times (such as during |
571 // safepoint) when we can't or don't want to lock the Service_lock. |
527 // safepoint) when we can't or don't want to lock the Service_lock. |
572 // |
528 // |
573 // Events will be held off to the side until there's a call to |
529 // Events will be held off to the side until there's a call to |