| // 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) |