VM Maker: VMMaker.oscog-eem.2875.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

VM Maker: VMMaker.oscog-eem.2875.mcz

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

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

Name: VMMaker.oscog-eem.2875
Author: eem
Time: 10 November 2020, 1:38:57.951349 pm
UUID: fbdf45b1-d757-4183-a2bd-1ebc595763e9
Ancestors: VMMaker.oscog-eem.2874

COGMTVM/interpreters: make sure the VM shuts down correctly, including terminating all threads/processes in the MT simulation, the SocketPlgin, etc.  Fix the mapping of Processes (which are emulating threads) to integers by adding Process>>asUnsignedInteger.  Hence CogThreadManager>>ioCurrentOSThread to answer Processor activeProcess.  In simulation make sure the VM calls ioShutdownAllModules.

InterpreterPlugin: Add the stackBooleanValue: from the 3D-ICC plugins.

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

Item was changed:
  ----- Method: AsynchFilePlugin>>shutdownModule (in category 'initialize-release') -----
  shutdownModule
  "Initialise the module"
  <export: true>
+ ^self asyncFileShutdown!
- ^self cCode: 'asyncFileShutdown()' inSmalltalk:[true]!

Item was changed:
  ----- Method: CoInterpreterMT>>ownVMFromUnidentifiedThread (in category 'vm scheduling') -----
  ownVMFromUnidentifiedThread
  "Attempt to take ownership from a thread that as yet doesn't know its index.
  This supports callbacks where the callback could originate from any thread.
 
  Answer 0 if the owning thread is known to the VM.
  Answer 1 if the owning thread is unknown to the VM and now owns the VM.
  Answer -1 if the owning thread is unknown to the VM and fails to own the VM.
  Answer -2 if the owning thread is unknown to the VM and there is no foreign callback process installed."
  | count threadIndex vmThread |
  <var: #vmThread type: #'CogVMThread *'>
  <inline: false>
  (threadIndex := cogThreadManager ioGetThreadLocalThreadIndex) ~= 0 ifTrue:
  [ "this is a callback from a known thread"
  (cogThreadManager vmOwnerIs: threadIndex) ifTrue: "the VM has not been disowned"
  [self assert: (disowningVMThread isNil or: [disowningVMThread = self currentVMThread]).
  disowningVMThread := nil.
  self currentVMThread state: CTMAssignableOrInVM.
  ^VMAlreadyOwnedHenceDoNotDisown].
  ^self ownVM: threadIndex].
  foreignCallbackPriority = 0 ifTrue:
  [^-2].
  count := 0.
  "If the current thread doesn't have an index it's new to the vm
  and we need to allocate a new threadInfo, failing if we can't.
  We also need a process in the foreignCallbackProcessSlot upon
  which to run the thread's eventual callback."
+ [[cogit tryLockVMOwnerTo: cogThreadManager ioCurrentOSThread asUnsignedInteger] whileFalse:
- [[cogit tryLockVMOwnerTo: cogThreadManager ioCurrentOSThread] whileFalse:
  [self waitingPriorityIsAtLeast: foreignCallbackPriority.
  cogThreadManager ioTransferTimeslice].
  (objectMemory splObj: foreignCallbackProcessSlot) ~= objectMemory nilObject] whileFalse:
  [cogThreadManager releaseVM.
  (count := count + 1) > 1000 ifTrue:
  [^-2].
  cogThreadManager ioMilliSleep: 1].
 
  vmThread := cogThreadManager unusedThreadInfo.
  "N.B.  Keep the VM locked anonymously so that we reserve the non-nil ForeignCallbackProcess
  for this thread, avoiding the race between competing foreign callbacks.  The acquireVMFor: in
  ownVM: will set the vmOwner to the actual index.  So only unlock on failure."
  vmThread ifNil:
  [cogThreadManager releaseVM.
  ^-1].
  cogThreadManager setVMOwner: vmThread index.
  vmThread
  state: CTMWantingOwnership;
  priority: foreignCallbackPriority.
  cogThreadManager registerVMThread: vmThread.
  ^self ownVM: vmThread index + OwnVMForeignThreadFlag!

Item was changed:
  ----- Method: CogThreadManager>>ioCurrentOSThread (in category 'simulation') -----
  ioCurrentOSThread
  <doNotGenerate>
  "See platforms/<plat>/vm/sqPlatformSpecific.h for the real definition."
+ ^Processor activeProcess!
- ^Processor activeProcess identityHash!

Item was changed:
  ----- Method: CogThreadManager>>ioNewOSSemaphore: (in category 'simulation') -----
  ioNewOSSemaphore: semaphorePointer "<BlockClosure>"
  <doNotGenerate>
  "See platforms/Cross/vm/sq.h for the real definition."
+ semaphorePointer at: 0 put: Semaphore new.
- semaphorePointer value: Semaphore new.
  ^0!

Item was changed:
  ----- Method: CogThreadManager>>populate:from:to: (in category 'thread set') -----
  populate: vmThreadPointers from: start to: finish
  "Populate vmThreadPointers with vmThreads over the given range."
  <var: #vmThreadPointers type: #'CogVMThread **'>
  | nThreads vmThreads |
  <var: #vmThreads type: #'CogVMThread *'>
  <var: #vmThread type: #'CogVMThread *'>
  <inline: true>
  nThreads := finish - start + 1.
+ vmThreads := self cCode: [self calloc: nThreads _: (self sizeof: CogVMThread)]
- vmThreads := self cCode: [self c: nThreads alloc: (self sizeof: CogVMThread)]
  inSmalltalk: [CArrayAccessor on: ((1 to: nThreads) collect: [:ign| CogVMThread new])].
+ vmThreads ifNil:
- vmThreads isNil ifTrue:
  [^false].
+ "Since 0 is not a valid index, in C we allocate one extra CogVMThread and use 1-relative indices."
+ self cCode: [start = 1 ifTrue: [vmThreadPointers at: 0 put: nil]]
- self cCode:
- [start = 1 ifTrue:
- [vmThreadPointers at: 0 put: nil]]
  inSmalltalk: [].
  start to: finish do:
  [:i| | vmThread |
  vmThread := self addressOf: (vmThreads at: i - start).
+ (self ioNewOSSemaphore: (self addressOf: vmThread osSemaphore put: [:sem| vmThread osSemaphore: sem])) ~= 0 ifTrue:
- (self ioNewOSSemaphore: (self cCode: [self addressOf: vmThread osSemaphore]
- inSmalltalk: [[:sem| vmThread osSemaphore: sem]])) ~= 0 ifTrue:
  [start to: i - 1 do:
  [:j|
  vmThread := self addressOf: (vmThreads at: j - start).
  self ioDestroyOSSemaphore: (self addressOf: vmThread osSemaphore)].
  self free: vmThreads.
  ^false].
  vmThreadPointers at: i put: vmThread.
  vmThread awolProcLength: AWOLProcessesIncrement.
  vmThread index: i].
  ^true!

Item was added:
+ ----- Method: CogThreadManager>>shutdownModule (in category 'simulation') -----
+ shutdownModule
+ <doNotGenerate>
+ | guiProcess |
+ threads ifNil: [^self].
+ (guiProcess := self guiProcess) ~= Processor activeProcess ifTrue:
+ [guiProcess
+ signalException:
+ (Notification new tag: #evaluateQuit; yourself).
+ Processor terminateActive].
+ threads do:
+ [:ea|
+ ea osThread ifNotNil:
+ [:aProcess|
+ (aProcess ~~ Processor activeProcess and: [aProcess ~~ guiProcess]) ifTrue:
+ [aProcess terminate]]]!

Item was changed:
+ ----- Method: CogVMSimulator>>close (in category 'initialize-release') -----
- ----- Method: CogVMSimulator>>close (in category 'initialization') -----
  close  "close any files that ST may have opened, etc"
  pluginList do: [:assoc| | plugin | plugin := assoc value. plugin ~~ self ifTrue: [plugin close]].
  "Ugh; at least some of this code belongs in the UI..."
  displayView ifNotNil:
  [displayView activeHand removeEventListener: self].
  ActiveHand removeEventListener: self.
  World submorphs do:
  [:submorph|
  (submorph model isVMObjectInspector
  and: [submorph model coInterpreter == self]) ifTrue:
  [submorph delete].
  (submorph model isDebugger
  and: [(submorph model interruptedProcess suspendedContext ifNotNil:
  [:sctxt|
  sctxt findContextSuchThat:
  [:ctxt|
  (ctxt receiver == cogit
  and: [ctxt selector == #simulateCogCodeAt:])
  or: [ctxt receiver == self
  and: [ctxt selector == #interpret]]]]) notNil]) ifTrue:
  [submorph model windowIsClosing.
  submorph delete]]!

Item was changed:
+ ----- Method: CogVMSimulator>>desiredCogCodeSize: (in category 'initialize-release') -----
- ----- Method: CogVMSimulator>>desiredCogCodeSize: (in category 'initialization') -----
  desiredCogCodeSize: anInteger
  desiredCogCodeSize := anInteger!

Item was changed:
+ ----- Method: CogVMSimulator>>desiredEdenBytes: (in category 'initialize-release') -----
- ----- Method: CogVMSimulator>>desiredEdenBytes: (in category 'initialization') -----
  desiredEdenBytes: anInteger
  desiredEdenBytes := anInteger!

Item was changed:
+ ----- Method: CogVMSimulator>>desiredNumStackPages: (in category 'initialize-release') -----
- ----- Method: CogVMSimulator>>desiredNumStackPages: (in category 'initialization') -----
  desiredNumStackPages: anInteger
  desiredNumStackPages := anInteger!

Item was changed:
+ ----- Method: CogVMSimulator>>ensureMultiThreadingOverridesAreUpToDate (in category 'initialize-release') -----
- ----- Method: CogVMSimulator>>ensureMultiThreadingOverridesAreUpToDate (in category 'initialization') -----
  ensureMultiThreadingOverridesAreUpToDate
  "Make sure the CoInterpreterMT switch methods are implemented.  These methods select
  between CoInterpreterMT's implementation or CoInterpreter's implementation depending
  on cogThreadManager being non-nil or nil respectively.  i.e. they allow us to use this one
  simulator class to simulate for both CoInterpreterMT and CoInterpreter."
  | thisClass me mtInterpreterClass |
  self cppIf: COGMTVM ifTrue: [  ] ifFalse: [ ^self ].
  thisClass := thisContext methodClass.
  mtInterpreterClass := thisClass superclass.
  me := thisClass name, '>>', thisContext method selector.
  "We want override switches for everything implemented by CoInterpreter
  and CoInterpreterMT that is either not implemented by CogVMSimulator
  or already implemented by CogVMSimulator as an override switch."
  (mtInterpreterClass selectors select:
  [:sel|
  (mtInterpreterClass superclass whichClassIncludesSelector: sel) notNil
  and: [(thisClass organization categoryOfElement: sel)
  ifNil: [true]
  ifNotNil: [:cat| cat == #'multi-threading simulation switch']]])
  do: [:sel| | argNames desiredSource |
  argNames := Parser new
  initPattern: (mtInterpreterClass sourceCodeAt: sel)
  return: [:pattern| pattern second].
  desiredSource := String streamContents:
  [:str|
  argNames isEmpty
  ifTrue: [str nextPutAll: sel]
  ifFalse:
  [sel keywords with: argNames do:
  [:kw :arg| str nextPutAll: kw; space; nextPutAll: arg; space].
  str skip: -1].
  str
  crtab;
  nextPutAll: '"This method includes or excludes ', mtInterpreterClass name, ' methods as required.';
  crtab;
  nextPutAll: ' Auto-generated by ', me, '"';
  cr;
  crtab;
  nextPutAll: '^self perform: ';
  store: sel;
  crtab: 2;
  nextPutAll: 'withArguments: {'.
  argNames
  do: [:arg| str nextPutAll: arg]
  separatedBy: [str nextPut: $.; space].
  str
  nextPut: $};
  crtab: 2;
  nextPutAll: 'inSuperclass: (cogThreadManager ifNil: [';
  print: mtInterpreterClass superclass;
  nextPutAll: '] ifNotNil: [';
  print: mtInterpreterClass;
  nextPutAll: '])'].
  desiredSource ~= (thisClass sourceCodeAt: sel ifAbsent: ['']) asString ifTrue:
  [((thisClass includesSelector: sel)
   and: [(thisClass compiledMethodAt: sel) messages includesAnyOf: #(halt halt:)])
  ifTrue: [self transcript cr; nextPutAll: 'WARNING, because of halts, not generating '; nextPutAll: desiredSource; cr; flush]
  ifFalse: [thisClass compile: desiredSource classified: #'multi-threading simulation switch']]].
  "Make sure obsolete CoInterpreterMT switch methods are deleted."
  ((thisContext methodClass organization listAtCategoryNamed: #'multi-threading simulation switch') select:
  [:sel| (mtInterpreterClass whichClassIncludesSelector: sel) isNil]) do:
  [:sel| thisClass removeSelector: sel]!

Item was changed:
+ ----- Method: CogVMSimulator>>initialEnterSmalltalkExecutive (in category 'initialize-release') -----
- ----- Method: CogVMSimulator>>initialEnterSmalltalkExecutive (in category 'initialization') -----
  initialEnterSmalltalkExecutive
  "Main entry-point into the interpreter at system start-up.
  Override to choose between the threaded and non-threaded versions and if threaded
  to ensure that the switch method overrides are up-to-date."
  self ensureMultiThreadingOverridesAreUpToDate.
  self assert: (cogit processor fp = CFramePointer and: [cogit processor sp = CStackPointer]).
  ^self perform: #initialEnterSmalltalkExecutive
  withArguments: {}
  inSuperclass: (cogThreadManager ifNil: [CoInterpreterPrimitives] ifNotNil: [CoInterpreterMT])!

Item was changed:
+ ----- Method: CogVMSimulator>>initialize (in category 'initialize-release') -----
- ----- Method: CogVMSimulator>>initialize (in category 'initialization') -----
  initialize
  "Initialize the CogVMSimulator when running the interpreter inside Smalltalk.  The
  primary responsibility of this method is to allocate Smalltalk Arrays for variables
  that will be declared as statically-allocated global arrays in the translated code."
  super initialize.
 
  transcript := Transcript.
 
  objectMemory ifNil:
  [objectMemory := self class objectMemoryClass simulatorClass new].
  cogit ifNil:
  [cogit := self class cogitClass new setInterpreter: self].
  objectMemory coInterpreter: self cogit: cogit.
 
  (cogit numRegArgs > 0
  and: [VMClass initializationOptions at: #CheckStackDepth ifAbsent: [true]]) ifTrue:
  [debugStackDepthDictionary := Dictionary new].
 
  cogThreadManager ifNotNil:
  [super initialize].
 
  self assert: ConstMinusOne = (objectMemory integerObjectOf: -1).
 
  cogMethodZone := cogit methodZone. "Because Slang can't remove intermediate implicit receivers (cogit methodZone foo doesn't reduce to foo())"
  enableCog := true.
 
  methodCache := Array new: MethodCacheSize.
  nsMethodCache := Array new: NSMethodCacheSize.
  atCache := nil.
  self flushMethodCache.
  cogCompiledCodeCompactionCalledFor := false.
  gcSemaphoreIndex := 0.
  externalSemaphoreSignalRequests := externalSemaphoreSignalResponses := #().
  externalPrimitiveTable := CArrayAccessor on: (Array new: MaxExternalPrimitiveTableSize).
  externalPrimitiveTableFirstFreeIndex := 0.
  primitiveTable := self class primitiveTable copy.
  self initializePluginEntries.
  desiredNumStackPages := InitializationOptions at: #desiredNumStackPages ifAbsent: [0].
  desiredEdenBytes := InitializationOptions at: #desiredEdenBytes ifAbsent: [0].
  desiredCogCodeSize  := InitializationOptions at: #desiredCogCodeSize ifAbsent: [0].
  "This is initialized on loading the image, but convenient for testing stack page values..."
  numStackPages := self defaultNumStackPages.
  startMicroseconds := lastYieldMicroseconds := self ioUTCStartMicroseconds.
  maxLiteralCountForCompile := MaxLiteralCountForCompile.
  minBackwardJumpCountForCompile := MinBackwardJumpCountForCompile.
  flagInterpretedMethods := false.
 
  "initialize InterpreterSimulator variables used for debugging"
  byteCount := lastPollCount := sendCount := lookupCount := 0.
  quitBlock := [^self close].
  traceOn := true.
  printSends := printFrameAtEachStep := printBytecodeAtEachStep := false.
  myBitBlt := BitBltSimulator new setInterpreter: self.
  displayForm := fakeForm := 'Display has not yet been installed' asDisplayText form.
  suppressHeartbeatFlag := deferSmash := deferredSmash := false.
  systemAttributes := Dictionary new.
  primTraceLog := CArrayAccessor on: (Array new: 256 withAll: 0).
  primTraceLogIndex := 0.
  traceLog := CArrayAccessor on: (Array new: TraceBufferSize withAll: 0).
  traceLogIndex := 0.
  traceSources := TraceSources.
  statCodeCompactionCount := 0.
  statCodeCompactionUsecs := 0.
  extSemTabSize := 256!

Item was changed:
+ ----- Method: CogVMSimulator>>initializeThreadSupport (in category 'initialize-release') -----
- ----- Method: CogVMSimulator>>initializeThreadSupport (in category 'initialization') -----
  initializeThreadSupport
  "Do this post new if you want to simulate with thread support."
  cogThreadManager := CogThreadManager new setInterpreter: self cogit: cogit.
  cogit setThreadManager: cogThreadManager!

Item was changed:
  ----- Method: CogVMSimulator>>ioExit (in category 'primitive support') -----
  ioExit
+ self ioExitWithErrorCode: 0!
- self threadManager ifNotNil:
- [:threadManager|
- threadManager guiProcess ~= Processor activeProcess ifTrue:
- [threadManager guiProcess
- signalException:
- (Notification new tag: #evaluateQuit; yourself).
- Processor terminateActive]].
- quitBlock value  "Cause return from #test"!

Item was changed:
  ----- Method: CogVMSimulator>>ioExitWithErrorCode: (in category 'primitive support') -----
  ioExitWithErrorCode: ec
+ self ioShutdownAllModules.
+ self threadManager ifNotNil:
+ [:threadManager| threadManager shutdownModule].
+ quitBlock value  "Cause return from #test"!
- self ioExit!

Item was changed:
+ ----- Method: CogVMSimulator>>ioInitHeartbeat (in category 'initialize-release') -----
- ----- Method: CogVMSimulator>>ioInitHeartbeat (in category 'initialization') -----
  ioInitHeartbeat
  "No-op in the simulator.  We cause a poll every 1000 bytecodes instead."!

Item was added:
+ ----- Method: CogVMSimulator>>ioShutdownAllModules (in category 'initialize-release') -----
+ ioShutdownAllModules
+ pluginList do:
+ [:assoc| | pluginOrSelf |
+ ((pluginOrSelf := assoc value) ~~ self
+  and: [pluginOrSelf respondsTo: #shutdownModule]) ifTrue:
+ [pluginOrSelf shutdownModule]]!

Item was changed:
+ ----- Method: CogVMSimulator>>moveMethodCacheToMemoryAt: (in category 'initialize-release') -----
- ----- Method: CogVMSimulator>>moveMethodCacheToMemoryAt: (in category 'initialization') -----
  moveMethodCacheToMemoryAt: address
  | oldMethodCache |
  oldMethodCache := methodCache.
  "In the VM the methodCache is written as a normal array with 1-relative addressing.
  In C this works by allocating an extra element in the methodCache array (see
  class-side declareCVarsIn:).  In simulation simply position the start of the methodCache
  one word lower, achieving the same effect.  -1 because CArrayAccessor is 0-relative
  and adds 1 on accesses itself."
  methodCache := CMethodCacheAccessor new
  objectMemory: objectMemory
  at: address
  array: oldMethodCache
  functionPointerIndex: MethodCachePrimFunction
  entrySize: MethodCacheEntrySize.
  self assert: address - objectMemory wordSize = self methodCacheAddress.
  1 to: MethodCacheSize do:
  [:i|
  self assert: (methodCache at: i) = 0].
  methodCache at: 1 put: 16rC4EC4.
  self assert: (objectMemory longAt: address) = 16rC4EC4.
  1 to: MethodCacheSize do:
  [:i|
  methodCache at: i put: (oldMethodCache at: i)]!

Item was changed:
+ ----- Method: CogVMSimulator>>movePrimTraceLogToMemoryAt: (in category 'initialize-release') -----
- ----- Method: CogVMSimulator>>movePrimTraceLogToMemoryAt: (in category 'initialization') -----
  movePrimTraceLogToMemoryAt: address
  | oldTraceLog |
  oldTraceLog := primTraceLog.
  primTraceLog := CArrayOfLongsAccessor new
  objectMemory: objectMemory at: address.
  self assert: address = self primTraceLogAddress.
  0 to: PrimTraceLogSize - 1 do:
  [:i|
  self assert: (primTraceLog at: i) = 0].
  primTraceLog at: 0 put: 16rC4EC4.
  self assert: (objectMemory longAt: address) = 16rC4EC4.
  0 to: PrimTraceLogSize - 1 do:
  [:i|
  primTraceLog at: i put: (oldTraceLog at: i)]!

Item was changed:
+ ----- Method: CogVMSimulator>>nextShortFrom: (in category 'initialize-release') -----
- ----- Method: CogVMSimulator>>nextShortFrom: (in category 'initialization') -----
  nextShortFrom: aStream
  "Read a 16-bit quantity from the given (binary) stream."
  ^self subclassResponsibility!

Item was changed:
+ ----- Method: CogVMSimulator>>openOn:extraMemory: (in category 'initialize-release') -----
- ----- Method: CogVMSimulator>>openOn:extraMemory: (in category 'initialization') -----
  openOn: fileName extraMemory: extraBytes
  "CogVMSimulator new openOn: 'clone.im' extraMemory: 100000"
 
  | f version headerSize dataSize count oldBaseAddr bytesToShift swapBytes
   headerFlags firstSegSize heapSize
   hdrNumStackPages hdrEdenBytes hdrMaxExtSemTabSize hdrCogCodeSize
   stackZoneSize methodCacheSize primTraceLogSize allocationReserve |
  "open image file and read the header"
 
  (f := self openImageFileNamed: fileName) ifNil: [^self].
 
  "Set the image name and the first argument; there are
  no arguments during simulation unless set explicitly."
  systemAttributes at: 1 put: fileName.
 
  ["begin ensure block..."
  imageName := f fullName.
  f binary.
 
  version := self getWord32FromFile: f swap: false.  "current version: 16r1968 (=6504) vive la revolucion!!"
  (self readableFormat: version)
  ifTrue: [swapBytes := false]
  ifFalse: [(version := version byteSwap32) = self imageFormatVersion
  ifTrue: [swapBytes := true]
  ifFalse: [self error: 'incomaptible image format']].
  headerSize := self getWord32FromFile: f swap: swapBytes.
  dataSize := self getLongFromFile: f swap: swapBytes.  "length of heap in file"
  oldBaseAddr := self getLongFromFile: f swap: swapBytes.  "object memory base address of image"
  objectMemory specialObjectsOop: (self getLongFromFile: f swap: swapBytes).
  objectMemory lastHash: (self getLongFromFile: f swap: swapBytes).  "Should be loaded from, and saved to the image header"
 
  savedWindowSize := self getLongFromFile: f swap: swapBytes.
  headerFlags := self getLongFromFile: f swap: swapBytes.
  self setImageHeaderFlagsFrom: headerFlags.
  extraVMMemory := self getWord32FromFile: f swap: swapBytes.
  hdrNumStackPages := self getShortFromFile: f swap: swapBytes.
  "4 stack pages is small.  Should be able to run with as few as
  three. 4 should be comfortable but slow.  8 is a reasonable
  default. Can be changed via vmParameterAt: 43 put: n"
  numStackPages := desiredNumStackPages ~= 0
  ifTrue: [desiredNumStackPages]
  ifFalse: [hdrNumStackPages = 0
  ifTrue: [self defaultNumStackPages]
  ifFalse: [hdrNumStackPages]].
  desiredNumStackPages := hdrNumStackPages.
  stackZoneSize := self computeStackZoneSize.
  "This slot holds the size of the native method zone in 1k units. (pad to word boundary)."
  hdrCogCodeSize := (self getShortFromFile: f swap: swapBytes) * 1024.
  cogCodeSize := desiredCogCodeSize ~= 0
  ifTrue: [desiredCogCodeSize]
  ifFalse:
  [hdrCogCodeSize = 0
  ifTrue: [cogit defaultCogCodeSize]
  ifFalse: [hdrCogCodeSize]].
  desiredCogCodeSize := hdrCogCodeSize.
  self assert: f position = (objectMemory wordSize = 4 ifTrue: [40] ifFalse: [64]).
  hdrEdenBytes := self getWord32FromFile: f swap: swapBytes.
  objectMemory edenBytes: (desiredEdenBytes ~= 0
  ifTrue: [desiredEdenBytes]
  ifFalse:
  [hdrEdenBytes = 0
  ifTrue: [objectMemory defaultEdenBytes]
  ifFalse: [hdrEdenBytes]]).
  desiredEdenBytes := hdrEdenBytes.
  hdrMaxExtSemTabSize := self getShortFromFile: f swap: swapBytes.
  hdrMaxExtSemTabSize ~= 0 ifTrue:
  [self setMaxExtSemSizeTo: hdrMaxExtSemTabSize].
  "pad to word boundary.  This slot can be used for anything else that will fit in 16 bits.
  Preserve it to be polite to other VMs."
  the2ndUnknownShort := self getShortFromFile: f swap: swapBytes.
  self assert: f position = (objectMemory wordSize = 4 ifTrue: [48] ifFalse: [72]).
  firstSegSize := self getLongFromFile: f swap: swapBytes.
  objectMemory firstSegmentSize: firstSegSize.
  "For Open PICs to be able to probe the method cache during
  simulation the methodCache must be relocated to memory."
  methodCacheSize := methodCache size * objectMemory wordSize.
  primTraceLogSize := primTraceLog size * objectMemory wordSize.
 
  "To cope with modern OSs that disallow executing code in writable memory we dual-map
  the code zone, one mapping with read/write permissions and the other with read/execute
  permissions. In simulation all we can do is use memory, so if we're simulating dual mapping
  we use double the memory and simulate the memory sharing in the Cogit's backEnd."
  effectiveCogCodeSize := (InitializationOptions at: #DUAL_MAPPED_CODE_ZONE ifAbsent: [false])
  ifTrue: [cogCodeSize * 2]
  ifFalse: [cogCodeSize].
 
  "allocate interpreter memory. This list is in address order, low to high.
  In the actual VM the stack zone exists on the C stack."
  heapBase := (Cogit guardPageSize
  + effectiveCogCodeSize
  + stackZoneSize
  + methodCacheSize
  + primTraceLogSize
  + self rumpCStackSize) roundUpTo: objectMemory allocationUnit.
  "compare memory requirements with availability"
  allocationReserve := self interpreterAllocationReserveBytes.
  objectMemory hasSpurMemoryManagerAPI
  ifTrue:
  [| freeOldSpaceInImage headroom |
  freeOldSpaceInImage := self getLongFromFile: f swap: swapBytes.
  headroom := objectMemory
  initialHeadroom: extraVMMemory
  givenFreeOldSpaceInImage: freeOldSpaceInImage.
  heapSize := objectMemory roundUpHeapSize:
    dataSize
  + headroom
  + objectMemory newSpaceBytes
  + (headroom > allocationReserve
  ifTrue: [0]
  ifFalse: [allocationReserve])]
  ifFalse:
  [heapSize :=  dataSize
  + extraBytes
  + objectMemory newSpaceBytes
  + (extraBytes > allocationReserve
  ifTrue: [0]
  ifFalse: [allocationReserve])].
  heapBase := objectMemory
  setHeapBase: heapBase
  memoryLimit:  heapBase + heapSize
  endOfMemory: heapBase + dataSize.
 
  self assert: cogCodeSize \\ 4 = 0.
  self assert: objectMemory memoryLimit \\ 4 = 0.
  self assert: self rumpCStackSize \\ 4 = 0.
  objectMemory allocateMemoryOfSize: objectMemory memoryLimit.
  "read in the image in bulk, then swap the bytes if necessary"
  f position: headerSize.
  count := objectMemory readHeapFromImageFile: f dataBytes: dataSize.
  count ~= dataSize ifTrue: [self halt]]
  ensure: [f close].
  self moveMethodCacheToMemoryAt: objectMemory cogCodeBase + effectiveCogCodeSize + stackZoneSize.
  self movePrimTraceLogToMemoryAt: objectMemory cogCodeBase + effectiveCogCodeSize + stackZoneSize + methodCacheSize.
 
  self ensureImageFormatIsUpToDate: swapBytes.
 
  bytesToShift := objectMemory memoryBaseForImageRead - oldBaseAddr.  "adjust pointers for zero base address"
  UIManager default
  informUser: 'Relocating object pointers...'
  during: [self initializeInterpreter: bytesToShift].
  self initializeCodeGenerator!

Item was changed:
  ----- Method: CogVMThread>>osThread: (in category 'accessing') -----
  osThread: anObject
  "Set the value of osThread"
+ self assert: (osThread isNil or: [osThread isKindOf: Process]).
-
  ^osThread := anObject!

Item was changed:
  ----- Method: FilePlugin>>shutdownModule (in category 'initialize-release') -----
  shutdownModule
  <export: true>
+ ^self sqFileShutdown!
- ^self cCode: 'sqFileShutdown()' inSmalltalk:[true]!

Item was added:
+ ----- Method: FilePluginSimulator>>sqFileShutdown (in category 'initialize-release') -----
+ sqFileShutdown
+ self close.
+ ^true!

Item was changed:
  ----- Method: HostWindowPlugin>>shutdownModule (in category 'initialize-release') -----
  shutdownModule
  "do any window related VM closing down work your platform requires."
  <export: true>
+ ^self ioCloseAllWindows!
- ^self cCode: 'ioCloseAllWindows()' inSmalltalk:[true]!

Item was added:
+ ----- Method: InterpreterPlugin>>stackBooleanValue: (in category 'API access') -----
+ stackBooleanValue: index
+ <inline: #always>
+ ^interpreterProxy booleanValueOf: (interpreterProxy stackValue: index)!

Item was changed:
  ----- Method: Mpeg3Plugin>>shutdownModule (in category 'support') -----
  shutdownModule
  <export: true>
  1 to: maximumNumberOfFilesToWatch do:
+ [:i |
+ ((mpegFiles at: i) ~= 0) ifTrue:
+ [self mpeg3_close: (mpegFiles at: i).
- [:i | ((mpegFiles at: i) ~= 0) ifTrue:
- [self cCode: 'mpeg3_close(mpegFiles[i])'.
  mpegFiles at: i put: 0]].
  ^true!

Item was added:
+ ----- Method: Process>>asUnsignedInteger (in category '*VMMaker-simulation') -----
+ asUnsignedInteger
+ "Processes are used to model OS threads in the COGMTVM.
+ But native threads are typically simply pointers which can hence be mapped to integers.
+ This is used in locking the VM from an unknown thread on callback.  Hence mimic the
+ ability to map a thread to an integer by answering the receiver's identityHash."
+ ^self identityHash!

Item was added:
+ ----- Method: SmartSyntaxPluginSimulator>>shutdownModule (in category 'initialize') -----
+ shutdownModule
+ ^(actualPlugin respondsTo: #shutdownModule)
+ ifTrue: [actualPlugin shutdownModule]
+ ifFalse: [true]!

Item was changed:
  ----- Method: SocketPlugin>>shutdownModule (in category 'initialize-release') -----
  shutdownModule
  <export: true>
+ ^self socketShutdown!
- ^self cCode: 'socketShutdown()' inSmalltalk:[true]!

Item was added:
+ ----- Method: SocketPluginSimulator>>socketShutdown (in category 'simulation') -----
+ socketShutdown
+ self close.
+ ^true!

Item was changed:
+ ----- Method: StackInterpreterSimulator>>close (in category 'initialize-release') -----
- ----- Method: StackInterpreterSimulator>>close (in category 'initialization') -----
  close  "close any files that ST may have opened, etc"
  pluginList do: [:assoc| | plugin | plugin := assoc value. plugin ~~ self ifTrue: [plugin close]].
  "Ugh; at least some of this code belongs in the UI..."
  displayView ifNotNil:
  [displayView activeHand removeEventListener: self].
  ActiveHand removeEventListener: self.
  World submorphs do:
  [:submorph|
  (submorph model isVMObjectInspector
  and: [submorph model coInterpreter == self]) ifTrue:
  [submorph delete].
  (submorph model isDebugger
  and: [(submorph model interruptedProcess suspendedContext ifNotNil:
  [:sctxt|
  sctxt findContextSuchThat:
  [:ctxt|
  ctxt receiver == self
  and: [ctxt selector == #run]]]) notNil]) ifTrue:
  [submorph model windowIsClosing.
  submorph delete]]!

Item was changed:
+ ----- Method: StackInterpreterSimulator>>desiredEdenBytes: (in category 'initialize-release') -----
- ----- Method: StackInterpreterSimulator>>desiredEdenBytes: (in category 'initialization') -----
  desiredEdenBytes: anInteger
  desiredEdenBytes := anInteger!

Item was changed:
+ ----- Method: StackInterpreterSimulator>>desiredNumStackPages: (in category 'initialize-release') -----
- ----- Method: StackInterpreterSimulator>>desiredNumStackPages: (in category 'initialization') -----
  desiredNumStackPages: anInteger
  desiredNumStackPages := anInteger!

Item was changed:
+ ----- Method: StackInterpreterSimulator>>initialize (in category 'initialize-release') -----
- ----- Method: StackInterpreterSimulator>>initialize (in category 'initialization') -----
  initialize
  "Initialize the StackInterpreterSimulator when running the interpreter
  inside Smalltalk. The primary responsibility of this method is to allocate
  Smalltalk Arrays for variables that will be declared as statically-allocated
  global arrays in the translated code."
  super initialize.
 
  bootstrapping := false.
  transcript := Transcript.
 
  objectMemory ifNil:
  [objectMemory := self class objectMemoryClass simulatorClass new].
  objectMemory coInterpreter: self.
 
  self assert: ConstMinusOne = (objectMemory integerObjectOf: -1).
 
  methodCache := Array new: MethodCacheSize.
  nsMethodCache := Array new: NSMethodCacheSize.
  atCache := Array new: AtCacheTotalSize.
  self flushMethodCache.
  gcSemaphoreIndex := 0.
  externalSemaphoreSignalRequests := externalSemaphoreSignalResponses := #().
  externalPrimitiveTable := CArrayAccessor on: (Array new: MaxExternalPrimitiveTableSize).
  externalPrimitiveTableFirstFreeIndex := 0.
  primitiveTable := self class primitiveTable copy.
  self initializePluginEntries.
  desiredNumStackPages := desiredEdenBytes := 0.
  "This is initialized on loading the image, but convenient for testing stack page values..."
  numStackPages := self defaultNumStackPages.
  startMicroseconds := lastYieldMicroseconds := self ioUTCStartMicroseconds.
 
  "initialize InterpreterSimulator variables used for debugging"
  byteCount := sendCount := lookupCount := 0.
  quitBlock := [^self close].
  traceOn := true.
  printSends := printReturns := printFrameAtEachStep := printBytecodeAtEachStep := false.
  myBitBlt := BitBltSimulator new setInterpreter: self.
  displayForm := fakeForm := 'Display has not yet been installed' asDisplayText form.
  suppressHeartbeatFlag := false.
  systemAttributes := Dictionary new.
  extSemTabSize := 256.
  disableBooleanCheat := false.
  assertVEPAES := false. "a flag so the assertValidExecutionPointers can be disabled for simulation speed and enabled when necessary."!

Item was changed:
  ----- Method: StackInterpreterSimulator>>ioExit (in category 'primitive support') -----
  ioExit
+ self ioExitWithErrorCode: 0!
-
- quitBlock value  "Cause return from #test"!

Item was changed:
  ----- Method: StackInterpreterSimulator>>ioExitWithErrorCode: (in category 'primitive support') -----
  ioExitWithErrorCode: ec
+ self ioShutdownAllModules.
-
  quitBlock value  "Cause return from #test"!

Item was changed:
+ ----- Method: StackInterpreterSimulator>>ioInitHeartbeat (in category 'initialize-release') -----
- ----- Method: StackInterpreterSimulator>>ioInitHeartbeat (in category 'initialization') -----
  ioInitHeartbeat
  "No-op in the simulator.  We cause a poll every 1000 bytecodes instead."!

Item was added:
+ ----- Method: StackInterpreterSimulator>>ioShutdownAllModules (in category 'initialize-release') -----
+ ioShutdownAllModules
+ pluginList do:
+ [:assoc| | pluginOrSelf |
+ ((pluginOrSelf := assoc value) ~~ self
+  and: [pluginOrSelf respondsTo: #shutdownModule]) ifTrue:
+ [pluginOrSelf shutdownModule]]!

Item was changed:
+ ----- Method: StackInterpreterSimulator>>nextShortFrom: (in category 'initialize-release') -----
- ----- Method: StackInterpreterSimulator>>nextShortFrom: (in category 'initialization') -----
  nextShortFrom: aStream
  "Read a 16-bit quantity from the given (binary) stream."
  ^self subclassResponsibility!

Item was changed:
+ ----- Method: StackInterpreterSimulator>>openOn:extraMemory: (in category 'initialize-release') -----
- ----- Method: StackInterpreterSimulator>>openOn:extraMemory: (in category 'initialization') -----
  openOn: fileName extraMemory: extraBytes
  "StackInterpreterSimulator new openOn: 'clone.im' extraMemory: 100000"
 
  | f version headerSize dataSize count oldBaseAddr bytesToShift swapBytes
   headerFlags heapBase firstSegSize heapSize
   hdrNumStackPages hdrEdenBytes hdrMaxExtSemTabSize allocationReserve |
  "open image file and read the header"
 
  (f := self openImageFileNamed: fileName) ifNil: [^self].
 
  "Set the image name and the first argument; there are
  no arguments during simulation unless set explicitly."
  systemAttributes at: 1 put: fileName.
 
  ["begin ensure block..."
  imageName := f fullName.
  f binary.
 
  version := self getWord32FromFile: f swap: false.  "current version: 16r1968 (=6504) vive la revolucion!!"
  (self readableFormat: version)
  ifTrue: [swapBytes := false]
  ifFalse: [(version := objectMemory byteSwapped: version) = self imageFormatVersion
  ifTrue: [swapBytes := true]
  ifFalse: [self error: 'incomaptible image format']].
  headerSize := self getWord32FromFile: f swap: swapBytes.
  dataSize := self getLongFromFile: f swap: swapBytes.  "length of heap in file"
  oldBaseAddr := self getLongFromFile: f swap: swapBytes.  "object memory base address of image"
  objectMemory specialObjectsOop: (self getLongFromFile: f swap: swapBytes).
  objectMemory lastHash: (self getLongFromFile: f swap: swapBytes).  "Should be loaded from, and saved to the image header"
 
  savedWindowSize := self getLongFromFile: f swap: swapBytes.
  headerFlags := self getLongFromFile: f swap: swapBytes.
  self setImageHeaderFlagsFrom: headerFlags.
  extraVMMemory := self getWord32FromFile: f swap: swapBytes.
  hdrNumStackPages := self getShortFromFile: f swap: swapBytes.
  "4 stack pages is small.  Should be able to run with as few as
  three. 4 should be comfortable but slow.  8 is a reasonable
  default. Can be changed via vmParameterAt: 43 put: n"
  numStackPages := desiredNumStackPages ~= 0
  ifTrue: [desiredNumStackPages]
  ifFalse: [hdrNumStackPages = 0
  ifTrue: [self defaultNumStackPages]
  ifFalse: [hdrNumStackPages]].
  desiredNumStackPages := hdrNumStackPages.
  "pad to word boundary.  This slot can be used for anything else that will fit in 16 bits.
  It is used for the cog code size in Cog.  Preserve it to be polite to other VMs."
  theUnknownShort := self getShortFromFile: f swap: swapBytes.
  self assert: f position = (objectMemory wordSize = 4 ifTrue: [40] ifFalse: [64]).
  hdrEdenBytes := self getWord32FromFile: f swap: swapBytes.
  objectMemory edenBytes: (hdrEdenBytes = 0
  ifTrue: [objectMemory defaultEdenBytes]
  ifFalse: [hdrEdenBytes]).
  desiredEdenBytes := hdrEdenBytes.
  hdrMaxExtSemTabSize := self getShortFromFile: f swap: swapBytes.
  hdrMaxExtSemTabSize ~= 0 ifTrue:
  [self setMaxExtSemSizeTo: hdrMaxExtSemTabSize].
  "pad to word boundary.  This slot can be used for anything else that will fit in 16 bits.
  Preserve it to be polite to other VMs."
  the2ndUnknownShort := self getShortFromFile: f swap: swapBytes.
  self assert: f position = (objectMemory wordSize = 4 ifTrue: [48] ifFalse: [72]).
  firstSegSize := self getLongFromFile: f swap: swapBytes.
  objectMemory firstSegmentSize: firstSegSize.
  "compare memory requirements with availability"
  allocationReserve := self interpreterAllocationReserveBytes.
  objectMemory hasSpurMemoryManagerAPI
  ifTrue:
  [| freeOldSpaceInImage headroom |
  freeOldSpaceInImage := self getLongFromFile: f swap: swapBytes.
  headroom := objectMemory
  initialHeadroom: extraVMMemory
  givenFreeOldSpaceInImage: freeOldSpaceInImage.
  heapSize := objectMemory roundUpHeapSize:
    dataSize
  + headroom
  + objectMemory newSpaceBytes
  + (headroom > allocationReserve
  ifTrue: [0]
  ifFalse: [allocationReserve])]
  ifFalse:
  [heapSize :=  dataSize
  + extraBytes
  + objectMemory newSpaceBytes
  + (extraBytes > allocationReserve
  ifTrue: [0]
  ifFalse: [allocationReserve])].
  "allocate interpreter memory"
  heapBase := objectMemory startOfMemory.
  objectMemory
  setHeapBase: heapBase
  memoryLimit: heapBase + heapSize
  endOfMemory: heapBase + dataSize. "bogus for Spur"
  objectMemory allocateMemoryOfSize: objectMemory memoryLimit.
  "read in the image in bulk, then swap the bytes if necessary"
  f position: headerSize.
  count := objectMemory readHeapFromImageFile: f dataBytes: dataSize.
  count ~= dataSize ifTrue: [self halt]]
  ensure: [f close].
 
  self ensureImageFormatIsUpToDate: swapBytes.
 
  bytesToShift := objectMemory memoryBaseForImageRead - oldBaseAddr.  "adjust pointers for zero base address"
  UIManager default
  informUser: 'Relocating object pointers...'
  during: [self initializeInterpreter: bytesToShift]!

Item was changed:
+ ----- Method: StackInterpreterSimulator>>startOfMemory (in category 'initialize-release') -----
- ----- Method: StackInterpreterSimulator>>startOfMemory (in category 'initialization') -----
  startOfMemory
  self shouldNotImplement!