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