Pastie now auto-senses if line-wrap is a bad or good idea. Feedback?
## mark a section (Learn more)
diff --git a/kernel/alpha.rb b/kernel/alpha.rb index 55d4eb4..e19fe9b 100644 --- a/kernel/alpha.rb +++ b/kernel/alpha.rb @@ -101,6 +101,39 @@ module Kernel def method_missing(meth, *args) raise NoMethodError, "Unable to send '#{meth}' on '#{self}' (#{self.class})" end + + # reimplemented in kernel/common/kernel.rb + def initialize_copy(other) + end + + def copy_header(other) + Ruby.primitive :object_copy_header + raise PrimitiveFailure, "Kernel#copy_header primitive failed" + end + + def copy_object(other) + Ruby.primitive :object_copy_object + raise PrimitiveFailure, "Kernel#copy_object primitive failed" + end + + def copy_metaclass(other) + Ruby.primitive :object_copy_metaclass + raise PrimitiveFailure, "Kernel#copy_metaclass primitive failed" + end + + def dup + copy = self.class.allocate + copy.copy_object self + copy.send :initialize_copy, self + copy + end + + def clone + copy = dup + copy.copy_metaclass self + copy.freeze if frozen? + copy + end end class CompiledMethod < Executable diff --git a/kernel/bootstrap/bytearray.rb b/kernel/bootstrap/bytearray.rb index 3be2594..d5dee09 100644 --- a/kernel/bootstrap/bytearray.rb +++ b/kernel/bootstrap/bytearray.rb @@ -1,11 +1,15 @@ class ByteArray - def self.allocate(cnt) + def self.allocate + raise TypeError, "ByteArray cannot be created via allocate()" + end + + def self.allocate_sized(cnt) Ruby.primitive :bytearray_allocate raise PrimitiveFailure, "ByteArray#allocate primitive failed" end def self.new(cnt) - obj = allocate(cnt) + obj = allocate_sized cnt Rubinius.asm(obj) do |obj| push_block run obj @@ -53,7 +57,8 @@ class ByteArray def dup(cls=nil) cls ||= self.class obj = cls.new(self.size) - dup_into obj + obj.copy_object self + obj.send :initialize_copy, self return obj end diff --git a/kernel/bootstrap/data.rb b/kernel/bootstrap/data.rb new file mode 100644 index 0000000..741ea90 --- /dev/null +++ b/kernel/bootstrap/data.rb @@ -0,0 +1,8 @@ +class Data + def dup + copy = self.class.allocate + copy.copy_header self + copy.send :initialize_copy, self + copy + end +end diff --git a/kernel/bootstrap/kernel.rb b/kernel/bootstrap/kernel.rb index eeaf07e..16efb97 100644 --- a/kernel/bootstrap/kernel.rb +++ b/kernel/bootstrap/kernel.rb @@ -1,15 +1,5 @@ module Kernel - def clone - Ruby.primitive :object_clone - raise TypeError, "Kernel#clone primitive failed" - end - - def dup - Ruby.primitive :object_dup - raise TypeError, "Kernel#dup primitive failed" - end - def equal?(other) Ruby.primitive :object_equal raise PrimitiveFailure, "Kernel#equal? primitive failed" diff --git a/kernel/bootstrap/lookuptable.rb b/kernel/bootstrap/lookuptable.rb index 0459d2f..1376b00 100644 --- a/kernel/bootstrap/lookuptable.rb +++ b/kernel/bootstrap/lookuptable.rb @@ -76,12 +76,16 @@ class LookupTable end end - def dup - Ruby.primitive :lookuptable_dup - raise PrimitiveFailure, "LookupTable#dup primitive failed" + def duplicate + Ruby.primitive :lookuptable_duplicate + raise PrimitiveFailure, "LookupTable#duplicate primitive failed" end - alias_method :clone, :dup + def dup + copy = duplicate + copy.send :initialize_copy, self + copy + end def fetch(key, return_on_failure) Ruby.primitive :lookuptable_fetch diff --git a/kernel/bootstrap/tuple.rb b/kernel/bootstrap/tuple.rb index 62ced70..506ea19 100644 --- a/kernel/bootstrap/tuple.rb +++ b/kernel/bootstrap/tuple.rb @@ -1,5 +1,9 @@ class Tuple + def self.allocate + raise TypeError, "Tuple cannot be created via allocate()" + end + def self.new(cnt) Ruby.primitive :tuple_allocate raise PrimitiveFailure, "Tuple.new primitive failed" @@ -40,6 +44,13 @@ class Tuple raise PrimitiveFailure, "Tuple#copy_from primitive failed" end + def dup + obj = self.class.new(self.size) + obj.copy_object self + obj.send :initialize_copy, self + obj + end + def delete(start,length,object) Ruby.primitive :tuple_delete_inplace raise PrimitiveFailure, "Tuple#delete primitive failed" diff --git a/kernel/common/kernel.rb b/kernel/common/kernel.rb index 5a4e4d0..c4de1b7 100644 --- a/kernel/common/kernel.rb +++ b/kernel/common/kernel.rb @@ -77,23 +77,6 @@ module Kernel end private :FloatValue - alias_method :primitive_clone, :clone - - def clone - copy = primitive_clone - copy.send :initialize_copy, self - copy.freeze if frozen? - copy - end - - alias_method :primitive_dup, :dup - - def dup - copy = primitive_dup - copy.send :initialize_copy, self - copy - end - def initialize_copy(source) unless source.class == self.class then raise TypeError, "initialize_copy should take same class object" diff --git a/kernel/platform/memorypointer.rb b/kernel/platform/memorypointer.rb index ff43ef1..5efb0c4 100644 --- a/kernel/platform/memorypointer.rb +++ b/kernel/platform/memorypointer.rb @@ -82,25 +82,18 @@ module FFI end end - def clone - other = Platform::POSIX.malloc total - other.total = total - other.type_size = type_size - Platform::POSIX.memcpy other, self, total - other - end - def dup other = Platform::POSIX.malloc total other.total = total other.type_size = type_size Platform::POSIX.memcpy other, self, total + other.send :initialize_copy, self other end - def address= thingy + def address=(address) Ruby.primitive :memorypointer_set_address - raise PrimitiveFailure, "Unable to fuck over your address well enough" + raise PrimitiveFailure, "MemoryPointer#address= primitive failed" end # Indicates how many bytes the chunk of memory that is pointed to takes up. diff --git a/kernel/platform/struct.rb b/kernel/platform/struct.rb index 44b7ce7..71ebd48 100644 --- a/kernel/platform/struct.rb +++ b/kernel/platform/struct.rb @@ -77,8 +77,8 @@ module FFI @pointer.free end - def initialize_copy ptr - @pointer = @pointer.dup + def initialize_copy(ptr) + @pointer = ptr.pointer.dup end def [](field) diff --git a/vm/builtin/lookuptable.cpp b/vm/builtin/lookuptable.cpp index d256c00..b8dd6e5 100644 --- a/vm/builtin/lookuptable.cpp +++ b/vm/builtin/lookuptable.cpp @@ -49,7 +49,7 @@ namespace rubinius { return tbl; } - LookupTable* LookupTable::dup(STATE) { + LookupTable* LookupTable::duplicate(STATE) { size_t size, i; LookupTable *dup; diff --git a/vm/builtin/lookuptable.hpp b/vm/builtin/lookuptable.hpp index 9fc12cc..8103c86 100644 --- a/vm/builtin/lookuptable.hpp +++ b/vm/builtin/lookuptable.hpp @@ -96,8 +96,8 @@ namespace rubinius { Object* fetch(STATE, Object* key, bool* found); - // Ruby.primitive :lookuptable_dup - LookupTable* dup(STATE); + // Ruby.primitive :lookuptable_duplicate + LookupTable* duplicate(STATE); void redistribute(STATE, size_t size); LookupTableBucket* find_entry(STATE, Object* key); Object* find(STATE, Object* key); diff --git a/vm/builtin/object.cpp b/vm/builtin/object.cpp index 931a00f..aa380e6 100644 --- a/vm/builtin/object.cpp +++ b/vm/builtin/object.cpp @@ -51,41 +51,39 @@ namespace rubinius { type_info(state)->cleanup(this); } - Object* Object::clone(STATE) { - Object* other = dup(state); + Object* Object::duplicate(STATE) { + Object* other = state->om->allocate_object(this->total_size(state)); + + return other->copy_object(state, this); + } - other->copy_internal_state_from(state, this); + Object* Object::copy_object(STATE, Object* other) { + copy_header(state, other); + copy_body(state, other); - return other; + return this; } - void Object::copy_internal_state_from(STATE, Object* original) { - if(MetaClass* mc = try_as<MetaClass>(original->klass())) { - LookupTable* source_methods = mc->method_table()->dup(state); - LookupTable* source_constants = mc->constants()->dup(state); + Object* Object::copy_metaclass(STATE, Object* other) { + if(MetaClass* mc = try_as<MetaClass>(other->klass())) { + LookupTable* source_methods = mc->method_table()->duplicate(state); + LookupTable* source_constants = mc->constants()->duplicate(state); - this->metaclass(state)->method_table(state, source_methods); - this->metaclass(state)->constants(state, source_constants); + metaclass(state)->method_table(state, source_methods); + metaclass(state)->constants(state, source_constants); // This allows us to preserve included modules - this->metaclass(state)->superclass(state, mc->superclass()); + metaclass(state)->superclass(state, mc->superclass()); } - } - Object* Object::dup(STATE) { - Object* other = state->om->allocate_object(this->total_size(state)); - -#ifdef RBX_GC_STATS - // This counter is only valid if the line above allocates in the - // young object space. - stats::GCStats::get()->young_object_types[this->type_id()]++; -#endif + return this; + } - other->initialize_copy(this, age); - other->copy_body(state, this); + Object* Object::copy_header(STATE, Object* other) { + initialize_copy(other, age); - // Set the dup's class this's class - other->klass(state, class_object(state)); + // Ensure that the metaclass is not shared + klass(state, other->class_object(state)); // HACK: If other is mature, remember it. // We could inspect inspect the references we just copied to see @@ -93,19 +91,19 @@ namespace rubinius { // then remember other. The up side to just remembering it like // this is that other is rarely mature, and the remember_set is // flushed on each collection anyway. - if(other->zone == MatureObjectZone) { - state->om->remember_object(other); + if(zone == MatureObjectZone) { + state->om->remember_object(this); } // Copy ivars. - if(ivars_->reference_p()) { + if(other->ivars_->reference_p()) { // NOTE Don't combine these 2 branches even though they both just call - // ::dup. There is a special LookupTable::dup that can only be seen + // ::copy. There is a special LookupTable::copy that can only be seen // when the receiver is of LookupTable* type. Without the explicit cast // and call, the wrong one will be called. - if(LookupTable* lt = try_as<LookupTable>(ivars_)) { - other->ivars_ = lt->dup(state); - LookupTable* ld = as<LookupTable>(other->ivars_); + if(LookupTable* lt = try_as<LookupTable>(other->ivars_)) { + ivars_ = lt->duplicate(state); + LookupTable* ld = as<LookupTable>(ivars_); // We store the object_id in the ivar table, so nuke it. ld->remove(state, G(sym_object_id)); @@ -113,9 +111,9 @@ namespace rubinius { } else { // Use as<> so that we throw a TypeError if there is something else // here. - CompactLookupTable* clt = as<CompactLookupTable>(ivars_); - other->ivars_ = clt->dup(state); - CompactLookupTable* ld = as<CompactLookupTable>(other->ivars_); + CompactLookupTable* clt = as<CompactLookupTable>(other->ivars_); + ivars_ = clt->duplicate(state); + CompactLookupTable* ld = as<CompactLookupTable>(ivars_); // We store the object_id in the ivar table, so nuke it. ld->remove(state, G(sym_object_id)); @@ -123,7 +121,7 @@ namespace rubinius { }; } - return other; + return this; } Object* Object::equal(STATE, Object* other) { diff --git a/vm/builtin/object.hpp b/vm/builtin/object.hpp index 8a1cc72..e01c08b 100644 --- a/vm/builtin/object.hpp +++ b/vm/builtin/object.hpp @@ -108,17 +108,38 @@ namespace rubinius { public: /* Type information, field access, copy support &c. */ - /** Sets the other Object's flags the same as this. @see vm/oop.hpp. */ - void copy_flags(STATE, Object* other); - /** Copies metaclass from original to this one. @see clone(). */ - void copy_internal_state_from(STATE, Object* original); - /** NOT IMPLEMENTED. Copies instance variables to the other Object. */ - void copy_ivars(STATE, Object* other); - /** NOT IMPLEMENTED. Copies this Object's MetaClass to the other Object. */ - void copy_metaclass(STATE, Object* other); + /** + * Returns a copy of this object. This is NOT the same as Ruby + * Object#dup. Code that needs Object#dup semantics MUST call + * #dup from Ruby. This method is used in the VM to duplicate + * data structures. It will not call the Ruby allocate() or + * initialize_copy() methods. + */ + Object* duplicate(STATE); + + /** + * Copies the header and instance variables from other. Called + * by Kernel#dup. + */ + // Ruby.primitive :object_copy_header + Object* copy_header(STATE, Object* other); + + /** + * Copies the entire object by first calling copy_header and + * then copying the body. Called by ByteArray#dup and Tuple#dup. + */ + // Ruby.primitive :object_copy_object + Object* copy_object(STATE, Object* other); + + /** + * Copies this Object's MetaClass to the other Object. Called + * by Kernel#clone. + */ + // Ruby.primitive :object_copy_metaclass + Object* copy_metaclass(STATE, Object* other); /** True if this Object* is actually a Fixnum, false otherwise. */ - bool fixnum_p() const; + bool fixnum_p() const; /** * Retrieve the Object stored in given field index of this Object. @@ -175,33 +196,11 @@ namespace rubinius { // Ruby.primitive :object_change_class_to Object* change_class_to(STATE, Class* other_klass); - /** - * Ruby #clone. - * - * Creates and returns a new Object that is a copy of this one - * including internal state. - * - * @see dup() - */ - // Ruby.primitive :object_clone - Object* clone(STATE); - /** Returns the Class object of which this Object is an instance. */ // Ruby.primitive :object_class Class* class_object(STATE) const; /** - * Ruby #dup. - * - * Creates and returns a new Object that is a copy of this one - * except for internal state. - * - * @see clone() - */ - // Ruby.primitive :object_dup - Object* dup(STATE); - - /** * Ruby #equal?. * * Returns true if and only if this and the other object are diff --git a/vm/builtin/string.cpp b/vm/builtin/string.cpp index 18ec906..c725eaf 100644 --- a/vm/builtin/string.cpp +++ b/vm/builtin/string.cpp @@ -185,7 +185,7 @@ namespace rubinius { String* String::string_dup(STATE) { String* ns; - ns = as<String>(dup(state)); + ns = as<String>(duplicate(state)); ns->shared(state, Qtrue); shared(state, Qtrue); @@ -195,7 +195,7 @@ namespace rubinius { } void String::unshare(STATE) { - data(state, as<ByteArray>(data_->dup(state))); + data(state, as<ByteArray>(data_->duplicate(state))); shared(state, Qfalse); } diff --git a/vm/capi/object.cpp b/vm/capi/object.cpp index 29fefb5..e5d8676 100644 --- a/vm/capi/object.cpp +++ b/vm/capi/object.cpp @@ -130,9 +130,8 @@ extern "C" { VALUE rb_obj_clone(VALUE obj_handle) { NativeMethodEnvironment* env = NativeMethodEnvironment::get(); - Object* object = env->get_object(obj_handle); - - return env->get_handle(object->clone(env->state())); + env->flush_cached_data(false); + return rb_funcall(obj_handle, rb_intern("clone"), 0); } VALUE rb_inspect(VALUE obj_handle) {
This paste will be private.
From the Design Piracy series on my blog: