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

commits at source.squeak.org commits at source.squeak.org
Thu Jan 31 01:15:23 UTC 2013


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

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

Name: VMMaker.oscog-eem.261
Author: eem
Time: 30 January 2013, 5:12:32.411 pm
UUID: eeb310a3-23e0-41f6-8a92-5749b798e623
Ancestors: VMMaker.oscog-lw.260

Merge with VMMaker.oscog-lw.260, but put push of link register
where I think it should go in trampolines.

Move determination of the ammount of headroom to the platform in
osCogStackPageHeadroom (in the various sqFooMain.c files).

Provide a routine to monitor the ammount of unused headroom,
which requires the stack memory be zeroed before use.  Assume
the platform will provide a -reportheadroom flag for enabling the
report.  Provide primitiveMinimumUnusedHeadroom for in-image
access.

Add some asserts to check that a page's frame pointer is always
in range (setHeadFP:andSP:inPage: already did this).

Implement some missing prototypes in InterpreterProxy.  Add a
comment to preDeclareInterpreterProxyOn: to eyeball all prototypes.

=============== Diff against VMMaker.oscog-lw.260 ===============

Item was changed:
  ----- Method: CCodeGeneratorTests>>testIntegerGeneration (in category 'tests') -----
  testIntegerGeneration
  
  	"Test the 32-bit integers. They need to be marked as unsigned longs.
  	 Test 16rFFFFFFFF, 16rFFFFFFFE, ... through to ..., 16rC0000000, 16r80000000"
  	((0 to: 31) collect: [:shift| 16rFFFFFFFF bitClear: (1 bitShift: shift) - 1]) do:
  		[:number| | literal |
  		literal := self cg cLiteralFor: number.
  		self assert: ((literal allButLast: 2) allSatisfy: [:c| c isDigit]).
  		self assert: (literal endsWith: 'UL').
  
  		literal := self cg cLiteralFor: number name: 'Mask'.
  		self assert: (literal beginsWith: '0x').
  		self assert: (((literal allButFirst: 2) allButLast: 2) allSatisfy: [:c| '0123456789CEF' includes: c]).
  		self assert: (literal endsWith: 'UL')].
  
  	"Test the 64-bit integers. They need to be marked as unsigned long longs."
+ 	((32 to: 63) collect: [:shift| 16rFFFFFFFFFFFFFFFF bitClear: (1 bitShift: shift) - 1]) do:
- 	((32 to: 64) collect: [:shift| 16rFFFFFFFFFFFFFFFF bitClear: (1 bitShift: shift) - 1]) do:
  		[:number| | literal |
  		literal := self cg cLiteralFor: number.
  		self assert: ((literal allButLast: 3) allSatisfy: [:c| c isDigit]).
  		self assert: (literal endsWith: 'ULL').
  
  		literal := self cg cLiteralFor: number name: 'Mask'.
  		self assert: (literal beginsWith: '0x').
  		self assert: (((literal allButFirst: 2) allButLast: 3) allSatisfy: [:c| '0123456789CEF' includes: c]).
  		self assert: (literal endsWith: 'ULL')]!

Item was changed:
  ----- Method: CoInterpreter>>initStackPagesAndInterpret (in category 'initialization') -----
  initStackPagesAndInterpret
  	"Initialize the stack pages and enter interpret. Use alloca'ed memory so that when
  	 we have a JIT its stack pointer will be on the native stack since alloca allocates
  	 memory on the stack. Certain thread systems use the native stack pointer as the
  	 frame ID so putting the stack anywhere else can confuse the thread system."
  
  	"Override to establish the setjmp/longjmp handler for reentering the interpreter
  	 from machine code, and disable executablity on the heap and stack pages."
  
  	"This should be in its own initStackPages method but Slang can't inline
  	 C code strings."
  	| stackPageBytes stackPagesBytes theStackMemory |
  	<var: #theStackMemory type: #'char *'>
  	stackPageBytes := self stackPageByteSize.
  	stackPagesBytes := self computeStackZoneSize.
  	theStackMemory := self
  						cCode: [self alloca: stackPagesBytes]
  						inSmalltalk:
  							[stackPages := self stackPagesClass new.
  							 stackPages initializeWithByteSize: stackPagesBytes for: self].
+ 	self cCode: [self me: theStackMemory ms: 0 et: stackPagesBytes].
  	self sqMakeMemoryNotExecutableFrom: objectMemory startOfMemory asUnsignedInteger
  		To: objectMemory memoryLimit asUnsignedInteger.
  	self sqMakeMemoryNotExecutableFrom: theStackMemory asUnsignedInteger
  		To: theStackMemory asUnsignedInteger + stackPagesBytes.
  	stackPages
  		initializeStack: theStackMemory
  		numSlots: stackPagesBytes / BytesPerWord
  		pageSize: stackPageBytes / BytesPerWord.
+ 	self assert: self minimumUnusedHeadroom = stackPageBytes.
  
  	"Once the stack pages are initialized we can continue to bootstrap the system."
  	self loadInitialContext.
  	"We're ready for the heartbeat (poll interrupt)"
  	self ioInitHeartbeat.
  	self initialEnterSmalltalkExecutive.
  	^nil!

Item was changed:
  ----- Method: CoInterpreter>>interpretMethodFromMachineCode (in category 'message sending') -----
  interpretMethodFromMachineCode
  	"Execute a method interpretively from machine code.  We assume (require) that newMethod
  	 messageSelector, primitiveFunctionPointer and argumentCount have been set in the caller.
  	 Once evaluated either continue in the interpreter via a jongjmp or in machine code via an
  	 enilopmart (a form of longjmp - a stinking rose by any other name)."
  	<inline: false>
  	cogit assertCStackWellAligned.
  	self assert: (self validInstructionPointer: instructionPointer inFrame: framePointer).
  	primitiveFunctionPointer ~= 0
  		ifTrue:
  			[primitiveFunctionPointer = #primitiveInvokeObjectAsMethod
  				ifTrue: [self assert: (objectMemory isOopCompiledMethod: newMethod) not]
  				ifFalse: [self assert: ((objectMemory isOopCompiledMethod: newMethod)
  									  and: [(self primitiveIndexOf: newMethod) ~= 0])].
  			 "Invoke an interpreter primitive (because the method is to be interpreted or has not yet been
  			  compiled).  This is very similar to invoking an interpreter primitive from a compiled primitive
  			  (see e.g. SimpleStackBasedCogit>>compileInterpreterPrimitive:).  Cut back the stack pointer
  			  (done above) to skip the return address and invoke the function.  On return if it has succeeded
  			  simply continue otherwise restore the stackPointer, collect the pc and interpret.  Note that
  			  frame building primitives such as primitiveClosureValue, primitiveEvaluateMethod et al will not
  			  return but will instead jump into either machine code or longjmp back to the interpreter."
  			"Assign stackPage headFP so we can tell if the primitive built a frame.  We can't simply save
  			 the framePointer since e.g. assignment to contexts (via primitiveInstVarAt:put:) can change the
  			 framePointer.  But context assignments will change both the framePointer and stackPage headFP."
+ 			
+ 			 self assert: (framePointer < stackPage baseAddress
+ 						and: [framePointer > (stackPage realStackLimit - (LargeContextSize / 2))]).
  			 stackPage headFP: framePointer.
  			 self isPrimitiveFunctionPointerAnIndex
  				ifTrue:
  					[self externalQuickPrimitiveResponse.
  					 primFailCode := 0]
  				ifFalse:
  					[self slowPrimitiveResponse].
  			self successful ifTrue:
  				[self return: self popStack toExecutive: false
  				 "NOTREACHED"]]
  		ifFalse:
  			[self assert: ((objectMemory isOopCompiledMethod: newMethod)
  						   and: [(self primitiveIndexOf: newMethod) = 0
  								or: [(self functionPointerFor: (self primitiveIndexOf: newMethod) inClass: objectMemory nilObject) = 0
  								or: [self isNullExternalPrimitiveCall: newMethod]]])].
  	"if not primitive, or primitive failed, activate the method and reenter the interpreter"
  	self activateNewMethod.
  	self siglong: reenterInterpreter jmp: ReturnToInterpreter.
  	"NOTREACHED"
  	^nil!

Item was added:
+ ----- Method: CoInterpreter>>minimumUnusedHeadroom (in category 'debug support') -----
+ minimumUnusedHeadroom
+ 	"Traverse all stack pages looking for non-zero bytes in the headroom part of each page.
+ 	 Answer the minimum size of unused headroom (zero bytes) in the pages.  This is for
+ 	 checking that there is enough headroom allocated in stack pages."
+ 	| minUnused page |
+ 	<var: #page type: #'StackPage *'>
+ 	<var: #p type: #'char *'>
+ 	minUnused := (stackPages stackPageAt: 0) baseAddress - (stackPages stackPageAt: 0) lastAddress.
+ 	0 to: numStackPages - 1 do:
+ 		[:i| | p unused |
+ 		page := stackPages stackPageAt: i.
+ 		p := page lastAddress.
+ 		[p := p + BytesPerWord.
+ 		(self longAtPointer: p) = 0
+ 		 and: [p <= page baseAddress]] whileTrue.
+ 		unused := p - BytesPerWord - page lastAddress.
+ 		unused < minUnused ifTrue:
+ 			[minUnused := unused]].
+ 	^minUnused!

Item was changed:
  ----- Method: CoInterpreter>>moveFramesIn:through:toPage: (in category 'frame access') -----
  moveFramesIn: oldPage through: theFP toPage: newPage
  	"Move frames from the hot end of oldPage through to theFP to newPage.
  	 This has the effect of making theFP a base frame which can be stored into.
  	 Answer theFP's new location."
  	| newSP newFP stackedReceiverOffset delta callerFP callerIP fpInNewPage offsetCallerFP theContext |
  	<inline: false>
  	<var: #oldPage type: #'StackPage *'>
  	<var: #theFP type: #'char *'>
  	<var: #newPage type: #'StackPage *'>
  	<var: #newSP type: #'char *'>
  	<var: #newFP type: #'char *'>
  	<var: #callerFP type: #'char *'>
  	<var: #fpInNewPage type: #'char *'>
  	<var: #offsetCallerFP type: #'char *'>
  	<var: #source type: #'char *'>
  	<returnTypeC: #'char *'>
  	"A base frame must have a context for cannotReturn: processing."
  	self assert: (self isBaseFrame: theFP) not.
  	self assert: self validStackPageBaseFrames.
  	callerFP := self frameCallerFP: theFP.
  	self assert: (self frameHasContext: callerFP).
  	self assert: (self isContext: (self frameContext: callerFP)).
  	theContext := self ensureFrameIsMarried: theFP
  					SP: theFP + ((self isMachineCodeFrame: theFP) ifTrue: [FoxMFReceiver] ifFalse: [FoxIFReceiver]).
  	stackPages
  		longAt: (newSP := newPage baseAddress) put: (self frameContext: callerFP);
  		longAt: (newSP := newSP - BytesPerWord) put:  theContext.
  	stackedReceiverOffset := self frameStackedReceiverOffset: theFP.
  	"First move the data, leaving room for the caller and base frame contexts.  We will fix up frame pointers later."
  	theFP + stackedReceiverOffset
  		to: oldPage headSP
  		by: BytesPerWord negated
  		do: [:source|
  			newSP := newSP - BytesPerWord.
  			stackPages longAt: newSP put: (stackPages longAt: source)].
  	"newSP = oldSP + delta => delta = newSP - oldSP"
  	delta := newSP - oldPage headSP.
  	newFP := newPage baseAddress - stackedReceiverOffset - (2 * BytesPerWord).
  	self setHeadFP: oldPage headFP + delta andSP: newSP inPage: newPage.
  	newPage baseFP: newFP.
  	callerIP := self oopForPointer: (self frameCallerSavedIP: theFP).
  	callerIP asUnsignedInteger >= objectMemory startOfMemory ifTrue:
  		[self iframeSavedIP: callerFP put: callerIP.
  		 callerIP := cogit ceReturnToInterpreterPC].
  	stackPages longAt: theFP + stackedReceiverOffset put: callerIP.
+ 	self assert: (callerFP < oldPage baseAddress
+ 				and: [callerFP > (oldPage realStackLimit - (LargeContextSize / 2))]).
  	oldPage
  		headFP: callerFP;
  		headSP: theFP + stackedReceiverOffset.
  	"Mark the new base frame in the new page"
  	stackPages
  		longAt: newFP + FoxCallerSavedIP put: cogit ceBaseFrameReturnPC;
  		longAt: newFP + FoxSavedFP put: 0.
  	"Now relocate frame pointers, updating married contexts to refer to their moved spouse frames."
  	fpInNewPage := newPage headFP.
  	[offsetCallerFP := self frameCallerFP: fpInNewPage.
  	 offsetCallerFP ~= 0 ifTrue:
  		[offsetCallerFP := offsetCallerFP + delta].
  	 stackPages longAt: fpInNewPage + FoxSavedFP put: (self oopForPointer: offsetCallerFP).
  	 (self frameHasContext: fpInNewPage) ifTrue:
  		[theContext := self frameContext: fpInNewPage.
  		 objectMemory storePointerUnchecked: SenderIndex
  			ofObject: theContext
  			withValue: (self withSmallIntegerTags: fpInNewPage).
  		 objectMemory storePointerUnchecked: InstructionPointerIndex
  			ofObject: theContext
  			withValue: (self withSmallIntegerTags: offsetCallerFP)].
  	 fpInNewPage := offsetCallerFP.
  	 fpInNewPage ~= 0] whileTrue.
  	self assert: self validStackPageBaseFrames.
  	^newFP!

Item was added:
+ ----- Method: CoInterpreter>>reportMinimumUnusedHeadroom (in category 'debug support') -----
+ reportMinimumUnusedHeadroom
+ 	"Report the stack page size and minimum unused headroom to stdout."
+ 	<api>
+ 	self cCode:
+ 			[self prin: 'stack page size %ld minimum unused stack headroom %ld bytes\n'
+ 				t: self stackPageByteSize
+ 				f: self minimumUnusedHeadroom]
+ 		inSmalltalk:
+ 			[self print: 'stack page size '; printNum: self stackPageByteSize;
+ 				print: ' minimum unused stack headroom '; printNum: self minimumUnusedHeadroom;
+ 				print: ' bytes'; cr]!

Item was changed:
  ----- Method: CoInterpreter>>stackPageHeadroom (in category 'stack pages') -----
  stackPageHeadroom
  	"Return a minimum amount of headroom for each stack page (in bytes).
+ 	 In the interpreter we don't actually need any headroom.  In a JIT the stack
+ 	 has to have room for interrupt handlers which will run on the stack.
+ 	 Defer to the platform for this one."
+ 	<inline: true>
+ 	^self osCogStackPageHeadroom!
- 	 In a JIT the stack has to have room for interrupt handlers which will run on the
- 	 stack.  In the interpreter we don't actually need any headroom."
- 	^cogit stackPageHeadroomBytes + 1024!

Item was added:
+ ----- Method: CoInterpreterPrimitives>>primitiveMinimumUnusedHeadroom (in category 'other primitives') -----
+ primitiveMinimumUnusedHeadroom
+ 	<export: true>
+ 	self methodReturnValue: (self integerObjectOf: self minimumUnusedHeadroom)!

Item was added:
+ TestCase subclass: #CoInterpreterTests
+ 	instanceVariableNames: ''
+ 	classVariableNames: ''
+ 	poolDictionaries: 'VMBasicConstants'
+ 	category: 'VMMaker-Tests'!

Item was added:
+ ----- Method: CoInterpreterTests>>testMinimumUnusedHeadroom (in category 'tests') -----
+ testMinimumUnusedHeadroom
+ 	"self new testMinimumUnusedHeadroom"
+ 	| ci |
+ 	CoInterpreter initializeWithOptions: Dictionary new.
+ 	ci := CogVMSimulator new.
+ 	ci initStackPagesForTests.
+ 	self assert: ci minimumUnusedHeadroom = ci stackPageByteSize.
+ 	0 to: ci stackPageByteSize - 1 by: BytesPerWord do:
+ 		[:p|
+ 		0 to: ci numStackPages - 1 do:
+ 			[:i| | page |
+ 			page := ci stackPages stackPageAt: i.
+ 			ci longAt: page baseAddress - p put: 1].
+ 		self assert: ci minimumUnusedHeadroom = (ci stackPageByteSize - (p + BytesPerWord))]!

Item was added:
+ ----- Method: CogClass class>>minimumUnusedStackHeadroom (in category 'system primitives') -----
+ minimumUnusedStackHeadroom
+ 	"self minimumUnusedStackHeadroom"
+ 	<primitive: 'primitiveMinimumUnusedHeadroom'>
+ 	self primitiveFailed!

Item was added:
+ ----- Method: CogVMSimulator>>initStackPagesForTests (in category 'test support') -----
+ initStackPagesForTests
+ 	numStackPages := 8.
+ 	stackPages := self stackPagesClass new.
+ 	objectMemory allocateMemoryOfSize: 1024 * 1024.
+ 	cogCodeSize := 0.
+ 	heapBase := self methodCacheSize
+ 				+ self primTraceLogSize
+ 				+ self rumpCStackSize
+ 				+ self computeStackZoneSize.
+ 	self initStackPages!

Item was added:
+ ----- Method: CogVMSimulator>>numStackPages (in category 'test support') -----
+ numStackPages
+ 	^numStackPages!

Item was added:
+ ----- Method: CogVMSimulator>>osCogStackPageHeadroom (in category 'stack pages') -----
+ osCogStackPageHeadroom
+ 	"Notional headroom for the simulator.  The platform provides this in the real VM."
+ 	^1024!

Item was changed:
  ----- Method: Cogit>>compileTrampolineFor:callJumpBar:numArgs:arg:arg:arg:arg:saveRegs:resultReg: (in category 'initialization') -----
  compileTrampolineFor: aRoutine callJumpBar: callJumpBar "<Boolean>" numArgs: numArgs arg: regOrConst0 arg: regOrConst1 arg: regOrConst2 arg: regOrConst3 saveRegs: saveRegs resultReg: resultRegOrNil
  	"Generate a trampoline with up to four arguments.  Generate either a call or a jump to aRoutine
  	 as requested by callJumpBar.  If generating a call and resultRegOrNil is non-zero pass the C result
  	 back in resultRegOrNil.
  	 Hack: a negative value indicates an abstract register, a non-negative value indicates a constant."
  	<var: #aRoutine type: #'void *'>
  	<inline: false>
+ 	"If on a RISC processor the return address needs to be pushed to the
+ 	 stack so that the interpreter sees the same stack layout as on CISC."
+ 	backEnd hasLinkRegister ifTrue:
+ 		[self PushR: LinkReg].
  	self genSaveStackPointers.
  	self genLoadCStackPointers.
  	cStackAlignment > BytesPerWord ifTrue:
  		[backEnd
  			genAlignCStackSavingRegisters: saveRegs
  			numArgs: numArgs
  			wordAlignment: cStackAlignment / BytesPerWord].
  	saveRegs ifTrue:
  		[callJumpBar ifFalse:
  			[self error: 'why save registers when you''re not going to return?'].
  		 backEnd genSaveRegisters].
  	numArgs > 0 ifTrue:
  		[numArgs > 1 ifTrue:
  			[numArgs > 2 ifTrue:
  				[numArgs > 3 ifTrue:
  					[regOrConst3 < 0
  						ifTrue: [backEnd genPassReg: regOrConst3 asArgument: 3]
  						ifFalse: [backEnd genPassConst: regOrConst3 asArgument: 3]].
  				 regOrConst2 < 0
  					ifTrue: [backEnd genPassReg: regOrConst2 asArgument: 2]
  					ifFalse: [backEnd genPassConst: regOrConst2 asArgument: 2]].
  			regOrConst1 < 0
  				ifTrue: [backEnd genPassReg: regOrConst1 asArgument: 1]
  				ifFalse: [backEnd genPassConst: regOrConst1 asArgument: 1]].
  		regOrConst0 < 0
  			ifTrue: [backEnd genPassReg: regOrConst0 asArgument: 0]
  			ifFalse: [backEnd genPassConst: regOrConst0 asArgument: 0]].
- 	backEnd hasLinkRegister 
- 		ifTrue: [self gen: PushR operand: LinkReg].
  	self gen: (callJumpBar ifTrue: [Call] ifFalse: [Jump])
  		operand: (self cCode: [aRoutine asUnsignedInteger]
  					   inSmalltalk: [self simulatedTrampolineFor: aRoutine]).
  	callJumpBar ifTrue:
  		[resultRegOrNil ifNotNil:
  			[backEnd genWriteCResultIntoReg: resultRegOrNil].
  		 saveRegs ifTrue:
  			[numArgs > 0 ifTrue:
  				[backEnd genRemoveNArgsFromStack: numArgs].
  			resultRegOrNil
  				ifNotNil: [backEnd genRestoreRegsExcept: resultRegOrNil]
  				ifNil: [backEnd genRestoreRegs]].
  		self genLoadStackPointers.
+ 		backEnd hasLinkRegister ifTrue:
+ 			[self PopR: LinkReg].
  		self RetN: 0]!

Item was changed:
  ----- Method: Cogit>>genMethodAbortTrampoline (in category 'initialization') -----
  genMethodAbortTrampoline
  	"Generate the abort for a method.  This abort performs either a call of ceSICMiss:
  	 to handle a single-in-line cache miss or a call of ceStackOverflow: to handle a
  	 stack overflow.  It distinguishes the two by testing ResultReceiverReg.  If the
  	 register is zero then this is a stack-overflow because a) the receiver has already
  	 been pushed and so can be set to zero before calling the abort, and b) the
  	 receiver must always contain an object (and hence be non-zero) on SIC miss."
  	| jumpSICMiss |
  	<var: #jumpSICMiss type: #'AbstractInstruction *'>
  	opcodeIndex := 0.
  	self CmpCq: 0 R: ReceiverResultReg.
  	jumpSICMiss := self JumpNonZero: 0.
- 	backEnd hasLinkRegister 
- 		ifTrue: [self MoveR: LinkReg Mw: 0 r: SPReg]. "overwrite send ret address with ceMethodAbortTrampoline call ret address"
  	self compileTrampolineFor: #ceStackOverflow:
  		callJumpBar: true
  		numArgs: 1
  		arg: SendNumArgsReg
  		arg: nil
  		arg: nil
  		arg: nil
  		saveRegs: false
  		resultReg: nil.
  	jumpSICMiss jmpTarget: self Label.
- 	backEnd hasLinkRegister 
- 		ifTrue: [self PushR: LinkReg]. "push ret address for ceMethodAbortTrampoline call"
  	^self genTrampolineFor: #ceSICMiss:
  		called: 'ceMethodAbort'
  		callJumpBar: true
  		numArgs: 1
  		arg: ReceiverResultReg
  		arg: nil
  		arg: nil
  		arg: nil
  		saveRegs: false
  		resultReg: nil
  		appendOpcodes: true!

Item was removed:
- ----- Method: Cogit>>stackPageHeadroomBytes (in category 'jit - api') -----
- stackPageHeadroomBytes
- 	<api>
- 	"Delegate this to the processor..."
- 	^backEnd stackPageInterruptHeadroomBytes!

Item was added:
+ ----- Method: InterpreterProxy>>callbackEnter: (in category 'callback support') -----
+ callbackEnter: callbackID
+ 	"Re-enter the interpreter for executing a callback"
+ 	<var: #callbackID type: #'sqInt *'>
+ 	^self notYetImplementedError!

Item was added:
+ ----- Method: InterpreterProxy>>callbackLeave: (in category 'callback support') -----
+ callbackLeave: cbID
+ 	"Leave from a previous callback"
+ 	<var: #callbackID type: #'sqInt *'>
+ 	^self notYetImplementedError!

Item was changed:
  ----- Method: InterpreterProxy>>disownVM: (in category 'FFI support') -----
  disownVM: flags
+ 	^self notYetImplementedError!
- 	self error: 'not yet implemented in Smalltalk'!

Item was changed:
  ----- Method: InterpreterProxy>>getInterruptPending (in category 'other') -----
  getInterruptPending
+ 	^self notYetImplementedError!
- 	self error: 'not yet implemented in Smalltalk'!

Item was changed:
  ----- Method: InterpreterProxy>>getStackPointer (in category 'other') -----
  getStackPointer
  	<returnTypeC: #'sqInt *'>
+ 	^self notYetImplementedError!
- 	self error: 'not yet implemented in Smalltalk'!

Item was changed:
  ----- Method: InterpreterProxy>>isOopImmutable: (in category 'testing') -----
  isOopImmutable: anOop
  	<api>
+ 	^self notYetImplementedError!
- 	^self error: 'not yet implemented in Smalltalk'!

Item was changed:
  ----- Method: InterpreterProxy>>isOopMutable: (in category 'testing') -----
  isOopMutable: anOop
  	<api>
+ 	^self notYetImplementedError!
- 	^self error: 'not yet implemented in Smalltalk'!

Item was changed:
  ----- Method: InterpreterProxy>>isYoung: (in category 'FFI support') -----
  isYoung: anOop
+ 	^self notYetImplementedError!
- 	self error: 'not yet implemented in Smalltalk'!

Item was added:
+ ----- Method: InterpreterProxy>>notYetImplementedError (in category 'private') -----
+ notYetImplementedError
+ 	^self error: 'not yet implemented in Smalltalk'!

Item was changed:
  ----- Method: InterpreterProxy>>ownVM: (in category 'FFI support') -----
  ownVM: flags
+ 	^self notYetImplementedError!
- 	self error: 'not yet implemented in Smalltalk'!

Item was changed:
  ----- Method: InterpreterProxy>>setInterruptCheckChain: (in category 'other') -----
  setInterruptCheckChain: aFunction
  	<returnTypeC: 'void (*setInterruptCheckChain(void (*aFunction)(void)))()'>
  	<var: #aFunction declareC: 'void (*aFunction)()'>
+ 	^self notYetImplementedError!
- 	self error: 'not yet implemented in Smalltalk'!

Item was changed:
  ----- Method: InterpreterProxy>>signalNoResume: (in category 'callback support') -----
  signalNoResume: aSemaphore
+ 	^self notYetImplementedError!
- 	self error: 'not yet implemented in Smalltalk'!

Item was changed:
  ----- Method: StackInterpreter>>initStackPages (in category 'initialization') -----
  initStackPages
  	"Initialize the stackPages.  This version is only for simulation
  	 because Slang refuses to inline it, which makes the alloca invalid."
  	| stackPageBytes stackPagesBytes theStackMemory |
  	stackPageBytes := self stackPageByteSize.
  	stackPagesBytes := self computeStackZoneSize.
  	theStackMemory := self
  						cCode: [self alloca: stackPagesBytes]
  						inSmalltalk:
  							[stackPages := self stackPagesClass new.
  							 stackPages initializeWithByteSize: stackPagesBytes for: self].
+ 	self cCode: [self me: theStackMemory ms: 0 et: stackPagesBytes].
  	stackPages
  		initializeStack: theStackMemory
  		numSlots: stackPagesBytes / BytesPerWord
  		pageSize: stackPageBytes / BytesPerWord!

Item was changed:
  ----- Method: StackInterpreter>>initStackPagesAndInterpret (in category 'initialization') -----
  initStackPagesAndInterpret
  	"Initialize the stack pages and enter interpret. Use alloca'ed memory so that when
  	 we have a JIT its stack pointer will be on the native stack since alloca allocates
  	 memory on the stack. Certain thread systems use the native stack pointer as the
  	 frame ID so putting the stack anywhere else can confuse the thread system."
  
  	"This should be in its own initStackPages method but Slang can't inline
  	 C code strings."
  	| stackPageBytes stackPagesBytes theStackMemory |
  	<var: #theStackMemory type: #'void *'>
  	stackPageBytes := self stackPageByteSize.
  	stackPagesBytes := self computeStackZoneSize.
  	theStackMemory := self
  						cCode: [self alloca: stackPagesBytes]
  						inSmalltalk:
  							[stackPages := self stackPagesClass new.
  							 stackPages initializeWithByteSize: stackPagesBytes for: self].
+ 	self cCode: [self me: theStackMemory ms: 0 et: stackPagesBytes].
  	stackPages
  		initializeStack: theStackMemory
  		numSlots: stackPagesBytes / BytesPerWord
  		pageSize: stackPageBytes / BytesPerWord.
  
  	"Once the stack pages are initialized we can continue to bootstrap the system."
  	self loadInitialContext.
  	"We're ready for the heartbeat (poll interrupt)"
  	self ioInitHeartbeat.
  	self interpret.
  	^nil!

Item was changed:
  ----- Method: StackInterpreter>>moveFramesIn:through:toPage: (in category 'frame access') -----
  moveFramesIn: oldPage through: theFP toPage: newPage
  	"Move frames from the hot end of oldPage through to theFP to newPage.
  	 This has the effect of making theFP a base frame which can be stored into.
  	 Answer theFP's new location."
  	| newSP newFP stackedReceiverOffset delta callerFP callerIP fpInNewPage offsetCallerFP theContext |
  	<inline: false>
  	<var: #oldPage type: #'StackPage *'>
  	<var: #theFP type: #'char *'>
  	<var: #newPage type: #'StackPage *'>
  	<var: #newSP type: #'char *'>
  	<var: #newFP type: #'char *'>
  	<var: #callerFP type: #'char *'>
  	<var: #fpInNewPage type: #'char *'>
  	<var: #offsetCallerFP type: #'char *'>
  	<var: #source type: #'char *'>
  	<returnTypeC: 'char *'>
  	newSP := newPage baseAddress + BytesPerWord.
  	stackedReceiverOffset := self frameStackedReceiverOffset: theFP.
  	"First move the data.  We will fix up frame pointers later."
  	theFP + stackedReceiverOffset
  		to: oldPage headSP
  		by: BytesPerWord negated
  		do: [:source|
  			newSP := newSP - BytesPerWord.
  			stackPages longAt: newSP put: (stackPages longAt: source)].
  	"newSP = oldSP + delta => delta = newSP - oldSP"
  	delta := newSP - oldPage headSP.
  	newFP := newPage baseAddress - stackedReceiverOffset.
  	self setHeadFP: oldPage headFP + delta andSP: newSP inPage: newPage.
  	newPage baseFP: newFP.
  	callerFP := self frameCallerFP: theFP.
  	self assert: (self isBaseFrame: theFP) not.
  	self assert: (self frameHasContext: callerFP).
  	callerIP := self oopForPointer: (self frameCallerSavedIP: theFP).
  	stackPages longAt: theFP + stackedReceiverOffset put: callerIP.
+ 	self assert: (callerFP < oldPage baseAddress
+ 				and: [callerFP > (oldPage realStackLimit - (LargeContextSize / 2))]).
  	oldPage
  		headFP: callerFP;
  		headSP: theFP + stackedReceiverOffset.
  	"Mark the new base frame in the new page (FoxCallerContext a.k.a. FoxCallerSavedIP)"
  	stackPages longAt: newFP + FoxCallerContext put:  (self frameContext: callerFP).
  	stackPages longAt: newFP + FoxSavedFP put: 0.
  	"Now relocate frame pointers, updating married contexts to refer to their moved spouse frames."
  	fpInNewPage := newPage headFP.
  	[offsetCallerFP := self frameCallerFP: fpInNewPage.
  	 offsetCallerFP ~= 0 ifTrue:
  		[offsetCallerFP := offsetCallerFP + delta].
  	 stackPages longAt: fpInNewPage + FoxSavedFP put: (self oopForPointer: offsetCallerFP).
  	 (self frameHasContext: fpInNewPage) ifTrue:
  		[theContext := self frameContext: fpInNewPage.
  		 objectMemory storePointerUnchecked: SenderIndex
  			ofObject: theContext
  			withValue: (self withSmallIntegerTags: fpInNewPage).
  		 objectMemory storePointerUnchecked: InstructionPointerIndex
  			ofObject: theContext
  			withValue: (self withSmallIntegerTags: offsetCallerFP)].
  	 fpInNewPage := offsetCallerFP.
  	 fpInNewPage ~= 0] whileTrue.
  	^newFP!

Item was changed:
  ----- Method: VMPluginCodeGenerator>>preDeclareInterpreterProxyOn: (in category 'C code generator') -----
  preDeclareInterpreterProxyOn: aStream
  	"Put the necessary #defines needed before interpreterProxy.  Basically
  	 internal plugins use the VM's interpreterProxy variable and external plugins
  	 use their own.  Override to keep local copies of all functions in external
  	 prims, and link directly in internal plugins."
+ 	"| pcc |
+ 	pcc := self new.
+ 	(InterpreterProxy selectors reject: [:s| #(initialize private) includes: (InterpreterProxy whichCategoryIncludesSelector: s)]) do:
+ 		[:s| pcc noteUsedPluginFunction: s].
+ 	pcc preDeclareInterpreterProxyOn: Transcript.
+ 	Transcript flush"
  	| pluginsToClone |
  	(pluginsToClone := self pluginFunctionsToClone) isEmpty ifTrue:
  		[^super preDeclareInterpreterProxyOn: aStream].
  	aStream cr; nextPutAll: '#if !!defined(SQUEAK_BUILTIN_PLUGIN)'; cr.
  	pluginsToClone do:
  		[:selector| | functionName |
  		functionName := self cFunctionNameFor: selector.
  		aStream nextPutAll:
  			((String streamContents:
  				[:s|
  				(self compileToTMethodSelector: selector in: InterpreterProxy)
  					emitCFunctionPrototype: s generator: self])
  				copyReplaceAll: functionName
  				with: '(*', functionName, ')').
  		aStream nextPut: $;; cr].
  	aStream nextPutAll: '#else /* !!defined(SQUEAK_BUILTIN_PLUGIN) */'; cr.
  	pluginsToClone do:
  		[:selector|
  		aStream nextPutAll: 'extern '.
  		(self compileToTMethodSelector: selector in: InterpreterProxy)
  			static: false;
  			emitCFunctionPrototype: aStream generator: self.
  		aStream nextPut: $;; cr].
  	aStream cr; nextPutAll: 'extern'.
  	aStream cr; nextPutAll: '#endif'; cr!



More information about the Vm-dev mailing list