| // Copyright (c) 2019, 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 'dart:typed_data'; | 
 |  | 
 | import 'package:collection/collection.dart'; | 
 | import 'package:kernel/binary/tag.dart' show Tag; | 
 | import 'package:path/path.dart' as path; | 
 |  | 
 | import 'dart2native_macho.dart' show writeAppendedMachOExecutable; | 
 | import 'dart2native_pe.dart' show writeAppendedPortableExecutable; | 
 |  | 
 | final binDir = File(Platform.resolvedExecutable).parent; | 
 | final executableSuffix = Platform.isWindows ? '.exe' : ''; | 
 | final genKernel = path.join( | 
 |   binDir.path, | 
 |   'snapshots', | 
 |   'gen_kernel_aot.dart.snapshot', | 
 | ); | 
 | final genSnapshot = path.join( | 
 |   binDir.path, | 
 |   'utils', | 
 |   'gen_snapshot$executableSuffix', | 
 | ); | 
 | final platformDill = path.join( | 
 |   binDir.parent.path, | 
 |   'lib', | 
 |   '_internal', | 
 |   'vm_platform_strong.dill', | 
 | ); | 
 | final productPlatformDill = path.join( | 
 |   binDir.parent.path, | 
 |   'lib', | 
 |   '_internal', | 
 |   'vm_platform_strong_product.dill', | 
 | ); | 
 |  | 
 | // Maximum page size across all supported architectures (arm64 macOS has 16K | 
 | // pages, some arm64 Linux distributions have 64K pages). | 
 | const elfPageSize = 65536; | 
 | const appJitMagicNumber = <int>[0xdc, 0xdc, 0xf6, 0xf6, 0, 0, 0, 0]; | 
 |  | 
 | Future<bool> isKernelFile(String path) async { | 
 |   const kernelMagicNumber = Tag.ComponentFile; | 
 |   // Convert the 32-bit header into a list of 4 bytes. | 
 |   final kernelMagicNumberList = Uint8List(4) | 
 |     ..buffer.asByteData().setInt32( | 
 |           0, | 
 |           kernelMagicNumber, | 
 |           Endian.big, | 
 |         ); | 
 |  | 
 |   final header = await File(path) | 
 |       .openRead( | 
 |         0, | 
 |         kernelMagicNumberList.length, | 
 |       ) | 
 |       .first; | 
 |  | 
 |   return header.equals(kernelMagicNumberList); | 
 | } | 
 |  | 
 | // WARNING: this method is used within google3, so don't try to refactor so | 
 | // [dartaotruntime] is a constant inside this file. | 
 | Future<void> writeAppendedExecutable( | 
 |   String dartaotruntime, | 
 |   String payloadPath, | 
 |   String outputPath, | 
 | ) async { | 
 |   if (Platform.isMacOS) { | 
 |     return await writeAppendedMachOExecutable( | 
 |         dartaotruntime, payloadPath, outputPath); | 
 |   } else if (Platform.isWindows) { | 
 |     return await writeAppendedPortableExecutable( | 
 |         dartaotruntime, payloadPath, outputPath); | 
 |   } | 
 |  | 
 |   final dartaotruntimeFile = File(dartaotruntime); | 
 |   final dartaotruntimeLength = dartaotruntimeFile.lengthSync(); | 
 |  | 
 |   final padding = (elfPageSize - dartaotruntimeLength) % elfPageSize; | 
 |   final padBytes = Uint8List(padding); | 
 |   final offset = dartaotruntimeLength + padding; | 
 |  | 
 |   // Note: The offset is always Little Endian regardless of host. | 
 |   final offsetBytes = ByteData(8) // 64 bit in bytes. | 
 |     ..setUint64(0, offset, Endian.little); | 
 |  | 
 |   final outputFile = File(outputPath).openWrite(); | 
 |   outputFile.add(dartaotruntimeFile.readAsBytesSync()); | 
 |   outputFile.add(padBytes); | 
 |   outputFile.add(File(payloadPath).readAsBytesSync()); | 
 |   outputFile.add(offsetBytes.buffer.asUint8List()); | 
 |   outputFile.add(appJitMagicNumber); | 
 |   await outputFile.close(); | 
 | } | 
 |  | 
 | Future<ProcessResult> markExecutable(String outputFile) { | 
 |   return Process.run('chmod', ['+x', outputFile]); | 
 | } | 
 |  | 
 | /// Generates kernel by running the provided [genKernel] path. | 
 | /// | 
 | /// Also takes a path to the [recordedUsagesFile] JSON file, where the method | 
 | /// calls to static functions annotated with `@RecordUse` will be collected. | 
 | Future<ProcessResult> generateKernelHelper({ | 
 |   required String dartaotruntime, | 
 |   String? sourceFile, | 
 |   required String kernelFile, | 
 |   String? packages, | 
 |   List<String> defines = const [], | 
 |   String enableExperiment = '', | 
 |   String? targetOS, | 
 |   List<String> extraGenKernelOptions = const [], | 
 |   String? nativeAssets, | 
 |   String? recordedUsagesFile, | 
 |   String? depFile, | 
 |   bool enableAsserts = false, | 
 |   bool fromDill = false, | 
 |   bool aot = false, | 
 |   bool embedSources = false, | 
 |   bool linkPlatform = true, | 
 |   bool product = true, | 
 | }) { | 
 |   final args = [ | 
 |     genKernel, | 
 |     '--platform=${product ? productPlatformDill : platformDill}', | 
 |     if (product) '-Ddart.vm.product=true', | 
 |     if (enableExperiment.isNotEmpty) '--enable-experiment=$enableExperiment', | 
 |     if (targetOS != null) '--target-os=$targetOS', | 
 |     if (fromDill) '--from-dill=$sourceFile', | 
 |     if (aot) '--aot', | 
 |     if (!embedSources) '--no-embed-sources', | 
 |     if (!linkPlatform) '--no-link-platform', | 
 |     if (enableAsserts) '--enable-asserts', | 
 |     ...defines.map((d) => '-D$d'), | 
 |     if (packages != null) '--packages=$packages', | 
 |     if (nativeAssets != null) '--native-assets=$nativeAssets', | 
 |     if (recordedUsagesFile != null) | 
 |       '--recorded-usages-file=$recordedUsagesFile', | 
 |     if (depFile != null) '--depfile=$depFile', | 
 |     '--output=$kernelFile', | 
 |     ...extraGenKernelOptions, | 
 |     if (sourceFile != null) sourceFile, | 
 |   ]; | 
 |   return Process.run(dartaotruntime, args); | 
 | } | 
 |  | 
 | Future<ProcessResult> generateAotSnapshotHelper( | 
 |     String kernelFile, | 
 |     String snapshotFile, | 
 |     String? debugFile, | 
 |     bool enableAsserts, | 
 |     List<String> extraGenSnapshotOptions) { | 
 |   return Process.run(genSnapshot, [ | 
 |     '--snapshot-kind=app-aot-elf', | 
 |     '--elf=$snapshotFile', | 
 |     if (debugFile != null) '--save-debugging-info=$debugFile', | 
 |     if (debugFile != null) '--dwarf-stack-traces', | 
 |     if (debugFile != null) '--strip', | 
 |     if (enableAsserts) '--enable-asserts', | 
 |     ...extraGenSnapshotOptions, | 
 |     kernelFile | 
 |   ]); | 
 | } |