Files
sdk/pkg/compiler/test/js/js_spec_optimization_test.dart
Stephen Adams c8869151bd [dart2js] Remove obsolete code from DCE
Remove an obsolete optimization: an instruction that has no users and
has the only effect of checking the the receiver is non-null, can be
removed when followed by another instruction with the same
null-checking effect.

With sound null safety, this rarely occurs. Most cases where this
would have fired are now explicit null checks that are not dead
because the second instruction is data-dependent of the check
instruction. There is similar code in instruction selection to omit
null checks, so we can rely on that.

The remaining cases are with back-to-back JS-fragments. This can be managed by adding a null check. Added a test case for an added null check.

Issue: #60327
Change-Id: Iace58bd944839166bc677d85bba2fe8d5c75da4c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/446483
Reviewed-by: Mayank Patke <fishythefish@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
2025-08-28 13:40:10 -07:00

140 lines
4.3 KiB
Dart

// Copyright (c) 2015, 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 'package:compiler/src/elements/entities.dart';
import 'package:expect/async_helper.dart';
import 'package:expect/expect.dart';
import '../helpers/compiler_helper.dart';
import 'package:compiler/src/util/memory_compiler.dart';
const String TEST_1 = r"""
import 'dart:_foreign_helper';
main() {
// present: 'Moose'
JS('', 'Moose');
// absent: 'Phantom' - pure.
JS('returns: bool;effects:none;depends:none;throws:never', 'Phantom');
// present: 'Spider' - unused after constant folding 'is', but unpure.
print(JS('returns:bool;effects:none;depends:all', 'Spider') is bool);
// absent: 'Wasp' - unused after constant folding 'is', and unpure.
print(JS('returns:bool;effects:none;depends:all;throws:never', 'Wasp')
is bool);
JS('', 'Array'); // absent: "Array"
}
""";
const String TEST_2 = r"""
import 'dart:_foreign_helper';
main() {
var w1 = JS('returns:int;depends:none;effects:none;throws:never',
'foo(#)', 1);
var w2 = JS('returns:int;depends:none;effects:none;throws:never',
'foo(#)', 2);
print([w2, w1]);
// present: '[foo(2), foo(1)]' - since 'foo' is pure, we expect to generate
// code out-of-order.
}
""";
const String TEST_3 = r"""
import 'dart:_foreign_helper';
main() {
var s = JS('String|Null', '"Hello"');
var s1 = JS('returns:String;depends:none;effects:none;throws:null(1)',
'#.toLowerCase()', s);
var s2 = JS('returns:String;depends:none;effects:none;throws:null(1)',
'#.toUpperCase()', s);
print(s2);
// present: 'toLowerCase'
// present: 'toUpperCase'
}
""";
const String TEST_4 = r"""
import 'dart:_foreign_helper';
main() {
var s = JS('String|Null', '"Hello"');
var s1 = JS('returns:String;depends:none;effects:none;throws:null(1)',
'#.toLowerCase()', s);
var s2 = JS('returns:String;depends:none;effects:none;throws:null(1)',
'#.toUpperCase()', s);
// present: 'erCase' - retained at least one call to guarantee exception.
}
""";
const String TEST_5 = r"""
import 'dart:_foreign_helper';
main() {
var s = JS('String', '"Hello"');
var s1 = JS('returns:String;depends:none;effects:none;throws:null(1)',
'#.toLowerCase()', s);
var s2 = JS('returns:String;depends:none;effects:none;throws:null(1)',
'#.toUpperCase()', s);
// absent: 'erCase' - neither call needs to be retained since there is no
// exception.
}
""";
const String TEST_6 = r"""
import 'dart:_foreign_helper';
main() {
var s = JS('String|Null', '"Hello"');
s!;
var s1 = JS('returns:String;depends:none;effects:none;throws:null(1)',
'#.toLowerCase()', s);
var s2 = JS('returns:String;depends:none;effects:none;throws:null(1)',
'#.toUpperCase()', s);
print(s2);
// absent: 'toLowerCase' - removed since has no effect after null check.
// present: 'toUpperCase' - retained since used.
// present: '"Hello".toUpperCase' - null check folded into call.
// absent: '.toString;' - no null check as folded into 's.toUpperCase()'
}
""";
main() {
runTests() async {
check(String test) async {
var checker = checkerForAbsentPresent(test);
String main = 'sdk/tests/web/native/main.dart';
Uri entryPoint = Uri.parse('memory:$main');
var result = await runCompiler(
entryPoint: entryPoint,
memorySourceFiles: {main: test},
);
Expect.isTrue(result.isSuccess);
var compiler = result.compiler!;
var closedWorld = compiler.backendClosedWorldForTesting!;
var elementEnvironment = closedWorld.elementEnvironment;
MemberEntity element = elementEnvironment.mainFunction!;
String generated = compiler.backendStrategy.getGeneratedCodeForTesting(
element,
)!;
checker(generated);
}
await check(TEST_1);
await check(TEST_2);
await check(TEST_3);
await check(TEST_4);
await check(TEST_5);
await check(TEST_6);
}
asyncTest(() async {
print('--test from kernel------------------------------------------------');
await runTests();
});
}