Skip to content

Commit

Permalink
Support weakly-referencing to all kinds of objects
Browse files Browse the repository at this point in the history
Current WeakRef implementation doesn't support to reference to nil and false.

The reason for nil is that it can't know whether referenced object is nil or it
is garbage-collected and set to nil. The reason for false is that there is an
incorrect assumption that referenced objects can't be evaluated to false.

By adding a new field to C++ WeakRef class to record whether referenced object
is immediate or reference, WeakRef truly supports all kinds of objects.
  • Loading branch information
ryoqun committed May 2, 2012
1 parent c57090a commit 8103af4
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 9 deletions.
7 changes: 5 additions & 2 deletions kernel/bootstrap/weakref.rb
Expand Up @@ -21,12 +21,15 @@ def __object__

def __getobj__
obj = __object__()
::Kernel.raise RefError, "Object has been collected as garbage" unless obj
unless weakref_alive?
::Kernel.raise RefError, "Object has been collected as garbage"
end
return obj
end

def weakref_alive?
!!__object__
Rubinius.primitive :weakref_alive_p
::Kernel.raise PrimitiveFailure, "WeakRef#weakref_alive? failed"
end

def method_missing(method, *args, &block)
Expand Down
2 changes: 1 addition & 1 deletion vm/builtin/weakref.cpp
Expand Up @@ -28,7 +28,7 @@ namespace rubinius {

void WeakRef::Info::mark(Object* obj, ObjectMark& mark) {
WeakRef* ref = as<WeakRef>(obj);
if(ref->alive_p()) {
if(ref->reference_alive_p()) {
mark.gc->add_weak_ref(obj);
}
}
Expand Down
18 changes: 15 additions & 3 deletions vm/builtin/weakref.hpp
Expand Up @@ -12,6 +12,7 @@ namespace rubinius {

private:
Object* object_;
bool reference_;

public:

Expand All @@ -20,14 +21,15 @@ namespace rubinius {
return object_;
}

void set_object(gc::WriteBarrier* wb, Object* obj) {
void update_object(gc::WriteBarrier* wb, Object* obj) {
object_ = obj;
write_barrier(wb, obj);
}

// Rubinius.primitive :weakref_set_object
Object* set_object(STATE, Object* obj) {
object_ = obj;
reference_ = obj->reference_p();
write_barrier(state, obj);
return obj;
}
Expand All @@ -37,8 +39,18 @@ namespace rubinius {
// Rubinius.primitive+ :weakref_new
static WeakRef* create(STATE, Object* obj);

bool alive_p() {
return object_->reference_p();

bool reference_alive_p() {
return reference_ && object_->reference_p();
}

// Rubinius.primitive :weakref_alive_p
Object* alive_p() {
if(reference_ && !object_->reference_p()) {
return cFalse;
} else {
return cTrue;
}
}

class Info : public TypeInfo {
Expand Down
6 changes: 3 additions & 3 deletions vm/gc/gc.cpp
Expand Up @@ -319,13 +319,13 @@ namespace rubinius {
if(check_forwards) {
if(obj->young_object_p()) {
if(!obj->forwarded_p()) {
ref->set_object(object_memory_, cNil);
ref->update_object(object_memory_, cNil);
} else {
ref->set_object(object_memory_, obj->forward());
ref->update_object(object_memory_, obj->forward());
}
}
} else if(!obj->marked_p(object_memory_->mark())) {
ref->set_object(object_memory_, cNil);
ref->update_object(object_memory_, cNil);
}
}

Expand Down

0 comments on commit 8103af4

Please sign in to comment.