Skip to content

Commit 11457cf

Browse files
committed
feat: use second table to visit members
visit members in large projects will generate large switch case, it can be optimized to call_indirect when reference-types enabled.
1 parent 4e7734b commit 11457cf

10 files changed

+5132
-967
lines changed

src/builtins.ts

+59-11
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ import {
9999

100100
import {
101101
CommonFlags,
102+
CommonNames,
102103
Feature,
103104
featureToString,
104105
TypeinfoFlags
@@ -10841,16 +10842,12 @@ function ensureVisitMembersOf(compiler: Compiler, instance: Class): void {
1084110842
}
1084210843
}
1084310844

10844-
/** Compiles the `__visit_members` function. */
10845-
export function compileVisitMembers(compiler: Compiler): void {
10845+
function compileVisitMembersWithSwitchCase(compiler: Compiler): ExpressionRef {
1084610846
let program = compiler.program;
1084710847
let module = compiler.module;
1084810848
let usizeType = program.options.usizeType;
1084910849
let sizeTypeRef = usizeType.toRef();
1085010850
let managedClasses = program.managedClasses;
10851-
let visitInstance = assert(program.visitInstance);
10852-
compiler.compileFunction(visitInstance, true); // is lazy, make sure it is compiled
10853-
1085410851
// Prepare a mapping of class names to visitor calls. Each name corresponds to
1085510852
// the respective sequential (0..N) class id.
1085610853
let names = new Array<string>();
@@ -10907,16 +10904,67 @@ export function compileVisitMembers(compiler: Compiler): void {
1090710904
current,
1090810905
cases[names.length - 1]
1090910906
], TypeRef.None);
10907+
return current;
10908+
}
1091010909

10910+
function compileVisitMembersWithCallIndirect(compiler: Compiler): ExpressionRef {
10911+
let program = compiler.program;
10912+
let module = compiler.module;
10913+
let sizeTypeRef = program.options.usizeType.toRef();
10914+
let managedClasses = program.managedClasses;
10915+
let objectInstance = program.objectInstance;
10916+
let tableFunc = new Array<string>();
10917+
let managedClassKeys = Map_keys(managedClasses), l = managedClassKeys.length
10918+
for (let i = 0; i < l; ++i) {
10919+
let instanceId = managedClassKeys[i];
10920+
let instance = assert(managedClasses.get(instanceId));
10921+
if (instance.isPointerfree) {
10922+
// optimize for non pointer object
10923+
ensureVisitMembersOf(compiler, objectInstance);
10924+
tableFunc[i] = `${objectInstance.internalName}~visit`;
10925+
} else {
10926+
ensureVisitMembersOf(compiler, instance);
10927+
tableFunc[i] = `${instance.internalName}~visit`
10928+
}
10929+
}
10930+
console.log(tableFunc)
10931+
module.addFunctionTable(CommonNames.VisitorTable, l, l, tableFunc, module.i32(0));
10932+
return module.call_indirect(CommonNames.VisitorTable,
10933+
// load<u32>(changetype<usize>(this) - 8)
10934+
module.load(4, false,
10935+
sizeTypeRef == TypeRef.I64
10936+
? module.binary(BinaryOp.SubI64,
10937+
module.local_get(0, sizeTypeRef),
10938+
module.i64(8)
10939+
)
10940+
: module.binary(BinaryOp.SubI32,
10941+
module.local_get(0, sizeTypeRef),
10942+
module.i32(8) // rtId is at -8
10943+
),
10944+
TypeRef.I32, 0
10945+
), [
10946+
module.local_get(0, sizeTypeRef), // this
10947+
module.local_get(1, TypeRef.I32) // cookie
10948+
], createType([sizeTypeRef, TypeRef.I32]), TypeRef.None, false);
10949+
}
10950+
/** Compiles the `__visit_members` function. */
10951+
export function compileVisitMembers(compiler: Compiler): void {
10952+
let program = compiler.program;
10953+
let module = compiler.module;
10954+
let usizeType = program.options.usizeType;
10955+
let sizeTypeRef = usizeType.toRef();
10956+
let visitInstance = assert(program.visitInstance);
10957+
compiler.compileFunction(visitInstance, true); // is lazy, make sure it is compiled
10958+
const current = compiler.options.hasFeature(Feature.ReferenceTypes)
10959+
? compileVisitMembersWithCallIndirect(compiler)
10960+
: compileVisitMembersWithSwitchCase(compiler);
1091110961
// Add the function, executing an unreachable if breaking to 'invalid'
10912-
module.addFunction(BuiltinNames.visit_members,
10913-
createType([ sizeTypeRef, TypeRef.I32 ]), // this, cookie
10962+
module.addFunction(
10963+
BuiltinNames.visit_members,
10964+
createType([sizeTypeRef, TypeRef.I32]), // this, cookie
1091410965
TypeRef.None, // => void
1091510966
null,
10916-
module.flatten([
10917-
current,
10918-
module.unreachable()
10919-
])
10967+
module.flatten([current, module.unreachable()])
1092010968
);
1092110969
}
1092210970

src/common.ts

+1
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ export namespace CommonNames {
267267
// memory & table
268268
export const DefaultMemory = "0";
269269
export const DefaultTable = "0";
270+
export const VisitorTable = "~/lib/rt/visitor";
270271
}
271272

272273
// shared

tests/compiler/bindings/esm.debug.wat

+12-85
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,10 @@
8484
(data $20 (i32.const 1052) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00*\00\00\00O\00b\00j\00e\00c\00t\00 \00a\00l\00r\00e\00a\00d\00y\00 \00p\00i\00n\00n\00e\00d\00\00\00")
8585
(data $21 (i32.const 1116) "<\00\00\00\00\00\00\00\00\00\00\00\02\00\00\00(\00\00\00O\00b\00j\00e\00c\00t\00 \00i\00s\00 \00n\00o\00t\00 \00p\00i\00n\00n\00e\00d\00\00\00\00\00")
8686
(data $22 (i32.const 1184) "\10\00\00\00 \00\00\00 \00\00\00 \00\00\00\00\00\00\00\00\00\00\00\81\08\00\00\01\19\00\00\01\02\00\00$\t\00\00\a4\00\00\00$\n\00\00\02\t\00\00\02A\00\00\00\00\00\00A\00\00\00 \00\00\00")
87+
(table $~/lib/rt/visitor 16 16 funcref)
8788
(table $0 2 2 funcref)
88-
(elem $0 (i32.const 1) $start:bindings/esm~anonymous|0)
89+
(elem $~/lib/rt/visitor (table $~/lib/rt/visitor) (i32.const 0) func $~lib/object/Object~visit $~lib/object/Object~visit $~lib/object/Object~visit $~lib/arraybuffer/ArrayBufferView~visit $~lib/function/Function<%28%29=>void>~visit $~lib/typedarray/Int16Array~visit $~lib/typedarray/Float32Array~visit $~lib/typedarray/Uint64Array~visit $~lib/object/Object~visit $~lib/object/Object~visit $~lib/object/Object~visit $~lib/array/Array<i32>~visit $~lib/array/Array<~lib/string/String>~visit $bindings/esm/PlainObject~visit $~lib/typedarray/Uint8Array~visit $~lib/object/Object~visit)
90+
(elem $0 (table $0) (i32.const 1) func $start:bindings/esm~anonymous|0)
8991
(export "plainGlobal" (global $bindings/esm/plainGlobal))
9092
(export "plainMutableGlobal" (global $bindings/esm/plainMutableGlobal))
9193
(export "stringGlobal" (global $bindings/esm/stringGlobal))
@@ -2867,6 +2869,8 @@
28672869
local.get $0
28682870
call $~lib/rt/itcms/__visit
28692871
)
2872+
(func $~lib/object/Object~visit (param $0 i32) (param $1 i32)
2873+
)
28702874
(func $~lib/arraybuffer/ArrayBufferView~visit (param $0 i32) (param $1 i32)
28712875
(local $2 i32)
28722876
local.get $0
@@ -2881,8 +2885,6 @@
28812885
call $~lib/rt/itcms/__visit
28822886
end
28832887
)
2884-
(func $~lib/object/Object~visit (param $0 i32) (param $1 i32)
2885-
)
28862888
(func $~lib/function/Function<%28%29=>void>#get:_env (param $this i32) (result i32)
28872889
local.get $this
28882890
i32.load offset=4
@@ -2970,88 +2972,13 @@
29702972
call $~lib/arraybuffer/ArrayBufferView~visit
29712973
)
29722974
(func $~lib/rt/__visit_members (param $0 i32) (param $1 i32)
2973-
block $invalid
2974-
block $bindings/esm/NonPlainObject
2975-
block $~lib/typedarray/Uint8Array
2976-
block $bindings/esm/PlainObject
2977-
block $~lib/array/Array<~lib/string/String>
2978-
block $~lib/array/Array<i32>
2979-
block $~lib/staticarray/StaticArray<i64>
2980-
block $~lib/staticarray/StaticArray<u16>
2981-
block $~lib/staticarray/StaticArray<i32>
2982-
block $~lib/typedarray/Uint64Array
2983-
block $~lib/typedarray/Float32Array
2984-
block $~lib/typedarray/Int16Array
2985-
block $~lib/function/Function<%28%29=>void>
2986-
block $~lib/arraybuffer/ArrayBufferView
2987-
block $~lib/string/String
2988-
block $~lib/arraybuffer/ArrayBuffer
2989-
block $~lib/object/Object
2990-
local.get $0
2991-
i32.const 8
2992-
i32.sub
2993-
i32.load
2994-
br_table $~lib/object/Object $~lib/arraybuffer/ArrayBuffer $~lib/string/String $~lib/arraybuffer/ArrayBufferView $~lib/function/Function<%28%29=>void> $~lib/typedarray/Int16Array $~lib/typedarray/Float32Array $~lib/typedarray/Uint64Array $~lib/staticarray/StaticArray<i32> $~lib/staticarray/StaticArray<u16> $~lib/staticarray/StaticArray<i64> $~lib/array/Array<i32> $~lib/array/Array<~lib/string/String> $bindings/esm/PlainObject $~lib/typedarray/Uint8Array $bindings/esm/NonPlainObject $invalid
2995-
end
2996-
return
2997-
end
2998-
return
2999-
end
3000-
return
3001-
end
3002-
local.get $0
3003-
local.get $1
3004-
call $~lib/arraybuffer/ArrayBufferView~visit
3005-
return
3006-
end
3007-
local.get $0
3008-
local.get $1
3009-
call $~lib/function/Function<%28%29=>void>~visit
3010-
return
3011-
end
3012-
local.get $0
3013-
local.get $1
3014-
call $~lib/typedarray/Int16Array~visit
3015-
return
3016-
end
3017-
local.get $0
3018-
local.get $1
3019-
call $~lib/typedarray/Float32Array~visit
3020-
return
3021-
end
3022-
local.get $0
3023-
local.get $1
3024-
call $~lib/typedarray/Uint64Array~visit
3025-
return
3026-
end
3027-
return
3028-
end
3029-
return
3030-
end
3031-
return
3032-
end
3033-
local.get $0
3034-
local.get $1
3035-
call $~lib/array/Array<i32>~visit
3036-
return
3037-
end
3038-
local.get $0
3039-
local.get $1
3040-
call $~lib/array/Array<~lib/string/String>~visit
3041-
return
3042-
end
3043-
local.get $0
3044-
local.get $1
3045-
call $bindings/esm/PlainObject~visit
3046-
return
3047-
end
3048-
local.get $0
3049-
local.get $1
3050-
call $~lib/typedarray/Uint8Array~visit
3051-
return
3052-
end
3053-
return
3054-
end
2975+
local.get $0
2976+
local.get $1
2977+
local.get $0
2978+
i32.const 8
2979+
i32.sub
2980+
i32.load
2981+
call_indirect $~/lib/rt/visitor (type $0)
30552982
unreachable
30562983
)
30572984
(func $~setArgumentsLength (param $0 i32)

0 commit comments

Comments
 (0)