Skip to content

Commit 28654b9

Browse files
mralephCommit Bot
authored and
Commit Bot
committed
[vm] Avoid local labels in assembly snapshots.
Labels starting with L are treated as local by the assembler and cause problems down the line. When targeting ARM64 Mach-O having local labels cause linker to break when trying to generate compact unwinding information with a cryptic error ld: too many compact unwind infos in function <...> This happens because local labels are not seen as function boundaries and multiple .cfi_startproc/.cfi_endproc are mashed into a single function. Fixes flutter/flutter#102281 TEST=runtime/tests/vm/dart{,_2}/no_local_labels_test.dart Change-Id: I0171dc08f49c71ccb1ca02b398e01ac241efd9a8 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/241962 Reviewed-by: Daco Harkes <[email protected]> Commit-Queue: Slava Egorov <[email protected]>
1 parent b2717a1 commit 28654b9

File tree

3 files changed

+168
-0
lines changed

3 files changed

+168
-0
lines changed
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// This test verifies that assembly snapshot does not contain local labels.
6+
// (labels starting with 'L').
7+
8+
import 'dart:io';
9+
10+
import 'package:expect/expect.dart';
11+
import 'package:path/path.dart' as path;
12+
13+
import 'use_flag_test_helper.dart';
14+
15+
main(List<String> args) async {
16+
if (!isAOTRuntime) {
17+
return; // Running in JIT: AOT binaries not available.
18+
}
19+
20+
if (Platform.isAndroid) {
21+
return; // SDK tree not available on the test device.
22+
}
23+
24+
// These are the tools we need to be available to run on a given platform:
25+
if (!File(platformDill).existsSync()) {
26+
throw "Cannot run test as $platformDill does not exist";
27+
}
28+
if (!await testExecutable(genSnapshot)) {
29+
throw "Cannot run test as $genSnapshot not available";
30+
}
31+
32+
await withTempDir('no-local-labels-test', (String tempDir) async {
33+
final script = path.join(tempDir, 'program.dart');
34+
final scriptDill = path.join(tempDir, 'program.dill');
35+
36+
await File(script).writeAsString('''
37+
class Local {
38+
@pragma('vm:never-inline')
39+
void foo() {
40+
}
41+
42+
@pragma('vm:never-inline')
43+
void bar() {
44+
}
45+
}
46+
47+
void main(List<String> args) {
48+
Local()..foo()..bar();
49+
}
50+
''');
51+
52+
// Compile script to Kernel IR.
53+
await run(genKernel, <String>[
54+
'--aot',
55+
'--platform=$platformDill',
56+
'-o',
57+
scriptDill,
58+
script,
59+
]);
60+
61+
if (Platform.isWindows) {
62+
return; // No assembly generation on Windows.
63+
}
64+
65+
final assembly = path.join(tempDir, 'program.S');
66+
await run(genSnapshot, <String>[
67+
'--snapshot-kind=app-aot-assembly',
68+
'--assembly=$assembly',
69+
scriptDill,
70+
]);
71+
72+
final localLabelRe = RegExp(r'^L[a-zA-Z0-9_\.$]*:$', multiLine: true);
73+
final match = localLabelRe.firstMatch(await File(assembly).readAsString());
74+
if (match != null) {
75+
Expect.isTrue(false, 'unexpected local label found ${match[0]!}');
76+
}
77+
});
78+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// This test verifies that assembly snapshot does not contain local labels.
6+
// (labels starting with 'L').
7+
8+
// @dart=2.9
9+
10+
import 'dart:io';
11+
12+
import 'package:expect/expect.dart';
13+
import 'package:path/path.dart' as path;
14+
15+
import 'use_flag_test_helper.dart';
16+
17+
main(List<String> args) async {
18+
if (!isAOTRuntime) {
19+
return; // Running in JIT: AOT binaries not available.
20+
}
21+
22+
if (Platform.isAndroid) {
23+
return; // SDK tree not available on the test device.
24+
}
25+
26+
// These are the tools we need to be available to run on a given platform:
27+
if (!File(platformDill).existsSync()) {
28+
throw "Cannot run test as $platformDill does not exist";
29+
}
30+
if (!await testExecutable(genSnapshot)) {
31+
throw "Cannot run test as $genSnapshot not available";
32+
}
33+
34+
await withTempDir('no-local-labels-test', (String tempDir) async {
35+
final script = path.join(tempDir, 'program.dart');
36+
final scriptDill = path.join(tempDir, 'program.dill');
37+
38+
await File(script).writeAsString('''
39+
class Local {
40+
@pragma('vm:never-inline')
41+
void foo() {
42+
}
43+
44+
@pragma('vm:never-inline')
45+
void bar() {
46+
}
47+
}
48+
49+
void main(List<String> args) {
50+
Local()..foo()..bar();
51+
}
52+
''');
53+
54+
// Compile script to Kernel IR.
55+
await run(genKernel, <String>[
56+
'--aot',
57+
'--platform=$platformDill',
58+
'-o',
59+
scriptDill,
60+
script,
61+
]);
62+
63+
if (Platform.isWindows) {
64+
return; // No assembly generation on Windows.
65+
}
66+
67+
final assembly = path.join(tempDir, 'program.S');
68+
await run(genSnapshot, <String>[
69+
'--snapshot-kind=app-aot-assembly',
70+
'--assembly=$assembly',
71+
scriptDill,
72+
]);
73+
74+
final localLabelRe = RegExp(r'^L[a-zA-Z0-9_\.$]*:$', multiLine: true);
75+
final match = localLabelRe.firstMatch(await File(assembly).readAsString());
76+
if (match != null) {
77+
Expect.isTrue(false, 'unexpected local label found ${match[0]}');
78+
}
79+
});
80+
}

runtime/vm/image_snapshot.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,6 +1108,16 @@ void AssemblyImageWriter::Finalize() {
11081108

11091109
static void AddAssemblerIdentifier(ZoneTextBuffer* printer, const char* label) {
11101110
ASSERT(label[0] != '.');
1111+
if (label[0] == 'L' && printer->length() == 0) {
1112+
// Assembler treats labels starting with `L` as local which can cause
1113+
// some issues down the line e.g. on Mac the linker might fail to encode
1114+
// compact unwind information because multiple functions end up being
1115+
// treated as a single function. See https://github.com/flutter/flutter/issues/102281.
1116+
//
1117+
// Avoid this by prepending an underscore.
1118+
printer->AddString("_");
1119+
}
1120+
11111121
for (char c = *label; c != '\0'; c = *++label) {
11121122
#define OP(dart_name, asm_name) \
11131123
if (strncmp(label, dart_name, strlen(dart_name)) == 0) { \

0 commit comments

Comments
 (0)