| Index: src/global-handles.h
|
| ===================================================================
|
| --- src/global-handles.h (revision 2585)
|
| +++ src/global-handles.h (working copy)
|
| @@ -57,8 +57,29 @@
|
| class GlobalHandles : public AllStatic {
|
| public:
|
| // Creates a new global handle that is alive until Destroy is called.
|
| - static Handle<Object> Create(Object* value);
|
| + static Handle<Object> Create(Object* value) {
|
| + Counters::global_handles.Increment();
|
| + Node* result;
|
| + if (first_free()) {
|
| + // Take the first node in the free list.
|
| + result = first_free();
|
| + set_first_free(result->next_free());
|
| + } else if (first_deallocated()) {
|
| + // Next try deallocated list
|
| + result = first_deallocated();
|
| + set_first_deallocated(result->next_free());
|
| + set_head(result);
|
| + } else {
|
| + // Allocate a new node.
|
| + result = pool_.Allocate();
|
| + result->set_next(head());
|
| + set_head(result);
|
| + }
|
| + result->Initialize(value);
|
| + return result->handle();
|
| + }
|
|
|
| +
|
| // Destroy a global handle.
|
| static void Destroy(Object** location);
|
|
|
| @@ -123,8 +144,156 @@
|
| #endif
|
| private:
|
| // Internal node structure, one for each global handle.
|
| - class Node;
|
| + class Node {
|
| + public:
|
| + // Transition diagram:
|
| + // NORMAL <-> WEAK -> PENDING -> NEAR_DEATH -> { NORMAL, WEAK, DESTROYED }
|
| + enum State {
|
| + NORMAL, // Normal global handle.
|
| + WEAK, // Flagged as weak but not yet finalized.
|
| + PENDING, // Has been recognized as only reachable by weak handles.
|
| + NEAR_DEATH, // Callback has informed the handle is near death.
|
| + DESTROYED
|
| + };
|
|
|
| + Node() { state_ = DESTROYED; }
|
| +
|
| + explicit Node(Object* object) {
|
| + Initialize(object);
|
| + // Initialize link structure.
|
| + next_ = NULL;
|
| + }
|
| +
|
| + ~Node() {
|
| + if (state_ != DESTROYED) Destroy();
|
| +#ifdef DEBUG
|
| + // Zap the values for eager trapping.
|
| + object_ = NULL;
|
| + next_ = NULL;
|
| + parameter_or_next_free_.next_free = NULL;
|
| +#endif
|
| + }
|
| +
|
| + void Initialize(Object* object) {
|
| + // Set the initial value of the handle.
|
| + object_ = object;
|
| + state_ = NORMAL;
|
| + parameter_or_next_free_.parameter = NULL;
|
| + callback_ = NULL;
|
| + }
|
| +
|
| + void Destroy();
|
| +
|
| + // Accessors for next_.
|
| + Node* next() { return next_; }
|
| + void set_next(Node* value) { next_ = value; }
|
| + Node** next_addr() { return &next_; }
|
| +
|
| + // Accessors for next free node in the free list.
|
| + Node* next_free() {
|
| + ASSERT(state_ == DESTROYED);
|
| + return parameter_or_next_free_.next_free;
|
| + }
|
| + void set_next_free(Node* value) {
|
| + ASSERT(state_ == DESTROYED);
|
| + parameter_or_next_free_.next_free = value;
|
| + }
|
| +
|
| + // Returns a link from the handle.
|
| + static Node* FromLocation(Object** location) {
|
| + ASSERT(OFFSET_OF(Node, object_) == 0);
|
| + return reinterpret_cast<Node*>(location);
|
| + }
|
| +
|
| + // Returns the handle.
|
| + Handle<Object> handle() { return Handle<Object>(&object_); }
|
| +
|
| + // Make this handle weak.
|
| + void MakeWeak(void* parameter, WeakReferenceCallback callback);
|
| + void ClearWeakness();
|
| +
|
| + bool IsNearDeath() {
|
| + // Check for PENDING to ensure correct answer when processing callbacks.
|
| + return state_ == PENDING || state_ == NEAR_DEATH;
|
| + }
|
| +
|
| + bool IsWeak() {
|
| + return state_ == WEAK;
|
| + }
|
| +
|
| + // Returns the id for this weak handle.
|
| + void set_parameter(void* parameter) {
|
| + ASSERT(state_ != DESTROYED);
|
| + parameter_or_next_free_.parameter = parameter;
|
| + }
|
| + void* parameter() {
|
| + ASSERT(state_ != DESTROYED);
|
| + return parameter_or_next_free_.parameter;
|
| + }
|
| +
|
| + // Returns the callback for this weak handle.
|
| + WeakReferenceCallback callback() { return callback_; }
|
| +
|
| + void PostGarbageCollectionProcessing();
|
| +
|
| + // Place the handle address first to avoid offset computation.
|
| + Object* object_; // Storage for object pointer.
|
| +
|
| + State state_;
|
| +
|
| + private:
|
| + // Handle specific callback.
|
| + WeakReferenceCallback callback_;
|
| + // Provided data for callback. In DESTROYED state, this is used for
|
| + // the free list link.
|
| + union {
|
| + void* parameter;
|
| + Node* next_free;
|
| + } parameter_or_next_free_;
|
| +
|
| + // Linkage for the list.
|
| + Node* next_;
|
| +
|
| + public:
|
| + TRACK_MEMORY("GlobalHandles::Node")
|
| + };
|
| +
|
| +
|
| + class Pool BASE_EMBEDDED {
|
| + public:
|
| + Pool() {
|
| + current_ = new Chunk();
|
| + current_->previous = NULL;
|
| + next_ = current_->nodes;
|
| + limit_ = current_->nodes + kNodesPerChunk;
|
| + }
|
| +
|
| + Node* Allocate() {
|
| + if (next_ < limit_) {
|
| + return next_++;
|
| + }
|
| + return SlowAllocate();
|
| + }
|
| +
|
| + void Release();
|
| +
|
| + private:
|
| + static const int kNodesPerChunk = 8192;
|
| + struct Chunk : public Malloced {
|
| + Chunk* previous;
|
| + Node nodes[kNodesPerChunk];
|
| + };
|
| +
|
| + Node* SlowAllocate();
|
| +
|
| + Chunk* current_;
|
| + Node* next_;
|
| + Node* limit_;
|
| + };
|
| +
|
| + static Pool pool_;
|
| +
|
| +
|
| // Field always containing the number of weak and near-death handles.
|
| static int number_of_weak_handles_;
|
|
|
| @@ -142,6 +311,15 @@
|
| static Node* first_free_;
|
| static Node* first_free() { return first_free_; }
|
| static void set_first_free(Node* value) { first_free_ = value; }
|
| +
|
| + // List of deallocated nodes. Even though they are deallocated,
|
| + // they keep correct next pointers, so allocating it back is just a matter
|
| + // of setting head to it (and ajusting |first_deallocated_|)
|
| + static Node* first_deallocated_;
|
| + static Node* first_deallocated() { return first_deallocated_; }
|
| + static void set_first_deallocated(Node* value) {
|
| + first_deallocated_ = value;
|
| + }
|
| };
|
|
|
|
|
|
|