• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
BUILTIN(DataViewConstructor)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.
BUILTIN(DataViewConstructor_ConstructStub)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
BUILTIN(DataViewPrototypeGetBuffer)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
BUILTIN(DataViewPrototypeGetByteLength)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
BUILTIN(DataViewPrototypeGetByteOffset)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 
NeedToFlipBytes(bool is_little_endian)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>
CopyBytes(uint8_t * target,uint8_t const * source)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>
FlipBytes(uint8_t * target,uint8_t const * source)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>
GetViewValue(Isolate * isolate,Handle<JSDataView> data_view,Handle<Object> request_index,bool is_little_endian)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 <>
DataViewConvertValue(double value)206 int8_t DataViewConvertValue<int8_t>(double value) {
207   return static_cast<int8_t>(DoubleToInt32(value));
208 }
209 
210 template <>
DataViewConvertValue(double value)211 int16_t DataViewConvertValue<int16_t>(double value) {
212   return static_cast<int16_t>(DoubleToInt32(value));
213 }
214 
215 template <>
DataViewConvertValue(double value)216 int32_t DataViewConvertValue<int32_t>(double value) {
217   return DoubleToInt32(value);
218 }
219 
220 template <>
DataViewConvertValue(double value)221 uint8_t DataViewConvertValue<uint8_t>(double value) {
222   return static_cast<uint8_t>(DoubleToUint32(value));
223 }
224 
225 template <>
DataViewConvertValue(double value)226 uint16_t DataViewConvertValue<uint16_t>(double value) {
227   return static_cast<uint16_t>(DoubleToUint32(value));
228 }
229 
230 template <>
DataViewConvertValue(double value)231 uint32_t DataViewConvertValue<uint32_t>(double value) {
232   return DoubleToUint32(value);
233 }
234 
235 template <>
DataViewConvertValue(double value)236 float DataViewConvertValue<float>(double value) {
237   return static_cast<float>(value);
238 }
239 
240 template <>
DataViewConvertValue(double value)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>
SetViewValue(Isolate * isolate,Handle<JSDataView> data_view,Handle<Object> request_index,bool is_little_endian,Handle<Object> value)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