Index: runtime/vm/flow_graph_compiler.cc |
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc |
index e1c8a0113e9743421e959d5441295684503e5f4a..d25fd7c2f29092c1880fc0716f2c0e7a2d18b087 100644 |
--- a/runtime/vm/flow_graph_compiler.cc |
+++ b/runtime/vm/flow_graph_compiler.cc |
@@ -152,31 +152,6 @@ void CompilerDeoptInfo::EmitMaterializations(Environment* env, |
} |
-// Returns true if OnebyteString is a frequent receiver class. We inline |
-// Smi check as well, since a Smi check must be done anyway. |
-// TODO(srdjan): Add check and code if Smi class is hot. |
-bool FlowGraphCompiler::ShouldInlineSmiStringHashCode(const ICData& ic_data) { |
- if (!FLAG_inline_smi_string_hashcode || |
- (ic_data.target_name() != Symbols::hashCode().raw())) { |
- return false; |
- } |
- // Precompiled code has no ICData, optimistically inline it. |
- if (ic_data.IsNull() || ic_data.NumberOfChecksIs(0)) { |
- return true; |
- } |
- // Check if OneByteString is hot enough. |
- const ICData& ic_data_sorted = |
- ICData::Handle(ic_data.AsUnaryClassChecksSortedByCount()); |
- ASSERT(!ic_data_sorted.NumberOfChecksIs(0)); |
- if (ic_data_sorted.GetReceiverClassIdAt(0) == kOneByteStringCid) { |
- const intptr_t total_count = ic_data_sorted.AggregateCount(); |
- const intptr_t ratio = (ic_data_sorted.GetCountAt(0) * 100) / total_count; |
- return ratio > FLAG_inline_smi_string_hashcode_ratio; |
Vyacheslav Egorov (Google)
2017/03/10 10:31:30
if you killed the code, kill the flag.
but also w
erikcorry
2017/03/10 13:30:01
Flag killed.
It was introduced here with no expla
|
- } |
- return false; |
-} |
- |
- |
FlowGraphCompiler::FlowGraphCompiler( |
Assembler* assembler, |
FlowGraph* flow_graph, |
@@ -1618,29 +1593,53 @@ ParallelMoveResolver::ScratchRegisterScope::~ScratchRegisterScope() { |
} |
-static int HighestCountFirst(const CidTarget* a, const CidTarget* b) { |
+template <typename T> |
+static int HighestCountFirst(const T* a, const T* b) { |
// Negative if 'a' should sort before 'b'. |
return b->count - a->count; |
} |
+static int LowestCidFirst(const CidRangeTarget* a, const CidRangeTarget* b) { |
+ // Negative if 'a' should sort before 'b'. |
+ return a->cid_start - b->cid_start; |
+} |
+ |
+ |
// Returns 'sorted' array in decreasing count order. |
// The expected number of elements to sort is less than 10. |
-void FlowGraphCompiler::SortICDataByCount(const ICData& ic_data, |
- GrowableArray<CidTarget>* sorted, |
- bool drop_smi) { |
+void FlowGraphCompiler::SortICDataByCount( |
+ const ICData& ic_data, |
+ GrowableArray<CidRangeTarget>* sorted_arg, |
+ bool drop_smi) { |
+ GrowableArray<CidRangeTarget>& sorted = *sorted_arg; |
ASSERT(ic_data.NumArgsTested() == 1); |
const intptr_t len = ic_data.NumberOfChecks(); |
- sorted->Clear(); |
+ sorted.Clear(); |
for (int i = 0; i < len; i++) { |
intptr_t receiver_cid = ic_data.GetReceiverClassIdAt(i); |
if (drop_smi && (receiver_cid == kSmiCid)) continue; |
- sorted->Add(CidTarget(receiver_cid, |
- &Function::ZoneHandle(ic_data.GetTargetAt(i)), |
- ic_data.GetCountAt(i))); |
+ Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i)); |
+ sorted.Add(CidRangeTarget(receiver_cid, receiver_cid, &target, |
+ ic_data.GetCountAt(i))); |
+ } |
+ sorted.Sort(LowestCidFirst); |
+ int dest = 0; |
+ |
+ // Merge adjacent ranges. |
+ for (int src = 0; src < sorted.length(); src++) { |
+ if (src > 0 && sorted[src - 1].cid_end + 1 == sorted[src].cid_start && |
+ sorted[src - 1].target->raw() == sorted[src].target->raw()) { |
+ sorted[dest - 1].cid_end++; |
+ sorted[dest - 1].count += sorted[dest].count; |
+ } else { |
+ sorted[dest++] = sorted[src]; |
+ } |
} |
- sorted->Sort(HighestCountFirst); |
+ |
+ sorted.SetLength(dest); |
+ sorted.Sort(HighestCountFirst); |
} |
@@ -1782,6 +1781,38 @@ const ICData& FlowGraphCompiler::TrySpecializeICDataByReceiverCid( |
} |
+intptr_t FlowGraphCompiler::GetGoodBias( |
+ const GrowableArray<CidRangeTarget>& sorted, |
+ intptr_t max_immediate) { |
+ // Sometimes a bias can be useful so we can emit more compact compare |
+ // instructions. |
+ intptr_t min_cid = 1000000; |
+ intptr_t max_cid = -1; |
+ |
+ const intptr_t sorted_len = sorted.length(); |
+ |
+ for (intptr_t i = 0; i < sorted_len + 1; i++) { |
+ bool done = (i == sorted_len); |
+ intptr_t start = done ? 0 : sorted[i].cid_start; |
+ intptr_t end = done ? 0 : sorted[i].cid_end; |
+ bool is_range = start != end; |
+ bool spread_too_big = start - min_cid > max_immediate; |
+ if (done || is_range || spread_too_big) { |
+ if (i >= 2 && max_cid - min_cid <= max_immediate && |
+ max_cid > max_immediate) { |
+ return min_cid; |
+ } else { |
+ return 0; |
+ } |
+ } |
+ min_cid = Utils::Minimum(min_cid, start); |
+ max_cid = Utils::Maximum(max_cid, end); |
+ } |
+ UNREACHABLE(); |
+ return 0; |
+} |
+ |
+ |
#if !defined(TARGET_ARCH_DBC) |
// DBC emits calls very differently from other architectures due to its |
// interpreted nature. |
@@ -1791,7 +1822,8 @@ void FlowGraphCompiler::EmitPolymorphicInstanceCall(const ICData& ic_data, |
intptr_t deopt_id, |
TokenPosition token_pos, |
LocationSummary* locs, |
- bool complete) { |
+ bool complete, |
+ intptr_t total_ic_calls) { |
if (FLAG_polymorphic_with_deopt) { |
Label* deopt = |
AddDeoptStub(deopt_id, ICData::kDeoptPolymorphicInstanceCallTestFail); |
@@ -1799,7 +1831,7 @@ void FlowGraphCompiler::EmitPolymorphicInstanceCall(const ICData& ic_data, |
EmitTestAndCall(ic_data, argument_count, argument_names, |
deopt, // No cid match. |
&ok, // Found cid. |
- deopt_id, token_pos, locs, complete); |
+ deopt_id, token_pos, locs, complete, total_ic_calls); |
assembler()->Bind(&ok); |
} else { |
if (complete) { |
@@ -1807,7 +1839,7 @@ void FlowGraphCompiler::EmitPolymorphicInstanceCall(const ICData& ic_data, |
EmitTestAndCall(ic_data, argument_count, argument_names, |
NULL, // No cid match. |
&ok, // Found cid. |
- deopt_id, token_pos, locs, true); |
+ deopt_id, token_pos, locs, true, total_ic_calls); |
assembler()->Bind(&ok); |
} else { |
EmitSwitchableInstanceCall(ic_data, argument_count, deopt_id, token_pos, |