Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(34)

Side by Side Diff: src/d8.cc

Issue 10459047: Clean up d8 ArrayBuffer implementation and fix bug in readbuffer: (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed Michael's comments. Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/d8.h ('k') | test/mjsunit/external-array.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 #endif // V8_SHARED 310 #endif // V8_SHARED
311 if (raw_value > static_cast<int32_t>(kMaxLength)) { 311 if (raw_value > static_cast<int32_t>(kMaxLength)) {
312 ThrowException( 312 ThrowException(
313 String::New("Array length exceeds maximum length.")); 313 String::New("Array length exceeds maximum length."));
314 } 314 }
315 return static_cast<size_t>(raw_value); 315 return static_cast<size_t>(raw_value);
316 } 316 }
317 317
318 318
319 const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_"; 319 const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_";
320 const char kArrayBufferReferencePropName[] = "d8::_array_buffer_ref_";
321 320
322 static const int kExternalArrayAllocationHeaderSize = 2; 321
322 Handle<Value> Shell::CreateExternalArrayBuffer(int32_t length) {
323 static const int32_t kMaxSize = 0x7fffffff;
324 // Make sure the total size fits into a (signed) int.
325 if (length < 0 || length > kMaxSize) {
326 return ThrowException(String::New("ArrayBuffer exceeds maximum size (2G)"));
327 }
328 uint8_t* data = new uint8_t[length];
329 if (data == NULL) {
330 return ThrowException(String::New("Memory allocation failed."));
331 }
332 memset(data, 0, length);
333
334 Handle<Object> buffer = Object::New();
335 buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True());
336 Persistent<Object> persistent_array = Persistent<Object>::New(buffer);
337 persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
338 persistent_array.MarkIndependent();
339 V8::AdjustAmountOfExternalAllocatedMemory(length);
340
341 buffer->SetIndexedPropertiesToExternalArrayData(
342 data, v8::kExternalByteArray, length);
343 buffer->Set(String::New("byteLength"), Int32::New(length), ReadOnly);
344
345 return buffer;
346 }
347
348
349 Handle<Value> Shell::CreateExternalArrayBuffer(const Arguments& args) {
350 if (args.Length() == 0) {
351 return ThrowException(
352 String::New("ArrayBuffer constructor must have one parameter."));
353 }
354 TryCatch try_catch;
355 int32_t length = convertToUint(args[0], &try_catch);
356 if (try_catch.HasCaught()) return try_catch.Exception();
357
358 return CreateExternalArrayBuffer(length);
359 }
360
323 361
324 Handle<Value> Shell::CreateExternalArray(const Arguments& args, 362 Handle<Value> Shell::CreateExternalArray(const Arguments& args,
325 ExternalArrayType type, 363 ExternalArrayType type,
326 size_t element_size) { 364 int32_t element_size) {
327 TryCatch try_catch; 365 TryCatch try_catch;
328 bool is_array_buffer_construct = element_size == 0; 366 ASSERT(element_size == 1 || element_size == 2 ||
329 if (is_array_buffer_construct) { 367 element_size == 4 || element_size == 8);
330 type = v8::kExternalByteArray; 368
331 element_size = 1; 369 // Currently, only the following constructors are supported:
332 } 370 // TypedArray(unsigned long length)
333 ASSERT(element_size == 1 || element_size == 2 || element_size == 4 || 371 // TypedArray(ArrayBuffer buffer,
334 element_size == 8); 372 // optional unsigned long byteOffset,
373 // optional unsigned long length)
374 Handle<Object> buffer;
375 int32_t length;
376 int32_t byteLength;
377 int32_t byteOffset;
335 if (args.Length() == 0) { 378 if (args.Length() == 0) {
336 return ThrowException( 379 return ThrowException(
337 String::New("Array constructor must have at least one parameter.")); 380 String::New("Array constructor must have at least one parameter."));
338 } 381 }
339 bool first_arg_is_array_buffer = 382 if (args[0]->IsObject() &&
340 args[0]->IsObject() && 383 !args[0]->ToObject()->GetHiddenValue(
341 !args[0]->ToObject()->GetHiddenValue( 384 String::New(kArrayBufferMarkerPropName)).IsEmpty()) {
342 String::New(kArrayBufferMarkerPropName)).IsEmpty(); 385 buffer = args[0]->ToObject();
343 // Currently, only the following constructors are supported: 386 int32_t bufferLength =
344 // ArrayBuffer(unsigned long length)
345 // TypedArray(unsigned long length)
346 // TypedArray(ArrayBuffer buffer,
347 // optional unsigned long byteOffset,
348 // optional unsigned long length)
349 size_t length;
350 size_t byteLength;
351 size_t byteOffset;
352 void* data = NULL;
353 Handle<Object> array = Object::New();
354 if (is_array_buffer_construct) {
355 byteLength = convertToUint(args[0], &try_catch);
356 if (try_catch.HasCaught()) return try_catch.Exception();
357 byteOffset = 0;
358 length = byteLength;
359
360 array->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True());
361 } else if (first_arg_is_array_buffer) {
362 Handle<Object> buffer = args[0]->ToObject();
363 data = buffer->GetIndexedPropertiesExternalArrayData();
364 byteLength =
365 convertToUint(buffer->Get(String::New("byteLength")), &try_catch); 387 convertToUint(buffer->Get(String::New("byteLength")), &try_catch);
366 if (try_catch.HasCaught()) return try_catch.Exception(); 388 if (try_catch.HasCaught()) return try_catch.Exception();
367 if (data == NULL && byteLength != 0) {
368 return ThrowException(String::New("ArrayBuffer does not have data"));
369 }
370 389
371 if (args.Length() < 2 || args[1]->IsUndefined()) { 390 if (args.Length() < 2 || args[1]->IsUndefined()) {
372 byteOffset = 0; 391 byteOffset = 0;
373 } else { 392 } else {
374 byteOffset = convertToUint(args[1], &try_catch); 393 byteOffset = convertToUint(args[1], &try_catch);
375 if (try_catch.HasCaught()) return try_catch.Exception(); 394 if (try_catch.HasCaught()) return try_catch.Exception();
376 if (byteOffset > byteLength) { 395 if (byteOffset > bufferLength) {
377 return ThrowException(String::New("byteOffset out of bounds")); 396 return ThrowException(String::New("byteOffset out of bounds"));
378 } 397 }
379 if (byteOffset % element_size != 0) { 398 if (byteOffset % element_size != 0) {
380 return ThrowException( 399 return ThrowException(
381 String::New("byteOffset must be multiple of element_size")); 400 String::New("byteOffset must be multiple of element_size"));
382 } 401 }
383 } 402 }
384 403
385 if (args.Length() < 3 || args[2]->IsUndefined()) { 404 if (args.Length() < 3 || args[2]->IsUndefined()) {
405 byteLength = bufferLength - byteOffset;
406 length = byteLength / element_size;
386 if (byteLength % element_size != 0) { 407 if (byteLength % element_size != 0) {
387 return ThrowException( 408 return ThrowException(
388 String::New("buffer size must be multiple of element_size")); 409 String::New("buffer size must be multiple of element_size"));
389 } 410 }
390 length = (byteLength - byteOffset) / element_size;
391 } else { 411 } else {
392 length = convertToUint(args[2], &try_catch); 412 length = convertToUint(args[2], &try_catch);
393 if (try_catch.HasCaught()) return try_catch.Exception(); 413 if (try_catch.HasCaught()) return try_catch.Exception();
414 byteLength = length * element_size;
415 if (byteOffset + byteLength > bufferLength) {
416 return ThrowException(String::New("length out of bounds"));
417 }
394 } 418 }
395
396 if (byteOffset + length * element_size > byteLength) {
397 return ThrowException(String::New("length out of bounds"));
398 }
399 byteLength = byteOffset + length * element_size;
400
401 // Hold a reference to the ArrayBuffer so its buffer doesn't get collected.
402 array->SetHiddenValue(
403 String::New(kArrayBufferReferencePropName), args[0]);
404 } else { 419 } else {
405 length = convertToUint(args[0], &try_catch); 420 length = convertToUint(args[0], &try_catch);
406 byteLength = length * element_size; 421 byteLength = length * element_size;
407 byteOffset = 0; 422 byteOffset = 0;
423 Handle<Value> result = CreateExternalArrayBuffer(byteLength);
424 if (!result->IsObject()) return result;
425 buffer = result->ToObject();
408 } 426 }
409 427
410 Persistent<Object> persistent_array = Persistent<Object>::New(array); 428 void* data = buffer->GetIndexedPropertiesExternalArrayData();
411 if (data == NULL && byteLength != 0) { 429 ASSERT(data != NULL);
412 ASSERT(byteOffset == 0);
413 // Prepend the size of the allocated chunk to the data itself.
414 int total_size =
415 byteLength + kExternalArrayAllocationHeaderSize * sizeof(size_t);
416 static const int kMaxSize = 0x7fffffff;
417 // Make sure the total size fits into a (signed) int.
418 if (total_size > kMaxSize) {
419 return ThrowException(String::New("Array exceeds maximum size (2G)"));
420 }
421 data = malloc(total_size);
422 if (data == NULL) {
423 return ThrowException(String::New("Memory allocation failed."));
424 }
425 *reinterpret_cast<size_t*>(data) = total_size;
426 data = reinterpret_cast<size_t*>(data) + kExternalArrayAllocationHeaderSize;
427 memset(data, 0, byteLength);
428 V8::AdjustAmountOfExternalAllocatedMemory(total_size);
429 }
430 persistent_array.MakeWeak(data, ExternalArrayWeakCallback);
431 persistent_array.MarkIndependent();
432 430
431 Handle<Object> array = Object::New();
433 array->SetIndexedPropertiesToExternalArrayData( 432 array->SetIndexedPropertiesToExternalArrayData(
434 reinterpret_cast<uint8_t*>(data) + byteOffset, type, 433 static_cast<uint8_t*>(data) + byteOffset, type, length);
435 static_cast<int>(length)); 434 array->Set(String::New("byteLength"), Int32::New(byteLength), ReadOnly);
436 array->Set(String::New("byteLength"), 435 array->Set(String::New("byteOffset"), Int32::New(byteOffset), ReadOnly);
437 Int32::New(static_cast<int32_t>(byteLength)), ReadOnly); 436 array->Set(String::New("length"), Int32::New(length), ReadOnly);
438 if (!is_array_buffer_construct) { 437 array->Set(String::New("BYTES_PER_ELEMENT"), Int32::New(element_size));
439 array->Set(String::New("byteOffset"), 438 array->Set(String::New("buffer"), buffer, ReadOnly);
440 Int32::New(static_cast<int32_t>(byteOffset)), ReadOnly); 439
441 array->Set(String::New("length"),
442 Int32::New(static_cast<int32_t>(length)), ReadOnly);
443 array->Set(String::New("BYTES_PER_ELEMENT"),
444 Int32::New(static_cast<int32_t>(element_size)));
445 // We currently support 'buffer' property only if constructed from a buffer.
446 if (first_arg_is_array_buffer) {
447 array->Set(String::New("buffer"), args[0], ReadOnly);
448 }
449 }
450 return array; 440 return array;
451 } 441 }
452 442
453 443
454 void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) { 444 void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) {
455 HandleScope scope; 445 HandleScope scope;
456 Handle<String> prop_name = String::New(kArrayBufferReferencePropName); 446 Local<Value> length = object->ToObject()->Get(String::New("byteLength"));
457 Handle<Object> converted_object = object->ToObject(); 447 V8::AdjustAmountOfExternalAllocatedMemory(-length->Uint32Value());
458 Local<Value> prop_value = converted_object->GetHiddenValue(prop_name); 448 delete[] static_cast<uint8_t*>(data);
459 if (data != NULL && prop_value.IsEmpty()) {
460 data = reinterpret_cast<size_t*>(data) - kExternalArrayAllocationHeaderSize;
461 V8::AdjustAmountOfExternalAllocatedMemory(
462 -static_cast<int>(*reinterpret_cast<size_t*>(data)));
463 free(data);
464 }
465 object.Dispose(); 449 object.Dispose();
466 } 450 }
467 451
468 452
469 Handle<Value> Shell::ArrayBuffer(const Arguments& args) { 453 Handle<Value> Shell::ArrayBuffer(const Arguments& args) {
470 return CreateExternalArray(args, v8::kExternalByteArray, 0); 454 return CreateExternalArrayBuffer(args);
471 } 455 }
472 456
473 457
474 Handle<Value> Shell::Int8Array(const Arguments& args) { 458 Handle<Value> Shell::Int8Array(const Arguments& args) {
475 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t)); 459 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t));
476 } 460 }
477 461
478 462
479 Handle<Value> Shell::Uint8Array(const Arguments& args) { 463 Handle<Value> Shell::Uint8Array(const Arguments& args) {
480 return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t)); 464 return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t));
(...skipping 547 matching lines...) Expand 10 before | Expand all | Expand 10 after
1028 int read = static_cast<int>(fread(&chars[i], 1, size - i, file)); 1012 int read = static_cast<int>(fread(&chars[i], 1, size - i, file));
1029 i += read; 1013 i += read;
1030 } 1014 }
1031 fclose(file); 1015 fclose(file);
1032 *size_out = size; 1016 *size_out = size;
1033 return chars; 1017 return chars;
1034 } 1018 }
1035 1019
1036 1020
1037 Handle<Value> Shell::ReadBuffer(const Arguments& args) { 1021 Handle<Value> Shell::ReadBuffer(const Arguments& args) {
1022 STATIC_ASSERT(sizeof(char) == sizeof(uint8_t)); // NOLINT
1038 String::Utf8Value filename(args[0]); 1023 String::Utf8Value filename(args[0]);
1039 int length; 1024 int length;
1040 if (*filename == NULL) { 1025 if (*filename == NULL) {
1041 return ThrowException(String::New("Error loading file")); 1026 return ThrowException(String::New("Error loading file"));
1042 } 1027 }
1043 char* data = ReadChars(*filename, &length); 1028
1029 uint8_t* data = reinterpret_cast<uint8_t*>(ReadChars(*filename, &length));
1044 if (data == NULL) { 1030 if (data == NULL) {
1045 return ThrowException(String::New("Error reading file")); 1031 return ThrowException(String::New("Error reading file"));
1046 } 1032 }
1047
1048 Handle<Object> buffer = Object::New(); 1033 Handle<Object> buffer = Object::New();
1049 buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True()); 1034 buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True());
1050
1051 Persistent<Object> persistent_buffer = Persistent<Object>::New(buffer); 1035 Persistent<Object> persistent_buffer = Persistent<Object>::New(buffer);
1052 persistent_buffer.MakeWeak(data, ExternalArrayWeakCallback); 1036 persistent_buffer.MakeWeak(data, ExternalArrayWeakCallback);
1053 persistent_buffer.MarkIndependent(); 1037 persistent_buffer.MarkIndependent();
1038 V8::AdjustAmountOfExternalAllocatedMemory(length);
1054 1039
1055 buffer->SetIndexedPropertiesToExternalArrayData( 1040 buffer->SetIndexedPropertiesToExternalArrayData(
1056 reinterpret_cast<uint8_t*>(data), kExternalUnsignedByteArray, length); 1041 data, kExternalUnsignedByteArray, length);
1057 buffer->Set(String::New("byteLength"), 1042 buffer->Set(String::New("byteLength"),
1058 Int32::New(static_cast<int32_t>(length)), ReadOnly); 1043 Int32::New(static_cast<int32_t>(length)), ReadOnly);
1059 return buffer; 1044 return buffer;
1060 } 1045 }
1061 1046
1062 1047
1063 #ifndef V8_SHARED 1048 #ifndef V8_SHARED
1064 static char* ReadToken(char* data, char token) { 1049 static char* ReadToken(char* data, char token) {
1065 char* next = i::OS::StrChr(data, token); 1050 char* next = i::OS::StrChr(data, token);
1066 if (next != NULL) { 1051 if (next != NULL) {
1067 *next = '\0'; 1052 *next = '\0';
1068 return (next + 1); 1053 return (next + 1);
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
1213 if (!Shell::ExecuteString(source, file_name, false, true)) { 1198 if (!Shell::ExecuteString(source, file_name, false, true)) {
1214 Shell::Exit(1); 1199 Shell::Exit(1);
1215 } 1200 }
1216 } 1201 }
1217 } 1202 }
1218 } 1203 }
1219 1204
1220 1205
1221 Handle<String> SourceGroup::ReadFile(const char* name) { 1206 Handle<String> SourceGroup::ReadFile(const char* name) {
1222 int size; 1207 int size;
1223 const char* chars = ReadChars(name, &size); 1208 char* chars = ReadChars(name, &size);
1224 if (chars == NULL) return Handle<String>(); 1209 if (chars == NULL) return Handle<String>();
1225 Handle<String> result = String::New(chars, size); 1210 Handle<String> result = String::New(chars, size);
1226 delete[] chars; 1211 delete[] chars;
1227 return result; 1212 return result;
1228 } 1213 }
1229 1214
1230 1215
1231 #ifndef V8_SHARED 1216 #ifndef V8_SHARED
1232 i::Thread::Options SourceGroup::GetThreadOptions() { 1217 i::Thread::Options SourceGroup::GetThreadOptions() {
1233 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less 1218 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after
1556 } 1541 }
1557 1542
1558 } // namespace v8 1543 } // namespace v8
1559 1544
1560 1545
1561 #ifndef GOOGLE3 1546 #ifndef GOOGLE3
1562 int main(int argc, char* argv[]) { 1547 int main(int argc, char* argv[]) {
1563 return v8::Shell::Main(argc, argv); 1548 return v8::Shell::Main(argc, argv);
1564 } 1549 }
1565 #endif 1550 #endif
OLDNEW
« no previous file with comments | « src/d8.h ('k') | test/mjsunit/external-array.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698