[dart2wasm] Make throw call to helper function that gets stacktrace and throws object

This reduces flute complex compiled with `-O4` by 3.2% (or 41kb)

Change-Id: I46e1e933b5b283a7e502571971802885c1c79372
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/349261
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index bb43d23..509ff61 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -2883,8 +2883,7 @@
     // assume non-nullable here.
     assert(!dartTypeOf(node.expression).isPotentiallyNullable);
     wrap(node.expression, translator.topInfo.nonNullableType);
-    call(translator.stackTraceCurrent.reference);
-    call(translator.errorThrow.reference);
+    call(translator.errorThrowWithCurrentStackTrace.reference);
     b.unreachable();
     return expectedType;
   }
diff --git a/pkg/dart2wasm/lib/kernel_nodes.dart b/pkg/dart2wasm/lib/kernel_nodes.dart
index 062ea04..4688c39 100644
--- a/pkg/dart2wasm/lib/kernel_nodes.dart
+++ b/pkg/dart2wasm/lib/kernel_nodes.dart
@@ -251,8 +251,8 @@
   late final Class errorClass = index.getClass("dart:core", "Error");
   late final Field errorClassStackTraceField =
       index.getField("dart:core", "Error", "_stackTrace");
-  late final Procedure errorThrow =
-      index.getProcedure("dart:core", "Error", "_throw");
+  late final Procedure errorThrowWithCurrentStackTrace =
+      index.getProcedure("dart:core", "Error", "_throwWithCurrentStackTrace");
 
   // dart:core type procedures
   late final Procedure getClosureRuntimeType =
diff --git a/sdk/lib/_internal/wasm/lib/errors_patch.dart b/sdk/lib/_internal/wasm/lib/errors_patch.dart
index 37decf4..2b04b0e 100644
--- a/sdk/lib/_internal/wasm/lib/errors_patch.dart
+++ b/sdk/lib/_internal/wasm/lib/errors_patch.dart
@@ -14,6 +14,10 @@
     return jsonEncode(string);
   }
 
+  @pragma('wasm:entry-point')
+  static Never _throwWithCurrentStackTrace(Object object) =>
+      Error._throw(object, StackTrace.current);
+
   @patch
   StackTrace? get stackTrace => _stackTrace;
 
diff --git a/tests/language/stack_trace/full2_test.dart b/tests/language/stack_trace/full2_test.dart
index ece2252..ae1e936 100644
--- a/tests/language/stack_trace/full2_test.dart
+++ b/tests/language/stack_trace/full2_test.dart
@@ -12,6 +12,8 @@
 
 import "package:expect/expect.dart";
 
+import 'non_web_helper.dart' if (dart.library.js_interop) 'web_helper.dart';
+
 @pragma("vm:entry-point") // Prevent obfuscation.
 void func1() {
   throw new Exception("Test full stacktrace");
@@ -78,6 +80,7 @@
 }
 
 main() {
+  configureStackFrameLimit();
   var i = func7();
   Expect.equals(1, i);
 }
diff --git a/tests/language/stack_trace/full3_test.dart b/tests/language/stack_trace/full3_test.dart
index 92eac16..5dc16ae 100644
--- a/tests/language/stack_trace/full3_test.dart
+++ b/tests/language/stack_trace/full3_test.dart
@@ -12,6 +12,8 @@
 
 import "package:expect/expect.dart";
 
+import 'non_web_helper.dart' if (dart.library.js_interop) 'web_helper.dart';
+
 @pragma("vm:entry-point") // Prevent obfuscation
 void func1() {
   throw new Exception("Test full stacktrace");
@@ -77,6 +79,7 @@
 }
 
 main() {
+  configureStackFrameLimit();
   var i = func7();
   Expect.equals(1, i);
 }
diff --git a/tests/language/stack_trace/non_web_helper.dart b/tests/language/stack_trace/non_web_helper.dart
new file mode 100644
index 0000000..c4d11d2
--- /dev/null
+++ b/tests/language/stack_trace/non_web_helper.dart
@@ -0,0 +1,5 @@
+// (c) 2024, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+void configureStackFrameLimit() {}
diff --git a/tests/language/stack_trace/web_helper.dart b/tests/language/stack_trace/web_helper.dart
new file mode 100644
index 0000000..ecdf245
--- /dev/null
+++ b/tests/language/stack_trace/web_helper.dart
@@ -0,0 +1,25 @@
+// (c) 2024, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:js_interop';
+
+void configureStackFrameLimit() {
+  // Different browsers have different limits on how many top frames
+  // are captured in stack traces (e.g. Chrome's limit is 10).
+  // We can configure that here manually, to ensure the tests pass
+  // on all compiler+browser combinations.
+  eval('''
+    var globalState = (typeof window != "undefined") ? window
+      : (typeof global != "undefined") ? global
+      : (typeof self != "undefined") ? self : null;
+
+    // By default, stack traces cutoff at 10 in Chrome.
+    if (globalState.Error) {
+      globalState.Error.stackTraceLimit = Infinity;
+    }
+''');
+}
+
+@JS()
+external void eval(String code);