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

Commit

Permalink
Merge pull request #52 from sjrd/make-list-work
Browse files Browse the repository at this point in the history
Make List work.
  • Loading branch information
tanishiking authored Apr 1, 2024
2 parents b2973ef + 5433b67 commit f0d3890
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 22 deletions.
1 change: 1 addition & 0 deletions cli/src/main/scala/TestSuites.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ object TestSuites {
TestSuite("testsuite.core.Simple"),
TestSuite("testsuite.core.Add"),
TestSuite("testsuite.core.ArrayTest"),
TestSuite("testsuite.core.BasicListTest"),
TestSuite("testsuite.core.CloneTest"),
TestSuite("testsuite.core.ControlStructuresTest"),
TestSuite("testsuite.core.VirtualDispatch"),
Expand Down
15 changes: 15 additions & 0 deletions test-suite/src/main/scala/testsuite/core/BasicListTest.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package testsuite.core

import testsuite.Assert._

object BasicListTest {
def main(): Unit = {
val l = List(5, 13, 29)
val x = l.tail.head
assertSame(13, x)

val l2 = l.map(x => x * 2)
assertSame(3, l2.size)
assertSame(26, l2(1))
}
}
10 changes: 5 additions & 5 deletions wasm/src/main/scala/ir2wasm/HelperFunctions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -760,15 +760,15 @@ object HelperFunctions {
fctx.buildAndAddToContext()
}

/** Generate clone function for the given class, if it implements Cloneable interface. The
* generated clone function will be registered in the typeData of the class (which resides in the
* vtable of the class), and will be invoked when the `super.clone()` method is called on the
* class instance.
/** Generate clone function for the given class, if it is concrete and implements the Cloneable
* interface. The generated clone function will be registered in the typeData of the class (which
* resides in the vtable of the class), and will be invoked when the `super.clone()` method is
* called on the class instance.
*/
def genCloneFunction(clazz: LinkedClass)(implicit ctx: WasmContext): Unit = {
import WasmImmediate._
val info = ctx.getClassInfo(clazz.name.name)
if (info.ancestors.contains(IRNames.CloneableClass) && !info.isInterface) {
if (info.ancestors.contains(IRNames.CloneableClass) && !info.isAbstract) {
val heapType =
WasmHeapType.Type(WasmTypeName.WasmStructTypeName(clazz.name.name))
val fctx = WasmFunctionContext(
Expand Down
15 changes: 11 additions & 4 deletions wasm/src/main/scala/ir2wasm/Preprocessor.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,28 @@ object Preprocessor {
Nil
}

val infos = clazz.methods
.filter(_.flags.namespace == IRTrees.MemberNamespace.Public)
.map(method => makeWasmFunctionInfo(clazz, method))
val classMethodInfos = {
if (clazz.kind.isClass || clazz.kind == ClassKind.HijackedClass) {
clazz.methods
.filter(_.flags.namespace == IRTrees.MemberNamespace.Public)
.map(method => makeWasmFunctionInfo(clazz, method))
} else {
Nil
}
}

ctx.putClassInfo(
clazz.name.name,
new WasmClassInfo(
clazz.name.name,
clazz.kind,
clazz.jsClassCaptures,
infos,
classMethodInfos,
allFieldDefs,
clazz.superClass.map(_.name),
clazz.interfaces.map(_.name),
clazz.ancestors,
!clazz.hasDirectInstances,
clazz.jsNativeLoadSpec,
clazz.jsNativeMembers.map(m => m.name.name -> m.jsNativeLoadSpec).toMap
)
Expand Down
4 changes: 2 additions & 2 deletions wasm/src/main/scala/ir2wasm/WasmBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -175,9 +175,9 @@ class WasmBuilder {
typeRef match {
case IRTypes.ClassRef(className) =>
val classInfo = ctx.getClassInfo(className)
// If the class implements the `java.lang.Cloneable`,
// If the class is concrete and implements the `java.lang.Cloneable`,
// `HelperFunctions.genCloneFunction` should've generated the clone function
if (classInfo.ancestors.contains(IRNames.CloneableClass))
if (!classInfo.isAbstract && classInfo.ancestors.contains(IRNames.CloneableClass))
REF_FUNC(FuncIdx(WasmFunctionName.clone(className)))
else nullref
case _ => nullref
Expand Down
3 changes: 3 additions & 0 deletions wasm/src/main/scala/ir2wasm/WasmExpressionBuilder.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,9 @@ private class WasmExpressionBuilder private (
println(tree)
???
}
} else if (info.isInterface) {
if (!info.isAncestorOfHijackedClass)
instrs += REF_CAST_NULL(HeapType(Types.WasmHeapType.ObjectType))
}

case IRTypes.ArrayType(arrayTypeRef) =>
Expand Down
24 changes: 13 additions & 11 deletions wasm/src/main/scala/wasm4s/WasmContext.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,26 +55,27 @@ trait ReadOnlyWasmContext {
IRTypes.ArrayType(typeRef)
}

/** Collects all methods declared, inherited, and mixed-in by the given class, super-class, and
* interfaces.
/** Collects all methods declared and inherited by the given class, super-class.
*
* @param className
* class to collect methods from
* @param includeAbstractMethods
* whether to include abstract methods
* @return
* list of methods in order that "collectMethods(superClass) ++ methods from interfaces ++
* methods from the class"
* list of methods in order that "collectVTableMethods(superClass) ++ methods from the class"
*/
private def collectMethods(
private def collectVTableMethods(
className: IRNames.ClassName,
includeAbstractMethods: Boolean
): List[WasmFunctionInfo] = {
val info = classInfo.getOrElse(className, throw new Error(s"Class not found: $className"))
assert(
info.kind.isClass || info.kind == ClassKind.HijackedClass,
s"collectVTableMethods cannot be called for non-class ${className.nameString}"
)
val fromSuperClass =
info.superClass.map(collectMethods(_, includeAbstractMethods)).getOrElse(Nil)
val fromInterfaces = info.interfaces.flatMap(collectMethods(_, includeAbstractMethods))
fromSuperClass ++ fromInterfaces ++
info.superClass.map(collectVTableMethods(_, includeAbstractMethods)).getOrElse(Nil)
fromSuperClass ++
(if (includeAbstractMethods) info.methods
else info.methods.filterNot(_.isAbstract))
}
Expand All @@ -83,7 +84,7 @@ trait ReadOnlyWasmContext {
val vtableType = calculateVtableType(name)
// Do not include abstract methods when calculating vtable instance,
// all slots should be filled with the function reference to the concrete methods
val methodsReverse = collectMethods(name, includeAbstractMethods = false).reverse
val methodsReverse = collectVTableMethods(name, includeAbstractMethods = false).reverse
vtableType.functions.map { slot =>
methodsReverse
.find(_.name.simpleName == slot.name.simpleName)
Expand All @@ -95,11 +96,11 @@ trait ReadOnlyWasmContext {
vtablesCache.getOrElseUpdate(
name, {
val functions =
collectMethods(name, includeAbstractMethods = true)
collectVTableMethods(name, includeAbstractMethods = true)
.foldLeft(Array.empty[WasmFunctionInfo]) { case (acc, m) =>
acc.indexWhere(_.name.simpleName == m.name.simpleName) match {
case i if i < 0 => acc :+ m
case i => acc.updated(i, m)
case i => if (m.isAbstract) acc else acc.updated(i, m)
}
}
.toList
Expand Down Expand Up @@ -574,6 +575,7 @@ object WasmContext {
val superClass: Option[IRNames.ClassName],
val interfaces: List[IRNames.ClassName],
val ancestors: List[IRNames.ClassName],
val isAbstract: Boolean,
val jsNativeLoadSpec: Option[IRTrees.JSNativeLoadSpec],
val jsNativeMembers: Map[IRNames.MethodName, IRTrees.JSNativeLoadSpec]
) {
Expand Down

0 comments on commit f0d3890

Please sign in to comment.