@@ -8136,7 +8136,8 @@ export class Compiler extends DiagnosticEmitter {
81368136 var parts = expression . parts ;
81378137 var numParts = parts . length ;
81388138 var expressions = expression . expressions ;
8139- assert ( numParts - 1 == expressions . length ) ;
8139+ var numExpressions = expressions . length ;
8140+ assert ( numExpressions == numParts - 1 ) ;
81408141
81418142 var module = this . module ;
81428143 var stringInstance = this . program . stringInstance ;
@@ -8202,8 +8203,8 @@ export class Compiler extends DiagnosticEmitter {
82028203 return this . makeCallDirect ( concatMethod , [ lhs , rhs ] , expression ) ;
82038204 }
82048205
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 ;
82078208 let values = new Array < usize > ( length ) ;
82088209 values [ 0 ] = this . ensureStaticString ( parts [ 0 ] ) ;
82098210 for ( let i = 1 ; i < numParts ; ++ i ) {
@@ -8215,19 +8216,33 @@ export class Compiler extends DiagnosticEmitter {
82158216 let offset = i64_add ( segment . offset , i64_new ( this . program . totalOverhead ) ) ;
82168217 let joinInstance = assert ( arrayInstance . getMethod ( "join" ) ) ;
82178218 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 ) {
82208225 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 ,
82248229 this . makeToString (
82258230 this . compileExpression ( expression , stringType ) ,
82268231 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 ( ) )
82288242 ] , expression ) ;
8243+ flow . freeTempLocal ( temps [ i ] ) ;
82298244 }
8230- stmts [ numParts - 1 ] = this . makeCallDirect ( joinInstance , [
8245+ stmts [ 2 * numExpressions ] = this . makeCallDirect ( joinInstance , [
82318246 module . usize ( offset ) ,
82328247 this . ensureStaticString ( "" )
82338248 ] , expression ) ;
@@ -8385,19 +8400,7 @@ export class Compiler extends DiagnosticEmitter {
83858400
83868401 // otherwise allocate a new array header and make it wrap a copy of the static buffer
83878402 } 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 ) ;
84018404 }
84028405 }
84038406
@@ -8419,16 +8422,7 @@ export class Compiler extends DiagnosticEmitter {
84198422 // tempThis = __newArray(length, alignLog2, classId, source = 0)
84208423 stmts . push (
84218424 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 ) ,
84328426 arrayType . isManaged
84338427 )
84348428 ) ;
@@ -8466,6 +8460,37 @@ export class Compiler extends DiagnosticEmitter {
84668460 return module . flatten ( stmts , arrayTypeRef ) ;
84678461 }
84688462
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+
84698494 /** Compiles a special `fixed` array literal. */
84708495 private compileStaticArrayLiteral (
84718496 expression : ArrayLiteralExpression ,
0 commit comments