1 // 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
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.
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.
30 // This file relies on the fact that the following declaration has been made
32 // var $Array = global.Array;
33 var $ArrayBuffer = global.ArrayBuffer;
36 // --------------- Typed Arrays ---------------------
37 macro TYPED_ARRAYS(FUNCTION)
38 // arrayIds below should be synchronized with Runtime_TypedArrayInitialize.
39 FUNCTION(1, Uint8Array, 1)
40 FUNCTION(2, Int8Array, 1)
41 FUNCTION(3, Uint16Array, 2)
42 FUNCTION(4, Int16Array, 2)
43 FUNCTION(5, Uint32Array, 4)
44 FUNCTION(6, Int32Array, 4)
45 FUNCTION(7, Float32Array, 4)
46 FUNCTION(8, Float64Array, 8)
47 FUNCTION(9, Uint8ClampedArray, 1)
50 macro TYPED_ARRAY_CONSTRUCTOR(ARRAY_ID, NAME, ELEMENT_SIZE)
51 function NAMEConstructByArrayBuffer(obj, buffer, byteOffset, length) {
52 var bufferByteLength = buffer.byteLength;
54 if (IS_UNDEFINED(byteOffset)) {
57 offset = ToPositiveInteger(byteOffset, "invalid_typed_array_length");
59 if (offset % ELEMENT_SIZE !== 0) {
60 throw MakeRangeError("invalid_typed_array_alignment",
61 "start offset", "NAME", ELEMENT_SIZE);
63 if (offset > bufferByteLength) {
64 throw MakeRangeError("invalid_typed_array_offset");
70 if (IS_UNDEFINED(length)) {
71 if (bufferByteLength % ELEMENT_SIZE !== 0) {
72 throw MakeRangeError("invalid_typed_array_alignment",
73 "byte length", "NAME", ELEMENT_SIZE);
75 newByteLength = bufferByteLength - offset;
76 newLength = newByteLength / ELEMENT_SIZE;
78 var newLength = ToPositiveInteger(length, "invalid_typed_array_length");
79 newByteLength = newLength * ELEMENT_SIZE;
81 if ((offset + newByteLength > bufferByteLength)
82 || (newLength > %MaxSmi())) {
83 throw MakeRangeError("invalid_typed_array_length");
85 %TypedArrayInitialize(obj, ARRAY_ID, buffer, offset, newByteLength);
88 function NAMEConstructByLength(obj, length) {
89 var l = IS_UNDEFINED(length) ?
90 0 : ToPositiveInteger(length, "invalid_typed_array_length");
92 throw MakeRangeError("invalid_typed_array_length");
94 var byteLength = l * ELEMENT_SIZE;
95 var buffer = new $ArrayBuffer(byteLength);
96 %TypedArrayInitialize(obj, ARRAY_ID, buffer, 0, byteLength);
99 function NAMEConstructByArrayLike(obj, arrayLike) {
100 var length = arrayLike.length;
101 var l = ToPositiveInteger(length, "invalid_typed_array_length");
103 throw MakeRangeError("invalid_typed_array_length");
105 if(!%TypedArrayInitializeFromArrayLike(obj, ARRAY_ID, arrayLike, l)) {
106 for (var i = 0; i < l; i++) {
107 // It is crucial that we let any execptions from arrayLike[i]
108 // propagate outside the function.
109 obj[i] = arrayLike[i];
114 function NAMEConstructor(arg1, arg2, arg3) {
116 if (%_IsConstructCall()) {
117 if (IS_ARRAYBUFFER(arg1)) {
118 NAMEConstructByArrayBuffer(this, arg1, arg2, arg3);
119 } else if (IS_NUMBER(arg1) || IS_STRING(arg1) ||
120 IS_BOOLEAN(arg1) || IS_UNDEFINED(arg1)) {
121 NAMEConstructByLength(this, arg1);
123 NAMEConstructByArrayLike(this, arg1);
126 throw MakeTypeError("constructor_not_function", ["NAME"])
131 TYPED_ARRAYS(TYPED_ARRAY_CONSTRUCTOR)
133 function TypedArrayGetBuffer() {
134 return %TypedArrayGetBuffer(this);
137 function TypedArrayGetByteLength() {
138 return %TypedArrayGetByteLength(this);
141 function TypedArrayGetByteOffset() {
142 return %TypedArrayGetByteOffset(this);
145 function TypedArrayGetLength() {
146 return %TypedArrayGetLength(this);
149 function CreateSubArray(elementSize, constructor) {
150 return function(begin, end) {
151 var srcLength = %TypedArrayGetLength(this);
152 var beginInt = TO_INTEGER(begin);
154 beginInt = MathMax(0, srcLength + beginInt);
156 beginInt = MathMin(srcLength, beginInt);
159 var endInt = IS_UNDEFINED(end) ? srcLength : TO_INTEGER(end);
161 endInt = MathMax(0, srcLength + endInt);
163 endInt = MathMin(endInt, srcLength);
165 if (endInt < beginInt) {
168 var newLength = endInt - beginInt;
169 var beginByteOffset =
170 %TypedArrayGetByteOffset(this) + beginInt * elementSize;
171 return new constructor(%TypedArrayGetBuffer(this),
172 beginByteOffset, newLength);
176 function TypedArraySetFromArrayLike(target, source, sourceLength, offset) {
178 for (var i = 0; i < sourceLength; i++) {
179 target[offset + i] = source[i];
183 for (var i = 0; i < sourceLength; i++) {
184 target[i] = source[i];
189 function TypedArraySetFromOverlappingTypedArray(target, source, offset) {
190 var sourceElementSize = source.BYTES_PER_ELEMENT;
191 var targetElementSize = target.BYTES_PER_ELEMENT;
192 var sourceLength = source.length;
195 function CopyLeftPart() {
196 // First un-mutated byte after the next write
197 var targetPtr = target.byteOffset + (offset + 1) * targetElementSize;
198 // Next read at sourcePtr. We do not care for memory changing before
199 // sourcePtr - we have already copied it.
200 var sourcePtr = source.byteOffset;
201 for (var leftIndex = 0;
202 leftIndex < sourceLength && targetPtr <= sourcePtr;
204 target[offset + leftIndex] = source[leftIndex];
205 targetPtr += targetElementSize;
206 sourcePtr += sourceElementSize;
210 var leftIndex = CopyLeftPart();
213 function CopyRightPart() {
214 // First unmutated byte before the next write
216 target.byteOffset + (offset + sourceLength - 1) * targetElementSize;
217 // Next read before sourcePtr. We do not care for memory changing after
218 // sourcePtr - we have already copied it.
220 source.byteOffset + sourceLength * sourceElementSize;
221 for(var rightIndex = sourceLength - 1;
222 rightIndex >= leftIndex && targetPtr >= sourcePtr;
224 target[offset + rightIndex] = source[rightIndex];
225 targetPtr -= targetElementSize;
226 sourcePtr -= sourceElementSize;
230 var rightIndex = CopyRightPart();
232 var temp = new $Array(rightIndex + 1 - leftIndex);
233 for (var i = leftIndex; i <= rightIndex; i++) {
234 temp[i - leftIndex] = source[i];
236 for (i = leftIndex; i <= rightIndex; i++) {
237 target[offset + i] = temp[i - leftIndex];
241 function TypedArraySet(obj, offset) {
242 var intOffset = IS_UNDEFINED(offset) ? 0 : TO_INTEGER(offset);
244 throw MakeTypeError("typed_array_set_negative_offset");
247 if (intOffset > %MaxSmi()) {
248 throw MakeRangeError("typed_array_set_source_too_large");
250 switch (%TypedArraySetFastCases(this, obj, intOffset)) {
251 // These numbers should be synchronized with runtime.cc.
252 case 0: // TYPED_ARRAY_SET_TYPED_ARRAY_SAME_TYPE
254 case 1: // TYPED_ARRAY_SET_TYPED_ARRAY_OVERLAPPING
255 TypedArraySetFromOverlappingTypedArray(this, obj, intOffset);
257 case 2: // TYPED_ARRAY_SET_TYPED_ARRAY_NONOVERLAPPING
258 TypedArraySetFromArrayLike(this, obj, obj.length, intOffset);
260 case 3: // TYPED_ARRAY_SET_NON_TYPED_ARRAY
262 if (IS_UNDEFINED(l)) {
263 if (IS_NUMBER(obj)) {
264 // For number as a first argument, throw TypeError
265 // instead of silently ignoring the call, so that
266 // the user knows (s)he did something wrong.
267 // (Consistent with Firefox and Blink/WebKit)
268 throw MakeTypeError("invalid_argument");
272 if (intOffset + l > this.length) {
273 throw MakeRangeError("typed_array_set_source_too_large");
275 TypedArraySetFromArrayLike(this, obj, l, intOffset);
280 // -------------------------------------------------------------------
282 function SetupTypedArray(constructor, fun, elementSize) {
283 %CheckIsBootstrapping();
284 %SetCode(constructor, fun);
285 %FunctionSetPrototype(constructor, new $Object());
287 %SetProperty(constructor, "BYTES_PER_ELEMENT", elementSize,
288 READ_ONLY | DONT_ENUM | DONT_DELETE);
289 %SetProperty(constructor.prototype,
290 "constructor", constructor, DONT_ENUM);
291 %SetProperty(constructor.prototype,
292 "BYTES_PER_ELEMENT", elementSize,
293 READ_ONLY | DONT_ENUM | DONT_DELETE);
294 InstallGetter(constructor.prototype, "buffer", TypedArrayGetBuffer);
295 InstallGetter(constructor.prototype, "byteOffset", TypedArrayGetByteOffset);
296 InstallGetter(constructor.prototype, "byteLength", TypedArrayGetByteLength);
297 InstallGetter(constructor.prototype, "length", TypedArrayGetLength);
299 InstallFunctions(constructor.prototype, DONT_ENUM, $Array(
300 "subarray", CreateSubArray(elementSize, constructor),
305 macro SETUP_TYPED_ARRAY(ARRAY_ID, NAME, ELEMENT_SIZE)
306 SetupTypedArray (global.NAME, NAMEConstructor, ELEMENT_SIZE);
309 TYPED_ARRAYS(SETUP_TYPED_ARRAY)
311 // --------------------------- DataView -----------------------------
313 var $DataView = global.DataView;
315 function DataViewConstructor(buffer, byteOffset, byteLength) { // length = 3
316 if (%_IsConstructCall()) {
317 if (!IS_ARRAYBUFFER(buffer)) {
318 throw MakeTypeError('data_view_not_array_buffer', []);
320 var bufferByteLength = buffer.byteLength;
321 var offset = IS_UNDEFINED(byteOffset) ?
322 0 : ToPositiveInteger(byteOffset, 'invalid_data_view_offset');
323 if (offset > bufferByteLength) {
324 throw MakeRangeError('invalid_data_view_offset');
326 var length = IS_UNDEFINED(byteLength) ?
327 bufferByteLength - offset : TO_INTEGER(byteLength);
328 if (length < 0 || offset + length > bufferByteLength) {
329 throw new MakeRangeError('invalid_data_view_length');
331 %DataViewInitialize(this, buffer, offset, length);
333 throw MakeTypeError('constructor_not_function', ["DataView"]);
337 function DataViewGetBuffer() {
338 if (!IS_DATAVIEW(this)) {
339 throw MakeTypeError('incompatible_method_receiver',
340 ['DataView.buffer', this]);
342 return %DataViewGetBuffer(this);
345 function DataViewGetByteOffset() {
346 if (!IS_DATAVIEW(this)) {
347 throw MakeTypeError('incompatible_method_receiver',
348 ['DataView.byteOffset', this]);
350 return %DataViewGetByteOffset(this);
353 function DataViewGetByteLength() {
354 if (!IS_DATAVIEW(this)) {
355 throw MakeTypeError('incompatible_method_receiver',
356 ['DataView.byteLength', this]);
358 return %DataViewGetByteLength(this);
361 macro DATA_VIEW_TYPES(FUNCTION)
372 function ToPositiveDataViewOffset(offset) {
373 return ToPositiveInteger(offset, 'invalid_data_view_accessor_offset');
377 macro DATA_VIEW_GETTER_SETTER(TYPENAME)
378 function DataViewGetTYPENAME(offset, little_endian) {
379 if (!IS_DATAVIEW(this)) {
380 throw MakeTypeError('incompatible_method_receiver',
381 ['DataView.getTYPENAME', this]);
383 if (%_ArgumentsLength() < 1) {
384 throw MakeTypeError('invalid_argument');
386 return %DataViewGetTYPENAME(this,
387 ToPositiveDataViewOffset(offset),
391 function DataViewSetTYPENAME(offset, value, little_endian) {
392 if (!IS_DATAVIEW(this)) {
393 throw MakeTypeError('incompatible_method_receiver',
394 ['DataView.setTYPENAME', this]);
396 if (%_ArgumentsLength() < 2) {
397 throw MakeTypeError('invalid_argument');
399 %DataViewSetTYPENAME(this,
400 ToPositiveDataViewOffset(offset),
401 TO_NUMBER_INLINE(value),
406 DATA_VIEW_TYPES(DATA_VIEW_GETTER_SETTER)
408 function SetupDataView() {
409 %CheckIsBootstrapping();
411 // Setup the DataView constructor.
412 %SetCode($DataView, DataViewConstructor);
413 %FunctionSetPrototype($DataView, new $Object);
415 // Set up constructor property on the DataView prototype.
416 %SetProperty($DataView.prototype, "constructor", $DataView, DONT_ENUM);
418 InstallGetter($DataView.prototype, "buffer", DataViewGetBuffer);
419 InstallGetter($DataView.prototype, "byteOffset", DataViewGetByteOffset);
420 InstallGetter($DataView.prototype, "byteLength", DataViewGetByteLength);
422 InstallFunctions($DataView.prototype, DONT_ENUM, $Array(
423 "getInt8", DataViewGetInt8,
424 "setInt8", DataViewSetInt8,
426 "getUint8", DataViewGetUint8,
427 "setUint8", DataViewSetUint8,
429 "getInt16", DataViewGetInt16,
430 "setInt16", DataViewSetInt16,
432 "getUint16", DataViewGetUint16,
433 "setUint16", DataViewSetUint16,
435 "getInt32", DataViewGetInt32,
436 "setInt32", DataViewSetInt32,
438 "getUint32", DataViewGetUint32,
439 "setUint32", DataViewSetUint32,
441 "getFloat32", DataViewGetFloat32,
442 "setFloat32", DataViewSetFloat32,
444 "getFloat64", DataViewGetFloat64,
445 "setFloat64", DataViewSetFloat64