blob: 231300e595be74842e241850bdf2144a308c403b [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_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(Thread* thread)
: translation_helper_(thread),
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);
}
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(main->EnclosingName());
// 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, 0,
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 = invocation->target()->EnclosingName();
ASSERT(annotation_class->IsClass());
String* class_name = annotation_class->name();
// Just compare by name, do not generate the annotation class.
int length = sizeof("ExternalName") - 1;
if (class_name->size() != length) continue;
if (memcmp(class_name->buffer(), "ExternalName", length) != 0) continue;
ASSERT(annotation_class->parent()->IsLibrary());
String* library_name = annotation_class->parent()->name();
length = sizeof("dart:_internal") - 1;
if (library_name->size() != length) continue;
if (memcmp(library_name->buffer(), "dart:_internal", length) != 0) {
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 source_uri_index, String* import_uri) {
Script& script = Script::ZoneHandle(Z);
script ^= scripts_.At(source_uri_index);
if (script.IsNull()) {
// Create script with correct uri(s).
String* uri = program_->source_uri_table().strings()[source_uri_index];
dart::String& uri_string = H.DartString(uri, Heap::kOld);
dart::String& import_uri_string =
import_uri == NULL ? uri_string : H.DartString(import_uri, Heap::kOld);
dart::String& source_code = H.DartString(
program_->source_table().SourceFor(source_uri_index), Heap::kOld);
script = Script::New(import_uri_string, uri_string, source_code,
RawScript::kKernelTag);
scripts_.SetAt(source_uri_index, script);
// Create line_starts array for the script.
intptr_t* line_starts =
program_->source_table().LineStartsFor(source_uri_index);
intptr_t line_count =
program_->source_table().LineCountFor(source_uri_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(
source_uri_index, &program_->valid_token_positions);
script.set_debug_positions(array_object);
// Create yield_positions array for the script.
array_object ^= AsSortedDuplicateFreeArray(
source_uri_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.thread());
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)