V8 Project
runtime-typedarray.cc
Go to the documentation of this file.
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"
10 
11 
12 namespace v8 {
13 namespace internal {
14 
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));
30  V8::ArrayBufferAllocator()->Free(phantom_array_buffer->backing_store(),
31  allocated_length);
32 }
33 
34 
36  Handle<JSArrayBuffer> array_buffer,
37  bool is_external, void* data,
38  size_t allocated_length) {
39  DCHECK(array_buffer->GetInternalFieldCount() ==
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 
48  Handle<Object> byte_length =
49  isolate->factory()->NewNumberFromSize(allocated_length);
50  CHECK(byte_length->IsSmi() || byte_length->IsHeapNumber());
51  array_buffer->set_byte_length(*byte_length);
52 
53  array_buffer->set_weak_next(isolate->heap()->array_buffers_list());
54  isolate->heap()->set_array_buffers_list(*array_buffer);
55  array_buffer->set_weak_first_view(isolate->heap()->undefined_value());
56 }
57 
58 
60  Handle<JSArrayBuffer> array_buffer,
61  size_t allocated_length,
62  bool initialize) {
63  void* data;
65  if (allocated_length != 0) {
66  if (initialize) {
67  data = V8::ArrayBufferAllocator()->Allocate(allocated_length);
68  } else {
69  data =
71  }
72  if (data == NULL) return false;
73  } else {
74  data = NULL;
75  }
76 
77  SetupArrayBuffer(isolate, array_buffer, false, data, allocated_length);
78 
79  reinterpret_cast<v8::Isolate*>(isolate)
80  ->AdjustAmountOfExternalAllocatedMemory(allocated_length);
81 
82  return true;
83 }
84 
85 
87  Isolate* isolate = array_buffer->GetIsolate();
88  for (Handle<Object> view_obj(array_buffer->weak_first_view(), isolate);
89  !view_obj->IsUndefined();) {
90  Handle<JSArrayBufferView> view(JSArrayBufferView::cast(*view_obj));
91  if (view->IsJSTypedArray()) {
92  JSTypedArray::cast(*view)->Neuter();
93  } else if (view->IsJSDataView()) {
94  JSDataView::cast(*view)->Neuter();
95  } else {
96  UNREACHABLE();
97  }
98  view_obj = handle(view->weak_next(), isolate);
99  }
100  array_buffer->Neuter();
101 }
102 
103 
104 RUNTIME_FUNCTION(Runtime_ArrayBufferInitialize) {
105  HandleScope scope(isolate);
106  DCHECK(args.length() == 2);
108  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byteLength, 1);
109  if (!holder->byte_length()->IsUndefined()) {
110  // ArrayBuffer is already initialized; probably a fuzz test.
111  return *holder;
112  }
113  size_t allocated_length = 0;
114  if (!TryNumberToSize(isolate, *byteLength, &allocated_length)) {
116  isolate, NewRangeError("invalid_array_buffer_length",
117  HandleVector<Object>(NULL, 0)));
118  }
119  if (!Runtime::SetupArrayBufferAllocatingData(isolate, holder,
120  allocated_length)) {
122  isolate, NewRangeError("invalid_array_buffer_length",
123  HandleVector<Object>(NULL, 0)));
124  }
125  return *holder;
126 }
127 
128 
129 RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) {
130  SealHandleScope shs(isolate);
131  DCHECK(args.length() == 1);
133  return holder->byte_length();
134 }
135 
136 
137 RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) {
138  HandleScope scope(isolate);
139  DCHECK(args.length() == 3);
143  RUNTIME_ASSERT(!source.is_identical_to(target));
144  size_t start = 0;
145  RUNTIME_ASSERT(TryNumberToSize(isolate, *first, &start));
146  size_t target_length = NumberToSize(isolate, target->byte_length());
147 
148  if (target_length == 0) return isolate->heap()->undefined_value();
149 
150  size_t source_byte_length = NumberToSize(isolate, source->byte_length());
151  RUNTIME_ASSERT(start <= source_byte_length);
152  RUNTIME_ASSERT(source_byte_length - start >= target_length);
153  uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
154  uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
155  CopyBytes(target_data, source_data + start, target_length);
156  return isolate->heap()->undefined_value();
157 }
158 
159 
160 RUNTIME_FUNCTION(Runtime_ArrayBufferIsView) {
161  HandleScope scope(isolate);
162  DCHECK(args.length() == 1);
163  CONVERT_ARG_CHECKED(Object, object, 0);
164  return isolate->heap()->ToBoolean(object->IsJSArrayBufferView());
165 }
166 
167 
168 RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
169  HandleScope scope(isolate);
170  DCHECK(args.length() == 1);
171  CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0);
172  if (array_buffer->backing_store() == NULL) {
173  CHECK(Smi::FromInt(0) == array_buffer->byte_length());
174  return isolate->heap()->undefined_value();
175  }
176  DCHECK(!array_buffer->is_external());
177  void* backing_store = array_buffer->backing_store();
178  size_t byte_length = NumberToSize(isolate, array_buffer->byte_length());
179  array_buffer->set_is_external(true);
180  Runtime::NeuterArrayBuffer(array_buffer);
181  V8::ArrayBufferAllocator()->Free(backing_store, byte_length);
182  return isolate->heap()->undefined_value();
183 }
184 
185 
186 void Runtime::ArrayIdToTypeAndSize(int arrayId, ExternalArrayType* array_type,
187  ElementsKind* external_elements_kind,
188  ElementsKind* fixed_elements_kind,
189  size_t* element_size) {
190  switch (arrayId) {
191 #define ARRAY_ID_CASE(Type, type, TYPE, ctype, size) \
192  case ARRAY_ID_##TYPE: \
193  *array_type = kExternal##Type##Array; \
194  *external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS; \
195  *fixed_elements_kind = TYPE##_ELEMENTS; \
196  *element_size = size; \
197  break;
198 
200 #undef ARRAY_ID_CASE
201 
202  default:
203  UNREACHABLE();
204  }
205 }
206 
207 
208 RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) {
209  HandleScope scope(isolate);
210  DCHECK(args.length() == 5);
212  CONVERT_SMI_ARG_CHECKED(arrayId, 1);
213  CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2);
214  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3);
215  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4);
216 
218  arrayId <= Runtime::ARRAY_ID_LAST);
219 
220  ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
221  size_t element_size = 1; // Bogus initialization.
222  ElementsKind external_elements_kind =
223  EXTERNAL_INT8_ELEMENTS; // Bogus initialization.
224  ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization.
225  Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind,
226  &fixed_elements_kind, &element_size);
227  RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
228 
229  size_t byte_offset = 0;
230  size_t byte_length = 0;
231  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset_object, &byte_offset));
232  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length_object, &byte_length));
233 
234  if (maybe_buffer->IsJSArrayBuffer()) {
235  Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
236  size_t array_buffer_byte_length =
237  NumberToSize(isolate, buffer->byte_length());
238  RUNTIME_ASSERT(byte_offset <= array_buffer_byte_length);
239  RUNTIME_ASSERT(array_buffer_byte_length - byte_offset >= byte_length);
240  } else {
241  RUNTIME_ASSERT(maybe_buffer->IsNull());
242  }
243 
244  RUNTIME_ASSERT(byte_length % element_size == 0);
245  size_t length = byte_length / element_size;
246 
247  if (length > static_cast<unsigned>(Smi::kMaxValue)) {
249  isolate, NewRangeError("invalid_typed_array_length",
250  HandleVector<Object>(NULL, 0)));
251  }
252 
253  // All checks are done, now we can modify objects.
254 
255  DCHECK(holder->GetInternalFieldCount() ==
257  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
258  holder->SetInternalField(i, Smi::FromInt(0));
259  }
260  Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
261  holder->set_length(*length_obj);
262  holder->set_byte_offset(*byte_offset_object);
263  holder->set_byte_length(*byte_length_object);
264 
265  if (!maybe_buffer->IsNull()) {
266  Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
267  holder->set_buffer(*buffer);
268  holder->set_weak_next(buffer->weak_first_view());
269  buffer->set_weak_first_view(*holder);
270 
271  Handle<ExternalArray> elements = isolate->factory()->NewExternalArray(
272  static_cast<int>(length), array_type,
273  static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
274  Handle<Map> map =
275  JSObject::GetElementsTransitionMap(holder, external_elements_kind);
276  JSObject::SetMapAndElements(holder, map, elements);
277  DCHECK(IsExternalArrayElementsKind(holder->map()->elements_kind()));
278  } else {
279  holder->set_buffer(Smi::FromInt(0));
280  holder->set_weak_next(isolate->heap()->undefined_value());
281  Handle<FixedTypedArrayBase> elements =
282  isolate->factory()->NewFixedTypedArray(static_cast<int>(length),
283  array_type);
284  holder->set_elements(*elements);
285  }
286  return isolate->heap()->undefined_value();
287 }
288 
289 
290 // Initializes a typed array from an array-like object.
291 // If an array-like object happens to be a typed array of the same type,
292 // initializes backing store using memove.
293 //
294 // Returns true if backing store was initialized or false otherwise.
295 RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
296  HandleScope scope(isolate);
297  DCHECK(args.length() == 4);
299  CONVERT_SMI_ARG_CHECKED(arrayId, 1);
301  CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3);
302 
304  arrayId <= Runtime::ARRAY_ID_LAST);
305 
306  ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization.
307  size_t element_size = 1; // Bogus initialization.
308  ElementsKind external_elements_kind =
309  EXTERNAL_INT8_ELEMENTS; // Bogus intialization.
310  ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization.
311  Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind,
312  &fixed_elements_kind, &element_size);
313 
314  RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind);
315 
316  Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
317  if (source->IsJSTypedArray() &&
318  JSTypedArray::cast(*source)->type() == array_type) {
319  length_obj = Handle<Object>(JSTypedArray::cast(*source)->length(), isolate);
320  }
321  size_t length = 0;
322  RUNTIME_ASSERT(TryNumberToSize(isolate, *length_obj, &length));
323 
324  if ((length > static_cast<unsigned>(Smi::kMaxValue)) ||
325  (length > (kMaxInt / element_size))) {
327  isolate, NewRangeError("invalid_typed_array_length",
328  HandleVector<Object>(NULL, 0)));
329  }
330  size_t byte_length = length * element_size;
331 
332  DCHECK(holder->GetInternalFieldCount() ==
334  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
335  holder->SetInternalField(i, Smi::FromInt(0));
336  }
337 
338  // NOTE: not initializing backing store.
339  // We assume that the caller of this function will initialize holder
340  // with the loop
341  // for(i = 0; i < length; i++) { holder[i] = source[i]; }
342  // We assume that the caller of this function is always a typed array
343  // constructor.
344  // If source is a typed array, this loop will always run to completion,
345  // so we are sure that the backing store will be initialized.
346  // Otherwise, the indexing operation might throw, so the loop will not
347  // run to completion and the typed array might remain partly initialized.
348  // However we further assume that the caller of this function is a typed array
349  // constructor, and the exception will propagate out of the constructor,
350  // therefore uninitialized memory will not be accessible by a user program.
351  //
352  // TODO(dslomov): revise this once we support subclassing.
353 
354  if (!Runtime::SetupArrayBufferAllocatingData(isolate, buffer, byte_length,
355  false)) {
357  isolate, NewRangeError("invalid_array_buffer_length",
358  HandleVector<Object>(NULL, 0)));
359  }
360 
361  holder->set_buffer(*buffer);
362  holder->set_byte_offset(Smi::FromInt(0));
363  Handle<Object> byte_length_obj(
364  isolate->factory()->NewNumberFromSize(byte_length));
365  holder->set_byte_length(*byte_length_obj);
366  holder->set_length(*length_obj);
367  holder->set_weak_next(buffer->weak_first_view());
368  buffer->set_weak_first_view(*holder);
369 
370  Handle<ExternalArray> elements = isolate->factory()->NewExternalArray(
371  static_cast<int>(length), array_type,
372  static_cast<uint8_t*>(buffer->backing_store()));
373  Handle<Map> map =
374  JSObject::GetElementsTransitionMap(holder, external_elements_kind);
375  JSObject::SetMapAndElements(holder, map, elements);
376 
377  if (source->IsJSTypedArray()) {
378  Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
379 
380  if (typed_array->type() == holder->type()) {
381  uint8_t* backing_store =
382  static_cast<uint8_t*>(typed_array->GetBuffer()->backing_store());
383  size_t source_byte_offset =
384  NumberToSize(isolate, typed_array->byte_offset());
385  memcpy(buffer->backing_store(), backing_store + source_byte_offset,
386  byte_length);
387  return isolate->heap()->true_value();
388  }
389  }
390 
391  return isolate->heap()->false_value();
392 }
393 
394 
395 #define BUFFER_VIEW_GETTER(Type, getter, accessor) \
396  RUNTIME_FUNCTION(Runtime_##Type##Get##getter) { \
397  HandleScope scope(isolate); \
398  DCHECK(args.length() == 1); \
399  CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0); \
400  return holder->accessor(); \
401  }
402 
403 BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length)
404 BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset)
405 BUFFER_VIEW_GETTER(TypedArray, Length, length)
406 BUFFER_VIEW_GETTER(DataView, Buffer, buffer)
407 
408 #undef BUFFER_VIEW_GETTER
409 
410 RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
411  HandleScope scope(isolate);
412  DCHECK(args.length() == 1);
414  return *holder->GetBuffer();
415 }
416 
417 
418 // Return codes for Runtime_TypedArraySetFastCases.
419 // Should be synchronized with typedarray.js natives.
421  // Set from typed array of the same type.
422  // This is processed by TypedArraySetFastCases
424  // Set from typed array of the different type, overlapping in memory.
426  // Set from typed array of the different type, non-overlapping.
428  // Set from non-typed array.
430 };
431 
432 
433 RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) {
434  HandleScope scope(isolate);
435  DCHECK(args.length() == 3);
436  if (!args[0]->IsJSTypedArray()) {
438  isolate,
439  NewTypeError("not_typed_array", HandleVector<Object>(NULL, 0)));
440  }
441 
442  if (!args[1]->IsJSTypedArray())
444 
447  CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2);
448 
449  Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
450  Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
451  size_t offset = 0;
452  RUNTIME_ASSERT(TryNumberToSize(isolate, *offset_obj, &offset));
453  size_t target_length = NumberToSize(isolate, target->length());
454  size_t source_length = NumberToSize(isolate, source->length());
455  size_t target_byte_length = NumberToSize(isolate, target->byte_length());
456  size_t source_byte_length = NumberToSize(isolate, source->byte_length());
457  if (offset > target_length || offset + source_length > target_length ||
458  offset + source_length < offset) { // overflow
460  isolate, NewRangeError("typed_array_set_source_too_large",
461  HandleVector<Object>(NULL, 0)));
462  }
463 
464  size_t target_offset = NumberToSize(isolate, target->byte_offset());
465  size_t source_offset = NumberToSize(isolate, source->byte_offset());
466  uint8_t* target_base =
467  static_cast<uint8_t*>(target->GetBuffer()->backing_store()) +
468  target_offset;
469  uint8_t* source_base =
470  static_cast<uint8_t*>(source->GetBuffer()->backing_store()) +
471  source_offset;
472 
473  // Typed arrays of the same type: use memmove.
474  if (target->type() == source->type()) {
475  memmove(target_base + offset * target->element_size(), source_base,
476  source_byte_length);
478  }
479 
480  // Typed arrays of different types over the same backing store
481  if ((source_base <= target_base &&
482  source_base + source_byte_length > target_base) ||
483  (target_base <= source_base &&
484  target_base + target_byte_length > source_base)) {
485  // We do not support overlapping ArrayBuffers
486  DCHECK(target->GetBuffer()->backing_store() ==
487  source->GetBuffer()->backing_store());
489  } else { // Non-overlapping typed arrays
491  }
492 }
493 
494 
495 RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) {
496  DCHECK(args.length() == 0);
497  DCHECK_OBJECT_SIZE(FLAG_typed_array_max_size_in_heap +
499  return Smi::FromInt(FLAG_typed_array_max_size_in_heap);
500 }
501 
502 
503 RUNTIME_FUNCTION(Runtime_DataViewInitialize) {
504  HandleScope scope(isolate);
505  DCHECK(args.length() == 4);
508  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset, 2);
509  CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length, 3);
510 
511  DCHECK(holder->GetInternalFieldCount() ==
513  for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
514  holder->SetInternalField(i, Smi::FromInt(0));
515  }
516  size_t buffer_length = 0;
517  size_t offset = 0;
518  size_t length = 0;
520  TryNumberToSize(isolate, buffer->byte_length(), &buffer_length));
521  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_offset, &offset));
522  RUNTIME_ASSERT(TryNumberToSize(isolate, *byte_length, &length));
523 
524  // TODO(jkummerow): When we have a "safe numerics" helper class, use it here.
525  // Entire range [offset, offset + length] must be in bounds.
526  RUNTIME_ASSERT(offset <= buffer_length);
527  RUNTIME_ASSERT(offset + length <= buffer_length);
528  // No overflow.
529  RUNTIME_ASSERT(offset + length >= offset);
530 
531  holder->set_buffer(*buffer);
532  holder->set_byte_offset(*byte_offset);
533  holder->set_byte_length(*byte_length);
534 
535  holder->set_weak_next(buffer->weak_first_view());
536  buffer->set_weak_first_view(*holder);
537 
538  return isolate->heap()->undefined_value();
539 }
540 
541 
542 inline static bool NeedToFlipBytes(bool is_little_endian) {
543 #ifdef V8_TARGET_LITTLE_ENDIAN
544  return !is_little_endian;
545 #else
546  return is_little_endian;
547 #endif
548 }
549 
550 
551 template <int n>
552 inline void CopyBytes(uint8_t* target, uint8_t* source) {
553  for (int i = 0; i < n; i++) {
554  *(target++) = *(source++);
555  }
556 }
557 
558 
559 template <int n>
560 inline void FlipBytes(uint8_t* target, uint8_t* source) {
561  source = source + (n - 1);
562  for (int i = 0; i < n; i++) {
563  *(target++) = *(source--);
564  }
565 }
566 
567 
568 template <typename T>
569 inline static bool DataViewGetValue(Isolate* isolate,
570  Handle<JSDataView> data_view,
571  Handle<Object> byte_offset_obj,
572  bool is_little_endian, T* result) {
573  size_t byte_offset = 0;
574  if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
575  return false;
576  }
577  Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
578 
579  size_t data_view_byte_offset =
580  NumberToSize(isolate, data_view->byte_offset());
581  size_t data_view_byte_length =
582  NumberToSize(isolate, data_view->byte_length());
583  if (byte_offset + sizeof(T) > data_view_byte_length ||
584  byte_offset + sizeof(T) < byte_offset) { // overflow
585  return false;
586  }
587 
588  union Value {
589  T data;
590  uint8_t bytes[sizeof(T)];
591  };
592 
593  Value value;
594  size_t buffer_offset = data_view_byte_offset + byte_offset;
595  DCHECK(NumberToSize(isolate, buffer->byte_length()) >=
596  buffer_offset + sizeof(T));
597  uint8_t* source =
598  static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
599  if (NeedToFlipBytes(is_little_endian)) {
600  FlipBytes<sizeof(T)>(value.bytes, source);
601  } else {
602  CopyBytes<sizeof(T)>(value.bytes, source);
603  }
604  *result = value.data;
605  return true;
606 }
607 
608 
609 template <typename T>
610 static bool DataViewSetValue(Isolate* isolate, Handle<JSDataView> data_view,
611  Handle<Object> byte_offset_obj,
612  bool is_little_endian, T data) {
613  size_t byte_offset = 0;
614  if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
615  return false;
616  }
617  Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
618 
619  size_t data_view_byte_offset =
620  NumberToSize(isolate, data_view->byte_offset());
621  size_t data_view_byte_length =
622  NumberToSize(isolate, data_view->byte_length());
623  if (byte_offset + sizeof(T) > data_view_byte_length ||
624  byte_offset + sizeof(T) < byte_offset) { // overflow
625  return false;
626  }
627 
628  union Value {
629  T data;
630  uint8_t bytes[sizeof(T)];
631  };
632 
633  Value value;
634  value.data = data;
635  size_t buffer_offset = data_view_byte_offset + byte_offset;
636  DCHECK(NumberToSize(isolate, buffer->byte_length()) >=
637  buffer_offset + sizeof(T));
638  uint8_t* target =
639  static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
640  if (NeedToFlipBytes(is_little_endian)) {
641  FlipBytes<sizeof(T)>(target, value.bytes);
642  } else {
643  CopyBytes<sizeof(T)>(target, value.bytes);
644  }
645  return true;
646 }
647 
648 
649 #define DATA_VIEW_GETTER(TypeName, Type, Converter) \
650  RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) { \
651  HandleScope scope(isolate); \
652  DCHECK(args.length() == 3); \
653  CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
654  CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \
655  CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2); \
656  Type result; \
657  if (DataViewGetValue(isolate, holder, offset, is_little_endian, \
658  &result)) { \
659  return *isolate->factory()->Converter(result); \
660  } else { \
661  THROW_NEW_ERROR_RETURN_FAILURE( \
662  isolate, NewRangeError("invalid_data_view_accessor_offset", \
663  HandleVector<Object>(NULL, 0))); \
664  } \
665  }
666 
667 DATA_VIEW_GETTER(Uint8, uint8_t, NewNumberFromUint)
668 DATA_VIEW_GETTER(Int8, int8_t, NewNumberFromInt)
669 DATA_VIEW_GETTER(Uint16, uint16_t, NewNumberFromUint)
670 DATA_VIEW_GETTER(Int16, int16_t, NewNumberFromInt)
671 DATA_VIEW_GETTER(Uint32, uint32_t, NewNumberFromUint)
672 DATA_VIEW_GETTER(Int32, int32_t, NewNumberFromInt)
673 DATA_VIEW_GETTER(Float32, float, NewNumber)
674 DATA_VIEW_GETTER(Float64, double, NewNumber)
675 
676 #undef DATA_VIEW_GETTER
677 
678 
679 template <typename T>
680 static T DataViewConvertValue(double value);
681 
682 
683 template <>
684 int8_t DataViewConvertValue<int8_t>(double value) {
685  return static_cast<int8_t>(DoubleToInt32(value));
686 }
687 
688 
689 template <>
691  return static_cast<int16_t>(DoubleToInt32(value));
692 }
693 
694 
695 template <>
697  return DoubleToInt32(value);
698 }
699 
700 
701 template <>
702 uint8_t DataViewConvertValue<uint8_t>(double value) {
703  return static_cast<uint8_t>(DoubleToUint32(value));
704 }
705 
706 
707 template <>
709  return static_cast<uint16_t>(DoubleToUint32(value));
710 }
711 
712 
713 template <>
715  return DoubleToUint32(value);
716 }
717 
718 
719 template <>
720 float DataViewConvertValue<float>(double value) {
721  return static_cast<float>(value);
722 }
723 
724 
725 template <>
726 double DataViewConvertValue<double>(double value) {
727  return value;
728 }
729 
730 
731 #define DATA_VIEW_SETTER(TypeName, Type) \
732  RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) { \
733  HandleScope scope(isolate); \
734  DCHECK(args.length() == 4); \
735  CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0); \
736  CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1); \
737  CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2); \
738  CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3); \
739  Type v = DataViewConvertValue<Type>(value->Number()); \
740  if (DataViewSetValue(isolate, holder, offset, is_little_endian, v)) { \
741  return isolate->heap()->undefined_value(); \
742  } else { \
743  THROW_NEW_ERROR_RETURN_FAILURE( \
744  isolate, NewRangeError("invalid_data_view_accessor_offset", \
745  HandleVector<Object>(NULL, 0))); \
746  } \
747  }
748 
749 DATA_VIEW_SETTER(Uint8, uint8_t)
750 DATA_VIEW_SETTER(Int8, int8_t)
751 DATA_VIEW_SETTER(Uint16, uint16_t)
753 DATA_VIEW_SETTER(Uint32, uint32_t)
755 DATA_VIEW_SETTER(Float32, float)
756 DATA_VIEW_SETTER(Float64, double)
757 
758 #undef DATA_VIEW_SETTER
759 }
760 } // namespace v8::internal
static const int kInternalFieldCount
Definition: v8.h:2992
virtual void * Allocate(size_t length)=0
Allocate |length| bytes.
virtual void Free(void *data, size_t length)=0
Free the memory block of size |length|, pointed to by |data|.
virtual void * AllocateUninitialized(size_t length)=0
Allocate |length| bytes.
static const int kInternalFieldCount
Definition: v8.h:2955
Isolate represents an isolated instance of the V8 engine.
Definition: v8.h:4356
The superclass of all JavaScript values and objects.
Definition: v8.h:1440
static const int kDataOffset
Definition: objects.h:4716
static Handle< T > cast(Handle< S > that)
Definition: handles.h:116
void set_array_buffers_list(Object *object)
Definition: heap.h:795
Object * array_buffers_list() const
Definition: heap.h:796
Factory * factory()
Definition: isolate.h:982
static void SetMapAndElements(Handle< JSObject > object, Handle< Map > map, Handle< FixedArrayBase > elements)
Definition: objects-inl.h:1814
static Handle< Map > GetElementsTransitionMap(Handle< JSObject > object, ElementsKind to_kind)
Definition: objects.cc:3385
static void NeuterArrayBuffer(Handle< JSArrayBuffer > array_buffer)
static void SetupArrayBuffer(Isolate *isolate, Handle< JSArrayBuffer > array_buffer, bool is_external, void *data, size_t allocated_length)
static void ArrayIdToTypeAndSize(int array_id, ExternalArrayType *type, ElementsKind *external_elements_kind, ElementsKind *fixed_elements_kind, size_t *element_size)
static void FreeArrayBuffer(Isolate *isolate, JSArrayBuffer *phantom_array_buffer)
static bool SetupArrayBufferAllocatingData(Isolate *isolate, Handle< JSArrayBuffer > array_buffer, size_t allocated_length, bool initialize=true)
static const int kMaxValue
Definition: objects.h:1272
static Smi * FromInt(int value)
Definition: objects-inl.h:1321
static v8::ArrayBuffer::Allocator * ArrayBufferAllocator()
Definition: v8.h:72
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf map
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define THROW_NEW_ERROR_RETURN_FAILURE(isolate, call)
Definition: isolate.h:146
#define UNREACHABLE()
Definition: logging.h:30
#define CHECK(condition)
Definition: logging.h:36
#define DCHECK(condition)
Definition: logging.h:205
unsigned short uint16_t
Definition: unicode.cc:23
signed short int16_t
Definition: unicode.cc:22
int int32_t
Definition: unicode.cc:24
static T DataViewConvertValue(double value)
static bool NeedToFlipBytes(bool is_little_endian)
uint32_t DoubleToUint32(double x)
Definition: conversions.h:93
bool IsExternalArrayElementsKind(ElementsKind kind)
Definition: elements-kind.h:95
int16_t DataViewConvertValue< int16_t >(double value)
const int kMaxInt
Definition: globals.h:109
@ TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE
@ TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING
@ TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING
@ EXTERNAL_INT8_ELEMENTS
Definition: elements-kind.h:33
Handle< T > handle(T *t, Isolate *isolate)
Definition: handles.h:146
void FlipBytes(uint8_t *target, uint8_t *source)
static bool DataViewGetValue(Isolate *isolate, Handle< JSDataView > data_view, Handle< Object > byte_offset_obj, bool is_little_endian, T *result)
static bool DataViewSetValue(Isolate *isolate, Handle< JSDataView > data_view, Handle< Object > byte_offset_obj, bool is_little_endian, T data)
uint8_t DataViewConvertValue< uint8_t >(double value)
int32_t DoubleToInt32(double x)
float DataViewConvertValue< float >(double value)
double DataViewConvertValue< double >(double value)
int8_t DataViewConvertValue< int8_t >(double value)
size_t NumberToSize(Isolate *isolate, Object *number)
Definition: conversions.h:233
uint32_t DataViewConvertValue< uint32_t >(double value)
bool TryNumberToSize(Isolate *isolate, Object *number, size_t *result)
Definition: conversions.h:207
uint16_t DataViewConvertValue< uint16_t >(double value)
int32_t DataViewConvertValue< int32_t >(double value)
void CopyBytes(uint8_t *target, uint8_t *source)
@ RUNTIME_FUNCTION
Definition: serialize.h:23
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
ExternalArrayType
Definition: v8.h:2217
@ kExternalInt8Array
Definition: v8.h:2218
#define TYPED_ARRAYS(V)
Definition: objects.h:4433
#define ARRAY_ID_CASE(Type, type, TYPE, ctype, size)
#define DATA_VIEW_GETTER(TypeName, Type, Converter)
#define DATA_VIEW_SETTER(TypeName, Type)
#define BUFFER_VIEW_GETTER(Type, getter, accessor)
#define CONVERT_ARG_CHECKED(Type, name, index)
Definition: runtime-utils.h:24
#define RUNTIME_ASSERT(value)
Definition: runtime-utils.h:12
#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index)
Definition: runtime-utils.h:28
#define CONVERT_NUMBER_ARG_HANDLE_CHECKED(name, index)
Definition: runtime-utils.h:32
#define CONVERT_SMI_ARG_CHECKED(name, index)
Definition: runtime-utils.h:46
#define DCHECK_OBJECT_SIZE(size)
Definition: spaces.h:84
#define T(name, string, precedence)
Definition: token.cc:25