Version 1.3.0-dev.7.3
svn merge -c 34451 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 34464 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 34475 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 34489 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@34495 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 7a954ee..1427cba 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -1055,7 +1055,7 @@
EmitREX_RB(dst, src);
EmitUint8(0x0F);
EmitUint8(0x5E);
- EmitXmmRegisterOperand(dst & 6, src);
+ EmitXmmRegisterOperand(dst & 7, src);
}
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index c0bbbe2..0d1e38e 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -515,6 +515,10 @@
sinking->DetachMaterializations();
}
+ // Compute and store graph informations (call & instruction counts)
+ // to be later used by the inliner.
+ FlowGraphInliner::CollectGraphInfo(flow_graph, true);
+
// Perform register allocation on the SSA graph.
FlowGraphAllocator allocator(*flow_graph);
allocator.AllocateRegisters();
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 437366e..36be8de 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -47,7 +47,7 @@
"default 10%: calls above-equal 10% of max-count are inlined.");
DEFINE_FLAG(bool, inline_recursive, true,
"Inline recursive calls.");
-DEFINE_FLAG(bool, print_inline_tree, false, "Print inlining tree");
+DEFINE_FLAG(bool, print_inlining_tree, false, "Print inlining tree");
DECLARE_FLAG(bool, print_flow_graph);
DECLARE_FLAG(bool, print_flow_graph_optimized);
@@ -136,7 +136,7 @@
// parameters was fixed.
// TODO(fschneider): Determine new heuristic parameters that avoid
// these checks entirely.
- if (!call->HasRecognizedTarget() &&
+ if (!call->HasSingleRecognizedTarget() &&
(call->instance_call()->token_kind() != Token::kEQ)) {
++call_site_count_;
}
@@ -154,6 +154,26 @@
};
+// Structure for collecting inline data needed to print inlining tree.
+struct InlinedInfo {
+ const Function* caller;
+ const Function* inlined;
+ intptr_t inlined_depth;
+ const Definition* call_instr;
+ const char* bailout_reason;
+ InlinedInfo(const Function* caller_function,
+ const Function* inlined_function,
+ const intptr_t depth,
+ const Definition* call,
+ const char* reason = NULL)
+ : caller(caller_function),
+ inlined(inlined_function),
+ inlined_depth(depth),
+ call_instr(call),
+ bailout_reason(reason) {}
+};
+
+
// A collection of call sites to consider for inlining.
class CallSites : public ValueObject {
public:
@@ -254,14 +274,16 @@
}
}
- void FindCallSites(FlowGraph* graph, intptr_t depth) {
+ void FindCallSites(FlowGraph* graph,
+ intptr_t depth,
+ GrowableArray<InlinedInfo>* inlined_info) {
ASSERT(graph != NULL);
- // If depth is less than the threshold recursively add call sites.
+
if (depth > FLAG_inlining_depth_threshold) return;
// Recognized methods are not treated as normal calls. They don't have
// calls in themselves, so we keep adding those even when at the threshold.
- const bool only_recognized_methods =
+ const bool inline_only_recognized_methods =
(depth == FLAG_inlining_depth_threshold);
const intptr_t instance_call_start_ix = instance_calls_.length();
@@ -273,30 +295,44 @@
!it.Done();
it.Advance()) {
Instruction* current = it.Current();
- if (only_recognized_methods) {
+ if (current->IsPolymorphicInstanceCall()) {
PolymorphicInstanceCallInstr* instance_call =
current->AsPolymorphicInstanceCall();
- if ((instance_call != NULL) && instance_call->HasRecognizedTarget()) {
+ if (!inline_only_recognized_methods ||
+ instance_call->HasSingleRecognizedTarget()) {
instance_calls_.Add(InstanceCallInfo(instance_call, graph));
+ } else {
+ // Method not inlined because inlining too deep and method
+ // not recognized.
+ if (FLAG_print_inlining_tree) {
+ const Function* caller = &graph->parsed_function().function();
+ const Function* target =
+ &Function::ZoneHandle(
+ instance_call->ic_data().GetTargetAt(0));
+ inlined_info->Add(InlinedInfo(
+ caller, target, depth, instance_call, "Too deep"));
+ }
}
- continue;
- }
- // Collect all call sites (!only_recognized_methods).
- ClosureCallInstr* closure_call = current->AsClosureCall();
- if (closure_call != NULL) {
- closure_calls_.Add(ClosureCallInfo(closure_call, graph));
- continue;
- }
- StaticCallInstr* static_call = current->AsStaticCall();
- if (static_call != NULL) {
- static_calls_.Add(StaticCallInfo(static_call, graph));
- continue;
- }
- PolymorphicInstanceCallInstr* instance_call =
- current->AsPolymorphicInstanceCall();
- if (instance_call != NULL) {
- instance_calls_.Add(InstanceCallInfo(instance_call, graph));
- continue;
+ } else if (current->IsStaticCall()) {
+ StaticCallInstr* static_call = current->AsStaticCall();
+ if (!inline_only_recognized_methods ||
+ static_call->function().is_recognized()) {
+ static_calls_.Add(StaticCallInfo(static_call, graph));
+ } else {
+ // Method not inlined because inlining too deep and method
+ // not recognized.
+ if (FLAG_print_inlining_tree) {
+ const Function* caller = &graph->parsed_function().function();
+ const Function* target = &static_call->function();
+ inlined_info->Add(InlinedInfo(
+ caller, target, depth, static_call, "Too deep"));
+ }
+ }
+ } else if (current->IsClosureCall()) {
+ if (!inline_only_recognized_methods) {
+ ClosureCallInstr* closure_call = current->AsClosureCall();
+ closure_calls_.Add(ClosureCallInfo(closure_call, graph));
+ }
}
}
}
@@ -321,31 +357,14 @@
callee_graph(NULL),
parameter_stubs(NULL),
exit_collector(NULL),
- caller_(caller) { }
+ caller(caller) { }
Definition* call;
GrowableArray<Value*>* arguments;
FlowGraph* callee_graph;
ZoneGrowableArray<Definition*>* parameter_stubs;
InlineExitCollector* exit_collector;
- const Function& caller_;
-};
-
-
-// Structure for collecting inline data needed to print inlining tree.
-struct InlinedInfo {
- const Function* caller;
- const Function* inlined;
- intptr_t inlined_depth;
- const Definition* call_instr;
- InlinedInfo(const Function* caller_function,
- const Function* inlined_function,
- const intptr_t depth,
- const Definition* call)
- : caller(caller_function),
- inlined(inlined_function),
- inlined_depth(depth),
- call_instr(call) {}
+ const Function& caller;
};
@@ -437,7 +456,9 @@
collected_call_sites_ = &sites1;
inlining_call_sites_ = &sites2;
// Collect initial call sites.
- collected_call_sites_->FindCallSites(caller_graph_, inlining_depth_);
+ collected_call_sites_->FindCallSites(caller_graph_,
+ inlining_depth_,
+ &inlined_info_);
while (collected_call_sites_->HasCalls()) {
TRACE_INLINING(OS::Print(" Depth %" Pd " ----------\n",
inlining_depth_));
@@ -475,6 +496,11 @@
if (call_data->call->GetBlock()->try_index() !=
CatchClauseNode::kInvalidTryIndex) {
TRACE_INLINING(OS::Print(" Bailout: inside try-block\n"));
+ if (FLAG_print_inlining_tree) {
+ inlined_info_.Add(InlinedInfo(
+ &call_data->caller, &function, inlining_depth_, call_data->call,
+ "Inside try-block"));
+ }
return false;
}
@@ -484,6 +510,11 @@
// Abort if the inlinable bit on the function is low.
if (!function.IsInlineable()) {
TRACE_INLINING(OS::Print(" Bailout: not inlinable\n"));
+ if (FLAG_print_inlining_tree) {
+ inlined_info_.Add(InlinedInfo(
+ &call_data->caller, &function, inlining_depth_, call_data->call,
+ "Not inlinable"));
+ }
return false;
}
@@ -492,6 +523,11 @@
FLAG_deoptimization_counter_threshold) {
function.set_is_inlinable(false);
TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n"));
+ if (FLAG_print_inlining_tree) {
+ inlined_info_.Add(InlinedInfo(
+ &call_data->caller, &function, inlining_depth_, call_data->call,
+ "Deoptimization threshold exceeded"));
+ }
return false;
}
@@ -508,6 +544,11 @@
function.optimized_instruction_count(),
function.optimized_call_site_count(),
constant_arguments));
+ if (FLAG_print_inlining_tree) {
+ inlined_info_.Add(InlinedInfo(
+ &call_data->caller, &function, inlining_depth_, call_data->call,
+ "Early heuristic"));
+ }
return false;
}
@@ -634,10 +675,10 @@
for (intptr_t i = 0; i < param_stubs->length(); ++i) {
if ((*param_stubs)[i]->IsConstant()) ++constants_count;
}
- GraphInfoCollector info;
- info.Collect(*callee_graph);
- const intptr_t size = info.instruction_count();
- const intptr_t call_site_count = info.call_site_count();
+
+ FlowGraphInliner::CollectGraphInfo(callee_graph);
+ const intptr_t size = function.optimized_instruction_count();
+ const intptr_t call_site_count = function.optimized_call_site_count();
function.set_optimized_instruction_count(size);
function.set_optimized_call_site_count(call_site_count);
@@ -658,10 +699,17 @@
size,
call_site_count,
constants_count));
+ if (FLAG_print_inlining_tree) {
+ inlined_info_.Add(InlinedInfo(
+ &call_data->caller, &function, inlining_depth_, call_data->call,
+ "Heuristic fail"));
+ }
return false;
}
- collected_call_sites_->FindCallSites(callee_graph, inlining_depth_);
+ collected_call_sites_->FindCallSites(callee_graph,
+ inlining_depth_,
+ &inlined_info_);
// Add the function to the cache.
if (!in_cache) {
@@ -688,9 +736,9 @@
// disconnected from its function during the rest of compilation.
Code::ZoneHandle(unoptimized_code.raw());
TRACE_INLINING(OS::Print(" Success\n"));
- if (FLAG_print_inline_tree) {
+ if (FLAG_print_inlining_tree) {
inlined_info_.Add(
- InlinedInfo(&call_data->caller_, &function, inlining_depth_, call));
+ InlinedInfo(&call_data->caller, &function, inlining_depth_, call));
}
return true;
} else {
@@ -704,16 +752,24 @@
}
void PrintInlinedInfo(const Function& top) {
- OS::Print("Inlining into: %s\n", top.ToFullyQualifiedCString());
- PrintInlinedInfoFor(top, 1);
+ if (inlined_info_.length() > 0) {
+ OS::Print("Inlining into: '%s' growth: %f (%"Pd" -> %"Pd")\n",
+ top.ToFullyQualifiedCString(),
+ GrowthFactor(),
+ initial_size_,
+ inlined_size_);
+ PrintInlinedInfoFor(top, 1);
+ }
}
private:
friend class PolymorphicInliner;
void PrintInlinedInfoFor(const Function& caller, intptr_t depth) {
+ // Print those that were inlined.
for (intptr_t i = 0; i < inlined_info_.length(); i++) {
const InlinedInfo& info = inlined_info_[i];
+ if (info.bailout_reason != NULL) continue;
if ((info.inlined_depth == depth) &&
(info.caller->raw() == caller.raw())) {
for (int t = 0; t < depth; t++) {
@@ -725,6 +781,21 @@
PrintInlinedInfoFor(*info.inlined, depth + 1);
}
}
+ // Print those that were not inlined.
+ for (intptr_t i = 0; i < inlined_info_.length(); i++) {
+ const InlinedInfo& info = inlined_info_[i];
+ if (info.bailout_reason == NULL) continue;
+ if ((info.inlined_depth == depth) &&
+ (info.caller->raw() == caller.raw())) {
+ for (int t = 0; t < depth; t++) {
+ OS::Print(" ");
+ }
+ OS::Print("NO %" Pd " %s - %s\n",
+ info.call_instr->GetDeoptId(),
+ info.inlined->ToQualifiedCString(),
+ info.bailout_reason);
+ }
+ }
}
void InlineCall(InlinedCallData* call_data) {
@@ -843,6 +914,14 @@
target.ToCString(),
target.deoptimization_counter(),
call_info[call_idx].ratio));
+ if (FLAG_print_inlining_tree) {
+ inlined_info_.Add(InlinedInfo(
+ call_info[call_idx].caller,
+ &call->function(),
+ inlining_depth_,
+ call,
+ "Too cold"));
+ }
continue;
}
GrowableArray<Value*> arguments(call->ArgumentCount());
@@ -912,6 +991,14 @@
target.ToCString(),
target.deoptimization_counter(),
call_info[call_idx].ratio));
+ if (FLAG_print_inlining_tree) {
+ inlined_info_.Add(InlinedInfo(
+ call_info[call_idx].caller,
+ &target,
+ inlining_depth_,
+ call,
+ "Too cold"));
+ }
continue;
}
GrowableArray<Value*> arguments(call->ArgumentCount());
@@ -1021,7 +1108,7 @@
FlowGraph* caller_graph_;
bool inlined_;
- intptr_t initial_size_;
+ const intptr_t initial_size_;
intptr_t inlined_size_;
intptr_t inlining_depth_;
CallSites* collected_call_sites_;
@@ -1496,13 +1583,16 @@
}
-void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph) {
- GraphInfoCollector info;
- info.Collect(*flow_graph);
+void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph, bool force) {
const Function& function = flow_graph->parsed_function().function();
- function.set_optimized_instruction_count(
- ClampUint16(info.instruction_count()));
- function.set_optimized_call_site_count(ClampUint16(info.call_site_count()));
+ if (force || (function.optimized_instruction_count() == 0)) {
+ GraphInfoCollector info;
+ info.Collect(*flow_graph);
+
+ function.set_optimized_instruction_count(
+ ClampUint16(info.instruction_count()));
+ function.set_optimized_call_site_count(ClampUint16(info.call_site_count()));
+ }
}
@@ -1541,7 +1631,7 @@
CallSiteInliner inliner(flow_graph_);
inliner.InlineCalls();
- if (FLAG_print_inline_tree) {
+ if (FLAG_print_inlining_tree) {
inliner.PrintInlinedInfo(top);
}
diff --git a/runtime/vm/flow_graph_inliner.h b/runtime/vm/flow_graph_inliner.h
index e408d92..42c4fcf 100644
--- a/runtime/vm/flow_graph_inliner.h
+++ b/runtime/vm/flow_graph_inliner.h
@@ -21,7 +21,8 @@
// The flow graph is destructively updated upon inlining.
void Inline();
- static void CollectGraphInfo(FlowGraph* flow_graph);
+ // Compute graph info if it was not already computed or if 'force' is true.
+ static void CollectGraphInfo(FlowGraph* flow_graph, bool force = false);
static bool AlwaysInline(const Function& function);
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index a349017..db7cee1 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -132,7 +132,7 @@
}
-static void PrintICData(BufferFormatter* f, const ICData& ic_data) {
+static void PrintICDataHelper(BufferFormatter* f, const ICData& ic_data) {
f->Print(" IC[%" Pd ": ", ic_data.NumberOfChecks());
Function& target = Function::Handle();
for (intptr_t i = 0; i < ic_data.NumberOfChecks(); i++) {
@@ -159,6 +159,14 @@
}
+void FlowGraphPrinter::PrintICData(const ICData& ic_data) {
+ char buffer[1024];
+ BufferFormatter f(buffer, sizeof(buffer));
+ PrintICDataHelper(&f, ic_data);
+ OS::Print("%s\n", buffer);
+}
+
+
static void PrintUse(BufferFormatter* f, const Definition& definition) {
if (definition.is_used()) {
if (definition.HasSSATemp()) {
@@ -354,7 +362,7 @@
PushArgumentAt(i)->value()->PrintTo(f);
}
if (HasICData()) {
- PrintICData(f, *ic_data());
+ PrintICDataHelper(f, *ic_data());
}
}
@@ -365,7 +373,7 @@
f->Print(", ");
PushArgumentAt(i)->value()->PrintTo(f);
}
- PrintICData(f, ic_data());
+ PrintICDataHelper(f, ic_data());
}
@@ -852,7 +860,7 @@
void CheckClassInstr::PrintOperandsTo(BufferFormatter* f) const {
value()->PrintTo(f);
- PrintICData(f, unary_checks());
+ PrintICDataHelper(f, unary_checks());
if (IsNullCheck()) {
f->Print(" nullcheck");
}
diff --git a/runtime/vm/il_printer.h b/runtime/vm/il_printer.h
index 77a642f..e61f65b 100644
--- a/runtime/vm/il_printer.h
+++ b/runtime/vm/il_printer.h
@@ -57,6 +57,9 @@
static void PrintGraph(const char* phase, FlowGraph* flow_graph);
+ // Debugging helper function.
+ static void PrintICData(const ICData& ic_data);
+
private:
const Function& function_;
const GrowableArray<BlockEntryInstr*>& block_order_;
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 7e24716..7b4d385 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -2150,7 +2150,7 @@
}
-bool PolymorphicInstanceCallInstr::HasRecognizedTarget() const {
+bool PolymorphicInstanceCallInstr::HasSingleRecognizedTarget() const {
return ic_data().HasOneTarget() &&
(MethodRecognizer::RecognizeKind(
Function::Handle(ic_data().GetTargetAt(0))) !=
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index ea370fe..1177d69 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -2974,7 +2974,7 @@
return instance_call()->PushArgumentAt(index);
}
- bool HasRecognizedTarget() const;
+ bool HasSingleRecognizedTarget() const;
virtual intptr_t CallCount() const { return ic_data().AggregateCount(); }
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index 1157c78..51a4689 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -3187,6 +3187,9 @@
}
visitLiteralList(LiteralList node) {
+ bool oldSendIsMemberAccess = sendIsMemberAccess;
+ sendIsMemberAccess = false;
+
NodeList arguments = node.typeArguments;
DartType typeArgument;
if (arguments != null) {
@@ -3221,6 +3224,8 @@
if (node.isConst()) {
analyzeConstant(node);
}
+
+ sendIsMemberAccess = false;
}
visitConditional(Conditional node) {
@@ -3401,6 +3406,9 @@
}
visitLiteralMap(LiteralMap node) {
+ bool oldSendIsMemberAccess = sendIsMemberAccess;
+ sendIsMemberAccess = false;
+
NodeList arguments = node.typeArguments;
DartType keyTypeArgument;
DartType valueTypeArgument;
@@ -3445,6 +3453,8 @@
if (node.isConst()) {
analyzeConstant(node);
}
+
+ sendIsMemberAccess = false;
}
visitLiteralMapEntry(LiteralMapEntry node) {
diff --git a/sdk/lib/_internal/pub/lib/src/io.dart b/sdk/lib/_internal/pub/lib/src/io.dart
index d50e068..b054a77 100644
--- a/sdk/lib/_internal/pub/lib/src/io.dart
+++ b/sdk/lib/_internal/pub/lib/src/io.dart
@@ -256,8 +256,10 @@
isHidden(part) => part.startsWith(".") && part != "." && part != "..";
if (!includeHidden) {
- entities = entities.where(
- (entity) => !path.split(entity.path).any(isHidden));
+ entities = entities.where((entity) {
+ assert(entity.path.startsWith(dir));
+ return !path.split(entity.path.substring(dir.length + 1)).any(isHidden);
+ });
}
return entities.map((entity) => entity.path).toList();
diff --git a/sdk/lib/_internal/pub/test/io_test.dart b/sdk/lib/_internal/pub/test/io_test.dart
index a3d7b0e..cc5d2c4 100644
--- a/sdk/lib/_internal/pub/test/io_test.dart
+++ b/sdk/lib/_internal/pub/test/io_test.dart
@@ -50,6 +50,22 @@
]));
}), completes);
});
+
+ test("doesn't ignore hidden files above the directory being listed", () {
+ expect(withTempDir((temp) {
+ var dir = path.join(temp, '.foo', 'bar');
+ ensureDir(dir);
+ writeTextFile(path.join(dir, 'file1.txt'), '');
+ writeTextFile(path.join(dir, 'file2.txt'), '');
+ writeTextFile(path.join(dir, 'file3.txt'), '');
+
+ expect(listDir(dir, recursive: true), unorderedEquals([
+ path.join(dir, 'file1.txt'),
+ path.join(dir, 'file2.txt'),
+ path.join(dir, 'file3.txt')
+ ]));
+ }), completes);
+ });
});
group('canonicalize', () {
diff --git a/tests/language/first_class_types_literals_test.dart b/tests/language/first_class_types_literals_test.dart
index 8ba570a..422628a 100644
--- a/tests/language/first_class_types_literals_test.dart
+++ b/tests/language/first_class_types_literals_test.dart
@@ -15,6 +15,17 @@
}
main() {
+ void foo(a) {}
+
+ // Test that literals can be used in different contexts.
+ [int];
+ ([int]);
+ foo([int]);
+ [int].length;
+ ({1: int});
+ foo({1: int});
+ ({1: int}).keys;
+
// Test type literals.
Expect.equals(int, int);
Expect.notEquals(int, num);
diff --git a/tools/VERSION b/tools/VERSION
index b013c08..251158c 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
MINOR 3
PATCH 0
PRERELEASE 7
-PRERELEASE_PATCH 2
+PRERELEASE_PATCH 3