@@ -42,40 +42,97 @@ class WasmBuilder {
42
42
}
43
43
}
44
44
45
+ /** @return
46
+ * Optionally returns the generated struct type for this class. If the given LinkedClass is an
47
+ * abstract class, returns None
48
+ */
45
49
private def transformClassCommon (
46
50
clazz : LinkedClass
47
51
)(implicit ctx : WasmContext ): WasmStructType = {
48
- val (vtableType, vtableName) = genVTable(clazz)
52
+ // gen functions
53
+ clazz.methods.foreach { method =>
54
+ genFunction(clazz, method)
55
+ }
56
+ val className = clazz.name.name
57
+
58
+ // generate vtable type, this should be done for both abstract and concrete classes
59
+ val vtable = ctx.calculateVtableType(className)
60
+ val vtableType = genVTableType(clazz, vtable.functions)
61
+ ctx.addGCType(vtableType)
62
+
63
+ val isAbstractClass = {
64
+ // If number of declared functions doesn't match number of defined functions, it must be a AbstractClass
65
+ // TODO: better way to check if it's abstract class
66
+ val definedFunctions = ctx.calculateGlobalVTable(className)
67
+ val declaredFunctions = vtable.functions
68
+ declaredFunctions.length != definedFunctions.length
69
+ }
70
+
71
+ // we should't generate global vtable for abstract class because
72
+ // - Can't generate Global vtable because we can't fill the slot for abstract methods
73
+ // - We won't access vtable for abstract classes since we can't instantiate abstract classes, there's no point generating
74
+ //
75
+ // However, I couldn't find a way to test if the LinkedClass is abstract
76
+ // "clazz.methods.exists(m => m.body.isEmpty)" doesn't work because abstract methods are removed at linker optimization
77
+ // the WasmFunctionInfo of the abstract methods will be added specially in Preprocessor
78
+ val (gVtable, gItable) = if (! isAbstractClass) {
79
+ // Generate global vtable
80
+ val functions = ctx.calculateGlobalVTable(className)
81
+ val vtableInit = functions.map { method =>
82
+ WasmInstr .REF_FUNC (method.name)
83
+ } :+ WasmInstr .STRUCT_NEW (vtableType.name)
84
+ val vtableName = Names .WasmGlobalName .WasmGlobalVTableName (clazz.name.name)
85
+ val globalVTable =
86
+ WasmGlobal (
87
+ vtableName,
88
+ WasmRefNullType (WasmHeapType .Type (vtableType.name)),
89
+ WasmExpr (vtableInit),
90
+ isMutable = false
91
+ )
92
+ ctx.addGlobal(globalVTable)
93
+
94
+ // Generate class itable
95
+ val globalClassITable = calculateClassITable(clazz)
96
+ globalClassITable.foreach(ctx.addGlobal)
97
+
98
+ (Some (globalVTable), globalClassITable)
99
+ } else (None , None )
100
+
101
+ // Declare the strcut type for the class
102
+ genStructNewDefault(clazz, gVtable, gItable)
49
103
val vtableField = WasmStructField (
50
104
Names .WasmFieldName .vtable,
51
105
WasmRefNullType (WasmHeapType .Type (vtableType.name)),
52
106
isMutable = false
53
107
)
54
- calculateClassITable(clazz) match {
55
- case None =>
56
- genStructNewDefault(clazz, vtableName, None )
57
- case Some (globalITable) =>
58
- ctx.addGlobal(globalITable)
59
- genStructNewDefault(clazz, vtableName, Some (globalITable))
60
- }
61
-
62
- // type definition
63
108
val fields = clazz.fields.map(transformField)
64
109
val structType = WasmStructType (
65
110
Names .WasmTypeName .WasmStructTypeName (clazz.name.name),
66
111
vtableField +: WasmStructField .itables +: fields,
67
112
clazz.superClass.map(s => Names .WasmTypeName .WasmStructTypeName (s.name))
68
113
)
69
114
ctx.addGCType(structType)
70
-
71
- // implementation of methods
72
- clazz.methods.foreach { method =>
73
- genFunction(clazz, method)
74
- }
75
-
76
115
structType
77
116
}
78
117
118
+ private def genVTableType (clazz : LinkedClass , functions : List [WasmFunctionInfo ])(implicit
119
+ ctx : WasmContext
120
+ ): WasmStructType = {
121
+ val vtableFields =
122
+ functions.map { method =>
123
+ WasmStructField (
124
+ Names .WasmFieldName (method.name),
125
+ WasmRefNullType (WasmHeapType .Func (method.toWasmFunctionType().name)),
126
+ isMutable = false
127
+ )
128
+ }
129
+ WasmStructType (
130
+ Names .WasmTypeName .WasmVTableTypeName (clazz.name.name),
131
+ vtableFields,
132
+ clazz.superClass.map(s => Names .WasmTypeName .WasmVTableTypeName (s.name))
133
+ )
134
+ }
135
+
79
136
private def genLoadModuleFunc (clazz : LinkedClass )(implicit ctx : WasmContext ): Unit = {
80
137
import WasmImmediate ._
81
138
assert(clazz.kind == ClassKind .ModuleClass )
@@ -118,10 +175,18 @@ class WasmBuilder {
118
175
119
176
private def genStructNewDefault (
120
177
clazz : LinkedClass ,
121
- vtable : WasmGlobalName . WasmGlobalVTableName ,
178
+ vtable : Option [ WasmGlobal ] ,
122
179
itable : Option [WasmGlobal ]
123
180
)(implicit ctx : WasmContext ): Unit = {
124
- val getVTable = GLOBAL_GET (WasmImmediate .GlobalIdx (vtable))
181
+ val getVTable = vtable match {
182
+ case None =>
183
+ REF_NULL (
184
+ WasmImmediate .HeapType (
185
+ WasmHeapType .Type (WasmTypeName .WasmVTableTypeName (clazz.name.name))
186
+ )
187
+ )
188
+ case Some (v) => GLOBAL_GET (WasmImmediate .GlobalIdx (v.name))
189
+ }
125
190
val getITable = itable match {
126
191
case None => REF_NULL (WasmImmediate .HeapType (WasmHeapType .Type (WasmArrayType .itables.name)))
127
192
case Some (i) => GLOBAL_GET (WasmImmediate .GlobalIdx (i.name))
@@ -156,21 +221,7 @@ class WasmBuilder {
156
221
)(implicit ctx : ReadOnlyWasmContext ): Option [WasmGlobal ] = {
157
222
val classItables = ctx.calculateClassItables(clazz.name.name)
158
223
if (! classItables.isEmpty) {
159
- // val classITableTypeName = WasmTypeName.WasmITableTypeName(clazz.name.name)
160
- // val classITableType = WasmStructType(
161
- // classITableTypeName,
162
- // interfaceInfos.map { info =>
163
- // val itableTypeName = WasmTypeName.WasmITableTypeName(info.name)
164
- // WasmStructField(
165
- // Names.WasmFieldName(itableTypeName),
166
- // WasmRefType(WasmHeapType.Type(itableTypeName)),
167
- // isMutable = false
168
- // )
169
- // },
170
- // None
171
- // )
172
-
173
- val vtable = ctx.calculateVtable(clazz.name.name)
224
+ val vtable = ctx.calculateVtableType(clazz.name.name)
174
225
175
226
val itablesInit : List [WasmInstr ] = classItables.itables.flatMap { iface =>
176
227
iface.methods.map { method =>
@@ -194,44 +245,6 @@ class WasmBuilder {
194
245
} else None
195
246
}
196
247
197
- private def genVTable (
198
- clazz : LinkedClass
199
- )(implicit ctx : WasmContext ): (WasmStructType , WasmGlobalName .WasmGlobalVTableName ) = {
200
- val className = clazz.name.name
201
- def genVTableType (vtable : WasmVTable ): WasmStructType = {
202
- val vtableFields =
203
- vtable.functions.map { method =>
204
- WasmStructField (
205
- Names .WasmFieldName (method.name),
206
- WasmRefNullType (WasmHeapType .Func (method.toWasmFunctionType().name)),
207
- isMutable = false
208
- )
209
- }
210
- WasmStructType (
211
- Names .WasmTypeName .WasmVTableTypeName .fromIR(clazz.name.name),
212
- vtableFields,
213
- clazz.superClass.map(s => Names .WasmTypeName .WasmVTableTypeName .fromIR(s.name))
214
- )
215
- }
216
-
217
- val vtableName = Names .WasmGlobalName .WasmGlobalVTableName (clazz.name.name)
218
-
219
- val vtable = ctx.calculateVtable(className)
220
- val vtableType = genVTableType(vtable)
221
- ctx.addGCType(vtableType)
222
-
223
- val globalVTable =
224
- WasmGlobal (
225
- vtableName,
226
- WasmRefNullType (WasmHeapType .Type (vtableType.name)),
227
- WasmExpr (vtable.toVTableEntries(vtableType.name)),
228
- isMutable = false
229
- )
230
- ctx.addGlobal(globalVTable)
231
-
232
- (vtableType, vtableName)
233
- }
234
-
235
248
private def transformClass (clazz : LinkedClass )(implicit ctx : WasmContext ): Unit = {
236
249
assert(clazz.kind == ClassKind .Class )
237
250
transformClassCommon(clazz)
0 commit comments