| OLD | NEW |
| 1 // Copyright 2011 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 |
| 11 // with the distribution. | 11 // with the distribution. |
| (...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 if (source.IsEmpty()) { | 274 if (source.IsEmpty()) { |
| 275 return ThrowException(String::New("Error loading file")); | 275 return ThrowException(String::New("Error loading file")); |
| 276 } | 276 } |
| 277 if (!ExecuteString(source, String::New(*file), false, true)) { | 277 if (!ExecuteString(source, String::New(*file), false, true)) { |
| 278 return ThrowException(String::New("Error executing file")); | 278 return ThrowException(String::New("Error executing file")); |
| 279 } | 279 } |
| 280 } | 280 } |
| 281 return Undefined(); | 281 return Undefined(); |
| 282 } | 282 } |
| 283 | 283 |
| 284 static size_t convertToUint(Local<Value> value_in, TryCatch* try_catch) { |
| 285 if (value_in->IsUint32()) { |
| 286 return value_in->Uint32Value(); |
| 287 } |
| 288 |
| 289 Local<Value> number = value_in->ToNumber(); |
| 290 if (try_catch->HasCaught()) return 0; |
| 291 |
| 292 ASSERT(number->IsNumber()); |
| 293 Local<Int32> int32 = number->ToInt32(); |
| 294 if (try_catch->HasCaught() || int32.IsEmpty()) return 0; |
| 295 |
| 296 int32_t raw_value = int32->Int32Value(); |
| 297 if (try_catch->HasCaught()) return 0; |
| 298 |
| 299 if (raw_value < 0) { |
| 300 ThrowException(String::New("Array length must not be negative.")); |
| 301 return 0; |
| 302 } |
| 303 |
| 304 static const int kMaxLength = 0x3fffffff; |
| 305 #ifndef V8_SHARED |
| 306 ASSERT(kMaxLength == i::ExternalArray::kMaxLength); |
| 307 #endif // V8_SHARED |
| 308 if (raw_value > static_cast<int32_t>(kMaxLength)) { |
| 309 ThrowException( |
| 310 String::New("Array length exceeds maximum length.")); |
| 311 } |
| 312 return static_cast<size_t>(raw_value); |
| 313 } |
| 314 |
| 315 |
| 316 const char kArrayBufferReferencePropName[] = "_is_array_buffer_"; |
| 317 const char kArrayBufferMarkerPropName[] = "_array_buffer_ref_"; |
| 318 |
| 284 | 319 |
| 285 Handle<Value> Shell::CreateExternalArray(const Arguments& args, | 320 Handle<Value> Shell::CreateExternalArray(const Arguments& args, |
| 286 ExternalArrayType type, | 321 ExternalArrayType type, |
| 287 size_t element_size) { | 322 size_t element_size) { |
| 323 TryCatch try_catch; |
| 324 bool is_array_buffer_construct = element_size == 0; |
| 325 if (is_array_buffer_construct) { |
| 326 type = v8::kExternalByteArray; |
| 327 element_size = 1; |
| 328 } |
| 288 ASSERT(element_size == 1 || element_size == 2 || element_size == 4 || | 329 ASSERT(element_size == 1 || element_size == 2 || element_size == 4 || |
| 289 element_size == 8); | 330 element_size == 8); |
| 290 if (args.Length() != 1) { | 331 if (args.Length() == 0) { |
| 291 return ThrowException( | 332 return ThrowException( |
| 292 String::New("Array constructor needs one parameter.")); | 333 String::New("Array constructor must have at least one " |
| 334 "parameter.")); |
| 293 } | 335 } |
| 294 static const int kMaxLength = 0x3fffffff; | 336 bool first_arg_is_array_buffer = |
| 295 #ifndef V8_SHARED | 337 args[0]->IsObject() && |
| 296 ASSERT(kMaxLength == i::ExternalArray::kMaxLength); | 338 args[0]->ToObject()->Get( |
| 297 #endif // V8_SHARED | 339 String::New(kArrayBufferMarkerPropName))->IsTrue(); |
| 298 size_t length = 0; | 340 // Currently, only the following constructors are supported: |
| 299 TryCatch try_catch; | 341 // TypedArray(unsigned long length) |
| 300 if (args[0]->IsUint32()) { | 342 // TypedArray(ArrayBuffer buffer, |
| 301 length = args[0]->Uint32Value(); | 343 // optional unsigned long byteOffset, |
| 302 } else { | 344 // optional unsigned long length) |
| 303 Local<Number> number = args[0]->ToNumber(); | 345 if (args.Length() > 3) { |
| 304 if (number.IsEmpty()) { | 346 return ThrowException( |
| 305 ASSERT(try_catch.HasCaught()); | 347 String::New("Array constructor from ArrayBuffer must " |
| 306 return try_catch.Exception(); | 348 "have 1-3 parameters.")); |
| 349 } |
| 350 |
| 351 Local<Value> length_value = (args.Length() < 3) |
| 352 ? (first_arg_is_array_buffer |
| 353 ? args[0]->ToObject()->Get(String::New("length")) |
| 354 : args[0]) |
| 355 : args[2]; |
| 356 size_t length = convertToUint(length_value, &try_catch); |
| 357 if (try_catch.HasCaught()) return try_catch.Exception(); |
| 358 |
| 359 void* data = NULL; |
| 360 size_t offset = 0; |
| 361 |
| 362 Handle<Object> array = Object::New(); |
| 363 if (first_arg_is_array_buffer) { |
| 364 Handle<Object> derived_from = args[0]->ToObject(); |
| 365 data = derived_from->GetIndexedPropertiesExternalArrayData(); |
| 366 |
| 367 size_t array_buffer_length = convertToUint( |
| 368 derived_from->Get(String::New("length")), |
| 369 &try_catch); |
| 370 if (try_catch.HasCaught()) return try_catch.Exception(); |
| 371 |
| 372 if (data == NULL && array_buffer_length != 0) { |
| 373 return ThrowException( |
| 374 String::New("ArrayBuffer doesn't have data")); |
| 307 } | 375 } |
| 308 ASSERT(number->IsNumber()); | 376 |
| 309 Local<Int32> int32 = number->ToInt32(); | 377 if (args.Length() > 1) { |
| 310 if (int32.IsEmpty()) { | 378 offset = convertToUint(args[1], &try_catch); |
| 311 if (try_catch.HasCaught()) { | 379 if (try_catch.HasCaught()) return try_catch.Exception(); |
| 312 return try_catch.Exception(); | 380 |
| 381 // The given byteOffset must be a multiple of the element size of the |
| 382 // specific type, otherwise an exception is raised. |
| 383 if (offset % element_size != 0) { |
| 384 return ThrowException( |
| 385 String::New("offset must be multiple of element_size")); |
| 313 } | 386 } |
| 314 } | 387 } |
| 315 int32_t raw_length = int32->Int32Value(); | 388 |
| 316 if (try_catch.HasCaught()) { | 389 if (offset > array_buffer_length) { |
| 317 return try_catch.Exception(); | 390 return ThrowException( |
| 391 String::New("byteOffset must be less than ArrayBuffer length.")); |
| 318 } | 392 } |
| 319 if (raw_length < 0) { | 393 |
| 320 return ThrowException(String::New("Array length must not be negative.")); | 394 if (args.Length() == 2) { |
| 395 // If length is not explicitly specified, the length of the ArrayBuffer |
| 396 // minus the byteOffset must be a multiple of the element size of the |
| 397 // specific type, or an exception is raised. |
| 398 length = array_buffer_length - offset; |
| 321 } | 399 } |
| 322 if (raw_length > static_cast<int32_t>(kMaxLength)) { | 400 |
| 401 if (args.Length() != 3) { |
| 402 if (length % element_size != 0) { |
| 403 return ThrowException( |
| 404 String::New("ArrayBuffer length minus the byteOffset must be a " |
| 405 "multiple of the element size")); |
| 406 } |
| 407 length /= element_size; |
| 408 } |
| 409 |
| 410 // If a given byteOffset and length references an area beyond the end of |
| 411 // the ArrayBuffer an exception is raised. |
| 412 if (offset + (length * element_size) > array_buffer_length) { |
| 323 return ThrowException( | 413 return ThrowException( |
| 324 String::New("Array length exceeds maximum length.")); | 414 String::New("length references an area beyond the end of the " |
| 415 "ArrayBuffer")); |
| 325 } | 416 } |
| 326 length = static_cast<size_t>(raw_length); | 417 |
| 418 // Hold a reference to the ArrayBuffer so its buffer doesn't get collected. |
| 419 array->Set(String::New(kArrayBufferReferencePropName), args[0], ReadOnly); |
| 327 } | 420 } |
| 328 if (length > static_cast<size_t>(kMaxLength)) { | 421 |
| 329 return ThrowException(String::New("Array length exceeds maximum length.")); | 422 if (is_array_buffer_construct) { |
| 423 array->Set(String::New(kArrayBufferMarkerPropName), True(), ReadOnly); |
| 330 } | 424 } |
| 331 void* data = calloc(length, element_size); | 425 |
| 332 if (data == NULL) { | |
| 333 return ThrowException(String::New("Memory allocation failed.")); | |
| 334 } | |
| 335 Handle<Object> array = Object::New(); | |
| 336 Persistent<Object> persistent_array = Persistent<Object>::New(array); | 426 Persistent<Object> persistent_array = Persistent<Object>::New(array); |
| 337 persistent_array.MakeWeak(data, ExternalArrayWeakCallback); | 427 persistent_array.MakeWeak(data, ExternalArrayWeakCallback); |
| 338 persistent_array.MarkIndependent(); | 428 persistent_array.MarkIndependent(); |
| 339 array->SetIndexedPropertiesToExternalArrayData(data, type, | 429 if (data == NULL && length != 0) { |
| 340 static_cast<int>(length)); | 430 data = calloc(length, element_size); |
| 431 if (data == NULL) { |
| 432 return ThrowException(String::New("Memory allocation failed.")); |
| 433 } |
| 434 } |
| 435 |
| 436 array->SetIndexedPropertiesToExternalArrayData( |
| 437 reinterpret_cast<uint8_t*>(data) + offset, type, |
| 438 static_cast<int>(length)); |
| 341 array->Set(String::New("length"), | 439 array->Set(String::New("length"), |
| 342 Int32::New(static_cast<int32_t>(length)), ReadOnly); | 440 Int32::New(static_cast<int32_t>(length)), ReadOnly); |
| 343 array->Set(String::New("BYTES_PER_ELEMENT"), | 441 array->Set(String::New("BYTES_PER_ELEMENT"), |
| 344 Int32::New(static_cast<int32_t>(element_size))); | 442 Int32::New(static_cast<int32_t>(element_size))); |
| 345 return array; | 443 return array; |
| 346 } | 444 } |
| 347 | 445 |
| 348 | 446 |
| 349 void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) { | 447 void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) { |
| 350 free(data); | 448 HandleScope scope; |
| 449 Handle<String> prop_name = String::New(kArrayBufferReferencePropName); |
| 450 Handle<Object> converted_object = object->ToObject(); |
| 451 Local<Value> prop_value = converted_object->Get(prop_name); |
| 452 if (data != NULL && !prop_value->IsObject()) { |
| 453 free(data); |
| 454 } |
| 351 object.Dispose(); | 455 object.Dispose(); |
| 352 } | 456 } |
| 353 | 457 |
| 354 | 458 |
| 459 Handle<Value> Shell::ArrayBuffer(const Arguments& args) { |
| 460 return CreateExternalArray(args, v8::kExternalByteArray, 0); |
| 461 } |
| 462 |
| 463 |
| 355 Handle<Value> Shell::Int8Array(const Arguments& args) { | 464 Handle<Value> Shell::Int8Array(const Arguments& args) { |
| 356 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t)); | 465 return CreateExternalArray(args, v8::kExternalByteArray, sizeof(int8_t)); |
| 357 } | 466 } |
| 358 | 467 |
| 359 | 468 |
| 360 Handle<Value> Shell::Uint8Array(const Arguments& args) { | 469 Handle<Value> Shell::Uint8Array(const Arguments& args) { |
| 361 return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t)); | 470 return CreateExternalArray(args, kExternalUnsignedByteArray, sizeof(uint8_t)); |
| 362 } | 471 } |
| 363 | 472 |
| 364 | 473 |
| (...skipping 321 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 686 FunctionTemplate::New(ReadLine)); | 795 FunctionTemplate::New(ReadLine)); |
| 687 global_template->Set(String::New("load"), FunctionTemplate::New(Load)); | 796 global_template->Set(String::New("load"), FunctionTemplate::New(Load)); |
| 688 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit)); | 797 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit)); |
| 689 global_template->Set(String::New("version"), FunctionTemplate::New(Version)); | 798 global_template->Set(String::New("version"), FunctionTemplate::New(Version)); |
| 690 global_template->Set(String::New("enableProfiler"), | 799 global_template->Set(String::New("enableProfiler"), |
| 691 FunctionTemplate::New(EnableProfiler)); | 800 FunctionTemplate::New(EnableProfiler)); |
| 692 global_template->Set(String::New("disableProfiler"), | 801 global_template->Set(String::New("disableProfiler"), |
| 693 FunctionTemplate::New(DisableProfiler)); | 802 FunctionTemplate::New(DisableProfiler)); |
| 694 | 803 |
| 695 // Bind the handlers for external arrays. | 804 // Bind the handlers for external arrays. |
| 805 global_template->Set(String::New("ArrayBuffer"), |
| 806 FunctionTemplate::New(ArrayBuffer)); |
| 696 global_template->Set(String::New("Int8Array"), | 807 global_template->Set(String::New("Int8Array"), |
| 697 FunctionTemplate::New(Int8Array)); | 808 FunctionTemplate::New(Int8Array)); |
| 698 global_template->Set(String::New("Uint8Array"), | 809 global_template->Set(String::New("Uint8Array"), |
| 699 FunctionTemplate::New(Uint8Array)); | 810 FunctionTemplate::New(Uint8Array)); |
| 700 global_template->Set(String::New("Int16Array"), | 811 global_template->Set(String::New("Int16Array"), |
| 701 FunctionTemplate::New(Int16Array)); | 812 FunctionTemplate::New(Int16Array)); |
| 702 global_template->Set(String::New("Uint16Array"), | 813 global_template->Set(String::New("Uint16Array"), |
| 703 FunctionTemplate::New(Uint16Array)); | 814 FunctionTemplate::New(Uint16Array)); |
| 704 global_template->Set(String::New("Int32Array"), | 815 global_template->Set(String::New("Int32Array"), |
| 705 FunctionTemplate::New(Int32Array)); | 816 FunctionTemplate::New(Int32Array)); |
| (...skipping 687 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1393 } | 1504 } |
| 1394 | 1505 |
| 1395 } // namespace v8 | 1506 } // namespace v8 |
| 1396 | 1507 |
| 1397 | 1508 |
| 1398 #ifndef GOOGLE3 | 1509 #ifndef GOOGLE3 |
| 1399 int main(int argc, char* argv[]) { | 1510 int main(int argc, char* argv[]) { |
| 1400 return v8::Shell::Main(argc, argv); | 1511 return v8::Shell::Main(argc, argv); |
| 1401 } | 1512 } |
| 1402 #endif | 1513 #endif |
| OLD | NEW |