Eliot Miranda uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog-eem.3354.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.3354 Author: eem Time: 21 March 2024, 7:56:37.355946 pm UUID: 67b625b4-ae15-4b1d-a144-7fd52510caf2 Ancestors: VMMaker.oscog-eem.3353
Get rid of the vile hack that assigned multipleBytecodeSetsActive in the function imageFormatVersionFromSnapshot: used from the testing readableImage: (!!, this is really bad pratice ;-) ).
Refactor checkImageVersionFrom:startingAt: into checkImageVersionFrom:startingAt:assignRawVersion: & bailOutOfImageLoad:, decoupling the abort exit message from the image load check (the former assumes a console VM, waiting for a carriage return, which is dubious).
Also lose RawBitsArray>>byteAt: which is now in trunk. I trust the implementation there-in is correct.
=============== Diff against VMMaker.oscog-eem.3353 ===============
Item was changed: ----- Method: CoInterpreter>>readImageFromFile:HeapSize:StartingAt: (in category 'image save/restore') ----- readImageFromFile: f HeapSize: desiredHeapSize StartingAt: imageOffset "Read an image from the given file stream, allocating an amount of memory to its object heap. V3: desiredHeapSize is the total size of the heap. Fail if the image has an unknown format or requires more than the specified amount of memory.
Spur: desiredHeapSize is ignored; this routine will attempt to provide at least extraVMMemory's ammount of free space after the image is loaded, taking any free space in the image into account. extraVMMemory is stored in the image header and is accessible as vmParameterAt: 23. If extraVMMemory is 0, the value defaults to the default grow headroom. Fail if the image has an unknown format or if sufficient memory cannot be allocated.
Details: This method detects when the image was stored on a machine with the opposite byte ordering from this machine and swaps the bytes automatically. Furthermore, it allows the header information to start 512 bytes into the file, since some file transfer programs for the Macintosh apparently prepend a Mac-specific header of this size. Note that this same 512 bytes of prefix area could also be used to store an exec command on Unix systems, allowing one to launch Smalltalk by invoking the image name as a command."
<var: 'f' type: #sqImageFile> <var: 'desiredHeapSize' type: #usqInt> <var: 'imageOffset' type: #squeakFileOffsetType>
+ | version rawVersion swapBytes headerStart headerSize headerFlags dataSize bytesRead bytesToShift heapSize - | swapBytes headerStart headerSize headerFlags dataSize bytesRead bytesToShift heapSize minimumMemory allocationReserve cogCodeBase firstSegSize hdrNumStackPages hdrEdenBytes hdrCogCodeSize hdrMaxExtSemTabSize | <var: 'heapSize' type: #usqInt> <var: 'dataSize' type: #'size_t'> <var: 'minimumMemory' type: #usqInt> <var: 'allocationReserve' type: #usqInt> <var: 'headerStart' type: #squeakFileOffsetType>
transcript := #stdout. "stdout is not available at compile time. this is the earliest available point." metaclassNumSlots := 6. "guess Metaclass instSize" classNameIndex := 6. "guess (Class instVarIndexFor: 'name' ifAbsent: []) - 1" + version := self checkImageVersionFrom: f startingAt: imageOffset assignRawVersion: (self addressOf: rawVersion put: [:v| rawVersion := v]). + version = 0 ifTrue: + [self bailOutOfImageLoad: rawVersion]. + swapBytes := rawVersion ~= version. + multipleBytecodeSetsActive := version anyMask: MultipleBytecodeSetsBitmask. - swapBytes := self checkImageVersionFrom: f startingAt: imageOffset. headerStart := (self sqImageFilePosition: f) - 4. "record header start position"
headerSize := self getWord32FromFile: f swap: swapBytes. dataSize := self getLongFromFile: f swap: swapBytes. oldImageBaseAddress := self getLongFromFile: f swap: swapBytes. objectMemory specialObjectsOop: (self getLongFromFile: f swap: swapBytes). objectMemory lastHash: (self getLongFromFile: f swap: swapBytes). "N.B. not used by NewObjectMemory." savedWindowSize := self getLongFromFile: f swap: swapBytes. headerFlags := self getLongFromFile: f swap: swapBytes. self setImageHeaderFlagsFrom: headerFlags. extraVMMemory := self getWord32FromFile: f swap: swapBytes. "N.B. ignored in V3." hdrNumStackPages := self getShortFromFile: f swap: swapBytes. "4 stack pages is small. Should be able to run with as few as three. 4 should be comfortable but slow. 8 is a reasonable default. Can be changed via vmParameterAt: 43 put: n. Can be set as a preference (Info.plist, VM.ini, command line etc). If desiredNumStackPages is already non-zero then it has been set as a preference. Ignore (but preserve) the header's default." numStackPages := desiredNumStackPages ~= 0 ifTrue: [desiredNumStackPages] ifFalse: [hdrNumStackPages = 0 ifTrue: [self defaultNumStackPages] ifFalse: [hdrNumStackPages]]. desiredNumStackPages := hdrNumStackPages. "This slot holds the size of the native method zone in 1k units. (pad to word boundary)." hdrCogCodeSize := (self getShortFromFile: f swap: swapBytes) * 1024. cogCodeSize := desiredCogCodeSize ~= 0 ifTrue: [desiredCogCodeSize] ifFalse: [hdrCogCodeSize = 0 ifTrue: [cogit defaultCogCodeSize] ifFalse: [desiredCogCodeSize := hdrCogCodeSize]]. "set for vmParameter 47" cogCodeSize > cogit maxCogCodeSize ifTrue: [cogCodeSize := cogit maxCogCodeSize]. hdrEdenBytes := self getWord32FromFile: f swap: swapBytes. objectMemory edenBytes: (desiredEdenBytes ~= 0 ifTrue: [desiredEdenBytes] ifFalse: [hdrEdenBytes = 0 ifTrue: [objectMemory defaultEdenBytes] ifFalse: [hdrEdenBytes]]). desiredEdenBytes := hdrEdenBytes. hdrMaxExtSemTabSize := self getShortFromFile: f swap: swapBytes. hdrMaxExtSemTabSize ~= 0 ifTrue: [self setMaxExtSemSizeTo: hdrMaxExtSemTabSize]. the2ndUnknownShort := self getShortFromFile: f swap: swapBytes. "Set maxLiteralCountForCompile unless it has already been set on the command line." maxLiteralCountForCompile < 0 ifTrue: [maxLiteralCountForCompile := the2ndUnknownShort ~= 0 ifTrue: [the2ndUnknownShort] ifFalse: [MaxLiteralCountForCompile]]. firstSegSize := self getLongFromFile: f swap: swapBytes. objectMemory firstSegmentSize: firstSegSize.
"compare memory requirements with availability" allocationReserve := self interpreterAllocationReserveBytes. minimumMemory := cogCodeSize "no need to include the stackZone; this is alloca'ed" + dataSize + objectMemory newSpaceBytes + allocationReserve. "Compute how much space is needed for the initial heap allocation. no need to include the stackZone; this is alloca'ed. no need to include the JIT code zone size; this is allocated separately." objectMemory hasSpurMemoryManagerAPI ifTrue: [| freeOldSpaceInImage headroom | freeOldSpaceInImage := self getLongFromFile: f swap: swapBytes. headroom := objectMemory initialHeadroom: extraVMMemory givenFreeOldSpaceInImage: freeOldSpaceInImage. heapSize := objectMemory roundUpHeapSize: dataSize + headroom + objectMemory newSpaceBytes + (headroom > allocationReserve ifTrue: [0] ifFalse: [allocationReserve])] ifFalse: [heapSize := desiredHeapSize + objectMemory newSpaceBytes + (desiredHeapSize - dataSize > allocationReserve ifTrue: [0] ifFalse: [allocationReserve]). heapSize < minimumMemory ifTrue: [self insufficientMemorySpecifiedError]].
"allocateJITMemory will assign the actual size allocated, which is rounded up to a page boundary." cogCodeBase := (self allocateJITMemory: (self addressOf: cogCodeSize)) asInteger.
"allocate a contiguous block of memory for the Squeak heap and ancilliary data structures" (self allocateMemory: heapSize minimum: minimumMemory imageFile: f headerSize: headerSize) asUnsignedInteger ifNil: [self insufficientMemoryAvailableError] ifNotNil: [:mem| "cannot clash with the variable memory still in use in NewCoObjectMemory and superclasses" objectMemory setHeapBase: (heapBase := mem) memoryLimit: mem + heapSize endOfMemory: mem + dataSize].
"position file after the header" self sqImageFile: f Seek: headerStart + headerSize.
"read in the image in bulk, then swap the bytes if necessary" bytesRead := objectMemory readHeapFromImageFile: f dataBytes: dataSize. bytesRead ~= dataSize ifTrue: [self unableToReadImageError].
self ensureImageFormatIsUpToDate: swapBytes.
"compute difference between old and new memory base addresses" bytesToShift := objectMemory memoryBaseForImageRead - oldImageBaseAddress. self initializeInterpreter: bytesToShift. "adjusts all oops to new location" cogit initializeCodeZoneFrom: cogCodeBase upTo: cogCodeBase + cogCodeSize. ^dataSize!
Item was changed: ----- Method: CogVMSimulator>>openOn:extraMemory: (in category 'initialize-release') ----- openOn: fileName extraMemory: extraBytes "CogVMSimulator new openOn: 'clone.im' extraMemory: 100000"
| f version headerSize dataSize count bytesToShift swapBytes headerFlags firstSegSize heapSize hdrNumStackPages hdrEdenBytes hdrMaxExtSemTabSize hdrCogCodeSize stackZoneSize methodCacheSize primTraceLogSize allocationReserve | "open image file and read the header"
(f := self openImageFileNamed: fileName) ifNil: [^self].
"Set the image name and the first argument; there are no arguments during simulation unless set explicitly." systemAttributes at: 1 put: fileName.
["begin ensure block..." imageName := f fullName. f binary.
+ version := self getWord32FromFile: f swap: false. - version := self getWord32FromFile: f swap: false. "current version: 16r1968 (=6504) vive la revolucion!!" (self readableFormat: version) ifTrue: [swapBytes := false] ifFalse: [(version := version byteSwap32) = self imageFormatVersion ifTrue: [swapBytes := true] ifFalse: [self error: 'incomaptible image format']]. + multipleBytecodeSetsActive := version anyMask: MultipleBytecodeSetsBitmask. headerSize := self getWord32FromFile: f swap: swapBytes. dataSize := self getLongFromFile: f swap: swapBytes. "length of heap in file" oldImageBaseAddress := self getLongFromFile: f swap: swapBytes. "object memory base address of image" objectMemory specialObjectsOop: (self getLongFromFile: f swap: swapBytes). objectMemory lastHash: (self getLongFromFile: f swap: swapBytes). "Should be loaded from, and saved to the image header"
savedWindowSize := self getLongFromFile: f swap: swapBytes. headerFlags := self getLongFromFile: f swap: swapBytes. self setImageHeaderFlagsFrom: headerFlags. extraVMMemory := self getWord32FromFile: f swap: swapBytes. hdrNumStackPages := self getShortFromFile: f swap: swapBytes. "4 stack pages is small. Should be able to run with as few as three. 4 should be comfortable but slow. 8 is a reasonable default. Can be changed via vmParameterAt: 43 put: n" numStackPages := desiredNumStackPages ~= 0 ifTrue: [desiredNumStackPages] ifFalse: [hdrNumStackPages = 0 ifTrue: [self defaultNumStackPages] ifFalse: [hdrNumStackPages]]. desiredNumStackPages := hdrNumStackPages. stackZoneSize := self computeStackZoneSize. "This slot holds the size of the native method zone in 1k units. (pad to word boundary)." hdrCogCodeSize := (self getShortFromFile: f swap: swapBytes) * 1024. cogCodeSize := desiredCogCodeSize ~= 0 ifTrue: [desiredCogCodeSize] ifFalse: [hdrCogCodeSize = 0 ifTrue: [cogit defaultCogCodeSize] ifFalse: [hdrCogCodeSize]]. desiredCogCodeSize := hdrCogCodeSize. self assert: f position = (objectMemory wordSize = 4 ifTrue: [40] ifFalse: [64]). hdrEdenBytes := self getWord32FromFile: f swap: swapBytes. objectMemory edenBytes: (desiredEdenBytes ~= 0 ifTrue: [desiredEdenBytes] ifFalse: [hdrEdenBytes = 0 ifTrue: [objectMemory defaultEdenBytes] ifFalse: [hdrEdenBytes]]). desiredEdenBytes := hdrEdenBytes. hdrMaxExtSemTabSize := self getShortFromFile: f swap: swapBytes. hdrMaxExtSemTabSize ~= 0 ifTrue: [self setMaxExtSemSizeTo: hdrMaxExtSemTabSize]. the2ndUnknownShort := self getShortFromFile: f swap: swapBytes. "Set maxLiteralCountForCompile unless it has already been set on the command line." maxLiteralCountForCompile < 0 ifTrue: [maxLiteralCountForCompile := the2ndUnknownShort ~= 0 ifTrue: [the2ndUnknownShort] ifFalse: [MaxLiteralCountForCompile]]. self assert: f position = (objectMemory wordSize = 4 ifTrue: [48] ifFalse: [72]). firstSegSize := self getLongFromFile: f swap: swapBytes. objectMemory firstSegmentSize: firstSegSize. "For Open PICs to be able to probe the method cache during simulation the methodCache must be relocated to memory." methodCacheSize := methodCache size * objectMemory wordSize. primTraceLogSize := primTraceLog size * objectMemory wordSize.
"To cope with modern OSs that disallow executing code in writable memory we dual-map the code zone, one mapping with read/write permissions and the other with read/execute permissions. In simulation all we can do is use memory, so if we're simulating dual mapping we use double the memory and simulate the memory sharing in the Cogit's backEnd." effectiveCogCodeSize := (InitializationOptions at: #DUAL_MAPPED_CODE_ZONE ifAbsent: [false]) ifTrue: [cogCodeSize * 2 + Cogit guardPageSize] ifFalse: [cogCodeSize].
"allocate interpreter memory. This list is in address order, low to high. In the actual VM the stack zone exists on the C stack." heapBase := (Cogit guardPageSize + effectiveCogCodeSize + stackZoneSize + methodCacheSize + primTraceLogSize + self rumpCStackSize) roundUpTo: objectMemory allocationUnit. "compare memory requirements with availability" allocationReserve := self interpreterAllocationReserveBytes. objectMemory hasSpurMemoryManagerAPI ifTrue: [| freeOldSpaceInImage headroom | freeOldSpaceInImage := self getLongFromFile: f swap: swapBytes. headroom := objectMemory initialHeadroom: extraVMMemory givenFreeOldSpaceInImage: freeOldSpaceInImage. heapSize := objectMemory roundUpHeapSize: dataSize + headroom + objectMemory newSpaceBytes + (headroom > allocationReserve ifTrue: [0] ifFalse: [allocationReserve])] ifFalse: [heapSize := dataSize + extraBytes + objectMemory newSpaceBytes + (extraBytes > allocationReserve ifTrue: [0] ifFalse: [allocationReserve])]. "allocate interpreter memory" heapBase := objectMemory setHeapBase: heapBase memoryLimit: heapBase + heapSize endOfMemory: heapBase + dataSize. "bogus for Spur"
self assert: cogCodeSize \ 4 = 0. self assert: objectMemory memoryLimit \ 4 = 0. self assert: self rumpCStackSize \ 4 = 0. objectMemory allocateMemoryOfSize: objectMemory memoryLimit. "read in the image in bulk, then swap the bytes if necessary" f position: headerSize. count := objectMemory readHeapFromImageFile: f dataBytes: dataSize. count ~= dataSize ifTrue: [self halt]] ensure: [f close]. self moveMethodCacheToMemoryAt: objectMemory cogCodeBase + effectiveCogCodeSize + stackZoneSize. self movePrimTraceLogToMemoryAt: objectMemory cogCodeBase + effectiveCogCodeSize + stackZoneSize + methodCacheSize.
self ensureImageFormatIsUpToDate: swapBytes.
bytesToShift := objectMemory memoryBaseForImageRead - oldImageBaseAddress. "adjust pointers for zero base address" UIManager default informUser: 'Relocating object pointers...' during: [self initializeInterpreter: bytesToShift]. cogit initializeCodeZoneFrom: Cogit guardPageSize upTo: Cogit guardPageSize + cogCodeSize!
Item was removed: - ----- Method: RawBitsArray>>byteAt: (in category '*VMMaker-simulation') ----- - byteAt: anInteger - "emulate an access to raw (unsigned) bytes, as if the receiver was a ByteArray" - - | element p | - p := self bytesPerBasicElement. - p = 1 ifTrue: [^self basicAt: 1]. - element := self basicAt: anInteger + p - 1 // p. - ^Smalltalk isLittleEndian - ifTrue: [element digitAt: anInteger - 1 \ p + 1] - ifFalse: [element digitAt: p - (anInteger \ p)] - !
Item was added: + ----- Method: StackDepthFinder>>methodReturnSpecialConstant: (in category 'instruction decoding implicit literals') ----- + methodReturnSpecialConstant: aConstant + ^self methodReturnConstant: aConstant!
Item was added: + ----- Method: StackInterpreter>>bailOutOfImageLoad: (in category 'image save/restore') ----- + bailOutOfImageLoad: rawVersion + "Abort on image load, because of invalid version info, etc, with an error message" + self print: 'This interpreter (vers. '. + self printNum: self imageFormatVersion. + self print: ') cannot read image file (vers. '. + self printNum: rawVersion. + self print: ').'. + self cr. + self print: 'Press CR to quit...'. + self getchar. + self ioExitWithErrorCode: 1. + ^false!
Item was removed: - ----- Method: StackInterpreter>>checkImageVersionFrom:startingAt: (in category 'image save/restore') ----- - checkImageVersionFrom: f startingAt: imageOffset - "Read and verify the image file version number and return true if the the given image file needs to be byte-swapped. As a side effect, position the file stream just after the version number of the image header. This code prints a warning and does a hard-exit if it cannot find a valid version number." - "This code is based on C code by Ian Piumarta." - - <inline: false> - | version firstVersion | - <var: #f type: #sqImageFile> - <var: #imageOffset type: #squeakFileOffsetType> - - "check the version number" - self sqImageFile: f Seek: imageOffset. - version := firstVersion := self getWord32FromFile: f swap: false. - (self readableFormat: version) ifTrue: [^ false]. - - "try with bytes reversed" - self sqImageFile: f Seek: imageOffset. - version := self getWord32FromFile: f swap: true. - (self readableFormat: version) ifTrue: [^ true]. - - "Note: The following is only meaningful if not reading an embedded image" - imageOffset = 0 ifTrue:[ - "try skipping the first 512 bytes (prepended by certain Mac file transfer utilities)" - self sqImageFile: f Seek: 512. - version := self getWord32FromFile: f swap: false. - (self readableFormat: version) ifTrue: [^ false]. - - "try skipping the first 512 bytes with bytes reversed" - self sqImageFile: f Seek: 512. - version := self getWord32FromFile: f swap: true. - (self readableFormat: version) ifTrue: [^ true]]. - - "hard failure; abort" - self print: 'This interpreter (vers. '. - self printNum: self imageFormatVersion. - self print: ') cannot read image file (vers. '. - self printNum: firstVersion. - self print: ').'. - self cr. - self print: 'Press CR to quit...'. - self getchar. - self ioExitWithErrorCode: 1. - ^false!
Item was added: + ----- Method: StackInterpreter>>checkImageVersionFrom:startingAt:assignRawVersion: (in category 'image save/restore') ----- + checkImageVersionFrom: f startingAt: imageOffset assignRawVersion: rawVersionPtr + "Read and verify the image file version number and answer it. + Assign through rawVersionPtr the unswapped version number. The caller can then + infer if the given image file needs to be byte-swapped by seeing if the returned value + equals tha assigned through rawVersionPtr. + 0 is answered if no valid version could be found." + + <inline: false> + | version | + <var: 'f' type: #sqImageFile> + <var: 'imageOffset' type: #squeakFileOffsetType> + <var: 'rawVersionPtr' type: #'sqInt *'> + + "check the version number" + self sqImageFile: f Seek: imageOffset. + version := self getWord32FromFile: f swap: false. + rawVersionPtr at: 0 put: version. + (self readableFormat: version) ifTrue: + [^version]. + + "try with bytes reversed" + self sqImageFile: f Seek: imageOffset. + version := self getWord32FromFile: f swap: true. + (self readableFormat: version) ifTrue: + [^version]. + + "Note: The following is only meaningful if not reading an embedded image" + imageOffset = 0 ifTrue: + "try skipping the first 512 bytes (prepended by certain Mac file transfer utilities)" + [self sqImageFile: f Seek: 512. + version := self getWord32FromFile: f swap: false. + rawVersionPtr at: 0 put: version. + (self readableFormat: version) ifTrue: + [^version]. + + "try skipping the first 512 bytes with bytes reversed" + self sqImageFile: f Seek: 512. + version := self getWord32FromFile: f swap: true. + (self readableFormat: version) ifTrue: + [^version]]. + + ^0!
Item was changed: ----- Method: StackInterpreter>>imageFormatVersionFromSnapshot: (in category 'image save/restore') ----- imageFormatVersionFromSnapshot: imageVersion + "Snapshot image format can include additional state flags. + Currently that is the state of multipleBytecodeSetsActive. + Mask it out when checking compatibility with this interpreter." - "Snapshot image format includes the state of multipleBytecodeSetsActive, - mask it out when checking compatibility with this interpreter"
+ ^imageVersion bitClear: MultipleBytecodeSetsBitmask! - multipleBytecodeSetsActive := (imageVersion bitAnd: MultipleBytecodeSetsBitmask) ~= 0. - ^imageVersion bitAnd: ( -1 - MultipleBytecodeSetsBitmask) - !
Item was changed: ----- Method: StackInterpreter>>readImageFromFile:HeapSize:StartingAt: (in category 'image save/restore') ----- readImageFromFile: f HeapSize: desiredHeapSize StartingAt: imageOffset "Read an image from the given file stream, allocating an amount of memory to its object heap. V3: desiredHeapSize is the total size of the heap. Fail if the image has an unknown format or requires more than the specified amount of memory.
Spur: desiredHeapSize is ignored; this routine will attempt to provide at least extraVMMemory's ammount of free space after the image is loaded, taking any free space in teh image into account. extraVMMemory is stored in the image header and is accessible as vmParameterAt: 23. If extraVMMemory is 0, the value defaults to the default grow headroom. Fail if the image has an unknown format or if sufficient memory cannot be allocated.
Details: This method detects when the image was stored on a machine with the opposite byte ordering from this machine and swaps the bytes automatically. Furthermore, it allows the header information to start 512 bytes into the file, since some file transfer programs for the Macintosh apparently prepend a Mac-specific header of this size. Note that this same 512 bytes of prefix area could also be used to store an exec command on Unix systems, allowing one to launch Smalltalk by invoking the image name as a command."
+ | version rawVersion headerStart headerSize headerFlags dataSize swapBytes - | headerStart headerSize headerFlags dataSize swapBytes minimumMemory bytesRead bytesToShift heapSize firstSegSize hdrEdenBytes hdrMaxExtSemTabSize hdrNumStackPages allocationReserve | <var: 'f' type: #sqImageFile> <var: 'heapSize' type: #usqInt> <var: 'dataSize' type: #'size_t'> <var: 'minimumMemory' type: #usqInt> <var: 'desiredHeapSize' type: #usqInt> <var: 'allocationReserve' type: #usqInt> <var: 'headerStart' type: #squeakFileOffsetType> <var: 'imageOffset' type: #squeakFileOffsetType>
transcript := #stdout. "stdout is not available at compile time. this is the earliest available point." metaclassNumSlots := 6. "guess Metaclass instSize" classNameIndex := 6. "guess (Class instVarIndexFor: 'name' ifAbsent: []) - 1" + + version := self checkImageVersionFrom: f startingAt: imageOffset assignRawVersion: (self addressOf: rawVersion put: [:v| rawVersion := v]). + version = 0 ifTrue: + [self bailOutOfImageLoad: rawVersion]. + swapBytes := rawVersion ~= version. + multipleBytecodeSetsActive := version anyMask: MultipleBytecodeSetsBitmask. - swapBytes := self checkImageVersionFrom: f startingAt: imageOffset. headerStart := (self sqImageFilePosition: f) - 4. "record header start position"
headerSize := self getWord32FromFile: f swap: swapBytes. dataSize := self getLongFromFile: f swap: swapBytes. oldImageBaseAddress := self getLongFromFile: f swap: swapBytes. objectMemory specialObjectsOop: (self getLongFromFile: f swap: swapBytes). objectMemory lastHash: (self getLongFromFile: f swap: swapBytes). "N.B. not used by NewObjectMemory." savedWindowSize := self getLongFromFile: f swap: swapBytes. headerFlags := self getLongFromFile: f swap: swapBytes. self setImageHeaderFlagsFrom: headerFlags. extraVMMemory := self getWord32FromFile: f swap: swapBytes. hdrNumStackPages := self getShortFromFile: f swap: swapBytes. "4 stack pages is small. Should be able to run with as few as three. 4 should be comfortable but slow. 8 is a reasonable default. Can be changed via vmParameterAt: 43 put: n. Can be set as a preference (Info.plist, VM.ini, command line etc). If desiredNumStackPages is already non-zero then it has been set as a preference. Ignore (but preserve) the header's default." numStackPages := desiredNumStackPages ~= 0 ifTrue: [desiredNumStackPages] ifFalse: [hdrNumStackPages = 0 ifTrue: [self defaultNumStackPages] ifFalse: [hdrNumStackPages]]. desiredNumStackPages := hdrNumStackPages. "pad to word boundary. This slot can be used for anything else that will fit in 16 bits. It is used for the cog code size in Cog. Preserve it to be polite to other VMs." theUnknownShort := self getShortFromFile: f swap: swapBytes. hdrEdenBytes := self getWord32FromFile: f swap: swapBytes. objectMemory edenBytes: (desiredEdenBytes ~= 0 ifTrue: [desiredEdenBytes] ifFalse: [hdrEdenBytes = 0 ifTrue: [objectMemory defaultEdenBytes] ifFalse: [hdrEdenBytes]]). desiredEdenBytes := hdrEdenBytes. hdrMaxExtSemTabSize := self getShortFromFile: f swap: swapBytes. hdrMaxExtSemTabSize ~= 0 ifTrue: [self setMaxExtSemSizeTo: hdrMaxExtSemTabSize]. "pad to word boundary. This slot can be used for anything else that will fit in 16 bits. Preserve it to be polite to other VMs." the2ndUnknownShort := self getShortFromFile: f swap: swapBytes. firstSegSize := self getLongFromFile: f swap: swapBytes. objectMemory firstSegmentSize: firstSegSize. "compare memory requirements with availability" allocationReserve := self interpreterAllocationReserveBytes. minimumMemory := dataSize + objectMemory newSpaceBytes + allocationReserve. objectMemory hasSpurMemoryManagerAPI ifTrue: [| freeOldSpaceInImage headroom | freeOldSpaceInImage := self getLongFromFile: f swap: swapBytes. headroom := objectMemory initialHeadroom: extraVMMemory givenFreeOldSpaceInImage: freeOldSpaceInImage. heapSize := objectMemory roundUpHeapSize: dataSize + headroom + objectMemory newSpaceBytes + (headroom > allocationReserve ifTrue: [0] ifFalse: [allocationReserve])] ifFalse: [heapSize := desiredHeapSize + objectMemory newSpaceBytes + (desiredHeapSize - dataSize > allocationReserve ifTrue: [0] ifFalse: [allocationReserve]). heapSize < minimumMemory ifTrue: [self insufficientMemorySpecifiedError]].
"allocate a contiguous block of memory for the Squeak heap" (self allocateMemory: heapSize minimum: minimumMemory imageFile: f headerSize: headerSize) asUnsignedInteger ifNil: [self insufficientMemoryAvailableError] ifNotNil: [:mem| objectMemory setHeapBase: mem memoryLimit: mem + heapSize endOfMemory: mem + dataSize].
"position file after the header" self sqImageFile: f Seek: headerStart + headerSize.
"read in the image in bulk, then swap the bytes if necessary" bytesRead := objectMemory readHeapFromImageFile: f dataBytes: dataSize. bytesRead ~= dataSize ifTrue: [self unableToReadImageError].
self ensureImageFormatIsUpToDate: swapBytes.
"compute difference between old and new memory base addresses" bytesToShift := objectMemory memoryBaseForImageRead - oldImageBaseAddress. self initializeInterpreter: bytesToShift. "adjusts all oops to new location" ^dataSize!
Item was changed: ----- Method: StackInterpreterSimulator>>openOn:extraMemory: (in category 'initialize-release') ----- openOn: fileName extraMemory: extraBytes "StackInterpreterSimulator new openOn: 'clone.im' extraMemory: 100000"
| f version headerSize dataSize count bytesToShift swapBytes headerFlags heapBase firstSegSize heapSize hdrNumStackPages hdrEdenBytes hdrMaxExtSemTabSize allocationReserve | "open image file and read the header"
(f := self openImageFileNamed: fileName) ifNil: [^self].
"Set the image name and the first argument; there are no arguments during simulation unless set explicitly." systemAttributes at: 1 put: fileName.
["begin ensure block..." imageName := f fullName. f binary.
+ version := self getWord32FromFile: f swap: false. - version := self getWord32FromFile: f swap: false. "current version: 16r1968 (=6504) vive la revolucion!!" (self readableFormat: version) ifTrue: [swapBytes := false] ifFalse: [(version := version byteSwap32) = self imageFormatVersion ifTrue: [swapBytes := true] ifFalse: [self error: 'incomaptible image format']]. + multipleBytecodeSetsActive := version anyMask: MultipleBytecodeSetsBitmask. headerSize := self getWord32FromFile: f swap: swapBytes. dataSize := self getLongFromFile: f swap: swapBytes. "length of heap in file" oldImageBaseAddress := self getLongFromFile: f swap: swapBytes. "object memory base address of image" objectMemory specialObjectsOop: (self getLongFromFile: f swap: swapBytes). objectMemory lastHash: (self getLongFromFile: f swap: swapBytes). "Should be loaded from, and saved to the image header"
savedWindowSize := self getLongFromFile: f swap: swapBytes. headerFlags := self getLongFromFile: f swap: swapBytes. self setImageHeaderFlagsFrom: headerFlags. extraVMMemory := self getWord32FromFile: f swap: swapBytes. hdrNumStackPages := self getShortFromFile: f swap: swapBytes. "4 stack pages is small. Should be able to run with as few as three. 4 should be comfortable but slow. 8 is a reasonable default. Can be changed via vmParameterAt: 43 put: n" numStackPages := desiredNumStackPages ~= 0 ifTrue: [desiredNumStackPages] ifFalse: [hdrNumStackPages = 0 ifTrue: [self defaultNumStackPages] ifFalse: [hdrNumStackPages]]. desiredNumStackPages := hdrNumStackPages. "pad to word boundary. This slot can be used for anything else that will fit in 16 bits. It is used for the cog code size in Cog. Preserve it to be polite to other VMs." theUnknownShort := self getShortFromFile: f swap: swapBytes. self assert: f position = (objectMemory wordSize = 4 ifTrue: [40] ifFalse: [64]). hdrEdenBytes := self getWord32FromFile: f swap: swapBytes. objectMemory edenBytes: (hdrEdenBytes = 0 ifTrue: [objectMemory defaultEdenBytes] ifFalse: [hdrEdenBytes]). desiredEdenBytes := hdrEdenBytes. hdrMaxExtSemTabSize := self getShortFromFile: f swap: swapBytes. hdrMaxExtSemTabSize ~= 0 ifTrue: [self setMaxExtSemSizeTo: hdrMaxExtSemTabSize]. "pad to word boundary. This slot can be used for anything else that will fit in 16 bits. Preserve it to be polite to other VMs." the2ndUnknownShort := self getShortFromFile: f swap: swapBytes. self assert: f position = (objectMemory wordSize = 4 ifTrue: [48] ifFalse: [72]). firstSegSize := self getLongFromFile: f swap: swapBytes. objectMemory firstSegmentSize: firstSegSize. "compare memory requirements with availability" allocationReserve := self interpreterAllocationReserveBytes. objectMemory hasSpurMemoryManagerAPI ifTrue: [| freeOldSpaceInImage headroom | freeOldSpaceInImage := self getLongFromFile: f swap: swapBytes. headroom := objectMemory initialHeadroom: extraVMMemory givenFreeOldSpaceInImage: freeOldSpaceInImage. heapSize := objectMemory roundUpHeapSize: dataSize + headroom + objectMemory newSpaceBytes + (headroom > allocationReserve ifTrue: [0] ifFalse: [allocationReserve])] ifFalse: [heapSize := dataSize + extraBytes + objectMemory newSpaceBytes + (extraBytes > allocationReserve ifTrue: [0] ifFalse: [allocationReserve])]. "allocate interpreter memory" heapBase := objectMemory setHeapBase: objectMemory startOfMemory memoryLimit: objectMemory startOfMemory + heapSize endOfMemory: objectMemory startOfMemory + dataSize. "bogus for Spur" objectMemory allocateMemoryOfSize: objectMemory memoryLimit. "read in the image in bulk, then swap the bytes if necessary" f position: headerSize. count := objectMemory readHeapFromImageFile: f dataBytes: dataSize. count ~= dataSize ifTrue: [self halt]] ensure: [f close].
self ensureImageFormatIsUpToDate: swapBytes.
bytesToShift := objectMemory memoryBaseForImageRead - oldImageBaseAddress. "adjust pointers for zero base address" UIManager default informUser: 'Relocating object pointers...' during: [self initializeInterpreter: bytesToShift]!
vm-dev@lists.squeakfoundation.org