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(); +}