@@ -76,6 +76,7 @@ import {
76
76
FunctionTarget ,
77
77
Global ,
78
78
Local ,
79
+ ClosedLocal ,
79
80
EnumValue ,
80
81
Property ,
81
82
VariableLikeElement ,
@@ -396,6 +397,7 @@ export class Compiler extends DiagnosticEmitter {
396
397
var module = this . module ;
397
398
var program = this . program ;
398
399
400
+
399
401
// check and perform this program initialization if it hasn't been done
400
402
this . initializeProgram ( ) ;
401
403
@@ -415,6 +417,8 @@ export class Compiler extends DiagnosticEmitter {
415
417
module . addGlobal ( BuiltinNames . rtti_base , NativeType . I32 , true , module . i32 ( 0 ) ) ;
416
418
}
417
419
420
+ module . addGlobal ( BuiltinNames . global_closure , NativeType . I32 , true , module . i32 ( - 1 ) ) ;
421
+
418
422
// compile entry file(s) while traversing reachable elements
419
423
var files = program . filesByName ;
420
424
// TODO: for (let file of files.values()) {
@@ -3407,7 +3411,7 @@ export class Compiler extends DiagnosticEmitter {
3407
3411
// pretend to retain the expression immediately so the autorelease, if any, is skipped
3408
3412
var expr = this . compileExpression ( expression , returnType , constraints | Constraints . WILL_RETAIN ) ;
3409
3413
var flow = this . currentFlow ;
3410
- if ( returnType . isManaged ) {
3414
+ if ( returnType . isManaged || returnType . signatureReference ) {
3411
3415
// check if that worked, and if it didn't, keep the reference alive
3412
3416
if ( ! this . skippedAutoreleases . has ( expr ) ) {
3413
3417
let index = this . tryUndoAutorelease ( expr , flow ) ;
@@ -3460,6 +3464,18 @@ export class Compiler extends DiagnosticEmitter {
3460
3464
}
3461
3465
fromType = fromType . nonNullableType ;
3462
3466
}
3467
+ if ( fromType . is ( TypeFlags . CLOSURE ) ) {
3468
+ return module . block ( null , [
3469
+ module . store (
3470
+ 1 ,
3471
+ expr ,
3472
+ this . module . local_get ( fromType . locals ! [ 0 ] . index , this . options . nativeSizeType ) ,
3473
+ NativeType . I32 ,
3474
+ 4
3475
+ ) ,
3476
+ expr
3477
+ ] , NativeType . I32 )
3478
+ }
3463
3479
if ( fromType . isAssignableTo ( toType ) ) { // downcast or same
3464
3480
assert ( fromType . kind == toType . kind ) ;
3465
3481
this . currentType = toType ;
@@ -5801,6 +5817,10 @@ export class Compiler extends DiagnosticEmitter {
5801
5817
if ( target . hasDecorator ( DecoratorFlags . UNSAFE ) ) this . checkUnsafe ( expression ) ;
5802
5818
break ;
5803
5819
}
5820
+ case ElementKind . CLOSEDLOCAL : {
5821
+ targetType = Type . i32
5822
+ break ;
5823
+ }
5804
5824
case ElementKind . PROPERTY_PROTOTYPE : { // static property
5805
5825
let propertyPrototype = < PropertyPrototype > target ;
5806
5826
let setterPrototype = propertyPrototype . setterPrototype ;
@@ -5925,6 +5945,23 @@ export class Compiler extends DiagnosticEmitter {
5925
5945
}
5926
5946
return this . makeLocalAssignment ( local , valueExpr , valueType , tee ) ;
5927
5947
}
5948
+ case ElementKind . CLOSEDLOCAL : {
5949
+ this . error (
5950
+ DiagnosticCode . Not_implemented ,
5951
+ valueExpression . range
5952
+ ) ;
5953
+ return module . unreachable ( ) ;
5954
+ //return module.block(null, [
5955
+ //module.store(
5956
+ //1,
5957
+ //this.module.global_get(BuiltinNames.global_closure, this.options.nativeSizeType),
5958
+ //valueExpr,
5959
+ //NativeType.I32,
5960
+ //4
5961
+ //),
5962
+ //valueExpr
5963
+ //], NativeType.I32)
5964
+ }
5928
5965
case ElementKind . GLOBAL : {
5929
5966
let global = < Global > target ;
5930
5967
if ( ! this . compileGlobal ( global ) ) return module . unreachable ( ) ;
@@ -6307,7 +6344,6 @@ export class Compiler extends DiagnosticEmitter {
6307
6344
/** Constraints indicating contextual conditions. */
6308
6345
constraints : Constraints
6309
6346
) : ExpressionRef {
6310
-
6311
6347
var module = this . module ;
6312
6348
var flow = this . currentFlow ;
6313
6349
@@ -6376,8 +6412,8 @@ export class Compiler extends DiagnosticEmitter {
6376
6412
6377
6413
var signature : Signature | null ;
6378
6414
var indexArg : ExpressionRef ;
6415
+ var closedLocal : Local | null = null ;
6379
6416
switch ( target . kind ) {
6380
-
6381
6417
// direct call: concrete function
6382
6418
case ElementKind . FUNCTION_PROTOTYPE : {
6383
6419
let functionPrototype = < FunctionPrototype > target ;
@@ -6404,13 +6440,64 @@ export class Compiler extends DiagnosticEmitter {
6404
6440
// indirect call: index argument with signature (non-generic, can't be inlined)
6405
6441
case ElementKind . LOCAL : {
6406
6442
let local = < Local > target ;
6443
+ if ( local . type . is ( TypeFlags . CLOSURE ) ) {
6444
+ signature = new Signature ( this . program , [ ] , Type . i32 )
6445
+ var closedLocals = local . type . locals ! ;
6446
+ console . log ( closedLocals )
6447
+ indexArg = module . block ( null , [
6448
+ module . store (
6449
+ 1 ,
6450
+ this . module . local_get ( local . index , this . options . nativeSizeType ) ,
6451
+ this . module . local_get ( closedLocals [ 0 ] . index , NativeType . I32 ) ,
6452
+ NativeType . I32 ,
6453
+ 4
6454
+ ) ,
6455
+ module . global_set (
6456
+ BuiltinNames . global_closure ,
6457
+ this . module . local_get ( local . index , NativeType . I32 )
6458
+ ) ,
6459
+ module . load (
6460
+ 1 ,
6461
+ true ,
6462
+ this . module . local_get ( local . index , NativeType . I32 ) ,
6463
+ NativeType . I32 ,
6464
+ 0
6465
+ )
6466
+ ] , NativeType . I32 ) ;
6467
+ break ;
6468
+ }
6407
6469
signature = local . type . signatureReference ;
6408
6470
if ( signature ) {
6409
6471
if ( local . is ( CommonFlags . INLINED ) ) {
6410
6472
indexArg = module . i32 ( i64_low ( local . constantIntegerValue ) ) ;
6411
6473
} else {
6412
6474
indexArg = module . local_get ( local . index , NativeType . I32 ) ;
6413
6475
}
6476
+ indexArg = module . if (
6477
+ module . binary (
6478
+ BinaryOp . EqI32 ,
6479
+ module . binary (
6480
+ BinaryOp . RemI32 ,
6481
+ indexArg ,
6482
+ module . i32 ( 16 )
6483
+ ) ,
6484
+ module . i32 ( 0 )
6485
+ ) ,
6486
+ module . block ( null , [
6487
+ module . global_set (
6488
+ BuiltinNames . global_closure ,
6489
+ indexArg
6490
+ ) ,
6491
+ module . load (
6492
+ 1 ,
6493
+ true ,
6494
+ indexArg ,
6495
+ NativeType . I32 ,
6496
+ 0
6497
+ )
6498
+ ] , NativeType . I32 ) ,
6499
+ indexArg
6500
+ )
6414
6501
break ;
6415
6502
}
6416
6503
this . error (
@@ -6512,14 +6599,32 @@ export class Compiler extends DiagnosticEmitter {
6512
6599
return module . unreachable ( ) ;
6513
6600
}
6514
6601
}
6515
- return this . compileCallIndirect (
6602
+ var callExpr = this . compileCallIndirect (
6516
6603
assert ( signature ) , // FIXME: asc can't see this yet
6517
6604
indexArg ,
6518
6605
expression . arguments ,
6519
6606
expression ,
6520
6607
0 ,
6521
6608
contextualType == Type . void
6522
6609
) ;
6610
+
6611
+ //Closure write-back
6612
+ //if (closedLocal) {
6613
+ //return module.block(null, [
6614
+ //callExpr,
6615
+ //module.local_set(
6616
+ //closedLocal.index,
6617
+ //module.load(
6618
+ //1,
6619
+ //true,
6620
+ //this.module.global_get(BuiltinNames.global_closure, NativeType.I32),
6621
+ //NativeType.I32,
6622
+ //4
6623
+ //)
6624
+ //)
6625
+ //], NativeType.I32)
6626
+ //}
6627
+ return callExpr ;
6523
6628
}
6524
6629
6525
6630
private compileCallExpressionBuiltin (
@@ -7016,6 +7121,7 @@ export class Compiler extends DiagnosticEmitter {
7016
7121
var module = this . module ;
7017
7122
var flow = this . currentFlow ;
7018
7123
var nativeSizeType = this . options . nativeSizeType ;
7124
+ assert ( false )
7019
7125
if ( alreadyRetained ) {
7020
7126
// (t1=newExpr), __release(oldExpr), t1
7021
7127
// it is important that `newExpr` evaluates before `oldExpr` is released, hence the local
@@ -7082,6 +7188,7 @@ export class Compiler extends DiagnosticEmitter {
7082
7188
//
7083
7189
// callReceivingAReference((__release(t = callReturningAReference()), t))
7084
7190
//
7191
+ assert ( false )
7085
7192
var local = flow . getAutoreleaseLocal ( type ) ;
7086
7193
if ( flow . isNonnull ( expr , type ) ) flow . setLocalFlag ( local . index , LocalFlags . NONNULL ) ;
7087
7194
return this . module . local_tee ( local . index , expr ) ;
@@ -7608,8 +7715,83 @@ export class Compiler extends DiagnosticEmitter {
7608
7715
var instance : Function | null ;
7609
7716
var contextualTypeArguments = makeMap ( flow . contextualTypeArguments ) ;
7610
7717
7611
- // compile according to context. this differs from a normal function in that omitted parameter
7612
- // and return types can be inferred and omitted arguments can be replaced with dummies.
7718
+ if ( prototype . name . startsWith ( "anonymous" ) ) {
7719
+ console . log ( "compiling " + prototype . name + " as a closure" )
7720
+ let generatedClosureType = new Type (
7721
+ TypeKind . U32 ,
7722
+ TypeFlags . CLOSURE | TypeFlags . REFERENCE | TypeFlags . POINTER , //flags
7723
+ 64
7724
+ )
7725
+
7726
+ this . currentType = generatedClosureType ;
7727
+
7728
+ assert ( ! contextualSignature )
7729
+
7730
+ instance = this . resolver . resolveFunction ( prototype , null , contextualTypeArguments ) ;
7731
+ if ( ! instance ) return this . module . unreachable ( ) ;
7732
+ this . compileFunction ( instance ) ;
7733
+ //this.currentType = instance.signature.type;
7734
+
7735
+ //create function
7736
+ var index = this . ensureFunctionTableEntry ( instance ! ) ; // reports
7737
+ console . log ( "closure " + prototype . name + " was assigned func table entry " + index . toString ( ) )
7738
+
7739
+ var closedLocals = instance . closedLocals
7740
+
7741
+
7742
+ var names = [ "fn" , "scopeI32" ] ;
7743
+ var numNames = names . length ;
7744
+ var values = [
7745
+ this . module . i32 ( index ) ,
7746
+ this . module . local_get ( closedLocals [ 0 ] . index , NativeType . I32 )
7747
+ ] ;
7748
+ var exprs = new Array < ExpressionRef > ( numNames + 2 ) ;
7749
+ var flow = this . currentFlow ;
7750
+ //var tempLocal = flow.getAutoreleaseLocal(generatedClosureType);
7751
+ var tempLocal = flow . getTempLocal ( generatedClosureType ) ;
7752
+
7753
+ generatedClosureType . locals = closedLocals ;
7754
+
7755
+ for ( let i = 0 , k = numNames ; i < k ; ++ i ) {
7756
+ exprs [ i + 1 ] = this . module . store ( // TODO: handle setters as well
7757
+ 1 ,
7758
+ this . module . local_get ( tempLocal . index , this . options . nativeSizeType ) ,
7759
+ values [ i ] ,
7760
+ NativeType . I32 ,
7761
+ i * 4
7762
+ ) ;
7763
+ }
7764
+ //this.currentType = classReference.type.nonNullableType;
7765
+ this . currentType = generatedClosureType ;
7766
+
7767
+ // allocate a new instance first and assign 'this' to the temp. local
7768
+ exprs [ 0 ] = this . module . local_set (
7769
+ tempLocal . index ,
7770
+ this . module . call ( this . program . allocInstance . internalName , [
7771
+ this . module . i32 ( 2 ) ,
7772
+ this . module . i32 ( 0 )
7773
+ ] , NativeType . I32 )
7774
+ ) ;
7775
+
7776
+ //Set closure global
7777
+ //exprs[exprs.length - 2] = this.module.global_set(
7778
+ //BuiltinNames.global_closure,
7779
+ //this.module.local_get(tempLocal.index, NativeType.I32)
7780
+ //)
7781
+ //exprs[exprs.length - 2] = this.module.global_set("GLOBAL_CLOSURE", this.module.i32(1))
7782
+
7783
+ // once all field values have been set, return 'this'
7784
+ exprs [ exprs . length - 1 ] = this . module . local_get ( tempLocal . index , this . options . nativeSizeType ) ;
7785
+
7786
+ return this . module . flatten ( exprs , this . options . nativeSizeType ) ;
7787
+
7788
+ //return index < 0
7789
+ //? this.module.unreachable()
7790
+ //: this.module.i32(index);
7791
+ }
7792
+
7793
+ //compile according to context. this differs from a normal function in that omitted parameter
7794
+ //and return types can be inferred and omitted arguments can be replaced with dummies.
7613
7795
if ( contextualSignature ) {
7614
7796
let signatureNode = prototype . functionTypeNode ;
7615
7797
let parameterNodes = signatureNode . parameters ;
@@ -7965,6 +8147,17 @@ export class Compiler extends DiagnosticEmitter {
7965
8147
this . currentType = functionInstance . signature . type ;
7966
8148
return module . i32 ( index ) ;
7967
8149
}
8150
+ case ElementKind . CLOSEDLOCAL : {
8151
+ let closedLocal = < ClosedLocal > target ;
8152
+
8153
+ return module . load (
8154
+ 1 ,
8155
+ true ,
8156
+ this . module . global_get ( BuiltinNames . global_closure , NativeType . I32 ) ,
8157
+ NativeType . I32 ,
8158
+ 4
8159
+ ) ;
8160
+ }
7968
8161
}
7969
8162
this . error (
7970
8163
DiagnosticCode . Not_implemented ,
0 commit comments