Version 2.14.0-163.0.dev
Merge commit '0e5417a48fa9ca32c5e617c570a4712eb3b18c34' into 'dev'
diff --git a/BUILD.gn b/BUILD.gn
index c25c176..6c26e7e 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -61,6 +61,10 @@
"utils/dds:dds",
]
}
+
+ if (is_linux || is_android) {
+ deps += [ "runtime/bin:abstract_socket_test" ]
+ }
}
# A separate target and not included in group("runtime"). This way the target\
@@ -82,6 +86,9 @@
"runtime/bin:dart_precompiled_runtime",
"runtime/bin:process_test",
]
+ if (is_linux || is_android) {
+ deps += [ "runtime/bin:abstract_socket_test" ]
+ }
}
group("create_sdk") {
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 852469a..e41c39c 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -751,11 +751,6 @@
ConstructorElement? getNamedConstructor(String name) =>
getNamedConstructorFromList(name, constructors);
- void resetMixinApplicationConstructors() {
- assert(isMixinApplication);
- _constructors = _Sentinel.constructorElement;
- }
-
void setLinkedData(Reference reference, ElementLinkedData linkedData) {
this.reference = reference;
reference.element = this;
diff --git a/pkg/analyzer/lib/src/summary2/informative_data.dart b/pkg/analyzer/lib/src/summary2/informative_data.dart
index 35eb1dd..132f6fd 100644
--- a/pkg/analyzer/lib/src/summary2/informative_data.dart
+++ b/pkg/analyzer/lib/src/summary2/informative_data.dart
@@ -13,6 +13,7 @@
import 'package:analyzer/src/summary2/data_reader.dart';
import 'package:analyzer/src/summary2/data_writer.dart';
import 'package:analyzer/src/summary2/linked_element_factory.dart';
+import 'package:analyzer/src/util/collection.dart';
import 'package:analyzer/src/util/comment.dart';
import 'package:collection/collection.dart';
@@ -56,7 +57,7 @@
_applyToAccessors(unitElement.accessors, unitInfo.accessors);
- _forEach2(
+ forCorrespondingPairs(
unitElement.types
.where((element) => !element.isMixinApplication)
.toList(),
@@ -64,7 +65,7 @@
_applyToClassDeclaration,
);
- _forEach2(
+ forCorrespondingPairs(
unitElement.types
.where((element) => element.isMixinApplication)
.toList(),
@@ -72,21 +73,22 @@
_applyToClassTypeAlias,
);
- _forEach2(unitElement.enums, unitInfo.enums, _applyToEnumDeclaration);
+ forCorrespondingPairs(
+ unitElement.enums, unitInfo.enums, _applyToEnumDeclaration);
- _forEach2(unitElement.extensions, unitInfo.extensions,
+ forCorrespondingPairs(unitElement.extensions, unitInfo.extensions,
_applyToExtensionDeclaration);
- _forEach2(unitElement.functions, unitInfo.functions,
+ forCorrespondingPairs(unitElement.functions, unitInfo.functions,
_applyToFunctionDeclaration);
- _forEach2(unitElement.mixins, unitInfo.mixinDeclarations,
+ forCorrespondingPairs(unitElement.mixins, unitInfo.mixinDeclarations,
_applyToMixinDeclaration);
- _forEach2(unitElement.topLevelVariables, unitInfo.topLevelVariable,
- _applyToTopLevelVariable);
+ forCorrespondingPairs(unitElement.topLevelVariables,
+ unitInfo.topLevelVariable, _applyToTopLevelVariable);
- _forEach2(
+ forCorrespondingPairs(
unitElement.typeAliases
.cast<TypeAliasElementImpl>()
.where((e) => e.isFunctionTypeAliasBased)
@@ -95,7 +97,7 @@
_applyToFunctionTypeAlias,
);
- _forEach2(
+ forCorrespondingPairs(
unitElement.typeAliases
.cast<TypeAliasElementImpl>()
.where((e) => !e.isFunctionTypeAliasBased)
@@ -113,7 +115,7 @@
List<PropertyAccessorElement> elementList,
List<_InfoMethodDeclaration> infoList,
) {
- _forEach2<PropertyAccessorElement, _InfoMethodDeclaration>(
+ forCorrespondingPairs<PropertyAccessorElement, _InfoMethodDeclaration>(
elementList.notSynthetic,
infoList,
(element, info) {
@@ -169,7 +171,7 @@
List<NamespaceCombinator> elementList,
List<_InfoCombinator> infoList,
) {
- _forEach2<NamespaceCombinator, _InfoCombinator>(
+ forCorrespondingPairs<NamespaceCombinator, _InfoCombinator>(
elementList,
infoList,
(element, info) {
@@ -185,7 +187,7 @@
List<ConstructorElement> elementList,
List<_InfoConstructorDeclaration> infoList,
) {
- _forEach2<ConstructorElement, _InfoConstructorDeclaration>(
+ forCorrespondingPairs<ConstructorElement, _InfoConstructorDeclaration>(
elementList,
infoList,
(element, info) {
@@ -212,7 +214,7 @@
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
- _forEach2<FieldElement, _InfoEnumConstantDeclaration>(
+ forCorrespondingPairs<FieldElement, _InfoEnumConstantDeclaration>(
element.constants_unresolved,
info.constants,
(element, info) {
@@ -245,7 +247,7 @@
List<FieldElement> elementList,
List<_InfoFieldDeclaration> infoList,
) {
- _forEach2<FieldElement, _InfoFieldDeclaration>(
+ forCorrespondingPairs<FieldElement, _InfoFieldDeclaration>(
elementList.notSynthetic,
infoList,
(element, info) {
@@ -265,7 +267,7 @@
List<ParameterElement> parameters,
List<_InfoFormalParameter> infoList,
) {
- _forEach2<ParameterElement, _InfoFormalParameter>(
+ forCorrespondingPairs<ParameterElement, _InfoFormalParameter>(
parameters,
infoList,
(element, info) {
@@ -332,7 +334,7 @@
element.documentationComment = info.docComment;
}
- _forEach2<ImportElement, _InfoImport>(
+ forCorrespondingPairs<ImportElement, _InfoImport>(
element.imports_unresolved,
info.imports,
(element, info) {
@@ -349,7 +351,7 @@
},
);
- _forEach2<ExportElement, _InfoExport>(
+ forCorrespondingPairs<ExportElement, _InfoExport>(
element.exports_unresolved,
info.exports,
(element, info) {
@@ -364,7 +366,7 @@
List<MethodElement> elementList,
List<_InfoMethodDeclaration> infoList,
) {
- _forEach2<MethodElement, _InfoMethodDeclaration>(
+ forCorrespondingPairs<MethodElement, _InfoMethodDeclaration>(
elementList,
infoList,
(element, info) {
@@ -420,7 +422,7 @@
List<TypeParameterElement> elementList,
List<_InfoTypeParameter> infoList,
) {
- _forEach2<TypeParameterElement, _InfoTypeParameter>(
+ forCorrespondingPairs<TypeParameterElement, _InfoTypeParameter>(
elementList,
infoList,
(element, info) {
@@ -430,18 +432,6 @@
},
);
}
-
- static void _forEach2<T1, T2>(
- List<T1> list1,
- List<T2> list2,
- void Function(T1, T2) f,
- ) {
- var i1 = list1.iterator;
- var i2 = list2.iterator;
- while (i1.moveNext() && i2.moveNext()) {
- f(i1.current, i2.current);
- }
- }
}
class _InfoClassDeclaration {
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
index 7fe4fe8..577d10f 100644
--- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -11,6 +11,7 @@
import 'package:analyzer/src/dart/ast/extensions.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/summary/link.dart' as graph
show DependencyWalker, Node;
@@ -19,6 +20,8 @@
import 'package:analyzer/src/summary2/linking_node_scope.dart';
import 'package:analyzer/src/task/inference_error.dart';
import 'package:analyzer/src/task/strong_mode.dart';
+import 'package:analyzer/src/util/collection.dart';
+import 'package:analyzer/src/utilities/extensions/collection.dart';
import 'package:collection/collection.dart';
/// Resolver for typed constant top-level variables and fields initializers.
@@ -118,11 +121,23 @@
}
}
+/// Information about a base constructor of a mixin application.
+class _BaseConstructor {
+ final InterfaceType superType;
+ final ConstructorElement element;
+
+ _BaseConstructor(this.superType, this.element);
+}
+
class _ConstructorInferenceNode extends _InferenceNode {
final _InferenceWalker _walker;
final ConstructorElement _constructor;
final List<_FieldFormalParameterWithField> _parameters = [];
+ /// If this node is a constructor of a mixin application, this field
+ /// is the corresponding constructor of the superclass.
+ _BaseConstructor? _baseConstructor;
+
@override
bool isEvaluated = false;
@@ -139,6 +154,21 @@
}
}
}
+
+ var classElement = _constructor.enclosingElement;
+ if (classElement.isMixinApplication) {
+ var superType = classElement.supertype;
+ if (superType != null) {
+ var index = classElement.constructors.indexOf(_constructor);
+ var superConstructors = superType.element.constructors;
+ if (index < superConstructors.length) {
+ _baseConstructor = _BaseConstructor(
+ superType,
+ superConstructors[index],
+ );
+ }
+ }
+ }
}
@override
@@ -146,10 +176,16 @@
@override
List<_InferenceNode> computeDependencies() {
- return _parameters
+ var dependencies = _parameters
.map((e) => _walker.getNode(e.field))
.whereNotNull()
.toList();
+
+ dependencies.addIfNotNull(
+ _walker.getNode(_baseConstructor?.element),
+ );
+
+ return dependencies;
}
@override
@@ -158,6 +194,24 @@
var parameter = parameterWithField.parameter;
parameter.type = parameterWithField.field.type;
}
+
+ // We have inferred formal parameter types of the base constructor.
+ // Update types of a mixin application constructor formal parameters.
+ var baseConstructor = _baseConstructor;
+ if (baseConstructor != null) {
+ var substitution = Substitution.fromInterfaceType(
+ baseConstructor.superType,
+ );
+ forCorrespondingPairs<ParameterElement, ParameterElement>(
+ _constructor.parameters,
+ baseConstructor.element.parameters,
+ (parameter, baseParameter) {
+ var type = substitution.substituteType(baseParameter.type);
+ (parameter as ParameterElementImpl).type = type;
+ },
+ );
+ }
+
isEvaluated = true;
}
@@ -241,7 +295,7 @@
}
}
- _InferenceNode? getNode(Element element) {
+ _InferenceNode? getNode(Element? element) {
return _nodes[element];
}
@@ -282,7 +336,6 @@
void perform() {
_walker.walkNodes();
- _resetMixinApplicationConstructors();
}
void _addClassConstructorFieldFormals(ClassElement class_) {
@@ -327,28 +380,6 @@
(element as PropertyInducingElementImpl).type = DynamicTypeImpl.instance;
}
}
-
- /// This is necessary to work around the ordering issue - we infer types
- /// of fields and types of field formal parameters in constructors as one
- /// graph walking operation. So, we ask for mixin application constructors,
- /// and copy not-yet-computed types of formal parameters from base classes.
- ///
- /// Here we reset constructors, so that when we create them again, we will
- /// get inferred types of formal parameters.
- ///
- /// TODO(scheglov) Ideally we should use correct ordering instead.
- void _resetMixinApplicationConstructors() {
- for (var builder in _linker.builders.values) {
- for (var unitElement in builder.element.units) {
- for (var classElement in unitElement.types) {
- if (classElement is ClassElementImpl &&
- classElement.isMixinApplication) {
- classElement.resetMixinApplicationConstructors();
- }
- }
- }
- }
- }
}
class _PropertyInducingElementTypeInference
diff --git a/pkg/analyzer/lib/src/util/collection.dart b/pkg/analyzer/lib/src/util/collection.dart
new file mode 100644
index 0000000..7e132cf
--- /dev/null
+++ b/pkg/analyzer/lib/src/util/collection.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2021, 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.
+
+/// Call [f] for each corresponding pair of elements from [list1] and [list2].
+///
+/// If one of the lists has less elements than other, the remainder is ignored.
+void forCorrespondingPairs<T1, T2>(
+ List<T1> list1,
+ List<T2> list2,
+ void Function(T1, T2) f,
+) {
+ var i1 = list1.iterator;
+ var i2 = list2.iterator;
+ while (i1.moveNext() && i2.moveNext()) {
+ f(i1.current, i2.current);
+ }
+}
diff --git a/pkg/analyzer/lib/src/utilities/extensions/collection.dart b/pkg/analyzer/lib/src/utilities/extensions/collection.dart
new file mode 100644
index 0000000..091d858
--- /dev/null
+++ b/pkg/analyzer/lib/src/utilities/extensions/collection.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2021, 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.
+
+extension ListExtension<E> on List<E> {
+ void addIfNotNull(E? element) {
+ if (element != null) {
+ add(element);
+ }
+ }
+}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 8cd8eb7..590f551 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -13119,10 +13119,6 @@
''');
}
- @FailingTest(reason: '''
-Synthetic mixin application constructors are created before types of fields
-are inferred.
-''')
test_type_inference_field_depends_onFieldFormal_withMixinApp() async {
var library = await checkLibrary('''
class A<T> {
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index 42d895a..ff820cf 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -875,6 +875,11 @@
sources = [ "process_test.cc" ]
}
+executable("abstract_socket_test") {
+ sources = [ "abstract_socket_test.cc" ]
+ include_dirs = [ ".." ]
+}
+
executable("run_vm_tests") {
if (target_os == "fuchsia") {
testonly = true
diff --git a/runtime/bin/abstract_socket_test.cc b/runtime/bin/abstract_socket_test.cc
new file mode 100644
index 0000000..7af06b6
--- /dev/null
+++ b/runtime/bin/abstract_socket_test.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2021, 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.
+
+// This is a utility program for testing that a Dart program can connect to an
+// abstract UNIX socket created by a non-Dart program. It creates such a socket
+// accepts one connection, echoes back the first message it receives, and then
+// closes the connection and UNIX socket.
+
+#include "platform/globals.h"
+#if defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+const intptr_t kOffsetOfPtr = 32;
+
+#define OFFSET_OF(type, field) \
+ (reinterpret_cast<intptr_t>( \
+ &(reinterpret_cast<type*>(kOffsetOfPtr)->field)) - \
+ kOffsetOfPtr) // NOLINT
+
+int main(int argc, char* argv[]) {
+ struct sockaddr_un addr;
+ char* socket_path;
+ int server_socket;
+ char buf[1024];
+
+ if (argc < 2) {
+ fprintf(
+ stderr,
+ "Usage: abstract_socket_test <address>\n\n"
+ "<address> should be an abstract UNIX socket address like @hidden\n");
+ exit(-1);
+ }
+
+ socket_path = argv[1];
+ if (socket_path[0] != '@') {
+ fprintf(stderr,
+ "The first argument should be an abstract socket "
+ "address and start with '@'\n");
+ exit(-1);
+ }
+
+ if ((server_socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ perror("socket error");
+ exit(-1);
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ addr.sun_path[0] = '\0';
+ strncpy(addr.sun_path + 1, socket_path + 1, sizeof(addr.sun_path) - 2);
+
+ int address_length =
+ OFFSET_OF(struct sockaddr_un, sun_path) + strlen(socket_path);
+ if (bind(server_socket, (struct sockaddr*)&addr, address_length) == -1) {
+ perror("bind error");
+ exit(-1);
+ }
+
+ if (listen(server_socket, 5) == -1) {
+ perror("listen error");
+ exit(-1);
+ }
+
+ int client_socket;
+ if ((client_socket = accept(server_socket, NULL, NULL)) == -1) {
+ perror("accept error");
+ exit(-1);
+ }
+
+ int read_count;
+ while ((read_count = read(client_socket, buf, sizeof(buf))) > 0) {
+ int write_count = 0;
+ while (write_count < read_count) {
+ int w;
+ if ((w = write(client_socket, buf, read_count)) < 0) {
+ perror("write");
+ exit(-1);
+ }
+ write_count += w;
+ }
+ }
+ if (read_count == -1) {
+ perror("read");
+ exit(-1);
+ }
+
+ close(client_socket);
+ close(server_socket);
+ return 0;
+}
+
+#else
+
+int main() {
+ return -1;
+}
+
+#endif // defined(HOST_OS_LINUX) || defined(HOST_OS_ANDROID)
diff --git a/runtime/bin/socket_base.cc b/runtime/bin/socket_base.cc
index e90b138..7a62ab8 100644
--- a/runtime/bin/socket_base.cc
+++ b/runtime/bin/socket_base.cc
@@ -42,8 +42,26 @@
return sizeof(struct sockaddr_in6);
case AF_INET:
return sizeof(struct sockaddr_in);
- case AF_UNIX:
- return sizeof(struct sockaddr_un);
+ case AF_UNIX: {
+ // For an abstract UNIX socket, trailing null bytes in the name are
+ // meaningful. That is, the bytes '\0/tmp/dbus-xxxx' are a different name
+ // than '\0/tmp/dbus-xxxx\0\0\0...'. The length of the address structure
+ // passed to connect() etc. tells those calls how many bytes of the name
+ // to look at. Therefore, when computing the length of the address in
+ // this case, any trailing null bytes are trimmed.
+ // TODO(dart:io): Support abstract UNIX socket addresses that have
+ // trailing null bytes on purpose.
+ // https://github.com/dart-lang/sdk/issues/46158
+ intptr_t nulls = 0;
+ if (addr.un.sun_path[0] == '\0') {
+ intptr_t i = sizeof(addr.un.sun_path) - 1;
+ while (addr.un.sun_path[i] == '\0') {
+ nulls++;
+ i--;
+ }
+ }
+ return sizeof(struct sockaddr_un) - nulls;
+ }
default:
UNREACHABLE();
return 0;
diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc
index e6b7e5c..686852f 100644
--- a/runtime/bin/socket_linux.cc
+++ b/runtime/bin/socket_linux.cc
@@ -223,7 +223,7 @@
intptr_t backlog) {
intptr_t fd = Create(addr);
if (NO_RETRY_EXPECTED(bind(fd, (struct sockaddr*)&addr.un,
- sizeof(struct sockaddr_un))) < 0) {
+ SocketAddress::GetAddrLength(addr))) < 0) {
FDUtils::SaveErrorAndClose(fd);
return -1;
}
diff --git a/runtime/tests/vm/dart/transferable_throws_oom_test.dart b/runtime/tests/vm/dart/transferable_throws_oom_test.dart
index 6930795..8e95792 100644
--- a/runtime/tests/vm/dart/transferable_throws_oom_test.dart
+++ b/runtime/tests/vm/dart/transferable_throws_oom_test.dart
@@ -26,7 +26,7 @@
// Attempt to create total 1tb uint8list which should fail on 32 and 64-bit
// platforms.
final bytes100MB = Uint8List(100 * 1024 * 1024);
- final total1TB = List<Uint8List>.filled(10000, bytes100MB);
- // Try to make a 1 TB transferable.
- Expect.throws(() => TransferableTypedData.fromList(total1TB));
+ final total1PB = List<Uint8List>.filled(10 * 1000 * 1000, bytes100MB);
+ // Try to make a 1 PB transferable.
+ Expect.throws(() => TransferableTypedData.fromList(total1PB));
}
diff --git a/runtime/tests/vm/dart_2/transferable_throws_oom_test.dart b/runtime/tests/vm/dart_2/transferable_throws_oom_test.dart
index 6930795..8e95792 100644
--- a/runtime/tests/vm/dart_2/transferable_throws_oom_test.dart
+++ b/runtime/tests/vm/dart_2/transferable_throws_oom_test.dart
@@ -26,7 +26,7 @@
// Attempt to create total 1tb uint8list which should fail on 32 and 64-bit
// platforms.
final bytes100MB = Uint8List(100 * 1024 * 1024);
- final total1TB = List<Uint8List>.filled(10000, bytes100MB);
- // Try to make a 1 TB transferable.
- Expect.throws(() => TransferableTypedData.fromList(total1TB));
+ final total1PB = List<Uint8List>.filled(10 * 1000 * 1000, bytes100MB);
+ // Try to make a 1 PB transferable.
+ Expect.throws(() => TransferableTypedData.fromList(total1PB));
}
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 62f28bc..55da50a 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -3264,6 +3264,12 @@
}
}
+ if ((speculative_mode_ == kGuardInputs) && !ComputeCanDeoptimize()) {
+ // Remember if we ever learn out input doesn't require checking, as
+ // the input Value might be later changed that would make us forget.
+ speculative_mode_ = kNotSpeculative;
+ }
+
return this;
}
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 823d9da..a0b3cd1 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -7118,8 +7118,9 @@
intptr_t ValueOffset() const { return Boxing::ValueOffset(representation_); }
+ protected:
const Representation representation_;
- const SpeculativeMode speculative_mode_;
+ SpeculativeMode speculative_mode_;
DISALLOW_COPY_AND_ASSIGN(UnboxInstr);
};
diff --git a/runtime/vm/compiler/backend/il_printer.cc b/runtime/vm/compiler/backend/il_printer.cc
index 02c1790..8f9792f 100644
--- a/runtime/vm/compiler/backend/il_printer.cc
+++ b/runtime/vm/compiler/backend/il_printer.cc
@@ -989,6 +989,11 @@
if (is_truncating()) {
f->AddString("[tr], ");
}
+ if (SpeculativeModeOfInputs() == kGuardInputs) {
+ f->AddString("[guard-inputs], ");
+ } else {
+ f->AddString("[non-speculative], ");
+ }
Definition::PrintOperandsTo(f);
}
diff --git a/runtime/vm/compiler/backend/il_test.cc b/runtime/vm/compiler/backend/il_test.cc
index 48654fb..1e2e053 100644
--- a/runtime/vm/compiler/backend/il_test.cc
+++ b/runtime/vm/compiler/backend/il_test.cc
@@ -11,6 +11,7 @@
#include "vm/compiler/backend/il_printer.h"
#include "vm/compiler/backend/il_test_helper.h"
#include "vm/compiler/backend/range_analysis.h"
+#include "vm/compiler/backend/type_propagator.h"
#include "vm/unit_test.h"
namespace dart {
@@ -313,4 +314,65 @@
EXPECT(ret->value()->definition() == v0);
}
+// Regression test for issue 46018.
+ISOLATE_UNIT_TEST_CASE(IL_UnboxIntegerCanonicalization) {
+ using compiler::BlockBuilder;
+
+ CompilerState S(thread, /*is_aot=*/false, /*is_optimizing=*/true);
+
+ FlowGraphBuilderHelper H;
+
+ auto normal_entry = H.flow_graph()->graph_entry()->normal_entry();
+ Definition* unbox;
+
+ {
+ BlockBuilder builder(H.flow_graph(), normal_entry);
+ Definition* index = H.IntConstant(0);
+ Definition* int_type =
+ H.flow_graph()->GetConstant(Type::Handle(Type::IntType()));
+
+ Definition* float64_array =
+ builder.AddParameter(0, 0, /*with_frame=*/true, kTagged);
+ Definition* int64_array =
+ builder.AddParameter(1, 1, /*with_frame=*/true, kTagged);
+
+ Definition* load_indexed = builder.AddDefinition(new LoadIndexedInstr(
+ new Value(float64_array), new Value(index),
+ /* index_unboxed */ false,
+ /* index_scale */ 8, kTypedDataFloat64ArrayCid, kAlignedAccess,
+ S.GetNextDeoptId(), InstructionSource()));
+ Definition* box = builder.AddDefinition(
+ BoxInstr::Create(kUnboxedDouble, new Value(load_indexed)));
+ Definition* cast = builder.AddDefinition(new AssertAssignableInstr(
+ InstructionSource(), new Value(box), new Value(int_type),
+ /* instantiator_type_arguments */
+ new Value(H.flow_graph()->constant_null()),
+ /* function_type_arguments */
+ new Value(H.flow_graph()->constant_null()),
+ /* dst_name */ String::Handle(String::New("not-null")),
+ S.GetNextDeoptId()));
+ unbox = builder.AddDefinition(new UnboxInt64Instr(
+ new Value(cast), S.GetNextDeoptId(), BoxInstr::kGuardInputs));
+
+ builder.AddInstruction(new StoreIndexedInstr(
+ new Value(int64_array), new Value(index), new Value(unbox),
+ kNoStoreBarrier,
+ /* index_unboxed */ false,
+ /* index_scale */ 8, kTypedDataInt64ArrayCid, kAlignedAccess,
+ S.GetNextDeoptId(), InstructionSource()));
+ builder.AddReturn(new Value(index));
+ }
+
+ H.FinishGraph();
+
+ FlowGraphTypePropagator::Propagate(H.flow_graph());
+ EXPECT(!unbox->ComputeCanDeoptimize());
+
+ H.flow_graph()->Canonicalize();
+ EXPECT(!unbox->ComputeCanDeoptimize());
+
+ H.flow_graph()->RemoveRedefinitions();
+ EXPECT(!unbox->ComputeCanDeoptimize()); // Previously this reverted to true.
+}
+
} // namespace dart
diff --git a/tests/language/nnbd/static_errors/late_final_without_initializer.dart b/tests/language/nnbd/static_errors/late_final_without_initializer_test.dart
similarity index 99%
rename from tests/language/nnbd/static_errors/late_final_without_initializer.dart
rename to tests/language/nnbd/static_errors/late_final_without_initializer_test.dart
index 9938078..57c0485 100644
--- a/tests/language/nnbd/static_errors/late_final_without_initializer.dart
+++ b/tests/language/nnbd/static_errors/late_final_without_initializer_test.dart
@@ -2,7 +2,6 @@
// 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.
-
// Test that it is not a compile time error for a `final` variable to not have
// an initializer if that variable is declared as `late`.
import 'package:expect/expect.dart';
diff --git a/tests/language/nnbd/static_errors/local_function_inference.dart b/tests/language/nnbd/static_errors/local_function_inference_test.dart
similarity index 77%
rename from tests/language/nnbd/static_errors/local_function_inference.dart
rename to tests/language/nnbd/static_errors/local_function_inference_test.dart
index af81145..94e55fc 100644
--- a/tests/language/nnbd/static_errors/local_function_inference.dart
+++ b/tests/language/nnbd/static_errors/local_function_inference_test.dart
@@ -23,7 +23,9 @@
return 3;
}
}
- // ^
- // [analyzer] undefined
- // [cfe] undefined
+//^
+// [analyzer] unspecified
+// [cfe] unspecified
+// TODO(45942): This may be the wrong location, but until the linked issue is
+// fixed and implementations report the error, this is as good as any.
}
diff --git a/tests/language/nnbd/syntax/late_modifier_bug_39658.dart b/tests/language/nnbd/syntax/late_modifier_bug_39658_test.dart
similarity index 100%
rename from tests/language/nnbd/syntax/late_modifier_bug_39658.dart
rename to tests/language/nnbd/syntax/late_modifier_bug_39658_test.dart
diff --git a/tests/standalone/io/unix_socket_test.dart b/tests/standalone/io/unix_socket_test.dart
index e3fec83..d5ee7cb 100644
--- a/tests/standalone/io/unix_socket_test.dart
+++ b/tests/standalone/io/unix_socket_test.dart
@@ -163,6 +163,47 @@
await completer.future;
}
+String getAbstractSocketTestFileName() {
+ var executable = Platform.executable;
+ var dirIndex = executable.lastIndexOf('dart');
+ var buffer = new StringBuffer(executable.substring(0, dirIndex));
+ buffer.write('abstract_socket_test');
+ return buffer.toString();
+}
+
+Future testShortAbstractAddress() async {
+ if (!Platform.isLinux && !Platform.isAndroid) {
+ return;
+ }
+ Process? process;
+ try {
+ var socketAddress = '@hidden';
+ var abstractSocketServer = getAbstractSocketTestFileName();
+ process = await Process.start(abstractSocketServer, [socketAddress]);
+ var serverAddress =
+ InternetAddress(socketAddress, type: InternetAddressType.unix);
+ Socket client = await Socket.connect(serverAddress, 0);
+ List<int> sendData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ List<int> data = [];
+ var completer = Completer<void>();
+ client.listen(data.addAll, onDone: () {
+ Expect.listEquals(sendData, data);
+ completer.complete();
+ });
+ client.add(sendData);
+ await client.close();
+ await completer.future;
+ client.destroy();
+ var exitCode = await process.exitCode;
+ process = null;
+ Expect.equals(exitCode, 0);
+ } catch (e, st) {
+ Expect.fail('Failed with exception:\n$e\n$st');
+ } finally {
+ process?.kill(ProcessSignal.sigkill);
+ }
+}
+
Future testExistingFile(String name) async {
// Test that a leftover file(In case of previous process being killed and
// finalizer doesn't clean up the file) will be cleaned up and bind() should
@@ -398,6 +439,7 @@
await withTempDir('unix_socket_test', (Directory dir) async {
await testHttpServer('${dir.path}');
});
+ await testShortAbstractAddress();
} catch (e) {
if (Platform.isMacOS || Platform.isLinux || Platform.isAndroid) {
Expect.fail("Unexpected exception $e is thrown");
diff --git a/tests/standalone_2/io/unix_socket_test.dart b/tests/standalone_2/io/unix_socket_test.dart
index 31acd7b..aa86ae8 100644
--- a/tests/standalone_2/io/unix_socket_test.dart
+++ b/tests/standalone_2/io/unix_socket_test.dart
@@ -165,6 +165,47 @@
await completer.future;
}
+String getAbstractSocketTestFileName() {
+ var executable = Platform.executable;
+ var dirIndex = executable.lastIndexOf('dart');
+ var buffer = new StringBuffer(executable.substring(0, dirIndex));
+ buffer.write('abstract_socket_test');
+ return buffer.toString();
+}
+
+Future testShortAbstractAddress() async {
+ if (!Platform.isLinux && !Platform.isAndroid) {
+ return;
+ }
+ Process process;
+ try {
+ var socketAddress = '@hidden';
+ var abstractSocketServer = getAbstractSocketTestFileName();
+ process = await Process.start(abstractSocketServer, [socketAddress]);
+ var serverAddress =
+ InternetAddress(socketAddress, type: InternetAddressType.unix);
+ Socket client = await Socket.connect(serverAddress, 0);
+ List<int> sendData = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
+ List<int> data = [];
+ var completer = Completer<void>();
+ client.listen(data.addAll, onDone: () {
+ Expect.listEquals(sendData, data);
+ completer.complete();
+ });
+ client.add(sendData);
+ await client.close();
+ await completer.future;
+ client.destroy();
+ var exitCode = await process.exitCode;
+ process = null;
+ Expect.equals(exitCode, 0);
+ } catch (e, st) {
+ Expect.fail('Failed with exception:\n$e\n$st');
+ } finally {
+ process?.kill(ProcessSignal.sigkill);
+ }
+}
+
Future testExistingFile(String name) async {
// Test that a leftover file(In case of previous process being killed and
// finalizer doesn't clean up the file) will be cleaned up and bind() should
@@ -400,6 +441,7 @@
await withTempDir('unix_socket_test', (Directory dir) async {
await testHttpServer('${dir.path}');
});
+ await testShortAbstractAddress();
} catch (e) {
if (Platform.isMacOS || Platform.isLinux || Platform.isAndroid) {
Expect.fail("Unexpected exception $e is thrown");
diff --git a/tools/VERSION b/tools/VERSION
index 868836c..f039084 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 14
PATCH 0
-PRERELEASE 162
+PRERELEASE 163
PRERELEASE_PATCH 0
\ No newline at end of file