@@ -49,7 +49,7 @@ class ClassEmitter(coreSpec: CoreSpec) {
49
49
if (classInfo.hasRuntimeTypeInfo && ! (clazz.kind.isClass && clazz.hasDirectInstances)) {
50
50
// Gen typeData -- for concrete Scala classes, we do it as part of the vtable generation instead
51
51
val typeDataFieldValues = genTypeDataFieldValues(clazz, Nil )
52
- genTypeDataGlobal(clazz.className, genTypeID.typeData, typeDataFieldValues, Nil )
52
+ genTypeDataGlobal(clazz.className, genTypeID.typeData, typeDataFieldValues, Nil , Nil )
53
53
}
54
54
55
55
// Declare static fields
@@ -138,15 +138,6 @@ class ClassEmitter(coreSpec: CoreSpec) {
138
138
}
139
139
}
140
140
141
- /** Generate common itable global for all array classes. */
142
- def genGlobalArrayClassItable ()(implicit ctx : WasmContext ): Unit = {
143
- genGlobalClassItable(
144
- genGlobalID.arrayClassITable, ctx.getClassInfo(ObjectClass ),
145
- List (SerializableClass , CloneableClass ),
146
- OriginalName (genGlobalID.arrayClassITable.toString())
147
- )
148
- }
149
-
150
141
private def genIsJSClassInstanceFunction (clazz : LinkedClass )(
151
142
implicit ctx : WasmContext ): Option [wanme.FunctionID ] = {
152
143
implicit val noPos : Position = Position .NoPosition
@@ -330,10 +321,11 @@ class ClassEmitter(coreSpec: CoreSpec) {
330
321
}
331
322
332
323
private def genTypeDataGlobal (className : ClassName , typeDataTypeID : wanme.TypeID ,
333
- typeDataFieldValues : List [wa.Instr ], vtableElems : List [wa.RefFunc ])(
324
+ typeDataFieldValues : List [wa.Instr ], itableSlots : List [wa.Instr ],
325
+ vtableElems : List [wa.RefFunc ])(
334
326
implicit ctx : WasmContext ): Unit = {
335
327
val instrs : List [wa.Instr ] =
336
- typeDataFieldValues ::: vtableElems ::: wa.StructNew (typeDataTypeID) :: Nil
328
+ typeDataFieldValues ::: itableSlots ::: vtableElems ::: wa.StructNew (typeDataTypeID) :: Nil
337
329
ctx.addGlobal(
338
330
wamod.Global (
339
331
genGlobalID.forVTable(className),
@@ -356,19 +348,17 @@ class ClassEmitter(coreSpec: CoreSpec) {
356
348
357
349
val isAbstractClass = ! clazz.hasDirectInstances
358
350
359
- // Generate the vtable and itable for concrete classes
351
+ // Generate the vtable for concrete classes
360
352
if (! isAbstractClass) {
361
353
// Generate an actual vtable, which we integrate into the typeData
362
354
val reflectiveProxies =
363
355
classInfo.resolvedMethodInfos.valuesIterator.filter(_.methodName.isReflectiveProxy).toList
364
356
val typeDataFieldValues = genTypeDataFieldValues(clazz, reflectiveProxies)
357
+ val itableSlots = genItableSlots(classInfo, clazz.ancestors)
365
358
val vtableElems = classInfo.tableEntries.map { methodName =>
366
359
wa.RefFunc (classInfo.resolvedMethodInfos(methodName).tableEntryID)
367
360
}
368
- genTypeDataGlobal(className, vtableTypeID, typeDataFieldValues, vtableElems)
369
-
370
- // Generate the itable
371
- genGlobalClassItable(clazz)
361
+ genTypeDataGlobal(className, vtableTypeID, typeDataFieldValues, itableSlots, vtableElems)
372
362
}
373
363
374
364
// Declare the struct type for the class
@@ -378,12 +368,6 @@ class ClassEmitter(coreSpec: CoreSpec) {
378
368
watpe.RefType (vtableTypeID),
379
369
isMutable = false
380
370
)
381
- val itablesField = watpe.StructField (
382
- genFieldID.objStruct.itables,
383
- itablesOriginalName,
384
- watpe.RefType (genTypeID.itables),
385
- isMutable = false
386
- )
387
371
val fields = classInfo.allFieldDefs.map { field =>
388
372
watpe.StructField (
389
373
genFieldID.forClassInstanceField(field.name.name),
@@ -405,7 +389,7 @@ class ClassEmitter(coreSpec: CoreSpec) {
405
389
}
406
390
val structTypeID = genTypeID.forClass(className)
407
391
val superType = clazz.superClass.map(s => genTypeID.forClass(s.name))
408
- val structType = watpe.StructType (vtableField :: itablesField :: fields ::: jlClassDataField)
392
+ val structType = watpe.StructType (vtableField :: fields ::: jlClassDataField)
409
393
val subType = watpe.SubType (
410
394
structTypeID,
411
395
makeDebugName(ns.ClassInstance , className),
@@ -461,6 +445,14 @@ class ClassEmitter(coreSpec: CoreSpec) {
461
445
implicit ctx : WasmContext ): wanme.TypeID = {
462
446
val className = classInfo.name
463
447
val typeID = genTypeID.forVTable(className)
448
+ val itableSlotFields = (0 until ctx.itablesLength).map { i =>
449
+ watpe.StructField (
450
+ genFieldID.vtableStruct.itableSlot(i),
451
+ OriginalName .NoOriginalName ,
452
+ watpe.RefType .nullable(watpe.HeapType .Struct ),
453
+ isMutable = false
454
+ )
455
+ }.toList
464
456
val vtableFields =
465
457
classInfo.tableEntries.map { methodName =>
466
458
watpe.StructField (
@@ -474,7 +466,7 @@ class ClassEmitter(coreSpec: CoreSpec) {
474
466
case None => genTypeID.typeData
475
467
case Some (s) => genTypeID.forVTable(s.name)
476
468
}
477
- val structType = watpe.StructType (ctx.coreLib.typeDataStructFields ::: vtableFields)
469
+ val structType = watpe.StructType (ctx.coreLib.typeDataStructFields ::: itableSlotFields ::: vtableFields)
478
470
val subType = watpe.SubType (
479
471
typeID,
480
472
makeDebugName(ns.VTable , className),
@@ -525,10 +517,10 @@ class ClassEmitter(coreSpec: CoreSpec) {
525
517
/* Test whether the itable at the target interface's slot is indeed an
526
518
* instance of that interface's itable struct type.
527
519
*/
528
- fb += wa.StructGet (genTypeID.ObjectStruct , genFieldID.objStruct.itables )
520
+ fb += wa.StructGet (genTypeID.ObjectStruct , genFieldID.objStruct.vtable )
529
521
fb += wa.StructGet (
530
- genTypeID.itables ,
531
- genFieldID.itablesStruct .itableSlot(classInfo.itableIdx)
522
+ genTypeID.ObjectVTable ,
523
+ genFieldID.vtableStruct .itableSlot(classInfo.itableIdx)
532
524
)
533
525
fb += wa.RefTest (watpe.RefType (genTypeID.forITable(className)))
534
526
fb += wa.Return
@@ -642,12 +634,6 @@ class ClassEmitter(coreSpec: CoreSpec) {
642
634
fb.setResultType(watpe.RefType (structTypeID))
643
635
644
636
fb += wa.GlobalGet (genGlobalID.forVTable(className))
645
-
646
- if (classInfo.classImplementsAnyInterface)
647
- fb += wa.GlobalGet (genGlobalID.forITable(className))
648
- else
649
- fb += wa.GlobalGet (genGlobalID.emptyITable)
650
-
651
637
classInfo.allFieldDefs.foreach { f =>
652
638
fb += genZeroOf(f.ftpe)
653
639
}
@@ -689,9 +675,8 @@ class ClassEmitter(coreSpec: CoreSpec) {
689
675
fb += wa.RefCast (structRefType)
690
676
fb += wa.LocalSet (fromTypedLocal)
691
677
692
- // Push vtable and itables on the stack (there is at least Cloneable in the itables)
678
+ // Push the vtable on the stack
693
679
fb += wa.GlobalGet (genGlobalID.forVTable(className))
694
- fb += wa.GlobalGet (genGlobalID.forITable(className))
695
680
696
681
// Push every field of `fromTyped` on the stack
697
682
info.allFieldDefs.foreach { field =>
@@ -822,55 +807,6 @@ class ClassEmitter(coreSpec: CoreSpec) {
822
807
fb.buildAndAddToModule()
823
808
}
824
809
825
- /** Generates the global instance of the class itable.
826
- *
827
- * If the class implements no interface at all, we skip this step. Instead,
828
- * we will use the unique `emptyITable` as itable for this class.
829
- */
830
- private def genGlobalClassItable (clazz : LinkedClass )(implicit ctx : WasmContext ): Unit = {
831
- val className = clazz.className
832
- val classInfo = ctx.getClassInfo(className)
833
- if (classInfo.classImplementsAnyInterface) {
834
- genGlobalClassItable(
835
- genGlobalID.forITable(className),
836
- classInfo,
837
- clazz.ancestors,
838
- makeDebugName(ns.ITable , classInfo.name)
839
- )
840
- }
841
- }
842
-
843
- private def genGlobalClassItable (classITableGlobalID : wanme.GlobalID ,
844
- classInfoForResolving : WasmContext .ClassInfo , ancestors : List [ClassName ],
845
- originalName : OriginalName )(
846
- implicit ctx : WasmContext ): Unit = {
847
- val itablesInit = Array .fill[List [wa.Instr ]](ctx.itablesLength) {
848
- List (wa.RefNull (watpe.HeapType .Struct ))
849
- }
850
- val resolvedMethodInfos = classInfoForResolving.resolvedMethodInfos
851
-
852
- for {
853
- ancestor <- ancestors
854
- // Use getClassInfoOption in case the reachability analysis got rid of those interfaces
855
- interfaceInfo <- ctx.getClassInfoOption(ancestor)
856
- if interfaceInfo.isInterface
857
- } {
858
- val init = interfaceInfo.tableEntries.map { method =>
859
- wa.RefFunc (resolvedMethodInfos(method).tableEntryID)
860
- } :+ wa.StructNew (genTypeID.forITable(ancestor))
861
- itablesInit(interfaceInfo.itableIdx) = init
862
- }
863
-
864
- val global = wamod.Global (
865
- classITableGlobalID,
866
- originalName,
867
- isMutable = false ,
868
- watpe.RefType (genTypeID.itables),
869
- wa.Expr (itablesInit.flatten.toList :+ wa.StructNew (genTypeID.itables))
870
- )
871
- ctx.addGlobal(global)
872
- }
873
-
874
810
private def genInterface (clazz : LinkedClass )(implicit ctx : WasmContext ): Unit = {
875
811
assert(clazz.kind == ClassKind .Interface )
876
812
// gen itable type
@@ -1563,5 +1499,36 @@ object ClassEmitter {
1563
1499
1564
1500
private val thisOriginalName : OriginalName = OriginalName (" this" )
1565
1501
private val vtableOriginalName : OriginalName = OriginalName (" vtable" )
1566
- private val itablesOriginalName : OriginalName = OriginalName (" itables" )
1502
+
1503
+ /** Generates the itable slots of a class.
1504
+ *
1505
+ * @param classInfoForResolving
1506
+ * The `ClassInfo` from which to resolve methods. This is normally the
1507
+ * class info of the class for which we are generating the itable slots.
1508
+ * For the itable slots of array classes, it must be the info of `jl.Object`.
1509
+ * @param ancestors
1510
+ * The list of ancestors of the target class.
1511
+ */
1512
+ def genItableSlots (classInfoForResolving : WasmContext .ClassInfo ,
1513
+ ancestors : List [ClassName ])(
1514
+ implicit ctx : WasmContext ): List [wa.Instr ] = {
1515
+ val itablesInit = Array .fill[List [wa.Instr ]](ctx.itablesLength) {
1516
+ List (wa.RefNull (watpe.HeapType .Struct ))
1517
+ }
1518
+ val resolvedMethodInfos = classInfoForResolving.resolvedMethodInfos
1519
+
1520
+ for {
1521
+ ancestor <- ancestors
1522
+ // Use getClassInfoOption in case the reachability analysis got rid of those interfaces
1523
+ interfaceInfo <- ctx.getClassInfoOption(ancestor)
1524
+ if interfaceInfo.isInterface
1525
+ } {
1526
+ val init = interfaceInfo.tableEntries.map { method =>
1527
+ wa.RefFunc (resolvedMethodInfos(method).tableEntryID)
1528
+ } :+ wa.StructNew (genTypeID.forITable(ancestor))
1529
+ itablesInit(interfaceInfo.itableIdx) = init
1530
+ }
1531
+
1532
+ itablesInit.flatten.toList
1533
+ }
1567
1534
}
0 commit comments