bc8afad855
TEST=ci Issue: https://github.com/dart-lang/sdk/issues/48378 Change-Id: I089ba4ed5613f30eec29f0db4ac6d5d8fbffd185 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/249980 Reviewed-by: Martin Kustermann <kustermann@google.com> Reviewed-by: Slava Egorov <vegorov@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
462 lines
20 KiB
C++
462 lines
20 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_COMPILER_FRONTEND_KERNEL_BINARY_FLOWGRAPH_H_
|
|
#define RUNTIME_VM_COMPILER_FRONTEND_KERNEL_BINARY_FLOWGRAPH_H_
|
|
|
|
#if defined(DART_PRECOMPILED_RUNTIME)
|
|
#error "AOT runtime should not use compiler sources (including header files)"
|
|
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
|
|
|
#include "vm/compiler/frontend/constant_reader.h"
|
|
#include "vm/compiler/frontend/kernel_to_il.h"
|
|
#include "vm/compiler/frontend/kernel_translation_helper.h"
|
|
#include "vm/compiler/frontend/scope_builder.h"
|
|
#include "vm/kernel.h"
|
|
#include "vm/kernel_binary.h"
|
|
#include "vm/object.h"
|
|
|
|
namespace dart {
|
|
namespace kernel {
|
|
|
|
class StreamingFlowGraphBuilder : public KernelReaderHelper {
|
|
public:
|
|
StreamingFlowGraphBuilder(FlowGraphBuilder* flow_graph_builder,
|
|
const ExternalTypedData& 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),
|
|
active_class_(&flow_graph_builder->active_class_),
|
|
constant_reader_(this, active_class_),
|
|
type_translator_(this,
|
|
&constant_reader_,
|
|
active_class_,
|
|
/* finalize= */ true),
|
|
direct_call_metadata_helper_(this),
|
|
inferred_type_metadata_helper_(this, &constant_reader_),
|
|
procedure_attributes_metadata_helper_(this),
|
|
call_site_attributes_metadata_helper_(this, &type_translator_),
|
|
closure_owner_(Object::Handle(flow_graph_builder->zone_)) {}
|
|
|
|
virtual ~StreamingFlowGraphBuilder() {}
|
|
|
|
FlowGraph* BuildGraph();
|
|
|
|
void ReportUnexpectedTag(const char* variant, Tag tag) override;
|
|
|
|
Fragment BuildStatementAt(intptr_t kernel_offset);
|
|
|
|
intptr_t num_ast_nodes() const { return num_ast_nodes_; }
|
|
|
|
private:
|
|
Thread* thread() const { return flow_graph_builder_->thread_; }
|
|
|
|
void ParseKernelASTFunction();
|
|
void ReadForwardingStubTarget(const Function& function);
|
|
void SetupDefaultParameterValues();
|
|
|
|
FlowGraph* BuildGraphOfFieldInitializer();
|
|
Fragment BuildFieldInitializer(const Field& field,
|
|
bool only_for_side_effects);
|
|
Fragment BuildLateFieldInitializer(const Field& field, bool has_initializer);
|
|
Fragment BuildInitializers(const Class& parent_class);
|
|
FlowGraph* BuildGraphOfFunction(bool constructor);
|
|
|
|
Fragment BuildExpression(TokenPosition* position = nullptr,
|
|
bool allow_late_uninitialized = false);
|
|
Fragment BuildStatement(TokenPosition* position = nullptr);
|
|
Fragment BuildStatementWithBranchCoverage(TokenPosition* position = nullptr);
|
|
|
|
// Kernel offset:
|
|
// start of function expression -> end of function body statement
|
|
Fragment BuildFunctionBody(const Function& dart_function,
|
|
LocalVariable* first_parameter,
|
|
bool constructor);
|
|
|
|
// Pieces of the prologue. They are all agnostic to the current Kernel offset.
|
|
Fragment BuildEveryTimePrologue(const Function& dart_function,
|
|
TokenPosition token_position,
|
|
intptr_t type_parameters_offset);
|
|
Fragment BuildFirstTimePrologue(const Function& dart_function,
|
|
LocalVariable* first_parameter,
|
|
intptr_t type_parameters_offset);
|
|
Fragment ClearRawParameters(const Function& dart_function);
|
|
Fragment DebugStepCheckInPrologue(const Function& dart_function,
|
|
TokenPosition position);
|
|
Fragment SetAsyncStackTrace(const Function& dart_function);
|
|
Fragment CheckStackOverflowInPrologue(const Function& dart_function);
|
|
Fragment SetupCapturedParameters(const Function& dart_function);
|
|
Fragment InitSuspendableFunction(const Function& dart_function);
|
|
Fragment ShortcutForUserDefinedEquals(const Function& dart_function,
|
|
LocalVariable* first_parameter);
|
|
Fragment TypeArgumentsHandling(const Function& dart_function);
|
|
|
|
static UncheckedEntryPointStyle ChooseEntryPointStyle(
|
|
const Function& dart_function,
|
|
const Fragment& implicit_type_checks,
|
|
const Fragment& first_time_prologue,
|
|
const Fragment& every_time_prologue,
|
|
const Fragment& type_args_handling);
|
|
|
|
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 block_expression_depth();
|
|
void block_expression_depth_inc();
|
|
void block_expression_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();
|
|
Value* stack();
|
|
void set_stack(Value* top);
|
|
void Push(Definition* definition);
|
|
Value* Pop();
|
|
Class& GetSuperOrDie();
|
|
|
|
Tag PeekArgumentsFirstPositionalTag();
|
|
const TypeArguments& PeekArgumentsInstantiatedType(const Class& klass);
|
|
intptr_t PeekArgumentsCount();
|
|
|
|
// See BaseFlowGraphBuilder::MakeTemporary.
|
|
LocalVariable* MakeTemporary(const char* suffix = nullptr);
|
|
Fragment DropTemporary(LocalVariable** variable);
|
|
|
|
LocalVariable* LookupVariable(intptr_t kernel_offset);
|
|
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 IndirectGoto(intptr_t target_count);
|
|
Fragment Return(
|
|
TokenPosition position,
|
|
intptr_t yield_index = UntaggedPcDescriptors::kInvalidYieldIndex);
|
|
Fragment EvaluateAssertion();
|
|
Fragment RethrowException(TokenPosition position, int catch_try_index);
|
|
Fragment ThrowNoSuchMethodError(const Function& target,
|
|
bool incompatible_arguments);
|
|
Fragment Constant(const Object& value);
|
|
Fragment IntConstant(int64_t value);
|
|
Fragment LoadStaticField(const Field& field, bool calls_initializer);
|
|
Fragment RedefinitionWithType(const AbstractType& type);
|
|
Fragment CheckNull(TokenPosition position,
|
|
LocalVariable* receiver,
|
|
const String& function_name,
|
|
bool clear_the_temp = true);
|
|
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 = nullptr,
|
|
intptr_t type_args_len = 0,
|
|
bool use_unchecked_entry = false);
|
|
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 Function& tearoff_interface_target,
|
|
const InferredTypeMetadata* result_type = nullptr,
|
|
bool use_unchecked_entry = false,
|
|
const CallSiteAttributesMetadata* call_site_attrs = nullptr,
|
|
bool receiver_is_not_smi = false,
|
|
bool is_call_on_this = false);
|
|
|
|
Fragment ThrowException(TokenPosition position);
|
|
Fragment BooleanNegate();
|
|
Fragment TranslateInstantiatedTypeArguments(
|
|
const TypeArguments& type_arguments);
|
|
Fragment StrictCompare(TokenPosition position,
|
|
Token::Kind kind,
|
|
bool number_check = false);
|
|
Fragment AllocateObject(TokenPosition position,
|
|
const Class& klass,
|
|
intptr_t argument_count);
|
|
Fragment AllocateContext(const ZoneGrowableArray<const Slot*>& context_slots);
|
|
Fragment LoadNativeField(const Slot& field);
|
|
Fragment StoreLocal(TokenPosition position, LocalVariable* variable);
|
|
Fragment StoreStaticField(TokenPosition position, const Field& field);
|
|
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(const ZoneGrowableArray<const Slot*>& context_slots);
|
|
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 MakeTemp();
|
|
Fragment NullConstant();
|
|
JoinEntryInstr* BuildJoinEntry();
|
|
JoinEntryInstr* BuildJoinEntry(intptr_t try_index);
|
|
Fragment Goto(JoinEntryInstr* destination);
|
|
Fragment BuildImplicitClosureCreation(const Function& target);
|
|
Fragment CheckBoolean(TokenPosition position);
|
|
Fragment CheckArgumentType(LocalVariable* variable, const AbstractType& type);
|
|
Fragment RecordCoverage(TokenPosition position);
|
|
Fragment EnterScope(intptr_t kernel_offset,
|
|
const LocalScope** scope = nullptr);
|
|
Fragment ExitScope(intptr_t kernel_offset);
|
|
|
|
TestFragment TranslateConditionForControl();
|
|
|
|
const TypeArguments& BuildTypeArguments();
|
|
Fragment BuildArguments(Array* argument_names,
|
|
intptr_t* argument_count,
|
|
intptr_t* positional_argument_count);
|
|
Fragment BuildArgumentsFromActualArguments(Array* argument_names);
|
|
|
|
Fragment BuildInvalidExpression(TokenPosition* position);
|
|
Fragment BuildVariableGet(TokenPosition* position,
|
|
bool allow_late_uninitialized = false);
|
|
Fragment BuildVariableGet(uint8_t payload,
|
|
TokenPosition* position,
|
|
bool allow_late_uninitialized = false);
|
|
Fragment BuildVariableGetImpl(intptr_t variable_kernel_position,
|
|
TokenPosition position,
|
|
bool allow_late_uninitialized = false);
|
|
Fragment BuildVariableSet(TokenPosition* position);
|
|
Fragment BuildVariableSet(uint8_t payload, TokenPosition* position);
|
|
Fragment BuildVariableSetImpl(TokenPosition position,
|
|
intptr_t variable_kernel_position);
|
|
Fragment BuildInstanceGet(TokenPosition* position);
|
|
Fragment BuildDynamicGet(TokenPosition* position);
|
|
Fragment BuildInstanceTearOff(TokenPosition* position);
|
|
Fragment BuildFunctionTearOff(TokenPosition* position);
|
|
Fragment BuildInstanceSet(TokenPosition* position);
|
|
Fragment BuildDynamicSet(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 BuildStaticGet(TokenPosition* position);
|
|
Fragment BuildStaticSet(TokenPosition* position);
|
|
Fragment BuildMethodInvocation(TokenPosition* position, bool is_dynamic);
|
|
Fragment BuildLocalFunctionInvocation(TokenPosition* position);
|
|
Fragment BuildFunctionInvocation(TokenPosition* position);
|
|
Fragment BuildEqualsCall(TokenPosition* position);
|
|
Fragment BuildEqualsNull(TokenPosition* position);
|
|
Fragment BuildSuperMethodInvocation(TokenPosition* position);
|
|
Fragment BuildStaticInvocation(TokenPosition* position);
|
|
Fragment BuildConstructorInvocation(TokenPosition* position);
|
|
Fragment BuildNot(TokenPosition* position);
|
|
Fragment BuildNullCheck(TokenPosition* position);
|
|
Fragment BuildLogicalExpression(TokenPosition* position);
|
|
Fragment TranslateLogicalExpressionForValue(bool negated,
|
|
TestFragment* side_exits);
|
|
Fragment BuildConditionalExpression(TokenPosition* position);
|
|
Fragment BuildStringConcatenation(TokenPosition* position);
|
|
Fragment BuildIsExpression(TokenPosition* position);
|
|
Fragment BuildAsExpression(TokenPosition* position);
|
|
Fragment BuildTypeLiteral(TokenPosition* position);
|
|
Fragment BuildThisExpression(TokenPosition* position);
|
|
Fragment BuildRethrow(TokenPosition* position);
|
|
Fragment BuildThrow(TokenPosition* position);
|
|
Fragment BuildListLiteral(TokenPosition* position);
|
|
Fragment BuildMapLiteral(TokenPosition* position);
|
|
Fragment BuildFunctionExpression();
|
|
Fragment BuildLet(TokenPosition* position);
|
|
Fragment BuildBlockExpression();
|
|
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, Tag tag);
|
|
Fragment BuildPartialTearoffInstantiation(TokenPosition* position);
|
|
Fragment BuildLibraryPrefixAction(TokenPosition* position,
|
|
const String& selector);
|
|
Fragment BuildAwaitExpression(TokenPosition* position);
|
|
|
|
Fragment BuildExpressionStatement(TokenPosition* position);
|
|
Fragment BuildBlock(TokenPosition* position);
|
|
Fragment BuildEmptyStatement();
|
|
Fragment BuildAssertBlock(TokenPosition* position);
|
|
Fragment BuildAssertStatement(TokenPosition* position);
|
|
Fragment BuildLabeledStatement(TokenPosition* position);
|
|
Fragment BuildBreakStatement(TokenPosition* position);
|
|
Fragment BuildWhileStatement(TokenPosition* position);
|
|
Fragment BuildDoStatement(TokenPosition* position);
|
|
Fragment BuildForStatement(TokenPosition* position);
|
|
Fragment BuildForInStatement(bool async, TokenPosition* position);
|
|
Fragment BuildSwitchStatement(TokenPosition* position);
|
|
Fragment BuildContinueSwitchStatement(TokenPosition* position);
|
|
Fragment BuildIfStatement(TokenPosition* position);
|
|
Fragment BuildReturnStatement(TokenPosition* position);
|
|
Fragment BuildTryCatch(TokenPosition* position);
|
|
Fragment BuildTryFinally(TokenPosition* position);
|
|
Fragment BuildYieldStatement(TokenPosition* position);
|
|
Fragment BuildVariableDeclaration(TokenPosition* position);
|
|
Fragment BuildFunctionDeclaration(intptr_t offset, TokenPosition* position);
|
|
Fragment BuildFunctionNode(TokenPosition parent_position,
|
|
StringIndex name_index,
|
|
bool has_valid_annotation,
|
|
bool has_pragma,
|
|
intptr_t func_decl_offset);
|
|
|
|
// Build flow graph for '_nativeEffect'.
|
|
Fragment BuildNativeEffect();
|
|
|
|
// Build the call-site manually, to avoid doing initialization checks
|
|
// for late fields.
|
|
Fragment BuildReachabilityFence();
|
|
|
|
// Build flow graph for '_loadAbiSpecificInt' and
|
|
// '_loadAbiSpecificIntAtIndex', '_storeAbiSpecificInt', and
|
|
// '_storeAbiSpecificIntAtIndex' call sites.
|
|
//
|
|
// The second argument is either offsetInBytes (at_index==false), or
|
|
// index (at_index==true).
|
|
Fragment BuildLoadAbiSpecificInt(bool at_index);
|
|
Fragment BuildStoreAbiSpecificInt(bool at_index);
|
|
|
|
// Build FG for '_asFunctionInternal'. Reads an Arguments from the
|
|
// Kernel buffer and pushes the resulting closure.
|
|
Fragment BuildFfiAsFunctionInternal();
|
|
|
|
// Build FG for '_nativeCallbackFunction'. Reads an Arguments from the
|
|
// Kernel buffer and pushes the resulting Function object.
|
|
Fragment BuildFfiNativeCallbackFunction();
|
|
|
|
// Piece of a StringConcatenation.
|
|
// Represents either a StringLiteral, or a Reader offset to the expression.
|
|
struct ConcatPiece {
|
|
intptr_t offset;
|
|
const String* literal;
|
|
};
|
|
|
|
// Collector that automatically concatenates adjacent string ConcatPieces.
|
|
struct PiecesCollector {
|
|
explicit PiecesCollector(Zone* z, TranslationHelper* translation_helper)
|
|
: pieces(5),
|
|
literal_run(z, 1),
|
|
translation_helper(translation_helper) {}
|
|
|
|
GrowableArray<ConcatPiece> pieces;
|
|
GrowableHandlePtrArray<const String> literal_run;
|
|
TranslationHelper* translation_helper;
|
|
|
|
void Add(const ConcatPiece& piece) {
|
|
if (piece.literal != nullptr) {
|
|
literal_run.Add(*piece.literal);
|
|
} else {
|
|
FlushRun();
|
|
pieces.Add(piece);
|
|
}
|
|
}
|
|
|
|
void FlushRun() {
|
|
switch (literal_run.length()) {
|
|
case 0:
|
|
return;
|
|
case 1:
|
|
pieces.Add({-1, &literal_run[0]});
|
|
break;
|
|
default:
|
|
pieces.Add({-1, &translation_helper->DartString(literal_run)});
|
|
}
|
|
literal_run.Clear();
|
|
}
|
|
};
|
|
|
|
// Flattens and collects pieces of StringConcatenations such that:
|
|
// ["a", "", "b"] => ["ab"]
|
|
// ["a", StringConcat("b", "c")] => ["abc"]
|
|
// ["a", "", StringConcat("b", my_var), "c"] => ["ab", my_var, "c"]
|
|
void FlattenStringConcatenation(PiecesCollector* collector);
|
|
|
|
FlowGraphBuilder* flow_graph_builder_;
|
|
ActiveClass* const active_class_;
|
|
ConstantReader constant_reader_;
|
|
TypeTranslator type_translator_;
|
|
DirectCallMetadataHelper direct_call_metadata_helper_;
|
|
InferredTypeMetadataHelper inferred_type_metadata_helper_;
|
|
ProcedureAttributesMetadataHelper procedure_attributes_metadata_helper_;
|
|
CallSiteAttributesMetadataHelper call_site_attributes_metadata_helper_;
|
|
Object& closure_owner_;
|
|
intptr_t num_ast_nodes_ = 0;
|
|
|
|
friend class KernelLoader;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(StreamingFlowGraphBuilder);
|
|
};
|
|
|
|
} // namespace kernel
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_VM_COMPILER_FRONTEND_KERNEL_BINARY_FLOWGRAPH_H_
|