Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 24 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
12 changes: 12 additions & 0 deletions src/som/primitives/ObjectPrimitives.java
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion src/som/vm/Universe.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
27 changes: 3 additions & 24 deletions src/som/vmobjects/SClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
115 changes: 115 additions & 0 deletions tests/som/tests/ClassFieldsTests.java
Original file line number Diff line number Diff line change
@@ -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<Object[]> 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());
}
}