Skip to content

Commit ca02a7d

Browse files
authored
fix: Fix growing factor for capacity in Array (AssemblyScript#1841)
1 parent 802a233 commit ca02a7d

36 files changed

+2185
-1228
lines changed

std/assembly/array.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,28 @@ import { joinBooleanArray, joinIntegerArray, joinFloatArray, joinStringArray, jo
66
import { idof, isArray as builtin_isArray } from "./builtins";
77
import { E_INDEXOUTOFRANGE, E_INVALIDLENGTH, E_ILLEGALGENTYPE, E_EMPTYARRAY, E_HOLEYARRAY } from "./util/error";
88

9+
// @ts-ignore: decorator
10+
@inline @lazy const MIN_SIZE: usize = 8;
11+
912
/** Ensures that the given array has _at least_ the specified backing size. */
10-
function ensureSize(array: usize, minSize: usize, alignLog2: u32): void {
11-
// depends on the fact that Arrays mimic ArrayBufferView
12-
var oldCapacity = changetype<ArrayBufferView>(array).byteLength;
13-
if (minSize > <usize>oldCapacity >>> alignLog2) {
14-
if (minSize > BLOCK_MAXSIZE >>> alignLog2) throw new RangeError(E_INVALIDLENGTH);
13+
function ensureCapacity(array: usize, newSize: usize, alignLog2: u32, canGrow: bool = true): void {
14+
// Depends on the fact that Arrays mimic ArrayBufferView
15+
var oldCapacity = <usize>changetype<ArrayBufferView>(array).byteLength;
16+
if (newSize > oldCapacity >>> alignLog2) {
17+
if (newSize > BLOCK_MAXSIZE >>> alignLog2) throw new RangeError(E_INVALIDLENGTH);
1518
let oldData = changetype<usize>(changetype<ArrayBufferView>(array).buffer);
16-
let newCapacity = minSize << alignLog2;
19+
// Grows old capacity by factor of two.
20+
// Make sure we don't reach BLOCK_MAXSIZE for new growed capacity.
21+
let newCapacity = max(newSize, MIN_SIZE) << alignLog2;
22+
if (canGrow) newCapacity = max(min(oldCapacity << 1, BLOCK_MAXSIZE), newCapacity);
1723
let newData = __renew(oldData, newCapacity);
1824
memory.fill(newData + oldCapacity, 0, newCapacity - oldCapacity);
1925
if (newData !== oldData) { // oldData has been free'd
2026
store<usize>(array, newData, offsetof<ArrayBufferView>("buffer"));
2127
store<usize>(array, newData, offsetof<ArrayBufferView>("dataStart"));
2228
__link(array, changetype<usize>(newData), false);
2329
}
24-
store<u32>(array, newCapacity, offsetof<ArrayBufferView>("byteLength"));
30+
store<u32>(array, <u32>newCapacity, offsetof<ArrayBufferView>("byteLength"));
2531
}
2632
}
2733

@@ -56,7 +62,8 @@ export class Array<T> {
5662

5763
constructor(length: i32 = 0) {
5864
if (<u32>length > <u32>BLOCK_MAXSIZE >>> alignof<T>()) throw new RangeError(E_INVALIDLENGTH);
59-
var bufferSize = <usize>length << alignof<T>();
65+
// reserve capacity for at least MIN_SIZE elements
66+
var bufferSize = <usize>max(length, MIN_SIZE) << alignof<T>();
6067
var buffer = changetype<ArrayBuffer>(__new(bufferSize, idof<ArrayBuffer>()));
6168
memory.fill(changetype<usize>(buffer), 0, bufferSize);
6269
this.buffer = buffer; // links
@@ -70,7 +77,7 @@ export class Array<T> {
7077
}
7178

7279
set length(newLength: i32) {
73-
ensureSize(changetype<usize>(this), newLength, alignof<T>());
80+
ensureCapacity(changetype<usize>(this), newLength, alignof<T>(), false);
7481
this.length_ = newLength;
7582
}
7683

@@ -106,7 +113,7 @@ export class Array<T> {
106113
@operator("[]=") private __set(index: i32, value: T): void {
107114
if (<u32>index >= <u32>this.length_) {
108115
if (index < 0) throw new RangeError(E_INDEXOUTOFRANGE);
109-
ensureSize(changetype<usize>(this), index + 1, alignof<T>());
116+
ensureCapacity(changetype<usize>(this), index + 1, alignof<T>());
110117
this.length_ = index + 1;
111118
}
112119
this.__uset(index, value);
@@ -204,7 +211,7 @@ export class Array<T> {
204211
push(value: T): i32 {
205212
var length = this.length_;
206213
var newLength = length + 1;
207-
ensureSize(changetype<usize>(this), newLength, alignof<T>());
214+
ensureCapacity(changetype<usize>(this), newLength, alignof<T>());
208215
if (isManaged<T>()) {
209216
store<usize>(this.dataStart + (<usize>length << alignof<T>()), changetype<usize>(value));
210217
__link(changetype<usize>(this), changetype<usize>(value), true);
@@ -353,7 +360,7 @@ export class Array<T> {
353360

354361
unshift(value: T): i32 {
355362
var newLength = this.length_ + 1;
356-
ensureSize(changetype<usize>(this), newLength, alignof<T>());
363+
ensureCapacity(changetype<usize>(this), newLength, alignof<T>());
357364
var dataStart = this.dataStart;
358365
memory.copy(
359366
dataStart + sizeof<T>(),

tests/compiler/assert-nonnull.optimized.wat

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
if
5959
i32.const 1184
6060
i32.const 1248
61-
i32.const 92
61+
i32.const 99
6262
i32.const 42
6363
call $~lib/builtins/abort
6464
unreachable
@@ -212,7 +212,7 @@
212212
if
213213
i32.const 1184
214214
i32.const 1248
215-
i32.const 92
215+
i32.const 99
216216
i32.const 42
217217
call $~lib/builtins/abort
218218
unreachable
@@ -228,7 +228,7 @@
228228
if
229229
i32.const 1296
230230
i32.const 1248
231-
i32.const 96
231+
i32.const 103
232232
i32.const 40
233233
call $~lib/builtins/abort
234234
unreachable

tests/compiler/assert-nonnull.untouched.wat

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@
309309
if
310310
i32.const 160
311311
i32.const 224
312-
i32.const 92
312+
i32.const 99
313313
i32.const 42
314314
call $~lib/builtins/abort
315315
unreachable
@@ -334,7 +334,7 @@
334334
if
335335
i32.const 272
336336
i32.const 224
337-
i32.const 96
337+
i32.const 103
338338
i32.const 40
339339
call $~lib/builtins/abort
340340
unreachable
@@ -365,7 +365,7 @@
365365
if
366366
i32.const 160
367367
i32.const 224
368-
i32.const 92
368+
i32.const 99
369369
i32.const 42
370370
call $~lib/builtins/abort
371371
unreachable

tests/compiler/class.optimized.wat

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1820,13 +1820,13 @@
18201820
i32.const 0
18211821
i32.store offset=12
18221822
global.get $~lib/memory/__stack_pointer
1823-
i32.const 0
1823+
i32.const 32
18241824
i32.const 0
18251825
call $~lib/rt/itcms/__new
18261826
local.tee $1
18271827
i32.store offset=4
18281828
local.get $1
1829-
i32.const 0
1829+
i32.const 32
18301830
call $~lib/memory/memory.fill
18311831
local.get $0
18321832
local.get $1
@@ -1835,7 +1835,7 @@
18351835
local.get $1
18361836
i32.store offset=4
18371837
local.get $0
1838-
i32.const 0
1838+
i32.const 32
18391839
i32.store offset=8
18401840
local.get $0
18411841
i32.const 0

tests/compiler/class.untouched.wat

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2683,6 +2683,8 @@
26832683
(local $2 i32)
26842684
(local $3 i32)
26852685
(local $4 i32)
2686+
(local $5 i32)
2687+
(local $6 i32)
26862688
global.get $~lib/memory/__stack_pointer
26872689
i32.const 8
26882690
i32.sub
@@ -2721,44 +2723,51 @@
27212723
if
27222724
i32.const 432
27232725
i32.const 480
2724-
i32.const 58
2726+
i32.const 64
27252727
i32.const 60
27262728
call $~lib/builtins/abort
27272729
unreachable
27282730
end
27292731
local.get $1
2732+
local.tee $2
2733+
i32.const 8
2734+
local.tee $3
2735+
local.get $2
2736+
local.get $3
2737+
i32.gt_s
2738+
select
27302739
i32.const 2
27312740
i32.shl
2732-
local.set $2
2741+
local.set $4
27332742
global.get $~lib/memory/__stack_pointer
2734-
local.get $2
2743+
local.get $4
27352744
i32.const 0
27362745
call $~lib/rt/itcms/__new
2737-
local.tee $3
2746+
local.tee $5
27382747
i32.store offset=4
2739-
local.get $3
2748+
local.get $5
27402749
i32.const 0
2741-
local.get $2
2750+
local.get $4
27422751
call $~lib/memory/memory.fill
27432752
local.get $0
2744-
local.get $3
2753+
local.get $5
27452754
call $~lib/array/Array<i32>#set:buffer
27462755
local.get $0
2747-
local.get $3
2756+
local.get $5
27482757
call $~lib/array/Array<i32>#set:dataStart
27492758
local.get $0
2750-
local.get $2
2759+
local.get $4
27512760
call $~lib/array/Array<i32>#set:byteLength
27522761
local.get $0
27532762
local.get $1
27542763
call $~lib/array/Array<i32>#set:length_
27552764
local.get $0
2756-
local.set $4
2765+
local.set $6
27572766
global.get $~lib/memory/__stack_pointer
27582767
i32.const 8
27592768
i32.add
27602769
global.set $~lib/memory/__stack_pointer
2761-
local.get $4
2770+
local.get $6
27622771
)
27632772
(func $class/GenericInitializer<i32>#constructor (param $0 i32) (result i32)
27642773
(local $1 i32)

tests/compiler/extends-baseaggregate.optimized.wat

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2150,15 +2150,14 @@
21502150
i32.store offset=4
21512151
i32.const 1180
21522152
i32.load
2153-
local.tee $9
2153+
local.tee $8
21542154
i32.const 1
21552155
i32.add
2156-
local.tee $5
2157-
local.set $1
2158-
local.get $5
2156+
local.tee $9
2157+
local.tee $1
21592158
i32.const 1176
21602159
i32.load
2161-
local.tee $6
2160+
local.tee $4
21622161
i32.const 2
21632162
i32.shr_u
21642163
i32.gt_u
@@ -2169,45 +2168,65 @@
21692168
if
21702169
i32.const 1616
21712170
i32.const 1664
2172-
i32.const 14
2171+
i32.const 17
21732172
i32.const 48
21742173
call $~lib/builtins/abort
21752174
unreachable
21762175
end
21772176
i32.const 1168
21782177
i32.load
2179-
local.tee $7
2178+
local.tee $6
21802179
local.set $0
21812180
block $__inlined_func$~lib/rt/itcms/__renew
2181+
local.get $4
2182+
i32.const 1
2183+
i32.shl
2184+
local.tee $3
2185+
i32.const 1073741820
2186+
local.get $3
2187+
i32.const 1073741820
2188+
i32.lt_u
2189+
select
2190+
local.tee $3
2191+
local.get $1
2192+
i32.const 8
21822193
local.get $1
2194+
i32.const 8
2195+
i32.gt_u
2196+
select
21832197
i32.const 2
21842198
i32.shl
2185-
local.tee $8
2199+
local.tee $1
2200+
local.get $1
2201+
local.get $3
2202+
i32.lt_u
2203+
select
2204+
local.tee $7
21862205
local.tee $3
2187-
local.get $7
2206+
local.get $6
21882207
i32.const 20
21892208
i32.sub
2190-
local.tee $4
2209+
local.tee $5
21912210
i32.load
21922211
i32.const -4
21932212
i32.and
21942213
i32.const 16
21952214
i32.sub
21962215
i32.le_u
21972216
if
2198-
local.get $4
2217+
local.get $5
21992218
local.get $3
22002219
i32.store offset=16
22012220
br $__inlined_func$~lib/rt/itcms/__renew
22022221
end
22032222
local.get $3
2204-
local.get $4
2223+
local.get $5
22052224
i32.load offset=12
22062225
call $~lib/rt/itcms/__new
22072226
local.tee $1
22082227
local.get $0
22092228
local.get $3
2210-
local.get $4
2229+
local.get $5
22112230
i32.load offset=16
22122231
local.tee $0
22132232
local.get $0
@@ -2219,14 +2238,14 @@
22192238
local.set $0
22202239
end
22212240
local.get $0
2222-
local.get $6
2241+
local.get $4
22232242
i32.add
2224-
local.get $8
2225-
local.get $6
2243+
local.get $7
2244+
local.get $4
22262245
i32.sub
22272246
call $~lib/memory/memory.fill
22282247
local.get $0
2229-
local.get $7
2248+
local.get $6
22302249
i32.ne
22312250
if
22322251
i32.const 1168
@@ -2241,12 +2260,12 @@
22412260
call $~lib/rt/itcms/__link
22422261
end
22432262
i32.const 1176
2244-
local.get $8
2263+
local.get $7
22452264
i32.store
22462265
end
22472266
i32.const 1172
22482267
i32.load
2249-
local.get $9
2268+
local.get $8
22502269
i32.const 2
22512270
i32.shl
22522271
i32.add
@@ -2257,7 +2276,7 @@
22572276
i32.const 1
22582277
call $~lib/rt/itcms/__link
22592278
i32.const 1180
2260-
local.get $5
2279+
local.get $9
22612280
i32.store
22622281
global.get $~lib/memory/__stack_pointer
22632282
i32.const 8

0 commit comments

Comments
 (0)