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>
353 lines
13 KiB
C++
353 lines
13 KiB
C++
// Copyright (c) 2012, 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/parser.h"
|
|
#include "vm/flags.h"
|
|
|
|
#if !defined(DART_PRECOMPILED_RUNTIME)
|
|
|
|
#include "lib/invocation_mirror.h"
|
|
#include "platform/utils.h"
|
|
#include "vm/bit_vector.h"
|
|
#include "vm/bootstrap.h"
|
|
#include "vm/class_finalizer.h"
|
|
#include "vm/compiler/aot/precompiler.h"
|
|
#include "vm/compiler/backend/il_printer.h"
|
|
#include "vm/compiler/frontend/scope_builder.h"
|
|
#include "vm/compiler/jit/compiler.h"
|
|
#include "vm/dart_api_impl.h"
|
|
#include "vm/dart_entry.h"
|
|
#include "vm/growable_array.h"
|
|
#include "vm/handles.h"
|
|
#include "vm/hash_table.h"
|
|
#include "vm/isolate.h"
|
|
#include "vm/longjump.h"
|
|
#include "vm/native_arguments.h"
|
|
#include "vm/native_entry.h"
|
|
#include "vm/object.h"
|
|
#include "vm/object_store.h"
|
|
#include "vm/os.h"
|
|
#include "vm/regexp/regexp_assembler.h"
|
|
#include "vm/resolver.h"
|
|
#include "vm/scopes.h"
|
|
#include "vm/stack_frame.h"
|
|
#include "vm/symbols.h"
|
|
#include "vm/tags.h"
|
|
#include "vm/timeline.h"
|
|
#include "vm/zone.h"
|
|
|
|
namespace dart {
|
|
|
|
// Quick access to the current thread, isolate and zone.
|
|
#define T (thread())
|
|
#define I (isolate())
|
|
#define Z (zone())
|
|
|
|
ParsedFunction::ParsedFunction(Thread* thread, const Function& function)
|
|
: thread_(thread),
|
|
function_(function),
|
|
code_(Code::Handle(zone(), function.unoptimized_code())),
|
|
scope_(nullptr),
|
|
regexp_compile_data_(nullptr),
|
|
function_type_arguments_(nullptr),
|
|
parent_type_arguments_(nullptr),
|
|
current_context_var_(nullptr),
|
|
arg_desc_var_(nullptr),
|
|
expression_temp_var_(nullptr),
|
|
entry_points_temp_var_(nullptr),
|
|
finally_return_temp_var_(nullptr),
|
|
dynamic_closure_call_vars_(nullptr),
|
|
guarded_fields_(),
|
|
default_parameter_values_(nullptr),
|
|
raw_type_arguments_var_(nullptr),
|
|
first_parameter_index_(),
|
|
num_stack_locals_(0),
|
|
have_seen_await_expr_(false),
|
|
kernel_scopes_(nullptr) {
|
|
DEBUG_ASSERT(function.IsNotTemporaryScopedHandle());
|
|
// Every function has a local variable for the current context.
|
|
LocalVariable* temp = new (zone())
|
|
LocalVariable(function.token_pos(), function.token_pos(),
|
|
Symbols::CurrentContextVar(), Object::dynamic_type());
|
|
current_context_var_ = temp;
|
|
|
|
if (function.PrologueNeedsArgumentsDescriptor()) {
|
|
arg_desc_var_ = new (zone())
|
|
LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
|
|
Symbols::ArgDescVar(), Object::dynamic_type());
|
|
}
|
|
|
|
// The code generated by the prologue builder for loading optional arguments
|
|
// requires the expression temporary variable.
|
|
if (function.HasOptionalParameters()) {
|
|
EnsureExpressionTemp();
|
|
}
|
|
}
|
|
|
|
void ParsedFunction::AddToGuardedFields(const Field* field) const {
|
|
if ((field->guarded_cid() == kDynamicCid) ||
|
|
(field->guarded_cid() == kIllegalCid)) {
|
|
return;
|
|
}
|
|
|
|
const Field** other = guarded_fields_.Lookup(field);
|
|
if (other != nullptr) {
|
|
ASSERT(field->Original() == (*other)->Original());
|
|
// Abort background compilation early if the guarded state of this field
|
|
// has changed during compilation. We will not be able to commit
|
|
// the resulting code anyway.
|
|
if (Compiler::IsBackgroundCompilation()) {
|
|
if (!(*other)->IsConsistentWith(*field)) {
|
|
Compiler::AbortBackgroundCompilation(
|
|
DeoptId::kNone, "Field's guarded state changed during compilation");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Note: the list of guarded fields must contain copies during optimizing
|
|
// compilation because we will look at their guarded_cid when copying
|
|
// the array of guarded fields from callee into the caller during
|
|
// inlining.
|
|
ASSERT(field->IsOriginal() ==
|
|
!CompilerState::Current().should_clone_fields());
|
|
guarded_fields_.Insert(&Field::ZoneHandle(Z, field->ptr()));
|
|
}
|
|
|
|
void ParsedFunction::Bailout(const char* origin, const char* reason) const {
|
|
Report::MessageF(Report::kBailout, Script::Handle(function_.script()),
|
|
function_.token_pos(), Report::AtLocation,
|
|
"%s Bailout in %s: %s", origin,
|
|
String::Handle(function_.name()).ToCString(), reason);
|
|
UNREACHABLE();
|
|
}
|
|
|
|
kernel::ScopeBuildingResult* ParsedFunction::EnsureKernelScopes() {
|
|
if (kernel_scopes_ == nullptr) {
|
|
kernel::ScopeBuilder builder(this);
|
|
kernel_scopes_ = builder.BuildScopes();
|
|
}
|
|
return kernel_scopes_;
|
|
}
|
|
|
|
LocalVariable* ParsedFunction::EnsureExpressionTemp() {
|
|
if (!has_expression_temp_var()) {
|
|
LocalVariable* temp =
|
|
new (Z) LocalVariable(function_.token_pos(), function_.token_pos(),
|
|
Symbols::ExprTemp(), Object::dynamic_type());
|
|
ASSERT(temp != nullptr);
|
|
set_expression_temp_var(temp);
|
|
}
|
|
ASSERT(has_expression_temp_var());
|
|
return expression_temp_var();
|
|
}
|
|
|
|
LocalVariable* ParsedFunction::EnsureEntryPointsTemp() {
|
|
if (!has_entry_points_temp_var()) {
|
|
LocalVariable* temp = new (Z)
|
|
LocalVariable(function_.token_pos(), function_.token_pos(),
|
|
Symbols::EntryPointsTemp(), Object::dynamic_type());
|
|
ASSERT(temp != nullptr);
|
|
set_entry_points_temp_var(temp);
|
|
}
|
|
ASSERT(has_entry_points_temp_var());
|
|
return entry_points_temp_var();
|
|
}
|
|
|
|
void ParsedFunction::EnsureFinallyReturnTemp(bool is_async) {
|
|
if (!has_finally_return_temp_var()) {
|
|
LocalVariable* temp =
|
|
new (Z) LocalVariable(function_.token_pos(), function_.token_pos(),
|
|
Symbols::FinallyRetVal(), Object::dynamic_type());
|
|
ASSERT(temp != nullptr);
|
|
temp->set_is_final();
|
|
if (is_async) {
|
|
temp->set_is_captured();
|
|
}
|
|
set_finally_return_temp_var(temp);
|
|
}
|
|
ASSERT(has_finally_return_temp_var());
|
|
}
|
|
|
|
void ParsedFunction::SetRegExpCompileData(
|
|
RegExpCompileData* regexp_compile_data) {
|
|
ASSERT(regexp_compile_data_ == nullptr);
|
|
ASSERT(regexp_compile_data != nullptr);
|
|
regexp_compile_data_ = regexp_compile_data;
|
|
}
|
|
|
|
void ParsedFunction::AllocateVariables() {
|
|
ASSERT(!function().IsIrregexpFunction());
|
|
LocalScope* scope = this->scope();
|
|
const intptr_t num_fixed_params = function().num_fixed_parameters();
|
|
const intptr_t num_opt_params = function().NumOptionalParameters();
|
|
const intptr_t num_params = num_fixed_params + num_opt_params;
|
|
const bool copy_parameters = function().MakesCopyOfParameters();
|
|
|
|
// Before we start allocating indices to variables, we'll setup the
|
|
// parameters array, which can be used to access the raw parameters (i.e. not
|
|
// the potentially variables which are in the context)
|
|
|
|
raw_parameters_ = new (Z) ZoneGrowableArray<LocalVariable*>(Z, num_params);
|
|
for (intptr_t param = 0; param < num_params; ++param) {
|
|
LocalVariable* variable = ParameterVariable(param);
|
|
LocalVariable* raw_parameter = variable;
|
|
if (variable->is_captured()) {
|
|
String& tmp = String::ZoneHandle(Z);
|
|
tmp = Symbols::FromConcat(T, Symbols::OriginalParam(), variable->name());
|
|
|
|
RELEASE_ASSERT(scope->LocalLookupVariable(
|
|
tmp, LocalVariable::kNoKernelOffset) == nullptr);
|
|
raw_parameter = new LocalVariable(
|
|
variable->declaration_token_pos(), variable->token_pos(), tmp,
|
|
variable->static_type(), LocalVariable::kNoKernelOffset,
|
|
variable->inferred_type(), variable->inferred_arg_type(),
|
|
variable->inferred_arg_value());
|
|
raw_parameter->set_annotations_offset(variable->annotations_offset());
|
|
if (variable->is_explicit_covariant_parameter()) {
|
|
raw_parameter->set_is_explicit_covariant_parameter();
|
|
}
|
|
if (variable->needs_covariant_check_in_method()) {
|
|
raw_parameter->set_needs_covariant_check_in_method();
|
|
}
|
|
raw_parameter->set_type_check_mode(variable->type_check_mode());
|
|
if (copy_parameters) {
|
|
bool ok = scope->AddVariable(raw_parameter);
|
|
ASSERT(ok);
|
|
} else {
|
|
raw_parameter->set_index(
|
|
VariableIndex(function().NumParameters() - param));
|
|
}
|
|
}
|
|
raw_parameters_->Add(raw_parameter);
|
|
}
|
|
if (function_type_arguments_ != nullptr) {
|
|
LocalVariable* raw_type_args_parameter = function_type_arguments_;
|
|
if (function_type_arguments_->is_captured()) {
|
|
String& tmp = String::ZoneHandle(Z);
|
|
tmp = Symbols::FromConcat(T, Symbols::OriginalParam(),
|
|
function_type_arguments_->name());
|
|
|
|
ASSERT(scope->LocalLookupVariable(tmp, LocalVariable::kNoKernelOffset) ==
|
|
nullptr);
|
|
raw_type_args_parameter =
|
|
new LocalVariable(function_type_arguments_->declaration_token_pos(),
|
|
function_type_arguments_->token_pos(), tmp,
|
|
function_type_arguments_->static_type(),
|
|
LocalVariable::kNoKernelOffset);
|
|
bool ok = scope->AddVariable(raw_type_args_parameter);
|
|
ASSERT(ok);
|
|
}
|
|
raw_type_arguments_var_ = raw_type_args_parameter;
|
|
}
|
|
|
|
// The copy parameters implementation will still write to local variables
|
|
// which we assign indices as with the old CopyParams implementation.
|
|
VariableIndex first_local_index;
|
|
{
|
|
// Compute start indices to parameters and locals, and the number of
|
|
// parameters to copy.
|
|
if (!copy_parameters) {
|
|
ASSERT(suspend_state_var() == nullptr);
|
|
first_parameter_index_ = VariableIndex(num_params);
|
|
first_local_index = VariableIndex(0);
|
|
} else {
|
|
// :suspend_state variable is inserted at the fixed slot
|
|
// before the copied parameters.
|
|
const intptr_t reserved_var_slot_count =
|
|
(suspend_state_var() != nullptr) ? 1 : 0;
|
|
first_parameter_index_ = VariableIndex(-reserved_var_slot_count);
|
|
first_local_index =
|
|
VariableIndex(first_parameter_index_.value() - num_params);
|
|
}
|
|
}
|
|
|
|
// Allocate parameters and local variables, either in the local frame or
|
|
// in the context(s).
|
|
bool found_captured_variables = false;
|
|
VariableIndex next_free_index = scope->AllocateVariables(
|
|
function(), first_parameter_index_, num_params, first_local_index,
|
|
nullptr, &found_captured_variables);
|
|
|
|
num_stack_locals_ = -next_free_index.value();
|
|
}
|
|
|
|
void ParsedFunction::AllocateIrregexpVariables(intptr_t num_stack_locals) {
|
|
ASSERT(function().IsIrregexpFunction());
|
|
ASSERT(function().NumOptionalParameters() == 0);
|
|
const intptr_t num_params = function().num_fixed_parameters();
|
|
ASSERT(num_params == RegExpMacroAssembler::kParamCount);
|
|
// Compute start indices to parameters and locals, and the number of
|
|
// parameters to copy.
|
|
first_parameter_index_ = VariableIndex(num_params);
|
|
|
|
// Frame indices are relative to the frame pointer and are decreasing.
|
|
num_stack_locals_ = num_stack_locals;
|
|
}
|
|
|
|
void ParsedFunction::SetCovariantParameters(
|
|
const BitVector* covariant_parameters) {
|
|
ASSERT(covariant_parameters_ == nullptr);
|
|
ASSERT(covariant_parameters->length() == function_.NumParameters());
|
|
covariant_parameters_ = covariant_parameters;
|
|
}
|
|
|
|
void ParsedFunction::SetGenericCovariantImplParameters(
|
|
const BitVector* generic_covariant_impl_parameters) {
|
|
ASSERT(generic_covariant_impl_parameters_ == nullptr);
|
|
ASSERT(generic_covariant_impl_parameters->length() ==
|
|
function_.NumParameters());
|
|
generic_covariant_impl_parameters_ = generic_covariant_impl_parameters;
|
|
}
|
|
|
|
bool ParsedFunction::IsCovariantParameter(intptr_t i) const {
|
|
ASSERT(covariant_parameters_ != nullptr);
|
|
ASSERT((i >= 0) && (i < function_.NumParameters()));
|
|
return covariant_parameters_->Contains(i);
|
|
}
|
|
|
|
bool ParsedFunction::IsGenericCovariantImplParameter(intptr_t i) const {
|
|
ASSERT(generic_covariant_impl_parameters_ != nullptr);
|
|
ASSERT((i >= 0) && (i < function_.NumParameters()));
|
|
return generic_covariant_impl_parameters_->Contains(i);
|
|
}
|
|
|
|
ParsedFunction::DynamicClosureCallVars*
|
|
ParsedFunction::EnsureDynamicClosureCallVars() {
|
|
ASSERT(function().IsDynamicClosureCallDispatcher());
|
|
if (dynamic_closure_call_vars_ != nullptr) return dynamic_closure_call_vars_;
|
|
const auto& saved_args_desc =
|
|
Array::Handle(zone(), function().saved_args_desc());
|
|
const ArgumentsDescriptor descriptor(saved_args_desc);
|
|
|
|
dynamic_closure_call_vars_ =
|
|
new (zone()) DynamicClosureCallVars(zone(), descriptor.NamedCount());
|
|
|
|
auto const pos = function().token_pos();
|
|
const auto& type_Dynamic = Object::dynamic_type();
|
|
const auto& type_Function =
|
|
Type::ZoneHandle(zone(), Type::DartFunctionType());
|
|
const auto& type_Smi = Type::ZoneHandle(zone(), Type::SmiType());
|
|
#define INIT_FIELD(Name, TypeName, Symbol) \
|
|
dynamic_closure_call_vars_->Name = new (zone()) LocalVariable( \
|
|
pos, pos, Symbols::DynamicCall##Symbol##Var(), type_##TypeName);
|
|
FOR_EACH_DYNAMIC_CLOSURE_CALL_VARIABLE(INIT_FIELD);
|
|
#undef INIT_FIELD
|
|
|
|
for (intptr_t i = 0; i < descriptor.NamedCount(); i++) {
|
|
auto const name = OS::SCreate(
|
|
zone(), ":dyn_call_named_argument_%" Pd "_parameter_index", i);
|
|
auto const var = new (zone()) LocalVariable(
|
|
pos, pos, String::ZoneHandle(zone(), Symbols::New(thread(), name)),
|
|
type_Smi);
|
|
dynamic_closure_call_vars_->named_argument_parameter_indices.Add(var);
|
|
}
|
|
|
|
return dynamic_closure_call_vars_;
|
|
}
|
|
|
|
} // namespace dart
|
|
|
|
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|