Chromium Code Reviews| Index: src/runtime.cc |
| diff --git a/src/runtime.cc b/src/runtime.cc |
| index 0f49613aa2998018e73af015513551c72221df7c..da7b09d90e82226f09832bccc2b7dbc4fa9a6c70 100644 |
| --- a/src/runtime.cc |
| +++ b/src/runtime.cc |
| @@ -891,6 +891,121 @@ TYPED_ARRAY_GETTER(Length, length) |
| #undef TYPED_ARRAY_GETTER |
| +RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetSpecialCases) { |
|
rossberg
2013/05/07 13:53:23
Nit: I'd change the name, since it's the normal ca
Dmitry Lomov (no reviews)
2013/05/07 14:20:00
Done.
|
| + HandleScope scope(isolate); |
| + CONVERT_ARG_HANDLE_CHECKED(Object, target_obj, 0); |
| + CONVERT_ARG_HANDLE_CHECKED(Object, source_obj, 1); |
| + CONVERT_ARG_HANDLE_CHECKED(Object, offset_obj, 2); |
| + if (!target_obj->IsJSTypedArray() || !source_obj->IsJSTypedArray()) |
| + return isolate->heap()->false_value(); |
| + |
| + Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj)); |
| + Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj)); |
| + size_t offset = NumberToSize(isolate, *offset_obj); |
| + size_t target_length = NumberToSize(isolate, target->length()); |
| + size_t source_length = NumberToSize(isolate, source->length()); |
| + size_t target_byte_length = NumberToSize(isolate, target->byte_length()); |
| + size_t source_byte_length = NumberToSize(isolate, source->byte_length()); |
| + if (offset > target_length || |
| + offset + source_length > target_length || |
| + offset + source_length < offset) // overflow |
| + return isolate->Throw(*isolate->factory()->NewRangeError( |
| + "typed_array_set_source_too_long", HandleVector<Object>(NULL, 0))); |
| + |
| + Handle<JSArrayBuffer> target_buffer(JSArrayBuffer::cast(target->buffer())); |
| + Handle<JSArrayBuffer> source_buffer(JSArrayBuffer::cast(source->buffer())); |
| + size_t target_offset = NumberToSize(isolate, target->byte_offset()); |
| + size_t source_offset = NumberToSize(isolate, source->byte_offset()); |
| + uint8_t* target_base = |
| + static_cast<uint8_t*>(target_buffer->backing_store()) + target_offset; |
| + uint8_t* source_base = |
| + static_cast<uint8_t*>(source_buffer->backing_store()) + source_offset; |
| + |
| + // Typed arrays of the same type: use memmove. |
| + if (target->type() == source->type()) { |
| + memmove(target_base + offset * target->element_size(), |
| + source_base, source_byte_length); |
| + return isolate->heap()->true_value(); |
| + } |
| + |
| + // Typed arrays of different types over the same backing store |
| + if ((source_base <= target_base && |
| + source_base + source_byte_length > target_base) || |
|
rossberg
2013/05/07 13:53:23
Style nit: spurious space
Dmitry Lomov (no reviews)
2013/05/07 14:20:00
Done.
|
| + (target_base <= source_base && |
| + target_base + target_byte_length > source_base)) { |
| + size_t target_element_size = target->element_size(); |
| + size_t source_element_size = source->element_size(); |
| + |
| + size_t source_length = NumberToSize(isolate, source->length()); |
| + |
| + // Copy left part |
| + size_t left_index; |
| + { |
| + // First un-mutated byte after the next write |
| + uint8_t* target_ptr = target_base + (offset + 1) * target_element_size; |
| + // Next read at source_ptr. We do not care for memory changing before |
| + // source_ptr - we have already copied it. |
| + uint8_t* source_ptr = source_base; |
| + for (left_index = 0; |
| + left_index < source_length && target_ptr <= source_ptr; |
| + left_index++) { |
| + Handle<Object> v = Object::GetElement( |
| + source, static_cast<uint32_t>(left_index)); |
| + JSObject::SetElement( |
| + target, static_cast<uint32_t>(offset + left_index), v, |
| + NONE, kNonStrictMode); |
| + target_ptr += target_element_size; |
| + source_ptr += source_element_size; |
| + } |
| + } |
| + // Copy right part |
| + size_t right_index; |
| + { |
| + // First unmutated byte before the next write |
| + uint8_t* target_ptr = |
| + target_base + (offset + source_length - 1) * target_element_size; |
| + // Next read before source_ptr. We do not care for memory changing after |
| + // source_ptr - we have already copied it. |
| + uint8_t* source_ptr = |
| + source_base + source_length * source_element_size; |
| + for (right_index = source_length - 1; |
| + right_index >= left_index && target_ptr >= source_ptr; |
| + right_index--) { |
| + Handle<Object> v = Object::GetElement( |
| + source, static_cast<uint32_t>(right_index)); |
| + JSObject::SetElement( |
| + target, static_cast<uint32_t>(offset + right_index), v, |
| + NONE, kNonStrictMode); |
| + target_ptr -= target_element_size; |
| + source_ptr -= source_element_size; |
| + } |
| + } |
| + ASSERT((right_index + 1) - left_index <= 8); |
|
rossberg
2013/05/07 13:53:23
I'd keep a comment similar to the one I had in d8
Dmitry Lomov (no reviews)
2013/05/07 14:20:00
Done.
|
| + Handle<Object> temp[8]; |
| + size_t idx; |
| + for (idx = left_index; idx <= right_index; idx++) { |
| + temp[idx - left_index] = Object::GetElement( |
| + source, static_cast<uint32_t>(idx)); |
| + } |
| + for (idx = left_index; idx <= right_index; idx++) { |
| + JSObject::SetElement( |
| + target, static_cast<uint32_t>(offset + idx), temp[idx-left_index], |
| + NONE, kNonStrictMode); |
| + } |
| + } else { // Non-overlapping typed arrays |
|
rossberg
2013/05/07 13:53:23
Perhaps negate the conditional to put the common a
Dmitry Lomov (no reviews)
2013/05/07 14:20:00
Can I please not? :))
On 2013/05/07 13:53:23, ross
|
| + for (size_t idx = 0; idx < source_length; idx++) { |
| + Handle<Object> value = Object::GetElement( |
| + source, static_cast<uint32_t>(idx)); |
| + JSObject::SetElement( |
| + target, static_cast<uint32_t>(offset + idx), value, |
| + NONE, kNonStrictMode); |
| + } |
| + } |
| + |
| + return isolate->heap()->true_value(); |
| +} |
| + |
| + |
| RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) { |
| HandleScope scope(isolate); |
| ASSERT(args.length() == 1); |