Skip to content

Commit 5cfe2df

Browse files
committed
Works but virtual table is hard coded
1 parent 044a9d5 commit 5cfe2df

File tree

6 files changed

+622
-61
lines changed

6 files changed

+622
-61
lines changed

src/compiler.ts

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ import {
8080
PropertyPrototype,
8181
IndexSignature,
8282
File,
83-
mangleInternalName
83+
mangleInternalName,
84+
Interface
8485
} from "./program";
8586

8687
import {
@@ -452,7 +453,6 @@ export class Compiler extends DiagnosticEmitter {
452453
// set up virtual table
453454
this.compileVirtualTable();
454455

455-
456456
// set up function table
457457
var functionTable = this.functionTable;
458458
module.setFunctionTable(functionTable.length, 0xffffffff, functionTable);
@@ -465,7 +465,6 @@ export class Compiler extends DiagnosticEmitter {
465465
for (let file of this.program.filesByName.values()) {
466466
if (file.source.sourceKind == SourceKind.USER_ENTRY) this.ensureModuleExports(file);
467467
}
468-
console.log(functionTable.join(",\n"));
469468
return module;
470469
}
471470

@@ -1334,7 +1333,7 @@ export class Compiler extends DiagnosticEmitter {
13341333
NativeType.I32
13351334
);
13361335
let callVirtual = module.call(
1337-
"~lib/virtual",
1336+
"~virtual",
13381337
[loadMethodID, loadClass],
13391338
NativeType.I32
13401339
);
@@ -3005,6 +3004,14 @@ export class Compiler extends DiagnosticEmitter {
30053004
}
30063005
}
30073006
}
3007+
// Check if a converting to an Interface
3008+
if (toType.is(TypeFlags.REFERENCE)) {
3009+
assert(toType.classReference != null && toType.classReference != null);
3010+
if (toType.classReference!.kind == ElementKind.INTERFACE) {
3011+
(<Interface>toType.classReference!).implementers.add(fromType.classReference!);
3012+
}
3013+
3014+
}
30083015

30093016
if (fromType.is(TypeFlags.FLOAT)) {
30103017

@@ -6260,7 +6267,7 @@ export class Compiler extends DiagnosticEmitter {
62606267
}
62616268
var parameterTypes = signature.parameterTypes;
62626269
for (let i = 0; i < numArguments; ++i, ++index) {
6263-
if (parameterTypes[i].is(TypeFlags.REFERENCE)){
6270+
if (parameterTypes[i].is(TypeFlags.REFERENCE)) {
62646271

62656272
}
62666273
let arg_type = this.resolver.resolveExpression(argumentExpressions[i], this.currentFlow);
@@ -9188,31 +9195,39 @@ export class Compiler extends DiagnosticEmitter {
91889195

91899196
compileVirtualTable(): void {
91909197
const interfaces = this.program.interfaces;
9191-
const implementers: ClassPrototype[] = this.program.queuedImplements;
9192-
const program: Program = this.program;
9193-
const getFunc = (funcP: FunctionPrototype): Function => {
9194-
if (!program.instancesByName.has(funcP.internalName)) {
9195-
this.compileElement(funcP);
9196-
}
9197-
return <Function> program.instancesByName.get(funcP.internalName)!;
9198-
};
9199-
const methods: Function[] = [];
9200-
debugger;
9201-
// for (const _class of implementers) {
9202-
// methods.concat(_class.instanceMethods.map(getFunc)
9203-
// .filter(func => {
9204-
// return interfaces.some(_interface => {
9205-
// return _interface.prototype.instanceMethods.map(getFunc)
9206-
// .some(ifunc => func.signature.id == ifunc.signature.id )
9207-
// })
9208-
// }))
9209-
// }
9198+
const methods: Map<number, Function[]> = new Map();
9199+
for (let _interface of interfaces) {
9200+
for (let func of _interface.methodInstances) {
9201+
const id = func.signature.id;
9202+
if (!methods.has(id)) {
9203+
methods.set(id, []);
9204+
}
9205+
const newFuncs: Function[] = <Function[]>_interface.getFuncPrototypeImplementation(func).map(
9206+
// tslint:disable-next-line: as-types
9207+
funcP => {
9208+
const newFunc = this.resolver.resolveFunction(funcP, null, func.contextualTypeArguments);
9209+
if (newFunc == null) {
9210+
throw new Error(`Couldn't resolve ${funcP.name}`);
9211+
}
9212+
this.compileFunction(newFunc);
9213+
this.ensureFunctionTableEntry(newFunc);
9214+
return newFunc;
9215+
}
9216+
);
9217+
methods.get(id)!.concat(newFuncs);
9218+
}
9219+
}
9220+
92109221
const relooper = this.module.createRelooper();
9222+
debugger;
9223+
for (const [id, funcs] of methods) {
9224+
9225+
}
92119226
var typeRef = this.ensureFunctionType([Type.u32, Type.u32], Type.u32, null);
92129227

92139228

92149229
// let body = this.module.
9215-
// this.module.addFunction("~lib/_virtual", typeRef, null, );
9230+
this.module.addFunction("~virtual", typeRef, null, this.module.i32(1));
92169231

92179232
}
92189233
}

src/program.ts

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3382,30 +3382,7 @@ export class Class extends TypedElement {
33823382
isAssignableTo(target: Class): bool {
33833383
var current: Class | null = this;
33843384
if (target.kind == ElementKind.INTERFACE) {
3385-
if (current.prototype.implementsNodes) {
3386-
return current.prototype.implementsNodes.some((element) => element.name.identifier.symbol == target.name)
3387-
} else {
3388-
return false;
3389-
}
3390-
// const members = (<Interface>target).prototype.instanceMembers;
3391-
// if (members == null) return true; // Is an empty interface always castable?
3392-
// let curr_members = current.prototype.instanceMembers;
3393-
// if (curr_members == null) return false; // Interface is non-empty but class is.
3394-
// for (const interface_member of members.values()) {
3395-
// let hasMember = false;
3396-
// for (const class_member of curr_members.values()) {
3397-
// if (interface_member.kind == ElementKind.FUNCTION &&
3398-
// class_member.kind == ElementKind.FUNCTION &&
3399-
// (<Function>interface_member).signature.id == (<Function> class_member).signature.id ) {
3400-
// hasMember = true;
3401-
// break;
3402-
// }
3403-
// }
3404-
// if (!hasMember) {
3405-
// return false;
3406-
// }
3407-
// }
3408-
// return true;
3385+
return (<Interface>target).checkClass(this);
34093386
}
34103387
do if (current == target) return true;
34113388
while (current = current.base);
@@ -3666,32 +3643,52 @@ export class Interface extends Class { // FIXME
36663643
);
36673644
}
36683645

3646+
get methods(): FunctionPrototype[] {
3647+
if (this.members == null) return [];
3648+
return <FunctionPrototype[]>filter(this.members.values(), v => v.kind == ElementKind.FUNCTION_PROTOTYPE)
3649+
}
3650+
3651+
get methodInstances(): Function[] {
3652+
var funcs: Function[] = [];
3653+
for (let func of this.methods) {
3654+
if (func.instances == null) continue;
3655+
map(func.instances.values(), (func: Function): void => {
3656+
if (funcs.findIndex(f => f.signature.id == func.signature.id) < 0) {
3657+
funcs.push(func);
3658+
}
3659+
});
3660+
}
3661+
return funcs;
3662+
}
3663+
36693664
addImplementer(_class: Class): void {
36703665
this.implementers.add(_class);
36713666
}
36723667

36733668
checkClass(_class: Class): bool {
3674-
return this.prototype.instanceMethods.reduce<bool>((acc, ifunc) =>
3669+
return this.methods.reduce<bool>((acc, ifunc) =>
36753670
(this.getFunc(_class, ifunc) != null ) && acc, true);
36763671
}
36773672

36783673
private getFunc(_class: Class, ifunc: FunctionPrototype): FunctionPrototype | null {
3679-
const methods = _class.prototype.instanceMethods;
3680-
const index = methods.findIndex(func => (func.internalName == ifunc.internalName && (
3681-
func.functionTypeNode.equals(ifunc.functionTypeNode) &&
3682-
TypeNode.arrayEquals(func.typeParameterNodes, ifunc.typeParameterNodes)
3683-
)));
3684-
if (index > 0){
3685-
return methods[index];
3686-
}
3687-
return null;
3674+
if (_class.members == null) return null;
3675+
return <FunctionPrototype>_class.members.get(ifunc.name);
36883676
}
36893677

36903678
getFuncPrototypeImplementation(ifunc: Function): FunctionPrototype[] {
3691-
return <FunctionPrototype[]> map<Class, FunctionPrototype | null>(this.implementers, _class => this.getFunc(_class, ifunc.prototype))
3679+
return <FunctionPrototype[]> map(this.implementers,
3680+
_class => this.getFunc(_class, ifunc.prototype))
36923681
.filter(func => func != null);
36933682
}
36943683

3684+
get methodsToCompile(): FunctionPrototype[] {
3685+
var funcs: FunctionPrototype[] = [];
3686+
for (let func of this.methodInstances) {
3687+
funcs.concat(this.getFuncPrototypeImplementation(func));
3688+
}
3689+
return funcs;
3690+
}
3691+
36953692

36963693
}
36973694

src/resolver.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2440,7 +2440,7 @@ export class Resolver extends DiagnosticEmitter {
24402440
/** Type arguments provided. */
24412441
typeArguments: Type[] | null,
24422442
/** Contextual types, i.e. `T`. */
2443-
ctxTypes: Map<string,Type> = makeMap<string,Type>(),
2443+
ctxTypes: Map<string,Type> | null = makeMap<string,Type>(),
24442444
/** How to proceed with eventual diagnostics. */
24452445
reportMode: ReportMode = ReportMode.REPORT
24462446
): Function | null {
@@ -2449,6 +2449,7 @@ export class Resolver extends DiagnosticEmitter {
24492449
: prototype.parent;
24502450
var classInstance: Class | null = null; // if an instance method
24512451
var instanceKey = typeArguments ? typesToString(typeArguments) : "";
2452+
ctxTypes = ctxTypes || makeMap<string, Type>();
24522453

24532454
// Instance method prototypes are pre-bound to their concrete class as their parent
24542455
if (prototype.is(CommonFlags.INSTANCE)) {
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
(module
2+
(type $FUNCSIG$iii (func (param i32 i32) (result i32)))
3+
(type $FUNCSIG$vi (func (param i32)))
4+
(type $FUNCSIG$viiii (func (param i32 i32 i32 i32)))
5+
(type $FUNCSIG$v (func))
6+
(type $FUNCSIG$i (func (result i32)))
7+
(import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32)))
8+
(memory $0 1)
9+
(data (i32.const 8) "\18\00\00\00\01\00\00\00\01\00\00\00\18\00\00\00i\00n\00t\00e\00r\00f\00a\00c\00e\00.\00t\00s")
10+
(table $0 2 funcref)
11+
(elem (i32.const 0) $null $interface/AFoo#foo)
12+
(global $~lib/rt/stub/startOffset (mut i32) (i32.const 0))
13+
(global $~lib/rt/stub/offset (mut i32) (i32.const 0))
14+
(global $interface/aFoo (mut i32) (i32.const 0))
15+
(export "memory" (memory $0))
16+
(start $start)
17+
(func $~lib/rt/stub/maybeGrowMemory (; 1 ;) (type $FUNCSIG$vi) (param $0 i32)
18+
(local $1 i32)
19+
(local $2 i32)
20+
local.get $0
21+
memory.size
22+
local.tee $2
23+
i32.const 16
24+
i32.shl
25+
local.tee $1
26+
i32.gt_u
27+
if
28+
local.get $2
29+
local.get $0
30+
local.get $1
31+
i32.sub
32+
i32.const 65535
33+
i32.add
34+
i32.const -65536
35+
i32.and
36+
i32.const 16
37+
i32.shr_u
38+
local.tee $1
39+
local.get $2
40+
local.get $1
41+
i32.gt_s
42+
select
43+
memory.grow
44+
i32.const 0
45+
i32.lt_s
46+
if
47+
local.get $1
48+
memory.grow
49+
i32.const 0
50+
i32.lt_s
51+
if
52+
unreachable
53+
end
54+
end
55+
end
56+
local.get $0
57+
global.set $~lib/rt/stub/offset
58+
)
59+
(func $~lib/rt/stub/__alloc (; 2 ;) (type $FUNCSIG$i) (result i32)
60+
(local $0 i32)
61+
(local $1 i32)
62+
global.get $~lib/rt/stub/offset
63+
i32.const 16
64+
i32.add
65+
local.tee $1
66+
i32.const 16
67+
i32.add
68+
call $~lib/rt/stub/maybeGrowMemory
69+
local.get $1
70+
i32.const 16
71+
i32.sub
72+
local.tee $0
73+
i32.const 16
74+
i32.store
75+
local.get $0
76+
i32.const -1
77+
i32.store offset=4
78+
local.get $0
79+
i32.const 3
80+
i32.store offset=8
81+
local.get $0
82+
i32.const 4
83+
i32.store offset=12
84+
local.get $1
85+
)
86+
(func $interface/passAnInterface (; 3 ;) (type $FUNCSIG$vi) (param $0 i32)
87+
local.get $0
88+
i32.const 8
89+
i32.sub
90+
i32.load
91+
drop
92+
local.get $0
93+
i32.const 1
94+
call $interface/AFoo#foo
95+
i32.const 42
96+
i32.ne
97+
if
98+
i32.const 0
99+
i32.const 24
100+
i32.const 17
101+
i32.const 2
102+
call $~lib/builtins/abort
103+
unreachable
104+
end
105+
)
106+
(func $start (; 4 ;) (type $FUNCSIG$v)
107+
(local $0 i32)
108+
i32.const 48
109+
global.set $~lib/rt/stub/startOffset
110+
i32.const 48
111+
global.set $~lib/rt/stub/offset
112+
call $~lib/rt/stub/__alloc
113+
local.tee $0
114+
i32.const 41
115+
i32.store
116+
local.get $0
117+
global.set $interface/aFoo
118+
global.get $interface/aFoo
119+
call $interface/passAnInterface
120+
)
121+
(func $interface/AFoo#foo (; 5 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
122+
local.get $0
123+
i32.load
124+
local.get $1
125+
i32.add
126+
)
127+
(func $null (; 6 ;) (type $FUNCSIG$v)
128+
nop
129+
)
130+
)

0 commit comments

Comments
 (0)