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
|