| // 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 VisitListOfExpressions(); | |
| void VisitListOfNamedExpressions(); | |
| void VisitArguments(); | |
| void VisitVariableDeclaration(); | |
| LocalVariable* VisitVariable(); | |
| void VisitVariableGet(intptr_t declaration_binary_offset); | |
| void VisitDartType(); | |
| void VisitInterfaceType(bool simple); | |
| void VisitFunctionType(bool simple); | |
| void VisitRecordType(); | |
| void VisitTypeParameterType(); | |
| void VisitIntersectionType(); | |
| void VisitExtensionType(); | |
| void VisitFutureOrType(); | |
| 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 requiring 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, | |
| // No non-covariant checks are performed, and any covariant checks are | |
| // performed by the target. | |
| kTypeCheckForImplicitClosureFunction, | |
| }; | |
| // 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. Variable). | |
| void AddParameter(intptr_t pos, | |
| ParameterTypeCheckMode type_check_mode, | |
| const ProcedureAttributesMetadata& attrs); | |
| LocalVariable* MakeVariable( | |
| TokenPosition declaration_pos, | |
| TokenPosition token_pos, | |
| const String& name, | |
| const AbstractType& type, | |
| intptr_t kernel_offset = LocalVariable::kNoKernelOffset, | |
| bool is_late = false, | |
| const InferredTypeMetadata* inferred_type_md = nullptr, | |
| const InferredTypeMetadata* inferred_arg_type_md = nullptr); | |
| 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 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); | |
| const String& GenerateName(const char* prefix, intptr_t suffix); | |
| void HandleLoadReceiver(); | |
| void HandleSpecialLoad(LocalVariable** variable, | |
| const String& symbol, | |
| intptr_t kernel_offset); | |
| ScriptPtr Script() { return active_class_.ActiveScript(); } | |
| struct DepthState { | |
| explicit DepthState(intptr_t function) | |
| : loop_(0), function_(function), try_(0), catch_(0), finally_(0) {} | |
| intptr_t loop_; | |
| intptr_t function_; | |
| intptr_t try_; | |
| intptr_t catch_; | |
| intptr_t finally_; | |
| }; | |
| ScopeBuildingResult* result_; | |
| ParsedFunction* parsed_function_; | |
| ActiveClass active_class_; | |
| TranslationHelper translation_helper_; | |
| Zone* zone_; | |
| LocalScope* current_function_scope_; | |
| LocalScope* scope_; | |
| DepthState depth_; | |
| bool needs_expr_temp_; | |
| TokenPosition first_body_token_position_ = TokenPosition::kNoSource; | |
| KernelReaderHelper helper_; | |
| ConstantReader constant_reader_; | |
| TypeTranslator type_translator_; | |
| InferredTypeMetadataHelper inferred_type_metadata_helper_; | |
| InferredTypeMetadataHelper inferred_arg_type_metadata_helper_; | |
| ProcedureAttributesMetadataHelper procedure_attributes_metadata_helper_; | |
| DISALLOW_COPY_AND_ASSIGN(ScopeBuilder); | |
| }; | |
| struct FunctionScope { | |
| intptr_t kernel_offset; | |
| LocalScope* scope; | |
| }; | |
| class ScopeBuildingResult : public ZoneObject { | |
| public: | |
| ScopeBuildingResult() | |
| : switch_variable(nullptr), | |
| finally_return_variable(nullptr), | |
| setter_value(nullptr), | |
| raw_variable_counter_(0) {} | |
| bool IsClosureWithEmptyContext(intptr_t function_node_offset) { | |
| for (intptr_t i = 0; i < closure_offsets_without_captures.length(); ++i) { | |
| if (closure_offsets_without_captures[i] == function_node_offset) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| IntMap<LocalVariable*> locals; | |
| IntMap<LocalScope*> scopes; | |
| GrowableArray<FunctionScope> function_scopes; | |
| // Non-nullptr when the function contains a switch statement. | |
| LocalVariable* switch_variable; | |
| // Non-nullptr when the function contains a return inside a finally block. | |
| LocalVariable* finally_return_variable; | |
| // Non-nullptr when the function is a setter. | |
| LocalVariable* setter_value; | |
| // 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_; | |
| // Remembers closure function kernel offsets that do not capture any | |
| // variables. | |
| GrowableArray<intptr_t> closure_offsets_without_captures; | |
| void PrintTo(BaseTextBuffer* f) const; | |
| const char* ToCString() const; | |
| private: | |
| DISALLOW_COPY_AND_ASSIGN(ScopeBuildingResult); | |
| }; | |
| } // namespace kernel | |
| } // namespace dart | |
| #endif // RUNTIME_VM_COMPILER_FRONTEND_SCOPE_BUILDER_H_ |