Files
sdk/runtime/vm/compiler/frontend/kernel_binary_flowgraph.h
T
Daco Harkes d3ea8bff5c [vm/ffi] Fix constant Finalizables
The kernel builder relied on only seeing expressions emitted by the
finalizable transform (variable get and this) as arguments to the fence.

However, other transforms can run later. In this case the expression
was turned into a constant.

This CL changes the implementation to accept any expression rather than
accepting a subset of expressions.

TEST=tests/ffi/regress_49402_test.dart

Closes: https://github.com/dart-lang/sdk/issues/49402
Change-Id: I1a962a5b7a38099eb5c3bbf5a5a8145b16727d97
Cq-Include-Trybots: luci.dart.try:vm-kernel-precomp-linux-debug-x64-try
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/250744
Commit-Queue: Daco Harkes <dacoharkes@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
2022-07-07 08:39:21 +00:00

464 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);
Fragment CompleteBodyWithYieldContinuations(Fragment body);
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();
GrowableArray<YieldContinuation>& yield_continuations();
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_