From 52f54a2edd706cdd9f54efdb112bb74b60475a5b Mon Sep 17 00:00:00 2001 From: "sgjesse@google.com" Date: Thu, 11 Apr 2013 07:15:08 +0000 Subject: [PATCH] Add support for typed data views on native threads The deserializer running outside the VM can now decode typed data views. As the typed data views are implemented as normal Dart instances and not a internal VM object the deserializer have been expanded to process serialized objects of the type used to create these views. The typed data object that the view is based on will always be serialized as part of the message. Currently only vews created with constructor Uint8List.view on top of an Uint8List are supported. R=ager@google.com BUG=https://code.google.com/p/dart/issues/detail?id=9484 Review URL: https://codereview.chromium.org//14065006 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@21252 260f80e4-7a28-3924-810f-c04153c831b5 --- runtime/vm/dart_api_message.cc | 84 +++++++++++++++++-- runtime/vm/dart_api_message.h | 22 ++++- runtime/vm/snapshot_test.cc | 67 +++++++++++++-- tests/standalone/io/file_typed_data_test.dart | 42 ++++++++++ 4 files changed, 201 insertions(+), 14 deletions(-) create mode 100644 tests/standalone/io/file_typed_data_test.dart diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc index ab1e0605a14..5315301baef 100644 --- a/runtime/vm/dart_api_message.cc +++ b/runtime/vm/dart_api_message.cc @@ -164,6 +164,22 @@ Dart_CObject* ApiMessageReader::AllocateDartCObjectArray(intptr_t length) { } +Dart_CObject_Internal* ApiMessageReader::AllocateDartCObjectInternal( + Dart_CObject_Internal::Type type) { + Dart_CObject_Internal* value = + reinterpret_cast( + alloc_(NULL, 0, sizeof(Dart_CObject_Internal))); + ASSERT(value != NULL); + value->type = static_cast(type); + return value; +} + + +Dart_CObject_Internal* ApiMessageReader::AllocateDartCObjectClass() { + return AllocateDartCObjectInternal(Dart_CObject_Internal::kClass); +} + + ApiMessageReader::BackRefNode* ApiMessageReader::AllocateBackRefNode( Dart_CObject* reference, DeserializeState state) { @@ -182,9 +198,55 @@ Dart_CObject* ApiMessageReader::ReadInlinedObject(intptr_t object_id) { USE(tags); intptr_t class_id; - // Reading of regular dart instances is not supported. + // There is limited support for reading regular dart instances. Only + // typed data views are currently handled. if (SerializedHeaderData::decode(class_header) == kInstanceObjectId) { - return AllocateDartCObjectUnsupported(); + Dart_CObject_Internal* object = + reinterpret_cast(GetBackRef(object_id)); + if (object == NULL) { + object = + AllocateDartCObjectInternal(Dart_CObject_Internal::kUninitialized); + AddBackRef(object_id, object, kIsDeserialized); + // Read class of object. + object->cls = reinterpret_cast(ReadObjectImpl()); + ASSERT(object->cls->type == + static_cast(Dart_CObject_Internal::kClass)); + } + ASSERT(object->type == + static_cast( + Dart_CObject_Internal::kUninitialized)); + + // Handle typed data views. + char* library_url = + object->cls->internal.as_class.library_url->value.as_string; + char* class_name = + object->cls->internal.as_class.class_name->value.as_string; + if (strcmp("dart:typeddata", library_url) == 0 && + strncmp("_Uint8ArrayView", class_name, 15) == 0) { + object->type = + static_cast(Dart_CObject_Internal::kView); + // Skip type arguments. + ReadObjectImpl(); + object->internal.as_view.buffer = ReadObjectImpl(); + object->internal.as_view.offset_in_bytes = ReadSmiValue(); + object->internal.as_view.length = ReadSmiValue(); + + // The buffer is fully read now as typed data objects are + // serialized in-line. + Dart_CObject* buffer = object->internal.as_view.buffer; + ASSERT(buffer->type == Dart_CObject::kUint8Array); + + // Now turn the view into a byte array. + object->type = Dart_CObject::kUint8Array; + object->value.as_byte_array.length = object->internal.as_view.length; + object->value.as_byte_array.values = + buffer->value.as_byte_array.values + + object->internal.as_view.offset_in_bytes; + } else { + // TODO(sgjesse): Handle other instances. Currently this will + // skew the reading as the fields of the instance is not read. + } + return object; } ASSERT((class_header & kSmiTagMask) != 0); @@ -265,11 +327,17 @@ Dart_CObject* ApiMessageReader::ReadObjectRef() { // Read the class header information and lookup the class. intptr_t class_header = ReadIntptrValue(); - // Reading of regular dart instances is not supported. + // Reading of regular dart instances has limited support in order to + // read typed data views. if (SerializedHeaderData::decode(class_header) == kInstanceObjectId) { intptr_t object_id = SerializedHeaderData::decode(value); - Dart_CObject* object = AllocateDartCObjectUnsupported(); + Dart_CObject_Internal* object = + AllocateDartCObjectInternal(Dart_CObject_Internal::kUninitialized); AddBackRef(object_id, object, kIsNotDeserialized); + // Read class of object. + object->cls = reinterpret_cast(ReadObjectImpl()); + ASSERT(object->cls->type == + static_cast(Dart_CObject_Internal::kClass)); return object; } ASSERT((class_header & kSmiTagMask) != 0); @@ -313,8 +381,14 @@ Dart_CObject* ApiMessageReader::ReadInternalVMObject(intptr_t class_id, intptr_t object_id) { switch (class_id) { case kClassCid: { - Dart_CObject* object = AllocateDartCObjectUnsupported(); + Dart_CObject_Internal* object = AllocateDartCObjectClass(); AddBackRef(object_id, object, kIsDeserialized); + object->internal.as_class.library_url = ReadObjectImpl(); + ASSERT(object->internal.as_class.library_url->type == + Dart_CObject::kString); + object->internal.as_class.class_name = ReadObjectImpl(); + ASSERT(object->internal.as_class.class_name->type == + Dart_CObject::kString); return object; } case kTypeArgumentsCid: { diff --git a/runtime/vm/dart_api_message.h b/runtime/vm/dart_api_message.h index 84d44a8cf35..d215ab01f2a 100644 --- a/runtime/vm/dart_api_message.h +++ b/runtime/vm/dart_api_message.h @@ -14,13 +14,26 @@ namespace dart { // data. These are objects that we need to process in order to // generate the Dart_CObject graph but that we don't want to expose in // that graph. -// TODO(sjesse): Remove this when message serialization format is -// updated. struct Dart_CObject_Internal : public Dart_CObject { enum Type { kTypeArguments = Dart_CObject::kNumberOfTypes, kDynamicType, + kClass, + kView, + kUninitialized, }; + struct Dart_CObject_Internal* cls; + union { + struct { + struct _Dart_CObject* library_url; + struct _Dart_CObject* class_name; + } as_class; + struct { + struct _Dart_CObject* buffer; + int offset_in_bytes; + int length; + } as_view; + } internal; }; @@ -79,6 +92,11 @@ class ApiMessageReader : public BaseReader { Dart_CObject* AllocateDartCObjectUint8Array(intptr_t length); // Allocates a C array of Dart_CObject objects. Dart_CObject* AllocateDartCObjectArray(intptr_t length); + // Allocates a Dart_CObject_Internal object with the specified type. + Dart_CObject_Internal* AllocateDartCObjectInternal( + Dart_CObject_Internal::Type type); + // Allocates a Dart_CObject_Internal object for a class object. + Dart_CObject_Internal* AllocateDartCObjectClass(); // Allocates a backwards reference node. BackRefNode* AllocateBackRefNode(Dart_CObject* ref, DeserializeState state); diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc index c9a977b24d1..b1e8af8f048 100644 --- a/runtime/vm/snapshot_test.cc +++ b/runtime/vm/snapshot_test.cc @@ -1800,12 +1800,21 @@ UNIT_TEST_CASE(DartGeneratedListMessagesWithBackref) { " for (var i = 0; i < kArrayLength; i++) list[i] = d;\n" " return list;\n" "}\n" - "getByteArrayList() {\n" + "getTypedDataList() {\n" " var byte_array = new Uint8List(256);\n" " var list = new List(kArrayLength);\n" " for (var i = 0; i < kArrayLength; i++) list[i] = byte_array;\n" " return list;\n" "}\n" + "getTypedDataViewList() {\n" + " var uint8_list = new Uint8List(256);\n" + " uint8_list[64] = 1;\n" + " var uint8_list_view =\n" + " new Uint8List.view(uint8_list.buffer, 64, 128);\n" + " var list = new List(kArrayLength);\n" + " for (var i = 0; i < kArrayLength; i++) list[i] = uint8_list_view;\n" + " return list;\n" + "}\n" "getMixedList() {\n" " var list = new List(kArrayLength);\n" " for (var i = 0; i < kArrayLength; i++) {\n" @@ -1890,9 +1899,9 @@ UNIT_TEST_CASE(DartGeneratedListMessagesWithBackref) { } } { - // Generate a list of doubles from Dart code. + // Generate a list of Uint8Lists from Dart code. ApiNativeScope scope; - Dart_CObject* root = GetDeserializedDartMessage(lib, "getByteArrayList"); + Dart_CObject* root = GetDeserializedDartMessage(lib, "getTypedDataList"); EXPECT_NOTNULL(root); EXPECT_EQ(Dart_CObject::kArray, root->type); EXPECT_EQ(kArrayLength, root->value.as_array.length); @@ -1903,6 +1912,23 @@ UNIT_TEST_CASE(DartGeneratedListMessagesWithBackref) { EXPECT_EQ(256, element->value.as_byte_array.length); } } + { + // Generate a list of Uint8List views from Dart code. + ApiNativeScope scope; + Dart_CObject* root = + GetDeserializedDartMessage(lib, "getTypedDataViewList"); + EXPECT_NOTNULL(root); + EXPECT_EQ(Dart_CObject::kArray, root->type); + EXPECT_EQ(kArrayLength, root->value.as_array.length); + for (int i = 0; i < kArrayLength; i++) { + Dart_CObject* element = root->value.as_array.values[i]; + EXPECT_EQ(root->value.as_array.values[0], element); + EXPECT_EQ(Dart_CObject::kUint8Array, element->type); + EXPECT_EQ(128, element->value.as_byte_array.length); + EXPECT_EQ(1, element->value.as_byte_array.values[0]); + EXPECT_EQ(0, element->value.as_byte_array.values[1]); + } + } { // Generate a list of objects of different types from Dart code. ApiNativeScope scope; @@ -1973,7 +1999,7 @@ UNIT_TEST_CASE(DartGeneratedArrayLiteralMessagesWithBackref) { " list.add(3.14);;\n" " return list;\n" "}\n" - "getByteArrayList() {\n" + "getTypedDataList() {\n" " var byte_array = new Uint8List(256);\n" " var list = [];\n" " for (var i = 0; i < kArrayLength; i++) {\n" @@ -1981,6 +2007,17 @@ UNIT_TEST_CASE(DartGeneratedArrayLiteralMessagesWithBackref) { " }\n" " return list;\n" "}\n" + "getTypedDataViewList() {\n" + " var uint8_list = new Uint8List(256);\n" + " uint8_list[64] = 1;\n" + " var uint8_list_view =\n" + " new Uint8List.view(uint8_list.buffer, 64, 128);\n" + " var list = [];\n" + " for (var i = 0; i < kArrayLength; i++) {\n" + " list.add(uint8_list_view);\n" + " }\n" + " return list;\n" + "}\n" "getMixedList() {\n" " var list = [];\n" " for (var i = 0; i < kArrayLength; i++) {\n" @@ -2006,7 +2043,6 @@ UNIT_TEST_CASE(DartGeneratedArrayLiteralMessagesWithBackref) { { DARTSCOPE(isolate); - { // Generate a list of strings from Dart code. ApiNativeScope scope; @@ -2065,9 +2101,9 @@ UNIT_TEST_CASE(DartGeneratedArrayLiteralMessagesWithBackref) { } } { - // Generate a list of doubles from Dart code. + // Generate a list of Uint8Lists from Dart code. ApiNativeScope scope; - Dart_CObject* root = GetDeserializedDartMessage(lib, "getByteArrayList"); + Dart_CObject* root = GetDeserializedDartMessage(lib, "getTypedDataList"); EXPECT_NOTNULL(root); EXPECT_EQ(Dart_CObject::kArray, root->type); EXPECT_EQ(kArrayLength, root->value.as_array.length); @@ -2078,6 +2114,23 @@ UNIT_TEST_CASE(DartGeneratedArrayLiteralMessagesWithBackref) { EXPECT_EQ(256, element->value.as_byte_array.length); } } + { + // Generate a list of Uint8List views from Dart code. + ApiNativeScope scope; + Dart_CObject* root = + GetDeserializedDartMessage(lib, "getTypedDataViewList"); + EXPECT_NOTNULL(root); + EXPECT_EQ(Dart_CObject::kArray, root->type); + EXPECT_EQ(kArrayLength, root->value.as_array.length); + for (int i = 0; i < kArrayLength; i++) { + Dart_CObject* element = root->value.as_array.values[i]; + EXPECT_EQ(root->value.as_array.values[0], element); + EXPECT_EQ(Dart_CObject::kUint8Array, element->type); + EXPECT_EQ(128, element->value.as_byte_array.length); + EXPECT_EQ(1, element->value.as_byte_array.values[0]); + EXPECT_EQ(0, element->value.as_byte_array.values[1]); + } + } { // Generate a list of objects of different types from Dart code. ApiNativeScope scope; diff --git a/tests/standalone/io/file_typed_data_test.dart b/tests/standalone/io/file_typed_data_test.dart new file mode 100644 index 00000000000..027c191aad2 --- /dev/null +++ b/tests/standalone/io/file_typed_data_test.dart @@ -0,0 +1,42 @@ +// Copyright (c) 2013, 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. +// +// Dart test program for testing file I/O. + +import "package:expect/expect.dart"; +import 'dart:async'; +import 'dart:io'; +import 'dart:isolate'; +import 'dart:typeddata'; + +void testWriteUint8ListAndView() { + ReceivePort port = new ReceivePort(); + Uint8List list = new Uint8List(8); + for (int i = 0; i < 8; i++) list[i] = i; + var view = new Uint8List.view(list.buffer, 2, 4); + + new Directory('').createTemp().then((temp) { + var file = new File("${temp.path}/test"); + file.open(mode: FileMode.WRITE).then((raf) { + return raf.writeList(list, 0, 8); + }).then((raf) { + return raf.writeList(view, 0, 4); + }).then((raf) { + return raf.close(); + }).then((_) { + var expected = []; + expected.addAll(list); + expected.addAll(view); + var content = file.readAsBytesSync(); + Expect.listEquals(expected, content); + temp.deleteSync(recursive: true); + port.close(); + }); + }); +} + + +main() { + testWriteUint8ListAndView(); +}