Skip to content

Commit e3efa58

Browse files
committed
Added relooper table and if cases
1 parent 5cfe2df commit e3efa58

File tree

6 files changed

+261
-88
lines changed

6 files changed

+261
-88
lines changed

src/compiler.ts

Lines changed: 97 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ import {
4343
getLocalSetIndex,
4444
FeatureFlags,
4545
needsExplicitUnreachable,
46-
getLocalSetValue
46+
getLocalSetValue,
47+
RelooperBlockRef
4748
} from "./module";
4849

4950
import {
@@ -1313,55 +1314,10 @@ export class Compiler extends DiagnosticEmitter {
13131314
);
13141315
// Virtual Methods
13151316
} else if (instance.is( CommonFlags.VIRTUAL)) {
1316-
let func: Function = instance;
1317-
let signature = func.signature;
1318-
let typeRef = this.ensureFunctionType(
1319-
signature.parameterTypes,
1320-
signature.returnType,
1321-
signature.thisType
1322-
);
1323-
let loadMethodID = module.i32(signature.id);
1324-
// let target = this.compiler.program.instancesByName("virtual");
1325-
let loadClass = module.load(
1326-
4,
1327-
false,
1328-
module.binary(
1329-
BinaryOp.SubI32,
1330-
module.local_get(0, NativeType.I32),
1331-
module.i32(8)
1332-
),
1333-
NativeType.I32
1334-
);
1335-
let callVirtual = module.call(
1336-
"~virtual",
1337-
[loadMethodID, loadClass],
1338-
NativeType.I32
1339-
);
1340-
// module.removeFunction(member.internalName);
1341-
1342-
let callIndirect = module.call_indirect(
1343-
callVirtual,
1344-
func.localsByIndex.map<number>(local =>
1345-
module.local_get(local.index, local.type.toNativeType())
1346-
),
1347-
1348-
Signature.makeSignatureString(
1349-
func.signature.parameterTypes,
1350-
func.signature.returnType,
1351-
func.signature.thisType
1352-
)
1353-
);
1354-
1355-
let body = module.block(
1356-
null,
1357-
[callIndirect],
1358-
func.signature.returnType.toNativeType()
1359-
);
1360-
13611317
funcRef = module.addFunction(instance.internalName,
13621318
typeRef,
13631319
null,
1364-
body
1320+
module.nop()
13651321
);
13661322
// imported function
13671323
} else {
@@ -9195,45 +9151,128 @@ export class Compiler extends DiagnosticEmitter {
91959151

91969152
compileVirtualTable(): void {
91979153
const interfaces = this.program.interfaces;
9198-
const methods: Map<number, Function[]> = new Map();
9154+
const instanceMethods: Map<number, Map<number, Function>> = new Map();
9155+
const interfaceMethods: Map<number, Function[]> = new Map();
9156+
// Gather all instatiated interface methods
91999157
for (let _interface of interfaces) {
92009158
for (let func of _interface.methodInstances) {
92019159
const id = func.signature.id;
9202-
if (!methods.has(id)) {
9203-
methods.set(id, []);
9160+
if (!interfaceMethods.has(id)) {
9161+
interfaceMethods.set(id, []);
9162+
}
9163+
interfaceMethods.get(id)!.push(func);
9164+
if (!instanceMethods.has(id)) {
9165+
instanceMethods.set(id, new Map());
92049166
}
9205-
const newFuncs: Function[] = <Function[]>_interface.getFuncPrototypeImplementation(func).map(
9167+
const currentMap = instanceMethods.get(id)!;
9168+
<Function[]>_interface.getFuncImplementations(func).map(
92069169
// tslint:disable-next-line: as-types
92079170
funcP => {
9171+
// TODO: Better way to pass contextual type info
92089172
const newFunc = this.resolver.resolveFunction(funcP, null, func.contextualTypeArguments);
92099173
if (newFunc == null) {
92109174
throw new Error(`Couldn't resolve ${funcP.name}`);
92119175
}
92129176
this.compileFunction(newFunc);
92139177
this.ensureFunctionTableEntry(newFunc);
9178+
currentMap.set((<Class>newFunc.parent).id, newFunc);
92149179
return newFunc;
92159180
}
92169181
);
9217-
methods.get(id)!.concat(newFuncs);
92189182
}
92199183
}
92209184

9185+
const module = this.module;
9186+
// Create relooper to build table
92219187
const relooper = this.module.createRelooper();
9222-
debugger;
9223-
for (const [id, funcs] of methods) {
9224-
9225-
}
9188+
const iFuncs: [number, Map<number, Function>][] = Array.from(instanceMethods.entries());
9189+
const methodBlocks: RelooperBlockRef[] = [];
9190+
const getArg = (i: i32): ExpressionRef => module.local_get(i, Type.i32.toNativeType());
9191+
// Condition to switch on
9192+
const first = relooper.addBlockWithSwitch(module.nop(), getArg(0));
9193+
const zero = relooper.addBlock(module.drop(module.i32(0)));
9194+
9195+
for (let index: i32 = 0; index < iFuncs.length; index++) {
9196+
const [funcID, classes] = iFuncs[index];
9197+
// Compile the interface methods with index
9198+
for (const iFunc of interfaceMethods.get(funcID)!) {
9199+
iFunc.finalize(module, this.compileInterfaceMethod(iFunc, index));
9200+
}
9201+
const innerBlock = relooper.addBlock(module.nop());
9202+
relooper.addBranchForSwitch(first, innerBlock, [index]);
9203+
for (const [classID, func] of classes.entries()) {
9204+
const methodCase = relooper.addBlock(module.return(module.i32(func.functionTableIndex)));
9205+
const condition = module.binary(BinaryOp.EqI32, getArg(1), module.i32(classID));
9206+
relooper.addBranch(innerBlock, methodCase, condition);
9207+
}
9208+
relooper.addBranch(innerBlock, zero, 0, module.unreachable());
9209+
}
9210+
relooper.addBranchForSwitch(first, zero, [], module.unreachable());
9211+
92269212
var typeRef = this.ensureFunctionType([Type.u32, Type.u32], Type.u32, null);
92279213

9214+
const body = module.block(
9215+
null,
9216+
[relooper.renderAndDispose(first, 0), module.i32(0)],
9217+
Type.u32.toNativeType()
9218+
);;
9219+
const hardCoded = this.module.i32(1);
9220+
this.module.addFunction("~virtual", typeRef, null, body);
92289221

9229-
// let body = this.module.
9230-
this.module.addFunction("~virtual", typeRef, null, this.module.i32(1));
9222+
}
92319223

9224+
compileInterfaceMethod(func: Function, methodID: i32): ExpressionRef {
9225+
const signature = func.signature;
9226+
const module = this.module;
9227+
const typeRef = this.ensureFunctionType(
9228+
signature.parameterTypes,
9229+
signature.returnType,
9230+
signature.thisType
9231+
);
9232+
const loadMethodID = module.i32(methodID);
9233+
// let target = this.compiler.program.instancesByName("virtual");
9234+
const loadClass = module.load(
9235+
4,
9236+
false,
9237+
module.binary(
9238+
BinaryOp.SubI32,
9239+
module.local_get(0, NativeType.I32),
9240+
module.i32(8)
9241+
),
9242+
NativeType.I32
9243+
);
9244+
const callVirtual = module.call(
9245+
"~virtual",
9246+
[loadMethodID, loadClass],
9247+
NativeType.I32
9248+
);
9249+
// module.removeFunction(member.internalName);
9250+
9251+
const callIndirect = module.call_indirect(
9252+
callVirtual,
9253+
func.localsByIndex.map<number>(local =>
9254+
module.local_get(local.index, local.type.toNativeType())
9255+
),
9256+
Signature.makeSignatureString(
9257+
func.signature.parameterTypes,
9258+
func.signature.returnType,
9259+
func.signature.thisType
9260+
)
9261+
);
9262+
9263+
const body = module.block(
9264+
null,
9265+
[callIndirect],
9266+
func.signature.returnType.toNativeType()
9267+
);
9268+
module.removeFunction(func.internalName);
9269+
return module.addFunction(func.internalName, typeRef, null, body);
92329270
}
92339271
}
92349272

92359273
// helpers
92369274

9275+
92379276
function mangleImportName(
92389277
element: Element,
92399278
declaration: DeclarationStatement

src/program.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3675,7 +3675,7 @@ export class Interface extends Class { // FIXME
36753675
return <FunctionPrototype>_class.members.get(ifunc.name);
36763676
}
36773677

3678-
getFuncPrototypeImplementation(ifunc: Function): FunctionPrototype[] {
3678+
getFuncImplementations(ifunc: Function): FunctionPrototype[] {
36793679
return <FunctionPrototype[]> map(this.implementers,
36803680
_class => this.getFunc(_class, ifunc.prototype))
36813681
.filter(func => func != null);
@@ -3684,7 +3684,7 @@ export class Interface extends Class { // FIXME
36843684
get methodsToCompile(): FunctionPrototype[] {
36853685
var funcs: FunctionPrototype[] = [];
36863686
for (let func of this.methodInstances) {
3687-
funcs.concat(this.getFuncPrototypeImplementation(func));
3687+
funcs.concat(this.getFuncImplementations(func));
36883688
}
36893689
return funcs;
36903690
}

std/portable/index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,7 @@ declare class Array<T> {
380380

381381
static isArray<U>(value: any): value is Array<any>;
382382
static create<T>(capacity?: i32): Array<T>;
383+
static from<T>(iter: Iterator<T>): Array<T>;
383384

384385
[key: number]: T;
385386
length: i32;

tests/compiler/interface.optimized.wat

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
(type $FUNCSIG$iii (func (param i32 i32) (result i32)))
33
(type $FUNCSIG$vi (func (param i32)))
44
(type $FUNCSIG$viiii (func (param i32 i32 i32 i32)))
5+
(type $FUNCSIG$iiii (func (param i32 i32 i32) (result i32)))
56
(type $FUNCSIG$v (func))
67
(type $FUNCSIG$i (func (result i32)))
78
(import "env" "abort" (func $~lib/builtins/abort (param i32 i32 i32 i32)))
89
(memory $0 1)
910
(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)
11+
(table $0 3 funcref)
12+
(elem (i32.const 0) $null $interface/AFoo#foo $interface/AFoo#faa)
1213
(global $~lib/rt/stub/startOffset (mut i32) (i32.const 0))
1314
(global $~lib/rt/stub/offset (mut i32) (i32.const 0))
1415
(global $interface/aFoo (mut i32) (i32.const 0))
@@ -84,20 +85,41 @@
8485
local.get $1
8586
)
8687
(func $interface/passAnInterface (; 3 ;) (type $FUNCSIG$vi) (param $0 i32)
88+
local.get $0
89+
i32.const 1
90+
i32.const 0
8791
local.get $0
8892
i32.const 8
8993
i32.sub
9094
i32.load
91-
drop
95+
call $~virtual
96+
call_indirect (type $FUNCSIG$iii)
97+
i32.const 42
98+
i32.ne
99+
if
100+
i32.const 0
101+
i32.const 24
102+
i32.const 23
103+
i32.const 2
104+
call $~lib/builtins/abort
105+
unreachable
106+
end
92107
local.get $0
93108
i32.const 1
94-
call $interface/AFoo#foo
95-
i32.const 42
109+
i32.const 3
110+
i32.const 1
111+
local.get $0
112+
i32.const 8
113+
i32.sub
114+
i32.load
115+
call $~virtual
116+
call_indirect (type $FUNCSIG$iiii)
117+
i32.const 4
96118
i32.ne
97119
if
98120
i32.const 0
99121
i32.const 24
100-
i32.const 17
122+
i32.const 24
101123
i32.const 2
102124
call $~lib/builtins/abort
103125
unreachable
@@ -124,7 +146,39 @@
124146
local.get $1
125147
i32.add
126148
)
127-
(func $null (; 6 ;) (type $FUNCSIG$v)
149+
(func $interface/AFoo#faa (; 6 ;) (type $FUNCSIG$iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
150+
local.get $1
151+
local.get $2
152+
i32.add
153+
)
154+
(func $~virtual (; 7 ;) (type $FUNCSIG$iii) (param $0 i32) (param $1 i32) (result i32)
155+
block $switch$1$default
156+
block $switch$1$case$5
157+
block $switch$1$case$3
158+
local.get $0
159+
br_table $switch$1$case$3 $switch$1$case$5 $switch$1$default
160+
end
161+
local.get $1
162+
i32.const 3
163+
i32.ne
164+
if
165+
unreachable
166+
end
167+
i32.const 1
168+
return
169+
end
170+
local.get $1
171+
i32.const 3
172+
i32.ne
173+
if
174+
unreachable
175+
end
176+
i32.const 2
177+
return
178+
end
179+
unreachable
180+
)
181+
(func $null (; 8 ;) (type $FUNCSIG$v)
128182
nop
129183
)
130184
)

tests/compiler/interface.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
interface IFoo {
33
foo(i: i32): i32;
4+
faa(i: i32, i2: i32): i32;
45
}
56

67
class AFoo implements IFoo {
@@ -9,12 +10,18 @@ class AFoo implements IFoo {
910
foo(i: i32): i32 {
1011
return this.i + i;
1112
}
13+
14+
faa(i: i32, i2: i32): i32 {
15+
return i + i2;
16+
}
17+
1218
}
1319

1420
let aFoo = new AFoo();
1521

1622
function passAnInterface(foo: IFoo): void {
1723
assert(foo.foo(1) == 42);
24+
assert(foo.faa(1,3) == 4);
1825
}
1926

2027
passAnInterface(aFoo);

0 commit comments

Comments
 (0)