Version 2.18.0-259.0.dev
Merge commit 'a2ab7ccea463d68823e7f3cb01367be2407e61b2' into 'dev'
diff --git a/runtime/tests/vm/dart/regress_49372_deferred.dart b/runtime/tests/vm/dart/regress_49372_deferred.dart
new file mode 100644
index 0000000..f466fe2
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_49372_deferred.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2022, 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 https://github.com/dart-lang/sdk/issues/49372.
+// Verifies that dedup optimization doesn't merge Code from different unit.
+
+@pragma('vm:never-inline')
+int foo() => 10;
+
+@pragma('vm:never-inline')
+int bar() => foo() + 2;
\ No newline at end of file
diff --git a/runtime/tests/vm/dart/regress_49372_test.dart b/runtime/tests/vm/dart/regress_49372_test.dart
new file mode 100644
index 0000000..7453b2b
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_49372_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2022, 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 https://github.com/dart-lang/sdk/issues/49372.
+// Verifies that dedup optimization doesn't merge Code from different unit.
+
+import 'package:expect/expect.dart';
+import 'regress_49372_deferred.dart' deferred as lib;
+
+@pragma('vm:never-inline')
+int foo() => 10;
+
+@pragma('vm:never-inline')
+int bar() => foo() + 7;
+
+void main() async {
+ await lib.loadLibrary();
+ Expect.equals(12, lib.bar());
+ Expect.equals(17, bar());
+}
diff --git a/runtime/tests/vm/dart_2/regress_49372_deferred.dart b/runtime/tests/vm/dart_2/regress_49372_deferred.dart
new file mode 100644
index 0000000..5c5ce0f
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_49372_deferred.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2022, 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 https://github.com/dart-lang/sdk/issues/49372.
+// Verifies that dedup optimization doesn't merge Code from different unit.
+
+// @dart = 2.9
+
+@pragma('vm:never-inline')
+int foo() => 10;
+
+@pragma('vm:never-inline')
+int bar() => foo() + 2;
\ No newline at end of file
diff --git a/runtime/tests/vm/dart_2/regress_49372_test.dart b/runtime/tests/vm/dart_2/regress_49372_test.dart
new file mode 100644
index 0000000..7c7990c
--- /dev/null
+++ b/runtime/tests/vm/dart_2/regress_49372_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2022, 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 https://github.com/dart-lang/sdk/issues/49372.
+// Verifies that dedup optimization doesn't merge Code from different unit.
+
+// @dart = 2.9
+
+import 'package:expect/expect.dart';
+import 'regress_49372_deferred.dart' deferred as lib;
+
+@pragma('vm:never-inline')
+int foo() => 10;
+
+@pragma('vm:never-inline')
+int bar() => foo() + 7;
+
+void main() async {
+ await lib.loadLibrary();
+ Expect.equals(12, lib.bar());
+ Expect.equals(17, bar());
+}
diff --git a/runtime/vm/compiler/backend/flow_graph_compiler.cc b/runtime/vm/compiler/backend/flow_graph_compiler.cc
index 32c36ac..6355ea9 100644
--- a/runtime/vm/compiler/backend/flow_graph_compiler.cc
+++ b/runtime/vm/compiler/backend/flow_graph_compiler.cc
@@ -3606,49 +3606,21 @@
}
}
-// The assignment to loading units here must match that in
-// AssignLoadingUnitsCodeVisitor, which runs after compilation is done.
-static intptr_t LoadingUnitOf(Zone* zone, const Function& function) {
- const Class& cls = Class::Handle(zone, function.Owner());
- const Library& lib = Library::Handle(zone, cls.library());
- const LoadingUnit& unit = LoadingUnit::Handle(zone, lib.loading_unit());
- ASSERT(!unit.IsNull());
- return unit.id();
-}
-
-static intptr_t LoadingUnitOf(Zone* zone, const Code& code) {
- // No WeakSerializationReference owners here because those are only
- // introduced during AOT serialization.
- if (code.IsStubCode() || code.IsTypeTestStubCode()) {
- return LoadingUnit::kRootId;
- } else if (code.IsAllocationStubCode()) {
- const Class& cls = Class::Cast(Object::Handle(zone, code.owner()));
- const Library& lib = Library::Handle(zone, cls.library());
- const LoadingUnit& unit = LoadingUnit::Handle(zone, lib.loading_unit());
- ASSERT(!unit.IsNull());
- return unit.id();
- } else if (code.IsFunctionCode()) {
- return LoadingUnitOf(zone,
- Function::Cast(Object::Handle(zone, code.owner())));
- } else {
- UNREACHABLE();
- return LoadingUnit::kIllegalId;
- }
-}
-
bool FlowGraphCompiler::CanPcRelativeCall(const Function& target) const {
- return FLAG_precompiled_mode &&
- (LoadingUnitOf(zone_, function()) == LoadingUnitOf(zone_, target));
+ return FLAG_precompiled_mode && (LoadingUnit::LoadingUnitOf(function()) ==
+ LoadingUnit::LoadingUnitOf(target));
}
bool FlowGraphCompiler::CanPcRelativeCall(const Code& target) const {
return FLAG_precompiled_mode && !target.InVMIsolateHeap() &&
- (LoadingUnitOf(zone_, function()) == LoadingUnitOf(zone_, target));
+ (LoadingUnit::LoadingUnitOf(function()) ==
+ LoadingUnit::LoadingUnitOf(target));
}
bool FlowGraphCompiler::CanPcRelativeCall(const AbstractType& target) const {
return FLAG_precompiled_mode && !target.InVMIsolateHeap() &&
- (LoadingUnitOf(zone_, function()) == LoadingUnit::kRootId);
+ (LoadingUnit::LoadingUnitOf(function()) ==
+ LoadingUnit::LoadingUnit::kRootId);
}
#undef __
diff --git a/runtime/vm/hash.h b/runtime/vm/hash.h
index 955bb57..79c4435 100644
--- a/runtime/vm/hash.h
+++ b/runtime/vm/hash.h
@@ -20,10 +20,9 @@
hash += hash << 3;
hash ^= hash >> 11; // Logical shift, unsigned hash.
hash += hash << 15;
- // FinalizeHash gets called with values for hashbits that are bigger than 31
- // (like kBitsPerWord - 1). Therefore we are careful to use a type
- // (uintptr_t) big enough to avoid undefined behavior with the left shift.
- hash &= (static_cast<uintptr_t>(1) << hashbits) - 1;
+ if (hashbits < kBitsPerInt32) {
+ hash &= (static_cast<uint32_t>(1) << hashbits) - 1;
+ }
return (hash == 0) ? 1 : hash;
}
diff --git a/runtime/vm/hash_map_test.cc b/runtime/vm/hash_map_test.cc
index 014de42..30ed7d1 100644
--- a/runtime/vm/hash_map_test.cc
+++ b/runtime/vm/hash_map_test.cc
@@ -11,7 +11,9 @@
class TestValue {
public:
explicit TestValue(intptr_t x) : x_(x) {}
- uword Hash() const { return x_ & 1; }
+ // FinalizeHash is used here to provide coverage for FinalizeHash(...)
+ // function.
+ uword Hash() const { return FinalizeHash(static_cast<uint32_t>(x_) & 1); }
bool Equals(const TestValue& other) { return x_ == other.x_; }
private:
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 3cc799f..bdd1af2 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -18602,6 +18602,60 @@
return DartEntry::InvokeFunction(func, args);
}
+// The assignment to loading units here must match that in
+// AssignLoadingUnitsCodeVisitor, which runs after compilation is done.
+intptr_t LoadingUnit::LoadingUnitOf(const Function& function) {
+ Thread* thread = Thread::Current();
+ REUSABLE_CLASS_HANDLESCOPE(thread);
+ REUSABLE_LIBRARY_HANDLESCOPE(thread);
+ REUSABLE_LOADING_UNIT_HANDLESCOPE(thread);
+
+ Class& cls = thread->ClassHandle();
+ Library& lib = thread->LibraryHandle();
+ LoadingUnit& unit = thread->LoadingUnitHandle();
+
+ cls = function.Owner();
+ lib = cls.library();
+ unit = lib.loading_unit();
+ ASSERT(!unit.IsNull());
+ return unit.id();
+}
+
+intptr_t LoadingUnit::LoadingUnitOf(const Code& code) {
+ if (code.IsStubCode() || code.IsTypeTestStubCode()) {
+ return LoadingUnit::kRootId;
+ } else {
+ Thread* thread = Thread::Current();
+ REUSABLE_FUNCTION_HANDLESCOPE(thread);
+ REUSABLE_CLASS_HANDLESCOPE(thread);
+ REUSABLE_LIBRARY_HANDLESCOPE(thread);
+ REUSABLE_LOADING_UNIT_HANDLESCOPE(thread);
+
+ Class& cls = thread->ClassHandle();
+ Library& lib = thread->LibraryHandle();
+ LoadingUnit& unit = thread->LoadingUnitHandle();
+ Function& func = thread->FunctionHandle();
+
+ if (code.IsAllocationStubCode()) {
+ cls ^= code.owner();
+ lib = cls.library();
+ unit = lib.loading_unit();
+ ASSERT(!unit.IsNull());
+ return unit.id();
+ } else if (code.IsFunctionCode()) {
+ func ^= code.function();
+ cls = func.Owner();
+ lib = cls.library();
+ unit = lib.loading_unit();
+ ASSERT(!unit.IsNull());
+ return unit.id();
+ } else {
+ UNREACHABLE();
+ return LoadingUnit::kIllegalId;
+ }
+ }
+}
+
const char* Error::ToErrorCString() const {
if (IsNull()) {
return "Error: null";
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 0ed84a6..ab528c3 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -7432,6 +7432,9 @@
return RoundedAllocationSize(sizeof(UntaggedLoadingUnit));
}
+ static intptr_t LoadingUnitOf(const Function& function);
+ static intptr_t LoadingUnitOf(const Code& code);
+
LoadingUnitPtr parent() const;
void set_parent(const LoadingUnit& value) const;
diff --git a/runtime/vm/program_visitor.cc b/runtime/vm/program_visitor.cc
index b87fa96..7c195a9 100644
--- a/runtime/vm/program_visitor.cc
+++ b/runtime/vm/program_visitor.cc
@@ -1214,7 +1214,11 @@
if (pair->UncheckedEntryPointOffset() != key->UncheckedEntryPointOffset()) {
return false;
}
- return Instructions::Equals(pair->instructions(), key->instructions());
+ if (!Instructions::Equals(pair->instructions(), key->instructions())) {
+ return false;
+ }
+ return LoadingUnit::LoadingUnitOf(*pair) ==
+ LoadingUnit::LoadingUnitOf(*key);
}
};
#endif
diff --git a/runtime/vm/reusable_handles.h b/runtime/vm/reusable_handles.h
index 5fcb2f7..c139552 100644
--- a/runtime/vm/reusable_handles.h
+++ b/runtime/vm/reusable_handles.h
@@ -96,6 +96,8 @@
ReusableInstanceHandleScope reused_instance_handle(thread);
#define REUSABLE_LIBRARY_HANDLESCOPE(thread) \
ReusableLibraryHandleScope reused_library_handle(thread);
+#define REUSABLE_LOADING_UNIT_HANDLESCOPE(thread) \
+ ReusableLoadingUnitHandleScope reused_loading_unit_handle(thread);
#define REUSABLE_OBJECT_HANDLESCOPE(thread) \
ReusableObjectHandleScope reused_object_handle(thread);
#define REUSABLE_PC_DESCRIPTORS_HANDLESCOPE(thread) \
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 5f9660d..e0bc2a0 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -84,6 +84,7 @@
V(GrowableObjectArray) \
V(Instance) \
V(Library) \
+ V(LoadingUnit) \
V(Object) \
V(PcDescriptors) \
V(Smi) \
diff --git a/sdk/lib/_internal/vm/lib/ffi_patch.dart b/sdk/lib/_internal/vm/lib/ffi_patch.dart
index be50104..9035da0 100644
--- a/sdk/lib/_internal/vm/lib/ffi_patch.dart
+++ b/sdk/lib/_internal/vm/lib/ffi_patch.dart
@@ -80,8 +80,8 @@
external Pointer<T> _fromAddress<T extends NativeType>(int ptr);
// The real implementation of this function (for interface calls) lives in
-// BuildFfiAsFunctionCall in the Kernel frontend. No calls can actually reach
-// this function.
+// BuildFfiAsFunctionInternal in the Kernel frontend. No calls can actually
+// reach this function.
@pragma("vm:recognized", "other")
@pragma("vm:external-name", "Ffi_asFunctionInternal")
external DS _asFunctionInternal<DS extends Function, NS extends Function>(
diff --git a/tools/VERSION b/tools/VERSION
index 1ebe470..f835735 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 18
PATCH 0
-PRERELEASE 258
+PRERELEASE 259
PRERELEASE_PATCH 0
\ No newline at end of file