Skip to content

Commit 1b8c510

Browse files
committed
temp
1 parent 0553d16 commit 1b8c510

File tree

8 files changed

+260
-10
lines changed

8 files changed

+260
-10
lines changed

src/builtins.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,9 @@ export namespace BuiltinNames {
560560
export const visit_globals = "~lib/rt/__visit_globals";
561561
export const visit_members = "~lib/rt/__visit_members";
562562

563+
// std/closure.ts
564+
export const global_closure = "~lib/closure/__global_closure";
565+
563566
// std/number.ts
564567
export const isNaN = "~lib/number/isNaN";
565568
export const isFinite = "~lib/number/isFinite";

src/compiler.ts

Lines changed: 199 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ import {
7676
FunctionTarget,
7777
Global,
7878
Local,
79+
ClosedLocal,
7980
EnumValue,
8081
Property,
8182
VariableLikeElement,
@@ -396,6 +397,7 @@ export class Compiler extends DiagnosticEmitter {
396397
var module = this.module;
397398
var program = this.program;
398399

400+
399401
// check and perform this program initialization if it hasn't been done
400402
this.initializeProgram();
401403

@@ -415,6 +417,8 @@ export class Compiler extends DiagnosticEmitter {
415417
module.addGlobal(BuiltinNames.rtti_base, NativeType.I32, true, module.i32(0));
416418
}
417419

420+
module.addGlobal(BuiltinNames.global_closure, NativeType.I32, true, module.i32(-1));
421+
418422
// compile entry file(s) while traversing reachable elements
419423
var files = program.filesByName;
420424
// TODO: for (let file of files.values()) {
@@ -3407,7 +3411,7 @@ export class Compiler extends DiagnosticEmitter {
34073411
// pretend to retain the expression immediately so the autorelease, if any, is skipped
34083412
var expr = this.compileExpression(expression, returnType, constraints | Constraints.WILL_RETAIN);
34093413
var flow = this.currentFlow;
3410-
if (returnType.isManaged) {
3414+
if (returnType.isManaged || returnType.signatureReference) {
34113415
// check if that worked, and if it didn't, keep the reference alive
34123416
if (!this.skippedAutoreleases.has(expr)) {
34133417
let index = this.tryUndoAutorelease(expr, flow);
@@ -3460,6 +3464,18 @@ export class Compiler extends DiagnosticEmitter {
34603464
}
34613465
fromType = fromType.nonNullableType;
34623466
}
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+
}
34633479
if (fromType.isAssignableTo(toType)) { // downcast or same
34643480
assert(fromType.kind == toType.kind);
34653481
this.currentType = toType;
@@ -5801,6 +5817,10 @@ export class Compiler extends DiagnosticEmitter {
58015817
if (target.hasDecorator(DecoratorFlags.UNSAFE)) this.checkUnsafe(expression);
58025818
break;
58035819
}
5820+
case ElementKind.CLOSEDLOCAL: {
5821+
targetType = Type.i32
5822+
break;
5823+
}
58045824
case ElementKind.PROPERTY_PROTOTYPE: { // static property
58055825
let propertyPrototype = <PropertyPrototype>target;
58065826
let setterPrototype = propertyPrototype.setterPrototype;
@@ -5925,6 +5945,23 @@ export class Compiler extends DiagnosticEmitter {
59255945
}
59265946
return this.makeLocalAssignment(local, valueExpr, valueType, tee);
59275947
}
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+
}
59285965
case ElementKind.GLOBAL: {
59295966
let global = <Global>target;
59305967
if (!this.compileGlobal(global)) return module.unreachable();
@@ -6307,7 +6344,6 @@ export class Compiler extends DiagnosticEmitter {
63076344
/** Constraints indicating contextual conditions. */
63086345
constraints: Constraints
63096346
): ExpressionRef {
6310-
63116347
var module = this.module;
63126348
var flow = this.currentFlow;
63136349

@@ -6376,8 +6412,8 @@ export class Compiler extends DiagnosticEmitter {
63766412

63776413
var signature: Signature | null;
63786414
var indexArg: ExpressionRef;
6415+
var closedLocal: Local | null = null;
63796416
switch (target.kind) {
6380-
63816417
// direct call: concrete function
63826418
case ElementKind.FUNCTION_PROTOTYPE: {
63836419
let functionPrototype = <FunctionPrototype>target;
@@ -6404,13 +6440,64 @@ export class Compiler extends DiagnosticEmitter {
64046440
// indirect call: index argument with signature (non-generic, can't be inlined)
64056441
case ElementKind.LOCAL: {
64066442
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+
}
64076469
signature = local.type.signatureReference;
64086470
if (signature) {
64096471
if (local.is(CommonFlags.INLINED)) {
64106472
indexArg = module.i32(i64_low(local.constantIntegerValue));
64116473
} else {
64126474
indexArg = module.local_get(local.index, NativeType.I32);
64136475
}
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+
)
64146501
break;
64156502
}
64166503
this.error(
@@ -6512,14 +6599,32 @@ export class Compiler extends DiagnosticEmitter {
65126599
return module.unreachable();
65136600
}
65146601
}
6515-
return this.compileCallIndirect(
6602+
var callExpr = this.compileCallIndirect(
65166603
assert(signature), // FIXME: asc can't see this yet
65176604
indexArg,
65186605
expression.arguments,
65196606
expression,
65206607
0,
65216608
contextualType == Type.void
65226609
);
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;
65236628
}
65246629

65256630
private compileCallExpressionBuiltin(
@@ -7016,6 +7121,7 @@ export class Compiler extends DiagnosticEmitter {
70167121
var module = this.module;
70177122
var flow = this.currentFlow;
70187123
var nativeSizeType = this.options.nativeSizeType;
7124+
assert(false)
70197125
if (alreadyRetained) {
70207126
// (t1=newExpr), __release(oldExpr), t1
70217127
// it is important that `newExpr` evaluates before `oldExpr` is released, hence the local
@@ -7082,6 +7188,7 @@ export class Compiler extends DiagnosticEmitter {
70827188
//
70837189
// callReceivingAReference((__release(t = callReturningAReference()), t))
70847190
//
7191+
assert(false)
70857192
var local = flow.getAutoreleaseLocal(type);
70867193
if (flow.isNonnull(expr, type)) flow.setLocalFlag(local.index, LocalFlags.NONNULL);
70877194
return this.module.local_tee(local.index, expr);
@@ -7608,8 +7715,83 @@ export class Compiler extends DiagnosticEmitter {
76087715
var instance: Function | null;
76097716
var contextualTypeArguments = makeMap(flow.contextualTypeArguments);
76107717

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.
76137795
if (contextualSignature) {
76147796
let signatureNode = prototype.functionTypeNode;
76157797
let parameterNodes = signatureNode.parameters;
@@ -7965,6 +8147,17 @@ export class Compiler extends DiagnosticEmitter {
79658147
this.currentType = functionInstance.signature.type;
79668148
return module.i32(index);
79678149
}
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+
}
79688161
}
79698162
this.error(
79708163
DiagnosticCode.Not_implemented,

src/flow.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,9 @@ export class Flow {
505505

506506
/** Sets the specified flag or flags on the local at the specified index. */
507507
setLocalFlag(index: i32, flag: LocalFlags): void {
508+
if(flag == LocalFlags.RETAINED) {
509+
assert(false)
510+
}
508511
if (index < 0) return;
509512
var localFlags = this.localFlags;
510513
var flags = index < localFlags.length ? unchecked(localFlags[index]) : 0;

0 commit comments

Comments
 (0)