Skip to content

Commit 03301c9

Browse files
rmacnak-googleCommit Queue
authored andcommitted
[vm] Support assembly output for Windows.
The resulting DLL lacks debugging information / PDB. TEST=ci Bug: #60812 Bug: #60813 Cq-Include-Trybots: luci.dart.try:vm-aot-win-debug-arm64-try,vm-aot-win-debug-x64-try,vm-aot-win-release-arm64-try,vm-aot-win-release-x64-try Change-Id: I305bad0081ec24f27249ad9b75ff8d32fa9c4893 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/428200 Reviewed-by: Tess Strickland <[email protected]> Commit-Queue: Ryan Macnak <[email protected]>
1 parent bd9ab13 commit 03301c9

21 files changed

+168
-46
lines changed

pkg/test_runner/lib/src/compiler_configuration.dart

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -956,14 +956,16 @@ class PrecompilerCompilerConfiguration extends CompilerConfiguration
956956
}
957957

958958
var format = _configuration.genSnapshotFormat!;
959-
var basename = (format == GenSnapshotFormat.assembly) ? 'out.S' : 'out.aotsnapshot';
959+
var output = (format == GenSnapshotFormat.assembly)
960+
? tempAssemblyFile(tempDir)
961+
: tempAOTFile(tempDir);
960962
// Whether or not loading units are used. Mach-O doesn't currently support
961963
// this, and this isn't done for assembly output to avoid having to handle
962964
// the assembly of multiple assembly output files.
963965
var split = format == GenSnapshotFormat.elf;
964966
var args = [
965967
"--snapshot-kind=${format.snapshotType}",
966-
"--${format.fileOption}=$tempDir/$basename",
968+
"--${format.fileOption}=$output",
967969
if (split) "--loading-unit-manifest=$tempDir/ignored.json",
968970
if (_isAndroid && (_isArm || _isArmX64)) ...[
969971
'--no-sim-use-hardfp',
@@ -1074,6 +1076,8 @@ class PrecompilerCompilerConfiguration extends CompilerConfiguration
10741076
case Architecture.arm_x64:
10751077
target = ['-arch', 'armv7'];
10761078
break;
1079+
case Architecture.arm64:
1080+
case Architecture.arm64c:
10771081
case Architecture.simarm64:
10781082
case Architecture.simarm64c:
10791083
target = ['-arch', 'arm64'];
@@ -1087,6 +1091,25 @@ class PrecompilerCompilerConfiguration extends CompilerConfiguration
10871091
target = ['-arch', 'riscv64'];
10881092
break;
10891093
}
1094+
} else if (Platform.isWindows) {
1095+
cc = 'buildtools\\win-x64\\clang\\bin\\clang.exe';
1096+
shared = '-shared';
1097+
switch (_configuration.architecture) {
1098+
case Architecture.x64:
1099+
case Architecture.x64c:
1100+
case Architecture.simx64:
1101+
case Architecture.simx64c:
1102+
target = ['--target=x86_64-windows'];
1103+
break;
1104+
case Architecture.arm64:
1105+
case Architecture.arm64c:
1106+
case Architecture.simarm64:
1107+
case Architecture.simarm64c:
1108+
target = ['--target=arm64-windows'];
1109+
break;
1110+
}
1111+
ldFlags.add('-nostdlib');
1112+
ldFlags.add('-Wl,/NOENTRY');
10901113
} else {
10911114
throw "Platform not supported: ${Platform.operatingSystem}";
10921115
}
@@ -1096,8 +1119,8 @@ class PrecompilerCompilerConfiguration extends CompilerConfiguration
10961119
...ldFlags,
10971120
shared,
10981121
'-o',
1099-
'$tempDir/out.aotsnapshot',
1100-
'$tempDir/out.S'
1122+
tempAOTFile(tempDir),
1123+
tempAssemblyFile(tempDir),
11011124
];
11021125

11031126
return CompilationCommand('assemble', tempDir, bootstrapDependencies(), cc,
@@ -1109,7 +1132,7 @@ class PrecompilerCompilerConfiguration extends CompilerConfiguration
11091132
String tempDir, Map<String, String> environmentOverrides) {
11101133
var stripTool = "$ndkPath/toolchains/llvm/prebuilt/"
11111134
"$host-x86_64/bin/llvm-strip";
1112-
var args = ['--strip-unneeded', "$tempDir/out.aotsnapshot"];
1135+
var args = ['--strip-unneeded', tempAOTFile(tempDir)];
11131136
return CompilationCommand('strip', tempDir, bootstrapDependencies(),
11141137
stripTool, args, environmentOverrides,
11151138
alwaysCompile: !_useSdk);
@@ -1124,8 +1147,19 @@ class PrecompilerCompilerConfiguration extends CompilerConfiguration
11241147
/// almost identical configurations are tested simultaneously.
11251148
Command computeRemoveAssemblyCommand(String tempDir, List arguments,
11261149
Map<String, String> environmentOverrides) {
1127-
return CompilationCommand('remove_assembly', tempDir,
1128-
bootstrapDependencies(), 'rm', ['$tempDir/out.S'], environmentOverrides,
1150+
String exec;
1151+
List<String> args;
1152+
1153+
if (Platform.isWindows) {
1154+
exec = "cmd.exe";
1155+
args = ["/c", "del", tempAssemblyFile(tempDir)];
1156+
} else {
1157+
exec = "rm";
1158+
args = [tempAssemblyFile(tempDir)];
1159+
}
1160+
1161+
return CompilationCommand("remove_assembly", tempDir,
1162+
bootstrapDependencies(), exec, args, environmentOverrides,
11291163
alwaysCompile: !_useSdk);
11301164
}
11311165

@@ -1169,8 +1203,7 @@ class PrecompilerCompilerConfiguration extends CompilerConfiguration
11691203
// directory on the device, use that one instead.
11701204
dir = DartPrecompiledAdbRuntimeConfiguration.deviceTestDir;
11711205
}
1172-
originalArguments =
1173-
_replaceDartFiles(originalArguments, "$dir/out.aotsnapshot");
1206+
originalArguments = _replaceDartFiles(originalArguments, tempAOTFile(dir));
11741207

11751208
return [
11761209
if (_enableAsserts) '--enable_asserts',
@@ -1373,6 +1406,21 @@ abstract mixin class VMKernelCompilerMixin {
13731406

13741407
String tempKernelFile(String tempDir) =>
13751408
Path('$tempDir/out.dill').toNativePath();
1409+
String tempAssemblyFile(String tempDir) =>
1410+
Path('$tempDir/out.S').toNativePath();
1411+
String tempAOTFile(String tempDir) {
1412+
switch (_configuration.system) {
1413+
case System.android:
1414+
case System.fuchsia:
1415+
case System.linux:
1416+
return Path('$tempDir/libout.so').toNativePath();
1417+
case System.mac:
1418+
return Path('$tempDir/libout.dylib').toNativePath();
1419+
case System.win:
1420+
return Path('$tempDir/out.dll').toNativePath();
1421+
}
1422+
return Path('$tempDir/out.aotsnapshot').toNativePath();
1423+
}
13761424

13771425
Command computeCompileToKernelCommand(String tempDir, List<String> arguments,
13781426
Map<String, String> environmentOverrides) {

pkg/vm_service/test/common/test_helper.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Uri _getTestUri(String script) {
3535
// If running from pub we can assume that we're in the root of the package
3636
// directory.
3737
return Uri.parse('test/$script');
38-
} else if (io.Platform.script.toFilePath().endsWith('out.aotsnapshot')) {
38+
} else if (!io.Platform.script.toFilePath().endsWith('.dart')) {
3939
// We're running an AOT test. In this case, we need to use the exact URI we
4040
// launched with.
4141
return io.Platform.script;

runtime/bin/dartutils.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ dart::SimpleHashMap* DartUtils::environment_ = nullptr;
3535

3636
MagicNumberData appjit_magic_number = {8, {0xdc, 0xdc, 0xf6, 0xf6, 0, 0, 0, 0}};
3737
MagicNumberData aotelf_magic_number = {4, {0x7F, 0x45, 0x4C, 0x46, 0x0}};
38+
MagicNumberData aotpe_magic_number = {2, {0x4d, 0x5a}};
3839
MagicNumberData aotcoff_arm32_magic_number = {2, {0x01, 0xC0}};
3940
MagicNumberData aotcoff_arm64_magic_number = {2, {0xAA, 0x64}};
4041
MagicNumberData aotcoff_riscv32_magic_number = {2, {0x50, 0x32}};
@@ -404,6 +405,7 @@ DartUtils::MagicNumber DartUtils::SniffForMagicNumber(const char* filename) {
404405
ASSERT(aotelf_magic_number.length <= appjit_magic_number.length);
405406
ASSERT(static_cast<intptr_t>(sizeof(mach_o::mach_header::magic)) <=
406407
appjit_magic_number.length);
408+
ASSERT(aotpe_magic_number.length <= appjit_magic_number.length);
407409
ASSERT(aotcoff_arm32_magic_number.length <= appjit_magic_number.length);
408410
ASSERT(aotcoff_arm64_magic_number.length <= appjit_magic_number.length);
409411
ASSERT(aotcoff_riscv32_magic_number.length <= appjit_magic_number.length);
@@ -465,6 +467,10 @@ DartUtils::MagicNumber DartUtils::SniffForMagicNumber(const uint8_t* buffer,
465467
}
466468
}
467469

470+
if (CheckMagicNumber(buffer, buffer_length, aotpe_magic_number)) {
471+
return kAotPEMagicNumber;
472+
}
473+
468474
if (CheckMagicNumber(buffer, buffer_length, aotcoff_arm32_magic_number)) {
469475
return kAotCoffARM32MagicNumber;
470476
}

runtime/bin/dartutils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ class DartUtils {
264264
// ("cigam") ones, as we can't load a reverse-endian snapshot anyway.
265265
kAotMachO32MagicNumber,
266266
kAotMachO64MagicNumber,
267+
kAotPEMagicNumber,
267268
kAotCoffARM32MagicNumber,
268269
kAotCoffARM64MagicNumber,
269270
kAotCoffRISCV32MagicNumber,

runtime/bin/gen_snapshot.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,14 @@ static int ParseArguments(int argc,
297297
"an output file for --assembly.\n\n");
298298
return -1;
299299
}
300+
#if defined(DART_TARGET_OS_WINDOWS)
301+
if (debugging_info_filename != nullptr) {
302+
// TODO(https://github.com/dart-lang/sdk/issues/60812): Support PDB.
303+
Syslog::PrintErr(
304+
"warning: ignoring --save-debugging-info when "
305+
"generating assembly for Windows.\n\n");
306+
}
307+
#endif
300308
break;
301309
}
302310
}

runtime/include/dart_api.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3998,7 +3998,8 @@ DART_EXPORT Dart_Handle Dart_LoadingUnitLibraryUris(intptr_t loading_unit_id);
39983998
* debugging sections.
39993999
*
40004000
* If debug_callback_data is provided, debug_callback_data will be used with
4001-
* the callback to provide separate debugging information.
4001+
* the callback to provide separate debugging information. Ignored when
4002+
* targeting Windows.
40024003
*
40034004
* \return A valid handle if no error occurs during the operation.
40044005
*/

runtime/tests/vm/dart/awaiter_stacks/harness.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,10 @@ bool shouldSkip() {
249249
final stack = StackTrace.current.toString();
250250
final isObfuscateMode = !stack.contains('shouldSkip');
251251
final isDwarfStackTracesMode = stack.contains('*** ***');
252+
final isDLL = Platform.script.toString().endsWith(".dll");
252253

253254
// We should skip the test if we are running without DWARF stack
254-
// traces enabled but with obfuscation.
255-
return !isDwarfStackTracesMode && isObfuscateMode;
255+
// traces enabled but with obfuscation. Or if running from a DLL,
256+
// which lacks DWARF.
257+
return isDLL || (!isDwarfStackTracesMode && isObfuscateMode);
256258
}

runtime/tests/vm/dart/build_id_test.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'dart:developer';
6+
import 'dart:io';
67

78
import 'package:expect/expect.dart';
89

910
import 'use_flag_test_helper.dart';
1011

1112
void main() {
1213
final buildId = NativeRuntime.buildId;
13-
if (isAOTRuntime) {
14+
15+
if (Platform.script.toString().endsWith(".dll")) {
16+
Expect.isNull(buildId); // No build id in DLLs.
17+
} else if (isAOTRuntime) {
1418
Expect.isNotNull(buildId);
1519
Expect.isTrue(buildId!.isNotEmpty, 'Build ID is an empty string');
1620
} else {

runtime/tests/vm/dart/use_dwarf_stack_traces_flag_deferred_test.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,11 @@ Future<void> main() async {
3535
'use_dwarf_stack_traces_flag_deferred_program.dart',
3636
),
3737
runNonDwarf,
38-
[runElf, runAssembly],
38+
[
39+
runElf,
40+
// Don't run assembly on Windows since DLLs don't contain DWARF.
41+
if (!Platform.isWindows) runAssembly,
42+
],
3943
);
4044
}
4145

runtime/tests/vm/dart/use_dwarf_stack_traces_flag_helper.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Object get skipAssembly {
2323
if (isSimulator) {
2424
return "running on a simulated architecture";
2525
}
26-
return (Platform.isLinux || Platform.isMacOS)
26+
return (Platform.isLinux || Platform.isMacOS || Platform.isWindows)
2727
? false
2828
: "no process for assembling snapshots on this platform";
2929
}

runtime/tests/vm/dart/use_dwarf_stack_traces_flag_test.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ Future<void> main() async {
3434
// Only generate Mach-O on MacOS, since there is no MachOLoader
3535
// to run the binary on platforms where that isn't the native format.
3636
if (Platform.isMacOS) runMachODylib,
37-
runAssembly,
37+
// Don't run assembly on Windows since DLLs don't contain DWARF.
38+
if (!Platform.isWindows) runAssembly,
3839
],
3940
);
4041
}

runtime/tests/vm/dart/use_flag_test_helper.dart

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ String? get clangBuildToolsDir {
105105
return null;
106106
}
107107
var clangDir = path.join(sdkDir, 'buildtools', archDir, 'clang', 'bin');
108+
print(clangDir);
108109
return Directory(clangDir).existsSync() ? clangDir : null;
109110
}
110111

@@ -113,7 +114,7 @@ Future<void> assembleSnapshot(
113114
String snapshotPath, {
114115
bool debug = false,
115116
}) async {
116-
if (!Platform.isLinux && !Platform.isMacOS) {
117+
if (!Platform.isLinux && !Platform.isMacOS && !Platform.isWindows) {
117118
throw "Unsupported platform ${Platform.operatingSystem} for assembling";
118119
}
119120

@@ -171,20 +172,21 @@ Future<void> stripSnapshot(
171172
String strippedPath, {
172173
bool forceElf = false,
173174
}) async {
174-
if (!Platform.isLinux && !Platform.isMacOS) {
175+
if (!Platform.isLinux && !Platform.isMacOS && !Platform.isWindows) {
175176
throw "Unsupported platform ${Platform.operatingSystem} for stripping";
176177
}
177178

178179
var strip = 'strip';
179180

180-
if (isSimulator || (Platform.isMacOS && forceElf)) {
181-
final clangBuildTools = clangBuildToolsDir;
182-
if (clangBuildTools != null) {
183-
strip = path.join(clangBuildTools, 'llvm-strip');
184-
} else {
185-
throw 'Cannot strip ELF files for ${path.basename(buildDir)} '
186-
'without //buildtools on ${Platform.operatingSystem}';
187-
}
181+
final clangBuildTools = clangBuildToolsDir;
182+
if (clangBuildTools != null) {
183+
strip = path.join(
184+
clangBuildTools,
185+
Platform.isWindows ? 'llvm-strip.exe' : 'llvm-strip',
186+
);
187+
} else {
188+
throw 'Cannot strip ELF files for ${path.basename(buildDir)} '
189+
'without //buildtools on ${Platform.operatingSystem}';
188190
}
189191

190192
await run(strip, <String>['-o', strippedPath, snapshotPath]);

runtime/tests/vm/dart/use_resolve_dwarf_paths_flag_test.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ main(List<String> args) async {
1919
if (Platform.isAndroid) {
2020
return;
2121
}
22+
if (Platform.script.toString().endsWith(".dll")) {
23+
return;
24+
}
2225

2326
final isDwarfStackTraces = StackTrace.current.toString().contains('*** ***');
2427
if (!isDwarfStackTraces) {

runtime/vm/dart_api_impl.cc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6451,7 +6451,13 @@ static void CreateAppAOTSnapshot(
64516451
FullSnapshotWriter::kInitialSize);
64526452
ZoneWriteStream isolate_snapshot_instructions(T->zone(), kInitialSize);
64536453

6454-
const bool generate_debug = debug_callback_data != nullptr;
6454+
bool generate_debug = debug_callback_data != nullptr;
6455+
#if defined(DART_TARGET_OS_WINDOWS)
6456+
if (format == Dart_AotBinaryFormat_Assembly) {
6457+
// TODO(https://github.com/dart-lang/sdk/issues/60812): Support PDB.
6458+
generate_debug = false; // PDB unimplemented, no DWARF in PE.
6459+
}
6460+
#endif
64556461

64566462
auto* const deobfuscation_trie =
64576463
(strip && !generate_debug) ? nullptr
@@ -6574,8 +6580,6 @@ Dart_CreateAppAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback,
65746580
void* debug_callback_data) {
65756581
#if defined(TARGET_ARCH_IA32)
65766582
return Api::NewError("AOT compilation is not supported on IA32.");
6577-
#elif defined(DART_TARGET_OS_WINDOWS)
6578-
return Api::NewError("Assembly generation is not implemented for Windows.");
65796583
#elif !defined(DART_PRECOMPILER)
65806584
return Api::NewError(
65816585
"This VM was built without support for AOT compilation.");
@@ -6603,8 +6607,6 @@ DART_EXPORT Dart_Handle Dart_CreateAppAOTSnapshotAsAssemblies(
66036607
Dart_StreamingCloseCallback close_callback) {
66046608
#if defined(TARGET_ARCH_IA32)
66056609
return Api::NewError("AOT compilation is not supported on IA32.");
6606-
#elif defined(DART_TARGET_OS_WINDOWS)
6607-
return Api::NewError("Assembly generation is not implemented for Windows.");
66086610
#elif !defined(DART_PRECOMPILER)
66096611
return Api::NewError(
66106612
"This VM was built without support for AOT compilation.");
@@ -6627,8 +6629,6 @@ Dart_CreateVMAOTSnapshotAsAssembly(Dart_StreamingWriteCallback callback,
66276629
void* callback_data) {
66286630
#if defined(TARGET_ARCH_IA32)
66296631
return Api::NewError("AOT compilation is not supported on IA32.");
6630-
#elif defined(DART_TARGET_OS_WINDOWS)
6631-
return Api::NewError("Assembly generation is not implemented for Windows.");
66326632
#elif !defined(DART_PRECOMPILER)
66336633
return Api::NewError(
66346634
"This VM was built without support for AOT compilation.");

0 commit comments

Comments
 (0)