| // 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. | |
| #ifndef RUNTIME_VM_PARSER_H_ | |
| #define RUNTIME_VM_PARSER_H_ | |
| #include "include/dart_api.h" | |
| #include "lib/invocation_mirror.h" | |
| #include "platform/assert.h" | |
| #include "platform/globals.h" | |
| #include "vm/allocation.h" | |
| #include "vm/class_finalizer.h" | |
| #include "vm/hash_table.h" | |
| #include "vm/kernel.h" | |
| #include "vm/object.h" | |
| #include "vm/raw_object.h" | |
| #include "vm/scopes.h" | |
| #include "vm/token.h" | |
| namespace dart { | |
| // Forward declarations. | |
| namespace kernel { | |
| class ScopeBuildingResult; | |
| } // namespace kernel | |
| class ArgumentsDescriptor; | |
| class BitVector; | |
| class Isolate; | |
| class LocalScope; | |
| class LocalVariable; | |
| struct RegExpCompileData; | |
| template <typename T> | |
| class GrowableArray; | |
| class Parser; | |
| class FieldKeyValueTrait { | |
| public: | |
| // Typedefs needed for the DirectChainedHashMap template. | |
| typedef const Field* Key; | |
| typedef const Field* Value; | |
| typedef const Field* Pair; | |
| static Key KeyOf(Pair kv) { return kv; } | |
| static Value ValueOf(Pair kv) { return kv; } | |
| static inline uword Hash(Key key) { | |
| const TokenPosition token_pos = key->token_pos(); | |
| if (token_pos.IsReal()) { | |
| return token_pos.Hash(); | |
| } | |
| return key->kernel_offset(); | |
| } | |
| static inline bool IsKeyEqual(Pair pair, Key key) { | |
| return pair->Original() == key->Original(); | |
| } | |
| }; | |
| typedef DirectChainedHashMap<FieldKeyValueTrait> FieldSet; | |
| // The class ParsedFunction holds the result of parsing a function. | |
| class ParsedFunction : public ZoneObject { | |
| public: | |
| ParsedFunction(Thread* thread, const Function& function); | |
| const Function& function() const { return function_; } | |
| LocalScope* scope() const { return scope_; } | |
| void set_scope(LocalScope* scope) { | |
| ASSERT(scope_ == nullptr); | |
| ASSERT(scope != nullptr); | |
| scope_ = scope; | |
| } | |
| RegExpCompileData* regexp_compile_data() const { | |
| return regexp_compile_data_; | |
| } | |
| void SetRegExpCompileData(RegExpCompileData* regexp_compile_data); | |
| LocalVariable* function_type_arguments() const { | |
| return function_type_arguments_; | |
| } | |
| void set_function_type_arguments(LocalVariable* function_type_arguments) { | |
| ASSERT(function_type_arguments != nullptr); | |
| function_type_arguments_ = function_type_arguments; | |
| } | |
| LocalVariable* parent_type_arguments() const { | |
| return parent_type_arguments_; | |
| } | |
| void set_parent_type_arguments(LocalVariable* parent_type_arguments) { | |
| ASSERT(parent_type_arguments != nullptr); | |
| parent_type_arguments_ = parent_type_arguments; | |
| } | |
| LocalVariable* suspend_state_var() const { return suspend_state_var_; } | |
| void set_suspend_state_var(LocalVariable* suspend_state_var) { | |
| ASSERT(suspend_state_var != nullptr); | |
| suspend_state_var_ = suspend_state_var; | |
| } | |
| void set_default_parameter_values(ZoneGrowableArray<const Instance*>* list) { | |
| default_parameter_values_ = list; | |
| #if defined(DEBUG) | |
| if (list == nullptr) return; | |
| for (intptr_t i = 0; i < list->length(); i++) { | |
| DEBUG_ASSERT(list->At(i)->IsNotTemporaryScopedHandle()); | |
| } | |
| #endif | |
| } | |
| const Instance& DefaultParameterValueAt(intptr_t i) const { | |
| ASSERT(default_parameter_values_ != nullptr); | |
| return *default_parameter_values_->At(i); | |
| } | |
| ZoneGrowableArray<const Instance*>* default_parameter_values() const { | |
| return default_parameter_values_; | |
| } | |
| LocalVariable* current_context_var() const { return current_context_var_; } | |
| bool has_arg_desc_var() const { return arg_desc_var_ != nullptr; } | |
| LocalVariable* arg_desc_var() const { return arg_desc_var_; } | |
| LocalVariable* receiver_var() const { | |
| ASSERT(receiver_var_ != nullptr); | |
| return receiver_var_; | |
| } | |
| void set_receiver_var(LocalVariable* value) { | |
| ASSERT(receiver_var_ == nullptr); | |
| ASSERT(value != nullptr); | |
| receiver_var_ = value; | |
| } | |
| bool has_receiver_var() const { return receiver_var_ != nullptr; } | |
| void set_receiver_used() { receiver_used_ = true; } | |
| bool is_receiver_used() const { | |
| ASSERT(kernel_scopes_ != nullptr); | |
| ASSERT(!receiver_used_ || receiver_var() != nullptr); | |
| return receiver_used_; | |
| } | |
| LocalVariable* expression_temp_var() const { | |
| ASSERT(has_expression_temp_var()); | |
| return expression_temp_var_; | |
| } | |
| void set_expression_temp_var(LocalVariable* value) { | |
| ASSERT(!has_expression_temp_var()); | |
| expression_temp_var_ = value; | |
| } | |
| bool has_expression_temp_var() const { | |
| return expression_temp_var_ != nullptr; | |
| } | |
| LocalVariable* entry_points_temp_var() const { | |
| ASSERT(has_entry_points_temp_var()); | |
| return entry_points_temp_var_; | |
| } | |
| void set_entry_points_temp_var(LocalVariable* value) { | |
| ASSERT(!has_entry_points_temp_var()); | |
| entry_points_temp_var_ = value; | |
| } | |
| bool has_entry_points_temp_var() const { | |
| return entry_points_temp_var_ != nullptr; | |
| } | |
| LocalVariable* EnsureExpressionTemp(); | |
| LocalVariable* EnsureEntryPointsTemp(); | |
| const FieldSet* guarded_fields() const { return &guarded_fields_; } | |
| VariableIndex first_parameter_index() const { return first_parameter_index_; } | |
| int num_stack_locals() const { return num_stack_locals_; } | |
| void AllocateVariables(); | |
| void record_await() { have_seen_await_expr_ = true; } | |
| bool have_seen_await() const { return have_seen_await_expr_; } | |
| Thread* thread() const { return thread_; } | |
| Isolate* isolate() const { return thread_->isolate(); } | |
| Zone* zone() const { return thread_->zone(); } | |
| // Adds only relevant fields: field must be unique and its guarded_cid() | |
| // relevant. | |
| void AddToGuardedFields(const Field* field) const; | |
| void Bailout(const char* origin, const char* reason) const; | |
| kernel::ScopeBuildingResult* EnsureKernelScopes(); | |
| LocalVariable* RawTypeArgumentsVariable() const { | |
| return raw_type_arguments_var_; | |
| } | |
| void SetRawTypeArgumentsVariable(LocalVariable* raw_type_arguments_var) { | |
| raw_type_arguments_var_ = raw_type_arguments_var; | |
| } | |
| void SetRawParameters(ZoneGrowableArray<LocalVariable*>* raw_parameters) { | |
| raw_parameters_ = raw_parameters; | |
| } | |
| LocalVariable* RawParameterVariable(intptr_t i) const { | |
| return raw_parameters_->At(i); | |
| } | |
| LocalVariable* ParameterVariable(intptr_t i) const { | |
| ASSERT((i >= 0) && (i < function_.NumParameters())); | |
| ASSERT(scope() != nullptr); | |
| return scope()->VariableAt(i); | |
| } | |
| // Remembers the set of covariant parameters. | |
| // [covariant_parameters] is a bitvector of function.NumParameters() length. | |
| void SetCovariantParameters(const BitVector* covariant_parameters); | |
| // Remembers the set of generic-covariant-impl parameters. | |
| // [covariant_parameters] is a bitvector of function.NumParameters() length. | |
| void SetGenericCovariantImplParameters( | |
| const BitVector* generic_covariant_impl_parameters); | |
| // Returns true if i-th parameter is covariant. | |
| // SetCovariantParameters should be called before using this method. | |
| bool IsCovariantParameter(intptr_t i) const; | |
| // Returns true if i-th parameter is generic-covariant-impl. | |
| // SetGenericCovariantImplParameters should be called before using this | |
| // method. | |
| bool IsGenericCovariantImplParameter(intptr_t i) const; | |
| // Variables needed for the InvokeFieldDispatcher for dynamic closure calls, | |
| // because they are both read and written to by the builders. | |
| struct DynamicClosureCallVars : ZoneObject { | |
| DynamicClosureCallVars(Zone* zone, intptr_t num_named) | |
| : named_argument_parameter_indices(zone, num_named) {} | |
| #define FOR_EACH_DYNAMIC_CLOSURE_CALL_VARIABLE(V) \ | |
| V(current_function, Function, CurrentFunction) \ | |
| V(current_num_processed, Smi, CurrentNumProcessed) \ | |
| V(current_param_index, Smi, CurrentParamIndex) \ | |
| V(current_type_param, Dynamic, CurrentTypeParam) \ | |
| V(function_type_args, Dynamic, FunctionTypeArgs) \ | |
| V(instantiator_type_args, Dynamic, InstantiatorTypeArgs) \ | |
| V(parent_function_type_args, Dynamic, ParentFunctionTypeArgs) \ | |
| V(delayed_type_args, Dynamic, DelayedTypeArgs) | |
| #define DEFINE_FIELD(Name, _, __) LocalVariable* Name = nullptr; | |
| FOR_EACH_DYNAMIC_CLOSURE_CALL_VARIABLE(DEFINE_FIELD) | |
| #undef DEFINE_FIELD | |
| // An array of local variables, one for each named parameter in the | |
| // saved arguments descriptor. | |
| ZoneGrowableArray<LocalVariable*> named_argument_parameter_indices; | |
| }; | |
| DynamicClosureCallVars* dynamic_closure_call_vars() const { | |
| return dynamic_closure_call_vars_; | |
| } | |
| DynamicClosureCallVars* EnsureDynamicClosureCallVars(); | |
| private: | |
| Thread* thread_; | |
| const Function& function_; | |
| LocalScope* scope_; | |
| RegExpCompileData* regexp_compile_data_; | |
| LocalVariable* function_type_arguments_; | |
| LocalVariable* parent_type_arguments_; | |
| LocalVariable* suspend_state_var_ = nullptr; | |
| LocalVariable* current_context_var_; | |
| LocalVariable* arg_desc_var_; | |
| LocalVariable* receiver_var_ = nullptr; | |
| LocalVariable* expression_temp_var_; | |
| LocalVariable* entry_points_temp_var_; | |
| DynamicClosureCallVars* dynamic_closure_call_vars_; | |
| mutable FieldSet guarded_fields_; | |
| ZoneGrowableArray<const Instance*>* default_parameter_values_; | |
| bool receiver_used_ = false; | |
| LocalVariable* raw_type_arguments_var_; | |
| ZoneGrowableArray<LocalVariable*>* raw_parameters_ = nullptr; | |
| VariableIndex first_parameter_index_; | |
| int num_stack_locals_; | |
| bool have_seen_await_expr_; | |
| kernel::ScopeBuildingResult* kernel_scopes_; | |
| const BitVector* generic_covariant_impl_parameters_ = nullptr; | |
| friend class Parser; | |
| DISALLOW_COPY_AND_ASSIGN(ParsedFunction); | |
| }; | |
| class Parser : public ValueObject { | |
| public: | |
| // Parse a function to retrieve parameter information that is not retained in | |
| // the Function object. Returns either an error if the parse fails (which | |
| // could be the case for local functions), or a flat array of entries for each | |
| // parameter. Each parameter entry contains: * a Dart bool indicating whether | |
| // the parameter was declared final * its default value (or null if none was | |
| // declared) * an array of metadata (or null if no metadata was declared). | |
| enum { | |
| kParameterIsFinalOffset, | |
| kParameterDefaultValueOffset, | |
| kParameterMetadataOffset, | |
| kParameterEntrySize, | |
| }; | |
| private: | |
| DISALLOW_COPY_AND_ASSIGN(Parser); | |
| }; | |
| } // namespace dart | |
| #endif // RUNTIME_VM_PARSER_H_ |