summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--compiler.c16
-rw-r--r--tests/custom/04_bugs/11_switch_stack_mismatch27
2 files changed, 42 insertions, 1 deletions
diff --git a/compiler.c b/compiler.c
index e5a294a..7a533f5 100644
--- a/compiler.c
+++ b/compiler.c
@@ -2475,7 +2475,7 @@ out:
static void
uc_compiler_compile_switch(uc_compiler_t *compiler)
{
- size_t i, test_jmp, skip_jmp, next_jmp, value_slot, default_off = 0;
+ size_t i, test_jmp, skip_jmp, next_jmp = 0, value_slot, default_off = 0;
uc_chunk_t *chunk = uc_compiler_current_chunk(compiler);
uc_patchlist_t p = { .depth = compiler->scope_depth };
uc_locals_t *locals = &compiler->locals;
@@ -2628,6 +2628,10 @@ uc_compiler_compile_switch(uc_compiler_t *compiler)
/* jump to target */
uc_compiler_emit_jmp_dest(compiler, 0, cases.entries[default_off + 2]);
+
+ /* do not patch final match failure jump later, we handle it here
+ * in the default case */
+ next_jmp = 0;
}
uc_compiler_set_jmpaddr(compiler, skip_jmp, chunk->count);
@@ -2640,6 +2644,16 @@ uc_compiler_compile_switch(uc_compiler_t *compiler)
uc_compiler_leave_scope(compiler);
+ /* if no default case exists, patch last case match failure jump */
+ if (next_jmp) {
+ /* There's pop instructions for all local variables including the
+ * switch test value itself on the stack. Jump onto the last POP
+ * instruction (-1) to get rid of the on-stack switch test value
+ * but skip the POP instructions for all other scoped local variables
+ * which never have been initialized. */
+ uc_compiler_set_jmpaddr(compiler, next_jmp, chunk->count - 1);
+ }
+
uc_compiler_backpatch(compiler, chunk->count, 0);
}
diff --git a/tests/custom/04_bugs/11_switch_stack_mismatch b/tests/custom/04_bugs/11_switch_stack_mismatch
index cc3b41a..0cf82f0 100644
--- a/tests/custom/04_bugs/11_switch_stack_mismatch
+++ b/tests/custom/04_bugs/11_switch_stack_mismatch
@@ -37,3 +37,30 @@ Matching 3:
}
%}
-- End --
+
+-- Expect stdout --
+Matching 1:
+Matching 2:
+ - 2: [ 3, 4 ]
+ - 3: [ 3, 4, 5, 6 ]
+Matching 3:
+ - 3: [ null, null, 5, 6 ]
+-- End --
+
+-- Testcase --
+{%
+ for (let n in [1, 2, 3]) {
+ printf("Matching %d:\n", n);
+
+ switch (n) {
+ case 2:
+ let a = 3, b = 4;
+ print(" - 2: ", [a, b], "\n");
+
+ case 3:
+ let c = 5, d = 6;
+ print(" - 3: ", [a, b, c, d], "\n");
+ }
+ }
+%}
+-- End --