Eliot Miranda uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog-eem.521.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.521 Author: eem Time: 25 November 2013, 4:43:55.229 pm UUID: 083a987f-b44f-4765-a2fb-48b2fe95d0f0 Ancestors: VMMaker.oscog-eem.520
Simplify the setHeapBase:memoryLimit:endOfMemory: logic in CoInterpreter>>readImageFromFile:HeapSize:StartingAt:.
Revers eth eill=considered decision to output wordSize as BytesPerWord in VMMaker.oscog-eem.363.
Fix a compilation warning in followForwardingPointersInStackZone:.
=============== Diff against VMMaker.oscog-eem.520 ===============
Item was changed: ----- Method: CCodeGenerator>>initializeCTranslationDictionary (in category 'C translation') ----- initializeCTranslationDictionary "Initialize the dictionary mapping message names to actions for C code generation."
| pairs | translationDict := Dictionary new: 200. pairs := #( #& #generateAnd:on:indent: #| #generateOr:on:indent: #and: #generateSequentialAnd:on:indent: #or: #generateSequentialOr:on:indent: #not #generateNot:on:indent:
#+ #generatePlus:on:indent: #- #generateMinus:on:indent: #negated #generateNegated:on:indent: #* #generateTimes:on:indent: #/ #generateDivide:on:indent: #// #generateDivide:on:indent: #\ #generateModulo:on:indent: #<< #generateShiftLeft:on:indent: #>> #generateShiftRight:on:indent: #min: #generateMin:on:indent: #max: #generateMax:on:indent: #between:and: #generateBetweenAnd:on:indent:
#bitAnd: #generateBitAnd:on:indent: #bitOr: #generateBitOr:on:indent: #bitXor: #generateBitXor:on:indent: #bitShift: #generateBitShift:on:indent: #signedBitShift: #generateSignedBitShift:on:indent: #bitInvert32 #generateBitInvert32:on:indent: #bitClear: #generateBitClear:on:indent: #truncateTo: #generateTruncateTo:on:indent: #rounded #generateRounded:on:indent:
#< #generateLessThan:on:indent: #<= #generateLessThanOrEqual:on:indent: #= #generateEqual:on:indent: #> #generateGreaterThan:on:indent: #>= #generateGreaterThanOrEqual:on:indent: #~= #generateNotEqual:on:indent: #== #generateEqual:on:indent: #~~ #generateNotEqual:on:indent: #isNil #generateIsNil:on:indent: #notNil #generateNotNil:on:indent:
#whileTrue: #generateWhileTrue:on:indent: #whileFalse: #generateWhileFalse:on:indent: #whileTrue #generateDoWhileTrue:on:indent: #whileFalse #generateDoWhileFalse:on:indent: #to:do: #generateToDo:on:indent: #to:by:do: #generateToByDo:on:indent: #repeat #generateRepeat:on:indent:
#ifTrue: #generateIfTrue:on:indent: #ifFalse: #generateIfFalse:on:indent: #ifTrue:ifFalse: #generateIfTrueIfFalse:on:indent: #ifFalse:ifTrue: #generateIfFalseIfTrue:on:indent:
#ifNotNil: #generateIfNotNil:on:indent: #ifNil: #generateIfNil:on:indent: #ifNotNil:ifNil: #generateIfNotNilIfNil:on:indent: #ifNil:ifNotNil: #generateIfNilIfNotNil:on:indent:
#at: #generateAt:on:indent: #at:put: #generateAtPut:on:indent: #basicAt: #generateAt:on:indent: #basicAt:put: #generateAtPut:on:indent:
#integerValueOf: #generateIntegerValueOf:on:indent: #integerObjectOf: #generateIntegerObjectOf:on:indent: #isIntegerObject: #generateIsIntegerObject:on:indent: #cCode: #generateInlineCCode:on:indent: #cCode:inSmalltalk: #generateInlineCCode:on:indent: #cPreprocessorDirective: #generateInlineCPreprocessorDirective:on:indent: #cppIf:ifTrue:ifFalse: #generateInlineCppIfElse:on:indent: #cppIf:ifTrue: #generateInlineCppIfElse:on:indent: #cCoerce:to: #generateCCoercion:on:indent: #cCoerceSimple:to: #generateCCoercion:on:indent: #addressOf: #generateAddressOf:on:indent: #addressOf:put: #generateAddressOf:on:indent: #signedIntFromLong #generateSignedIntFromLong:on:indent: #signedIntToLong #generateSignedIntToLong:on:indent: #signedIntFromShort #generateSignedIntFromShort:on:indent: #signedIntToShort #generateSignedIntToShort:on:indent: #preIncrement #generatePreIncrement:on:indent: #preDecrement #generatePreDecrement:on:indent: #inline: #generateInlineDirective:on:indent: #asFloat #generateAsFloat:on:indent: #asInteger #generateAsInteger:on:indent: #asUnsignedInteger #generateAsUnsignedInteger:on:indent: #asLong #generateAsLong:on:indent: #asUnsignedLong #generateAsUnsignedLong:on:indent: #asVoidPointer #generateAsVoidPointer:on:indent: #asSymbol #generateAsSymbol:on:indent: #flag: #generateFlag:on:indent: #anyMask: #generateBitAnd:on:indent: #noMask: #generateNoMask:on:indent: #raisedTo: #generateRaisedTo:on:indent: #touch: #generateTouch:on:indent:
#bytesPerWord #generateBytesPerWord:on:indent: - #wordSize #generateBytesPerWord:on:indent: #baseHeaderSize #generateBaseHeaderSize:on:indent: #sharedCodeNamed:inCase: #generateSharedCodeDirective:on:indent:
#perform: #generatePerform:on:indent: #perform:with: #generatePerform:on:indent: #perform:with:with: #generatePerform:on:indent: #perform:with:with:with: #generatePerform:on:indent: #perform:with:with:with:with: #generatePerform:on:indent: #perform:with:with:with:with:with: #generatePerform:on:indent:
#value #generateValue:on:indent: #value: #generateValue:on:indent: #value:value: #generateValue:on:indent:
#shouldNotImplement #generateSmalltalkMetaError:on:indent: #shouldBeImplemented #generateSmalltalkMetaError:on:indent: #subclassResponsibility #generateSmalltalkMetaError:on:indent: ).
1 to: pairs size by: 2 do: [:i | translationDict at: (pairs at: i) put: (pairs at: i + 1)].
pairs := #( #ifTrue: #generateIfTrueAsArgument:on:indent: #ifFalse: #generateIfFalseAsArgument:on:indent: #ifTrue:ifFalse: #generateIfTrueIfFalseAsArgument:on:indent: #ifFalse:ifTrue: #generateIfFalseIfTrueAsArgument:on:indent: #ifNotNil: #generateIfNotNilAsArgument:on:indent: #ifNil: #generateIfNilAsArgument:on:indent: #ifNotNil:ifNil: #generateIfNotNilIfNilAsArgument:on:indent: #ifNil:ifNotNil: #generateIfNilIfNotNilAsArgument:on:indent: #cCode: #generateInlineCCodeAsArgument:on:indent: #cCode:inSmalltalk: #generateInlineCCodeAsArgument:on:indent: #cppIf:ifTrue:ifFalse: #generateInlineCppIfElseAsArgument:on:indent: #cppIf:ifTrue: #generateInlineCppIfElseAsArgument:on:indent:
#value #generateValueAsArgument:on:indent: #value: #generateValueAsArgument:on:indent: #value:value: #generateValueAsArgument:on:indent: ).
asArgumentTranslationDict := Dictionary new: 8. 1 to: pairs size by: 2 do: [:i | asArgumentTranslationDict at: (pairs at: i) put: (pairs at: i + 1)]. !
Item was changed: ----- Method: CoInterpreter>>followForwardingPointersInStackZone: (in category 'object memory support') ----- followForwardingPointersInStackZone: theBecomeEffectsFlags "Spur's become: is lazy, turning the becommed object into a forwarding object to the other. + The read-barrier is minimised by arranging that forwarding pointers will fail a method cache + probe, since notionally objects' internals are accessed only via sending messages to them, + the exception is primitives that access the internals of the non-receiver argument(s). + To avoid a read barrier on bytecode, literal and inst var fetch we scan the receivers and + methods in the stack zone and follow any forwarded ones. This is of course way cheaper + than scanning all of memory as in the old become." - The read-barrier is minimised by arranging that forwarding pointers will fail a method cache probe, - since notionally objects' internals are accessed only via sending messages to them (the exception - is primitives that access the internals of the non-receiver argument(s). - To avoid a read barrier on bytecode, literal and inst var fetch we scan the receivers and methods - in the stack zone and follow any forwarded ones. This is of course way cheaper than scanning all - of memory as in the old become." | theIPPtr | <inline: false> <var: #thePage type: #'StackPage *'> <var: #theSP type: #'char *'> <var: #theFP type: #'char *'> <var: #callerFP type: #'char *'> <var: #theIPPtr type: #usqInt>
(theBecomeEffectsFlags anyMask: BecameCompiledMethodFlag) ifTrue: [(objectMemory isForwarded: method) ifTrue: [theIPPtr := instructionPointer - method. method := objectMemory followForwarded: method. instructionPointer := method + theIPPtr]. (objectMemory isForwarded: newMethod) ifTrue: [newMethod := objectMemory followForwarded: newMethod]].
self assert: stackPage ~= 0. 0 to: numStackPages - 1 do: [:i| | thePage theSP theFP callerFP oop offset | thePage := stackPages stackPageAt: i. thePage isFree ifFalse: [theSP := thePage headSP. theFP := thePage headFP. "Skip the instruction pointer on top of stack of inactive pages." thePage = stackPage ifTrue: [theIPPtr := 0] ifFalse: [theIPPtr := theSP asUnsignedInteger. theSP := theSP + BytesPerWord]. [self assert: (thePage addressIsInPage: theFP). self assert: (theIPPtr = 0 or: [thePage addressIsInPage: theIPPtr asVoidPointer]). + offset := self frameStackedReceiverOffset: theFP. + oop := stackPages longAt: theFP + offset. - offset := theFP + (self frameStackedReceiverOffset: theFP). - oop := stackPages longAt: offset. ((objectMemory isNonImmediate: oop) and: [(objectMemory isForwarded: oop)]) ifTrue: [stackPages + longAt: theFP + offset - longAt: offset put: (objectMemory followForwarded: oop)]. ((self frameHasContext: theFP) and: [(objectMemory isForwarded: (self frameContext: theFP))]) ifTrue: [stackPages longAt: theFP + FoxThisContext put: (objectMemory followForwarded: (self frameContext: theFP))]. (self isMachineCodeFrame: theFP) ifTrue: [oop := stackPages longAt: theFP + FoxIFReceiver. ((objectMemory isNonImmediate: oop) and: [(objectMemory isForwarded: oop)]) ifTrue: [stackPages longAt: theFP + FoxIFReceiver put: (objectMemory followForwarded: oop)]. self assert: (objectMemory isForwarded: (self frameMethodObject: theFP)) not] ifFalse: [oop := stackPages longAt: theFP + FoxIFReceiver. ((objectMemory isNonImmediate: oop) and: [(objectMemory isForwarded: oop)]) ifTrue: [stackPages longAt: theFP + FoxIFReceiver put: (objectMemory followForwarded: oop)]. oop := self frameMethod: theFP. (objectMemory isForwarded: oop) ifTrue: [| delta | delta := (objectMemory followForwarded: oop) - oop. (theIPPtr ~= 0 and: [(stackPages longAt: theIPPtr) > (self frameMethod: theFP)]) ifTrue: [stackPages longAt: theIPPtr put: (stackPages longAt: theIPPtr) + delta]. stackPages longAt: theFP + FoxIFSavedIP put: (stackPages longAt: theFP + FoxIFSavedIP) + delta. stackPages longAt: theFP + FoxMethod put: (objectMemory followForwarded: oop)]]. self followNecessaryForwardingInMethod: (self frameMethod: theFP). (callerFP := self frameCallerFP: theFP) ~= 0] whileTrue: [theIPPtr := (theFP + FoxCallerSavedIP) asUnsignedInteger. theFP := callerFP]]]!
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 the given amount of memory to its object heap. Fail if the image has an unknown format or requires more than the given amount of memory." "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." "This code is based on C code by Ian Piumarta and Smalltalk code by Tim Rowledge. Many thanks to both of you!!!!"
| swapBytes headerStart headerSize dataSize oldBaseAddr minimumMemory heapSize bytesRead bytesToShift firstSegSize hdrNumStackPages hdrEdenBytes hdrCogCodeSize headerFlags hdrMaxExtSemTabSize | <var: #f type: #sqImageFile> <var: #dataSize type: #'size_t'> <var: #desiredHeapSize type: #usqInt> <var: #headerStart type: #squeakFileOffsetType> <var: #imageOffset type: #squeakFileOffsetType>
metaclassNumSlots := 6. "guess Metaclass instSize" classNameIndex := 6. "guess (Class instVarIndexFor: 'name' ifAbsent: []) - 1" swapBytes := self checkImageVersionFrom: f startingAt: imageOffset. headerStart := (self sqImageFilePosition: f) - BytesPerWord. "record header start position"
headerSize := self getLongFromFile: 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." savedWindowSize := self getLongFromFile: f swap: swapBytes. headerFlags := self getLongFromFile: f swap: swapBytes. self setImageHeaderFlagsFrom: headerFlags. extraVMMemory := self getLongFromFile: f swap: swapBytes. "N.B. not used." 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: [self defaultCogCodeSize] ifFalse: [hdrCogCodeSize]]. hdrEdenBytes := self getLongFromFile: 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" minimumMemory := cogCodeSize "no need to include the stackZone; this is alloca'ed" + dataSize + objectMemory newSpaceBytes + self interpreterAllocationReserveBytes. heapSize := cogCodeSize "no need to include the stackZone; this is alloca'ed" + desiredHeapSize "+ edenBytes" "don't include edenBytes; this is part of the heap and so part of desiredHeapSize" + self interpreterAllocationReserveBytes. heapSize < minimumMemory ifTrue: [self insufficientMemorySpecifiedError].
"allocate a contiguous block of memory for the Squeak heap and ancilliary data structures" objectMemory memory: (self allocateMemory: heapSize minimum: minimumMemory imageFile: f headerSize: headerSize) asUnsignedInteger. objectMemory memory ifNil: [self insufficientMemoryAvailableError].
heapBase := objectMemory + setHeapBase: objectMemory memory + cogCodeSize - setHeapBase: objectMemory memory memoryLimit: objectMemory memory + heapSize endOfMemory: objectMemory memory + 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 - oldBaseAddr. self initializeInterpreter: bytesToShift. "adjusts all oops to new location" self initializeCodeGenerator. ^dataSize!
Item was removed: - ----- Method: Spur32BitCoMemoryManager>>setHeapBase:memoryLimit:endOfMemory: (in category 'snapshot') ----- - setHeapBase: baseOfHeap memoryLimit: memLimit endOfMemory: memEnd - "Set the dimensions of the heap, answering the start of oldSpace. - Override to position the cog code zone beneath the heap." - ^super setHeapBase: coInterpreter cogCodeSize memoryLimit: memLimit endOfMemory: memEnd!
Item was removed: - ----- Method: Spur32BitMMLECoSimulator>>setHeapBase:memoryLimit:endOfMemory: (in category 'initialization') ----- - setHeapBase: baseOfHeap memoryLimit: memLimit endOfMemory: memEnd - "Set the dimensions of the heap, answering the start of oldSpace. - Override to add a guard page beneath the code zone. We can't use - super; we need to skip over the super implementation." - ^self - perform: #setHeapBase:memoryLimit:endOfMemory: - withArguments: { baseOfHeap. - memLimit. - memEnd } - inSuperclass: Spur32BitMemoryManager!
Item was changed: ----- Method: SpurMemoryManager>>initializeOldSpaceFirstFree: (in category 'free space') ----- initializeOldSpaceFirstFree: startOfFreeOldSpace <var: 'startOfFreeOldSpace' type: #usqLong> | limit freeOldStart freeChunk | <var: 'limit' type: #usqLong> <var: 'freeOldStart' type: #usqLong> limit := endOfMemory - self bridgeSize. limit > startOfFreeOldSpace ifTrue: [totalFreeOldSpace := totalFreeOldSpace + (limit - startOfFreeOldSpace). freeOldStart := startOfFreeOldSpace. + self wordSize > 4 ifTrue: + [[limit - freeOldStart >= (1 << 32)] whileTrue: + [freeChunk := self freeChunkWithBytes: (1 << 32) at: freeOldStart. + freeOldStart := freeOldStart + (1 << 32). + self assert: freeOldStart = (self addressAfter: freeChunk)]]. - [limit - freeOldStart >= (2 raisedTo: 32)] whileTrue: - [freeChunk := self freeChunkWithBytes: (2 raisedTo: 32) at: freeOldStart. - freeOldStart := freeOldStart + (2 raisedTo: 32). - self assert: freeOldStart = (self addressAfter: freeChunk)]. freeOldStart < limit ifTrue: [freeChunk := self freeChunkWithBytes: limit - freeOldStart at: freeOldStart. self assert: (self addressAfter: freeChunk) = limit]]. freeOldSpaceStart := endOfMemory. self checkFreeSpace!
Item was changed: ----- Method: StackInterpreter>>followForwardingPointersInStackZone: (in category 'object memory support') ----- followForwardingPointersInStackZone: theBecomeEffectsFlags "Spur's become: is lazy, turning the becommed object into a forwarding object to the other. + The read-barrier is minimised by arranging that forwarding pointers will fail a method cache + probe, since notionally objects' internals are accessed only via sending messages to them, + the exception is primitives that access the internals of the non-receiver argument(s). + To avoid a read barrier on bytecode, literal and inst var fetch we scan the receivers and + methods in the stack zone and follow any forwarded ones. This is of course way cheaper + than scanning all of memory as in the old become." - The read-barrier is minimised by arranging that forwarding pointers will fail a method cache probe, - since notionally objects' internals are accessed only via sending messages to them (the exception - is primitives that access the internals of the non-receiver argument(s). - To avoid a read barrier on bytecode, literal and inst var fetch we scan the receivers and methods - in the stack zone and follow any forwarded ones. This is of course way cheaper than scanning all - of memory as in the old become." | theIPPtr | <inline: false> <var: #thePage type: #'StackPage *'> <var: #theSP type: #'char *'> <var: #theFP type: #'char *'> <var: #callerFP type: #'char *'> <var: #theIPPtr type: #usqInt>
(theBecomeEffectsFlags anyMask: BecameCompiledMethodFlag) ifTrue: [(objectMemory isForwarded: method) ifTrue: [theIPPtr := instructionPointer - method. method := objectMemory followForwarded: method. instructionPointer := method + theIPPtr]. (objectMemory isForwarded: newMethod) ifTrue: [newMethod := objectMemory followForwarded: newMethod]].
self assert: stackPage ~= 0. 0 to: numStackPages - 1 do: [:i| | thePage theSP theFP callerFP theIP oop | thePage := stackPages stackPageAt: i. thePage isFree ifFalse: [theSP := thePage headSP. theFP := thePage headFP. "Skip the instruction pointer on top of stack of inactive pages." thePage = stackPage ifTrue: [theIPPtr := 0] ifFalse: [theIPPtr := theSP asUnsignedInteger. theSP := theSP + BytesPerWord]. [self assert: (thePage addressIsInPage: theFP). self assert: (theIPPtr = 0 or: [thePage addressIsInPage: theIPPtr asVoidPointer]). oop := stackPages longAt: theFP + FoxReceiver. ((objectMemory isNonImmediate: oop) and: [(objectMemory isForwarded: oop)]) ifTrue: [stackPages longAt: theFP + FoxReceiver put: (objectMemory followForwarded: oop)]. theIP := (theFP + (self frameStackedReceiverOffset: theFP)) asUnsignedInteger. "reuse theIP; its just an offset here" oop := stackPages longAt: theIP. ((objectMemory isNonImmediate: oop) and: [(objectMemory isForwarded: oop)]) ifTrue: [stackPages longAt: theIP put: (objectMemory followForwarded: oop)]. ((self frameHasContext: theFP) and: [(objectMemory isForwarded: (self frameContext: theFP))]) ifTrue: [stackPages longAt: theFP + FoxThisContext put: (objectMemory followForwarded: (self frameContext: theFP))]. oop := self frameMethod: theFP. (objectMemory isForwarded: oop) ifTrue: [| delta | theIPPtr ~= 0 ifTrue: [self assert: (stackPages longAt: theIPPtr) > (self frameMethod: theFP). delta := (objectMemory followForwarded: oop) - oop. stackPages longAt: theIPPtr put: (stackPages longAt: theIPPtr) + delta]. stackPages longAt: theFP + FoxMethod put: (objectMemory followForwarded: oop)]. self followNecessaryForwardingInMethod: (self frameMethod: theFP). (callerFP := self frameCallerFP: theFP) ~= 0] whileTrue: [theIPPtr := (theFP + FoxCallerSavedIP) asUnsignedInteger. theFP := callerFP]]]!
vm-dev@lists.squeakfoundation.org