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>
128 lines
3.7 KiB
C++
128 lines
3.7 KiB
C++
// Copyright (c) 2016, 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.
|
|
|
|
#ifndef RUNTIME_VM_KERNEL_H_
|
|
#define RUNTIME_VM_KERNEL_H_
|
|
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
#include "platform/assert.h"
|
|
#include "vm/allocation.h"
|
|
#include "vm/globals.h"
|
|
#include "vm/growable_array.h"
|
|
#include "vm/object.h"
|
|
#include "vm/token_position.h"
|
|
|
|
namespace dart {
|
|
|
|
class Field;
|
|
class ParsedFunction;
|
|
class Zone;
|
|
|
|
namespace kernel {
|
|
|
|
class Reader;
|
|
|
|
class StringIndex {
|
|
public:
|
|
StringIndex() : value_(-1) {}
|
|
explicit StringIndex(int value) : value_(value) {}
|
|
|
|
operator int() const { return value_; }
|
|
|
|
private:
|
|
int value_;
|
|
};
|
|
|
|
class NameIndex {
|
|
public:
|
|
NameIndex() : value_(-1) {}
|
|
explicit NameIndex(int value) : value_(value) {}
|
|
|
|
operator int() const { return value_; }
|
|
|
|
private:
|
|
int value_;
|
|
};
|
|
|
|
const uint8_t kNativeYieldFlags = 0x2;
|
|
|
|
enum LogicalOperator { kAnd, kOr };
|
|
|
|
class Program {
|
|
public:
|
|
~Program() {
|
|
if (buffer_ownership_ && kernel_data_ != NULL) {
|
|
ASSERT(release_callback != NULL);
|
|
release_callback(const_cast<uint8_t*>(kernel_data_));
|
|
}
|
|
kernel_data_ = NULL;
|
|
}
|
|
|
|
/**
|
|
* Read a kernel Program from the given Reader. Note the returned Program
|
|
* can potentially contain several "sub programs", though the library count
|
|
* etc will reference the last "sub program" only.
|
|
* @param reader
|
|
* @param take_buffer_ownership if set to true, the release callback will be
|
|
* called upon Program destruction, i.e. the data from reader will likely be
|
|
* released. If set to false the data will not be released. This is for
|
|
* instance useful for creating Programs out of "sub programs" where each
|
|
* "sub program" should not try to release the buffer.
|
|
* @return
|
|
*/
|
|
static Program* ReadFrom(Reader* reader, bool take_buffer_ownership = true);
|
|
|
|
bool is_single_program() { return single_program_; }
|
|
NameIndex main_method() { return main_method_reference_; }
|
|
intptr_t source_table_offset() const { return source_table_offset_; }
|
|
intptr_t string_table_offset() const { return string_table_offset_; }
|
|
intptr_t name_table_offset() const { return name_table_offset_; }
|
|
const uint8_t* kernel_data() { return kernel_data_; }
|
|
intptr_t kernel_data_size() { return kernel_data_size_; }
|
|
intptr_t library_count() { return library_count_; }
|
|
void set_release_buffer_callback(Dart_ReleaseBufferCallback callback) {
|
|
release_callback = callback;
|
|
}
|
|
|
|
private:
|
|
Program()
|
|
: kernel_data_(NULL), kernel_data_size_(-1), release_callback(NULL) {}
|
|
|
|
bool single_program_;
|
|
bool buffer_ownership_;
|
|
NameIndex main_method_reference_; // Procedure.
|
|
intptr_t library_count_;
|
|
|
|
// The offset from the start of the binary to the start of the source table.
|
|
intptr_t source_table_offset_;
|
|
|
|
// The offset from the start of the binary to the canonical name table.
|
|
intptr_t name_table_offset_;
|
|
|
|
// The offset from the start of the binary to the start of the string table.
|
|
intptr_t string_table_offset_;
|
|
|
|
const uint8_t* kernel_data_;
|
|
intptr_t kernel_data_size_;
|
|
Dart_ReleaseBufferCallback release_callback;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(Program);
|
|
};
|
|
|
|
ParsedFunction* ParseStaticFieldInitializer(Zone* zone, const Field& field);
|
|
|
|
bool FieldHasFunctionLiteralInitializer(const Field& field,
|
|
TokenPosition* start,
|
|
TokenPosition* end);
|
|
|
|
} // namespace kernel
|
|
|
|
kernel::Program* ReadPrecompiledKernelFromBuffer(const uint8_t* buffer,
|
|
intptr_t buffer_length);
|
|
|
|
} // namespace dart
|
|
|
|
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
|
#endif // RUNTIME_VM_KERNEL_H_
|