From d32e2ece05a7139d8fc8eee75e3859e3a53d2254 Mon Sep 17 00:00:00 2001 From: Martin Kustermann Date: Mon, 10 Jun 2024 07:11:05 +0000 Subject: [PATCH] [dart2wasm] Move `StackTrace.current` for `as` checks into shared runtime code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When an implicit or explicit `as` check fails we throw a [TypeError] exception with a stack trace. Though that stack trace doesn't really have to have the top-frame being where the check failed, it's fine if there's an additional frame from the runtime code that actually throws the exception. Doing so removes `StackTrace.current` from every `as` check and therefore reduces size. Change-Id: Ia34b59ebaa54b8cdcd2dc7b153a1e4e2fe1dd0e9 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/370340 Reviewed-by: Ömer Ağacan Commit-Queue: Martin Kustermann --- pkg/dart2wasm/lib/kernel_nodes.dart | 2 ++ pkg/dart2wasm/lib/types.dart | 16 +++++----------- sdk/lib/_internal/wasm/lib/errors_patch.dart | 4 ++-- sdk/lib/_internal/wasm/lib/type.dart | 8 ++++++++ 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/pkg/dart2wasm/lib/kernel_nodes.dart b/pkg/dart2wasm/lib/kernel_nodes.dart index 2e50bf292114..b31229f4b890 100644 --- a/pkg/dart2wasm/lib/kernel_nodes.dart +++ b/pkg/dart2wasm/lib/kernel_nodes.dart @@ -294,6 +294,8 @@ mixin KernelNodes { index.getTopLevelProcedure("dart:core", "_getMasqueradedRuntimeType"); late final Procedure isSubtype = index.getTopLevelProcedure("dart:core", "_isSubtype"); + late final Procedure asSubtype = + index.getTopLevelProcedure("dart:core", "_asSubtype"); late final Procedure isTypeSubtype = index.getTopLevelProcedure("dart:core", "_isTypeSubtype"); late final Procedure verifyOptimizedTypeCheck = diff --git a/pkg/dart2wasm/lib/types.dart b/pkg/dart2wasm/lib/types.dart index 630377ea48a7..f82979ef12f3 100644 --- a/pkg/dart2wasm/lib/types.dart +++ b/pkg/dart2wasm/lib/types.dart @@ -426,16 +426,12 @@ class Types { w.Local operand = b.addLocal(boxedOperandType, isParameter: false); b.local_tee(operand); - w.Label asCheckBlock = b.block(); - b.local_get(operand); - emitIsTest(codeGen, testedAgainstType, operandType, location); - b.br_if(asCheckBlock); - b.local_get(operand); makeType(codeGen, testedAgainstType); - codeGen.call(translator.stackTraceCurrent.reference); - codeGen.call(translator.throwAsCheckError.reference); - b.unreachable(); - b.end(); + final outputs = codeGen.call(translator.asSubtype.reference); + for (final _ in outputs) { + b.drop(); + } + b.local_get(operand); return operand.type; } @@ -594,8 +590,6 @@ class Types { b.local_get(b.locals[0]); translator.constants.instantiateConstant(function, b, TypeLiteralConstant(testedAgainstType), nonNullableTypeType); - b.call(translator.functions - .getFunction(translator.stackTraceCurrent.reference)); b.call(translator.functions .getFunction(translator.throwAsCheckError.reference)); b.unreachable(); diff --git a/sdk/lib/_internal/wasm/lib/errors_patch.dart b/sdk/lib/_internal/wasm/lib/errors_patch.dart index 7d34fdcee3b3..551047daa5ea 100644 --- a/sdk/lib/_internal/wasm/lib/errors_patch.dart +++ b/sdk/lib/_internal/wasm/lib/errors_patch.dart @@ -65,8 +65,8 @@ class _TypeError extends _Error implements TypeError { } @pragma("wasm:entry-point") - static Never _throwAsCheckError( - Object? operand, Type? type, StackTrace stackTrace) { + static Never _throwAsCheckError(Object? operand, Type? type) { + final stackTrace = StackTrace.current; final typeError = _TypeError.fromMessageAndStackTrace( "Type '${operand.runtimeType}' is not a subtype of type '$type'" " in type cast", diff --git a/sdk/lib/_internal/wasm/lib/type.dart b/sdk/lib/_internal/wasm/lib/type.dart index ed055830355e..c47a31428417 100644 --- a/sdk/lib/_internal/wasm/lib/type.dart +++ b/sdk/lib/_internal/wasm/lib/type.dart @@ -1186,6 +1186,14 @@ bool _isTypeSubtype(_Type s, _Type t) { return _TypeUniverse.isSubtype(s, null, t, null); } +@pragma("wasm:entry-point") +@pragma("wasm:prefer-inline") +void _asSubtype(Object? o, _Type t) { + if (!_isSubtype(o, t)) { + _TypeError._throwAsCheckError(o, t); + } +} + @pragma("wasm:entry-point") bool _verifyOptimizedTypeCheck( bool result, Object? o, _Type t, String? location) {