Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2863.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.2863
Author: eem
Time: 29 October 2020, 6:11:02.270516 pm
UUID: b8007876-9c01-49e1-90da-6b2059369a5c
Ancestors: VMMaker.oscog-eem.2862
Cogit: Make sure stackLimit is the first clustered variable, ticky because it has a pseudonym.
Implement flag setting in compare-and-swaps that do so (X64).
Correct the range of valid pcs in simulateLeafCallOf:.
Remember to pass the argument to ceTryLockVMOwner.
Simplify the FakeStdinStream crap, providing line-oriented input.
=============== Diff against VMMaker.oscog-eem.2862 ===============
Item was changed:
----- Method: CoInterpreter class>>clusteredVariableNames (in category 'translation') -----
clusteredVariableNames
"Insist that these variables are present early in the list of variables, and in this order,
so that e.g. they are conveniently accessed via the VarBaseReg if it is available."
+ ^#(stackLimitFromMachineCode "ensures zero offset in simulation" stackLimit "stackLimit is e.g. lowest using the clang toolchain on MacOS X"
+ stackPointer framePointer CStackPointer CFramePointer CReturnAddress
+ scavengeThreshold freeStart needGCFlag specialObjectsOop
- ^#(stackPointer framePointer CStackPointer CFramePointer CReturnAddress
- stackLimit scavengeThreshold freeStart needGCFlag specialObjectsOop
primFailCode newMethod instructionPointer argumentCount nextProfileTick
nativeSP nativeStackPointer shadowCallStackPointer)!
Item was changed:
----- Method: CoInterpreterMT>>ownVM: (in category 'vm scheduling') -----
ownVM: threadIndexAndFlags
<api>
<inline: false>
"This is the entry-point for plugins and primitives that wish to reacquire the VM after having
released it via disownVM or callbacks that want to acquire it without knowing their ownership
status. This call will block until the VM is owned by the current thread or an error occurs.
The argument should be the value answered by disownVM, or 0 for callbacks that don't know
if they have disowned or not. This is both an optimization to avoid having to query thread-
local storage for the current thread's index (since it can easily keep it in some local variable),
and a record of when an unbound process becomes affined to a thread for the dynamic
extent of some operation.
Answer 0 if the current thread is known to the VM.
Answer 1 if the current thread is unknown to the VM and takes ownership.
Answer -1 if the current thread is unknown to the VM and fails to take ownership."
| threadIndex flags vmThread myProc activeProc sched |
<var: #vmThread type: #'CogVMThread *'>
threadIndexAndFlags = 0 ifTrue:
[^self ownVMFromUnidentifiedThread].
threadIndex := threadIndexAndFlags bitAnd: ThreadIdMask.
flags := threadIndexAndFlags >> DisownFlagsShift.
(flags anyMask: DisownVMForProcessorRelinquish) ifTrue:
[relinquishing := false.
self sqLowLevelMFence].
(threadIndexAndFlags anyMask: LockGUIThreadFlag) ifTrue:
[self assert: (noThreadingOfGUIThread and: [self inGUIThread]).
self assert: disowningVMThread = nil.
(flags anyMask: DisownVMLockOutFullGC) ifTrue:
[objectMemory decrementFullGCLock].
cogit recordEventTrace ifTrue:
[self recordTrace: TraceOwnVM thing: ConstZero source: 0].
^0].
vmThread := cogThreadManager acquireVMFor: threadIndex.
disownCount := disownCount - 1.
(flags anyMask: DisownVMLockOutFullGC) ifTrue:
[objectMemory decrementFullGCLock].
+ disowningVMThread ifNotNil:
- disowningVMThread notNil ifTrue:
[vmThread = disowningVMThread ifTrue:
[self cCode: ''
inSmalltalk:
[| range |
range := self cStackRangeForThreadIndex: threadIndex.
self assert: (range includes: CStackPointer).
self assert: (range includes: CFramePointer)].
self assert: self successful.
self assert: (objectMemory fetchPointer: MyListIndex ofObject: self activeProcess) = objectMemory nilObject.
disowningVMThread := nil.
cogit recordEventTrace ifTrue:
[self recordTrace: TraceOwnVM thing: ConstOne source: 0].
^0]. "if not preempted we're done."
self preemptDisowningThread].
"We've been preempted; we must restore state and update the threadId
in our process, and may have to put the active process to sleep."
sched := self schedulerPointer.
activeProc := objectMemory fetchPointer: ActiveProcessIndex ofObject: sched.
(threadIndexAndFlags anyMask: OwnVMForeignThreadFlag)
ifTrue:
[self assert: foreignCallbackProcessSlot == ForeignCallbackProcess.
myProc := objectMemory splObj: foreignCallbackProcessSlot.
self assert: myProc ~= objectMemory nilObject.
objectMemory splObj: foreignCallbackProcessSlot put: objectMemory nilObject]
ifFalse: [myProc := cogThreadManager popAWOLProcess: vmThread].
self assert: activeProc ~= myProc.
(activeProc ~= objectMemory nilObject
and: [(objectMemory fetchPointer: MyListIndex ofObject: activeProc) = objectMemory nilObject]) ifTrue:
[self putToSleep: activeProc yieldingIf: preemptionYields].
self assert: (objectMemory fetchPointer: MyListIndex ofObject: myProc) = (objectMemory splObj: ProcessInExternalCodeTag).
objectMemory
storePointer: ActiveProcessIndex ofObject: sched withValue: myProc;
storePointerUnchecked: MyListIndex ofObject: myProc withValue: objectMemory nilObject.
"Only unaffine if the process was affined at this level and did not become bound in the interim."
((threadIndexAndFlags anyMask: ProcessUnaffinedOnDisown)
and: [(self isBoundProcess: myProc) not]) ifTrue:
[self setOwnerIndexOfProcess: myProc to: 0 bind: false].
self initPrimCall.
self externalSetStackPageAndPointersForSuspendedContextOfProcess: myProc.
"If this primitive is called from machine code maintain the invariant that the return pc
of an interpreter callee calling a machine code caller is ceReturnToInterpreterPC."
(vmThread inMachineCode
and: [instructionPointer >= objectMemory startOfMemory]) ifTrue:
[self iframeSavedIP: framePointer put: instructionPointer.
instructionPointer := cogit ceReturnToInterpreterPC].
newMethod := vmThread newMethodOrNull.
argumentCount := vmThread argumentCount.
vmThread newMethodOrNull: nil.
self cCode: ''
inSmalltalk:
[| range |
range := self cStackRangeForThreadIndex: threadIndex.
self assert: (range includes: vmThread cStackPointer).
self assert: (range includes: vmThread cFramePointer)].
self setCFramePointer: vmThread cFramePointer setCStackPointer: vmThread cStackPointer.
self assert: newMethod ~~ nil.
cogit recordEventTrace ifTrue:
[self recordTrace: TraceOwnVM thing: ConstTwo source: 0].
^threadIndexAndFlags bitAnd: OwnVMForeignThreadFlag!
Item was changed:
----- Method: CogThreadManager>>acquireVMFor: (in category 'public api') -----
acquireVMFor: threadIndex
"Attempt to acquire the VM, eventually blocking until it becomes available.
Spin until the maxWaitingPriority has been updated if it is lower than this thread's priority."
<returnTypeC: #'CogVMThread *'>
| vmThread |
<var: #vmThread type: #'CogVMThread *'>
self assert: threadIndex = self ioGetThreadLocalThreadIndex.
vmThread := self vmThreadAt: threadIndex.
self assert: (vmThread state = CTMUnavailable
or: [vmThread state = CTMWantingOwnership]).
(cogit tryLockVMOwner: threadIndex) ifFalse:
[vmThread state: CTMWantingOwnership.
+ [cogit tryLockVMOwner: threadIndex] whileFalse:
- [cogit tryLockVMToIndex: threadIndex] whileFalse:
[[coInterpreter getMaxWaitingPriority < vmThread priority] whileTrue:
[coInterpreter waitingPriorityIsAtLeast: vmThread priority].
vmOwner ~= threadIndex ifTrue:
[self ioWaitOnOSSemaphore: (self addressOf: vmThread osSemaphore)]]].
vmOSThread := vmThread osThread.
vmThread state: CTMAssignableOrInVM.
^vmThread!
Item was changed:
----- Method: CogThreadManager>>vmOwnerFromMachineCode (in category 'simulation') -----
vmOwnerFromMachineCode
+ <doNotGenerate>
^vmOwner!
Item was changed:
----- Method: CogThreadManager>>vmOwnerFromMachineCode: (in category 'simulation') -----
vmOwnerFromMachineCode: aValue
+ <doNotGenerate>
+ self assert: (aValue between: 0 and: numThreads).
vmOwner := aValue!
Item was changed:
----- Method: Cogit>>handleCompareAndSwapSimulationTrap: (in category 'simulation only') -----
handleCompareAndSwapSimulationTrap: aCompareAndSwapSimulationTrap
| variableValue accessor |
variableValue := (simulatedVariableGetters
at: aCompareAndSwapSimulationTrap address
ifAbsent: [self errorProcessingSimulationTrap: aCompareAndSwapSimulationTrap
in: simulatedVariableGetters])
value asInteger.
variableValue = aCompareAndSwapSimulationTrap expectedValue ifTrue:
[(simulatedVariableSetters
at: aCompareAndSwapSimulationTrap address
ifAbsent: [self errorProcessingSimulationTrap: aCompareAndSwapSimulationTrap
in: simulatedVariableSetters]) value: aCompareAndSwapSimulationTrap storedValue].
+ processor setFlagsForCompareAndSwap: variableValue = aCompareAndSwapSimulationTrap expectedValue.
accessor := aCompareAndSwapSimulationTrap registerAccessor.
processor
perform: accessor
with: (processor convertIntegerToInternal: variableValue).
processor pc: aCompareAndSwapSimulationTrap nextpc.
aCompareAndSwapSimulationTrap resume: processor!
Item was changed:
----- Method: Cogit>>simulateLeafCallOf: (in category 'simulation only') -----
simulateLeafCallOf: someFunction
"Simulate execution of machine code that leaf-calls someFunction,
answering the result returned by someFunction."
"CogProcessorAlienInspector openFor: coInterpreter"
<doNotGenerate>
| priorSP priorPC priorLR spOnEntry bogusRetPC |
self recordRegisters.
priorSP := processor sp.
priorPC := processor pc.
priorLR := backEnd hasLinkRegister ifTrue: [processor lr].
processor
setFramePointer: coInterpreter getCFramePointer stackPointer: coInterpreter getCStackPointer;
simulateLeafCallOf: someFunction
nextpc: (bogusRetPC := 16rBADF00D5 roundTo: backEnd codeGranularity)
memory: coInterpreter memory.
spOnEntry := processor sp.
self recordInstruction: {'(simulated call of '. someFunction. ')'}.
+ ^[[processor pc between: self class guardPageSize and: methodZone zoneEnd] whileTrue:
- ^[[processor pc between: 0 and: methodZone zoneEnd] whileTrue:
[[singleStep
ifTrue: [self recordProcessing.
self maybeBreakAt: processor pc.
processor
singleStepIn: coInterpreter memory
minimumAddress: guardPageSize
readOnlyBelow: methodZone zoneEnd]
ifFalse: [processor
runInMemory: coInterpreter memory
minimumAddress: guardPageSize
readOnlyBelow: methodZone zoneEnd]]
on: ProcessorSimulationTrap, Error
do: [:ex|
"Again this is a hack for the processor simulators not properly simulating returns to bogus addresses.
In this case BochsX64Alien doesn't do the right thing."
processor pc = bogusRetPC ifTrue:
[self recordInstruction: {'(simulated (real) return to '. processor pc. ')'}.
^processor cResultRegister].
ex isProcessorSimulationTrap ifFalse:
[ex pass].
ex applyTo: self.
ex type == #return ifTrue:
[^processor cResultRegister]]].
processor pc = bogusRetPC ifTrue:
[self recordInstruction: {'(simulated (real) return to '. processor pc. ')'}].
processor cResultRegister]
ensure:
[processor sp: priorSP.
processor pc: priorPC.
priorLR ifNotNil: [:lr| processor lr: lr]]!
Item was changed:
----- Method: Cogit>>tryLockVMOwner: (in category 'multi-threading') -----
tryLockVMOwner: value
<api>
"ceTryLockVMOwner does an atomic compare-and-swap of the lock
with the argument and zero, setting the lock to value if it was zero.
It answers non-zero if the lock was zero."
<cmacro: '(value) ceTryLockVMOwner(value)'>
+ processor abiMarshallArg0: value.
^(self simulateLeafCallOf: ceTryLockVMOwner) ~= 0!
Item was added:
+ ----- Method: FakeStdinStream>>sqFile:Read:Into:At: (in category 'accessing') -----
+ sqFile: file Read: count Into: byteArrayIndexArg At: startIndex
+ "Simulate the read primitive by answering a line of input"
+ | inputLine n |
+ position >= readLimit ifTrue:
+ [simulator isThreadedVM ifTrue:
+ [simulator forceInterruptCheckFromHeartbeat].
+ inputLine := FillInTheBlankMorph
+ request: 'Input please!!'
+ initialAnswer: ''
+ centerAt: ActiveHand cursorPoint
+ inWorld: ActiveWorld
+ onCancelReturn: nil
+ acceptOnCR: true.
+ inputLine ifNil: [self atEnd: true. ^0].
+ collection size <= inputLine size ifTrue:
+ [collection := collection species new: inputLine size + 1].
+ collection
+ replaceFrom: 1 to: inputLine size with: inputLine startingAt: 1;
+ at: (readLimit := inputLine size + 1) put: Character lf.
+ position := 0].
+ n := count min: readLimit - position.
+ simulator
+ strncpy: byteArrayIndexArg + startIndex
+ _: (collection copyFrom: position + 1 to: position + n)
+ _: n.
+ position := position + n.
+ ^n!
Item was changed:
----- Method: FilePluginSimulator>>sqFile:Read:Into:At: (in category 'simulation') -----
+ sqFile: file Read: count Into: byteArrayIndexArg At: startIndex
+ | byteArrayIndex |
+ file isFakeStdinStream ifTrue:
+ [^file sqFile: file Read: count Into: byteArrayIndexArg At: startIndex].
- sqFile: file Read: countArg Into: byteArrayIndexArg At: startIndex
- | byteArrayIndex count |
- count := file isFakeStdinStream
- ifTrue: [1]
- ifFalse: [countArg].
byteArrayIndex := byteArrayIndexArg asInteger. "Coerces CArray et al correctly"
[[startIndex to: startIndex + count - 1 do:
[ :i |
+ interpreterProxy byteAt: byteArrayIndex + i put: (file next ifNil: [^i - startIndex] ifNotNil: [:charOrByte| charOrByte asInteger])]]
- file atEnd ifTrue: [^i - startIndex].
- interpreterProxy
- byteAt: byteArrayIndex + i
- put: (file next ifNil: [file isFakeStdinStream ifTrue: [^0]] ifNotNil: [:c| c asInteger])]]
on: Error
do: [:ex|
(file isStream and: [file isTranscriptStream]) ifFalse:
[ex pass].
^0]]
ensure: [self recordStateOf: file].
^count!
Branch: refs/heads/Cog
Home: https://github.com/OpenSmalltalk/opensmalltalk-vm
Commit: f027c5ce8940e88b9d02db8b7c5c0c2bbec456e8
https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/f027c5ce8940e88b9d…
Author: Eliot Miranda <eliot.miranda(a)gmail.com>
Date: 2020-10-29 (Thu, 29 Oct 2020)
Changed paths:
M src/plugins/UnixOSProcessPlugin/UnixOSProcessPlugin.c
Log Message:
-----------
UnixOSProcessPlugin as per VMConstruction-Plugins-OSProcessPlugin.oscog-eem.71
Get the UnixOSProcessPlugin to simulate correctly environmentAtAsType:,
the innards of primitiveEnvironmentAt[AsBytes]
Eliot Miranda uploaded a new version of VMConstruction-Plugins-OSProcessPlugin to project OSProcessPlugin:
http://www.squeaksource.com/OSProcessPlugin/VMConstruction-Plugins-OSProces…
==================== Summary ====================
Name: VMConstruction-Plugins-OSProcessPlugin.oscog-eem.71
Author: eem
Time: 29 October 2020, 3:42:55.794304 pm
UUID: f543fca0-f9e8-49e3-9ab3-d7839df6378a
Ancestors: VMConstruction-Plugins-OSProcessPlugin.oscog-eem.70
Fix a slip in the last commit.
Branch: refs/heads/Cog
Home: https://github.com/OpenSmalltalk/opensmalltalk-vm
Commit: c14b7173411680b35353844aa619d0b091d10e13
https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/c14b7173411680b353…
Author: Eliot Miranda <eliot.miranda(a)gmail.com>
Date: 2020-10-29 (Thu, 29 Oct 2020)
Changed paths:
M build.macos64x64/bochsx64/exploration/Makefile
M nsspur64src/vm/cogit.h
M nsspur64src/vm/cogitARMv8.c
M nsspur64src/vm/cogitX64SysV.c
M nsspur64src/vm/cogitX64WIN64.c
M nsspur64src/vm/cointerp.c
M nsspur64src/vm/cointerp.h
M nsspur64src/vm/gcc3x-cointerp.c
M nsspur64src/vm/vmCallback.h
M nsspursrc/vm/cogit.h
M nsspursrc/vm/cogitARMv5.c
M nsspursrc/vm/cogitIA32.c
M nsspursrc/vm/cogitMIPSEL.c
M nsspursrc/vm/cointerp.c
M nsspursrc/vm/cointerp.h
M nsspursrc/vm/gcc3x-cointerp.c
M nsspursrc/vm/vmCallback.h
M nsspurstack64src/vm/gcc3x-interp.c
M nsspurstack64src/vm/interp.c
M nsspurstack64src/vm/vmCallback.h
M nsspurstacksrc/vm/gcc3x-interp.c
M nsspurstacksrc/vm/interp.c
M nsspurstacksrc/vm/vmCallback.h
M platforms/iOS/vm/OSX/sqPlatformSpecific.h
M processors/IA32/bochs/explorationx64/printcpu.c
M processors/IA32/bochs/explorationx64/printcpucr.c
M processors/IA32/bochs/explorationx64/printcpuxmm.c
M scripts/gitrevert
M spur64src/vm/cogit.h
M spur64src/vm/cogitARMv8.c
M spur64src/vm/cogitX64SysV.c
M spur64src/vm/cogitX64WIN64.c
M spur64src/vm/cointerp.c
M spur64src/vm/cointerp.h
M spur64src/vm/cointerpmt.c
M spur64src/vm/cointerpmt.h
M spur64src/vm/gcc3x-cointerp.c
M spur64src/vm/gcc3x-cointerpmt.c
M spur64src/vm/vmCallback.h
M spurlowcode64src/vm/cogit.h
M spurlowcode64src/vm/cogitARMv8.c
M spurlowcode64src/vm/cogitX64SysV.c
M spurlowcode64src/vm/cogitX64WIN64.c
M spurlowcode64src/vm/cointerp.c
M spurlowcode64src/vm/cointerp.h
M spurlowcode64src/vm/gcc3x-cointerp.c
M spurlowcode64src/vm/vmCallback.h
M spurlowcodesrc/vm/cogit.h
M spurlowcodesrc/vm/cogitARMv5.c
M spurlowcodesrc/vm/cogitIA32.c
M spurlowcodesrc/vm/cogitMIPSEL.c
M spurlowcodesrc/vm/cointerp.c
M spurlowcodesrc/vm/cointerp.h
M spurlowcodesrc/vm/gcc3x-cointerp.c
M spurlowcodesrc/vm/vmCallback.h
M spurlowcodestack64src/vm/gcc3x-interp.c
M spurlowcodestack64src/vm/interp.c
M spurlowcodestack64src/vm/vmCallback.h
M spurlowcodestacksrc/vm/gcc3x-interp.c
M spurlowcodestacksrc/vm/interp.c
M spurlowcodestacksrc/vm/vmCallback.h
M spursista64src/vm/cogit.h
M spursista64src/vm/cogitARMv8.c
M spursista64src/vm/cogitX64SysV.c
M spursista64src/vm/cogitX64WIN64.c
M spursista64src/vm/cointerp.c
M spursista64src/vm/cointerp.h
M spursista64src/vm/gcc3x-cointerp.c
M spursista64src/vm/vmCallback.h
M spursistasrc/vm/cogit.h
M spursistasrc/vm/cogitARMv5.c
M spursistasrc/vm/cogitIA32.c
M spursistasrc/vm/cogitMIPSEL.c
M spursistasrc/vm/cointerp.c
M spursistasrc/vm/cointerp.h
M spursistasrc/vm/gcc3x-cointerp.c
M spursistasrc/vm/vmCallback.h
M spursrc/vm/cogit.h
M spursrc/vm/cogitARMv5.c
M spursrc/vm/cogitIA32.c
M spursrc/vm/cogitMIPSEL.c
M spursrc/vm/cointerp.c
M spursrc/vm/cointerp.h
M spursrc/vm/cointerpmt.c
M spursrc/vm/cointerpmt.h
M spursrc/vm/gcc3x-cointerp.c
M spursrc/vm/gcc3x-cointerpmt.c
M spursrc/vm/vmCallback.h
M spurstack64src/vm/gcc3x-interp.c
M spurstack64src/vm/interp.c
M spurstack64src/vm/validImage.c
M spurstack64src/vm/vmCallback.h
M spurstacksrc/vm/gcc3x-interp.c
M spurstacksrc/vm/interp.c
M spurstacksrc/vm/validImage.c
M spurstacksrc/vm/vmCallback.h
M src/plugins/B2DPlugin/B2DPlugin.c
M src/plugins/FilePlugin/FilePlugin.c
M src/plugins/SocketPlugin/SocketPlugin.c
M src/plugins/SqueakFFIPrims/ARM32FFIPlugin.c
M src/plugins/SqueakFFIPrims/ARM64FFIPlugin.c
M src/plugins/SqueakFFIPrims/IA32FFIPlugin.c
M src/plugins/SqueakFFIPrims/X64SysVFFIPlugin.c
M src/plugins/SqueakFFIPrims/X64Win64FFIPlugin.c
M src/plugins/UnixOSProcessPlugin/UnixOSProcessPlugin.c
M src/vm/cogit.h
M src/vm/cogitARMv5.c
M src/vm/cogitIA32.c
M src/vm/cogitMIPSEL.c
M src/vm/cointerp.c
M src/vm/cointerp.h
M src/vm/cointerpmt.c
M src/vm/cointerpmt.h
M src/vm/gcc3x-cointerp.c
M src/vm/gcc3x-cointerpmt.c
M src/vm/vmCallback.h
M stacksrc/vm/gcc3x-interp.c
M stacksrc/vm/interp.c
M stacksrc/vm/vmCallback.h
Log Message:
-----------
CogVM source as per Name: VMMaker.oscog-eem.2862
Cogit: Revise deriving the varBaseAddress after finding on MacOS that the linker
may not "follow orders". So take the minimum of several likely addresses,
secretly hoping the minimum is something like stackLimit, which likely has the
highest dynamic frequency (well done clang).
Eliminate ceEnterInterpreterOnReturnFromCogCode and have the
ceReturnToInterpreterTrampoline invoke interpret directly, using the same code
as ceInvokeInterpret. Do this by moving the setMethod: send into interpret
from senders; setMethod: is key because it sets the bytecodeSetSelector to
enable multiple bytecode set support, but machine code is (and should remain)
ignorant of the details of bytecode set selection in compiled method headers.
cogitARMv8.c Add __ARM_ARCH >= 8 to cogit.c's ARMv8 identifying macros.
CoInterpreterMT: Get rid of vmOwnerLock; what a bogus idea. Just use CAS on
vmOwner as God (DS) intended. Fix a bug in CoInterpreterMT>>wakeHighestPriority.
Refactor ABI callout marshalling on X64 to use the same CArg0Reg thru CArg3Reg
pattern as on ARMv8. Make CPUID the first processor specific opcode on Intel.
Eliminate use of reenterInterpreter, this is StackInterpreter only now.
FilePlugin:
Add FilePlugin>>primitiveFileReadPinningAndDisowning, for file read in COGMTVM.
Use methodReturnInteger: rather than methodReturnValue: ... integerObjectOf::
Slang: generate neater code for pointer indirection. Instead of indexing with
zero, dereference with *. Eliminate a space in function type printing.
Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2861.mcz
==================== Summary ====================
Name: VMMaker.oscog-eem.2861
Author: eem
Time: 29 October 2020, 11:50:34.437951 am
UUID: fe74d94b-c82c-47d0-8e6d-f2ac85eda597
Ancestors: VMMaker.oscog-eem.2860
Cog: Eliminate ceEnterInterpreterOnReturnFromCogCode and have the ceReturnToInterpreterTrampoline invoke interpret directly, using the same code as ceInvokeInterpret. Do this by moving the setMethod: send into interpret from senders; setMethod: is key because it sets the bytecodeSetSelector to enable multiple bytecode set support, but machine code is (and should remain) ignorant of the details of bytecode set selection in compiled method headers.
Simulation:
Eliminate teh simulator versions of interpret (too easy to get out of sync with the real versions). Do this by providing stubs for breakpointing and inctrementing of the bytecode count, in the real VMs and have these stubs implemented in teh simulators as they were in their own interpret imlementations.
Sista: fix a pseeling rorre.
=============== Diff against VMMaker.oscog-eem.2860 ===============
Item was added:
+ ----- Method: CoInterpreter>>aboutToDispatchBytecode (in category 'interpreter shell') -----
+ aboutToDispatchBytecode
+ "This is a hook for the simulator; null in production"
+ <inline: #always>!
Item was removed:
- ----- Method: CoInterpreter>>ceEnterInterpreterOnReturnFromCogCode (in category 'trampolines') -----
- ceEnterInterpreterOnReturnFromCogCode
- "Perform a return from a machine code frame to an interpreted frame.
- The machine code has executed a return instruction when the return address
- is set to ceReturnToInterpreterPC. Push the result and call interpret."
- <api>
- self assert: (objectMemory addressCouldBeOop: self stackTop).
- self deny: (self isMachineCodeFrame: framePointer).
- self setMethod: (self iframeMethod: framePointer).
- instructionPointer := self iframeSavedIP: framePointer.
- self assertValidExecutionPointe: instructionPointer r: framePointer s: stackPointer imbar: true line: #'__LINE__'.
- cogit ceInvokeInterpret.
- "NOTREACHED"
- ^nil!
Item was changed:
----- Method: CoInterpreter>>enterSmalltalkExecutiveImplementation (in category 'initialization') -----
enterSmalltalkExecutiveImplementation
"Main entry-point into the interpreter at each execution level, where an execution
level is either the start of execution or reentry for a callback. Capture the C stack
pointers so that calls from machine-code into the C run-time occur at this level.
This is the actual implementation, separated from enterSmalltalkExecutive so the
simulator can wrap it in an exception handler and hence simulate the setjmp/longjmp."
<inline: false>
cogit assertCStackWellAligned.
cogit ceCaptureCStackPointers.
(self isMachineCodeFrame: framePointer) ifTrue:
[self returnToExecutive: false postContextSwitch: true
"NOTREACHED"].
- self setMethod: (self iframeMethod: framePointer).
- instructionPointer = cogit ceReturnToInterpreterPC ifTrue:
- [instructionPointer := self iframeSavedIP: framePointer].
- self assertValidExecutionPointe: instructionPointer r: framePointer s: stackPointer imbar: true line: #'__LINE__'.
self interpret.
^0!
Item was changed:
----- Method: CoInterpreter>>interpret (in category 'interpreter shell') -----
interpret
"This is the main interpreter loop.
In a pure interpreter it loops forever, fetching and executing bytecodes.
With the Cogit JIT executing code as well, the interpreter is reentered from machine code
whenever the machine code wants to interpret a method instead of executing its machine
code. Entry into the interpreter is done via a ''jump call'' in machine code that uses
CFramePointer and CStackPointer to find the base of the C stack (set in CoInterpreter>>
enterSmalltalkExecutiveImplementation) and substitutes CReturnAddress as the return
address in the code so it always appears that interpret has been called from
CoInterpreter>>enterSmalltalkExecutiveImplementation, which may be important to,
for example, C exception handling inside the VM.
When running in the context of a browser plugin VM the interpreter must return control
to the browser periodically. This should done only when the state of the currently running
Squeak thread is safely stored in the object heap. Since this is the case at the moment
that a check for interrupts is performed, that is when we return to the browser if it is time
to do so. Interrupt checks happen quite frequently."
<inline: false>
"If stacklimit is zero then the stack pages have not been initialized."
stackLimit = 0 ifTrue:
[^self initStackPagesAndInterpret].
"An unchecked write is probably faster, so instead of
CReturnAddress ifNil:
[CReturnAddress := self cCoerceSimple: self getReturnAddress to: #usqIntptr_t]
we have simply"
self assert: (CReturnAddress isNil or: [CReturnAddress = (self cCoerceSimple: self getReturnAddress to: #usqIntptr_t)]).
CReturnAddress := self cCoerceSimple: self getReturnAddress to: #usqIntptr_t.
+
+ self useCogitBreakBlockIfNone.
"record entry time when running as a browser plug-in"
self browserPluginInitialiseIfNeeded.
+ self setMethod: (self iframeMethod: framePointer).
+ self deny: instructionPointer = cogit ceReturnToInterpreterPC.
+ self assertValidExecutionPointe: instructionPointer r: framePointer s: stackPointer imbar: true line: #'__LINE__'.
self internalizeIPandSP.
self initExtensions.
self fetchNextBytecode.
+ [true] whileTrue:
+ [self aboutToDispatchBytecode.
+ self dispatchOn: currentBytecode in: BytecodeTable].
- [true] whileTrue: [self dispatchOn: currentBytecode in: BytecodeTable].
localIP := localIP - 1. "undo the pre-increment of IP before returning"
self externalizeIPandSP.
^nil!
Item was added:
+ ----- Method: CoInterpreter>>useCogitBreakBlockIfNone (in category 'interpreter shell') -----
+ useCogitBreakBlockIfNone
+ "This is a hook for the simulator; null in production"
+ <inline: #always>!
Item was added:
+ ----- Method: CogVMSimulator>>aboutToDispatchBytecode (in category 'interpreter shell') -----
+ aboutToDispatchBytecode
+ self incrementByteCount.
+ self assertValidExecutionPointers.
+ atEachStepBlock value "N.B. may be nil"!
Item was removed:
- ----- Method: CogVMSimulator>>interpret (in category 'interpreter shell') -----
- interpret
- "This is the main interpreter loop. It normally loops forever, fetching and executing bytecodes.
- When running in the context of a web browser plugin VM, however, it must return control to the
- web browser periodically. This should done only when the state of the currently running Squeak
- thread is safely stored in the object heap. Since this is the case at the moment that a check for
- interrupts is performed, that is when we return to the browser if it is time to do so. Interrupt
- checks happen quite frequently.
-
- Override for simulation to insert bytecode breakpoint support."
-
- "If stacklimit is zero then the stack pages have not been initialized."
- stackLimit = 0 ifTrue:
- [^self initStackPagesAndInterpret].
-
- "An unchecked write is probably faster, so instead of
- CReturnAddress ifNil:
- [CReturnAddress := self cCoerceSimple: self getReturnAddress to: #usqIntptr_t]
- we have simply"
- self assert: (CReturnAddress isNil or: [CReturnAddress = self getReturnAddress]).
- CReturnAddress := self cCoerceSimple: self getReturnAddress to: #usqIntptr_t.
-
- self useCogitBreakBlockIfNone.
- "record entry time when running as a browser plug-in"
- self browserPluginInitialiseIfNeeded.
- self internalizeIPandSP.
- self initExtensions.
- self fetchNextBytecode.
- [true] whileTrue:
- [self assertValidExecutionPointers.
- atEachStepBlock value. "N.B. may be nil"
- self dispatchOn: currentBytecode in: BytecodeTable.
- self incrementByteCount].
- localIP := localIP - 1. "undo the pre-increment of IP before returning"
- self externalizeIPandSP.
- ^nil
- !
Item was changed:
----- Method: Cogit>>genReturnToInterpreterTrampoline (in category 'initialization') -----
genReturnToInterpreterTrampoline
+ | startAddress |
+ <inline: false>
+ startAddress := methodZoneBase.
self zeroOpcodeIndex.
+ "Push the result, set the instruction pointer to the interpreter frame's saved ip,
+ set the method and the bytecode set offset, then call interpret."
- "Set the instruction pointer to the interpreter frame's saved ip, set the method and the bytecode set offset,
- then call interpret."
self PushR: ReceiverResultReg. "The result"
+ "Assign the iframeSavedIP to instructionPointer"
+ self MoveMw: FoxIFSavedIP r: FPReg R: TempReg.
+ self MoveR: TempReg Aw: coInterpreter instructionPointerAddress.
+ self genSmalltalkToCStackSwitch: false "pushLinkReg".
+ cFramePointerInUse
+ ifTrue: [backEnd genLoadCStackPointers]
+ ifFalse: [backEnd genLoadCStackPointer].
+ "Sideways call interpret so that the stack looks correct, for exception handling etc"
+ backEnd genMarshallNArgs: 0 arg: nil arg: nil arg: nil arg: nil.
+ backEnd hasLinkRegister
+ ifTrue:
+ [self MoveAw: coInterpreter cReturnAddressAddress R: LinkReg]
+ ifFalse:
+ [self MoveAw: coInterpreter cReturnAddressAddress R: ABIResultReg.
+ backEnd genSubstituteReturnAddressR: ABIResultReg].
+ self JumpFullRT: (self
+ cCode: [#interpret asUnsignedInteger]
+ inSmalltalk: [self simulatedTrampolineFor: #interpret]).
+ self outputInstructionsForGeneratedRuntimeAt: startAddress.
+ self recordGeneratedRunTime: 'ceReturnToInterpreterTrampoline' address: startAddress.
+ ^self cCoerceSimple: startAddress to: #'void (*)(void)'!
- ^self genTrampolineFor: #ceEnterInterpreterOnReturnFromCogCode
- called: 'ceEnterInterpreterOnReturnFromCogCode'
- numArgs: 0 arg: nil arg: nil arg: nil arg: nil
- regsToSave: self emptyRegisterMask
- pushLinkReg: false
- resultReg: NoReg
- appendOpcodes: true!
Item was changed:
----- Method: StackInterpreter class>>initializeBytecodeTableForSistaV1 (in category 'initialization') -----
initializeBytecodeTableForSistaV1
"See e.g. the cass comment for EncoderForSistaV1"
"StackInterpreter initializeBytecodeTableForSistaV1"
"Note: This table will be used to generate a C switch statement."
InitializationOptions at: #SistaV1BytecodeSet put: (SistaV1BytecodeSet := true).
BytecodeTable := Array new: 256.
BytecodeEncoderClassName := #EncoderForSistaV1.
BytecodeSetHasDirectedSuperSend := true.
BytecodeSetHasExtensions := true.
LongStoreBytecode := 245.
self table: BytecodeTable from:
#( "1 byte bytecodes"
( 0 15 pushReceiverVariableBytecode)
( 16 31 pushLiteralVariable16CasesBytecode)
( 32 63 pushLiteralConstantBytecode)
( 64 75 pushTemporaryVariableBytecode)
( 76 pushReceiverBytecode)
( 77 pushConstantTrueBytecode)
( 78 pushConstantFalseBytecode)
( 79 pushConstantNilBytecode)
( 80 pushConstantZeroBytecode)
( 81 pushConstantOneBytecode)
( 82 extPushPseudoVariable)
( 83 duplicateTopBytecode)
( 84 87 unknownBytecode)
( 88 returnReceiver)
( 89 returnTrue)
( 90 returnFalse)
( 91 returnNil)
( 92 returnTopFromMethod)
( 93 returnNilFromBlock)
( 94 returnTopFromBlock)
( 95 extNopBytecode)
( 96 bytecodePrimAdd)
( 97 bytecodePrimSubtract)
( 98 bytecodePrimLessThanSistaV1) "for booleanCheatSistaV1:"
( 99 bytecodePrimGreaterThanSistaV1) "for booleanCheatSistaV1:"
(100 bytecodePrimLessOrEqualSistaV1) "for booleanCheatSistaV1:"
(101 bytecodePrimGreaterOrEqualSistaV1) "for booleanCheatSistaV1:"
(102 bytecodePrimEqualSistaV1) "for booleanCheatSistaV1:"
(103 bytecodePrimNotEqualSistaV1) "for booleanCheatSistaV1:"
(104 bytecodePrimMultiply)
(105 bytecodePrimDivide)
(106 bytecodePrimMod)
(107 bytecodePrimMakePoint)
(108 bytecodePrimBitShift)
(109 bytecodePrimDiv)
(110 bytecodePrimBitAnd)
(111 bytecodePrimBitOr)
(112 bytecodePrimAt)
(113 bytecodePrimAtPut)
(114 bytecodePrimSize)
(115 bytecodePrimNext) "i.e. a 0 arg special selector"
(116 bytecodePrimNextPut) "i.e. a 1 arg special selector"
(117 bytecodePrimAtEnd)
(118 bytecodePrimIdenticalSistaV1) "for booleanCheatSistaV1:"
(119 bytecodePrimClass)
(120 bytecodePrimNotIdenticalSistaV1) "was blockCopy:"
(121 bytecodePrimValue)
(122 bytecodePrimValueWithArg)
(123 bytecodePrimDo) "i.e. a 1 arg special selector"
(124 bytecodePrimNew) "i.e. a 0 arg special selector"
(125 bytecodePrimNewWithArg) "i.e. a 1 arg special selector"
(126 bytecodePrimPointX) "i.e. a 0 arg special selector"
(127 bytecodePrimPointY) "i.e. a 0 arg special selector"
(128 143 sendLiteralSelector0ArgsBytecode)
(144 159 sendLiteralSelector1ArgBytecode)
(160 175 sendLiteralSelector2ArgsBytecode)
(176 183 shortUnconditionalJump)
(184 191 shortConditionalJumpTrue)
(192 199 shortConditionalJumpFalse)
(200 207 storeAndPopReceiverVariableBytecode)
(208 215 storeAndPopTemporaryVariableBytecode)
(216 popStackBytecode)
+ (217 unconditionalTrapBytecode)
- (217 unconditionnalTrapBytecode)
(218 223 unknownBytecode)
"2 byte bytecodes"
(224 extABytecode)
(225 extBBytecode)
(226 extPushReceiverVariableBytecode)
(227 extPushLiteralVariableBytecode)
(228 extPushLiteralBytecode)
(229 longPushTemporaryVariableBytecode)
(230 unknownBytecode)
(231 pushNewArrayBytecode)
(232 extPushIntegerBytecode)
(233 extPushCharacterBytecode)
(234 extSendBytecode)
(235 extSendSuperBytecode)
(236 callMappedInlinedPrimitive)
(237 extUnconditionalJump)
(238 extJumpIfTrue)
(239 extJumpIfFalse)
(240 extStoreAndPopReceiverVariableBytecode)
(241 extStoreAndPopLiteralVariableBytecode)
(242 longStoreAndPopTemporaryVariableBytecode)
(243 extStoreReceiverVariableBytecode)
(244 extStoreLiteralVariableBytecode)
(245 longStoreTemporaryVariableBytecode)
(246 247 unknownBytecode)
"3 byte bytecodes"
(248 callPrimitiveBytecode)
(249 extPushFullClosureBytecode)
(250 extPushClosureBytecode)
(251 pushRemoteTempLongBytecode)
(252 storeRemoteTempLongBytecode)
(253 storeAndPopRemoteTempLongBytecode)
(254 255 unknownBytecode)
)!
Item was added:
+ ----- Method: StackInterpreter>>aboutToDispatchBytecode (in category 'interpreter shell') -----
+ aboutToDispatchBytecode
+ "This is a hook for the simulator; null in production"
+ <inline: #always>!
Item was changed:
----- Method: StackInterpreter>>enterSmalltalkExecutiveImplementation (in category 'initialization') -----
enterSmalltalkExecutiveImplementation
"Main entry-point into the interpreter at each execution level, where an execution
level is either the start of execution or reentry for a callback.
This is the actual implementation, separated from enterSmalltalkExecutive so the
simulator can wrap it in an exception handler and hence simulate the setjmp/longjmp."
<inline: false>
"Setjmp for reentry into interpreter from elsewhere, e.g. FFI exception primitive failure."
self _setjmp: reenterInterpreter.
- self setMethod: (self frameMethod: framePointer).
- self assertValidExecutionPointe: instructionPointer r: framePointer s: stackPointer imbar: true line: #'__LINE__'.
self interpret.
^0!
Item was changed:
----- Method: StackInterpreter>>interpret (in category 'interpreter shell') -----
interpret
"This is the main interpreter loop. It normally loops forever, fetching and executing bytecodes. When running in the context of a browser plugin VM, however, it must return control to the browser periodically. This should done only when the state of the currently running Squeak thread is safely stored in the object heap. Since this is the case at the moment that a check for interrupts is performed, that is when we return to the browser if it is time to do so. Interrupt checks happen quite frequently."
<inline: false>
"If stacklimit is zero then the stack pages have not been initialized."
stackLimit = 0 ifTrue:
[^self initStackPagesAndInterpret].
"record entry time when running as a browser plug-in"
self browserPluginInitialiseIfNeeded.
+ self setMethod: (self frameMethod: framePointer).
+ self assertValidExecutionPointe: instructionPointer r: framePointer s: stackPointer imbar: true line: #'__LINE__'.
self internalizeIPandSP.
self initExtensions.
self fetchNextBytecode.
+ [true] whileTrue:
+ [self aboutToDispatchBytecode.
+ self dispatchOn: currentBytecode in: BytecodeTable].
- [true] whileTrue: [self dispatchOn: currentBytecode in: BytecodeTable].
localIP := localIP - 1. "undo the pre-increment of IP before returning"
self externalizeIPandSP.
+ ^nil!
- ^nil
- !
Item was changed:
----- Method: StackInterpreter>>respondToSistaTrap (in category 'sista bytecodes') -----
respondToSistaTrap
| ourContext |
+ <sharedCodeInCase: #unconditionalTrapBytecode>
- <sharedCodeInCase: #unconditionnalTrapBytecode>
messageSelector := objectMemory splObj: SelectorSistaTrap.
ourContext := self ensureFrameIsMarried: localFP SP: localSP.
self internalPush: ourContext.
argumentCount := 0.
self normalSend!
Item was added:
+ ----- Method: StackInterpreter>>unconditionalTrapBytecode (in category 'sista bytecodes') -----
+ unconditionalTrapBytecode
+ "SistaV1: * 217 Trap"
+ SistaVM
+ ifTrue: [^self respondToSistaTrap]
+ ifFalse: [^self respondToUnknownBytecode]!
Item was removed:
- ----- Method: StackInterpreter>>unconditionnalTrapBytecode (in category 'sista bytecodes') -----
- unconditionnalTrapBytecode
- "SistaV1: * 217 Trap"
- SistaVM
- ifTrue: [^self respondToSistaTrap]
- ifFalse: [^self respondToUnknownBytecode]!
Item was added:
+ ----- Method: StackInterpreterSimulator>>aboutToDispatchBytecode (in category 'interpreter shell') -----
+ aboutToDispatchBytecode
+ self incrementByteCount.
+ self assertValidExecutionPointers.
+ atEachStepBlock value "N.B. may be nil"!
Item was removed:
- ----- Method: StackInterpreterSimulator>>interpret (in category 'interpreter shell') -----
- interpret
- "This is the main interpreter loop. It normally loops forever, fetching and executing bytecodes.
- When running in the context of a web browser plugin VM, however, it must return control to the
- web browser periodically. This should done only when the state of the currently running Squeak
- thread is safely stored in the object heap. Since this is the case at the moment that a check for
- interrupts is performed, that is when we return to the browser if it is time to do so. Interrupt
- checks happen quite frequently.
-
- Override for simulation to insert bytecode breakpoint support."
-
- <inline: false>
- "If stacklimit is zero then the stack pages have not been initialized."
- stackLimit = 0 ifTrue:
- [^self initStackPagesAndInterpret].
- "record entry time when running as a browser plug-in"
- self browserPluginInitialiseIfNeeded.
- self internalizeIPandSP.
- self initExtensions.
- self fetchNextBytecode.
- [true] whileTrue:
- [self assertValidExecutionPointers.
- atEachStepBlock value. "N.B. may be nil"
- self dispatchOn: currentBytecode in: BytecodeTable.
- self incrementByteCount].
- localIP := localIP - 1. "undo the pre-increment of IP before returning"
- self externalizeIPandSP.
- ^nil!