LCOV - code coverage report
Current view: top level - src/builtins - builtins-dataview.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 81 83 97.6 %
Date: 2017-04-26 Functions: 58 79 73.4 %

          Line data    Source code
       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         129 : BUILTIN(DataViewConstructor) {
      21             :   HandleScope scope(isolate);
      22         172 :   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       17181 : BUILTIN(DataViewConstructor_ConstructStub) {
      30             :   HandleScope scope(isolate);
      31        5727 :   Handle<JSFunction> target = args.target();
      32        5727 :   Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
      33             :   Handle<Object> buffer = args.atOrUndefined(isolate, 1);
      34        5727 :   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        5727 :   if (!buffer->IsJSArrayBuffer()) {
      41         172 :     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       11282 :   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        5613 :   if (offset->Number() > buffer_byte_length) {
      61          56 :     THROW_NEW_ERROR_RETURN_FAILURE(
      62             :         isolate, NewRangeError(MessageTemplate::kInvalidOffset, offset));
      63             :   }
      64             : 
      65             :   Handle<Object> view_byte_length;
      66        5585 :   if (byte_length->IsUndefined(isolate)) {
      67             :     // 8. If byteLength is undefined, then
      68             :     //       a. Let viewByteLength be bufferByteLength - offset.
      69             :     view_byte_length =
      70         816 :         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        9538 :     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
      77             :         isolate, view_byte_length,
      78             :         Object::ToIndex(isolate, byte_length,
      79             :                         MessageTemplate::kInvalidDataViewLength));
      80        4769 :     if (offset->Number() + view_byte_length->Number() > buffer_byte_length) {
      81          86 :       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       11084 :   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
      92             :                                      JSObject::New(target, new_target));
      93       11084 :   for (int i = 0; i < ArrayBufferView::kEmbedderFieldCount; ++i) {
      94             :     Handle<JSDataView>::cast(result)->SetEmbedderField(i, Smi::kZero);
      95             :   }
      96             : 
      97             :   // 12. Set O's [[ViewedArrayBuffer]] internal slot to buffer.
      98        5542 :   Handle<JSDataView>::cast(result)->set_buffer(*array_buffer);
      99             : 
     100             :   // 13. Set O's [[ByteLength]] internal slot to viewByteLength.
     101        5542 :   Handle<JSDataView>::cast(result)->set_byte_length(*view_byte_length);
     102             : 
     103             :   // 14. Set O's [[ByteOffset]] internal slot to offset.
     104        5542 :   Handle<JSDataView>::cast(result)->set_byte_offset(*offset);
     105             : 
     106             :   // 15. Return O.
     107        5542 :   return *result;
     108             : }
     109             : 
     110             : // ES6 section 24.2.4.1 get DataView.prototype.buffer
     111         840 : BUILTIN(DataViewPrototypeGetBuffer) {
     112             :   HandleScope scope(isolate);
     113         448 :   CHECK_RECEIVER(JSDataView, data_view, "get DataView.prototype.buffer");
     114         224 :   return data_view->buffer();
     115             : }
     116             : 
     117             : // ES6 section 24.2.4.2 get DataView.prototype.byteLength
     118       20907 : BUILTIN(DataViewPrototypeGetByteLength) {
     119             :   HandleScope scope(isolate);
     120        7137 :   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        6913 :   return data_view->byte_length();
     124             : }
     125             : 
     126             : // ES6 section 24.2.4.3 get DataView.prototype.byteOffset
     127        1035 : BUILTIN(DataViewPrototypeGetByteOffset) {
     128             :   HandleScope scope(isolate);
     129         513 :   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         289 :   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        1624 :   for (size_t i = 0; i < n; i++) {
     148        1624 :     *(target++) = *(source++);
     149             :   }
     150             : }
     151             : 
     152             : template <size_t n>
     153             : void FlipBytes(uint8_t* target, uint8_t const* source) {
     154         658 :   source = source + (n - 1);
     155        6048 :   for (size_t i = 0; i < n; i++) {
     156        6048 :     *(target++) = *(source--);
     157             :   }
     158             : }
     159             : 
     160             : // ES6 section 24.2.1.1 GetViewValue (view, requestIndex, isLittleEndian, type)
     161             : template <typename T>
     162        6664 : MaybeHandle<Object> GetViewValue(Isolate* isolate, Handle<JSDataView> data_view,
     163             :                                  Handle<Object> request_index,
     164             :                                  bool is_little_endian) {
     165       13328 :   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        6356 :   if (!TryNumberToSize(*request_index, &get_index)) {
     172           0 :     THROW_NEW_ERROR(
     173             :         isolate, NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset),
     174             :         Object);
     175             :   }
     176             :   Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()),
     177             :                                isolate);
     178        6356 :   size_t const data_view_byte_offset = NumberToSize(data_view->byte_offset());
     179        6356 :   size_t const data_view_byte_length = NumberToSize(data_view->byte_length());
     180        6356 :   if (get_index + sizeof(T) > data_view_byte_length ||
     181             :       get_index + sizeof(T) < get_index) {  // overflow
     182       10192 :     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        1260 :   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        1260 :       static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
     194        1260 :   if (NeedToFlipBytes(is_little_endian)) {
     195             :     FlipBytes<sizeof(T)>(v.bytes, source);
     196             :   } else {
     197             :     CopyBytes<sizeof(T)>(v.bytes, source);
     198             :   }
     199        1260 :   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         182 :   return static_cast<int8_t>(DoubleToInt32(value));
     208             : }
     209             : 
     210             : template <>
     211             : int16_t DataViewConvertValue<int16_t>(double value) {
     212         182 :   return static_cast<int16_t>(DoubleToInt32(value));
     213             : }
     214             : 
     215             : template <>
     216             : int32_t DataViewConvertValue<int32_t>(double value) {
     217         182 :   return DoubleToInt32(value);
     218             : }
     219             : 
     220             : template <>
     221             : uint8_t DataViewConvertValue<uint8_t>(double value) {
     222         238 :   return static_cast<uint8_t>(DoubleToUint32(value));
     223             : }
     224             : 
     225             : template <>
     226             : uint16_t DataViewConvertValue<uint16_t>(double value) {
     227         238 :   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          98 :   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        6874 : MaybeHandle<Object> SetViewValue(Isolate* isolate, Handle<JSDataView> data_view,
     249             :                                  Handle<Object> request_index,
     250             :                                  bool is_little_endian, Handle<Object> value) {
     251       13748 :   ASSIGN_RETURN_ON_EXCEPTION(
     252             :       isolate, request_index,
     253             :       Object::ToIndex(isolate, request_index,
     254             :                       MessageTemplate::kInvalidDataViewAccessorOffset),
     255             :       Object);
     256       13132 :   ASSIGN_RETURN_ON_EXCEPTION(isolate, value, Object::ToNumber(value), Object);
     257             :   size_t get_index = 0;
     258        6566 :   if (!TryNumberToSize(*request_index, &get_index)) {
     259           0 :     THROW_NEW_ERROR(
     260             :         isolate, NewRangeError(MessageTemplate::kInvalidDataViewAccessorOffset),
     261             :         Object);
     262             :   }
     263             :   Handle<JSArrayBuffer> buffer(JSArrayBuffer::cast(data_view->buffer()),
     264             :                                isolate);
     265        6566 :   size_t const data_view_byte_offset = NumberToSize(data_view->byte_offset());
     266        6566 :   size_t const data_view_byte_length = NumberToSize(data_view->byte_length());
     267        6566 :   if (get_index + sizeof(T) > data_view_byte_length ||
     268             :       get_index + sizeof(T) < get_index) {  // overflow
     269       10192 :     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        1470 :   v.data = DataViewConvertValue<T>(value->Number());
     278        1470 :   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        1470 :       static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
     282        1470 :   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        2604 : DATA_VIEW_PROTOTYPE_GET(Int8, int8_t)
     306        3052 : DATA_VIEW_PROTOTYPE_GET(Uint8, uint8_t)
     307        4074 : DATA_VIEW_PROTOTYPE_GET(Int16, int16_t)
     308        4522 : DATA_VIEW_PROTOTYPE_GET(Uint16, uint16_t)
     309        4466 : DATA_VIEW_PROTOTYPE_GET(Int32, int32_t)
     310        5138 : DATA_VIEW_PROTOTYPE_GET(Uint32, uint32_t)
     311       12810 : DATA_VIEW_PROTOTYPE_GET(Float32, float)
     312       12810 : 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        3178 : DATA_VIEW_PROTOTYPE_SET(Int8, int8_t)
     330        3682 : DATA_VIEW_PROTOTYPE_SET(Uint8, uint8_t)
     331        4858 : DATA_VIEW_PROTOTYPE_SET(Int16, int16_t)
     332        5362 : DATA_VIEW_PROTOTYPE_SET(Uint16, uint16_t)
     333        5306 : DATA_VIEW_PROTOTYPE_SET(Int32, int32_t)
     334        5936 : DATA_VIEW_PROTOTYPE_SET(Uint32, uint32_t)
     335       14854 : DATA_VIEW_PROTOTYPE_SET(Float32, float)
     336       14854 : DATA_VIEW_PROTOTYPE_SET(Float64, double)
     337             : #undef DATA_VIEW_PROTOTYPE_SET
     338             : 
     339             : }  // namespace internal
     340             : }  // namespace v8

Generated by: LCOV version 1.10