blob: 87ef12b1b11662dfae37b6f35ae7dbd5715d772f [file] [log] [blame]
// 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_COMPILER_FRONTEND_KERNEL_BINARY_FLOWGRAPH_H_
#define RUNTIME_VM_COMPILER_FRONTEND_KERNEL_BINARY_FLOWGRAPH_H_
#if !defined(DART_PRECOMPILED_RUNTIME)
#include <map>
#include "vm/compiler/frontend/kernel_to_il.h"
#include "vm/kernel.h"
#include "vm/kernel_binary.h"
#include "vm/object.h"
namespace dart {
namespace kernel {
class KernelReaderHelper;
// 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.
// Simple fields are stored (e.g. integers) and can be fetched from this class.
// If asked to read a compound field (e.g. an expression) it will be skipped.
class FunctionNodeHelper {
public:
enum Field {
kStart, // tag.
kPosition,
kEndPosition,
kAsyncMarker,
kDartAsyncMarker,
kTypeParameters,
kTotalParameterCount,
kRequiredParameterCount,
kPositionalParameters,
kNamedParameters,
kReturnType,
kBody,
kEnd,
};
enum AsyncMarker {
kSync = 0,
kSyncStar = 1,
kAsync = 2,
kAsyncStar = 3,
kSyncYielding = 4,
};
explicit FunctionNodeHelper(KernelReaderHelper* helper) {
helper_ = helper;
next_read_ = kStart;
}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
TokenPosition position_;
TokenPosition end_position_;
AsyncMarker async_marker_;
AsyncMarker dart_async_marker_;
intptr_t total_parameter_count_;
intptr_t required_parameter_count_;
private:
KernelReaderHelper* helper_;
intptr_t next_read_;
};
class TypeParameterHelper {
public:
enum Field {
kStart, // tag.
kFlags,
kAnnotations,
kName,
kBound,
kDefaultType,
kEnd,
};
enum Flag {
kIsGenericCovariantImpl = 1 << 0,
kIsGenericCovariantInterface = 1 << 1
};
explicit TypeParameterHelper(KernelReaderHelper* helper) {
helper_ = helper;
next_read_ = kStart;
}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
void ReadUntilExcludingAndSetJustRead(Field field) {
ReadUntilExcluding(field);
SetJustRead(field);
}
void Finish() { ReadUntilExcluding(kEnd); }
TokenPosition position_;
uint8_t flags_;
StringIndex name_index_;
private:
KernelReaderHelper* helper_;
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.
// Simple fields are stored (e.g. integers) and can be fetched from this class.
// If asked to read a compound field (e.g. an expression) it will be skipped.
class VariableDeclarationHelper {
public:
enum Field {
kPosition,
kEqualPosition,
kAnnotations,
kFlags,
kNameIndex,
kType,
kInitializer,
kEnd,
};
enum Flag {
kFinal = 1 << 0,
kConst = 1 << 1,
kCovariant = 1 << 3,
kIsGenericCovariantImpl = 1 << 5,
kIsGenericCovariantInterface = 1 << 6
};
explicit VariableDeclarationHelper(KernelReaderHelper* helper)
: helper_(helper), next_read_(kPosition) {}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
bool IsConst() { return (flags_ & kConst) != 0; }
bool IsFinal() { return (flags_ & kFinal) != 0; }
bool IsCovariant() { return (flags_ & kCovariant) != 0; }
bool IsGenericCovariantInterface() {
return (flags_ & kIsGenericCovariantInterface) != 0;
}
bool IsGenericCovariantImpl() {
return (flags_ & kIsGenericCovariantImpl) != 0;
}
TokenPosition position_;
TokenPosition equals_position_;
uint8_t flags_;
StringIndex name_index_;
private:
KernelReaderHelper* helper_;
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.
// Simple fields are stored (e.g. integers) and can be fetched from this class.
// If asked to read a compound field (e.g. an expression) it will be skipped.
class FieldHelper {
public:
enum Field {
kStart, // tag.
kCanonicalName,
kSourceUriIndex,
kPosition,
kEndPosition,
kFlags,
kName,
kAnnotations,
kType,
kInitializer,
kEnd,
};
enum Flag {
kFinal = 1 << 0,
kConst = 1 << 1,
kStatic = 1 << 2,
kIsCovariant = 1 << 5,
kIsGenericCovariantImpl = 1 << 6,
kIsGenericCovariantInterface = 1 << 7
};
explicit FieldHelper(KernelReaderHelper* helper)
: helper_(helper),
next_read_(kStart),
has_function_literal_initializer_(false) {}
FieldHelper(KernelReaderHelper* helper, intptr_t offset);
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field,
bool detect_function_literal_initializer = false);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
bool IsConst() { return (flags_ & kConst) != 0; }
bool IsFinal() { return (flags_ & kFinal) != 0; }
bool IsStatic() { return (flags_ & kStatic) != 0; }
bool IsCovariant() const { return (flags_ & kIsCovariant) != 0; }
bool IsGenericCovariantImpl() {
return (flags_ & kIsGenericCovariantImpl) != 0;
}
bool IsGenericCovariantInterface() {
return (flags_ & kIsGenericCovariantInterface) != 0;
}
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_;
uint8_t flags_;
intptr_t source_uri_index_;
intptr_t annotation_count_;
private:
KernelReaderHelper* helper_;
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.
// Simple fields are stored (e.g. integers) and can be fetched from this class.
// If asked to read a compound field (e.g. an expression) it will be skipped.
class ProcedureHelper {
public:
enum Field {
kStart, // tag.
kCanonicalName,
kSourceUriIndex,
kPosition,
kEndPosition,
kKind,
kFlags,
kName,
kAnnotations,
kForwardingStubSuperTarget,
kForwardingStubInterfaceTarget,
kFunction,
kEnd,
};
enum Kind {
kMethod,
kGetter,
kSetter,
kOperator,
kFactory,
};
enum Flag {
kStatic = 1 << 0,
kAbstract = 1 << 1,
kExternal = 1 << 2,
kConst = 1 << 3, // Only for external const factories.
kForwardingStub = 1 << 4,
// TODO(29841): Remove this line after the issue is resolved.
kRedirectingFactoryConstructor = 1 << 6,
kNoSuchMethodForwarder = 1 << 7,
};
explicit ProcedureHelper(KernelReaderHelper* helper)
: helper_(helper), next_read_(kStart) {}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
bool IsStatic() { return (flags_ & kStatic) != 0; }
bool IsAbstract() { return (flags_ & kAbstract) != 0; }
bool IsExternal() { return (flags_ & kExternal) != 0; }
bool IsConst() { return (flags_ & kConst) != 0; }
bool IsForwardingStub() { return (flags_ & kForwardingStub) != 0; }
bool IsRedirectingFactoryConstructor() {
return (flags_ & kRedirectingFactoryConstructor) != 0;
}
bool IsNoSuchMethodForwarder() {
return (flags_ & kNoSuchMethodForwarder) != 0;
}
NameIndex canonical_name_;
TokenPosition position_;
TokenPosition end_position_;
Kind kind_;
uint8_t flags_;
intptr_t source_uri_index_;
intptr_t annotation_count_;
// Only valid if the 'isForwardingStub' flag is set.
NameIndex forwarding_stub_super_target_;
private:
KernelReaderHelper* helper_;
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.
// Simple fields are stored (e.g. integers) and can be fetched from this class.
// If asked to read a compound field (e.g. an expression) it will be skipped.
class ConstructorHelper {
public:
enum Field {
kStart, // tag.
kCanonicalName,
kSourceUriIndex,
kPosition,
kEndPosition,
kFlags,
kName,
kAnnotations,
kFunction,
kInitializers,
kEnd,
};
enum Flag {
kConst = 1 << 0,
kExternal = 1 << 1,
kSynthetic = 1 << 2,
};
explicit ConstructorHelper(KernelReaderHelper* helper)
: helper_(helper), next_read_(kStart) {}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
bool IsExternal() { return (flags_ & kExternal) != 0; }
bool IsConst() { return (flags_ & kConst) != 0; }
bool IsSynthetic() { return (flags_ & kSynthetic) != 0; }
NameIndex canonical_name_;
TokenPosition position_;
TokenPosition end_position_;
uint8_t flags_;
intptr_t source_uri_index_;
intptr_t annotation_count_;
private:
KernelReaderHelper* helper_;
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.
// Simple fields are stored (e.g. integers) and can be fetched from this class.
// If asked to read a compound field (e.g. an expression) it will be skipped.
class ClassHelper {
public:
enum Field {
kStart, // tag.
kCanonicalName,
kSourceUriIndex,
kPosition,
kEndPosition,
kFlags,
kNameIndex,
kAnnotations,
kTypeParameters,
kSuperClass,
kMixinType,
kImplementedClasses,
kFields,
kConstructors,
kProcedures,
kClassIndex,
kEnd,
};
enum Flag {
kIsAbstract = 1,
kIsEnumClass = 2,
};
explicit ClassHelper(KernelReaderHelper* helper)
: helper_(helper), next_read_(kStart) {}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
bool is_abstract() { return flags_ & Flag::kIsAbstract; }
bool is_enum_class() { return flags_ & Flag::kIsEnumClass; }
NameIndex canonical_name_;
TokenPosition position_;
TokenPosition end_position_;
StringIndex name_index_;
intptr_t source_uri_index_;
intptr_t annotation_count_;
intptr_t procedure_count_;
uint8_t flags_;
private:
KernelReaderHelper* helper_;
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.
// Simple fields are stored (e.g. integers) and can be fetched from this class.
// If asked to read a compound field (e.g. an expression) it will be skipped.
class LibraryHelper {
public:
enum Field {
kFlags,
kCanonicalName,
kName,
kSourceUriIndex,
kAnnotations,
kDependencies,
kAdditionalExports,
kParts,
kTypedefs,
kClasses,
kToplevelField,
kToplevelProcedures,
kLibraryIndex,
kEnd,
};
enum Flag {
kExternal = 1,
};
explicit LibraryHelper(KernelReaderHelper* helper)
: helper_(helper), next_read_(kFlags) {}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
void SetNext(Field field) { next_read_ = field; }
void SetJustRead(Field field) { next_read_ = field + 1; }
bool IsExternal() const { return (flags_ & kExternal) != 0; }
uint8_t flags_;
NameIndex canonical_name_;
StringIndex name_index_;
intptr_t source_uri_index_;
intptr_t class_count_;
intptr_t procedure_count_;
private:
KernelReaderHelper* helper_;
intptr_t next_read_;
};
class LibraryDependencyHelper {
public:
enum Field {
kFileOffset,
kFlags,
kAnnotations,
kTargetLibrary,
kName,
kCombinators,
kEnd,
};
enum Flag {
Export = 1 << 0,
Deferred = 1 << 1,
};
enum CombinatorFlag {
Show = 1 << 0,
};
explicit LibraryDependencyHelper(KernelReaderHelper* helper)
: helper_(helper), next_read_(kFileOffset) {}
void ReadUntilIncluding(Field field) {
ReadUntilExcluding(static_cast<Field>(static_cast<int>(field) + 1));
}
void ReadUntilExcluding(Field field);
uint8_t flags_;
StringIndex name_index_;
NameIndex target_library_canonical_name_;
private:
KernelReaderHelper* helper_;
intptr_t next_read_;
};
// Base class for helpers accessing metadata of a certain kind.
// Assumes that metadata is accessed in linear order.
class MetadataHelper {
public:
explicit MetadataHelper(StreamingFlowGraphBuilder* builder);
void SetMetadataMappings(intptr_t mappings_offset, intptr_t mappings_num);
protected:
// Look for metadata mapping with node offset greater or equal than the given.
intptr_t FindMetadataMapping(intptr_t node_offset);
// Return offset of the metadata payload corresponding to the given node,
// or -1 if there is no metadata.
// Assumes metadata is accesses for nodes in linear order most of the time.
intptr_t GetNextMetadataPayloadOffset(intptr_t node_offset);
StreamingFlowGraphBuilder* builder_;
TranslationHelper& translation_helper_;
private:
intptr_t mappings_offset_;
intptr_t mappings_num_;
intptr_t last_node_offset_;
intptr_t last_mapping_index_;
};
struct DirectCallMetadata {
DirectCallMetadata(const Function& target, bool check_receiver_for_null)
: target_(target), check_receiver_for_null_(check_receiver_for_null) {}
const Function& target_;
const bool check_receiver_for_null_;
};
// Helper class which provides access to direct call metadata.
class DirectCallMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.direct-call.metadata"; }
explicit DirectCallMetadataHelper(StreamingFlowGraphBuilder* builder)
: MetadataHelper(builder) {}
DirectCallMetadata GetDirectTargetForPropertyGet(intptr_t node_offset);
DirectCallMetadata GetDirectTargetForPropertySet(intptr_t node_offset);
DirectCallMetadata GetDirectTargetForMethodInvocation(intptr_t node_offset);
private:
bool ReadMetadata(intptr_t node_offset,
NameIndex* target_name,
bool* check_receiver_for_null);
};
struct InferredTypeMetadata {
InferredTypeMetadata(intptr_t cid_, bool nullable_)
: cid(cid_), nullable(nullable_) {}
const intptr_t cid;
const bool nullable;
bool IsTrivial() const { return (cid == kDynamicCid) && nullable; }
};
// Helper class which provides access to inferred type metadata.
class InferredTypeMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.inferred-type.metadata"; }
explicit InferredTypeMetadataHelper(StreamingFlowGraphBuilder* builder)
: MetadataHelper(builder) {}
InferredTypeMetadata GetInferredType(intptr_t node_offset);
};
struct ProcedureAttributesMetadata {
ProcedureAttributesMetadata(bool has_dynamic_invocations = true,
bool has_non_this_uses = true,
bool has_tearoff_uses = true)
: has_dynamic_invocations(has_dynamic_invocations),
has_non_this_uses(has_non_this_uses),
has_tearoff_uses(has_tearoff_uses) {}
bool has_dynamic_invocations;
bool has_non_this_uses;
bool has_tearoff_uses;
};
// Helper class which provides access to direct call metadata.
class ProcedureAttributesMetadataHelper : public MetadataHelper {
public:
static const char* tag() { return "vm.procedure-attributes.metadata"; }
explicit ProcedureAttributesMetadataHelper(StreamingFlowGraphBuilder* builder)
: MetadataHelper(builder) {}
ProcedureAttributesMetadata GetProcedureAttributes(intptr_t node_offset);
private:
bool ReadMetadata(intptr_t node_offset,
ProcedureAttributesMetadata* metadata);
};
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 Class& receiver_class,
intptr_t length);
const Type& ReceiverType(const Class& klass);
private:
// Can build a malformed type.
void BuildTypeInternal(bool invalid_as_dynamic = false);
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 KernelLoader;
};
class StreamingScopeBuilder {
public:
explicit StreamingScopeBuilder(ParsedFunction* parsed_function);
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 HandleLocalFunction(intptr_t parent_kernel_offset);
AbstractType& BuildAndVisitVariableType();
void EnterScope(intptr_t kernel_offset);
void ExitScope(TokenPosition start_position, TokenPosition end_position);
virtual void ReportUnexpectedTag(const char* variant, Tag tag);
// This enum controls which parameters would be marked as requring type
// check on the callee side.
enum ParameterTypeCheckMode {
// All parameters will be checked.
kTypeCheckAllParameters,
// Only parameters marked as covariant or generic-covariant-impl will be
// checked.
kTypeCheckForNonDynamicallyInvokedMethod,
// Only parameters *not* marked as covariant or generic-covariant-impl will
// be checked. The rest would be checked in the method itself.
// Inverse of kTypeCheckOnlyGenericCovariantImplParameters.
kTypeCheckForTearOffOfNonDynamicallyInvokedMethod,
// No parameters will be checked.
kTypeCheckForStaticFunction,
};
// This assumes that the reader is at a FunctionNode,
// about to read the positional parameters.
void AddPositionalAndNamedParameters(
intptr_t pos,
ParameterTypeCheckMode type_check_mode,
const ProcedureAttributesMetadata& attrs);
// This assumes that the reader is at a FunctionNode,
// about to read a parameter (i.e. VariableDeclaration).
void AddVariableDeclarationParameter(
intptr_t pos,
ParameterTypeCheckMode type_check_mode,
const ProcedureAttributesMetadata& attrs);
LocalVariable* MakeVariable(TokenPosition declaration_pos,
TokenPosition token_pos,
const String& name,
const AbstractType& type,
const InferredTypeMetadata* param_type_md = NULL);
void AddExceptionVariable(GrowableArray<LocalVariable*>* variables,
const char* prefix,
intptr_t nesting_depth);
void 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 String& GenerateName(const char* prefix, intptr_t suffix);
void HandleSpecialLoad(LocalVariable** variable, const String& symbol);
void LookupCapturedVariableByName(LocalVariable** variable,
const String& name);
struct DepthState {
explicit DepthState(intptr_t function)
: loop_(0),
function_(function),
try_(0),
catch_(0),
finally_(0),
for_in_(0) {}
intptr_t loop_;
intptr_t function_;
intptr_t try_;
intptr_t catch_;
intptr_t finally_;
intptr_t for_in_;
};
ScopeBuildingResult* result_;
ParsedFunction* parsed_function_;
ActiveClass active_class_;
TranslationHelper translation_helper_;
Zone* zone_;
FunctionNodeHelper::AsyncMarker current_function_async_marker_;
LocalScope* current_function_scope_;
LocalScope* scope_;
DepthState depth_;
intptr_t name_index_;
bool needs_expr_temp_;
TokenPosition first_body_token_position_;
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() {}
bool IsCached(intptr_t offset);
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:
bool IsAllowedToEvaluate();
void EvaluateAsExpression();
void EvaluateVariableGet();
void EvaluateVariableGet(uint8_t payload);
void EvaluatePropertyGet();
void EvaluateDirectPropertyGet();
void EvaluateStaticGet();
void EvaluateMethodInvocation();
void EvaluateDirectMethodInvocation();
void EvaluateSuperMethodInvocation();
void EvaluateStaticInvocation();
void EvaluateConstructorInvocationInternal();
void EvaluateNot();
void EvaluateLogicalExpression();
void EvaluateConditionalExpression();
void EvaluateStringConcatenation();
void EvaluateSymbolLiteral();
void EvaluateTypeLiteral();
void EvaluateListLiteralInternal();
void EvaluateMapLiteralInternal();
void EvaluateLet();
void EvaluatePartialTearoffInstantiation();
void EvaluateBigIntLiteral();
void EvaluateStringLiteral();
void EvaluateIntLiteral(uint8_t payload);
void EvaluateIntLiteral(bool is_negative);
void EvaluateDoubleLiteral();
void EvaluateBoolLiteral(bool value);
void EvaluateNullLiteral();
void EvaluateConstantExpression();
void EvaluateGetStringLength(intptr_t expression_offset,
TokenPosition position);
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);
const Object& RunMethodCall(const Function& function,
const Instance* receiver);
RawObject* EvaluateConstConstructorCall(const Class& type_class,
const TypeArguments& type_arguments,
const Function& constructor,
const Object& argument);
const TypeArguments* TranslateTypeArguments(const Function& target,
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_;
const Script& script_;
Instance& result_;
};
class KernelReaderHelper {
public:
KernelReaderHelper(Zone* zone,
TranslationHelper* translation_helper,
const Script& script,
const TypedData& data,
intptr_t data_program_offset)
: zone_(zone),
translation_helper_(*translation_helper),
reader_(data),
script_(script),
data_program_offset_(data_program_offset) {}
KernelReaderHelper(Zone* zone,
TranslationHelper* translation_helper,
const uint8_t* data_buffer,
intptr_t buffer_length,
intptr_t data_program_offset)
: zone_(zone),
translation_helper_(*translation_helper),
reader_(data_buffer, buffer_length),
script_(Script::Handle(zone_)),
data_program_offset_(data_program_offset) {}
virtual ~KernelReaderHelper() {}
void SetOffset(intptr_t offset);
intptr_t ReadListLength();
virtual void ReportUnexpectedTag(const char* variant, Tag tag);
protected:
const Script& script() const { return script_; }
virtual void set_current_script_id(intptr_t id) {
// Do nothing by default. This is overridden in StreamingFlowGraphBuilder.
USE(id);
}
virtual void RecordYieldPosition(TokenPosition position) {
// Do nothing by default. This is overridden in StreamingFlowGraphBuilder.
USE(position);
}
virtual void RecordTokenPosition(TokenPosition position) {
// Do nothing by default. This is overridden in StreamingFlowGraphBuilder.
USE(position);
}
intptr_t ReaderOffset() const;
void SkipBytes(intptr_t skip);
bool ReadBool();
uint8_t ReadByte();
uint32_t ReadUInt();
uint32_t ReadUInt32();
uint32_t PeekUInt();
double ReadDouble();
uint32_t PeekListLength();
StringIndex ReadStringReference();
NameIndex ReadCanonicalNameReference();
StringIndex ReadNameAsStringIndex();
const String& ReadNameAsMethodName();
const String& ReadNameAsGetterName();
const String& ReadNameAsSetterName();
const String& ReadNameAsFieldName();
void SkipFlags();
void SkipStringReference();
void SkipConstantReference();
void SkipCanonicalNameReference();
void SkipDartType();
void SkipOptionalDartType();
void SkipInterfaceType(bool simple);
void SkipFunctionType(bool simple);
void SkipStatementList();
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);
Tag ReadTag(uint8_t* payload = NULL);
Tag PeekTag(uint8_t* payload = NULL);
uint8_t ReadFlags() { return reader_.ReadFlags(); }
Zone* zone_;
TranslationHelper& translation_helper_;
Reader reader_;
const Script& script_;
// Some items like variables are specified in the kernel binary as
// absolute offsets (as in, offsets within the whole kernel program)
// of their declaration nodes. Hence, to cache and/or access them
// uniquely from within a function's kernel data, we need to
// add/subtract the offset of the kernel data in the over all
// kernel program.
intptr_t data_program_offset_;
friend class ClassHelper;
friend class ConstantHelper;
friend class ConstructorHelper;
friend class DirectCallMetadataHelper;
friend class ProcedureAttributesMetadataHelper;
friend class FieldHelper;
friend class FunctionNodeHelper;
friend class InferredTypeMetadataHelper;
friend class KernelLoader;
friend class LibraryDependencyHelper;
friend class LibraryHelper;
friend class MetadataHelper;
friend class ProcedureHelper;
friend class SimpleExpressionConverter;
friend class StreamingConstantEvaluator;
friend class StreamingDartTypeTranslator;
friend class StreamingScopeBuilder;
friend class VariableDeclarationHelper;
friend class TypeParameterHelper;
};
class KernelFingerprintHelper : public KernelReaderHelper {
public:
KernelFingerprintHelper(Zone* zone,
TranslationHelper* translation_helper,
const Script& script,
const TypedData& data,
intptr_t data_program_offset)
: KernelReaderHelper(zone,
translation_helper,
script,
data,
data_program_offset),
hash_(0) {}
virtual ~KernelFingerprintHelper() {}
uint32_t CalculateFieldFingerprint();
uint32_t CalculateFunctionFingerprint();
static uint32_t CalculateHash(uint32_t current, uint32_t val) {
return current * 31 + val;
}
private:
void BuildHash(uint32_t val);
void CalculateConstructorFingerprint();
void CalculateArgumentsFingerprint();
void CalculateVariableDeclarationFingerprint();
void CalculateStatementListFingerprint();
void CalculateListOfExpressionsFingerprint();
void CalculateListOfDartTypesFingerprint();
void CalculateListOfVariableDeclarationsFingerprint();
void CalculateStringReferenceFingerprint();
void CalculateListOfStringsFingerprint();
void CalculateTypeParameterFingerprint();
void CalculateTypeParametersListFingerprint();
void CalculateCanonicalNameFingerprint();
void CalculateInitializerFingerprint();
void CalculateDartTypeFingerprint();
void CalculateOptionalDartTypeFingerprint();
void CalculateInterfaceTypeFingerprint(bool simple);
void CalculateFunctionTypeFingerprint(bool simple);
void CalculateGetterNameFingerprint();
void CalculateSetterNameFingerprint();
void CalculateMethodNameFingerprint();
void CalculateExpressionFingerprint();
void CalculateStatementFingerprint();
void CalculateFunctionNodeFingerprint();
uint32_t hash_;
};
class StreamingFlowGraphBuilder : public KernelReaderHelper {
public:
StreamingFlowGraphBuilder(FlowGraphBuilder* flow_graph_builder,
const TypedData& data,
intptr_t data_program_offset)
: KernelReaderHelper(
flow_graph_builder->zone_,
&flow_graph_builder->translation_helper_,
Script::Handle(
flow_graph_builder->zone_,
flow_graph_builder->parsed_function_->function().script()),
data,
data_program_offset),
flow_graph_builder_(flow_graph_builder),
constant_evaluator_(this),
type_translator_(this, /* finalize= */ true),
current_script_id_(-1),
record_for_script_id_(-1),
record_token_positions_into_(NULL),
record_yield_positions_into_(NULL),
direct_call_metadata_helper_(this),
inferred_type_metadata_helper_(this),
procedure_attributes_metadata_helper_(this),
metadata_scanned_(false) {}
StreamingFlowGraphBuilder(TranslationHelper* translation_helper,
Zone* zone,
const uint8_t* data_buffer,
intptr_t buffer_length,
intptr_t data_program_offset)
: KernelReaderHelper(zone,
translation_helper,
data_buffer,
buffer_length,
data_program_offset),
flow_graph_builder_(NULL),
constant_evaluator_(this),
type_translator_(this, /* finalize= */ true),
current_script_id_(-1),
record_for_script_id_(-1),
record_token_positions_into_(NULL),
record_yield_positions_into_(NULL),
direct_call_metadata_helper_(this),
inferred_type_metadata_helper_(this),
procedure_attributes_metadata_helper_(this),
metadata_scanned_(false) {}
StreamingFlowGraphBuilder(TranslationHelper* translation_helper,
const Script& script,
Zone* zone,
const TypedData& data,
intptr_t data_program_offset)
: KernelReaderHelper(zone,
translation_helper,
script,
data,
data_program_offset),
flow_graph_builder_(NULL),
constant_evaluator_(this),
type_translator_(this, /* finalize= */ true),
current_script_id_(-1),
record_for_script_id_(-1),
record_token_positions_into_(NULL),
record_yield_positions_into_(NULL),
direct_call_metadata_helper_(this),
inferred_type_metadata_helper_(this),
procedure_attributes_metadata_helper_(this),
metadata_scanned_(false) {}
virtual ~StreamingFlowGraphBuilder() {}
FlowGraph* BuildGraph(intptr_t kernel_offset);
void ReportUnexpectedTag(const char* variant, Tag tag) override;
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,
intptr_t kernel_offset,
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);
RawTypedData* GetLineStartsFor(intptr_t index);
// If a 'ParsedFunction' is provided for 'set_forwarding_stub', this method
// will attach the forwarding stub target reference to the parsed function if
// it crosses a procedure node for a concrete forwarding stub.
void ReadUntilFunctionNode(ParsedFunction* set_forwarding_stub = NULL);
enum DispatchCategory { Interface, ViaThis, Closure, DynamicDispatch };
private:
void LoadAndSetupTypeParameters(ActiveClass* active_class,
const Object& set_on,
intptr_t type_parameter_count,
const Function& parameterized_function);
void DiscoverEnclosingElements(Zone* zone,
const Function& function,
Function* outermost_function);
StringIndex GetNameFromVariableDeclaration(intptr_t kernel_offset,
const Function& function);
bool optimizing();
FlowGraph* BuildGraphOfFieldInitializer();
FlowGraph* BuildGraphOfFieldAccessor(LocalVariable* setter_value);
void SetupDefaultParameterValues();
Fragment BuildFieldInitializer(NameIndex canonical_name);
Fragment BuildInitializers(const Class& parent_class);
FlowGraph* BuildGraphOfImplicitClosureFunction(const Function& function);
FlowGraph* BuildGraphOfFunction(bool constructor);
FlowGraph* BuildGraphOfNoSuchMethodForwarder(
const Function& function,
bool is_implicit_closure_function,
bool throw_no_such_method_error = false);
intptr_t GetOffsetForSourceInfo(intptr_t index);
Fragment BuildExpression(TokenPosition* position = NULL);
Fragment BuildStatement();
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();
Class& GetSuperOrDie();
Tag PeekArgumentsFirstPositionalTag();
const TypeArguments& PeekArgumentsInstantiatedType(const Class& klass);
intptr_t PeekArgumentsCount();
// See BaseFlowGraphBuilder::MakeTemporary.
LocalVariable* MakeTemporary();
LocalVariable* LookupVariable(intptr_t kernel_offset);
RawFunction* LookupMethodByMember(NameIndex target,
const String& method_name);
Function& FindMatchingFunctionAnyArgs(const Class& klass, const String& name);
Function& FindMatchingFunction(const Class& klass,
const String& name,
int type_args_len,
int argument_count,
const Array& argument_names);
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 CheckNull(TokenPosition position,
LocalVariable* receiver,
const String& function_name);
Fragment StaticCall(TokenPosition position,
const Function& target,
intptr_t argument_count,
ICData::RebindRule rebind_rule);
Fragment StaticCall(TokenPosition position,
const Function& target,
intptr_t argument_count,
const Array& argument_names,
ICData::RebindRule rebind_rule,
const InferredTypeMetadata* result_type = NULL,
intptr_t type_args_len = 0);
Fragment InstanceCall(TokenPosition position,
const String& name,
Token::Kind kind,
intptr_t argument_count,
intptr_t checked_argument_count = 1);
Fragment InstanceCall(TokenPosition position,
const String& name,
Token::Kind kind,
intptr_t type_args_len,
intptr_t argument_count,
const Array& argument_names,
intptr_t checked_argument_count,
const Function& interface_target,
const InferredTypeMetadata* result_type = NULL);
enum TypeChecksToBuild {
kDefaultTypeChecks,
kTypeChecksForNoDynamicInvocationsTearOff
};
Fragment BuildArgumentTypeChecks(TypeChecksToBuild mode = kDefaultTypeChecks);
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 Class& klass,
intptr_t argument_count);
Fragment AllocateObject(const 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 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(TokenPosition position);
Fragment CloneContext(intptr_t num_context_variables);
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,
bool is_synthesized);
Fragment TryCatch(int try_handler_index);
Fragment Drop();
// Drop given number of temps from the stack but preserve top of the stack.
Fragment DropTempsPreserveTop(intptr_t num_temps_to_drop);
Fragment NullConstant();
JoinEntryInstr* BuildJoinEntry();
JoinEntryInstr* BuildJoinEntry(intptr_t try_index);
Fragment Goto(JoinEntryInstr* destination);
Fragment BuildImplicitClosureCreation(const Function& target);
Fragment CheckBoolean();
Fragment CheckAssignableInCheckedMode(const AbstractType& dst_type,
const String& dst_name);
Fragment CheckArgumentType(LocalVariable* variable, const AbstractType& type);
Fragment CheckTypeArgumentBound(const AbstractType& parameter,
const AbstractType& bound,
const String& dst_name);
Fragment CheckVariableTypeInCheckedMode(intptr_t variable_kernel_position);
Fragment CheckVariableTypeInCheckedMode(const AbstractType& dst_type,
const String& name_symbol);
Fragment EnterScope(intptr_t kernel_offset,
intptr_t* num_context_variables = NULL);
Fragment ExitScope(intptr_t kernel_offset);
Fragment TranslateCondition(bool* negate);
const TypeArguments& BuildTypeArguments();
Fragment BuildArguments(Array* argument_names,
intptr_t* argument_count,
intptr_t* positional_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 BuildAllocateInvocationMirrorCall(TokenPosition position,
const String& name,
intptr_t num_type_arguments,
intptr_t num_arguments,
const Array& argument_names,
LocalVariable* actuals_array,
Fragment build_rest_of_actuals);
Fragment BuildSuperPropertyGet(TokenPosition* position);
Fragment BuildSuperPropertySet(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 BuildSuperMethodInvocation(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 BuildFutureNullValue(TokenPosition* position);
Fragment BuildConstantExpression(TokenPosition* position);
Fragment BuildPartialTearoffInstantiation(TokenPosition* position);
Fragment BuildExpressionStatement();
Fragment BuildBlock();
Fragment BuildEmptyStatement();
Fragment BuildAssertBlock();
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(ActiveClass* active_class,
const Class& klass,
const Function& function,
bool is_method,
bool is_closure,
FunctionNodeHelper* function_node_helper);
void set_current_script_id(intptr_t id) override { current_script_id_ = id; }
void RecordTokenPosition(TokenPosition position) override;
void RecordYieldPosition(TokenPosition position) override;
// Scan through metadata mappings section and cache offsets for recognized
// metadata kinds.
void EnsureMetadataIsScanned();
FlowGraphBuilder* flow_graph_builder_;
StreamingConstantEvaluator constant_evaluator_;
StreamingDartTypeTranslator type_translator_;
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_;
DirectCallMetadataHelper direct_call_metadata_helper_;
InferredTypeMetadataHelper inferred_type_metadata_helper_;
ProcedureAttributesMetadataHelper procedure_attributes_metadata_helper_;
bool metadata_scanned_;
friend class ClassHelper;
friend class ConstantHelper;
friend class ConstructorHelper;
friend class DirectCallMetadataHelper;
friend class ProcedureAttributesMetadataHelper;
friend class FieldHelper;
friend class FunctionNodeHelper;
friend class InferredTypeMetadataHelper;
friend class KernelLoader;
friend class KernelReaderHelper;
friend class LibraryDependencyHelper;
friend class LibraryHelper;
friend class MetadataHelper;
friend class ProcedureHelper;
friend class SimpleExpressionConverter;
friend class StreamingConstantEvaluator;
friend class StreamingDartTypeTranslator;
friend class StreamingScopeBuilder;
friend class VariableDeclarationHelper;
friend class TypeParameterHelper;
};
class AlternativeScriptScope {
public:
AlternativeScriptScope(TranslationHelper* helper,
const Script& new_script,
const Script& old_script)
: helper_(helper), old_script_(old_script) {
helper_->Reset();
helper_->InitFromScript(new_script);
}
~AlternativeScriptScope() {
helper_->Reset();
helper_->InitFromScript(old_script_);
}
TranslationHelper* helper_;
const Script& old_script_;
};
// 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 Constant from binary.
class ConstantHelper {
public:
ConstantHelper(ActiveClass* active_class,
StreamingFlowGraphBuilder* builder,
StreamingDartTypeTranslator* type_translator,
TranslationHelper* translation_helper,
Zone* zone,
NameIndex skip_vmservice_library)
: skip_vmservice_library_(skip_vmservice_library),
active_class_(active_class),
builder_(*builder),
type_translator_(*type_translator),
const_evaluator_(&builder_),
translation_helper_(*translation_helper),
zone_(zone),
temp_type_(AbstractType::Handle(zone)),
temp_type_arguments_(TypeArguments::Handle(zone)),
temp_type_arguments2_(TypeArguments::Handle(zone)),
temp_type_arguments3_(TypeArguments::Handle(zone)),
temp_object_(Object::Handle(zone)),
temp_array_(Array::Handle(zone)),
temp_instance_(Instance::Handle(zone)),
temp_field_(Field::Handle(zone)),
temp_class_(Class::Handle(zone)),
temp_function_(Function::Handle(zone)),
temp_closure_(Closure::Handle(zone)),
temp_context_(Context::Handle(zone)),
temp_integer_(Integer::Handle(zone)) {}
// Reads the constant table from the binary.
//
// This method assumes the Reader is positioned already at the constant table
// and an active class scope is setup.
const Array& ReadConstantTable();
private:
void InstantiateTypeArguments(const Class& receiver_class,
TypeArguments* type_arguments);
// If [index] has `dart:vm_service` as a parent and we are skipping the VM
// service library, this method returns `true`, otherwise `false`.
bool ShouldSkipConstant(NameIndex index);
NameIndex skip_vmservice_library_;
ActiveClass* active_class_;
StreamingFlowGraphBuilder& builder_;
StreamingDartTypeTranslator& type_translator_;
StreamingConstantEvaluator const_evaluator_;
TranslationHelper translation_helper_;
Zone* zone_;
AbstractType& temp_type_;
TypeArguments& temp_type_arguments_;
TypeArguments& temp_type_arguments2_;
TypeArguments& temp_type_arguments3_;
Object& temp_object_;
Array& temp_array_;
Instance& temp_instance_;
Field& temp_field_;
Class& temp_class_;
Function& temp_function_;
Closure& temp_closure_;
Context& temp_context_;
Integer& temp_integer_;
};
} // namespace kernel
} // namespace dart
#endif // !defined(DART_PRECOMPILED_RUNTIME)
#endif // RUNTIME_VM_COMPILER_FRONTEND_KERNEL_BINARY_FLOWGRAPH_H_