swiftwasm / swift

WebAssembly support for the Swift programming language
https://swiftwasm.org
1.32k stars 28 forks source link

Fix `indirect call type mismatch` #30

Closed kateinoigakukun closed 4 years ago

kateinoigakukun commented 4 years ago

Now, most of test cases that depends on StdlibUnittest fails due to same error.

Environment: wasmtime 0.8.0

Caused by:
    0: Instantiation failed during setup
    1: Trap occurred while invoking start function: wasm trap: indirect call type mismatch, source location: @c0925

To debug this problem, I'm developing a debugger of wasm at first. This crash may be related with https://github.com/swiftwasm/swift/pull/6 🤔

kateinoigakukun commented 4 years ago

Progress report

I developed a WebAssembly debugger kateinoigakukun/wasminspect. If you are interested in fixing test cases, this tool is very useful to investigate.

As far as I investigated, CapturePropagation pass in SILOptimizer omits partial_apply which is emitted for thunk function call.

For example,


sil @main : $@convention(c) (Builtin.Int32, Builtin.RawPointer) -> Builtin.Int32 {
bb0(%c : $Builtin.Int32, %v : $Builtin.RawPointer):
  // function_ref createInstance()
  %1 = function_ref @$s5Katei14createInstanceAA1SVSgyF : $@convention(thin) () -> Optional<S> // user: %3
  // function_ref thunk for @escaping @convention(thin) () -> (@unowned S?)
  %2 = function_ref @$s5Katei1SVSgIetd_ADIegd_TR : $@convention(thin) (@convention(thin) () -> Optional<S>) -> Optional<S> // user: %3
  %3 = partial_apply [callee_guaranteed] [on_stack] %2(%1) : $@convention(thin) (@convention(thin) () -> Optional<S>) -> Optional<S> // users: %5, %9
}

this SIL is optimized to be that.


sil @main : $@convention(c) (Builtin.Int32, Builtin.RawPointer) -> Builtin.Int32 {
bb0(%c : $Builtin.Int32, %v : $Builtin.RawPointer):
  // function_ref specialized thunk for @callee_guaranteed () -> (@unowned S?)
  %1 = function_ref @$s5Katei1SVSgIgd_ADIegr_TR69$s5Katei1SVSgIetd_ADIegd_TR33$s5Katei14createInstanceAA1SVSgyFTf3pf_nTf3npf_n : $@convention(thin) @noescape () -> @out Optional<S> // user: %2
  %2 = thin_to_thick_function %3 : $@convention(thin) @noescape () -> @out Optional<S> to $@noescape @callee_guaranteed () -> @out Optional<S>
}

// specialized thunk for @callee_guaranteed () -> (@unowned S?)
sil shared [transparent] [reabstraction_thunk] @$s5Katei1SVSgIgd_ADIegr_TR69$s5Katei1SVSgIetd_ADIegd_TR33$s5Katei14createInstanceAA1SVSgyFTf3pf_nTf3npf_n : $@convention(thin) @noescape () -> @out Optional<S> {
// %0                                             // user: %5
bb0(%0 : $*Optional<S>):
  // function_ref createInstance()
  %1 =  function_ref @$s5Katei14createInstanceAA1SVSgyF : $@convention(thin) () -> Optional<S> // user: %3
  %2 = apply %1() : $@convention(method) () -> S // user: %3
  %3 = enum $Optional<S>, #Optional.some!enumelt.1, %2 : $S // user: %4
  store %3 to %0 : $*Optional<S>                  // id: %4
  %5 = tuple ()                                   // user: %6
  return %5 : $()                                 // id: %6
} // end sil function '$s5Katei1SVSgIgd_ADIegr_TR69$s5Katei1SVSgIetd_ADIegd_TR33$s5Katei14createInstanceAA1SVSgyFTf3pf_nTf3npf_n'

This means thin_to_thick_function should emit LLVM IR level thunk function through IRGen module.

If -Onone is set, most of stdlib test cases are passed 😜