codefrau / SqueakJS

A Squeak Smalltalk VM in Javascript
https://squeak.js.org
MIT License
371 stars 76 forks source link

Add support for the `68533` image format #138

Closed LinqLover closed 1 year ago

LinqLover commented 2 years ago

At a first glance, everything seems to work as expected. :-)

Also updated build files.

Closes #137.

LinqLover commented 2 years ago

Very sorry for the late reply!

but isn't there a new 32bit format number, too?

Unfortunately, I don't have more details about the image format numbers, maybe @marceltaeumel could help?

Also, it looks like you accidentally checked in .gitpod.yml and .nvmrc

If you don't like them, I can remove them again ... but tbh they make the setup easier, at least for me 😅

LinqLover commented 2 years ago

but isn't there a new 32bit format number, too?

Unfortunately, I don't have more details about the image format numbers, maybe @marceltaeumel could help?

I found out the new 32-bit format number with mt's help - 7033 -, but unfortunately, the VM seems unable to parse this image format (Uncaught RangeError: Invalid typed array length: 25439843 from readBits()). I'm afraid I don't understand enough to fix this. :(

(Btw, I think that Smalltalk image imageFormatVersion seems to output nonsense in SqueakJS, or is the fallback code wrong?)

dtlewis290 commented 2 years ago

FYI - The image format numbers are documented in the package named "ImageFormat" which can be loaded from the VMMaker repository at source.squeak.org. This is a stand-alone package with no dependencies on VMMaker itself, so you can load it into any Squeak image. Take a look at the class comments, utility methods, and unit tests to see how the numbering system works.

dtlewis290 commented 2 years ago

Note also that for both the 32-bit and 64-bit image, you can clear one bit in the image format number (as read from the disk file) to get the image format number that is currently recognized:

7033 bitClear: 2r1000000000 ==> 6521 68533 bitClear: 2r1000000000 ==> 68021

Since we know that the SqueakJS VM supports multiple bytecode sets (Sista), then it may be that all that is needed here is to clear the bit after reading it from the image file. The only complexity is that we need to remember that bit setting so we can write it back out to disk with the bit set properly. In the compiled VMs, the setting is maintained in an instance variable in the interpreter.

dtlewis290 commented 2 years ago

Possibly useful references: In class ImageFormat, I started with five historical image format numbers:

ImageFormat baseVersionNumbers ==> #(6502 6504 68000 68002 68004)

hasClosures and wordSize need to be derived from these five numbers (not from a bit test). The other things are simple bit tests that are the same for 32-bit and 64-bit images. The logic is in ImageFormat>>fromInteger:

To illustrate:

7033 bitAt: 10 put: 0 ==> 6521 6521 bitAt: 5 put: 0 ==> 6505 6505 bitAt: 1 put: 0 ==> 6504

68533 bitAt: 10 put: 0 ==> 68021 68021 bitAt: 5 put: 0 ==> 68005 68005 bitAt: 1 put: 0 ==> 68004

dtlewis290 commented 2 years ago

@codefrau this is untested and I am not a Javascript pern but I think that the image format reading might work like the following. Note that the multipleByteCodeSetsActive variable is useful only if we also implement the #primitiveMultipleBytecodeSetsActive primitive in the interpreter. This is of no immediate interest for SqueakJS but I added the variable to show how it would be set if it was needed.

    // read version and determine endianness
    var baseVersions = [6502, 6504, 68000, 68002, 68004],
        baseVersionMask = 0x119EE,
        version = 0,
        fileHeaderSize = 0;
    while (true) {  // try all four endianness + header combos
        littleEndian = !littleEndian;
        pos = fileHeaderSize;
        version = readWord();
        if (baseVersions.indexOf(version & baseVersionMask) >= 0) break;
        if (!littleEndian) fileHeaderSize += 512;
        if (fileHeaderSize > 512) throw Error("bad image version");
    };
    this.version = version;
    var nativeFloats = version & 1;
    this.hasClosures = [6502, 68000].indexOf(version) < 0;
    this.isSpur = version & 16;
    var multipleByteCodeSetsActive = version & 256; // probably not needed(?)
    var is64Bit = version >= 68000;
codefrau commented 1 year ago

merged