Initial export.
git-svn-id: http://v8.googlecode.com/svn/trunk@2 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/global-handles.cc b/src/global-handles.cc
new file mode 100644
index 0000000..8c7dc8e
--- /dev/null
+++ b/src/global-handles.cc
@@ -0,0 +1,379 @@
+// Copyright 2007-2008 Google Inc. All Rights Reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "v8.h"
+
+#include "api.h"
+#include "global-handles.h"
+
+namespace v8 { namespace internal {
+
+class GlobalHandles::Node : public Malloced {
+ public:
+
+ void Initialize(Object* object) {
+ // Set the initial value of the handle.
+ object_ = object;
+ state_ = NORMAL;
+ parameter_or_next_free_.parameter = NULL;
+ callback_ = NULL;
+ }
+
+ 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 Destroy() {
+ if (state_ == WEAK || IsNearDeath()) {
+ GlobalHandles::number_of_weak_handles_--;
+ if (object_->IsJSGlobalObject()) {
+ GlobalHandles::number_of_global_object_weak_handles_--;
+ }
+ }
+ state_ = DESTROYED;
+ }
+
+ // 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) {
+ LOG(HandleEvent("GlobalHandle::MakeWeak", handle().location()));
+ if (state_ != WEAK && !IsNearDeath()) {
+ GlobalHandles::number_of_weak_handles_++;
+ if (object_->IsJSGlobalObject()) {
+ GlobalHandles::number_of_global_object_weak_handles_++;
+ }
+ }
+ state_ = WEAK;
+ set_parameter(parameter);
+ callback_ = callback;
+ }
+
+ void ClearWeakness() {
+ LOG(HandleEvent("GlobalHandle::ClearWeakness", handle().location()));
+ if (state_ == WEAK || IsNearDeath()) {
+ GlobalHandles::number_of_weak_handles_--;
+ if (object_->IsJSGlobalObject()) {
+ GlobalHandles::number_of_global_object_weak_handles_--;
+ }
+ }
+ state_ = NORMAL;
+ set_parameter(NULL);
+ }
+
+ 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() {
+ if (state_ != Node::PENDING) return;
+ LOG(HandleEvent("GlobalHandle::Processing", handle().location()));
+ void* par = parameter();
+ state_ = NEAR_DEATH;
+ set_parameter(NULL);
+ // The callback function is resolved as late as possible to preserve old
+ // behavior.
+ WeakReferenceCallback func = callback();
+ if (func != NULL) {
+ func(v8::Persistent<v8::Object>(ToApi<v8::Object>(handle())), par);
+ }
+ }
+
+ // Place the handle address first to avoid offset computation.
+ Object* object_; // Storage for object pointer.
+
+ // 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
+ };
+ 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")
+};
+
+
+Handle<Object> GlobalHandles::Create(Object* value) {
+ Counters::global_handles.Increment();
+ Node* result;
+ if (first_free() == NULL) {
+ // Allocate a new node.
+ result = new Node(value);
+ result->set_next(head());
+ set_head(result);
+ } else {
+ // Take the first node in the free list.
+ result = first_free();
+ set_first_free(result->next_free());
+ result->Initialize(value);
+ }
+ return result->handle();
+}
+
+
+void GlobalHandles::Destroy(Object** location) {
+ Counters::global_handles.Decrement();
+ if (location == NULL) return;
+ Node* node = Node::FromLocation(location);
+ node->Destroy();
+ // Link the destroyed.
+ node->set_next_free(first_free());
+ set_first_free(node);
+}
+
+
+void GlobalHandles::MakeWeak(Object** location, void* parameter,
+ WeakReferenceCallback callback) {
+ ASSERT(callback != NULL);
+ Node::FromLocation(location)->MakeWeak(parameter, callback);
+}
+
+
+void GlobalHandles::ClearWeakness(Object** location) {
+ Node::FromLocation(location)->ClearWeakness();
+}
+
+
+bool GlobalHandles::IsNearDeath(Object** location) {
+ return Node::FromLocation(location)->IsNearDeath();
+}
+
+
+bool GlobalHandles::IsWeak(Object** location) {
+ return Node::FromLocation(location)->IsWeak();
+}
+
+
+void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
+ // Traversal of GC roots in the global handle list that are marked as
+ // WEAK or PENDING.
+ for (Node* current = head_; current != NULL; current = current->next()) {
+ if (current->state_ == Node::WEAK
+ || current->state_ == Node::PENDING
+ || current->state_ == Node::NEAR_DEATH) {
+ v->VisitPointer(¤t->object_);
+ }
+ }
+}
+
+
+void GlobalHandles::MarkWeakRoots(WeakSlotCallback f) {
+ for (Node* current = head_; current != NULL; current = current->next()) {
+ if (current->state_ == Node::WEAK) {
+ if (f(¤t->object_)) {
+ current->state_ = Node::PENDING;
+ LOG(HandleEvent("GlobalHandle::Pending", current->handle().location()));
+ }
+ }
+ }
+}
+
+
+void GlobalHandles::PostGarbageCollectionProcessing() {
+ // Process weak global handle callbacks. This must be done after the
+ // GC is completely done, because the callbacks may invoke arbitrary
+ // API functions.
+ // At the same time deallocate all DESTORYED nodes
+ ASSERT(Heap::gc_state() == Heap::NOT_IN_GC);
+ Node** p = &head_;
+ while (*p != NULL) {
+ (*p)->PostGarbageCollectionProcessing();
+ if ((*p)->state_ == Node::DESTROYED) {
+ // Delete the link.
+ Node* node = *p;
+ *p = node->next(); // Update the link.
+ delete node;
+ } else {
+ p = (*p)->next_addr();
+ }
+ }
+ set_first_free(NULL);
+}
+
+
+void GlobalHandles::IterateRoots(ObjectVisitor* v) {
+ // Traversal of global handles marked as NORMAL or NEAR_DEATH.
+ for (Node* current = head_; current != NULL; current = current->next()) {
+ if (current->state_ == Node::NORMAL) {
+ v->VisitPointer(¤t->object_);
+ }
+ }
+}
+
+void GlobalHandles::TearDown() {
+ // Delete all the nodes in the linked list.
+ Node* current = head_;
+ while (current != NULL) {
+ Node* n = current;
+ current = current->next();
+ delete n;
+ }
+ // Reset the head and free_list.
+ set_head(NULL);
+ set_first_free(NULL);
+}
+
+
+int GlobalHandles::number_of_weak_handles_ = 0;
+int GlobalHandles::number_of_global_object_weak_handles_ = 0;
+
+GlobalHandles::Node* GlobalHandles::head_ = NULL;
+GlobalHandles::Node* GlobalHandles::first_free_ = NULL;
+
+#ifdef DEBUG
+
+void GlobalHandles::PrintStats() {
+ int total = 0;
+ int weak = 0;
+ int pending = 0;
+ int near_death = 0;
+ int destroyed = 0;
+
+ for (Node* current = head_; current != NULL; current = current->next()) {
+ total++;
+ if (current->state_ == Node::WEAK) weak++;
+ if (current->state_ == Node::PENDING) pending++;
+ if (current->state_ == Node::NEAR_DEATH) near_death++;
+ if (current->state_ == Node::DESTROYED) destroyed++;
+ }
+
+ PrintF("Global Handle Statistics:\n");
+ PrintF(" allocated memory = %dB\n", sizeof(Node) * total);
+ PrintF(" # weak = %d\n", weak);
+ PrintF(" # pending = %d\n", pending);
+ PrintF(" # near_death = %d\n", near_death);
+ PrintF(" # destroyed = %d\n", destroyed);
+ PrintF(" # total = %d\n", total);
+}
+
+void GlobalHandles::Print() {
+ PrintF("Global handles:\n");
+ for (Node* current = head_; current != NULL; current = current->next()) {
+ PrintF(" handle %p to %p (weak=%d)\n", current->handle().location(),
+ *current->handle(), current->state_ == Node::WEAK);
+ }
+}
+
+#endif
+
+List<ObjectGroup*> GlobalHandles::object_groups_(4);
+
+void GlobalHandles::AddToGroup(void* id, Object** handle) {
+ for (int i = 0; i < object_groups_.length(); i++) {
+ ObjectGroup* entry = object_groups_[i];
+ if (entry->id_ == id) {
+ entry->objects_.Add(handle);
+ return;
+ }
+ }
+
+ // not found
+ ObjectGroup* new_entry = new ObjectGroup(id);
+ new_entry->objects_.Add(handle);
+ object_groups_.Add(new_entry);
+}
+
+
+void GlobalHandles::RemoveObjectGroups() {
+ for (int i = 0; i< object_groups_.length(); i++) {
+ delete object_groups_[i];
+ }
+ object_groups_.Clear();
+}
+
+
+} } // namespace v8::internal