// 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. // @dart = 2.9 import 'package:kernel/binary/ast_from_binary.dart'; import 'package:kernel/binary/ast_to_binary.dart'; import 'package:kernel/src/tool/find_referenced_libraries.dart'; import 'binary/utils.dart'; main() { Component component1 = createComponent(42); Component component2 = createComponent(43); expectReachable( findAllReferencedLibraries(component1.libraries), component1.libraries); if (duplicateLibrariesReachable(component1.libraries)) { throw "Didn't expect duplicates libraries!"; } expectReachable( findAllReferencedLibraries(component2.libraries), component2.libraries); if (duplicateLibrariesReachable(component2.libraries)) { throw "Didn't expect duplicates libraries!"; } ByteSink sink = new ByteSink(); new BinaryPrinter(sink).writeComponentFile(component1); List writtenBytes1 = sink.builder.takeBytes(); sink = new ByteSink(); new BinaryPrinter(sink).writeComponentFile(component2); List writtenBytes2 = sink.builder.takeBytes(); // Loading a single one works as one would expect: It's linked to itself. Component component1Prime = new Component(); new BinaryBuilder(writtenBytes1).readSingleFileComponent(component1Prime); Procedure target1 = getMainTarget(component1Prime); Procedure procedureLib1 = getLibProcedure(component1Prime); if (target1 != procedureLib1) throw "Unexpected target."; expectReachable(findAllReferencedLibraries(component1Prime.libraries), component1Prime.libraries); if (duplicateLibrariesReachable(component1Prime.libraries)) { throw "Didn't expect duplicates libraries!"; } // Loading another one saying it should overwrite works as one would expect // for this component: It gives a component that is linked to itself that is // different from the one loaded "on top of". Component component2Prime = new Component(nameRoot: component1Prime.root); new BinaryBuilder(writtenBytes2, alwaysCreateNewNamedNodes: true) .readSingleFileComponent(component2Prime); Procedure target2 = getMainTarget(component2Prime); Procedure procedureLib2 = getLibProcedure(component2Prime); if (procedureLib2 == procedureLib1) throw "Unexpected procedure."; if (target2 != procedureLib2) throw "Unexpected target."; expectReachable(findAllReferencedLibraries(component2Prime.libraries), component2Prime.libraries); if (duplicateLibrariesReachable(component2Prime.libraries)) { throw "Didn't expect duplicates libraries!"; } // The old one that was loaded on top of was re-linked so it also points to // procedureLib2. target1 = getMainTarget(component1Prime); if (target1 != procedureLib2) throw "Unexpected target."; // Relink back and forth a number of times: It keeps working as expected. for (int i = 0; i < 6; i++) { // Before the relink the lib from component2Prime is also reachable! expectReachable( findAllReferencedLibraries(component1Prime.libraries), [] ..addAll(component1Prime.libraries) ..add(procedureLib2.enclosingLibrary)); if (!duplicateLibrariesReachable(component1Prime.libraries)) { throw "Expected duplicates libraries!"; } // Relinking component1Prime works as one would expected: Both components // main now points to procedureLib1. component1Prime.relink(); // After the relink only the libs from component1Prime are reachable! expectReachable(findAllReferencedLibraries(component1Prime.libraries), component1Prime.libraries); if (duplicateLibrariesReachable(component1Prime.libraries)) { throw "Didn't expect duplicates libraries!"; } target1 = getMainTarget(component1Prime); if (target1 != procedureLib1) throw "Unexpected target."; target2 = getMainTarget(component2Prime); if (target2 != procedureLib1) throw "Unexpected target."; // Before the relink the lib from component1Prime is also reachable! expectReachable( findAllReferencedLibraries(component2Prime.libraries), [] ..addAll(component2Prime.libraries) ..add(procedureLib1.enclosingLibrary)); if (!duplicateLibrariesReachable(component2Prime.libraries)) { throw "Expected duplicates libraries!"; } // Relinking component2Prime works as one would expected: Both components // main now points to procedureLib2. component2Prime.relink(); // After the relink only the libs from component1Prime are reachable! expectReachable(findAllReferencedLibraries(component2Prime.libraries), component2Prime.libraries); if (duplicateLibrariesReachable(component2Prime.libraries)) { throw "Didn't expect duplicates libraries!"; } target1 = getMainTarget(component1Prime); if (target1 != procedureLib2) throw "Unexpected target."; target2 = getMainTarget(component2Prime); if (target2 != procedureLib2) throw "Unexpected target."; } } void expectReachable( Set findAllReferencedLibraries, List libraries) { Set onlyInReferenced = findAllReferencedLibraries.toSet() ..removeAll(libraries); Set onlyInLibraries = libraries.toSet() ..removeAll(findAllReferencedLibraries); if (onlyInReferenced.isNotEmpty || onlyInLibraries.isNotEmpty) { throw "Expected to be the same, but ${onlyInReferenced} was only in " "reachable and ${onlyInLibraries} was only in libraries"; } } Procedure getLibProcedure(Component component1Prime) { if (component1Prime.libraries[1].importUri != Uri.parse('org-dartlang:///lib.dart')) { throw "Expected lib second, got ${component1Prime.libraries[1].importUri}"; } Procedure procedureLib = component1Prime.libraries[1].procedures[0]; return procedureLib; } Procedure getMainTarget(Component component1Prime) { if (component1Prime.libraries[0].importUri != Uri.parse('org-dartlang:///main.dart')) { throw "Expected main first, got ${component1Prime.libraries[0].importUri}"; } Block block = component1Prime.libraries[0].procedures[0].function.body; ReturnStatement returnStatement = block.statements[0]; StaticInvocation staticInvocation = returnStatement.expression; Procedure target = staticInvocation.target; return target; } Component createComponent(int literal) { final Uri libUri = Uri.parse('org-dartlang:///lib.dart'); final Library lib = new Library(libUri, fileUri: libUri); final Block libProcedureBody = new Block([new ReturnStatement(new IntLiteral(literal))]); final Procedure libProcedure = new Procedure( new Name("method"), ProcedureKind.Method, new FunctionNode(libProcedureBody, returnType: new DynamicType()), fileUri: libUri); lib.addProcedure(libProcedure); final Uri mainUri = Uri.parse('org-dartlang:///main.dart'); final Library main = new Library(mainUri, fileUri: mainUri); final Block mainProcedureBody = new Block([ new ReturnStatement( new StaticInvocation(libProcedure, new Arguments.empty())) ]); final Procedure mainProcedure = new Procedure( new Name("method"), ProcedureKind.Method, new FunctionNode(mainProcedureBody, returnType: new DynamicType()), fileUri: mainUri); main.addProcedure(mainProcedure); return new Component(libraries: [main, lib]) ..setMainMethodAndMode(null, false, NonNullableByDefaultCompiledMode.Weak); }