dart-sdk/runtime/vm/kernel_loader.h
Martin Kustermann d354a28cb2 [kernel] Add kernel2kernel constant evaluation, binary format as well as vm support
The introduced "constants" transformation can evaluate constant expressions.  The
original use-sites of constant expressions are replaced by a new [ConstantExpression]
node, which points to a subclass of a new [Constant] class hierarchy.  Constant
[Field]s and [VariableDeclarations]s will be removed, since all use-sites are
re-written.

The [Constant] class hierarchy is, similarly to the [DartType] class hierarchy, not
part of the AST tree (also has no parent pointer).  The constants form a
DAG (directed acyclic graph).

There is no canonicalization requirement of the [Constant] objects referenced by the
AST (via [ConstantExpression]).  Although it is beneficial to canonicalize them during
construction, since it reduces time spent in operator==/hashCode.

This CL furthermore adds support for a constant table in the binary format.  Similarly
to [String]s, we canonicalize the constants before writing the table to the binary.
The constant table entries in the binary are written in a post-order way, to ensure
easy construction on the backend side.

The text format will be augmented with a "constants { ... }" section at the end,
which lists the constants in the same order as in the binary format.

The transformation can be used by those backends who choose to do so.  It is not
enabled by default atm.  It should therefore not affect analyzer, fasta or other
components.

Change-Id: I57cd9624fedcf537ab6870db76246149647bed21
Reviewed-on: https://dart-review.googlesource.com/14382
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Kevin Millikin <kmillikin@google.com>
2017-11-16 11:08:02 +00:00

297 lines
9.2 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_LOADER_H_
#define RUNTIME_VM_KERNEL_LOADER_H_
#if !defined(DART_PRECOMPILED_RUNTIME)
#include <map>
#include "vm/compiler/frontend/kernel_binary_flowgraph.h"
#include "vm/compiler/frontend/kernel_to_il.h"
#include "vm/kernel.h"
#include "vm/object.h"
namespace dart {
namespace kernel {
class KernelLoader;
class BuildingTranslationHelper : public TranslationHelper {
public:
BuildingTranslationHelper(KernelLoader* loader, Thread* thread)
: TranslationHelper(thread), loader_(loader) {}
virtual ~BuildingTranslationHelper() {}
virtual RawLibrary* LookupLibraryByKernelLibrary(NameIndex library);
virtual RawClass* LookupClassByKernelClass(NameIndex klass);
private:
KernelLoader* loader_;
};
template <typename VmType>
class Mapping {
public:
bool Lookup(intptr_t canonical_name, VmType** handle) {
typename MapType::Pair* pair = map_.LookupPair(canonical_name);
if (pair != NULL) {
*handle = pair->value;
return true;
}
return false;
}
void Insert(intptr_t canonical_name, VmType* object) {
map_.Insert(canonical_name, object);
}
private:
typedef IntMap<VmType*> MapType;
MapType map_;
};
class LibraryIndex {
public:
// |kernel_data| is the kernel data for one library alone.
explicit LibraryIndex(const TypedData& kernel_data);
intptr_t class_count() const { return class_count_; }
intptr_t procedure_count() const { return procedure_count_; }
intptr_t ClassOffset(intptr_t index) const {
return reader_.ReadUInt32At(class_index_offset_ + index * 4);
}
intptr_t ProcedureOffset(intptr_t index) const {
return reader_.ReadUInt32At(procedure_index_offset_ + index * 4);
}
intptr_t SizeOfClassAtOffset(intptr_t class_offset) const {
for (intptr_t i = 0, offset = class_index_offset_; i < class_count_;
++i, offset += 4) {
if (static_cast<intptr_t>(reader_.ReadUInt32At(offset)) == class_offset) {
return reader_.ReadUInt32At(offset + 4) - class_offset;
}
}
UNREACHABLE();
return -1;
}
private:
Reader reader_;
intptr_t class_index_offset_;
intptr_t class_count_;
intptr_t procedure_index_offset_;
intptr_t procedure_count_;
DISALLOW_COPY_AND_ASSIGN(LibraryIndex);
};
class ClassIndex {
public:
// |class_offset| is the offset of class' kernel data in |buffer| of
// size |size|. The size of the class' kernel data is |class_size|.
ClassIndex(const uint8_t* buffer,
intptr_t buffer_size,
intptr_t class_offset,
intptr_t class_size);
// |class_offset| is the offset of class' kernel data in |kernel_data|.
// The size of the class' kernel data is |class_size|.
ClassIndex(const TypedData& kernel_data,
intptr_t class_offset,
intptr_t class_size);
intptr_t procedure_count() const { return procedure_count_; }
intptr_t ProcedureOffset(intptr_t index) const {
return reader_.ReadUInt32At(procedure_index_offset_ + index * 4);
}
private:
void Init(intptr_t class_offset, intptr_t class_size);
Reader reader_;
intptr_t procedure_count_;
intptr_t procedure_index_offset_;
DISALLOW_COPY_AND_ASSIGN(ClassIndex);
};
class KernelLoader {
public:
explicit KernelLoader(Program* program);
static Object& LoadEntireProgram(Program* program);
// Returns the library containing the main procedure, null if there
// was no main procedure, or a failure object if there was an error.
Object& LoadProgram(bool process_pending_classes = true);
// Finds all libraries that have been modified in this incremental
// version of the kernel program file.
static void FindModifiedLibraries(Program* program,
Isolate* isolate,
BitVector* modified_libs,
bool force_reload);
void LoadLibrary(intptr_t index);
static void FinishLoading(const Class& klass);
const Array& ReadConstantTable();
void AnnotateNativeProcedures(const Array& constant_table);
const String& DartSymbol(StringIndex index) {
return translation_helper_.DartSymbol(index);
}
const String& LibraryUri(intptr_t library_index) {
return translation_helper_.DartSymbol(
translation_helper_.CanonicalNameString(
library_canonical_name(library_index)));
}
intptr_t library_offset(intptr_t index) {
kernel::Reader reader(program_->kernel_data(),
program_->kernel_data_size());
return reader.ReadFromIndexNoReset(reader.size(),
LibraryCountFieldCountFromEnd + 1,
program_->library_count() + 1, index);
}
NameIndex library_canonical_name(intptr_t index) {
kernel::Reader reader(program_->kernel_data(),
program_->kernel_data_size());
reader.set_offset(library_offset(index));
// Start reading library.
reader.ReadFlags();
return reader.ReadCanonicalNameReference();
}
uint8_t CharacterAt(StringIndex string_index, intptr_t index);
private:
friend class BuildingTranslationHelper;
KernelLoader(const Script& script,
const TypedData& kernel_data,
intptr_t data_program_offset);
void initialize_fields();
static void index_programs(kernel::Reader* reader,
GrowableArray<intptr_t>* subprogram_file_starts);
void walk_incremental_kernel(BitVector* modified_libs);
void LoadPreliminaryClass(ClassHelper* class_helper,
intptr_t type_parameter_count);
Class& LoadClass(const Library& library,
const Class& toplevel_class,
intptr_t class_end);
void FinishClassLoading(const Class& klass,
const Library& library,
const Class& toplevel_class,
intptr_t class_offset,
const ClassIndex& class_index,
ClassHelper* class_helper);
void LoadProcedure(const Library& library,
const Class& owner,
bool in_class,
intptr_t procedure_end);
RawArray* MakeFunctionsArray();
RawScript* LoadScriptAt(intptr_t index);
// If klass's script is not the script at the uri index, return a PatchClass
// for klass whose script corresponds to the uri index.
// Otherwise return klass.
const Object& ClassForScriptAt(const Class& klass, intptr_t source_uri_index);
RawScript* ScriptAt(intptr_t source_uri_index,
StringIndex import_uri = StringIndex());
void GenerateFieldAccessors(const Class& klass,
const Field& field,
FieldHelper* field_helper);
void SetupFieldAccessorFunction(const Class& klass, const Function& function);
void LoadLibraryImportsAndExports(Library* library);
Library& LookupLibrary(NameIndex library);
Class& LookupClass(NameIndex klass);
RawFunction::Kind GetFunctionType(ProcedureHelper::Kind procedure_kind);
void EnsureExternalClassIsLookedUp() {
if (external_name_class_.IsNull()) {
ASSERT(external_name_field_.IsNull());
const Library& internal_lib =
Library::Handle(zone_, dart::Library::InternalLibrary());
external_name_class_ = internal_lib.LookupClass(Symbols::ExternalName());
external_name_field_ = external_name_class_.LookupField(Symbols::name());
} else {
ASSERT(!external_name_field_.IsNull());
}
}
void EnsurePotentialNatives() {
potential_natives_ = kernel_program_info_.potential_natives();
if (potential_natives_.IsNull()) {
// To avoid too many grows in this array, we'll set it's initial size to
// something close to the actual number of potential native functions.
potential_natives_ = GrowableObjectArray::New(100, Heap::kNew);
kernel_program_info_.set_potential_natives(potential_natives_);
}
}
Program* program_;
Thread* thread_;
Zone* zone_;
Isolate* isolate_;
bool is_service_isolate_;
Array& patch_classes_;
ActiveClass active_class_;
// This is the offset of the current library within
// the whole kernel program.
intptr_t library_kernel_offset_;
// This is the offset by which offsets, which are set relative
// to their library's kernel data, have to be corrected.
intptr_t correction_offset_;
bool loading_native_wrappers_library_;
NameIndex skip_vmservice_library_;
TypedData& library_kernel_data_;
KernelProgramInfo& kernel_program_info_;
BuildingTranslationHelper translation_helper_;
StreamingFlowGraphBuilder builder_;
Class& external_name_class_;
Field& external_name_field_;
GrowableObjectArray& potential_natives_;
Mapping<Library> libraries_;
Mapping<Class> classes_;
GrowableArray<const Function*> functions_;
GrowableArray<const Field*> fields_;
};
class ClassLoader {
public:
void LoadClassMembers();
};
} // namespace kernel
} // namespace dart
#endif // !defined(DART_PRECOMPILED_RUNTIME)
#endif // RUNTIME_VM_KERNEL_LOADER_H_