// 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 #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 T* PutIfAbsent(Thread* thread, ZoneGrowableArray** array_slot, intptr_t index, std::function create) { auto array = *array_slot; if (array == nullptr) { Zone* const Z = thread->zone(); *array_slot = array = new (Z) ZoneGrowableArray(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(TypedData, TypedList, typed_list, _TypedList) #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