// Copyright (c) 2017, 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_KERNEL_BINARY_FLOWGRAPH_H_ #define RUNTIME_VM_KERNEL_BINARY_FLOWGRAPH_H_ #if !defined(DART_PRECOMPILED_RUNTIME) #include #include "vm/kernel.h" #include "vm/kernel_binary.h" #include "vm/kernel_to_il.h" #include "vm/object.h" namespace dart { namespace kernel { class StreamingDartTypeTranslator { public: StreamingDartTypeTranslator(StreamingFlowGraphBuilder* builder, bool finalize = false); // Can return a malformed type. AbstractType& BuildType(); // Can return a malformed type. AbstractType& BuildTypeWithoutFinalization(); // Is guaranteed to be not malformed. AbstractType& BuildVariableType(); // Will return `TypeArguments::null()` in case any of the arguments are // malformed. const TypeArguments& BuildTypeArguments(intptr_t length); // Will return `TypeArguments::null()` in case any of the arguments are // malformed. const TypeArguments& BuildInstantiatedTypeArguments( const dart::Class& receiver_class, intptr_t length); const Type& ReceiverType(const dart::Class& klass); private: // Can build a malformed type. void BuildTypeInternal(); void BuildInterfaceType(bool simple); void BuildFunctionType(bool simple); void BuildTypeParameterType(); class TypeParameterScope { public: TypeParameterScope(StreamingDartTypeTranslator* translator, intptr_t parameter_count) : parameter_count_(parameter_count), outer_(translator->type_parameter_scope_), translator_(translator) { outer_parameter_count_ = 0; if (outer_ != NULL) { outer_parameter_count_ = outer_->outer_parameter_count_ + outer_->parameter_count_; } translator_->type_parameter_scope_ = this; } ~TypeParameterScope() { translator_->type_parameter_scope_ = outer_; } TypeParameterScope* outer() const { return outer_; } intptr_t parameter_count() const { return parameter_count_; } intptr_t outer_parameter_count() const { return outer_parameter_count_; } private: intptr_t parameter_count_; intptr_t outer_parameter_count_; TypeParameterScope* outer_; StreamingDartTypeTranslator* translator_; }; StreamingFlowGraphBuilder* builder_; TranslationHelper& translation_helper_; ActiveClass* active_class_; TypeParameterScope* type_parameter_scope_; Zone* zone_; AbstractType& result_; bool finalize_; friend class StreamingScopeBuilder; friend class KernelReader; }; class StreamingScopeBuilder { public: StreamingScopeBuilder(ParsedFunction* parsed_function, intptr_t relative_kernel_offset, const TypedData& data); virtual ~StreamingScopeBuilder(); ScopeBuildingResult* BuildScopes(); private: void VisitField(); void VisitProcedure(); void VisitConstructor(); void VisitFunctionNode(); void VisitNode(); void VisitInitializer(); void VisitExpression(); void VisitStatement(); void VisitArguments(); void VisitVariableDeclaration(); void VisitDartType(); void VisitInterfaceType(bool simple); void VisitFunctionType(bool simple); void VisitTypeParameterType(); void VisitVectorType(); void HandleLocalFunction(intptr_t parent_kernel_offset); void EnterScope(intptr_t kernel_offset); void ExitScope(TokenPosition start_position, TokenPosition end_position); /** * This assumes that the reader is at a FunctionNode, * about to read the positional parameters. */ void AddPositionalAndNamedParameters(intptr_t pos = 0); /** * This assumes that the reader is at a FunctionNode, * about to read a parameter (i.e. VariableDeclaration). */ void AddVariableDeclarationParameter(intptr_t pos); LocalVariable* MakeVariable(TokenPosition declaration_pos, TokenPosition token_pos, const dart::String& name, const AbstractType& type); void AddExceptionVariable(GrowableArray* variables, const char* prefix, intptr_t nesting_depth); void AddTryVariables(); void AddCatchVariables(); 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. void LookupVariable(intptr_t declaration_binary_offset); const dart::String& GenerateName(const char* prefix, intptr_t suffix); void HandleSpecialLoad(LocalVariable** variable, const dart::String& symbol); void LookupCapturedVariableByName(LocalVariable** variable, const dart::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_; intptr_t relative_kernel_offset_; ActiveClass active_class_; TranslationHelper translation_helper_; Zone* zone_; FunctionNode::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_; StreamingFlowGraphBuilder* builder_; StreamingDartTypeTranslator type_translator_; }; // There are several cases when we are compiling constant expressions: // // * constant field initializers: // const FieldName = ; // // * constant expressions: // const [, ...] // const { : , ...} // const Constructor(, ...) // // * constant default parameters: // f(a, [b = ]) // f(a, {b: }) // // * constant values to compare in a [SwitchCase] // case : // // In all cases `` must be recursively evaluated and canonicalized at // compile-time. class StreamingConstantEvaluator { public: explicit StreamingConstantEvaluator(StreamingFlowGraphBuilder* builder); virtual ~StreamingConstantEvaluator() {} Instance& EvaluateExpression(intptr_t offset, bool reset_position = true); Instance& EvaluateListLiteral(intptr_t offset, bool reset_position = true); Instance& EvaluateMapLiteral(intptr_t offset, bool reset_position = true); Instance& EvaluateConstructorInvocation(intptr_t offset, bool reset_position = true); Object& EvaluateExpressionSafe(intptr_t offset); private: void EvaluateVariableGet(); void EvaluateVariableGet(uint8_t payload); void EvaluatePropertyGet(); void EvaluateStaticGet(); void EvaluateMethodInvocation(); void EvaluateStaticInvocation(); void EvaluateConstructorInvocationInternal(); void EvaluateNot(); void EvaluateLogicalExpression(); void EvaluateConditionalExpression(); void EvaluateStringConcatenation(); void EvaluateSymbolLiteral(); void EvaluateTypeLiteral(); void EvaluateListLiteralInternal(); void EvaluateMapLiteralInternal(); void EvaluateLet(); void EvaluateBigIntLiteral(); void EvaluateStringLiteral(); void EvaluateIntLiteral(uint8_t payload); void EvaluateIntLiteral(bool is_negative); void EvaluateDoubleLiteral(); void EvaluateBoolLiteral(bool value); void EvaluateNullLiteral(); const Object& RunFunction(const Function& function, intptr_t argument_count, const Instance* receiver, const TypeArguments* type_args); const Object& RunFunction(const Function& function, const Array& arguments, const Array& names); RawObject* EvaluateConstConstructorCall(const dart::Class& type_class, const TypeArguments& type_arguments, const Function& constructor, const Object& argument); const TypeArguments* TranslateTypeArguments(const Function& target, dart::Class* target_klass); void AssertBool() { if (!result_.IsBool()) { translation_helper_.ReportError("Expected boolean expression."); } } bool EvaluateBooleanExpressionHere(); bool GetCachedConstant(intptr_t kernel_offset, Instance* value); void CacheConstantValue(intptr_t kernel_offset, const Instance& value); StreamingFlowGraphBuilder* builder_; Isolate* isolate_; Zone* zone_; TranslationHelper& translation_helper_; StreamingDartTypeTranslator& type_translator_; Script& script_; Instance& result_; }; class FunctionNodeHelper; class StreamingFlowGraphBuilder { public: StreamingFlowGraphBuilder(FlowGraphBuilder* flow_graph_builder, intptr_t relative_kernel_offset, const TypedData& data) : flow_graph_builder_(flow_graph_builder), translation_helper_(flow_graph_builder->translation_helper_), zone_(flow_graph_builder->zone_), reader_(new Reader(data)), constant_evaluator_(this), type_translator_(this, /* finalize= */ true), relative_kernel_offset_(relative_kernel_offset), current_script_id_(-1), record_for_script_id_(-1), record_token_positions_into_(NULL), record_yield_positions_into_(NULL) {} StreamingFlowGraphBuilder(TranslationHelper* translation_helper, Zone* zone, const uint8_t* buffer, intptr_t buffer_length) : flow_graph_builder_(NULL), translation_helper_(*translation_helper), zone_(zone), reader_(new Reader(buffer, buffer_length)), constant_evaluator_(this), type_translator_(this, /* finalize= */ true), relative_kernel_offset_(0), current_script_id_(-1), record_for_script_id_(-1), record_token_positions_into_(NULL), record_yield_positions_into_(NULL) {} StreamingFlowGraphBuilder(TranslationHelper* translation_helper, Zone* zone, intptr_t relative_kernel_offset, const TypedData& data) : flow_graph_builder_(NULL), translation_helper_(*translation_helper), zone_(zone), reader_(new Reader(data)), constant_evaluator_(this), type_translator_(this, /* finalize= */ true), relative_kernel_offset_(relative_kernel_offset), current_script_id_(-1), record_for_script_id_(-1), record_token_positions_into_(NULL), record_yield_positions_into_(NULL) {} ~StreamingFlowGraphBuilder() { delete reader_; } FlowGraph* BuildGraph(intptr_t kernel_offset); Fragment BuildStatementAt(intptr_t kernel_offset); RawObject* BuildParameterDescriptor(intptr_t kernel_offset); RawObject* EvaluateMetadata(intptr_t kernel_offset); void CollectTokenPositionsFor( intptr_t script_index, intptr_t initial_script_index, GrowableArray* record_token_positions_in, GrowableArray* record_yield_positions_in); intptr_t SourceTableSize(); String& SourceTableUriFor(intptr_t index); String& GetSourceFor(intptr_t index); Array& GetLineStartsFor(intptr_t index); private: void DiscoverEnclosingElements(Zone* zone, const Function& function, Function* outermost_function); void ReadUntilFunctionNode(); StringIndex GetNameFromVariableDeclaration(intptr_t kernel_offset, const Function& function); FlowGraph* BuildGraphOfStaticFieldInitializer(); FlowGraph* BuildGraphOfFieldAccessor(LocalVariable* setter_value); void SetupDefaultParameterValues(); Fragment BuildFieldInitializer(NameIndex canonical_name); Fragment BuildInitializers(const Class& parent_class); FlowGraph* BuildGraphOfImplicitClosureFunction(const Function& function); FlowGraph* BuildGraphOfConvertedClosureFunction(const Function& function); FlowGraph* BuildGraphOfFunction(bool constructor); Fragment BuildExpression(TokenPosition* position = NULL); Fragment BuildStatement(); intptr_t ReaderOffset(); void SetOffset(intptr_t offset); void SkipBytes(intptr_t skip); bool ReadBool(); uint8_t ReadByte(); uint32_t ReadUInt(); uint32_t PeekUInt(); intptr_t ReadListLength(); StringIndex ReadStringReference(); NameIndex ReadCanonicalNameReference(); StringIndex ReadNameAsStringIndex(); const dart::String& ReadNameAsMethodName(); const dart::String& ReadNameAsGetterName(); const dart::String& ReadNameAsSetterName(); const dart::String& ReadNameAsFieldName(); void SkipStringReference(); void SkipCanonicalNameReference(); void SkipDartType(); void SkipOptionalDartType(); void SkipInterfaceType(bool simple); void SkipFunctionType(bool simple); void SkipListOfExpressions(); void SkipListOfDartTypes(); void SkipListOfStrings(); void SkipListOfVariableDeclarations(); void SkipTypeParametersList(); void SkipInitializer(); void SkipExpression(); void SkipStatement(); void SkipFunctionNode(); void SkipName(); void SkipArguments(); void SkipVariableDeclaration(); void SkipLibraryCombinator(); void SkipLibraryDependency(); void SkipLibraryPart(); void SkipLibraryTypedef(); TokenPosition ReadPosition(bool record = true); void record_token_position(TokenPosition position); void record_yield_position(TokenPosition position); Tag ReadTag(uint8_t* payload = NULL); Tag PeekTag(uint8_t* payload = NULL); word ReadFlags(); void loop_depth_inc(); void loop_depth_dec(); intptr_t for_in_depth(); void for_in_depth_inc(); void for_in_depth_dec(); void catch_depth_inc(); void catch_depth_dec(); void try_depth_inc(); void try_depth_dec(); intptr_t CurrentTryIndex(); intptr_t AllocateTryIndex(); LocalVariable* CurrentException(); LocalVariable* CurrentStackTrace(); CatchBlock* catch_block(); ActiveClass* active_class(); ScopeBuildingResult* scopes(); void set_scopes(ScopeBuildingResult* scope); ParsedFunction* parsed_function(); TryFinallyBlock* try_finally_block(); SwitchBlock* switch_block(); BreakableBlock* breakable_block(); GrowableArray& yield_continuations(); Value* stack(); void Push(Definition* definition); Value* Pop(); Tag PeekArgumentsFirstPositionalTag(); const TypeArguments& PeekArgumentsInstantiatedType(const dart::Class& klass); intptr_t PeekArgumentsCount(); intptr_t PeekArgumentsTypeCount(); void SkipArgumentsBeforeActualArguments(); LocalVariable* LookupVariable(intptr_t kernel_offset); LocalVariable* MakeTemporary(); Token::Kind MethodKind(const dart::String& name); dart::RawFunction* LookupMethodByMember(NameIndex target, const dart::String& method_name); bool NeedsDebugStepCheck(const Function& function, TokenPosition position); bool NeedsDebugStepCheck(Value* value, TokenPosition position); void InlineBailout(const char* reason); Fragment DebugStepCheck(TokenPosition position); Fragment LoadLocal(LocalVariable* variable); Fragment Return(TokenPosition position); Fragment PushArgument(); Fragment EvaluateAssertion(); Fragment RethrowException(TokenPosition position, int catch_try_index); Fragment ThrowNoSuchMethodError(); Fragment Constant(const Object& value); Fragment IntConstant(int64_t value); Fragment LoadStaticField(); Fragment StaticCall(TokenPosition position, const Function& target, intptr_t argument_count); Fragment StaticCall(TokenPosition position, const Function& target, intptr_t argument_count, const Array& argument_names); Fragment InstanceCall(TokenPosition position, const dart::String& name, Token::Kind kind, intptr_t argument_count, intptr_t checked_argument_count = 1); Fragment InstanceCall(TokenPosition position, const dart::String& name, Token::Kind kind, intptr_t type_args_len, intptr_t argument_count, const Array& argument_names, intptr_t checked_argument_count); Fragment ThrowException(TokenPosition position); Fragment BooleanNegate(); Fragment TranslateInstantiatedTypeArguments( const TypeArguments& type_arguments); Fragment StrictCompare(Token::Kind kind, bool number_check = false); Fragment AllocateObject(TokenPosition position, const dart::Class& klass, intptr_t argument_count); Fragment AllocateObject(const dart::Class& klass, const Function& closure_function); Fragment AllocateContext(intptr_t size); Fragment LoadField(intptr_t offset); Fragment StoreLocal(TokenPosition position, LocalVariable* variable); Fragment StoreStaticField(TokenPosition position, const dart::Field& field); Fragment StoreInstanceField(TokenPosition position, intptr_t offset); Fragment StringInterpolate(TokenPosition position); Fragment StringInterpolateSingle(TokenPosition position); Fragment ThrowTypeError(); Fragment LoadInstantiatorTypeArguments(); Fragment LoadFunctionTypeArguments(); Fragment InstantiateType(const AbstractType& type); Fragment CreateArray(); Fragment StoreIndexed(intptr_t class_id); Fragment CheckStackOverflow(); Fragment CloneContext(); Fragment TranslateFinallyFinalizers(TryFinallyBlock* outer_finally, intptr_t target_context_depth); Fragment BranchIfTrue(TargetEntryInstr** then_entry, TargetEntryInstr** otherwise_entry, bool negate); Fragment BranchIfEqual(TargetEntryInstr** then_entry, TargetEntryInstr** otherwise_entry, bool negate); Fragment BranchIfNull(TargetEntryInstr** then_entry, TargetEntryInstr** otherwise_entry, bool negate = false); Fragment CatchBlockEntry(const Array& handler_types, intptr_t handler_index, bool needs_stacktrace); Fragment TryCatch(int try_handler_index); Fragment Drop(); Fragment NullConstant(); JoinEntryInstr* BuildJoinEntry(); JoinEntryInstr* BuildJoinEntry(intptr_t try_index); Fragment Goto(JoinEntryInstr* destination); Fragment BuildImplicitClosureCreation(const Function& target); Fragment CheckBooleanInCheckedMode(); Fragment CheckAssignableInCheckedMode(const dart::AbstractType& dst_type, const dart::String& dst_name); Fragment CheckVariableTypeInCheckedMode(intptr_t variable_kernel_position); Fragment CheckVariableTypeInCheckedMode(const AbstractType& dst_type, const dart::String& name_symbol); Fragment EnterScope(intptr_t kernel_offset, bool* new_context = NULL); Fragment ExitScope(intptr_t kernel_offset); Fragment TranslateCondition(bool* negate); const TypeArguments& BuildTypeArguments(); Fragment BuildArguments(Array* argument_names, intptr_t* argument_count, bool skip_push_arguments = false, bool do_drop = false); Fragment BuildArgumentsFromActualArguments(Array* argument_names, bool skip_push_arguments = false, bool do_drop = false); Fragment BuildInvalidExpression(TokenPosition* position); Fragment BuildVariableGet(TokenPosition* position); Fragment BuildVariableGet(uint8_t payload, TokenPosition* position); Fragment BuildVariableSet(TokenPosition* position); Fragment BuildVariableSet(uint8_t payload, TokenPosition* position); Fragment BuildPropertyGet(TokenPosition* position); Fragment BuildPropertySet(TokenPosition* position); Fragment BuildDirectPropertyGet(TokenPosition* position); Fragment BuildDirectPropertySet(TokenPosition* position); Fragment BuildStaticGet(TokenPosition* position); Fragment BuildStaticSet(TokenPosition* position); Fragment BuildMethodInvocation(TokenPosition* position); Fragment BuildDirectMethodInvocation(TokenPosition* position); Fragment BuildStaticInvocation(bool is_const, TokenPosition* position); Fragment BuildConstructorInvocation(bool is_const, TokenPosition* position); Fragment BuildNot(TokenPosition* position); Fragment BuildLogicalExpression(TokenPosition* position); Fragment BuildConditionalExpression(TokenPosition* position); Fragment BuildStringConcatenation(TokenPosition* position); Fragment BuildIsExpression(TokenPosition* position); Fragment BuildAsExpression(TokenPosition* position); Fragment BuildSymbolLiteral(TokenPosition* position); Fragment BuildTypeLiteral(TokenPosition* position); Fragment BuildThisExpression(TokenPosition* position); Fragment BuildRethrow(TokenPosition* position); Fragment BuildThrow(TokenPosition* position); Fragment BuildListLiteral(bool is_const, TokenPosition* position); Fragment BuildMapLiteral(bool is_const, TokenPosition* position); Fragment BuildFunctionExpression(); Fragment BuildLet(TokenPosition* position); Fragment BuildBigIntLiteral(TokenPosition* position); Fragment BuildStringLiteral(TokenPosition* position); Fragment BuildIntLiteral(uint8_t payload, TokenPosition* position); Fragment BuildIntLiteral(bool is_negative, TokenPosition* position); Fragment BuildDoubleLiteral(TokenPosition* position); Fragment BuildBoolLiteral(bool value, TokenPosition* position); Fragment BuildNullLiteral(TokenPosition* position); Fragment BuildVectorCreation(TokenPosition* position); Fragment BuildVectorGet(TokenPosition* position); Fragment BuildVectorSet(TokenPosition* position); Fragment BuildVectorCopy(TokenPosition* position); Fragment BuildClosureCreation(TokenPosition* position); Fragment BuildInvalidStatement(); Fragment BuildExpressionStatement(); Fragment BuildBlock(); Fragment BuildEmptyStatement(); Fragment BuildAssertStatement(); Fragment BuildLabeledStatement(); Fragment BuildBreakStatement(); Fragment BuildWhileStatement(); Fragment BuildDoStatement(); Fragment BuildForStatement(); Fragment BuildForInStatement(bool async); Fragment BuildSwitchStatement(); Fragment BuildContinueSwitchStatement(); Fragment BuildIfStatement(); Fragment BuildReturnStatement(); Fragment BuildTryCatch(); Fragment BuildTryFinally(); Fragment BuildYieldStatement(); Fragment BuildVariableDeclaration(); Fragment BuildFunctionDeclaration(); Fragment BuildFunctionNode(TokenPosition parent_position, StringIndex name_index); void SetupFunctionParameters(const dart::Class& klass, const dart::Function& function, bool is_method, bool is_closure, FunctionNodeHelper* function_node_helper); FlowGraphBuilder* flow_graph_builder_; TranslationHelper& translation_helper_; Zone* zone_; Reader* reader_; StreamingConstantEvaluator constant_evaluator_; StreamingDartTypeTranslator type_translator_; intptr_t relative_kernel_offset_; intptr_t current_script_id_; intptr_t record_for_script_id_; GrowableArray* record_token_positions_into_; GrowableArray* record_yield_positions_into_; friend class StreamingConstantEvaluator; friend class StreamingDartTypeTranslator; friend class StreamingScopeBuilder; friend class FunctionNodeHelper; friend class VariableDeclarationHelper; friend class FieldHelper; friend class ProcedureHelper; friend class ClassHelper; friend class LibraryHelper; friend class ConstructorHelper; friend class SimpleExpressionConverter; friend class KernelReader; }; // A helper class that saves the current reader position, goes to another reader // position, and upon destruction, resets to the original reader position. class AlternativeReadingScope { public: AlternativeReadingScope(Reader* reader, intptr_t new_position) : reader_(reader), saved_size_(reader_->size()), saved_raw_buffer_(reader_->raw_buffer()), saved_typed_data_(reader_->typed_data()), saved_offset_(reader_->offset()) { reader_->set_offset(new_position); } AlternativeReadingScope(Reader* reader, const TypedData* new_typed_data, intptr_t new_position) : reader_(reader), saved_size_(reader_->size()), saved_raw_buffer_(reader_->raw_buffer()), saved_typed_data_(reader_->typed_data()), saved_offset_(reader_->offset()) { reader_->set_raw_buffer(NULL); reader_->set_typed_data(new_typed_data); reader_->set_size(new_typed_data->Length()); reader_->set_offset(new_position); } explicit AlternativeReadingScope(Reader* reader) : reader_(reader), saved_size_(reader_->size()), saved_raw_buffer_(reader_->raw_buffer()), saved_typed_data_(reader_->typed_data()), saved_offset_(reader_->offset()) {} ~AlternativeReadingScope() { reader_->set_raw_buffer(saved_raw_buffer_); reader_->set_typed_data(saved_typed_data_); reader_->set_size(saved_size_); reader_->set_offset(saved_offset_); } intptr_t saved_offset() { return saved_offset_; } private: Reader* reader_; intptr_t saved_size_; const uint8_t* saved_raw_buffer_; const TypedData* saved_typed_data_; intptr_t saved_offset_; }; // Helper class that reads a kernel FunctionNode from binary. // // Use ReadUntilExcluding to read up to but not including a field. // One can then for instance read the field from the call-site (and remember to // call SetAt to inform this helper class), and then use this to read more. // "Dumb" fields are stored (e.g. integers) and can be fetched from this class. // If asked to read a "non-dumb" field (e.g. an expression) it will be skipped. class FunctionNodeHelper { public: enum Fields { kStart, // tag. kPosition, kEndPosition, kAsyncMarker, kDartAsyncMarker, kTypeParameters, kTotalParameterCount, kRequiredParameterCount, kPositionalParameters, kNamedParameters, kReturnType, kBody, kEnd }; explicit FunctionNodeHelper(StreamingFlowGraphBuilder* builder) { builder_ = builder; next_read_ = kStart; } void ReadUntilIncluding(Fields field) { ReadUntilExcluding(static_cast(static_cast(field) + 1)); } void ReadUntilExcluding(Fields field) { if (field <= next_read_) return; // Ordered with fall-through. switch (next_read_) { case kStart: { Tag tag = builder_->ReadTag(); // read tag. ASSERT(tag == kFunctionNode); if (++next_read_ == field) return; } case kPosition: position_ = builder_->ReadPosition(); // read position. if (++next_read_ == field) return; case kEndPosition: end_position_ = builder_->ReadPosition(); // read end position. if (++next_read_ == field) return; case kAsyncMarker: async_marker_ = static_cast( builder_->ReadByte()); // read async marker. if (++next_read_ == field) return; case kDartAsyncMarker: dart_async_marker_ = static_cast( builder_->ReadByte()); // read dart async marker. if (++next_read_ == field) return; case kTypeParameters: builder_->SkipTypeParametersList(); // read type parameters. if (++next_read_ == field) return; case kTotalParameterCount: total_parameter_count_ = builder_->ReadUInt(); // read total parameter count. if (++next_read_ == field) return; case kRequiredParameterCount: required_parameter_count_ = builder_->ReadUInt(); // read required parameter count. if (++next_read_ == field) return; case kPositionalParameters: builder_->SkipListOfVariableDeclarations(); // read positionals. if (++next_read_ == field) return; case kNamedParameters: builder_->SkipListOfVariableDeclarations(); // read named. if (++next_read_ == field) return; case kReturnType: builder_->SkipDartType(); // read return type. if (++next_read_ == field) return; case kBody: if (builder_->ReadTag() == kSomething) builder_->SkipStatement(); // read body. if (++next_read_ == field) return; case kEnd: return; } } void SetNext(Fields field) { next_read_ = field; } void SetJustRead(Fields field) { next_read_ = field; ++next_read_; } TokenPosition position_; TokenPosition end_position_; FunctionNode::AsyncMarker async_marker_; FunctionNode::AsyncMarker dart_async_marker_; intptr_t total_parameter_count_; intptr_t required_parameter_count_; private: StreamingFlowGraphBuilder* builder_; intptr_t next_read_; }; // Helper class that reads a kernel VariableDeclaration from binary. // // Use ReadUntilExcluding to read up to but not including a field. // One can then for instance read the field from the call-site (and remember to // call SetAt to inform this helper class), and then use this to read more. // "Dumb" fields are stored (e.g. integers) and can be fetched from this class. // If asked to read a "non-dumb" field (e.g. an expression) it will be skipped. class VariableDeclarationHelper { public: enum Fields { kPosition, kEqualPosition, kFlags, kNameIndex, kType, kInitializer, kEnd }; explicit VariableDeclarationHelper(StreamingFlowGraphBuilder* builder) { builder_ = builder; next_read_ = kPosition; } void ReadUntilIncluding(Fields field) { ReadUntilExcluding(static_cast(static_cast(field) + 1)); } void ReadUntilExcluding(Fields field) { if (field <= next_read_) return; // Ordered with fall-through. switch (next_read_) { case kPosition: position_ = builder_->ReadPosition(); // read position. if (++next_read_ == field) return; case kEqualPosition: equals_position_ = builder_->ReadPosition(); // read equals position. if (++next_read_ == field) return; case kFlags: flags_ = builder_->ReadFlags(); // read flags. if (++next_read_ == field) return; case kNameIndex: name_index_ = builder_->ReadStringReference(); // read name index. if (++next_read_ == field) return; case kType: builder_->SkipDartType(); // read type. if (++next_read_ == field) return; case kInitializer: if (builder_->ReadTag() == kSomething) builder_->SkipExpression(); // read initializer. if (++next_read_ == field) return; case kEnd: return; } } void SetNext(Fields field) { next_read_ = field; } void SetJustRead(Fields field) { next_read_ = field; ++next_read_; } bool IsConst() { return (flags_ & VariableDeclaration::kFlagConst) == VariableDeclaration::kFlagConst; } bool IsFinal() { return (flags_ & VariableDeclaration::kFlagFinal) == VariableDeclaration::kFlagFinal; } TokenPosition position_; TokenPosition equals_position_; word flags_; StringIndex name_index_; private: StreamingFlowGraphBuilder* builder_; intptr_t next_read_; }; // Helper class that reads a kernel Field from binary. // // Use ReadUntilExcluding to read up to but not including a field. // One can then for instance read the field from the call-site (and remember to // call SetAt to inform this helper class), and then use this to read more. // "Dumb" fields are stored (e.g. integers) and can be fetched from this class. // If asked to read a "non-dumb" field (e.g. an expression) it will be skipped. class FieldHelper { public: enum Fields { kStart, // tag. kCanonicalName, kPosition, kEndPosition, kFlags, kName, kSourceUriIndex, kDocumentationCommentIndex, kAnnotations, kType, kInitializer, kEnd }; explicit FieldHelper(StreamingFlowGraphBuilder* builder) : builder_(builder), next_read_(kStart), has_function_literal_initializer_(false) {} FieldHelper(StreamingFlowGraphBuilder* builder, intptr_t offset) : builder_(builder), next_read_(kStart), has_function_literal_initializer_(false) { builder_->SetOffset(offset); } void ReadUntilIncluding(Fields field) { ReadUntilExcluding(static_cast(static_cast(field) + 1)); } void ReadUntilExcluding(Fields field, bool detect_function_literal_initializer = false) { if (field <= next_read_) return; // Ordered with fall-through. switch (next_read_) { case kStart: { Tag tag = builder_->ReadTag(); // read tag. ASSERT(tag == kField); if (++next_read_ == field) return; } case kCanonicalName: canonical_name_ = builder_->ReadCanonicalNameReference(); // read canonical_name. if (++next_read_ == field) return; case kPosition: position_ = builder_->ReadPosition(false); // read position. if (++next_read_ == field) return; case kEndPosition: end_position_ = builder_->ReadPosition(false); // read end position. if (++next_read_ == field) return; case kFlags: flags_ = builder_->ReadFlags(); // read flags. if (++next_read_ == field) return; case kName: builder_->SkipName(); // read name. if (++next_read_ == field) return; case kSourceUriIndex: source_uri_index_ = builder_->ReadUInt(); // read source_uri_index. builder_->current_script_id_ = source_uri_index_; builder_->record_token_position(position_); builder_->record_token_position(end_position_); if (++next_read_ == field) return; case kDocumentationCommentIndex: builder_->ReadStringReference(); if (++next_read_ == field) return; case kAnnotations: { annotation_count_ = builder_->ReadListLength(); // read list length. for (intptr_t i = 0; i < annotation_count_; ++i) { builder_->SkipExpression(); // read ith expression. } if (++next_read_ == field) return; } case kType: builder_->SkipDartType(); // read type. if (++next_read_ == field) return; case kInitializer: if (builder_->ReadTag() == kSomething) { if (detect_function_literal_initializer && builder_->PeekTag() == kFunctionExpression) { AlternativeReadingScope alt(builder_->reader_); Tag tag = builder_->ReadTag(); ASSERT(tag == kFunctionExpression); FunctionNodeHelper helper(builder_); helper.ReadUntilIncluding(FunctionNodeHelper::kEndPosition); has_function_literal_initializer_ = true; function_literal_start_ = helper.position_; function_literal_end_ = helper.end_position_; } builder_->SkipExpression(); // read initializer. } if (++next_read_ == field) return; case kEnd: return; } } void SetNext(Fields field) { next_read_ = field; } void SetJustRead(Fields field) { next_read_ = field; ++next_read_; } bool IsConst() { return (flags_ & Field::kFlagConst) == Field::kFlagConst; } bool IsFinal() { return (flags_ & Field::kFlagFinal) == Field::kFlagFinal; } bool IsStatic() { return (flags_ & Field::kFlagStatic) == Field::kFlagStatic; } bool FieldHasFunctionLiteralInitializer(TokenPosition* start, TokenPosition* end) { if (has_function_literal_initializer_) { *start = function_literal_start_; *end = function_literal_end_; } return has_function_literal_initializer_; } NameIndex canonical_name_; TokenPosition position_; TokenPosition end_position_; word flags_; intptr_t source_uri_index_; intptr_t annotation_count_; private: StreamingFlowGraphBuilder* builder_; intptr_t next_read_; bool has_function_literal_initializer_; TokenPosition function_literal_start_; TokenPosition function_literal_end_; }; // Helper class that reads a kernel Procedure from binary. // // Use ReadUntilExcluding to read up to but not including a field. // One can then for instance read the field from the call-site (and remember to // call SetAt to inform this helper class), and then use this to read more. // "Dumb" fields are stored (e.g. integers) and can be fetched from this class. // If asked to read a "non-dumb" field (e.g. an expression) it will be skipped. class ProcedureHelper { public: enum Fields { kStart, // tag. kCanonicalName, kPosition, kEndPosition, kKind, kFlags, kName, kSourceUriIndex, kDocumentationCommentIndex, kAnnotations, kFunction, kEnd }; explicit ProcedureHelper(StreamingFlowGraphBuilder* builder) { builder_ = builder; next_read_ = kStart; } void ReadUntilIncluding(Fields field) { ReadUntilExcluding(static_cast(static_cast(field) + 1)); } void ReadUntilExcluding(Fields field) { if (field <= next_read_) return; // Ordered with fall-through. switch (next_read_) { case kStart: { Tag tag = builder_->ReadTag(); // read tag. ASSERT(tag == kProcedure); if (++next_read_ == field) return; } case kCanonicalName: canonical_name_ = builder_->ReadCanonicalNameReference(); // read canonical_name. if (++next_read_ == field) return; case kPosition: position_ = builder_->ReadPosition(false); // read position. if (++next_read_ == field) return; case kEndPosition: end_position_ = builder_->ReadPosition(false); // read end position. if (++next_read_ == field) return; case kKind: kind_ = static_cast( builder_->ReadByte()); // read kind. if (++next_read_ == field) return; case kFlags: flags_ = builder_->ReadFlags(); // read flags. if (++next_read_ == field) return; case kName: builder_->SkipName(); // read name. if (++next_read_ == field) return; case kSourceUriIndex: source_uri_index_ = builder_->ReadUInt(); // read source_uri_index. builder_->current_script_id_ = source_uri_index_; builder_->record_token_position(position_); builder_->record_token_position(end_position_); if (++next_read_ == field) return; case kDocumentationCommentIndex: builder_->ReadStringReference(); if (++next_read_ == field) return; case kAnnotations: { annotation_count_ = builder_->ReadListLength(); // read list length. for (intptr_t i = 0; i < annotation_count_; ++i) { builder_->SkipExpression(); // read ith expression. } if (++next_read_ == field) return; } case kFunction: if (builder_->ReadTag() == kSomething) builder_->SkipFunctionNode(); // read function node. if (++next_read_ == field) return; case kEnd: return; } } void SetNext(Fields field) { next_read_ = field; } void SetJustRead(Fields field) { next_read_ = field; ++next_read_; } bool IsStatic() { return (flags_ & Procedure::kFlagStatic) == Procedure::kFlagStatic; } bool IsAbstract() { return (flags_ & Procedure::kFlagAbstract) == Procedure::kFlagAbstract; } bool IsExternal() { return (flags_ & Procedure::kFlagExternal) == Procedure::kFlagExternal; } bool IsConst() { return (flags_ & Procedure::kFlagConst) == Procedure::kFlagConst; } NameIndex canonical_name_; TokenPosition position_; TokenPosition end_position_; Procedure::ProcedureKind kind_; word flags_; intptr_t source_uri_index_; intptr_t annotation_count_; private: StreamingFlowGraphBuilder* builder_; intptr_t next_read_; }; // Helper class that reads a kernel Constructor from binary. // // Use ReadUntilExcluding to read up to but not including a field. // One can then for instance read the field from the call-site (and remember to // call SetAt to inform this helper class), and then use this to read more. // "Dumb" fields are stored (e.g. integers) and can be fetched from this class. // If asked to read a "non-dumb" field (e.g. an expression) it will be skipped. class ConstructorHelper { public: enum Fields { kStart, // tag. kCanonicalName, kPosition, kEndPosition, kFlags, kName, kDocumentationCommentIndex, kAnnotations, kFunction, kInitializers, kEnd }; explicit ConstructorHelper(StreamingFlowGraphBuilder* builder) { builder_ = builder; next_read_ = kStart; } void ReadUntilIncluding(Fields field) { ReadUntilExcluding(static_cast(static_cast(field) + 1)); } void ReadUntilExcluding(Fields field) { if (field <= next_read_) return; // Ordered with fall-through. switch (next_read_) { case kStart: { Tag tag = builder_->ReadTag(); // read tag. ASSERT(tag == kConstructor); if (++next_read_ == field) return; } case kCanonicalName: canonical_name_ = builder_->ReadCanonicalNameReference(); // read canonical_name. if (++next_read_ == field) return; case kPosition: position_ = builder_->ReadPosition(); // read position. if (++next_read_ == field) return; case kEndPosition: end_position_ = builder_->ReadPosition(); // read end position. if (++next_read_ == field) return; case kFlags: flags_ = builder_->ReadFlags(); // read flags. if (++next_read_ == field) return; case kName: builder_->SkipName(); // read name. if (++next_read_ == field) return; case kDocumentationCommentIndex: builder_->ReadStringReference(); if (++next_read_ == field) return; case kAnnotations: { annotation_count_ = builder_->ReadListLength(); // read list length. for (intptr_t i = 0; i < annotation_count_; ++i) { builder_->SkipExpression(); // read ith expression. } if (++next_read_ == field) return; } case kFunction: builder_->SkipFunctionNode(); // read function. if (++next_read_ == field) return; case kInitializers: { intptr_t list_length = builder_->ReadListLength(); // read initializers list length. for (intptr_t i = 0; i < list_length; i++) { Tag tag = builder_->ReadTag(); builder_->ReadByte(); // read isSynthetic. switch (tag) { case kInvalidInitializer: continue; case kFieldInitializer: builder_->SkipCanonicalNameReference(); // read field_reference. builder_->SkipExpression(); // read value. continue; case kSuperInitializer: builder_->SkipCanonicalNameReference(); // read target_reference. builder_->SkipArguments(); // read arguments. continue; case kRedirectingInitializer: builder_->SkipCanonicalNameReference(); // read target_reference. builder_->SkipArguments(); // read arguments. continue; case kLocalInitializer: builder_->SkipVariableDeclaration(); // read variable. continue; default: UNREACHABLE(); } } if (++next_read_ == field) return; } case kEnd: return; } } void SetNext(Fields field) { next_read_ = field; } void SetJustRead(Fields field) { next_read_ = field; ++next_read_; } bool IsExternal() { return (flags_ & Constructor::kFlagExternal) == Constructor::kFlagExternal; } bool IsConst() { return (flags_ & Constructor::kFlagConst) == Constructor::kFlagConst; } NameIndex canonical_name_; TokenPosition position_; TokenPosition end_position_; word flags_; intptr_t annotation_count_; private: StreamingFlowGraphBuilder* builder_; intptr_t next_read_; }; // Helper class that reads a kernel Class from binary. // // Use ReadUntilExcluding to read up to but not including a field. // One can then for instance read the field from the call-site (and remember to // call SetAt to inform this helper class), and then use this to read more. // "Dumb" fields are stored (e.g. integers) and can be fetched from this class. // If asked to read a "non-dumb" field (e.g. an expression) it will be skipped. class ClassHelper { public: enum Fields { kStart, // tag. kCanonicalName, kPosition, kEndPosition, kIsAbstract, kNameIndex, kSourceUriIndex, kDocumentationCommentIndex, kAnnotations, kTypeParameters, kSuperClass, kMixinType, kImplementedClasses, kFields, kConstructors, kProcedures, kEnd }; explicit ClassHelper(StreamingFlowGraphBuilder* builder) { builder_ = builder; next_read_ = kStart; } void ReadUntilIncluding(Fields field) { ReadUntilExcluding(static_cast(static_cast(field) + 1)); } void ReadUntilExcluding(Fields field) { if (field <= next_read_) return; // Ordered with fall-through. switch (next_read_) { case kStart: { Tag tag = builder_->ReadTag(); // read tag. ASSERT(tag == kClass); if (++next_read_ == field) return; } case kCanonicalName: canonical_name_ = builder_->ReadCanonicalNameReference(); // read canonical_name. if (++next_read_ == field) return; case kPosition: position_ = builder_->ReadPosition(false); // read position. if (++next_read_ == field) return; case kEndPosition: end_position_ = builder_->ReadPosition(); // read end position. if (++next_read_ == field) return; case kIsAbstract: is_abstract_ = builder_->ReadBool(); // read is_abstract. if (++next_read_ == field) return; case kNameIndex: name_index_ = builder_->ReadStringReference(); // read name index. if (++next_read_ == field) return; case kSourceUriIndex: source_uri_index_ = builder_->ReadUInt(); // read source_uri_index. builder_->current_script_id_ = source_uri_index_; builder_->record_token_position(position_); if (++next_read_ == field) return; case kDocumentationCommentIndex: builder_->ReadStringReference(); if (++next_read_ == field) return; case kAnnotations: { annotation_count_ = builder_->ReadListLength(); // read list length. for (intptr_t i = 0; i < annotation_count_; ++i) { builder_->SkipExpression(); // read ith expression. } if (++next_read_ == field) return; } case kTypeParameters: builder_->SkipTypeParametersList(); // read type parameters. if (++next_read_ == field) return; case kSuperClass: { Tag type_tag = builder_->ReadTag(); // read super class type (part 1). if (type_tag == kSomething) { builder_->SkipDartType(); // read super class type (part 2). } if (++next_read_ == field) return; } case kMixinType: { Tag type_tag = builder_->ReadTag(); // read mixin type (part 1). if (type_tag == kSomething) { builder_->SkipDartType(); // read mixin type (part 2). } if (++next_read_ == field) return; } case kImplementedClasses: builder_->SkipListOfDartTypes(); // read implemented_classes. if (++next_read_ == field) return; case kFields: { intptr_t list_length = builder_->ReadListLength(); // read fields list length. for (intptr_t i = 0; i < list_length; i++) { FieldHelper field_helper(builder_); field_helper.ReadUntilExcluding(FieldHelper::kEnd); // read field. } if (++next_read_ == field) return; } case kConstructors: { intptr_t list_length = builder_->ReadListLength(); // read constructors list length. for (intptr_t i = 0; i < list_length; i++) { ConstructorHelper constructor_helper(builder_); constructor_helper.ReadUntilExcluding( ConstructorHelper::kEnd); // read constructor. } if (++next_read_ == field) return; } case kProcedures: { intptr_t list_length = builder_->ReadListLength(); // read procedures list length. for (intptr_t i = 0; i < list_length; i++) { ProcedureHelper procedure_helper(builder_); procedure_helper.ReadUntilExcluding( ProcedureHelper::kEnd); // read procedure. } if (++next_read_ == field) return; } case kEnd: return; } } void SetNext(Fields field) { next_read_ = field; } void SetJustRead(Fields field) { next_read_ = field; ++next_read_; } NameIndex canonical_name_; TokenPosition position_; TokenPosition end_position_; bool is_abstract_; StringIndex name_index_; intptr_t source_uri_index_; intptr_t annotation_count_; private: StreamingFlowGraphBuilder* builder_; intptr_t next_read_; }; // Helper class that reads a kernel Library from binary. // // Use ReadUntilExcluding to read up to but not including a field. // One can then for instance read the field from the call-site (and remember to // call SetAt to inform this helper class), and then use this to read more. // "Dumb" fields are stored (e.g. integers) and can be fetched from this class. // If asked to read a "non-dumb" field (e.g. an expression) it will be skipped. class LibraryHelper { public: enum Fields { kFlags, kCanonicalName, kName, kSourceUriIndex, kAnnotations, kDependencies, kParts, kTypedefs, kClasses, kToplevelField, kToplevelProcedures, kEnd }; explicit LibraryHelper(StreamingFlowGraphBuilder* builder) { builder_ = builder; next_read_ = kFlags; } void ReadUntilIncluding(Fields field) { ReadUntilExcluding(static_cast(static_cast(field) + 1)); } void ReadUntilExcluding(Fields field) { if (field <= next_read_) return; // Ordered with fall-through. switch (next_read_) { case kFlags: { word flags = builder_->ReadFlags(); // read flags. ASSERT(flags == 0); // external libraries not supported if (++next_read_ == field) return; } case kCanonicalName: canonical_name_ = builder_->ReadCanonicalNameReference(); // read canonical_name. if (++next_read_ == field) return; case kName: name_index_ = builder_->ReadStringReference(); // read name index. if (++next_read_ == field) return; case kSourceUriIndex: source_uri_index_ = builder_->ReadUInt(); // read source_uri_index. builder_->current_script_id_ = source_uri_index_; if (++next_read_ == field) return; case kAnnotations: builder_->SkipListOfExpressions(); // read annotations. if (++next_read_ == field) return; case kDependencies: { intptr_t dependency_count = builder_->ReadUInt(); // read list length. for (intptr_t i = 0; i < dependency_count; ++i) { builder_->SkipLibraryDependency(); } if (++next_read_ == field) return; } case kParts: { intptr_t part_count = builder_->ReadUInt(); // read list length. for (intptr_t i = 0; i < part_count; ++i) { builder_->SkipLibraryPart(); } if (++next_read_ == field) return; } case kTypedefs: { intptr_t typedef_count = builder_->ReadListLength(); // read list length. for (intptr_t i = 0; i < typedef_count; i++) { builder_->SkipLibraryTypedef(); } if (++next_read_ == field) return; } case kClasses: { int class_count = builder_->ReadListLength(); // read list length. for (intptr_t i = 0; i < class_count; ++i) { ClassHelper class_helper(builder_); class_helper.ReadUntilExcluding(ClassHelper::kEnd); } if (++next_read_ == field) return; } case kToplevelField: { intptr_t field_count = builder_->ReadListLength(); // read list length. for (intptr_t i = 0; i < field_count; ++i) { FieldHelper field_helper(builder_); field_helper.ReadUntilExcluding(FieldHelper::kEnd); } if (++next_read_ == field) return; } case kToplevelProcedures: { intptr_t procedure_count = builder_->ReadListLength(); // read list length. for (intptr_t i = 0; i < procedure_count; ++i) { ProcedureHelper procedure_helper(builder_); procedure_helper.ReadUntilExcluding(ProcedureHelper::kEnd); } if (++next_read_ == field) return; } case kEnd: return; } } void SetNext(Fields field) { next_read_ = field; } void SetJustRead(Fields field) { next_read_ = field; ++next_read_; } NameIndex canonical_name_; StringIndex name_index_; intptr_t source_uri_index_; private: StreamingFlowGraphBuilder* builder_; intptr_t next_read_; }; } // namespace kernel } // namespace dart #endif // !defined(DART_PRECOMPILED_RUNTIME) #endif // RUNTIME_VM_KERNEL_BINARY_FLOWGRAPH_H_