Eliot Miranda uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog-eem.163.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.163 Author: eem Time: 21 June 2012, 1:41:16.462 pm UUID: 886d6e40-a3f6-4483-bdfc-f71a846f0737 Ancestors: VMMaker.oscog-eem.162
Fix warning due to wakeHighestPriority changes. Add abstractions for setting frame context and frame has context flag. Set all unused StackInterpreter frame offsets to #undefined in CoInterpreter. Fix asking to close the VM window twice. Ask before nuking the transcript.
=============== Diff against VMMaker.oscog-eem.162 ===============
Item was changed: ----- Method: CoInterpreter class>>initializeFrameIndices (in category 'initialization') ----- initializeFrameIndices "Format of a stack frame. Word-sized indices relative to the frame pointer. Terminology Frames are either single (have no context) or married (have a context). Contexts are either single (exist on the heap), married (have a context) or widowed (had a frame that has exited). Stacks grow down:
receiver for method activations/closure for block activations arg0 ... argN caller's saved ip/this stackPage (for a base frame) fp-> saved fp method context (initialized to nil) frame flags (interpreter only) saved method ip (initialized to 0; interpreter only) receiver first temp ... sp-> Nth temp
In an interpreter frame frame flags holds the number of arguments (since argument temporaries are above the frame) the flag for a block activation and the flag indicating if the context field is valid (whether the frame is married). saved method ip holds the saved method ip when the callee frame is a machine code frame. This is because the saved method ip is actually the ceReturnToInterpreterTrampoline address. In a machine code frame the flag indicating if the context is valid is the least significant bit of the method pointer the flag for a block activation is the next most significant bit of the method pointer
Interpreter frames are distinguished from method frames by the method field which will be a pointer into the heap for an interpreter frame and a pointer into the method zone for a machine code frame.
The first frame in a stack page is the baseFrame and is marked as such by a saved fp being its stackPage, in which case the first word on the stack is the caller context (possibly hybrid) beneath the base frame."
| fxCallerSavedIP fxSavedFP fxMethod fxIFrameFlags fxThisContext fxIFReceiver fxMFReceiver fxIFSavedIP | fxCallerSavedIP := 1. fxSavedFP := 0. fxMethod := -1. fxThisContext := -2. fxIFrameFlags := -3. "Can find numArgs, needed for fast temp access. args are above fxCallerSavedIP. Can find ``is block'' bit Can find ``has context'' bit" fxIFSavedIP := -4. fxIFReceiver := -5. fxMFReceiver := -3.
"For debugging nil out values that differ in the StackInterpreter." + FrameSlots := #undeclared asSymbol. - FrameSlots := nil. IFrameSlots := fxCallerSavedIP - fxIFReceiver + 1. MFrameSlots := fxCallerSavedIP - fxMFReceiver + 1.
FoxCallerSavedIP := fxCallerSavedIP * BytesPerWord. "In Cog a base frame's caller context is stored on the first word of the stack page." + FoxCallerContext := #undeclared asSymbol. - FoxCallerContext := nil. FoxSavedFP := fxSavedFP * BytesPerWord. FoxMethod := fxMethod * BytesPerWord. FoxThisContext := fxThisContext * BytesPerWord. + FoxFrameFlags := #undeclared asSymbol. - FoxFrameFlags := nil. FoxIFrameFlags := fxIFrameFlags * BytesPerWord. FoxIFSavedIP := fxIFSavedIP * BytesPerWord. FoxReceiver := #undeclared asSymbol. FoxIFReceiver := fxIFReceiver * BytesPerWord. FoxMFReceiver := fxMFReceiver * BytesPerWord.
"N.B. There is room for one more flag given the current 8 byte alignment of methods (which is at least needed to distinguish the checked and uncecked entry points by their alignment." MFMethodFlagHasContextFlag := 1. MFMethodFlagIsBlockFlag := 2. MFMethodFlagsMask := MFMethodFlagHasContextFlag + MFMethodFlagIsBlockFlag. MFMethodMask := (MFMethodFlagsMask + 1) negated!
Item was changed: ----- Method: CoInterpreter>>marryFrame:SP: (in category 'frame access') ----- marryFrame: theFP SP: theSP "Marry an unmarried frame. This means creating a spouse context initialized with a subset of the frame's state (state through the last argument) that references the frame. This is important enough for performance to be worth streamlining.
Override to set the ``has context'' flag appropriately for both machine code and interpreter frames and to streamline the machine code/interpreter differences.." | theContext methodFieldOrObj closureOrNil rcvr byteSize numArgs numStack | <inline: false> <var: #theFP type: #'char *'> <var: #theSP type: #'char *'> <var: #cogMethod type: #'CogMethod *'> self assert: (self frameHasContext: theFP) not. self assert: (self isBaseFrame: theFP) not. "base frames must aready be married for cannotReturn: processing"
"Decide how much of the stack to preserve in widowed contexts. Preserving too much state will potentially hold onto garbage. Holding onto too little may mean that a dead context isn't informative enough in a debugging situation. We compromise, retaining only the arguments with no temporaries. Note that we still set the stack pointer to its current value, but stack contents other than the arguments are nil." methodFieldOrObj := self frameMethodField: theFP. methodFieldOrObj asUnsignedInteger < objectMemory startOfMemory "inline (self isMachineCodeFrame: theFP)" ifTrue: [| cogMethod | stackPages longAt: theFP + FoxMethod put: methodFieldOrObj + MFMethodFlagHasContextFlag. cogMethod := self cCoerceSimple: (methodFieldOrObj bitAnd: MFMethodMask) to: #'CogMethod *'. numArgs := cogMethod cmNumArgs. cogMethod cmType = CMMethod ifTrue: [closureOrNil := objectMemory nilObject] ifFalse: [cogMethod := (self cCoerceSimple: cogMethod to: #'CogBlockMethod *') cmHomeMethod. closureOrNil := self frameStackedReceiver: theFP numArgs: numArgs]. byteSize := (cogMethod methodHeader bitAnd: LargeContextBit) ~= 0 ifTrue: [LargeContextSize] ifFalse: [SmallContextSize]. methodFieldOrObj := cogMethod methodObject. rcvr := self mframeReceiver: theFP. numStack := self stackPointerIndexForMFrame: theFP WithSP: theSP numArgs: numArgs] ifFalse: + [self setIFrameHasContext: theFP. - [stackPages byteAt: theFP + FoxIFrameFlags + 2 put: 1. numArgs := self iframeNumArgs: theFP. byteSize := ((self headerOf: methodFieldOrObj) bitAnd: LargeContextBit) ~= 0 ifTrue: [LargeContextSize] ifFalse: [SmallContextSize]. closureOrNil := (self iframeIsBlockActivation: theFP) ifTrue: [self frameStackedReceiver: theFP numArgs: numArgs] ifFalse: [objectMemory nilObject]. rcvr := self iframeReceiver: theFP. numStack := self stackPointerIndexForIFrame: theFP WithSP: theSP numArgs: numArgs]. theContext := objectMemory eeInstantiateMethodContextByteSize: byteSize. + self setFrameContext: theFP to: theContext. - stackPages longAt: theFP + FoxThisContext put: theContext. "Mark context as married by setting its sender to the frame pointer plus SmallInteger tags and the InstructionPointer to the saved fp (which ensures correct alignment w.r.t. the frame when we check for validity)" objectMemory storePointerUnchecked: SenderIndex ofObject: theContext withValue: (self withSmallIntegerTags: theFP). objectMemory storePointerUnchecked: InstructionPointerIndex ofObject: theContext withValue: (self withSmallIntegerTags: (self frameCallerFP: theFP)). objectMemory storePointerUnchecked: StackPointerIndex ofObject: theContext withValue: (objectMemory integerObjectOf: numStack). objectMemory storePointerUnchecked: MethodIndex ofObject: theContext withValue: methodFieldOrObj. objectMemory storePointerUnchecked: ClosureIndex ofObject: theContext withValue: closureOrNil. objectMemory storePointerUnchecked: ReceiverIndex ofObject: theContext withValue: rcvr. 1 to: numArgs do: [:i| objectMemory storePointerUnchecked: ReceiverIndex + i ofObject: theContext withValue: (self temporary: i - 1 in: theFP)]. numArgs + 1 to: numStack do: [:i| objectMemory storePointerUnchecked: ReceiverIndex + i ofObject: theContext withValue: objectMemory nilObject].
self assert: (self frameHasContext: theFP). self assert: (self frameOfMarriedContext: theContext) = theFP. self assert: numStack + ReceiverIndex < (objectMemory lengthOf: theContext).
^theContext!
Item was added: + ----- Method: CoInterpreter>>setIFrameHasContext: (in category 'frame access') ----- + setIFrameHasContext: theFP + "See encodeFrameFieldHasContext:numArgs:" + <inline: true> + <var: #theFP type: #'char *'> + stackPages byteAt: theFP + FoxIFrameFlags + 2 put: 1!
Item was changed: ----- Method: CogVMSimulator>>run (in category 'testing') ----- run "Just run" + quitBlock := [| topWindow | + + (displayView notNil + and: [topWindow := displayView outermostMorphThat: + [:m| m isSystemWindow and: [World submorphs includes: m]]. + topWindow notNil + and: [UIManager default confirm: 'close?']]) ifTrue: + [topWindow delete]. - quitBlock := [(displayView notNil - and: [UIManager default confirm: 'close?']) ifTrue: - [(displayView outermostMorphThat: [:m| m isSystemWindow]) ifNotNil: - [:topWindow| topWindow delete]]. ^self]. self initStackPages. self loadInitialContext. self initialEnterSmalltalkExecutive!
Item was changed: ----- Method: FilePluginSimulator>>sqFileStdioHandlesInto: (in category 'simulation') ----- sqFileStdioHandlesInto: anArray + (interpreterProxy transcript ~~ Transcript + or: [UIManager default confirm: 'clear transcript?']) ifTrue: + [interpreterProxy transcript clear]. - interpreterProxy transcript clear. "See FilePluginSimulator>>initialiseModule" anArray at: 1 put: 0; at: 2 put: 1; at: 3 put: 2. ^7!
Item was changed: ----- Method: StackInterpreter>>marryFrame:SP: (in category 'frame access') ----- marryFrame: theFP SP: theSP "Marry an unmarried frame. This means creating a spouse context initialized with a subset of the frame's state (state through the last argument) that references the frame." | theContext methodHeader byteSize numArgs numStack closureOrNil | <inline: false> <var: #theFP type: #'char *'> <var: #theSP type: #'char *'> self assert: (self frameHasContext: theFP) not.
methodHeader := self headerOf: (self frameMethod: theFP). "Decide how much of the stack to preserve in widowed contexts. Preserving too much state will potentially hold onto garbage. Holding onto too little may mean that a dead context isn't informative enough in a debugging situation. We compromise, retaining only the arguments with no temporaries. Note that we still set the stack pointer to its current value, but stack contents other than the arguments are nil." numArgs := self frameNumArgs: theFP. numStack := self stackPointerIndexForFrame: theFP WithSP: theSP.
closureOrNil := (self frameIsBlockActivation: theFP) ifTrue: [self pushedReceiverOrClosureOfFrame: theFP] ifFalse: [objectMemory nilObject].
byteSize := (methodHeader bitAnd: LargeContextBit) ~= 0 ifTrue: [LargeContextSize] ifFalse: [SmallContextSize]. theContext := objectMemory eeInstantiateMethodContextByteSize: byteSize. self assert: numStack + ReceiverIndex << ShiftForWord + BaseHeaderSize <= byteSize. "Mark context as married by setting its sender to the frame pointer plus SmallInteger tags and the InstructionPointer to the saved fp (which ensures correct alignment w.r.t. the frame when we check for validity)" objectMemory storePointerUnchecked: SenderIndex ofObject: theContext withValue: (self withSmallIntegerTags: theFP). objectMemory storePointerUnchecked: InstructionPointerIndex ofObject: theContext withValue: (self withSmallIntegerTags: (self frameCallerFP: theFP)). objectMemory storePointerUnchecked: StackPointerIndex ofObject: theContext withValue: (objectMemory integerObjectOf: numStack). objectMemory storePointerUnchecked: MethodIndex ofObject: theContext withValue: (self frameMethod: theFP). objectMemory storePointerUnchecked: ClosureIndex ofObject: theContext withValue: closureOrNil. objectMemory storePointerUnchecked: ReceiverIndex ofObject: theContext withValue: (self frameReceiver: theFP). "Store just the arguments. If the frame is divorced the context will have valid arguments but all temporaries will be nil." 1 to: numArgs do: [:i| objectMemory storePointerUnchecked: ReceiverIndex + i ofObject: theContext "inline self temporary: i - 1 in:theFP" withValue: (stackPages longAt: theFP + FoxCallerSavedIP + ((numArgs - i + 1) * BytesPerWord))]. numArgs + 1 to: numStack do: [:i| objectMemory storePointerUnchecked: ReceiverIndex + i ofObject: theContext withValue: objectMemory nilObject].
+ self setFrameContext: theFP to: theContext. + self setFrameHasContext: theFP. - stackPages longAt: theFP + FoxThisContext put: theContext. - stackPages byteAt: theFP + FoxFrameFlags + 2 put: 1.
self assert: (self frameHasContext: theFP). self assert: (self frameOfMarriedContext: theContext) = theFP. self assert: numStack + ReceiverIndex < (objectMemory lengthOf: theContext).
^theContext !
Item was added: + ----- Method: StackInterpreter>>setFrameContext:to: (in category 'frame access') ----- + setFrameContext: theFP to: aContext + <inline: true> + <var: #theFP type: #'char *'> + stackPages longAt: theFP + FoxThisContext put: aContext!
Item was added: + ----- Method: StackInterpreter>>setFrameHasContext: (in category 'frame access') ----- + setFrameHasContext: theFP + "See encodeFrameFieldHasContext:numArgs:" + <inline: true> + <var: #theFP type: #'char *'> + stackPages byteAt: theFP + FoxFrameFlags + 2 put: 1!
Item was changed: ----- Method: StackInterpreter>>wakeHighestPriority (in category 'process primitive support') ----- wakeHighestPriority "Return the highest priority process that is ready to run. To save time looking at many empty lists before finding a runnable process the VM maintains a variable holding the highest priority runnable process. If this variable is 0 then the VM does not know the highest priority and must search all lists. Note: It is a fatal VM error if there is no runnable process." | schedLists p processList proc ctxt | + self externalWriteBackHeadFramePointers. schedLists := objectMemory fetchPointer: ProcessListsIndex ofObject: self schedulerPointer. p := highestRunnableProcessPriority = 0 ifTrue: [objectMemory fetchWordLengthOf: schedLists] ifFalse: [highestRunnableProcessPriority]. [(p := p - 1) >= 0] whileTrue: [processList := objectMemory fetchPointer: p ofObject: schedLists. [self isEmptyList: processList] whileFalse: ["Only answer processes with a runnable suspendedContext. Discard those that aren't; the VM would crash otherwise." proc := self removeFirstLinkOfList: processList. ctxt := objectMemory fetchPointer: SuspendedContextIndex ofObject: proc. (self isLiveContext: ctxt) ifTrue: [highestRunnableProcessPriority := p + 1. ^proc]. self warning: 'evicted zombie process from run queue']]. self error: 'scheduler could not find a runnable process'. ^nil!
vm-dev@lists.squeakfoundation.org