diff options
Diffstat (limited to 'proc.c')
-rw-r--r-- | proc.c | 44 |
1 files changed, 40 insertions, 4 deletions
@@ -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; } |