summaryrefslogtreecommitdiffhomepage
path: root/vm.c
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2022-07-28 11:16:34 +0200
committerJo-Philipp Wich <jo@mein.io>2022-07-30 00:41:56 +0200
commit6becc643230180c8985d135007c344a2fa966552 (patch)
tree5cb50af01baf46af4a985239a0b8d5fc0392029c /vm.c
parent341896786c604d3f37e3095cdef16d786192f014 (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.c31
1 files changed, 27 insertions, 4 deletions
diff --git a/vm.c b/vm.c
index d0fe80e..61fc7f3 100644
--- a/vm.c
+++ b/vm.c
@@ -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);