Skip to content

Commit 867a65f

Browse files
KKiiimatc-github
authored andcommitted
feat(as): optimize zero-initialized member variable (#120)
AssemblyScript/assemblyscript#2948
1 parent 75c95c0 commit 867a65f

28 files changed

+1083
-3157
lines changed

assemblyscript/src/compiler.ts

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9965,6 +9965,14 @@ export class Compiler extends DiagnosticEmitter {
99659965

99669966
// === Specialized code generation ==============================================================
99679967

9968+
/** Check if possible to optimize the active initialization away if it's zero */
9969+
canOptimizeZeroInitialization(valueExpr: ExpressionRef): bool {
9970+
const runtime = this.options.runtime;
9971+
return (runtime == Runtime.Incremental || runtime == Runtime.Stub)
9972+
? isConstZero(valueExpr)
9973+
: false;
9974+
}
9975+
99689976
/** Makes a constant zero of the specified type. */
99699977
makeZero(type: Type): ExpressionRef {
99709978
let module = this.module;
@@ -10312,6 +10320,7 @@ export class Compiler extends DiagnosticEmitter {
1031210320
let parameterIndex = fieldPrototype.parameterIndex;
1031310321

1031410322
// Defer non-parameter fields until parameter fields are initialized
10323+
// Since non-parameter may depend on parameter fields
1031510324
if (parameterIndex < 0) {
1031610325
if (!nonParameterFields) nonParameterFields = new Array();
1031710326
nonParameterFields.push(property);
@@ -10347,16 +10356,25 @@ export class Compiler extends DiagnosticEmitter {
1034710356
let initializerNode = fieldPrototype.initializerNode;
1034810357
assert(fieldPrototype.parameterIndex < 0);
1034910358
let setterInstance = assert(field.setterInstance);
10350-
let expr = this.makeCallDirect(setterInstance, [
10351-
module.local_get(thisLocalIndex, sizeTypeRef),
10352-
initializerNode // use initializer if present, otherwise initialize with zero
10353-
? this.compileExpression(initializerNode, fieldType, Constraints.ConvImplicit)
10354-
: this.makeZero(fieldType)
10355-
], field.identifierNode, true);
10356-
if (this.currentType != Type.void) { // in case
10357-
expr = module.drop(expr);
10359+
10360+
if (initializerNode) {
10361+
// Explicit initializer
10362+
// Check if we need to initialize this field
10363+
const valueExpr: ExpressionRef = this.compileExpression(initializerNode, fieldType, Constraints.ConvImplicit);
10364+
// Memory will be filled with 0 on itcms.__new
10365+
// Memory grow will default to initialized with 0 as wasm spec
10366+
// So, optimize the active initialization away if it's zero
10367+
if (!this.canOptimizeZeroInitialization(valueExpr)) {
10368+
let expr = this.makeCallDirect(setterInstance, [
10369+
module.local_get(thisLocalIndex, sizeTypeRef),
10370+
valueExpr
10371+
], field.identifierNode, true);
10372+
if (this.currentType != Type.void) { // in case
10373+
expr = module.drop(expr);
10374+
}
10375+
stmts.push(expr);
10376+
}
1035810377
}
10359-
stmts.push(expr);
1036010378
}
1036110379
}
1036210380

tests/frontend/compiler/assignment-chain.wat

Lines changed: 23 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -3286,18 +3286,6 @@
32863286
)
32873287
(local.get $this)
32883288
)
3289-
(func $assignment-chain/A#set:x (param $this i32) (param $x i64)
3290-
(i64.store
3291-
(local.get $this)
3292-
(local.get $x)
3293-
)
3294-
)
3295-
(func $assignment-chain/A#set:y (param $this i32) (param $y i64)
3296-
(i64.store offset=8
3297-
(local.get $this)
3298-
(local.get $y)
3299-
)
3300-
)
33013289
(func $assignment-chain/A#constructor (param $this i32) (result i32)
33023290
(if
33033291
(i32.eqz
@@ -3323,19 +3311,19 @@
33233311
)
33243312
)
33253313
)
3326-
(call $assignment-chain/A#set:x
3327-
(call $~lib/rt/__tmptostack
3328-
(local.get $this)
3329-
)
3330-
(i64.const 0)
3314+
(local.get $this)
3315+
)
3316+
(func $assignment-chain/A#set:y (param $this i32) (param $y i64)
3317+
(i64.store offset=8
3318+
(local.get $this)
3319+
(local.get $y)
33313320
)
3332-
(call $assignment-chain/A#set:y
3333-
(call $~lib/rt/__tmptostack
3334-
(local.get $this)
3335-
)
3336-
(i64.const 0)
3321+
)
3322+
(func $assignment-chain/A#set:x (param $this i32) (param $x i64)
3323+
(i64.store
3324+
(local.get $this)
3325+
(local.get $x)
33373326
)
3338-
(local.get $this)
33393327
)
33403328
(func $assignment-chain/normal_assignment_chain
33413329
(local $x i32)
@@ -3398,24 +3386,6 @@
33983386
)
33993387
)
34003388
)
3401-
(func $assignment-chain/B#set:_setter_cnt (param $this i32) (param $_setter_cnt i32)
3402-
(i32.store
3403-
(local.get $this)
3404-
(local.get $_setter_cnt)
3405-
)
3406-
)
3407-
(func $assignment-chain/B#set:_getter_cnt (param $this i32) (param $_getter_cnt i32)
3408-
(i32.store offset=4
3409-
(local.get $this)
3410-
(local.get $_getter_cnt)
3411-
)
3412-
)
3413-
(func $assignment-chain/B#set:_y (param $this i32) (param $_y f64)
3414-
(f64.store offset=8
3415-
(local.get $this)
3416-
(local.get $_y)
3417-
)
3418-
)
34193389
(func $assignment-chain/B#constructor (param $this i32) (result i32)
34203390
(if
34213391
(i32.eqz
@@ -3441,31 +3411,25 @@
34413411
)
34423412
)
34433413
)
3444-
(call $assignment-chain/B#set:_setter_cnt
3445-
(call $~lib/rt/__tmptostack
3446-
(local.get $this)
3447-
)
3448-
(i32.const 0)
3449-
)
3450-
(call $assignment-chain/B#set:_getter_cnt
3451-
(call $~lib/rt/__tmptostack
3452-
(local.get $this)
3453-
)
3454-
(i32.const 0)
3455-
)
3456-
(call $assignment-chain/B#set:_y
3457-
(call $~lib/rt/__tmptostack
3458-
(local.get $this)
3459-
)
3460-
(f64.const 0)
3461-
)
34623414
(local.get $this)
34633415
)
34643416
(func $assignment-chain/B#get:_setter_cnt (param $this i32) (result i32)
34653417
(i32.load
34663418
(local.get $this)
34673419
)
34683420
)
3421+
(func $assignment-chain/B#set:_setter_cnt (param $this i32) (param $_setter_cnt i32)
3422+
(i32.store
3423+
(local.get $this)
3424+
(local.get $_setter_cnt)
3425+
)
3426+
)
3427+
(func $assignment-chain/B#set:_y (param $this i32) (param $_y f64)
3428+
(f64.store offset=8
3429+
(local.get $this)
3430+
(local.get $_y)
3431+
)
3432+
)
34693433
(func $assignment-chain/B#set:y (param $this i32) (param $z f64)
34703434
(call $assignment-chain/B#set:_setter_cnt
34713435
(call $~lib/rt/__tmptostack

tests/frontend/compiler/call-rest.wat

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3976,28 +3976,20 @@
39763976
(local $4 i32)
39773977
(local $i i32)
39783978
(local $k i32)
3979-
(block
3980-
(if
3981-
(i32.eqz
3982-
(local.get $this)
3983-
)
3984-
(then
3985-
(local.set $this
3986-
(call $~lib/rt/__localtostack
3987-
(call $~lib/rt/itcms/__new
3988-
(i32.const 4)
3989-
(i32.const 7)
3990-
)
3979+
(if
3980+
(i32.eqz
3981+
(local.get $this)
3982+
)
3983+
(then
3984+
(local.set $this
3985+
(call $~lib/rt/__localtostack
3986+
(call $~lib/rt/itcms/__new
3987+
(i32.const 4)
3988+
(i32.const 7)
39913989
)
39923990
)
39933991
)
39943992
)
3995-
(call $call-rest/Foo#set:values
3996-
(call $~lib/rt/__tmptostack
3997-
(local.get $this)
3998-
)
3999-
(i32.const 0)
4000-
)
40013993
)
40023994
(call $call-rest/Foo#set:values
40033995
(call $~lib/rt/__tmptostack

tests/frontend/compiler/class.wat

Lines changed: 10 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3612,46 +3612,20 @@
36123612
(local $3 i32)
36133613
(local $bufferSize i32)
36143614
(local $buffer i32)
3615-
(block
3616-
(if
3617-
(i32.eqz
3618-
(local.get $this)
3619-
)
3620-
(then
3621-
(local.set $this
3622-
(call $~lib/rt/__localtostack
3623-
(call $~lib/rt/itcms/__new
3624-
(i32.const 16)
3625-
(i32.const 6)
3626-
)
3615+
(if
3616+
(i32.eqz
3617+
(local.get $this)
3618+
)
3619+
(then
3620+
(local.set $this
3621+
(call $~lib/rt/__localtostack
3622+
(call $~lib/rt/itcms/__new
3623+
(i32.const 16)
3624+
(i32.const 6)
36273625
)
36283626
)
36293627
)
36303628
)
3631-
(call $~lib/array/Array<i32>#set:buffer
3632-
(call $~lib/rt/__tmptostack
3633-
(local.get $this)
3634-
)
3635-
(i32.const 0)
3636-
)
3637-
(call $~lib/array/Array<i32>#set:dataStart
3638-
(call $~lib/rt/__tmptostack
3639-
(local.get $this)
3640-
)
3641-
(i32.const 0)
3642-
)
3643-
(call $~lib/array/Array<i32>#set:byteLength
3644-
(call $~lib/rt/__tmptostack
3645-
(local.get $this)
3646-
)
3647-
(i32.const 0)
3648-
)
3649-
(call $~lib/array/Array<i32>#set:length_
3650-
(call $~lib/rt/__tmptostack
3651-
(local.get $this)
3652-
)
3653-
(i32.const 0)
3654-
)
36553629
)
36563630
(if
36573631
(i32.gt_u

tests/frontend/compiler/constructor.wat

Lines changed: 20 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3323,35 +3323,21 @@
33233323
)
33243324
(local.get $this)
33253325
)
3326-
(func $constructor/EmptyCtorWithFieldNoInit#set:a (param $this i32) (param $a i32)
3327-
(i32.store
3328-
(local.get $this)
3329-
(local.get $a)
3330-
)
3331-
)
33323326
(func $constructor/EmptyCtorWithFieldNoInit#constructor (param $this i32) (result i32)
3333-
(block
3334-
(if
3335-
(i32.eqz
3336-
(local.get $this)
3337-
)
3338-
(then
3339-
(local.set $this
3340-
(call $~lib/rt/__localtostack
3341-
(call $~lib/rt/itcms/__new
3342-
(i32.const 4)
3343-
(i32.const 6)
3344-
)
3327+
(if
3328+
(i32.eqz
3329+
(local.get $this)
3330+
)
3331+
(then
3332+
(local.set $this
3333+
(call $~lib/rt/__localtostack
3334+
(call $~lib/rt/itcms/__new
3335+
(i32.const 4)
3336+
(i32.const 6)
33453337
)
33463338
)
33473339
)
33483340
)
3349-
(call $constructor/EmptyCtorWithFieldNoInit#set:a
3350-
(call $~lib/rt/__tmptostack
3351-
(local.get $this)
3352-
)
3353-
(i32.const 0)
3354-
)
33553341
)
33563342
(local.get $this)
33573343
)
@@ -3362,28 +3348,20 @@
33623348
)
33633349
)
33643350
(func $constructor/EmptyCtorWithFieldAccess#constructor (param $this i32) (result i32)
3365-
(block
3366-
(if
3367-
(i32.eqz
3368-
(local.get $this)
3369-
)
3370-
(then
3371-
(local.set $this
3372-
(call $~lib/rt/__localtostack
3373-
(call $~lib/rt/itcms/__new
3374-
(i32.const 4)
3375-
(i32.const 7)
3376-
)
3351+
(if
3352+
(i32.eqz
3353+
(local.get $this)
3354+
)
3355+
(then
3356+
(local.set $this
3357+
(call $~lib/rt/__localtostack
3358+
(call $~lib/rt/itcms/__new
3359+
(i32.const 4)
3360+
(i32.const 7)
33773361
)
33783362
)
33793363
)
33803364
)
3381-
(call $constructor/EmptyCtorWithFieldAccess#set:a
3382-
(call $~lib/rt/__tmptostack
3383-
(local.get $this)
3384-
)
3385-
(i32.const 0)
3386-
)
33873365
)
33883366
(call $constructor/EmptyCtorWithFieldAccess#set:a
33893367
(call $~lib/rt/__tmptostack
@@ -3477,12 +3455,6 @@
34773455
)
34783456
(local.get $this)
34793457
)
3480-
(func $constructor/JustFieldNoInit#set:a (param $this i32) (param $a i32)
3481-
(i32.store
3482-
(local.get $this)
3483-
(local.get $a)
3484-
)
3485-
)
34863458
(func $constructor/JustFieldNoInit#constructor (param $this i32) (result i32)
34873459
(if
34883460
(i32.eqz
@@ -3508,12 +3480,6 @@
35083480
)
35093481
)
35103482
)
3511-
(call $constructor/JustFieldNoInit#set:a
3512-
(call $~lib/rt/__tmptostack
3513-
(local.get $this)
3514-
)
3515-
(i32.const 0)
3516-
)
35173483
(local.get $this)
35183484
)
35193485
(func $constructor/CtorReturns#constructor (param $this i32) (result i32)

0 commit comments

Comments
 (0)