diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 14262ea..2280d68 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,14 +3,21 @@ 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 + - &setup-java + uses: actions/setup-java@v6 + with: + distribution: temurin + java-version: '25' + - name: Tests run: | ant test @@ -20,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 @@ -37,10 +53,14 @@ 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} + # 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 @@ -54,7 +74,5 @@ jobs: - name: AWFY Test Run run: | - pwd - export JAVA_HOME=$JAVA_HOME_8_X64 pip install ReBench - rebench awfy-test.conf + rebench -D awfy-test.conf 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 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) { 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()); + } +}