Version 1.5.0-dev.4.3
svn merge -c 37076 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 37077 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 37097 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 37101 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 37107 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
Merge 37105, 37104, 37095, 37042, 37022, 37016 by applying
https://codereview.chromium.org/321583008/
git-svn-id: http://dart.googlecode.com/svn/trunk@37110 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 72706ac..417a905 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -633,10 +633,12 @@
caller_code.SetStaticCallTargetCodeAt(caller_frame->pc(), target_code);
}
if (FLAG_trace_patching) {
- OS::PrintErr("PatchStaticCall: patching from %#" Px " to '%s' %#" Px "\n",
+ OS::PrintErr("PatchStaticCall: patching caller pc %#" Px ""
+ " to '%s' new entry point %#" Px " (%s)\n",
caller_frame->pc(),
target_function.ToFullyQualifiedCString(),
- target_code.EntryPoint());
+ target_code.EntryPoint(),
+ target_code.is_optimized() ? "optimized" : "unoptimized");
}
arguments.SetReturn(target_code);
}
@@ -1293,9 +1295,11 @@
caller_code.SetStaticCallTargetCodeAt(frame->pc(), current_target_code);
}
if (FLAG_trace_patching) {
- OS::PrintErr("FixCallersTarget: patching from %#" Px " to '%s' %#" Px "\n",
+ OS::PrintErr("FixCallersTarget: caller %#" Px " "
+ "target '%s' %#" Px " -> %#" Px "\n",
frame->pc(),
target_function.ToFullyQualifiedCString(),
+ target_code.EntryPoint(),
current_target_code.EntryPoint());
}
arguments.SetReturn(current_target_code);
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index da3feb1..b8805f8 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -59,6 +59,7 @@
"Enable compiler verification assertions");
DECLARE_FLAG(bool, trace_failed_optimization_attempts);
+DECLARE_FLAG(bool, trace_patching);
DECLARE_FLAG(bool, warn_on_javascript_compatibility);
DECLARE_FLAG(bool, warning_as_error);
@@ -556,8 +557,12 @@
if (optimized) {
if (osr_id == Isolate::kNoDeoptId) {
CodePatcher::PatchEntry(Code::Handle(function.CurrentCode()));
- if (FLAG_trace_compiler) {
- OS::Print("--> patching entry %#" Px "\n",
+ if (FLAG_trace_compiler || FLAG_trace_patching) {
+ if (FLAG_trace_compiler) {
+ OS::Print(" ");
+ }
+ OS::Print("Patch unoptimized '%s' entry point %#" Px "\n",
+ function.ToFullyQualifiedCString(),
Code::Handle(function.unoptimized_code()).EntryPoint());
}
}
@@ -575,11 +580,10 @@
ASSERT(CodePatcher::CodeIsPatchable(code));
}
if (parsed_function->HasDeferredPrefixes()) {
- GrowableObjectArray* prefixes = parsed_function->DeferredPrefixes();
- LibraryPrefix& prefix = LibraryPrefix::Handle();
- for (intptr_t i = 0; i < prefixes->Length(); i++) {
- prefix ^= prefixes->At(i);
- prefix.RegisterDependentCode(code);
+ ZoneGrowableArray<const LibraryPrefix*>* prefixes =
+ parsed_function->deferred_prefixes();
+ for (intptr_t i = 0; i < prefixes->length(); i++) {
+ (*prefixes)[i]->RegisterDependentCode(code);
}
}
}
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index afaffa1..c0c74a6 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -42,7 +42,8 @@
use_far_branches_(false),
loop_headers_(NULL),
loop_invariant_loads_(NULL),
- guarded_fields_(builder.guarded_fields()) {
+ guarded_fields_(builder.guarded_fields()),
+ deferred_prefixes_(builder.deferred_prefixes()) {
DiscoverBlocks();
}
@@ -63,6 +64,21 @@
}
+void FlowGraph::AddToDeferredPrefixes(
+ ZoneGrowableArray<const LibraryPrefix*>* from) {
+ ZoneGrowableArray<const LibraryPrefix*>* to = deferred_prefixes();
+ for (intptr_t i = 0; i < from->length(); i++) {
+ const LibraryPrefix* prefix = (*from)[i];
+ for (intptr_t j = 0; j < to->length(); j++) {
+ if ((*to)[j]->raw() == prefix->raw()) {
+ return;
+ }
+ }
+ to->Add(prefix);
+ }
+}
+
+
bool FlowGraph::ShouldReorderBlocks(const Function& function,
bool is_optimized) {
return is_optimized && FLAG_reorder_basic_blocks && !function.is_intrinsic();
diff --git a/runtime/vm/flow_graph.h b/runtime/vm/flow_graph.h
index 9d2d42e..1868d0a 100644
--- a/runtime/vm/flow_graph.h
+++ b/runtime/vm/flow_graph.h
@@ -216,11 +216,16 @@
static void AddToGuardedFields(ZoneGrowableArray<const Field*>* array,
const Field* field);
+ void AddToDeferredPrefixes(ZoneGrowableArray<const LibraryPrefix*>* from);
ZoneGrowableArray<const Field*>* guarded_fields() const {
return guarded_fields_;
}
+ ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes() const {
+ return deferred_prefixes_;
+ }
+
private:
friend class IfConverter;
friend class BranchSimplifier;
@@ -300,6 +305,7 @@
ZoneGrowableArray<BlockEntryInstr*>* loop_headers_;
ZoneGrowableArray<BitVector*>* loop_invariant_loads_;
ZoneGrowableArray<const Field*>* guarded_fields_;
+ ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes_;
};
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index 7632971..8467cb5 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -199,6 +199,10 @@
return guarded_fields_;
}
+ ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes() const {
+ return parsed_function_->deferred_prefixes();
+ }
+
intptr_t temp_count() const { return temp_count_; }
intptr_t AllocateTemp() { return temp_count_++; }
void DeallocateTemps(intptr_t count) {
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index b07c635..11fedc1 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -802,6 +802,9 @@
FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(),
(*callee_graph->guarded_fields())[i]);
}
+ // When inlined, we add the deferred prefixes of the callee to the
+ // caller's list of deferred prefixes.
+ caller_graph()->AddToDeferredPrefixes(callee_graph->deferred_prefixes());
// We allocate a ZoneHandle for the unoptimized code so that it cannot be
// disconnected from its function during the rest of compilation.
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 2f9559b..cc02d9a 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -2523,6 +2523,13 @@
if (!CodePatcher::IsEntryPatched(code)) {
CodePatcher::PatchEntry(code);
}
+ } else if (!function.HasCode() && (code.GetEntryPatchPc() != 0)) {
+ // The code has already been disconnected, make it invalid. Do not
+ // bother with OSR compiled code that has no valid entry-patch.
+ ReportSwitchingCode(code);
+ if (!CodePatcher::IsEntryPatched(code)) {
+ CodePatcher::PatchEntry(code);
+ }
}
}
}
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 8667c20..c41e5c1 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -135,16 +135,12 @@
void ParsedFunction::AddDeferredPrefix(const LibraryPrefix& prefix) {
ASSERT(prefix.is_deferred_load());
ASSERT(!prefix.is_loaded());
- if (deferred_prefixes_ == NULL) {
- deferred_prefixes_ =
- &GrowableObjectArray::ZoneHandle(GrowableObjectArray::New());
- }
- for (intptr_t i = 0; i < deferred_prefixes_->Length(); i++) {
- if (deferred_prefixes_->At(i) == prefix.raw()) {
+ for (intptr_t i = 0; i < deferred_prefixes_->length(); i++) {
+ if ((*deferred_prefixes_)[i]->raw() == prefix.raw()) {
return;
}
}
- deferred_prefixes_->Add(prefix);
+ deferred_prefixes_->Add(&LibraryPrefix::ZoneHandle(I, prefix.raw()));
}
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index f187032..15de41f 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -47,7 +47,7 @@
saved_current_context_var_(NULL),
saved_entry_context_var_(NULL),
expression_temp_var_(NULL),
- deferred_prefixes_(NULL),
+ deferred_prefixes_(new ZoneGrowableArray<const LibraryPrefix*>()),
first_parameter_index_(0),
first_stack_local_index_(0),
num_copied_params_(0),
@@ -110,8 +110,10 @@
static LocalVariable* CreateExpressionTempVar(intptr_t token_pos);
LocalVariable* EnsureExpressionTemp();
- bool HasDeferredPrefixes() const { return deferred_prefixes_ != NULL; }
- GrowableObjectArray* DeferredPrefixes() const { return deferred_prefixes_; }
+ bool HasDeferredPrefixes() const { return deferred_prefixes_->length() != 0; }
+ ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes() const {
+ return deferred_prefixes_;
+ }
void AddDeferredPrefix(const LibraryPrefix& prefix);
int first_parameter_index() const { return first_parameter_index_; }
@@ -132,7 +134,7 @@
LocalVariable* saved_current_context_var_;
LocalVariable* saved_entry_context_var_;
LocalVariable* expression_temp_var_;
- GrowableObjectArray* deferred_prefixes_;
+ ZoneGrowableArray<const LibraryPrefix*>* deferred_prefixes_;
int first_parameter_index_;
int first_stack_local_index_;
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart
index e067fe3..79106ff 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart
@@ -292,6 +292,12 @@
bailout('Used as key in Map');
}
+ if (info.targetsIncludeNoSuchMethod &&
+ info.arguments != null &&
+ info.arguments.contains(currentUser)) {
+ bailout('Passed to noSuchMethod');
+ }
+
Iterable<Element> inferredTargetTypes = info.targets.map((element) {
return inferrer.types.getInferredTypeOf(element);
});
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart
index 355ca78..f8d4594 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart
@@ -248,6 +248,19 @@
});
}
+ String getInferredSignatureOf(FunctionElement function) {
+ ElementTypeInformation info = getInferredTypeOf(function);
+ FunctionElement impl = function.implementation;
+ FunctionSignature signature = impl.functionSignature;
+ var res = "";
+ signature.forEachParameter((Element parameter) {
+ TypeInformation type = getInferredTypeOf(parameter);
+ res += "${res.isEmpty ? '(' : ', '}${type.type} ${parameter.name}";
+ });
+ res += ") -> ${info.type}";
+ return res;
+ }
+
TypeInformation nonNullSubtype(ClassElement type) {
return getConcreteTypeFor(new TypeMask.nonNullSubtype(type.declaration));
}
@@ -640,6 +653,25 @@
'at ${(info.type as MapTypeMask).allocationElement} '
'after ${info.refineCount}');
});
+ types.allocatedClosures.forEach((TypeInformation info) {
+ if (info is ElementTypeInformation) {
+ print('${types.getInferredSignatureOf(info.element)} for '
+ '${info.element}');
+ } else if (info is ClosureTypeInformation) {
+ print('${types.getInferredSignatureOf(info.element)} for '
+ '${info.element}');
+ } else if (info is DynamicCallSiteTypeInformation) {
+ for (Element target in info.targets) {
+ if (target is FunctionElement) {
+ print('${types.getInferredSignatureOf(target)} for ${target}');
+ } else {
+ print('${types.getInferredTypeOf(target).type} for ${target}');
+ }
+ }
+ } else {
+ print('${info.type} for some unknown kind of closure');
+ }
+ });
analyzedElements.forEach((Element elem) {
TypeInformation type = types.getInferredTypeOf(elem);
print('${elem} :: ${type} from ${type.assignments} ');
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
index 26dd4d1..ead1c4a 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
@@ -562,6 +562,14 @@
}
}
+ bool get targetsIncludeNoSuchMethod {
+ return targets.any((Element e) {
+ return e is FunctionElement &&
+ e.isInstanceMember &&
+ e.name == Compiler.NO_SUCH_METHOD;
+ });
+ }
+
/**
* We optimize certain operations on the [int] class because we know
* more about their return type than the actual Dart code. For
diff --git a/sdk/lib/_internal/compiler/implementation/source_map_builder.dart b/sdk/lib/_internal/compiler/implementation/source_map_builder.dart
index 16697e9..b486a1c 100644
--- a/sdk/lib/_internal/compiler/implementation/source_map_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/source_map_builder.dart
@@ -183,15 +183,15 @@
encodeVLQ(output, sourceUrlIndex - previousSourceUrlIndex);
encodeVLQ(output, sourceLine - previousSourceLine);
encodeVLQ(output, sourceColumn - previousSourceColumn);
- updatePreviousSourceLocation(entry.sourceLocation);
- if (sourceName == null) {
- return;
+ if (sourceName != null) {
+ int sourceNameIndex = indexOf(sourceNameList, sourceName, sourceNameMap);
+ encodeVLQ(output, sourceNameIndex - previousSourceNameIndex);
}
- int sourceNameIndex = indexOf(sourceNameList, sourceName, sourceNameMap);
- encodeVLQ(output, sourceNameIndex - previousSourceNameIndex);
-
+ // Update previous source location to ensure the next indices are relative
+ // to those if [entry.sourceLocation].
+ updatePreviousSourceLocation(entry.sourceLocation);
}
int indexOf(List<String> list, String value, Map<String, int> map) {
@@ -254,14 +254,14 @@
class TokenSourceFileLocation extends SourceFileLocation {
final Token token;
+ final String name;
- TokenSourceFileLocation(SourceFile sourceFile, this.token)
+ TokenSourceFileLocation(SourceFile sourceFile, this.token, this.name)
: super(sourceFile);
int get offset => token.charOffset;
String getSourceName() {
- if (token.isIdentifier()) return token.value;
- return null;
+ return name;
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 2b87a74..6f004fe 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -1052,14 +1052,7 @@
}
SourceFile currentSourceFile() {
- Element element = sourceElement;
- // TODO(johnniwinther): remove the 'element.patch' hack.
- if (element is FunctionElement) {
- FunctionElement functionElement = element;
- if (functionElement.patch != null) element = functionElement.patch;
- }
- Script script = element.compilationUnit.script;
- return script.file;
+ return sourceElement.implementation.compilationUnit.script.file;
}
void checkValidSourceFileLocation(
@@ -2307,7 +2300,7 @@
SourceFileLocation sourceFileLocationForToken(ast.Node node, Token token) {
SourceFile sourceFile = currentSourceFile();
SourceFileLocation location =
- new TokenSourceFileLocation(sourceFile, token);
+ new TokenSourceFileLocation(sourceFile, token, sourceElement.name);
checkValidSourceFileLocation(location, sourceFile, token.charOffset);
return location;
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 8a9fd0f..30a0d9a9 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -19,6 +19,7 @@
// TODO(sra): Attaching positions might be cleaner if the source position
// was on a wrapping node.
SourceFile sourceFile = sourceFileOfElement(element);
+ String name = element.name;
AstElement implementation = element.implementation;
ast.Node expression = implementation.node;
Token beginToken;
@@ -34,21 +35,18 @@
// checks below.
var sourcePosition, endSourcePosition;
if (beginToken.charOffset < sourceFile.length) {
- sourcePosition = new TokenSourceFileLocation(sourceFile, beginToken);
+ sourcePosition =
+ new TokenSourceFileLocation(sourceFile, beginToken, name);
}
if (endToken.charOffset < sourceFile.length) {
- endSourcePosition = new TokenSourceFileLocation(sourceFile, endToken);
+ endSourcePosition =
+ new TokenSourceFileLocation(sourceFile, endToken, name);
}
return node.withPosition(sourcePosition, endSourcePosition);
}
SourceFile sourceFileOfElement(Element element) {
- // TODO(johnniwinther): remove the 'element.patch' hack.
- FunctionElement functionElement = element.asFunctionElement();
- if (functionElement != null && functionElement.patch != null) {
- element = functionElement.patch;
- }
- return element.compilationUnit.script.file;
+ return element.implementation.compilationUnit.script.file;
}
js.Fun buildJavaScriptFunction(FunctionElement element,
diff --git a/tests/compiler/dart2js_extra/19191_test.dart b/tests/compiler/dart2js_extra/19191_test.dart
new file mode 100644
index 0000000..a5c4b56
--- /dev/null
+++ b/tests/compiler/dart2js_extra/19191_test.dart
@@ -0,0 +1,41 @@
+// Copyright (c) 2014, 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.
+
+// Regression test for http://dartbug.com/19191
+
+class A {
+ var method;
+
+ noSuchMethod(Invocation invocation) {
+ if (invocation.isGetter) {
+ return method;
+ } else if (invocation.isSetter) {
+ method = invocation.positionalArguments[0];
+ return null;
+ } else if (invocation.isMethod) {
+ return Function.apply(method, invocation.positionalArguments,
+ invocation.namedArguments);
+ } else {
+ throw new NoSuchMethodError(this, invocation.memberName,
+ invocation.positionalArguments, invocation.namedArguments);
+ }
+ }
+
+ init() {
+ closure_fails = (String str) {
+ return str.toUpperCase();
+ };
+ }
+
+ run() {
+ print(closure_fails("Hello World"));
+ }
+}
+
+void main() {
+ var a = new A();
+ a.init();
+ a.run();
+}
+
diff --git a/tests/language/deferred_inlined_test.dart b/tests/language/deferred_inlined_test.dart
new file mode 100644
index 0000000..4808a3f
--- /dev/null
+++ b/tests/language/deferred_inlined_test.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2014, 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.
+// VMOptions=--optimization-counter-threshold=10
+
+// Declares foo that returns 42.
+import "deferred_constraints_lib2.dart" deferred as lib;
+
+import 'package:expect/expect.dart';
+
+bool libLoaded = false;
+
+main() {
+ Expect.equals(88, heyhey());
+
+ // Trigger optimization of 'hehey' which inlines 'barbar'.
+ for (int i = 0; i < 30000; i++) {
+ heyhey();
+ }
+
+ lib.loadLibrary().then((_) {
+ libLoaded = true;
+ Expect.equals(42, heyhey());
+ });
+}
+
+
+// Inline bar in optimized code.
+heyhey() => barbar();
+
+
+barbar() {
+ if (libLoaded) {
+ // Returns 42.
+ return lib.foo();
+ }
+ return 88;
+}
\ No newline at end of file
diff --git a/tests/language/deferred_optimized_test.dart b/tests/language/deferred_optimized_test.dart
new file mode 100644
index 0000000..ef3c2a0
--- /dev/null
+++ b/tests/language/deferred_optimized_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2014, 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.
+// VMOptions=--optimization-counter-threshold=10 --no-use-inlining
+
+// Declares foo that returns 42.
+import "deferred_constraints_lib2.dart" deferred as lib;
+
+import 'package:expect/expect.dart';
+
+bool libLoaded = false;
+
+main() {
+ Expect.equals(88, heyhey());
+
+ for (int i = 0; i < 30; i++) {
+ heyhey();
+ }
+
+ lib.loadLibrary().then((_) {
+ libLoaded = true;
+ Expect.equals(42, heyhey());
+ });
+}
+
+
+heyhey() => barbar();
+
+
+barbar() {
+ if (libLoaded) {
+ // Returns 42.
+ return lib.foo();
+ }
+ return 88;
+}
\ No newline at end of file
diff --git a/tools/VERSION b/tools/VERSION
index bbd311b..dbc0a4a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
MINOR 5
PATCH 0
PRERELEASE 4
-PRERELEASE_PATCH 2
+PRERELEASE_PATCH 3