@@ -5016,86 +5016,89 @@ export class Compiler extends DiagnosticEmitter {
5016
5016
rightExpr = this . performAutoreleasesWithValue ( rightFlow , rightExpr , rightType ) ;
5017
5017
rightFlow . freeScopedLocals ( ) ;
5018
5018
this . currentFlow = flow ;
5019
- this . currentType = Type . bool ;
5020
5019
expr = module . if (
5021
5020
this . makeIsTrueish ( leftExpr , leftType ) ,
5022
5021
this . makeIsTrueish ( rightExpr , rightType ) ,
5023
5022
module . i32 ( 0 )
5024
5023
) ;
5024
+ this . currentType = Type . bool ;
5025
5025
5026
- // references must properly retain and release, with the same outcome independent of the branch taken
5027
- } else if ( leftType . isManaged ) {
5028
- let leftAutoreleaseSkipped = this . skippedAutoreleases . has ( leftExpr ) ;
5029
- let rightAutoreleaseSkipped = this . skippedAutoreleases . has ( rightExpr ) ;
5030
- let temp = flow . getTempLocal ( leftType ) ;
5031
- leftExpr = module . local_tee ( temp . index , leftExpr ) ;
5032
-
5033
- // instead of retaining left and releasing it again in right when right
5034
- // is taken, we can also just retain left if right is not taken
5035
- let retainLeftInElse = false ;
5036
- if ( leftAutoreleaseSkipped != rightAutoreleaseSkipped ) { // xor
5037
- if ( ! leftAutoreleaseSkipped ) {
5038
- retainLeftInElse = true ;
5039
- } else {
5040
- rightExpr = this . makeRetain ( rightExpr ) ;
5041
- rightAutoreleaseSkipped = true ;
5042
- }
5043
- } else if ( ! ( constraints & Constraints . WILL_RETAIN ) ) { // otherwise keep right alive a little longer
5044
- rightExpr = this . delayAutorelease ( rightExpr , rightType , rightFlow , flow ) ;
5045
- }
5026
+ } else {
5046
5027
5047
- let rightStmts = new Array < ExpressionRef > ( ) ;
5048
- if ( leftAutoreleaseSkipped ) { // left turned out to be true'ish and is dropped
5049
- rightStmts . unshift (
5050
- this . makeRelease (
5051
- module . local_get ( temp . index , leftType . toNativeType ( ) )
5052
- )
5053
- ) ;
5054
- }
5055
- rightExpr = this . performAutoreleasesWithValue ( rightFlow , rightExpr , rightType , rightStmts ) ;
5056
- rightFlow . freeScopedLocals ( ) ;
5057
- this . currentFlow = flow ;
5028
+ // references must properly retain and release, with the same outcome independent of the branch taken
5029
+ if ( leftType . isManaged ) {
5030
+ let leftAutoreleaseSkipped = this . skippedAutoreleases . has ( leftExpr ) ;
5031
+ let rightAutoreleaseSkipped = this . skippedAutoreleases . has ( rightExpr ) ;
5032
+ let temp = flow . getTempLocal ( leftType ) ;
5033
+ leftExpr = module . local_tee ( temp . index , leftExpr ) ;
5034
+
5035
+ // instead of retaining left and releasing it again in right when right
5036
+ // is taken, we can also just retain left if right is not taken
5037
+ let retainLeftInElse = false ;
5038
+ if ( leftAutoreleaseSkipped != rightAutoreleaseSkipped ) { // xor
5039
+ if ( ! leftAutoreleaseSkipped ) {
5040
+ retainLeftInElse = true ;
5041
+ } else {
5042
+ rightExpr = this . makeRetain ( rightExpr ) ;
5043
+ rightAutoreleaseSkipped = true ;
5044
+ }
5045
+ } else if ( ! ( constraints & Constraints . WILL_RETAIN ) ) { // otherwise keep right alive a little longer
5046
+ rightExpr = this . delayAutorelease ( rightExpr , rightType , rightFlow , flow ) ;
5047
+ }
5058
5048
5059
- expr = module . if (
5060
- this . makeIsTrueish ( leftExpr , leftType ) ,
5061
- rightExpr ,
5062
- retainLeftInElse
5063
- ? this . makeRetain (
5049
+ let rightStmts = new Array < ExpressionRef > ( ) ;
5050
+ if ( leftAutoreleaseSkipped ) { // left turned out to be true'ish and is dropped
5051
+ rightStmts . unshift (
5052
+ this . makeRelease (
5064
5053
module . local_get ( temp . index , leftType . toNativeType ( ) )
5065
5054
)
5066
- : module . local_get ( temp . index , leftType . toNativeType ( ) )
5067
- ) ;
5068
- if ( leftAutoreleaseSkipped || rightAutoreleaseSkipped ) this . skippedAutoreleases . add ( expr ) ;
5069
- if ( temp ) flow . freeTempLocal ( temp ) ;
5070
-
5071
- // basic values can use more aggressive optimizations
5072
- } else {
5073
- rightExpr = this . performAutoreleasesWithValue ( rightFlow , rightExpr , rightType ) ;
5074
- rightFlow . freeScopedLocals ( ) ;
5075
- this . currentFlow = flow ;
5055
+ ) ;
5056
+ }
5057
+ rightExpr = this . performAutoreleasesWithValue ( rightFlow , rightExpr , rightType , rightStmts ) ;
5058
+ rightFlow . freeScopedLocals ( ) ;
5059
+ this . currentFlow = flow ;
5076
5060
5077
- // simplify if cloning left without side effects is possible
5078
- if ( expr = module . cloneExpression ( leftExpr , true , 0 ) ) {
5079
5061
expr = module . if (
5080
- this . makeIsTrueish ( leftExpr , this . currentType ) ,
5062
+ this . makeIsTrueish ( leftExpr , leftType ) ,
5081
5063
rightExpr ,
5082
- expr
5064
+ retainLeftInElse
5065
+ ? this . makeRetain (
5066
+ module . local_get ( temp . index , leftType . toNativeType ( ) )
5067
+ )
5068
+ : module . local_get ( temp . index , leftType . toNativeType ( ) )
5083
5069
) ;
5070
+ if ( leftAutoreleaseSkipped || rightAutoreleaseSkipped ) this . skippedAutoreleases . add ( expr ) ;
5071
+ if ( temp ) flow . freeTempLocal ( temp ) ;
5084
5072
5085
- // if not possible, tee left to a temp
5073
+ // basic values can use more aggressive optimizations
5086
5074
} else {
5087
- let tempLocal = flow . getTempLocal ( leftType ) ;
5088
- if ( ! flow . canOverflow ( leftExpr , leftType ) ) flow . setLocalFlag ( tempLocal . index , LocalFlags . WRAPPED ) ;
5089
- if ( flow . isNonnull ( leftExpr , leftType ) ) flow . setLocalFlag ( tempLocal . index , LocalFlags . NONNULL ) ;
5090
- expr = module . if (
5091
- this . makeIsTrueish ( module . local_tee ( tempLocal . index , leftExpr ) , leftType ) ,
5092
- rightExpr ,
5093
- module . local_get ( tempLocal . index , leftType . toNativeType ( ) )
5094
- ) ;
5095
- flow . freeTempLocal ( tempLocal ) ;
5075
+ rightExpr = this . performAutoreleasesWithValue ( rightFlow , rightExpr , rightType ) ;
5076
+ rightFlow . freeScopedLocals ( ) ;
5077
+ this . currentFlow = flow ;
5078
+
5079
+ // simplify if cloning left without side effects is possible
5080
+ if ( expr = module . cloneExpression ( leftExpr , true , 0 ) ) {
5081
+ expr = module . if (
5082
+ this . makeIsTrueish ( leftExpr , this . currentType ) ,
5083
+ rightExpr ,
5084
+ expr
5085
+ ) ;
5086
+
5087
+ // if not possible, tee left to a temp
5088
+ } else {
5089
+ let tempLocal = flow . getTempLocal ( leftType ) ;
5090
+ if ( ! flow . canOverflow ( leftExpr , leftType ) ) flow . setLocalFlag ( tempLocal . index , LocalFlags . WRAPPED ) ;
5091
+ if ( flow . isNonnull ( leftExpr , leftType ) ) flow . setLocalFlag ( tempLocal . index , LocalFlags . NONNULL ) ;
5092
+ expr = module . if (
5093
+ this . makeIsTrueish ( module . local_tee ( tempLocal . index , leftExpr ) , leftType ) ,
5094
+ rightExpr ,
5095
+ module . local_get ( tempLocal . index , leftType . toNativeType ( ) )
5096
+ ) ;
5097
+ flow . freeTempLocal ( tempLocal ) ;
5098
+ }
5096
5099
}
5100
+ this . currentType = leftType ;
5097
5101
}
5098
- this . currentType = leftType ;
5099
5102
break ;
5100
5103
}
5101
5104
case Token . BAR_BAR : { // left || right -> ((t = left) ? t : right)
@@ -5115,88 +5118,91 @@ export class Compiler extends DiagnosticEmitter {
5115
5118
rightExpr = this . performAutoreleasesWithValue ( rightFlow , rightExpr , leftType ) ;
5116
5119
rightFlow . freeScopedLocals ( ) ;
5117
5120
this . currentFlow = flow ;
5118
- this . currentType = Type . bool ;
5119
5121
expr = module . if (
5120
5122
this . makeIsTrueish ( leftExpr , leftType ) ,
5121
5123
module . i32 ( 1 ) ,
5122
5124
this . makeIsTrueish ( rightExpr , rightType )
5123
5125
) ;
5126
+ this . currentType = Type . bool ;
5124
5127
5125
- // references must properly retain and release, with the same outcome independent of the branch taken
5126
- } else if ( leftType . isManaged ) {
5127
- let leftAutoreleaseSkipped = this . skippedAutoreleases . has ( leftExpr ) ;
5128
- let rightAutoreleaseSkipped = this . skippedAutoreleases . has ( rightExpr ) ;
5129
- let temp = flow . getTempLocal ( leftType ) ;
5130
- leftExpr = module . local_tee ( temp . index , leftExpr ) ;
5131
-
5132
- // instead of retaining left and releasing it again in right when right
5133
- // is taken, we can also just retain left if right is not taken
5134
- let retainLeftInThen = false ;
5135
- if ( leftAutoreleaseSkipped != rightAutoreleaseSkipped ) { // xor
5136
- if ( ! leftAutoreleaseSkipped ) {
5137
- retainLeftInThen = true ;
5138
- } else {
5139
- rightExpr = this . makeRetain ( rightExpr ) ;
5140
- rightAutoreleaseSkipped = true ;
5141
- }
5142
- } else if ( ! ( constraints & Constraints . WILL_RETAIN ) ) { // otherwise keep right alive a little longer
5143
- rightExpr = this . delayAutorelease ( rightExpr , rightType , rightFlow , flow ) ;
5144
- }
5128
+ } else {
5145
5129
5146
- let rightStmts = new Array < ExpressionRef > ( ) ;
5147
- if ( leftAutoreleaseSkipped ) { // left turned out to be false'ish and is dropped
5148
- // TODO: usually, false'ish means left is null, but this might not hold
5149
- // once implicit conversion with strings is performed and left is "", so:
5150
- rightStmts . unshift (
5151
- this . makeRelease (
5152
- module . local_get ( temp . index , leftType . toNativeType ( ) )
5153
- )
5154
- ) ;
5155
- }
5156
- rightExpr = this . performAutoreleasesWithValue ( rightFlow , rightExpr , rightType , rightStmts ) ;
5157
- rightFlow . freeScopedLocals ( ) ;
5158
- this . currentFlow = flow ;
5130
+ // references must properly retain and release, with the same outcome independent of the branch taken
5131
+ if ( leftType . isManaged ) {
5132
+ let leftAutoreleaseSkipped = this . skippedAutoreleases . has ( leftExpr ) ;
5133
+ let rightAutoreleaseSkipped = this . skippedAutoreleases . has ( rightExpr ) ;
5134
+ let temp = flow . getTempLocal ( leftType ) ;
5135
+ leftExpr = module . local_tee ( temp . index , leftExpr ) ;
5136
+
5137
+ // instead of retaining left and releasing it again in right when right
5138
+ // is taken, we can also just retain left if right is not taken
5139
+ let retainLeftInThen = false ;
5140
+ if ( leftAutoreleaseSkipped != rightAutoreleaseSkipped ) { // xor
5141
+ if ( ! leftAutoreleaseSkipped ) {
5142
+ retainLeftInThen = true ;
5143
+ } else {
5144
+ rightExpr = this . makeRetain ( rightExpr ) ;
5145
+ rightAutoreleaseSkipped = true ;
5146
+ }
5147
+ } else if ( ! ( constraints & Constraints . WILL_RETAIN ) ) { // otherwise keep right alive a little longer
5148
+ rightExpr = this . delayAutorelease ( rightExpr , rightType , rightFlow , flow ) ;
5149
+ }
5159
5150
5160
- expr = module . if (
5161
- this . makeIsTrueish ( leftExpr , leftType ) ,
5162
- retainLeftInThen
5163
- ? this . makeRetain (
5151
+ let rightStmts = new Array < ExpressionRef > ( ) ;
5152
+ if ( leftAutoreleaseSkipped ) { // left turned out to be false'ish and is dropped
5153
+ // TODO: usually, false'ish means left is null, but this might not hold
5154
+ // once implicit conversion with strings is performed and left is "", so:
5155
+ rightStmts . unshift (
5156
+ this . makeRelease (
5164
5157
module . local_get ( temp . index , leftType . toNativeType ( ) )
5165
5158
)
5166
- : module . local_get ( temp . index , leftType . toNativeType ( ) ) ,
5167
- rightExpr
5168
- ) ;
5169
- if ( leftAutoreleaseSkipped || rightAutoreleaseSkipped ) this . skippedAutoreleases . add ( expr ) ;
5170
- if ( temp ) flow . freeTempLocal ( temp ) ;
5171
-
5172
- // basic values can use more aggressive optimizations
5173
- } else {
5174
- rightExpr = this . performAutoreleasesWithValue ( rightFlow , rightExpr , rightType ) ;
5175
- rightFlow . freeScopedLocals ( ) ;
5176
- this . currentFlow = flow ;
5159
+ ) ;
5160
+ }
5161
+ rightExpr = this . performAutoreleasesWithValue ( rightFlow , rightExpr , rightType , rightStmts ) ;
5162
+ rightFlow . freeScopedLocals ( ) ;
5163
+ this . currentFlow = flow ;
5177
5164
5178
- // simplify if cloning left without side effects is possible
5179
- if ( expr = module . cloneExpression ( leftExpr , true , 0 ) ) {
5180
5165
expr = module . if (
5181
5166
this . makeIsTrueish ( leftExpr , leftType ) ,
5182
- expr ,
5167
+ retainLeftInThen
5168
+ ? this . makeRetain (
5169
+ module . local_get ( temp . index , leftType . toNativeType ( ) )
5170
+ )
5171
+ : module . local_get ( temp . index , leftType . toNativeType ( ) ) ,
5183
5172
rightExpr
5184
5173
) ;
5174
+ if ( leftAutoreleaseSkipped || rightAutoreleaseSkipped ) this . skippedAutoreleases . add ( expr ) ;
5175
+ if ( temp ) flow . freeTempLocal ( temp ) ;
5185
5176
5186
- // if not possible, tee left to a temp. local
5177
+ // basic values can use more aggressive optimizations
5187
5178
} else {
5188
- let temp = flow . getTempLocal ( leftType ) ;
5189
- if ( ! flow . canOverflow ( leftExpr , leftType ) ) flow . setLocalFlag ( temp . index , LocalFlags . WRAPPED ) ;
5190
- if ( flow . isNonnull ( leftExpr , leftType ) ) flow . setLocalFlag ( temp . index , LocalFlags . NONNULL ) ;
5191
- expr = module . if (
5192
- this . makeIsTrueish ( module . local_tee ( temp . index , leftExpr ) , leftType ) ,
5193
- module . local_get ( temp . index , leftType . toNativeType ( ) ) ,
5194
- rightExpr
5195
- ) ;
5196
- flow . freeTempLocal ( temp ) ;
5179
+ rightExpr = this . performAutoreleasesWithValue ( rightFlow , rightExpr , rightType ) ;
5180
+ rightFlow . freeScopedLocals ( ) ;
5181
+ this . currentFlow = flow ;
5182
+
5183
+ // simplify if cloning left without side effects is possible
5184
+ if ( expr = module . cloneExpression ( leftExpr , true , 0 ) ) {
5185
+ expr = module . if (
5186
+ this . makeIsTrueish ( leftExpr , leftType ) ,
5187
+ expr ,
5188
+ rightExpr
5189
+ ) ;
5190
+
5191
+ // if not possible, tee left to a temp. local
5192
+ } else {
5193
+ let temp = flow . getTempLocal ( leftType ) ;
5194
+ if ( ! flow . canOverflow ( leftExpr , leftType ) ) flow . setLocalFlag ( temp . index , LocalFlags . WRAPPED ) ;
5195
+ if ( flow . isNonnull ( leftExpr , leftType ) ) flow . setLocalFlag ( temp . index , LocalFlags . NONNULL ) ;
5196
+ expr = module . if (
5197
+ this . makeIsTrueish ( module . local_tee ( temp . index , leftExpr ) , leftType ) ,
5198
+ module . local_get ( temp . index , leftType . toNativeType ( ) ) ,
5199
+ rightExpr
5200
+ ) ;
5201
+ flow . freeTempLocal ( temp ) ;
5202
+ }
5197
5203
}
5204
+ this . currentType = leftType ;
5198
5205
}
5199
- this . currentType = leftType ;
5200
5206
break ;
5201
5207
}
5202
5208
default : {
0 commit comments