Eliot Miranda uploaded a new version of VMMaker to project VM Maker: http://source.squeak.org/VMMaker/VMMaker.oscog-eem.547.mcz ==================== Summary ==================== Name: VMMaker.oscog-eem.547 Author: eem Time: 7 December 2013, 1:39:54.394 pm UUID: 5a0db750-d6a5-4742-b20a-e35ecb43ab38 Ancestors: VMMaker.oscog-eem.546 Rename handleForwardedSendFaultFor: to handleForwardedSendFaultForTag:. Add handleForwardedSelectorFaultFor:. Implement forwarding fault handling in ceSend:super:to:numArgs: et al and rewrite the handling in ceSendFromInLineCacheMiss: to match. Abstract out the method following in handleForwardedSelectorFaultFor: and override in CoInterpreter to follow the cogMethod. Follow forwarded methdos in the method cache post-become. Rename genEnsureRegNotForwarded:scratchReg: to genEnsureObjInRegRegNotForwarded:scratchReg: and use to implement forwarder following in Cogit special selector #== (and rewritten lit var access). Comment forwarder following in genGetClassObjectOf:into:scratchReg:instRegIsReceiver: Fix Spur's couldBeObject: to filter-out 0 (for closed PICs). Fix printOopShortInner: to print forwarders (for frame printing). Print how much space is missing when the scavenger eden limit - freeStart > coInterpreter interpreterAllocationReserveBytes assert fails on scavenge. Slang and clients: Fix dead code elimination in if exprs when there expr is just a single boolean-constant-returning send. Refactor var:type:array: in terms of arrayInitializerCalled:for:type:. Fix decls of memory, heapBase & labelCounter so they're not hacked as static. Make cePositive32BitIntegerTrampoline & eFlushICache private. =============== Diff against VMMaker.oscog-eem.546 =============== Item was changed: ----- Method: CCodeGenerator>>emitCVariablesOn: (in category 'C code generator') ----- emitCVariablesOn: aStream "Store the global variable declarations on the given stream." aStream cr; nextPutAll: '/*** Variables ***/'; cr. (self sortStrings: variables) do: [:var | | varString decl | varString := var asString. decl := variableDeclarations at: varString ifAbsent: ['sqInt ' , varString]. decl first == $# "support cgen var: #bytecodeSetSelector declareC: '#define bytecodeSetSelector 0' hack" ifTrue: [aStream nextPutAll: decl; cr] ifFalse: [self isGeneratingPluginCode ifTrue: [varString = 'interpreterProxy' ifTrue: "quite special..." [self preDeclareInterpreterProxyOn: aStream] ifFalse: [(decl beginsWith: 'static') ifFalse: [aStream nextPutAll: 'static ']]] ifFalse: + [(vmClass mustBeGlobal: varString) + ifTrue: + [(decl beginsWith: 'static ') ifTrue: + [decl := decl allButFirst: 7]] + ifFalse: + [(decl beginsWith: 'static') ifFalse: + [aStream nextPutAll: 'static ']]]. - [(vmClass mustBeGlobal: varString) ifFalse: - [(decl beginsWith: 'static') ifFalse: - [aStream nextPutAll: 'static ']]]. aStream nextPutAll: decl; nextPut: $;; cr]]. aStream cr! Item was changed: ----- Method: CCodeGenerator>>emitGlobalCVariablesOn: (in category 'C code generator') ----- emitGlobalCVariablesOn: aStream "Store the global variable declarations on the given stream." aStream cr; nextPutAll: '/*** Global Variables ***/'; cr. (self sortStrings: (variables select: [:v| vmClass mustBeGlobal: v])) do: [:var | | varString decl | varString := var asString. decl := variableDeclarations at: varString ifAbsent: ['sqInt ' , varString]. decl first == $# "support cgen var: #bytecodeSetSelector declareC: '#define bytecodeSetSelector 0' hack" ifTrue: [aStream nextPutAll: decl; cr] ifFalse: [((decl includesSubString: ' private ') + "or: [decl beginsWith: 'static']") ifFalse: "work-around hack to prevent localization of variables only referenced once." - or: [decl beginsWith: 'static']) ifFalse: "work-around hack to prevent localization of variables only referenced once." [(decl includes: $=) ifTrue: [decl := decl copyFrom: 1 to: (decl indexOf: $=) - 1]. aStream nextPutAll: decl; nextPut: $;; cr]]]. aStream cr! Item was changed: ----- Method: CCodeGenerator>>nilOrBooleanConstantReceiverOf: (in category 'utilities') ----- nilOrBooleanConstantReceiverOf: aNode "Answer nil or the boolean constant that is the receiver of the given message send. Used to suppress conditional code when the condition is a translation-time constant." generateDeadCode ifTrue:[^nil]. (aNode isConstant and: [#(true false) includes: aNode value]) ifTrue: [^aNode value]. aNode isSend ifTrue: [((#(or: and:) includes: aNode selector) and: [aNode args last isStmtList and: [aNode args last statements size = 1]]) ifTrue: [(self nilOrBooleanConstantReceiverOf: aNode receiver) ifNotNil: [:rcvr| (self nilOrBooleanConstantReceiverOf: aNode args last statements first) ifNotNil: [:arg| ^rcvr perform: aNode selector with: [arg]]]]. ((#(= ~= < > <= >=) includes: aNode selector) and: [(aNode receiver isConstant and: [aNode receiver value isInteger]) and: [(aNode args first isConstant and: [aNode args first value isInteger])]]) ifTrue: + [^aNode receiver value perform: aNode selector with: aNode args first value]. + (self methodNamed: aNode selector) ifNotNil: + [:m| + (m statements size = 1 + and: [m statements last isReturn]) ifTrue: + [^self nilOrBooleanConstantReceiverOf: m statements last expression]]]. - [^aNode receiver value perform: aNode selector with: aNode args first value]]. ^nil ! Item was removed: - ----- Method: CCodeGenerator>>printArray:on: (in category 'private') ----- - printArray: array on: aStream - | first | - first := true. - 1 to: array size do: - [:i | - first - ifTrue: [first := false] - ifFalse: [aStream nextPutAll: ', ']. - i \\ 16 = 1 ifTrue: [aStream cr]. - self printInt: (array at: i) on: aStream]! Item was removed: - ----- Method: CCodeGenerator>>printInt:on: (in category 'private') ----- - printInt: int on: aStream - aStream print: int. - (int between: -2147483648 and: 2147483647) - ifFalse: [(int between: 2147483648 and: 4294967295) - ifTrue: [aStream nextPut: $U] - ifFalse: [aStream nextPut: $L]]! Item was changed: ----- Method: CCodeGenerator>>var:type:array: (in category 'public') ----- + var: varName type: cType array: array + "Use this in preference to #var:declareC: when possible. This produces a C + statment of the form + int * fooArray[]={1,2,3} + See also #var:type: for simple var decls" - var: varName type: type array: array - "use this in preference to #var:declareC: when possible. This produces a C statment of the form - int * fooArray[]={1,2,3} - See also #var:type: for simple var decls" self var: varName + declareC: (self arrayInitializerCalled: varName for: array type: cType)! - declareC: (String streamContents: [:s | - s nextPutAll: type. - s space. - s nextPutAll: varName. - s nextPutAll: '[] = {'. - self printArray: array on: s. - s nextPut: $}])! Item was changed: ----- Method: CoInterpreter class>>declareCVarsIn: (in category 'translation') ----- declareCVarsIn: aCCodeGenerator "Override to avoid repeating StackInterpreter's declarations and add our own extensions" | threaded | self class == thisContext methodClass ifFalse: [^self]. "Don't duplicate decls in subclasses" threaded := aCCodeGenerator vmClass isThreadedVM. aCCodeGenerator addHeaderFile:'"sqCogStackAlignment.h"'; addHeaderFile:'"cogmethod.h"'; addHeaderFile: (threaded ifTrue: ['"cointerpmt.h"'] ifFalse: ['"cointerp.h"']); addHeaderFile:'"cogit.h"'. self declareInterpreterVersionIn: aCCodeGenerator defaultName: (threaded ifTrue: ['Cog MT'] ifFalse: ['Cog']). aCCodeGenerator + var: #heapBase type: #usqInt; + var: #statCodeCompactionUsecs type: #usqLong; - var: #heapBase - declareC: 'static usqInt heapBase'; var: #maxLiteralCountForCompile + declareC: 'sqInt maxLiteralCountForCompile = MaxLiteralCountForCompile /* ', MaxLiteralCountForCompile printString, ' */'; - declareC: 'sqInt maxLiteralCountForCompile = MaxLiteralCountForCompile /* ', MaxLiteralCountForCompile printString, ' */'; var: #minBackwardJumpCountForCompile + declareC: 'sqInt minBackwardJumpCountForCompile = MinBackwardJumpCountForCompile /* ', MinBackwardJumpCountForCompile printString, ' */'. - declareC: 'sqInt minBackwardJumpCountForCompile = MinBackwardJumpCountForCompile /* ', MinBackwardJumpCountForCompile printString, ' */'. aCCodeGenerator var: #reenterInterpreter declareC: 'jmp_buf reenterInterpreter; /* private export */'. aCCodeGenerator - var: #statCodeCompactionUsecs - type: #usqLong. - aCCodeGenerator var: #primTraceLogIndex type: #'unsigned char'; var: #primTraceLog declareC: 'sqInt primTraceLog[256]'; var: #traceLog declareC: 'sqInt traceLog[TraceBufferSize /* ', TraceBufferSize printString, ' */]'; + var: #traceSources type: #'char *' array: TraceSources! - var: #traceSources - declareC: (aCCodeGenerator - arrayInitializerCalled: 'traceSources' - for: TraceSources - type: 'char *')! Item was changed: ----- Method: CoInterpreter>>ceDynamicSuperSend:to:numArgs: (in category 'trampolines') ----- ceDynamicSuperSend: selector to: rcvr numArgs: numArgs "Entry-point for an unlinked dynamic super send in a CogMethod. Smalltalk stack looks like receiver args head sp -> sender return pc If an MNU then defer to handleMNUInMachineCodeTo:... which will dispatch the MNU and may choose to allocate a closed PIC with a fast MNU dispatch for this send. Otherwise attempt to link the send site as efficiently as possible. All link attempts may fail; e.g. because we're out of code memory. Continue execution via either executeMethod or interpretMethodFromMachineCode: depending on whether the target method is cogged or not." <api> <option: #NewspeakVM> | class classTag canLinkCacheTag errSelIdx cogMethod mClassMixin mixinApplication | <inline: false> <var: #cogMethod type: #'CogMethod *'> <var: #newCogMethod type: #'CogMethod *'> "self printExternalHeadFrame" "self printStringOf: selector" cogit assertCStackWellAligned. self assert: (objectMemory addressCouldBeOop: rcvr). self sendBreakpoint: selector receiver: rcvr. mClassMixin := self mMethodClass. mixinApplication := self findApplicationOfTargetMixin: mClassMixin startingAtBehavior: (objectMemory fetchClassOf: rcvr). self assert: (objectMemory lengthOf: mixinApplication) > (InstanceSpecificationIndex + 1). classTag := self classTagForClass: (self superclassOf: mixinApplication). class := objectMemory fetchClassOf: rcvr. "what about the read barrier??" canLinkCacheTag := (objectMemory isYoungObject: class) not or: [cogit canLinkToYoungClasses]. argumentCount := numArgs. (self lookupInMethodCacheSel: selector classTag: classTag) ifTrue:"check for coggability because method is in the cache" [self ifAppropriateCompileToNativeCode: newMethod selector: selector] ifFalse: + [(objectMemory isOopForwarded: selector) ifTrue: + [^self + ceDynamicSuperSend: (self handleForwardedSelectorFaultFor: selector) + to: rcvr + numArgs: numArgs]. + (objectMemory isForwardedClassTag: classTag) ifTrue: + [^self + ceDynamicSuperSend: selector + to: (self handleForwardedSendFaultForReceiver: rcvr) + numArgs: numArgs]. + messageSelector := selector. - [messageSelector := selector. (errSelIdx := self lookupMethodNoMNUEtcInClass: (objectMemory classForClassTag: classTag)) ~= 0 ifTrue: [self handleMNU: errSelIdx InMachineCodeTo: rcvr classForMessage: (objectMemory classForClassTag: classTag). self assert: false "NOTREACHED"]]. "Method found and has a cog method. Attempt to link to it." (self maybeMethodHasCogMethod: newMethod) ifTrue: [cogMethod := self cogMethodOf: newMethod. cogMethod selector = objectMemory nilObject ifTrue: [cogit setSelectorOf: cogMethod to: selector] ifFalse: ["Deal with anonymous accessors, e.g. in Newspeak. The cogMethod may not have the correct selector. If not, try and compile a new method with the correct selector." cogMethod selector ~= selector ifTrue: [(cogit cog: newMethod selector: selector) ifNotNil: [:newCogMethod| cogMethod := newCogMethod]]]. (cogMethod selector = selector and: [canLinkCacheTag]) ifTrue: [cogit linkSendAt: (stackPages longAt: stackPointer) in: (self mframeHomeMethod: framePointer) to: cogMethod offset: cogit dynSuperEntryOffset receiver: rcvr]. instructionPointer := self popStack. self executeNewMethod. self assert: false "NOTREACHED"]. instructionPointer := self popStack. ^self interpretMethodFromMachineCode "NOTREACHED"! Item was changed: ----- Method: CoInterpreter>>ceInterpretMethodFromPIC:receiver: (in category 'trampolines') ----- ceInterpretMethodFromPIC: aMethodObj receiver: rcvr <api> | pic primitiveIndex | <var: #pic type: #'CogMethod *'> self assert: (self methodHasCogMethod: aMethodObj) not. "pop off inner return and locate open PIC" pic := self cCoerceSimple: self popStack - cogit interpretOffset to: #'CogMethod *'. self assert: (pic cmType = CMOpenPIC or: [pic cmType = CMClosedPIC]). + "If found from an open PIC then it must be an uncogged method and, since it's been found - "If found from an open PIC then it must be an uncoged method and, since it's been found in the method cache, should be cogged if possible. If found from a closed PIC it should be interpreted (since being reached by that route implies it is uncoggable)." pic cmType = CMOpenPIC ifTrue: [(self methodShouldBeCogged: aMethodObj) ifTrue: [cogit cog: aMethodObj selector: pic selector. (self methodHasCogMethod: aMethodObj) ifTrue: [self executeCogMethodFromUnlinkedSend: (self cogMethodOf: aMethodObj) withReceiver: rcvr]]] ifFalse: [self assert: (cogCompiledCodeCompactionCalledFor or: [(cogit methodShouldBeCogged: aMethodObj) not])]. messageSelector := pic selector. newMethod := aMethodObj. primitiveIndex := self primitiveIndexOf: aMethodObj. primitiveFunctionPointer := self functionPointerFor: primitiveIndex inClass: objectMemory nilObject. argumentCount := pic cmNumArgs. instructionPointer := self popStack. ^self interpretMethodFromMachineCode "NOTREACHED"! Item was changed: ----- Method: CoInterpreter>>ceSend:super:to:numArgs: (in category 'trampolines') ----- ceSend: selector super: superNormalBar to: rcvr numArgs: numArgs "Entry-point for an unlinked send in a CogMethod. Smalltalk stack looks like receiver args head sp -> sender return pc If an MNU then defer to handleMNUInMachineCodeTo:... which will dispatch the MNU and may choose to allocate a closed PIC with a fast MNU dispatch for this send. Otherwise attempt to link the send site as efficiently as possible. All link attempts may fail; e.g. because we're out of code memory. Continue execution via either executeMethod or interpretMethodFromMachineCode: depending on whether the target method is cogged or not." <api> | classTag canLinkCacheTag errSelIdx cogMethod | <inline: false> <var: #cogMethod type: #'CogMethod *'> <var: #newCogMethod type: #'CogMethod *'> "self printExternalHeadFrame" "self printStringOf: selector" cogit assertCStackWellAligned. self assert: (objectMemory addressCouldBeOop: rcvr). self sendBreakpoint: selector receiver: rcvr. superNormalBar = 0 ifTrue: [classTag := objectMemory fetchClassTagOf: rcvr] ifFalse: [classTag := objectMemory classTagForClass: (self superclassOf: (self methodClassOf: (self frameMethodObject: framePointer)))]. canLinkCacheTag := cogit canLinkToYoungClasses or: [(objectMemory isYoungObject: classTag) not]. argumentCount := numArgs. (self lookupInMethodCacheSel: selector classTag: classTag) ifTrue:"check for coggability because method is in the cache" [self ifAppropriateCompileToNativeCode: newMethod selector: selector] ifFalse: + [(objectMemory isOopForwarded: selector) ifTrue: + [^self + ceSend: (self handleForwardedSelectorFaultFor: selector) + super: superNormalBar + to: rcvr + numArgs: numArgs]. + (objectMemory isForwardedClassTag: classTag) ifTrue: + [self assert: superNormalBar = 0. + ^self + ceSend: selector + super: superNormalBar + to: (self handleForwardedSendFaultForReceiver: rcvr) + numArgs: numArgs]. + messageSelector := selector. - [messageSelector := selector. (errSelIdx := self lookupMethodNoMNUEtcInClass: (objectMemory classForClassTag: classTag)) ~= 0 ifTrue: [(canLinkCacheTag and: [errSelIdx = SelectorDoesNotUnderstand and: [(cogMethod := cogit cogMNUPICSelector: messageSelector methodOperand: (self mnuMethodOrNilFor: rcvr) numArgs: argumentCount) asUnsignedInteger > cogit minCogMethodAddress]]) ifTrue: [cogit linkSendAt: (stackPages longAt: stackPointer) in: (self mframeHomeMethod: framePointer) to: cogMethod offset: (superNormalBar = 0 ifTrue: [cogit entryOffset] ifFalse: [cogit noCheckEntryOffset]) receiver: rcvr]. self handleMNU: errSelIdx InMachineCodeTo: rcvr classForMessage: (objectMemory classForClassTag: classTag). self assert: false "NOTREACHED"]]. "Method found and has a cog method. Attempt to link to it. The receiver's class may be young. If the Cogit can't store young classes in inline caches we can link to an open PIC instead." (self maybeMethodHasCogMethod: newMethod) ifTrue: [cogMethod := self cogMethodOf: newMethod. cogMethod selector = objectMemory nilObject ifTrue: [cogit setSelectorOf: cogMethod to: selector] ifFalse: ["Deal with anonymous accessors, e.g. in Newspeak. The cogMethod may not have the correct selector. If not, try and compile a new method with the correct selector." cogMethod selector ~= selector ifTrue: [(cogit cog: newMethod selector: selector) ifNotNil: [:newCogMethod| cogMethod := newCogMethod]]]. (cogMethod selector = selector and: [canLinkCacheTag]) ifTrue: [cogit linkSendAt: (stackPages longAt: stackPointer) in: (self mframeHomeMethod: framePointer) to: cogMethod offset: (superNormalBar = 0 ifTrue: [cogit entryOffset] ifFalse: [cogit noCheckEntryOffset]) receiver: rcvr] ifFalse: "If patchToOpenPICFor:.. returns we're out of code memory" [cogit patchToOpenPICFor: selector numArgs: numArgs receiver: rcvr]. instructionPointer := self popStack. self executeNewMethod. self assert: false "NOTREACHED"]. instructionPointer := self popStack. ^self interpretMethodFromMachineCode "NOTREACHED"! Item was changed: ----- Method: CoInterpreter>>ceSendFromInLineCacheMiss: (in category 'trampolines') ----- ceSendFromInLineCacheMiss: cogMethodOrPIC "Send from an Open PIC when the first-level method lookup probe has failed, or to continue when PIC creation has failed (e.g. because we're out of code space), or when a send has failed due to a forwarded receiver." <api> <var: #cogMethodOrPIC type: #'CogMethod *'> | numArgs rcvr classTag errSelIdx | "self printFrame: stackPage headFP WithSP: stackPage headSP" "self printStringOf: selector" numArgs := cogMethodOrPIC cmNumArgs. rcvr := self stackValue: numArgs + 1. "skip return pc" self assert: (objectMemory addressCouldBeOop: rcvr). classTag := objectMemory fetchClassTagOf: rcvr. argumentCount := numArgs. (self lookupInMethodCacheSel: cogMethodOrPIC selector classTag: classTag) ifTrue:"check for coggability because method is in the cache" [self ifAppropriateCompileToNativeCode: newMethod selector: cogMethodOrPIC selector] ifFalse: + [(objectMemory isOopForwarded: cogMethodOrPIC selector) ifTrue: + [self handleForwardedSelectorFaultFor: cogMethodOrPIC selector. + ^self ceSendFromInLineCacheMiss: cogMethodOrPIC]. + (objectMemory isForwardedClassTag: classTag) ifTrue: + [self handleForwardedSendFaultForReceiver: rcvr. + ^self ceSendFromInLineCacheMiss: cogMethodOrPIC]. + messageSelector := cogMethodOrPIC selector. - [messageSelector := cogMethodOrPIC selector. - ((objectMemory isOopForwarded: messageSelector) - or: [objectMemory isForwardedClassTag: classTag]) ifTrue: - [(objectMemory isOopForwarded: messageSelector) ifTrue: - [messageSelector := self handleForwardedSelectorFaultFor: messageSelector]. - (objectMemory isForwardedClassTag: classTag) ifTrue: - [classTag := self handleForwardedSendFaultFor: classTag]]. (errSelIdx := self lookupMethodNoMNUEtcInClass: (objectMemory classForClassTag: classTag)) ~= 0 ifTrue: [self handleMNU: errSelIdx InMachineCodeTo: rcvr classForMessage: (objectMemory classForClassTag: classTag). "NOTREACHED" self assert: false]]. instructionPointer := self popStack. (self maybeMethodHasCogMethod: newMethod) ifTrue: [self executeNewMethod. self assert: false "NOTREACHED"]. ^self interpretMethodFromMachineCode "NOTREACHED"! Item was changed: ----- Method: CoInterpreter>>findNewMethodInClassTag: (in category 'message sending') ----- findNewMethodInClassTag: classTagArg "Find the compiled method to be run when the current messageSelector is sent to the given classTag, setting the values of newMethod and primitiveIndex." | ok class classTag | <inline: false> ok := self lookupInMethodCacheSel: messageSelector classTag: classTagArg. ok ifTrue: [self ifAppropriateCompileToNativeCode: newMethod selector: messageSelector] ifFalse: ["entry was not found in the cache; perhaps soemthing was forwarded." classTag := classTagArg. ((objectMemory isOopForwarded: messageSelector) or: [objectMemory isForwardedClassTag: classTag]) ifTrue: [(objectMemory isOopForwarded: messageSelector) ifTrue: [messageSelector := self handleForwardedSelectorFaultFor: messageSelector]. (objectMemory isForwardedClassTag: classTag) ifTrue: + [classTag := self handleForwardedSendFaultForTag: classTag]. - [classTag := self handleForwardedSendFaultFor: classTag]. ok := self lookupInMethodCacheSel: messageSelector classTag: classTag. ok ifTrue: [^self ifAppropriateCompileToNativeCode: newMethod selector: messageSelector]]. "entry was not found in the cache; look it up the hard way " class := objectMemory classForClassTag: classTag. self lookupMethodInClass: class. self addNewMethodToCache: class]! Item was added: + ----- Method: CoInterpreter>>followForwardedFieldsInCurrentMethod (in category 'message sending') ----- + followForwardedFieldsInCurrentMethod + | cogMethod | + <var: #cogMethod type: #'CogMethod *'> + <inline: false> + (self isMachineCodeFrame: framePointer) + ifTrue: + [cogMethod := self mframeHomeMethod: framePointer. + objectMemory + followForwardedObjectFields: cogMethod methodObject + toDepth: 0. + cogit followForwardedLiteralsIn: cogMethod] + ifFalse: + [objectMemory + followForwardedObjectFields: method + toDepth: 0]! Item was added: + ----- Method: CoInterpreter>>followForwardedMethods (in category 'object memory support') ----- + followForwardedMethods + <doNotGenerate> + cogit followForwardedMethods! Item was added: + ----- Method: CoInterpreter>>handleForwardedSendFaultForReceiver: (in category 'message sending') ----- + handleForwardedSendFaultForReceiver: forwardedReceiver + "Handle a send fault that may be due to a send to a forwarded object. + Unforward the receiver on the stack and answer it." + <option: #SpurObjectMemory> + | rcvr | + <inline: false> + "should *not* be a super send, so the receiver should be forwarded." + self assert: (objectMemory isOopForwarded: forwardedReceiver). + + self assert: (self stackValue: argumentCount) = forwardedReceiver. + rcvr := objectMemory followForwarded: forwardedReceiver. + self stackValue: argumentCount put: rcvr. + self followForwardedFrameContents: framePointer + stackPointer: stackPointer + (argumentCount + 1 * BytesPerWord). "don't repeat effort" + (objectMemory isPointers: (self frameReceiver: framePointer)) ifTrue: + [objectMemory + followForwardedObjectFields: (self frameReceiver: framePointer) + toDepth: 0]. + self followForwardedFieldsInCurrentMethod. + ^rcvr! Item was changed: ----- Method: CoInterpreter>>internalFindNewMethod (in category 'message sending') ----- internalFindNewMethod "Find the compiled method to be run when the current messageSelector is sent to the given class, setting the values of newMethod and primitiveIndex." | ok | <inline: true> ok := self lookupInMethodCacheSel: messageSelector classTag: lkupClassTag. ok ifTrue: [self ifAppropriateCompileToNativeCode: newMethod selector: messageSelector] ifFalse: [self externalizeIPandSP. ((objectMemory isOopForwarded: messageSelector) or: [objectMemory isForwardedClassTag: lkupClassTag]) ifTrue: [(objectMemory isOopForwarded: messageSelector) ifTrue: [messageSelector := self handleForwardedSelectorFaultFor: messageSelector]. (objectMemory isForwardedClassTag: lkupClassTag) ifTrue: + [lkupClassTag := self handleForwardedSendFaultForTag: lkupClassTag]. - [lkupClassTag := self handleForwardedSendFaultFor: lkupClassTag]. ok := self lookupInMethodCacheSel: messageSelector classTag: lkupClassTag. ok ifTrue: [^self ifAppropriateCompileToNativeCode: newMethod selector: messageSelector]]. lkupClass := objectMemory classForClassTag: lkupClassTag. self lookupMethodInClass: lkupClass. self internalizeIPandSP. self addNewMethodToCache: lkupClass]! Item was added: + ----- Method: CogObjectRepresentation>>genEnsureObjInRegRegNotForwarded:scratchReg: (in category 'compile abstract instructions') ----- + genEnsureObjInRegRegNotForwarded: reg scratchReg: scratch + "Make sure that the object in reg is not forwarded. By default there is + nothing to do. Subclasses for memory managers that forward will override." + ^0! Item was removed: - ----- Method: CogObjectRepresentation>>genEnsureRegNotForwarded:scratchReg: (in category 'compile abstract instructions') ----- - genEnsureRegNotForwarded: reg scratchReg: scratch - "Make sure that the obejct in reg is not forwarded. By default there is - nothing to do. Subclasses for memory managers that forward will override." - ^0! Item was changed: ----- Method: CogObjectRepresentationForSpur>>couldBeObject: (in category 'garbage collection') ----- couldBeObject: literal + ^(objectMemory isNonImmediate: literal) + and: [self oop: literal isGreaterThanOrEqualTo: objectMemory startOfMemory]! - ^objectMemory isNonImmediate: literal! Item was added: + ----- Method: CogObjectRepresentationForSpur>>genEnsureObjInRegRegNotForwarded:scratchReg: (in category 'compile abstract instructions') ----- + genEnsureObjInRegRegNotForwarded: reg scratchReg: scratch + "Make sure that the obejct in reg is not forwarded." + | loop ok | + <var: #ok type: #'AbstractInstruction *'> + <var: #loop type: #'AbstractInstruction *'> + self assert: reg ~= scratch. + loop := cogit Label. + self genGetClassIndexOfNonImm: reg into: scratch. + cogit CmpCq: objectMemory isForwardedObjectClassIndexPun + R: TempReg. + ok := cogit JumpNonZero: 0. + self genLoadSlot: 0 sourceReg: reg destReg: reg. + cogit Jump: loop. + ok jmpTarget: cogit Label. + ^0! Item was removed: - ----- Method: CogObjectRepresentationForSpur>>genEnsureRegNotForwarded:scratchReg: (in category 'compile abstract instructions') ----- - genEnsureRegNotForwarded: reg scratchReg: scratch - "Make sure that the obejct in reg is not forwarded." - | loop ok | - <var: #ok type: #'AbstractInstruction *'> - <var: #loop type: #'AbstractInstruction *'> - self assert: reg ~= scratch. - loop := cogit Label. - self genGetClassIndexOfNonImm: reg into: scratch. - cogit CmpCq: objectMemory isForwardedObjectClassIndexPun - R: TempReg. - ok := cogit JumpNonZero: 0. - self genLoadSlot: 0 sourceReg: reg destReg: reg. - cogit Jump: loop. - ok jmpTarget: cogit Label. - ^0! Item was changed: ----- Method: CogObjectRepresentationForSpur>>genGetClassObjectOf:into:scratchReg:instRegIsReceiver: (in category 'compile abstract instructions') ----- genGetClassObjectOf: instReg into: destReg scratchReg: scratchReg instRegIsReceiver: instRegIsReceiver + "Fetch the instance's class into destReg. If the instance is forwarded, follow forwarding." - "Fetch the instance's class into destReg." | jumpIsImm jumpNotForwarded loop | <var: #jumpIsImm type: #'AbstractInstruction *'> <var: #jumpNotForwarded type: #'AbstractInstruction *'> <var: #loop type: #'AbstractInstruction *'> instReg = destReg ifTrue: [^BadRegisterSet]. loop := cogit MoveR: instReg R: scratchReg. cogit AndCq: objectMemory tagMask R: scratchReg. jumpIsImm := cogit JumpNonZero: 0. self flag: #endianness. "Get least significant half of header word in destReg" cogit MoveMw: 0 r: instReg R: scratchReg. "mask off class index" cogit AndCq: objectMemory classIndexMask R: scratchReg. instRegIsReceiver ifFalse: ["if it is forwarded..." cogit CmpCq: objectMemory isForwardedObjectClassIndexPun R: scratchReg. jumpNotForwarded := cogit JumpNonZero: 0. "...follow the forwarding pointer and loop to fetch its classIndex" cogit MoveMw: objectMemory baseHeaderSize r: instReg R: instReg. cogit Jump: loop. jumpNotForwarded jmpTarget: cogit Label]. jumpIsImm jmpTarget: (cogit MoveR: scratchReg R: destReg). cogit PushR: instReg. self genGetClassObjectOfClassIndex: destReg into: instReg scratchReg: TempReg. cogit MoveR: instReg R: destReg. cogit PopR: instReg. ^0! Item was added: + ----- Method: CogObjectRepresentationForSqueakV3>>isOopForwarded: (in category 'garbage collection') ----- + isOopForwarded: oop + "Compatibility wth SpurMemoryManager. In ObjectMemory, no forwarding pointers + are visible to the VM." + <inline: true> + ^false! Item was changed: ----- Method: Cogit class>>declareCVarsIn: (in category 'translation') ----- declareCVarsIn: aCCodeGenerator #( 'coInterpreter' 'objectMemory' 'methodZone' 'objectRepresentation' 'cogBlockMethodSurrogateClass' 'cogMethodSurrogateClass' 'threadManager' 'processor' 'lastNInstructions' 'simulatedAddresses' 'simulatedTrampolines' 'simulatedVariableGetters' 'simulatedVariableSetters' 'printRegisters' 'printInstructions' 'clickConfirm' 'singleStep') do: [:simulationVariableNotNeededForRealVM| aCCodeGenerator removeVariable: simulationVariableNotNeededForRealVM]. NewspeakVM ifFalse: [#( 'dynSuperEntry' 'dynSuperEntryAlignment' 'dynamicSuperSendTrampolines' 'ceImplicitReceiverTrampoline' 'ceExplicitReceiverTrampoline' 'cmDynSuperEntryOffset') do: [:variableNotNeededInNormalVM| aCCodeGenerator removeVariable: variableNotNeededInNormalVM]]. aCCodeGenerator removeConstant: #COGMTVM. "this should be defined at compile time" aCCodeGenerator addHeaderFile:'<stddef.h>'; "for e.g. offsetof" addHeaderFile:'"sqCogStackAlignment.h"'; addHeaderFile:'"cogmethod.h"'; addHeaderFile:'#if COGMTVM'; addHeaderFile:'"cointerpmt.h"'; addHeaderFile:'#else'; addHeaderFile:'"cointerp.h"'; addHeaderFile:'#endif'; addHeaderFile:'"cogit.h"'; addHeaderFile:'"dispdbg.h"'. aCCodeGenerator var: #ceGetSP declareC: 'unsigned long (*ceGetSP)(void)'; var: #ceCaptureCStackPointers declareC: 'void (*ceCaptureCStackPointers)(void)'; var: #ceEnterCogCodePopReceiverReg declareC: 'void (*ceEnterCogCodePopReceiverReg)(void)'; var: #realCEEnterCogCodePopReceiverReg declareC: 'void (*realCEEnterCogCodePopReceiverReg)(void)'; var: #ceEnterCogCodePopReceiverAndClassRegs declareC: 'void (*ceEnterCogCodePopReceiverAndClassRegs)(void)'; var: #realCEEnterCogCodePopReceiverAndClassRegs declareC: 'void (*realCEEnterCogCodePopReceiverAndClassRegs)(void)'; var: #ceFlushICache declareC: 'static void (*ceFlushICache)(unsigned long from, unsigned long to)'; var: #ceCheckFeaturesFunction declareC: 'static unsigned long (*ceCheckFeaturesFunction)(void)'; var: #ceTryLockVMOwner declareC: 'unsigned long (*ceTryLockVMOwner)(void)'; var: #ceUnlockVMOwner declareC: 'void (*ceUnlockVMOwner)(void)'; var: #postCompileHook declareC: 'void (*postCompileHook)(CogMethod *, void *)'; var: #openPICList declareC: 'CogMethod *openPICList = 0'; var: #maxMethodBefore type: #'CogBlockMethod *'. aCCodeGenerator declareVar: 'aMethodLabel' type: #'AbstractInstruction'; "Has to come lexicographically before backEnd & methodLabel" var: #backEnd declareC: 'AbstractInstruction * const backEnd = &aMethodLabel'; var: #methodLabel declareC: 'AbstractInstruction * const methodLabel = &aMethodLabel'; var: #primInvokeLabel type: #'AbstractInstruction *'. self declareC: #(abstractOpcodes stackCheckLabel blockEntryLabel blockEntryNoContextSwitch stackOverflowCall sendMissCall entry noCheckEntry dynSuperEntry mnuCall interpretCall endCPICCase0 endCPICCase1) as: #'AbstractInstruction *' in: aCCodeGenerator. aCCodeGenerator declareVar: #annotations type: #'InstructionAnnotation *'; declareVar: #blockStarts type: #'BlockStart *'; declareVar: #fixups type: #'BytecodeFixup *'. aCCodeGenerator var: #sendTrampolines declareC: 'sqInt sendTrampolines[NumSendTrampolines]'; var: #superSendTrampolines declareC: 'sqInt superSendTrampolines[NumSendTrampolines]'; var: #dynamicSuperSendTrampolines declareC: 'sqInt dynamicSuperSendTrampolines[NumSendTrampolines]'; var: #trampolineAddresses declareC: 'static char *trampolineAddresses[NumTrampolines*2]'; var: #objectReferencesInRuntime declareC: 'static sqInt objectReferencesInRuntime[NumObjRefsInRuntime]'; var: #cePositive32BitIntegerTrampoline declareC: 'static sqInt cePositive32BitIntegerTrampoline'; var: #labelCounter + type: #int; - declareC: 'static int labelCounter'; var: #traceFlags declareC: 'int traceFlags = 8 /* prim trace log on by default */'; var: #cStackAlignment declareC: 'const int cStackAlignment = STACK_ALIGN_BYTES'. aCCodeGenerator declareVar: #CFramePointer type: #'void *'; declareVar: #CStackPointer type: #'void *'; declareVar: #minValidCallAddress type: #'unsigned long'; declareVar: #debugPrimCallStackOffset type: #'unsigned long'. aCCodeGenerator var: #generatorTable declareC: 'BytecodeDescriptor generatorTable[', aCCodeGenerator vmClass generatorTable size, ']' , (self tableInitializerFor: aCCodeGenerator vmClass generatorTable in: aCCodeGenerator); var: #primitiveGeneratorTable declareC: 'PrimitiveDescriptor primitiveGeneratorTable[MaxCompiledPrimitiveIndex+1]' , (self tableInitializerFor: aCCodeGenerator vmClass primitiveTable in: aCCodeGenerator). "In C the abstract opcode names clash with the Smalltak generator syntactic sugar. Most of the syntactic sugar is inlined, but alas some remains. Rename the syntactic sugar to avoid the clash." (self organization listAtCategoryNamed: #'abstract instructions') do: [:s| aCCodeGenerator addSelectorTranslation: s to: 'g', (aCCodeGenerator cFunctionNameFor: s)]. aCCodeGenerator addSelectorTranslation: #halt: to: 'haltmsg'! Item was changed: ----- Method: Cogit class>>mustBeGlobal: (in category 'translation') ----- mustBeGlobal: var "Answer if a variable must be global and exported. Used for inst vars that are accessed from VM support code. include cePositive32BitIntegerTrampoline as a hack to prevent it being inlined (it is + only used outside of Cogit by the object representation). Include CFramePointer CStackPointer as + a hack to get them declared at all." - only used outside of Cogit by the object representation). Include labelCounter as a hack to stop it - being inlined into genLabel, and CFramePointer CStackPointer as a hack to get them declared at all." ^#('ceBaseFrameReturnTrampoline' 'ceCaptureCStackPointers' 'ceCheckForInterruptTrampoline' 'ceEnterCogCodePopReceiverReg' 'realCEEnterCogCodePopReceiverReg' 'ceEnterCogCodePopReceiverAndClassRegs' 'realCEEnterCogCodePopReceiverAndClassRegs' 'ceReturnToInterpreterTrampoline' 'ceCannotResumeTrampoline' + 'ceTryLockVMOwner' 'ceUnlockVMOwner' - 'cePositive32BitIntegerTrampoline' 'ceFlushICache' 'ceTryLockVMOwner' 'ceUnlockVMOwner' 'cmEntryOffset' 'cmNoCheckEntryOffset' 'cmDynSuperEntryOffset' 'blockNoContextSwitchOffset' 'breakPC' + 'CFramePointer' 'CStackPointer' 'cFramePointerInUse' 'ceGetSP' - 'labelCounter' 'CFramePointer' 'CStackPointer' 'cFramePointerInUse' 'ceGetSP' 'traceFlags' 'traceStores' 'debugPrimCallStackOffset') includes: var! Item was added: + ----- Method: Cogit>>followForwardedLiteralsIn: (in category 'garbage collection') ----- + followForwardedLiteralsIn: cogMethod + <api> + <option: #SpurObjectMemory> + <var: #cogMethod type: #'CogMethod *'> + self assert: (objectMemory shouldRemapOop: cogMethod methodObject) not. + (objectMemory shouldRemapOop: cogMethod selector) ifTrue: + [cogMethod selector: (objectMemory remapObj: cogMethod selector)]. + self mapFor: cogMethod + performUntil: (self cppIf: NewspeakVM + ifTrue: [#remapNSIfObjectRef:pc:hasYoung:] + ifFalse: [#remapIfObjectRef:pc:hasYoung:]) + arg: 0! Item was added: + ----- Method: Cogit>>followForwardedMethods (in category 'garbage collection') ----- + followForwardedMethods + <api> + <option: #SpurObjectMemory> + <var: #cogMethod type: #'CogMethod *'> + | cogMethod freedPIC | + <var: #cogMethod type: #'CogMethod *'> + freedPIC := false. + cogMethod := self cCoerceSimple: methodZoneBase to: #'CogMethod *'. + [cogMethod < methodZone limitZony] whileTrue: + [cogMethod cmType = CMMethod ifTrue: + [(objectMemory shouldRemapOop: cogMethod methodObject) ifTrue: + [cogMethod methodObject: (objectMemory remapObj: cogMethod methodObject). + (cogMethod cmRefersToYoung not + and: [objectMemory isYoungObject: cogMethod methodObject]) ifTrue: + [methodZone addToYoungReferrers: cogMethod methodObject]]]. + cogMethod cmType = CMClosedPIC ifTrue: + [(self mapObjectReferencesInClosedPIC: cogMethod) ifTrue: + [freedPIC := true. + methodZone freeMethod: cogMethod]]. + cogMethod := methodZone methodAfter: cogMethod]. + freedPIC ifTrue: + [self unlinkSendsToFree. + processor flushICacheFrom: codeBase to: methodZone limitZony asInteger]! Item was changed: ----- Method: ObjectMemory class>>declareCVarsIn: (in category 'translation') ----- declareCVarsIn: aCCodeGenerator + self declareCAsOop: + #( memory endOfMemory memoryLimit + youngStart youngStartLocal freeBlock + compStart compEnd + fwdTableNext fwdTableLast + gcBiasToGrowThreshold ) + in: aCCodeGenerator. + self declareCAsUSqLong: + #( gcStartUsecs statFullGCUsecs statIncrGCUsecs statIGCDeltaUsecs ) + in: aCCodeGenerator. aCCodeGenerator - var: #memory - declareC: 'static usqInt memory'. - aCCodeGenerator var: #remapBuffer declareC: 'sqInt remapBuffer[RemapBufferSize + 1 /* ', (RemapBufferSize + 1) printString, ' */]'. aCCodeGenerator var: #rootTable declareC: 'sqInt rootTable[RootTableSize + 1 /* ', (RootTableSize + 1) printString, ' */]'. "Weak roots must be large enough for roots+remapBuffer+sizeof(allCallsOn: #markAndTrace:)" aCCodeGenerator var: #weakRoots declareC: 'sqInt weakRoots[WeakRootTableSize + 1 /* ', (WeakRootTableSize + 1) printString, ' */]'. aCCodeGenerator var: #headerTypeBytes declareC: 'sqInt headerTypeBytes[4]'. aCCodeGenerator var: #extraRoots declareC: 'sqInt* extraRoots[ExtraRootSize + 1 /* ', (ExtraRootSize + 1) printString, ' */]'. - self declareCAsOop: { - #youngStart . - #endOfMemory . - #memoryLimit . - #youngStartLocal . - #freeBlock . - #compStart . - #compEnd . - #fwdTableNext . - #fwdTableLast . - #gcBiasToGrowThreshold } - in: aCCodeGenerator. aCCodeGenerator + var: #headerTypeBytes type: 'const sqInt' array: HeaderTypeExtraBytes! - var: #headerTypeBytes type: 'const sqInt' array: HeaderTypeExtraBytes. - self declareCAsUSqLong: #(gcStartUsecs statFullGCUsecs statIncrGCUsecs statIGCDeltaUsecs) - in: aCCodeGenerator! Item was changed: ----- Method: ObjectMemory class>>mustBeGlobal: (in category 'translation') ----- mustBeGlobal: var "Answer if a variable must be global and exported. Used for inst vars that are accessed from VM support code." + ^false "used to be: ^'memory' = var"! - ^'memory' = var! Item was changed: ----- Method: ObjectMemory>>isOopForwarded: (in category 'interpreter access') ----- isOopForwarded: oop "Compatibility wth SpurMemoryManager. In ObjectMemory, no forwarding pointers are visible to the VM." - <api> - <cmacro: '(oop) false'> <inline: true> ^false! Item was changed: ----- Method: SimpleStackBasedCogit>>genPushLiteralVariable: (in category 'bytecode generators') ----- genPushLiteralVariable: literalIndex <inline: false> | association | association := self getLiteral: literalIndex. "N.B. Do _not_ use ReceiverResultReg to avoid overwriting receiver in assignment in frameless methods." self annotate: (self MoveCw: association R: ClassReg) objRef: association. - objectRepresentation genEnsureRegNotForwarded: ClassReg scratchReg: TempReg. objectRepresentation + genEnsureObjInRegRegNotForwarded: ClassReg + scratchReg: TempReg. + objectRepresentation genLoadSlot: ValueIndex sourceReg: ClassReg destReg: TempReg. self PushR: TempReg. ^0! Item was changed: ----- Method: SimpleStackBasedCogit>>genSpecialSelectorEqualsEquals (in category 'bytecode generators') ----- genSpecialSelectorEqualsEquals | jumpNotEqual jumpPush | <var: #jumpNotEqual type: #'AbstractInstruction *'> <var: #jumpPush type: #'AbstractInstruction *'> + self PopR: Arg0Reg. + objectRepresentation + genEnsureObjInRegRegNotForwarded: Arg0Reg + scratchReg: TempReg. - self PopR: TempReg. self MoveMw: 0 r: SPReg R: ClassReg. + objectRepresentation + genEnsureObjInRegRegNotForwarded: ClassReg + scratchReg: TempReg. + self CmpR: Arg0Reg R: ClassReg. - self CmpR: TempReg R: ClassReg. jumpNotEqual := self JumpNonZero: 0. + self annotate: (self MoveCw: objectMemory trueObject R: Arg0Reg) - self annotate: (self MoveCw: objectMemory trueObject R: TempReg) objRef: objectMemory trueObject. jumpPush := self Jump: 0. + jumpNotEqual jmpTarget: (self annotate: (self MoveCw: objectMemory falseObject R: Arg0Reg) - jumpNotEqual jmpTarget: (self annotate: (self MoveCw: objectMemory falseObject R: TempReg) objRef: objectMemory falseObject). + jumpPush jmpTarget: (self MoveR: Arg0Reg Mw: 0 r: SPReg). - jumpPush jmpTarget: (self MoveR: TempReg Mw: 0 r: SPReg). ^0! Item was changed: ----- Method: SimpleStackBasedCogit>>genStorePop:LiteralVariable: (in category 'bytecode generators') ----- genStorePop: popBoolean LiteralVariable: litVarIndex <inline: false> | association | self assert: needsFrame. association := self getLiteral: litVarIndex. self annotate: (self MoveCw: association R: ReceiverResultReg) objRef: association. + objectRepresentation + genEnsureObjInRegRegNotForwarded: ReceiverResultReg + scratchReg: TempReg. - objectRepresentation genEnsureRegNotForwarded: ReceiverResultReg scratchReg: TempReg. popBoolean ifTrue: [self PopR: ClassReg] ifFalse: [self MoveMw: 0 r: SPReg R: ClassReg]. traceStores > 0 ifTrue: [self CallRT: ceTraceStoreTrampoline]. ^objectRepresentation genStoreSourceReg: ClassReg slotIndex: ValueIndex destReg: ReceiverResultReg scratchReg: TempReg! Item was changed: ----- Method: Spur32BitCoMemoryManager>>startOfMemory (in category 'accessing') ----- startOfMemory "Return the start of object memory. This is immediately after the native code zone. N.B. the stack zone is alloca'ed. Use a macro so as not to punish the debug VM." + <api> <cmacro: '() heapBase'> <returnTypeC: #usqInt> ^coInterpreter heapBase! Item was changed: ----- Method: SpurMemoryManager>>scavengingGCTenuringIf: (in category 'gc - scavenging') ----- scavengingGCTenuringIf: tenuringCriterion "Run the scavenger." self assert: remapBufferCount = 0. + (self asserta: scavenger eden limit - freeStart > coInterpreter interpreterAllocationReserveBytes) ifFalse: + [coInterpreter tab; + printNum: scavenger eden limit - freeStart; space; + printNum: coInterpreter interpreterAllocationReserveBytes; space; + printNum: coInterpreter interpreterAllocationReserveBytes - (scavenger eden limit - freeStart); cr]. - self assert: scavenger eden limit - freeStart > coInterpreter interpreterAllocationReserveBytes. self checkMemoryMap. self checkFreeSpace. "coInterpreter printCallStackFP: coInterpreter framePointer" self runLeakCheckerForFullGC: false. coInterpreter preGCAction: GCModeScavenge; "would prefer this to be in mapInterpreterOops, but compatibility with ObjectMemory dictates it goes here." flushMethodCacheFrom: newSpaceStart to: newSpaceLimit. needGCFlag := false. gcStartUsecs := coInterpreter ioUTCMicrosecondsNow. self doScavenge: tenuringCriterion. statScavenges := statScavenges + 1. statGCEndUsecs := coInterpreter ioUTCMicrosecondsNow. statSGCDeltaUsecs := statGCEndUsecs - gcStartUsecs. statScavengeGCUsecs := statScavengeGCUsecs + statSGCDeltaUsecs. statRootTableCount := scavenger rememberedSetSize. coInterpreter postGCAction: GCModeScavenge. self runLeakCheckerForFullGC: false. self checkFreeSpace! Item was changed: ----- Method: StackInterpreter>>findNewMethodInClassTag: (in category 'message sending') ----- findNewMethodInClassTag: classTagArg "Find the compiled method to be run when the current messageSelector is sent to the given class, setting the values of 'newMethod' and 'primitiveIndex'." | ok class classTag | <inline: false> ok := self lookupInMethodCacheSel: messageSelector classTag: classTagArg. ok ifFalse: "entry was not found in the cache; look it up the hard way " [classTag := classTagArg. ((objectMemory isOopForwarded: messageSelector) or: [objectMemory isForwardedClassTag: classTag]) ifTrue: [(objectMemory isOopForwarded: messageSelector) ifTrue: [messageSelector := self handleForwardedSelectorFaultFor: messageSelector]. (objectMemory isForwardedClassTag: classTag) ifTrue: + [classTag := self handleForwardedSendFaultForTag: classTag]. - [classTag := self handleForwardedSendFaultFor: classTag]. ok := self lookupInMethodCacheSel: messageSelector classTag: classTag. ok ifTrue: [^nil]]. class := objectMemory classForClassTag: classTag. self lookupMethodInClass: class. self addNewMethodToCache: class]! Item was added: + ----- Method: StackInterpreter>>followForwardedFieldsInCurrentMethod (in category 'message sending') ----- + followForwardedFieldsInCurrentMethod + objectMemory + followForwardedObjectFields: method + toDepth: 0! Item was added: + ----- Method: StackInterpreter>>followForwardedMethods (in category 'object memory support') ----- + followForwardedMethods + "This is just a stub for the CoInterpreter"! Item was added: + ----- Method: StackInterpreter>>followForwardedMethodsInMethodCache (in category 'object memory support') ----- + followForwardedMethodsInMethodCache + 0 to: MethodCacheSize - 1 by: MethodCacheEntrySize do: + [:i | | c s m | + c := methodCache at: i + MethodCacheClass. + s := methodCache at: i + MethodCacheSelector. + m := methodCache at: i + MethodCacheMethod. + (c ~= 0 and: [s ~= 0 and: [m ~= 0 + and: [objectMemory isOopForwarded: m]]]) ifTrue: + [m := objectMemory followForwarded: m. + methodCache at: i + MethodCacheMethod put: m]]! Item was changed: ----- Method: StackInterpreter>>handleForwardedSelectorFaultFor: (in category 'message sending') ----- handleForwardedSelectorFaultFor: selectorOop "Handle a send fault that is due to a send using a forwarded selector. Unforward the selector and follow the current method and special selectors array to unforward the source of the forwarded selector." + <option: #SpurObjectMemory> <inline: false> self assert: (objectMemory isOopForwarded: selectorOop). + self followForwardedFieldsInCurrentMethod. - objectMemory - followForwardedObjectFields: method - toDepth: 0; followForwardedObjectFields: (objectMemory splObj: SpecialSelectors) + toDepth: 0. - toDepth: 0. ^objectMemory followForwarded: selectorOop! Item was removed: - ----- Method: StackInterpreter>>handleForwardedSendFaultFor: (in category 'message sending') ----- - handleForwardedSendFaultFor: classTag - "Handle a send fault that may be due to a send to a forwarded object. - Unforward the receiver on the stack and answer its actual class." - | rcvr | - <inline: false> - self assert: (objectMemory isForwardedClassTag: classTag). - - rcvr := self stackValue: argumentCount. - "should *not* be a super send, so the receiver should be forwarded." - self assert: (objectMemory isOopForwarded: rcvr). - rcvr := objectMemory followForwarded: rcvr. - self stackValue: argumentCount put: rcvr. - self followForwardedFrameContents: framePointer - stackPointer: stackPointer + (argumentCount + 1 * BytesPerWord). "don't repeat effort" - (objectMemory isPointers: (self frameReceiver: framePointer)) ifTrue: - [objectMemory - followForwardedObjectFields: (self frameReceiver: framePointer) - toDepth: 0]. - ^objectMemory fetchClassTagOf: rcvr! Item was added: + ----- Method: StackInterpreter>>handleForwardedSendFaultForTag: (in category 'message sending') ----- + handleForwardedSendFaultForTag: classTag + "Handle a send fault that may be due to a send to a forwarded object. + Unforward the receiver on the stack and answer its actual class." + <option: #SpurObjectMemory> + | rcvr | + <inline: false> + self assert: (objectMemory isForwardedClassTag: classTag). + + rcvr := self stackValue: argumentCount. + "should *not* be a super send, so the receiver should be forwarded." + self assert: (objectMemory isOopForwarded: rcvr). + rcvr := objectMemory followForwarded: rcvr. + self stackValue: argumentCount put: rcvr. + self followForwardedFrameContents: framePointer + stackPointer: stackPointer + (argumentCount + 1 * BytesPerWord). "don't repeat effort" + (objectMemory isPointers: (self frameReceiver: framePointer)) ifTrue: + [objectMemory + followForwardedObjectFields: (self frameReceiver: framePointer) + toDepth: 0]. + ^objectMemory fetchClassTagOf: rcvr! Item was changed: ----- Method: StackInterpreter>>internalFindNewMethod (in category 'message sending') ----- internalFindNewMethod "Find the compiled method to be run when the current messageSelector is sent to the class 'lkupClass', setting the values of 'newMethod' and 'primitiveIndex'." | ok | <inline: true> ok := self lookupInMethodCacheSel: messageSelector classTag: lkupClassTag. ok ifFalse: "entry was not found in the cache; look it up the hard way" [self externalizeIPandSP. ((objectMemory isOopForwarded: messageSelector) or: [objectMemory isForwardedClassTag: lkupClassTag]) ifTrue: [(objectMemory isOopForwarded: messageSelector) ifTrue: [messageSelector := self handleForwardedSelectorFaultFor: messageSelector]. (objectMemory isForwardedClassTag: lkupClassTag) ifTrue: + [lkupClassTag := self handleForwardedSendFaultForTag: lkupClassTag]. - [lkupClassTag := self handleForwardedSendFaultFor: lkupClassTag]. ok := self lookupInMethodCacheSel: messageSelector classTag: lkupClassTag. ok ifTrue: [^nil]]. lkupClass := objectMemory classForClassTag: lkupClassTag. self lookupMethodInClass: lkupClass. self internalizeIPandSP. self addNewMethodToCache: lkupClass]! Item was changed: ----- Method: StackInterpreter>>postBecomeAction: (in category 'object memory support') ----- postBecomeAction: theBecomeEffectsFlags theBecomeEffectsFlags ~= 0 ifTrue: [self followForwardingPointersInStackZone: theBecomeEffectsFlags. + (theBecomeEffectsFlags anyMask: BecameCompiledMethodFlag) ifTrue: + [self followForwardedMethodsInMethodCache]. + self followForwardedMethods. "for CoInterpreter" self followForwardingPointersInScheduler]! Item was changed: ----- Method: StackInterpreter>>printOopShortInner: (in category 'debug printing') ----- printOopShortInner: oop | classOop name nameLen | <var: #name type: #'char *'> <inline: true> (objectMemory isImmediate: oop) ifTrue: [(objectMemory isImmediateCharacter: oop) ifTrue: [^self printChar: $$; printChar: (objectMemory characterValueOf: oop); printChar: $(; printHex: (objectMemory integerValueOf: oop); printChar: $)]. ^self printNum: (objectMemory integerValueOf: oop); printChar: $(; printHex: (objectMemory integerValueOf: oop); printChar: $)]. (objectMemory addressCouldBeObj: oop) ifFalse: [^self print: ((oop bitAnd: objectMemory allocationUnit - 1) ~= 0 ifTrue: [' is misaligned'] ifFalse: [' is not on the heap'])]. + (objectMemory isOopForwarded: oop) ifTrue: + [^self printHex: oop; print: ' is a forwarder to '; printHex: (objectMemory followForwarded: oop)]. (self isFloatObject: oop) ifTrue: [^self printFloat: (self dbgFloatValueOf: oop)]. classOop := objectMemory fetchClassOfNonImm: oop. (objectMemory addressCouldBeObj: classOop) ifFalse: [^self print: 'a ??']. (objectMemory numSlotsOf: classOop) = metaclassNumSlots ifTrue: [^self printNameOfClass: oop count: 5]. oop = objectMemory nilObject ifTrue: [^self print: 'nil']. oop = objectMemory trueObject ifTrue: [^self print: 'true']. oop = objectMemory falseObject ifTrue: [^self print: 'false']. nameLen := self lengthOfNameOfClass: classOop. nameLen = 0 ifTrue: [^self print: 'a ??']. name := self nameOfClass: classOop. nameLen = 10 ifTrue: [(self str: name n: 'ByteString' cmp: 10) not "strncmp is weird" ifTrue: [^self printChar: $'; printStringOf: oop; printChar: $']. (self str: name n: 'ByteSymbol' cmp: 10) not "strncmp is weird" ifTrue: [self printChar: $#; printStringOf: oop. ^self]]. (nameLen = 9 and: [(self str: name n: 'Character' cmp: 9) not]) ifTrue: [^self printChar: $$; printChar: (objectMemory integerValueOf: (objectMemory fetchPointer: 0 ofObject: oop))]. self print: 'a(n) '. self cCode: [0 to: nameLen - 1 do: [:i| self printChar: (name at: i)]] inSmalltalk: [name isString ifTrue: [self print: name] ifFalse: [0 to: nameLen - 1 do: [:i| self printChar: (name at: i)]]]. "Try to spot association-like things; they're all subclasses of LookupKey" ((objectMemory instanceSizeOf: classOop) = (ValueIndex + 1) and: [(self superclassOf: classOop) = (self superclassOf: (objectMemory fetchClassOfNonImm: (objectMemory splObj: SchedulerAssociation))) and: [objectMemory isBytes: (objectMemory fetchPointer: KeyIndex ofObject: oop)]]) ifTrue: [self space; printOopShort: (objectMemory fetchPointer: KeyIndex ofObject: oop); print: ' -> '; printHex: (objectMemory fetchPointer: ValueIndex ofObject: oop)]! Item was changed: ----- Method: StackToRegisterMappingCogit>>genPushLiteralVariable: (in category 'bytecode generators') ----- genPushLiteralVariable: literalIndex <inline: false> | association freeReg | freeReg := self ssAllocatePreferredReg: ClassReg. association := self getLiteral: literalIndex. "N.B. Do _not_ use ReceiverResultReg to avoid overwriting receiver in assignment in frameless methods." "So far descriptors are not rich enough to describe the entire dereference so generate the register load but don't push the result. There is an order-of-evaluation issue if we defer the dereference." self annotate: (self MoveCw: association R: TempReg) objRef: association. - objectRepresentation genEnsureRegNotForwarded: TempReg scratchReg: freeReg. objectRepresentation + genEnsureObjInRegRegNotForwarded: TempReg + scratchReg: freeReg. + objectRepresentation genLoadSlot: ValueIndex sourceReg: TempReg destReg: freeReg. self ssPushRegister: freeReg. ^0! Item was changed: ----- Method: StackToRegisterMappingCogit>>genStorePop:LiteralVariable: (in category 'bytecode generators') ----- genStorePop: popBoolean LiteralVariable: litVarIndex <inline: false> | topReg valueReg association constVal | self flag: 'with better register allocation this wouldn''t need a frame. e.g. use SendNumArgs instead of ReceiverResultReg'. self assert: needsFrame. optStatus isReceiverResultRegLive: false. "N.B. No need to check the stack for references because we generate code for literal variable loads that stores the result in a register, deferring only the register push." association := self getLiteral: litVarIndex. constVal := self ssTop maybeConstant. "Avoid store check for immediate values" (self ssTop type = SSConstant and: [(objectRepresentation shouldAnnotateObjectReference: constVal) not]) ifTrue: [self ssAllocateRequiredReg: ReceiverResultReg. self annotate: (self MoveCw: association R: ReceiverResultReg) objRef: association. + objectRepresentation + genEnsureObjInRegRegNotForwarded: ReceiverResultReg + scratchReg: TempReg. - objectRepresentation genEnsureRegNotForwarded: ReceiverResultReg scratchReg: TempReg. self ssStorePop: popBoolean toPreferredReg: TempReg. traceStores > 0 ifTrue: [self CallRT: ceTraceStoreTrampoline]. ^objectRepresentation genStoreImmediateInSourceReg: TempReg slotIndex: ValueIndex destReg: ReceiverResultReg]. ((topReg := self ssTop registerOrNil) isNil or: [topReg = ReceiverResultReg]) ifTrue: [topReg := ClassReg]. self ssPop: 1. self ssAllocateCallReg: topReg. "for the ceStoreCheck call in genStoreSourceReg:... below" self ssPush: 1. valueReg := self ssStorePop: popBoolean toPreferredReg: topReg. valueReg = ReceiverResultReg ifTrue: [self MoveR: valueReg R: topReg]. self ssAllocateCallReg: ReceiverResultReg. self annotate: (self MoveCw: association R: ReceiverResultReg) objRef: association. + objectRepresentation genEnsureObjInRegRegNotForwarded: ReceiverResultReg scratchReg: TempReg. - objectRepresentation genEnsureRegNotForwarded: ReceiverResultReg scratchReg: TempReg. traceStores > 0 ifTrue: [self MoveR: topReg R: TempReg. self CallRT: ceTraceStoreTrampoline]. ^objectRepresentation genStoreSourceReg: topReg slotIndex: ValueIndex destReg: ReceiverResultReg scratchReg: TempReg! |
Free forum by Nabble | Edit this page |