From d5f2d5b3833c3c6af3b3fe4887cb68b891152cd6 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 15 Sep 2022 16:06:49 +0200 Subject: [PATCH 1/5] fix missing managed stack trace on managed exceptions marshaled to JS --- .../JavaScript/Interop/JavaScriptExports.cs | 28 ++++++++++++++++++- .../JavaScript/JSImportExportTest.cs | 16 +++++++++-- .../JavaScript/JavaScriptTestHelper.cs | 7 +++-- .../JavaScript/JavaScriptTestHelper.mjs | 11 ++++++++ src/mono/wasm/runtime/logging.ts | 8 ++++-- src/mono/wasm/runtime/managed-exports.ts | 21 +++++++++++++- src/mono/wasm/runtime/marshal-to-js.ts | 8 +++--- src/mono/wasm/runtime/marshal.ts | 16 +++++++---- src/mono/wasm/runtime/run.ts | 5 ++-- src/mono/wasm/runtime/types.ts | 3 ++ 10 files changed, 103 insertions(+), 20 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs index 5b932edb7965dc..81a665b659ca05 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs @@ -124,7 +124,7 @@ public static void ReleaseJSOwnedObjectByGCHandle(JSMarshalerArgument* arguments public static void CreateTaskCallback(JSMarshalerArgument* arguments_buffer) { ref JSMarshalerArgument arg_exc = ref arguments_buffer[0]; // initialized by caller in alloc_stack_frame() - ref JSMarshalerArgument arg_return = ref arguments_buffer[1]; // used as return vaule + ref JSMarshalerArgument arg_return = ref arguments_buffer[1]; // used as return value try { JSHostImplementation.TaskCallback holder = new JSHostImplementation.TaskCallback(); @@ -195,6 +195,32 @@ public static void CompleteTask(JSMarshalerArgument* arguments_buffer) } } + [MethodImpl(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425 + // the marshaled signature is: + // string GetManagedStackTrace(GCHandle exception) + public static void GetManagedStackTrace(JSMarshalerArgument* arguments_buffer) + { + ref JSMarshalerArgument arg_exc = ref arguments_buffer[0]; // initialized by caller in alloc_stack_frame() + ref JSMarshalerArgument arg_return = ref arguments_buffer[1]; // used as return value + ref JSMarshalerArgument arg_1 = ref arguments_buffer[2];// initialized and set by caller + try + { + GCHandle exception_gc_handle = (GCHandle)arg_1.slot.GCHandle; + if (exception_gc_handle.Target is Exception exception) + { + arg_return.ToJS(exception.ToString()); + } + else + { + throw new InvalidOperationException("Exception is null"); + } + } + catch (Exception ex) + { + arg_exc.ToJS(ex); + } + } + #if FEATURE_WASM_THREADS [MethodImpl(MethodImplOptions.NoInlining)] // https://github.com/dotnet/runtime/issues/71425 diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs index dded93a4059ab7..4e3ea3a78ba786 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs @@ -1372,11 +1372,20 @@ public void JsExportException(Exception value, string clazz) [Fact] public void JsExportThrows() { - var ex = Assert.Throws(() => JavaScriptTestHelper.invoke1_String("-t-e-s-t-", nameof(JavaScriptTestHelper.Throw))); + var ex = Assert.Throws(() => JavaScriptTestHelper.invoke1_String("-t-e-s-t-", nameof(JavaScriptTestHelper.ThrowFromJSExport))); Assert.DoesNotContain("Unexpected error", ex.Message); Assert.Contains("-t-e-s-t-", ex.Message); } + [Fact] + public void JsExportCatchToString() + { + var toString = JavaScriptTestHelper.catch1toString("-t-e-s-t-", nameof(JavaScriptTestHelper.ThrowFromJSExport)); + Assert.DoesNotContain("Unexpected error", toString); + Assert.Contains("-t-e-s-t-", toString); + Assert.Contains("ThrowFromJSExport", toString); + } + #endregion Exception #region JSObject @@ -1924,7 +1933,10 @@ private void JsImportTest(T value var exThrow1 = Assert.Throws(() => throw1(value)); Assert.Contains("throw1-msg", exThrow1.Message); - Assert.DoesNotContain(" at ", exThrow1.Message); + if (!typeof(Exception).IsAssignableFrom(typeof(T))) + { + Assert.DoesNotContain(" at ", exThrow1.Message); + } Assert.Contains(" at Module.throw1", exThrow1.StackTrace); // anything is a system.object, sometimes it would be JSObject wrapper diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs index cca24202da298d..01ae60bc1a79d9 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs @@ -32,8 +32,11 @@ public static void ConsoleWriteLine([JSMarshalAs] string message) Console.WriteLine(message); } + [JSImport("catch1toString", "JavaScriptTestHelper")] + public static partial string catch1toString(string message, string functionName); + [JSExport] - public static void Throw(string message) + public static void ThrowFromJSExport(string message) { throw new ArgumentException(message); } @@ -1278,4 +1281,4 @@ public partial record struct NestedRecordStruct [System.Runtime.InteropServices.JavaScript.JSExport] public static string EchoString(string message) => message + "85"; } -} \ No newline at end of file +} diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs index db9d18c5adbc35..e2cb28c5e8fc96 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs @@ -110,6 +110,17 @@ export function throw0() { throw new Error('throw-0-msg'); } +export function catch1toString(message, functionName) { + const JavaScriptTestHelper = dllExports.System.Runtime.InteropServices.JavaScript.Tests.JavaScriptTestHelper; + const fn = JavaScriptTestHelper[functionName]; + try { + fn(message); + return "bad"; + } catch (err) { + return err.toString(); + } +} + export function throw1(arg1) { //console.log(`throw1(arg1:${arg1 !== null ? arg1 : ''})`) throw new Error('throw1-msg ' + arg1); diff --git a/src/mono/wasm/runtime/logging.ts b/src/mono/wasm/runtime/logging.ts index 2d40d7c4d20e29..13f15697503bcf 100644 --- a/src/mono/wasm/runtime/logging.ts +++ b/src/mono/wasm/runtime/logging.ts @@ -3,6 +3,7 @@ import BuildConfiguration from "consts:configuration"; import { INTERNAL, Module, runtimeHelpers } from "./imports"; +import { ManagedError } from "./marshal"; import { CharPtr, VoidPtr } from "./types/emscripten"; const wasm_func_map = new Map(); @@ -60,10 +61,11 @@ export function mono_wasm_symbolicate_string(message: string): string { } } -export function mono_wasm_stringify_as_error_with_stack(err: Error | string): string { +export function mono_wasm_stringify_as_error_with_stack(err: Error | ManagedError | string): string { let errObj: any = err; - if (!(err instanceof Error)) - errObj = new Error(err); + if (!(errObj instanceof Error) && !(errObj instanceof ManagedError)) { + errObj = new Error(errObj); + } // Error return mono_wasm_symbolicate_string(errObj.stack); diff --git a/src/mono/wasm/runtime/managed-exports.ts b/src/mono/wasm/runtime/managed-exports.ts index 09f6d9a33d0241..65186e4c0b270f 100644 --- a/src/mono/wasm/runtime/managed-exports.ts +++ b/src/mono/wasm/runtime/managed-exports.ts @@ -7,7 +7,7 @@ import { Module, runtimeHelpers, ENVIRONMENT_IS_PTHREAD } from "./imports"; import { alloc_stack_frame, get_arg, get_arg_gc_handle, MarshalerType, set_arg_type, set_gc_handle } from "./marshal"; import { invoke_method_and_handle_exception } from "./invoke-cs"; import { marshal_array_to_cs_impl, marshal_exception_to_cs, marshal_intptr_to_cs } from "./marshal-to-cs"; -import { marshal_int32_to_js, marshal_task_to_js } from "./marshal-to-js"; +import { marshal_int32_to_js, marshal_string_to_js, marshal_task_to_js } from "./marshal-to-js"; export function init_managed_exports(): void { const anyModule = Module as any; @@ -34,6 +34,9 @@ export function init_managed_exports(): void { mono_assert(complete_task_method, "Can't find CompleteTask method"); const call_delegate_method = get_method("CallDelegate"); mono_assert(call_delegate_method, "Can't find CallDelegate method"); + const get_managed_stack_trace_method = get_method("GetManagedStackTrace"); + mono_assert(get_managed_stack_trace_method, "Can't find GetManagedStackTrace method"); + runtimeHelpers.javaScriptExports.call_entry_point = (entry_point: MonoMethod, program_args?: string[]) => { const sp = anyModule.stackSave(); try { @@ -134,6 +137,22 @@ export function init_managed_exports(): void { anyModule.stackRestore(sp); } }; + runtimeHelpers.javaScriptExports.get_managed_stack_trace = (exception_gc_handle: GCHandle) => { + const sp = anyModule.stackSave(); + try { + const args = alloc_stack_frame(3); + + const arg1 = get_arg(args, 2); + set_arg_type(arg1, MarshalerType.Exception); + set_gc_handle(arg1, exception_gc_handle); + + invoke_method_and_handle_exception(get_managed_stack_trace_method, args); + const res = get_arg(args, 1); + return marshal_string_to_js(res); + } finally { + anyModule.stackRestore(sp); + } + }; if (install_sync_context) { runtimeHelpers.javaScriptExports.install_synchronization_context = () => { diff --git a/src/mono/wasm/runtime/marshal-to-js.ts b/src/mono/wasm/runtime/marshal-to-js.ts index b3f469fc05f5ce..a26de6dc1470df 100644 --- a/src/mono/wasm/runtime/marshal-to-js.ts +++ b/src/mono/wasm/runtime/marshal-to-js.ts @@ -33,7 +33,7 @@ export function initialize_marshalers_to_js(): void { cs_to_js_marshalers.set(MarshalerType.Single, _marshal_float_to_js); cs_to_js_marshalers.set(MarshalerType.IntPtr, _marshal_intptr_to_js); cs_to_js_marshalers.set(MarshalerType.Double, _marshal_double_to_js); - cs_to_js_marshalers.set(MarshalerType.String, _marshal_string_to_js); + cs_to_js_marshalers.set(MarshalerType.String, marshal_string_to_js); cs_to_js_marshalers.set(MarshalerType.Exception, marshal_exception_to_js); cs_to_js_marshalers.set(MarshalerType.JSException, marshal_exception_to_js); cs_to_js_marshalers.set(MarshalerType.JSObject, _marshal_js_object_to_js); @@ -296,7 +296,7 @@ export function mono_wasm_marshal_promise(args: JSMarshalerArguments): void { set_arg_type(exc, MarshalerType.None); } -function _marshal_string_to_js(arg: JSMarshalerArgument): string | null { +export function marshal_string_to_js(arg: JSMarshalerArgument): string | null { const type = get_arg_type(arg); if (type == MarshalerType.None) { return null; @@ -326,7 +326,7 @@ export function marshal_exception_to_js(arg: JSMarshalerArgument): Error | null let result = _lookup_js_owned_object(gc_handle); if (result === null || result === undefined) { // this will create new ManagedError - const message = _marshal_string_to_js(arg); + const message = marshal_string_to_js(arg); result = new ManagedError(message!); setup_managed_proxy(result, gc_handle); @@ -405,7 +405,7 @@ function _marshal_array_to_js_impl(arg: JSMarshalerArgument, element_type: Marsh result = new Array(length); for (let index = 0; index < length; index++) { const element_arg = get_arg(buffer_ptr, index); - result[index] = _marshal_string_to_js(element_arg); + result[index] = marshal_string_to_js(element_arg); } cwraps.mono_wasm_deregister_root(buffer_ptr); } diff --git a/src/mono/wasm/runtime/marshal.ts b/src/mono/wasm/runtime/marshal.ts index 591f3976292164..dd2c3b61b8b66b 100644 --- a/src/mono/wasm/runtime/marshal.ts +++ b/src/mono/wasm/runtime/marshal.ts @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. import { js_owned_gc_handle_symbol, teardown_managed_proxy } from "./gc-handles"; -import { Module } from "./imports"; +import { Module, runtimeHelpers } from "./imports"; import { getF32, getF64, getI16, getI32, getI64Big, getU16, getU32, getU8, setF32, setF64, setI16, setI32, setI64Big, setU16, setU32, setU8 } from "./memory"; import { mono_wasm_new_external_root } from "./roots"; import { mono_assert, GCHandle, JSHandle, MonoObject, MonoString, GCHandleNull, JSMarshalerArguments, JSFunctionSignature, JSMarshalerType, JSMarshalerArgument, MarshalerToJs, MarshalerToCs, WasmRoot } from "./types"; @@ -321,9 +321,15 @@ export class ManagedError extends Error implements IDisposable { super(message); } - get stack(): string | undefined { - //todo implement lazy managed stack strace from this[js_owned_gc_handle_symbol]! - return super.stack; + get managedStack(): string | undefined { + const gc_handle = (this)[js_owned_gc_handle_symbol]; + if (gc_handle) { + const managed_stack = runtimeHelpers.javaScriptExports.get_managed_stack_trace(gc_handle); + if (managed_stack) { + return managed_stack + "\n" + this.stack; + } + } + return this.stack; } dispose(): void { @@ -335,7 +341,7 @@ export class ManagedError extends Error implements IDisposable { } toString(): string { - return `ManagedError(gc_handle: ${(this)[js_owned_gc_handle_symbol]})`; + return this.managedStack || this.message; } } diff --git a/src/mono/wasm/runtime/run.ts b/src/mono/wasm/runtime/run.ts index 1e224837222ca0..e9afabc90a759e 100644 --- a/src/mono/wasm/runtime/run.ts +++ b/src/mono/wasm/runtime/run.ts @@ -8,6 +8,7 @@ import cwraps from "./cwraps"; import { assembly_load } from "./class-loader"; import { mono_assert } from "./types"; import { consoleWebSocket, mono_wasm_stringify_as_error_with_stack } from "./logging"; +import { ManagedError } from "./marshal"; /** * Possible signatures are described here https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/main-command-line @@ -109,7 +110,7 @@ function set_exit_code_and_quit_now(exit_code: number, reason?: any): void { if (runtimeHelpers.ExitStatus) { if (reason && !(reason instanceof runtimeHelpers.ExitStatus)) { if (!runtimeHelpers.config.logExitCode) { - if (reason instanceof Error) + if (reason instanceof Error || reason instanceof ManagedError) Module.printErr(mono_wasm_stringify_as_error_with_stack(reason)); else if (typeof reason == "string") Module.printErr(reason); @@ -146,7 +147,7 @@ function appendElementOnExit(exit_code: number) { function logErrorOnExit(exit_code: number, reason?: any) { if (runtimeHelpers.config.logExitCode) { if (exit_code != 0 && reason) { - if (reason instanceof Error) + if (reason instanceof Error || reason instanceof ManagedError) console.error(mono_wasm_stringify_as_error_with_stack(reason)); else if (typeof reason == "string") console.error(reason); diff --git a/src/mono/wasm/runtime/types.ts b/src/mono/wasm/runtime/types.ts index ba56005ef2d604..ca914585d1d6e6 100644 --- a/src/mono/wasm/runtime/types.ts +++ b/src/mono/wasm/runtime/types.ts @@ -414,6 +414,9 @@ export interface JavaScriptExports { // the marshaled signature is: void InstallSynchronizationContext() install_synchronization_context(): void; + + // the marshaled signature is: string GetManagedStackTrace(GCHandle exception) + get_managed_stack_trace(exception_gc_handle: GCHandle): string | null } export type MarshalerToJs = (arg: JSMarshalerArgument, sig?: JSMarshalerType, res_converter?: MarshalerToJs, arg1_converter?: MarshalerToCs, arg2_converter?: MarshalerToCs, arg3_converter?: MarshalerToCs) => any; From 1e50c5e6a439b2e9e03f08b46f012a22a04d62d8 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 16 Sep 2022 15:10:21 +0200 Subject: [PATCH 2/5] feedback --- src/mono/wasm/runtime/logging.ts | 5 ++--- src/mono/wasm/runtime/run.ts | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/mono/wasm/runtime/logging.ts b/src/mono/wasm/runtime/logging.ts index 13f15697503bcf..cdb2d00dba723d 100644 --- a/src/mono/wasm/runtime/logging.ts +++ b/src/mono/wasm/runtime/logging.ts @@ -3,7 +3,6 @@ import BuildConfiguration from "consts:configuration"; import { INTERNAL, Module, runtimeHelpers } from "./imports"; -import { ManagedError } from "./marshal"; import { CharPtr, VoidPtr } from "./types/emscripten"; const wasm_func_map = new Map(); @@ -61,9 +60,9 @@ export function mono_wasm_symbolicate_string(message: string): string { } } -export function mono_wasm_stringify_as_error_with_stack(err: Error | ManagedError | string): string { +export function mono_wasm_stringify_as_error_with_stack(err: Error | string): string { let errObj: any = err; - if (!(errObj instanceof Error) && !(errObj instanceof ManagedError)) { + if (!(errObj instanceof Error)) { errObj = new Error(errObj); } diff --git a/src/mono/wasm/runtime/run.ts b/src/mono/wasm/runtime/run.ts index e9afabc90a759e..1e224837222ca0 100644 --- a/src/mono/wasm/runtime/run.ts +++ b/src/mono/wasm/runtime/run.ts @@ -8,7 +8,6 @@ import cwraps from "./cwraps"; import { assembly_load } from "./class-loader"; import { mono_assert } from "./types"; import { consoleWebSocket, mono_wasm_stringify_as_error_with_stack } from "./logging"; -import { ManagedError } from "./marshal"; /** * Possible signatures are described here https://docs.microsoft.com/en-us/dotnet/csharp/fundamentals/program-structure/main-command-line @@ -110,7 +109,7 @@ function set_exit_code_and_quit_now(exit_code: number, reason?: any): void { if (runtimeHelpers.ExitStatus) { if (reason && !(reason instanceof runtimeHelpers.ExitStatus)) { if (!runtimeHelpers.config.logExitCode) { - if (reason instanceof Error || reason instanceof ManagedError) + if (reason instanceof Error) Module.printErr(mono_wasm_stringify_as_error_with_stack(reason)); else if (typeof reason == "string") Module.printErr(reason); @@ -147,7 +146,7 @@ function appendElementOnExit(exit_code: number) { function logErrorOnExit(exit_code: number, reason?: any) { if (runtimeHelpers.config.logExitCode) { if (exit_code != 0 && reason) { - if (reason instanceof Error || reason instanceof ManagedError) + if (reason instanceof Error) console.error(mono_wasm_stringify_as_error_with_stack(reason)); else if (typeof reason == "string") console.error(reason); From 57aa8eafc6957e1d1debd78b1979d9fd5ceee38a Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 16 Sep 2022 17:32:26 +0200 Subject: [PATCH 3/5] override `get stack` instead of `toString` --- src/mono/wasm/runtime/marshal.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/mono/wasm/runtime/marshal.ts b/src/mono/wasm/runtime/marshal.ts index dd2c3b61b8b66b..9a0d9cc9c3aff7 100644 --- a/src/mono/wasm/runtime/marshal.ts +++ b/src/mono/wasm/runtime/marshal.ts @@ -317,19 +317,24 @@ export class ManagedObject implements IDisposable { } export class ManagedError extends Error implements IDisposable { + private superStack: any; constructor(message: string) { super(message); + this.superStack = Object.getOwnPropertyDescriptor(this, "stack"); + Object.defineProperty(this, "stack", { + get: this.getManageStack, + }); } - get managedStack(): string | undefined { - const gc_handle = (this)[js_owned_gc_handle_symbol]; + getManageStack() { + const gc_handle = (this)[js_owned_gc_handle_symbol]; if (gc_handle) { const managed_stack = runtimeHelpers.javaScriptExports.get_managed_stack_trace(gc_handle); if (managed_stack) { - return managed_stack + "\n" + this.stack; + return managed_stack + "\n" + this.superStack.value; } } - return this.stack; + return this.superStack.value; } dispose(): void { @@ -339,10 +344,6 @@ export class ManagedError extends Error implements IDisposable { get isDisposed(): boolean { return (this)[js_owned_gc_handle_symbol] === GCHandleNull; } - - toString(): string { - return this.managedStack || this.message; - } } export function get_signature_marshaler(signature: JSFunctionSignature, index: number): JSHandle { From e7608305ca0834d72320e2ce8fda80e8155751d5 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 16 Sep 2022 17:37:22 +0200 Subject: [PATCH 4/5] fix tests --- .../JavaScript/JSImportExportTest.cs | 15 ++++++++++----- .../JavaScript/JavaScriptTestHelper.cs | 3 +++ .../JavaScript/JavaScriptTestHelper.mjs | 11 +++++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs index 4e3ea3a78ba786..cbdf7b040899c3 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs @@ -1383,7 +1383,15 @@ public void JsExportCatchToString() var toString = JavaScriptTestHelper.catch1toString("-t-e-s-t-", nameof(JavaScriptTestHelper.ThrowFromJSExport)); Assert.DoesNotContain("Unexpected error", toString); Assert.Contains("-t-e-s-t-", toString); - Assert.Contains("ThrowFromJSExport", toString); + Assert.DoesNotContain("ThrowFromJSExport", toString); + } + + [Fact] + public void JsExportCatchStack() + { + var stack = JavaScriptTestHelper.catch1stack("-t-e-s-t-", nameof(JavaScriptTestHelper.ThrowFromJSExport)); + Assert.Contains("ThrowFromJSExport", stack); + Assert.Contains("catch1stack", stack); } #endregion Exception @@ -1933,10 +1941,7 @@ private void JsImportTest(T value var exThrow1 = Assert.Throws(() => throw1(value)); Assert.Contains("throw1-msg", exThrow1.Message); - if (!typeof(Exception).IsAssignableFrom(typeof(T))) - { - Assert.DoesNotContain(" at ", exThrow1.Message); - } + Assert.DoesNotContain(" at ", exThrow1.Message); Assert.Contains(" at Module.throw1", exThrow1.StackTrace); // anything is a system.object, sometimes it would be JSObject wrapper diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs index 01ae60bc1a79d9..ea3f5f1b7809cd 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs @@ -35,6 +35,9 @@ public static void ConsoleWriteLine([JSMarshalAs] string message) [JSImport("catch1toString", "JavaScriptTestHelper")] public static partial string catch1toString(string message, string functionName); + [JSImport("catch1stack", "JavaScriptTestHelper")] + public static partial string catch1stack(string message, string functionName); + [JSExport] public static void ThrowFromJSExport(string message) { diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs index e2cb28c5e8fc96..c9fccbacb43b7b 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs @@ -121,6 +121,17 @@ export function catch1toString(message, functionName) { } } +export function catch1stack(message, functionName) { + const JavaScriptTestHelper = dllExports.System.Runtime.InteropServices.JavaScript.Tests.JavaScriptTestHelper; + const fn = JavaScriptTestHelper[functionName]; + try { + fn(message); + return "bad"; + } catch (err) { + return err.stack; + } +} + export function throw1(arg1) { //console.log(`throw1(arg1:${arg1 !== null ? arg1 : ''})`) throw new Error('throw1-msg ' + arg1); From 9a88ea55c52bf7962282e00903a1ca7e5bf2efc1 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Fri, 16 Sep 2022 18:32:08 +0200 Subject: [PATCH 5/5] fix Firefox --- .../JavaScript/Interop/JavaScriptExports.cs | 2 +- .../JavaScript/JSImportExportTest.cs | 8 ++-- .../JavaScript/JavaScriptTestHelper.cs | 48 +++++++++---------- .../JavaScript/JavaScriptTestHelper.mjs | 4 +- src/mono/wasm/runtime/marshal.ts | 13 +++-- 5 files changed, 41 insertions(+), 34 deletions(-) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs index 81a665b659ca05..2fbf3f448f5cd5 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/src/System/Runtime/InteropServices/JavaScript/Interop/JavaScriptExports.cs @@ -208,7 +208,7 @@ public static void GetManagedStackTrace(JSMarshalerArgument* arguments_buffer) GCHandle exception_gc_handle = (GCHandle)arg_1.slot.GCHandle; if (exception_gc_handle.Target is Exception exception) { - arg_return.ToJS(exception.ToString()); + arg_return.ToJS(exception.StackTrace); } else { diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs index cbdf7b040899c3..51215e0b5e863d 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs @@ -1383,14 +1383,14 @@ public void JsExportCatchToString() var toString = JavaScriptTestHelper.catch1toString("-t-e-s-t-", nameof(JavaScriptTestHelper.ThrowFromJSExport)); Assert.DoesNotContain("Unexpected error", toString); Assert.Contains("-t-e-s-t-", toString); - Assert.DoesNotContain("ThrowFromJSExport", toString); + Assert.DoesNotContain(nameof(JavaScriptTestHelper.ThrowFromJSExport), toString); } [Fact] public void JsExportCatchStack() { var stack = JavaScriptTestHelper.catch1stack("-t-e-s-t-", nameof(JavaScriptTestHelper.ThrowFromJSExport)); - Assert.Contains("ThrowFromJSExport", stack); + Assert.Contains(nameof(JavaScriptTestHelper.ThrowFromJSExport), stack); Assert.Contains("catch1stack", stack); } @@ -1937,12 +1937,12 @@ private void JsImportTest(T value var exThrow0 = Assert.Throws(() => JavaScriptTestHelper.throw0()); Assert.Contains("throw-0-msg", exThrow0.Message); Assert.DoesNotContain(" at ", exThrow0.Message); - Assert.Contains(" at Module.throw0", exThrow0.StackTrace); + Assert.Contains("throw0fn", exThrow0.StackTrace); var exThrow1 = Assert.Throws(() => throw1(value)); Assert.Contains("throw1-msg", exThrow1.Message); Assert.DoesNotContain(" at ", exThrow1.Message); - Assert.Contains(" at Module.throw1", exThrow1.StackTrace); + Assert.Contains("throw1fn", exThrow1.StackTrace); // anything is a system.object, sometimes it would be JSObject wrapper if (typeof(T).IsPrimitive) diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs index ea3f5f1b7809cd..9f00a46a951b17 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.cs @@ -105,7 +105,7 @@ public static int Optimized2R(int a1, int a2) [return: JSMarshalAs] internal static partial string getClass1(); - [JSImport("throw0", "JavaScriptTestHelper")] + [JSImport("throw0fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial void throw0(); @@ -263,7 +263,7 @@ internal static partial void Relaxed(string a1, Exception ex, [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_Int32([JSMarshalAs] int value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial int throw1_Int32([JSMarshalAs] int value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -289,7 +289,7 @@ public static int EchoInt32([JSMarshalAs] int arg1) [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_String([JSMarshalAs] string value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial string throw1_String([JSMarshalAs] string value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -321,7 +321,7 @@ public static string EchoString([JSMarshalAs] string arg1) [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_Object([JSMarshalAs] object value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial object throw1_Object([JSMarshalAs] object value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -347,7 +347,7 @@ public static object EchoObject([JSMarshalAs] object arg1) [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_Exception([JSMarshalAs] Exception value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial Exception throw1_Exception([JSMarshalAs] Exception value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -479,7 +479,7 @@ public static Func BackFuncOfIntInt([JSMarshalAs] internal static partial bool identity1_Boolean([JSMarshalAs] bool value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool throw1_Boolean([JSMarshalAs] bool value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -506,7 +506,7 @@ public static bool EchoBoolean([JSMarshalAs] bool arg1) [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_Char([JSMarshalAs] char value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial char throw1_Char([JSMarshalAs] char value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -532,7 +532,7 @@ public static char EchoChar([JSMarshalAs] char arg1) [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_Byte([JSMarshalAs] byte value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial byte throw1_Byte([JSMarshalAs] byte value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -558,7 +558,7 @@ public static byte EchoByte([JSMarshalAs] byte arg1) [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_Int16([JSMarshalAs] short value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial short throw1_Int16([JSMarshalAs] short value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -584,7 +584,7 @@ public static short EchoInt16([JSMarshalAs] short arg1) [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_Int52([JSMarshalAs] long value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial long throw1_Int52([JSMarshalAs] long value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -610,7 +610,7 @@ public static long EchoInt52([JSMarshalAs] long arg1) [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_BigInt64([JSMarshalAs] long value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial long throw1_BigInt64([JSMarshalAs] long value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -636,7 +636,7 @@ public static long EchoBigInt64([JSMarshalAs] long arg1) [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_Double([JSMarshalAs] double value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial double throw1_Double([JSMarshalAs] double value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -662,7 +662,7 @@ public static double EchoDouble([JSMarshalAs] double arg1) [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_Single([JSMarshalAs] float value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial float throw1_Single([JSMarshalAs] float value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -688,7 +688,7 @@ public static float EchoSingle([JSMarshalAs] float arg1) [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_IntPtr([JSMarshalAs] IntPtr value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial IntPtr throw1_IntPtr([JSMarshalAs] IntPtr value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -715,7 +715,7 @@ public static IntPtr EchoIntPtr([JSMarshalAs] IntPtr arg1) [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal unsafe static partial bool identity1_VoidPtr([JSMarshalAs] void* value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal unsafe static partial void* throw1_VoidPtr([JSMarshalAs] void* value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -741,7 +741,7 @@ public static IntPtr EchoIntPtr([JSMarshalAs] IntPtr arg1) [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_DateTime([JSMarshalAs] DateTime value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial DateTime throw1_DateTime([JSMarshalAs] DateTime value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -767,7 +767,7 @@ public static DateTime EchoDateTime([JSMarshalAs] DateTime arg1) [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_DateTimeOffset([JSMarshalAs] DateTimeOffset value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial DateTimeOffset throw1_DateTimeOffset([JSMarshalAs] DateTimeOffset value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -794,7 +794,7 @@ public static DateTimeOffset EchoDateTimeOffset([JSMarshalAs] DateT [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_NullableBoolean([JSMarshalAs] bool? value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool? throw1_NullableBoolean([JSMarshalAs] bool? value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -821,7 +821,7 @@ public static DateTimeOffset EchoDateTimeOffset([JSMarshalAs] DateT [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_NullableInt32([JSMarshalAs] int? value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial int? throw1_NullableInt32([JSMarshalAs] int? value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -848,7 +848,7 @@ public static DateTimeOffset EchoDateTimeOffset([JSMarshalAs] DateT [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_NullableBigInt64([JSMarshalAs] long? value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial long? throw1_NullableBigInt64([JSMarshalAs] long? value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -875,7 +875,7 @@ public static DateTimeOffset EchoDateTimeOffset([JSMarshalAs] DateT [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_NullableIntPtr([JSMarshalAs] IntPtr? value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial IntPtr? throw1_NullableIntPtr([JSMarshalAs] IntPtr? value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -902,7 +902,7 @@ public static DateTimeOffset EchoDateTimeOffset([JSMarshalAs] DateT [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_NullableDouble([JSMarshalAs] double? value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial double? throw1_NullableDouble([JSMarshalAs] double? value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -929,7 +929,7 @@ public static DateTimeOffset EchoDateTimeOffset([JSMarshalAs] DateT [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_NullableDateTime([JSMarshalAs] DateTime? value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial DateTime? throw1_NullableDateTime([JSMarshalAs] DateTime? value); [JSImport("invoke1", "JavaScriptTestHelper")] @@ -955,7 +955,7 @@ public static DateTimeOffset EchoDateTimeOffset([JSMarshalAs] DateT [JSImport("identity1", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial bool identity1_JSObject([JSMarshalAs] JSObject value); - [JSImport("throw1", "JavaScriptTestHelper")] + [JSImport("throw1fn", "JavaScriptTestHelper")] [return: JSMarshalAs] internal static partial JSObject throw1_JSObject([JSMarshalAs] JSObject value); [JSImport("invoke1", "JavaScriptTestHelper")] diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs index c9fccbacb43b7b..ad5c8eac152179 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JavaScriptTestHelper.mjs @@ -105,7 +105,7 @@ export function retrieve1() { return val; } -export function throw0() { +export function throw0fn() { //console.log(`throw0()`) throw new Error('throw-0-msg'); } @@ -132,7 +132,7 @@ export function catch1stack(message, functionName) { } } -export function throw1(arg1) { +export function throw1fn(arg1) { //console.log(`throw1(arg1:${arg1 !== null ? arg1 : ''})`) throw new Error('throw1-msg ' + arg1); } diff --git a/src/mono/wasm/runtime/marshal.ts b/src/mono/wasm/runtime/marshal.ts index 9a0d9cc9c3aff7..c1e7e35535d6cf 100644 --- a/src/mono/wasm/runtime/marshal.ts +++ b/src/mono/wasm/runtime/marshal.ts @@ -320,21 +320,28 @@ export class ManagedError extends Error implements IDisposable { private superStack: any; constructor(message: string) { super(message); - this.superStack = Object.getOwnPropertyDescriptor(this, "stack"); + this.superStack = Object.getOwnPropertyDescriptor(this, "stack"); // this works on Chrome Object.defineProperty(this, "stack", { get: this.getManageStack, }); } + getSuperStack() { + if (this.superStack) { + return this.superStack.value; + } + return super.stack; // this works on FF + } + getManageStack() { const gc_handle = (this)[js_owned_gc_handle_symbol]; if (gc_handle) { const managed_stack = runtimeHelpers.javaScriptExports.get_managed_stack_trace(gc_handle); if (managed_stack) { - return managed_stack + "\n" + this.superStack.value; + return managed_stack + "\n" + this.getSuperStack(); } } - return this.superStack.value; + return this.getSuperStack(); } dispose(): void {