Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 void* data = ReadChars(*filename, &length); | |
|
Michael Starzinger
2012/06/01 09:43:28
Why this change? I would prefer it to stay "char*"
rossberg
2012/06/01 11:42:35
Actually, changed it to uint8_t, which is more ade
| |
| 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(); |
|
Michael Starzinger
2012/06/01 09:43:28
I think we are missing a positive adjustment of th
rossberg
2012/06/01 11:42:35
Done.
| |
| 1054 | 1038 |
| 1055 buffer->SetIndexedPropertiesToExternalArrayData( | 1039 buffer->SetIndexedPropertiesToExternalArrayData( |
| 1056 reinterpret_cast<uint8_t*>(data), kExternalUnsignedByteArray, length); | 1040 reinterpret_cast<uint8_t*>(data), kExternalUnsignedByteArray, length); |
| 1057 buffer->Set(String::New("byteLength"), | 1041 buffer->Set(String::New("byteLength"), |
| 1058 Int32::New(static_cast<int32_t>(length)), ReadOnly); | 1042 Int32::New(static_cast<int32_t>(length)), ReadOnly); |
| 1059 return buffer; | 1043 return buffer; |
| 1060 } | 1044 } |
| 1061 | 1045 |
| 1062 | 1046 |
| 1063 #ifndef V8_SHARED | 1047 #ifndef V8_SHARED |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1213 if (!Shell::ExecuteString(source, file_name, false, true)) { | 1197 if (!Shell::ExecuteString(source, file_name, false, true)) { |
| 1214 Shell::Exit(1); | 1198 Shell::Exit(1); |
| 1215 } | 1199 } |
| 1216 } | 1200 } |
| 1217 } | 1201 } |
| 1218 } | 1202 } |
| 1219 | 1203 |
| 1220 | 1204 |
| 1221 Handle<String> SourceGroup::ReadFile(const char* name) { | 1205 Handle<String> SourceGroup::ReadFile(const char* name) { |
| 1222 int size; | 1206 int size; |
| 1223 const char* chars = ReadChars(name, &size); | 1207 char* chars = ReadChars(name, &size); |
| 1224 if (chars == NULL) return Handle<String>(); | 1208 if (chars == NULL) return Handle<String>(); |
| 1225 Handle<String> result = String::New(chars, size); | 1209 Handle<String> result = String::New(chars, size); |
| 1226 delete[] chars; | 1210 delete[] chars; |
| 1227 return result; | 1211 return result; |
| 1228 } | 1212 } |
| 1229 | 1213 |
| 1230 | 1214 |
| 1231 #ifndef V8_SHARED | 1215 #ifndef V8_SHARED |
| 1232 i::Thread::Options SourceGroup::GetThreadOptions() { | 1216 i::Thread::Options SourceGroup::GetThreadOptions() { |
| 1233 // On some systems (OSX 10.6) the stack size default is 0.5Mb or less | 1217 // 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 Loading... | |
| 1556 } | 1540 } |
| 1557 | 1541 |
| 1558 } // namespace v8 | 1542 } // namespace v8 |
| 1559 | 1543 |
| 1560 | 1544 |
| 1561 #ifndef GOOGLE3 | 1545 #ifndef GOOGLE3 |
| 1562 int main(int argc, char* argv[]) { | 1546 int main(int argc, char* argv[]) { |
| 1563 return v8::Shell::Main(argc, argv); | 1547 return v8::Shell::Main(argc, argv); |
| 1564 } | 1548 } |
| 1565 #endif | 1549 #endif |
| OLD | NEW |