6c2232cb60
This CL copies the kernel bodies for all functions and fields into the VM heap. The function bodies in the VM heap are then used when compiling the flowgraphs. This theoretically means that the malloc'd data can be freed and that snapshotting from kernel could possibly work, though it hasn't been tested. R=kmillikin@google.com Review-Url: https://codereview.chromium.org/2972343002 .
1575 lines
54 KiB
C++
1575 lines
54 KiB
C++
// 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 <map>
|
|
|
|
#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<LocalVariable*>* 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 = <expr>;
|
|
//
|
|
// * constant expressions:
|
|
// const [<expr>, ...]
|
|
// const {<expr> : <expr>, ...}
|
|
// const Constructor(<expr>, ...)
|
|
//
|
|
// * constant default parameters:
|
|
// f(a, [b = <expr>])
|
|
// f(a, {b: <expr>})
|
|
//
|
|
// * constant values to compare in a [SwitchCase]
|
|
// case <expr>:
|
|
//
|
|
// In all cases `<expr>` 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<intptr_t>* record_token_positions_in,
|
|
GrowableArray<intptr_t>* 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 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<YieldContinuation>& 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<intptr_t>* record_token_positions_into_;
|
|
GrowableArray<intptr_t>* 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<Fields>(static_cast<int>(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<FunctionNode::AsyncMarker>(
|
|
builder_->ReadByte()); // read async marker.
|
|
if (++next_read_ == field) return;
|
|
case kDartAsyncMarker:
|
|
dart_async_marker_ = static_cast<FunctionNode::AsyncMarker>(
|
|
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<Fields>(static_cast<int>(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<Fields>(static_cast<int>(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<Fields>(static_cast<int>(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<Procedure::ProcedureKind>(
|
|
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<Fields>(static_cast<int>(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<Fields>(static_cast<int>(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<Fields>(static_cast<int>(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_
|