Skip to content

Conversation

rhys-h-walker
Copy link

@rhys-h-walker rhys-h-walker commented May 30, 2025

This PR implements the standard Vector class as well as the Vector from the Are We Fast Yet benchmarks as primitives. The Vector object is represented by VMVector and most of Vector's methods are lowered to primitives.

The use of VMVector and the primitives is controlled by the USE_VECTOR_PRIMITIVES compilation flag, which is true per default and allows disabling the use of the vector primitives/strategy.

Methods are hashed with murmur3_32 to determine whether primitives are applicable.
These hashes can now be shown by running SOM++ with the -prim-hash-check flag, which causes an error when the hashes do not match. This is used in CI for testing that the core-lib and primitives match.

Limitations

Because SOM++ is implemented as a non-recursive interpreter, primitives cannot make message sends that need to return execution to the primitive.
This means, we cannot lower any method that needs to activate a block passed as a parameter, and we can't implement #contains: and #indexOf:, because they rely on the #= message to determine equality.

Comment on lines 114 to 178
vm_oop_t VMVector::RemoveObj(vm_oop_t other) {
const int64_t first = INT_VAL(load_ptr(this->first));
const int64_t last = INT_VAL(load_ptr(this->last));
VMArray* storage = load_ptr(this->storage);

for (int64_t i = first - 1; i < last - 1; ++i) {
vm_oop_t current = storage->GetIndexableField(i);

// Check where integers are tagged or references can be checked
if (current == other) {
Remove(NEW_INT(i - first + 2)); // Convert to 1-indexing
return load_ptr(trueObject);
}
}
return load_ptr(falseObject);
}

vm_oop_t VMVector::Remove(vm_oop_t inx) {
const int64_t first = INT_VAL(load_ptr(this->first));
int64_t last = INT_VAL(load_ptr(this->last));
VMArray* storage = load_ptr(this->storage);
int64_t index = INT_VAL(inx);

if ((last - first) != 0 && index == 0) {
index = index;
}

if (index < 1 || index > last - first) {
IndexOutOfBounds();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code here is a bit odd. I think Remove(inx) is not used anywhere else, and allocating an int here seems unnecessary for a helper.
But the code is also too general, I think.
If this is truly only a helper for RemoveObj() (if I didn't miss anything), then it doesn't need to handle the failure case, i.e., IndexOutOfBounds

@smarr smarr force-pushed the master branch 3 times, most recently from 760116b to e979852 Compare June 18, 2025 20:23
Copy link
Member

@smarr smarr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some quick comments. Thanks!

@smarr smarr force-pushed the master branch 2 times, most recently from 6943b96 to 87dc7f3 Compare July 8, 2025 14:50
@smarr
Copy link
Member

smarr commented Jul 8, 2025

@rhys-h-walker I just rebased this PR, and did a bit of work on the flag you added.
I had already forgotten, that we already had the printing of mismatching hashes.
So, I thought, it would instead be useful to make the flag check that there are no mismatches.
I am using this now in CI to see whether they are up to date.
Would be great if you could look at the last two commits and check whether you see any issues.

Thanks!

@smarr smarr force-pushed the master branch 2 times, most recently from a265562 to c704ef4 Compare July 8, 2025 16:57
@smarr smarr force-pushed the master branch 2 times, most recently from 841644d to 6cdab1e Compare August 20, 2025 17:10
rhys-h-walker and others added 6 commits August 20, 2025 21:48
This implements Vector in the interpreter, and most of its methods as primitives.
The implementation uses the new VMVector class as representation.

The #contains: and #indexOf: can’t work it in the current SOM++ design. Because when sending a message, we yield back to the bytecode loop, which is not recursive, and thus, can’t come back to the primitive code.

The `USE_VECTOR_PRIMITIVES` compilation flag is `true` per default and allows disabling the use of the vector primitives/strategy.

The implementation supports AWFY/Vector and core-lib/Vector and loads the correct primitive methods for each implementation.

Methods are hashed with murmur3_32 to determine whether primitives are applicable.
These hashes can now be shown by running SOM++ with the -prim-hashes flag.

Adapt PrimitiveContainer to store a pair of primitives, with their bytecode hash. Also reduce the code duplication in InstallPrimitives by using template parameters and function pointers.

Co-authored-by: Stefan Marr <git@stefan-marr.de>
This avoid exploding the number of configurations that need to be run in CI.
Feels a bit too much to double it.
It also makes sure the USE_VECTOR_PRIMITIVE flag is configured for unit tests.

Signed-off-by: Stefan Marr <git@stefan-marr.de>
Signed-off-by: Stefan Marr <git@stefan-marr.de>
Signed-off-by: Stefan Marr <git@stefan-marr.de>
- fix Main.cpp

Signed-off-by: Stefan Marr <git@stefan-marr.de>
This allows us to use the flag in CI and check that the hashes are correct.

Signed-off-by: Stefan Marr <git@stefan-marr.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants