@@ -8136,7 +8136,8 @@ export class Compiler extends DiagnosticEmitter {
8136
8136
var parts = expression . parts ;
8137
8137
var numParts = parts . length ;
8138
8138
var expressions = expression . expressions ;
8139
- assert ( numParts - 1 == expressions . length ) ;
8139
+ var numExpressions = expressions . length ;
8140
+ assert ( numExpressions == numParts - 1 ) ;
8140
8141
8141
8142
var module = this . module ;
8142
8143
var stringInstance = this . program . stringInstance ;
@@ -8202,8 +8203,8 @@ export class Compiler extends DiagnosticEmitter {
8202
8203
return this . makeCallDirect ( concatMethod , [ lhs , rhs ] , expression ) ;
8203
8204
}
8204
8205
8205
- // Compile to a `StaticArray<string>#join("") for general case
8206
- let length = 2 * numParts - 1 ;
8206
+ // Compile to a `StaticArray<string>#join("") in the general case
8207
+ let length = numParts + numExpressions ;
8207
8208
let values = new Array < usize > ( length ) ;
8208
8209
values [ 0 ] = this . ensureStaticString ( parts [ 0 ] ) ;
8209
8210
for ( let i = 1 ; i < numParts ; ++ i ) {
@@ -8215,19 +8216,33 @@ export class Compiler extends DiagnosticEmitter {
8215
8216
let offset = i64_add ( segment . offset , i64_new ( this . program . totalOverhead ) ) ;
8216
8217
let joinInstance = assert ( arrayInstance . getMethod ( "join" ) ) ;
8217
8218
let indexedSetInstance = assert ( arrayInstance . lookupOverload ( OperatorKind . INDEXED_SET , true ) ) ;
8218
- let stmts = new Array < ExpressionRef > ( numParts ) ;
8219
- for ( let i = 0 , k = numParts - 1 ; i < k ; ++ i ) {
8219
+ let stmts = new Array < ExpressionRef > ( 2 * numExpressions + 1 ) ;
8220
+ // Use one local per toString'ed subexpression, since otherwise recursion on the same
8221
+ // static array would overwrite already prepared parts. Avoids a temporary array.
8222
+ let temps = new Array < Local > ( numExpressions ) ;
8223
+ let flow = this . currentFlow ;
8224
+ for ( let i = 0 ; i < numExpressions ; ++ i ) {
8220
8225
let expression = expressions [ i ] ;
8221
- stmts [ i ] = this . makeCallDirect ( indexedSetInstance , [
8222
- module . usize ( offset ) ,
8223
- module . i32 ( 2 * i + 1 ) ,
8226
+ let temp = flow . getTempLocal ( stringType ) ;
8227
+ temps [ i ] = temp ;
8228
+ stmts [ i ] = module . local_set ( temp . index ,
8224
8229
this . makeToString (
8225
8230
this . compileExpression ( expression , stringType ) ,
8226
8231
this . currentType , expression
8227
- )
8232
+ ) ,
8233
+ true
8234
+ ) ;
8235
+ }
8236
+ // Populate the static array with the toString'ed subexpressions and call .join("")
8237
+ for ( let i = 0 ; i < numExpressions ; ++ i ) {
8238
+ stmts [ numExpressions + i ] = this . makeCallDirect ( indexedSetInstance , [
8239
+ module . usize ( offset ) ,
8240
+ module . i32 ( 2 * i + 1 ) ,
8241
+ module . local_get ( temps [ i ] . index , stringType . toRef ( ) )
8228
8242
] , expression ) ;
8243
+ flow . freeTempLocal ( temps [ i ] ) ;
8229
8244
}
8230
- stmts [ numParts - 1 ] = this . makeCallDirect ( joinInstance , [
8245
+ stmts [ 2 * numExpressions ] = this . makeCallDirect ( joinInstance , [
8231
8246
module . usize ( offset ) ,
8232
8247
this . ensureStaticString ( "" )
8233
8248
] , expression ) ;
@@ -8385,19 +8400,7 @@ export class Compiler extends DiagnosticEmitter {
8385
8400
8386
8401
// otherwise allocate a new array header and make it wrap a copy of the static buffer
8387
8402
} else {
8388
- // __newArray(length, alignLog2, classId, staticBuffer)
8389
- let expr = this . makeCallDirect ( program . newArrayInstance , [
8390
- module . i32 ( length ) ,
8391
- program . options . isWasm64
8392
- ? module . i64 ( elementType . alignLog2 )
8393
- : module . i32 ( elementType . alignLog2 ) ,
8394
- module . i32 ( arrayInstance . id ) ,
8395
- program . options . isWasm64
8396
- ? module . i64 ( i64_low ( bufferAddress ) , i64_high ( bufferAddress ) )
8397
- : module . i32 ( i64_low ( bufferAddress ) )
8398
- ] , expression ) ;
8399
- this . currentType = arrayType ;
8400
- return expr ;
8403
+ return this . makeNewArray ( arrayInstance , length , bufferAddress , expression ) ;
8401
8404
}
8402
8405
}
8403
8406
@@ -8419,16 +8422,7 @@ export class Compiler extends DiagnosticEmitter {
8419
8422
// tempThis = __newArray(length, alignLog2, classId, source = 0)
8420
8423
stmts . push (
8421
8424
module . local_set ( tempThis . index ,
8422
- this . makeCallDirect ( program . newArrayInstance , [
8423
- module . i32 ( length ) ,
8424
- program . options . isWasm64
8425
- ? module . i64 ( elementType . alignLog2 )
8426
- : module . i32 ( elementType . alignLog2 ) ,
8427
- module . i32 ( arrayInstance . id ) ,
8428
- program . options . isWasm64
8429
- ? module . i64 ( 0 )
8430
- : module . i32 ( 0 )
8431
- ] , expression ) ,
8425
+ this . makeNewArray ( arrayInstance , length , i64_new ( 0 ) , expression ) ,
8432
8426
arrayType . isManaged
8433
8427
)
8434
8428
) ;
@@ -8466,6 +8460,37 @@ export class Compiler extends DiagnosticEmitter {
8466
8460
return module . flatten ( stmts , arrayTypeRef ) ;
8467
8461
}
8468
8462
8463
+ /** Makes a new array instance from a static buffer segment. */
8464
+ private makeNewArray (
8465
+ /** Concrete array class. */
8466
+ arrayInstance : Class ,
8467
+ /** Length of the array. */
8468
+ length : i32 ,
8469
+ /** Source address to copy from. Array is zeroed if `0`. */
8470
+ source : i64 ,
8471
+ /** Report node. */
8472
+ reportNode : Node
8473
+ ) : ExpressionRef {
8474
+ var program = this . program ;
8475
+ var module = this . module ;
8476
+ assert ( ! arrayInstance . extends ( program . staticArrayPrototype ) ) ;
8477
+ var elementType = arrayInstance . getArrayValueType ( ) ; // asserts
8478
+
8479
+ // __newArray(length, alignLog2, classId, staticBuffer)
8480
+ var expr = this . makeCallDirect ( program . newArrayInstance , [
8481
+ module . i32 ( length ) ,
8482
+ program . options . isWasm64
8483
+ ? module . i64 ( elementType . alignLog2 )
8484
+ : module . i32 ( elementType . alignLog2 ) ,
8485
+ module . i32 ( arrayInstance . id ) ,
8486
+ program . options . isWasm64
8487
+ ? module . i64 ( i64_low ( source ) , i64_high ( source ) )
8488
+ : module . i32 ( i64_low ( source ) )
8489
+ ] , reportNode ) ;
8490
+ this . currentType = arrayInstance . type ;
8491
+ return expr ;
8492
+ }
8493
+
8469
8494
/** Compiles a special `fixed` array literal. */
8470
8495
private compileStaticArrayLiteral (
8471
8496
expression : ArrayLiteralExpression ,
0 commit comments