Files
sdk/runtime/vm/compiler/frontend/scope_builder.h
T
Tess Strickland d9685d1c4c [vm/compiler] Move type argument type checks out of closure bodies.
These checks are now performed in the dynamic closure call dispatcher.
To avoid having to create type argument vectors (TAVs) for default type
arguments at runtime, we cache a compile-time created TAV in the
ClosureData for the closure function which is retrieved by the
dispatcher when needed.

We also keep an associated packed field of information that can also be
determined at compile time:

* Whether the cached TAV needs instantiation or can share its
  instantiator or function type arguments.

* The number of parent type parameters.

The former allows the generated IL to keep the invariant that the
InstantiateTypeArguments instruction (and the runtime entry it calls) is
only used for uninstantiated TAVs.

Also changes the destination name to an Value input for the
AssertSubtype instruction and adds handling for non-constant types and
names in that instruction's backend.

Additional changes:

* Adds new slots for ClosureData, Function, and TypeArguments.

* Adds a new kUnboxedUint8 representation (needed for
  TypeParameterLayout::flags_, which is of type uint8_t).

  * Extends LoadField to handle uint8_t unboxed native fields.

  * Adds BoxUint8 for boxing unboxed uint8_t values.

Code size impact on Flutter gallery in release mode:

* arm7: total +0.08%, vmisolate: +0.56%, isolate: +0.42%,
        readonly: -0.04%, instructions: -0.03%

* arm8: total +0.12%, vmisolate: +0.56%, isolate: +0.42%,
        readonly: -0.002%, instructions: +0.03%

Cq-Include-Trybots: luci.dart.try:vm-kernel-linux-debug-ia32-try,vm-kernel-linux-debug-x64-try,vm-kernel-nnbd-linux-debug-ia32-try,vm-kernel-nnbd-linux-debug-x64-try,vm-kernel-precomp-linux-debug-simarm_x64-try,vm-kernel-precomp-linux-debug-x64-try,vm-kernel-precomp-nnbd-linux-debug-simarm_x64-try,vm-kernel-precomp-nnbd-linux-debug-x64-try,vm-kernel-linux-release-simarm-try,vm-kernel-linux-release-simarm64-try,vm-kernel-nnbd-linux-release-simarm-try,vm-kernel-nnbd-linux-release-simarm64-try,vm-kernel-precomp-linux-release-simarm-try,vm-kernel-precomp-linux-release-simarm64-try,vm-kernel-precomp-nnbd-linux-release-simarm64-try
Bug: https://github.com/dart-lang/sdk/issues/40813
Change-Id: I5a7de27a17e3119e27752bd0d10e1c6bc1b52a16
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/158844
Commit-Queue: Tess Strickland <sstrickl@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Régis Crelier <regis@google.com>
2020-10-26 18:48:18 +00:00

246 lines
8.0 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.
#ifndef RUNTIME_VM_COMPILER_FRONTEND_SCOPE_BUILDER_H_
#define RUNTIME_VM_COMPILER_FRONTEND_SCOPE_BUILDER_H_
#if defined(DART_PRECOMPILED_RUNTIME)
#error "AOT runtime should not use compiler sources (including header files)"
#endif // defined(DART_PRECOMPILED_RUNTIME)
#include "vm/compiler/frontend/constant_reader.h"
#include "vm/compiler/frontend/kernel_translation_helper.h"
#include "vm/hash_map.h"
#include "vm/object.h"
#include "vm/parser.h" // For ParsedFunction.
namespace dart {
namespace kernel {
class ScopeBuildingResult;
class ScopeBuilder {
public:
explicit ScopeBuilder(ParsedFunction* parsed_function);
virtual ~ScopeBuilder() = default;
ScopeBuildingResult* BuildScopes();
private:
void VisitField();
void VisitProcedure();
void VisitConstructor();
void VisitFunctionNode();
void VisitNode();
void VisitInitializer();
void VisitExpression();
void VisitStatement();
void VisitArguments();
void VisitVariableDeclaration();
void VisitVariableGet(intptr_t declaration_binary_offset);
void VisitDartType();
void VisitInterfaceType(bool simple);
void VisitFunctionType(bool simple);
void VisitTypeParameterType();
void HandleLocalFunction(intptr_t parent_kernel_offset);
AbstractType& BuildAndVisitVariableType();
void EnterScope(intptr_t kernel_offset);
void ExitScope(TokenPosition start_position, TokenPosition end_position);
virtual void ReportUnexpectedTag(const char* variant, Tag tag);
// This enum controls which parameters would be marked as requring type
// check on the callee side.
enum ParameterTypeCheckMode {
// All parameters will be checked.
kTypeCheckAllParameters,
// Only parameters marked as covariant or generic-covariant-impl will be
// checked.
kTypeCheckForNonDynamicallyInvokedMethod,
// Only parameters *not* marked as covariant or generic-covariant-impl will
// be checked. The rest would be checked in the method itself.
// Inverse of kTypeCheckForNonDynamicallyInvokedMethod.
kTypeCheckEverythingNotCheckedInNonDynamicallyInvokedMethod,
// No parameters will be checked.
kTypeCheckForStaticFunction,
};
// This assumes that the reader is at a FunctionNode,
// about to read the positional parameters.
void AddPositionalAndNamedParameters(
intptr_t pos,
ParameterTypeCheckMode type_check_mode,
const ProcedureAttributesMetadata& attrs);
// This assumes that the reader is at a FunctionNode,
// about to read a parameter (i.e. VariableDeclaration).
void AddVariableDeclarationParameter(
intptr_t pos,
ParameterTypeCheckMode type_check_mode,
const ProcedureAttributesMetadata& attrs);
LocalVariable* MakeVariable(TokenPosition declaration_pos,
TokenPosition token_pos,
const String& name,
const AbstractType& type,
const InferredTypeMetadata* param_type_md = NULL);
void AddExceptionVariable(GrowableArray<LocalVariable*>* variables,
const char* prefix,
intptr_t nesting_depth);
void FinalizeExceptionVariable(GrowableArray<LocalVariable*>* variables,
GrowableArray<LocalVariable*>* raw_variables,
const String& symbol,
intptr_t nesting_depth);
void AddTryVariables();
void AddCatchVariables();
void FinalizeCatchVariables();
void AddIteratorVariable();
void AddSwitchVariable();
// Record an assignment or reference to a variable. If the occurrence is
// in a nested function, ensure that the variable is handled properly as a
// captured variable.
LocalVariable* LookupVariable(intptr_t declaration_binary_offset);
StringIndex GetNameFromVariableDeclaration(intptr_t kernel_offset,
const Function& function);
const String& GenerateName(const char* prefix, intptr_t suffix);
void HandleLoadReceiver();
void HandleSpecialLoad(LocalVariable** variable, const String& symbol);
void LookupCapturedVariableByName(LocalVariable** variable,
const String& name);
struct DepthState {
explicit DepthState(intptr_t function)
: loop_(0),
function_(function),
try_(0),
catch_(0),
finally_(0),
for_in_(0) {}
intptr_t loop_;
intptr_t function_;
intptr_t try_;
intptr_t catch_;
intptr_t finally_;
intptr_t for_in_;
};
ScopeBuildingResult* result_;
ParsedFunction* parsed_function_;
ActiveClass active_class_;
TranslationHelper translation_helper_;
Zone* zone_;
FunctionNodeHelper::AsyncMarker current_function_async_marker_;
LocalScope* current_function_scope_;
LocalScope* scope_;
DepthState depth_;
intptr_t name_index_;
bool needs_expr_temp_;
TokenPosition first_body_token_position_;
KernelReaderHelper helper_;
ConstantReader constant_reader_;
InferredTypeMetadataHelper inferred_type_metadata_helper_;
ProcedureAttributesMetadataHelper procedure_attributes_metadata_helper_;
TypeTranslator type_translator_;
DISALLOW_COPY_AND_ASSIGN(ScopeBuilder);
};
struct FunctionScope {
intptr_t kernel_offset;
LocalScope* scope;
};
class ScopeBuildingResult : public ZoneAllocated {
public:
ScopeBuildingResult()
: type_arguments_variable(NULL),
switch_variable(NULL),
finally_return_variable(NULL),
setter_value(NULL),
yield_jump_variable(NULL),
yield_context_variable(NULL),
raw_variable_counter_(0) {}
IntMap<LocalVariable*> locals;
IntMap<LocalScope*> scopes;
GrowableArray<FunctionScope> function_scopes;
// Only non-NULL for factory constructor functions.
LocalVariable* type_arguments_variable;
// Non-NULL when the function contains a switch statement.
LocalVariable* switch_variable;
// Non-NULL when the function contains a return inside a finally block.
LocalVariable* finally_return_variable;
// Non-NULL when the function is a setter.
LocalVariable* setter_value;
// Non-NULL if the function contains yield statement.
// TODO(27590) actual variable is called :await_jump_var, we should rename
// it to reflect the fact that it is used for both await and yield.
LocalVariable* yield_jump_variable;
// Non-NULL if the function contains yield statement.
// TODO(27590) actual variable is called :await_ctx_var, we should rename
// it to reflect the fact that it is used for both await and yield.
LocalVariable* yield_context_variable;
// Variables used in exception handlers, one per exception handler nesting
// level.
GrowableArray<LocalVariable*> exception_variables;
GrowableArray<LocalVariable*> stack_trace_variables;
GrowableArray<LocalVariable*> catch_context_variables;
// These are used to access the raw exception/stacktrace variables (and are
// used to put them into the captured variables in the context).
GrowableArray<LocalVariable*> raw_exception_variables;
GrowableArray<LocalVariable*> raw_stack_trace_variables;
intptr_t raw_variable_counter_;
// For-in iterators, one per for-in nesting level.
GrowableArray<LocalVariable*> iterator_variables;
private:
DISALLOW_COPY_AND_ASSIGN(ScopeBuildingResult);
};
// Returns true if the given method can skip type checks for all type arguments
// that are not covariant or generic covariant in its implementation.
bool MethodCanSkipTypeChecksForNonCovariantTypeArguments(
const Function& method);
// Returns true if the given method can skip type checks for all arguments
// that are not covariant or generic covariant in its implementation.
bool MethodCanSkipTypeChecksForNonCovariantArguments(const Function& method);
} // namespace kernel
} // namespace dart
#endif // RUNTIME_VM_COMPILER_FRONTEND_SCOPE_BUILDER_H_