summaryrefslogtreecommitdiff
path: root/object.c
diff options
context:
space:
mode:
authorJemma Issroff <jemmaissroff@gmail.com>2022-10-03 11:14:32 -0400
committerAaron Patterson <tenderlove@ruby-lang.org>2022-10-11 08:40:56 -0700
commitad63b668e22e21c352b852f3119ae98a7acf99f1 (patch)
treecdaea65a9cae753a25f521c06d9d6a205085335f /object.c
parent5ffbb2be187681a37f2722ce1d7db4ec5c128464 (diff)
downloadruby-ad63b668e22e21c352b852f3119ae98a7acf99f1.tar.gz
Revert "Revert "This commit implements the Object Shapes technique in CRuby.""
This reverts commit 9a6803c90b817f70389cae10d60b50ad752da48f.
Diffstat (limited to 'object.c')
-rw-r--r--object.c46
1 files changed, 44 insertions, 2 deletions
diff --git a/object.c b/object.c
index c47d9ab3b2..648946beb3 100644
--- a/object.c
+++ b/object.c
@@ -39,6 +39,7 @@
#include "ruby/util.h"
#include "ruby/assert.h"
#include "builtin.h"
+#include "shape.h"
/*!
* \addtogroup object
@@ -271,9 +272,33 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
VALUE *src_buf = ROBJECT_IVPTR(obj);
uint32_t dest_len = ROBJECT_NUMIV(dest);
uint32_t src_len = ROBJECT_NUMIV(obj);
- uint32_t len = dest_len < src_len ? dest_len : src_len;
+ uint32_t max_len = dest_len < src_len ? src_len : dest_len;
- MEMCPY(dest_buf, src_buf, VALUE, len);
+ rb_ensure_iv_list_size(dest, dest_len, max_len);
+
+ dest_len = ROBJECT_NUMIV(dest);
+ uint32_t min_len = dest_len > src_len ? src_len : dest_len;
+
+ if (RBASIC(obj)->flags & ROBJECT_EMBED) {
+ src_buf = ROBJECT(obj)->as.ary;
+
+ // embedded -> embedded
+ if (RBASIC(dest)->flags & ROBJECT_EMBED) {
+ dest_buf = ROBJECT(dest)->as.ary;
+ }
+ // embedded -> extended
+ else {
+ dest_buf = ROBJECT(dest)->as.heap.ivptr;
+ }
+ }
+ // extended -> extended
+ else {
+ RUBY_ASSERT(!(RBASIC(dest)->flags & ROBJECT_EMBED));
+ dest_buf = ROBJECT(dest)->as.heap.ivptr;
+ src_buf = ROBJECT(obj)->as.heap.ivptr;
+ }
+
+ MEMCPY(dest_buf, src_buf, VALUE, min_len);
}
static void
@@ -283,10 +308,23 @@ init_copy(VALUE dest, VALUE obj)
rb_raise(rb_eTypeError, "[bug] frozen object (%s) allocated", rb_obj_classname(dest));
}
RBASIC(dest)->flags &= ~(T_MASK|FL_EXIVAR);
+ // Copies the shape id from obj to dest
RBASIC(dest)->flags |= RBASIC(obj)->flags & (T_MASK|FL_EXIVAR);
rb_copy_wb_protected_attribute(dest, obj);
rb_copy_generic_ivar(dest, obj);
rb_gc_copy_finalizer(dest, obj);
+
+ rb_shape_t *shape_to_set = rb_shape_get_shape(obj);
+
+ // If the object is frozen, the "dup"'d object will *not* be frozen,
+ // so we need to copy the frozen shape's parent to the new object.
+ if (rb_shape_frozen_shape_p(shape_to_set)) {
+ shape_to_set = shape_to_set->parent;
+ }
+
+ // shape ids are different
+ rb_shape_set_shape(dest, shape_to_set);
+
if (RB_TYPE_P(obj, T_OBJECT)) {
rb_obj_copy_ivar(dest, obj);
}
@@ -392,6 +430,9 @@ mutable_obj_clone(VALUE obj, VALUE kwfreeze)
case Qnil:
rb_funcall(clone, id_init_clone, 1, obj);
RBASIC(clone)->flags |= RBASIC(obj)->flags & FL_FREEZE;
+ if (RB_OBJ_FROZEN(obj)) {
+ rb_shape_transition_shape_frozen(clone);
+ }
break;
case Qtrue:
{
@@ -407,6 +448,7 @@ mutable_obj_clone(VALUE obj, VALUE kwfreeze)
argv[1] = freeze_true_hash;
rb_funcallv_kw(clone, id_init_clone, 2, argv, RB_PASS_KEYWORDS);
RBASIC(clone)->flags |= FL_FREEZE;
+ rb_shape_transition_shape_frozen(clone);
break;
}
case Qfalse: