Improve performance of Dart_ListGetAsBytes.

This fixes two performance issues with Dart_ListGetAsBytes:

1. Avoid excessive handle allocation when copying from a generic List.

2. Add a fast path when copying from byte-size typed data view objects. The
old version only supported typed data, but no views.

R=asiva@google.com

Review URL: https://codereview.chromium.org//21562002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@25731 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
fschneider@google.com 2013-08-02 11:32:05 +00:00
parent dd75544c89
commit eae62fa866
3 changed files with 74 additions and 8 deletions

View file

@ -2136,6 +2136,20 @@ static RawObject* ThrowArgumentError(const char* exception_message) {
return Api::NewError("Invalid length passed in to access array elements"); \
static Dart_Handle CopyBytes(const TypedData& array,
intptr_t offset,
uint8_t* native_array,
intptr_t length) {
ASSERT(array.IsTypedData());
ASSERT(array.ElementSizeInBytes() == 1);
NoGCScope no_gc;
memmove(native_array,
reinterpret_cast<uint8_t*>(array.DataAddr(offset)),
length);
return Api::Success();
}
DART_EXPORT Dart_Handle Dart_ListGetAsBytes(Dart_Handle list,
intptr_t offset,
uint8_t* native_array,
@ -2146,14 +2160,32 @@ DART_EXPORT Dart_Handle Dart_ListGetAsBytes(Dart_Handle list,
if (obj.IsTypedData()) {
const TypedData& array = TypedData::Cast(obj);
if (array.ElementSizeInBytes() == 1) {
if (Utils::RangeCheck(offset, length, array.Length())) {
NoGCScope no_gc;
memmove(native_array,
reinterpret_cast<uint8_t*>(array.DataAddr(offset)),
length);
return Api::Success();
if (!Utils::RangeCheck(offset, length, array.Length())) {
return Api::NewError(
"Invalid length passed in to access list elements");
}
return CopyBytes(array, offset, native_array, length);
}
}
if (RawObject::IsTypedDataViewClassId(obj.GetClassId())) {
const Instance& view = Instance::Cast(obj);
if (TypedDataView::ElementSizeInBytes(view) == 1) {
intptr_t view_length = Smi::Value(TypedDataView::Length(view));
if (!Utils::RangeCheck(offset, length, view_length)) {
return Api::NewError(
"Invalid length passed in to access list elements");
}
const Instance& data = Instance::Handle(TypedDataView::Data(view));
if (data.IsTypedData()) {
const TypedData& array = TypedData::Cast(data);
if (array.ElementSizeInBytes() == 1) {
intptr_t data_offset =
Smi::Value(TypedDataView::OffsetInBytes(view)) + offset;
// Range check already performed on the view object.
ASSERT(Utils::RangeCheck(data_offset, length, array.Length()));
return CopyBytes(array, data_offset, native_array, length);
}
}
return Api::NewError("Invalid length passed in to access list elements");
}
}
if (obj.IsArray()) {
@ -2193,6 +2225,7 @@ DART_EXPORT Dart_Handle Dart_ListGetAsBytes(Dart_Handle list,
const Array& args = Array::Handle(isolate, Array::New(kNumArgs));
args.SetAt(0, instance); // Set up the receiver as the first argument.
for (int i = 0; i < length; i++) {
HANDLESCOPE(isolate);
intobj = Integer::New(offset + i);
args.SetAt(1, intobj);
result = DartEntry::InvokeFunction(function, args);

View file

@ -832,6 +832,39 @@ TEST_CASE(ListAccess) {
}
TEST_CASE(TypedDataViewListGetAsBytes) {
const int kSize = 1000;
const char* kScriptChars =
"import 'dart:typed_data';\n"
"List main(int size) {\n"
" var a = new Int8List(size);\n"
" var view = new Int8List.view(a.buffer, 0, size);\n"
" return view;\n"
"}\n";
// Create a test library and Load up a test script in it.
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
// Test with a typed data view object.
Dart_Handle dart_args[1];
dart_args[0] = Dart_NewInteger(kSize);
Dart_Handle view_obj = Dart_Invoke(lib, NewString("main"), 1, dart_args);
EXPECT_VALID(view_obj);
for (intptr_t i = 0; i < kSize; ++i) {
EXPECT_VALID(Dart_ListSetAt(view_obj, i, Dart_NewInteger(i & 0xff)));
}
uint8_t* data = new uint8_t[kSize];
EXPECT_VALID(Dart_ListGetAsBytes(view_obj, 0, data, kSize));
for (intptr_t i = 0; i < kSize; ++i) {
EXPECT_EQ(i & 0xff, data[i]);
}
Dart_Handle result = Dart_ListGetAsBytes(view_obj, 0, data, kSize + 1);
EXPECT(Dart_IsError(result));
delete[] data;
}
TEST_CASE(TypedDataAccess) {
EXPECT_EQ(Dart_TypedData_kInvalid,
Dart_GetTypeOfTypedData(Dart_True()));

View file

@ -32,7 +32,7 @@ RawObject* DartEntry::InvokeFunction(const Function& function,
const Array& arguments,
const Array& arguments_descriptor) {
const Context& context =
Context::ZoneHandle(Isolate::Current()->object_store()->empty_context());
Context::Handle(Isolate::Current()->object_store()->empty_context());
ASSERT(context.isolate() == Isolate::Current());
return InvokeFunction(function, arguments, arguments_descriptor, context);
}