Disable hoisting CheckClass due to excessive deoptimization (issue 16285). Detect that a deoptimization was caused by hoisted check class instruction and disable hoisting of CheckClassInstr for that function. This is a short-term solution to fix excessive deoptimization causing slow start-ups.

R=johnmccutchan@google.com

Review URL: https://codereview.chromium.org//157833004

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@32460 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
srdjan@google.com
2014-02-08 00:02:22 +00:00
parent 61ba258618
commit 2c37517875
12 changed files with 54 additions and 26 deletions
+1
View File
@@ -71,6 +71,7 @@ DECLARE_RUNTIME_ENTRY(UpdateFieldCid);
V(UnaryOp) \
V(UnboxInteger) \
V(CheckClass) \
V(HoistedCheckClass) \
V(CheckSmi) \
V(CheckArrayBound) \
V(AtCall) \
+1 -5
View File
@@ -48,8 +48,6 @@ DEFINE_FLAG(bool, allocation_sinking, true,
"Attempt to sink temporary allocations to side exits");
DEFINE_FLAG(int, deoptimization_counter_threshold, 16,
"How many times we allow deoptimization before we disallow optimization.");
DEFINE_FLAG(int, deoptimization_counter_licm_threshold, 8,
"How many times we allow deoptimization before we disable LICM.");
DEFINE_FLAG(bool, print_flow_graph, false, "Print the IR flow graph.");
DEFINE_FLAG(bool, print_flow_graph_optimized, false,
"Print the IR flow graph when optimizing.");
@@ -442,9 +440,7 @@ static bool CompileParsedFunctionHelper(ParsedFunction* parsed_function,
optimizer.TryOptimizePatterns();
DEBUG_ASSERT(flow_graph->VerifyUseLists());
if (FLAG_loop_invariant_code_motion &&
(function.deoptimization_counter() <
FLAG_deoptimization_counter_licm_threshold)) {
if (FLAG_loop_invariant_code_motion) {
LICM licm(flow_graph);
licm.Optimize();
DEBUG_ASSERT(flow_graph->VerifyUseLists());
+3
View File
@@ -584,6 +584,9 @@ class DeoptRetAddressInstr : public DeoptInstr {
if (!ic_data.IsNull()) {
ic_data.set_deopt_reason(deopt_context->deopt_reason());
}
} else if (deopt_context->deopt_reason() == kDeoptHoistedCheckClass) {
// Prevent excessive deoptimization.
Function::Handle(code.function()).set_allows_hoisting_check_class(false);
}
}
+13 -4
View File
@@ -23,6 +23,8 @@ namespace dart {
DEFINE_FLAG(bool, array_bounds_check_elimination, true,
"Eliminate redundant bounds checks.");
DEFINE_FLAG(int, getter_setter_ratio, 13,
"Ratio of getter/setter usage used for double field unboxing heuristics");
DEFINE_FLAG(bool, load_cse, true, "Use redundant load elimination.");
DEFINE_FLAG(int, max_polymorphic_checks, 4,
"Maximum number of polymorphic check, otherwise it is megamorphic.");
@@ -32,15 +34,13 @@ DEFINE_FLAG(int, max_equality_polymorphic_checks, 32,
DEFINE_FLAG(bool, remove_redundant_phis, true, "Remove redundant phis.");
DEFINE_FLAG(bool, trace_constant_propagation, false,
"Print constant propagation and useless code elimination.");
DEFINE_FLAG(bool, trace_load_optimization, false,
"Print live sets for load optimization pass.");
DEFINE_FLAG(bool, trace_optimization, false, "Print optimization details.");
DEFINE_FLAG(bool, trace_range_analysis, false, "Trace range analysis progress");
DEFINE_FLAG(bool, truncating_left_shift, true,
"Optimize left shift to truncate if possible");
DEFINE_FLAG(bool, use_cha, true, "Use class hierarchy analysis.");
DEFINE_FLAG(bool, trace_load_optimization, false,
"Print live sets for load optimization pass.");
DEFINE_FLAG(int, getter_setter_ratio, 13,
"Ratio of getter/setter usage used for double field unboxing heuristics");
DECLARE_FLAG(bool, eliminate_type_checks);
DECLARE_FLAG(bool, enable_type_checks);
DECLARE_FLAG(bool, trace_type_check_elimination);
@@ -4493,6 +4493,9 @@ LICM::LICM(FlowGraph* flow_graph) : flow_graph_(flow_graph) {
void LICM::Hoist(ForwardInstructionIterator* it,
BlockEntryInstr* pre_header,
Instruction* current) {
if (current->IsCheckClass()) {
current->AsCheckClass()->set_licm_hoisted(true);
}
// TODO(fschneider): Avoid repeated deoptimization when
// speculatively hoisting checks.
if (FLAG_trace_optimization) {
@@ -4580,6 +4583,12 @@ static bool IsLoopInvariantLoad(ZoneGrowableArray<BitVector*>* sets,
void LICM::Optimize() {
if (!flow_graph()->parsed_function().function().
allows_hoisting_check_class()) {
// Do not hoist any.
return;
}
const ZoneGrowableArray<BlockEntryInstr*>& loop_headers =
flow_graph()->loop_headers();
+1 -1
View File
@@ -85,7 +85,7 @@ bool Value::Equals(Value* other) const {
CheckClassInstr::CheckClassInstr(Value* value,
intptr_t deopt_id,
const ICData& unary_checks)
: unary_checks_(unary_checks) {
: unary_checks_(unary_checks), licm_hoisted_(false) {
ASSERT(unary_checks.IsZoneHandle());
// Expected useful check data.
ASSERT(!unary_checks_.IsNull());
+3
View File
@@ -6793,8 +6793,11 @@ class CheckClassInstr : public TemplateInstruction<1> {
virtual bool MayThrow() const { return false; }
void set_licm_hoisted(bool value) { licm_hoisted_ = value; }
private:
const ICData& unary_checks_;
bool licm_hoisted_;
DISALLOW_COPY_AND_ASSIGN(CheckClassInstr);
};
+4 -4
View File
@@ -4546,9 +4546,10 @@ LocationSummary* CheckClassInstr::MakeLocationSummary(bool opt) const {
void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const DeoptReasonId deopt_reason =
licm_hoisted_ ? kDeoptHoistedCheckClass : kDeoptCheckClass;
if (IsNullCheck()) {
Label* deopt = compiler->AddDeoptStub(deopt_id(),
kDeoptCheckClass);
Label* deopt = compiler->AddDeoptStub(deopt_id(), deopt_reason);
__ CompareImmediate(locs()->in(0).reg(),
reinterpret_cast<intptr_t>(Object::null()));
__ b(deopt, EQ);
@@ -4559,8 +4560,7 @@ void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
(unary_checks().NumberOfChecks() > 1));
Register value = locs()->in(0).reg();
Register temp = locs()->temp(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(),
kDeoptCheckClass);
Label* deopt = compiler->AddDeoptStub(deopt_id(), deopt_reason);
Label is_ok;
intptr_t cix = 0;
if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) {
+4 -4
View File
@@ -4518,9 +4518,10 @@ LocationSummary* CheckClassInstr::MakeLocationSummary(bool opt) const {
void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const DeoptReasonId deopt_reason =
licm_hoisted_ ? kDeoptHoistedCheckClass : kDeoptCheckClass;
if (IsNullCheck()) {
Label* deopt = compiler->AddDeoptStub(deopt_id(),
kDeoptCheckClass);
Label* deopt = compiler->AddDeoptStub(deopt_id(), deopt_reason);
const Immediate& raw_null =
Immediate(reinterpret_cast<intptr_t>(Object::null()));
__ cmpl(locs()->in(0).reg(), raw_null);
@@ -4532,8 +4533,7 @@ void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
(unary_checks().NumberOfChecks() > 1));
Register value = locs()->in(0).reg();
Register temp = locs()->temp(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(),
kDeoptCheckClass);
Label* deopt = compiler->AddDeoptStub(deopt_id(), deopt_reason);
Label is_ok;
intptr_t cix = 0;
if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) {
+4 -4
View File
@@ -3806,9 +3806,10 @@ LocationSummary* CheckClassInstr::MakeLocationSummary(bool opt) const {
void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const DeoptReasonId deopt_reason =
licm_hoisted_ ? kDeoptHoistedCheckClass : kDeoptCheckClass;
if (IsNullCheck()) {
Label* deopt = compiler->AddDeoptStub(deopt_id(),
kDeoptCheckClass);
Label* deopt = compiler->AddDeoptStub(deopt_id(), deopt_reason);
__ BranchEqual(locs()->in(0).reg(),
reinterpret_cast<int32_t>(Object::null()), deopt);
return;
@@ -3818,8 +3819,7 @@ void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
(unary_checks().NumberOfChecks() > 1));
Register value = locs()->in(0).reg();
Register temp = locs()->temp(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(),
kDeoptCheckClass);
Label* deopt = compiler->AddDeoptStub(deopt_id(), deopt_reason);
Label is_ok;
intptr_t cix = 0;
if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) {
+4 -4
View File
@@ -4587,9 +4587,10 @@ LocationSummary* CheckClassInstr::MakeLocationSummary(bool opt) const {
void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
const DeoptReasonId deopt_reason =
licm_hoisted_ ? kDeoptHoistedCheckClass : kDeoptCheckClass;
if (IsNullCheck()) {
Label* deopt = compiler->AddDeoptStub(deopt_id(),
kDeoptCheckClass);
Label* deopt = compiler->AddDeoptStub(deopt_id(), deopt_reason);
__ CompareObject(locs()->in(0).reg(),
Object::null_object(), PP);
__ j(EQUAL, deopt);
@@ -4600,8 +4601,7 @@ void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
(unary_checks().NumberOfChecks() > 1));
Register value = locs()->in(0).reg();
Register temp = locs()->temp(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(),
kDeoptCheckClass);
Label* deopt = compiler->AddDeoptStub(deopt_id(), deopt_reason);
Label is_ok;
intptr_t cix = 0;
if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) {
+8
View File
@@ -5007,11 +5007,18 @@ void Function::SetIsNativeAutoSetupScope(bool value) const {
set_is_optimizable(value);
}
void Function::set_is_optimizable(bool value) const {
set_kind_tag(OptimizableBit::update(value, raw_ptr()->kind_tag_));
}
void Function::set_allows_hoisting_check_class(bool value) const {
set_kind_tag(
AllowsHoistingCheckClassBit::update(value, raw_ptr()->kind_tag_));
}
void Function::set_is_native(bool value) const {
set_kind_tag(NativeBit::update(value, raw_ptr()->kind_tag_));
}
@@ -5525,6 +5532,7 @@ RawFunction* Function::New(const String& name,
result.set_optimized_call_site_count(0);
result.set_is_optimizable(is_native ? false : true);
result.set_is_inlinable(true);
result.set_allows_hoisting_check_class(true);
if (kind == RawFunction::kClosureFunction) {
const ClosureData& data = ClosureData::Handle(ClosureData::New());
result.set_data(data);
+8
View File
@@ -1722,6 +1722,11 @@ class Function : public Object {
}
void set_is_redirecting(bool value) const;
bool allows_hoisting_check_class() const {
return AllowsHoistingCheckClassBit::decode(raw_ptr()->kind_tag_);
}
void set_allows_hoisting_check_class(bool value) const;
bool HasOptimizedCode() const;
// Returns true if the argument counts are valid for calling this function.
@@ -1892,6 +1897,7 @@ class Function : public Object {
kNativeBit = 12,
kRedirectingBit = 13,
kExternalBit = 14,
kAllowsHoistingCheckClassBit = 15,
};
class KindBits :
public BitField<RawFunction::Kind, kKindTagBit, kKindTagSize> {}; // NOLINT
@@ -1906,6 +1912,8 @@ class Function : public Object {
class NativeBit : public BitField<bool, kNativeBit, 1> {};
class ExternalBit : public BitField<bool, kExternalBit, 1> {};
class RedirectingBit : public BitField<bool, kRedirectingBit, 1> {};
class AllowsHoistingCheckClassBit :
public BitField<bool, kAllowsHoistingCheckClassBit, 1> {}; // NOLINT
void set_name(const String& value) const;
void set_kind(RawFunction::Kind value) const;