blob: d31e00a425ff759f1477d670061172a42967cec1 [file] [log] [blame]
// 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/frontend/bytecode_scope_builder.h"
#include "vm/compiler/frontend/bytecode_reader.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
namespace dart {
namespace kernel {
#define Z (zone_)
BytecodeScopeBuilder::BytecodeScopeBuilder(ParsedFunction* parsed_function)
: parsed_function_(parsed_function),
zone_(parsed_function->zone()),
scope_(nullptr) {}
void BytecodeScopeBuilder::BuildScopes() {
if (parsed_function_->node_sequence() != nullptr) {
return; // Scopes are already built.
}
const Function& function = parsed_function_->function();
LocalScope* enclosing_scope = nullptr;
if (function.IsImplicitClosureFunction() && !function.is_static()) {
// Create artificial enclosing scope for the tear-off that contains
// captured receiver value. This ensure that AssertAssignable will correctly
// load instantiator type arguments if they are needed.
LocalVariable* receiver_variable =
MakeReceiverVariable(/* is_parameter = */ false);
receiver_variable->set_is_captured();
enclosing_scope = new (Z) LocalScope(NULL, 0, 0);
enclosing_scope->set_context_level(0);
enclosing_scope->AddVariable(receiver_variable);
enclosing_scope->AddContextVariable(receiver_variable);
}
scope_ = new (Z) LocalScope(enclosing_scope, 0, 0);
scope_->set_begin_token_pos(function.token_pos());
scope_->set_end_token_pos(function.end_token_pos());
// Add function type arguments variable before current context variable.
if ((function.IsGeneric() || function.HasGenericParent())) {
LocalVariable* type_args_var = MakeVariable(
Symbols::FunctionTypeArgumentsVar(), AbstractType::dynamic_type());
scope_->AddVariable(type_args_var);
parsed_function_->set_function_type_arguments(type_args_var);
}
bool needs_expr_temp = false;
if (parsed_function_->has_arg_desc_var()) {
needs_expr_temp = true;
scope_->AddVariable(parsed_function_->arg_desc_var());
}
LocalVariable* context_var = parsed_function_->current_context_var();
context_var->set_is_forced_stack();
scope_->AddVariable(context_var);
parsed_function_->SetNodeSequence(
new SequenceNode(TokenPosition::kNoSource, scope_));
switch (function.kind()) {
case RawFunction::kImplicitClosureFunction: {
ASSERT(function.NumImplicitParameters() == 1);
LocalVariable* closure_parameter = MakeVariable(
Symbols::ClosureParameter(), AbstractType::dynamic_type());
closure_parameter->set_is_forced_stack();
scope_->InsertParameterAt(0, closure_parameter);
// Type check all parameters by default.
// This may be overridden with parameter flags in
// BytecodeReaderHelper::ParseImplicitClosureFunction.
AddParameters(function, LocalVariable::kDoTypeCheck);
break;
}
case RawFunction::kImplicitGetter:
case RawFunction::kImplicitSetter: {
const bool is_setter = function.IsImplicitSetterFunction();
const bool is_method = !function.IsStaticFunction();
intptr_t pos = 0;
if (is_method) {
MakeReceiverVariable(/* is_parameter = */ true);
++pos;
}
if (is_setter) {
LocalVariable* setter_value = MakeVariable(
Symbols::Value(),
AbstractType::ZoneHandle(Z, function.ParameterTypeAt(pos)));
scope_->InsertParameterAt(pos++, setter_value);
if (is_method) {
const Field& field = Field::Handle(Z, function.accessor_field());
if (field.is_covariant()) {
setter_value->set_is_explicit_covariant_parameter();
} else if (!field.is_generic_covariant_impl()) {
setter_value->set_type_check_mode(
LocalVariable::kTypeCheckedByCaller);
}
}
}
break;
}
case RawFunction::kImplicitStaticGetter:
ASSERT(!IsStaticFieldGetterGeneratedAsInitializer(function, Z));
break;
case RawFunction::kDynamicInvocationForwarder: {
// Create [this] variable.
MakeReceiverVariable(/* is_parameter = */ true);
// Type check all parameters by default.
// This may be overridden with parameter flags in
// BytecodeReaderHelper::ParseImplicitClosureFunction.
AddParameters(function, LocalVariable::kDoTypeCheck);
break;
}
case RawFunction::kMethodExtractor: {
// Add a receiver parameter. Though it is captured, we emit code to
// explicitly copy it to a fixed offset in a freshly-allocated context
// instead of using the generic code for regular functions.
// Therefore, it isn't necessary to mark it as captured here.
MakeReceiverVariable(/* is_parameter = */ true);
break;
}
default:
UNREACHABLE();
}
if (needs_expr_temp) {
scope_->AddVariable(parsed_function_->EnsureExpressionTemp());
}
if (parsed_function_->function().MayHaveUncheckedEntryPoint(
parsed_function_->isolate())) {
scope_->AddVariable(parsed_function_->EnsureEntryPointsTemp());
}
parsed_function_->AllocateVariables();
}
// TODO(alexmarkov): pass bitvectors of parameter covariance to set type
// check mode before AllocateVariables.
void BytecodeScopeBuilder::AddParameters(const Function& function,
LocalVariable::TypeCheckMode mode) {
for (intptr_t i = function.NumImplicitParameters(),
n = function.NumParameters();
i < n; ++i) {
// LocalVariable caches handles, so new handles are created for each
// parameter.
String& name = String::ZoneHandle(Z, function.ParameterNameAt(i));
AbstractType& type =
AbstractType::ZoneHandle(Z, function.ParameterTypeAt(i));
LocalVariable* variable = MakeVariable(name, type);
variable->set_type_check_mode(mode);
scope_->InsertParameterAt(i, variable);
}
}
LocalVariable* BytecodeScopeBuilder::MakeVariable(const String& name,
const AbstractType& type) {
return new (Z) LocalVariable(TokenPosition::kNoSource,
TokenPosition::kNoSource, name, type, nullptr);
}
LocalVariable* BytecodeScopeBuilder::MakeReceiverVariable(bool is_parameter) {
const auto& cls = Class::Handle(Z, parsed_function_->function().Owner());
const auto& type = Type::ZoneHandle(Z, cls.DeclarationType());
LocalVariable* receiver_variable = MakeVariable(Symbols::This(), type);
parsed_function_->set_receiver_var(receiver_variable);
if (is_parameter) {
scope_->InsertParameterAt(0, receiver_variable);
}
return receiver_variable;
}
} // namespace kernel
} // namespace dart
#endif // !defined(DART_PRECOMPILED_RUNTIME)