From 07dd1dadd302e6021da1ad0e23acb57896151b41 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 9 Oct 2026 11:58:30 +0200 Subject: [PATCH 1/6] Added #instVarNamed: primitive Signed-off-by: Stefan Marr --- src/som/primitives/ObjectPrimitives.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/som/primitives/ObjectPrimitives.java b/src/som/primitives/ObjectPrimitives.java index 22d60bd..b86bb14 100644 --- a/src/som/primitives/ObjectPrimitives.java +++ b/src/som/primitives/ObjectPrimitives.java @@ -176,6 +176,18 @@ public void invoke(final Frame frame, final Interpreter interpreter) { } }); + installInstancePrimitive(new SPrimitive("instVarNamed:", universe) { + @Override + public void invoke(final Frame frame, final Interpreter interpreter) { + SSymbol sym = (SSymbol) frame.pop(); + SObject self = (SObject) frame.pop(); + + int idx = self.getFieldIndex(sym); + + frame.push(self.getField(idx)); + } + }); + installInstancePrimitive(new SPrimitive("class", universe) { @Override public void invoke(final Frame frame, final Interpreter interpreter) { From c725699219dcfa623b83d11a5dd8770aef0de9ec Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 9 Oct 2026 11:58:42 +0200 Subject: [PATCH 2/6] Update core-lib Signed-off-by: Stefan Marr --- core-lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-lib b/core-lib index a721b4f..c67b309 160000 --- a/core-lib +++ b/core-lib @@ -1 +1 @@ -Subproject commit a721b4ff6ecb1ade54e0afe0bd15a8e80e41af17 +Subproject commit c67b309fdb6c41ec0c31a414f86dd3cb53cabb32 From f1675b9ceadf9ef9e105b7d723d87af639c3a5f7 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 9 Oct 2026 15:27:28 +0200 Subject: [PATCH 3/6] Fix SClass.getInstanceFieldName and getNumberOfInstanceFields At some point, we changed how fields from superclasses are dealt with, and these two methods were overlooked in that change. Since fields from the superclass are integral part of the class at this point, these two methods are much simpler. Signed-off-by: Stefan Marr --- src/som/vm/Universe.java | 2 +- src/som/vmobjects/SClass.java | 27 +----- tests/som/tests/ClassFieldsTests.java | 115 ++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 25 deletions(-) create mode 100644 tests/som/tests/ClassFieldsTests.java diff --git a/src/som/vm/Universe.java b/src/som/vm/Universe.java index 08c44ac..1103d10 100644 --- a/src/som/vm/Universe.java +++ b/src/som/vm/Universe.java @@ -333,7 +333,7 @@ private SAbstractObject interpretMethod(final SAbstractObject receiver, return interpreter.start(); } - private SAbstractObject initializeObjectSystem() throws ProgramDefinitionError { + public SAbstractObject initializeObjectSystem() throws ProgramDefinitionError { // Allocate the nil object nilObject = new SObject(null); diff --git a/src/som/vmobjects/SClass.java b/src/som/vmobjects/SClass.java index bec0411..2097ed7 100644 --- a/src/som/vmobjects/SClass.java +++ b/src/som/vmobjects/SClass.java @@ -206,33 +206,12 @@ public void addInstancePrimitive(final SPrimitive value, final boolean suppressW } } - public SSymbol getInstanceFieldName(int index) { - // Get the name of the instance field with the given index - if (index >= getNumberOfSuperInstanceFields()) { - // Adjust the index to account for fields defined in the super class - index -= getNumberOfSuperInstanceFields(); - - // Return the symbol representing the instance fields name - return (SSymbol) getInstanceFields().getIndexableField(index); - } else { - // Ask the super class to return the name of the instance field - return ((SClass) getSuperClass()).getInstanceFieldName(index); - } + public SSymbol getInstanceFieldName(final int index) { + return (SSymbol) getInstanceFields().getIndexableField(index); } public int getNumberOfInstanceFields() { - // Get the total number of instance fields in this class - return instanceFields.getNumberOfIndexableFields() - + getNumberOfSuperInstanceFields(); - } - - private int getNumberOfSuperInstanceFields() { - // Get the total number of instance fields defined in super classes - if (hasSuperClass()) { - return ((SClass) getSuperClass()).getNumberOfInstanceFields(); - } else { - return 0; - } + return instanceFields.getNumberOfIndexableFields(); } public boolean hasPrimitives() { diff --git a/tests/som/tests/ClassFieldsTests.java b/tests/som/tests/ClassFieldsTests.java new file mode 100644 index 0000000..efd827d --- /dev/null +++ b/tests/som/tests/ClassFieldsTests.java @@ -0,0 +1,115 @@ +package som.tests; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import som.compiler.ProgramDefinitionError; +import som.vm.Universe; +import som.vmobjects.SClass; +import som.vmobjects.SObject; + + +/** + * Checks that classes report the expected fields. + */ +@RunWith(Parameterized.class) +public class ClassFieldsTests { + + private static final String[] NONE = new String[0]; + + @Parameters(name = "{0} [{index}]") + public static Iterable data() { + return Arrays.asList(new Object[][] { + // system classes + {"Object", NONE, NONE}, + {"Class", NONE, NONE}, + {"Metaclass", NONE, NONE}, + {"Nil", NONE, NONE}, + {"Array", NONE, NONE}, + {"Method", NONE, NONE}, + {"Symbol", NONE, NONE}, + {"Integer", NONE, NONE}, + {"Primitive", NONE, NONE}, + {"String", NONE, NONE}, + {"Double", NONE, NONE}, + {"Block", NONE, NONE}, + {"Boolean", NONE, NONE}, + {"True", NONE, NONE}, + {"False", NONE, NONE}, + {"System", NONE, NONE}, + + // other library classes + {"Pair", new String[] {"key", "value"}, NONE}, + {"Vector", new String[] {"first", "last", "storage"}, NONE}, + {"HashEntry", new String[] {"key", "value", "next", "hash"}, NONE}, + + // test classes with fields in a class hierarchy + {"ClassA", new String[] {"a", "b"}, new String[] {"c1", "c2", "c3"}}, + {"ClassB", new String[] {"a", "b", "c", "d"}, + new String[] {"c1", "c2", "c3", "c4", "c5", "c6"}}, + {"ClassC", new String[] {"a", "b", "c", "d", "e", "f"}, + new String[] {"c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9"}}, + }); + } + + private final String className; + private final String[] instanceFields; + private final String[] classFields; + + public ClassFieldsTests(final String className, final String[] instanceFields, + final String[] classFields) { + this.className = className; + this.instanceFields = instanceFields; + this.classFields = classFields; + } + + private Universe universe; + + private SClass loadClass() throws ProgramDefinitionError { + Universe u = new Universe(true); + universe = u; + u.setupClassPath("Smalltalk:TestSuite"); + u.initializeObjectSystem(); + return u.loadClass(u.symbolFor(className)); + } + + private static void assertFields(final String[] expected, final SClass clazz) { + assertEquals(expected.length, clazz.getNumberOfInstanceFields()); + + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], clazz.getInstanceFieldName(i).getEmbeddedString()); + assertEquals(i, clazz.lookupFieldIndex(clazz.getInstanceFieldName(i))); + } + } + + @Test + public void testInstanceSide() throws ProgramDefinitionError { + SClass clazz = loadClass(); + assertFields(instanceFields, clazz); + } + + @Test + public void testClassSide() throws ProgramDefinitionError { + SClass clazz = loadClass(); + assertFields(classFields, clazz.getSOMClass()); + } + + @Test + public void testNumberOfFieldsOfClassObject() throws ProgramDefinitionError { + SClass clazz = loadClass(); + assertEquals(classFields.length, clazz.getNumberOfFields()); + } + + @Test + public void testNumberOfFieldsOfNewInstance() throws ProgramDefinitionError { + SClass clazz = loadClass(); + SObject obj = universe.newInstance(clazz); + assertEquals(instanceFields.length, obj.getNumberOfFields()); + } +} From c996e184db13279d4034f2abaf1975a28453c62d Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 9 Oct 2026 17:12:52 +0200 Subject: [PATCH 4/6] Update Eclipse for format checking Signed-off-by: Stefan Marr --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 14262ea..c52c004 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,7 @@ jobs: - name: Download Eclipse run: | export ECLIPSE_TAR=eclipse.tar.gz - export ECLIPSE_URL='https://www.eclipse.org/downloads/download.php?file=/eclipse/downloads/drops4/R-4.38-202512010920/eclipse-SDK-4.38-linux-gtk-x86_64.tar.gz&r=1' + export ECLIPSE_URL='https://www.eclipse.org/downloads/download.php?file=/eclipse/downloads/drops4/R-4.41-202608281142/eclipse-SDK-4.41-linux-gtk-x86_64.tar.gz&r=1' wget --progress=dot:giga ${ECLIPSE_URL} -O ${ECLIPSE_TAR} tar -C ${GITHUB_WORKSPACE}/.. -xzf ${ECLIPSE_TAR} From 0bfd0733fe75f65e02adee12275c29609a5a2bdd Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 9 Oct 2026 17:20:16 +0200 Subject: [PATCH 5/6] [GHA] Use JDK 25 Signed-off-by: Stefan Marr --- .github/workflows/ci.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c52c004..5b86c5d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,11 @@ jobs: with: submodules: true + - uses: actions/setup-java@v6 + with: + distribution: temurin + java-version: '25' + - name: Tests run: | ant test @@ -54,7 +59,5 @@ jobs: - name: AWFY Test Run run: | - pwd - export JAVA_HOME=$JAVA_HOME_8_X64 pip install ReBench rebench awfy-test.conf From ff54785196ef7c3eff758f3c08764ed94284fa36 Mon Sep 17 00:00:00 2001 From: Stefan Marr Date: Fri, 9 Oct 2026 17:27:22 +0200 Subject: [PATCH 6/6] [GHA] Split tests into two parts running in parallel Signed-off-by: Stefan Marr --- .github/workflows/ci.yml | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5b86c5d..2280d68 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,15 +3,17 @@ name: Tests on: [push, pull_request] jobs: - test_som: + part1: runs-on: ubuntu-24.04 # ubuntu-latest steps: - - name: Checkout + - &checkout + name: Checkout uses: actions/checkout@v7 with: submodules: true - - uses: actions/setup-java@v6 + - &setup-java + uses: actions/setup-java@v6 with: distribution: temurin java-version: '25' @@ -25,6 +27,15 @@ jobs: ./som.sh -cp core-lib/Smalltalk:core-lib/TestSuite:core-lib/SomSom/src/compiler:core-lib/SomSom/src/vm:core-lib/SomSom/src/vmobjects:core-lib/SomSom/src/interpreter:core-lib/SomSom/src/primitives \ core-lib/SomSom/tests/SomSomTests.som + part2: + runs-on: ubuntu-24.04 # ubuntu-latest + steps: + - *checkout + + - name: Compile + run: | + ant jar + - name: Integration Tests run: | python -m pip install --upgrade pip @@ -46,6 +57,10 @@ jobs: wget --progress=dot:giga ${ECLIPSE_URL} -O ${ECLIPSE_TAR} tar -C ${GITHUB_WORKSPACE}/.. -xzf ${ECLIPSE_TAR} + # Setup Java only here, use the system java for compiling + # then we don't have to worry about env vars for rebench + - *setup-java + - name: Check Eclipse Format run: | export ECLIPSE_EXE=${GITHUB_WORKSPACE}/../eclipse/eclipse @@ -60,4 +75,4 @@ jobs: - name: AWFY Test Run run: | pip install ReBench - rebench awfy-test.conf + rebench -D awfy-test.conf