[vm/compiler] Remove speculative inlining from AOT
TEST=ci Change-Id: I43817742de295dbbd8c3166d88cecb89b5dfbcf7 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/398581 Reviewed-by: Slava Egorov <vegorov@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
committed by
Commit Queue
parent
09571ad48b
commit
21db850e54
@@ -62,12 +62,9 @@ static void GetUniqueDynamicTarget(IsolateGroup* isolate_group,
|
||||
isolate_group->object_store()->unique_dynamic_targets());
|
||||
}
|
||||
|
||||
AotCallSpecializer::AotCallSpecializer(
|
||||
Precompiler* precompiler,
|
||||
FlowGraph* flow_graph,
|
||||
SpeculativeInliningPolicy* speculative_policy)
|
||||
AotCallSpecializer::AotCallSpecializer(Precompiler* precompiler,
|
||||
FlowGraph* flow_graph)
|
||||
: CallSpecializer(flow_graph,
|
||||
speculative_policy,
|
||||
/* should_clone_fields=*/false),
|
||||
precompiler_(precompiler),
|
||||
has_unique_no_such_method_(false) {
|
||||
|
||||
@@ -14,13 +14,10 @@
|
||||
namespace dart {
|
||||
|
||||
class Precompiler;
|
||||
class SpeculativeInliningPolicy;
|
||||
|
||||
class AotCallSpecializer : public CallSpecializer {
|
||||
public:
|
||||
AotCallSpecializer(Precompiler* precompiler,
|
||||
FlowGraph* flow_graph,
|
||||
SpeculativeInliningPolicy* speculative_policy);
|
||||
AotCallSpecializer(Precompiler* precompiler, FlowGraph* flow_graph);
|
||||
|
||||
virtual ~AotCallSpecializer() {}
|
||||
|
||||
|
||||
@@ -76,11 +76,6 @@ DEFINE_FLAG(charp,
|
||||
nullptr,
|
||||
"Print layout of Dart objects to the given file");
|
||||
DEFINE_FLAG(bool, trace_precompiler, false, "Trace precompiler.");
|
||||
DEFINE_FLAG(
|
||||
int,
|
||||
max_speculative_inlining_attempts,
|
||||
1,
|
||||
"Max number of attempts with speculative inlining (precompilation only)");
|
||||
DEFINE_FLAG(charp,
|
||||
write_retained_reasons_to,
|
||||
nullptr,
|
||||
@@ -3502,8 +3497,6 @@ bool PrecompileParsedFunctionHelper::Compile() {
|
||||
bool done = false;
|
||||
// volatile because the variable may be clobbered by a longjmp.
|
||||
volatile intptr_t far_branch_level = 0;
|
||||
SpeculativeInliningPolicy speculative_policy(
|
||||
true, FLAG_max_speculative_inlining_attempts);
|
||||
|
||||
while (!done) {
|
||||
LongJumpScope jump;
|
||||
@@ -3544,14 +3537,12 @@ bool PrecompileParsedFunctionHelper::Compile() {
|
||||
FlowGraphPrinter::PrintGraph("Unoptimized Compilation", flow_graph);
|
||||
}
|
||||
|
||||
CompilerPassState pass_state(thread(), flow_graph, &speculative_policy,
|
||||
precompiler_);
|
||||
CompilerPassState pass_state(thread(), flow_graph, precompiler_);
|
||||
|
||||
if (optimized()) {
|
||||
TIMELINE_DURATION(thread(), CompilerVerbose, "OptimizationPasses");
|
||||
|
||||
AotCallSpecializer call_specializer(precompiler_, flow_graph,
|
||||
&speculative_policy);
|
||||
AotCallSpecializer call_specializer(precompiler_, flow_graph);
|
||||
pass_state.call_specializer = &call_specializer;
|
||||
|
||||
flow_graph = CompilerPass::RunPipeline(CompilerPass::kAOT, &pass_state);
|
||||
@@ -3597,9 +3588,8 @@ bool PrecompileParsedFunctionHelper::Compile() {
|
||||
|
||||
FlowGraphCompiler graph_compiler(
|
||||
&assembler, flow_graph, *parsed_function(), optimized(),
|
||||
&speculative_policy, pass_state.inline_id_to_function,
|
||||
pass_state.inline_id_to_token_pos, pass_state.caller_inline_id,
|
||||
ic_data_array, function_stats);
|
||||
pass_state.inline_id_to_function, pass_state.inline_id_to_token_pos,
|
||||
pass_state.caller_inline_id, ic_data_array, function_stats);
|
||||
pass_state.graph_compiler = &graph_compiler;
|
||||
CompilerPass::GenerateCode(&pass_state);
|
||||
{
|
||||
@@ -3660,20 +3650,6 @@ bool PrecompileParsedFunctionHelper::Compile() {
|
||||
done = false;
|
||||
RELEASE_ASSERT(far_branch_level < 2);
|
||||
far_branch_level = far_branch_level + 1;
|
||||
} else if (error.ptr() == Object::speculative_inlining_error().ptr()) {
|
||||
// The return value of setjmp is the deopt id of the check instruction
|
||||
// that caused the bailout.
|
||||
done = false;
|
||||
if (!speculative_policy.AllowsSpeculativeInlining()) {
|
||||
// Assert that we don't repeatedly retry speculation.
|
||||
UNREACHABLE();
|
||||
}
|
||||
if (!speculative_policy.AddBlockedDeoptId(val)) {
|
||||
if (FLAG_trace_compiler || FLAG_trace_optimizing_compiler) {
|
||||
THR_Print("Disabled speculative inlining after %" Pd " attempts.\n",
|
||||
speculative_policy.length());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the error isn't due to an out of range branch offset, we don't
|
||||
// try again (done = true), and indicate that we did not finish
|
||||
|
||||
@@ -137,7 +137,6 @@ FlowGraphCompiler::FlowGraphCompiler(
|
||||
FlowGraph* flow_graph,
|
||||
const ParsedFunction& parsed_function,
|
||||
bool is_optimizing,
|
||||
SpeculativeInliningPolicy* speculative_policy,
|
||||
const GrowableArray<const Function*>& inline_id_to_function,
|
||||
const GrowableArray<TokenPosition>& inline_id_to_token_pos,
|
||||
const GrowableArray<intptr_t>& caller_inline_id,
|
||||
@@ -160,7 +159,6 @@ FlowGraphCompiler::FlowGraphCompiler(
|
||||
static_calls_target_table_(),
|
||||
indirect_gotos_(),
|
||||
is_optimizing_(is_optimizing),
|
||||
speculative_policy_(speculative_policy),
|
||||
may_reoptimize_(false),
|
||||
intrinsic_mode_(false),
|
||||
stats_(stats),
|
||||
@@ -1248,15 +1246,9 @@ compiler::Label* FlowGraphCompiler::AddDeoptStub(intptr_t deopt_id,
|
||||
|
||||
// No deoptimization allowed when 'FLAG_precompiled_mode' is set.
|
||||
if (FLAG_precompiled_mode) {
|
||||
if (FLAG_trace_compiler) {
|
||||
THR_Print(
|
||||
"Retrying compilation %s, suppressing inlining of deopt_id:%" Pd "\n",
|
||||
FATAL("Speculative instructions are not allowed in AOT: %s, deopt_id %" Pd
|
||||
"\n",
|
||||
parsed_function_.function().ToFullyQualifiedCString(), deopt_id);
|
||||
}
|
||||
ASSERT(speculative_policy_->AllowsSpeculativeInlining());
|
||||
ASSERT(deopt_id != 0); // longjmp must return non-zero value.
|
||||
Thread::Current()->long_jump_base()->Jump(
|
||||
deopt_id, Object::speculative_inlining_error());
|
||||
}
|
||||
|
||||
ASSERT(is_optimizing_);
|
||||
|
||||
@@ -33,7 +33,6 @@ class Function;
|
||||
template <typename T>
|
||||
class GrowableArray;
|
||||
class ParsedFunction;
|
||||
class SpeculativeInliningPolicy;
|
||||
|
||||
namespace compiler {
|
||||
struct TableSelector;
|
||||
@@ -381,7 +380,6 @@ class FlowGraphCompiler : public ValueObject {
|
||||
FlowGraph* flow_graph,
|
||||
const ParsedFunction& parsed_function,
|
||||
bool is_optimizing,
|
||||
SpeculativeInliningPolicy* speculative_policy,
|
||||
const GrowableArray<const Function*>& inline_id_to_function,
|
||||
const GrowableArray<TokenPosition>& inline_id_to_token_pos,
|
||||
const GrowableArray<intptr_t>& caller_inline_id,
|
||||
@@ -1212,7 +1210,6 @@ class FlowGraphCompiler : public ValueObject {
|
||||
GrowableArray<const compiler::TableSelector*> dispatch_table_call_targets_;
|
||||
GrowableArray<IndirectGotoInstr*> indirect_gotos_;
|
||||
bool is_optimizing_;
|
||||
SpeculativeInliningPolicy* speculative_policy_;
|
||||
// Set to true if optimized code has IC calls.
|
||||
bool may_reoptimize_;
|
||||
// True while emitting intrinsic code.
|
||||
|
||||
@@ -146,14 +146,12 @@ FlowGraph* TestPipeline::RunPasses(
|
||||
BlockScheduler::AssignEdgeWeights(flow_graph_);
|
||||
}
|
||||
|
||||
pass_state_ =
|
||||
new CompilerPassState(thread, flow_graph_, speculative_policy_.get());
|
||||
pass_state_ = new CompilerPassState(thread, flow_graph_);
|
||||
|
||||
if (optimized) {
|
||||
JitCallSpecializer jit_call_specializer(flow_graph_,
|
||||
speculative_policy_.get());
|
||||
JitCallSpecializer jit_call_specializer(flow_graph_);
|
||||
AotCallSpecializer aot_call_specializer(
|
||||
/*precompiler=*/nullptr, flow_graph_, speculative_policy_.get());
|
||||
/*precompiler=*/nullptr, flow_graph_);
|
||||
if (mode_ == CompilerPass::kAOT) {
|
||||
pass_state_->call_specializer = &aot_call_specializer;
|
||||
} else {
|
||||
@@ -174,10 +172,8 @@ FlowGraph* TestPipeline::RunPasses(
|
||||
|
||||
void TestPipeline::RunAdditionalPasses(
|
||||
std::initializer_list<CompilerPass::Id> passes) {
|
||||
JitCallSpecializer jit_call_specializer(flow_graph_,
|
||||
speculative_policy_.get());
|
||||
AotCallSpecializer aot_call_specializer(/*precompiler=*/nullptr, flow_graph_,
|
||||
speculative_policy_.get());
|
||||
JitCallSpecializer jit_call_specializer(flow_graph_);
|
||||
AotCallSpecializer aot_call_specializer(/*precompiler=*/nullptr, flow_graph_);
|
||||
if (mode_ == CompilerPass::kAOT) {
|
||||
pass_state_->call_specializer = &aot_call_specializer;
|
||||
} else {
|
||||
@@ -216,8 +212,6 @@ void TestPipeline::CompileGraphAndAttachFunction() {
|
||||
Zone* zone = thread_->zone();
|
||||
const bool optimized = true;
|
||||
|
||||
SpeculativeInliningPolicy speculative_policy(/*enable_suppression=*/false);
|
||||
|
||||
#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_IA32)
|
||||
const intptr_t far_branch_level = 0;
|
||||
#else
|
||||
@@ -230,9 +224,8 @@ void TestPipeline::CompileGraphAndAttachFunction() {
|
||||
compiler::Assembler assembler(&object_pool_builder, far_branch_level);
|
||||
FlowGraphCompiler graph_compiler(
|
||||
&assembler, flow_graph_, *parsed_function_, optimized,
|
||||
&speculative_policy, pass_state_->inline_id_to_function,
|
||||
pass_state_->inline_id_to_token_pos, pass_state_->caller_inline_id,
|
||||
ic_data_array_);
|
||||
pass_state_->inline_id_to_function, pass_state_->inline_id_to_token_pos,
|
||||
pass_state_->caller_inline_id, ic_data_array_);
|
||||
|
||||
graph_compiler.CompileGraph();
|
||||
|
||||
|
||||
@@ -81,8 +81,6 @@ class TestPipeline : public ValueObject {
|
||||
is_optimizing,
|
||||
CompilerState::ShouldTrace(function)),
|
||||
hierarchy_info_(thread_),
|
||||
speculative_policy_(std::unique_ptr<SpeculativeInliningPolicy>(
|
||||
new SpeculativeInliningPolicy(/*enable_suppresson=*/false))),
|
||||
mode_(mode),
|
||||
flow_graph_(nullptr),
|
||||
function_(function),
|
||||
@@ -96,8 +94,6 @@ class TestPipeline : public ValueObject {
|
||||
/*is_optimizing=*/true,
|
||||
CompilerTracing::kOff),
|
||||
hierarchy_info_(thread_),
|
||||
speculative_policy_(std::unique_ptr<SpeculativeInliningPolicy>(
|
||||
new SpeculativeInliningPolicy(/*enable_suppresson=*/false))),
|
||||
mode_(mode),
|
||||
flow_graph_(fn()),
|
||||
function_(flow_graph_->function()),
|
||||
@@ -121,7 +117,6 @@ class TestPipeline : public ValueObject {
|
||||
Thread* thread_;
|
||||
CompilerState compiler_state_;
|
||||
HierarchyInfo hierarchy_info_;
|
||||
std::unique_ptr<SpeculativeInliningPolicy> speculative_policy_;
|
||||
CompilerPass::PipelineMode mode_;
|
||||
ZoneGrowableArray<const ICData*>* ic_data_array_ = nullptr;
|
||||
CompilerPassState* pass_state_ = nullptr;
|
||||
|
||||
@@ -1429,22 +1429,18 @@ class CallSiteInliner : public ValueObject {
|
||||
if (CompilerState::Current().is_aot()) {
|
||||
#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
|
||||
AotCallSpecializer call_specializer(inliner_->precompiler_,
|
||||
callee_graph,
|
||||
inliner_->speculative_policy_);
|
||||
callee_graph);
|
||||
|
||||
CompilerPassState state(Thread::Current(), callee_graph,
|
||||
inliner_->speculative_policy_);
|
||||
CompilerPassState state(Thread::Current(), callee_graph);
|
||||
state.call_specializer = &call_specializer;
|
||||
CompilerPass::RunInliningPipeline(CompilerPass::kAOT, &state);
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif // defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
|
||||
} else {
|
||||
JitCallSpecializer call_specializer(callee_graph,
|
||||
inliner_->speculative_policy_);
|
||||
JitCallSpecializer call_specializer(callee_graph);
|
||||
|
||||
CompilerPassState state(Thread::Current(), callee_graph,
|
||||
inliner_->speculative_policy_);
|
||||
CompilerPassState state(Thread::Current(), callee_graph);
|
||||
state.call_specializer = &call_specializer;
|
||||
CompilerPass::RunInliningPipeline(CompilerPass::kJIT, &state);
|
||||
}
|
||||
@@ -2396,14 +2392,12 @@ FlowGraphInliner::FlowGraphInliner(
|
||||
GrowableArray<const Function*>* inline_id_to_function,
|
||||
GrowableArray<TokenPosition>* inline_id_to_token_pos,
|
||||
GrowableArray<intptr_t>* caller_inline_id,
|
||||
SpeculativeInliningPolicy* speculative_policy,
|
||||
Precompiler* precompiler)
|
||||
: flow_graph_(flow_graph),
|
||||
inline_id_to_function_(inline_id_to_function),
|
||||
inline_id_to_token_pos_(inline_id_to_token_pos),
|
||||
caller_inline_id_(caller_inline_id),
|
||||
trace_inlining_(FLAG_trace_inlining && flow_graph->should_print()),
|
||||
speculative_policy_(speculative_policy),
|
||||
precompiler_(precompiler) {}
|
||||
|
||||
void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph,
|
||||
|
||||
@@ -30,72 +30,12 @@ class Precompiler;
|
||||
class StaticCallInstr;
|
||||
class TargetEntryInstr;
|
||||
|
||||
class SpeculativeInliningPolicy {
|
||||
public:
|
||||
explicit SpeculativeInliningPolicy(bool enable_suppression,
|
||||
intptr_t limit = -1)
|
||||
: enable_suppression_(enable_suppression), remaining_(limit) {}
|
||||
|
||||
bool AllowsSpeculativeInlining() const {
|
||||
return !enable_suppression_ || remaining_ > 0;
|
||||
}
|
||||
|
||||
bool IsAllowedForInlining(intptr_t call_deopt_id) const {
|
||||
// If we are not suppressing, we always enable optimistic inlining.
|
||||
if (!enable_suppression_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we have already suppressed the deopt-id we don't allow inlining it.
|
||||
if (IsSuppressed(call_deopt_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allow it if we can bailout at least one more time.
|
||||
return remaining_ > 0;
|
||||
}
|
||||
|
||||
bool AddBlockedDeoptId(intptr_t id) {
|
||||
ASSERT(enable_suppression_);
|
||||
#if defined(DEBUG)
|
||||
ASSERT(!IsSuppressed(id));
|
||||
#endif
|
||||
|
||||
// If we exhausted the number of suppression entries there is no point
|
||||
// in adding entries to the list.
|
||||
if (remaining_ <= 0) return false;
|
||||
|
||||
inlining_suppressions_.Add(id);
|
||||
remaining_ -= 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
intptr_t length() const { return inlining_suppressions_.length(); }
|
||||
|
||||
private:
|
||||
bool IsSuppressed(intptr_t id) const {
|
||||
for (intptr_t i = 0; i < inlining_suppressions_.length(); ++i) {
|
||||
if (inlining_suppressions_[i] == id) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Whether we enable suppressing inlining at specific deopt-ids.
|
||||
const bool enable_suppression_;
|
||||
|
||||
// After we reach [remaining_] number of deopt-ids in [inlining_suppressions_]
|
||||
// list, we'll disable speculative inlining entirely.
|
||||
intptr_t remaining_;
|
||||
GrowableArray<intptr_t> inlining_suppressions_;
|
||||
};
|
||||
|
||||
class FlowGraphInliner : ValueObject {
|
||||
public:
|
||||
FlowGraphInliner(FlowGraph* flow_graph,
|
||||
GrowableArray<const Function*>* inline_id_to_function,
|
||||
GrowableArray<TokenPosition>* inline_id_to_token_pos,
|
||||
GrowableArray<intptr_t>* caller_inline_id,
|
||||
SpeculativeInliningPolicy* speculative_policy,
|
||||
Precompiler* precompiler);
|
||||
|
||||
// The flow graph is destructively updated upon inlining. Returns the max
|
||||
@@ -133,10 +73,6 @@ class FlowGraphInliner : ValueObject {
|
||||
|
||||
bool trace_inlining() const { return trace_inlining_; }
|
||||
|
||||
SpeculativeInliningPolicy* speculative_policy() {
|
||||
return speculative_policy_;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class CallSiteInliner;
|
||||
|
||||
@@ -145,7 +81,6 @@ class FlowGraphInliner : ValueObject {
|
||||
GrowableArray<TokenPosition>* inline_id_to_token_pos_;
|
||||
GrowableArray<intptr_t>* caller_inline_id_;
|
||||
const bool trace_inlining_;
|
||||
SpeculativeInliningPolicy* speculative_policy_;
|
||||
Precompiler* precompiler_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FlowGraphInliner);
|
||||
|
||||
@@ -1051,8 +1051,8 @@ bool CallSpecializer::TryInlineInstanceMethod(InstanceCallInstr* call) {
|
||||
}
|
||||
}
|
||||
|
||||
return TryReplaceInstanceCallWithInline(flow_graph_, current_iterator(), call,
|
||||
speculative_policy_);
|
||||
return TryReplaceInstanceCallWithInline(flow_graph_, current_iterator(),
|
||||
call);
|
||||
}
|
||||
|
||||
// If type tests specified by 'ic_data' do not depend on type arguments,
|
||||
@@ -1273,9 +1273,8 @@ void CallSpecializer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
|
||||
if (as_bool.IsNull() || CompilerState::Current().is_aot()) {
|
||||
if (results->length() == number_of_checks * 2) {
|
||||
const bool can_deopt = SpecializeTestCidsForNumericTypes(results, type);
|
||||
if (can_deopt &&
|
||||
!speculative_policy_->IsAllowedForInlining(call->deopt_id())) {
|
||||
// Guard against repeated speculative inlining.
|
||||
if (can_deopt && CompilerState::Current().is_aot()) {
|
||||
// Guard against speculative inlining.
|
||||
return;
|
||||
}
|
||||
TestCidsInstr* test_cids = new (Z) TestCidsInstr(
|
||||
@@ -1305,12 +1304,11 @@ void CallSpecializer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
|
||||
}
|
||||
|
||||
void CallSpecializer::VisitStaticCall(StaticCallInstr* call) {
|
||||
if (TryReplaceStaticCallWithInline(flow_graph_, current_iterator(), call,
|
||||
speculative_policy_)) {
|
||||
if (TryReplaceStaticCallWithInline(flow_graph_, current_iterator(), call)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (speculative_policy_->IsAllowedForInlining(call->deopt_id())) {
|
||||
if (!CompilerState::Current().is_aot()) {
|
||||
// Only if speculative inlining is enabled.
|
||||
|
||||
MethodRecognizer::Kind recognized_kind = call->function().recognized_kind();
|
||||
@@ -1984,18 +1982,28 @@ static bool InlineDoubleOp(FlowGraph* flow_graph,
|
||||
Definition* left = receiver;
|
||||
Definition* right = call->ArgumentAt(1);
|
||||
|
||||
if (CompilerState::Current().is_aot()) {
|
||||
if (!left->Type()->IsDouble() || !right->Type()->IsDouble()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
*entry =
|
||||
new (Z) FunctionEntryInstr(graph_entry, flow_graph->allocate_block_id(),
|
||||
call->GetBlock()->try_index(), DeoptId::kNone);
|
||||
(*entry)->InheritDeoptTarget(Z, call);
|
||||
left =
|
||||
UnboxInstr::Create(kUnboxedDouble, new (Z) Value(left), call->deopt_id(),
|
||||
UnboxInstr::ValueMode::kCheckType);
|
||||
flow_graph->InsertBefore(call, left, call->env(), FlowGraph::kValue);
|
||||
right =
|
||||
UnboxInstr::Create(kUnboxedDouble, new (Z) Value(right), call->deopt_id(),
|
||||
UnboxInstr::ValueMode::kCheckType);
|
||||
flow_graph->InsertBefore(call, right, call->env(), FlowGraph::kValue);
|
||||
if (!left->Type()->IsDouble()) {
|
||||
left =
|
||||
UnboxInstr::Create(kUnboxedDouble, new (Z) Value(left),
|
||||
call->deopt_id(), UnboxInstr::ValueMode::kCheckType);
|
||||
flow_graph->InsertBefore(call, left, call->env(), FlowGraph::kValue);
|
||||
}
|
||||
if (!right->Type()->IsDouble()) {
|
||||
right =
|
||||
UnboxInstr::Create(kUnboxedDouble, new (Z) Value(right),
|
||||
call->deopt_id(), UnboxInstr::ValueMode::kCheckType);
|
||||
flow_graph->InsertBefore(call, right, call->env(), FlowGraph::kValue);
|
||||
}
|
||||
BinaryDoubleOpInstr* double_bin_op = new (Z)
|
||||
BinaryDoubleOpInstr(op_kind, new (Z) Value(left), new (Z) Value(right),
|
||||
call->deopt_id(), call->source());
|
||||
@@ -2179,8 +2187,7 @@ static bool InlineStringBaseCodeUnitAt(FlowGraph* flow_graph,
|
||||
bool CallSpecializer::TryReplaceInstanceCallWithInline(
|
||||
FlowGraph* flow_graph,
|
||||
ForwardInstructionIterator* iterator,
|
||||
InstanceCallInstr* call,
|
||||
SpeculativeInliningPolicy* policy) {
|
||||
InstanceCallInstr* call) {
|
||||
const CallTargets& targets = call->Targets();
|
||||
ASSERT(targets.IsMonomorphic());
|
||||
const intptr_t receiver_cid = targets.MonomorphicReceiverCid();
|
||||
@@ -2194,8 +2201,7 @@ bool CallSpecializer::TryReplaceInstanceCallWithInline(
|
||||
if (CallSpecializer::TryInlineRecognizedMethod(
|
||||
flow_graph, receiver_cid, target, call,
|
||||
call->Receiver()->definition(), call->source(), call->ic_data(),
|
||||
/*graph_entry=*/nullptr, &entry, &last, &result, policy,
|
||||
&exactness_info)) {
|
||||
/*graph_entry=*/nullptr, &entry, &last, &result, &exactness_info)) {
|
||||
// The empty Object constructor is the only case where the inlined body is
|
||||
// empty and there is no result.
|
||||
ASSERT((last != nullptr && result != nullptr) ||
|
||||
@@ -2267,8 +2273,7 @@ bool CallSpecializer::TryReplaceInstanceCallWithInline(
|
||||
bool CallSpecializer::TryReplaceStaticCallWithInline(
|
||||
FlowGraph* flow_graph,
|
||||
ForwardInstructionIterator* iterator,
|
||||
StaticCallInstr* call,
|
||||
SpeculativeInliningPolicy* policy) {
|
||||
StaticCallInstr* call) {
|
||||
FunctionEntryInstr* entry = nullptr;
|
||||
Instruction* last = nullptr;
|
||||
Definition* result = nullptr;
|
||||
@@ -2281,7 +2286,7 @@ bool CallSpecializer::TryReplaceStaticCallWithInline(
|
||||
if (CallSpecializer::TryInlineRecognizedMethod(
|
||||
flow_graph, receiver_cid, call->function(), call, receiver,
|
||||
call->source(), call->ic_data(), /*graph_entry=*/nullptr, &entry,
|
||||
&last, &result, policy)) {
|
||||
&last, &result)) {
|
||||
// The empty Object constructor is the only case where the inlined body is
|
||||
// empty and there is no result.
|
||||
ASSERT((last != nullptr && result != nullptr) ||
|
||||
@@ -3183,7 +3188,6 @@ bool CallSpecializer::TryInlineRecognizedMethod(
|
||||
FunctionEntryInstr** entry,
|
||||
Instruction** last,
|
||||
Definition** result,
|
||||
SpeculativeInliningPolicy* policy,
|
||||
CallSpecializer::ExactnessInfo* exactness) {
|
||||
COMPILER_TIMINGS_TIMER_SCOPE(flow_graph->thread(), InlineRecognizedMethod);
|
||||
|
||||
@@ -3194,7 +3198,9 @@ bool CallSpecializer::TryInlineRecognizedMethod(
|
||||
return false;
|
||||
}
|
||||
|
||||
const bool can_speculate = policy->IsAllowedForInlining(call->deopt_id());
|
||||
const bool can_speculate = !CompilerState::Current().is_aot() ||
|
||||
(receiver == nullptr) ||
|
||||
(receiver->Type()->ToCid() == receiver_cid);
|
||||
const bool is_dynamic_call = Function::IsDynamicInvocationForwarderName(
|
||||
String::Handle(flow_graph->zone(), target.name()));
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
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.
|
||||
@@ -35,11 +33,8 @@ class SpeculativeInliningPolicy;
|
||||
// optimizations and AotCallSpecializer for AOT specific optimizations.
|
||||
class CallSpecializer : public FlowGraphVisitor {
|
||||
public:
|
||||
CallSpecializer(FlowGraph* flow_graph,
|
||||
SpeculativeInliningPolicy* speculative_policy,
|
||||
bool should_clone_fields)
|
||||
CallSpecializer(FlowGraph* flow_graph, bool should_clone_fields)
|
||||
: FlowGraphVisitor(flow_graph->reverse_postorder()),
|
||||
speculative_policy_(speculative_policy),
|
||||
should_clone_fields_(should_clone_fields),
|
||||
flow_graph_(flow_graph) {}
|
||||
|
||||
@@ -145,7 +140,6 @@ class CallSpecializer : public FlowGraphVisitor {
|
||||
Environment* deopt_environment,
|
||||
Instruction* insert_before);
|
||||
|
||||
SpeculativeInliningPolicy* speculative_policy_;
|
||||
const bool should_clone_fields_;
|
||||
|
||||
private:
|
||||
@@ -191,14 +185,12 @@ class CallSpecializer : public FlowGraphVisitor {
|
||||
static bool TryReplaceInstanceCallWithInline(
|
||||
FlowGraph* flow_graph,
|
||||
ForwardInstructionIterator* iterator,
|
||||
InstanceCallInstr* call,
|
||||
SpeculativeInliningPolicy* policy);
|
||||
InstanceCallInstr* call);
|
||||
|
||||
static bool TryReplaceStaticCallWithInline(
|
||||
FlowGraph* flow_graph,
|
||||
ForwardInstructionIterator* iterator,
|
||||
StaticCallInstr* call,
|
||||
SpeculativeInliningPolicy* policy);
|
||||
StaticCallInstr* call);
|
||||
|
||||
static bool TryInlineRecognizedMethod(FlowGraph* flow_graph,
|
||||
intptr_t receiver_cid,
|
||||
@@ -211,7 +203,6 @@ class CallSpecializer : public FlowGraphVisitor {
|
||||
FunctionEntryInstr** entry,
|
||||
Instruction** last,
|
||||
Definition** result,
|
||||
SpeculativeInliningPolicy* policy,
|
||||
ExactnessInfo* exactness = nullptr);
|
||||
|
||||
FlowGraph* flow_graph_;
|
||||
|
||||
@@ -51,17 +51,14 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
CompilerPassState::CompilerPassState(
|
||||
Thread* thread,
|
||||
FlowGraph* flow_graph,
|
||||
SpeculativeInliningPolicy* speculative_policy,
|
||||
Precompiler* precompiler)
|
||||
CompilerPassState::CompilerPassState(Thread* thread,
|
||||
FlowGraph* flow_graph,
|
||||
Precompiler* precompiler)
|
||||
: thread(thread),
|
||||
precompiler(precompiler),
|
||||
inlining_depth(0),
|
||||
sinking(nullptr),
|
||||
call_specializer(nullptr),
|
||||
speculative_policy(speculative_policy),
|
||||
sticky_flags(0),
|
||||
flow_graph_(flow_graph) {
|
||||
// Top scope function is at inlining id 0.
|
||||
@@ -395,9 +392,9 @@ COMPILER_PASS(SetOuterInliningId, {
|
||||
});
|
||||
|
||||
COMPILER_PASS(Inlining, {
|
||||
FlowGraphInliner inliner(
|
||||
flow_graph, &state->inline_id_to_function, &state->inline_id_to_token_pos,
|
||||
&state->caller_inline_id, state->speculative_policy, state->precompiler);
|
||||
FlowGraphInliner inliner(flow_graph, &state->inline_id_to_function,
|
||||
&state->inline_id_to_token_pos,
|
||||
&state->caller_inline_id, state->precompiler);
|
||||
state->inlining_depth = inliner.Inline();
|
||||
});
|
||||
|
||||
|
||||
@@ -64,14 +64,12 @@ class FlowGraph;
|
||||
class FlowGraphCompiler;
|
||||
class Function;
|
||||
class Precompiler;
|
||||
class SpeculativeInliningPolicy;
|
||||
class TimelineStream;
|
||||
class Thread;
|
||||
|
||||
struct CompilerPassState {
|
||||
CompilerPassState(Thread* thread,
|
||||
FlowGraph* flow_graph,
|
||||
SpeculativeInliningPolicy* speculative_policy,
|
||||
Precompiler* precompiler = nullptr);
|
||||
|
||||
FlowGraph* flow_graph() const { return flow_graph_; }
|
||||
@@ -93,8 +91,6 @@ struct CompilerPassState {
|
||||
|
||||
CallSpecializer* call_specializer;
|
||||
|
||||
SpeculativeInliningPolicy* speculative_policy;
|
||||
|
||||
intptr_t sticky_flags;
|
||||
|
||||
FlowGraphCompiler* graph_compiler = nullptr;
|
||||
|
||||
@@ -491,10 +491,6 @@ CodePtr CompileParsedFunctionHelper::Compile() {
|
||||
// volatile because the variable may be clobbered by a longjmp.
|
||||
volatile intptr_t far_branch_level = 0;
|
||||
|
||||
// In the JIT case we allow speculative inlining and have no need for a
|
||||
// suppression, since we don't restart optimization.
|
||||
SpeculativeInliningPolicy speculative_policy(/*enable_suppression=*/false);
|
||||
|
||||
Code* volatile result = &Code::ZoneHandle(zone);
|
||||
while (!done) {
|
||||
*result = Code::null();
|
||||
@@ -551,12 +547,12 @@ CodePtr CompileParsedFunctionHelper::Compile() {
|
||||
BlockScheduler::AssignEdgeWeights(flow_graph);
|
||||
}
|
||||
|
||||
CompilerPassState pass_state(thread(), flow_graph, &speculative_policy);
|
||||
CompilerPassState pass_state(thread(), flow_graph);
|
||||
|
||||
if (optimized()) {
|
||||
TIMELINE_DURATION(thread(), CompilerVerbose, "OptimizationPasses");
|
||||
|
||||
JitCallSpecializer call_specializer(flow_graph, &speculative_policy);
|
||||
JitCallSpecializer call_specializer(flow_graph);
|
||||
pass_state.call_specializer = &call_specializer;
|
||||
|
||||
flow_graph = CompilerPass::RunPipeline(CompilerPass::kJIT, &pass_state);
|
||||
@@ -568,9 +564,8 @@ CodePtr CompileParsedFunctionHelper::Compile() {
|
||||
compiler::Assembler assembler(&object_pool_builder, far_branch_level);
|
||||
FlowGraphCompiler graph_compiler(
|
||||
&assembler, flow_graph, *parsed_function(), optimized(),
|
||||
&speculative_policy, pass_state.inline_id_to_function,
|
||||
pass_state.inline_id_to_token_pos, pass_state.caller_inline_id,
|
||||
ic_data_array);
|
||||
pass_state.inline_id_to_function, pass_state.inline_id_to_token_pos,
|
||||
pass_state.caller_inline_id, ic_data_array);
|
||||
pass_state.graph_compiler = &graph_compiler;
|
||||
CompilerPass::GenerateCode(&pass_state);
|
||||
|
||||
@@ -642,9 +637,6 @@ CodePtr CompileParsedFunctionHelper::Compile() {
|
||||
done = false;
|
||||
RELEASE_ASSERT(far_branch_level < 2);
|
||||
far_branch_level += 1;
|
||||
} else if (error.ptr() == Object::speculative_inlining_error().ptr()) {
|
||||
// Can only happen with precompilation.
|
||||
UNREACHABLE();
|
||||
} else {
|
||||
// If the error isn't due to an out of range branch offset, we don't
|
||||
// try again (done = true).
|
||||
|
||||
@@ -29,11 +29,8 @@ namespace dart {
|
||||
// Quick access to the current zone.
|
||||
#define Z (zone())
|
||||
|
||||
JitCallSpecializer::JitCallSpecializer(
|
||||
FlowGraph* flow_graph,
|
||||
SpeculativeInliningPolicy* speculative_policy)
|
||||
JitCallSpecializer::JitCallSpecializer(FlowGraph* flow_graph)
|
||||
: CallSpecializer(flow_graph,
|
||||
speculative_policy,
|
||||
CompilerState::Current().should_clone_fields()) {}
|
||||
|
||||
bool JitCallSpecializer::IsAllowedForInlining(intptr_t deopt_id) const {
|
||||
|
||||
@@ -15,8 +15,7 @@ namespace dart {
|
||||
|
||||
class JitCallSpecializer : public CallSpecializer {
|
||||
public:
|
||||
explicit JitCallSpecializer(FlowGraph* flow_graph,
|
||||
SpeculativeInliningPolicy* speculative_policy);
|
||||
explicit JitCallSpecializer(FlowGraph* flow_graph);
|
||||
|
||||
virtual ~JitCallSpecializer() {}
|
||||
|
||||
|
||||
@@ -1271,9 +1271,6 @@ void Object::Init(IsolateGroup* isolate_group) {
|
||||
error_str = String::New("Branch offset overflow", Heap::kOld);
|
||||
*branch_offset_error_ =
|
||||
LanguageError::New(error_str, Report::kBailout, Heap::kOld);
|
||||
error_str = String::New("Speculative inlining failed", Heap::kOld);
|
||||
*speculative_inlining_error_ =
|
||||
LanguageError::New(error_str, Report::kBailout, Heap::kOld);
|
||||
error_str = String::New("Background Compilation Failed", Heap::kOld);
|
||||
*background_compilation_error_ =
|
||||
LanguageError::New(error_str, Report::kBailout, Heap::kOld);
|
||||
@@ -1397,8 +1394,6 @@ void Object::Init(IsolateGroup* isolate_group) {
|
||||
ASSERT(snapshot_writer_error_->IsLanguageError());
|
||||
ASSERT(!branch_offset_error_->IsSmi());
|
||||
ASSERT(branch_offset_error_->IsLanguageError());
|
||||
ASSERT(!speculative_inlining_error_->IsSmi());
|
||||
ASSERT(speculative_inlining_error_->IsLanguageError());
|
||||
ASSERT(!background_compilation_error_->IsSmi());
|
||||
ASSERT(background_compilation_error_->IsLanguageError());
|
||||
ASSERT(!out_of_memory_error_->IsSmi());
|
||||
|
||||
@@ -511,7 +511,6 @@ class Object {
|
||||
V(UnwindError, unwind_in_progress_error) \
|
||||
V(LanguageError, snapshot_writer_error) \
|
||||
V(LanguageError, branch_offset_error) \
|
||||
V(LanguageError, speculative_inlining_error) \
|
||||
V(LanguageError, background_compilation_error) \
|
||||
V(LanguageError, no_debuggable_code_error) \
|
||||
V(LanguageError, out_of_memory_error) \
|
||||
|
||||
Reference in New Issue
Block a user