diff options
author | Jo-Philipp Wich <jo@mein.io> | 2022-07-28 11:16:34 +0200 |
---|---|---|
committer | Jo-Philipp Wich <jo@mein.io> | 2022-07-30 00:41:56 +0200 |
commit | 6becc643230180c8985d135007c344a2fa966552 (patch) | |
tree | 5cb50af01baf46af4a985239a0b8d5fc0392029c /vm.c | |
parent | 341896786c604d3f37e3095cdef16d786192f014 (diff) |
vm: transparently resolve upvalue references
Resolve upvalue references to their actual values when pushing such
references onto the stack (or when attempting to call them as method).
This allows constructing objects of pointers, as needed for wildcard
module imports.
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
Diffstat (limited to 'vm.c')
-rw-r--r-- | vm.c | 31 |
1 files changed, 27 insertions, 4 deletions
@@ -363,20 +363,43 @@ uc_vm_frame_dump(uc_vm_t *vm, uc_callframe_t *frame) } } +static uc_value_t * +uc_vm_resolve_upval(uc_vm_t *vm, uc_value_t *value) +{ + uc_upvalref_t *ref; + +#ifdef __clang_analyzer__ + /* Clang static analyzer does not understand that ucv_type(NULL) can't + * possibly yield UC_UPVALUE. Nudge it. */ + if (value != NULL && ucv_type(value) == UC_UPVALUE) +#else + if (ucv_type(value) == UC_UPVALUE) +#endif + { + ref = (uc_upvalref_t *)value; + + if (ref->closed) + return ucv_get(ref->value); + else + return ucv_get(vm->stack.entries[ref->slot]); + } + + return value; +} + void uc_vm_stack_push(uc_vm_t *vm, uc_value_t *value) { uc_vector_grow(&vm->stack); ucv_put(vm->stack.entries[vm->stack.count]); - - vm->stack.entries[vm->stack.count] = value; + vm->stack.entries[vm->stack.count] = uc_vm_resolve_upval(vm, value); vm->stack.count++; if (vm->trace) { fprintf(stderr, " [+%zd] %s\n", vm->stack.count - 1, - uc_vm_format_val(vm, value)); + uc_vm_format_val(vm, vm->stack.entries[vm->stack.count - 1])); } } @@ -2230,7 +2253,7 @@ uc_vm_insn_mcall(uc_vm_t *vm, uc_vm_insn_t insn) size_t key_slot = vm->stack.count - (vm->arg.u32 & 0xffff) - 1; uc_value_t *ctx = vm->stack.entries[key_slot - 1]; uc_value_t *key = vm->stack.entries[key_slot]; - uc_value_t *fno = ucv_key_get(vm, ctx, key); + uc_value_t *fno = uc_vm_resolve_upval(vm, ucv_key_get(vm, ctx, key)); if (!ucv_is_callable(fno) && insn == I_QMCALL) return uc_vm_skip_call(vm, true); |