Index: src/runtime.cc |
diff --git a/src/runtime.cc b/src/runtime.cc |
index 0f49613aa2998018e73af015513551c72221df7c..4f178ebfccdf400bf537a3ff565f02cb9734faef 100644 |
--- a/src/runtime.cc |
+++ b/src/runtime.cc |
@@ -891,6 +891,128 @@ TYPED_ARRAY_GETTER(Length, length) |
#undef TYPED_ARRAY_GETTER |
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TypedArraySetFastCases) { |
+ 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()) |
+ return isolate->Throw(*isolate->factory()->NewTypeError( |
+ "not_typed_array", HandleVector<Object>(NULL, 0))); |
+ |
+ if (!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_large", 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) || |
+ (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; |
+ } |
+ } |
+ // There can be at most 8 entries left in the middle that need buffering |
+ // (because the largest element_size is 8 times the smallest). |
+ ASSERT((right_index + 1) - left_index <= 8); |
+ 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 |
+ 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); |