Skip to content

Commit bd78683

Browse files
MaxGraeydcodeIO
authored andcommitted
Refactor ArrayBufferView (#865)
1 parent f1b13a4 commit bd78683

40 files changed

+2845
-4311
lines changed

src/compiler.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,9 +1592,9 @@ export class Compiler extends DiagnosticEmitter {
15921592

15931593
var bufferAddress32 = i64_low(bufferSegment.offset) + runtimeHeaderSize;
15941594
assert(!program.options.isWasm64); // TODO
1595-
assert(arrayInstance.writeField("data", bufferAddress32, buf, runtimeHeaderSize));
1595+
assert(arrayInstance.writeField("buffer", bufferAddress32, buf, runtimeHeaderSize));
15961596
assert(arrayInstance.writeField("dataStart", bufferAddress32, buf, runtimeHeaderSize));
1597-
assert(arrayInstance.writeField("dataLength", bufferLength, buf, runtimeHeaderSize));
1597+
assert(arrayInstance.writeField("byteLength", bufferLength, buf, runtimeHeaderSize));
15981598
assert(arrayInstance.writeField("length_", arrayLength, buf, runtimeHeaderSize));
15991599

16001600
return this.addMemorySegment(buf);

std/assembly/array.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,25 @@
22

33
import { BLOCK_MAXSIZE } from "./rt/common";
44
import { COMPARATOR, SORT } from "./util/sort";
5-
import { ArrayBuffer, ArrayBufferView } from "./arraybuffer";
5+
import { ArrayBufferView } from "./arraybuffer";
66
import { joinBooleanArray, joinIntegerArray, joinFloatArray, joinStringArray, joinArrays, joinObjectArray } from "./util/string";
77
import { idof, isArray as builtin_isArray } from "./builtins";
88
import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH, E_EMPTYARRAY, E_HOLEYARRAY } from "./util/error";
99

1010
/** Ensures that the given array has _at least_ the specified backing size. */
1111
function ensureSize(array: usize, minSize: usize, alignLog2: u32): void {
12-
var oldCapacity = changetype<ArrayBufferView>(array).dataLength;
13-
if (minSize > oldCapacity >>> alignLog2) {
12+
var oldCapacity = changetype<ArrayBufferView>(array).byteLength;
13+
if (minSize > <usize>oldCapacity >>> alignLog2) {
1414
if (minSize > BLOCK_MAXSIZE >>> alignLog2) throw new RangeError(E_INVALIDLENGTH);
15-
let oldData = changetype<usize>(changetype<ArrayBufferView>(array).data);
15+
let oldData = changetype<usize>(changetype<ArrayBufferView>(array).buffer);
1616
let newCapacity = minSize << alignLog2;
1717
let newData = __realloc(oldData, newCapacity);
1818
memory.fill(newData + oldCapacity, 0, newCapacity - oldCapacity);
1919
if (newData !== oldData) { // oldData has been free'd
20-
store<usize>(changetype<usize>(array), __retain(newData), offsetof<ArrayBufferView>("data"));
21-
changetype<ArrayBufferView>(array).dataStart = newData;
20+
store<usize>(array, __retain(newData), offsetof<ArrayBufferView>("buffer"));
21+
store<usize>(array, newData, offsetof<ArrayBufferView>("dataStart"));
2222
}
23-
changetype<ArrayBufferView>(array).dataLength = <u32>newCapacity;
23+
store<u32>(array, newCapacity, offsetof<ArrayBufferView>("byteLength"));
2424
}
2525
}
2626

@@ -53,10 +53,6 @@ export class Array<T> extends ArrayBufferView {
5353
this.length_ = length;
5454
}
5555

56-
@unsafe get buffer(): ArrayBuffer {
57-
return this.data;
58-
}
59-
6056
get length(): i32 {
6157
return this.length_;
6258
}
@@ -492,6 +488,6 @@ export class Array<T> extends ArrayBufferView {
492488
cur += sizeof<usize>();
493489
}
494490
}
495-
// automatically visits ArrayBufferView (.data) next
491+
// automatically visits ArrayBufferView (.buffer) next
496492
}
497493
}

std/assembly/arraybuffer.ts

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,27 @@ import { E_INVALIDLENGTH } from "./util/error";
66

77
export abstract class ArrayBufferView {
88

9-
@unsafe data: ArrayBuffer;
10-
@unsafe dataStart: usize;
11-
@unsafe dataLength: u32;
12-
13-
protected constructor(length: i32, alignLog2: i32) {
14-
if (<u32>length > <u32>BLOCK_MAXSIZE >>> alignLog2) throw new RangeError(E_INVALIDLENGTH);
15-
var buffer = __alloc(length = length << alignLog2, idof<ArrayBuffer>());
16-
memory.fill(buffer, 0, <usize>length);
17-
this.data = changetype<ArrayBuffer>(buffer); // retains
18-
this.dataStart = buffer;
19-
this.dataLength = length;
20-
}
9+
readonly buffer: ArrayBuffer;
10+
@unsafe readonly dataStart: usize;
11+
readonly byteLength: i32;
2112

2213
get byteOffset(): i32 {
23-
return <i32>(this.dataStart - changetype<usize>(this.data));
24-
}
25-
26-
get byteLength(): i32 {
27-
return this.dataLength;
14+
return <i32>(this.dataStart - changetype<usize>(this.buffer));
2815
}
2916

3017
get length(): i32 {
3118
ERROR("missing implementation: subclasses must implement ArrayBufferView#length");
3219
return unreachable();
3320
}
21+
22+
protected constructor(length: i32, alignLog2: i32) {
23+
if (<u32>length > <u32>BLOCK_MAXSIZE >>> alignLog2) throw new RangeError(E_INVALIDLENGTH);
24+
var buffer = __alloc(length = length << alignLog2, idof<ArrayBuffer>());
25+
memory.fill(buffer, 0, <usize>length);
26+
this.buffer = changetype<ArrayBuffer>(buffer); // retains
27+
this.dataStart = buffer;
28+
this.byteLength = length;
29+
}
3430
}
3531

3632
@sealed export class ArrayBuffer {

std/assembly/dataview.ts

Lines changed: 29 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,13 @@ import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH } from "./util/error";
66

77
export class DataView {
88

9-
private data: ArrayBuffer;
10-
private dataStart: usize;
11-
private dataLength: i32;
9+
readonly buffer: ArrayBuffer;
10+
@unsafe readonly dataStart: usize;
11+
readonly byteLength: i32;
12+
13+
get byteOffset(): i32 {
14+
return <i32>(this.dataStart - changetype<usize>(this.buffer));
15+
}
1216

1317
constructor(
1418
buffer: ArrayBuffer,
@@ -19,28 +23,15 @@ export class DataView {
1923
i32(<u32>byteLength > <u32>BLOCK_MAXSIZE) |
2024
i32(<u32>byteOffset + byteLength > <u32>buffer.byteLength)
2125
) throw new RangeError(E_INVALIDLENGTH);
22-
this.data = buffer; // retains
26+
this.buffer = buffer; // retains
2327
var dataStart = changetype<usize>(buffer) + <usize>byteOffset;
2428
this.dataStart = dataStart;
25-
this.dataLength = byteLength;
26-
}
27-
28-
get buffer(): ArrayBuffer {
29-
return this.data;
30-
}
31-
32-
get byteOffset(): i32 {
33-
return <i32>(this.dataStart - changetype<usize>(this.data));
34-
}
35-
36-
get byteLength(): i32 {
37-
return this.dataLength;
29+
this.byteLength = byteLength;
3830
}
3931

4032
getFloat32(byteOffset: i32, littleEndian: boolean = false): f32 {
4133
if (
42-
i32(byteOffset < 0) |
43-
i32(byteOffset + 4 > this.dataLength)
34+
(byteOffset >>> 31) | i32(byteOffset + 4 > this.byteLength)
4435
) throw new RangeError(E_INDEXOUTOFRANGE);
4536
return littleEndian
4637
? load<f32>(this.dataStart + <usize>byteOffset)
@@ -53,8 +44,7 @@ export class DataView {
5344

5445
getFloat64(byteOffset: i32, littleEndian: boolean = false): f64 {
5546
if (
56-
i32(byteOffset < 0) |
57-
i32(byteOffset + 8 > this.dataLength)
47+
(byteOffset >>> 31) | i32(byteOffset + 8 > this.byteLength)
5848
) throw new RangeError(E_INDEXOUTOFRANGE);
5949
return littleEndian
6050
? load<f64>(this.dataStart + <usize>byteOffset)
@@ -66,107 +56,97 @@ export class DataView {
6656
}
6757

6858
getInt8(byteOffset: i32): i8 {
69-
if (<u32>byteOffset >= <u32>this.dataLength) throw new RangeError(E_INDEXOUTOFRANGE);
59+
if (<u32>byteOffset >= <u32>this.byteLength) throw new RangeError(E_INDEXOUTOFRANGE);
7060
return load<i8>(this.dataStart + <usize>byteOffset);
7161
}
7262

7363
getInt16(byteOffset: i32, littleEndian: boolean = false): i16 {
7464
if (
75-
i32(byteOffset < 0) |
76-
i32(byteOffset + 2 > this.dataLength)
65+
(byteOffset >>> 31) | i32(byteOffset + 2 > this.byteLength)
7766
) throw new RangeError(E_INDEXOUTOFRANGE);
7867
var result: i16 = load<i16>(this.dataStart + <usize>byteOffset);
7968
return littleEndian ? result : bswap<i16>(result);
8069
}
8170

8271
getInt32(byteOffset: i32, littleEndian: boolean = false): i32 {
8372
if (
84-
i32(byteOffset < 0) |
85-
i32(byteOffset + 4 > this.dataLength)
73+
(byteOffset >>> 31) | i32(byteOffset + 4 > this.byteLength)
8674
) throw new RangeError(E_INDEXOUTOFRANGE);
8775
var result: i32 = load<i32>(this.dataStart + <usize>byteOffset);
8876
return littleEndian ? result : bswap<i32>(result);
8977
}
9078

9179
getUint8(byteOffset: i32): u8 {
92-
if (<u32>byteOffset >= <u32>this.dataLength) throw new RangeError(E_INDEXOUTOFRANGE);
80+
if (<u32>byteOffset >= <u32>this.byteLength) throw new RangeError(E_INDEXOUTOFRANGE);
9381
return load<u8>(this.dataStart + <usize>byteOffset);
9482
}
9583

9684
getUint16(byteOffset: i32, littleEndian: boolean = false): u16 {
9785
if (
98-
i32(byteOffset < 0) |
99-
i32(byteOffset + 2 > this.dataLength)
86+
(byteOffset >>> 31) | i32(byteOffset + 2 > this.byteLength)
10087
) throw new RangeError(E_INDEXOUTOFRANGE);
10188
var result: u16 = load<u16>(this.dataStart + <usize>byteOffset);
10289
return littleEndian ? result : bswap<u16>(result);
10390
}
10491

10592
getUint32(byteOffset: i32, littleEndian: boolean = false): u32 {
10693
if (
107-
i32(byteOffset < 0) |
108-
i32(byteOffset + 4 > this.dataLength)
94+
(byteOffset >>> 31) | i32(byteOffset + 4 > this.byteLength)
10995
) throw new RangeError(E_INDEXOUTOFRANGE);
11096
var result: u32 = load<u32>(this.dataStart + <usize>byteOffset);
11197
return littleEndian ? result : bswap<u32>(result);
11298
}
11399

114100
setFloat32(byteOffset: i32, value: f32, littleEndian: boolean = false): void {
115101
if (
116-
i32(byteOffset < 0) |
117-
i32(byteOffset + 4 > this.dataLength)
102+
(byteOffset >>> 31) | i32(byteOffset + 4 > this.byteLength)
118103
) throw new RangeError(E_INDEXOUTOFRANGE);
119104
if (littleEndian) store<f32>(this.dataStart + <usize>byteOffset, value);
120105
else store<u32>(this.dataStart + <usize>byteOffset, bswap<u32>(reinterpret<u32>(value)));
121106
}
122107

123108
setFloat64(byteOffset: i32, value: f64, littleEndian: boolean = false): void {
124109
if (
125-
i32(byteOffset < 0) |
126-
i32(byteOffset + 8 > this.dataLength)
110+
(byteOffset >>> 31) | i32(byteOffset + 8 > this.byteLength)
127111
) throw new RangeError(E_INDEXOUTOFRANGE);
128112
if (littleEndian) store<f64>(this.dataStart + <usize>byteOffset, value);
129113
else store<u64>(this.dataStart + <usize>byteOffset, bswap<u64>(reinterpret<u64>(value)));
130114
}
131115

132116
setInt8(byteOffset: i32, value: i8): void {
133-
if (<u32>byteOffset >= <u32>this.dataLength) throw new RangeError(E_INDEXOUTOFRANGE);
117+
if (<u32>byteOffset >= <u32>this.byteLength) throw new RangeError(E_INDEXOUTOFRANGE);
134118
store<i8>(this.dataStart + <usize>byteOffset, value);
135119
}
136120

137121
setInt16(byteOffset: i32, value: i16, littleEndian: boolean = false): void {
138122
if (
139-
i32(byteOffset < 0) |
140-
i32(byteOffset + 2 > this.dataLength)
123+
(byteOffset >>> 31) | i32(byteOffset + 2 > this.byteLength)
141124
) throw new RangeError(E_INDEXOUTOFRANGE);
142125
store<i16>(this.dataStart + <usize>byteOffset, littleEndian ? value : bswap<i16>(value));
143126
}
144127

145128
setInt32(byteOffset: i32, value: i32, littleEndian: boolean = false): void {
146129
if (
147-
i32(byteOffset < 0) |
148-
i32(byteOffset + 4 > this.dataLength)
130+
(byteOffset >>> 31) | i32(byteOffset + 4 > this.byteLength)
149131
) throw new RangeError(E_INDEXOUTOFRANGE);
150132
store<i32>(this.dataStart + <usize>byteOffset, littleEndian ? value : bswap<i32>(value));
151133
}
152134

153135
setUint8(byteOffset: i32, value: u8): void {
154-
if (<u32>byteOffset >= <u32>this.dataLength) throw new RangeError(E_INDEXOUTOFRANGE);
136+
if (<u32>byteOffset >= <u32>this.byteLength) throw new RangeError(E_INDEXOUTOFRANGE);
155137
store<u8>(this.dataStart + <usize>byteOffset, value);
156138
}
157139

158140
setUint16(byteOffset: i32, value: u16, littleEndian: boolean = false): void {
159141
if (
160-
i32(byteOffset < 0) |
161-
i32(byteOffset + 2 > this.dataLength)
142+
(byteOffset >>> 31) | i32(byteOffset + 2 > this.byteLength)
162143
) throw new RangeError(E_INDEXOUTOFRANGE);
163144
store<u16>(this.dataStart + <usize>byteOffset, littleEndian ? value : bswap<u16>(value));
164145
}
165146

166147
setUint32(byteOffset: i32, value: u32, littleEndian: boolean = false): void {
167148
if (
168-
i32(byteOffset < 0) |
169-
i32(byteOffset + 4 > this.dataLength)
149+
(byteOffset >>> 31) | i32(byteOffset + 4 > this.byteLength)
170150
) throw new RangeError(E_INDEXOUTOFRANGE);
171151
store<u32>(this.dataStart + <usize>byteOffset, littleEndian ? value : bswap<u32>(value));
172152
}
@@ -175,34 +155,30 @@ export class DataView {
175155

176156
getInt64(byteOffset: i32, littleEndian: boolean = false): i64 {
177157
if (
178-
i32(byteOffset < 0) |
179-
i32(byteOffset + 8 > this.dataLength)
158+
(byteOffset >>> 31) | i32(byteOffset + 8 > this.byteLength)
180159
) throw new RangeError(E_INDEXOUTOFRANGE);
181160
var result: i64 = load<i64>(this.dataStart + <usize>byteOffset);
182161
return littleEndian ? result : bswap<i64>(result);
183162
}
184163

185164
getUint64(byteOffset: i32, littleEndian: boolean = false): u64 {
186165
if (
187-
i32(byteOffset < 0) |
188-
i32(byteOffset + 8 > this.dataLength)
166+
(byteOffset >>> 31) | i32(byteOffset + 8 > this.byteLength)
189167
) throw new RangeError(E_INDEXOUTOFRANGE);
190168
var result = load<u64>(this.dataStart + <usize>byteOffset);
191169
return littleEndian ? result : bswap<u64>(result);
192170
}
193171

194172
setInt64(byteOffset: i32, value: i64, littleEndian: boolean = false): void {
195173
if (
196-
i32(byteOffset < 0) |
197-
i32(byteOffset + 8 > this.dataLength)
174+
(byteOffset >>> 31) | i32(byteOffset + 8 > this.byteLength)
198175
) throw new RangeError(E_INDEXOUTOFRANGE);
199176
store<i64>(this.dataStart + <usize>byteOffset, littleEndian ? value : bswap<i64>(value));
200177
}
201178

202179
setUint64(byteOffset: i32, value: u64, littleEndian: boolean = false): void {
203180
if (
204-
i32(byteOffset < 0) |
205-
i32(byteOffset + 8 > this.dataLength)
181+
(byteOffset >>> 31) | i32(byteOffset + 8 > this.byteLength)
206182
) throw new RangeError(E_INDEXOUTOFRANGE);
207183
store<u64>(this.dataStart + <usize>byteOffset, littleEndian ? value : bswap<u64>(value));
208184
}

std/assembly/index.d.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,8 +1154,7 @@ interface ArrayLike<T> {
11541154
}
11551155

11561156
/** Interface for a typed view on an array buffer. */
1157-
interface ArrayBufferView<T> {
1158-
[key: number]: T;
1157+
interface ArrayBufferView {
11591158
/** The {@link ArrayBuffer} referenced by this view. */
11601159
readonly buffer: ArrayBuffer;
11611160
/** The offset in bytes from the start of the referenced {@link ArrayBuffer}. */
@@ -1165,12 +1164,12 @@ interface ArrayBufferView<T> {
11651164
}
11661165

11671166
/* @internal */
1168-
declare abstract class TypedArray<T> implements ArrayBufferView<T> {
1167+
declare abstract class TypedArray<T> implements ArrayBufferView {
11691168
[key: number]: T;
11701169
/** Number of bytes per element. */
11711170
static readonly BYTES_PER_ELEMENT: usize;
11721171
/** Wrap an ArrayBuffer */
1173-
static wrap(buffer: ArrayBuffer, byteOffset?: i32, length?: i32): TypedArray<T>;
1172+
static wrap(buffer: ArrayBuffer, byteOffset?: i32, length?: i32): ArrayBufferView;
11741173
/** Constructs a new typed array. */
11751174
constructor(length: i32);
11761175
/** The {@link ArrayBuffer} referenced by this view. */

std/assembly/rt.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ export function __allocArray(length: i32, alignLog2: usize, id: u32, data: usize
4141
var array = __alloc(offsetof<i32[]>(), id);
4242
var bufferSize = <usize>length << alignLog2;
4343
var buffer = __alloc(bufferSize, idof<ArrayBuffer>());
44-
store<usize>(array, __retain(buffer), offsetof<ArrayBufferView>("data"));
45-
changetype<ArrayBufferView>(array).dataStart = buffer;
46-
changetype<ArrayBufferView>(array).dataLength = bufferSize;
44+
store<usize>(array, __retain(buffer), offsetof<ArrayBufferView>("buffer"));
45+
store<usize>(array, buffer, offsetof<ArrayBufferView>("dataStart"));
46+
store<u32>(array, bufferSize, offsetof<ArrayBufferView>("byteLength"));
4747
store<i32>(changetype<usize>(array), length, offsetof<i32[]>("length_"));
4848
if (data) memory.copy(buffer, data, bufferSize);
4949
return array;

0 commit comments

Comments
 (0)