Skip to content

Commit b794620

Browse files
authored
Decouple Array<T> from ArrayBufferView (#1121)
1 parent 9876c3f commit b794620

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+8549
-5822
lines changed

lib/loader/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ function postInstantiate(baseModule, instance) {
162162
/** Allocates a new array in the module's memory and returns its retained pointer. */
163163
function __allocArray(id, values) {
164164
const info = getInfo(id);
165-
if (!(info & (ARRAYBUFFERVIEW | ARRAY))) throw Error("not an array: " + id + " @ " + info);
165+
if (!(info & (ARRAYBUFFERVIEW | ARRAY))) throw Error("not an array: " + id + ", flags= " + info);
166166
const align = getValueAlign(info);
167167
const length = values.length;
168168
const buf = alloc(length << align, ARRAYBUFFER_ID);
@@ -188,7 +188,7 @@ function postInstantiate(baseModule, instance) {
188188
const U32 = new Uint32Array(memory.buffer);
189189
const id = U32[arr + ID_OFFSET >>> 2];
190190
const info = getInfo(id);
191-
if (!(info & ARRAYBUFFERVIEW)) throw Error("not an array: " + id);
191+
if (!(info & (ARRAYBUFFERVIEW | ARRAY))) throw Error("not an array: " + id + ", flags=" + info);
192192
const align = getValueAlign(info);
193193
var buf = U32[arr + ARRAYBUFFERVIEW_DATASTART_OFFSET >>> 2];
194194
const length = info & ARRAY

lib/loader/tests/build/default.wasm

2 Bytes
Binary file not shown.

lib/loader/tests/build/legacy.wasm

2 Bytes
Binary file not shown.

src/builtins.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7910,7 +7910,10 @@ export function compileRTTI(compiler: Compiler): void {
79107910
if (instance !== abvInstance && instance.extends(abvPrototype)) {
79117911
let valueType = instance.getArrayValueType();
79127912
flags |= TypeinfoFlags.ARRAYBUFFERVIEW;
7913-
if (instance.extends(arrayPrototype)) flags |= TypeinfoFlags.ARRAY;
7913+
flags |= TypeinfoFlags.VALUE_ALIGN_0 * typeToRuntimeFlags(valueType);
7914+
} else if (instance.extends(arrayPrototype)) {
7915+
let valueType = instance.getArrayValueType();
7916+
flags |= TypeinfoFlags.ARRAY;
79147917
flags |= TypeinfoFlags.VALUE_ALIGN_0 * typeToRuntimeFlags(valueType);
79157918
} else if (instance.extends(setPrototype)) {
79167919
let typeArguments = assert(instance.getTypeArgumentsTo(setPrototype));

src/program.ts

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3751,25 +3751,37 @@ export class Class extends TypedElement {
37513751
getArrayValueType(): Type {
37523752
var current: Class = this;
37533753
var program = this.program;
3754+
var arrayPrototype = program.arrayPrototype;
3755+
if (this.extends(arrayPrototype)) {
3756+
return this.getTypeArgumentsTo(arrayPrototype)![0];
3757+
}
37543758
var abvInstance = program.arrayBufferViewInstance;
37553759
while (current.base !== abvInstance) {
37563760
current = assert(current.base);
37573761
}
37583762
var prototype = current.prototype;
3759-
if (prototype == program.arrayPrototype) {
3760-
return this.getTypeArgumentsTo(program.arrayPrototype)![0];
3761-
}
3762-
if (prototype == program.i8ArrayPrototype) return Type.i8;
3763-
if (prototype == program.i16ArrayPrototype) return Type.i16;
3764-
if (prototype == program.i32ArrayPrototype) return Type.i32;
3765-
if (prototype == program.i64ArrayPrototype) return Type.i64;
3766-
if (prototype == program.u8ArrayPrototype) return Type.u8;
3767-
if (prototype == program.u8ClampedArrayPrototype) return Type.u8;
3768-
if (prototype == program.u16ArrayPrototype) return Type.u16;
3769-
if (prototype == program.u32ArrayPrototype) return Type.u32;
3770-
if (prototype == program.u64ArrayPrototype) return Type.u64;
3771-
if (prototype == program.f32ArrayPrototype) return Type.f32;
3772-
if (prototype == program.f64ArrayPrototype) return Type.f64;
3763+
switch (prototype.name.charCodeAt(0)) {
3764+
case CharCode.F: {
3765+
if (prototype == program.f32ArrayPrototype) return Type.f32;
3766+
if (prototype == program.f64ArrayPrototype) return Type.f64;
3767+
break;
3768+
}
3769+
case CharCode.I: {
3770+
if (prototype == program.i8ArrayPrototype) return Type.i8;
3771+
if (prototype == program.i16ArrayPrototype) return Type.i16;
3772+
if (prototype == program.i32ArrayPrototype) return Type.i32;
3773+
if (prototype == program.i64ArrayPrototype) return Type.i64;
3774+
break;
3775+
}
3776+
case CharCode.U: {
3777+
if (prototype == program.u8ArrayPrototype) return Type.u8;
3778+
if (prototype == program.u8ClampedArrayPrototype) return Type.u8;
3779+
if (prototype == program.u16ArrayPrototype) return Type.u16;
3780+
if (prototype == program.u32ArrayPrototype) return Type.u32;
3781+
if (prototype == program.u64ArrayPrototype) return Type.u64;
3782+
break;
3783+
}
3784+
}
37733785
assert(false);
37743786
return Type.void;
37753787
}

std/assembly/array.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
import { BLOCK_MAXSIZE } from "./rt/common";
44
import { COMPARATOR, SORT } from "./util/sort";
5-
import { ArrayBufferView } from "./arraybuffer";
65
import { joinBooleanArray, joinIntegerArray, joinFloatArray, joinStringArray, joinReferenceArray } from "./util/string";
76
import { idof, isArray as builtin_isArray } from "./builtins";
87
import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH, E_EMPTYARRAY, E_HOLEYARRAY } from "./util/error";
98

109
/** Ensures that the given array has _at least_ the specified backing size. */
1110
function ensureSize(array: usize, minSize: usize, alignLog2: u32): void {
11+
// depends on the fact that Arrays mimic ArrayBufferView
1212
var oldCapacity = changetype<ArrayBufferView>(array).byteLength;
1313
if (minSize > <usize>oldCapacity >>> alignLog2) {
1414
if (minSize > BLOCK_MAXSIZE >>> alignLog2) throw new RangeError(E_INVALIDLENGTH);
@@ -24,12 +24,17 @@ function ensureSize(array: usize, minSize: usize, alignLog2: u32): void {
2424
}
2525
}
2626

27-
export class Array<T> extends ArrayBufferView {
27+
export class Array<T> {
2828
[key: number]: T;
2929

30-
// Implementing ArrayBufferView isn't strictly necessary here but is done to allow glue code
30+
// Mimicking ArrayBufferView isn't strictly necessary here but is done to allow glue code
3131
// to work with typed and normal arrays interchangeably. Technically, normal arrays do not need
32-
// `dataStart` (equals `data`) and `dataLength` (equals computed `data.byteLength`).
32+
// `dataStart` (equals `buffer`) and `byteLength` (equals computed `buffer.byteLength`), but the
33+
// block is 16 bytes anyway so it's fine to have a couple extra fields in there.
34+
35+
private buffer: ArrayBuffer;
36+
private dataStart: usize;
37+
private byteLength: i32;
3338

3439
// Also note that Array<T> with non-nullable T must guard against uninitialized null values
3540
// whenever an element is accessed. Otherwise, the compiler wouldn't be able to guarantee
@@ -49,7 +54,13 @@ export class Array<T> extends ArrayBufferView {
4954
}
5055

5156
constructor(length: i32 = 0) {
52-
super(length, alignof<T>());
57+
if (<u32>length > <u32>BLOCK_MAXSIZE >>> alignof<T>()) throw new RangeError(E_INVALIDLENGTH);
58+
var bufferSize = <usize>length << alignof<T>();
59+
var buffer = __alloc(bufferSize, idof<ArrayBuffer>());
60+
memory.fill(buffer, 0, bufferSize);
61+
this.buffer = changetype<ArrayBuffer>(buffer); // retains
62+
this.dataStart = buffer;
63+
this.byteLength = <i32>bufferSize;
5364
this.length_ = length;
5465
}
5566

@@ -498,6 +509,6 @@ export class Array<T> extends ArrayBufferView {
498509
cur += sizeof<usize>();
499510
}
500511
}
501-
// automatically visits ArrayBufferView (.buffer) next
512+
__visit(changetype<usize>(this.buffer), cookie);
502513
}
503514
}

tests/compiler/assert-nonnull.optimized.wat

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
if
8686
i32.const 1104
8787
i32.const 1168
88-
i32.const 93
88+
i32.const 104
8989
i32.const 41
9090
call $~lib/builtins/abort
9191
unreachable
@@ -98,7 +98,7 @@
9898
if
9999
i32.const 1216
100100
i32.const 1168
101-
i32.const 97
101+
i32.const 108
102102
i32.const 39
103103
call $~lib/builtins/abort
104104
unreachable
@@ -113,7 +113,7 @@
113113
if
114114
i32.const 1104
115115
i32.const 1168
116-
i32.const 93
116+
i32.const 104
117117
i32.const 41
118118
call $~lib/builtins/abort
119119
unreachable

tests/compiler/assert-nonnull.untouched.wat

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@
122122
if
123123
i32.const 96
124124
i32.const 160
125-
i32.const 93
125+
i32.const 104
126126
i32.const 41
127127
call $~lib/builtins/abort
128128
unreachable
@@ -138,7 +138,7 @@
138138
call $~lib/rt/stub/__release
139139
i32.const 208
140140
i32.const 160
141-
i32.const 97
141+
i32.const 108
142142
i32.const 39
143143
call $~lib/builtins/abort
144144
unreachable
@@ -188,7 +188,7 @@
188188
if
189189
i32.const 96
190190
i32.const 160
191-
i32.const 93
191+
i32.const 104
192192
i32.const 41
193193
call $~lib/builtins/abort
194194
unreachable

tests/compiler/builtins.optimized.wat

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -605,8 +605,8 @@
605605
f64.const 0
606606
f64.const 0
607607
f64.const 12
608-
f64.const 24
609-
f64.const 24
608+
f64.const 25
609+
f64.const 25
610610
call $~lib/builtins/trace
611611
i32.const 1216
612612
i32.const 1216

tests/compiler/builtins.untouched.wat

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,9 +1563,9 @@
15631563
local.set $1
15641564
i32.const 12
15651565
local.set $6
1566-
i32.const 24
1566+
i32.const 25
15671567
local.set $7
1568-
i32.const 24
1568+
i32.const 25
15691569
local.set $8
15701570
i32.const 128
15711571
i32.const 5

tests/compiler/class.optimized.wat

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
(type $i32_i32_=>_i32 (func (param i32 i32) (result i32)))
55
(memory $0 1)
66
(data (i32.const 1024) "\1c\00\00\00\01\00\00\00\01\00\00\00\1c\00\00\00I\00n\00v\00a\00l\00i\00d\00 \00l\00e\00n\00g\00t\00h")
7-
(data (i32.const 1072) "&\00\00\00\01\00\00\00\01\00\00\00&\00\00\00~\00l\00i\00b\00/\00a\00r\00r\00a\00y\00b\00u\00f\00f\00e\00r\00.\00t\00s")
7+
(data (i32.const 1072) "\1a\00\00\00\01\00\00\00\01\00\00\00\1a\00\00\00~\00l\00i\00b\00/\00a\00r\00r\00a\00y\00.\00t\00s")
88
(global $~lib/rt/stub/startOffset (mut i32) (i32.const 0))
99
(global $~lib/rt/stub/offset (mut i32) (i32.const 0))
1010
(export "memory" (memory $0))
@@ -123,23 +123,14 @@
123123
i32.const 4
124124
i32.const 4
125125
call $~lib/rt/stub/__alloc
126-
i32.const 16
127-
i32.const 5
128-
call $~lib/rt/stub/__alloc
129-
local.set $0
130126
i32.const 0
131127
i32.const 0
132128
call $~lib/rt/stub/__alloc
133129
local.set $1
134-
local.get $0
135-
i32.eqz
136-
if
137-
i32.const 12
138-
i32.const 2
139-
call $~lib/rt/stub/__alloc
140-
local.set $0
141-
end
142-
local.get $0
130+
i32.const 16
131+
i32.const 5
132+
call $~lib/rt/stub/__alloc
133+
local.tee $0
143134
i32.const 0
144135
i32.store
145136
local.get $0
@@ -149,6 +140,9 @@
149140
i32.const 0
150141
i32.store offset=8
151142
local.get $0
143+
i32.const 0
144+
i32.store offset=12
145+
local.get $0
152146
i32.load
153147
drop
154148
local.get $0
@@ -164,15 +158,12 @@
164158
i32.const 0
165159
i32.store offset=12
166160
local.get $0
167-
i32.const 0
168-
i32.store offset=12
169-
local.get $0
170161
i32.store
171162
)
172163
(func $~start (; 3 ;)
173-
i32.const 1136
164+
i32.const 1120
174165
global.set $~lib/rt/stub/startOffset
175-
i32.const 1136
166+
i32.const 1120
176167
global.set $~lib/rt/stub/offset
177168
)
178169
)

0 commit comments

Comments
 (0)