blob: 339fd26a8ca2c9dfa2fdf4e5fa40323222fd2b59 [file] [log] [blame]
// Copyright (c) 2023, 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:io';
import 'package:compiler/compiler_api.dart' as api;
import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/util/memory_compiler.dart';
import 'package:expect/expect.dart';
const int numShards = 4;
const List<String> dataDirs = ['data', '../inference/data'];
const Set<String> needsLibs = {'deferred.dart'};
const jsOutFilename = 'out.js';
const sourceMapFilename = '${jsOutFilename}.map';
const dumpInfoFilename = 'out.info.json';
typedef CompiledOutput = Map<api.OutputType, Map<String, String>>;
Future<CompiledOutput> compileWithSerialization(
{Uri? entryPoint,
required Map<String, dynamic> memorySourceFiles,
required List<String> options}) async {
final cfeDillUri = 'memory:cfe.dill';
final closedWorldUri = 'memory:world.data';
final globalDataUri = 'memory:global.data';
final codegenUri = 'memory:codegen';
final jsOutUri = 'memory:$jsOutFilename';
Future<CompiledOutput> compile(List<String> options) async {
final outputProvider = OutputCollector();
CompilationResult result = await runCompiler(
entryPoint: entryPoint,
memorySourceFiles: memorySourceFiles,
outputProvider: outputProvider,
unsafeToTouchSourceFiles: true,
options: options);
Expect.isTrue(result.isSuccess);
outputProvider.binaryOutputMap.forEach((fileName, binarySink) {
memorySourceFiles[fileName.path] = binarySink.list;
});
return outputProvider.clear();
}
await compile([...options, '--out=$cfeDillUri', Flags.cfeOnly]);
await compile([
...options,
'${Flags.inputDill}=$cfeDillUri',
'${Flags.writeClosedWorld}=$closedWorldUri'
]);
await compile([
...options,
'${Flags.inputDill}=$cfeDillUri',
'${Flags.readClosedWorld}=$closedWorldUri',
'${Flags.writeData}=$globalDataUri'
]);
await compile([
...options,
'${Flags.inputDill}=$cfeDillUri',
'${Flags.readClosedWorld}=$closedWorldUri',
'${Flags.readData}=$globalDataUri',
'${Flags.writeCodegen}=$codegenUri',
'${Flags.codegenShards}=2',
'${Flags.codegenShard}=0',
]);
await compile([
...options,
'${Flags.inputDill}=$cfeDillUri',
'${Flags.readClosedWorld}=$closedWorldUri',
'${Flags.readData}=$globalDataUri',
'${Flags.writeCodegen}=$codegenUri',
'${Flags.codegenShards}=2',
'${Flags.codegenShard}=1',
]);
final output = await compile([
...options,
'${Flags.inputDill}=$cfeDillUri',
'${Flags.readClosedWorld}=$closedWorldUri',
'${Flags.readData}=$globalDataUri',
'${Flags.readCodegen}=$codegenUri',
'${Flags.codegenShards}=2',
'--out=$jsOutUri'
]);
return output;
}
Future<CompiledOutput> compileWithoutSerialization(
{Uri? entryPoint,
required Map<String, dynamic> memorySourceFiles,
required List<String> options}) async {
final jsOutUri = 'memory:$jsOutFilename';
final outputProvider = OutputCollector();
CompilationResult result = await runCompiler(
entryPoint: entryPoint,
memorySourceFiles: memorySourceFiles,
unsafeToTouchSourceFiles: true,
outputProvider: outputProvider,
options: [...options, '--out=$jsOutUri']);
Expect.isTrue(result.isSuccess);
return outputProvider.clear();
}
// TODO(natebiggs): Check dump info diff when the results are aligned with and
// without serialization.
Set<api.OutputType> _outputTypesToIgnore = {api.OutputType.dumpInfo};
Future<void> compareResults(CompiledOutput serializationResult,
CompiledOutput noSerializationResult) async {
serializationResult.forEach((outputType, outputs) {
if (_outputTypesToIgnore.contains(outputType)) return;
Expect.isTrue(noSerializationResult.containsKey(outputType));
final otherOutputs = noSerializationResult[outputType]!;
Expect.mapEquals(outputs, otherOutputs);
});
}
Future runTests(List<String> args, int shard) async {
assert(shard >= 0 && shard < numShards,
'Shard must be between 0 and ${numShards - 1} (inclusive)');
final libDirectory = Directory.fromUri(Platform.script.resolve('libs'));
final testFiles = dataDirs
.map((e) => Directory.fromUri(Platform.script.resolve('data')))
.expand((dataDir) => dataDir.listSync());
int i = 0;
for (final testFile in testFiles) {
if (!testFile.uri.pathSegments.last.endsWith('.dart')) continue;
if (i++ % numShards != shard) continue;
String name = testFile.uri.pathSegments.last;
List<String> testOptions = [Flags.dumpInfo];
print('----------------------------------------------------------------');
print('Test file: ${testFile.uri}');
String mainCode = await File.fromUri(testFile.uri).readAsString();
final mainUri = _createUri('src/main.dart');
Map<String, dynamic> memorySourceFiles = {mainUri.path: mainCode};
if (needsLibs.contains(name)) {
print('Supporting libraries:');
String filePrefix = name.substring(0, name.lastIndexOf('.'));
await for (final libFile in libDirectory.list()) {
String libFileName = libFile.uri.pathSegments.last;
if (libFileName.startsWith(filePrefix)) {
print(' - libs/$libFileName');
Uri libFileUri = _createUri('libs/$libFileName');
String libCode = await File.fromUri(libFile.uri).readAsString();
memorySourceFiles[libFileUri.path] = libCode;
}
}
}
final serializationResult = await compileWithSerialization(
entryPoint: mainUri,
memorySourceFiles: memorySourceFiles,
options: testOptions);
final noSerializationResult = await compileWithoutSerialization(
entryPoint: mainUri,
memorySourceFiles: memorySourceFiles,
options: testOptions);
await compareResults(serializationResult, noSerializationResult);
}
}
// Pretend this is a dart2js_native test to allow use of 'native' keyword
// and import of private libraries.
Uri _createUri(String fileName) {
return Uri.parse('memory:sdk/tests/web/native/$fileName');
}