Skip to content

Commit 4af307f

Browse files
committed
[Implement] idof function references
1 parent 4c938f7 commit 4af307f

File tree

14 files changed

+183
-57
lines changed

14 files changed

+183
-57
lines changed

src/builtins.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3592,7 +3592,12 @@ export function compileCall(
35923592
case BuiltinSymbols.idof: {
35933593
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
35943594
compiler.currentType = Type.u32;
3595-
if (!type) return module.unreachable();
3595+
if (!type || checkArgsOptional(operands, 0, 0, reportNode, compiler)) return module.unreachable();
3596+
3597+
if (type.is(TypeFlags.REFERENCE) && type.signatureReference !== null) {
3598+
return module.i32(type.signatureReference.id);
3599+
}
3600+
35963601
let classReference = type.classReference;
35973602
if (!classReference || classReference.hasDecorator(DecoratorFlags.UNMANAGED)) {
35983603
compiler.error(

src/compiler.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,8 @@ export class Compiler extends DiagnosticEmitter {
305305
runtimeFeatures: RuntimeFeatures = RuntimeFeatures.NONE;
306306
/** Expressions known to have skipped an autorelease. Usually function returns. */
307307
skippedAutoreleases: Set<ExpressionRef> = new Set();
308+
/** A table of signatures. */
309+
signatures: Signature[] = new Array<Signature>(0);
308310

309311
/** Compiles a {@link Program} to a {@link Module} using the specified options. */
310312
static compile(program: Program, options: Options | null = null): Module {
@@ -344,7 +346,7 @@ export class Compiler extends DiagnosticEmitter {
344346
program.initialize(options);
345347

346348
// set up the main start function
347-
var startFunctionInstance = program.makeNativeFunction("start", new Signature([], Type.void));
349+
var startFunctionInstance = program.makeNativeFunction("start", new Signature(program, [], Type.void, null));
348350
startFunctionInstance.internalName = "start";
349351
var startFunctionBody = new Array<ExpressionRef>();
350352
this.currentFlow = startFunctionInstance.flow;
@@ -6367,7 +6369,7 @@ export class Compiler extends DiagnosticEmitter {
63676369
assert(operandIndex == minOperands);
63686370

63696371
// create the trampoline element
6370-
var trampolineSignature = new Signature(originalParameterTypes, returnType, thisType);
6372+
var trampolineSignature = new Signature(this.program, originalParameterTypes, returnType, thisType);
63716373
trampolineSignature.requiredParameters = maxArguments;
63726374
trampolineSignature.parameterNames = originalSignature.parameterNames;
63736375
trampoline = new Function(
@@ -7082,7 +7084,7 @@ export class Compiler extends DiagnosticEmitter {
70827084
}
70837085
}
70847086

7085-
let signature = new Signature(parameterTypes, returnType, thisType);
7087+
let signature = new Signature(this.program, parameterTypes, returnType, thisType);
70867088
signature.requiredParameters = numParameters; // !
70877089
signature.parameterNames = parameterNames;
70887090
instance = new Function(
@@ -7845,7 +7847,7 @@ export class Compiler extends DiagnosticEmitter {
78457847
CommonFlags.INSTANCE | CommonFlags.CONSTRUCTOR
78467848
)
78477849
),
7848-
new Signature(null, classInstance.type, classInstance.type),
7850+
new Signature(this.program, null, classInstance.type, classInstance.type),
78497851
null
78507852
);
78517853
}
@@ -9009,6 +9011,7 @@ export class Compiler extends DiagnosticEmitter {
90099011
flow.popBreakLabel();
90109012
return module.block(label, conditions, NativeType.I32);
90119013
}
9014+
90129015
}
90139016

90149017
// helpers

src/program.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,8 @@ export class Program extends DiagnosticEmitter {
336336
typeClasses: Map<TypeKind,Class> = new Map();
337337
/** Managed classes contained in the program, by id. */
338338
managedClasses: Map<i32,Class> = new Map();
339+
signatureTypes: Signature[] = new Array<Signature>(0);
340+
signatureID: i32 = 0;
339341

340342
// standard references
341343

@@ -2141,7 +2143,7 @@ export class File extends Element {
21412143
program.filesByName.set(this.internalName, this);
21422144
var startFunction = this.program.makeNativeFunction(
21432145
"start:" + this.internalName,
2144-
new Signature(null, Type.void),
2146+
new Signature(program, null, Type.void),
21452147
this
21462148
);
21472149
startFunction.internalName = startFunction.name;

src/resolver.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ export class Resolver extends DiagnosticEmitter {
405405
);
406406
if (!returnType) return null;
407407
}
408-
var signature = new Signature(parameterTypes, returnType, thisType);
408+
var signature = new Signature(this.program, parameterTypes, returnType, thisType);
409409
signature.parameterNames = parameterNames;
410410
signature.requiredParameters = requiredParameters;
411411
signature.hasRest = hasRest;
@@ -1551,7 +1551,7 @@ export class Resolver extends DiagnosticEmitter {
15511551
returnType = type;
15521552
}
15531553

1554-
var signature = new Signature(parameterTypes, returnType, thisType);
1554+
var signature = new Signature(this.program, parameterTypes, returnType, thisType);
15551555
signature.parameterNames = parameterNames;
15561556
signature.requiredParameters = requiredParameters;
15571557

src/types.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,8 @@ export function typesToString(types: Type[]): string {
556556

557557
/** Represents a fully resolved function signature. */
558558
export class Signature {
559-
559+
/** The unique program id that represents this signature. */
560+
id: i32 = -1;
560561
/** Parameter types, if any, excluding `this`. */
561562
parameterTypes: Type[];
562563
/** Parameter names, if known, excluding `this`. */
@@ -573,20 +574,38 @@ export class Signature {
573574
cachedFunctionTarget: FunctionTarget | null = null;
574575
/** Respective function type. */
575576
type: Type;
577+
/** The program that created this signature. */
578+
program: Program;
576579

577580
/** Constructs a new signature. */
578581
constructor(
582+
program: Program,
579583
parameterTypes: Type[] | null = null,
580584
returnType: Type | null = null,
581-
thisType: Type | null = null
585+
thisType: Type | null = null,
582586
) {
583587
this.parameterTypes = parameterTypes ? parameterTypes : [];
584588
this.parameterNames = null;
585589
this.requiredParameters = 0;
586590
this.returnType = returnType ? returnType : Type.void;
587591
this.thisType = thisType;
592+
this.program = program;
588593
this.hasRest = false;
589594
this.type = Type.u32.asFunction(this);
595+
596+
let compare: Signature;
597+
let signatureTypes = program.signatureTypes;
598+
let length = signatureTypes.length;
599+
for (let i = 0; i < length; i++) {
600+
compare = signatureTypes[i];
601+
if (this.isAssignableTo(compare)) {
602+
this.id = compare.id;
603+
}
604+
}
605+
if (this.id === -1) {
606+
program.signatureTypes.push(this);
607+
this.id = program.signatureID++;
608+
}
590609
}
591610

592611
asFunctionTarget(program: Program): FunctionTarget {

std/assembly/builtins.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { I32 } from "number";
2+
13
// @ts-ignore: decorator
24
@builtin
35
export declare function isInteger<T>(value?: T): bool;
@@ -130,6 +132,10 @@ export declare function alignof<T>(): usize; // | u32 / u64
130132
@builtin
131133
export declare function offsetof<T>(fieldName?: string): usize; // | u32 / u64
132134

135+
// @ts-ignore: decorator
136+
@builtin
137+
export declare function signatureof<T>(): i32;
138+
133139
// @ts-ignore: decorator
134140
@builtin
135141
export declare function idof<T>(): u32;

std/assembly/index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ declare function sizeof<T>(): usize;
112112
declare function alignof<T>(): usize;
113113
/** Determines the end offset of the given class type. Compiles to a constant. */
114114
declare function offsetof<T>(): usize;
115+
/** Determines the unique signature id of a given function. */
116+
declare function signatureof<T extends (...params: any[]) => any>(): i32;
115117
/** Determines the offset of the specified field within the given class type. Compiles to a constant. */
116118
declare function offsetof<T>(fieldName: keyof T | string): usize;
117119
/** Determines the offset of the specified field within the given class type. Returns the class type's end offset if field name has been omitted. Compiles to a constant. */

tests/compiler/binary.optimized.wat

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@
2929
local.get $2
3030
i32.wrap_i64
3131
i32.const 0
32-
i32.ne
33-
i32.const 0
3432
local.get $1
3533
i32.const 2147483647
3634
i32.and

tests/compiler/builtins.optimized.wat

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
(type $FUNCSIG$if (func (param f32) (result i32)))
44
(type $FUNCSIG$id (func (param f64) (result i32)))
55
(type $FUNCSIG$vii (func (param i32 i32)))
6+
(type $FUNCSIG$viiddddd (func (param i32 i32 f64 f64 f64 f64 f64)))
67
(type $FUNCSIG$v (func))
78
(import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32)))
9+
(import "env" "trace" (func $~lib/builtins/trace (param i32 i32 f64 f64 f64 f64 f64)))
810
(memory $0 1)
911
(data (i32.const 12) "\01\00\00\00\01")
1012
(data (i32.const 24) "\06\00\00\00\01\00\00\00\01\00\00\00\06\00\00\00a\00b\00c")
1113
(data (i32.const 48) "\16\00\00\00\01\00\00\00\01\00\00\00\16\00\00\00b\00u\00i\00l\00t\00i\00n\00s\00.\00t\00s")
14+
(data (i32.const 88) "\14\00\00\00\01\00\00\00\01\00\00\00\14\00\00\00s\00i\00g\00n\00a\00t\00u\00r\00e\00s")
1215
(table $0 2 funcref)
1316
(elem (i32.const 0) $builtins/test $start:builtins~anonymous|0)
1417
(global $builtins/b (mut i32) (i32.const 0))
@@ -23,34 +26,34 @@
2326
(export "memory" (memory $0))
2427
(export "test" (func $builtins/test))
2528
(start $start)
26-
(func $~lib/number/isNaN<f32> (; 1 ;) (type $FUNCSIG$if) (param $0 f32) (result i32)
29+
(func $~lib/number/isNaN<f32> (; 2 ;) (type $FUNCSIG$if) (param $0 f32) (result i32)
2730
local.get $0
2831
local.get $0
2932
f32.ne
3033
)
31-
(func $~lib/number/isFinite<f32> (; 2 ;) (type $FUNCSIG$if) (param $0 f32) (result i32)
34+
(func $~lib/number/isFinite<f32> (; 3 ;) (type $FUNCSIG$if) (param $0 f32) (result i32)
3235
local.get $0
3336
local.get $0
3437
f32.sub
3538
f32.const 0
3639
f32.eq
3740
)
38-
(func $~lib/number/isNaN<f64> (; 3 ;) (type $FUNCSIG$id) (param $0 f64) (result i32)
41+
(func $~lib/number/isNaN<f64> (; 4 ;) (type $FUNCSIG$id) (param $0 f64) (result i32)
3942
local.get $0
4043
local.get $0
4144
f64.ne
4245
)
43-
(func $~lib/number/isFinite<f64> (; 4 ;) (type $FUNCSIG$id) (param $0 f64) (result i32)
46+
(func $~lib/number/isFinite<f64> (; 5 ;) (type $FUNCSIG$id) (param $0 f64) (result i32)
4447
local.get $0
4548
local.get $0
4649
f64.sub
4750
f64.const 0
4851
f64.eq
4952
)
50-
(func $start:builtins~anonymous|0 (; 5 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
53+
(func $start:builtins~anonymous|0 (; 6 ;) (type $FUNCSIG$vii) (param $0 i32) (param $1 i32)
5154
nop
5255
)
53-
(func $start:builtins (; 6 ;) (type $FUNCSIG$v)
56+
(func $start:builtins (; 7 ;) (type $FUNCSIG$v)
5457
i32.const 31
5558
global.set $builtins/i
5659
i32.const 0
@@ -685,11 +688,19 @@
685688
i32.const 8
686689
f64.const 1
687690
f64.store
691+
i32.const 104
692+
i32.const 5
693+
f64.const 0
694+
f64.const 0
695+
f64.const 12
696+
f64.const 27
697+
f64.const 27
698+
call $~lib/builtins/trace
688699
)
689-
(func $builtins/test (; 7 ;) (type $FUNCSIG$v)
700+
(func $builtins/test (; 8 ;) (type $FUNCSIG$v)
690701
nop
691702
)
692-
(func $start (; 8 ;) (type $FUNCSIG$v)
703+
(func $start (; 9 ;) (type $FUNCSIG$v)
693704
call $start:builtins
694705
)
695706
)

tests/compiler/builtins.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,3 +418,18 @@ f64.store(8, 1.0);
418418

419419
f32.trunc(1.0);
420420
f64.trunc(1.0);
421+
422+
423+
{
424+
let a = idof<() => void>();
425+
let b = idof<() => void>();
426+
let c = idof<(a: u32) => void>();
427+
assert(a == b);
428+
assert(a != c);
429+
assert(c == idof<(b: u32) => void>());
430+
431+
let d = idof<(val: C) => C>();
432+
let e = idof<(val2: C) => C>();
433+
assert(d == e);
434+
trace("signatures", 5, a, b, c, d, e);
435+
}

0 commit comments

Comments
 (0)