VM Maker: VMMaker.oscog-eem.2699.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.2699.mcz

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

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

Name: VMMaker.oscog-eem.2699
Author: eem
Time: 3 February 2020, 3:26:15.630866 pm
UUID: dc6180ae-b25f-4ece-9834-af9793616fbf
Ancestors: VMMaker.oscog-eem.2698

Cogit:
Fix a regression in generateCaptureCStackPointers: (TempReg is used and TempReg is a caller-saced reg, so if TempReg is used to save VarBaseReg, VarBaseReg will get corrupted.

Make sure VarBase is different from stackPointerAddress so that assembler decoration is not confusing.

As a displacement activity from implementing the range of cache flusing required for the dual mapped code zone, sort variables by size so that they occupy a little less space.

The reenterInterpreter does *not* need to be exported.

Nuke unused Cogit Lowcode vars when not generating a LowcodeVM.

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

Item was changed:
  ----- Method: CCodeGenerator>>emitCVariablesOn: (in category 'C code generator') -----
  emitCVariablesOn: aStream
  "Store the global variable declarations on the given stream."
 
  aStream cr; nextPutAll: '/*** Variables ***/'; cr.
+ (self segregateByGroupingSizeAndVisibility: (self sortStrings: variables)) do:
- (self sortStrings: variables) do:
  [:var | | varString |
  (self variableDeclarationStringsForVariable: (varString := var asString)) do:
  [:declArg| | decl |
  (decl := declArg) first == $#
  ifTrue:
  [aStream nextPutAll: decl; cr]
  ifFalse:
  [self isGeneratingPluginCode
  ifTrue:
  [varString = 'interpreterProxy'
  ifTrue: "quite special..."
  [self preDeclareInterpreterProxyOn: aStream]
  ifFalse: [(decl beginsWith: 'static') ifFalse:
  [aStream nextPutAll: 'static ']]]
  ifFalse:
  [(vmClass mustBeGlobal: varString)
  ifTrue:
  [(decl beginsWith: 'static ') ifTrue:
  [decl := decl allButFirst: 7]]
  ifFalse:
  [(decl beginsWith: 'static') ifFalse:
  [aStream nextPutAll: 'static ']]].
  aStream
  nextPutAll: decl;
  nextPut: $;;
  cr]]].
  aStream cr!

Item was added:
+ ----- Method: CCodeGenerator>>hasVariable: (in category 'utilities') -----
+ hasVariable: variableName
+ ^variables includes: variableName!

Item was added:
+ ----- Method: CCodeGenerator>>segregateByGroupingSizeAndVisibility: (in category 'utilities') -----
+ segregateByGroupingSizeAndVisibility: variables
+ "Sort variables by grouping (clusteredVariables first), by size (pointer & integer
+ vars sorted from defaultWordSize to bytes), and finally by size, public last.  The
+ intent is to group smaller variables together for better locality (because we can)."
+ | clusteredVariableNames streams defaultStream defaultWordSize groupedBySize privateStream publicStream |
+ clusteredVariableNames := ([vmClass clusteredVariableNames]
+ on: MessageNotUnderstood
+ do: [:ex| #()]).
+ streams := (1 to: 8) collect: [:i| i isPowerOfTwo ifTrue: [(Array new: variables size // 2) writeStream]].
+ defaultStream := (Array new: variables size // 2) writeStream.
+ defaultWordSize := vmClass ifNotNil: [vmClass objectMemoryClass wordSize] ifNil: 8. "We now live in a 64-bit"
+ variables do:
+ [:varName| | type |
+ (clusteredVariableNames includes: varName) ifFalse:
+ [type := variableDeclarations
+ at: varName
+ ifPresent: [:decl| self extractTypeFor: varName fromDeclaration: decl]
+ ifAbsent: [#sqInt].
+ ((self isSimpleType: type)
+ ifTrue: [streams at: ((self isPointerCType: type)
+ ifTrue: [defaultWordSize]
+ ifFalse: [self sizeOfIntegralCType: type])]
+ ifFalse: [defaultStream])
+ nextPut: varName]].
+ groupedBySize := Array new: variables size streamContents:
+ [:varStream|
+ varStream
+ nextPutAll: clusteredVariableNames;
+ nextPutAll: (streams at: defaultWordSize) contents;
+ nextPutAll: (streams at: (defaultWordSize = 8 ifTrue: [4] ifFalse: [8])) contents;
+ nextPutAll: (streams at: 2) contents;
+ nextPutAll: (streams at: 1) contents;
+ nextPutAll: defaultStream contents].
+ publicStream := (Array new: variables size // 2) writeStream.
+ privateStream := (Array new: variables size // 2) writeStream.
+ groupedBySize do:
+ [:varName|
+ (((self mustBeGlobal: varName) or: [clusteredVariableNames includes: varName])
+ ifTrue: [publicStream]
+ ifFalse: [privateStream]) nextPut: varName].
+ ^privateStream contents, publicStream contents!

Item was changed:
  ----- Method: CCodeGeneratorGlobalStructure>>buildSortedVariablesCollection (in category 'C code generator') -----
  buildSortedVariablesCollection
  "Build sorted vars, end result will be sorted collection based on static usage,
  perhaps cache lines will like this!!"
 
  | globalNames |
  globalNames := Bag new: globalVariableUsage size.
  globalVariableUsage keysAndValuesDo:
  [:k :v | | count |
  count := 0.
  v do:
  [:methodName|
  (methods at: methodName ifAbsent: []) ifNotNil:
  [:method|
  method parseTree nodesDo:
  [:n|
  (n isVariable
  and: [n name hasEqualElements: k]) ifTrue:
  [count := count + 1]]]].
  globalNames
  add: k "move arrays (e.g. methodCache) to end of struct"
  withOccurrences: (((variableDeclarations at: k ifAbsent: ['']) includes: $[)
  ifTrue: [count]
  ifFalse: [count + 1000])].
  variableDeclarations keysDo:
  [:e | globalNames add: e withOccurrences: 0].
  variables do:
  [:e | globalNames add: e withOccurrences: 0].
- "Allow vmClass to specify some number of names that should be emitted first in a specific order.
- This is for the Cogit's use of VarBaseRegister."
- ([vmClass clusteredVariableNames]
- on: MessageNotUnderstood
- do: [:ex| nil]) ifNotNil:
- [:clusteredVariableNames|
- clusteredVariableNames with: (clusteredVariableNames size - 1 * 10000 + 1000000 to: 1000000 by: -10000) do:
- [:variable :occurrences|
- (globalNames includes: variable) ifTrue:
- [globalNames
- remove: variable;
- add: variable withOccurrences: occurrences]]].
  ^(globalNames sortedElements asSortedCollection:
  [:a1 :a2| a1 value > a2 value or: [a1 value = a2 value and: [a1 key <= a2 key]]]) collect:
  [:ea| ea key]!

Item was changed:
  ----- Method: CCodeGeneratorGlobalStructure>>emitCVariablesOn: (in category 'C code generator') -----
  emitCVariablesOn: aStream
  "Store the global variable declarations on the given stream.
  Break logic into vars for structure and vars for non-structure."
  | structure nonstruct |
 
  structure := WriteStream on: (String new: 32768).
  nonstruct := WriteStream on: (String new: 32768).
  aStream nextPutAll: '/*** Variables ***/'; cr.
  structure
  nextPutAll: '#if SQ_USE_GLOBAL_STRUCT'; cr;
  nextPutAll: '# define _iss /* define in-struct static as void */'; cr;
  nextPutAll: 'static struct foo {'; cr;
  nextPutAll: '#else'; cr;
  nextPutAll: '# define _iss static'; cr;
  nextPutAll: '#endif'; cr.
+ (self segregateByGroupingSizeAndVisibility: self buildSortedVariablesCollection) do:
- self buildSortedVariablesCollection do:
  [ :var | | varString inStruct target |
  target := (inStruct := self placeInStructure: (varString := var asString))
  ifTrue: [structure]
  ifFalse: [nonstruct].
  (self variableDeclarationStringsForVariable: varString) do:
  [:decl|
  decl first == $#
  ifTrue:
  [target nextPutAll: decl; cr]
  ifFalse:
  [self isGeneratingPluginCode
  ifTrue:
  [varString = 'interpreterProxy'
  ifTrue: "quite special..."
  [self preDeclareInterpreterProxyOn: target]
  ifFalse: [target nextPutAll: 'static ']]
  ifFalse:
  [(vmClass mustBeGlobal: varString) ifFalse:
  [target nextPutAll: (inStruct ifTrue: ['_iss '] ifFalse: ['static '])]].
  target nextPutAll: decl; nextPut: $;; cr]]].
  structure
  nextPutAll: '#undef _iss'; cr;
  nextPutAll: '#if SQ_USE_GLOBAL_STRUCT'; cr;
  nextPutAll: ' } fum;'; cr;
  nextPutAll: ' #if SQ_USE_GLOBAL_STRUCT_REG';cr;
  nextPutAll: '# define DECL_MAYBE_SQ_GLOBAL_STRUCT /* using a global reg pointer */'; cr;
  nextPutAll: '# define DECL_MAYBE_VOLATILE_SQ_GLOBAL_STRUCT /* using a global reg pointer */'; cr;
  nextPutAll:'#else';cr;
  nextPutAll: '# define DECL_MAYBE_SQ_GLOBAL_STRUCT register struct foo * foo = &fum;'; cr;
  nextPutAll: '# define DECL_MAYBE_VOLATILE_SQ_GLOBAL_STRUCT volatile register struct foo * foo = &fum;'; cr;
  nextPutAll: '#endif';cr;
  nextPutAll: '# define GIV(interpreterInstVar) (foo->interpreterInstVar)'; cr;
  nextPutAll: '#else'; cr;
  nextPutAll: '# define DECL_MAYBE_SQ_GLOBAL_STRUCT /* oh, no mr bill!! */'; cr;
  nextPutAll: '# define DECL_MAYBE_VOLATILE_SQ_GLOBAL_STRUCT /* oh no, mr bill!! */'; cr;
  nextPutAll: '# define GIV(interpreterInstVar) interpreterInstVar'; cr;
  nextPutAll: '#endif'; cr.
 
  "if the machine needs the fum structure defining locally, do it now; global register users don't need that, but DO need some batshit insane C macro fudging in order to convert the define of USE_GLOBAL_STRUCT_REG into a simple string to use in the asm clause below. Sigh."
  structure
  nextPutAll: '#if SQ_USE_GLOBAL_STRUCT'; cr;
  nextPutAll: '#if SQ_USE_GLOBAL_STRUCT_REG';cr;
  nextPutAll: '#define fooxstr(s) foostr(s)'; cr;
  nextPutAll: '#define foostr(s)  #s'; cr;
  nextPutAll: 'register struct foo * foo asm(fooxstr(USE_GLOBAL_STRUCT_REG));'; cr;
  nextPutAll: '#else'; cr;
  nextPutAll: 'static struct foo * foo = &fum;'; cr;
  nextPutAll: '#endif'; cr;
  nextPutAll: '#endif'; cr.
 
  aStream
  nextPutAll: structure contents;
  nextPutAll: nonstruct contents;
  cr!

Item was changed:
  ----- Method: Cogit class>>declareCVarsIn: (in category 'translation') -----
  declareCVarsIn: aCCodeGenerator
+ | backEnd |
+ backEnd := CogCompilerClass basicNew.
  #( 'coInterpreter' 'objectMemory' 'methodZone' 'objectRepresentation'
  'cogBlockMethodSurrogateClass' 'cogMethodSurrogateClass' 'nsSendCacheSurrogateClass'
  'threadManager' 'processor' 'lastNInstructions' 'simulatedAddresses'
  'simulatedTrampolines' 'simulatedVariableGetters' 'simulatedVariableSetters'
  'processorFrameValid' 'printRegisters' 'printInstructions' 'clickConfirm' 'singleStep') do:
  [:simulationVariableNotNeededForRealVM|
  aCCodeGenerator removeVariable: simulationVariableNotNeededForRealVM].
  NewspeakVM ifFalse:
  [#( 'selfSendTrampolines' 'dynamicSuperSendTrampolines'
  'implicitReceiverSendTrampolines' 'outerSendTrampolines'
  'ceEnclosingObjectTrampoline' 'numIRCs' 'indexOfIRC' 'theIRCs') do:
  [:variableNotNeededInNormalVM|
  aCCodeGenerator removeVariable: variableNotNeededInNormalVM]].
  aCCodeGenerator removeConstant: #COGMTVM. "this should be defined at compile time"
  aCCodeGenerator
  addHeaderFile:'<stddef.h>'; "for e.g. offsetof"
  addHeaderFile:'"sqCogStackAlignment.h"';
  addHeaderFile:'"dispdbg.h"'; "must precede cointerp.h & cogit.h otherwise NoDbgRegParms gets screwed up"
  addHeaderFile:'"cogmethod.h"'.
  NewspeakVM ifTrue:
  [aCCodeGenerator addHeaderFile:'"nssendcache.h"'].
  aCCodeGenerator
  addHeaderFile:'#if COGMTVM';
  addHeaderFile:'"cointerpmt.h"';
  addHeaderFile:'#else';
  addHeaderFile:'"cointerp.h"';
  addHeaderFile:'#endif';
  addHeaderFile:'"cogit.h"'.
  aCCodeGenerator
  var: #ceGetFP
  declareC: 'usqIntptr_t (*ceGetFP)(void)';
  var: #ceGetSP
  declareC: 'usqIntptr_t (*ceGetSP)(void)';
  var: #ceCaptureCStackPointers
  declareC: 'void (*ceCaptureCStackPointers)(void)';
  var: #ceEnterCogCodePopReceiverReg
  declareC: 'void (*ceEnterCogCodePopReceiverReg)(void)';
  var: #realCEEnterCogCodePopReceiverReg
  declareC: 'void (*realCEEnterCogCodePopReceiverReg)(void)';
  var: #ceCallCogCodePopReceiverReg
  declareC: 'void (*ceCallCogCodePopReceiverReg)(void)';
  var: #realCECallCogCodePopReceiverReg
  declareC: 'void (*realCECallCogCodePopReceiverReg)(void)';
  var: #ceCallCogCodePopReceiverAndClassRegs
  declareC: 'void (*ceCallCogCodePopReceiverAndClassRegs)(void)';
  var: #realCECallCogCodePopReceiverAndClassRegs
  declareC: 'void (*realCECallCogCodePopReceiverAndClassRegs)(void)';
  var: #postCompileHook
  declareC: 'void (*postCompileHook)(CogMethod *)';
  var: #openPICList declareC: 'CogMethod *openPICList = 0';
  var: #maxMethodBefore type: #'CogBlockMethod *';
  var: 'enumeratingCogMethod' type: #'CogMethod *'.
 
  aCCodeGenerator
  var: #ceTryLockVMOwner
  declareC: '#if COGMTVM\usqIntptr_t (*ceTryLockVMOwner)(void)' withCRs;
  var: #ceUnlockVMOwner
  declareC: 'void (*ceUnlockVMOwner)(void)\#endif /* COGMTVM */' withCRs.
 
+ backEnd numCheckLZCNTOpcodes > 0 ifTrue:
- CogCompilerClass basicNew numCheckLZCNTOpcodes > 0 ifTrue:
  [aCCodeGenerator
  var: #ceCheckLZCNTFunction
  declareC: 'static usqIntptr_t (*ceCheckLZCNTFunction)(void)'].
+ backEnd numCheckFeaturesOpcodes > 0 ifTrue:
- CogCompilerClass basicNew numCheckFeaturesOpcodes > 0 ifTrue:
  [aCCodeGenerator
  var: #ceCheckFeaturesFunction
  declareC: 'static usqIntptr_t (*ceCheckFeaturesFunction)(void)'].
+ backEnd numICacheFlushOpcodes > 0 ifTrue:
- CogCompilerClass basicNew numICacheFlushOpcodes > 0 ifTrue:
  [aCCodeGenerator
  var: #ceFlushICache
  declareC: 'static void (*ceFlushICache)(usqIntptr_t from, usqIntptr_t to)'].
 
  aCCodeGenerator
  declareVar: 'aMethodLabel' type: #'AbstractInstruction'; "Has to come lexicographically before backEnd & methodLabel"
  var: #backEnd declareC: 'AbstractInstruction * const backEnd = &aMethodLabel';
  var: #methodLabel declareC: 'AbstractInstruction * const methodLabel = &aMethodLabel'.
  self declareC: #(abstractOpcodes stackCheckLabel
  blockEntryLabel blockEntryNoContextSwitch
  stackOverflowCall sendMiss
  entry noCheckEntry selfSendEntry dynSuperEntry
  fullBlockNoContextSwitchEntry fullBlockEntry
  picMNUAbort picInterpretAbort  endCPICCase0 endCPICCase1 cPICEndOfCodeLabel)
  as: #'AbstractInstruction *'
  in: aCCodeGenerator.
- aCCodeGenerator declareVar: #cPICPrototype type: #'CogMethod *'.
  aCCodeGenerator
+ declareVar: #cPICPrototype type: #'CogMethod *';
  declareVar: #blockStarts type: #'BlockStart *';
+ declareVar: #fixups type: #'BytecodeFixup *';
+ declareVar: #methodZoneBase type: #usqInt.
- declareVar: #fixups type: #'BytecodeFixup *'.
  aCCodeGenerator
  var: #ordinarySendTrampolines
  declareC: 'sqInt ordinarySendTrampolines[NumSendTrampolines]';
  var: #superSendTrampolines
  declareC: 'sqInt superSendTrampolines[NumSendTrampolines]'.
  BytecodeSetHasDirectedSuperSend ifTrue:
  [aCCodeGenerator
  var: #directedSuperSendTrampolines
  declareC: 'sqInt directedSuperSendTrampolines[NumSendTrampolines]';
  var: #directedSuperBindingSendTrampolines
  declareC: 'sqInt directedSuperBindingSendTrampolines[NumSendTrampolines]'].
  NewspeakVM ifTrue:
  [aCCodeGenerator
  var: #selfSendTrampolines
  declareC: 'sqInt selfSendTrampolines[NumSendTrampolines]';
  var: #dynamicSuperSendTrampolines
  declareC: 'sqInt dynamicSuperSendTrampolines[NumSendTrampolines]';
  var: #implicitReceiverSendTrampolines
  declareC: 'sqInt implicitReceiverSendTrampolines[NumSendTrampolines]';
  var: #outerSendTrampolines
  declareC: 'sqInt outerSendTrampolines[NumSendTrampolines]'].
  aCCodeGenerator
  var: #trampolineAddresses
  declareC: 'static char *trampolineAddresses[NumTrampolines*2]';
  var: #objectReferencesInRuntime
  declareC: 'static usqInt objectReferencesInRuntime[NumObjRefsInRuntime+1]';
  var: #labelCounter
  type: #int;
  var: #traceFlags
  declareC: 'int traceFlags = 8 /* prim trace log on by default */';
  var: #cStackAlignment
  declareC: 'const int cStackAlignment = STACK_ALIGN_BYTES'.
  aCCodeGenerator
  declareVar: #minValidCallAddress type: #'usqIntptr_t';
  declareVar: #debugPrimCallStackOffset type: #'usqIntptr_t'.
  aCCodeGenerator vmClass generatorTable ifNotNil:
  [:bytecodeGenTable|
  aCCodeGenerator
  var: #generatorTable
  declareC: 'static BytecodeDescriptor generatorTable[', bytecodeGenTable size printString, ']',
  (self tableInitializerFor: bytecodeGenTable
  in: aCCodeGenerator)].
+ "In C the abstract opcode names clash with the Smalltalk generator syntactic sugar.
- "In C the abstract opcode names clash with the Smalltak generator syntactic sugar.
  Most of the syntactic sugar is inlined, but alas some remains.  Rename the syntactic
  sugar to avoid the clash."
  (self organization listAtCategoryNamed: #'abstract instructions') do:
  [:s|
  aCCodeGenerator addSelectorTranslation: s to: 'g', (aCCodeGenerator cFunctionNameFor: s)].
+ aCCodeGenerator addSelectorTranslation: #halt: to: 'haltmsg'.
+ self declareFlagVarsAsByteIn: aCCodeGenerator!
- aCCodeGenerator addSelectorTranslation: #halt: to: 'haltmsg'!

Item was added:
+ ----- Method: Cogit class>>declareFlagVarsAsByteIn: (in category 'translation') -----
+ declareFlagVarsAsByteIn: aCCodeGenerator
+ CogCompilerClass basicNew byteReadsZeroExtend ifTrue:
+ [self declareC: #(cFramePointerInUse codeModified deadCode directedSendUsesBinding
+ hasMovableLiteral hasNativeFrame hasYoungReferent inBlock needsFrame
+ regArgsHaveBeenPushed traceStores useTwoPaths)
+ as: #'unsigned char'
+ ifPresentIn: aCCodeGenerator]!

Item was changed:
  ----- Method: Cogit>>generateCaptureCStackPointers: (in category 'initialization') -----
  generateCaptureCStackPointers: captureFramePointer
  "Generate the routine that writes the current values of the C frame and stack pointers into
  variables.  These are used to establish the C stack in trampolines back into the C run-time.
+ This routine assumes the system's frame pointer is the same as that used in generated code."
+ | startAddress callerSavedReg pushedVarBaseReg |
+ <inline: #never>
-
- This is a presumptuous quick hack for x86.  It is presumptuous for two reasons.  Firstly
- the system's frame and stack pointers may differ from those we use in generated code,
- e.g. on register-rich RISCs.  Secondly the ABI may not support a simple frameless call
- as written here (for example 128-bit stack alignment on Mac OS X)."
- | startAddress callerSavedReg |
- <inline: false>
  self allocateOpcodes: 32 bytecodes: 0.
  startAddress := methodZoneBase.
  "Must happen first; value may be used in accessing any of the following addresses"
  callerSavedReg := 0.
+ pushedVarBaseReg := false.
  backEnd hasVarBaseRegister ifTrue:
  [(self isCallerSavedReg: VarBaseReg) ifFalse:
  ["VarBaseReg is not caller-saved; must save and restore it, either by using an available caller-saved reg or push/pop."
+ callerSavedReg := self availableRegisterOrNoneIn: (ABICallerSavedRegisterMask bitClear: 1 << TempReg). "TempReg used below"
- callerSavedReg := self availableRegisterOrNoneIn: ABICallerSavedRegisterMask.
  callerSavedReg = NoReg
+ ifTrue: [self NativePushR: VarBaseReg. pushedVarBaseReg := true]
- ifTrue: [self NativePushR: VarBaseReg]
  ifFalse: [self MoveR: VarBaseReg R: callerSavedReg]].
  self MoveCq: self varBaseAddress R: VarBaseReg].
  captureFramePointer ifTrue:
  [self MoveR: FPReg Aw: self cFramePointerAddress].
  "Capture the stack pointer prior to the call.  If we've pushed VarBaseReg take that into account."
+ (backEnd leafCallStackPointerDelta ~= 0 or: [pushedVarBaseReg])
- (backEnd leafCallStackPointerDelta ~= 0
- or: [backEnd hasVarBaseRegister])
  ifTrue:
  [self LoadEffectiveAddressMw:
+ (pushedVarBaseReg
- ((backEnd hasVarBaseRegister and: [callerSavedReg = NoReg])
  ifTrue: [backEnd leafCallStackPointerDelta + objectMemory wordSize]
  ifFalse: [backEnd leafCallStackPointerDelta])
  r: NativeSPReg
  R: TempReg.
  self MoveR: TempReg Aw: self cStackPointerAddress]
+ ifFalse:
+ [self MoveR: NativeSPReg Aw: self cStackPointerAddress].
- ifFalse: [self MoveR: NativeSPReg Aw: self cStackPointerAddress].
  backEnd hasVarBaseRegister ifTrue:
  [(self isCallerSavedReg: VarBaseReg) ifFalse:
+ [pushedVarBaseReg
- ["VarBaseReg is not caller-saved; must save and restore it"
- callerSavedReg = NoReg
  ifTrue: [self NativePopR: VarBaseReg]
  ifFalse: [self MoveR: callerSavedReg R: VarBaseReg]]].
  self NativeRetN: 0.
  self outputInstructionsForGeneratedRuntimeAt: startAddress.
  backEnd flushICacheFrom: startAddress asUnsignedInteger to: methodZoneBase asUnsignedInteger.
  self recordGeneratedRunTime: 'ceCaptureCStackPointers' address: startAddress.
  ceCaptureCStackPointers := self cCoerceSimple: startAddress to: #'void (*)(void)'!

Item was added:
+ ----- Method: Cogit>>trampolineAddressFor: (in category 'debugging') -----
+ trampolineAddressFor: trampolineName
+ <doNotGenerate>
+ 0 to: trampolineTableIndex - 3 by: 2 do:
+ [:i|
+ (trampolineAddresses at: i) = trampolineName ifTrue:
+ [^trampolineAddresses at: i + 1]].
+ ^nil!

Item was changed:
  ----- Method: Cogit>>varBaseAddress (in category 'accessing') -----
  varBaseAddress
+ ^coInterpreter stackPointerAddress - objectMemory wordSize!
- ^coInterpreter stackPointerAddress!

Item was changed:
  ----- Method: StackInterpreter class>>declareCVarsIn: (in category 'translation') -----
  declareCVarsIn: aCCodeGenerator
  | vmClass |
  self class == thisContext methodClass ifFalse: [^self]. "Don't duplicate decls in subclasses"
  vmClass := aCCodeGenerator vmClass. "Generate primitiveTable etc based on vmClass, not just StackInterpreter"
  aCCodeGenerator
  addHeaderFile:'<stddef.h> /* for e.g. alloca */';
  addHeaderFile:'<setjmp.h>';
  addHeaderFile:'<wchar.h> /* for wint_t */';
  addHeaderFile:'"vmCallback.h"';
  addHeaderFile:'"sqMemoryFence.h"';
  addHeaderFile:'"dispdbg.h"'.
  LowcodeVM ifTrue: [ aCCodeGenerator addHeaderFile:'"sqLowcodeFFI.h"'].
 
  vmClass declareInterpreterVersionIn: aCCodeGenerator defaultName: 'Stack'.
  aCCodeGenerator
  var: #interpreterProxy  type: #'struct VirtualMachine*'.
  aCCodeGenerator
  declareVar: #sendTrace type: 'volatile int';
  declareVar: #byteCount type: #usqInt.
  "These need to be pointers or unsigned."
  self declareC: #(instructionPointer method newMethod)
  as: #usqInt
  in: aCCodeGenerator.
  "These are all pointers; char * because Slang has no support for C pointer arithmetic."
  self declareC: #(localIP localSP localFP stackPointer framePointer stackLimit breakSelector)
  as: #'char *'
  in: aCCodeGenerator.
  aCCodeGenerator
  var: #breakSelectorLength
  declareC: 'sqInt breakSelectorLength = MinSmallInteger'.
  self declareC: #(stackPage overflowedPage)
  as: #'StackPage *'
  in: aCCodeGenerator.
  aCCodeGenerator removeVariable: 'stackPages'.  "this is an implicit receiver in the translated code."
  "This defines bytecodeSetSelector as 0 if MULTIPLEBYTECODESETS
  is not defined, for the benefit of the interpreter on slow machines."
  aCCodeGenerator addConstantForBinding: (self bindingOf: #MULTIPLEBYTECODESETS).
  MULTIPLEBYTECODESETS == false ifTrue:
  [aCCodeGenerator
  removeVariable: 'bytecodeSetSelector'].
  BytecodeSetHasExtensions == false ifTrue:
  [aCCodeGenerator
  removeVariable: 'extA';
  removeVariable: 'extB'].
  aCCodeGenerator
  var: #methodCache
  declareC: 'sqIntptr_t methodCache[MethodCacheSize + 1 /* ', (MethodCacheSize + 1) printString, ' */]'.
  NewspeakVM
  ifTrue:
  [aCCodeGenerator
  var: #nsMethodCache
  declareC: 'sqIntptr_t nsMethodCache[NSMethodCacheSize + 1 /* ', (NSMethodCacheSize + 1) printString, ' */]']
  ifFalse:
  [aCCodeGenerator
  removeVariable: #nsMethodCache;
  removeVariable: 'localAbsentReceiver';
  removeVariable: 'localAbsentReceiverOrZero'].
  AtCacheTotalSize isInteger ifTrue:
  [aCCodeGenerator
  var: #atCache
  declareC: 'sqInt atCache[AtCacheTotalSize + 1 /* ', (AtCacheTotalSize + 1) printString, ' */]'].
  aCCodeGenerator
  var: #primitiveTable
  declareC: 'void (*primitiveTable[MaxPrimitiveIndex + 2 /* ', (MaxPrimitiveIndex + 2) printString, ' */])(void) = ', vmClass primitiveTableString.
  vmClass primitiveTable do:
  [:symbolOrNot|
  (symbolOrNot isSymbol
  and: [symbolOrNot ~~ #primitiveFail]) ifTrue:
  [(aCCodeGenerator methodNamed: symbolOrNot) ifNotNil:
  [:tMethod| tMethod returnType: #void]]].
  vmClass objectMemoryClass hasSpurMemoryManagerAPI
  ifTrue:
  [aCCodeGenerator
  var: #primitiveAccessorDepthTable
  type: 'signed char'
  sizeString: 'MaxPrimitiveIndex + 2 /* ', (MaxPrimitiveIndex + 2) printString, ' */'
  array: vmClass primitiveAccessorDepthTable]
  ifFalse:
  [aCCodeGenerator removeVariable: #primitiveAccessorDepthTable].
  aCCodeGenerator
  var: #displayBits type: #'void *'.
  self declareC: #(displayWidth displayHeight displayDepth) as: #int in: aCCodeGenerator.
  aCCodeGenerator
  var: #primitiveFunctionPointer
  declareC: 'void (*primitiveFunctionPointer)()';
  var: #externalPrimitiveTable
  declareC: 'void (*externalPrimitiveTable[MaxExternalPrimitiveTableSize + 1 /* ', (MaxExternalPrimitiveTableSize + 1) printString, ' */])(void)';
  var: #interruptCheckChain
  declareC: 'void (*interruptCheckChain)(void) = 0';
  var: #showSurfaceFn
  declareC: 'int (*showSurfaceFn)(sqIntptr_t, int, int, int, int)';
  var: #jmpBuf
  declareC: 'jmp_buf jmpBuf[MaxJumpBuf + 1 /* ', (MaxJumpBuf + 1) printString, ' */]';
  var: #suspendedCallbacks
  declareC: 'usqInt suspendedCallbacks[MaxJumpBuf + 1 /* ', (MaxJumpBuf + 1) printString, ' */]';
  var: #suspendedMethods
  declareC: 'usqInt suspendedMethods[MaxJumpBuf + 1 /* ', (MaxJumpBuf + 1) printString, ' */]'.
 
  self declareCAsUSqLong: #(nextPollUsecs nextWakeupUsecs longRunningPrimitiveGCUsecs
  longRunningPrimitiveStartUsecs longRunningPrimitiveStopUsecs
  "these are high-frequency enough that they're overflowing quite quickly on modern hardware"
  statProcessSwitch statIOProcessEvents statForceInterruptCheck
  statCheckForEvents statStackOverflow statStackPageDivorce
  statIdleUsecs)
  in: aCCodeGenerator.
  aCCodeGenerator var: #nextProfileTick type: #sqLong.
+ aCCodeGenerator var: #reenterInterpreter type: 'jmp_buf'.
- aCCodeGenerator
- var: #reenterInterpreter
- declareC: 'jmp_buf reenterInterpreter; /* private export */'.
  LowcodeVM
  ifTrue:
  [aCCodeGenerator
  var: #lowcodeCalloutState type: #'sqLowcodeCalloutState*'.
  self declareC: #(nativeSP nativeStackPointer shadowCallStackPointer)
  as: #'char *'
  in: aCCodeGenerator]
  ifFalse:
  [#(lowcodeCalloutState nativeSP nativeStackPointer shadowCallStackPointer) do:
  [:var| aCCodeGenerator removeVariable: var]].
 
  aCCodeGenerator
  var: #primitiveDoMixedArithmetic
  declareC: 'char primitiveDoMixedArithmetic = 1'.!

Item was changed:
  ----- Method: StackInterpreter class>>mustBeGlobal: (in category 'translation') -----
  mustBeGlobal: var
  "Answer if a variable must be global and exported.  Used for inst vars that are accessed from VM support code,
  and for variables that are initialized to some value (e.g. primitiveDoMixedArithmetic)."
 
  ^(super mustBeGlobal: var)
    or: [(self objectMemoryClass mustBeGlobal: var)
    or: [(#('interpreterProxy' 'interpreterVersion' 'inIOProcessEvents' 'sendWheelEvents'
  'deferDisplayUpdates' 'extraVMMemory'
  'showSurfaceFn' 'displayBits' 'displayWidth' 'displayHeight' 'displayDepth'
  'desiredNumStackPages' 'desiredEdenBytes'
  'primitiveDoMixedArithmetic'
  'breakLookupClassTag' 'breakSelector' 'breakSelectorLength' 'sendTrace' 'checkAllocFiller' 'checkedPluginName'
+ "'reenterInterpreter'" 'suppressHeartbeatFlag' 'ffiExceptionResponse'
- 'reenterInterpreter' 'suppressHeartbeatFlag' 'ffiExceptionResponse'
  'debugCallbackInvokes' 'debugCallbackPath' 'debugCallbackReturns') includes: var)
    or: [ "This allows slow machines to define bytecodeSetSelector as 0
  to avoid the interpretation overhead."
  MULTIPLEBYTECODESETS not and: [var = 'bytecodeSetSelector']]]]!

Item was changed:
  ----- Method: StackToRegisterMappingCogit class>>declareCVarsIn: (in category 'translation') -----
  declareCVarsIn: aCodeGen
  aCodeGen
  var: #methodAbortTrampolines
  declareC: 'sqInt methodAbortTrampolines[4]';
  var: #picAbortTrampolines
  declareC: 'sqInt picAbortTrampolines[4]';
  var: #picMissTrampolines
  declareC: 'sqInt picMissTrampolines[4]';
  var: 'ceCall0ArgsPIC'
  declareC: 'void (*ceCall0ArgsPIC)(void)';
  var: 'ceCall1ArgsPIC'
  declareC: 'void (*ceCall1ArgsPIC)(void)';
  var: 'ceCall2ArgsPIC'
  declareC: 'void (*ceCall2ArgsPIC)(void)';
  var: #ceCallCogCodePopReceiverArg0Regs
  declareC: 'void (*ceCallCogCodePopReceiverArg0Regs)(void)';
  var: #realCECallCogCodePopReceiverArg0Regs
  declareC: 'void (*realCECallCogCodePopReceiverArg0Regs)(void)';
  var: #ceCallCogCodePopReceiverArg1Arg0Regs
  declareC: 'void (*ceCallCogCodePopReceiverArg1Arg0Regs)(void)';
  var: #realCECallCogCodePopReceiverArg1Arg0Regs
  declareC: 'void (*realCECallCogCodePopReceiverArg1Arg0Regs)(void)';
  var: 'simStack'
  declareC: 'SimStackEntry simStack[', self simStackSlots asString, ']';
  var: 'simSelf'
  type: #CogSimStackEntry;
  var: #optStatus
  type: #CogSSOptStatus;
  var: 'prevBCDescriptor'
  type: #'BytecodeDescriptor *'.
+ LowcodeVM
+ ifTrue:
+ [aCodeGen
+ var: 'simNativeStack'
+ declareC: 'CogSimStackNativeEntry simNativeStack[', self simNativeStackSlots asString, ']']
+ ifFalse:
+ [#(simNativeSpillBase simNativeStack "simNativeStackPtr" simNativeStackSize hasNativeFrame) do:
+ [:lowcodeVar| aCodeGen removeVariable: lowcodeVar ifAbsent: []]].
- LowcodeVM ifTrue: [
- aCodeGen var: 'simNativeStack'
- declareC: 'CogSimStackNativeEntry simNativeStack[', self simNativeStackSlots asString, ']'
- ].
 
  self numPushNilsFunction ifNotNil:
  [aCodeGen
  var: 'numPushNilsFunction'
  declareC: 'sqInt (* const numPushNilsFunction)(struct _BytecodeDescriptor *,sqInt,sqInt,sqInt) = ', (aCodeGen cFunctionNameFor: self numPushNilsFunction);
  var: 'pushNilSizeFunction'
  declareC: 'sqInt (* const pushNilSizeFunction)(sqInt,sqInt) = ', (aCodeGen cFunctionNameFor: self pushNilSizeFunction)].
 
  aCodeGen
  addSelectorTranslation: #register to: (aCodeGen cFunctionNameFor: 'registerr');
+ addSelectorTranslation: #register: to: (aCodeGen cFunctionNameFor: 'registerr:').
+
+ self declareFlagVarsAsByteIn: aCodeGen!
- addSelectorTranslation: #register: to: (aCodeGen cFunctionNameFor: 'registerr:')!

Item was added:
+ ----- Method: VMClass class>>declareC:as:ifPresentIn: (in category 'translation') -----
+ declareC: arrayOfVariableNames as: aCType ifPresentIn: aCCodeGenerator
+ "Declare the variables in arrayOfVariableNames with the given type."
+
+ arrayOfVariableNames do:
+ [:varName |
+ (aCCodeGenerator hasVariable: varName) ifTrue:
+ [((self mustBeGlobal: varName)
+ and: [(aCCodeGenerator typeOfVariable: varName) ifNil: [false] ifNotNil: [:varType| aCType ~= varType]]) ifTrue:
+ [self error: 'attempting to change type of global var ', varName, '!!!!'].
+ aCCodeGenerator var: varName type: aCType]]!

Item was changed:
  ----- Method: VMClass>>promptHex: (in category 'simulation support') -----
  promptHex: string
  <doNotGenerate>
  | s |
  s := UIManager default request: string, ' (hex)'.
  s := s withBlanksTrimmed.
  ^(s notEmpty and: ['-+0123456789abcdefABCDEF' includes: s first]) ifTrue:
+ [(s beginsWith: 'ce')
- [(s includes: $r)
  ifTrue:
+ [self cogit trampolineAddressFor: s]
- [Number readFrom: s readStream]
  ifFalse:
+ [(s includes: $r)
+ ifTrue:
+ [Number readFrom: s readStream]
+ ifFalse:
+ [(#('0x' '-0x') detect: [:prefix| s beginsWith: prefix] ifNone: []) ifNotNil:
+ [:prefix|
+ s := s allButFirst: prefix size.
+ prefix first = $- ifTrue: [s := '-', s]].
+ Integer readFrom: s readStream base: 16]]]!
- [(#('0x' '-0x') detect: [:prefix| s beginsWith: prefix] ifNone: []) ifNotNil:
- [:prefix|
- s := s allButFirst: prefix size.
- prefix first = $- ifTrue: [s := '-', s]].
- Integer readFrom: s readStream base: 16]]!