• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16package escompat;
17
18/**
19 * Either ArrayBuffer or SharedArrayBuffer
20 */
21// NOTE (kprokopenko): make abstract after abstract overloads get to work
22abstract class Buffer {
23    abstract getByteLength(): int
24    abstract at(i: int): byte
25    abstract set(i: int, b: byte)
26    // NOTE (egor-porsev): should be slice(int, int) without an extra 'sliceInternal' method. This is a workaround for #13402
27    abstract sliceInternal(begin: int, end: int): Buffer
28}
29
30export interface ArrayBufferView {
31    /**
32     * The ArrayBuffer instance referenced by the array.
33     */
34    readonly buffer: ArrayBufferLike
35
36    /**
37     * The length in bytes of the array.
38     */
39    readonly byteLength: number
40
41    /**
42     * The offset in bytes of the array.
43     */
44    readonly byteOffset: number
45}
46
47/**
48 * JS ArrayBuffer API-compatible class
49 */
50export class ArrayBuffer extends Buffer
51{
52    /**
53     * Creates ArrayBuffer with size equal to length parameter
54     *
55     * @param length size of ArrayBuffer
56     */
57    public constructor(length: int)
58    {
59        this.data = new byte[length]
60        this._byteLength = length
61    }
62
63    /**
64     * Creates ArrayBuffer with size equal to length parameter
65     *
66     * @param length size of ArrayBuffer
67     */
68    public constructor(length: number)
69    {
70        this(length as int)
71    }
72
73    /**
74     * Checks if the passed Object is a View
75     *
76     * @param obj to check
77     *
78     * @returns true if obj is instance of typed array
79     */
80    public static isView(obj: Object): boolean
81    {
82        //TODO(ivan-tyulyandin): add DataView and unsigned TypedArray API when it will be implemented
83        return ( obj instanceof Int8Array
84            || obj instanceof Int16Array
85            || obj instanceof Int32Array
86            || obj instanceof BigInt64Array
87            || obj instanceof Float32Array
88            || obj instanceof Float64Array
89            || obj instanceof Uint8Array
90            || obj instanceof Uint8ClampedArray
91            || obj instanceof Uint16Array
92            || obj instanceof Uint32Array
93            || obj instanceof BigUint64Array)
94    }
95
96    internal override sliceInternal(begin: int, end: int): Buffer {
97        const byteLength = this.getByteLength()
98
99        const startIndex = normalizeIndex(begin, byteLength)
100        const endIndex = normalizeIndex(end, byteLength)
101
102        let resultLength = endIndex - startIndex
103        if (resultLength < 0) {
104            resultLength = 0
105        }
106
107        let result = new ArrayBuffer(resultLength);
108
109        if (resultLength == 0) return result
110        for (let i = 0; i < resultLength; ++i) {
111            result.set(i, this.data[startIndex + i])
112        }
113
114        return result
115    }
116
117    /**
118     * Creates a new ArrayBuffer with copy of bytes in range [begin;end)
119     *
120     * @param begin an inclusive index to start copying with
121     *
122     * @param end a last exclusive index to stop copying
123     *
124     * @returns data taken from current ArrayBuffer with respect to begin and end parameters
125     */
126    public slice(begin: number, end?: number): ArrayBuffer {
127        if (end == undefined) return this.slice(begin as int)
128        else return this.slice(begin as int, end as int)
129    }
130
131    /**
132     * Creates a new ArrayBuffer with copy of bytes in range [begin;end)
133     *
134     * @param begin an inclusive index to start copying with
135     *
136     * @param end a last exclusive index to stop copying
137     *
138     * @returns data taken from current ArrayBuffer with respect to begin and end parameters
139     */
140    public slice(begin: int, end?: int): ArrayBuffer {
141        if (end == undefined) return this.sliceInternal(begin, this.getByteLength()) as ArrayBuffer
142        else return this.sliceInternal(begin, end) as ArrayBuffer
143    }
144
145    /**
146     * Returns data at specified index.
147     * No such method in JS library, required for TypedArrays
148     *
149     * @param i index
150     *
151     * @returns byte at index
152     */
153    internal override at(i: int): byte {
154        return this.data[i]
155    }
156
157    /**
158     * Sets data at specified index.
159     * No such method in JS library, required for TypedArrays
160     *
161     * @param b new value
162     *
163     * @param i index
164     */
165    internal override set(i: int, b: byte) {
166        this.data[i] = b
167    }
168
169    internal override getByteLength(): int {
170        return this._byteLength;
171    }
172
173    get byteLength(): number {
174        return this._byteLength
175    }
176
177    /**
178     * Resizes the ArrayBuffer
179     *
180     * @param newLen new length
181     */
182    public resize(newLen : number): void {
183        /* return */ this.resize(newLen as int)
184    }
185
186    /**
187     * Resizes the ArrayBuffer
188     *
189     * @param newLen new length
190     */
191    //NOTE: return undefined
192    public resize(newLen : int): void {
193        let newData = new byte[newLen]
194        let size = min(newLen, this.data.length)
195        for (let i = 0; i < size; ++i) {
196            newData[i] = this.data[i]
197        }
198        this.data = newData
199        this._byteLength = newLen
200    }
201
202    public static native from(array: Object): ArrayBuffer;
203
204    private data: byte[]
205    /** Length in bytes */
206    private _byteLength: int
207}
208
209/**
210 * Internal non-movable memory of a SharedArrayBuffer
211 */
212class SharedMemory {
213    private data: byte[]
214    private waiterPtr: long
215
216    private constructor() {}
217
218    internal native static create(byteLength: int): SharedMemory;
219
220    internal at(i: int): byte {
221        return this.data[i]
222    }
223
224    internal set(i: int, value: byte): void {
225        this.data[i] = value
226    }
227
228    internal getByteLength(): int {
229        return this.data.length
230    }
231
232    internal native atomicAddI8(index: int, value: byte): byte;
233
234    internal native atomicAndI8(index: int, value: byte): byte;
235
236    internal native atomicCompareExchangeI8(index: int, expectedValue: byte, replacementValue: byte): byte;
237
238    internal native atomicExchangeI8(index: int, value: byte): byte;
239
240    internal native atomicLoadI8(index: int): byte;
241
242    internal native atomicOrI8(index: int, value: byte): byte;
243
244    internal native atomicStoreI8(index: int, value: byte): byte;
245
246    internal native atomicSubI8(index: int, value: byte): byte;
247
248    internal native atomicXorI8(index: int, value: byte): byte;
249
250    internal native atomicAddI16(index: int, value: short): short;
251
252    internal native atomicAndI16(index: int, value: short): short;
253
254    internal native atomicCompareExchangeI16(index: int, expectedValue: short, replacementValue: short): short;
255
256    internal native atomicExchangeI16(index: int, value: short): short;
257
258    internal native atomicLoadI16(index: int): short;
259
260    internal native atomicOrI16(index: int, value: short): short;
261
262    internal native atomicStoreI16(index: int, value: short): short;
263
264    internal native atomicSubI16(index: int, value: short): short;
265
266    internal native atomicXorI16(index: int, value: short): short;
267
268    internal native atomicAddI32(index: int, value: int): int;
269
270    internal native atomicAndI32(index: int, value: int): int;
271
272    internal native atomicCompareExchangeI32(index: int, expectedValue: int, replacementValue: int): int;
273
274    internal native atomicExchangeI32(index: int, value: int): int;
275
276    internal native atomicLoadI32(index: int): int;
277
278    internal native atomicOrI32(index: int, value: int): int;
279
280    internal native atomicStoreI32(index: int, value: int): int;
281
282    internal native atomicSubI32(index: int, value: int): int;
283
284    internal native atomicXorI32(index: int, value: int): int;
285
286    internal native atomicAddI64(index: int, value: long): long;
287
288    internal native atomicAndI64(index: int, value: long): long;
289
290    internal native atomicCompareExchangeI64(index: int, expectedValue: long, replacementValue: long): long;
291
292    internal native atomicExchangeI64(index: int, value: long): long;
293
294    internal native atomicLoadI64(index: int): long;
295
296    internal native atomicOrI64(index: int, value: long): long;
297
298    internal native atomicStoreI64(index: int, value: long): long;
299
300    internal native atomicSubI64(index: int, value: long): long;
301
302    internal native atomicXorI64(index: int, value: long): long;
303
304    internal native atomicAddU8(index: int, value: byte): byte;
305
306    internal native atomicAndU8(index: int, value: byte): byte;
307
308    internal native atomicCompareExchangeU8(index: int, expectedValue: byte, replacementValue: byte): byte;
309
310    internal native atomicExchangeU8(index: int, value: byte): byte;
311
312    internal native atomicLoadU8(index: int): byte;
313
314    internal native atomicOrU8(index: int, value: byte): byte;
315
316    internal native atomicStoreU8(index: int, value: byte): byte;
317
318    internal native atomicSubU8(index: int, value: byte): byte;
319
320    internal native atomicXorU8(index: int, value: byte): byte;
321
322    internal native atomicAddU16(index: int, value: short): short;
323
324    internal native atomicAndU16(index: int, value: short): short;
325
326    internal native atomicCompareExchangeU16(index: int, expectedValue: short, replacementValue: short): short;
327
328    internal native atomicExchangeU16(index: int, value: short): short;
329
330    internal native atomicLoadU16(index: int): short;
331
332    internal native atomicOrU16(index: int, value: short): short;
333
334    internal native atomicStoreU16(index: int, value: short): short;
335
336    internal native atomicSubU16(index: int, value: short): short;
337
338    internal native atomicXorU16(index: int, value: short): short;
339
340    internal native atomicAddU32(index: int, value: int): int;
341
342    internal native atomicAndU32(index: int, value: int): int;
343
344    internal native atomicCompareExchangeU32(index: int, expectedValue: int, replacementValue: int): int;
345
346    internal native atomicExchangeU32(index: int, value: int): int;
347
348    internal native atomicLoadU32(index: int): int;
349
350    internal native atomicOrU32(index: int, value: int): int;
351
352    internal native atomicStoreU32(index: int, value: int): int;
353
354    internal native atomicSubU32(index: int, value: int): int;
355
356    internal native atomicXorU32(index: int, value: int): int;
357
358    internal native atomicAddU64(index: int, value: long): long;
359
360    internal native atomicAndU64(index: int, value: long): long;
361
362    internal native atomicCompareExchangeU64(index: int, expectedValue: long, replacementValue: long): long;
363
364    internal native atomicExchangeU64(index: int, value: long): long;
365
366    internal native atomicLoadU64(index: int): long;
367
368    internal native atomicOrU64(index: int, value: long): long;
369
370    internal native atomicStoreU64(index: int, value: long): long;
371
372    internal native atomicSubU64(index: int, value: long): long;
373
374    internal native atomicXorU64(index: int, value: long): long;
375
376    internal native atomicWaitI32(byteOffset: int, value: int): int;
377
378    internal native atomicWaitI64(byteOffset: int, value: long): int;
379
380    internal native atomicTimedWaitI32(byteOffset: int, value: int, timeout: long): int;
381
382    internal native atomicTimedWaitI64(byteOffset: int, value: long, timeout: long): int;
383
384    internal native atomicNotify(byteOffset: int): int;
385
386    internal native atomicBoundedNotify(byteOffset: int, count: int): int;
387}
388
389export class SharedArrayBuffer extends Buffer {
390    private sharedMemory: SharedMemory
391
392    public constructor(byteLength: int) {
393        super()
394        this.sharedMemory = SharedMemory.create(byteLength)
395    }
396
397    internal getSharedMemory(): SharedMemory {
398        return this.sharedMemory
399    }
400
401    internal override getByteLength(): int {
402        return this.sharedMemory.getByteLength()
403    }
404
405    /**
406     * Returns data at specified index.
407     * No such method in JS library, required for TypedArrays
408     *
409     * @param i index
410     *
411     * @returns byte at index
412     */
413    internal override at(i: int): byte {
414        return this.sharedMemory.at(i)
415    }
416
417    /**
418     * Sets data at specified index.
419     * No such method in JS library, required for TypedArrays
420     *
421     * @param b new value
422     *
423     * @param i index
424     */
425    internal override set(i: int, b: byte) {
426        this.sharedMemory.set(i, b)
427    }
428
429    internal override sliceInternal(begin: int, end: int): Buffer {
430        // TODO(egor-porsev): code duplication
431        let byteLength = this.getByteLength()
432        if (begin < -byteLength) {
433            begin = 0
434        }
435        if (begin < 0) {
436            begin = byteLength + begin
437        }
438        if (begin >= byteLength) {
439            begin = byteLength
440        }
441
442        if (end < -byteLength) {
443            end = 0
444        }
445        if (end < 0) {
446            end = byteLength + end
447        }
448        if (end >= byteLength) {
449            end = byteLength
450        }
451
452        if (end <= begin) {
453            return new SharedArrayBuffer(0)
454        }
455
456        let len = end - begin
457        if (len < 0) {
458            len = 0
459        }
460        let res = new SharedArrayBuffer(len);
461        for (let i = 0; i < len; ++i) {
462            res.set(i, this.at(begin + i))
463        }
464        return res
465    }
466
467    /**
468     * Creates a new ArrayBuffer with copy of bytes in range [begin;end)
469     *
470     * @param begin an inclusive index to start copying with
471     *
472     * @param end a last exclusive index to stop copying
473     *
474     * @returns data taken from current ArrayBuffer with respect to begin and end parameters
475     */
476    public slice(begin: int, end: int): SharedArrayBuffer {
477        return this.sliceInternal(begin, end) as SharedArrayBuffer
478    }
479
480    public grow(newLength: int) {
481        // grow() cannot shrink the array and cannot expand it beyond 'maxByteLength'.
482        // Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer/grow
483        // This is because the underlying SharedMemory object is non-movable and cannot be reallocated.
484        //
485        // Possible implementation: when SharedArrayBuffer(curByteLength, { maxByteLength }) is constructed
486        // preallocate a SharedMemory object of size 'maxByteLength' but the user should observe the length to be 'curByteLength'.
487        // In other words, SharedMemory may be implemented as (pointer to data, current length, max capacity).
488        throw new Error("not implemented");
489    }
490}
491
492export type ArrayBufferLike = ArrayBuffer | SharedArrayBuffer
493