summaryrefslogtreecommitdiff
path: root/struct.c
diff options
context:
space:
mode:
Diffstat (limited to 'struct.c')
-rw-r--r--struct.c21
1 files changed, 13 insertions, 8 deletions
diff --git a/struct.c b/struct.c
index 7a8a642021..3ee4408393 100644
--- a/struct.c
+++ b/struct.c
@@ -835,23 +835,28 @@ rb_struct_transient_heap_evacuate(VALUE obj, int promote)
static VALUE
struct_alloc(VALUE klass)
{
- long n;
- NEWOBJ_OF(st, struct RStruct, klass, T_STRUCT | (RGENGC_WB_PROTECTED_STRUCT ? FL_WB_PROTECTED : 0), sizeof(struct RStruct), 0);
+ long n = num_members(klass);
+ size_t embedded_size = offsetof(struct RStruct, as.ary) + (sizeof(VALUE) * n);
+ VALUE flags = T_STRUCT | (RGENGC_WB_PROTECTED_STRUCT ? FL_WB_PROTECTED : 0);
+
+ if (n > 0 && rb_gc_size_allocatable_p(embedded_size)) {
+ flags |= n << RSTRUCT_EMBED_LEN_SHIFT;
- n = num_members(klass);
+ NEWOBJ_OF(st, struct RStruct, klass, flags, embedded_size, 0);
- if (0 < n && n <= RSTRUCT_EMBED_LEN_MAX) {
- RBASIC(st)->flags &= ~RSTRUCT_EMBED_LEN_MASK;
- RBASIC(st)->flags |= n << RSTRUCT_EMBED_LEN_SHIFT;
rb_mem_clear((VALUE *)st->as.ary, n);
+
+ return (VALUE)st;
}
else {
+ NEWOBJ_OF(st, struct RStruct, klass, flags, embedded_size, 0);
+
st->as.heap.ptr = struct_heap_alloc((VALUE)st, n);
rb_mem_clear((VALUE *)st->as.heap.ptr, n);
st->as.heap.len = n;
- }
- return (VALUE)st;
+ return (VALUE)st;
+ }
}
VALUE