Home | History | Annotate | Download | only in runtime
      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/runtime/runtime-utils.h"
      6 
      7 #include "src/arguments.h"
      8 #include "src/factory.h"
      9 #include "src/messages.h"
     10 #include "src/objects-inl.h"
     11 #include "src/runtime/runtime.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 
     16 RUNTIME_FUNCTION(Runtime_ArrayBufferGetByteLength) {
     17   SealHandleScope shs(isolate);
     18   DCHECK(args.length() == 1);
     19   CONVERT_ARG_CHECKED(JSArrayBuffer, holder, 0);
     20   return holder->byte_length();
     21 }
     22 
     23 
     24 RUNTIME_FUNCTION(Runtime_ArrayBufferSliceImpl) {
     25   HandleScope scope(isolate);
     26   DCHECK(args.length() == 4);
     27   CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, source, 0);
     28   CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, target, 1);
     29   CONVERT_NUMBER_ARG_HANDLE_CHECKED(first, 2);
     30   CONVERT_NUMBER_ARG_HANDLE_CHECKED(new_length, 3);
     31 
     32   if (source->was_neutered() || target->was_neutered()) {
     33     THROW_NEW_ERROR_RETURN_FAILURE(
     34         isolate, NewTypeError(MessageTemplate::kDetachedOperation,
     35                               isolate->factory()->NewStringFromAsciiChecked(
     36                                   "ArrayBuffer.prototype.slice")));
     37   }
     38 
     39   CHECK(!source.is_identical_to(target));
     40   size_t start = 0, target_length = 0;
     41   CHECK(TryNumberToSize(isolate, *first, &start));
     42   CHECK(TryNumberToSize(isolate, *new_length, &target_length));
     43   CHECK(NumberToSize(isolate, target->byte_length()) >= target_length);
     44 
     45   if (target_length == 0) return isolate->heap()->undefined_value();
     46 
     47   size_t source_byte_length = NumberToSize(isolate, source->byte_length());
     48   CHECK(start <= source_byte_length);
     49   CHECK(source_byte_length - start >= target_length);
     50   uint8_t* source_data = reinterpret_cast<uint8_t*>(source->backing_store());
     51   uint8_t* target_data = reinterpret_cast<uint8_t*>(target->backing_store());
     52   CopyBytes(target_data, source_data + start, target_length);
     53   return isolate->heap()->undefined_value();
     54 }
     55 
     56 
     57 RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) {
     58   HandleScope scope(isolate);
     59   DCHECK(args.length() == 1);
     60   CONVERT_ARG_HANDLE_CHECKED(JSArrayBuffer, array_buffer, 0);
     61   if (array_buffer->backing_store() == NULL) {
     62     CHECK(Smi::FromInt(0) == array_buffer->byte_length());
     63     return isolate->heap()->undefined_value();
     64   }
     65   // Shared array buffers should never be neutered.
     66   CHECK(!array_buffer->is_shared());
     67   DCHECK(!array_buffer->is_external());
     68   void* backing_store = array_buffer->backing_store();
     69   size_t byte_length = NumberToSize(isolate, array_buffer->byte_length());
     70   array_buffer->set_is_external(true);
     71   isolate->heap()->UnregisterArrayBuffer(*array_buffer);
     72   array_buffer->Neuter();
     73   isolate->array_buffer_allocator()->Free(backing_store, byte_length);
     74   return isolate->heap()->undefined_value();
     75 }
     76 
     77 
     78 void Runtime::ArrayIdToTypeAndSize(int arrayId, ExternalArrayType* array_type,
     79                                    ElementsKind* fixed_elements_kind,
     80                                    size_t* element_size) {
     81   switch (arrayId) {
     82 #define ARRAY_ID_CASE(Type, type, TYPE, ctype, size)      \
     83   case ARRAY_ID_##TYPE:                                   \
     84     *array_type = kExternal##Type##Array;                 \
     85     *fixed_elements_kind = TYPE##_ELEMENTS;               \
     86     *element_size = size;                                 \
     87     break;
     88 
     89     TYPED_ARRAYS(ARRAY_ID_CASE)
     90 #undef ARRAY_ID_CASE
     91 
     92     default:
     93       UNREACHABLE();
     94   }
     95 }
     96 
     97 
     98 RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) {
     99   HandleScope scope(isolate);
    100   DCHECK(args.length() == 6);
    101   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
    102   CONVERT_SMI_ARG_CHECKED(arrayId, 1);
    103   CONVERT_ARG_HANDLE_CHECKED(Object, maybe_buffer, 2);
    104   CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_offset_object, 3);
    105   CONVERT_NUMBER_ARG_HANDLE_CHECKED(byte_length_object, 4);
    106   CONVERT_BOOLEAN_ARG_CHECKED(initialize, 5);
    107 
    108   CHECK(arrayId >= Runtime::ARRAY_ID_FIRST &&
    109         arrayId <= Runtime::ARRAY_ID_LAST);
    110 
    111   ExternalArrayType array_type = kExternalInt8Array;  // Bogus initialization.
    112   size_t element_size = 1;                            // Bogus initialization.
    113   ElementsKind fixed_elements_kind = INT8_ELEMENTS;  // Bogus initialization.
    114   Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &fixed_elements_kind,
    115                                 &element_size);
    116   CHECK(holder->map()->elements_kind() == fixed_elements_kind);
    117 
    118   size_t byte_offset = 0;
    119   size_t byte_length = 0;
    120   CHECK(TryNumberToSize(isolate, *byte_offset_object, &byte_offset));
    121   CHECK(TryNumberToSize(isolate, *byte_length_object, &byte_length));
    122 
    123   if (maybe_buffer->IsJSArrayBuffer()) {
    124     Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
    125     size_t array_buffer_byte_length =
    126         NumberToSize(isolate, buffer->byte_length());
    127     CHECK(byte_offset <= array_buffer_byte_length);
    128     CHECK(array_buffer_byte_length - byte_offset >= byte_length);
    129   } else {
    130     CHECK(maybe_buffer->IsNull(isolate));
    131   }
    132 
    133   CHECK(byte_length % element_size == 0);
    134   size_t length = byte_length / element_size;
    135 
    136   if (length > static_cast<unsigned>(Smi::kMaxValue)) {
    137     THROW_NEW_ERROR_RETURN_FAILURE(
    138         isolate, NewRangeError(MessageTemplate::kInvalidTypedArrayLength));
    139   }
    140 
    141   // All checks are done, now we can modify objects.
    142 
    143   DCHECK_EQ(v8::ArrayBufferView::kInternalFieldCount,
    144             holder->GetInternalFieldCount());
    145   for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
    146     holder->SetInternalField(i, Smi::FromInt(0));
    147   }
    148   Handle<Object> length_obj = isolate->factory()->NewNumberFromSize(length);
    149   holder->set_length(*length_obj);
    150   holder->set_byte_offset(*byte_offset_object);
    151   holder->set_byte_length(*byte_length_object);
    152 
    153   if (!maybe_buffer->IsNull(isolate)) {
    154     Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(maybe_buffer);
    155     holder->set_buffer(*buffer);
    156 
    157     Handle<FixedTypedArrayBase> elements =
    158         isolate->factory()->NewFixedTypedArrayWithExternalPointer(
    159             static_cast<int>(length), array_type,
    160             static_cast<uint8_t*>(buffer->backing_store()) + byte_offset);
    161     holder->set_elements(*elements);
    162   } else {
    163     Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
    164     JSArrayBuffer::Setup(buffer, isolate, true, NULL, byte_length,
    165                          SharedFlag::kNotShared);
    166     holder->set_buffer(*buffer);
    167     Handle<FixedTypedArrayBase> elements =
    168         isolate->factory()->NewFixedTypedArray(static_cast<int>(length),
    169                                                array_type, initialize);
    170     holder->set_elements(*elements);
    171   }
    172   return isolate->heap()->undefined_value();
    173 }
    174 
    175 
    176 // Initializes a typed array from an array-like object.
    177 // If an array-like object happens to be a typed array of the same type,
    178 // initializes backing store using memove.
    179 //
    180 // Returns true if backing store was initialized or false otherwise.
    181 RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) {
    182   HandleScope scope(isolate);
    183   DCHECK(args.length() == 4);
    184   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
    185   CONVERT_SMI_ARG_CHECKED(arrayId, 1);
    186   CONVERT_ARG_HANDLE_CHECKED(Object, source, 2);
    187   CONVERT_NUMBER_ARG_HANDLE_CHECKED(length_obj, 3);
    188 
    189   CHECK(arrayId >= Runtime::ARRAY_ID_FIRST &&
    190         arrayId <= Runtime::ARRAY_ID_LAST);
    191 
    192   ExternalArrayType array_type = kExternalInt8Array;  // Bogus initialization.
    193   size_t element_size = 1;                            // Bogus initialization.
    194   ElementsKind fixed_elements_kind = INT8_ELEMENTS;  // Bogus initialization.
    195   Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &fixed_elements_kind,
    196                                 &element_size);
    197 
    198   CHECK(holder->map()->elements_kind() == fixed_elements_kind);
    199 
    200   Handle<JSArrayBuffer> buffer = isolate->factory()->NewJSArrayBuffer();
    201   size_t length = 0;
    202   if (source->IsJSTypedArray() &&
    203       JSTypedArray::cast(*source)->type() == array_type) {
    204     length_obj = handle(JSTypedArray::cast(*source)->length(), isolate);
    205     length = JSTypedArray::cast(*source)->length_value();
    206   } else {
    207     CHECK(TryNumberToSize(isolate, *length_obj, &length));
    208   }
    209 
    210   if ((length > static_cast<unsigned>(Smi::kMaxValue)) ||
    211       (length > (kMaxInt / element_size))) {
    212     THROW_NEW_ERROR_RETURN_FAILURE(
    213         isolate, NewRangeError(MessageTemplate::kInvalidTypedArrayLength));
    214   }
    215   size_t byte_length = length * element_size;
    216 
    217   DCHECK_EQ(v8::ArrayBufferView::kInternalFieldCount,
    218             holder->GetInternalFieldCount());
    219   for (int i = 0; i < v8::ArrayBufferView::kInternalFieldCount; i++) {
    220     holder->SetInternalField(i, Smi::FromInt(0));
    221   }
    222 
    223   // NOTE: not initializing backing store.
    224   // We assume that the caller of this function will initialize holder
    225   // with the loop
    226   //      for(i = 0; i < length; i++) { holder[i] = source[i]; }
    227   // We assume that the caller of this function is always a typed array
    228   // constructor.
    229   // If source is a typed array, this loop will always run to completion,
    230   // so we are sure that the backing store will be initialized.
    231   // Otherwise, the indexing operation might throw, so the loop will not
    232   // run to completion and the typed array might remain partly initialized.
    233   // However we further assume that the caller of this function is a typed array
    234   // constructor, and the exception will propagate out of the constructor,
    235   // therefore uninitialized memory will not be accessible by a user program.
    236   //
    237   // TODO(dslomov): revise this once we support subclassing.
    238 
    239   if (!JSArrayBuffer::SetupAllocatingData(buffer, isolate, byte_length,
    240                                           false)) {
    241     THROW_NEW_ERROR_RETURN_FAILURE(
    242         isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength));
    243   }
    244 
    245   holder->set_buffer(*buffer);
    246   holder->set_byte_offset(Smi::FromInt(0));
    247   Handle<Object> byte_length_obj(
    248       isolate->factory()->NewNumberFromSize(byte_length));
    249   holder->set_byte_length(*byte_length_obj);
    250   holder->set_length(*length_obj);
    251 
    252   Handle<FixedTypedArrayBase> elements =
    253       isolate->factory()->NewFixedTypedArrayWithExternalPointer(
    254           static_cast<int>(length), array_type,
    255           static_cast<uint8_t*>(buffer->backing_store()));
    256   holder->set_elements(*elements);
    257 
    258   if (source->IsJSTypedArray()) {
    259     Handle<JSTypedArray> typed_array(JSTypedArray::cast(*source));
    260 
    261     if (typed_array->type() == holder->type()) {
    262       uint8_t* backing_store =
    263           static_cast<uint8_t*>(typed_array->GetBuffer()->backing_store());
    264       size_t source_byte_offset =
    265           NumberToSize(isolate, typed_array->byte_offset());
    266       memcpy(buffer->backing_store(), backing_store + source_byte_offset,
    267              byte_length);
    268       return isolate->heap()->true_value();
    269     }
    270   }
    271 
    272   return isolate->heap()->false_value();
    273 }
    274 
    275 
    276 #define BUFFER_VIEW_GETTER(Type, getter, accessor)   \
    277   RUNTIME_FUNCTION(Runtime_##Type##Get##getter) {    \
    278     HandleScope scope(isolate);                      \
    279     DCHECK_EQ(1, args.length());                     \
    280     CONVERT_ARG_HANDLE_CHECKED(JS##Type, holder, 0); \
    281     return holder->accessor();                       \
    282   }
    283 
    284 BUFFER_VIEW_GETTER(ArrayBufferView, ByteLength, byte_length)
    285 BUFFER_VIEW_GETTER(ArrayBufferView, ByteOffset, byte_offset)
    286 BUFFER_VIEW_GETTER(TypedArray, Length, length)
    287 
    288 #undef BUFFER_VIEW_GETTER
    289 
    290 RUNTIME_FUNCTION(Runtime_TypedArrayGetBuffer) {
    291   HandleScope scope(isolate);
    292   DCHECK_EQ(1, args.length());
    293   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, holder, 0);
    294   return *holder->GetBuffer();
    295 }
    296 
    297 
    298 // Return codes for Runtime_TypedArraySetFastCases.
    299 // Should be synchronized with typedarray.js natives.
    300 enum TypedArraySetResultCodes {
    301   // Set from typed array of the same type.
    302   // This is processed by TypedArraySetFastCases
    303   TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE = 0,
    304   // Set from typed array of the different type, overlapping in memory.
    305   TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING = 1,
    306   // Set from typed array of the different type, non-overlapping.
    307   TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING = 2,
    308   // Set from non-typed array.
    309   TYPED_ARRAY_SET_NON_TYPED_ARRAY = 3
    310 };
    311 
    312 
    313 RUNTIME_FUNCTION(Runtime_TypedArraySetFastCases) {
    314   HandleScope scope(isolate);
    315   DCHECK(args.length() == 3);
    316   if (!args[0]->IsJSTypedArray()) {
    317     THROW_NEW_ERROR_RETURN_FAILURE(
    318         isolate, NewTypeError(MessageTemplate::kNotTypedArray));
    319   }
    320 
    321   if (!args[1]->IsJSTypedArray())
    322     return Smi::FromInt(TYPED_ARRAY_SET_NON_TYPED_ARRAY);
    323 
    324   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, target_obj, 0);
    325   CONVERT_ARG_HANDLE_CHECKED(JSTypedArray, source_obj, 1);
    326   CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset_obj, 2);
    327 
    328   Handle<JSTypedArray> target(JSTypedArray::cast(*target_obj));
    329   Handle<JSTypedArray> source(JSTypedArray::cast(*source_obj));
    330   size_t offset = 0;
    331   CHECK(TryNumberToSize(isolate, *offset_obj, &offset));
    332   size_t target_length = target->length_value();
    333   size_t source_length = source->length_value();
    334   size_t target_byte_length = NumberToSize(isolate, target->byte_length());
    335   size_t source_byte_length = NumberToSize(isolate, source->byte_length());
    336   if (offset > target_length || offset + source_length > target_length ||
    337       offset + source_length < offset) {  // overflow
    338     THROW_NEW_ERROR_RETURN_FAILURE(
    339         isolate, NewRangeError(MessageTemplate::kTypedArraySetSourceTooLarge));
    340   }
    341 
    342   size_t target_offset = NumberToSize(isolate, target->byte_offset());
    343   size_t source_offset = NumberToSize(isolate, source->byte_offset());
    344   uint8_t* target_base =
    345       static_cast<uint8_t*>(target->GetBuffer()->backing_store()) +
    346       target_offset;
    347   uint8_t* source_base =
    348       static_cast<uint8_t*>(source->GetBuffer()->backing_store()) +
    349       source_offset;
    350 
    351   // Typed arrays of the same type: use memmove.
    352   if (target->type() == source->type()) {
    353     memmove(target_base + offset * target->element_size(), source_base,
    354             source_byte_length);
    355     return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE);
    356   }
    357 
    358   // Typed arrays of different types over the same backing store
    359   if ((source_base <= target_base &&
    360        source_base + source_byte_length > target_base) ||
    361       (target_base <= source_base &&
    362        target_base + target_byte_length > source_base)) {
    363     // We do not support overlapping ArrayBuffers
    364     DCHECK(target->GetBuffer()->backing_store() ==
    365            source->GetBuffer()->backing_store());
    366     return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING);
    367   } else {  // Non-overlapping typed arrays
    368     return Smi::FromInt(TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING);
    369   }
    370 }
    371 
    372 
    373 RUNTIME_FUNCTION(Runtime_TypedArrayMaxSizeInHeap) {
    374   DCHECK(args.length() == 0);
    375   DCHECK_OBJECT_SIZE(FLAG_typed_array_max_size_in_heap +
    376                      FixedTypedArrayBase::kDataOffset);
    377   return Smi::FromInt(FLAG_typed_array_max_size_in_heap);
    378 }
    379 
    380 
    381 RUNTIME_FUNCTION(Runtime_IsTypedArray) {
    382   HandleScope scope(isolate);
    383   DCHECK(args.length() == 1);
    384   return isolate->heap()->ToBoolean(args[0]->IsJSTypedArray());
    385 }
    386 
    387 
    388 RUNTIME_FUNCTION(Runtime_IsSharedTypedArray) {
    389   HandleScope scope(isolate);
    390   DCHECK(args.length() == 1);
    391   return isolate->heap()->ToBoolean(
    392       args[0]->IsJSTypedArray() &&
    393       JSTypedArray::cast(args[0])->GetBuffer()->is_shared());
    394 }
    395 
    396 
    397 RUNTIME_FUNCTION(Runtime_IsSharedIntegerTypedArray) {
    398   HandleScope scope(isolate);
    399   DCHECK(args.length() == 1);
    400   if (!args[0]->IsJSTypedArray()) {
    401     return isolate->heap()->false_value();
    402   }
    403 
    404   Handle<JSTypedArray> obj(JSTypedArray::cast(args[0]));
    405   return isolate->heap()->ToBoolean(obj->GetBuffer()->is_shared() &&
    406                                     obj->type() != kExternalFloat32Array &&
    407                                     obj->type() != kExternalFloat64Array &&
    408                                     obj->type() != kExternalUint8ClampedArray);
    409 }
    410 
    411 
    412 RUNTIME_FUNCTION(Runtime_IsSharedInteger32TypedArray) {
    413   HandleScope scope(isolate);
    414   DCHECK(args.length() == 1);
    415   if (!args[0]->IsJSTypedArray()) {
    416     return isolate->heap()->false_value();
    417   }
    418 
    419   Handle<JSTypedArray> obj(JSTypedArray::cast(args[0]));
    420   return isolate->heap()->ToBoolean(obj->GetBuffer()->is_shared() &&
    421                                     obj->type() == kExternalInt32Array);
    422 }
    423 
    424 
    425 inline static bool NeedToFlipBytes(bool is_little_endian) {
    426 #ifdef V8_TARGET_LITTLE_ENDIAN
    427   return !is_little_endian;
    428 #else
    429   return is_little_endian;
    430 #endif
    431 }
    432 
    433 
    434 template <int n>
    435 inline void CopyBytes(uint8_t* target, uint8_t* source) {
    436   for (int i = 0; i < n; i++) {
    437     *(target++) = *(source++);
    438   }
    439 }
    440 
    441 
    442 template <int n>
    443 inline void FlipBytes(uint8_t* target, uint8_t* source) {
    444   source = source + (n - 1);
    445   for (int i = 0; i < n; i++) {
    446     *(target++) = *(source--);
    447   }
    448 }
    449 
    450 
    451 template <typename T>
    452 inline static bool DataViewGetValue(Isolate* isolate,
    453                                     Handle<JSDataView> data_view,
    454                                     Handle<Object> byte_offset_obj,
    455                                     bool is_little_endian, T* result) {
    456   size_t byte_offset = 0;
    457   if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
    458     return false;
    459   }
    460   Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
    461 
    462   size_t data_view_byte_offset =
    463       NumberToSize(isolate, data_view->byte_offset());
    464   size_t data_view_byte_length =
    465       NumberToSize(isolate, data_view->byte_length());
    466   if (byte_offset + sizeof(T) > data_view_byte_length ||
    467       byte_offset + sizeof(T) < byte_offset) {  // overflow
    468     return false;
    469   }
    470 
    471   union Value {
    472     T data;
    473     uint8_t bytes[sizeof(T)];
    474   };
    475 
    476   Value value;
    477   size_t buffer_offset = data_view_byte_offset + byte_offset;
    478   DCHECK(NumberToSize(isolate, buffer->byte_length()) >=
    479          buffer_offset + sizeof(T));
    480   uint8_t* source =
    481       static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
    482   if (NeedToFlipBytes(is_little_endian)) {
    483     FlipBytes<sizeof(T)>(value.bytes, source);
    484   } else {
    485     CopyBytes<sizeof(T)>(value.bytes, source);
    486   }
    487   *result = value.data;
    488   return true;
    489 }
    490 
    491 
    492 template <typename T>
    493 static bool DataViewSetValue(Isolate* isolate, Handle<JSDataView> data_view,
    494                              Handle<Object> byte_offset_obj,
    495                              bool is_little_endian, T data) {
    496   size_t byte_offset = 0;
    497   if (!TryNumberToSize(isolate, *byte_offset_obj, &byte_offset)) {
    498     return false;
    499   }
    500   Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()));
    501 
    502   size_t data_view_byte_offset =
    503       NumberToSize(isolate, data_view->byte_offset());
    504   size_t data_view_byte_length =
    505       NumberToSize(isolate, data_view->byte_length());
    506   if (byte_offset + sizeof(T) > data_view_byte_length ||
    507       byte_offset + sizeof(T) < byte_offset) {  // overflow
    508     return false;
    509   }
    510 
    511   union Value {
    512     T data;
    513     uint8_t bytes[sizeof(T)];
    514   };
    515 
    516   Value value;
    517   value.data = data;
    518   size_t buffer_offset = data_view_byte_offset + byte_offset;
    519   DCHECK(NumberToSize(isolate, buffer->byte_length()) >=
    520          buffer_offset + sizeof(T));
    521   uint8_t* target =
    522       static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
    523   if (NeedToFlipBytes(is_little_endian)) {
    524     FlipBytes<sizeof(T)>(target, value.bytes);
    525   } else {
    526     CopyBytes<sizeof(T)>(target, value.bytes);
    527   }
    528   return true;
    529 }
    530 
    531 
    532 #define DATA_VIEW_GETTER(TypeName, Type, Converter)                        \
    533   RUNTIME_FUNCTION(Runtime_DataViewGet##TypeName) {                        \
    534     HandleScope scope(isolate);                                            \
    535     DCHECK(args.length() == 3);                                            \
    536     CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);                     \
    537     CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1);                          \
    538     CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 2);                      \
    539     Type result;                                                           \
    540     if (DataViewGetValue(isolate, holder, offset, is_little_endian,        \
    541                          &result)) {                                       \
    542       return *isolate->factory()->Converter(result);                       \
    543     } else {                                                               \
    544       THROW_NEW_ERROR_RETURN_FAILURE(                                      \
    545           isolate,                                                         \
    546           NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset)); \
    547     }                                                                      \
    548   }
    549 
    550 DATA_VIEW_GETTER(Uint8, uint8_t, NewNumberFromUint)
    551 DATA_VIEW_GETTER(Int8, int8_t, NewNumberFromInt)
    552 DATA_VIEW_GETTER(Uint16, uint16_t, NewNumberFromUint)
    553 DATA_VIEW_GETTER(Int16, int16_t, NewNumberFromInt)
    554 DATA_VIEW_GETTER(Uint32, uint32_t, NewNumberFromUint)
    555 DATA_VIEW_GETTER(Int32, int32_t, NewNumberFromInt)
    556 DATA_VIEW_GETTER(Float32, float, NewNumber)
    557 DATA_VIEW_GETTER(Float64, double, NewNumber)
    558 
    559 #undef DATA_VIEW_GETTER
    560 
    561 
    562 template <typename T>
    563 static T DataViewConvertValue(double value);
    564 
    565 
    566 template <>
    567 int8_t DataViewConvertValue<int8_t>(double value) {
    568   return static_cast<int8_t>(DoubleToInt32(value));
    569 }
    570 
    571 
    572 template <>
    573 int16_t DataViewConvertValue<int16_t>(double value) {
    574   return static_cast<int16_t>(DoubleToInt32(value));
    575 }
    576 
    577 
    578 template <>
    579 int32_t DataViewConvertValue<int32_t>(double value) {
    580   return DoubleToInt32(value);
    581 }
    582 
    583 
    584 template <>
    585 uint8_t DataViewConvertValue<uint8_t>(double value) {
    586   return static_cast<uint8_t>(DoubleToUint32(value));
    587 }
    588 
    589 
    590 template <>
    591 uint16_t DataViewConvertValue<uint16_t>(double value) {
    592   return static_cast<uint16_t>(DoubleToUint32(value));
    593 }
    594 
    595 
    596 template <>
    597 uint32_t DataViewConvertValue<uint32_t>(double value) {
    598   return DoubleToUint32(value);
    599 }
    600 
    601 
    602 template <>
    603 float DataViewConvertValue<float>(double value) {
    604   return static_cast<float>(value);
    605 }
    606 
    607 
    608 template <>
    609 double DataViewConvertValue<double>(double value) {
    610   return value;
    611 }
    612 
    613 
    614 #define DATA_VIEW_SETTER(TypeName, Type)                                   \
    615   RUNTIME_FUNCTION(Runtime_DataViewSet##TypeName) {                        \
    616     HandleScope scope(isolate);                                            \
    617     DCHECK(args.length() == 4);                                            \
    618     CONVERT_ARG_HANDLE_CHECKED(JSDataView, holder, 0);                     \
    619     CONVERT_NUMBER_ARG_HANDLE_CHECKED(offset, 1);                          \
    620     CONVERT_NUMBER_ARG_HANDLE_CHECKED(value, 2);                           \
    621     CONVERT_BOOLEAN_ARG_CHECKED(is_little_endian, 3);                      \
    622     Type v = DataViewConvertValue<Type>(value->Number());                  \
    623     if (DataViewSetValue(isolate, holder, offset, is_little_endian, v)) {  \
    624       return isolate->heap()->undefined_value();                           \
    625     } else {                                                               \
    626       THROW_NEW_ERROR_RETURN_FAILURE(                                      \
    627           isolate,                                                         \
    628           NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset)); \
    629     }                                                                      \
    630   }
    631 
    632 DATA_VIEW_SETTER(Uint8, uint8_t)
    633 DATA_VIEW_SETTER(Int8, int8_t)
    634 DATA_VIEW_SETTER(Uint16, uint16_t)
    635 DATA_VIEW_SETTER(Int16, int16_t)
    636 DATA_VIEW_SETTER(Uint32, uint32_t)
    637 DATA_VIEW_SETTER(Int32, int32_t)
    638 DATA_VIEW_SETTER(Float32, float)
    639 DATA_VIEW_SETTER(Float64, double)
    640 
    641 #undef DATA_VIEW_SETTER
    642 }  // namespace internal
    643 }  // namespace v8
    644