summaryrefslogtreecommitdiff
path: root/proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'proc.c')
-rw-r--r--proc.c44
1 files changed, 40 insertions, 4 deletions
diff --git a/proc.c b/proc.c
index 95b0d04791..d3f96d703a 100644
--- a/proc.c
+++ b/proc.c
@@ -680,6 +680,29 @@ cfunc_proc_new(VALUE klass, VALUE ifunc)
return procval;
}
+VALUE
+rb_func_proc_dup(VALUE src_obj)
+{
+ RUBY_ASSERT(rb_typeddata_is_instance_of(src_obj, &proc_data_type));
+
+ rb_proc_t *src_proc;
+ GetProcPtr(src_obj, src_proc);
+ RUBY_ASSERT(vm_block_type(&src_proc->block) == block_type_ifunc);
+
+ cfunc_proc_t *proc;
+ VALUE proc_obj = TypedData_Make_Struct(rb_obj_class(src_obj), cfunc_proc_t, &proc_data_type, proc);
+
+ memcpy(&proc->basic, src_proc, sizeof(rb_proc_t));
+
+ VALUE *ep = *(VALUE **)&proc->basic.block.as.captured.ep = proc->env + VM_ENV_DATA_SIZE - 1;
+ ep[VM_ENV_DATA_INDEX_FLAGS] = src_proc->block.as.captured.ep[VM_ENV_DATA_INDEX_FLAGS];
+ ep[VM_ENV_DATA_INDEX_ME_CREF] = src_proc->block.as.captured.ep[VM_ENV_DATA_INDEX_ME_CREF];
+ ep[VM_ENV_DATA_INDEX_SPECVAL] = src_proc->block.as.captured.ep[VM_ENV_DATA_INDEX_SPECVAL];
+ ep[VM_ENV_DATA_INDEX_ENV] = src_proc->block.as.captured.ep[VM_ENV_DATA_INDEX_ENV];
+
+ return proc_obj;
+}
+
static VALUE
sym_proc_new(VALUE klass, VALUE sym)
{
@@ -1311,12 +1334,17 @@ proc_eq(VALUE self, VALUE other)
}
break;
case block_type_ifunc:
- if (self_block->as.captured.ep != \
- other_block->as.captured.ep ||
- self_block->as.captured.code.ifunc != \
+ if (self_block->as.captured.code.ifunc != \
other_block->as.captured.code.ifunc) {
return Qfalse;
}
+
+ if (memcmp(
+ ((cfunc_proc_t *)self_proc)->env,
+ ((cfunc_proc_t *)other_proc)->env,
+ sizeof(((cfunc_proc_t *)self_proc)->env))) {
+ return Qfalse;
+ }
break;
case block_type_proc:
if (self_block->as.proc != other_block->as.proc) {
@@ -1445,6 +1473,7 @@ rb_hash_proc(st_index_t hash, VALUE prc)
break;
case block_type_ifunc:
hash = rb_st_hash_uint(hash, (st_index_t)proc->block.as.captured.code.ifunc->func);
+ hash = rb_st_hash_uint(hash, (st_index_t)proc->block.as.captured.code.ifunc->data);
break;
case block_type_symbol:
hash = rb_st_hash_uint(hash, rb_any_hash(proc->block.as.symbol));
@@ -1456,7 +1485,14 @@ rb_hash_proc(st_index_t hash, VALUE prc)
rb_bug("rb_hash_proc: unknown block type %d", vm_block_type(&proc->block));
}
- return rb_hash_uint(hash, (st_index_t)proc->block.as.captured.ep);
+ /* ifunc procs have their own allocated ep. If an ifunc is duplicated, they
+ * will point to different ep but they should return the same hash code, so
+ * we cannot include the ep in the hash. */
+ if (vm_block_type(&proc->block) != block_type_ifunc) {
+ hash = rb_hash_uint(hash, (st_index_t)proc->block.as.captured.ep);
+ }
+
+ return hash;
}