2e794c4e16
- Instead of a pointer to new'd memory, Kernel strings now have an offset from the start of the string data. - When the streaming reader encounters the string data it records the offset from the start of the binary. This offset is stored in the Kernel Program and is used to compute the offset for strings. - When a KernelReader is constructed, the string data is copied into a Uint8 array in the VM's heap. - A pointer to the string data is put into every Kernel script so it can be used for constructing VM strings at compile time. The source table does not use Kernel strings any more because those strings are not found in the raw string data. Instead, the source table uses new'd buffers for strings (but this will be cleaned up separately). R=jensj@google.com Review-Url: https://codereview.chromium.org/2820363002 .
892 lines
35 KiB
C++
892 lines
35 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.
|
|
|
|
#include "vm/kernel_reader.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "vm/dart_api_impl.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 (type_translator_)
|
|
#define H (translation_helper_)
|
|
|
|
class SimpleExpressionConverter : public ExpressionVisitor {
|
|
public:
|
|
explicit SimpleExpressionConverter(TranslationHelper* helper)
|
|
: translation_helper_(*helper),
|
|
zone_(translation_helper_.zone()),
|
|
is_simple_(false),
|
|
simple_value_(NULL) {}
|
|
|
|
virtual void VisitDefaultExpression(Expression* node) { is_simple_ = false; }
|
|
|
|
virtual void VisitIntLiteral(IntLiteral* node) {
|
|
is_simple_ = true;
|
|
simple_value_ =
|
|
&Integer::ZoneHandle(Z, Integer::New(node->value(), Heap::kOld));
|
|
*simple_value_ = H.Canonicalize(*simple_value_);
|
|
}
|
|
|
|
virtual void VisitBigintLiteral(BigintLiteral* node) {
|
|
is_simple_ = true;
|
|
simple_value_ = &Integer::ZoneHandle(
|
|
Z, Integer::New(H.DartString(node->value(), Heap::kOld)));
|
|
*simple_value_ = H.Canonicalize(*simple_value_);
|
|
}
|
|
|
|
virtual void VisitDoubleLiteral(DoubleLiteral* node) {
|
|
is_simple_ = true;
|
|
simple_value_ = &Double::ZoneHandle(
|
|
Z, Double::New(H.DartString(node->value()), Heap::kOld));
|
|
*simple_value_ = H.Canonicalize(*simple_value_);
|
|
}
|
|
|
|
virtual void VisitBoolLiteral(BoolLiteral* node) {
|
|
is_simple_ = true;
|
|
simple_value_ = &Bool::Handle(Z, Bool::Get(node->value()).raw());
|
|
}
|
|
|
|
virtual void VisitNullLiteral(NullLiteral* node) {
|
|
is_simple_ = true;
|
|
simple_value_ = &dart::Instance::ZoneHandle(Z, dart::Instance::null());
|
|
}
|
|
|
|
virtual void VisitStringLiteral(StringLiteral* node) {
|
|
is_simple_ = true;
|
|
simple_value_ = &H.DartSymbol(node->value());
|
|
}
|
|
|
|
bool IsSimple(Expression* expression) {
|
|
expression->AcceptExpressionVisitor(this);
|
|
return is_simple_;
|
|
}
|
|
|
|
const dart::Instance& SimpleValue() { return *simple_value_; }
|
|
dart::Zone* zone() const { return zone_; }
|
|
|
|
private:
|
|
TranslationHelper& translation_helper_;
|
|
dart::Zone* zone_;
|
|
bool is_simple_;
|
|
dart::Instance* simple_value_;
|
|
};
|
|
|
|
|
|
RawArray* KernelReader::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(
|
|
CanonicalName* library) {
|
|
return reader_->LookupLibrary(library).raw();
|
|
}
|
|
|
|
|
|
RawClass* BuildingTranslationHelper::LookupClassByKernelClass(
|
|
CanonicalName* klass) {
|
|
return reader_->LookupClass(klass).raw();
|
|
}
|
|
|
|
|
|
KernelReader::KernelReader(Program* program)
|
|
: program_(program),
|
|
thread_(dart::Thread::Current()),
|
|
zone_(thread_->zone()),
|
|
isolate_(thread_->isolate()),
|
|
scripts_(Array::ZoneHandle(zone_)),
|
|
translation_helper_(this, thread_),
|
|
type_translator_(&translation_helper_,
|
|
&active_class_,
|
|
/*finalize=*/false) {
|
|
intptr_t source_file_count = program->source_table().size();
|
|
scripts_ = Array::New(source_file_count, Heap::kOld);
|
|
|
|
// Copy the Kernel strings out of the binary and into the VM's heap. The size
|
|
// of the string data can be computed from the offset and size of the last
|
|
// string. This relies on the strings occurring in order in the program's
|
|
// string table.
|
|
List<String>& strings = program->string_table().strings();
|
|
String* last_string = strings[strings.length() - 1];
|
|
intptr_t size = last_string->offset() + last_string->size();
|
|
TypedData& data = TypedData::Handle(
|
|
Z, TypedData::New(kTypedDataUint8ArrayCid, size, Heap::kOld));
|
|
ASSERT(program->string_data_offset() >= 0);
|
|
// We need at least one library to get access to the binary.
|
|
ASSERT(program->libraries().length() > 0);
|
|
{
|
|
NoSafepointScope no_safepoint;
|
|
memmove(data.DataAddr(0), program->libraries()[0]->kernel_data() +
|
|
program->string_data_offset(),
|
|
size);
|
|
}
|
|
H.SetStringData(data);
|
|
}
|
|
|
|
|
|
Object& KernelReader::ReadProgram() {
|
|
LongJumpScope jump;
|
|
if (setjmp(*jump.Set()) == 0) {
|
|
intptr_t length = program_->libraries().length();
|
|
for (intptr_t i = 0; i < length; i++) {
|
|
Library* kernel_library = program_->libraries()[i];
|
|
ReadLibrary(kernel_library);
|
|
}
|
|
|
|
for (intptr_t i = 0; i < length; i++) {
|
|
dart::Library& library =
|
|
LookupLibrary(program_->libraries()[i]->canonical_name());
|
|
if (!library.Loaded()) library.SetLoaded();
|
|
}
|
|
|
|
if (ClassFinalizer::ProcessPendingClasses(/*from_kernel=*/true)) {
|
|
CanonicalName* main = program_->main_method();
|
|
dart::Library& library = LookupLibrary(H.EnclosingName(main));
|
|
|
|
// Sanity check that we can find the main entrypoint.
|
|
Object& main_obj = Object::Handle(
|
|
Z, library.LookupObjectAllowPrivate(H.DartSymbol("main")));
|
|
ASSERT(!main_obj.IsNull());
|
|
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 KernelReader::ReadLibrary(Library* kernel_library) {
|
|
dart::Library& library = LookupLibrary(kernel_library->canonical_name());
|
|
if (library.Loaded()) return;
|
|
library.SetName(H.DartSymbol(kernel_library->name()));
|
|
|
|
// 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).
|
|
|
|
Script& script = ScriptAt(kernel_library->source_uri_index(),
|
|
kernel_library->import_uri());
|
|
dart::Class& toplevel_class = dart::Class::Handle(
|
|
Z, dart::Class::New(library, Symbols::TopLevel(), script,
|
|
TokenPosition::kNoSource));
|
|
toplevel_class.set_is_cycle_free();
|
|
library.set_toplevel_class(toplevel_class);
|
|
|
|
fields_.Clear();
|
|
functions_.Clear();
|
|
ActiveClassScope active_class_scope(&active_class_, NULL, &toplevel_class);
|
|
// Load toplevel fields.
|
|
for (intptr_t i = 0; i < kernel_library->fields().length(); i++) {
|
|
Field* kernel_field = kernel_library->fields()[i];
|
|
|
|
ActiveMemberScope active_member_scope(&active_class_, kernel_field);
|
|
const dart::String& name = H.DartFieldName(kernel_field->name());
|
|
const Object& script_class =
|
|
ClassForScriptAt(toplevel_class, kernel_field->source_uri_index());
|
|
dart::Field& field = dart::Field::Handle(
|
|
Z, dart::Field::NewTopLevel(name, kernel_field->IsFinal(),
|
|
kernel_field->IsConst(), script_class,
|
|
kernel_field->position()));
|
|
field.set_kernel_field(kernel_field);
|
|
const AbstractType& type = T.TranslateType(kernel_field->type());
|
|
field.SetFieldType(type);
|
|
field.set_has_initializer(kernel_field->initializer() != NULL);
|
|
GenerateFieldAccessors(toplevel_class, field, kernel_field);
|
|
fields_.Add(&field);
|
|
library.AddObject(field, name);
|
|
}
|
|
toplevel_class.AddFields(fields_);
|
|
|
|
// Load toplevel procedures.
|
|
for (intptr_t i = 0; i < kernel_library->procedures().length(); i++) {
|
|
Procedure* kernel_procedure = kernel_library->procedures()[i];
|
|
ReadProcedure(library, toplevel_class, kernel_procedure);
|
|
}
|
|
|
|
toplevel_class.SetFunctions(Array::Handle(MakeFunctionsArray()));
|
|
|
|
const GrowableObjectArray& classes =
|
|
GrowableObjectArray::Handle(I->object_store()->pending_classes());
|
|
|
|
// Load all classes.
|
|
for (intptr_t i = 0; i < kernel_library->classes().length(); i++) {
|
|
Class* kernel_klass = kernel_library->classes()[i];
|
|
classes.Add(ReadClass(library, toplevel_class, kernel_klass), Heap::kOld);
|
|
}
|
|
|
|
classes.Add(toplevel_class, Heap::kOld);
|
|
}
|
|
|
|
|
|
void KernelReader::ReadPreliminaryClass(dart::Class* klass,
|
|
Class* kernel_klass) {
|
|
ASSERT(kernel_klass->IsNormalClass());
|
|
NormalClass* kernel_normal_class = NormalClass::Cast(kernel_klass);
|
|
|
|
ActiveClassScope active_class_scope(&active_class_, kernel_klass, klass);
|
|
|
|
// 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());
|
|
intptr_t num_type_parameters = kernel_klass->type_parameters().length();
|
|
if (num_type_parameters > 0) {
|
|
dart::TypeParameter& parameter = dart::TypeParameter::Handle(Z);
|
|
Type& null_bound = Type::Handle(Z, Type::null());
|
|
|
|
// Step a) Create array of [TypeParameter] objects (without bound).
|
|
type_parameters = TypeArguments::New(num_type_parameters);
|
|
for (intptr_t i = 0; i < num_type_parameters; i++) {
|
|
parameter = dart::TypeParameter::New(
|
|
*klass, Function::Handle(Z), i,
|
|
H.DartSymbol(kernel_klass->type_parameters()[i]->name()), null_bound,
|
|
TokenPosition::kNoSource);
|
|
type_parameters.SetTypeAt(i, parameter);
|
|
}
|
|
klass->set_type_parameters(type_parameters);
|
|
|
|
// Step b) Fill in the bounds of all [TypeParameter]s.
|
|
for (intptr_t i = 0; i < num_type_parameters; i++) {
|
|
TypeParameter* kernel_parameter = kernel_klass->type_parameters()[i];
|
|
// TODO(github.com/dart-lang/kernel/issues/42): This should be handled
|
|
// by the frontend.
|
|
if (kernel_parameter->bound()->IsDynamicType()) {
|
|
parameter ^= type_parameters.TypeAt(i);
|
|
parameter.set_bound(Type::Handle(Z, I->object_store()->object_type()));
|
|
} else {
|
|
AbstractType& bound =
|
|
T.TranslateTypeWithoutFinalization(kernel_parameter->bound());
|
|
if (bound.IsMalformedOrMalbounded()) {
|
|
bound = I->object_store()->object_type();
|
|
}
|
|
|
|
parameter ^= type_parameters.TypeAt(i);
|
|
parameter.set_bound(bound);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set super type. Some classes (e.g., Object) do not have one.
|
|
if (kernel_normal_class->super_class() != NULL) {
|
|
AbstractType& super_type =
|
|
T.TranslateTypeWithoutFinalization(kernel_normal_class->super_class());
|
|
if (super_type.IsMalformed()) H.ReportError("Malformed super type");
|
|
klass->set_super_type(super_type);
|
|
}
|
|
|
|
// Build implemented interface types
|
|
intptr_t interface_count = kernel_klass->implemented_classes().length();
|
|
const dart::Array& interfaces =
|
|
dart::Array::Handle(Z, dart::Array::New(interface_count, Heap::kOld));
|
|
for (intptr_t i = 0; i < interface_count; i++) {
|
|
InterfaceType* kernel_interface_type =
|
|
kernel_klass->implemented_classes()[i];
|
|
const AbstractType& type =
|
|
T.TranslateTypeWithoutFinalization(kernel_interface_type);
|
|
if (type.IsMalformed()) H.ReportError("Malformed interface type.");
|
|
interfaces.SetAt(i, type);
|
|
}
|
|
klass->set_interfaces(interfaces);
|
|
if (kernel_klass->is_abstract()) klass->set_is_abstract();
|
|
}
|
|
|
|
|
|
dart::Class& KernelReader::ReadClass(const dart::Library& library,
|
|
const dart::Class& toplevel_class,
|
|
Class* kernel_klass) {
|
|
dart::Class& klass = LookupClass(kernel_klass->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()) {
|
|
klass.set_script(ScriptAt(kernel_klass->source_uri_index()));
|
|
}
|
|
if (klass.token_pos() == TokenPosition::kNoSource) {
|
|
klass.set_token_pos(kernel_klass->position());
|
|
}
|
|
if (!klass.is_cycle_free()) {
|
|
ReadPreliminaryClass(&klass, kernel_klass);
|
|
}
|
|
|
|
ActiveClassScope active_class_scope(&active_class_, kernel_klass, &klass);
|
|
fields_.Clear();
|
|
functions_.Clear();
|
|
|
|
if (library.raw() == dart::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 {
|
|
for (intptr_t i = 0; i < kernel_klass->fields().length(); i++) {
|
|
Field* kernel_field = kernel_klass->fields()[i];
|
|
ActiveMemberScope active_member_scope(&active_class_, kernel_field);
|
|
|
|
const dart::String& name = H.DartFieldName(kernel_field->name());
|
|
const AbstractType& type =
|
|
T.TranslateTypeWithoutFinalization(kernel_field->type());
|
|
const Object& script_class =
|
|
ClassForScriptAt(klass, kernel_field->source_uri_index());
|
|
dart::Field& field = dart::Field::Handle(
|
|
Z,
|
|
dart::Field::New(name, kernel_field->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.
|
|
kernel_field->IsFinal() || kernel_field->IsConst(),
|
|
kernel_field->IsConst(),
|
|
false, // is_reflectable
|
|
script_class, type, kernel_field->position()));
|
|
field.set_kernel_field(kernel_field);
|
|
field.set_has_initializer(kernel_field->initializer() != NULL);
|
|
GenerateFieldAccessors(klass, field, kernel_field);
|
|
fields_.Add(&field);
|
|
}
|
|
klass.AddFields(fields_);
|
|
}
|
|
|
|
for (intptr_t i = 0; i < kernel_klass->constructors().length(); i++) {
|
|
Constructor* kernel_constructor = kernel_klass->constructors()[i];
|
|
ActiveMemberScope active_member_scope(&active_class_, kernel_constructor);
|
|
ActiveFunctionScope active_function_scope(&active_class_,
|
|
kernel_constructor->function());
|
|
|
|
const dart::String& name =
|
|
H.DartConstructorName(kernel_constructor->canonical_name());
|
|
Function& function = dart::Function::ZoneHandle(
|
|
Z, dart::Function::New(name, RawFunction::kConstructor,
|
|
false, // is_static
|
|
kernel_constructor->IsConst(),
|
|
false, // is_abstract
|
|
kernel_constructor->IsExternal(),
|
|
false, // is_native
|
|
klass, kernel_constructor->position()));
|
|
function.set_end_token_pos(kernel_constructor->end_position());
|
|
functions_.Add(&function);
|
|
function.set_kernel_function(kernel_constructor);
|
|
function.set_result_type(T.ReceiverType(klass));
|
|
SetupFunctionParameters(H, T, klass, function,
|
|
kernel_constructor->function(),
|
|
true, // is_method
|
|
false); // is_closure
|
|
|
|
if (FLAG_enable_mirrors) {
|
|
library.AddFunctionMetadata(function, TokenPosition::kNoSource,
|
|
kernel_constructor);
|
|
}
|
|
}
|
|
|
|
for (intptr_t i = 0; i < kernel_klass->procedures().length(); i++) {
|
|
Procedure* kernel_procedure = kernel_klass->procedures()[i];
|
|
ActiveMemberScope active_member_scope(&active_class_, kernel_procedure);
|
|
ReadProcedure(library, klass, kernel_procedure, kernel_klass);
|
|
}
|
|
|
|
klass.SetFunctions(Array::Handle(MakeFunctionsArray()));
|
|
|
|
if (!klass.is_marked_for_parsing()) {
|
|
klass.set_is_marked_for_parsing();
|
|
}
|
|
|
|
if (FLAG_enable_mirrors) {
|
|
library.AddClassMetadata(klass, toplevel_class, TokenPosition::kNoSource,
|
|
kernel_klass);
|
|
}
|
|
|
|
return klass;
|
|
}
|
|
|
|
|
|
void KernelReader::ReadProcedure(const dart::Library& library,
|
|
const dart::Class& owner,
|
|
Procedure* kernel_procedure,
|
|
Class* kernel_klass) {
|
|
ActiveClassScope active_class_scope(&active_class_, kernel_klass, &owner);
|
|
ActiveMemberScope active_member_scope(&active_class_, kernel_procedure);
|
|
ActiveFunctionScope active_function_scope(&active_class_,
|
|
kernel_procedure->function());
|
|
|
|
const dart::String& name =
|
|
H.DartProcedureName(kernel_procedure->canonical_name());
|
|
bool is_method = kernel_klass != NULL && !kernel_procedure->IsStatic();
|
|
bool is_abstract = kernel_procedure->IsAbstract();
|
|
bool is_external = kernel_procedure->IsExternal();
|
|
dart::String* native_name = NULL;
|
|
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.
|
|
for (int i = 0; i < kernel_procedure->annotations().length(); ++i) {
|
|
Expression* annotation = kernel_procedure->annotations()[i];
|
|
if (!annotation->IsConstructorInvocation()) continue;
|
|
ConstructorInvocation* invocation =
|
|
ConstructorInvocation::Cast(annotation);
|
|
CanonicalName* annotation_class = H.EnclosingName(invocation->target());
|
|
ASSERT(H.IsClass(annotation_class));
|
|
String* class_name = annotation_class->name();
|
|
// Just compare by name, do not generate the annotation class.
|
|
if (!H.StringEquals(class_name, "ExternalName")) continue;
|
|
ASSERT(H.IsLibrary(annotation_class->parent()));
|
|
String* library_name = annotation_class->parent()->name();
|
|
if (!H.StringEquals(library_name, "dart:_internal")) continue;
|
|
|
|
is_external = false;
|
|
ASSERT(invocation->arguments()->positional().length() == 1 &&
|
|
invocation->arguments()->named().length() == 0);
|
|
StringLiteral* literal =
|
|
StringLiteral::Cast(invocation->arguments()->positional()[0]);
|
|
native_name = &H.DartSymbol(literal->value());
|
|
break;
|
|
}
|
|
}
|
|
const Object& script_class =
|
|
ClassForScriptAt(owner, kernel_procedure->source_uri_index());
|
|
dart::Function& function = dart::Function::ZoneHandle(
|
|
Z, Function::New(name, GetFunctionType(kernel_procedure),
|
|
!is_method, // is_static
|
|
false, // is_const
|
|
is_abstract, is_external,
|
|
native_name != NULL, // is_native
|
|
script_class, kernel_procedure->position()));
|
|
function.set_end_token_pos(kernel_procedure->end_position());
|
|
functions_.Add(&function);
|
|
function.set_kernel_function(kernel_procedure);
|
|
|
|
function.set_is_debuggable(
|
|
kernel_procedure->function()->dart_async_marker() == FunctionNode::kSync);
|
|
switch (kernel_procedure->function()->dart_async_marker()) {
|
|
case FunctionNode::kSyncStar:
|
|
function.set_modifier(RawFunction::kSyncGen);
|
|
break;
|
|
case FunctionNode::kAsync:
|
|
function.set_modifier(RawFunction::kAsync);
|
|
function.set_is_inlinable(!FLAG_causal_async_stacks);
|
|
break;
|
|
case FunctionNode::kAsyncStar:
|
|
function.set_modifier(RawFunction::kAsyncGen);
|
|
function.set_is_inlinable(!FLAG_causal_async_stacks);
|
|
break;
|
|
default:
|
|
// no special modifier
|
|
break;
|
|
}
|
|
ASSERT(kernel_procedure->function()->async_marker() == FunctionNode::kSync);
|
|
|
|
if (native_name != NULL) {
|
|
function.set_native_name(*native_name);
|
|
}
|
|
|
|
SetupFunctionParameters(H, T, owner, function, kernel_procedure->function(),
|
|
is_method,
|
|
false); // is_closure
|
|
|
|
if (kernel_klass == NULL) {
|
|
library.AddObject(function, name);
|
|
ASSERT(!Object::Handle(
|
|
Z, library.LookupObjectAllowPrivate(
|
|
H.DartProcedureName(kernel_procedure->canonical_name())))
|
|
.IsNull());
|
|
}
|
|
if (FLAG_enable_mirrors) {
|
|
library.AddFunctionMetadata(function, TokenPosition::kNoSource,
|
|
kernel_procedure);
|
|
}
|
|
}
|
|
|
|
const Object& KernelReader::ClassForScriptAt(const dart::Class& klass,
|
|
intptr_t source_uri_index) {
|
|
Script& correct_script = ScriptAt(source_uri_index);
|
|
if (klass.script() != correct_script.raw()) {
|
|
// TODO(jensj): We could probably cache this so we don't create
|
|
// new PatchClasses all the time
|
|
return PatchClass::ZoneHandle(Z, PatchClass::New(klass, correct_script));
|
|
}
|
|
return klass;
|
|
}
|
|
|
|
static int LowestFirst(const intptr_t* a, const intptr_t* b) {
|
|
return *a - *b;
|
|
}
|
|
|
|
/**
|
|
* If index exists as sublist in list, sort the sublist from lowest to highest,
|
|
* then copy it, as Smis and without duplicates,
|
|
* to a new Array in Heap::kOld which is returned.
|
|
* Note that the source list is both sorted and de-duplicated as well, but will
|
|
* possibly contain duplicate and unsorted data at the end.
|
|
* Otherwise (when sublist doesn't exist in list) return new empty array.
|
|
*/
|
|
static RawArray* AsSortedDuplicateFreeArray(
|
|
intptr_t index,
|
|
MallocGrowableArray<MallocGrowableArray<intptr_t>*>* list) {
|
|
if ((index < list->length()) && (list->At(index)->length() > 0)) {
|
|
MallocGrowableArray<intptr_t>* source = list->At(index);
|
|
source->Sort(LowestFirst);
|
|
|
|
intptr_t size = source->length();
|
|
intptr_t last = 0;
|
|
for (intptr_t current = 1; current < size; ++current) {
|
|
if (source->At(last) != source->At(current)) {
|
|
(*source)[++last] = source->At(current);
|
|
}
|
|
}
|
|
Array& array_object = Array::Handle();
|
|
array_object = Array::New(last + 1, Heap::kOld);
|
|
Smi& smi_value = Smi::Handle();
|
|
for (intptr_t i = 0; i <= last; ++i) {
|
|
smi_value = Smi::New(source->At(i));
|
|
array_object.SetAt(i, smi_value);
|
|
}
|
|
return array_object.raw();
|
|
} else {
|
|
return Array::New(0);
|
|
}
|
|
}
|
|
|
|
Script& KernelReader::ScriptAt(intptr_t index, String* import_uri) {
|
|
Script& script = Script::ZoneHandle(Z);
|
|
script ^= scripts_.At(index);
|
|
if (script.IsNull()) {
|
|
// Create script with correct uri(s).
|
|
uint8_t* uri_buffer = program_->source_table().UriFor(index);
|
|
intptr_t uri_size = program_->source_table().UriSizeFor(index);
|
|
dart::String& uri_string = H.DartString(uri_buffer, uri_size, Heap::kOld);
|
|
dart::String& import_uri_string =
|
|
import_uri == NULL ? uri_string : H.DartString(import_uri, Heap::kOld);
|
|
uint8_t* source_buffer = program_->source_table().SourceCodeFor(index);
|
|
intptr_t source_size = program_->source_table().SourceCodeSizeFor(index);
|
|
dart::String& source_code =
|
|
H.DartString(source_buffer, source_size, Heap::kOld);
|
|
script = Script::New(import_uri_string, uri_string, source_code,
|
|
RawScript::kKernelTag);
|
|
script.set_kernel_strings(H.string_data());
|
|
scripts_.SetAt(index, script);
|
|
|
|
// Create line_starts array for the script.
|
|
intptr_t* line_starts = program_->source_table().LineStartsFor(index);
|
|
intptr_t line_count = program_->source_table().LineCountFor(index);
|
|
Array& array_object = Array::Handle(Z, Array::New(line_count, Heap::kOld));
|
|
Smi& value = Smi::Handle(Z);
|
|
for (intptr_t i = 0; i < line_count; ++i) {
|
|
value = Smi::New(line_starts[i]);
|
|
array_object.SetAt(i, value);
|
|
}
|
|
script.set_line_starts(array_object);
|
|
|
|
// Create tokens_seen array for the script.
|
|
array_object =
|
|
AsSortedDuplicateFreeArray(index, &program_->valid_token_positions);
|
|
script.set_debug_positions(array_object);
|
|
|
|
// Create yield_positions array for the script.
|
|
array_object =
|
|
AsSortedDuplicateFreeArray(index, &program_->yield_token_positions);
|
|
script.set_yield_positions(array_object);
|
|
}
|
|
return script;
|
|
}
|
|
|
|
void KernelReader::GenerateFieldAccessors(const dart::Class& klass,
|
|
const dart::Field& field,
|
|
Field* kernel_field) {
|
|
if (kernel_field->IsStatic() && kernel_field->initializer() == NULL) {
|
|
// Static fields without an initializer are implicitly initialized to null.
|
|
// We do not need a getter.
|
|
field.SetStaticValue(Instance::Handle(Z), true);
|
|
return;
|
|
}
|
|
if (kernel_field->initializer() != NULL) {
|
|
SimpleExpressionConverter converter(&H);
|
|
const bool has_simple_initializer =
|
|
converter.IsSimple(kernel_field->initializer());
|
|
if (kernel_field->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 JitOptimizer::VisitStoreInstanceField for more details.
|
|
field.RecordStore(converter.SimpleValue());
|
|
if (!converter.SimpleValue().IsNull() &&
|
|
converter.SimpleValue().IsDouble()) {
|
|
field.set_is_double_initialized(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
const dart::String& getter_name =
|
|
H.DartGetterName(kernel_field->canonical_name());
|
|
const Object& script_class =
|
|
ClassForScriptAt(klass, kernel_field->source_uri_index());
|
|
Function& getter = Function::ZoneHandle(
|
|
Z,
|
|
Function::New(
|
|
getter_name,
|
|
kernel_field->IsStatic() ? RawFunction::kImplicitStaticFinalGetter
|
|
: RawFunction::kImplicitGetter,
|
|
kernel_field->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.
|
|
kernel_field->IsStatic() ? kernel_field->IsConst()
|
|
: kernel_field->IsFinal(),
|
|
false, // is_abstract
|
|
false, // is_external
|
|
false, // is_native
|
|
script_class, kernel_field->position()));
|
|
functions_.Add(&getter);
|
|
getter.set_end_token_pos(kernel_field->end_position());
|
|
getter.set_kernel_function(kernel_field);
|
|
getter.set_result_type(AbstractType::Handle(Z, field.type()));
|
|
getter.set_is_debuggable(false);
|
|
SetupFieldAccessorFunction(klass, getter);
|
|
|
|
if (!kernel_field->IsStatic() && !kernel_field->IsFinal()) {
|
|
// Only static fields can be const.
|
|
ASSERT(!kernel_field->IsConst());
|
|
const dart::String& setter_name =
|
|
H.DartSetterName(kernel_field->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, kernel_field->position()));
|
|
functions_.Add(&setter);
|
|
setter.set_end_token_pos(kernel_field->end_position());
|
|
setter.set_kernel_function(kernel_field);
|
|
setter.set_result_type(Object::void_type());
|
|
setter.set_is_debuggable(false);
|
|
SetupFieldAccessorFunction(klass, setter);
|
|
}
|
|
}
|
|
|
|
|
|
void KernelReader::SetupFunctionParameters(TranslationHelper translation_helper,
|
|
DartTypeTranslator type_translator,
|
|
const dart::Class& klass,
|
|
const dart::Function& function,
|
|
FunctionNode* node,
|
|
bool is_method,
|
|
bool is_closure) {
|
|
dart::Zone* zone = translation_helper.zone();
|
|
|
|
ASSERT(!(is_method && is_closure));
|
|
bool is_factory = function.IsFactory();
|
|
intptr_t extra_parameters = (is_method || is_closure || is_factory) ? 1 : 0;
|
|
|
|
function.set_num_fixed_parameters(extra_parameters +
|
|
node->required_parameter_count());
|
|
if (node->named_parameters().length() > 0) {
|
|
function.SetNumOptionalParameters(node->named_parameters().length(), false);
|
|
} else {
|
|
function.SetNumOptionalParameters(node->positional_parameters().length() -
|
|
node->required_parameter_count(),
|
|
true);
|
|
}
|
|
intptr_t num_parameters = extra_parameters +
|
|
node->positional_parameters().length() +
|
|
node->named_parameters().length();
|
|
function.set_parameter_types(
|
|
Array::Handle(zone, Array::New(num_parameters, Heap::kOld)));
|
|
function.set_parameter_names(
|
|
Array::Handle(zone, Array::New(num_parameters, Heap::kOld)));
|
|
intptr_t pos = 0;
|
|
if (is_method) {
|
|
ASSERT(!klass.IsNull());
|
|
function.SetParameterTypeAt(pos,
|
|
translation_helper.GetCanonicalType(klass));
|
|
function.SetParameterNameAt(pos, Symbols::This());
|
|
pos++;
|
|
} else if (is_closure) {
|
|
function.SetParameterTypeAt(pos, AbstractType::dynamic_type());
|
|
function.SetParameterNameAt(pos, Symbols::ClosureParameter());
|
|
pos++;
|
|
} else if (is_factory) {
|
|
function.SetParameterTypeAt(pos, AbstractType::dynamic_type());
|
|
function.SetParameterNameAt(pos, Symbols::TypeArgumentsParameter());
|
|
pos++;
|
|
}
|
|
for (intptr_t i = 0; i < node->positional_parameters().length(); i++, pos++) {
|
|
VariableDeclaration* kernel_variable = node->positional_parameters()[i];
|
|
const AbstractType& type = type_translator.TranslateTypeWithoutFinalization(
|
|
kernel_variable->type());
|
|
function.SetParameterTypeAt(
|
|
pos, type.IsMalformed() ? Type::dynamic_type() : type);
|
|
function.SetParameterNameAt(
|
|
pos, translation_helper.DartSymbol(kernel_variable->name()));
|
|
}
|
|
for (intptr_t i = 0; i < node->named_parameters().length(); i++, pos++) {
|
|
VariableDeclaration* named_expression = node->named_parameters()[i];
|
|
const AbstractType& type = type_translator.TranslateTypeWithoutFinalization(
|
|
named_expression->type());
|
|
function.SetParameterTypeAt(
|
|
pos, type.IsMalformed() ? Type::dynamic_type() : type);
|
|
function.SetParameterNameAt(
|
|
pos, translation_helper.DartSymbol(named_expression->name()));
|
|
}
|
|
|
|
// The result type for generative constructors has already been set.
|
|
if (!function.IsGenerativeConstructor()) {
|
|
const AbstractType& return_type =
|
|
type_translator.TranslateTypeWithoutFinalization(node->return_type());
|
|
function.set_result_type(return_type.IsMalformed() ? Type::dynamic_type()
|
|
: return_type);
|
|
}
|
|
}
|
|
|
|
|
|
void KernelReader::SetupFieldAccessorFunction(const dart::Class& klass,
|
|
const dart::Function& function) {
|
|
bool is_setter = function.IsImplicitSetterFunction();
|
|
bool is_method = !function.IsStaticFunction();
|
|
intptr_t num_parameters = (is_method ? 1 : 0) + (is_setter ? 1 : 0);
|
|
|
|
function.SetNumOptionalParameters(0, false);
|
|
function.set_num_fixed_parameters(num_parameters);
|
|
function.set_parameter_types(
|
|
Array::Handle(Z, Array::New(num_parameters, Heap::kOld)));
|
|
function.set_parameter_names(
|
|
Array::Handle(Z, Array::New(num_parameters, 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++;
|
|
}
|
|
}
|
|
|
|
|
|
dart::Library& KernelReader::LookupLibrary(CanonicalName* library) {
|
|
dart::Library* handle = NULL;
|
|
if (!libraries_.Lookup(library, &handle)) {
|
|
const dart::String& url = H.DartSymbol(library->name());
|
|
handle =
|
|
&dart::Library::Handle(Z, dart::Library::LookupLibrary(thread_, url));
|
|
if (handle->IsNull()) {
|
|
*handle = dart::Library::New(url);
|
|
handle->Register(thread_);
|
|
}
|
|
ASSERT(!handle->IsNull());
|
|
libraries_.Insert(library, handle);
|
|
}
|
|
return *handle;
|
|
}
|
|
|
|
|
|
dart::Class& KernelReader::LookupClass(CanonicalName* klass) {
|
|
dart::Class* handle = NULL;
|
|
if (!classes_.Lookup(klass, &handle)) {
|
|
dart::Library& library = LookupLibrary(klass->parent());
|
|
const dart::String& name = H.DartClassName(klass);
|
|
handle = &dart::Class::Handle(Z, library.LookupClass(name));
|
|
if (handle->IsNull()) {
|
|
*handle = dart::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 KernelReader::GetFunctionType(Procedure* kernel_procedure) {
|
|
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>(kernel_procedure->kind());
|
|
if (kind == Procedure::kIncompleteProcedure) {
|
|
return RawFunction::kSignatureFunction;
|
|
} else {
|
|
ASSERT(0 <= kind && kind <= Procedure::kFactory);
|
|
return static_cast<RawFunction::Kind>(lookuptable[kind]);
|
|
}
|
|
}
|
|
|
|
|
|
ParsedFunction* ParseStaticFieldInitializer(Zone* zone,
|
|
const dart::Field& field) {
|
|
Thread* thread = Thread::Current();
|
|
kernel::Field* kernel_field = kernel::Field::Cast(
|
|
reinterpret_cast<kernel::Node*>(field.kernel_field()));
|
|
|
|
dart::String& init_name = dart::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,
|
|
dart::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_function(kernel_field);
|
|
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)
|