@@ -151,11 +151,6 @@ type Imports struct {
151151 classByName map [string ]* ClassInfo
152152 emval * EmvalTable
153153
154- // dead is set when a WASM call hits a fatal path (_abort, C++ throw,
155- // EM_JS throw) that cannot be recovered. Later calls return deadErr.
156- dead bool
157- deadErr error
158-
159154 // File descriptor state for /dev/urandom emulation
160155 urandomFD uint32
161156 nextFD uint32
@@ -177,26 +172,18 @@ func (imp *Imports) SetModule(m *Module) {
177172 imp .mod = m
178173}
179174
180- // markDead records a fatal WASM error so subsequent calls fail fast.
181- // The first fatal error is retained.
182- func (imp * Imports ) markDead (v any ) {
183- if imp .dead {
184- return
185- }
186- imp .dead = true
187- if err , ok := v .(error ); ok {
188- imp .deadErr = err
189- } else {
190- imp .deadErr = fmt .Errorf ("%v" , v )
191- }
192- }
175+ // wasmException marks a normal exception reported by the embedded module.
176+ type wasmException string
193177
194- // checkDead is the defer target for functions that dispatch into the WASM
195- // module: a fatal panic is converted to the dead- runtime error .
196- func ( imp * Imports ) checkDead (err * error ) {
178+ // recoverError converts ordinary WASM exceptions to errors. An abort or
179+ // unexpected panic may leave the runtime unusable, so propagate it .
180+ func recoverError (err * error ) {
197181 if v := recover (); v != nil {
198- imp .markDead (v )
199- * err = imp .deadErr
182+ if exception , ok := v .(wasmException ); ok {
183+ * err = errors .New (string (exception ))
184+ return
185+ }
186+ panic (v )
200187 }
201188}
202189
@@ -523,7 +510,7 @@ func (imp *Imports) Import_o(p0, p1, p2 uint32) uint32 { // EM_JS dispatcher
523510 if len (args ) >= 2 {
524511 errMsg = imp .readCStr (args [1 ])
525512 }
526- panic (fmt .Sprintf ("ltsm: EM_JS error: %s: %s" , errType , errMsg ))
513+ panic (wasmException ( fmt .Sprintf ("ltsm: EM_JS error: %s: %s" , errType , errMsg ) ))
527514
528515 case 1456985 : // init getRandomValues
529516 return 0
@@ -713,7 +700,7 @@ func (imp *Imports) Import_A(p0, p1 uint32) uint32 { // _emval_get_property
713700}
714701
715702func (imp * Imports ) Import_B (p0 , p1 , p2 uint32 ) { // __cxa_throw
716- panic (fmt .Sprintf ("ltsm: C++ exception thrown (type=%d, ptr=%d)" , p1 , p0 ))
703+ panic (wasmException ( fmt .Sprintf ("ltsm: C++ exception thrown (type=%d, ptr=%d)" , p1 , p0 ) ))
717704}
718705
719706func (imp * Imports ) Import_C (p0 uint32 ) uint32 { // emscripten_resize_heap
@@ -866,9 +853,6 @@ func toFloat64(v any) float64 {
866853
867854// CallMethod calls an embind instance method on a C++ object.
868855func (imp * Imports ) CallMethod (className , methodName string , thisPtr uint32 , args ... uint32 ) (uint32 , error ) {
869- if imp .dead {
870- return 0 , imp .deadErr
871- }
872856 ci := imp .classByName [className ]
873857 if ci == nil {
874858 return 0 , fmt .Errorf ("ltsm: class %q not found" , className )
@@ -897,9 +881,6 @@ func (imp *Imports) CallMethod(className, methodName string, thisPtr uint32, arg
897881
898882// CallStatic calls an embind static method.
899883func (imp * Imports ) CallStatic (className , methodName string , args ... uint32 ) (uint32 , error ) {
900- if imp .dead {
901- return 0 , imp .deadErr
902- }
903884 ci := imp .classByName [className ]
904885 if ci == nil {
905886 return 0 , fmt .Errorf ("ltsm: class %q not found" , className )
@@ -920,9 +901,6 @@ func (imp *Imports) CallStatic(className, methodName string, args ...uint32) (ui
920901
921902// Construct calls an embind class constructor.
922903func (imp * Imports ) Construct (className string , args ... uint32 ) (uint32 , error ) {
923- if imp .dead {
924- return 0 , imp .deadErr
925- }
926904 ci := imp .classByName [className ]
927905 if ci == nil {
928906 return 0 , fmt .Errorf ("ltsm: class %q not found" , className )
@@ -943,10 +921,7 @@ func (imp *Imports) Construct(className string, args ...uint32) (uint32, error)
943921
944922// Destroy invokes the registered C++ destructor for an embind object.
945923func (imp * Imports ) Destroy (className string , ptr uint32 ) (err error ) {
946- defer imp .checkDead (& err )
947- if imp .dead {
948- return imp .deadErr
949- }
924+ defer recoverError (& err )
950925 if ptr == 0 {
951926 return nil
952927 }
@@ -989,7 +964,7 @@ func (imp *Imports) MarkSecureKeyExportable(ptr uint32) {
989964// callIndirect dispatches to the appropriate callIndirectTN based on parameter count and types.
990965// Most embind methods use all-uint32 params, but some have uint64 (bigint) params or returns.
991966func (imp * Imports ) callIndirect (invokerIdx uint32 , argTypes []uint32 , callArgs []uint32 ) (ret uint32 , err error ) {
992- defer imp . checkDead (& err )
967+ defer recoverError (& err )
993968 m := imp .mod
994969 nArgs := len (callArgs )
995970
0 commit comments