Files
sdk/runtime/vm/compiler/frontend/bytecode_scope_builder.cc
T
Alexander Markov 61f0f5bc43 [vm/bytecode] Declare members in bytecode
This change replaces kernel AST declarations of fields and functions
with bytecode declarations.

Size of dilp files is reduced by 11-12%.

Startup latency:
Time to the first full frame: 1.945s -> 1.687s
FinalizeClass: 554ms -> 277ms
FinishClassLoading: 296ms -> 156ms

There are following regressions in bytecode mode, which will be fixed
in future:

* dart:mirrors are not supported yet (implementation of mirrors relies
  on reading kernel AST in certain cases).

  As the result, lib_2/mirrors/* tests fail.

* native extensions are not supported yet (annotations on libraries
  and classes in AST are cleaned up as they could reference members
  which are now removed from AST).

  As the result, standalone_2/entrypoints_verification_test test fails.

* language_2/spread_collections/const_error_test/* tests fail
  due to https://github.com/dart-lang/sdk/issues/36286.

Change-Id: I5130f401fd7b84038b136136e7ccc1a6e51b6cea
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/97561
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Ryan Macnak <rmacnak@google.com>
2019-03-26 21:40:10 +00:00

184 lines
6.8 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/frontend/bytecode_scope_builder.h"
#include "vm/compiler/frontend/bytecode_reader.h" // For IsBytecodeFieldInitializer.
#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::kImplicitStaticFinalGetter:
ASSERT(!IsBytecodeFieldInitializer(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)