blob: 0d903550495be2a6d792d279b547e7229ebf4ce5 [file] [log] [blame]
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00001// Copyright 2013 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28"use strict";
29
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000030// This file relies on the fact that the following declaration has been made
31// in runtime.js:
32// var $Array = global.Array;
33
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000034
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +000035
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000036// --------------- Typed Arrays ---------------------
37
38function CreateTypedArrayConstructor(name, elementSize, arrayId, constructor) {
danno@chromium.orgf005df62013-04-30 16:36:45 +000039 function ConstructByArrayBuffer(obj, buffer, byteOffset, length) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000040 var offset = ToPositiveInteger(byteOffset, "invalid_typed_array_length")
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000041
danno@chromium.orgf005df62013-04-30 16:36:45 +000042 if (offset % elementSize !== 0) {
43 throw MakeRangeError("invalid_typed_array_alignment",
44 "start offset", name, elementSize);
45 }
46 var bufferByteLength = %ArrayBufferGetByteLength(buffer);
ulan@chromium.org57ff8812013-05-10 08:16:55 +000047 if (offset > bufferByteLength) {
danno@chromium.orgf005df62013-04-30 16:36:45 +000048 throw MakeRangeError("invalid_typed_array_offset");
49 }
50
51 var newByteLength;
52 var newLength;
53 if (IS_UNDEFINED(length)) {
54 if (bufferByteLength % elementSize !== 0) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000055 throw MakeRangeError("invalid_typed_array_alignment",
danno@chromium.orgf005df62013-04-30 16:36:45 +000056 "byte length", name, elementSize);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000057 }
danno@chromium.orgf005df62013-04-30 16:36:45 +000058 newByteLength = bufferByteLength - offset;
59 newLength = newByteLength / elementSize;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +000060 } else {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000061 var newLength = ToPositiveInteger(length, "invalid_typed_array_length");
danno@chromium.orgf005df62013-04-30 16:36:45 +000062 newByteLength = newLength * elementSize;
63 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +000064 if (offset + newByteLength > bufferByteLength) {
danno@chromium.orgf005df62013-04-30 16:36:45 +000065 throw MakeRangeError("invalid_typed_array_length");
66 }
67 %TypedArrayInitialize(obj, arrayId, buffer, offset, newByteLength);
68 }
69
70 function ConstructByLength(obj, length) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000071 var l = ToPositiveInteger(length, "invalid_typed_array_length");
danno@chromium.orgf005df62013-04-30 16:36:45 +000072 var byteLength = l * elementSize;
ulan@chromium.org57ff8812013-05-10 08:16:55 +000073 var buffer = new global.ArrayBuffer(byteLength);
74 %TypedArrayInitialize(obj, arrayId, buffer, 0, byteLength);
75 }
76
77 function ConstructByArrayLike(obj, arrayLike) {
78 var length = arrayLike.length;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +000079 var l = ToPositiveInteger(length, "invalid_typed_array_length");
ulan@chromium.org57ff8812013-05-10 08:16:55 +000080 var byteLength = l * elementSize;
danno@chromium.orgf005df62013-04-30 16:36:45 +000081 var buffer = new $ArrayBuffer(byteLength);
82 %TypedArrayInitialize(obj, arrayId, buffer, 0, byteLength);
ulan@chromium.org57ff8812013-05-10 08:16:55 +000083 for (var i = 0; i < l; i++) {
84 obj[i] = arrayLike[i];
85 }
danno@chromium.orgf005df62013-04-30 16:36:45 +000086 }
87
88 return function (arg1, arg2, arg3) {
89 if (%_IsConstructCall()) {
90 if (IS_ARRAYBUFFER(arg1)) {
91 ConstructByArrayBuffer(this, arg1, arg2, arg3);
ulan@chromium.org57ff8812013-05-10 08:16:55 +000092 } else if (IS_NUMBER(arg1) || IS_STRING(arg1) || IS_BOOLEAN(arg1)) {
danno@chromium.orgf005df62013-04-30 16:36:45 +000093 ConstructByLength(this, arg1);
ulan@chromium.org57ff8812013-05-10 08:16:55 +000094 } else if (!IS_UNDEFINED(arg1)){
95 ConstructByArrayLike(this, arg1);
96 } else {
ulan@chromium.orgdfe53072013-06-06 14:14:51 +000097 throw MakeTypeError("parameterless_typed_array_constr", [name]);
danno@chromium.orgf005df62013-04-30 16:36:45 +000098 }
99 } else {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000100 throw MakeTypeError("constructor_not_function", [name])
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000101 }
102 }
103}
104
105function TypedArrayGetBuffer() {
106 return %TypedArrayGetBuffer(this);
107}
108
109function TypedArrayGetByteLength() {
110 return %TypedArrayGetByteLength(this);
111}
112
113function TypedArrayGetByteOffset() {
114 return %TypedArrayGetByteOffset(this);
115}
116
117function TypedArrayGetLength() {
118 return %TypedArrayGetLength(this);
119}
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000120
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000121function CreateSubArray(elementSize, constructor) {
122 return function(begin, end) {
123 var srcLength = %TypedArrayGetLength(this);
124 var beginInt = TO_INTEGER(begin);
125 if (beginInt < 0) {
126 beginInt = MathMax(0, srcLength + beginInt);
127 } else {
128 beginInt = MathMin(srcLength, beginInt);
129 }
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000130
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000131 var endInt = IS_UNDEFINED(end) ? srcLength : TO_INTEGER(end);
132 if (endInt < 0) {
133 endInt = MathMax(0, srcLength + endInt);
134 } else {
135 endInt = MathMin(endInt, srcLength);
136 }
137 if (endInt < beginInt) {
138 endInt = beginInt;
139 }
140 var newLength = endInt - beginInt;
141 var beginByteOffset =
142 %TypedArrayGetByteOffset(this) + beginInt * elementSize;
143 return new constructor(%TypedArrayGetBuffer(this),
144 beginByteOffset, newLength);
145 }
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000146}
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +0000147
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000148function TypedArraySet(obj, offset) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000149 var intOffset = IS_UNDEFINED(offset) ? 0 : TO_INTEGER(offset);
150 if (intOffset < 0) {
151 throw MakeTypeError("typed_array_set_negative_offset");
152 }
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000153 if (%TypedArraySetFastCases(this, obj, intOffset))
154 return;
155
156 var l = obj.length;
157 if (IS_UNDEFINED(l)) {
158 throw MakeTypeError("invalid_argument");
159 }
160 if (intOffset + l > this.length) {
161 throw MakeRangeError("typed_array_set_source_too_large");
162 }
163 for (var i = 0; i < l; i++) {
164 this[intOffset + i] = obj[i];
165 }
166}
167
168// -------------------------------------------------------------------
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000169
170function SetupTypedArray(arrayId, name, constructor, elementSize) {
danno@chromium.orgf005df62013-04-30 16:36:45 +0000171 %CheckIsBootstrapping();
172 var fun = CreateTypedArrayConstructor(name, elementSize,
173 arrayId, constructor);
174 %SetCode(constructor, fun);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000175 %FunctionSetPrototype(constructor, new $Object());
176
177 %SetProperty(constructor.prototype,
178 "constructor", constructor, DONT_ENUM);
179 %SetProperty(constructor.prototype,
180 "BYTES_PER_ELEMENT", elementSize,
181 READ_ONLY | DONT_ENUM | DONT_DELETE);
182 InstallGetter(constructor.prototype, "buffer", TypedArrayGetBuffer);
183 InstallGetter(constructor.prototype, "byteOffset", TypedArrayGetByteOffset);
184 InstallGetter(constructor.prototype, "byteLength", TypedArrayGetByteLength);
185 InstallGetter(constructor.prototype, "length", TypedArrayGetLength);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000186
187 InstallFunctions(constructor.prototype, DONT_ENUM, $Array(
188 "subarray", CreateSubArray(elementSize, constructor),
189 "set", TypedArraySet
190 ));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000191}
192
193// arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
danno@chromium.orgf005df62013-04-30 16:36:45 +0000194SetupTypedArray(1, "Uint8Array", global.Uint8Array, 1);
195SetupTypedArray(2, "Int8Array", global.Int8Array, 1);
196SetupTypedArray(3, "Uint16Array", global.Uint16Array, 2);
197SetupTypedArray(4, "Int16Array", global.Int16Array, 2);
198SetupTypedArray(5, "Uint32Array", global.Uint32Array, 4);
199SetupTypedArray(6, "Int32Array", global.Int32Array, 4);
200SetupTypedArray(7, "Float32Array", global.Float32Array, 4);
201SetupTypedArray(8, "Float64Array", global.Float64Array, 8);
ulan@chromium.org57ff8812013-05-10 08:16:55 +0000202SetupTypedArray(9, "Uint8ClampedArray", global.Uint8ClampedArray, 1);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000203
204
205// --------------------------- DataView -----------------------------
206
207var $DataView = global.DataView;
208
209function DataViewConstructor(buffer, byteOffset, byteLength) { // length = 3
210 if (%_IsConstructCall()) {
211 if (!IS_ARRAYBUFFER(buffer)) {
212 throw MakeTypeError('data_view_not_array_buffer', []);
213 }
214 var bufferByteLength = %ArrayBufferGetByteLength(buffer);
215 var offset = ToPositiveInteger(byteOffset, 'invalid_data_view_offset');
216 if (offset > bufferByteLength) {
217 throw MakeRangeError('invalid_data_view_offset');
218 }
219 var length = IS_UNDEFINED(byteLength) ?
220 bufferByteLength - offset : TO_INTEGER(byteLength);
221 if (length < 0 || offset + length > bufferByteLength) {
222 throw new MakeRangeError('invalid_data_view_length');
223 }
224 %DataViewInitialize(this, buffer, offset, length);
225 } else {
226 throw MakeTypeError('constructor_not_function', ["DataView"]);
227 }
228}
229
230function DataViewGetBuffer() {
231 if (!IS_DATAVIEW(this)) {
232 throw MakeTypeError('incompatible_method_reciever',
233 ['DataView.buffer', this]);
234 }
235 return %DataViewGetBuffer(this);
236}
237
238function DataViewGetByteOffset() {
239 if (!IS_DATAVIEW(this)) {
240 throw MakeTypeError('incompatible_method_reciever',
241 ['DataView.byteOffset', this]);
242 }
243 return %DataViewGetByteOffset(this);
244}
245
246function DataViewGetByteLength() {
247 if (!IS_DATAVIEW(this)) {
248 throw MakeTypeError('incompatible_method_reciever',
249 ['DataView.byteLength', this]);
250 }
251 return %DataViewGetByteLength(this);
252}
253
254function ToPositiveDataViewOffset(offset) {
255 return ToPositiveInteger(offset, 'invalid_data_view_accessor_offset');
256}
257
258function DataViewGetInt8(offset, little_endian) {
259 if (!IS_DATAVIEW(this)) {
260 throw MakeTypeError('incompatible_method_reciever',
261 ['DataView.getInt8', this]);
262 }
263 return %DataViewGetInt8(this,
264 ToPositiveDataViewOffset(offset),
265 !!little_endian);
266}
267
268function DataViewSetInt8(offset, value, little_endian) {
269 if (!IS_DATAVIEW(this)) {
270 throw MakeTypeError('incompatible_method_reciever',
271 ['DataView.setInt8', this]);
272 }
273 %DataViewSetInt8(this,
274 ToPositiveDataViewOffset(offset),
275 TO_NUMBER_INLINE(value),
276 !!little_endian);
277}
278
279function DataViewGetUint8(offset, little_endian) {
280 if (!IS_DATAVIEW(this)) {
281 throw MakeTypeError('incompatible_method_reciever',
282 ['DataView.getUint8', this]);
283 }
284 return %DataViewGetUint8(this,
285 ToPositiveDataViewOffset(offset),
286 !!little_endian);
287}
288
289function DataViewSetUint8(offset, value, little_endian) {
290 if (!IS_DATAVIEW(this)) {
291 throw MakeTypeError('incompatible_method_reciever',
292 ['DataView.setUint8', this]);
293 }
294 %DataViewSetUint8(this,
295 ToPositiveDataViewOffset(offset),
296 TO_NUMBER_INLINE(value),
297 !!little_endian);
298}
299
300function DataViewGetInt16(offset, little_endian) {
301 if (!IS_DATAVIEW(this)) {
302 throw MakeTypeError('incompatible_method_reciever',
303 ['DataView.getInt16', this]);
304 }
305 return %DataViewGetInt16(this,
306 ToPositiveDataViewOffset(offset),
307 !!little_endian);
308}
309
310function DataViewSetInt16(offset, value, little_endian) {
311 if (!IS_DATAVIEW(this)) {
312 throw MakeTypeError('incompatible_method_reciever',
313 ['DataView.setInt16', this]);
314 }
315 %DataViewSetInt16(this,
316 ToPositiveDataViewOffset(offset),
317 TO_NUMBER_INLINE(value),
318 !!little_endian);
319}
320
321function DataViewGetUint16(offset, little_endian) {
322 if (!IS_DATAVIEW(this)) {
323 throw MakeTypeError('incompatible_method_reciever',
324 ['DataView.getUint16', this]);
325 }
326 return %DataViewGetUint16(this,
327 ToPositiveDataViewOffset(offset),
328 !!little_endian);
329}
330
331function DataViewSetUint16(offset, value, little_endian) {
332 if (!IS_DATAVIEW(this)) {
333 throw MakeTypeError('incompatible_method_reciever',
334 ['DataView.setUint16', this]);
335 }
336 %DataViewSetUint16(this,
337 ToPositiveDataViewOffset(offset),
338 TO_NUMBER_INLINE(value),
339 !!little_endian);
340}
341
342function DataViewGetInt32(offset, little_endian) {
343 if (!IS_DATAVIEW(this)) {
344 throw MakeTypeError('incompatible_method_reciever',
345 ['DataView.getInt32', this]);
346 }
347 return %DataViewGetInt32(this,
348 ToPositiveDataViewOffset(offset),
349 !!little_endian);
350}
351
352function DataViewSetInt32(offset, value, little_endian) {
353 if (!IS_DATAVIEW(this)) {
354 throw MakeTypeError('incompatible_method_reciever',
355 ['DataView.setInt32', this]);
356 }
357 %DataViewSetInt32(this,
358 ToPositiveDataViewOffset(offset),
359 TO_NUMBER_INLINE(value),
360 !!little_endian);
361}
362
363function DataViewGetUint32(offset, little_endian) {
364 if (!IS_DATAVIEW(this)) {
365 throw MakeTypeError('incompatible_method_reciever',
366 ['DataView.getUint32', this]);
367 }
368 return %DataViewGetUint32(this,
369 ToPositiveDataViewOffset(offset),
370 !!little_endian);
371}
372
373function DataViewSetUint32(offset, value, little_endian) {
374 if (!IS_DATAVIEW(this)) {
375 throw MakeTypeError('incompatible_method_reciever',
376 ['DataView.setUint32', this]);
377 }
378 %DataViewSetUint32(this,
379 ToPositiveDataViewOffset(offset),
380 TO_NUMBER_INLINE(value),
381 !!little_endian);
382}
383
384function DataViewGetFloat32(offset, little_endian) {
385 if (!IS_DATAVIEW(this)) {
386 throw MakeTypeError('incompatible_method_reciever',
387 ['DataView.getFloat32', this]);
388 }
389 return %DataViewGetFloat32(this,
390 ToPositiveDataViewOffset(offset),
391 !!little_endian);
392}
393
394function DataViewSetFloat32(offset, value, little_endian) {
395 if (!IS_DATAVIEW(this)) {
396 throw MakeTypeError('incompatible_method_reciever',
397 ['DataView.setFloat32', this]);
398 }
399 %DataViewSetFloat32(this,
400 ToPositiveDataViewOffset(offset),
401 TO_NUMBER_INLINE(value),
402 !!little_endian);
403}
404
405function DataViewGetFloat64(offset, little_endian) {
406 if (!IS_DATAVIEW(this)) {
407 throw MakeTypeError('incompatible_method_reciever',
408 ['DataView.getFloat64', this]);
409 }
410 offset = TO_INTEGER(offset);
411 if (offset < 0) {
412 throw MakeRangeError("invalid_data_view_accessor_offset");
413 }
414 return %DataViewGetFloat64(this,
415 ToPositiveDataViewOffset(offset),
416 !!little_endian);
417}
418
419function DataViewSetFloat64(offset, value, little_endian) {
420 if (!IS_DATAVIEW(this)) {
421 throw MakeTypeError('incompatible_method_reciever',
422 ['DataView.setFloat64', this]);
423 }
424 offset = TO_INTEGER(offset);
425 if (offset < 0) {
426 throw MakeRangeError("invalid_data_view_accessor_offset");
427 }
428 %DataViewSetFloat64(this,
429 ToPositiveDataViewOffset(offset),
430 TO_NUMBER_INLINE(value),
431 !!little_endian);
432}
433
434function SetupDataView() {
435 %CheckIsBootstrapping();
436
437 // Setup the DataView constructor.
438 %SetCode($DataView, DataViewConstructor);
439 %FunctionSetPrototype($DataView, new $Object);
440
441 // Set up constructor property on the DataView prototype.
442 %SetProperty($DataView.prototype, "constructor", $DataView, DONT_ENUM);
443
444 InstallGetter($DataView.prototype, "buffer", DataViewGetBuffer);
445 InstallGetter($DataView.prototype, "byteOffset", DataViewGetByteOffset);
446 InstallGetter($DataView.prototype, "byteLength", DataViewGetByteLength);
447
448 InstallFunctions($DataView.prototype, DONT_ENUM, $Array(
449 "getInt8", DataViewGetInt8,
450 "setInt8", DataViewSetInt8,
451
452 "getUint8", DataViewGetUint8,
453 "setUint8", DataViewSetUint8,
454
455 "getInt16", DataViewGetInt16,
456 "setInt16", DataViewSetInt16,
457
458 "getUint16", DataViewGetUint16,
459 "setUint16", DataViewSetUint16,
460
461 "getInt32", DataViewGetInt32,
462 "setInt32", DataViewSetInt32,
463
464 "getUint32", DataViewGetUint32,
465 "setUint32", DataViewSetUint32,
466
467 "getFloat32", DataViewGetFloat32,
468 "setFloat32", DataViewSetFloat32,
469
470 "getFloat64", DataViewGetFloat64,
471 "setFloat64", DataViewSetFloat64
472 ));
473}
474
475SetupDataView();