| 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 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 317 ASSERT(kMaxLength == i::ExternalArray::kMaxLength); | 317 ASSERT(kMaxLength == i::ExternalArray::kMaxLength); |
| 318 #endif // V8_SHARED | 318 #endif // V8_SHARED |
| 319 if (raw_value > static_cast<int32_t>(kMaxLength)) { | 319 if (raw_value > static_cast<int32_t>(kMaxLength)) { |
| 320 ThrowException( | 320 ThrowException( |
| 321 String::New("Array length exceeds maximum length.")); | 321 String::New("Array length exceeds maximum length.")); |
| 322 } | 322 } |
| 323 return raw_value; | 323 return raw_value; |
| 324 } | 324 } |
| 325 | 325 |
| 326 | 326 |
| 327 // TODO(rossberg): should replace these by proper uses of HasInstance, |
| 328 // once we figure out a good way to make the templates global. |
| 327 const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_"; | 329 const char kArrayBufferMarkerPropName[] = "d8::_is_array_buffer_"; |
| 328 const char kArrayMarkerPropName[] = "d8::_is_typed_array_"; | 330 const char kArrayMarkerPropName[] = "d8::_is_typed_array_"; |
| 329 | 331 |
| 330 | 332 |
| 331 Handle<Value> Shell::CreateExternalArrayBuffer(Handle<Object> buffer, | 333 Handle<Value> Shell::CreateExternalArrayBuffer(Handle<Object> buffer, |
| 332 int32_t length) { | 334 int32_t length) { |
| 333 static const int32_t kMaxSize = 0x7fffffff; | 335 static const int32_t kMaxSize = 0x7fffffff; |
| 334 // Make sure the total size fits into a (signed) int. | 336 // Make sure the total size fits into a (signed) int. |
| 335 if (length < 0 || length > kMaxSize) { | 337 if (length < 0 || length > kMaxSize) { |
| 336 return ThrowException(String::New("ArrayBuffer exceeds maximum size (2G)")); | 338 return ThrowException(String::New("ArrayBuffer exceeds maximum size (2G)")); |
| 337 } | 339 } |
| 338 uint8_t* data = new uint8_t[length]; | 340 uint8_t* data = new uint8_t[length]; |
| 339 if (data == NULL) { | 341 if (data == NULL) { |
| 340 return ThrowException(String::New("Memory allocation failed.")); | 342 return ThrowException(String::New("Memory allocation failed")); |
| 341 } | 343 } |
| 342 memset(data, 0, length); | 344 memset(data, 0, length); |
| 343 | 345 |
| 344 buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True()); | 346 buffer->SetHiddenValue(String::New(kArrayBufferMarkerPropName), True()); |
| 345 Persistent<Object> persistent_array = Persistent<Object>::New(buffer); | 347 Persistent<Object> persistent_array = Persistent<Object>::New(buffer); |
| 346 persistent_array.MakeWeak(data, ExternalArrayWeakCallback); | 348 persistent_array.MakeWeak(data, ExternalArrayWeakCallback); |
| 347 persistent_array.MarkIndependent(); | 349 persistent_array.MarkIndependent(); |
| 348 V8::AdjustAmountOfExternalAllocatedMemory(length); | 350 V8::AdjustAmountOfExternalAllocatedMemory(length); |
| 349 | 351 |
| 350 buffer->SetIndexedPropertiesToExternalArrayData( | 352 buffer->SetIndexedPropertiesToExternalArrayData( |
| 351 data, v8::kExternalByteArray, length); | 353 data, v8::kExternalByteArray, length); |
| 352 buffer->Set(String::New("byteLength"), Int32::New(length), ReadOnly); | 354 buffer->Set(String::New("byteLength"), Int32::New(length), ReadOnly); |
| 353 | 355 |
| 354 return buffer; | 356 return buffer; |
| 355 } | 357 } |
| 356 | 358 |
| 357 | 359 |
| 358 Handle<Value> Shell::ArrayBuffer(const Arguments& args) { | 360 Handle<Value> Shell::ArrayBuffer(const Arguments& args) { |
| 359 if (!args.IsConstructCall()) { | 361 if (!args.IsConstructCall()) { |
| 360 Handle<Value>* rec_args = new Handle<Value>[args.Length()]; | 362 Handle<Value>* rec_args = new Handle<Value>[args.Length()]; |
| 361 for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i]; | 363 for (int i = 0; i < args.Length(); ++i) rec_args[i] = args[i]; |
| 362 Handle<Value> result = args.Callee()->NewInstance(args.Length(), rec_args); | 364 Handle<Value> result = args.Callee()->NewInstance(args.Length(), rec_args); |
| 363 delete[] rec_args; | 365 delete[] rec_args; |
| 364 return result; | 366 return result; |
| 365 } | 367 } |
| 366 | 368 |
| 367 if (args.Length() == 0) { | 369 if (args.Length() == 0) { |
| 368 return ThrowException( | 370 return ThrowException( |
| 369 String::New("ArrayBuffer constructor must have one parameter.")); | 371 String::New("ArrayBuffer constructor must have one argument")); |
| 370 } | 372 } |
| 371 TryCatch try_catch; | 373 TryCatch try_catch; |
| 372 int32_t length = convertToUint(args[0], &try_catch); | 374 int32_t length = convertToUint(args[0], &try_catch); |
| 373 if (try_catch.HasCaught()) return try_catch.Exception(); | 375 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 374 | 376 |
| 375 return CreateExternalArrayBuffer(args.This(), length); | 377 return CreateExternalArrayBuffer(args.This(), length); |
| 376 } | 378 } |
| 377 | 379 |
| 378 | 380 |
| 379 Handle<Object> Shell::CreateExternalArray(Handle<Object> array, | 381 Handle<Object> Shell::CreateExternalArray(Handle<Object> array, |
| 380 Handle<Object> buffer, | 382 Handle<Object> buffer, |
| 381 ExternalArrayType type, | 383 ExternalArrayType type, |
| 382 int32_t length, | 384 int32_t length, |
| 383 int32_t byteLength, | 385 int32_t byteLength, |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 425 // TypedArray(ArrayBuffer buffer, | 427 // TypedArray(ArrayBuffer buffer, |
| 426 // optional unsigned long byteOffset, | 428 // optional unsigned long byteOffset, |
| 427 // optional unsigned long length) | 429 // optional unsigned long length) |
| 428 Handle<Object> buffer; | 430 Handle<Object> buffer; |
| 429 int32_t length; | 431 int32_t length; |
| 430 int32_t byteLength; | 432 int32_t byteLength; |
| 431 int32_t byteOffset; | 433 int32_t byteOffset; |
| 432 bool init_from_array = false; | 434 bool init_from_array = false; |
| 433 if (args.Length() == 0) { | 435 if (args.Length() == 0) { |
| 434 return ThrowException( | 436 return ThrowException( |
| 435 String::New("Array constructor must have at least one parameter.")); | 437 String::New("Array constructor must have at least one argument")); |
| 436 } | 438 } |
| 437 if (args[0]->IsObject() && | 439 if (args[0]->IsObject() && |
| 438 !args[0]->ToObject()->GetHiddenValue( | 440 !args[0]->ToObject()->GetHiddenValue( |
| 439 String::New(kArrayBufferMarkerPropName)).IsEmpty()) { | 441 String::New(kArrayBufferMarkerPropName)).IsEmpty()) { |
| 440 // Construct from ArrayBuffer. | 442 // Construct from ArrayBuffer. |
| 441 buffer = args[0]->ToObject(); | 443 buffer = args[0]->ToObject(); |
| 442 int32_t bufferLength = | 444 int32_t bufferLength = |
| 443 convertToUint(buffer->Get(String::New("byteLength")), &try_catch); | 445 convertToUint(buffer->Get(String::New("byteLength")), &try_catch); |
| 444 if (try_catch.HasCaught()) return try_catch.Exception(); | 446 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 445 | 447 |
| 446 if (args.Length() < 2 || args[1]->IsUndefined()) { | 448 if (args.Length() < 2 || args[1]->IsUndefined()) { |
| 447 byteOffset = 0; | 449 byteOffset = 0; |
| 448 } else { | 450 } else { |
| 449 byteOffset = convertToUint(args[1], &try_catch); | 451 byteOffset = convertToUint(args[1], &try_catch); |
| 450 if (try_catch.HasCaught()) return try_catch.Exception(); | 452 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 451 if (byteOffset > bufferLength) { | 453 if (byteOffset > bufferLength) { |
| 452 return ThrowException(String::New("byteOffset out of bounds")); | 454 return ThrowException(String::New("byteOffset out of bounds")); |
| 453 } | 455 } |
| 454 if (byteOffset % element_size != 0) { | 456 if (byteOffset % element_size != 0) { |
| 455 return ThrowException( | 457 return ThrowException( |
| 456 String::New("byteOffset must be multiple of element_size")); | 458 String::New("byteOffset must be multiple of element size")); |
| 457 } | 459 } |
| 458 } | 460 } |
| 459 | 461 |
| 460 if (args.Length() < 3 || args[2]->IsUndefined()) { | 462 if (args.Length() < 3 || args[2]->IsUndefined()) { |
| 461 byteLength = bufferLength - byteOffset; | 463 byteLength = bufferLength - byteOffset; |
| 462 length = byteLength / element_size; | 464 length = byteLength / element_size; |
| 463 if (byteLength % element_size != 0) { | 465 if (byteLength % element_size != 0) { |
| 464 return ThrowException( | 466 return ThrowException( |
| 465 String::New("buffer size must be multiple of element_size")); | 467 String::New("buffer size must be multiple of element size")); |
| 466 } | 468 } |
| 467 } else { | 469 } else { |
| 468 length = convertToUint(args[2], &try_catch); | 470 length = convertToUint(args[2], &try_catch); |
| 469 if (try_catch.HasCaught()) return try_catch.Exception(); | 471 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 470 byteLength = length * element_size; | 472 byteLength = length * element_size; |
| 471 if (byteOffset + byteLength > bufferLength) { | 473 if (byteOffset + byteLength > bufferLength) { |
| 472 return ThrowException(String::New("length out of bounds")); | 474 return ThrowException(String::New("length out of bounds")); |
| 473 } | 475 } |
| 474 } | 476 } |
| 475 } else { | 477 } else { |
| 476 if (args[0]->IsObject() && | 478 if (args[0]->IsObject() && |
| 477 args[0]->ToObject()->Has(String::New("length"))) { | 479 args[0]->ToObject()->Has(String::New("length"))) { |
| 478 // Construct from array. | 480 // Construct from array. |
| 479 length = convertToUint( | 481 length = convertToUint( |
| 480 args[0]->ToObject()->Get(String::New("length")), &try_catch); | 482 args[0]->ToObject()->Get(String::New("length")), &try_catch); |
| 481 if (try_catch.HasCaught()) return try_catch.Exception(); | 483 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 482 init_from_array = true; | 484 init_from_array = true; |
| 483 } else { | 485 } else { |
| 484 // Construct from size. | 486 // Construct from size. |
| 485 length = convertToUint(args[0], &try_catch); | 487 length = convertToUint(args[0], &try_catch); |
| 486 if (try_catch.HasCaught()) return try_catch.Exception(); | 488 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 487 } | 489 } |
| 488 byteLength = length * element_size; | 490 byteLength = length * element_size; |
| 489 byteOffset = 0; | 491 byteOffset = 0; |
| 490 | 492 |
| 491 Handle<Object> global = Context::GetCurrent()->Global(); | 493 Handle<Object> global = Context::GetCurrent()->Global(); |
| 492 Handle<Value> array_buffer = global->Get(String::New("ArrayBuffer")); | 494 Handle<Value> array_buffer = global->Get(String::New("ArrayBuffer")); |
| 493 ASSERT(!try_catch.HasCaught() && array_buffer->IsFunction()); | 495 ASSERT(!try_catch.HasCaught() && array_buffer->IsFunction()); |
| 494 Handle<Value> buffer_args[] = { Uint32::New(byteLength) }; | 496 Handle<Value> buffer_args[] = { Uint32::New(byteLength) }; |
| 495 Handle<Value> result = Handle<Function>::Cast(array_buffer)->NewInstance( | 497 Handle<Value> result = Handle<Function>::Cast(array_buffer)->NewInstance( |
| 496 1, buffer_args); | 498 1, buffer_args); |
| 497 if (try_catch.HasCaught()) return result; | 499 if (try_catch.HasCaught()) return result; |
| 498 buffer = result->ToObject(); | 500 buffer = result->ToObject(); |
| 499 } | 501 } |
| 500 | 502 |
| 501 Handle<Object> array = CreateExternalArray( | 503 Handle<Object> array = CreateExternalArray( |
| 502 args.This(), buffer, type, length, byteLength, byteOffset, element_size); | 504 args.This(), buffer, type, length, byteLength, byteOffset, element_size); |
| 503 | 505 |
| 504 if (init_from_array) { | 506 if (init_from_array) { |
| 505 Handle<Object> init = args[0]->ToObject(); | 507 Handle<Object> init = args[0]->ToObject(); |
| 506 for (int i = 0; i < length; ++i) array->Set(i, init->Get(i)); | 508 for (int i = 0; i < length; ++i) array->Set(i, init->Get(i)); |
| 507 } | 509 } |
| 508 | 510 |
| 509 return array; | 511 return array; |
| 510 } | 512 } |
| 511 | 513 |
| 512 | 514 |
| 513 Handle<Value> Shell::SubArray(const Arguments& args) { | 515 Handle<Value> Shell::ArrayBufferSlice(const Arguments& args) { |
| 514 TryCatch try_catch; | 516 TryCatch try_catch; |
| 515 | 517 |
| 516 if (!args.This()->IsObject()) { | 518 if (!args.This()->IsObject()) { |
| 517 return ThrowException( | 519 return ThrowException( |
| 518 String::New("subarray invoked on non-object receiver.")); | 520 String::New("'slice' invoked on non-object receiver")); |
| 521 } |
| 522 |
| 523 Local<Object> self = args.This(); |
| 524 Local<Value> marker = |
| 525 self->GetHiddenValue(String::New(kArrayBufferMarkerPropName)); |
| 526 if (marker.IsEmpty()) { |
| 527 return ThrowException( |
| 528 String::New("'slice' invoked on wrong receiver type")); |
| 529 } |
| 530 |
| 531 int32_t length = |
| 532 convertToUint(self->Get(String::New("byteLength")), &try_catch); |
| 533 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 534 |
| 535 if (args.Length() == 0) { |
| 536 return ThrowException( |
| 537 String::New("'slice' must have at least one argument")); |
| 538 } |
| 539 int32_t begin = convertToInt(args[0], &try_catch); |
| 540 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 541 if (begin < 0) begin += length; |
| 542 if (begin < 0) begin = 0; |
| 543 if (begin > length) begin = length; |
| 544 |
| 545 int32_t end; |
| 546 if (args.Length() < 2 || args[1]->IsUndefined()) { |
| 547 end = length; |
| 548 } else { |
| 549 end = convertToInt(args[1], &try_catch); |
| 550 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 551 if (end < 0) end += length; |
| 552 if (end < 0) end = 0; |
| 553 if (end > length) end = length; |
| 554 if (end < begin) end = begin; |
| 555 } |
| 556 |
| 557 Local<Function> constructor = Local<Function>::Cast(self->GetConstructor()); |
| 558 Handle<Value> new_args[] = { Uint32::New(end - begin) }; |
| 559 Handle<Value> result = constructor->NewInstance(1, new_args); |
| 560 if (try_catch.HasCaught()) return result; |
| 561 Handle<Object> buffer = result->ToObject(); |
| 562 uint8_t* dest = |
| 563 static_cast<uint8_t*>(buffer->GetIndexedPropertiesExternalArrayData()); |
| 564 uint8_t* src = begin + static_cast<uint8_t*>( |
| 565 self->GetIndexedPropertiesExternalArrayData()); |
| 566 memcpy(dest, src, end - begin); |
| 567 |
| 568 return buffer; |
| 569 } |
| 570 |
| 571 |
| 572 Handle<Value> Shell::ArraySubArray(const Arguments& args) { |
| 573 TryCatch try_catch; |
| 574 |
| 575 if (!args.This()->IsObject()) { |
| 576 return ThrowException( |
| 577 String::New("'subarray' invoked on non-object receiver")); |
| 519 } | 578 } |
| 520 | 579 |
| 521 Local<Object> self = args.This(); | 580 Local<Object> self = args.This(); |
| 522 Local<Value> marker = self->GetHiddenValue(String::New(kArrayMarkerPropName)); | 581 Local<Value> marker = self->GetHiddenValue(String::New(kArrayMarkerPropName)); |
| 523 if (marker.IsEmpty()) { | 582 if (marker.IsEmpty()) { |
| 524 return ThrowException( | 583 return ThrowException( |
| 525 String::New("subarray invoked on wrong receiver type.")); | 584 String::New("'subarray' invoked on wrong receiver type")); |
| 526 } | 585 } |
| 527 | 586 |
| 528 Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject(); | 587 Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject(); |
| 529 if (try_catch.HasCaught()) return try_catch.Exception(); | 588 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 530 int32_t length = | 589 int32_t length = |
| 531 convertToUint(self->Get(String::New("length")), &try_catch); | 590 convertToUint(self->Get(String::New("length")), &try_catch); |
| 532 if (try_catch.HasCaught()) return try_catch.Exception(); | 591 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 533 int32_t byteOffset = | 592 int32_t byteOffset = |
| 534 convertToUint(self->Get(String::New("byteOffset")), &try_catch); | 593 convertToUint(self->Get(String::New("byteOffset")), &try_catch); |
| 535 if (try_catch.HasCaught()) return try_catch.Exception(); | 594 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 536 int32_t element_size = | 595 int32_t element_size = |
| 537 convertToUint(self->Get(String::New("BYTES_PER_ELEMENT")), &try_catch); | 596 convertToUint(self->Get(String::New("BYTES_PER_ELEMENT")), &try_catch); |
| 538 if (try_catch.HasCaught()) return try_catch.Exception(); | 597 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 539 | 598 |
| 540 if (args.Length() == 0) { | 599 if (args.Length() == 0) { |
| 541 return ThrowException( | 600 return ThrowException( |
| 542 String::New("subarray must have at least one parameter.")); | 601 String::New("'subarray' must have at least one argument")); |
| 543 } | 602 } |
| 544 int32_t begin = convertToInt(args[0], &try_catch); | 603 int32_t begin = convertToInt(args[0], &try_catch); |
| 545 if (try_catch.HasCaught()) return try_catch.Exception(); | 604 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 546 if (begin < 0) begin += length; | 605 if (begin < 0) begin += length; |
| 547 if (begin < 0) begin = 0; | 606 if (begin < 0) begin = 0; |
| 548 if (begin > length) begin = length; | 607 if (begin > length) begin = length; |
| 549 | 608 |
| 550 int32_t end; | 609 int32_t end; |
| 551 if (args.Length() < 2 || args[1]->IsUndefined()) { | 610 if (args.Length() < 2 || args[1]->IsUndefined()) { |
| 552 end = length; | 611 end = length; |
| 553 } else { | 612 } else { |
| 554 end = convertToInt(args[1], &try_catch); | 613 end = convertToInt(args[1], &try_catch); |
| 555 if (try_catch.HasCaught()) return try_catch.Exception(); | 614 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 556 if (end < 0) end += length; | 615 if (end < 0) end += length; |
| 557 if (end < 0) end = 0; | 616 if (end < 0) end = 0; |
| 558 if (end > length) end = length; | 617 if (end > length) end = length; |
| 559 if (end < begin) end = begin; | 618 if (end < begin) end = begin; |
| 560 } | 619 } |
| 561 | 620 |
| 562 length = end - begin; | 621 length = end - begin; |
| 563 byteOffset += begin * element_size; | 622 byteOffset += begin * element_size; |
| 564 | 623 |
| 565 Local<Function> constructor = Local<Function>::Cast(self->GetConstructor()); | 624 Local<Function> constructor = Local<Function>::Cast(self->GetConstructor()); |
| 566 Handle<Value> construct_args[] = { | 625 Handle<Value> construct_args[] = { |
| 567 buffer, Uint32::New(byteOffset), Uint32::New(length) | 626 buffer, Uint32::New(byteOffset), Uint32::New(length) |
| 568 }; | 627 }; |
| 569 return constructor->NewInstance(3, construct_args); | 628 return constructor->NewInstance(3, construct_args); |
| 570 } | 629 } |
| 571 | 630 |
| 572 | 631 |
| 632 Handle<Value> Shell::ArraySet(const Arguments& args) { |
| 633 TryCatch try_catch; |
| 634 |
| 635 if (!args.This()->IsObject()) { |
| 636 return ThrowException( |
| 637 String::New("'set' invoked on non-object receiver")); |
| 638 } |
| 639 |
| 640 Local<Object> self = args.This(); |
| 641 Local<Value> marker = self->GetHiddenValue(String::New(kArrayMarkerPropName)); |
| 642 if (marker.IsEmpty()) { |
| 643 return ThrowException( |
| 644 String::New("'set' invoked on wrong receiver type")); |
| 645 } |
| 646 int32_t length = |
| 647 convertToUint(self->Get(String::New("length")), &try_catch); |
| 648 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 649 int32_t element_size = |
| 650 convertToUint(self->Get(String::New("BYTES_PER_ELEMENT")), &try_catch); |
| 651 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 652 |
| 653 if (args.Length() == 0) { |
| 654 return ThrowException( |
| 655 String::New("'set' must have at least one argument")); |
| 656 } |
| 657 if (!args[0]->IsObject() || |
| 658 !args[0]->ToObject()->Has(String::New("length"))) { |
| 659 return ThrowException( |
| 660 String::New("'set' invoked with non-array argument")); |
| 661 } |
| 662 Handle<Object> source = args[0]->ToObject(); |
| 663 int32_t source_length = |
| 664 convertToUint(source->Get(String::New("length")), &try_catch); |
| 665 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 666 |
| 667 int32_t offset; |
| 668 if (args.Length() < 2 || args[1]->IsUndefined()) { |
| 669 offset = 0; |
| 670 } else { |
| 671 offset = convertToUint(args[1], &try_catch); |
| 672 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 673 } |
| 674 if (offset + source_length > length) { |
| 675 return ThrowException(String::New("offset or source length out of bounds")); |
| 676 } |
| 677 |
| 678 int32_t source_element_size; |
| 679 if (source->GetHiddenValue(String::New(kArrayMarkerPropName)).IsEmpty()) { |
| 680 source_element_size = 0; |
| 681 } else { |
| 682 source_element_size = |
| 683 convertToUint(source->Get(String::New("BYTES_PER_ELEMENT")), &try_catch); |
| 684 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 685 } |
| 686 |
| 687 if (element_size == source_element_size && |
| 688 self->GetConstructor()->StrictEquals(source->GetConstructor())) { |
| 689 // Use memmove on the array buffers. |
| 690 Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject(); |
| 691 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 692 Handle<Object> source_buffer = |
| 693 source->Get(String::New("buffer"))->ToObject(); |
| 694 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 695 int32_t byteOffset = |
| 696 convertToUint(self->Get(String::New("byteOffset")), &try_catch); |
| 697 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 698 int32_t source_byteOffset = |
| 699 convertToUint(source->Get(String::New("byteOffset")), &try_catch); |
| 700 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 701 |
| 702 uint8_t* dest = byteOffset + offset * element_size + static_cast<uint8_t*>( |
| 703 buffer->GetIndexedPropertiesExternalArrayData()); |
| 704 uint8_t* src = source_byteOffset + static_cast<uint8_t*>( |
| 705 source_buffer->GetIndexedPropertiesExternalArrayData()); |
| 706 memmove(dest, src, source_length * element_size); |
| 707 } else if (source_element_size == 0) { |
| 708 // Source is not a typed array, copy element-wise sequentially. |
| 709 for (int i = 0; i < source_length; ++i) { |
| 710 self->Set(offset + i, source->Get(i)); |
| 711 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 712 } |
| 713 } else { |
| 714 // Need to copy element-wise to make the right conversions. |
| 715 Handle<Object> buffer = self->Get(String::New("buffer"))->ToObject(); |
| 716 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 717 Handle<Object> source_buffer = |
| 718 source->Get(String::New("buffer"))->ToObject(); |
| 719 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 720 |
| 721 if (buffer->StrictEquals(source_buffer)) { |
| 722 // Same backing store, need to handle overlap correctly. |
| 723 // This gets a bit tricky in the case of different element sizes |
| 724 // (which, of course, is extremely unlikely to ever occur in practice). |
| 725 int32_t byteOffset = |
| 726 convertToUint(self->Get(String::New("byteOffset")), &try_catch); |
| 727 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 728 int32_t source_byteOffset = |
| 729 convertToUint(source->Get(String::New("byteOffset")), &try_catch); |
| 730 if (try_catch.HasCaught()) return try_catch.ReThrow(); |
| 731 |
| 732 // Copy as much as we can from left to right. |
| 733 int i = 0; |
| 734 int32_t next_dest_offset = byteOffset + (offset + 1) * element_size; |
| 735 int32_t next_src_offset = source_byteOffset + source_element_size; |
| 736 while (i < length && next_dest_offset <= next_src_offset) { |
| 737 self->Set(offset + i, source->Get(i)); |
| 738 ++i; |
| 739 next_dest_offset += element_size; |
| 740 next_src_offset += source_element_size; |
| 741 } |
| 742 // Of what's left, copy as much as we can from right to left. |
| 743 int j = length - 1; |
| 744 int32_t dest_offset = byteOffset + (offset + j) * element_size; |
| 745 int32_t src_offset = source_byteOffset + j * source_element_size; |
| 746 while (j >= i && dest_offset >= src_offset) { |
| 747 self->Set(offset + j, source->Get(j)); |
| 748 --j; |
| 749 dest_offset -= element_size; |
| 750 src_offset -= source_element_size; |
| 751 } |
| 752 // There can be at most 8 entries left in the middle that need buffering |
| 753 // (because the largest element_size is 8 times the smallest). |
| 754 ASSERT(j+1 - i <= 8); |
| 755 Handle<Value> temp[8]; |
| 756 for (int k = i; k <= j; ++k) { |
| 757 temp[k - i] = source->Get(k); |
| 758 } |
| 759 for (int k = i; k <= j; ++k) { |
| 760 self->Set(offset + k, temp[k - i]); |
| 761 } |
| 762 } else { |
| 763 // Different backing stores, safe to copy element-wise sequentially. |
| 764 for (int i = 0; i < source_length; ++i) |
| 765 self->Set(offset + i, source->Get(i)); |
| 766 } |
| 767 } |
| 768 |
| 769 return Undefined(); |
| 770 } |
| 771 |
| 772 |
| 573 void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) { | 773 void Shell::ExternalArrayWeakCallback(Persistent<Value> object, void* data) { |
| 574 HandleScope scope; | 774 HandleScope scope; |
| 575 int32_t length = | 775 int32_t length = |
| 576 object->ToObject()->Get(String::New("byteLength"))->Uint32Value(); | 776 object->ToObject()->Get(String::New("byteLength"))->Uint32Value(); |
| 577 V8::AdjustAmountOfExternalAllocatedMemory(-length); | 777 V8::AdjustAmountOfExternalAllocatedMemory(-length); |
| 578 delete[] static_cast<uint8_t*>(data); | 778 delete[] static_cast<uint8_t*>(data); |
| 579 object.Dispose(); | 779 object.Dispose(); |
| 580 } | 780 } |
| 581 | 781 |
| 582 | 782 |
| (...skipping 329 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 912 0, 1); | 1112 0, 1); |
| 913 if (result == BZ_OK) { | 1113 if (result == BZ_OK) { |
| 914 *raw_data_size = decompressed_size; | 1114 *raw_data_size = decompressed_size; |
| 915 } | 1115 } |
| 916 return result; | 1116 return result; |
| 917 } | 1117 } |
| 918 }; | 1118 }; |
| 919 #endif | 1119 #endif |
| 920 | 1120 |
| 921 | 1121 |
| 1122 Handle<FunctionTemplate> Shell::CreateArrayBufferTemplate( |
| 1123 InvocationCallback fun) { |
| 1124 Handle<FunctionTemplate> buffer_template = FunctionTemplate::New(fun); |
| 1125 Local<Template> proto_template = buffer_template->PrototypeTemplate(); |
| 1126 proto_template->Set(String::New("slice"), |
| 1127 FunctionTemplate::New(ArrayBufferSlice)); |
| 1128 return buffer_template; |
| 1129 } |
| 1130 |
| 1131 |
| 922 Handle<FunctionTemplate> Shell::CreateArrayTemplate(InvocationCallback fun) { | 1132 Handle<FunctionTemplate> Shell::CreateArrayTemplate(InvocationCallback fun) { |
| 923 Handle<FunctionTemplate> array_template = FunctionTemplate::New(fun); | 1133 Handle<FunctionTemplate> array_template = FunctionTemplate::New(fun); |
| 924 Local<Template> proto_template = array_template->PrototypeTemplate(); | 1134 Local<Template> proto_template = array_template->PrototypeTemplate(); |
| 925 proto_template->Set(String::New("subarray"), FunctionTemplate::New(SubArray)); | 1135 proto_template->Set(String::New("set"), FunctionTemplate::New(ArraySet)); |
| 1136 proto_template->Set(String::New("subarray"), |
| 1137 FunctionTemplate::New(ArraySubArray)); |
| 926 return array_template; | 1138 return array_template; |
| 927 } | 1139 } |
| 928 | 1140 |
| 929 | 1141 |
| 930 Handle<ObjectTemplate> Shell::CreateGlobalTemplate() { | 1142 Handle<ObjectTemplate> Shell::CreateGlobalTemplate() { |
| 931 Handle<ObjectTemplate> global_template = ObjectTemplate::New(); | 1143 Handle<ObjectTemplate> global_template = ObjectTemplate::New(); |
| 932 global_template->Set(String::New("print"), FunctionTemplate::New(Print)); | 1144 global_template->Set(String::New("print"), FunctionTemplate::New(Print)); |
| 933 global_template->Set(String::New("write"), FunctionTemplate::New(Write)); | 1145 global_template->Set(String::New("write"), FunctionTemplate::New(Write)); |
| 934 global_template->Set(String::New("read"), FunctionTemplate::New(Read)); | 1146 global_template->Set(String::New("read"), FunctionTemplate::New(Read)); |
| 935 global_template->Set(String::New("readbuffer"), | 1147 global_template->Set(String::New("readbuffer"), |
| 936 FunctionTemplate::New(ReadBuffer)); | 1148 FunctionTemplate::New(ReadBuffer)); |
| 937 global_template->Set(String::New("readline"), | 1149 global_template->Set(String::New("readline"), |
| 938 FunctionTemplate::New(ReadLine)); | 1150 FunctionTemplate::New(ReadLine)); |
| 939 global_template->Set(String::New("load"), FunctionTemplate::New(Load)); | 1151 global_template->Set(String::New("load"), FunctionTemplate::New(Load)); |
| 940 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit)); | 1152 global_template->Set(String::New("quit"), FunctionTemplate::New(Quit)); |
| 941 global_template->Set(String::New("version"), FunctionTemplate::New(Version)); | 1153 global_template->Set(String::New("version"), FunctionTemplate::New(Version)); |
| 942 global_template->Set(String::New("enableProfiler"), | 1154 global_template->Set(String::New("enableProfiler"), |
| 943 FunctionTemplate::New(EnableProfiler)); | 1155 FunctionTemplate::New(EnableProfiler)); |
| 944 global_template->Set(String::New("disableProfiler"), | 1156 global_template->Set(String::New("disableProfiler"), |
| 945 FunctionTemplate::New(DisableProfiler)); | 1157 FunctionTemplate::New(DisableProfiler)); |
| 946 | 1158 |
| 947 // Bind the handlers for external arrays. | 1159 // Bind the handlers for external arrays. |
| 948 PropertyAttribute attr = | 1160 PropertyAttribute attr = |
| 949 static_cast<PropertyAttribute>(ReadOnly | DontDelete); | 1161 static_cast<PropertyAttribute>(ReadOnly | DontDelete); |
| 950 global_template->Set(String::New("ArrayBuffer"), | 1162 global_template->Set(String::New("ArrayBuffer"), |
| 951 CreateArrayTemplate(ArrayBuffer), attr); | 1163 CreateArrayBufferTemplate(ArrayBuffer), attr); |
| 952 global_template->Set(String::New("Int8Array"), | 1164 global_template->Set(String::New("Int8Array"), |
| 953 CreateArrayTemplate(Int8Array), attr); | 1165 CreateArrayTemplate(Int8Array), attr); |
| 954 global_template->Set(String::New("Uint8Array"), | 1166 global_template->Set(String::New("Uint8Array"), |
| 955 CreateArrayTemplate(Uint8Array), attr); | 1167 CreateArrayTemplate(Uint8Array), attr); |
| 956 global_template->Set(String::New("Int16Array"), | 1168 global_template->Set(String::New("Int16Array"), |
| 957 CreateArrayTemplate(Int16Array), attr); | 1169 CreateArrayTemplate(Int16Array), attr); |
| 958 global_template->Set(String::New("Uint16Array"), | 1170 global_template->Set(String::New("Uint16Array"), |
| 959 CreateArrayTemplate(Uint16Array), attr); | 1171 CreateArrayTemplate(Uint16Array), attr); |
| 960 global_template->Set(String::New("Int32Array"), | 1172 global_template->Set(String::New("Int32Array"), |
| 961 CreateArrayTemplate(Int32Array), attr); | 1173 CreateArrayTemplate(Int32Array), attr); |
| (...skipping 715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1677 } | 1889 } |
| 1678 | 1890 |
| 1679 } // namespace v8 | 1891 } // namespace v8 |
| 1680 | 1892 |
| 1681 | 1893 |
| 1682 #ifndef GOOGLE3 | 1894 #ifndef GOOGLE3 |
| 1683 int main(int argc, char* argv[]) { | 1895 int main(int argc, char* argv[]) { |
| 1684 return v8::Shell::Main(argc, argv); | 1896 return v8::Shell::Main(argc, argv); |
| 1685 } | 1897 } |
| 1686 #endif | 1898 #endif |
| OLD | NEW |