deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / src / runtime / runtime-typedarray.cc
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #include "src/arguments.h"
8 #include "src/runtime/runtime.h"
9 #include "src/runtime/runtime-utils.h"
10
11
12 namespace v8 {
13 namespace internal {
14
15 void Runtime::FreeArrayBuffer(Isolate* isolate,
16                               JSArrayBuffer* phantom_array_buffer) {
17   if (phantom_array_buffer->should_be_freed()) {
18     DCHECK(phantom_array_buffer->is_external());
19     free(phantom_array_buffer->backing_store());
20   }
21   if (phantom_array_buffer->is_external()) return;
22
23   size_t allocated_length =
24       NumberToSize(isolate, phantom_array_buffer->byte_length());
25
26   reinterpret_cast<v8::Isolate*>(isolate)
27       ->AdjustAmountOfExternalAllocatedMemory(
28           -static_cast<int64_t>(allocated_length));
29   CHECK(V8::ArrayBufferAllocator() != NULL);
30   V8::ArrayBufferAllocator()->Free(phantom_array_buffer->backing_store(),
31                                    allocated_length);
32 }
33
34
35 void Runtime::SetupArrayBuffer(Isolate* isolate,
36                                Handle<JSArrayBuffer> array_buffer,
37                                bool is_external, void* data,
38                                size_t allocated_length) {
39   DCHECK(array_buffer->GetInternalFieldCount() ==
40          v8::ArrayBuffer::kInternalFieldCount);
41   for (int i = 0; i < v8::ArrayBuffer::kInternalFieldCount; i++) {
42     array_buffer->SetInternalField(i, Smi::FromInt(0));
43   }
44   array_buffer->set_backing_store(data);
45   array_buffer->set_flag(Smi::FromInt(0));
46   array_buffer->set_is_external(is_external);
47   array_buffer->set_is_neuterable(true);
48
49   Handle<Object> byte_length =
50       isolate->factory()->NewNumberFromSize(allocated_length);
51   CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
52   array_buffer->set_byte_length(*byte_length);
53
54   array_buffer->set_weak_next(isolate->heap()->array_buffers_list());
55   isolate->heap()->set_array_buffers_list(*array_buffer);
56   array_buffer->set_weak_first_view(isolate->heap()->undefined_value());
57 }
58
59
60 bool Runtime::SetupArrayBufferAllocatingData(Isolate* isolate,
61                                              Handle<JSArrayBuffer> array_buffer,
62                                              size_t allocated_length,
63                                              bool initialize) {
64   void* data;
65   CHECK(V8::ArrayBufferAllocator() != NULL);
66   // Prevent creating array buffers when serializing.
67   DCHECK(!isolate->serializer_enabled());
68   if (allocated_length != 0) {
69     if (initialize) {
70       data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
71     } else {
72       data =
73           V8::ArrayBufferAllocator()->AllocateUninitialized(allocated_length);
74     }
75     if (data == NULL) return false;
76   } else {
77     data = NULL;
78   }
79
80   SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length);
81
82   reinterpret_cast<v8::Isolate*>(isolate)
83       ->AdjustAmountOfExternalAllocatedMemory(allocated_length);
84
85   return true;
86 }
87
88
89 void Runtime::NeuterArrayBuffer(Handle<JSArrayBuffer> array_buffer) {
90   Isolate* isolate = array_buffer->GetIsolate();
91   // Firstly, iterate over the views which are referenced directly by the array
92   // buffer.
93   for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate);
94        !view_obj->IsUndefined();) {
95     Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj));
96     if (view->IsJSTypedArray()) {
97       JSTypedArray::cast(*view)->Neuter();
98     } else if (view->IsJSDataView()) {
99       JSDataView::cast(*view)->Neuter();
100     } else {
101       UNREACHABLE();
102     }
103     view_obj = handle(view->weak_next(), isolate);
104   }
105
106   // Secondly, iterate over the global list of new space views to find views
107   // that belong to the neutered array buffer.
108   Heap* heap = isolate->heap();
109   for (Handle<Object> view_obj(heap->new_array_buffer_views_list(), isolate);
110        !view_obj->IsUndefined();) {
111     Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj));
112     if (view->buffer() == *array_buffer) {
113       if (view->IsJSTypedArray()) {
114         JSTypedArray::cast(*view)->Neuter();
115       } else if (view->IsJSDataView()) {
116         JSDataView::cast(*view)->Neuter();
117       } else {
118         UNREACHABLE();
119       }
120     }
121     view_obj = handle(view->weak_next(), isolate);
122   }
123   array_buffer->Neuter();
124 }
125
126
127 RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) {
128   HandleScope scope(isolate);
129   DCHECK(args.length() == 2);
130   CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, holder, 0);
131   CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1);
132   if (!holder->byte_length()->IsUndefined()) {
133     // ArrayBuffer is already initialized; probably a fuzz test.
134     return *holder;
135   }
136   size_t allocated_length = 0;
137   if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) {
138     THROW_NEW_ERROR_RETURN_FAILURE(
139         isolate, NewRangeError("invalid_array_buffer_length",
140                                HandleVector<Object>(NULL, 0)));
141   }
142   if (!Runtime::SetupArrayBufferAllocatingData(isolate, holder,
143                                                allocated_length)) {
144     THROW_NEW_ERROR_RETURN_FAILURE(
145         isolate, NewRangeError("invalid_array_buffer_length",
146                                HandleVector<Object>(NULL, 0)));
147   }
148   return *holder;
149 }
150
151
152 RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) {
153   SealHandleScope shs(isolate);
154   DCHECK(args.length() == 1);
155   CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
156   return holder->byte_length();
157 }
158
159
160 RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) {
161   HandleScope scope(isolate);
162   DCHECK(args.length() == 3);
163   CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
164   CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
165   CONVERT_NUMBER_ARG_HANDLE_CHECKED(first, 2);
166   RUNTIME_ASSERT(!source.is_identical_to(target));
167   size_t start = 0;
168   RUNTIME_ASSERT(TryNumberToSize(isolate, *first, &start));
169   size_t target_length = NumberToSize(isolate, target->byte_length());
170
171   if (target_length == 0) return isolate->heap()->undefined_value();
172
173   size_t source_byte_length = NumberToSize(isolate, source->byte_length());
174   RUNTIME_ASSERT(start <= source_byte_length);
175   RUNTIME_ASSERT(source_byte_length - start >= target_length);
176   uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
177   uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
178   CopyBytes(target_data, source_data + start, target_length);
179   return isolate->heap()->undefined_value();
180 }
181
182
183 RUNTIME_FUNCTION(Runtime_ArrayBufferIsView) {
184   HandleScope scope(isolate);
185   DCHECK(args.length() == 1);
186   CONVERT_ARG_CHECKED(Object, object, 0);
187   return isolate->heap()->ToBoolean(object->IsJSArrayBufferView());
188 }
189
190
191 RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
192   HandleScope scope(isolate);
193   DCHECK(args.length() == 1);
194   CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0);
195   if (array_buffer->backing_store() == NULL) {
196     CHECK(Smi::FromInt(0) == array_buffer->byte_length());
197     return isolate->heap()->undefined_value();
198   }
199   DCHECK(!array_buffer->is_external());
200   void* backing_store = array_buffer->backing_store();
201   size_t byte_length = NumberToSize(isolate, array_buffer->byte_length());
202   array_buffer->set_is_external(true);
203   Runtime::NeuterArrayBuffer(array_buffer);
204   V8::ArrayBufferAllocator()->Free(backing_store, byte_length);
205   return isolate->heap()->undefined_value();
206 }
207
208
209 void Runtime::ArrayIdToTypeAndSize(int arrayId, ExternalArrayType* array_type,
210                                    ElementsKind* external_elements_kind,
211                                    ElementsKind* fixed_elements_kind,
212                                    size_t* element_size) {
213   switch (arrayId) {
214 #define ARRAY_ID_CASE(Type, type, TYPE, ctype, size)      \
215   case ARRAY_ID_##TYPE:                                   \
216     *array_type = kExternal##Type##Array;                 \
217     *external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS; \
218     *fixed_elements_kind = TYPE##_ELEMENTS;               \
219     *element_size = size;                                 \
220     break;
221
222     TYPED_ARRAYS(ARRAY_ID_CASE)
223 #undef ARRAY_ID_CASE
224
225     default:
226       UNREACHABLE();
227   }
228 }
229
230
231 RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) {
232   HandleScope scope(isolate);
233   DCHECK(args.length() == 5);
234   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
235   CONVERT_SMI_ARG_CHECKED(arrayId, 1);
236   CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2);
237   CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3);
238   CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4);
239
240   RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
241                  arrayId <= Runtime::ARRAY_ID_LAST);
242
243   ExternalArrayType array_type = kExternalInt8Array;  // Bogus initialization.
244   size_t element_size = 1;                            // Bogus initialization.
245   ElementsKind external_elements_kind =
246       EXTERNAL_INT8_ELEMENTS;                        // Bogus initialization.
247   ElementsKind fixed_elements_kind = INT8_ELEMENTS;  // Bogus initialization.
248   Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind,
249                                 &fixed_elements_kind, &element_size);
250   RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
251
252   size_t byte_offset = 0;
253   size_t byte_length = 0;
254   RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset_object, &byte_offset));
255   RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length_object, &byte_length));
256
257   if (maybe_buffer->IsJSArrayBuffer()) {
258     Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
259     size_t array_buffer_byte_length =
260         NumberToSize(isolate, buffer->byte_length());
261     RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length);
262     RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length);
263   } else {
264     RUNTIME_ASSERT(maybe_buffer->IsNull());
265   }
266
267   RUNTIME_ASSERT(byte_length % element_size == 0);
268   size_t length = byte_length / element_size;
269
270   if (length > static_cast<unsigned>(Smi::kMaxValue)) {
271     THROW_NEW_ERROR_RETURN_FAILURE(
272         isolate, NewRangeError("invalid_typed_array_length",
273                                HandleVector<Object>(NULL, 0)));
274   }
275
276   // All checks are done, now we can modify objects.
277
278   DCHECK(holder->GetInternalFieldCount() ==
279          v8::ArrayBufferView::kInternalFieldCount);
280   for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
281     holder->SetInternalField(i, Smi::FromInt(0));
282   }
283   Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
284   holder->set_length(*length_obj);
285   holder->set_byte_offset(*byte_offset_object);
286   holder->set_byte_length(*byte_length_object);
287
288   Heap* heap = isolate->heap();
289   if (!maybe_buffer->IsNull()) {
290     Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
291     holder->set_buffer(*buffer);
292
293     if (heap->InNewSpace(*holder)) {
294       holder->set_weak_next(heap->new_array_buffer_views_list());
295       heap->set_new_array_buffer_views_list(*holder);
296     } else {
297       holder->set_weak_next(buffer->weak_first_view());
298       buffer->set_weak_first_view(*holder);
299     }
300
301     Handle<ExternalArray> elements = isolate->factory()->NewExternalArray(
302         static_cast<int>(length), array_type,
303         static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
304     Handle<Map> map =
305         JSObject::GetElementsTransitionMap(holder, external_elements_kind);
306     JSObject::SetMapAndElements(holder, map, elements);
307     DCHECK(IsExternalArrayElementsKind(holder->map()->elements_kind()));
308   } else {
309     holder->set_buffer(Smi::FromInt(0));
310     holder->set_weak_next(isolate->heap()->undefined_value());
311     Handle<FixedTypedArrayBase> elements =
312         isolate->factory()->NewFixedTypedArray(static_cast<int>(length),
313                                                array_type);
314     holder->set_elements(*elements);
315   }
316   return isolate->heap()->undefined_value();
317 }
318
319
320 // Initializes a typed array from an array-like object.
321 // If an array-like object happens to be a typed array of the same type,
322 // initializes backing store using memove.
323 //
324 // Returns true if backing store was initialized or false otherwise.
325 RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
326   HandleScope scope(isolate);
327   DCHECK(args.length() == 4);
328   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
329   CONVERT_SMI_ARG_CHECKED(arrayId, 1);
330   CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
331   CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3);
332
333   RUNTIME_ASSERT(arrayId >= Runtime::ARRAY_ID_FIRST &&
334                  arrayId <= Runtime::ARRAY_ID_LAST);
335
336   ExternalArrayType array_type = kExternalInt8Array;  // Bogus initialization.
337   size_t element_size = 1;                            // Bogus initialization.
338   ElementsKind external_elements_kind =
339       EXTERNAL_INT8_ELEMENTS;                        // Bogus intialization.
340   ElementsKind fixed_elements_kind = INT8_ELEMENTS;  // Bogus initialization.
341   Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind,
342                                 &fixed_elements_kind, &element_size);
343
344   RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
345
346   Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
347   if (source->IsJSTypedArray() &&
348       JSTypedArray::cast(*source)->type() == array_type) {
349     length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate);
350   }
351   size_t length = 0;
352   RUNTIME_ASSERT(TryNumberToSize(isolate, *length_obj, &length));
353
354   if ((length > static_cast<unsigned>(Smi::kMaxValue)) ||
355       (length > (kMaxInt / element_size))) {
356     THROW_NEW_ERROR_RETURN_FAILURE(
357         isolate, NewRangeError("invalid_typed_array_length",
358                                HandleVector<Object>(NULL, 0)));
359   }
360   size_t byte_length = length * element_size;
361
362   DCHECK(holder->GetInternalFieldCount() ==
363          v8::ArrayBufferView::kInternalFieldCount);
364   for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
365     holder->SetInternalField(i, Smi::FromInt(0));
366   }
367
368   // NOTE: not initializing backing store.
369   // We assume that the caller of this function will initialize holder
370   // with the loop
371   //      for(i = 0; i < length; i++) { holder[i] = source[i]; }
372   // We assume that the caller of this function is always a typed array
373   // constructor.
374   // If source is a typed array, this loop will always run to completion,
375   // so we are sure that the backing store will be initialized.
376   // Otherwise, the indexing operation might throw, so the loop will not
377   // run to completion and the typed array might remain partly initialized.
378   // However we further assume that the caller of this function is a typed array
379   // constructor, and the exception will propagate out of the constructor,
380   // therefore uninitialized memory will not be accessible by a user program.
381   //
382   // TODO(dslomov): revise this once we support subclassing.
383
384   if (!Runtime::SetupArrayBufferAllocatingData(isolate, buffer, byte_length,
385                                                false)) {
386     THROW_NEW_ERROR_RETURN_FAILURE(
387         isolate, NewRangeError("invalid_array_buffer_length",
388                                HandleVector<Object>(NULL, 0)));
389   }
390
391   holder->set_buffer(*buffer);
392   holder->set_byte_offset(Smi::FromInt(0));
393   Handle<Object> byte_length_obj(
394       isolate->factory()->NewNumberFromSize(byte_length));
395   holder->set_byte_length(*byte_length_obj);
396   holder->set_length(*length_obj);
397
398   Heap* heap = isolate->heap();
399   if (heap->InNewSpace(*holder)) {
400     holder->set_weak_next(heap->new_array_buffer_views_list());
401     heap->set_new_array_buffer_views_list(*holder);
402   } else {
403     holder->set_weak_next(buffer->weak_first_view());
404     buffer->set_weak_first_view(*holder);
405   }
406
407   Handle<ExternalArray> elements = isolate->factory()->NewExternalArray(
408       static_cast<int>(length), array_type,
409       static_cast<uint8_t*>(buffer->backing_store()));
410   Handle<Map> map =
411       JSObject::GetElementsTransitionMap(holder, external_elements_kind);
412   JSObject::SetMapAndElements(holder, map, elements);
413
414   if (source->IsJSTypedArray()) {
415     Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
416
417     if (typed_array->type() == holder->type()) {
418       uint8_t* backing_store =
419           static_cast<uint8_t*>(typed_array->GetBuffer()->backing_store());
420       size_t source_byte_offset =
421           NumberToSize(isolate, typed_array->byte_offset());
422       memcpy(buffer->backing_store(), backing_store + source_byte_offset,
423              byte_length);
424       return isolate->heap()->true_value();
425     }
426   }
427
428   return isolate->heap()->false_value();
429 }
430
431
432 #define BUFFER_VIEW_GETTER(Type, getter, accessor)   \
433   RUNTIME_FUNCTION(Runtime_##Type##Get##getter) {    \
434     HandleScope scope(isolate);                      \
435     DCHECK(args.length() == 1);                      \
436     CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0); \
437     return holder->accessor();                       \
438   }
439
440 BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length)
441 BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset)
442 BUFFER_VIEW_GETTER(TypedArray, Length, length)
443 BUFFER_VIEW_GETTER(DataView, Buffer, buffer)
444
445 #undef BUFFER_VIEW_GETTER
446
447 RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
448   HandleScope scope(isolate);
449   DCHECK(args.length() == 1);
450   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
451   return *holder->GetBuffer();
452 }
453
454
455 // Return codes for Runtime_TypedArraySetFastCases.
456 // Should be synchronized with typedarray.js natives.
457 enum TypedArraySetResultCodes {
458   // Set from typed array of the same type.
459   // This is processed by TypedArraySetFastCases
460   TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
461   // Set from typed array of the different type, overlapping in memory.
462   TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
463   // Set from typed array of the different type, non-overlapping.
464   TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
465   // Set from non-typed array.
466   TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
467 };
468
469
470 RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) {
471   HandleScope scope(isolate);
472   DCHECK(args.length() == 3);
473   if (!args[0]->IsJSTypedArray()) {
474     THROW_NEW_ERROR_RETURN_FAILURE(
475         isolate,
476         NewTypeError("not_typed_array", HandleVector<Object>(NULL, 0)));
477   }
478
479   if (!args[1]->IsJSTypedArray())
480     return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
481
482   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0);
483   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1);
484   CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2);
485
486   Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
487   Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
488   size_t offset = 0;
489   RUNTIME_ASSERT(TryNumberToSize(isolate, *offset_obj, &offset));
490   size_t target_length = NumberToSize(isolate, target->length());
491   size_t source_length = NumberToSize(isolate, source->length());
492   size_t target_byte_length = NumberToSize(isolate, target->byte_length());
493   size_t source_byte_length = NumberToSize(isolate, source->byte_length());
494   if (offset > target_length || offset + source_length > target_length ||
495       offset + source_length < offset) {  // overflow
496     THROW_NEW_ERROR_RETURN_FAILURE(
497         isolate, NewRangeError("typed_array_set_source_too_large",
498                                HandleVector<Object>(NULL, 0)));
499   }
500
501   size_t target_offset = NumberToSize(isolate, target->byte_offset());
502   size_t source_offset = NumberToSize(isolate, source->byte_offset());
503   uint8_t* target_base =
504       static_cast<uint8_t*>(target->GetBuffer()->backing_store()) +
505       target_offset;
506   uint8_t* source_base =
507       static_cast<uint8_t*>(source->GetBuffer()->backing_store()) +
508       source_offset;
509
510   // Typed arrays of the same type: use memmove.
511   if (target->type() == source->type()) {
512     memmove(target_base + offset * target->element_size(), source_base,
513             source_byte_length);
514     return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
515   }
516
517   // Typed arrays of different types over the same backing store
518   if ((source_base <= target_base &&
519        source_base + source_byte_length > target_base) ||
520       (target_base <= source_base &&
521        target_base + target_byte_length > source_base)) {
522     // We do not support overlapping ArrayBuffers
523     DCHECK(target->GetBuffer()->backing_store() ==
524            source->GetBuffer()->backing_store());
525     return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
526   } else {  // Non-overlapping typed arrays
527     return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
528   }
529 }
530
531
532 RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) {
533   DCHECK(args.length() == 0);
534   DCHECK_OBJECT_SIZE(FLAG_typed_array_max_size_in_heap +
535                      FixedTypedArrayBase::kDataOffset);
536   return Smi::FromInt(FLAG_typed_array_max_size_in_heap);
537 }
538
539
540 RUNTIME_FUNCTION(Runtime_IsTypedArray) {
541   HandleScope scope(isolate);
542   DCHECK(args.length() == 1);
543   return isolate->heap()->ToBoolean(args[0]->IsJSTypedArray());
544 }
545
546
547 RUNTIME_FUNCTION(Runtime_DataViewInitialize) {
548   HandleScope scope(isolate);
549   DCHECK(args.length() == 4);
550   CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);
551   CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, buffer, 1);
552   CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2);
553   CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3);
554
555   DCHECK(holder->GetInternalFieldCount() ==
556          v8::ArrayBufferView::kInternalFieldCount);
557   for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
558     holder->SetInternalField(i, Smi::FromInt(0));
559   }
560   size_t buffer_length = 0;
561   size_t offset = 0;
562   size_t length = 0;
563   RUNTIME_ASSERT(
564       TryNumberToSize(isolate, buffer->byte_length(), &buffer_length));
565   RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset));
566   RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length));
567
568   // TODO(jkummerow): When we have a "safe numerics" helper class, use it here.
569   // Entire range [offset, offset + length] must be in bounds.
570   RUNTIME_ASSERT(offset <= buffer_length);
571   RUNTIME_ASSERT(offset + length <= buffer_length);
572   // No overflow.
573   RUNTIME_ASSERT(offset + length >= offset);
574
575   holder->set_buffer(*buffer);
576   holder->set_byte_offset(*byte_offset);
577   holder->set_byte_length(*byte_length);
578
579   Heap* heap = isolate->heap();
580   if (heap->InNewSpace(*holder)) {
581     holder->set_weak_next(heap->new_array_buffer_views_list());
582     heap->set_new_array_buffer_views_list(*holder);
583   } else {
584     holder->set_weak_next(buffer->weak_first_view());
585     buffer->set_weak_first_view(*holder);
586   }
587
588   return isolate->heap()->undefined_value();
589 }
590
591
592 inline static bool NeedToFlipBytes(bool is_little_endian) {
593 #ifdef V8_TARGET_LITTLE_ENDIAN
594   return !is_little_endian;
595 #else
596   return is_little_endian;
597 #endif
598 }
599
600
601 template <int n>
602 inline void CopyBytes(uint8_t* target, uint8_t* source) {
603   for (int i = 0; i < n; i++) {
604     *(target++) = *(source++);
605   }
606 }
607
608
609 template <int n>
610 inline void FlipBytes(uint8_t* target, uint8_t* source) {
611   source = source + (n - 1);
612   for (int i = 0; i < n; i++) {
613     *(target++) = *(source--);
614   }
615 }
616
617
618 template <typename T>
619 inline static bool DataViewGetValue(Isolate* isolate,
620                                     Handle<JSDataView> data_view,
621                                     Handle<Object> byte_offset_obj,
622                                     bool is_little_endian, T* result) {
623   size_t byte_offset = 0;
624   if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
625     return false;
626   }
627   Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
628
629   size_t data_view_byte_offset =
630       NumberToSize(isolate, data_view->byte_offset());
631   size_t data_view_byte_length =
632       NumberToSize(isolate, data_view->byte_length());
633   if (byte_offset + sizeof(T) > data_view_byte_length ||
634       byte_offset + sizeof(T) < byte_offset) {  // overflow
635     return false;
636   }
637
638   union Value {
639     T data;
640     uint8_t bytes[sizeof(T)];
641   };
642
643   Value value;
644   size_t buffer_offset = data_view_byte_offset + byte_offset;
645   DCHECK(NumberToSize(isolate, buffer->byte_length()) >=
646          buffer_offset + sizeof(T));
647   uint8_t* source =
648       static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
649   if (NeedToFlipBytes(is_little_endian)) {
650     FlipBytes<sizeof(T)>(value.bytes, source);
651   } else {
652     CopyBytes<sizeof(T)>(value.bytes, source);
653   }
654   *result = value.data;
655   return true;
656 }
657
658
659 template <typename T>
660 static bool DataViewSetValue(Isolate* isolate, Handle<JSDataView> data_view,
661                              Handle<Object> byte_offset_obj,
662                              bool is_little_endian, T data) {
663   size_t byte_offset = 0;
664   if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
665     return false;
666   }
667   Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
668
669   size_t data_view_byte_offset =
670       NumberToSize(isolate, data_view->byte_offset());
671   size_t data_view_byte_length =
672       NumberToSize(isolate, data_view->byte_length());
673   if (byte_offset + sizeof(T) > data_view_byte_length ||
674       byte_offset + sizeof(T) < byte_offset) {  // overflow
675     return false;
676   }
677
678   union Value {
679     T data;
680     uint8_t bytes[sizeof(T)];
681   };
682
683   Value value;
684   value.data = data;
685   size_t buffer_offset = data_view_byte_offset + byte_offset;
686   DCHECK(NumberToSize(isolate, buffer->byte_length()) >=
687          buffer_offset + sizeof(T));
688   uint8_t* target =
689       static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
690   if (NeedToFlipBytes(is_little_endian)) {
691     FlipBytes<sizeof(T)>(target, value.bytes);
692   } else {
693     CopyBytes<sizeof(T)>(target, value.bytes);
694   }
695   return true;
696 }
697
698
699 #define DATA_VIEW_GETTER(TypeName, Type, Converter)                   \
700   RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) {                   \
701     HandleScope scope(isolate);                                       \
702     DCHECK(args.length() == 3);                                       \
703     CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);                \
704     CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1);                     \
705     CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2);                 \
706     Type result;                                                      \
707     if (DataViewGetValue(isolate, holder, offset, is_little_endian,   \
708                          &result)) {                                  \
709       return *isolate->factory()->Converter(result);                  \
710     } else {                                                          \
711       THROW_NEW_ERROR_RETURN_FAILURE(                                 \
712           isolate, NewRangeError("invalid_data_view_accessor_offset", \
713                                  HandleVector<Object>(NULL, 0)));     \
714     }                                                                 \
715   }
716
717 DATA_VIEW_GETTER(Uint8, uint8_t, NewNumberFromUint)
718 DATA_VIEW_GETTER(Int8, int8_t, NewNumberFromInt)
719 DATA_VIEW_GETTER(Uint16, uint16_t, NewNumberFromUint)
720 DATA_VIEW_GETTER(Int16, int16_t, NewNumberFromInt)
721 DATA_VIEW_GETTER(Uint32, uint32_t, NewNumberFromUint)
722 DATA_VIEW_GETTER(Int32, int32_t, NewNumberFromInt)
723 DATA_VIEW_GETTER(Float32, float, NewNumber)
724 DATA_VIEW_GETTER(Float64, double, NewNumber)
725
726 #undef DATA_VIEW_GETTER
727
728
729 template <typename T>
730 static T DataViewConvertValue(double value);
731
732
733 template <>
734 int8_t DataViewConvertValue<int8_t>(double value) {
735   return static_cast<int8_t>(DoubleToInt32(value));
736 }
737
738
739 template <>
740 int16_t DataViewConvertValue<int16_t>(double value) {
741   return static_cast<int16_t>(DoubleToInt32(value));
742 }
743
744
745 template <>
746 int32_t DataViewConvertValue<int32_t>(double value) {
747   return DoubleToInt32(value);
748 }
749
750
751 template <>
752 uint8_t DataViewConvertValue<uint8_t>(double value) {
753   return static_cast<uint8_t>(DoubleToUint32(value));
754 }
755
756
757 template <>
758 uint16_t DataViewConvertValue<uint16_t>(double value) {
759   return static_cast<uint16_t>(DoubleToUint32(value));
760 }
761
762
763 template <>
764 uint32_t DataViewConvertValue<uint32_t>(double value) {
765   return DoubleToUint32(value);
766 }
767
768
769 template <>
770 float DataViewConvertValue<float>(double value) {
771   return static_cast<float>(value);
772 }
773
774
775 template <>
776 double DataViewConvertValue<double>(double value) {
777   return value;
778 }
779
780
781 #define DATA_VIEW_SETTER(TypeName, Type)                                  \
782   RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) {                       \
783     HandleScope scope(isolate);                                           \
784     DCHECK(args.length() == 4);                                           \
785     CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);                    \
786     CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1);                         \
787     CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);                          \
788     CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3);                     \
789     Type v = DataViewConvertValue<Type>(value->Number());                 \
790     if (DataViewSetValue(isolate, holder, offset, is_little_endian, v)) { \
791       return isolate->heap()->undefined_value();                          \
792     } else {                                                              \
793       THROW_NEW_ERROR_RETURN_FAILURE(                                     \
794           isolate, NewRangeError("invalid_data_view_accessor_offset",     \
795                                  HandleVector<Object>(NULL, 0)));         \
796     }                                                                     \
797   }
798
799 DATA_VIEW_SETTER(Uint8, uint8_t)
800 DATA_VIEW_SETTER(Int8, int8_t)
801 DATA_VIEW_SETTER(Uint16, uint16_t)
802 DATA_VIEW_SETTER(Int16, int16_t)
803 DATA_VIEW_SETTER(Uint32, uint32_t)
804 DATA_VIEW_SETTER(Int32, int32_t)
805 DATA_VIEW_SETTER(Float32, float)
806 DATA_VIEW_SETTER(Float64, double)
807
808 #undef DATA_VIEW_SETTER
809 }
810 }  // namespace v8::internal