Files
sdk/runtime/vm/compiler/call_specializer.h
T
Stevie Strickland 23f427b1a7 Reland [VM/Compiler] Removing definition status from Store{Indexed,InstanceField}.
Also do the same for the unsafe version of StoreIndexed.

Similar to the inliner, we may replace calls in the specializers with
these non-definition instructions, so we make variants that allow an
unrelated value to be used for the old users of the call site value. (In
all cases, this ends up being null, since the original calls wouldn't
have returned a useable value anyway.)

Change-Id: I0befd54920c4c0e63e086b804860ee4c9a7d3767
Reviewed-on: https://dart-review.googlesource.com/c/89585
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Stevie Strickland <sstrickl@google.com>
2019-01-15 17:23:21 +00:00

184 lines
7.2 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_CALL_SPECIALIZER_H_
#define RUNTIME_VM_COMPILER_CALL_SPECIALIZER_H_
#include "vm/compiler/backend/flow_graph.h"
#include "vm/compiler/backend/il.h"
namespace dart {
class SpeculativeInliningPolicy;
// Call specialization pass is responsible for replacing instance calls by
// faster alternatives based on type feedback (JIT), type speculations (AOT),
// locally propagated type information or global type information.
//
// This pass for example can
//
// * Replace a call to a binary arithmetic operator with corresponding IL
// instructions and necessary checks;
// * Replace a dynamic call with a static call, if reciever is known
// to have a certain class id;
// * Replace type check with a range check
//
// CallSpecializer is a base class that contains logic shared between
// JIT and AOT compilation pipelines, see JitCallSpecializer for JIT specific
// optimizations and AotCallSpecializer for AOT specific optimizations.
class CallSpecializer : public FlowGraphVisitor {
public:
CallSpecializer(FlowGraph* flow_graph,
SpeculativeInliningPolicy* speculative_policy,
bool should_clone_fields)
: FlowGraphVisitor(flow_graph->reverse_postorder()),
speculative_policy_(speculative_policy),
should_clone_fields_(should_clone_fields),
flow_graph_(flow_graph) {}
virtual ~CallSpecializer() {}
FlowGraph* flow_graph() const { return flow_graph_; }
// Use ICData to optimize, replace or eliminate instructions.
void ApplyICData();
// Use propagated class ids to optimize, replace or eliminate instructions.
void ApplyClassIds();
void InsertBefore(Instruction* next,
Instruction* instr,
Environment* env,
FlowGraph::UseKind use_kind) {
flow_graph_->InsertBefore(next, instr, env, use_kind);
}
virtual void VisitStaticCall(StaticCallInstr* instr);
// TODO(dartbug.com/30633) these methods have nothing to do with
// specialization of calls. They are here for historical reasons.
// Find a better place for them.
virtual void VisitLoadCodeUnits(LoadCodeUnitsInstr* instr);
protected:
Thread* thread() const { return flow_graph_->thread(); }
Isolate* isolate() const { return flow_graph_->isolate(); }
Zone* zone() const { return flow_graph_->zone(); }
const Function& function() const { return flow_graph_->function(); }
bool TryReplaceWithIndexedOp(InstanceCallInstr* call,
const ICData* unary_checks);
bool TryReplaceWithBinaryOp(InstanceCallInstr* call, Token::Kind op_kind);
bool TryReplaceWithUnaryOp(InstanceCallInstr* call, Token::Kind op_kind);
bool TryReplaceWithEqualityOp(InstanceCallInstr* call, Token::Kind op_kind);
bool TryReplaceWithRelationalOp(InstanceCallInstr* call, Token::Kind op_kind);
bool TryInlineInstanceGetter(InstanceCallInstr* call);
bool TryInlineInstanceSetter(InstanceCallInstr* call,
const ICData& unary_ic_data);
bool TryInlineInstanceMethod(InstanceCallInstr* call);
void ReplaceWithInstanceOf(InstanceCallInstr* instr);
// Replaces a call where the replacement code does not end in a
// value-returning instruction, so we must specify what definition should be
// used instead to replace uses of the call return value.
void ReplaceCallWithResult(Definition* call,
Instruction* replacement,
Definition* result);
void ReplaceCall(Definition* call, Definition* replacement);
// Add a class check for the call's first argument (receiver).
void AddReceiverCheck(InstanceCallInstr* call) {
AddChecksForArgNr(call, call->Receiver()->definition(),
/* argument_number = */ 0);
}
// Insert a null check if needed.
void AddCheckNull(Value* to_check,
const String& function_name,
intptr_t deopt_id,
Environment* deopt_environment,
Instruction* insert_before);
// Attempt to build ICData for call using propagated class-ids.
virtual bool TryCreateICData(InstanceCallInstr* call);
static bool HasOnlyTwoOf(const ICData& ic_data, intptr_t cid);
virtual bool TryReplaceInstanceOfWithRangeCheck(InstanceCallInstr* call,
const AbstractType& type);
virtual bool TryOptimizeStaticCallUsingStaticTypes(StaticCallInstr* call) = 0;
protected:
void InlineImplicitInstanceGetter(Definition* call, const Field& field);
SpeculativeInliningPolicy* speculative_policy_;
const bool should_clone_fields_;
private:
bool TypeCheckAsClassEquality(const AbstractType& type);
// Insert a check of 'to_check' determined by 'unary_checks'. If the
// check fails it will deoptimize to 'deopt_id' using the deoptimization
// environment 'deopt_environment'. The check is inserted immediately
// before 'insert_before'.
void AddCheckClass(Definition* to_check,
const Cids& cids,
intptr_t deopt_id,
Environment* deopt_environment,
Instruction* insert_before);
// Insert a Smi check if needed.
void AddCheckSmi(Definition* to_check,
intptr_t deopt_id,
Environment* deopt_environment,
Instruction* insert_before);
// Add a class check for a call's nth argument immediately before the
// call, using the call's IC data to determine the check, and the call's
// deopt ID and deoptimization environment if the check fails.
void AddChecksForArgNr(InstanceCallInstr* call,
Definition* instr,
int argument_number);
bool InlineSimdBinaryOp(InstanceCallInstr* call,
intptr_t cid,
Token::Kind op_kind);
bool TryInlineImplicitInstanceGetter(InstanceCallInstr* call);
RawBool* InstanceOfAsBool(const ICData& ic_data,
const AbstractType& type,
ZoneGrowableArray<intptr_t>* results) const;
bool TryOptimizeInstanceOfUsingStaticTypes(InstanceCallInstr* call,
const AbstractType& type);
void ReplaceWithMathCFunction(InstanceCallInstr* call,
MethodRecognizer::Kind recognized_kind);
bool TryStringLengthOneEquality(InstanceCallInstr* call, Token::Kind op_kind);
RawField* GetField(intptr_t class_id, const String& field_name);
void SpecializePolymorphicInstanceCall(PolymorphicInstanceCallInstr* call);
// Tries to add cid tests to 'results' so that no deoptimization is
// necessary for common number-related type tests. Unconditionally adds an
// entry for the Smi type to the start of the array.
static bool SpecializeTestCidsForNumericTypes(
ZoneGrowableArray<intptr_t>* results,
const AbstractType& type);
FlowGraph* flow_graph_;
};
} // namespace dart
#endif // RUNTIME_VM_COMPILER_CALL_SPECIALIZER_H_