4093bdaf5a
Previously catch blocks were hanging off the function entry blocks being effectively an alternative entry-point into the function. Now catch blocks are hanging off the try-entry blocks. Previously all the variables that are used in the catch block and beyond were declared as parameters to catch block. Now only those that have their definitions not dominating catch entry will become parameters (for example, if a variable is assigned in the try-block, it becomes a parameter to catch block). During OSR, if OSR target entry point is inside some try-blocks, then all of corresponding try-entry/catch-blocks are pulled up to the OSR entry forming a chain that ends with a jump to the OSR target entry. TEST=vm/dart/trycatch*, ci Change-Id: Iae20c6548d5d65c63be6d7a53c1b0d2adac7ac31 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/356311 Commit-Queue: Alexander Aprelev <aam@google.com> Reviewed-by: Slava Egorov <vegorov@google.com> Reviewed-by: Alexander Markov <alexmarkov@google.com>
249 lines
10 KiB
C++
249 lines
10 KiB
C++
// 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(Ffi, Array, array, Array)
|
|
DEFINE_CLASS_GETTER(Ffi, Compound, compound, Compound)
|
|
DEFINE_CLASS_GETTER(Ffi, Struct, struct, Struct)
|
|
DEFINE_CLASS_GETTER(Ffi, Union, union, Union)
|
|
DEFINE_CLASS_GETTER(TypedData, TypedData, typed_data, TypedData)
|
|
DEFINE_CLASS_GETTER(TypedData, TypedList, typed_list, _TypedList)
|
|
|
|
#undef DEFINE_CLASS_GETTER
|
|
|
|
const Field& CompilerState::CompoundOffsetInBytesField() {
|
|
if (compound_offset_in_bytes_field_ == nullptr) {
|
|
Thread* thread = Thread::Current();
|
|
Zone* zone = thread->zone();
|
|
const auto& field =
|
|
Field::ZoneHandle(zone, CompoundClass().LookupInstanceFieldAllowPrivate(
|
|
Symbols::_offsetInBytes()));
|
|
ASSERT(!field.IsNull());
|
|
compound_offset_in_bytes_field_ = &field;
|
|
}
|
|
return *compound_offset_in_bytes_field_;
|
|
}
|
|
|
|
const Field& CompilerState::CompoundTypedDataBaseField() {
|
|
if (compound_typed_data_base_field_ == nullptr) {
|
|
Thread* thread = Thread::Current();
|
|
Zone* zone = thread->zone();
|
|
const auto& field =
|
|
Field::ZoneHandle(zone, CompoundClass().LookupInstanceFieldAllowPrivate(
|
|
Symbols::_typedDataBase()));
|
|
ASSERT(!field.IsNull());
|
|
compound_typed_data_base_field_ = &field;
|
|
}
|
|
return *compound_typed_data_base_field_;
|
|
}
|
|
|
|
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
|