@@ -23,7 +23,8 @@ import {
2323 NativeType ,
2424 FunctionRef ,
2525 ExpressionId ,
26- FunctionTypeRef
26+ FunctionTypeRef ,
27+ GlobalRef
2728} from "./module" ;
2829
2930import {
@@ -194,29 +195,26 @@ export class Compiler extends DiagnosticEmitter {
194195 options : Options ;
195196 /** Module instance being compiled. */
196197 module : Module ;
197-
198- /** Start function being compiled. */
199- startFunction : Function ;
200- /** Start function statements. */
201- startFunctionBody : ExpressionRef [ ] = [ ] ;
202-
203198 /** Current function in compilation. */
204199 currentFunction : Function ;
205200 /** Current enum in compilation. */
206201 currentEnum : Enum | null = null ;
207202 /** Current type in compilation. */
208203 currentType : Type = Type . void ;
209-
204+ /** Start function being compiled. */
205+ startFunction : Function ;
206+ /** Start function statements. */
207+ startFunctionBody : ExpressionRef [ ] = [ ] ;
210208 /** Counting memory offset. */
211209 memoryOffset : I64 ;
212210 /** Memory segments being compiled. */
213211 memorySegments : MemorySegment [ ] = new Array ( ) ;
214212 /** Map of already compiled static string segments. */
215213 stringSegments : Map < string , MemorySegment > = new Map ( ) ;
216-
217214 /** Function table being compiled. */
218215 functionTable : Function [ ] = new Array ( ) ;
219-
216+ /** Argument count helper global. */
217+ argumentCountRef : GlobalRef = 0 ;
220218 /** Already processed file names. */
221219 files : Set < string > = new Set ( ) ;
222220
@@ -1192,7 +1190,7 @@ export class Compiler extends DiagnosticEmitter {
11921190 }
11931191 var functionTable = this . functionTable ;
11941192 var index = functionTable . length ;
1195- if ( func . signature . requiredParameters < func . signature . parameterTypes . length ) {
1193+ if ( ! func . is ( CommonFlags . TRAMPOLINE ) && func . signature . requiredParameters < func . signature . parameterTypes . length ) {
11961194 // insert the trampoline if the function has optional parameters
11971195 func = this . ensureTrampoline ( func ) ;
11981196 }
@@ -4314,8 +4312,7 @@ export class Compiler extends DiagnosticEmitter {
43144312 ++ minOperands ;
43154313 ++ maxOperands ;
43164314 }
4317- var numOptional = maxOperands - minOperands ;
4318- assert ( numOptional ) ;
4315+ var numOptional = assert ( maxOperands - minOperands ) ;
43194316
43204317 var forwardedOperands = new Array < ExpressionRef > ( minOperands ) ;
43214318 var operandIndex = 0 ;
@@ -4333,21 +4330,13 @@ export class Compiler extends DiagnosticEmitter {
43334330 }
43344331 assert ( operandIndex == minOperands ) ;
43354332
4336- // append an additional parameter taking the number of optional arguments provided
4337- var trampolineParameterTypes = new Array < Type > ( maxArguments + 1 ) ;
4338- for ( let i = 0 ; i < maxArguments ; ++ i ) {
4339- trampolineParameterTypes [ i ] = originalParameterTypes [ i ] ;
4340- }
4341- trampolineParameterTypes [ maxArguments ] = Type . i32 ;
4342-
43434333 // create the trampoline element
4344- var trampolineSignature = new Signature ( trampolineParameterTypes , commonReturnType , commonThisType ) ;
4334+ var trampolineSignature = new Signature ( originalParameterTypes , commonReturnType , commonThisType ) ;
43454335 var trampolineName = originalName + "|trampoline" ;
4346- trampolineSignature . requiredParameters = maxArguments + 1 ;
4336+ trampolineSignature . requiredParameters = maxArguments ;
43474337 trampoline = new Function ( original . prototype , trampolineName , trampolineSignature , original . memberOf ) ;
4348- trampoline . flags = original . flags ;
4338+ trampoline . set ( original . flags | CommonFlags . TRAMPOLINE | CommonFlags . COMPILED ) ;
43494339 trampoline . contextualTypeArguments = original . contextualTypeArguments ;
4350- trampoline . set ( CommonFlags . COMPILED ) ;
43514340 original . trampoline = trampoline ;
43524341
43534342 // compile initializers of omitted arguments in scope of the trampoline function
@@ -4356,23 +4345,24 @@ export class Compiler extends DiagnosticEmitter {
43564345 this . currentFunction = trampoline ;
43574346
43584347 // create a br_table switching over the number of optional parameters provided
4359- var numNames = numOptional + 1 ; // incl. 'with0'
4348+ var numNames = numOptional + 1 ; // incl. outer block
43604349 var names = new Array < string > ( numNames ) ;
4350+ var ofN = "of" + numOptional . toString ( 10 ) ;
43614351 for ( let i = 0 ; i < numNames ; ++ i ) {
4362- let label = "N=" + i . toString ( ) ;
4352+ let label = i . toString ( 10 ) + ofN ;
43634353 names [ i ] = label ;
43644354 }
43654355 var body = module . createBlock ( names [ 0 ] , [
4366- module . createBlock ( "N=invalid " , [
4367- module . createSwitch ( names , "N=invalid " ,
4368- // condition is number of provided optional operands , so subtract required operands
4369- minOperands
4356+ module . createBlock ( "oob " , [
4357+ module . createSwitch ( names , "oob " ,
4358+ // condition is number of provided optional arguments , so subtract required arguments
4359+ minArguments
43704360 ? module . createBinary (
43714361 BinaryOp . SubI32 ,
4372- module . createGetLocal ( maxOperands , NativeType . I32 ) ,
4373- module . createI32 ( minOperands )
4362+ module . createGetGlobal ( "argumentCount" , NativeType . I32 ) ,
4363+ module . createI32 ( minArguments )
43744364 )
4375- : module . createGetLocal ( maxOperands , NativeType . I32 )
4365+ : module . createGetGlobal ( "argumentCount" , NativeType . I32 )
43764366 )
43774367 ] ) ,
43784368 module . createUnreachable ( )
@@ -4409,7 +4399,10 @@ export class Compiler extends DiagnosticEmitter {
44094399 }
44104400
44114401 /** Creates a direct call to the specified function. */
4412- makeCallDirect ( instance : Function , operands : ExpressionRef [ ] | null = null ) : ExpressionRef {
4402+ makeCallDirect (
4403+ instance : Function ,
4404+ operands : ExpressionRef [ ] | null = null
4405+ ) : ExpressionRef {
44134406 var numOperands = operands ? operands . length : 0 ;
44144407 var numArguments = numOperands ;
44154408 var minArguments = instance . signature . requiredParameters ;
@@ -4422,27 +4415,39 @@ export class Compiler extends DiagnosticEmitter {
44224415 -- numArguments ;
44234416 }
44244417 assert ( numOperands >= minOperands ) ;
4418+
44254419 var module = this . module ;
44264420 if ( ! this . compileFunction ( instance ) ) return module . createUnreachable ( ) ;
4421+ var returnType = instance . signature . returnType ;
4422+ var isCallImport = instance . is ( CommonFlags . MODULE_IMPORT ) ;
4423+
4424+ // fill up omitted arguments with zeroes
44274425 if ( numOperands < maxOperands ) {
4428- instance = this . ensureTrampoline ( instance ) ;
4429- if ( ! this . compileFunction ( instance ) ) return module . createUnreachable ( ) ;
44304426 if ( ! operands ) {
4431- operands = new Array ( maxOperands + 1 ) ;
4427+ operands = new Array ( maxOperands ) ;
44324428 operands . length = 0 ;
44334429 }
4430+ let parameterTypes = instance . signature . parameterTypes ;
44344431 for ( let i = numArguments ; i < maxArguments ; ++ i ) {
4435- operands . push ( instance . signature . parameterTypes [ i ] . toNativeZero ( module ) ) ;
4432+ operands . push ( parameterTypes [ i ] . toNativeZero ( module ) ) ;
4433+ }
4434+ if ( ! isCallImport ) { // call the trampoline
4435+ instance = this . ensureTrampoline ( instance ) ;
4436+ if ( ! this . compileFunction ( instance ) ) return module . createUnreachable ( ) ;
4437+ let nativeReturnType = returnType . toNativeType ( ) ;
4438+ this . currentType = returnType ;
4439+ return module . createBlock ( null , [
4440+ this . ensureArgumentCount ( numArguments ) ,
4441+ module . createCall ( instance . internalName , operands , nativeReturnType )
4442+ ] , nativeReturnType ) ;
44364443 }
4437- operands . push ( module . createI32 ( numOperands ) ) ; // actual number of provided operands
44384444 }
4439- var returnType = instance . signature . returnType ;
4445+
4446+ // otherwise just call through
44404447 this . currentType = returnType ;
4441- if ( instance . is ( CommonFlags . MODULE_IMPORT ) ) {
4442- return module . createCallImport ( instance . internalName , operands , returnType . toNativeType ( ) ) ;
4443- } else {
4444- return module . createCall ( instance . internalName , operands , returnType . toNativeType ( ) ) ;
4445- }
4448+ return isCallImport
4449+ ? module . createCallImport ( instance . internalName , operands , returnType . toNativeType ( ) )
4450+ : module . createCall ( instance . internalName , operands , returnType . toNativeType ( ) ) ;
44464451 }
44474452
44484453 /** Compiles an indirect call using an index argument and a signature. */
@@ -4483,11 +4488,59 @@ export class Compiler extends DiagnosticEmitter {
44834488 }
44844489
44854490 /** Creates an indirect call to the function at `indexArg` in the function table. */
4486- makeCallIndirect ( signature : Signature , indexArg : ExpressionRef , operands : ExpressionRef [ ] ) : ExpressionRef {
4491+ makeCallIndirect (
4492+ signature : Signature ,
4493+ indexArg : ExpressionRef ,
4494+ operands : ExpressionRef [ ] | null = null
4495+ ) : ExpressionRef {
4496+ var numOperands = operands ? operands . length : 0 ;
4497+ var numArguments = numOperands ;
4498+ var minArguments = signature . requiredParameters ;
4499+ var minOperands = minArguments ;
4500+ var maxArguments = signature . parameterTypes . length ;
4501+ var maxOperands = maxArguments ;
4502+ if ( signature . thisType ) {
4503+ ++ minOperands ;
4504+ ++ maxOperands ;
4505+ -- numArguments ;
4506+ }
4507+ assert ( numOperands >= minOperands ) ;
4508+
4509+ this . ensureFunctionType ( signature ) ;
4510+ var module = this . module ;
4511+
4512+ // fill up omitted arguments with zeroes
4513+ if ( numOperands < maxOperands ) {
4514+ if ( ! operands ) {
4515+ operands = new Array ( maxOperands ) ;
4516+ operands . length = 0 ;
4517+ }
4518+ let parameterTypes = signature . parameterTypes ;
4519+ for ( let i = numArguments ; i < maxArguments ; ++ i ) {
4520+ operands . push ( parameterTypes [ i ] . toNativeZero ( module ) ) ;
4521+ }
4522+ }
4523+
44874524 var returnType = signature . returnType ;
44884525 this . currentType = returnType ;
4489- this . ensureFunctionType ( signature ) ;
4490- return this . module . createCallIndirect ( indexArg , operands , signature . toSignatureString ( ) ) ;
4526+ return module . createBlock ( null , [
4527+ this . ensureArgumentCount ( numArguments ) , // might still be calling a trampoline
4528+ module . createCallIndirect ( indexArg , operands , signature . toSignatureString ( ) )
4529+ ] , returnType . toNativeType ( ) ) ;
4530+ }
4531+
4532+ /** Makes sure that the `argumentCount` helper global is present and returns an expression that sets it. */
4533+ private ensureArgumentCount ( argumentCount : i32 ) : ExpressionRef {
4534+ var module = this . module ;
4535+ if ( ! this . argumentCountRef ) {
4536+ this . argumentCountRef = module . addGlobal (
4537+ "argumentCount" ,
4538+ NativeType . I32 ,
4539+ true ,
4540+ module . createI32 ( 0 )
4541+ ) ;
4542+ }
4543+ return module . createSetGlobal ( "argumentCount" , module . createI32 ( argumentCount ) ) ;
44914544 }
44924545
44934546 compileCommaExpression ( expression : CommaExpression , contextualType : Type ) : ExpressionRef {
0 commit comments