Home | History | Annotate | Download | only in builtins
      1 // Copyright 2016 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/builtins/builtins-utils.h"
      6 #include "src/builtins/builtins.h"
      7 #include "src/conversions.h"
      8 #include "src/counters.h"
      9 #include "src/factory.h"
     10 #include "src/isolate.h"
     11 #include "src/objects-inl.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 
     16 // -----------------------------------------------------------------------------
     17 // ES6 section 24.2 DataView Objects
     18 
     19 // ES6 section 24.2.2 The DataView Constructor for the [[Call]] case.
     20 BUILTIN(DataViewConstructor) {
     21   HandleScope scope(isolate);
     22   THROW_NEW_ERROR_RETURN_FAILURE(
     23       isolate,
     24       NewTypeError(MessageTemplate::kConstructorNotFunction,
     25                    isolate->factory()->NewStringFromAsciiChecked("DataView")));
     26 }
     27 
     28 // ES6 section 24.2.2 The DataView Constructor for the [[Construct]] case.
     29 BUILTIN(DataViewConstructor_ConstructStub) {
     30   HandleScope scope(isolate);
     31   Handle<JSFunction> target = args.target();
     32   Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
     33   Handle<Object> buffer = args.atOrUndefined(isolate, 1);
     34   Handle<Object> byte_offset = args.atOrUndefined(isolate, 2);
     35   Handle<Object> byte_length = args.atOrUndefined(isolate, 3);
     36 
     37   // 2. If Type(buffer) is not Object, throw a TypeError exception.
     38   // 3. If buffer does not have an [[ArrayBufferData]] internal slot, throw a
     39   //    TypeError exception.
     40   if (!buffer->IsJSArrayBuffer()) {
     41     THROW_NEW_ERROR_RETURN_FAILURE(
     42         isolate, NewTypeError(MessageTemplate::kDataViewNotArrayBuffer));
     43   }
     44   Handle<JSArrayBuffer> array_buffer = Handle<JSArrayBuffer>::cast(buffer);
     45 
     46   // 4. Let offset be ToIndex(byteOffset).
     47   Handle<Object> offset;
     48   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     49       isolate, offset,
     50       Object::ToIndex(isolate, byte_offset, MessageTemplate::kInvalidOffset));
     51 
     52   // 5. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
     53   // We currently violate the specification at this point.
     54 
     55   // 6. Let bufferByteLength be the value of buffer's [[ArrayBufferByteLength]]
     56   // internal slot.
     57   double const buffer_byte_length = array_buffer->byte_length()->Number();
     58 
     59   // 7. If offset > bufferByteLength, throw a RangeError exception
     60   if (offset->Number() > buffer_byte_length) {
     61     THROW_NEW_ERROR_RETURN_FAILURE(
     62         isolate, NewRangeError(MessageTemplate::kInvalidOffset, offset));
     63   }
     64 
     65   Handle<Object> view_byte_length;
     66   if (byte_length->IsUndefined(isolate)) {
     67     // 8. If byteLength is undefined, then
     68     //       a. Let viewByteLength be bufferByteLength - offset.
     69     view_byte_length =
     70         isolate->factory()->NewNumber(buffer_byte_length - offset->Number());
     71   } else {
     72     // 9. Else,
     73     //       a. Let viewByteLength be ? ToIndex(byteLength).
     74     //       b. If offset+viewByteLength > bufferByteLength, throw a RangeError
     75     //          exception
     76     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
     77         isolate, view_byte_length,
     78         Object::ToIndex(isolate, byte_length,
     79                         MessageTemplate::kInvalidDataViewLength));
     80     if (offset->Number() + view_byte_length->Number() > buffer_byte_length) {
     81       THROW_NEW_ERROR_RETURN_FAILURE(
     82           isolate, NewRangeError(MessageTemplate::kInvalidDataViewLength));
     83     }
     84   }
     85 
     86   // 10. Let O be ? OrdinaryCreateFromConstructor(NewTarget,
     87   //     "%DataViewPrototype%", [[DataView]], [[ViewedArrayBuffer]],
     88   //     [[ByteLength]], [[ByteOffset]]).
     89   // 11. Set O's [[DataView]] internal slot to true.
     90   Handle<JSObject> result;
     91   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
     92                                      JSObject::New(target, new_target));
     93   for (int i = 0; i < ArrayBufferView::kInternalFieldCount; ++i) {
     94     Handle<JSDataView>::cast(result)->SetInternalField(i, Smi::kZero);
     95   }
     96 
     97   // 12. Set O's [[ViewedArrayBuffer]] internal slot to buffer.
     98   Handle<JSDataView>::cast(result)->set_buffer(*array_buffer);
     99 
    100   // 13. Set O's [[ByteLength]] internal slot to viewByteLength.
    101   Handle<JSDataView>::cast(result)->set_byte_length(*view_byte_length);
    102 
    103   // 14. Set O's [[ByteOffset]] internal slot to offset.
    104   Handle<JSDataView>::cast(result)->set_byte_offset(*offset);
    105 
    106   // 15. Return O.
    107   return *result;
    108 }
    109 
    110 // ES6 section 24.2.4.1 get DataView.prototype.buffer
    111 BUILTIN(DataViewPrototypeGetBuffer) {
    112   HandleScope scope(isolate);
    113   CHECK_RECEIVER(JSDataView, data_view, "get DataView.prototype.buffer");
    114   return data_view->buffer();
    115 }
    116 
    117 // ES6 section 24.2.4.2 get DataView.prototype.byteLength
    118 BUILTIN(DataViewPrototypeGetByteLength) {
    119   HandleScope scope(isolate);
    120   CHECK_RECEIVER(JSDataView, data_view, "get DataView.prototype.byteLength");
    121   // TODO(bmeurer): According to the ES6 spec, we should throw a TypeError
    122   // here if the JSArrayBuffer of the {data_view} was neutered.
    123   return data_view->byte_length();
    124 }
    125 
    126 // ES6 section 24.2.4.3 get DataView.prototype.byteOffset
    127 BUILTIN(DataViewPrototypeGetByteOffset) {
    128   HandleScope scope(isolate);
    129   CHECK_RECEIVER(JSDataView, data_view, "get DataView.prototype.byteOffset");
    130   // TODO(bmeurer): According to the ES6 spec, we should throw a TypeError
    131   // here if the JSArrayBuffer of the {data_view} was neutered.
    132   return data_view->byte_offset();
    133 }
    134 
    135 namespace {
    136 
    137 bool NeedToFlipBytes(bool is_little_endian) {
    138 #ifdef V8_TARGET_LITTLE_ENDIAN
    139   return !is_little_endian;
    140 #else
    141   return is_little_endian;
    142 #endif
    143 }
    144 
    145 template <size_t n>
    146 void CopyBytes(uint8_t* target, uint8_t const* source) {
    147   for (size_t i = 0; i < n; i++) {
    148     *(target++) = *(source++);
    149   }
    150 }
    151 
    152 template <size_t n>
    153 void FlipBytes(uint8_t* target, uint8_t const* source) {
    154   source = source + (n - 1);
    155   for (size_t i = 0; i < n; i++) {
    156     *(target++) = *(source--);
    157   }
    158 }
    159 
    160 // ES6 section 24.2.1.1 GetViewValue (view, requestIndex, isLittleEndian, type)
    161 template <typename T>
    162 MaybeHandle<Object> GetViewValue(Isolate* isolate, Handle<JSDataView> data_view,
    163                                  Handle<Object> request_index,
    164                                  bool is_little_endian) {
    165   ASSIGN_RETURN_ON_EXCEPTION(
    166       isolate, request_index,
    167       Object::ToIndex(isolate, request_index,
    168                       MessageTemplate::kInvalidDataViewAccessorOffset),
    169       Object);
    170   size_t get_index = 0;
    171   if (!TryNumberToSize(*request_index, &get_index)) {
    172     THROW_NEW_ERROR(
    173         isolate, NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset),
    174         Object);
    175   }
    176   Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()),
    177                                isolate);
    178   size_t const data_view_byte_offset = NumberToSize(data_view->byte_offset());
    179   size_t const data_view_byte_length = NumberToSize(data_view->byte_length());
    180   if (get_index + sizeof(T) > data_view_byte_length ||
    181       get_index + sizeof(T) < get_index) {  // overflow
    182     THROW_NEW_ERROR(
    183         isolate, NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset),
    184         Object);
    185   }
    186   union {
    187     T data;
    188     uint8_t bytes[sizeof(T)];
    189   } v;
    190   size_t const buffer_offset = data_view_byte_offset + get_index;
    191   DCHECK_GE(NumberToSize(buffer->byte_length()), buffer_offset + sizeof(T));
    192   uint8_t const* const source =
    193       static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
    194   if (NeedToFlipBytes(is_little_endian)) {
    195     FlipBytes<sizeof(T)>(v.bytes, source);
    196   } else {
    197     CopyBytes<sizeof(T)>(v.bytes, source);
    198   }
    199   return isolate->factory()->NewNumber(v.data);
    200 }
    201 
    202 template <typename T>
    203 T DataViewConvertValue(double value);
    204 
    205 template <>
    206 int8_t DataViewConvertValue<int8_t>(double value) {
    207   return static_cast<int8_t>(DoubleToInt32(value));
    208 }
    209 
    210 template <>
    211 int16_t DataViewConvertValue<int16_t>(double value) {
    212   return static_cast<int16_t>(DoubleToInt32(value));
    213 }
    214 
    215 template <>
    216 int32_t DataViewConvertValue<int32_t>(double value) {
    217   return DoubleToInt32(value);
    218 }
    219 
    220 template <>
    221 uint8_t DataViewConvertValue<uint8_t>(double value) {
    222   return static_cast<uint8_t>(DoubleToUint32(value));
    223 }
    224 
    225 template <>
    226 uint16_t DataViewConvertValue<uint16_t>(double value) {
    227   return static_cast<uint16_t>(DoubleToUint32(value));
    228 }
    229 
    230 template <>
    231 uint32_t DataViewConvertValue<uint32_t>(double value) {
    232   return DoubleToUint32(value);
    233 }
    234 
    235 template <>
    236 float DataViewConvertValue<float>(double value) {
    237   return static_cast<float>(value);
    238 }
    239 
    240 template <>
    241 double DataViewConvertValue<double>(double value) {
    242   return value;
    243 }
    244 
    245 // ES6 section 24.2.1.2 SetViewValue (view, requestIndex, isLittleEndian, type,
    246 //                                    value)
    247 template <typename T>
    248 MaybeHandle<Object> SetViewValue(Isolate* isolate, Handle<JSDataView> data_view,
    249                                  Handle<Object> request_index,
    250                                  bool is_little_endian, Handle<Object> value) {
    251   ASSIGN_RETURN_ON_EXCEPTION(
    252       isolate, request_index,
    253       Object::ToIndex(isolate, request_index,
    254                       MessageTemplate::kInvalidDataViewAccessorOffset),
    255       Object);
    256   ASSIGN_RETURN_ON_EXCEPTION(isolate, value, Object::ToNumber(value), Object);
    257   size_t get_index = 0;
    258   if (!TryNumberToSize(*request_index, &get_index)) {
    259     THROW_NEW_ERROR(
    260         isolate, NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset),
    261         Object);
    262   }
    263   Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()),
    264                                isolate);
    265   size_t const data_view_byte_offset = NumberToSize(data_view->byte_offset());
    266   size_t const data_view_byte_length = NumberToSize(data_view->byte_length());
    267   if (get_index + sizeof(T) > data_view_byte_length ||
    268       get_index + sizeof(T) < get_index) {  // overflow
    269     THROW_NEW_ERROR(
    270         isolate, NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset),
    271         Object);
    272   }
    273   union {
    274     T data;
    275     uint8_t bytes[sizeof(T)];
    276   } v;
    277   v.data = DataViewConvertValue<T>(value->Number());
    278   size_t const buffer_offset = data_view_byte_offset + get_index;
    279   DCHECK(NumberToSize(buffer->byte_length()) >= buffer_offset + sizeof(T));
    280   uint8_t* const target =
    281       static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
    282   if (NeedToFlipBytes(is_little_endian)) {
    283     FlipBytes<sizeof(T)>(target, v.bytes);
    284   } else {
    285     CopyBytes<sizeof(T)>(target, v.bytes);
    286   }
    287   return isolate->factory()->undefined_value();
    288 }
    289 
    290 }  // namespace
    291 
    292 #define DATA_VIEW_PROTOTYPE_GET(Type, type)                                \
    293   BUILTIN(DataViewPrototypeGet##Type) {                                    \
    294     HandleScope scope(isolate);                                            \
    295     CHECK_RECEIVER(JSDataView, data_view, "DataView.prototype.get" #Type); \
    296     Handle<Object> byte_offset = args.atOrUndefined(isolate, 1);           \
    297     Handle<Object> is_little_endian = args.atOrUndefined(isolate, 2);      \
    298     Handle<Object> result;                                                 \
    299     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(                                    \
    300         isolate, result,                                                   \
    301         GetViewValue<type>(isolate, data_view, byte_offset,                \
    302                            is_little_endian->BooleanValue()));             \
    303     return *result;                                                        \
    304   }
    305 DATA_VIEW_PROTOTYPE_GET(Int8, int8_t)
    306 DATA_VIEW_PROTOTYPE_GET(Uint8, uint8_t)
    307 DATA_VIEW_PROTOTYPE_GET(Int16, int16_t)
    308 DATA_VIEW_PROTOTYPE_GET(Uint16, uint16_t)
    309 DATA_VIEW_PROTOTYPE_GET(Int32, int32_t)
    310 DATA_VIEW_PROTOTYPE_GET(Uint32, uint32_t)
    311 DATA_VIEW_PROTOTYPE_GET(Float32, float)
    312 DATA_VIEW_PROTOTYPE_GET(Float64, double)
    313 #undef DATA_VIEW_PROTOTYPE_GET
    314 
    315 #define DATA_VIEW_PROTOTYPE_SET(Type, type)                                \
    316   BUILTIN(DataViewPrototypeSet##Type) {                                    \
    317     HandleScope scope(isolate);                                            \
    318     CHECK_RECEIVER(JSDataView, data_view, "DataView.prototype.set" #Type); \
    319     Handle<Object> byte_offset = args.atOrUndefined(isolate, 1);           \
    320     Handle<Object> value = args.atOrUndefined(isolate, 2);                 \
    321     Handle<Object> is_little_endian = args.atOrUndefined(isolate, 3);      \
    322     Handle<Object> result;                                                 \
    323     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(                                    \
    324         isolate, result,                                                   \
    325         SetViewValue<type>(isolate, data_view, byte_offset,                \
    326                            is_little_endian->BooleanValue(), value));      \
    327     return *result;                                                        \
    328   }
    329 DATA_VIEW_PROTOTYPE_SET(Int8, int8_t)
    330 DATA_VIEW_PROTOTYPE_SET(Uint8, uint8_t)
    331 DATA_VIEW_PROTOTYPE_SET(Int16, int16_t)
    332 DATA_VIEW_PROTOTYPE_SET(Uint16, uint16_t)
    333 DATA_VIEW_PROTOTYPE_SET(Int32, int32_t)
    334 DATA_VIEW_PROTOTYPE_SET(Uint32, uint32_t)
    335 DATA_VIEW_PROTOTYPE_SET(Float32, float)
    336 DATA_VIEW_PROTOTYPE_SET(Float64, double)
    337 #undef DATA_VIEW_PROTOTYPE_SET
    338 
    339 }  // namespace internal
    340 }  // namespace v8
    341