blob: a1772454985e0892953d0e924e7e9e8e2ee398bf [file] [log] [blame]
// 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.
#include "vm/kernel_loader.h"
#include <string.h>
#include "vm/compiler/frontend/kernel_binary_flowgraph.h"
#include "vm/compiler/frontend/kernel_to_il.h"
#include "vm/dart_api_impl.h"
#include "vm/kernel_binary.h"
#include "vm/longjump.h"
#include "vm/object_store.h"
#include "vm/parser.h"
#include "vm/symbols.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
namespace dart {
namespace kernel {
#define Z (zone_)
#define I (isolate_)
#define T (builder_.type_translator_)
#define H (translation_helper_)
class SimpleExpressionConverter {
public:
SimpleExpressionConverter(TranslationHelper* helper,
StreamingFlowGraphBuilder* builder)
: translation_helper_(*helper),
zone_(translation_helper_.zone()),
simple_value_(NULL),
builder_(builder) {}
bool IsSimple(intptr_t kernel_offset) {
AlternativeReadingScope alt(builder_->reader_, kernel_offset);
uint8_t payload = 0;
Tag tag = builder_->ReadTag(&payload); // read tag.
switch (tag) {
case kBigIntLiteral: {
const String& literal_str =
H.DartString(builder_->ReadStringReference(),
Heap::kOld); // read index into string table.
simple_value_ = &Integer::ZoneHandle(Z, Integer::New(literal_str));
if (simple_value_->IsNull()) {
H.ReportError("Integer literal %s is out of range",
literal_str.ToCString());
UNREACHABLE();
}
*simple_value_ = H.Canonicalize(*simple_value_);
return true;
}
case kStringLiteral:
simple_value_ = &H.DartSymbol(
builder_->ReadStringReference()); // read index into string table.
return true;
case kSpecialIntLiteral:
simple_value_ =
&Integer::ZoneHandle(Z, Integer::New(static_cast<int32_t>(payload) -
SpecializedIntLiteralBias,
Heap::kOld));
*simple_value_ = H.Canonicalize(*simple_value_);
return true;
case kNegativeIntLiteral:
simple_value_ = &Integer::ZoneHandle(
Z, Integer::New(-static_cast<int64_t>(builder_->ReadUInt()),
Heap::kOld)); // read value.
*simple_value_ = H.Canonicalize(*simple_value_);
return true;
case kPositiveIntLiteral:
simple_value_ = &Integer::ZoneHandle(
Z, Integer::New(static_cast<int64_t>(builder_->ReadUInt()),
Heap::kOld)); // read value.
*simple_value_ = H.Canonicalize(*simple_value_);
return true;
case kDoubleLiteral:
simple_value_ = &Double::ZoneHandle(
Z, Double::New(H.DartString(builder_->ReadStringReference()),
Heap::kOld)); // read string reference.
*simple_value_ = H.Canonicalize(*simple_value_);
return true;
case kTrueLiteral:
simple_value_ = &Bool::Handle(Z, Bool::Get(true).raw());
return true;
case kFalseLiteral:
simple_value_ = &Bool::Handle(Z, Bool::Get(false).raw());
return true;
case kNullLiteral:
simple_value_ = &Instance::ZoneHandle(Z, Instance::null());
return true;
default:
return false;
}
}
const Instance& SimpleValue() { return *simple_value_; }
Zone* zone() const { return zone_; }
private:
TranslationHelper& translation_helper_;
Zone* zone_;
Instance* simple_value_;
StreamingFlowGraphBuilder* builder_;
};
RawArray* KernelLoader::MakeFunctionsArray() {
const intptr_t len = functions_.length();
const Array& res = Array::Handle(zone_, Array::New(len, Heap::kOld));
for (intptr_t i = 0; i < len; i++) {
res.SetAt(i, *functions_[i]);
}
return res.raw();
}
RawLibrary* BuildingTranslationHelper::LookupLibraryByKernelLibrary(
NameIndex library) {
return loader_->LookupLibrary(library).raw();
}
RawClass* BuildingTranslationHelper::LookupClassByKernelClass(NameIndex klass) {
return loader_->LookupClass(klass).raw();
}
KernelLoader::KernelLoader(Program* program)
: program_(program),
thread_(Thread::Current()),
zone_(thread_->zone()),
isolate_(thread_->isolate()),
scripts_(Array::ZoneHandle(zone_)),
patch_classes_(Array::ZoneHandle(zone_)),
translation_helper_(this, thread_),
builder_(&translation_helper_,
zone_,
program_->kernel_data(),
program_->kernel_data_size()) {
T.active_class_ = &active_class_;
T.finalize_ = false;
scripts_ = Array::New(builder_.SourceTableSize(), Heap::kOld);
patch_classes_ = Array::New(builder_.SourceTableSize(), Heap::kOld);
// Copy the Kernel string offsets out of the binary and into the VM's heap.
ASSERT(program->string_table_offset() >= 0);
Reader reader(program->kernel_data(), program->kernel_data_size());
reader.set_offset(program->string_table_offset());
intptr_t count = reader.ReadUInt() + 1;
TypedData& offsets = TypedData::Handle(
Z, TypedData::New(kTypedDataUint32ArrayCid, count, Heap::kOld));
offsets.SetUint32(0, 0);
intptr_t end_offset = 0;
for (intptr_t i = 1; i < count; ++i) {
end_offset = reader.ReadUInt();
offsets.SetUint32(i << 2, end_offset);
}
// Copy the string data out of the binary and into the VM's heap.
TypedData& data =
reader.CopyDataToVMHeap(Z, reader.offset(), reader.offset() + end_offset);
// Copy the canonical names into the VM's heap. Encode them as unsigned, so
// the parent indexes are adjusted when extracted.
reader.set_offset(program->name_table_offset());
count = reader.ReadUInt() * 2;
TypedData& names = TypedData::Handle(
Z, TypedData::New(kTypedDataUint32ArrayCid, count, Heap::kOld));
for (intptr_t i = 0; i < count; ++i) {
names.SetUint32(i << 2, reader.ReadUInt());
}
H.SetStringOffsets(offsets);
H.SetStringData(data);
H.SetCanonicalNames(names);
}
Object& KernelLoader::LoadProgram() {
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
intptr_t length = program_->library_count();
for (intptr_t i = 0; i < length; i++) {
LoadLibrary(library_offset(i));
}
for (intptr_t i = 0; i < length; i++) {
Library& library = LookupLibrary(library_canonical_name(i));
if (!library.Loaded()) library.SetLoaded();
}
if (ClassFinalizer::ProcessPendingClasses(/*from_kernel=*/true)) {
// If 'main' is not found return a null library, this is the case
// when bootstrapping is in progress.
NameIndex main = program_->main_method();
if (main == -1) {
return Library::Handle(Z);
}
NameIndex main_library = H.EnclosingName(main);
Library& library = LookupLibrary(main_library);
// Sanity check that we can find the main entrypoint.
ASSERT(library.LookupObjectAllowPrivate(H.DartSymbol("main")) !=
Object::null());
return library;
}
}
// Either class finalization failed or we caught a compile error.
// In both cases sticky error would be set.
Error& error = Error::Handle(Z);
error = thread_->sticky_error();
thread_->clear_sticky_error();
return error;
}
void KernelLoader::FindModifiedLibraries(Isolate* isolate,
BitVector* modified_libs,
bool force_reload) {
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (force_reload) {
// If a reload is being forced we mark all libraries as having
// been modified.
const GrowableObjectArray& libs =
GrowableObjectArray::Handle(isolate->object_store()->libraries());
intptr_t num_libs = libs.Length();
Library& lib = dart::Library::Handle(Z);
for (intptr_t i = 0; i < num_libs; i++) {
lib ^= libs.At(i);
if (!lib.is_dart_scheme()) {
modified_libs->Add(lib.index());
}
}
return;
}
// Now go through all the libraries that are present in the incremental
// kernel files, these will constitute the modified libraries.
intptr_t length = program_->library_count();
for (intptr_t i = 0; i < length; i++) {
intptr_t kernel_offset = library_offset(i);
builder_.SetOffset(kernel_offset);
LibraryHelper library_helper(&builder_);
library_helper.ReadUntilIncluding(LibraryHelper::kCanonicalName);
dart::Library& lib = LookupLibrary(library_helper.canonical_name_);
if (!lib.IsNull() && !lib.is_dart_scheme()) {
// This is a library that already exists so mark it as being modified.
modified_libs->Add(lib.index());
}
}
}
}
void KernelLoader::LoadLibrary(intptr_t kernel_offset) {
builder_.SetOffset(kernel_offset);
LibraryHelper library_helper(&builder_);
library_helper.ReadUntilIncluding(LibraryHelper::kCanonicalName);
Library& library = LookupLibrary(library_helper.canonical_name_);
// The Kernel library is external implies that it is already loaded.
ASSERT(!library_helper.IsExternal() || library.Loaded());
if (library.Loaded()) return;
library_helper.ReadUntilIncluding(LibraryHelper::kName);
library.SetName(H.DartSymbol(library_helper.name_index_));
// The bootstrapper will take care of creating the native wrapper classes, but
// we will add the synthetic constructors to them here.
if (library.name() ==
Symbols::Symbol(Symbols::kDartNativeWrappersLibNameId).raw()) {
ASSERT(library.LoadInProgress());
} else {
library.SetLoadInProgress();
}
// Setup toplevel class (which contains library fields/procedures).
StringIndex import_uri_index =
H.CanonicalNameString(library_helper.canonical_name_);
library_helper.ReadUntilIncluding(LibraryHelper::kSourceUriIndex);
Script& script = ScriptAt(library_helper.source_uri_index_, import_uri_index);
library_helper.ReadUntilExcluding(LibraryHelper::kDependencies);
LoadLibraryImportsAndExports(&library);
library_helper.SetJustRead(LibraryHelper::kDependencies);
Class& toplevel_class =
Class::Handle(Z, Class::New(library, Symbols::TopLevel(), script,
TokenPosition::kNoSource));
toplevel_class.set_is_cycle_free();
library.set_toplevel_class(toplevel_class);
const GrowableObjectArray& classes =
GrowableObjectArray::Handle(Z, I->object_store()->pending_classes());
library_helper.ReadUntilExcluding(LibraryHelper::kClasses);
// Load all classes.
int class_count = builder_.ReadListLength(); // read list length.
for (intptr_t i = 0; i < class_count; ++i) {
classes.Add(LoadClass(library, toplevel_class), Heap::kOld);
}
fields_.Clear();
functions_.Clear();
ActiveClassScope active_class_scope(&active_class_, &toplevel_class);
// Load toplevel fields.
intptr_t field_count = builder_.ReadListLength(); // read list length.
for (intptr_t i = 0; i < field_count; ++i) {
intptr_t field_offset = builder_.ReaderOffset();
ActiveMemberScope active_member_scope(&active_class_, NULL);
FieldHelper field_helper(&builder_);
field_helper.ReadUntilExcluding(FieldHelper::kName);
const String& name = builder_.ReadNameAsFieldName();
field_helper.SetJustRead(FieldHelper::kName);
field_helper.ReadUntilExcluding(FieldHelper::kType);
const Object& script_class =
ClassForScriptAt(toplevel_class, field_helper.source_uri_index_);
Field& field = Field::Handle(
Z,
Field::NewTopLevel(name, field_helper.IsFinal(), field_helper.IsConst(),
script_class, field_helper.position_));
field.set_kernel_offset(field_offset);
const AbstractType& type = T.BuildType(); // read type.
field.SetFieldType(type);
field_helper.SetJustRead(FieldHelper::kType);
field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
intptr_t field_initializer_offset = builder_.ReaderOffset();
field.set_has_initializer(builder_.PeekTag() == kSomething);
field_helper.ReadUntilExcluding(FieldHelper::kEnd);
TypedData& kernel_data = builder_.reader_->CopyDataToVMHeap(
Z, field_offset, builder_.ReaderOffset());
field.set_kernel_data(kernel_data);
{
// GenerateFieldAccessors reads (some of) the initializer.
AlternativeReadingScope alt(builder_.reader_, field_initializer_offset);
GenerateFieldAccessors(toplevel_class, field, &field_helper,
field_offset);
}
if (FLAG_enable_mirrors && field_helper.annotation_count_ > 0) {
library.AddFieldMetadata(field, TokenPosition::kNoSource, field_offset,
&kernel_data);
}
fields_.Add(&field);
library.AddObject(field, name);
}
toplevel_class.AddFields(fields_);
// Load toplevel procedures.
intptr_t procedure_count = builder_.ReadListLength(); // read list length.
for (intptr_t i = 0; i < procedure_count; ++i) {
LoadProcedure(library, toplevel_class, false);
}
toplevel_class.SetFunctions(Array::Handle(MakeFunctionsArray()));
classes.Add(toplevel_class, Heap::kOld);
}
void KernelLoader::LoadLibraryImportsAndExports(Library* library) {
GrowableObjectArray& show_list = GrowableObjectArray::Handle(Z);
GrowableObjectArray& hide_list = GrowableObjectArray::Handle(Z);
Array& show_names = Array::Handle(Z);
Array& hide_names = Array::Handle(Z);
Namespace& ns = Namespace::Handle(Z);
LibraryPrefix& library_prefix = LibraryPrefix::Handle(Z);
const intptr_t deps_count = builder_.ReadListLength();
for (intptr_t dep = 0; dep < deps_count; ++dep) {
LibraryDependencyHelper dependency_helper(&builder_);
dependency_helper.ReadUntilExcluding(LibraryDependencyHelper::kCombinators);
// Ignore the dependency if the target library is invalid.
// The error will be caught during compilation.
if (dependency_helper.target_library_canonical_name_ < 0) {
const intptr_t combinator_count = builder_.ReadListLength();
for (intptr_t c = 0; c < combinator_count; ++c) {
builder_.SkipLibraryCombinator();
}
continue;
}
// Prepare show and hide lists.
show_list = GrowableObjectArray::New(Heap::kOld);
hide_list = GrowableObjectArray::New(Heap::kOld);
const intptr_t combinator_count = builder_.ReadListLength();
for (intptr_t c = 0; c < combinator_count; ++c) {
uint8_t flags = builder_.ReadFlags();
intptr_t name_count = builder_.ReadListLength();
for (intptr_t n = 0; n < name_count; ++n) {
String& show_hide_name = H.DartSymbol(builder_.ReadStringReference());
if (flags & LibraryDependencyHelper::Show) {
show_list.Add(show_hide_name, Heap::kOld);
} else {
hide_list.Add(show_hide_name, Heap::kOld);
}
}
}
if (show_list.Length() > 0) {
show_names = Array::MakeFixedLength(show_list);
} else {
show_names = Array::null();
}
if (hide_list.Length() > 0) {
hide_names = Array::MakeFixedLength(hide_list);
} else {
hide_names = Array::null();
}
Library& target_library =
LookupLibrary(dependency_helper.target_library_canonical_name_);
String& prefix = H.DartSymbol(dependency_helper.name_index_);
ns = Namespace::New(target_library, show_names, hide_names);
if (dependency_helper.flags_ & LibraryDependencyHelper::Export) {
library->AddExport(ns);
} else {
if (prefix.IsNull() || prefix.Length() == 0) {
library->AddImport(ns);
} else {
library_prefix = library->LookupLocalLibraryPrefix(prefix);
if (!library_prefix.IsNull()) {
library_prefix.AddImport(ns);
} else {
library_prefix = LibraryPrefix::New(
prefix, ns,
dependency_helper.flags_ & LibraryDependencyHelper::Deferred,
*library);
library->AddObject(library_prefix, prefix);
}
}
}
}
}
void KernelLoader::LoadPreliminaryClass(Class* klass,
ClassHelper* class_helper,
intptr_t type_parameter_count) {
// Note: This assumes that ClassHelper is exactly at the position where
// the length of the type parameters have been read, and that the order in
// the binary is as follows: [...], kTypeParameters, kSuperClass, kMixinType,
// kImplementedClasses, [...].
// Set type parameters.
LoadAndSetupTypeParameters(*klass, type_parameter_count, *klass,
Function::Handle(Z));
// Set super type. Some classes (e.g., Object) do not have one.
Tag type_tag = builder_.ReadTag(); // read super class type (part 1).
if (type_tag == kSomething) {
AbstractType& super_type =
T.BuildTypeWithoutFinalization(); // read super class type (part 2).
if (super_type.IsMalformed()) H.ReportError("Malformed super type");
klass->set_super_type(super_type);
}
class_helper->SetJustRead(ClassHelper::kSuperClass);
class_helper->ReadUntilIncluding(ClassHelper::kMixinType);
// Build implemented interface types
intptr_t interface_count = builder_.ReadListLength();
const Array& interfaces =
Array::Handle(Z, Array::New(interface_count, Heap::kOld));
for (intptr_t i = 0; i < interface_count; i++) {
const AbstractType& type =
T.BuildTypeWithoutFinalization(); // read ith type.
if (type.IsMalformed()) H.ReportError("Malformed interface type.");
interfaces.SetAt(i, type);
}
class_helper->SetJustRead(ClassHelper::kImplementedClasses);
klass->set_interfaces(interfaces);
if (class_helper->is_abstract_) klass->set_is_abstract();
}
Class& KernelLoader::LoadClass(const Library& library,
const Class& toplevel_class) {
ClassHelper class_helper(&builder_);
intptr_t class_offset = builder_.ReaderOffset();
class_helper.ReadUntilIncluding(ClassHelper::kCanonicalName);
Class& klass = LookupClass(class_helper.canonical_name_);
// The class needs to have a script because all the functions in the class
// will inherit it. The predicate Function::IsOptimizable uses the absence of
// a script to detect test functions that should not be optimized.
if (klass.script() == Script::null()) {
class_helper.ReadUntilIncluding(ClassHelper::kSourceUriIndex);
klass.set_script(ScriptAt(class_helper.source_uri_index_));
}
if (klass.token_pos() == TokenPosition::kNoSource) {
class_helper.ReadUntilIncluding(ClassHelper::kPosition);
klass.set_token_pos(class_helper.position_);
}
class_helper.ReadUntilIncluding(ClassHelper::kAnnotations);
intptr_t class_offset_after_annotations = builder_.ReaderOffset();
class_helper.ReadUntilExcluding(ClassHelper::kTypeParameters);
intptr_t type_parameter_counts =
builder_.ReadListLength(); // read type_parameters list length.
ActiveClassScope active_class_scope(&active_class_, &klass);
if (!klass.is_cycle_free()) {
LoadPreliminaryClass(&klass, &class_helper, type_parameter_counts);
} else {
for (intptr_t i = 0; i < type_parameter_counts; ++i) {
builder_.SkipStringReference(); // read ith name index.
builder_.SkipDartType(); // read ith bound.
}
class_helper.SetJustRead(ClassHelper::kTypeParameters);
}
fields_.Clear();
functions_.Clear();
if (library.raw() == Library::InternalLibrary() &&
klass.Name() == Symbols::ClassID().raw()) {
// If this is a dart:internal.ClassID class ignore field declarations
// contained in the Kernel file and instead inject our own const
// fields.
klass.InjectCIDFields();
} else {
class_helper.ReadUntilExcluding(ClassHelper::kFields);
int field_count = builder_.ReadListLength(); // read list length.
for (intptr_t i = 0; i < field_count; ++i) {
intptr_t field_offset = builder_.ReaderOffset();
ActiveMemberScope active_member(&active_class_, NULL);
FieldHelper field_helper(&builder_);
field_helper.ReadUntilExcluding(FieldHelper::kName);
const String& name = builder_.ReadNameAsFieldName();
field_helper.SetJustRead(FieldHelper::kName);
field_helper.ReadUntilExcluding(FieldHelper::kType);
const AbstractType& type =
T.BuildTypeWithoutFinalization(); // read type.
field_helper.SetJustRead(FieldHelper::kType);
const Object& script_class =
ClassForScriptAt(klass, field_helper.source_uri_index_);
const bool is_reflectable =
field_helper.position_.IsReal() &&
!(library.is_dart_scheme() && library.IsPrivate(name));
Field& field = Field::Handle(
Z, Field::New(name, field_helper.IsStatic(),
// In the VM all const fields are implicitly final
// whereas in Kernel they are not final because they
// are not explicitly declared that way.
field_helper.IsFinal() || field_helper.IsConst(),
field_helper.IsConst(), is_reflectable, script_class,
type, field_helper.position_));
field.set_kernel_offset(field_offset);
field_helper.ReadUntilExcluding(FieldHelper::kInitializer);
intptr_t field_initializer_offset = builder_.ReaderOffset();
field.set_has_initializer(builder_.PeekTag() == kSomething);
field_helper.ReadUntilExcluding(FieldHelper::kEnd);
TypedData& kernel_data = builder_.reader_->CopyDataToVMHeap(
Z, field_offset, builder_.ReaderOffset());
field.set_kernel_data(kernel_data);
{
// GenerateFieldAccessors reads (some of) the initializer.
AlternativeReadingScope alt(builder_.reader_, field_initializer_offset);
GenerateFieldAccessors(klass, field, &field_helper, field_offset);
}
if (FLAG_enable_mirrors && field_helper.annotation_count_ > 0) {
library.AddFieldMetadata(field, TokenPosition::kNoSource, field_offset,
&kernel_data);
}
fields_.Add(&field);
}
klass.AddFields(fields_);
class_helper.SetJustRead(ClassHelper::kFields);
}
class_helper.ReadUntilExcluding(ClassHelper::kConstructors);
int constructor_count = builder_.ReadListLength(); // read list length.
for (intptr_t i = 0; i < constructor_count; ++i) {
intptr_t constructor_offset = builder_.ReaderOffset();
ActiveMemberScope active_member_scope(&active_class_, NULL);
ConstructorHelper constructor_helper(&builder_);
constructor_helper.ReadUntilExcluding(ConstructorHelper::kFunction);
const String& name =
H.DartConstructorName(constructor_helper.canonical_name_);
Function& function = Function::ZoneHandle(
Z, Function::New(name, RawFunction::kConstructor,
false, // is_static
constructor_helper.IsConst(),
false, // is_abstract
constructor_helper.IsExternal(),
false, // is_native
klass, constructor_helper.position_));
function.set_end_token_pos(constructor_helper.end_position_);
functions_.Add(&function);
function.set_kernel_offset(constructor_offset);
function.set_result_type(T.ReceiverType(klass));
FunctionNodeHelper function_node_helper(&builder_);
function_node_helper.ReadUntilExcluding(
FunctionNodeHelper::kRequiredParameterCount);
builder_.SetupFunctionParameters(klass, function,
true, // is_method
false, // is_closure
&function_node_helper);
function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd);
constructor_helper.SetJustRead(ConstructorHelper::kFunction);
constructor_helper.ReadUntilExcluding(ConstructorHelper::kEnd);
TypedData& kernel_data = builder_.reader_->CopyDataToVMHeap(
Z, constructor_offset, builder_.ReaderOffset());
function.set_kernel_data(kernel_data);
if (FLAG_enable_mirrors && constructor_helper.annotation_count_ > 0) {
library.AddFunctionMetadata(function, TokenPosition::kNoSource,
constructor_offset, &kernel_data);
}
}
class_helper.SetJustRead(ClassHelper::kConstructors);
class_helper.ReadUntilExcluding(ClassHelper::kProcedures);
int procedure_count = builder_.ReadListLength(); // read list length.
for (intptr_t i = 0; i < procedure_count; ++i) {
LoadProcedure(library, klass, true);
}
class_helper.SetJustRead(ClassHelper::kProcedures);
klass.SetFunctions(Array::Handle(MakeFunctionsArray()));
if (!klass.is_marked_for_parsing()) {
klass.set_is_marked_for_parsing();
}
if (FLAG_enable_mirrors && class_helper.annotation_count_ > 0) {
TypedData& header_data = builder_.reader_->CopyDataToVMHeap(
Z, class_offset, class_offset_after_annotations);
library.AddClassMetadata(klass, toplevel_class, TokenPosition::kNoSource,
class_offset, &header_data);
}
class_helper.ReadUntilExcluding(ClassHelper::kEnd);
return klass;
}
void KernelLoader::LoadProcedure(const Library& library,
const Class& owner,
bool in_class) {
intptr_t procedure_offset = builder_.ReaderOffset();
ProcedureHelper procedure_helper(&builder_);
procedure_helper.ReadUntilExcluding(ProcedureHelper::kAnnotations);
const String& name = H.DartProcedureName(procedure_helper.canonical_name_);
bool is_method = in_class && !procedure_helper.IsStatic();
bool is_abstract = procedure_helper.IsAbstract();
bool is_external = procedure_helper.IsExternal();
String* native_name = NULL;
intptr_t annotation_count;
if (is_external) {
// Maybe it has a native implementation, which is not external as far as
// the VM is concerned because it does have an implementation. Check for
// an ExternalName annotation and extract the string from it.
annotation_count = builder_.ReadListLength(); // read list length.
for (int i = 0; i < annotation_count; ++i) {
if (builder_.PeekTag() != kConstructorInvocation &&
builder_.PeekTag() != kConstConstructorInvocation) {
builder_.SkipExpression();
continue;
}
builder_.ReadTag();
builder_.ReadPosition();
NameIndex annotation_class = H.EnclosingName(
builder_.ReadCanonicalNameReference()); // read target reference,
ASSERT(H.IsClass(annotation_class));
StringIndex class_name_index = H.CanonicalNameString(annotation_class);
// Just compare by name, do not generate the annotation class.
if (!H.StringEquals(class_name_index, "ExternalName")) {
builder_.SkipArguments();
continue;
}
ASSERT(H.IsLibrary(H.CanonicalNameParent(annotation_class)));
StringIndex library_name_index =
H.CanonicalNameString(H.CanonicalNameParent(annotation_class));
if (!H.StringEquals(library_name_index, "dart:_internal")) {
builder_.SkipArguments();
continue;
}
is_external = false;
// Read arguments:
intptr_t total_arguments = builder_.ReadUInt(); // read argument count.
builder_.SkipListOfDartTypes(); // read list of types.
intptr_t positional_arguments = builder_.ReadListLength();
ASSERT(total_arguments == 1 && positional_arguments == 1);
Tag tag = builder_.ReadTag();
ASSERT(tag == kStringLiteral);
native_name = &H.DartSymbol(
builder_.ReadStringReference()); // read index into string table.
// List of named.
intptr_t list_length = builder_.ReadListLength(); // read list length.
ASSERT(list_length == 0);
// Skip remaining annotations
for (++i; i < annotation_count; ++i) {
builder_.SkipExpression(); // read ith annotation.
}
break;
}
procedure_helper.SetJustRead(ProcedureHelper::kAnnotations);
} else {
procedure_helper.ReadUntilIncluding(ProcedureHelper::kAnnotations);
annotation_count = procedure_helper.annotation_count_;
}
const Object& script_class =
ClassForScriptAt(owner, procedure_helper.source_uri_index_);
Function& function = Function::ZoneHandle(
Z, Function::New(name, GetFunctionType(procedure_helper.kind_),
!is_method, // is_static
false, // is_const
is_abstract, is_external,
native_name != NULL, // is_native
script_class, procedure_helper.position_));
function.set_end_token_pos(procedure_helper.end_position_);
functions_.Add(&function);
function.set_kernel_offset(procedure_offset);
ActiveMemberScope active_member(&active_class_, &function);
procedure_helper.ReadUntilExcluding(ProcedureHelper::kFunction);
Tag function_node_tag = builder_.ReadTag();
ASSERT(function_node_tag == kSomething);
FunctionNodeHelper function_node_helper(&builder_);
function_node_helper.ReadUntilIncluding(FunctionNodeHelper::kDartAsyncMarker);
function.set_is_debuggable(function_node_helper.dart_async_marker_ ==
FunctionNodeHelper::kSync);
switch (function_node_helper.dart_async_marker_) {
case FunctionNodeHelper::kSyncStar:
function.set_modifier(RawFunction::kSyncGen);
break;
case FunctionNodeHelper::kAsync:
function.set_modifier(RawFunction::kAsync);
function.set_is_inlinable(!FLAG_causal_async_stacks);
break;
case FunctionNodeHelper::kAsyncStar:
function.set_modifier(RawFunction::kAsyncGen);
function.set_is_inlinable(!FLAG_causal_async_stacks);
break;
default:
// no special modifier
break;
}
ASSERT(function_node_helper.async_marker_ == FunctionNodeHelper::kSync);
if (native_name != NULL) {
function.set_native_name(*native_name);
}
function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kTypeParameters);
if (!function.IsFactory()) {
// Read type_parameters list length.
intptr_t type_parameter_count = builder_.ReadListLength();
// Set type parameters.
LoadAndSetupTypeParameters(function, type_parameter_count, Class::Handle(Z),
function);
function_node_helper.SetJustRead(FunctionNodeHelper::kTypeParameters);
}
function_node_helper.ReadUntilExcluding(
FunctionNodeHelper::kRequiredParameterCount);
builder_.SetupFunctionParameters(owner, function, is_method,
false, // is_closure
&function_node_helper);
function_node_helper.ReadUntilExcluding(FunctionNodeHelper::kEnd);
procedure_helper.SetJustRead(ProcedureHelper::kFunction);
if (!in_class) {
library.AddObject(function, name);
ASSERT(!Object::Handle(
Z, library.LookupObjectAllowPrivate(
H.DartProcedureName(procedure_helper.canonical_name_)))
.IsNull());
}
procedure_helper.ReadUntilExcluding(ProcedureHelper::kEnd);
TypedData& kernel_data = builder_.reader_->CopyDataToVMHeap(
Z, procedure_offset, builder_.ReaderOffset());
function.set_kernel_data(kernel_data);
if (FLAG_enable_mirrors && annotation_count > 0) {
library.AddFunctionMetadata(function, TokenPosition::kNoSource,
procedure_offset, &kernel_data);
}
}
void KernelLoader::LoadAndSetupTypeParameters(
const Object& set_on,
intptr_t type_parameter_count,
const Class& parameterized_class,
const Function& parameterized_function) {
ASSERT(type_parameter_count >= 0);
if (type_parameter_count == 0) {
return;
}
// First setup the type parameters, so if any of the following code uses it
// (in a recursive way) we're fine.
TypeArguments& type_parameters =
TypeArguments::Handle(Z, TypeArguments::null());
TypeParameter& parameter = TypeParameter::Handle(Z);
Type& null_bound = Type::Handle(Z, Type::null());
// Step a) Create array of [TypeParameter] objects (without bound).
type_parameters = TypeArguments::New(type_parameter_count);
{
AlternativeReadingScope alt(builder_.reader_);
for (intptr_t i = 0; i < type_parameter_count; i++) {
builder_.SkipFlags();
parameter = TypeParameter::New(
parameterized_class, parameterized_function, i,
H.DartSymbol(builder_.ReadStringReference()), // read ith name index.
null_bound, TokenPosition::kNoSource);
type_parameters.SetTypeAt(i, parameter);
builder_.SkipDartType(); // read guard.
}
}
ASSERT(set_on.IsClass() || set_on.IsFunction());
if (set_on.IsClass()) {
Class::Cast(set_on).set_type_parameters(type_parameters);
} else {
Function::Cast(set_on).set_type_parameters(type_parameters);
}
// Step b) Fill in the bounds of all [TypeParameter]s.
for (intptr_t i = 0; i < type_parameter_count; i++) {
builder_.SkipFlags();
builder_.SkipStringReference(); // read ith name index.
// TODO(github.com/dart-lang/kernel/issues/42): This should be handled
// by the frontend.
parameter ^= type_parameters.TypeAt(i);
Tag tag = builder_.PeekTag(); // peek ith bound type.
if (tag == kDynamicType) {
builder_.SkipDartType(); // read ith bound.
parameter.set_bound(Type::Handle(Z, I->object_store()->object_type()));
} else {
AbstractType& bound =
T.BuildTypeWithoutFinalization(); // read ith bound.
if (bound.IsMalformedOrMalbounded()) {
bound = I->object_store()->object_type();
}
parameter.set_bound(bound);
}
}
}
const Object& KernelLoader::ClassForScriptAt(const Class& klass,
intptr_t source_uri_index) {
Script& correct_script = ScriptAt(source_uri_index);
if (klass.script() != correct_script.raw()) {
// Use cache for patch classes. This works best for in-order usages.
PatchClass& patch_class = PatchClass::ZoneHandle(Z);
patch_class ^= patch_classes_.At(source_uri_index);
if (patch_class.IsNull() || patch_class.origin_class() != klass.raw()) {
patch_class = PatchClass::New(klass, correct_script);
patch_classes_.SetAt(source_uri_index, patch_class);
}
return patch_class;
}
return klass;
}
Script& KernelLoader::ScriptAt(intptr_t index, StringIndex import_uri) {
Script& script = Script::ZoneHandle(Z);
script ^= scripts_.At(index);
if (script.IsNull()) {
// Create script with correct uri(s).
String& uri_string = builder_.SourceTableUriFor(index);
String& import_uri_string =
import_uri == -1 ? uri_string : H.DartString(import_uri, Heap::kOld);
script = Script::New(import_uri_string, uri_string,
builder_.GetSourceFor(index), RawScript::kKernelTag);
script.set_kernel_script_index(index);
script.set_kernel_string_offsets(H.string_offsets());
script.set_kernel_string_data(H.string_data());
script.set_kernel_canonical_names(H.canonical_names());
scripts_.SetAt(index, script);
script.set_line_starts(builder_.GetLineStartsFor(index));
script.set_debug_positions(Array::Handle(Array::null()));
script.set_yield_positions(Array::Handle(Array::null()));
}
return script;
}
void KernelLoader::GenerateFieldAccessors(const Class& klass,
const Field& field,
FieldHelper* field_helper,
intptr_t field_offset) {
Tag tag = builder_.PeekTag();
if (field_helper->IsStatic() && tag == kNothing) {
// Static fields without an initializer are implicitly initialized to null.
// We do not need a getter.
field.SetStaticValue(Instance::Handle(Z), true);
return;
}
if (tag == kSomething) {
SimpleExpressionConverter converter(&H, &builder_);
const bool has_simple_initializer =
converter.IsSimple(builder_.ReaderOffset() + 1); // ignore the tag.
if (field_helper->IsStatic()) {
// Static fields with initializers either have the static value set to the
// initializer value if it is simple enough or else set to an
// uninitialized sentinel.
if (has_simple_initializer) {
// We do not need a getter.
field.SetStaticValue(converter.SimpleValue(), true);
return;
}
// We do need a getter that evaluates the initializer if necessary.
field.SetStaticValue(Object::sentinel(), true);
} else if (has_simple_initializer) {
// Note: optimizer relies on DoubleInitialized bit in its field-unboxing
// heuristics. See JitCallSpecializer::VisitStoreInstanceField for more
// details.
field.RecordStore(converter.SimpleValue());
if (!converter.SimpleValue().IsNull() &&
converter.SimpleValue().IsDouble()) {
field.set_is_double_initialized(true);
}
}
}
const String& getter_name = H.DartGetterName(field_helper->canonical_name_);
const Object& script_class =
ClassForScriptAt(klass, field_helper->source_uri_index_);
Function& getter = Function::ZoneHandle(
Z,
Function::New(
getter_name,
field_helper->IsStatic() ? RawFunction::kImplicitStaticFinalGetter
: RawFunction::kImplicitGetter,
field_helper->IsStatic(),
// The functions created by the parser have is_const for static fields
// that are const (not just final) and they have is_const for
// non-static
// fields that are final.
field_helper->IsStatic() ? field_helper->IsConst()
: field_helper->IsFinal(),
false, // is_abstract
false, // is_external
false, // is_native
script_class, field_helper->position_));
functions_.Add(&getter);
getter.set_kernel_data(TypedData::Handle(Z, field.kernel_data()));
getter.set_end_token_pos(field_helper->end_position_);
getter.set_kernel_offset(field_offset);
getter.set_result_type(AbstractType::Handle(Z, field.type()));
getter.set_is_debuggable(false);
SetupFieldAccessorFunction(klass, getter);
if (!field_helper->IsStatic() && !field_helper->IsFinal()) {
// Only static fields can be const.
ASSERT(!field_helper->IsConst());
const String& setter_name = H.DartSetterName(field_helper->canonical_name_);
Function& setter = Function::ZoneHandle(
Z, Function::New(setter_name, RawFunction::kImplicitSetter,
false, // is_static
false, // is_const
false, // is_abstract
false, // is_external
false, // is_native
script_class, field_helper->position_));
functions_.Add(&setter);
setter.set_kernel_data(TypedData::Handle(Z, field.kernel_data()));
setter.set_end_token_pos(field_helper->end_position_);
setter.set_kernel_offset(field_offset);
setter.set_result_type(Object::void_type());
setter.set_is_debuggable(false);
SetupFieldAccessorFunction(klass, setter);
}
}
void KernelLoader::SetupFieldAccessorFunction(const Class& klass,
const Function& function) {
bool is_setter = function.IsImplicitSetterFunction();
bool is_method = !function.IsStaticFunction();
intptr_t parameter_count = (is_method ? 1 : 0) + (is_setter ? 1 : 0);
function.SetNumOptionalParameters(0, false);
function.set_num_fixed_parameters(parameter_count);
function.set_parameter_types(
Array::Handle(Z, Array::New(parameter_count, Heap::kOld)));
function.set_parameter_names(
Array::Handle(Z, Array::New(parameter_count, Heap::kOld)));
intptr_t pos = 0;
if (is_method) {
function.SetParameterTypeAt(pos, T.ReceiverType(klass));
function.SetParameterNameAt(pos, Symbols::This());
pos++;
}
if (is_setter) {
function.SetParameterTypeAt(pos, AbstractType::dynamic_type());
function.SetParameterNameAt(pos, Symbols::Value());
pos++;
}
}
Library& KernelLoader::LookupLibrary(NameIndex library) {
Library* handle = NULL;
if (!libraries_.Lookup(library, &handle)) {
const String& url = H.DartSymbol(H.CanonicalNameString(library));
handle = &Library::Handle(Z, Library::LookupLibrary(thread_, url));
if (handle->IsNull()) {
*handle = Library::New(url);
handle->Register(thread_);
}
ASSERT(!handle->IsNull());
libraries_.Insert(library, handle);
}
return *handle;
}
Class& KernelLoader::LookupClass(NameIndex klass) {
Class* handle = NULL;
if (!classes_.Lookup(klass, &handle)) {
Library& library = LookupLibrary(H.CanonicalNameParent(klass));
const String& name = H.DartClassName(klass);
handle = &Class::Handle(Z, library.LookupLocalClass(name));
if (handle->IsNull()) {
*handle = Class::New(library, name, Script::Handle(Z),
TokenPosition::kNoSource);
library.AddClass(*handle);
}
// Insert the class in the cache before calling ReadPreliminaryClass so
// we do not risk allocating the class again by calling LookupClass
// recursively from ReadPreliminaryClass for the same class.
classes_.Insert(klass, handle);
}
return *handle;
}
RawFunction::Kind KernelLoader::GetFunctionType(
ProcedureHelper::Kind procedure_kind) {
intptr_t lookuptable[] = {
RawFunction::kRegularFunction, // Procedure::kMethod
RawFunction::kGetterFunction, // Procedure::kGetter
RawFunction::kSetterFunction, // Procedure::kSetter
RawFunction::kRegularFunction, // Procedure::kOperator
RawFunction::kConstructor, // Procedure::kFactory
};
intptr_t kind = static_cast<int>(procedure_kind);
ASSERT(0 <= kind && kind <= ProcedureHelper::kFactory);
return static_cast<RawFunction::Kind>(lookuptable[kind]);
}
ParsedFunction* ParseStaticFieldInitializer(Zone* zone, const Field& field) {
Thread* thread = Thread::Current();
String& init_name = String::Handle(zone, field.name());
init_name = Symbols::FromConcat(thread, Symbols::InitPrefix(), init_name);
// Create a static initializer.
const Object& owner = Object::Handle(field.RawOwner());
const Function& initializer_fun = Function::ZoneHandle(
zone, Function::New(init_name, RawFunction::kImplicitStaticFinalGetter,
true, // is_static
false, // is_const
false, // is_abstract
false, // is_external
false, // is_native
owner, TokenPosition::kNoSource));
initializer_fun.set_kernel_data(TypedData::Handle(zone, field.kernel_data()));
initializer_fun.set_kernel_offset(field.kernel_offset());
initializer_fun.set_result_type(AbstractType::Handle(zone, field.type()));
initializer_fun.set_is_debuggable(false);
initializer_fun.set_is_reflectable(false);
initializer_fun.set_is_inlinable(false);
return new (zone) ParsedFunction(thread, initializer_fun);
}
} // namespace kernel
} // namespace dart
#endif // !defined(DART_PRECOMPILED_RUNTIME)