Eliot Miranda uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog-eem.3353.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.3353 Author: eem Time: 21 March 2024, 2:01:43.293285 pm UUID: 860ea747-484d-4072-8047-3b45e4687175 Ancestors: VMMaker.oscog-dtl.3352
VMMaker side of embedded images. Provide a function checkImageHeaderFromBytes:AndSize: that can be used by the platform to identify likely embedded image candidates.
Answer vmParameterAt: 50 with two boolean flags (encoded in an integer) of whether the image loaded with swizzling or not, and whether the image is embedded or not.
=============== Diff against VMMaker.oscog-dtl.3352 ===============
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>
| swapBytes headerStart headerSize headerFlags dataSize bytesRead bytesToShift heapSize + minimumMemory allocationReserve cogCodeBase firstSegSize - oldBaseAddr 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" 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. - headerSize := self getWord32FromFile: f swap: swapBytes. - dataSize := self getLongFromFile: f swap: swapBytes. - oldBaseAddr := 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. - objectMemory lastHash: (self getLongFromFile: f swap: swapBytes). "N.B. not used." - 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. - 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. - bytesToShift := objectMemory memoryBaseForImageRead - oldBaseAddr. 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 - | f version headerSize dataSize count oldBaseAddr 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. "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']]. 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" - oldBaseAddr := 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" - bytesToShift := objectMemory memoryBaseForImageRead - oldBaseAddr. "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: NewObjectMemory>>baseAddressOfImage (in category 'snapshot') ----- - baseAddressOfImage - "Answer the base address of the image data written to a sapshot." - ^self startOfMemory!
Item was added: + ----- Method: NewObjectMemory>>baseAddressOfImageSnapshot (in category 'snapshot') ----- + baseAddressOfImageSnapshot + "Answer the base address of the image data written to a sapshot." + ^self startOfMemory!
Item was removed: - ----- Method: SpurMemoryManager>>baseAddressOfImage (in category 'snapshot') ----- - baseAddressOfImage - ^oldSpaceStart!
Item was added: + ----- Method: SpurMemoryManager>>baseAddressOfImageSnapshot (in category 'snapshot') ----- + baseAddressOfImageSnapshot + ^oldSpaceStart!
Item was changed: InterpreterPrimitives subclass: #StackInterpreter (excessive size, no diff calculated)
Item was added: + ----- Method: StackInterpreter>>checkImageHeaderFromBytes:AndSize: (in category 'image save/restore') ----- + checkImageHeaderFromBytes: bytes AndSize: totalSize + "Support for embedded images. Check that the first few bytes of a potential header and answer if it + looks like something the VM can load, + The method checks the first three fields of the header (magic, header size & data size) & the total size. + The magic number should be correct. + The header size should be correct. + The size of the data should be at least as long as the headerSize plus the data size in the header" + + <var: 'bytes' type: #'char *'> + <public> + | version headerSize dataSize | + "Need at least headerSize bytes; no point going further if not..." + totalSize < (objectMemory wordSize * 16) ifTrue: + [^false]. + + version := self long32At: bytes. + headerSize := self longAt: bytes + 4. + dataSize := self longAt: bytes + 4 + objectMemory wordSize. + + (self readableFormat: version) ifFalse: + [(self readableFormat: version byteSwap32) ifFalse: + [^false]. + headerSize := objectMemory byteSwapped: headerSize. + dataSize := objectMemory byteSwapped: dataSize]. + + ^headerSize = objectMemory wordSize * 16 + and: [totalSize >= (headerSize + dataSize)]!
Item was added: + ----- Method: StackInterpreter>>imageLoadFlags (in category 'image save/restore') ----- + imageLoadFlags + "Answer the current image load flags (vm parameter 51). + Bit 0: image needed swizzling on load + Bit 1: image is embedded (e.g. as a resource) in this VM" + ^(oldImageBaseAddress ~= objectMemory baseAddressOfImageSnapshot + ifTrue: [1] + ifFalse: [0]) + + (self sqImageFileIsEmbedded + ifTrue: [2] + ifFalse: [0])!
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."
+ | headerStart headerSize headerFlags dataSize swapBytes - | headerStart headerSize headerFlags dataSize oldBaseAddr 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" 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. - headerSize := self getWord32FromFile: f swap: swapBytes. - dataSize := self getLongFromFile: f swap: swapBytes. - oldBaseAddr := 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. - objectMemory lastHash: (self getLongFromFile: f swap: swapBytes). "N.B. not used." - 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. - 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. - bytesToShift := objectMemory memoryBaseForImageRead - oldBaseAddr. self initializeInterpreter: bytesToShift. "adjusts all oops to new location" ^dataSize!
Item was added: + ----- Method: StackInterpreter>>sqImageFileIsEmbedded (in category 'simulation support') ----- + sqImageFileIsEmbedded + "Simulation place holder for something defined more meaningfully by the platform subsystem" + <doNotGenerate> + ^false!
Item was changed: ----- Method: StackInterpreter>>writeImageFileIO (in category 'image save/restore') ----- writeImageFileIO "Write the image header and heap contents to imageFile for snapshot. c.f. writeImageFileIOSimulation. The game below is to maintain 64-bit alignment for all putLong:toFile: occurrences." <inline: #never> | imageName headerStart headerSize f imageBytes bytesWritten sCWIfn okToWrite | <var: 'f' type: #sqImageFile> <var: 'headerStart' type: #squeakFileOffsetType> <var: 'sCWIfn' type: #'void *'> <var: 'imageName' declareC: 'extern char imageName[]'>
self cCode: [] inSmalltalk: [imageName := 'sooth compiler'. ^self writeImageFileIOSimulation].
"If the security plugin can be loaded, use it to check for write permission. If not, assume it's ok" sCWIfn := self ioLoadFunction: 'secCanWriteImage' From: 'SecurityPlugin'. sCWIfn ~= 0 ifTrue: [okToWrite := self cCode: '((sqInt (*)(void))sCWIfn)()'. okToWrite ifFalse:[^self primitiveFail]].
"local constants" headerStart := 0. headerSize := objectMemory wordSize * 16. "64 or 128; header size in bytes; do not change!!"
f := self sqImageFile: imageName Open: 'wb'. (self invalidSqImageFile: f) ifTrue: "could not open the image file for writing" [^self primitiveFailFor: PrimErrOperationFailed].
imageBytes := objectMemory imageSizeToWrite. headerStart := self sqImage: f File: imageName StartLocation: headerSize + imageBytes. self cCode: '/* Note: on Unix systems one could put an exec command here, padded to 512 bytes */'. "position file to start of header" self sqImageFile: f Seek: headerStart.
self putWord32: self imageFormatVersionForSnapshot toFile: f. self putWord32: headerSize toFile: f. self putLong: imageBytes toFile: f. + self putLong: objectMemory baseAddressOfImageSnapshot toFile: f. - self putLong: objectMemory baseAddressOfImage toFile: f. self putLong: objectMemory specialObjectsOop toFile: f. self putLong: objectMemory newObjectHash toFile: f. self putLong: self getSnapshotScreenSize toFile: f. self putLong: self getImageHeaderFlags toFile: f. self putWord32: extraVMMemory toFile: f. self putShort: desiredNumStackPages toFile: f. self putShort: self unknownShortOrCodeSizeInKs toFile: f. self putWord32: desiredEdenBytes toFile: f. self putShort: (maxExtSemTabSizeSet ifTrue: [self ioGetMaxExtSemTableSize] ifFalse: [0]) toFile: f. self putShort: the2ndUnknownShort toFile: f. objectMemory hasSpurMemoryManagerAPI ifTrue: [self putLong: objectMemory firstSegmentBytes toFile: f. self putLong: objectMemory bytesLeftInOldSpace toFile: f. 2 timesRepeat: [self putLong: 0 toFile: f] "Pad the rest of the header."] ifFalse: [4 timesRepeat: [self putLong: 0 toFile: f]]. "Pad the rest of the header."
objectMemory wordSize = 8 ifTrue: [3 timesRepeat: [self putLong: 0 toFile: f]]. "Pad the rest of the header."
self assert: headerStart + headerSize = (self sqImageFilePosition: f). "position file after the header" self sqImageFile: f Seek: headerStart + headerSize.
self successful ifFalse: "file write or seek failure" [self sqImageFileClose: f. ^nil].
"write the image data" objectMemory hasSpurMemoryManagerAPI ifTrue: [bytesWritten := objectMemory writeImageSegmentsToFile: f] ifFalse: + [bytesWritten := self sq: (self pointerForOop: objectMemory baseAddressOfImageSnapshot) - [bytesWritten := self sq: (self pointerForOop: objectMemory baseAddressOfImage) Image: (self sizeof: #char) File: imageBytes Write: f]. self success: bytesWritten = imageBytes. self sqImageFileClose: f!
Item was changed: ----- Method: StackInterpreter>>writeImageFileIOSimulation (in category 'image save/restore') ----- writeImageFileIOSimulation "Write the image header and heap contents to imageFile for snapshot. c.f. writeImageFileIO. The game below is to maintain 64-bit alignment for all putLong:toFile: occurrences." <doNotGenerate> | headerSize file | headerSize := objectMemory wordSize * 16.
(file := FileStream fileNamed: self imageName) ifNil: [self primitiveFail. ^nil]. [file binary. self putWord32: self imageFormatVersion toFile: file. self putWord32: headerSize toFile: file. { objectMemory imageSizeToWrite. + objectMemory baseAddressOfImageSnapshot. - objectMemory baseAddressOfImage. objectMemory specialObjectsOop. objectMemory lastHash. self ioScreenSize. self getImageHeaderFlags } do: [:long | self putLong: long toFile: file].
self putWord32: (extraVMMemory ifNil: [0]) toFile: file. { desiredNumStackPages. self unknownShortOrCodeSizeInKs } do: [:short| self putShort: short toFile: file].
self putWord32: desiredEdenBytes toFile: file.
{ maxExtSemTabSizeSet ifTrue: [self ioGetMaxExtSemTableSize] ifFalse: [0]. 0 } do: [:short| self putShort: short toFile: file].
objectMemory hasSpurMemoryManagerAPI ifTrue: [| bytesWritten | self putLong: objectMemory firstSegmentBytes toFile: file. self putLong: objectMemory bytesLeftInOldSpace toFile: file. 2 timesRepeat: [self putLong: 0 toFile: file] "Pad the rest of the header.". objectMemory wordSize = 8 ifTrue: [3 timesRepeat: [self putLong: 0 toFile: file]].
self assert: file position = headerSize.
bytesWritten := objectMemory writeImageSegmentsToFile: file. self assert: bytesWritten = objectMemory imageSizeToWrite] ifFalse: ["Pad the rest of the header." 4 timesRepeat: [self putLong: 0 toFile: file]. objectMemory wordSize = 8 ifTrue: [3 timesRepeat: [self putLong: 0 toFile: file]].
self assert: file position = headerSize.
"Write the object memory." file next: objectMemory imageSizeToWrite // objectMemory memory bytesPerElement putAll: objectMemory memory + startingAt: objectMemory baseAddressOfImageSnapshot - objectMemory memoryOffset // objectMemory memory bytesPerElement]. - startingAt: objectMemory baseAddressOfImage - objectMemory memoryOffset // objectMemory memory bytesPerElement]. file truncate: file position. self success: true] ensure: [file ifNotNil: [file close]]!
Item was changed: ----- Method: StackInterpreterPrimitives>>primitiveAllVMParameters: (in category 'system control primitives') ----- (excessive size, no diff calculated)
Item was changed: ----- Method: StackInterpreterPrimitives>>primitiveGetVMParameter: (in category 'system control primitives') ----- primitiveGetVMParameter: arg "See primitiveVMParameter method comment. N.B. written as a returning case to avoid branch limits in the V3 bytecode set." arg caseOf: { [1] -> [^self positiveMachineIntegerFor: objectMemory oldSpaceSize]. [2] -> [^objectMemory integerObjectOf: objectMemory newSpaceSize]. [3] -> [^self positiveMachineIntegerFor: objectMemory totalMemorySize]. [6] -> [^objectMemory integerObjectOf: objectMemory tenuringThreshold]. [7] -> [^objectMemory integerObjectOf: objectMemory statFullGCs]. [8] -> [^objectMemory integerObjectOf: objectMemory statFullGCUsecs + 500 // 1000]. [9] -> [^objectMemory integerObjectOf: (objectMemory hasSpurMemoryManagerAPI ifTrue: [objectMemory statScavenges] ifFalse: [objectMemory statIncrGCs])]. [10] -> [^objectMemory integerObjectOf: (objectMemory hasSpurMemoryManagerAPI ifTrue: [objectMemory statScavengeGCUsecs] ifFalse: [objectMemory statIncrGCUsecs]) + 500 // 1000]. [11] -> [^objectMemory integerObjectOf: objectMemory statTenures]. [12] -> [^objectMemory integerObjectOf: eventTraceMask]. [13] -> [^self getVMTickerStartUSecs]. [14] -> [^self getVMTickerCount]. [15] -> [^self getVMTickeeCallCount]. [16] -> [^self positive64BitIntegerFor: statIdleUsecs]. [17] -> [^(SistaVM and: [self isCog]) ifTrue: [objectMemory floatObjectOf: self getCogCodeZoneThreshold] ifFalse: [ConstZero]]. [18] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue: [objectMemory integerObjectOf: objectMemory statCompactionUsecs + 500 // 1000] ifFalse: [ConstZero]]. [19] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue: [objectMemory integerObjectOf: objectMemory scavengeThresholdAsExtent] ifFalse: [ConstZero]]. [20] -> [^objectMemory positive64BitIntegerFor: self ioUTCStartMicroseconds]. [21] -> [^objectMemory integerObjectOf: objectMemory rootTableCount]. [22] -> [^objectMemory integerObjectOf: objectMemory statRootTableOverflows]. [23] -> [^objectMemory integerObjectOf: extraVMMemory]. [24] -> [^objectMemory integerObjectOf: objectMemory shrinkThreshold]. [25] -> [^objectMemory integerObjectOf: objectMemory growHeadroom]. [26] -> [^objectMemory integerObjectOf: self ioHeartbeatMilliseconds]. [27] -> [^objectMemory integerObjectOf: objectMemory statMarkCount]. [28] -> [^objectMemory integerObjectOf: objectMemory statSweepCount]. [29] -> [^objectMemory integerObjectOf: objectMemory statMkFwdCount]. [30] -> [^objectMemory integerObjectOf: objectMemory statCompMoveCount]. [31] -> [^objectMemory integerObjectOf: objectMemory statGrowMemory]. [32] -> [^objectMemory integerObjectOf: objectMemory statShrinkMemory]. [33] -> [^objectMemory integerObjectOf: objectMemory statRootTableCount]. [34] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue:"was statAllocationCount" [objectMemory positive64BitIntegerFor: objectMemory currentAllocatedBytes]]. [35] -> [^objectMemory integerObjectOf: objectMemory statSurvivorCount]. [36] -> [^objectMemory integerObjectOf: (self microsecondsToMilliseconds: objectMemory statGCEndUsecs)]. [37] -> [^objectMemory integerObjectOf: objectMemory statSpecialMarkCount]. [38] -> [^objectMemory integerObjectOf: objectMemory statIGCDeltaUsecs + 500 // 1000]. [39] -> [^objectMemory integerObjectOf: statPendingFinalizationSignals]. [40] -> [^objectMemory integerObjectOf: objectMemory wordSize]. [41] -> [^objectMemory integerObjectOf: self imageFormatVersion]. [42] -> [^objectMemory integerObjectOf: numStackPages]. [43] -> [^objectMemory integerObjectOf: desiredNumStackPages]. [44] -> [^objectMemory integerObjectOf: objectMemory edenBytes]. [45] -> [^objectMemory integerObjectOf: desiredEdenBytes]. [46] -> [^self getCogCodeSize]. [47] -> [^self getDesiredCogCodeSize]. [48] -> [^self getImageHeaderFlagsParameter]. [49] -> [^objectMemory integerObjectOf: self ioGetMaxExtSemTableSize]. [50] -> [^self getMaxLiteralCountForCompile]. + [51] -> [^objectMemory integerObjectOf: self imageLoadFlags]. [52] -> [^objectMemory integerObjectOf: objectMemory rootTableCapacity]. [53] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue: [objectMemory integerObjectOf: objectMemory numSegments]]. [54] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue: [objectMemory integerObjectOf: objectMemory freeSize]]. [55] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue: [objectMemory floatObjectOf: objectMemory getHeapGrowthToSizeGCRatio]]. [56] -> [^self positive64BitIntegerFor: statProcessSwitch]. [57] -> [^self positive64BitIntegerFor: statIOProcessEvents]. [58] -> [^self positive64BitIntegerFor: statForceInterruptCheck]. [59] -> [^self positive64BitIntegerFor: statCheckForEvents]. [60] -> [^self positive64BitIntegerFor: statStackOverflow]. [61] -> [^self positive64BitIntegerFor: statStackPageDivorce]. [62] -> [^self getCodeCompactionCount]. [63] -> [^self getCodeCompactionMSecs]. [64] -> [^self getCogMethodCount]. [65] -> [^self getCogVMFeatureFlags]. [66] -> [^objectMemory integerObjectOf: stackPages bytesPerPage]. [67] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue: [self positiveMachineIntegerFor: objectMemory maxOldSpaceSize]]. [68] -> [^objectMemory floatObjectOf: stackPages statAverageLivePagesWhenMapping]. [69] -> [^objectMemory integerObjectOf: stackPages statMaxPageCountWhenMapping]. [70] -> [^objectMemory integerObjectOf: self vmProxyMajorVersion]. [71] -> [^objectMemory integerObjectOf: self vmProxyMinorVersion]. [72] -> [^objectMemory integerObjectOf: objectMemory statMarkUsecs + 500 // 1000]. [73] -> [^objectMemory integerObjectOf: objectMemory statSweepUsecs + 500 // 1000]. [74] -> [^objectMemory hasSpurMemoryManagerAPI ifTrue: [objectMemory integerObjectOf: objectMemory statMaxAllocSegmentTime + 500 // 1000]]. [75] -> [^objectMemory booleanObjectOf: self primitiveDoMixedArithmetic]. [76] -> [^objectMemory integerObjectOf: self minimumUnusedHeadroom] } otherwise: [^nil]!
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 - | f version headerSize dataSize count oldBaseAddr 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. "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']]. 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" - oldBaseAddr := 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" - bytesToShift := objectMemory memoryBaseForImageRead - oldBaseAddr. "adjust pointers for zero base address" UIManager default informUser: 'Relocating object pointers...' during: [self initializeInterpreter: bytesToShift]!
vm-dev@lists.squeakfoundation.org