[vm] Fix serialization of SIMD vectors.

Broken by bbefc0574887c1e00e00d07d7cb8a2b5acd249d6.

TEST=ci
Bug: https://github.com/dart-lang/sdk/issues/46793
Change-Id: I8e5869caee2d705cecaf974cca3ee3f0c542ad3c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/208840
Commit-Queue: Ryan Macnak <rmacnak@google.com>
Reviewed-by: Siva Annamalai <asiva@google.com>
diff --git a/runtime/vm/datastream.h b/runtime/vm/datastream.h
index 7da4532..c0c642f 100644
--- a/runtime/vm/datastream.h
+++ b/runtime/vm/datastream.h
@@ -85,7 +85,7 @@
   };
 
   // Reads 'len' bytes from the stream.
-  void ReadBytes(uint8_t* addr, intptr_t len) {
+  void ReadBytes(void* addr, intptr_t len) {
     ASSERT((end_ - current_) >= len);
     if (len != 0) {
       memmove(addr, current_, len);
diff --git a/runtime/vm/message_snapshot.cc b/runtime/vm/message_snapshot.cc
index 37bb767..3eca655 100644
--- a/runtime/vm/message_snapshot.cc
+++ b/runtime/vm/message_snapshot.cc
@@ -145,7 +145,7 @@
   void WriteWordWith32BitWrites(uword value) {
     stream_.WriteWordWith32BitWrites(value);
   }
-  void WriteBytes(const uint8_t* addr, intptr_t len) {
+  void WriteBytes(const void* addr, intptr_t len) {
     stream_.WriteBytes(addr, len);
   }
   void WriteAscii(const String& str) {
@@ -344,7 +344,7 @@
   }
   intptr_t ReadUnsigned() { return stream_.ReadUnsigned(); }
   uword ReadWordWith32BitReads() { return stream_.ReadWordWith32BitReads(); }
-  void ReadBytes(uint8_t* addr, intptr_t len) { stream_.ReadBytes(addr, len); }
+  void ReadBytes(void* addr, intptr_t len) { stream_.ReadBytes(addr, len); }
   const char* ReadAscii() {
     intptr_t len = ReadUnsigned();
     const char* result = reinterpret_cast<const char*>(CurrentBufferAddress());
@@ -1572,8 +1572,7 @@
       d->AssignRef(data.ptr());
       const intptr_t length_in_bytes = length * element_size;
       NoSafepointScope no_safepoint;
-      uint8_t* cdata = reinterpret_cast<uint8_t*>(data.untag()->data());
-      d->ReadBytes(cdata, length_in_bytes);
+      d->ReadBytes(data.untag()->data(), length_in_bytes);
     }
   }
 
@@ -2066,6 +2065,60 @@
   }
 };
 
+class Simd128MessageSerializationCluster : public MessageSerializationCluster {
+ public:
+  explicit Simd128MessageSerializationCluster(intptr_t cid)
+      : MessageSerializationCluster("Simd128",
+                                    MessagePhase::kBeforeTypes,
+                                    cid) {}
+  ~Simd128MessageSerializationCluster() {}
+
+  void Trace(MessageSerializer* s, Object* object) { objects_.Add(object); }
+
+  void WriteNodes(MessageSerializer* s) {
+    intptr_t count = objects_.length();
+    s->WriteUnsigned(count);
+    for (intptr_t i = 0; i < count; i++) {
+      Object* vector = objects_[i];
+      s->AssignRef(vector);
+      ASSERT_EQUAL(Int32x4::value_offset(), Float32x4::value_offset());
+      ASSERT_EQUAL(Int32x4::value_offset(), Float64x2::value_offset());
+      s->WriteBytes(&(static_cast<Int32x4Ptr>(vector->ptr())->untag()->value_),
+                    sizeof(simd128_value_t));
+    }
+  }
+
+ private:
+  GrowableArray<Object*> objects_;
+};
+
+class Simd128MessageDeserializationCluster
+    : public MessageDeserializationCluster {
+ public:
+  explicit Simd128MessageDeserializationCluster(intptr_t cid)
+      : MessageDeserializationCluster("Simd128"), cid_(cid) {}
+  ~Simd128MessageDeserializationCluster() {}
+
+  void ReadNodes(MessageDeserializer* d) {
+    intptr_t count = d->ReadUnsigned();
+    for (intptr_t i = 0; i < count; i++) {
+      ASSERT_EQUAL(Int32x4::InstanceSize(), Float32x4::InstanceSize());
+      ASSERT_EQUAL(Int32x4::InstanceSize(), Float64x2::InstanceSize());
+      ObjectPtr vector =
+          Object::Allocate(cid_, Int32x4::InstanceSize(), Heap::kNew,
+                           Int32x4::ContainsCompressedPointers());
+      d->AssignRef(vector);
+      ASSERT_EQUAL(Int32x4::value_offset(), Float32x4::value_offset());
+      ASSERT_EQUAL(Int32x4::value_offset(), Float64x2::value_offset());
+      d->ReadBytes(&(static_cast<Int32x4Ptr>(vector)->untag()->value_),
+                   sizeof(simd128_value_t));
+    }
+  }
+
+ private:
+  const intptr_t cid_;
+};
+
 class RegExpMessageSerializationCluster : public MessageSerializationCluster {
  public:
   RegExpMessageSerializationCluster()
@@ -3233,6 +3286,10 @@
       return new (Z) OneByteStringMessageSerializationCluster(Z, is_canonical);
     case kTwoByteStringCid:
       return new (Z) TwoByteStringMessageSerializationCluster(Z, is_canonical);
+    case kInt32x4Cid:
+    case kFloat32x4Cid:
+    case kFloat64x2Cid:
+      return new (Z) Simd128MessageSerializationCluster(cid);
     default:
       break;
   }
@@ -3321,6 +3378,11 @@
       return new (Z) OneByteStringMessageDeserializationCluster(is_canonical);
     case kTwoByteStringCid:
       return new (Z) TwoByteStringMessageDeserializationCluster(is_canonical);
+    case kInt32x4Cid:
+    case kFloat32x4Cid:
+    case kFloat64x2Cid:
+      ASSERT(!is_canonical);
+      return new (Z) Simd128MessageDeserializationCluster(cid);
     default:
       break;
   }
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index eb0d9e3..ce45815 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -859,6 +859,7 @@
   friend void UntaggedObject::Validate(IsolateGroup* isolate_group) const;
   friend class Closure;
   friend class InstanceDeserializationCluster;
+  friend class Simd128MessageDeserializationCluster;
   friend class OneByteString;
   friend class TwoByteString;
   friend class ExternalOneByteString;
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 3d442b2..885d79d 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -3024,6 +3024,8 @@
 
   ALIGN8 int32_t value_[4];
 
+  friend class Simd128MessageSerializationCluster;
+  friend class Simd128MessageDeserializationCluster;
 
  public:
   int32_t x() const { return value_[0]; }
diff --git a/tests/lib/isolate/simd_vectors_message_test.dart b/tests/lib/isolate/simd_vectors_message_test.dart
new file mode 100644
index 0000000..324d4ef
--- /dev/null
+++ b/tests/lib/isolate/simd_vectors_message_test.dart
@@ -0,0 +1,48 @@
+// 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.
+
+// See https://github.com/dart-lang/sdk/issues/46793
+
+import "dart:async";
+import "dart:isolate";
+import "dart:typed_data";
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+
+main() {
+  asyncStart();
+  var port;
+  port = new RawReceivePort((message) {
+    print("Receive $message");
+
+    var int32x4 = message[0] as Int32x4;
+    Expect.equals(-1, int32x4.x);
+    Expect.equals(0, int32x4.y);
+    Expect.equals(1, int32x4.z);
+    Expect.equals(2, int32x4.w);
+
+    var float32x4 = message[1] as Float32x4;
+    Expect.equals(-2.5, float32x4.x);
+    Expect.equals(0.0, float32x4.y);
+    Expect.equals(1.25, float32x4.z);
+    Expect.equals(2.125, float32x4.w);
+
+    var float64x2 = message[2] as Float64x2;
+    Expect.equals(16.5, float64x2.x);
+    Expect.equals(-32.25, float64x2.y);
+
+    port.close();
+    asyncEnd();
+  });
+
+
+  var list = [
+    new Int32x4(-1, 0, 1, 2),
+    new Float32x4(-2.5, 0.0, 1.25, 2.125),
+    new Float64x2(16.5, -32.25),
+  ];
+  print("Send $list");
+  port.sendPort.send(list);
+}
diff --git a/tests/lib_2/isolate/simd_vectors_message_test.dart b/tests/lib_2/isolate/simd_vectors_message_test.dart
new file mode 100644
index 0000000..fedd5a0
--- /dev/null
+++ b/tests/lib_2/isolate/simd_vectors_message_test.dart
@@ -0,0 +1,50 @@
+// 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.
+
+// See https://github.com/dart-lang/sdk/issues/46793
+
+// @dart = 2.9
+
+import "dart:async";
+import "dart:isolate";
+import "dart:typed_data";
+
+import "package:async_helper/async_helper.dart";
+import "package:expect/expect.dart";
+
+main() {
+  asyncStart();
+  var port;
+  port = new RawReceivePort((message) {
+    print("Receive $message");
+
+    var int32x4 = message[0] as Int32x4;
+    Expect.equals(-1, int32x4.x);
+    Expect.equals(0, int32x4.y);
+    Expect.equals(1, int32x4.z);
+    Expect.equals(2, int32x4.w);
+
+    var float32x4 = message[1] as Float32x4;
+    Expect.equals(-2.5, float32x4.x);
+    Expect.equals(0.0, float32x4.y);
+    Expect.equals(1.25, float32x4.z);
+    Expect.equals(2.125, float32x4.w);
+
+    var float64x2 = message[2] as Float64x2;
+    Expect.equals(16.5, float64x2.x);
+    Expect.equals(-32.25, float64x2.y);
+
+    port.close();
+    asyncEnd();
+  });
+
+
+  var list = [
+    new Int32x4(-1, 0, 1, 2),
+    new Float32x4(-2.5, 0.0, 1.25, 2.125),
+    new Float64x2(16.5, -32.25),
+  ];
+  print("Send $list");
+  port.sendPort.send(list);
+}