blob: ad1c9b0677f3fb95710dccb9fbbbd5566bd5af13 [file] [log] [blame] [edit]
// 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"
#ifndef DART_PRECOMPILED_RUNTIME
#include "lib/invocation_mirror.h"
#include "platform/utils.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/heap/heap.h"
#include "vm/heap/safepoint.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_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())),
node_sequence_(NULL),
regexp_compile_data_(NULL),
instantiator_(NULL),
function_type_arguments_(NULL),
parent_type_arguments_(NULL),
current_context_var_(NULL),
arg_desc_var_(NULL),
expression_temp_var_(NULL),
entry_points_temp_var_(NULL),
finally_return_temp_var_(NULL),
deferred_prefixes_(new ZoneGrowableArray<const LibraryPrefix*>()),
guarded_fields_(new ZoneGrowableArray<const Field*>()),
default_parameter_values_(NULL),
raw_type_arguments_var_(NULL),
first_parameter_index_(),
num_stack_locals_(0),
have_seen_await_expr_(false),
kernel_scopes_(NULL) {
ASSERT(function.IsZoneHandle());
// 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;
const bool reify_generic_argument = function.IsGeneric();
const bool load_optional_arguments = function.HasOptionalParameters();
const bool check_arguments = function_.IsClosureFunction();
const bool need_argument_descriptor =
load_optional_arguments || check_arguments || reify_generic_argument;
if (need_argument_descriptor) {
arg_desc_var_ = new (zone())
LocalVariable(TokenPosition::kNoSource, TokenPosition::kNoSource,
Symbols::ArgDescVar(), Object::dynamic_type());
}
}
void ParsedFunction::AddToGuardedFields(const Field* field) const {
if ((field->guarded_cid() == kDynamicCid) ||
(field->guarded_cid() == kIllegalCid)) {
return;
}
for (intptr_t j = 0; j < guarded_fields_->length(); j++) {
const Field* other = (*guarded_fields_)[j];
if (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 background
// 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() || Thread::Current()->IsMutatorThread());
guarded_fields_->Add(&Field::ZoneHandle(Z, field->raw()));
}
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_ == NULL) {
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 != NULL);
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 != NULL);
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 != NULL);
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::SetNodeSequence(SequenceNode* node_sequence) {
ASSERT(node_sequence_ == NULL);
ASSERT(node_sequence != NULL);
node_sequence_ = node_sequence;
}
void ParsedFunction::SetRegExpCompileData(
RegExpCompileData* regexp_compile_data) {
ASSERT(regexp_compile_data_ == NULL);
ASSERT(regexp_compile_data != NULL);
regexp_compile_data_ = regexp_compile_data;
}
void ParsedFunction::AddDeferredPrefix(const LibraryPrefix& prefix) {
// 'deferred_prefixes_' are used to invalidate code, but no invalidation is
// needed if --load_deferred_eagerly.
ASSERT(!FLAG_load_deferred_eagerly);
ASSERT(prefix.is_deferred_load());
ASSERT(!prefix.is_loaded());
for (intptr_t i = 0; i < deferred_prefixes_->length(); i++) {
if ((*deferred_prefixes_)[i]->raw() == prefix.raw()) {
return;
}
}
deferred_prefixes_->Add(&LibraryPrefix::ZoneHandle(Z, prefix.raw()));
}
void ParsedFunction::AllocateVariables() {
ASSERT(!function().IsIrregexpFunction());
LocalScope* scope = node_sequence()->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;
// 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* raw_parameter = scope->VariableAt(param);
if (raw_parameter->is_captured()) {
String& tmp = String::ZoneHandle(Z);
tmp = Symbols::FromConcat(T, Symbols::OriginalParam(),
raw_parameter->name());
RELEASE_ASSERT(scope->LocalLookupVariable(tmp) == NULL);
raw_parameter = new LocalVariable(raw_parameter->declaration_token_pos(),
raw_parameter->token_pos(), tmp,
raw_parameter->type());
if (function().HasOptionalParameters()) {
bool ok = scope->AddVariable(raw_parameter);
ASSERT(ok);
// Currently our optimizer cannot prove liveness of variables properly
// when a function has try/catch. It therefore makes the conservative
// estimate that all [LocalVariable]s in the frame are live and spills
// them before call sites (in some shape or form).
//
// Since we are guaranteed to not need that, we tell the try/catch
// spilling mechanism not to care about this variable.
raw_parameter->set_is_captured_parameter(true);
} else {
raw_parameter->set_index(
VariableIndex(function().NumParameters() - param));
}
}
raw_parameters_->Add(raw_parameter);
}
if (function_type_arguments_ != NULL) {
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) == NULL);
raw_type_args_parameter =
new LocalVariable(raw_type_args_parameter->declaration_token_pos(),
raw_type_args_parameter->token_pos(), tmp,
raw_type_args_parameter->type());
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 parameter_index_start;
VariableIndex reamining_local_variables_start;
{
// Compute start indices to parameters and locals, and the number of
// parameters to copy.
if (num_opt_params == 0) {
parameter_index_start = first_parameter_index_ =
VariableIndex(num_params);
reamining_local_variables_start = VariableIndex(0);
} else {
parameter_index_start = first_parameter_index_ = VariableIndex(0);
reamining_local_variables_start = VariableIndex(-num_params);
}
}
if (function_type_arguments_ != NULL && num_opt_params > 0) {
reamining_local_variables_start =
VariableIndex(reamining_local_variables_start.value() - 1);
}
// Allocate parameters and local variables, either in the local frame or
// in the context(s).
bool found_captured_variables = false;
VariableIndex first_local_index =
VariableIndex(parameter_index_start.value() > 0 ? 0 : -num_params);
VariableIndex next_free_index = scope->AllocateVariables(
parameter_index_start, num_params, first_local_index, NULL,
&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::AllocateBytecodeVariables(intptr_t num_stack_locals) {
ASSERT(!function().IsIrregexpFunction());
first_parameter_index_ = VariableIndex(function().num_fixed_parameters());
num_stack_locals_ = num_stack_locals;
}
} // namespace dart
#endif // DART_PRECOMPILED_RUNTIME