77 compileCall as compileBuiltinCall ,
88 compileAllocate ,
99 compileAbort ,
10- compileIterateRoots
10+ compileIterateRoots ,
11+ ensureGCHook
1112} from "./builtins" ;
1213
1314import {
@@ -6226,53 +6227,51 @@ export class Compiler extends DiagnosticEmitter {
62266227 /** Ensures that the specified string exists in static memory and returns a pointer to it. */
62276228 ensureStaticString ( stringValue : string ) : ExpressionRef {
62286229 var program = this . program ;
6229- var module = this . module ;
6230- var options = this . options ;
6231- var stringSegments = this . stringSegments ;
6232- var needsGCHeader = program . hasGC ;
6230+ var hasGC = program . hasGC ;
6231+ var gcHeaderSize = program . gcHeaderSize ;
62336232
6233+ var stringInstance = assert ( program . stringInstance ) ;
62346234 var stringSegment : MemorySegment ;
6235- var stringOffset : I64 ;
6236- if ( ! stringSegments . has ( stringValue ) ) {
6237- let stringLength = stringValue . length ;
6238- let stringSize = 4 + stringLength * 2 ;
6239- let offset = 0 ;
6240- let gcHeaderSize = program . gcHeaderSize ;
6241- if ( needsGCHeader ) {
6242- stringSize += gcHeaderSize ;
6243- offset += gcHeaderSize ;
6244- }
6245- let stringBuffer = new Uint8Array ( stringSize ) ;
6246- stringBuffer [ offset ] = stringLength & 0xff ;
6247- stringBuffer [ offset + 1 ] = ( stringLength >>> 8 ) & 0xff ;
6248- stringBuffer [ offset + 2 ] = ( stringLength >>> 16 ) & 0xff ;
6249- stringBuffer [ offset + 3 ] = ( stringLength >>> 24 ) & 0xff ;
6250- for ( let i = 0 ; i < stringLength ; ++ i ) {
6251- stringBuffer [ offset + 4 + i * 2 ] = stringValue . charCodeAt ( i ) & 0xff ;
6252- stringBuffer [ offset + 5 + i * 2 ] = ( stringValue . charCodeAt ( i ) >>> 8 ) & 0xff ;
6253- }
6254- stringSegment = this . addMemorySegment ( stringBuffer , options . usizeType . byteSize ) ;
6255- stringSegments . set ( stringValue , stringSegment ) ;
6256- if ( needsGCHeader ) {
6257- stringOffset = i64_add ( stringSegment . offset , i64_new ( gcHeaderSize , 0 ) ) ;
6235+
6236+ // if the string already exists, reuse it
6237+ var segments = this . stringSegments ;
6238+ if ( segments . has ( stringValue ) ) {
6239+ stringSegment = < MemorySegment > segments . get ( stringValue ) ;
6240+
6241+ // otherwise create it
6242+ } else {
6243+ let length = stringValue . length ;
6244+ let headerSize = ( stringInstance . currentMemoryOffset + 1 ) & ~ 1 ;
6245+ let totalSize = headerSize + length * 2 ;
6246+
6247+ let buf : Uint8Array ;
6248+ let pos : u32 ;
6249+
6250+ if ( hasGC ) {
6251+ buf = new Uint8Array ( gcHeaderSize + totalSize ) ;
6252+ pos = gcHeaderSize ;
6253+ writeI32 ( ensureGCHook ( this , stringInstance ) , buf , program . gcHookOffset ) ;
62586254 } else {
6259- stringOffset = stringSegment . offset ;
6255+ buf = new Uint8Array ( totalSize ) ;
6256+ pos = 0 ;
62606257 }
6261- } else {
6262- stringSegment = < MemorySegment > stringSegments . get ( stringValue ) ;
6263- stringOffset = stringSegment . offset ;
6264- }
6265- if ( program . typesLookup . has ( "string" ) ) {
6266- let stringType = < Type > program . typesLookup . get ( "string" ) ;
6267- this . currentType = stringType ;
6268- } else {
6269- this . currentType = options . usizeType ;
6258+ writeI32 ( length , buf , pos + stringInstance . offsetof ( "length" ) ) ;
6259+ pos += headerSize ;
6260+ for ( let i = 0 ; i < length ; ++ i ) {
6261+ writeI16 ( stringValue . charCodeAt ( i ) , buf , pos + ( i << 1 ) ) ;
6262+ }
6263+ stringSegment = this . addMemorySegment ( buf ) ;
6264+ segments . set ( stringValue , stringSegment ) ;
62706265 }
6271- if ( options . isWasm64 ) {
6272- return module . createI64 ( i64_low ( stringOffset ) , i64_high ( stringOffset ) ) ;
6266+ var stringOffset = stringSegment . offset ;
6267+ if ( hasGC ) stringOffset = i64_add ( stringOffset , i64_new ( gcHeaderSize ) ) ;
6268+
6269+ this . currentType = stringInstance . type ;
6270+ if ( this . options . isWasm64 ) {
6271+ return this . module . createI64 ( i64_low ( stringOffset ) , i64_high ( stringOffset ) ) ;
62736272 } else {
6274- assert ( i64_is_i32 ( stringOffset ) ) ;
6275- return module . createI32 ( i64_low ( stringOffset ) ) ;
6273+ assert ( i64_is_u32 ( stringOffset ) ) ;
6274+ return this . module . createI32 ( i64_low ( stringOffset ) ) ;
62766275 }
62776276 }
62786277
@@ -6282,52 +6281,32 @@ export class Compiler extends DiagnosticEmitter {
62826281
62836282 /** Ensures that the specified array exists in static memory and returns a pointer to it. */
62846283 ensureStaticArray ( elementType : Type , values : ExpressionRef [ ] ) : ExpressionRef {
6284+ var program = this . program ;
6285+ var hasGC = program . hasGC ;
6286+ var gcHeaderSize = program . gcHeaderSize ;
6287+
62856288 var length = values . length ;
62866289 var byteSize = elementType . byteSize ;
62876290 var byteLength = length * byteSize ;
62886291 var usizeTypeSize = this . options . usizeType . byteSize ;
62896292
6290- // determine the size of the Array header
6291- var arrayHeaderSize = ( usizeTypeSize + 4 + 7 ) & ~ 7 ; // .buffer_ + .length_ + alignment
6292- var arrayTotalSize = arrayHeaderSize ;
6293-
6294- // determine the size of the ArrayBuffer
6295- var bufferHeaderSize = ( 4 + 7 ) & ~ 7 ; // .byteLength + alignment
6296- var bufferTotalSize = 1 << ( 32 - clz ( byteLength + bufferHeaderSize - 1 ) ) ; // see internals
6297-
6298- var program = this . program ;
6299- var needsGC = program . hasGC ;
6300- var gcHeaderSize = program . gcHeaderSize ;
6301-
6302- var offset = 0 ;
6303- if ( needsGC ) {
6304- offset += gcHeaderSize ; // start writing after GC header
6305- arrayTotalSize += gcHeaderSize ;
6306- bufferTotalSize += gcHeaderSize ;
6307- }
6308-
6309- // create a compound segment holding both the the Array header and the ArrayBuffer
6310- var buffer = new Uint8Array ( arrayHeaderSize + bufferTotalSize ) ;
6311- var segment = this . addMemorySegment ( buffer ) ;
6312-
6313- // write the Array header first
6314- if ( usizeTypeSize == 8 ) {
6315- writeI64 ( i64_add ( segment . offset , i64_new ( arrayHeaderSize ) ) , buffer , offset ) ; // .buffer_
6316- offset += 8 ;
6293+ var buf : Uint8Array ;
6294+ var pos : u32 ;
6295+
6296+ // create the backing ArrayBuffer segment
6297+ var bufferInstance = assert ( program . arrayBufferInstance ) ;
6298+ var bufferHeaderSize = ( bufferInstance . currentMemoryOffset + 7 ) & ~ 7 ;
6299+ var bufferTotalSize = 1 << ( 32 - clz ( bufferHeaderSize + byteLength - 1 ) ) ;
6300+ if ( hasGC ) {
6301+ buf = new Uint8Array ( gcHeaderSize + bufferTotalSize ) ;
6302+ pos = gcHeaderSize ;
6303+ writeI32 ( ensureGCHook ( this , bufferInstance ) , buf , program . gcHookOffset ) ;
63176304 } else {
6318- assert ( i64_is_u32 ( segment . offset ) ) ;
6319- writeI32 ( i64_low ( segment . offset ) + arrayHeaderSize , buffer , offset ) ; // .buffer_
6320- offset += 4 ;
6305+ buf = new Uint8Array ( bufferTotalSize ) ;
6306+ pos = 0 ;
63216307 }
6322- writeI32 ( length , buffer , offset ) ; // .length_
6323- offset += 4 ;
6324- assert ( ( ( offset + 7 ) & ~ 7 ) == arrayTotalSize ) ; // incl. GC header if applicable
6325-
6326- // append the ArrayBuffer
6327- offset = arrayTotalSize ;
6328- if ( needsGC ) offset += gcHeaderSize ;
6329- writeI32 ( byteLength , buffer , offset ) ; // .byteLength
6330- offset += bufferHeaderSize ; // align
6308+ writeI32 ( byteLength , buf , pos + bufferInstance . offsetof ( "byteLength" ) ) ;
6309+ pos += bufferHeaderSize ;
63316310 var nativeType = elementType . toNativeType ( ) ;
63326311 switch ( nativeType ) {
63336312 case NativeType . I32 : {
@@ -6337,8 +6316,8 @@ export class Compiler extends DiagnosticEmitter {
63376316 let value = values [ i ] ;
63386317 assert ( getExpressionType ( value ) == nativeType ) ;
63396318 assert ( getExpressionId ( value ) == ExpressionId . Const ) ;
6340- writeI8 ( getConstValueI32 ( value ) , buffer , offset ) ;
6341- offset += 1 ;
6319+ writeI8 ( getConstValueI32 ( value ) , buf , pos ) ;
6320+ pos += 1 ;
63426321 }
63436322 break ;
63446323 }
@@ -6347,8 +6326,8 @@ export class Compiler extends DiagnosticEmitter {
63476326 let value = values [ i ] ;
63486327 assert ( getExpressionType ( value ) == nativeType ) ;
63496328 assert ( getExpressionId ( value ) == ExpressionId . Const ) ;
6350- writeI16 ( getConstValueI32 ( value ) , buffer , offset ) ;
6351- offset += 2 ;
6329+ writeI16 ( getConstValueI32 ( value ) , buf , pos ) ;
6330+ pos += 2 ;
63526331 }
63536332 break ;
63546333 }
@@ -6357,8 +6336,8 @@ export class Compiler extends DiagnosticEmitter {
63576336 let value = values [ i ] ;
63586337 assert ( getExpressionType ( value ) == nativeType ) ;
63596338 assert ( getExpressionId ( value ) == ExpressionId . Const ) ;
6360- writeI32 ( getConstValueI32 ( value ) , buffer , offset ) ;
6361- offset += 4 ;
6339+ writeI32 ( getConstValueI32 ( value ) , buf , pos ) ;
6340+ pos += 4 ;
63626341 }
63636342 break ;
63646343 }
@@ -6371,8 +6350,8 @@ export class Compiler extends DiagnosticEmitter {
63716350 let value = values [ i ] ;
63726351 assert ( getExpressionType ( value ) == nativeType ) ;
63736352 assert ( getExpressionId ( value ) == ExpressionId . Const ) ;
6374- writeI64 ( i64_new ( getConstValueI64Low ( value ) , getConstValueI64High ( value ) ) , buffer , offset ) ;
6375- offset += 8 ;
6353+ writeI64 ( i64_new ( getConstValueI64Low ( value ) , getConstValueI64High ( value ) ) , buf , pos ) ;
6354+ pos += 8 ;
63766355 }
63776356 break ;
63786357 }
@@ -6381,8 +6360,8 @@ export class Compiler extends DiagnosticEmitter {
63816360 let value = values [ i ] ;
63826361 assert ( getExpressionType ( value ) == nativeType ) ;
63836362 assert ( getExpressionId ( value ) == ExpressionId . Const ) ;
6384- writeF32 ( getConstValueF32 ( value ) , buffer , offset ) ;
6385- offset += 4 ;
6363+ writeF32 ( getConstValueF32 ( value ) , buf , pos ) ;
6364+ pos += 4 ;
63866365 }
63876366 break ;
63886367 }
@@ -6391,35 +6370,43 @@ export class Compiler extends DiagnosticEmitter {
63916370 let value = values [ i ] ;
63926371 assert ( getExpressionType ( value ) == nativeType ) ;
63936372 assert ( getExpressionId ( value ) == ExpressionId . Const ) ;
6394- writeF64 ( getConstValueF64 ( value ) , buffer , offset ) ;
6395- offset += 8 ;
6373+ writeF64 ( getConstValueF64 ( value ) , buf , pos ) ;
6374+ pos += 8 ;
63966375 }
63976376 break ;
63986377 }
63996378 default : assert ( false ) ;
64006379 }
6401- assert ( offset <= arrayTotalSize + bufferTotalSize ) ; // might have empty trailing space
6402-
6403- var arrayPrototype = this . program . arrayPrototype ;
6404- if ( arrayPrototype ) {
6405- let arrayInstance = this . resolver . resolveClass ( arrayPrototype , [ elementType ] , null , ReportMode . REPORT ) ;
6406- if ( ! arrayInstance ) {
6407- this . currentType = this . options . usizeType ;
6408- return this . module . createUnreachable ( ) ;
6409- }
6410- this . currentType = arrayInstance . type ;
6380+ var bufferSegment = this . addMemorySegment ( buf ) ;
6381+ var bufferOffset = bufferSegment . offset ;
6382+ if ( hasGC ) bufferOffset = i64_add ( bufferOffset , i64_new ( gcHeaderSize ) ) ;
6383+
6384+ // create the Array segment and return a pointer to it
6385+ var arrayPrototype = assert ( program . arrayPrototype ) ;
6386+ var arrayInstance = assert ( this . resolver . resolveClass ( arrayPrototype , [ elementType ] ) ) ;
6387+ var arrayHeaderSize = ( arrayInstance . currentMemoryOffset + 7 ) & ~ 7 ;
6388+ if ( hasGC ) {
6389+ buf = new Uint8Array ( gcHeaderSize + arrayHeaderSize ) ;
6390+ pos = gcHeaderSize ;
6391+ writeI32 ( ensureGCHook ( this , arrayInstance ) , buf , program . gcHookOffset ) ;
64116392 } else {
6412- this . currentType = this . options . usizeType ;
6393+ buf = new Uint8Array ( arrayHeaderSize ) ;
6394+ pos = 0 ;
64136395 }
6414-
6415- // return a pointer at the array header (skip GC header if present)
6416- var address = segment . offset ;
6417- if ( needsGC ) address = i64_add ( address , i64_new ( gcHeaderSize , 0 ) ) ;
6396+ var arraySegment = this . addMemorySegment ( buf ) ;
6397+ var arrayOffset = arraySegment . offset ;
6398+ if ( hasGC ) arrayOffset = i64_add ( arrayOffset , i64_new ( gcHeaderSize ) ) ;
6399+ this . currentType = arrayInstance . type ;
64186400 if ( usizeTypeSize == 8 ) {
6419- return this . module . createI64 ( i64_low ( address ) , i64_high ( address ) ) ;
6401+ writeI64 ( bufferOffset , buf , pos + arrayInstance . offsetof ( "buffer_" ) ) ;
6402+ writeI32 ( length , buf , pos + arrayInstance . offsetof ( "length_" ) ) ;
6403+ return this . module . createI64 ( i64_low ( arrayOffset ) , i64_high ( arrayOffset ) ) ;
64206404 } else {
6421- assert ( i64_is_u32 ( address ) ) ;
6422- return this . module . createI32 ( i64_low ( address ) ) ;
6405+ assert ( i64_is_u32 ( bufferOffset ) ) ;
6406+ writeI32 ( i64_low ( bufferOffset ) , buf , pos + arrayInstance . offsetof ( "buffer_" ) ) ;
6407+ writeI32 ( length , buf , pos + arrayInstance . offsetof ( "length_" ) ) ;
6408+ assert ( i64_is_u32 ( arrayOffset ) ) ;
6409+ return this . module . createI32 ( i64_low ( arrayOffset ) ) ;
64236410 }
64246411 }
64256412
@@ -6433,17 +6420,20 @@ export class Compiler extends DiagnosticEmitter {
64336420
64346421 // find out whether all elements are constant (array is static)
64356422 var length = expressions . length ;
6436- var values = new Array < ExpressionRef > ( length ) ;
6423+ var compiledValues = new Array < ExpressionRef > ( length ) ;
6424+ var constantValues = new Array < ExpressionRef > ( length ) ;
64376425 var nativeElementType = elementType . toNativeType ( ) ;
64386426 var isStatic = true ;
64396427 for ( let i = 0 ; i < length ; ++ i ) {
6440- values [ i ] = expressions [ i ]
6428+ let expr = expressions [ i ]
64416429 ? this . compileExpression ( < Expression > expressions [ i ] , elementType , ConversionKind . IMPLICIT , WrapMode . NONE )
64426430 : elementType . toNativeZero ( module ) ;
6431+ compiledValues [ i ] = expr ;
64436432 if ( isStatic ) {
6444- let expr = module . precomputeExpression ( values [ i ] ) ;
6433+ expr = module . precomputeExpression ( compiledValues [ i ] ) ;
64456434 if ( getExpressionId ( expr ) == ExpressionId . Const ) {
64466435 assert ( getExpressionType ( expr ) == nativeElementType ) ;
6436+ constantValues [ i ] = expr ;
64476437 } else {
64486438 if ( isConst ) {
64496439 this . warning (
@@ -6457,7 +6447,7 @@ export class Compiler extends DiagnosticEmitter {
64576447 }
64586448
64596449 // make a static array if possible
6460- if ( isStatic ) return this . ensureStaticArray ( elementType , values ) ;
6450+ if ( isStatic ) return this . ensureStaticArray ( elementType , constantValues ) ;
64616451
64626452 // otherwise obtain the array type
64636453 var arrayPrototype = assert ( this . program . arrayPrototype ) ;
@@ -6491,7 +6481,7 @@ export class Compiler extends DiagnosticEmitter {
64916481 stmts [ index ++ ] = this . makeCallDirect ( setter , [
64926482 module . createGetLocal ( tempLocal . index , nativeArrayType ) , // this
64936483 module . createI32 ( i ) ,
6494- values [ i ]
6484+ compiledValues [ i ]
64956485 ] ) ;
64966486 }
64976487 assert ( index + 1 == stmts . length ) ;
0 commit comments