@@ -119,6 +119,13 @@ import {
119119 typesToNativeTypes
120120} from "./types" ;
121121
122+ import {
123+ writeI32 ,
124+ writeI64 ,
125+ writeF32 ,
126+ writeF64
127+ } from "./util" ;
128+
122129/** Compilation target. */
123130export enum Target {
124131 /** WebAssembly with 32-bit pointers. */
@@ -4564,11 +4571,10 @@ export class Compiler extends DiagnosticEmitter {
45644571 let classType = contextualType . classType ;
45654572 if (
45664573 classType &&
4567- classType == this . program . elementsLookup . get ( "Array" ) &&
4568- classType . typeArguments && classType . typeArguments . length == 1
4574+ classType . prototype == this . program . elementsLookup . get ( "Array" )
45694575 ) {
45704576 return this . compileStaticArray (
4571- classType . typeArguments [ 0 ] ,
4577+ assert ( classType . typeArguments ) [ 0 ] ,
45724578 ( < ArrayLiteralExpression > expression ) . elementExpressions ,
45734579 expression
45744580 ) ;
@@ -4725,29 +4731,38 @@ export class Compiler extends DiagnosticEmitter {
47254731 }
47264732
47274733 compileStaticArray ( elementType : Type , expressions : ( Expression | null ) [ ] , reportNode : Node ) : ExpressionRef {
4728- // compile as static if all element expressions are precomputable, otherwise
4729- // initialize in place.
47304734 var isStatic = true ;
4731- var size = expressions . length ;
4732-
47334735 var module = this . module ;
4736+
4737+ // obtain the array type
4738+ var arrayPrototype = assert ( this . program . elementsLookup . get ( "Array" ) ) ;
4739+ if ( ! arrayPrototype || arrayPrototype . kind != ElementKind . CLASS_PROTOTYPE ) return module . createUnreachable ( ) ;
4740+ var arrayType = ( < ClassPrototype > arrayPrototype ) . resolve ( [ elementType ] ) ;
4741+ if ( ! arrayType ) return module . createUnreachable ( ) ;
4742+
4743+ var elementSize = expressions . length ;
47344744 var nativeType = elementType . toNativeType ( ) ;
47354745 var values : usize ;
4746+ var memorySize : usize ;
47364747 switch ( nativeType ) {
47374748 case NativeType . I32 : {
4738- values = changetype < usize > ( new Int32Array ( size ) ) ;
4749+ values = changetype < usize > ( new Int32Array ( elementSize ) ) ;
4750+ memorySize = elementSize * 4 ;
47394751 break ;
47404752 }
47414753 case NativeType . I64 : {
4742- values = changetype < usize > ( new Array < I64 > ( size ) ) ;
4754+ values = changetype < usize > ( new Array < I64 > ( elementSize ) ) ;
4755+ memorySize = elementSize * 8 ;
47434756 break ;
47444757 }
47454758 case NativeType . F32 : {
4746- values = changetype < usize > ( new Float32Array ( size ) ) ;
4759+ values = changetype < usize > ( new Float32Array ( elementSize ) ) ;
4760+ memorySize = elementSize * 4 ;
47474761 break ;
47484762 }
47494763 case NativeType . F64 : {
4750- values = changetype < usize > ( new Float64Array ( size ) ) ;
4764+ values = changetype < usize > ( new Float64Array ( elementSize ) ) ;
4765+ memorySize = elementSize * 8 ;
47514766 break ;
47524767 }
47534768 default : {
@@ -4760,9 +4775,10 @@ export class Compiler extends DiagnosticEmitter {
47604775 }
47614776 }
47624777
4763- var exprs = new Array < ExpressionRef > ( size ) ;
4778+ // precompute value expressions
4779+ var exprs = new Array < ExpressionRef > ( elementSize ) ;
47644780 var expr : BinaryenExpressionRef ;
4765- for ( let i = 0 ; i < size ; ++ i ) {
4781+ for ( let i = 0 ; i < elementSize ; ++ i ) {
47664782 exprs [ i ] = expressions [ i ]
47674783 ? this . compileExpression ( < Expression > expressions [ i ] , elementType )
47684784 : elementType . toNativeZero ( module ) ;
@@ -4801,14 +4817,78 @@ export class Compiler extends DiagnosticEmitter {
48014817 }
48024818 }
48034819
4820+ var usizeTypeSize = this . options . usizeType . byteSize ;
4821+ var headerSize = usizeTypeSize + 4 + 4 ; // memory + capacity + length
4822+
48044823 if ( isStatic ) {
4805- // TODO: convert to Uint8Array and create the segment
4824+ let buffer = new Uint8Array ( headerSize + memorySize ) ;
4825+ let segment = this . addMemorySegment ( buffer ) ;
4826+
4827+ // make header
4828+ let offset = 0 ;
4829+ if ( usizeTypeSize == 8 ) {
4830+ writeI64 ( i64_add ( segment . offset , i64_new ( headerSize ) ) , buffer , 0 ) ; // memory
4831+ } else {
4832+ assert ( i64_high ( segment . offset ) == 0 ) ;
4833+ writeI32 ( i64_low ( segment . offset ) + headerSize , buffer , 0 ) ; // memory
4834+ }
4835+ offset += usizeTypeSize ;
4836+ writeI32 ( elementSize , buffer , offset ) ; // capacity
4837+ offset += 4 ;
4838+ writeI32 ( elementSize , buffer , offset ) ; // length
4839+ offset += 4 ;
4840+ assert ( offset == headerSize ) ;
4841+
4842+ // make memory
4843+ switch ( nativeType ) {
4844+ case NativeType . I32 : {
4845+ for ( let i = 0 ; i < elementSize ; ++ i ) {
4846+ writeI32 ( changetype < i32 [ ] > ( values ) [ i ] , buffer , offset ) ; offset += 4 ;
4847+ }
4848+ break ;
4849+ }
4850+ case NativeType . I64 : {
4851+ for ( let i = 0 ; i < elementSize ; ++ i ) {
4852+ writeI64 ( changetype < I64 [ ] > ( values ) [ i ] , buffer , offset ) ; offset += 8 ;
4853+ }
4854+ break ;
4855+ }
4856+ case NativeType . F32 : {
4857+ for ( let i = 0 ; i < elementSize ; ++ i ) {
4858+ writeF32 ( changetype < f32 [ ] > ( values ) [ i ] , buffer , offset ) ; offset += 4 ;
4859+ }
4860+ break ;
4861+ }
4862+ case NativeType . F64 : {
4863+ for ( let i = 0 ; i < elementSize ; ++ i ) {
4864+ writeF64 ( changetype < f64 [ ] > ( values ) [ i ] , buffer , offset ) ; offset += 8 ;
4865+ }
4866+ break ;
4867+ }
4868+ default : {
4869+ assert ( false ) ;
4870+ this . error (
4871+ DiagnosticCode . Operation_not_supported ,
4872+ reportNode . range
4873+ ) ;
4874+ return module . createUnreachable ( ) ;
4875+ }
4876+ }
4877+ assert ( offset == headerSize + memorySize ) ;
4878+ this . currentType = arrayType . type ;
4879+ return usizeTypeSize == 8
4880+ ? module . createI64 (
4881+ i64_low ( segment . offset ) ,
4882+ i64_high ( segment . offset )
4883+ )
4884+ : module . createI32 (
4885+ i64_low ( segment . offset )
4886+ ) ;
48064887 } else {
4807- // TODO: initialize in place
4888+ // TODO: static elements *could* go into data segments while dynamic ones are initialized
4889+ // on top? any benefits?
4890+ throw new Error ( "not implemented" ) ;
48084891 }
4809- // TODO: alternatively, static elements could go into data segments while
4810- // dynamic ones are initialized on top? any benefits? (doesn't seem so)
4811- throw new Error ( "not implemented" ) ;
48124892 }
48134893
48144894 compileNewExpression ( expression : NewExpression , contextualType : Type ) : ExpressionRef {
0 commit comments