Skip to content
This repository was archived by the owner on Jul 12, 2024. It is now read-only.

Commit 26a1425

Browse files
authored
Merge pull request #22 from sjrd/inherited-fields
Take inherited fields into account.
2 parents 03b1755 + 8746b6b commit 26a1425

File tree

7 files changed

+84
-30
lines changed

7 files changed

+84
-30
lines changed

cli/src/main/scala/TestSuites.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ object TestSuites {
99
TestSuite("testsuite.core.InterfaceCall"),
1010
TestSuite("testsuite.core.AsInstanceOfTest"),
1111
TestSuite("testsuite.core.ClassOfTest"),
12+
TestSuite("testsuite.core.FieldsTest"),
1213
TestSuite("testsuite.core.GetClassTest"),
1314
TestSuite("testsuite.core.JSInteropTest"),
1415
TestSuite("testsuite.core.HijackedClassesDispatchTest"),
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package testsuite.core
2+
3+
import testsuite.Assert.ok
4+
5+
object FieldsTest {
6+
def main(): Unit = {
7+
val parent = new Parent(5)
8+
ok(parent.x == 5)
9+
ok(parent.getX == 5)
10+
11+
val child = new Child(6, "foo")
12+
ok(child.x == 6)
13+
ok(child.getX == 6)
14+
ok(child.foo() == 3)
15+
16+
val child2 = new Child(-6, "foo")
17+
ok(child2.x == -6)
18+
ok(child2.getX == -6)
19+
ok(child2.foo() == -3)
20+
}
21+
22+
class Parent(val x: Int) {
23+
def getX: Int = x
24+
}
25+
26+
class Child(x2: Int, y: String) extends Parent(x2) {
27+
def foo(): Int = if (x >= 0) y.length() else -y.length()
28+
}
29+
}

wasm/src/main/scala/Compiler.scala

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,14 @@ object Compiler {
6363
} yield {
6464
val onlyModule = moduleSet.modules.head
6565

66-
// Sort for stability
67-
val sortedClasses = onlyModule.classDefs.sortBy(_.className)
66+
/* Sort by ancestor count so that superclasses always appear before
67+
* subclasses, then tie-break by name for stability.
68+
*/
69+
val sortedClasses = onlyModule.classDefs.sortWith { (a, b) =>
70+
val cmp = a.ancestors.sizeCompare(b.ancestors)
71+
if (cmp != 0) cmp < 0
72+
else a.className.compareTo(b.className) < 0
73+
}
6874

6975
sortedClasses.foreach(showLinkedClass(_))
7076

wasm/src/main/scala/ir2wasm/Preprocessor.scala

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,23 @@ object Preprocessor {
2222
}
2323

2424
private def preprocess(clazz: LinkedClass)(implicit ctx: WasmContext): Unit = {
25+
val allFieldDefs: List[IRTrees.FieldDef] =
26+
if (clazz.kind.isClass) {
27+
val inheritedFields = clazz.superClass match {
28+
case None => Nil
29+
case Some(sup) => ctx.getClassInfo(sup.name).allFieldDefs
30+
}
31+
val myFieldDefs = clazz.fields.map {
32+
case fd: IRTrees.FieldDef =>
33+
fd
34+
case fd: IRTrees.JSFieldDef =>
35+
throw new AssertionError(s"Illegal $fd in Scala class ${clazz.className}")
36+
}
37+
inheritedFields ::: myFieldDefs
38+
} else {
39+
Nil
40+
}
41+
2542
val infos = clazz.methods
2643
.filter(_.flags.namespace == IRTrees.MemberNamespace.Public)
2744
.map(method => makeWasmFunctionInfo(clazz, method))
@@ -32,7 +49,7 @@ object Preprocessor {
3249
clazz.name.name,
3350
clazz.kind,
3451
infos,
35-
clazz.fields.collect { case f: IRTrees.FieldDef => Names.WasmFieldName(f.name.name) },
52+
allFieldDefs,
3653
clazz.superClass.map(_.name),
3754
clazz.interfaces.map(_.name),
3855
clazz.ancestors,

wasm/src/main/scala/ir2wasm/WasmBuilder.scala

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ class WasmBuilder {
143143

144144
val className = clazz.name.name
145145
val typeRef = IRTypes.ClassRef(className)
146+
val classInfo = ctx.getClassInfo(className)
146147

147148
// generate vtable type, this should be done for both abstract and concrete classes
148149
val vtable = ctx.calculateVtableType(className)
@@ -185,7 +186,7 @@ class WasmBuilder {
185186
WasmRefType(WasmHeapType.Type(vtableType.name)),
186187
isMutable = false
187188
)
188-
val fields = clazz.fields.map(transformField)
189+
val fields = classInfo.allFieldDefs.map(transformField)
189190
val structType = WasmStructType(
190191
Names.WasmTypeName.WasmStructTypeName(clazz.name.name),
191192
vtableField +: WasmStructField.itables +: fields,
@@ -195,7 +196,7 @@ class WasmBuilder {
195196

196197
// Define the `new` function, unless the class is abstract
197198
if (!isAbstractClass)
198-
genStructNewDefault(clazz, Some(gVtable), gItable)
199+
genStructNewDefault(classInfo, Some(gVtable), gItable)
199200

200201
structType
201202
}
@@ -269,15 +270,17 @@ class WasmBuilder {
269270
}
270271

271272
private def genStructNewDefault(
272-
clazz: LinkedClass,
273+
classInfo: WasmClassInfo,
273274
vtable: Option[WasmGlobal],
274275
itable: Option[WasmGlobal]
275276
)(implicit ctx: WasmContext): Unit = {
277+
val className = classInfo.name
278+
276279
val getVTable = vtable match {
277280
case None =>
278281
REF_NULL(
279282
WasmImmediate.HeapType(
280-
WasmHeapType.Type(WasmTypeName.WasmVTableTypeName(clazz.name.name))
283+
WasmHeapType.Type(WasmTypeName.WasmVTableTypeName(className))
281284
)
282285
)
283286
case Some(v) => GLOBAL_GET(WasmImmediate.GlobalIdx(v.name))
@@ -288,19 +291,19 @@ class WasmBuilder {
288291
}
289292
val defaultFields =
290293
getVTable +: getITable +:
291-
clazz.fields.collect { case f: IRTrees.FieldDef =>
294+
classInfo.allFieldDefs.map { f =>
292295
val ty = transformType(f.ftpe)
293296
Defaults.defaultValue(ty)
294297
}
295298

296-
val className = WasmTypeName.WasmStructTypeName(clazz.name.name)
299+
val structName = WasmTypeName.WasmStructTypeName(className)
297300
val body =
298-
defaultFields :+ STRUCT_NEW(WasmImmediate.TypeIdx(className))
301+
defaultFields :+ STRUCT_NEW(WasmImmediate.TypeIdx(structName))
299302
val sig =
300-
WasmFunctionSignature(Nil, List(WasmRefType(WasmHeapType.Type(className))))
303+
WasmFunctionSignature(Nil, List(WasmRefType(WasmHeapType.Type(structName))))
301304
val newDefaultTypeName = ctx.addFunctionType(sig)
302305
val func = WasmFunction(
303-
WasmFunctionName.newDefault(clazz.name.name),
306+
WasmFunctionName.newDefault(className),
304307
WasmFunctionType(newDefaultTypeName, sig),
305308
Nil,
306309
WasmExpr(body)
@@ -467,17 +470,10 @@ class WasmBuilder {
467470
}
468471

469472
private def transformField(
470-
field: IRTrees.AnyFieldDef
473+
field: IRTrees.FieldDef
471474
)(implicit ctx: WasmContext): WasmStructField = {
472-
val fieldName =
473-
field match {
474-
case f: IRTrees.FieldDef =>
475-
Names.WasmFieldName(f.name.name)
476-
// TODO
477-
case js: IRTrees.JSFieldDef => ???
478-
}
479475
WasmStructField(
480-
fieldName,
476+
Names.WasmFieldName(field.name.name),
481477
transformType(field.ftpe),
482478
// needs to be mutable even if it's flags.isMutable = false
483479
// because it's initialized by constructor

wasm/src/main/scala/ir2wasm/WasmExpressionBuilder.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ private class WasmExpressionBuilder private (
220220
case sel: IRTrees.Select =>
221221
val className = sel.field.name.className
222222
val fieldName = WasmFieldName(sel.field.name)
223-
val idx = ctx.getClassInfo(className).getFieldIdx(fieldName)
223+
val idx = ctx.getClassInfo(className).getFieldIdx(sel.field.name)
224224

225225
// For Select, the receiver can never be a hijacked class, so we can use genTreeAuto
226226
genTreeAuto(sel.qualifier)
@@ -231,7 +231,7 @@ private class WasmExpressionBuilder private (
231231
case sel: IRTrees.SelectStatic => // OK?
232232
val className = sel.field.name.className
233233
val fieldName = WasmFieldName(sel.field.name)
234-
val idx = ctx.getClassInfo(className).getFieldIdx(fieldName)
234+
val idx = ctx.getClassInfo(className).getFieldIdx(sel.field.name)
235235
instrs += GLOBAL_GET(
236236
GlobalIdx(Names.WasmGlobalName.WasmModuleInstanceName.fromIR(className))
237237
)
@@ -675,7 +675,7 @@ private class WasmExpressionBuilder private (
675675
private def genSelect(sel: IRTrees.Select): IRTypes.Type = {
676676
val className = sel.field.name.className
677677
val fieldName = WasmFieldName(sel.field.name)
678-
val idx = ctx.getClassInfo(className).getFieldIdx(fieldName)
678+
val idx = ctx.getClassInfo(className).getFieldIdx(sel.field.name)
679679

680680
// For Select, the receiver can never be a hijacked class, so we can use genTreeAuto
681681
genTreeAuto(sel.qualifier)

wasm/src/main/scala/wasm4s/WasmContext.scala

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -370,13 +370,16 @@ object WasmContext {
370370
val name: IRNames.ClassName,
371371
val kind: ClassKind,
372372
private var _methods: List[WasmFunctionInfo],
373-
private val fields: List[WasmFieldName],
373+
val allFieldDefs: List[IRTrees.FieldDef],
374374
val superClass: Option[IRNames.ClassName],
375375
val interfaces: List[IRNames.ClassName],
376376
val ancestors: List[IRNames.ClassName],
377377
val jsNativeLoadSpec: Option[IRTrees.JSNativeLoadSpec],
378378
val jsNativeMembers: Map[IRNames.MethodName, IRTrees.JSNativeLoadSpec]
379379
) {
380+
private val fieldIdxByName: Map[IRNames.FieldName, Int] =
381+
allFieldDefs.map(_.name.name).zipWithIndex.map(p => p._1 -> (p._2 + classFieldOffset)).toMap
382+
380383
def isAncestorOfHijackedClass: Boolean = AncestorsOfHijackedClasses.contains(name)
381384

382385
def isInterface = kind == ClassKind.Interface
@@ -400,11 +403,13 @@ object WasmContext {
400403
}
401404
}
402405

403-
def getFieldIdx(name: WasmFieldName): WasmImmediate.StructFieldIdx =
404-
fields.indexWhere(_ == name) match {
405-
case i if i < 0 => throw new Error(s"Field not found: $name")
406-
case i => WasmImmediate.StructFieldIdx(i + classFieldOffset)
407-
}
406+
def getFieldIdx(name: IRNames.FieldName): WasmImmediate.StructFieldIdx = {
407+
WasmImmediate.StructFieldIdx(fieldIdxByName.getOrElse(name, {
408+
throw new AssertionError(
409+
s"Unknown field ${name.nameString} in class ${this.name.nameString}"
410+
)
411+
}))
412+
}
408413
}
409414

410415
case class WasmFunctionInfo(

0 commit comments

Comments
 (0)