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