[Vm-dev] VM Maker: VMMaker.oscog-eem.254.mcz

commits at source.squeak.org commits at source.squeak.org
Sat Jan 12 03:08:46 UTC 2013


Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.254.mcz

==================== Summary ====================

Name: VMMaker.oscog-eem.254
Author: eem
Time: 11 January 2013, 7:05:37.389 pm
UUID: 74e6a299-691e-4f7d-986c-1a7d3d0ec02c
Ancestors: VMMaker.oscog-eem.253

Fix becomeForward: so that objects whose references are deleted are
freed and can no longer be resurrected via allObjects or allInstances.

Make primitiveIdentityHash pop all arguments, for Newspeak VMMirrors.

Simulator:
Fix stack depth assert checking for NewsqueakV4 methods.  Absent
receiver sends have a different stack delta to normal sends.

Make disassembly display and skip oops in implicit receiver caches.
Fix off-by-one limit check bug in disassembleMethodFor:.

Provide a filter on perform: to allow the simulator to avoid running
unsimulateable primitives/start-up code such as
ObjectiveCAlien class>>startUp:.

Fix detauledSymbolicMethod: for Newspeak methods containing
absent receiver sends.

Make priomptHex: accept C hex constants.

=============== Diff against VMMaker.oscog-eem.253 ===============

Item was changed:
  CoInterpreterMT subclass: #CogVMSimulator
+ 	instanceVariableNames: 'enableCog byteCount lastPollCount lastExtPC sendCount printSends traceOn myBitBlt displayForm imageName pluginList mappedPluginEntries quitBlock transcript displayView printFrameAtEachStep printBytecodeAtEachStep systemAttributes uniqueIndices uniqueIndex breakCount atEachStepBlock startMicroseconds externalSemaphoreSignalRequests externalSemaphoreSignalResponses extSemTabSize debugStackDepthDictionary performFilters'
- 	instanceVariableNames: 'enableCog byteCount lastPollCount lastExtPC sendCount printSends traceOn myBitBlt displayForm imageName pluginList mappedPluginEntries quitBlock transcript displayView printFrameAtEachStep printBytecodeAtEachStep systemAttributes uniqueIndices uniqueIndex breakCount atEachStepBlock startMicroseconds externalSemaphoreSignalRequests externalSemaphoreSignalResponses extSemTabSize debugStackDepthDictionary'
  	classVariableNames: ''
  	poolDictionaries: ''
  	category: 'VMMaker-JITSimulation'!
  
  !CogVMSimulator commentStamp: '<historical>' prior: 0!
  This class defines basic memory access and primitive simulation so that the StackInterpreter can run simulated in the Squeak environment.  It also defines a number of handy object viewing methods to facilitate pawing around in the object memory.
  
  To see the thing actually run, you could (after backing up this image and changes), execute
  
  	(CogVMSimulator new openOn: Smalltalk imageName) test
  
  and be patient both to wait for things to happen, and to accept various things that may go wrong depending on how large or unusual your image may be.  We usually do this with a small and simple benchmark image. You will probably have more luck using InterpreteSimulatorLSB or InterpreterSimulatorMSB as befits your machine.!

Item was added:
+ ----- Method: CogVMSimulator>>filterPerformOf:to: (in category 'control primitives') -----
+ filterPerformOf: selector to: receiver
+ 	"This is to allow simulator to filter start-up items to avoid as-yet unsimulatable plugins."
+ 	performFilters ifNil: [^false].
+ 	(performFilters at: (self shortPrint: receiver) ifAbsent: []) ifNotNil:
+ 		[:messages|
+ 		self halt.
+ 		^messages includes: (self stringOf: selector)].
+ 	^false!

Item was added:
+ ----- Method: CogVMSimulator>>forShortPrintString:filterPerformMessages: (in category 'control primitives') -----
+ forShortPrintString: shortPrintString filterPerformMessages: aCollection
+ 	performFilters ifNil:
+ 		[performFilters := Dictionary new].
+ 	performFilters at: shortPrintString put: aCollection!

Item was changed:
  ----- Method: CogVMSimulator>>maybeCheckStackDepth:sp:pc: (in category 'debug support') -----
  maybeCheckStackDepth: delta sp: sp pc: mcpc
  	| asp bcpc cogHomeMethod cogBlockMethod csp debugStackPointers |
  	debugStackDepthDictionary ifNil: [^self].
  	(self isMachineCodeFrame: framePointer) ifFalse: [^self].
  	cogBlockMethod := self mframeCogMethod: framePointer.
  	cogHomeMethod := self asCogHomeMethod: cogBlockMethod.
  	debugStackPointers := debugStackDepthDictionary
  								at: cogHomeMethod methodObject
  								ifAbsentPut: [self debugStackPointersFor: cogHomeMethod methodObject].
  	bcpc := cogit
  				bytecodePCFor: mcpc
  				startBcpc: (cogHomeMethod = cogBlockMethod
  								ifTrue: [self startPCOfMethod: cogHomeMethod methodObject]
  								ifFalse: [self startPCOfClosure: (self pushedReceiverOrClosureOfFrame: framePointer)])
  				in: cogBlockMethod.
  	self assert: bcpc ~= 0.
  	asp := self stackPointerIndexForFrame: framePointer WithSP: sp + BytesPerWord.
  	csp := debugStackPointers at: bcpc.
+ 	"Compensate lazily for absent receiver sends."
+ 	(NewspeakVM
+ 	 and: [asp - delta = csp
+ 	 and: [cogit isAbsentReceiverSendAt: mcpc in: cogHomeMethod]]) ifTrue:
+ 		[csp := debugStackPointers at: bcpc put: csp + 1].
  	self assert: asp - delta + 1 = csp!

Item was changed:
  ----- Method: CogVMSimulator>>primitiveDoPrimitiveWithArgs (in category 'debugging traps') -----
  primitiveDoPrimitiveWithArgs
  	| primIndex |
  	primIndex := objectMemory integerValueOf: (self stackValue: 1).
+ 	NewspeakVM ifFalse:
+ 		[transcript nextPutAll: 'DO PRIMITIVE: '; print: (self functionPointerFor: primIndex inClass: nil); cr; flush].
- 	transcript nextPutAll: 'DO PRIMITIVE: '; print: (self functionPointerFor: primIndex inClass: nil); cr; flush.
  	primIndex = 76 ifTrue:
  		[self halt].
  	^super primitiveDoPrimitiveWithArgs!

Item was added:
+ ----- Method: CogVMSimulator>>primitiveObject:perform:withArguments:lookedUpIn: (in category 'control primitives') -----
+ primitiveObject: actualReceiver perform: selector withArguments: argumentArray lookedUpIn: lookupClass
+ 	"Override to allow simulator to filter start-up items to avoid as-yet unsimulatable plugins."
+ 
+ 	(self filterPerformOf: selector to: actualReceiver) ifTrue:
+ 		[^self pop: argumentCount + 1 thenPush: actualReceiver].
+ 	^super primitiveObject: actualReceiver perform: selector withArguments: argumentArray lookedUpIn: lookupClass!

Item was changed:
  ----- Method: CogVMSimulator>>primitivePerform (in category 'debugging traps') -----
  primitivePerform
  	| selector |
  	selector := self stackValue: argumentCount - 1.
  	self sendBreak: selector + BaseHeaderSize
  		point: (objectMemory lengthOf: selector)
  		receiver: (self stackValue: argumentCount).
+ 	(self filterPerformOf: selector to: (self stackValue: argumentCount)) ifTrue:
+ 		[^self pop: argumentCount].
  	^super primitivePerform!

Item was added:
+ ----- Method: Cogit>>disassembleCachedOop: (in category 'simulation only') -----
+ disassembleCachedOop: address
+ 	<doNotGenerate>
+ 	| oopOrZero |
+ 	"Answer a disassembly string for an implicit receiver cache entry in a Newspeak send."
+ 	oopOrZero := objectMemory unalignedLongAt: address.
+ 	^(objectMemory addressCouldBeObj: oopOrZero)
+ 		ifTrue: [oopOrZero hex, ': ', (coInterpreter shortPrint: oopOrZero)]
+ 		ifFalse: [oopOrZero = 0 ifTrue: [oopOrZero printString] ifFalse: [oopOrZero hex]]!

Item was changed:
  ----- Method: Cogit>>disassembleCodeAt: (in category 'disassembly') -----
  disassembleCodeAt: pc
  	<doNotGenerate>
+ 	(pc between: (trampolineAddresses at: 1) and: methodZoneBase - 1) ifTrue:
- 	(pc between: (trampolineAddresses at: 1) and: methodZoneBase) ifTrue:
  		[^self disassembleTrampolineFor: pc].
  	self disassembleMethodFor: pc!

Item was changed:
  ----- Method: Cogit>>disassembleMethod:on: (in category 'disassembly') -----
  disassembleMethod: surrogateOrAddress on: aStream
  	<doNotGenerate>
  	| cogMethod mapEntries codeRanges |
  	cogMethod := surrogateOrAddress isInteger
  								ifTrue: [self cogMethodSurrogateAt: surrogateOrAddress]
  								ifFalse: [surrogateOrAddress].
  	cogMethod cmType = CMBlock ifTrue:
  		[^self disassembleMethod: cogMethod cmHomeMethod on: aStream].
  	self printMethodHeader: cogMethod on: aStream.
  
  	(mapEntries := Dictionary new)
  		at: cogMethod asInteger + cmEntryOffset put: 'entry'.
  	
  	cogMethod cmType = CMMethod ifTrue:
  		[mapEntries at: cogMethod asInteger + cmNoCheckEntryOffset put: 'noCheckEntry'.
  		self cppIf: NewspeakVM
  			ifTrue: [mapEntries at: cogMethod asInteger + dynSuperEntryAlignment put: 'dynSuperEntry']].
  
  	cogMethod cmType = CMClosedPIC ifTrue:
  		[mapEntries at: cogMethod asInteger + firstCPICCaseOffset put: 'ClosedPICCase0'.
  		 1 to: numPICCases - 1 do:
  			[:i|
  			mapEntries
  				at: cogMethod asInteger + firstCPICCaseOffset + (i * cPICCaseSize)
  				put: 'ClosedPICCase', i printString]].
  
  	self mapFor: cogMethod
  		performUntil: #collectMapEntry:address:into:
  		arg: mapEntries.
  
+ 	self cppIf: NewspeakVM
+ 		ifTrue:
+ 			[mapEntries keys do:
+ 				[:a|
+ 				(mapEntries at: a) = #IsNSSendCall ifTrue:
+ 					[mapEntries
+ 						at: a + backEnd jumpShortByteSize
+ 							put: {'Class'. #disassembleCachedOop:. BytesPerWord};
+ 						at: a + backEnd jumpShortByteSize + BytesPerOop
+ 							put: {'ImplicitReceiver'. #disassembleCachedOop:. BytesPerWord}]]].
+ 
  	"This would all be far more elegant and simple if we used blocks.
  	 But there are no blocks in C and the basic enumerators here need
  	 to be used in the real VM.  Apologies."
  	(codeRanges := self codeRangesFor: cogMethod) do:
  		[:range|
  		(cogMethod cmType = CMMethod) ifTrue:
  			[mapEntries keysAndValuesDo:
  				[:mcpc :label| | bcpc |
  				((range includes: mcpc)
  				 and: [#(IsSendCall HasBytecodePC) includes: label]) ifTrue:
  					[bcpc := self bytecodePCFor: mcpc startBcpc: range startpc in: range cogMethod.
  					 bcpc ~= 0 ifTrue:
  						[mapEntries at: mcpc put: label, ' bc ', bcpc printString, '/', (bcpc + 1) printString]]]].
  		(cogMethod blockEntryOffset ~= 0
  		 and: [range first = (cogMethod blockEntryOffset + cogMethod asInteger)])
  			ifTrue:
  				[aStream nextPutAll: 'blockEntry:'; cr.
  				 self blockDispatchFor: cogMethod
  					perform: #disassemble:from:to:arg:
  					arg: aStream]
  			ifFalse:
  				[range first > (cogMethod address + cmNoCheckEntryOffset) ifTrue:
  					[self printMethodHeader: range cogMethod
  						on: aStream].
  				self disassembleFrom: range first to: range last labels: mapEntries on: aStream]].
  	aStream nextPutAll: 'startpc: '; print: codeRanges first startpc; cr.
  	(cogMethod cmType = CMMethod
  	 or: [cogMethod cmType = CMOpenPIC]) ifTrue:
  		[[self mapFor: cogMethod
  			performUntil: #printMapEntry:mcpc:args:
  			arg: { aStream. codeRanges. cogMethod }]
  			on: AssertionFailure
  			do: [:ex|
  				ex primitiveChangeClassTo: ResumableVMError basicNew. ":) :) :)"
  				ex resume: nil]].
  	^cogMethod!

Item was added:
+ ----- Method: Cogit>>isAbsentReceiverSendAt:in: (in category 'simulation only') -----
+ isAbsentReceiverSendAt: mcpc in: cogHomeMethod
+ 	| prev this |
+ 	self mapFor: cogHomeMethod
+ 		do: [:a :m|
+ 			m < mcpc
+ 				ifTrue: [prev := a]
+ 				ifFalse: [m = mcpc ifTrue: [this := a]].
+ 			false].
+ 	^this = IsSendCall and: [prev = IsNSSendCall]!

Item was added:
+ ----- Method: DetailedInstructionPrinter>>stackHeightComputer (in category 'accessing') -----
+ stackHeightComputer
+ 	"Answer the value of stackHeightComputer"
+ 
+ 	^ stackHeightComputer!

Item was added:
+ ----- Method: DetailedInstructionPrinter>>stackHeightComputer: (in category 'accessing') -----
+ stackHeightComputer: anObject
+ 	"Set the value of stackHeightComputer"
+ 
+ 	stackHeightComputer := anObject!

Item was changed:
  ----- Method: InterpreterPrimitives>>primitiveIdentityHash (in category 'object access primitives') -----
  primitiveIdentityHash
  	| thisReceiver |
  	thisReceiver := self stackTop.
  	(objectMemory isIntegerObject: thisReceiver)
  		ifTrue: [self primitiveFail]
+ 		ifFalse: [self pop: argumentCount + 1
+ 					thenPushInteger: (objectMemory hashBitsOf: thisReceiver)]!
- 		ifFalse: [self pop:1 thenPushInteger: (objectMemory hashBitsOf: thisReceiver)]!

Item was changed:
  ----- Method: NewObjectMemory>>become:with:twoWay:copyHash: (in category 'become') -----
  become: array1 with: array2 twoWay: twoWayFlag copyHash: copyHashFlag
  	"All references to each object in array1 are swapped with all references to the corresponding object in array2. That is, all pointers to one object are replaced with with pointers to the other. The arguments must be arrays of the same length. 
  	Returns PrimNoErr if the primitive succeeds."
  	"Implementation: Uses forwarding blocks to update references as done in compaction."
  	| start |
  	self leakCheckBecome ifTrue:
  		[self runLeakCheckerForFullGC: true].
  	(self isArray: array1) ifFalse:
  		[^PrimErrBadReceiver].
  	((self isArray: array2)
  	 and: [(self lastPointerOf: array1) = (self lastPointerOf: array2)]) ifFalse:
  		[^PrimErrBadArgument].
+ 	(twoWayFlag or: [copyHashFlag])
- 	twoWayFlag
  		ifTrue: [(self containOnlyOops: array1 and: array2) ifFalse: [^PrimErrInappropriate]]
  		ifFalse: [(self containOnlyOops: array1) ifFalse: [^PrimErrInappropriate]].
  
  	(self prepareForwardingTableForBecoming: array1 with: array2 twoWay: twoWayFlag) ifFalse:
  		[^PrimErrNoMemory]. "fail; not enough space for forwarding table"
  
  	(self allYoung: array1 and: array2)
  		ifTrue: [start := youngStart"sweep only the young objects plus the roots"]
  		ifFalse: [start := self startOfMemory"sweep all objects"].
  	coInterpreter preBecomeAction.
  	self mapPointersInObjectsFrom: start to: endOfMemory.
  	twoWayFlag
  		ifTrue: [self restoreHeadersAfterBecoming: array1 with: array2]
  		ifFalse: [self restoreHeadersAfterForwardBecome: copyHashFlag].
  	coInterpreter postBecomeAction.
  
  	self initializeMemoryFirstFree: freeStart. "re-initialize memory used for forwarding table"
  	self leakCheckBecome ifTrue:
  		[self runLeakCheckerForFullGC: true].
  	self forceInterruptCheck. "pretty much guaranteed to take a long time, so check for timers etc ASAP"
  
  	^PrimNoErr "success"!

Item was added:
+ ----- Method: NewspeakStackDepthFinder>>sendToAbsentDynamicSuperclass:numArgs: (in category 'instruction decoding') -----
+ sendToAbsentDynamicSuperclass: selector numArgs: numArgs
+ 	"Dynamic Superclass Send Message With Selector, selector, to absent implicit receiver bytecode."
+ 	self drop: numArgs - 1 "e.g. if no args pushes a result"!

Item was changed:
  ----- Method: NewspeakStackDepthFinder>>sendToAbsentImplicitReceiver:numArgs: (in category 'instruction decoding') -----
  sendToAbsentImplicitReceiver: selector numArgs: numArgs
+ 	"Send Message With Selector, selector, to absent implicit receiver bytecode."
+ 	self drop: numArgs - 1 "e.g. if no args pushes a result"!
- 	"Send Message With Selector, selector, to dynamic superclass bytecode."
- 	self drop: numArgs - 1 "i.e. if 0 args, pushes a result"!

Item was changed:
  ----- Method: ObjectMemory>>allYoung:and: (in category 'become') -----
  allYoung: array1 and: array2 
  	"Return true if all the oops in both arrays, and the arrays 
  	themselves, are in the young object space."
  	| fieldOffset |
  	(self oop: array1 isLessThan: youngStart)
  		ifTrue: [^ false].
  	(self oop: array2 isLessThan: youngStart)
  		ifTrue: [^ false].
  	fieldOffset := self lastPointerOf: array1.
  	"same size as array2"
  	[fieldOffset >= BaseHeaderSize] whileTrue:
  		[(self oop: (self longAt: array1 + fieldOffset) isLessThan: youngStart)
  			ifTrue: [^ false].
+ 		((self oop: (self longAt: array2 + fieldOffset) isLessThan: youngStart)
+ 		 and: [self isNonIntegerObject: (self longAt: array2 + fieldOffset)])
- 		(self oop: (self longAt: array2 + fieldOffset) isLessThan: youngStart)
  			ifTrue: [^ false].
  		fieldOffset := fieldOffset - BytesPerWord].
  	^ true!

Item was added:
+ ----- Method: ObjectMemory>>freeObject: (in category 'become') -----
+ freeObject: obj
+ 	| objHeader objHeaderBytes objHeaderType objSize |
+ 	objHeader := self baseHeader: obj.
+ 	objHeaderType := objHeader bitAnd: TypeMask.
+ 	objHeaderBytes := headerTypeBytes at: objHeaderType.
+ 	(objHeaderType bitAnd: 1) = 1 "HeaderTypeClass or HeaderTypeShort"
+ 		ifTrue: [objSize := objHeader bitAnd: SizeMask]
+ 		ifFalse:
+ 			[objHeaderType = HeaderTypeFree
+ 				ifTrue: [^nil]. "already free"
+ 			objSize := (self sizeHeader: obj) bitAnd: LongSizeMask].
+ 	self assert: (objSize + objHeaderBytes bitAnd: AllButTypeMask) = (objSize + objHeaderBytes).
+ 	self longAt: obj - objHeaderBytes
+ 		put: ((objSize + objHeaderBytes) bitOr: HeaderTypeFree)!

Item was changed:
  ----- Method: ObjectMemory>>restoreHeadersAfterForwardBecome: (in category 'become') -----
+ restoreHeadersAfterForwardBecome: copyHashFlag
+ 	"Forward become leaves us with no original oops in the
+ 	 mutated object list, so we must enumerate the (four-word)
+ 	 forwarding blocks where we have stored backpointers."
- restoreHeadersAfterForwardBecome: copyHashFlag 
- 	"Forward become leaves us with no original oops in the 
- 	mutated object list, 
- 	so we must enumerate the (four-word) forwarding blocks 
- 	where we have stored backpointers."
  	"This loop start is copied from fwdTableInit:"
  	| oop1 fwdBlock oop2 hdr1 hdr2 |
  	fwdBlock := endOfMemory + BaseHeaderSize + 7 bitAnd: WordMask - 7.
  	self flag: #Dan.  "See flag comment in fwdTableInit: (dtl)"
  	fwdBlock := fwdBlock + (BytesPerWord*4).
  	"fwdBlockGet: did a pre-increment"
  	[self oop: fwdBlock isLessThanOrEqualTo: fwdTableNext
  	"fwdTableNext points to the last active block"]
+ 		whileTrue:
+ 			[oop1 := self longAt: fwdBlock + (BytesPerWord*2).
- 		whileTrue: [oop1 := self longAt: fwdBlock + (BytesPerWord*2).
  			"Backpointer to mutated object."
  			oop2 := self longAt: fwdBlock.
  			self restoreHeaderOf: oop1.
+ 			copyHashFlag ifTrue:
+ 				"Change the hash of the new oop (oop2) to be that of the old (oop1)
+ 				 so mutated objects in hash structures will be  happy after the change."
+ 				[hdr1 := self longAt: oop1.
+ 				 hdr2 := self longAt: oop2.
+ 				 self longAt: oop2 put: ((hdr2 bitAnd: AllButHashBits) bitOr: (hdr1 bitAnd: HashBits))].
+ 			"Free the old object so it won't resurface through e.g. alInstances or allObjects."
+ 			self freeObject: oop1.
- 			copyHashFlag
- 				ifTrue: ["Change the hash of the new oop (oop2) to be that of the old (oop1) 
- 					so mutated objects in hash structures will be 
- 					happy after the change."
- 					hdr1 := self longAt: oop1.
- 					hdr2 := self longAt: oop2.
- 					self longAt: oop2 put: ((hdr2 bitAnd: AllButHashBits) bitOr: (hdr1 bitAnd: HashBits))].
  			fwdBlock := fwdBlock + (BytesPerWord*4)]!

Item was changed:
  ----- Method: StackInterpreter>>detailedSymbolicMethod: (in category 'debug support') -----
  detailedSymbolicMethod: aMethod
  	<doNotGenerate>
+ 	| ts prim proxy |
- 	| ts prim |
  	(ts := self transcript) ensureCr.
  	(prim := self primitiveIndexOf: aMethod) > 0 ifTrue:
  		[ts nextPutAll: '<primitive: '; print: prim; nextPut: $>.
  		(self isQuickPrimitiveIndex: prim) ifTrue:
  			[ts nextPutAll: ' quick method'; cr; flush.
  			 ^self].
  		ts cr].
+ 	proxy := VMCompiledMethodProxy new
- 	(DetailedInstructionPrinter
- 			on: (VMCompiledMethodProxy new
  					for: aMethod
  					coInterpreter: self
+ 					objectMemory: objectMemory.
+ 	(DetailedInstructionPrinter on: proxy)
+ 		stackHeightComputer: ((NewspeakVM
+ 										ifTrue: [NewspeakStackDepthFinder]
+ 										ifFalse: [StackDepthFinder])
+ 									on: proxy);
- 					objectMemory: objectMemory))
  		indent: 0;
  		printInstructionsOn: ts.
  	ts flush!

Item was changed:
  ----- Method: StackInterpreter>>printCallStack (in category 'debug printing') -----
  printCallStack
  	<inline: false>
+ 	framePointer = nil
+ 		ifTrue: [self printCallStackOf: (objectMemory fetchPointer: SuspendedContextIndex ofObject: self activeProcess)]
+ 		ifFalse: [self printCallStackFP: framePointer]!
- 	self printCallStackFP: framePointer!

Item was changed:
  ----- Method: VMClass>>promptHex: (in category 'simulation support') -----
  promptHex: string
  	<doNotGenerate>
  	| s |
  	s := UIManager default request: string, ' (hex)'.
  	^s notEmpty ifTrue:
+ 		[(#('16r' '-16r' '0x' '-0x') detect: [:prefix| s beginsWith: prefix] ifNone: []) ifNotNil:
+ 			[:prefix|
+ 			s := s allButFirst: prefix size.
+ 			prefix first = $- ifTrue: [s := '-', s]].
- 		[(s size > 3 and: [s third = $r or: [s first = $- and: [s fourth = $r]]]) ifTrue:
- 			[s := (s first = $- ifTrue: ['-'] ifFalse: ['']), (s allButFirst: (s indexOf: $r))].
  		Integer readFrom: s readStream base: 16]!

Item was added:
+ ----- Method: VMCompiledMethodProxy>>numArgs (in category 'accessing') -----
+ numArgs
+ 	"Answer the argument count of the receiver."
+ 	
+ 	^coInterpreter argumentCountOf: oop!



More information about the Vm-dev mailing list