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 84 : BUILTIN(DataViewConstructor) {
21 : HandleScope scope(isolate);
22 112 : 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 11190 : BUILTIN(DataViewConstructor_ConstructStub) {
30 : HandleScope scope(isolate);
31 3730 : Handle<JSFunction> target = args.target();
32 3730 : Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
33 : Handle<Object> buffer = args.atOrUndefined(isolate, 1);
34 3730 : 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 3730 : if (!buffer->IsJSArrayBuffer()) {
41 112 : 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 7348 : 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 3656 : if (offset->Number() > buffer_byte_length) {
61 36 : THROW_NEW_ERROR_RETURN_FAILURE(
62 : isolate, NewRangeError(MessageTemplate::kInvalidOffset, offset));
63 : }
64 :
65 : Handle<Object> view_byte_length;
66 3638 : if (byte_length->IsUndefined(isolate)) {
67 : // 8. If byteLength is undefined, then
68 : // a. Let viewByteLength be bufferByteLength - offset.
69 : view_byte_length =
70 570 : 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 6136 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
77 : isolate, view_byte_length,
78 : Object::ToIndex(isolate, byte_length,
79 : MessageTemplate::kInvalidDataViewLength));
80 3068 : if (offset->Number() + view_byte_length->Number() > buffer_byte_length) {
81 56 : 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 7220 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
92 : JSObject::New(target, new_target));
93 7220 : for (int i = 0; i < ArrayBufferView::kEmbedderFieldCount; ++i) {
94 7220 : Handle<JSDataView>::cast(result)->SetEmbedderField(i, Smi::kZero);
95 : }
96 :
97 : // 12. Set O's [[ViewedArrayBuffer]] internal slot to buffer.
98 3610 : Handle<JSDataView>::cast(result)->set_buffer(*array_buffer);
99 :
100 : // 13. Set O's [[ByteLength]] internal slot to viewByteLength.
101 3610 : Handle<JSDataView>::cast(result)->set_byte_length(*view_byte_length);
102 :
103 : // 14. Set O's [[ByteOffset]] internal slot to offset.
104 3610 : Handle<JSDataView>::cast(result)->set_byte_offset(*offset);
105 :
106 : // 15. Return O.
107 3610 : return *result;
108 : }
109 :
110 : // ES6 section 24.2.4.1 get DataView.prototype.buffer
111 540 : BUILTIN(DataViewPrototypeGetBuffer) {
112 : HandleScope scope(isolate);
113 288 : CHECK_RECEIVER(JSDataView, data_view, "get DataView.prototype.buffer");
114 144 : return data_view->buffer();
115 : }
116 :
117 : // ES6 section 24.2.4.2 get DataView.prototype.byteLength
118 17268 : BUILTIN(DataViewPrototypeGetByteLength) {
119 : HandleScope scope(isolate);
120 5864 : 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 5720 : return data_view->byte_length();
124 : }
125 :
126 : // ES6 section 24.2.4.3 get DataView.prototype.byteOffset
127 672 : BUILTIN(DataViewPrototypeGetByteOffset) {
128 : HandleScope scope(isolate);
129 332 : 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 188 : 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 1044 : for (size_t i = 0; i < n; i++) {
148 1044 : *(target++) = *(source++);
149 : }
150 : }
151 :
152 : template <size_t n>
153 : void FlipBytes(uint8_t* target, uint8_t const* source) {
154 443 : source = source + (n - 1);
155 3948 : for (size_t i = 0; i < n; i++) {
156 3948 : *(target++) = *(source--);
157 : }
158 : }
159 :
160 : // ES6 section 24.2.1.1 GetViewValue (view, requestIndex, isLittleEndian, type)
161 : template <typename T>
162 4324 : MaybeHandle<Object> GetViewValue(Isolate* isolate, Handle<JSDataView> data_view,
163 : Handle<Object> request_index,
164 : bool is_little_endian) {
165 8648 : 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 4126 : 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 4126 : size_t const data_view_byte_offset = NumberToSize(data_view->byte_offset());
179 4126 : size_t const data_view_byte_length = NumberToSize(data_view->byte_length());
180 4126 : if (get_index + sizeof(T) > data_view_byte_length ||
181 : get_index + sizeof(T) < get_index) { // overflow
182 6552 : 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 850 : 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 850 : static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
194 850 : if (NeedToFlipBytes(is_little_endian)) {
195 : FlipBytes<sizeof(T)>(v.bytes, source);
196 : } else {
197 : CopyBytes<sizeof(T)>(v.bytes, source);
198 : }
199 850 : 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 117 : return static_cast<int8_t>(DoubleToInt32(value));
208 : }
209 :
210 : template <>
211 : int16_t DataViewConvertValue<int16_t>(double value) {
212 117 : return static_cast<int16_t>(DoubleToInt32(value));
213 : }
214 :
215 : template <>
216 : int32_t DataViewConvertValue<int32_t>(double value) {
217 117 : return DoubleToInt32(value);
218 : }
219 :
220 : template <>
221 : uint8_t DataViewConvertValue<uint8_t>(double value) {
222 153 : return static_cast<uint8_t>(DoubleToUint32(value));
223 : }
224 :
225 : template <>
226 : uint16_t DataViewConvertValue<uint16_t>(double value) {
227 153 : 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 63 : 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 4419 : MaybeHandle<Object> SetViewValue(Isolate* isolate, Handle<JSDataView> data_view,
249 : Handle<Object> request_index,
250 : bool is_little_endian, Handle<Object> value) {
251 8838 : ASSIGN_RETURN_ON_EXCEPTION(
252 : isolate, request_index,
253 : Object::ToIndex(isolate, request_index,
254 : MessageTemplate::kInvalidDataViewAccessorOffset),
255 : Object);
256 8442 : ASSIGN_RETURN_ON_EXCEPTION(isolate, value, Object::ToNumber(value), Object);
257 : size_t get_index = 0;
258 4221 : 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 4221 : size_t const data_view_byte_offset = NumberToSize(data_view->byte_offset());
266 4221 : size_t const data_view_byte_length = NumberToSize(data_view->byte_length());
267 4221 : if (get_index + sizeof(T) > data_view_byte_length ||
268 : get_index + sizeof(T) < get_index) { // overflow
269 6552 : 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 945 : v.data = DataViewConvertValue<T>(value->Number());
278 945 : 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 945 : static_cast<uint8_t*>(buffer->backing_store()) + buffer_offset;
282 945 : if (NeedToFlipBytes(is_little_endian)) {
283 : FlipBytes<sizeof(T)>(target, v.bytes);
284 : } else {
285 : CopyBytes<sizeof(T)>(target, v.bytes);
286 : }
287 945 : 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 1834 : DATA_VIEW_PROTOTYPE_GET(Int8, int8_t)
306 1962 : DATA_VIEW_PROTOTYPE_GET(Uint8, uint8_t)
307 2779 : DATA_VIEW_PROTOTYPE_GET(Int16, int16_t)
308 2907 : DATA_VIEW_PROTOTYPE_GET(Uint16, uint16_t)
309 2871 : DATA_VIEW_PROTOTYPE_GET(Int32, int32_t)
310 3303 : DATA_VIEW_PROTOTYPE_GET(Uint32, uint32_t)
311 8235 : DATA_VIEW_PROTOTYPE_GET(Float32, float)
312 8235 : 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 2043 : DATA_VIEW_PROTOTYPE_SET(Int8, int8_t)
330 2367 : DATA_VIEW_PROTOTYPE_SET(Uint8, uint8_t)
331 3123 : DATA_VIEW_PROTOTYPE_SET(Int16, int16_t)
332 3447 : DATA_VIEW_PROTOTYPE_SET(Uint16, uint16_t)
333 3411 : DATA_VIEW_PROTOTYPE_SET(Int32, int32_t)
334 3816 : DATA_VIEW_PROTOTYPE_SET(Uint32, uint32_t)
335 9549 : DATA_VIEW_PROTOTYPE_SET(Float32, float)
336 9549 : DATA_VIEW_PROTOTYPE_SET(Float64, double)
337 : #undef DATA_VIEW_PROTOTYPE_SET
338 :
339 : } // namespace internal
340 : } // namespace v8
|