Fix tail-call handling in interpreter and wasm2c (#2563)

diff --git a/src/c-writer.cc b/src/c-writer.cc
index 9370dbd..656377f 100644
--- a/src/c-writer.cc
+++ b/src/c-writer.cc
@@ -1931,7 +1931,7 @@
     Index num_results = func.GetNumResults();
     if (num_params >= 1) {
       Write(func.decl.sig.param_types, " params;", Newline());
-      Write("wasm_rt_memcpy(params, tail_call_stack, sizeof(params));",
+      Write("wasm_rt_memcpy(&params, tail_call_stack, sizeof(params));",
             Newline());
     }
 
@@ -4201,7 +4201,7 @@
 
         Write("next->fn = ", TailCallRef(func.name), ";", Newline());
         if (IsImport(func.name)) {
-          Write("*instance_ptr = ",
+          Write("*instance_ptr = instance->",
                 GlobalName(ModuleFieldType::Import,
                            import_module_sym_map_.at(func.name)),
                 ";", Newline());
diff --git a/src/interp/binary-reader-interp.cc b/src/interp/binary-reader-interp.cc
index 10b5a7d..9eb54d4 100644
--- a/src/interp/binary-reader-interp.cc
+++ b/src/interp/binary-reader-interp.cc
@@ -831,7 +831,10 @@
   depth_fixups_.Clear();
   label_stack_.clear();
 
-  func_fixups_.Resolve(istream_, defined_index);
+  // The fixups map is keyed by actual function index (not defined_index)
+  // (function imports don't have code and won't appear in the fixups map,
+  // but they still use function indexes)
+  func_fixups_.Resolve(istream_, index);
 
   CHECK_RESULT(validator_.BeginFunctionBody(GetLocation(), index));
 
diff --git a/test/spec/tail-call/return_call.txt b/test/spec/tail-call/return_call.txt
index 74145cd..246db8a 100644
--- a/test/spec/tail-call/return_call.txt
+++ b/test/spec/tail-call/return_call.txt
@@ -1,36 +1,40 @@
 ;;; TOOL: run-interp-spec
-;;; STDIN_FILE: third_party/testsuite/proposals/tail-call/return_call.wast
+;;; STDIN_FILE: third_party/testsuite/proposals/wasm-3.0/return_call.wast
 ;;; ARGS*: --enable-tail-call
 (;; STDOUT ;;;
-out/test/spec/tail-call/return_call.wast:124: assert_invalid passed:
+called host spectest.print_i32_f32(i32:5, f32:91.000000) =>
+out/test/spec/tail-call/return_call.wast:141: assert_invalid passed:
   out/test/spec/tail-call/return_call/return_call.1.wasm:000001e: error: return signatures have inconsistent types: expected [i32], got []
   000001e: error: OnReturnCallExpr callback failed
-out/test/spec/tail-call/return_call.wast:131: assert_invalid passed:
+out/test/spec/tail-call/return_call.wast:148: assert_invalid passed:
   out/test/spec/tail-call/return_call/return_call.2.wasm:000001f: error: return signatures have inconsistent types: expected [i32], got [i64]
   000001f: error: OnReturnCallExpr callback failed
-out/test/spec/tail-call/return_call.wast:139: assert_invalid passed:
+out/test/spec/tail-call/return_call.wast:156: assert_invalid passed:
   out/test/spec/tail-call/return_call/return_call.3.wasm:000001e: error: type mismatch in return_call, expected [i32] but got []
   000001e: error: OnReturnCallExpr callback failed
-out/test/spec/tail-call/return_call.wast:146: assert_invalid passed:
+out/test/spec/tail-call/return_call.wast:163: assert_invalid passed:
   out/test/spec/tail-call/return_call/return_call.4.wasm:000001f: error: type mismatch in return_call, expected [f64, i32] but got []
   000001f: error: OnReturnCallExpr callback failed
-out/test/spec/tail-call/return_call.wast:164: assert_invalid passed:
+out/test/spec/tail-call/return_call.wast:181: assert_invalid passed:
   out/test/spec/tail-call/return_call/return_call.7.wasm:0000022: error: type mismatch in return_call, expected [i32, i32] but got [i32]
   0000022: error: OnReturnCallExpr callback failed
-out/test/spec/tail-call/return_call.wast:171: assert_invalid passed:
+out/test/spec/tail-call/return_call.wast:188: assert_invalid passed:
   out/test/spec/tail-call/return_call/return_call.8.wasm:0000022: error: type mismatch in return_call, expected [i32, i32] but got [i32]
   0000022: error: OnReturnCallExpr callback failed
-out/test/spec/tail-call/return_call.wast:178: assert_invalid passed:
+out/test/spec/tail-call/return_call.wast:195: assert_invalid passed:
   out/test/spec/tail-call/return_call/return_call.9.wasm:000002a: error: type mismatch in return_call, expected [i32, f64] but got [f64, i32]
   000002a: error: OnReturnCallExpr callback failed
-out/test/spec/tail-call/return_call.wast:185: assert_invalid passed:
+out/test/spec/tail-call/return_call.wast:202: assert_invalid passed:
   out/test/spec/tail-call/return_call/return_call.10.wasm:000002a: error: type mismatch in return_call, expected [f64, i32] but got [i32, f64]
   000002a: error: OnReturnCallExpr callback failed
-out/test/spec/tail-call/return_call.wast:196: assert_invalid passed:
-  out/test/spec/tail-call/return_call/return_call.11.wasm:0000019: error: function variable out of range: 1 (max 1)
+out/test/spec/tail-call/return_call.wast:209: assert_invalid passed:
+  out/test/spec/tail-call/return_call/return_call.11.wasm:0000024: error: return signatures have inconsistent types: expected [i32], got [i32, i32]
+  0000024: error: OnReturnCallExpr callback failed
+out/test/spec/tail-call/return_call.wast:221: assert_invalid passed:
+  out/test/spec/tail-call/return_call/return_call.12.wasm:0000019: error: function variable out of range: 1 (max 1)
   0000019: error: OnReturnCallExpr callback failed
-out/test/spec/tail-call/return_call.wast:200: assert_invalid passed:
-  out/test/spec/tail-call/return_call/return_call.12.wasm:000001d: error: function variable out of range: 1012321300 (max 1)
+out/test/spec/tail-call/return_call.wast:225: assert_invalid passed:
+  out/test/spec/tail-call/return_call/return_call.13.wasm:000001d: error: function variable out of range: 1012321300 (max 1)
   000001d: error: OnReturnCallExpr callback failed
-44/44 tests passed.
+47/47 tests passed.
 ;;; STDOUT ;;)
diff --git a/test/spec/tail-call/return_call_indirect.txt b/test/spec/tail-call/return_call_indirect.txt
index d8b3df7..ee9f852 100644
--- a/test/spec/tail-call/return_call_indirect.txt
+++ b/test/spec/tail-call/return_call_indirect.txt
@@ -1,121 +1,128 @@
 ;;; TOOL: run-interp-spec
-;;; STDIN_FILE: third_party/testsuite/proposals/tail-call/return_call_indirect.wast
+;;; STDIN_FILE: third_party/testsuite/proposals/wasm-3.0/return_call_indirect.wast
 ;;; ARGS*: --enable-tail-call
 (;; STDOUT ;;;
-out/test/spec/tail-call/return_call_indirect.wast:234: assert_trap passed: indirect call signature mismatch
-out/test/spec/tail-call/return_call_indirect.wast:235: assert_trap passed: indirect call signature mismatch
-out/test/spec/tail-call/return_call_indirect.wast:236: assert_trap passed: undefined table index
-out/test/spec/tail-call/return_call_indirect.wast:237: assert_trap passed: undefined table index
-out/test/spec/tail-call/return_call_indirect.wast:238: assert_trap passed: undefined table index
-out/test/spec/tail-call/return_call_indirect.wast:244: assert_trap passed: indirect call signature mismatch
-out/test/spec/tail-call/return_call_indirect.wast:245: assert_trap passed: indirect call signature mismatch
-out/test/spec/tail-call/return_call_indirect.wast:273: assert_malformed passed:
+out/test/spec/tail-call/return_call_indirect.wast:260: assert_trap passed: indirect call signature mismatch
+out/test/spec/tail-call/return_call_indirect.wast:261: assert_trap passed: indirect call signature mismatch
+out/test/spec/tail-call/return_call_indirect.wast:262: assert_trap passed: undefined table index
+out/test/spec/tail-call/return_call_indirect.wast:263: assert_trap passed: undefined table index
+out/test/spec/tail-call/return_call_indirect.wast:264: assert_trap passed: undefined table index
+out/test/spec/tail-call/return_call_indirect.wast:270: assert_trap passed: indirect call signature mismatch
+out/test/spec/tail-call/return_call_indirect.wast:271: assert_trap passed: indirect call signature mismatch
+called host spectest.print_i32_f32(i32:5, f32:91.000000) =>
+out/test/spec/tail-call/return_call_indirect.wast:301: assert_malformed passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.1.wat:1:129: error: unexpected token "param", expected an expr.
   ...indirect (type $sig) (result i32) (param i32)    (i32.const 0) (i32.const ...
                                         ^^^^^
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.1.wat:1:173: error: unexpected token ), expected EOF.
   ...irect (type $sig) (result i32) (param i32)    (i32.const 0) (i32.const 0)  ))
                                                                                  ^
-out/test/spec/tail-call/return_call_indirect.wast:285: assert_malformed passed:
+out/test/spec/tail-call/return_call_indirect.wast:313: assert_malformed passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.2.wat:1:116: error: unexpected token "type", expected an expr.
   ...(return_call_indirect (param i32) (type $sig) (result i32)    (i32.const 0...
                                         ^^^^
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.2.wat:1:173: error: unexpected token ), expected EOF.
   ...irect (param i32) (type $sig) (result i32)    (i32.const 0) (i32.const 0)  ))
                                                                                  ^
-out/test/spec/tail-call/return_call_indirect.wast:297: assert_malformed passed:
+out/test/spec/tail-call/return_call_indirect.wast:325: assert_malformed passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.3.wat:1:129: error: unexpected token "type", expected an expr.
   ...indirect (param i32) (result i32) (type $sig)    (i32.const 0) (i32.const ...
                                         ^^^^
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.3.wat:1:173: error: unexpected token ), expected EOF.
   ...irect (param i32) (result i32) (type $sig)    (i32.const 0) (i32.const 0)  ))
                                                                                  ^
-out/test/spec/tail-call/return_call_indirect.wast:309: assert_malformed passed:
+out/test/spec/tail-call/return_call_indirect.wast:337: assert_malformed passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.4.wat:1:117: error: unexpected token "type", expected an expr.
   ...return_call_indirect (result i32) (type $sig) (param i32)    (i32.const 0)...
                                         ^^^^
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.4.wat:1:173: error: unexpected token ), expected EOF.
   ...irect (result i32) (type $sig) (param i32)    (i32.const 0) (i32.const 0)  ))
                                                                                  ^
-out/test/spec/tail-call/return_call_indirect.wast:321: assert_malformed passed:
+out/test/spec/tail-call/return_call_indirect.wast:349: assert_malformed passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.5.wat:1:117: error: unexpected token "param", expected an expr.
   ...return_call_indirect (result i32) (param i32) (type $sig)    (i32.const 0)...
                                         ^^^^^
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.5.wat:1:173: error: unexpected token ), expected EOF.
   ...irect (result i32) (param i32) (type $sig)    (i32.const 0) (i32.const 0)  ))
                                                                                  ^
-out/test/spec/tail-call/return_call_indirect.wast:333: assert_malformed passed:
+out/test/spec/tail-call/return_call_indirect.wast:361: assert_malformed passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.6.wat:1:74: error: unexpected token "param", expected an expr.
   ...return_call_indirect (result i32) (param i32)    (i32.const 0) (i32.const ...
                                         ^^^^^
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.6.wat:1:118: error: unexpected token ), expected EOF.
   ...urn_call_indirect (result i32) (param i32)    (i32.const 0) (i32.const 0)  ))
                                                                                  ^
-out/test/spec/tail-call/return_call_indirect.wast:345: assert_malformed passed:
+out/test/spec/tail-call/return_call_indirect.wast:373: assert_malformed passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.7.wat:1:53: error: unexpected token $x, expected ).
   ...cref)(func (return_call_indirect (param $x i32) (i32.const 0) (i32.const 0)))
                                              ^^
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.7.wat:1:89: error: unexpected token ), expected EOF.
   ...cref)(func (return_call_indirect (param $x i32) (i32.const 0) (i32.const 0)))
                                                                                  ^
-out/test/spec/tail-call/return_call_indirect.wast:352: assert_malformed passed:
+out/test/spec/tail-call/return_call_indirect.wast:380: assert_malformed passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.8.wat:1:57: error: expected 0 results, got 1
   ...ncref)(func (result i32)  (return_call_indirect (type $sig) (result i32) (...
                                 ^^^^^^^^^^^^^^^^^^^^
-out/test/spec/tail-call/return_call_indirect.wast:362: assert_malformed passed:
+out/test/spec/tail-call/return_call_indirect.wast:390: assert_malformed passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.9.wat:1:82: error: expected 1 arguments, got 0
   ...ncref)(func (result i32)  (return_call_indirect (type $sig) (result i32) (...
                                 ^^^^^^^^^^^^^^^^^^^^
-out/test/spec/tail-call/return_call_indirect.wast:372: assert_malformed passed:
+out/test/spec/tail-call/return_call_indirect.wast:400: assert_malformed passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.10.wat:1:69: error: expected 1 results, got 0
   ...))(table 0 funcref)(func  (return_call_indirect (type $sig) (param i32)   ...
                                 ^^^^^^^^^^^^^^^^^^^^
-out/test/spec/tail-call/return_call_indirect.wast:384: assert_malformed passed:
+out/test/spec/tail-call/return_call_indirect.wast:412: assert_malformed passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.11.wat:1:86: error: expected 2 arguments, got 1
   ...ncref)(func (result i32)  (return_call_indirect (type $sig) (param i32) (r...
                                 ^^^^^^^^^^^^^^^^^^^^
-out/test/spec/tail-call/return_call_indirect.wast:399: assert_invalid passed:
+out/test/spec/tail-call/return_call_indirect.wast:427: assert_invalid passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.12.wasm:000001c: error: table variable out of range: 0 (max 0)
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.12.wasm:000001c: error: type mismatch: return_call_indirect must reference table of funcref type
   000001c: error: OnReturnCallIndirectExpr callback failed
-out/test/spec/tail-call/return_call_indirect.wast:407: assert_invalid passed:
+out/test/spec/tail-call/return_call_indirect.wast:435: assert_invalid passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.13.wasm:0000024: error: type mismatch at end of function, expected [] but got [i32]
   0000024: error: EndFunctionBody callback failed
-out/test/spec/tail-call/return_call_indirect.wast:415: assert_invalid passed:
+out/test/spec/tail-call/return_call_indirect.wast:443: assert_invalid passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.14.wasm:0000026: error: return signatures have inconsistent types: expected [], got [i64]
   0000026: error: OnReturnCallIndirectExpr callback failed
-out/test/spec/tail-call/return_call_indirect.wast:424: assert_invalid passed:
+out/test/spec/tail-call/return_call_indirect.wast:452: assert_invalid passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.15.wasm:0000026: error: type mismatch in return_call_indirect, expected [i32] but got []
   0000026: error: OnReturnCallIndirectExpr callback failed
-out/test/spec/tail-call/return_call_indirect.wast:432: assert_invalid passed:
+out/test/spec/tail-call/return_call_indirect.wast:460: assert_invalid passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.16.wasm:0000027: error: type mismatch in return_call_indirect, expected [f64, i32] but got []
   0000027: error: OnReturnCallIndirectExpr callback failed
-out/test/spec/tail-call/return_call_indirect.wast:455: assert_invalid passed:
+out/test/spec/tail-call/return_call_indirect.wast:483: assert_invalid passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.19.wasm:0000027: error: type mismatch in return_call_indirect, expected [i32] but got []
   0000027: error: OnReturnCallIndirectExpr callback failed
-out/test/spec/tail-call/return_call_indirect.wast:463: assert_invalid passed:
+out/test/spec/tail-call/return_call_indirect.wast:491: assert_invalid passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.20.wasm:0000028: error: type mismatch in return_call_indirect, expected [i32] but got [... i64]
   0000028: error: OnReturnCallIndirectExpr callback failed
-out/test/spec/tail-call/return_call_indirect.wast:472: assert_invalid passed:
+out/test/spec/tail-call/return_call_indirect.wast:500: assert_invalid passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.21.wasm:000002a: error: type mismatch in return_call_indirect, expected [i32, i32] but got [i32]
   000002a: error: OnReturnCallIndirectExpr callback failed
-out/test/spec/tail-call/return_call_indirect.wast:482: assert_invalid passed:
+out/test/spec/tail-call/return_call_indirect.wast:510: assert_invalid passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.22.wasm:000002a: error: type mismatch in return_call_indirect, expected [i32, i32] but got [i32]
   000002a: error: OnReturnCallIndirectExpr callback failed
-out/test/spec/tail-call/return_call_indirect.wast:492: assert_invalid passed:
+out/test/spec/tail-call/return_call_indirect.wast:520: assert_invalid passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.23.wasm:0000032: error: type mismatch in return_call_indirect, expected [i32, f64] but got [f64, i32]
   0000032: error: OnReturnCallIndirectExpr callback failed
-out/test/spec/tail-call/return_call_indirect.wast:502: assert_invalid passed:
+out/test/spec/tail-call/return_call_indirect.wast:530: assert_invalid passed:
   out/test/spec/tail-call/return_call_indirect/return_call_indirect.24.wasm:0000032: error: type mismatch in return_call_indirect, expected [f64, i32] but got [i32, f64]
   0000032: error: OnReturnCallIndirectExpr callback failed
-out/test/spec/tail-call/return_call_indirect.wast:516: assert_invalid passed:
-  out/test/spec/tail-call/return_call_indirect/return_call_indirect.25.wasm:0000022: error: function type variable out of range: 1 (max 1)
+out/test/spec/tail-call/return_call_indirect.wast:540: assert_invalid passed:
+  out/test/spec/tail-call/return_call_indirect/return_call_indirect.25.wasm:0000034: error: return signatures have inconsistent types: expected [i32], got [i32, i32]
+  0000034: error: OnReturnCallIndirectExpr callback failed
+out/test/spec/tail-call/return_call_indirect.wast:553: assert_invalid passed:
+  out/test/spec/tail-call/return_call_indirect/return_call_indirect.26.wasm:0000022: error: type mismatch: return_call_indirect must reference table of funcref type
   0000022: error: OnReturnCallIndirectExpr callback failed
-out/test/spec/tail-call/return_call_indirect.wast:523: assert_invalid passed:
-  out/test/spec/tail-call/return_call_indirect/return_call_indirect.26.wasm:0000026: error: function type variable out of range: 1012321300 (max 1)
+out/test/spec/tail-call/return_call_indirect.wast:564: assert_invalid passed:
+  out/test/spec/tail-call/return_call_indirect/return_call_indirect.27.wasm:0000022: error: function type variable out of range: 1 (max 1)
+  0000022: error: OnReturnCallIndirectExpr callback failed
+out/test/spec/tail-call/return_call_indirect.wast:571: assert_invalid passed:
+  out/test/spec/tail-call/return_call_indirect/return_call_indirect.28.wasm:0000026: error: function type variable out of range: 1012321300 (max 1)
   0000026: error: OnReturnCallIndirectExpr callback failed
-out/test/spec/tail-call/return_call_indirect.wast:534: assert_invalid passed:
-  out/test/spec/tail-call/return_call_indirect/return_call_indirect.27.wasm:0000018: error: function variable out of range: 0 (max 0)
+out/test/spec/tail-call/return_call_indirect.wast:582: assert_invalid passed:
+  out/test/spec/tail-call/return_call_indirect/return_call_indirect.29.wasm:0000018: error: function variable out of range: 0 (max 0)
   0000018: error: OnRefFuncExpr callback failed
-75/75 tests passed.
+79/79 tests passed.
 ;;; STDOUT ;;)
diff --git a/test/wasm2c/spec/tail-call/return_call.txt b/test/wasm2c/spec/tail-call/return_call.txt
index 6218eea..b12b00b 100644
--- a/test/wasm2c/spec/tail-call/return_call.txt
+++ b/test/wasm2c/spec/tail-call/return_call.txt
@@ -1,6 +1,7 @@
 ;;; TOOL: run-spec-wasm2c
-;;; STDIN_FILE: third_party/testsuite/proposals/tail-call/return_call.wast
+;;; STDIN_FILE: third_party/testsuite/proposals/wasm-3.0/return_call.wast
 ;;; ARGS*: --enable-tail-call
 (;; STDOUT ;;;
-31/31 tests passed.
+spectest.print_i32_f32(5 91)
+33/33 tests passed.
 ;;; STDOUT ;;)
diff --git a/test/wasm2c/spec/tail-call/return_call_indirect.txt b/test/wasm2c/spec/tail-call/return_call_indirect.txt
index 8cf46bd..ceb9a77 100644
--- a/test/wasm2c/spec/tail-call/return_call_indirect.txt
+++ b/test/wasm2c/spec/tail-call/return_call_indirect.txt
@@ -1,6 +1,7 @@
 ;;; TOOL: run-spec-wasm2c
-;;; STDIN_FILE: third_party/testsuite/proposals/tail-call/return_call_indirect.wast
+;;; STDIN_FILE: third_party/testsuite/proposals/wasm-3.0/return_call_indirect.wast
 ;;; ARGS*: --enable-tail-call
 (;; STDOUT ;;;
-47/47 tests passed.
+spectest.print_i32_f32(5 91)
+49/49 tests passed.
 ;;; STDOUT ;;)
diff --git a/test/wasm2c/tail-calls.txt b/test/wasm2c/tail-calls.txt
index c34204b..a8bcc99 100644
--- a/test/wasm2c/tail-calls.txt
+++ b/test/wasm2c/tail-calls.txt
@@ -869,7 +869,7 @@
 {
   next->fn = NULL;
   struct wasm_multi_if params;
-  wasm_rt_memcpy(params, tail_call_stack, sizeof(params));
+  wasm_rt_memcpy(&params, tail_call_stack, sizeof(params));
   w2c_spectest_print_i32_f32(*instance_ptr, params.i0, params.f1);
 }
 
diff --git a/third_party/testsuite b/third_party/testsuite
index cbc54d7..d76759e 160000
--- a/third_party/testsuite
+++ b/third_party/testsuite
@@ -1 +1 @@
-Subproject commit cbc54d77065e5202bcb69e0d1c53ceccc29a7984
+Subproject commit d76759e746f3564a03f6106ae19679742f2a1831