[VM/Runtime] - Account for TransferableTypedData in Api Messages

Account for TransferableTypedData when receiving messages in
native ports and not crash.

TEST=added new API test

Bug:47686
Change-Id: I2dfad694532f544df3000cd97015089ebb5176fa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/222031
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Siva Annamalai <asiva@google.com>
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 5a9050a..426bb94 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -7854,7 +7854,8 @@
                "'foo1:///.dart_tool");
 }
 
-void NewNativePort_send123(Dart_Port dest_port_id, Dart_CObject* message) {
+static void NewNativePort_send123(Dart_Port dest_port_id,
+                                  Dart_CObject* message) {
   // Gets a send port message.
   EXPECT_NOTNULL(message);
   EXPECT_EQ(Dart_CObject_kArray, message->type);
@@ -7869,7 +7870,8 @@
                    response);
 }
 
-void NewNativePort_send321(Dart_Port dest_port_id, Dart_CObject* message) {
+static void NewNativePort_send321(Dart_Port dest_port_id,
+                                  Dart_CObject* message) {
   // Gets a null message.
   EXPECT_NOTNULL(message);
   EXPECT_EQ(Dart_CObject_kArray, message->type);
@@ -7978,8 +7980,8 @@
   EXPECT(Dart_CloseNativePort(port_id2));
 }
 
-void NewNativePort_sendInteger123(Dart_Port dest_port_id,
-                                  Dart_CObject* message) {
+static void NewNativePort_sendInteger123(Dart_Port dest_port_id,
+                                         Dart_CObject* message) {
   // Gets a send port message.
   EXPECT_NOTNULL(message);
   EXPECT_EQ(Dart_CObject_kArray, message->type);
@@ -7990,8 +7992,8 @@
                    123);
 }
 
-void NewNativePort_sendInteger321(Dart_Port dest_port_id,
-                                  Dart_CObject* message) {
+static void NewNativePort_sendInteger321(Dart_Port dest_port_id,
+                                         Dart_CObject* message) {
   // Gets a null message.
   EXPECT_NOTNULL(message);
   EXPECT_EQ(Dart_CObject_kArray, message->type);
@@ -8053,8 +8055,74 @@
   EXPECT(Dart_CloseNativePort(port_id2));
 }
 
-void NewNativePort_nativeReceiveNull(Dart_Port dest_port_id,
-                                     Dart_CObject* message) {
+static void NewNativePort_Transferrable1(Dart_Port dest_port_id,
+                                         Dart_CObject* message) {
+  // Gets a send port message.
+  EXPECT_NOTNULL(message);
+  EXPECT_EQ(Dart_CObject_kTypedData, message->type);
+  EXPECT_EQ(Dart_TypedData_kUint8, message->value.as_typed_data.type);
+  EXPECT_EQ(10, message->value.as_typed_data.length);
+  EXPECT_EQ(42, message->value.as_typed_data.values[0]);
+  free(message->value.as_typed_data.values);
+}
+
+static void NewNativePort_Transferrable2(Dart_Port dest_port_id,
+                                         Dart_CObject* message) {
+  // Gets a send port message.
+  EXPECT_NOTNULL(message);
+  EXPECT_EQ(Dart_CObject_kArray, message->type);
+  EXPECT_EQ(1, message->value.as_array.length);
+  Dart_CObject* cobj = message->value.as_array.values[0];
+  EXPECT_EQ(Dart_CObject_kTypedData, cobj->type);
+  EXPECT_EQ(Dart_TypedData_kUint8, cobj->value.as_typed_data.type);
+  EXPECT_EQ(10, cobj->value.as_typed_data.length);
+  EXPECT_EQ(42, cobj->value.as_typed_data.values[0]);
+  free(cobj->value.as_typed_data.values);
+}
+
+TEST_CASE(DartAPI_NativePortPostTransferrableTypedData) {
+  const char* kScriptChars =
+      "import 'dart:typed_data';\n"
+      "import 'dart:isolate';\n"
+      "void callPort(SendPort port1, SendPort port2) {\n"
+      "  final td1 ="
+      "     TransferableTypedData.fromList([Uint8List(10)..[0] = 42]);\n"
+      "  final td2 ="
+      "     TransferableTypedData.fromList([Uint8List(10)..[0] = 42]);\n"
+      "  port1.send(td1);\n"
+      "  port2.send([td2]);\n"
+      "}\n";
+  Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+  Dart_EnterScope();
+
+  Dart_Port port_id1 =
+      Dart_NewNativePort("Port123", NewNativePort_Transferrable1, true);
+  Dart_Port port_id2 =
+      Dart_NewNativePort("Port321", NewNativePort_Transferrable2, true);
+
+  Dart_Handle send_port1 = Dart_NewSendPort(port_id1);
+  EXPECT_VALID(send_port1);
+  Dart_Handle send_port2 = Dart_NewSendPort(port_id2);
+  EXPECT_VALID(send_port2);
+
+  // Test first port.
+  Dart_Handle dart_args[2];
+  dart_args[0] = send_port1;
+  dart_args[1] = send_port2;
+  Dart_Handle result = Dart_Invoke(lib, NewString("callPort"), 2, dart_args);
+  EXPECT_VALID(result);
+  result = Dart_RunLoop();
+  EXPECT_VALID(result);
+
+  Dart_ExitScope();
+
+  // Delete the native ports.
+  EXPECT(Dart_CloseNativePort(port_id1));
+  EXPECT(Dart_CloseNativePort(port_id2));
+}
+
+static void NewNativePort_nativeReceiveNull(Dart_Port dest_port_id,
+                                            Dart_CObject* message) {
   EXPECT_NOTNULL(message);
 
   if ((message->type == Dart_CObject_kArray) &&
@@ -8104,8 +8172,8 @@
   EXPECT(Dart_CloseNativePort(port_id1));
 }
 
-void NewNativePort_nativeReceiveInteger(Dart_Port dest_port_id,
-                                        Dart_CObject* message) {
+static void NewNativePort_nativeReceiveInteger(Dart_Port dest_port_id,
+                                               Dart_CObject* message) {
   EXPECT_NOTNULL(message);
 
   if ((message->type == Dart_CObject_kArray) &&
diff --git a/runtime/vm/message_snapshot.cc b/runtime/vm/message_snapshot.cc
index 4733db0..afc2bc3 100644
--- a/runtime/vm/message_snapshot.cc
+++ b/runtime/vm/message_snapshot.cc
@@ -2133,6 +2133,19 @@
           reinterpret_cast<uint8_t*>(finalizable_data.data), length));
     }
   }
+
+  void ReadNodesApi(ApiMessageDeserializer* d) {
+    intptr_t count = d->ReadUnsigned();
+    for (intptr_t i = 0; i < count; i++) {
+      Dart_CObject* data = d->Allocate(Dart_CObject_kTypedData);
+      data->value.as_typed_data.length = d->ReadUnsigned();
+      data->value.as_typed_data.type = Dart_TypedData_kUint8;
+      FinalizableData finalizable_data = d->finalizable_data()->Get();
+      data->value.as_typed_data.values =
+          reinterpret_cast<uint8_t*>(finalizable_data.data);
+      d->AssignRef(data);
+    }
+  }
 };
 
 class Simd128MessageSerializationCluster : public MessageSerializationCluster {