| // Copyright (c) 2018, 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/compiler/compiler_state.h" | |
| #include <functional> | |
| #include "vm/compiler/aot/precompiler.h" | |
| #include "vm/compiler/backend/flow_graph_compiler.h" | |
| #include "vm/compiler/backend/il_printer.h" | |
| #include "vm/compiler/backend/slot.h" | |
| #include "vm/growable_array.h" | |
| #include "vm/object_store.h" | |
| #include "vm/scopes.h" | |
| namespace dart { | |
| template <typename T> | |
| T* PutIfAbsent(Thread* thread, | |
| ZoneGrowableArray<T*>** array_slot, | |
| intptr_t index, | |
| std::function<T*()> create) { | |
| auto array = *array_slot; | |
| if (array == nullptr) { | |
| Zone* const Z = thread->zone(); | |
| *array_slot = array = new (Z) ZoneGrowableArray<T*>(Z, index + 1); | |
| } | |
| while (array->length() <= index) { | |
| array->Add(nullptr); | |
| } | |
| if (array->At(index) == nullptr) { | |
| (*array)[index] = create(); | |
| } | |
| return array->At(index); | |
| } | |
| CompilerTracing CompilerState::ShouldTrace(const Function& func) { | |
| return FlowGraphPrinter::ShouldPrint(func) ? CompilerTracing::kOn | |
| : CompilerTracing::kOff; | |
| } | |
| const Class& CompilerState::ComparableClass() { | |
| if (comparable_class_ == nullptr) { | |
| Thread* thread = Thread::Current(); | |
| Zone* zone = thread->zone(); | |
| // When obfuscation is enabled we need to obfuscate the name of the | |
| // class before looking it up. | |
| String& name = String::Handle(zone, Symbols::New(thread, "Comparable")); | |
| if (thread->isolate_group()->obfuscate()) { | |
| Obfuscator obfuscator(thread, Object::null_string()); | |
| name = obfuscator.Rename(name); | |
| } | |
| const Library& lib = Library::Handle(zone, Library::CoreLibrary()); | |
| const Class& cls = Class::ZoneHandle(zone, lib.LookupClass(name)); | |
| ASSERT(!cls.IsNull()); | |
| comparable_class_ = &cls; | |
| } | |
| return *comparable_class_; | |
| } | |
| const Function& CompilerState::StringBaseInterpolateSingle() { | |
| if (interpolate_single_ == nullptr) { | |
| Thread* thread = Thread::Current(); | |
| Zone* zone = thread->zone(); | |
| const Class& cls = | |
| Class::Handle(Library::LookupCoreClass(Symbols::StringBase())); | |
| ASSERT(!cls.IsNull()); | |
| interpolate_single_ = &Function::ZoneHandle( | |
| zone, cls.LookupFunctionAllowPrivate(Symbols::InterpolateSingle())); | |
| ASSERT(!interpolate_single_->IsNull()); | |
| } | |
| return *interpolate_single_; | |
| } | |
| const Function& CompilerState::StringBaseInterpolate() { | |
| if (interpolate_ == nullptr) { | |
| Thread* thread = Thread::Current(); | |
| Zone* zone = thread->zone(); | |
| const Class& cls = | |
| Class::Handle(Library::LookupCoreClass(Symbols::StringBase())); | |
| ASSERT(!cls.IsNull()); | |
| interpolate_ = &Function::ZoneHandle( | |
| zone, cls.LookupFunctionAllowPrivate(Symbols::Interpolate())); | |
| ASSERT(!interpolate_->IsNull()); | |
| } | |
| return *interpolate_; | |
| } | |
| #define DEFINE_TYPED_LIST_NATIVE_FUNCTION_GETTER(Upper, Lower) \ | |
| const Function& CompilerState::TypedListGet##Upper() { \ | |
| if (typed_list_get_##Lower##_ == nullptr) { \ | |
| Thread* thread = Thread::Current(); \ | |
| Zone* zone = thread->zone(); \ | |
| const auto& cls = CompilerState::TypedListClass(); \ | |
| typed_list_get_##Lower##_ = &Function::ZoneHandle( \ | |
| zone, cls.LookupFunctionAllowPrivate(Symbols::_nativeGet##Upper())); \ | |
| ASSERT(!typed_list_get_##Lower##_->IsNull()); \ | |
| } \ | |
| return *typed_list_get_##Lower##_; \ | |
| } \ | |
| const Function& CompilerState::TypedListSet##Upper() { \ | |
| if (typed_list_set_##Lower##_ == nullptr) { \ | |
| Thread* thread = Thread::Current(); \ | |
| Zone* zone = thread->zone(); \ | |
| const auto& cls = CompilerState::TypedListClass(); \ | |
| typed_list_set_##Lower##_ = &Function::ZoneHandle( \ | |
| zone, cls.LookupFunctionAllowPrivate(Symbols::_nativeSet##Upper())); \ | |
| ASSERT(!typed_list_set_##Lower##_->IsNull()); \ | |
| } \ | |
| return *typed_list_set_##Lower##_; \ | |
| } | |
| DEFINE_TYPED_LIST_NATIVE_FUNCTION_GETTER(Float32, float32) | |
| DEFINE_TYPED_LIST_NATIVE_FUNCTION_GETTER(Float64, float64) | |
| DEFINE_TYPED_LIST_NATIVE_FUNCTION_GETTER(Float32x4, float32x4) | |
| DEFINE_TYPED_LIST_NATIVE_FUNCTION_GETTER(Int32x4, int32x4) | |
| DEFINE_TYPED_LIST_NATIVE_FUNCTION_GETTER(Float64x2, float64x2) | |
| #undef DEFINE_TYPED_LIST_NATIVE_FUNCTION_GETTER | |
| #define DEFINE_CLASS_GETTER(Lib, Upper, Lower, Symbol) \ | |
| const Class& CompilerState::Upper##Class() { \ | |
| if (Lower##_class_ == nullptr) { \ | |
| Thread* thread = Thread::Current(); \ | |
| Zone* zone = thread->zone(); \ | |
| const auto& lib = Library::Handle(zone, Library::Lib##Library()); \ | |
| const auto& cls = \ | |
| Class::Handle(zone, lib.LookupClassAllowPrivate(Symbols::Symbol())); \ | |
| ASSERT(!cls.IsNull()); \ | |
| const Error& error = Error::Handle(zone, cls.EnsureIsFinalized(thread)); \ | |
| ASSERT(error.IsNull()); \ | |
| Lower##_class_ = &cls; \ | |
| } \ | |
| return *Lower##_class_; \ | |
| } | |
| DEFINE_CLASS_GETTER(Core, _Array, array_base, _Array) | |
| DEFINE_CLASS_GETTER(Internal, FinalizerBase, finalizer_base, FinalizerBase) | |
| DEFINE_CLASS_GETTER(TypedData, TypedList, typed_list, _TypedList) | |
| DEFINE_CLASS_GETTER(TypedData, TypedListBase, typed_list_base, _TypedListBase) | |
| DEFINE_CLASS_GETTER(TypedData, TypedListView, typed_list_view, _TypedListView) | |
| DEFINE_CLASS_GETTER(Core, StringBase, string_base, StringBase) | |
| DEFINE_CLASS_GETTER(CompactHash, | |
| LinkedHashBase, | |
| linked_hash_base, | |
| _LinkedHashBase) | |
| DEFINE_CLASS_GETTER(NativeWrappers, | |
| NativeFieldWrapperClass1, | |
| native_field_wrapper_class1, | |
| NativeFieldWrapperClass1) | |
| #undef DEFINE_CLASS_GETTER | |
| const Field& CompilerState::ErrorStackTraceField() { | |
| if (error_stack_trace_field_ == nullptr) { | |
| Thread* thread = Thread::Current(); | |
| Zone* zone = thread->zone(); | |
| const auto& error_class = Class::Handle( | |
| zone, thread->isolate_group()->object_store()->error_class()); | |
| const auto& field = Field::ZoneHandle( | |
| zone, | |
| error_class.LookupInstanceFieldAllowPrivate(Symbols::_stackTrace())); | |
| ASSERT(!field.IsNull()); | |
| error_stack_trace_field_ = &field; | |
| } | |
| return *error_stack_trace_field_; | |
| } | |
| static bool IsMarkedWithNoBoundsChecks(const Function& function) { | |
| Object& options = Object::Handle(); | |
| return Library::FindPragma(dart::Thread::Current(), | |
| /*only_core=*/false, function, | |
| Symbols::vm_unsafe_no_bounds_checks(), | |
| /*multiple=*/false, &options); | |
| } | |
| FunctionPragmas::FunctionPragmas(const Function& function) | |
| : function(function), | |
| unsafe_no_bounds_checks(IsMarkedWithNoBoundsChecks(function)) {} | |
| const FunctionPragmas& CompilerState::PragmasOf(const Function& function) { | |
| if (cached_pragmas_ == nullptr) { | |
| Zone* zone = thread()->zone(); | |
| cached_pragmas_ = new (zone) CachedPragmasMap(zone); | |
| } | |
| auto result = cached_pragmas_->LookupValue(&function); | |
| if (result == nullptr) { | |
| Zone* zone = thread()->zone(); | |
| result = new (zone) FunctionPragmas(Function::Handle(zone, function.ptr())); | |
| cached_pragmas_->Insert(result); | |
| } | |
| return *result; | |
| } | |
| void CompilerState::ReportCrash() { | |
| OS::PrintErr("=== Crash occurred when compiling %s in %s mode in %s pass\n", | |
| function() != nullptr ? function()->ToFullyQualifiedCString() | |
| : "unknown function", | |
| is_aot() ? "AOT" | |
| : is_optimizing() ? "optimizing JIT" | |
| : "unoptimized JIT", | |
| pass() != nullptr ? pass()->name() : "unknown"); | |
| if (pass_state() != nullptr && pass()->id() == CompilerPass::kGenerateCode) { | |
| if (pass_state()->graph_compiler->current_block() != nullptr) { | |
| OS::PrintErr("=== When compiling block %s\n", | |
| pass_state()->graph_compiler->current_block()->ToCString()); | |
| } | |
| if (pass_state()->graph_compiler->current_instruction() != nullptr) { | |
| OS::PrintErr( | |
| "=== When compiling instruction %s\n", | |
| pass_state()->graph_compiler->current_instruction()->ToCString()); | |
| } | |
| } | |
| if (pass_state() != nullptr && pass_state()->flow_graph() != nullptr) { | |
| pass_state()->flow_graph()->Print(pass()->name()); | |
| } else { | |
| OS::PrintErr("=== Flow Graph not available\n"); | |
| } | |
| } | |
| } // namespace dart |