07b6ec3425
The kernel format has been designed so that one can concatenate several dill files into one file and then load it. For instance the dart function BinaryBuilder.readProgram supports this. Currently a dill file contains one or more programs. In the VM each of these programs are called either program or subprogram. Technically a dill "program" isn't necessarily a program at all (e.g. it could be missing a library). This naming snafu should probably be cleaned up at some point, but that's for another CL. When loading a dill file via BinaryBuilder.readProgram what happens is this: - Each program in the dill file ends in 4 bytes that indicates the size of the program. - Reading the input from the end one can then read the size, skip back that amount of bytes, if we have more data (i.e. there's another program), read another size and so on, and continue until we have accounted for all bytes in the input. - We then read each program from the start, and basically overwrite any library, class, procedure etc. we find. The first main reference found is the one used though. (Saying that we overwrite is not completely true, but when the library is a non-external library that's basically what happens). This CL introduces (some) support on the C++ side for the same thing. So far the C++ side could only handle single-program-dills, and trying to load anything else would probably crash the VM. The support added is this: - Assume the SDK (i.e. vm_platform.dill) is not a concatenated file (error out if it is). - For user provided input, loop over each contained program one-by-one, for each individual one behave as normal. - The way LibraryLoad is implemented (i.e. it skips if the library is already loaded) this means that it currently would behave differently than the dart version (i.e. the first one is used, not the last one). For now it is assumed that that's not a problem. - There is a possibly snafu if the same script is included several times. This could probably mostly be remedied by not creating scripts up front, but only as needed. By the "keep only one" (and fixing the above point, probably by simply loading in the opposite order, i.e. last program in the binary first) the (theoretical) problem would probably do away. Note that we will have separate string tables, canonical name tables etc per "sub program" and that there might be some duplication. The implementation was tested as indicated below, but introduces no tests. $ cat test_lib1.dart import "test_lib2.dart" as lib2; String lib1field = "lib #1 field!!"; main() { foo(); lib2.foo(); print("From lib2: ${lib2.lib2field}"); } foo() { print("Hello, Foo, from test_lib1!"); var x = 42; print(x); } $ cat test_lib2.dart String lib2field = "Lib #2 field!!!!"; foo() { print("Hello, Foo, from test_lib2!"); var y = 34; print(y); } $ out/ReleaseX64/dart pkg/front_end/tool/_fasta/compile.dart --packages=.packages --platform=out/ReleaseX64/vm_platform.dill test_lib1.dart $ ls -lha test_lib1.dart.dill [...] 4.2M Oct 26 14:42 test_lib1.dart.dill $ dart pkg/kernel/bin/split.dart test_lib1.dart.dill Wrote test_lib1.dart.dill.part1.dill Wrote test_lib1.dart.dill.part2.dill $ ls -lha test_lib1.dart.dill.part{1,2}.dill [...] 811 Oct 26 14:42 test_lib1.dart.dill.part1.dill [...] 582 Oct 26 14:42 test_lib1.dart.dill.part2.dill $ cat test_lib1.dart.dill.part1.dill test_lib1.dart.dill.part2.dill > test_lib1.dart.dill.concat.dill $ ls -lha test_lib1.dart.dill.concat.dill [...] 1.4K Oct 26 14:44 test_lib1.dart.dill.concat.dill $ out/ReleaseX64/dart --kernel-binaries=out/ReleaseX64 --packages=.packages test_lib1.dart.dill.concat.dill Hello, Foo, from test_lib1! 42 Hello, Foo, from test_lib2! 34 From lib2: Lib #2 field!!!! Change-Id: I233a033aa3042b202dd4708908a5be3089474588 Reviewed-on: https://dart-review.googlesource.com/16820 Commit-Queue: Jens Johansen <jensj@google.com> Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>