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

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

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

Name: VMMaker.oscog-eem.2315
Author: eem
Time: 12 January 2018, 11:22:17.267383 am
UUID: 7bb299f2-2888-4047-b9ea-826c6a27d890
Ancestors: VMMaker.oscog-eem.2314

Double-back on the rash statement that there was a bad bug in ceSend:above:to:numArgs: which was written to accept an association, not a class.  This was by design.  generalize the JIT support for directed super sends so that it accepts both the
        pushLiteral: foo; directedSuperSend: bar numArgs: baz, and
        pushLiteralVariable: foo; directedSuperSend: bar numArgs: baz
forms.  Introduce aother directed send trampoline table for directedSuperBindingSends.  Implement ceSend:aboveClassBinding:to:numArgs: using ceSend:above:to:numArgs:.

Simplify, deleting genPushLiteralVariableGivenDirectedSuper: et al, and simply having genPushLiteralIndex: peek for a directed super send if the bytecode set includes it.  Add the directedSendUsesBinding variable, set only by genPushLiteralIndex: and consumed by genSendDirectedSuper:numArgs:, to distinguish between the two forms.

Keep the unused printPCMapPairsFor:, but mark it as doNotGenerate.
Implement targetMethodAndSendTableFor:annotation:into: in terms of offsetAndSendTableFor:annotation:into:.

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

Item was changed:
  ----- Method: CoInterpreter>>ceSend:above:to:numArgs: (in category 'trampolines') -----
  ceSend: selector above: methodClass to: rcvr numArgs: numArgs
  "Entry-point for an unlinked directed super send in a CogMethod.  Smalltalk stack looks like
  receiver
  args
  head sp -> sender return pc
+ methodClass is the class above which to start the lookup.
- startAssociation is an association whose value is the class above which to start the lookup.
 
  If an MNU then defer to handleMNUInMachineCodeTo:... which will dispatch the MNU and
  may choose to allocate a closed PIC with a fast MNU dispatch for this send.  Otherwise
  attempt to link the send site as efficiently as possible.  All link attempts may fail; e.g.
  because we're out of code memory.
 
  Continue execution via either executeMethod or interpretMethodFromMachineCode:
  depending on whether the target method is cogged or not."
  <api>
  <option: #BytecodeSetHasDirectedSuperSend>
  | classTag classObj errSelIdx cogMethod |
  <inline: false>
  <var: #cogMethod type: #'CogMethod *'>
  <var: #newCogMethod type: #'CogMethod *'>
  "self printExternalHeadFrame"
  "self printStringOf: selector"
  cogit assertCStackWellAligned.
  self assert: (objectMemory addressCouldBeOop: rcvr).
  self sendBreakpoint: selector receiver: rcvr.
  classTag := objectMemory classTagForClass: (self superclassOf: (objectMemory followMaybeForwarded: methodClass)).
  argumentCount := numArgs.
  (self lookupInMethodCacheSel: selector classTag: classTag)
  ifTrue:"check for coggability because method is in the cache"
  [self
  ifAppropriateCompileToNativeCode: newMethod
  selector: selector]
  ifFalse:
  [self deny: (objectMemory isForwardedClassTag: classTag).
  (objectMemory isOopForwarded: selector) ifTrue:
  [^self
  ceSend: (self handleForwardedSelectorFaultFor: selector)
  above: methodClass
  to: rcvr
  numArgs: numArgs].
  messageSelector := selector.
  classObj := objectMemory classForClassTag: classTag.
  (errSelIdx := self lookupOrdinaryNoMNUEtcInClass: classObj) ~= 0 ifTrue:
  [(errSelIdx = SelectorDoesNotUnderstand
   and: [(cogMethod := cogit cogMNUPICSelector: messageSelector
  receiver: rcvr
  methodOperand: (self mnuMethodOrNilFor: rcvr)
  numArgs: argumentCount) asUnsignedInteger
  > cogit minCogMethodAddress]) ifTrue:
  [cogit
  linkSendAt: (stackPages longAt: stackPointer)
  in: (self mframeHomeMethod: framePointer)
  to: cogMethod
  offset: cogit noCheckEntryOffset
  receiver: rcvr].
  self handleMNU: errSelIdx
  InMachineCodeTo: rcvr
  classForMessage: classObj.
  self assert: false "NOTREACHED"]].
  "Method found and has a cog method.  Attempt to link to it.  The receiver's class may be young.
  We must not link to an Open PIC since they perform normal sends."
  (self maybeMethodHasCogMethod: newMethod) ifTrue:
  [cogMethod := self cogMethodOf: newMethod.
  cogMethod selector = objectMemory nilObject
  ifTrue: [cogit setSelectorOf: cogMethod to: selector]
  ifFalse:
  ["Deal with anonymous accessors, e.g. in Newspeak.  The cogMethod may not have the
   correct selector.  If not, try and compile a new method with the correct selector."
  cogMethod selector ~= selector ifTrue:
  [(cogit cog: newMethod selector: selector) ifNotNil:
  [:newCogMethod| cogMethod := newCogMethod]]].
  cogMethod selector = selector ifTrue:
  [cogit
  linkSendAt: (stackPages longAt: stackPointer)
  in: (self mframeHomeMethod: framePointer)
  to: cogMethod
  offset: cogit noCheckEntryOffset
  receiver: rcvr].
  instructionPointer := self popStack.
  self executeNewMethod.
  self assert: false "NOTREACHED"].
  instructionPointer := self popStack.
  ^self interpretMethodFromMachineCode
  "NOTREACHED"!

Item was added:
+ ----- Method: CoInterpreter>>ceSend:aboveClassBinding:to:numArgs: (in category 'trampolines') -----
+ ceSend: selector aboveClassBinding: methodClassBinding to: rcvr numArgs: numArgs
+ "Entry-point for an unlinked directed super send in a CogMethod.  Smalltalk stack looks like
+ receiver
+ args
+ head sp -> sender return pc
+ methodClassBinding is an association whose value is the class above which to start the lookup."
+ <api>
+ <option: #BytecodeSetHasDirectedSuperSend>
+ self ceSend: selector
+ above: (objectMemory followMaybeForwarded: methodClassBinding)
+ to: rcvr
+ numArgs: numArgs!

Item was changed:
  CogClass subclass: #Cogit
+ instanceVariableNames: 'coInterpreter objectMemory objectRepresentation processor threadManager methodZone methodZoneBase codeBase minValidCallAddress lastNInstructions simulatedAddresses simulatedTrampolines simulatedVariableGetters simulatedVariableSetters printRegisters printInstructions compilationTrace clickConfirm breakPC breakBlock singleStep guardPageSize traceFlags traceStores breakMethod methodObj enumeratingCogMethod methodHeader initialPC endPC methodOrBlockNumArgs inBlock needsFrame hasYoungReferent primitiveIndex backEnd literalsManager postCompileHook methodLabel stackCheckLabel blockEntryLabel blockEntryNoContextSwitch blockNoContextSwitchOffset stackOverflowCall sendMiss missOffset entryPointMask checkedEntryAlignment uncheckedEntryAlignment cmEntryOffset entry cmNoCheckEntryOffset noCheckEntry fullBlockEntry cbEntryOffset fullBlockNoContextSwitchEntry cbNoSwitchEntryOffset picMNUAbort picInterpretAbort endCPICCase0 endCPICCase1 firstCPICCaseOffset cPICCaseSize cP
 ICEndSize closedPICSize openPICSize fixups abstractOpcodes generatorTable byte0 byte1 byte2 byte3 bytecodePC bytecodeSetOffset opcodeIndex numAbstractOpcodes blockStarts blockCount labelCounter cStackAlignment expectedSPAlignment expectedFPAlignment codeModified maxLitIndex ceMethodAbortTrampoline cePICAbortTrampoline ceCheckForInterruptTrampoline ceCPICMissTrampoline ceReturnToInterpreterTrampoline ceBaseFrameReturnTrampoline ceReapAndResetErrorCodeTrampoline ceSendMustBeBooleanAddTrueTrampoline ceSendMustBeBooleanAddFalseTrampoline ceCannotResumeTrampoline ceEnterCogCodePopReceiverReg ceCallCogCodePopReceiverReg ceCallCogCodePopReceiverAndClassRegs cePrimReturnEnterCogCode cePrimReturnEnterCogCodeProfiling ceNonLocalReturnTrampoline ceFetchContextInstVarTrampoline ceStoreContextInstVarTrampoline ceEnclosingObjectTrampoline ceFlushICache ceCheckFeaturesFunction ceTraceLinkedSendTrampoline ceTraceBlockActivationTrampoline ceTraceStoreTrampoline ceGetFP ceGetSP ceCaptureCStackPointer
 s ordinarySendTrampolines superSendTrampolines directedSuperSendTrampolines directedSuperBindingSendTrampolines dynamicSuperSendTrampolines outerSendTrampolines selfSendTrampolines firstSend lastSend realCEEnterCogCodePopReceiverReg realCECallCogCodePopReceiverReg realCECallCogCodePopReceiverAndClassRegs trampolineTableIndex trampolineAddresses objectReferencesInRuntime runtimeObjectRefIndex cFramePointerInUse debugPrimCallStackOffset ceTryLockVMOwner ceUnlockVMOwner extA extB numExtB tempOop numIRCs indexOfIRC theIRCs receiverTags implicitReceiverSendTrampolines cogMethodSurrogateClass cogBlockMethodSurrogateClass nsSendCacheSurrogateClass CStackPointer CFramePointer cPICPrototype cPICEndOfCodeOffset cPICEndOfCodeLabel ceMallocTrampoline ceFreeTrampoline ceFFICalloutTrampoline debugBytecodePointers debugOpcodeIndices disassemblingMethod cogConstituentIndex directedSendUsesBinding'
+ classVariableNames: 'AltBlockCreationBytecodeSize AltFirstSpecialSelector AltNSSendIsPCAnnotated AltNumSpecialSelectors AnnotationConstantNames AnnotationShift AnnotationsWithBytecodePCs BlockCreationBytecodeSize Debug DisplacementMask DisplacementX2N EagerInstructionDecoration FirstAnnotation FirstSpecialSelector HasBytecodePC IsAbsPCReference IsAnnotationExtension IsDirectedSuperBindingSend IsDirectedSuperSend IsDisplacementX2N IsNSDynamicSuperSend IsNSImplicitReceiverSend IsNSSelfSend IsNSSendCall IsObjectReference IsRelativeCall IsSendCall IsSuperSend MapEnd MaxCPICCases MaxCompiledPrimitiveIndex MaxStackAllocSize MaxX2NDisplacement NSCClassTagIndex NSCEnclosingObjectIndex NSCNumArgsIndex NSCSelectorIndex NSCTargetIndex NSSendIsPCAnnotated NumObjRefsInRuntime NumOopsPerNSC NumSpecialSelectors NumTrampolines ProcessorClass RRRName'
- instanceVariableNames: 'coInterpreter objectMemory objectRepresentation processor threadManager methodZone methodZoneBase codeBase minValidCallAddress lastNInstructions simulatedAddresses simulatedTrampolines simulatedVariableGetters simulatedVariableSetters printRegisters printInstructions compilationTrace clickConfirm breakPC breakBlock singleStep guardPageSize traceFlags traceStores breakMethod methodObj enumeratingCogMethod methodHeader initialPC endPC methodOrBlockNumArgs inBlock needsFrame hasYoungReferent primitiveIndex backEnd literalsManager postCompileHook methodLabel stackCheckLabel blockEntryLabel blockEntryNoContextSwitch blockNoContextSwitchOffset stackOverflowCall sendMiss missOffset entryPointMask checkedEntryAlignment uncheckedEntryAlignment cmEntryOffset entry cmNoCheckEntryOffset noCheckEntry fullBlockEntry cbEntryOffset fullBlockNoContextSwitchEntry cbNoSwitchEntryOffset picMNUAbort picInterpretAbort endCPICCase0 endCPICCase1 firstCPICCaseOffset cPICCaseSize cP
 ICEndSize closedPICSize openPICSize fixups abstractOpcodes generatorTable byte0 byte1 byte2 byte3 bytecodePC bytecodeSetOffset opcodeIndex numAbstractOpcodes blockStarts blockCount labelCounter cStackAlignment expectedSPAlignment expectedFPAlignment codeModified maxLitIndex ceMethodAbortTrampoline cePICAbortTrampoline ceCheckForInterruptTrampoline ceCPICMissTrampoline ceReturnToInterpreterTrampoline ceBaseFrameReturnTrampoline ceReapAndResetErrorCodeTrampoline ceSendMustBeBooleanAddTrueTrampoline ceSendMustBeBooleanAddFalseTrampoline ceCannotResumeTrampoline ceEnterCogCodePopReceiverReg ceCallCogCodePopReceiverReg ceCallCogCodePopReceiverAndClassRegs cePrimReturnEnterCogCode cePrimReturnEnterCogCodeProfiling ceNonLocalReturnTrampoline ceFetchContextInstVarTrampoline ceStoreContextInstVarTrampoline ceEnclosingObjectTrampoline ceFlushICache ceCheckFeaturesFunction ceTraceLinkedSendTrampoline ceTraceBlockActivationTrampoline ceTraceStoreTrampoline ceGetFP ceGetSP ceCaptureCStackPointer
 s ordinarySendTrampolines superSendTrampolines directedSuperSendTrampolines dynamicSuperSendTrampolines outerSendTrampolines selfSendTrampolines firstSend lastSend realCEEnterCogCodePopReceiverReg realCECallCogCodePopReceiverReg realCECallCogCodePopReceiverAndClassRegs trampolineTableIndex trampolineAddresses objectReferencesInRuntime runtimeObjectRefIndex cFramePointerInUse debugPrimCallStackOffset ceTryLockVMOwner ceUnlockVMOwner extA extB numExtB tempOop numIRCs indexOfIRC theIRCs receiverTags implicitReceiverSendTrampolines cogMethodSurrogateClass cogBlockMethodSurrogateClass nsSendCacheSurrogateClass CStackPointer CFramePointer cPICPrototype cPICEndOfCodeOffset cPICEndOfCodeLabel ceMallocTrampoline ceFreeTrampoline ceFFICalloutTrampoline debugBytecodePointers debugOpcodeIndices disassemblingMethod cogConstituentIndex'
- classVariableNames: 'AltBlockCreationBytecodeSize AltFirstSpecialSelector AltNSSendIsPCAnnotated AltNumSpecialSelectors AnnotationConstantNames AnnotationShift AnnotationsWithBytecodePCs BlockCreationBytecodeSize Debug DisplacementMask DisplacementX2N EagerInstructionDecoration FirstAnnotation FirstSpecialSelector HasBytecodePC IsAbsPCReference IsAnnotationExtension IsDirectedSuperSend IsDisplacementX2N IsNSDynamicSuperSend IsNSImplicitReceiverSend IsNSSelfSend IsNSSendCall IsObjectReference IsRelativeCall IsSendCall IsSuperSend MapEnd MaxCPICCases MaxCompiledPrimitiveIndex MaxStackAllocSize MaxX2NDisplacement NSCClassTagIndex NSCEnclosingObjectIndex NSCNumArgsIndex NSCSelectorIndex NSCTargetIndex NSSendIsPCAnnotated NumObjRefsInRuntime NumOopsPerNSC NumSpecialSelectors NumTrampolines ProcessorClass RRRName'
  poolDictionaries: 'CogAbstractRegisters CogCompilationConstants CogMethodConstants CogRTLOpcodes VMBasicConstants VMBytecodeConstants VMObjectIndices VMStackFrameOffsets'
  category: 'VMMaker-JIT'!
  Cogit class
  instanceVariableNames: 'generatorTable primitiveTable'!
 
  !Cogit commentStamp: 'eem 2/25/2017 17:53' prior: 0!
  I am the code generator for the Cog VM.  My job is to produce machine code versions of methods for faster execution and to manage inline caches for faster send performance.  I can be tested in the current image using my class-side in-image compilation facilities.  e.g. try
 
  StackToRegisterMappingCogit genAndDis: (Integer >> #benchFib)
 
  I have concrete subclasses that implement different levels of optimization:
  SimpleStackBasedCogit is the simplest code generator.
 
  StackToRegisterMappingCogit is the current production code generator  It defers pushing operands
  to the stack until necessary and implements a register-based calling convention for low-arity sends.
 
  SistaCogit is an experimental code generator with support for counting
  conditional branches, intended to support adaptive optimization.
 
  RegisterAllocatingCogit is an experimental code generator with support for allocating temporary variables
  to registers. It is inended to serve as the superclass to SistaCogit once it is working.
 
  SistaRegisterAllocatingCogit and SistaCogitClone are temporary classes that allow testing a clone of
  SistaCogit that inherits from RegisterAllocatingCogit.  Once things work these will be merged and
  will replace SistaCogit.
 
  coInterpreter <CoInterpreterSimulator>
  the VM's interpreter with which I cooperate
  methodZoneManager <CogMethodZoneManager>
  the manager of the machine code zone
  objectRepresentation <CogObjectRepresentation>
  the object used to generate object accesses
  processor <BochsIA32Alien|?>
  the simulator that executes the IA32/x86 machine code I generate when simulating execution in Smalltalk
  simulatedTrampolines <Dictionary of Integer -> MessageSend>
  the dictionary mapping trap jump addresses to run-time routines used to warp from simulated machine code in to the Smalltalk run-time.
  simulatedVariableGetters <Dictionary of Integer -> MessageSend>
  the dictionary mapping trap read addresses to variables in run-time objects used to allow simulated machine code to read variables in the Smalltalk run-time.
  simulatedVariableSetters <Dictionary of Integer -> MessageSend>
  the dictionary mapping trap write addresses to variables in run-time objects used to allow simulated machine code to write variables in the Smalltalk run-time.
  printRegisters printInstructions clickConfirm <Boolean>
  flags controlling debug printing and code simulation
  breakPC <Integer>
  machine code pc breakpoint
  cFramePointer cStackPointer <Integer>
  the variables representing the C stack & frame pointers, which must change on FFI callback and return
  selectorOop <sqInt>
  the oop of the methodObj being compiled
  methodObj <sqInt>
  the bytecode method being compiled
  initialPC endPC <Integer>
  the start and end pcs of the methodObj being compiled
  methodOrBlockNumArgs <Integer>
  argument count of current method or block being compiled
  needsFrame <Boolean>
  whether methodObj or block needs a frame to execute
  primitiveIndex <Integer>
  primitive index of current method being compiled
  methodLabel <CogAbstractOpcode>
  label for the method header
  blockEntryLabel <CogAbstractOpcode>
  label for the start of the block dispatch code
  stackOverflowCall <CogAbstractOpcode>
  label for the call of ceStackOverflow in the method prolog
  sendMissCall <CogAbstractOpcode>
  label for the call of ceSICMiss in the method prolog
  entryOffset <Integer>
  offset of method entry code from start (header) of method
  entry <CogAbstractOpcode>
  label for the first instruction of the method entry code
  noCheckEntryOffset <Integer>
  offset of the start of a method proper (after the method entry code) from start (header) of method
  noCheckEntry <CogAbstractOpcode>
  label for the first instruction of start of a method proper
  fixups <Array of <AbstractOpcode Label | nil>>
  the labels for forward jumps that will be fixed up when reaching the relevant bytecode.  fixups has one element per byte in methodObj's bytecode; initialPC maps to fixups[0].
  abstractOpcodes <Array of <AbstractOpcode>>
  the code generated when compiling methodObj
  byte0 byte1 byte2 byte3 <Integer>
  individual bytes of current bytecode being compiled in methodObj
  bytecodePointer <Integer>
  bytecode pc (same as Smalltalk) of the current bytecode being compiled
  opcodeIndex <Integer>
  the index of the next free entry in abstractOpcodes (this code is translated into C where OrderedCollection et al do not exist)
  numAbstractOpcodes <Integer>
  the number of elements in abstractOpcocdes
  blockStarts <Array of <BlockStart>>
  the starts of blocks in the current method
  blockCount
  the index into blockStarts as they are being noted, and hence eventually the total number of blocks in the current method
  labelCounter <Integer>
  a nicety for numbering labels not needed in the production system but probably not expensive enough to worry about
  ceStackOverflowTrampoline <Integer>
  ceSend0ArgsTrampoline <Integer>
  ceSend1ArgsTrampoline <Integer>
  ceSend2ArgsTrampoline <Integer>
  ceSendNArgsTrampoline <Integer>
  ceSendSuper0ArgsTrampoline <Integer>
  ceSendSuper1ArgsTrampoline <Integer>
  ceSendSuper2ArgsTrampoline <Integer>
  ceSendSuperNArgsTrampoline <Integer>
  ceSICMissTrampoline <Integer>
  ceCPICMissTrampoline <Integer>
  ceStoreCheckTrampoline <Integer>
  ceReturnToInterpreterTrampoline <Integer>
  ceBaseFrameReturnTrampoline <Integer>
  ceSendMustBeBooleanTrampoline <Integer>
  ceClosureCopyTrampoline <Integer>
  the various trampolines (system-call-like jumps from machine code to the run-time).
  See Cogit>>generateTrampolines for the mapping from trampoline to run-time
  routine and then read the run-time routine for a funcitonal description.
  ceEnterCogCodePopReceiverReg <Integer>
  the enilopmart (jump from run-time to machine-code)
  methodZoneBase <Integer>
  !
  Cogit class
  instanceVariableNames: 'generatorTable primitiveTable'!

Item was changed:
  ----- Method: Cogit class>>declareCVarsIn: (in category 'translation') -----
  declareCVarsIn: aCCodeGenerator
  #( 'coInterpreter' 'objectMemory' 'methodZone' 'objectRepresentation'
  'cogBlockMethodSurrogateClass' 'cogMethodSurrogateClass' 'nsSendCacheSurrogateClass'
  'threadManager' 'processor' 'lastNInstructions' 'simulatedAddresses'
  'simulatedTrampolines' 'simulatedVariableGetters' 'simulatedVariableSetters'
  '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: #ceFlushICache
  declareC: 'static void (*ceFlushICache)(usqIntptr_t from, usqIntptr_t to)';
  var: #ceCheckFeaturesFunction
  declareC: 'static usqIntptr_t (*ceCheckFeaturesFunction)(void)';
  var: #ceTryLockVMOwner
  declareC: 'usqIntptr_t (*ceTryLockVMOwner)(void)';
  var: #ceUnlockVMOwner
  declareC: 'void (*ceUnlockVMOwner)(void)';
  var: #postCompileHook
  declareC: 'void (*postCompileHook)(CogMethod *)';
  var: #openPICList declareC: 'CogMethod *openPICList = 0';
  var: #maxMethodBefore type: #'CogBlockMethod *';
  var: 'enumeratingCogMethod' type: #'CogMethod *'.
  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: #blockStarts type: #'BlockStart *';
  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
- declareC: 'sqInt superSendTrampolines[NumSendTrampolines]';
- var: #directedSuperSendTrampolines
- declareC: 'sqInt directedSuperSendTrampolines[NumSendTrampolines]';
- var: #selfSendTrampolines
- declareC: 'sqInt selfSendTrampolines[NumSendTrampolines]';
- var: #dynamicSuperSendTrampolines
- declareC: 'sqInt dynamicSuperSendTrampolines[NumSendTrampolines]';
- var: #implicitReceiverSendTrampolines
- declareC: 'sqInt implicitReceiverSendTrampolines[NumSendTrampolines]';
- var: #outerSendTrampolines
- declareC: 'sqInt outerSendTrampolines[NumSendTrampolines]';
  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: #CFramePointer type: #'void *';
  declareVar: #CStackPointer type: #'void *';
  declareVar: #minValidCallAddress type: #'usqIntptr_t';
  declareVar: #debugPrimCallStackOffset type: #'usqIntptr_t'.
  aCCodeGenerator vmClass generatorTable ifNotNil:
  [:bytecodeGenTable|
  aCCodeGenerator
  var: #generatorTable
  declareC: 'static BytecodeDescriptor generatorTable[', bytecodeGenTable size, ']',
  (self tableInitializerFor: bytecodeGenTable
  in: aCCodeGenerator)].
  "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'!

Item was changed:
  ----- Method: Cogit class>>initializeAnnotationConstants (in category 'class initialization') -----
  initializeAnnotationConstants
  "These form the method map for a cog method.  The map defines which addresses
  in a machine code method are ones with important functions, such as being a send
  site or being a reference to a heap object.  Each annotated instruction has a byte
  in the map, and each byte in the map has two parts.  In the least signficant bits are
  a distance in codeGranularity units from the start of the method or the previous
  map entry, except for the IsAnnotationExtension type.  In the most signficant bits
  are the type of annotation at the point reached.  A null byte ends the map.  The
  first mapped location is a distance from the cmNoCheckEntryOffset.
 
  The map occurs at the end of a method (*), in reverse, so that its start is found
  by adding the method's block size.  If the distance between two mapped
  instructions will not fit in the displacement field then one or more displacement
  entries are placed in the map to bridge the gap.  There is a * 32 displacement
  units type for spanning large gaps.  The displacements are in codeGranularity
  units so that processors like e.g. ARM, with 4-byte instructions, do not have overly
  large maps.  In [practice maps are very compact, but they should be as quick to
  navigate as possible, and hence be as compact as possible.
 
  There is only one kind of call annotation that serves for all calls from machine
  code. There are several kinds of call, sends, super sends, calls of the generated
  run-time, and direct calls of primitive functions in the interpreter.  These need
  different treatment at different times.  For example, when the send cache is
  flushed or the method zone is shrunk some sends must be unlinked and some
  sends must be relocated.  But to be able to parse bytecoded methods and match
  their pcs with corresponding machine code pcs the map needs to differentiate
  between sends and run-time calls.
 
  Sends can be distinguished from run-time or direct primitive calls based on address;
  only sends have their target between methodZoneBase and methodZone freeStart.
  We used to distinguish normal sends from super sends based on alignment of
  entry-point, because normal sends link to the checked entry-point, whereas super sends
  link to the unchecked entry-point, and both entry points have different alignments.
  But now we use the IsAnnotationExtension to label sends other than normal sends.
  For these ``exotic'' sends there is both an IsAnnotationExtension annotation and an
  IsSendCall annotation.
 
  While run-time calls can be distinguished from direct primitive calls on the basis
  of address there is no need to do so.  They are merely calls to locations that
  don't move during method zone compaction.
 
  Absolute PC references are used for method references and counter references.
  These are references from within a particular method to absolute pcs in that same
  method that must be relocated when the method moves."
  "self initializeAnnotationConstants"
 
  AnnotationShift := 5.
  IsDisplacementX2N := 0. "N.B. A 0 byte ends the map"
  IsAnnotationExtension := 1. "Used to extend IsSendCall with different codes for exotic send types."
  IsObjectReference := 2.
  IsAbsPCReference := 3.
  IsRelativeCall := 4.
  HasBytecodePC := 5.
  IsNSSendCall := NewspeakVM ifTrue: [6].
  IsSendCall := 7.
  "These are formed by combining IsSendCall and IsAnnotationExtension annotations."
  IsSuperSend := 8.
+ IsDirectedSuperSend := BytecodeSetHasDirectedSuperSend ifTrue: [9].
+ IsDirectedSuperBindingSend := BytecodeSetHasDirectedSuperSend ifTrue: [10].
+ IsNSSelfSend := NewspeakVM ifTrue: [11].
+ IsNSDynamicSuperSend := NewspeakVM ifTrue: [12].
+ IsNSImplicitReceiverSend := NewspeakVM ifTrue: [13].
- IsDirectedSuperSend := 9.
- IsNSSelfSend := NewspeakVM ifTrue: [10].
- IsNSDynamicSuperSend := NewspeakVM ifTrue: [11].
- IsNSImplicitReceiverSend := NewspeakVM ifTrue: [12].
 
  DisplacementMask := (1 << AnnotationShift) - 1.
  DisplacementX2N := IsDisplacementX2N << AnnotationShift.
  FirstAnnotation := IsObjectReference << AnnotationShift.
  MaxX2NDisplacement := DisplacementMask << AnnotationShift.
 
  MapEnd := 0.
 
  AnnotationConstantNames := #( IsDisplacementX2N
  IsAnnotationExtension
  IsObjectReference
  IsAbsPCReference
  IsRelativeCall
  HasBytecodePC
  IsNSSendCall
  IsSendCall
  IsSuperSend
  IsDirectedSuperSend
+ IsDirectedSuperBindingSend
  IsNSSelfSend
  IsNSDynamicSuperSend
  IsNSImplicitReceiverSend).
  AnnotationsWithBytecodePCs := #(HasBytecodePC
  IsNSSendCall
  IsSendCall
  IsSuperSend
  IsDirectedSuperSend
+ IsDirectedSuperBindingSend
  IsNSSelfSend
  IsNSDynamicSuperSend
  IsNSImplicitReceiverSend),
  {'IsRelativeCall:\HasBytecodePC' withCRs}!

Item was changed:
  ----- Method: Cogit class>>initializeNumTrampolines (in category 'class initialization') -----
  initializeNumTrampolines
  NumTrampolines := self numTrampolines
  + self objectRepresentationClass numTrampolines
+ + (NewspeakVM ifTrue: [NumSendTrampolines * 4 + 2] ifFalse: [0])
+ + (BytecodeSetHasDirectedSuperSend ifTrue: [NumSendTrampolines * 2] ifFalse: [0])!
- + (NewspeakVM ifTrue: [18] ifFalse: [0])
- + (BytecodeSetHasDirectedSuperSend ifTrue: [4] ifFalse: [0])!

Item was changed:
  ----- Method: Cogit>>annotationIsForUncheckedEntryPoint: (in category 'in-line cacheing') -----
  annotationIsForUncheckedEntryPoint: annotation
  <inline: true>
  ^annotation = IsSuperSend
+  or: [BytecodeSetHasDirectedSuperSend
+  and: [annotation
+ between: IsDirectedSuperSend
+ and: IsDirectedSuperBindingSend]]!
-  or: [BytecodeSetHasDirectedSuperSend and: [annotation = IsDirectedSuperSend]]!

Item was changed:
  ----- Method: Cogit>>generateClosedPICPrototype (in category 'initialization') -----
  generateClosedPICPrototype
  "Generate the prototype ClosedPIC to determine how much space as full PIC takes.
  When we first allocate a closed PIC it only has one or two cases and we want to grow it.
  So we have to determine how big a full one is before hand."
  | cPIC endAddress |
  <var: 'cPIC' type: #'CogMethod *'>
  "stack allocate the various collections so that they
  are effectively garbage collected on return."
  self allocateOpcodes: MaxCPICCases * 9 bytecodes: 0.
  methodLabel address: methodZoneBase; dependent: nil. "for pc-relative MoveCw: cPIC R: ClassReg"
  self compileClosedPICPrototype.
  self computeMaximumSizes.
  cPIC := (self cCoerceSimple: methodZoneBase to: #'CogMethod *').
  closedPICSize := (self sizeof: CogMethod) + (self generateInstructionsAt: methodZoneBase + (self sizeof: CogMethod)).
  endAddress := self outputInstructionsAt: methodZoneBase + (self sizeof: CogMethod).
  self assert: methodZoneBase + closedPICSize = endAddress.
  firstCPICCaseOffset := endCPICCase0 address - methodZoneBase.
  cPICEndOfCodeOffset := cPICEndOfCodeLabel address - methodZoneBase.
  cPICCaseSize := endCPICCase1 address - endCPICCase0 address.
  cPICEndSize := closedPICSize - (MaxCPICCases - 1 * cPICCaseSize + firstCPICCaseOffset).
  closedPICSize := methodZone roundUpLength: closedPICSize.
  self assert: picInterpretAbort address = (methodLabel address + self picInterpretAbortOffset).
  self assert: (self expectedClosedPICPrototype: cPIC) = 0.
 
  "tpr this is a little tiresome but after any assert checking we need to 0 out the case0 objRef rather than leaving 16r5EAF00D lying around"
 
  backEnd storeLiteral: 0 beforeFollowingAddress: endCPICCase0 address - backEnd jumpLongByteSize.
 
+ "update the methodZoneBase so we keep the prototype around for later use"
- "update the methodZoneBase so we keep the prototype aruond for later use"
  methodZoneBase := self alignUptoRoutineBoundary: endAddress.
  cPICPrototype := cPIC.
  "self cCode: ''
  inSmalltalk:
  [self disassembleFrom: cPIC + (self sizeof: CogMethod) to: cPIC + closedPICSize - 1.
  self halt]"!

Item was changed:
  ----- Method: Cogit>>generateSendTrampolines (in category 'initialization') -----
  generateSendTrampolines
  0 to: NumSendTrampolines - 1 do:
  [:numArgs|
  ordinarySendTrampolines
  at: numArgs
  put: (self genTrampolineFor: #ceSend:super:to:numArgs:
   called: (self trampolineName: 'ceSend' numArgs: numArgs)
   arg: ClassReg
   arg: (self trampolineArgConstant: false)
   arg: ReceiverResultReg
   arg: (self numArgsOrSendNumArgsReg: numArgs))].
 
  "Generate these in the middle so they are within [firstSend, lastSend]."
  NewspeakVM ifTrue:
  [self generateNewspeakSendTrampolines].
  BytecodeSetHasDirectedSuperSend ifTrue:
  [0 to: NumSendTrampolines - 1 do:
  [:numArgs|
  directedSuperSendTrampolines
  at: numArgs
  put: (self genTrampolineFor: #ceSend:above:to:numArgs:
   called: (self trampolineName: 'ceDirectedSuperSend' numArgs: numArgs)
   arg: ClassReg
   arg: TempReg
   arg: ReceiverResultReg
+  arg: (self numArgsOrSendNumArgsReg: numArgs)).
+ directedSuperBindingSendTrampolines
+ at: numArgs
+ put: (self genTrampolineFor: #ceSend:aboveClassBinding:to:numArgs:
+  called: (self trampolineName: 'ceDirectedSuperBindingSend' numArgs: numArgs)
+  arg: ClassReg
+  arg: TempReg
+  arg: ReceiverResultReg
   arg: (self numArgsOrSendNumArgsReg: numArgs))]].
 
  0 to: NumSendTrampolines - 1 do:
  [:numArgs|
  superSendTrampolines
  at: numArgs
  put: (self genTrampolineFor: #ceSend:super:to:numArgs:
   called: (self trampolineName: 'ceSuperSend' numArgs: numArgs)
   arg: ClassReg
   arg: (self trampolineArgConstant: true)
   arg: ReceiverResultReg
   arg: (self numArgsOrSendNumArgsReg: numArgs))].
  firstSend := ordinarySendTrampolines at: 0.
  lastSend := superSendTrampolines at: NumSendTrampolines - 1!

Item was changed:
  ----- Method: Cogit>>offsetAndSendTableFor:annotation:into: (in category 'in-line cacheing') -----
  offsetAndSendTableFor: entryPoint annotation: annotation into: binaryBlock
  "Find the relevant sendTable for a linked-send to entryPoint.  Do this based on the
  annotation.  c.f. annotationForSendTable:"
  <inline: true>
  | offset sendTable |
  <var: #sendTable type: #'sqInt *'>
  annotation = IsSendCall ifTrue:
  [offset := cmEntryOffset.
  sendTable := ordinarySendTrampolines] ifFalse:
  [(BytecodeSetHasDirectedSuperSend and: [annotation = IsDirectedSuperSend]) ifTrue:
  [offset := cmNoCheckEntryOffset.
  sendTable := directedSuperSendTrampolines] ifFalse:
+ [(BytecodeSetHasDirectedSuperSend and: [annotation = IsDirectedSuperBindingSend]) ifTrue:
+ [offset := cmNoCheckEntryOffset.
+ sendTable := directedSuperBindingSendTrampolines] ifFalse:
  [(NewspeakVM and: [annotation = IsNSSelfSend]) ifTrue:
  [offset := cmEntryOffset.
  sendTable := selfSendTrampolines] ifFalse:
  [(NewspeakVM and: [annotation = IsNSDynamicSuperSend]) ifTrue:
  [offset := cmEntryOffset.
  sendTable := dynamicSuperSendTrampolines] ifFalse:
  [self assert: annotation = IsSuperSend.
  offset := cmNoCheckEntryOffset.
+ sendTable := superSendTrampolines]]]]].
- sendTable := superSendTrampolines]]]].
 
  binaryBlock
  value: offset
  value: sendTable!

Item was changed:
  ----- Method: Cogit>>printPCMapPairsFor: (in category 'method map') -----
  printPCMapPairsFor: cogMethod
+ <doNotGenerate>
+ "<api>
- <api>
  <var: 'cogMethod' type: #'CogMethod *'>
+ <var: 'mapByte' type: #'unsigned char'>"
- <var: 'mapByte' type: #'unsigned char'>
  | mcpc map mapByte annotation value |
  mcpc := self firstMappedPCFor: cogMethod.
  map := self mapStartFor: cogMethod.
  [(mapByte := objectMemory byteAt: map) ~= MapEnd] whileTrue:
  [annotation := mapByte >> AnnotationShift.
  annotation = IsAnnotationExtension
  ifTrue:
  [value := (mapByte bitAnd: DisplacementMask) + IsSendCall]
  ifFalse:
  [value := annotation.
  mcpc := mcpc + (backEnd codeGranularity
  * (annotation = IsDisplacementX2N
  ifTrue: [mapByte - DisplacementX2N << AnnotationShift]
  ifFalse: [mapByte bitAnd: DisplacementMask]))].
  coInterpreter
  printHexnp: map;
  print: ': '.
  self
  cCode: [self print: '%02x' f: mapByte]
  inSmalltalk:
  [mapByte < 16 ifTrue:
  [coInterpreter putchar: $0].
  coInterpreter printHexnp: mapByte].
  coInterpreter
  printChar: $ ;
  printNum: annotation;
  print: ' ('.
+ (NewspeakVM
+  and: [value = IsNSSendCall
+     or: [value between: IsNSSendCall and: IsNSImplicitReceiverSend]]) ifTrue:
+ [value
+ caseOf: {
+ [IsNSSendCall] -> [coInterpreter print: 'NSSendCall'].
+ [IsNSSelfSend] -> [coInterpreter print: 'NSSelfSend'].
+ [IsNSDynamicSuperSend] -> [coInterpreter print: 'NSDynamicSuperSend'].
+ [IsNSImplicitReceiverSend] -> [coInterpreter print: 'NSImplicitReceiverSend'] }] ifFalse:
+ [(BytecodeSetHasDirectedSuperSend
+    and: [value between: IsDirectedSuperSend and: IsDirectedSuperBindingSend]) ifTrue:
+ [value
+ caseOf: {
+ [IsDirectedSuperSend] -> [coInterpreter print: 'DirectedSuperSend'].
+ [IsDirectedSuperBindingSend] -> [coInterpreter print: 'DirectedSuperBindingSend'] }] ifFalse:
+ [value
+ caseOf: {
+ [IsDisplacementX2N] -> [coInterpreter print: 'DisplacementX2N'].
+ [IsAnnotationExtension] -> [coInterpreter print: 'AnnotationExtension'].
+ [IsObjectReference] -> [coInterpreter print: 'ObjectReference'].
+ [IsAbsPCReference] -> [coInterpreter print: 'AbsPCReference'].
+ [HasBytecodePC] -> [coInterpreter print: 'HasBytecodePC'].
+ [IsRelativeCall] -> [coInterpreter print: 'RelativeCall'].
+ [IsSendCall] -> [coInterpreter print: 'SendCall'].
+ [IsSuperSend] -> [coInterpreter print: 'SuperSend'] }
+ otherwise: [coInterpreter print: '??? '; printHexnp: value]]].
- NewspeakVM
- ifTrue:
- [value
- caseOf: {
- [IsDisplacementX2N] -> [coInterpreter print: 'IsDisplacementX2N'].
- [IsAnnotationExtension] -> [coInterpreter print: 'IsAnnotationExtension'].
- [IsObjectReference] -> [coInterpreter print: 'IsObjectReference'].
- [IsAbsPCReference] -> [coInterpreter print: 'IsAbsPCReference'].
- [HasBytecodePC] -> [coInterpreter print: 'HasBytecodePC'].
- [IsRelativeCall] -> [coInterpreter print: 'IsRelativeCall'].
- [IsNSSendCall] -> [coInterpreter print: 'IsNSSendCall'].
- [IsSendCall] -> [coInterpreter print: 'IsSendCall'].
- [IsSuperSend] -> [coInterpreter print: 'IsSuperSend'].
- [IsDirectedSuperSend] -> [coInterpreter print: 'IsDirectedSuperSend'].
- [IsNSSelfSend] -> [coInterpreter print: 'IsNSSelfSend'].
- [IsNSDynamicSuperSend] -> [coInterpreter print: 'IsNSDynamicSuperSend'].
- [IsNSImplicitReceiverSend] -> [coInterpreter print: 'IsNSImplicitReceiverSend'] }
- otherwise: [coInterpreter print: '??? '; printHexnp: value]]
- ifFalse:
- [value
- caseOf: {
- [IsDisplacementX2N] -> [coInterpreter print: 'IsDisplacementX2N'].
- [IsAnnotationExtension] -> [coInterpreter print: 'IsAnnotationExtension'].
- [IsObjectReference] -> [coInterpreter print: 'IsObjectReference'].
- [IsAbsPCReference] -> [coInterpreter print: 'IsAbsPCReference'].
- [HasBytecodePC] -> [coInterpreter print: 'HasBytecodePC'].
- [IsRelativeCall] -> [coInterpreter print: 'IsRelativeCall'].
- [IsSendCall] -> [coInterpreter print: 'IsSendCall'].
- [IsSuperSend] -> [coInterpreter print: 'IsSuperSend'].
- [IsDirectedSuperSend] -> [coInterpreter print: 'IsDirectedSuperSend'] }
- otherwise: [coInterpreter print: '??? '; printHexnp: value]].
  coInterpreter
  print: ') ';
  printHexnp: (mapByte bitAnd: DisplacementMask);
  printChar: $ ;
  putchar: $@;
  printHex: mcpc;
  cr;
  flush.
  map := map - 1]!

Item was changed:
  ----- Method: Cogit>>setInterpreter: (in category 'initialization') -----
  setInterpreter: aCoInterpreter
  "Initialization of the code generator in the simulator.
  These objects already exist in the generated C VM
  or are used only in the simulation."
  <doNotGenerate>
  coInterpreter := aCoInterpreter.
  objectMemory := aCoInterpreter objectMemory.
  threadManager := aCoInterpreter threadManager. "N.B. may be nil"
  methodZone := self class methodZoneClass new.
  objectRepresentation := objectMemory objectRepresentationClass
  forCogit: self methodZone: methodZone.
  methodZone setInterpreter: aCoInterpreter
  objectRepresentation: objectRepresentation
  cogit: self.
  generatorTable := self class generatorTable.
  processor := ProcessorClass new.
  simulatedAddresses := Dictionary new.
  simulatedTrampolines := Dictionary new.
  simulatedVariableGetters := Dictionary new.
  simulatedVariableSetters := Dictionary new.
  traceStores := 0.
  traceFlags := (self class initializationOptions at: #recordPrimTrace ifAbsent: [true])
  ifTrue: [8] "record prim trace on by default (see Cogit class>>decareCVarsIn:)"
  ifFalse: [0].
  debugPrimCallStackOffset := 0.
  singleStep := printRegisters := printInstructions := clickConfirm := false.
  backEnd := CogCompilerClass for: self.
  methodLabel := CogCompilerClass for: self.
  (literalsManager := backEnd class literalsManagerClass new) cogit: self.
  ordinarySendTrampolines := CArrayAccessor on: (Array new: NumSendTrampolines).
  superSendTrampolines := CArrayAccessor on: (Array new: NumSendTrampolines).
  BytecodeSetHasDirectedSuperSend ifTrue:
+ [directedSuperSendTrampolines := CArrayAccessor on: (Array new: NumSendTrampolines).
+ directedSuperBindingSendTrampolines := CArrayAccessor on: (Array new: NumSendTrampolines).
+ directedSendUsesBinding := false].
- [directedSuperSendTrampolines := CArrayAccessor on: (Array new: NumSendTrampolines)].
  NewspeakVM ifTrue:
  [selfSendTrampolines := CArrayAccessor on: (Array new: NumSendTrampolines).
  dynamicSuperSendTrampolines := CArrayAccessor on: (Array new: NumSendTrampolines).
  implicitReceiverSendTrampolines := CArrayAccessor on: (Array new: NumSendTrampolines).
  outerSendTrampolines := CArrayAccessor on: (Array new: NumSendTrampolines)].
  "debug metadata"
  objectReferencesInRuntime := CArrayAccessor on: (Array new: NumObjRefsInRuntime).
  runtimeObjectRefIndex := 0.
  "debug metadata"
  trampolineAddresses := CArrayAccessor on: (Array new: NumTrampolines * 2).
  trampolineTableIndex := 0.
 
  extA := numExtB := extB := 0.
 
  compilationTrace ifNil: [compilationTrace := self class initializationOptions at: #compilationTrace ifAbsent: [0]].
  debugOpcodeIndices := self class initializationOptions at: #debugOpcodeIndices ifAbsent: [Set new].
  debugBytecodePointers := self class initializationOptions at: #debugBytecodePointers ifAbsent: [Set new].
  self class initializationOptions at: #breakPC ifPresent: [:pc| breakPC := pc]!

Item was changed:
  ----- Method: Cogit>>targetMethodAndSendTableFor:annotation:into: (in category 'in-line cacheing') -----
  targetMethodAndSendTableFor: entryPoint annotation: annotation into: binaryBlock
  "Evaluate binaryBlock with the targetMethod and relevant send table for a linked-send
  to entryPoint.  Do so based on the alignment of entryPoint.  N.B.  For Newspeak sends
  we don't need to distinguish between ceImplicitReceiver and the other sends since
  ceImplicitReceiver will never appear to be linked, so only three cases here."
  <inline: true>
- | targetMethod sendTable |
  <var: #targetMethod type: #'CogMethod *'>
- <var: #sendTable type: #'sqInt *'>
 
+ self offsetAndSendTableFor: entryPoint
+ annotation: annotation
+ into: [:offset :sendTable| | targetMethod |
+ targetMethod := self cCoerceSimple: entryPoint - offset to: #'CogMethod *'.
+ binaryBlock
+ value: targetMethod
+ value: sendTable]!
- annotation = IsSendCall ifTrue:
- [targetMethod := self cCoerceSimple: entryPoint - cmEntryOffset to: #'CogMethod *'.
- sendTable := ordinarySendTrampolines] ifFalse:
- [(BytecodeSetHasDirectedSuperSend and: [annotation = IsDirectedSuperSend]) ifTrue:
- [targetMethod := self cCoerceSimple: entryPoint - cmNoCheckEntryOffset to: #'CogMethod *'.
- sendTable := directedSuperSendTrampolines] ifFalse:
- [(NewspeakVM and: [annotation = IsNSSelfSend]) ifTrue:
- [targetMethod := self cCoerceSimple: entryPoint - cmEntryOffset to: #'CogMethod *'.
- sendTable := selfSendTrampolines] ifFalse:
- [(NewspeakVM and: [annotation = IsNSDynamicSuperSend]) ifTrue:
- [targetMethod := self cCoerceSimple: entryPoint - cmEntryOffset to: #'CogMethod *'.
- sendTable := dynamicSuperSendTrampolines] ifFalse:
- [self assert: annotation = IsSuperSend.
- targetMethod := self cCoerceSimple: entryPoint - cmNoCheckEntryOffset to: #'CogMethod *'.
- sendTable := superSendTrampolines]]]].
-
- binaryBlock
- value: targetMethod
- value: sendTable!

Item was changed:
  ----- Method: SimpleStackBasedCogit>>annotationForSendTable: (in category 'bytecode generator support') -----
  annotationForSendTable: sendTable
  "c.f. offsetAndSendTableFor:annotation:into:"
  <inline: true>
  <var: #sendTable type: #'sqInt *'>
+ sendTable == ordinarySendTrampolines ifTrue:
+ [^IsSendCall].
+ BytecodeSetHasDirectedSuperSend ifTrue:
+ [sendTable == directedSuperSendTrampolines ifTrue:
+ [^IsDirectedSuperSend].
+ sendTable == directedSuperBindingSendTrampolines ifTrue:
+ [^IsDirectedSuperBindingSend]].
+ NewspeakVM ifTrue:
+ [sendTable == implicitReceiverSendTrampolines ifTrue:
+ [self error: 'Unexpected implicit receiver send using dirty send machinery'].
+ sendTable == outerSendTrampolines ifTrue:
+ [self error: 'Unexpected outer send using dirty send machinery'].
+ sendTable == selfSendTrampolines ifTrue:
+ [^IsNSSelfSend].
+ sendTable == dynamicSuperSendTrampolines ifTrue:
+ [^IsNSDynamicSuperSend]].
+ self assert: sendTable == superSendTrampolines.
+ ^IsSuperSend!
- (NewspeakVM and: [sendTable == implicitReceiverSendTrampolines]) ifTrue:
- [self error: 'Unexpected implicit receiver send using dirty send machinery'].
- (NewspeakVM and: [sendTable == outerSendTrampolines]) ifTrue:
- [self error: 'Unexpected outer send using dirty send machinery'].
- (NewspeakVM and: [sendTable == selfSendTrampolines]) ifTrue:
- [^IsNSSelfSend].
- (NewspeakVM and: [sendTable == dynamicSuperSendTrampolines]) ifTrue:
- [^IsNSDynamicSuperSend].
- (BytecodeSetHasDirectedSuperSend and: [sendTable == directedSuperSendTrampolines]) ifTrue:
- [^IsDirectedSuperSend].
- sendTable == superSendTrampolines ifTrue:
- [^IsSuperSend].
- self assert: sendTable == ordinarySendTrampolines.
- ^IsSendCall!

Item was removed:
- ----- Method: SimpleStackBasedCogit>>genExtPushLitVarDirSupBytecode (in category 'bytecode generators') -----
- genExtPushLitVarDirSupBytecode
- "227 11100011 i i i i i i i i Push Literal Variable #iiiiiiii (+ Extend A * 256)"
- | index |
- index := byte1 + (extA << 8).
- extA := 0.
- ^self genPushLiteralVariableGivenDirectedSuper: index!

Item was removed:
- ----- Method: SimpleStackBasedCogit>>genPushLitVarDirSup16CasesBytecode (in category 'bytecode generators') -----
- genPushLitVarDirSup16CasesBytecode
- "e.g. SistaV1: 16-31 0001 iiii Push Literal Variable #iiii"
- ^self genPushLiteralVariableGivenDirectedSuper: (byte0 bitAnd: 15)!

Item was removed:
- ----- Method: SimpleStackBasedCogit>>genPushLitVarDirSupBytecode (in category 'bytecode generators') -----
- genPushLitVarDirSupBytecode
- ^self genPushLiteralVariableGivenDirectedSuper: (byte0 bitAnd: 31)!

Item was changed:
  ----- Method: SimpleStackBasedCogit>>genPushLiteralIndex: (in category 'bytecode generator support') -----
  genPushLiteralIndex: literalIndex "<SmallInteger>"
  <inline: false>
  | literal |
  literal := self getLiteral: literalIndex.
+ BytecodeSetHasDirectedSuperSend ifTrue:
+ [self nextDescriptorExtensionsAndNextPCInto:
+ [:descriptor :exta :extb :followingPC|
+ (self isDirectedSuper: descriptor extA: exta extB: extb) ifTrue:
+ [tempOop := literal.
+ ^0]]].
  ^self genPushLiteral: literal!

Item was changed:
  ----- Method: SimpleStackBasedCogit>>genPushLiteralVariable: (in category 'bytecode generator support') -----
  genPushLiteralVariable: literalIndex
  <inline: false>
  | association |
  association := self getLiteral: literalIndex.
+ "If followed by a directed super send bytecode, avoid generating any code yet.
+ The association will be passed to the directed send trampoline in a register
+ and fully dereferenced only when first linked.  It will be ignored in later sends."
+ BytecodeSetHasDirectedSuperSend ifTrue:
+ [self deny: directedSendUsesBinding.
+ self nextDescriptorExtensionsAndNextPCInto:
+ [:descriptor :exta :extb :followingPC|
+ (self isDirectedSuper: descriptor extA: exta extB: extb) ifTrue:
+ [tempOop := association.
+ directedSendUsesBinding := true.
+ ^0]]].
  "N.B. Do _not_ use ReceiverResultReg to avoid overwriting receiver in assignment in frameless methods."
  self genMoveConstant: association R: ClassReg.
  objectRepresentation
  genEnsureObjInRegNotForwarded: ClassReg
  scratchReg: TempReg.
  objectRepresentation
  genLoadSlot: ValueIndex
  sourceReg: ClassReg
  destReg: TempReg.
  self PushR: TempReg.
  ^0!

Item was removed:
- ----- Method: SimpleStackBasedCogit>>genPushLiteralVariableGivenDirectedSuper: (in category 'bytecode generator support') -----
- genPushLiteralVariableGivenDirectedSuper: literalIndex
- "This is a version of genPushLiteralVariable: that looks ahead for a directed super send bytecode
- and does not generate any code for the dereference yet if followed by a directed super send."
- <inline: false>
- self nextDescriptorExtensionsAndNextPCInto:
- [:descriptor :exta :extb :followingPC|
- (self isDirectedSuper: descriptor extA: exta extB: extb) ifTrue:
- [tempOop := self getLiteral: literalIndex.
- ^0]].
- ^self genPushLiteralVariable: literalIndex!

Item was changed:
  ----- Method: SimpleStackBasedCogit>>genSend:numArgs:sendTable: (in category 'bytecode generator support') -----
  genSend: selectorIndex numArgs: numArgs sendTable: sendTable
  <inline: false>
  <var: #sendTable type: #'sqInt *'>
  | annotation |
  self assert: needsFrame.
  annotation := self annotationForSendTable: sendTable.
  self assert: (numArgs between: 0 and: 255). "say"
  self MoveMw: numArgs * objectMemory wordSize r: SPReg R: ReceiverResultReg.
  "Deal with stale super sends; see SpurMemoryManager's class comment."
  (self annotationIsForUncheckedEntryPoint: annotation) ifTrue:
  [objectRepresentation genEnsureOopInRegNotForwarded: ReceiverResultReg scratchReg: TempReg].
  "0 through (NumSendTrampolines - 2) numArgs sends have the arg count implciti in the trampoline.
  The last send trampoline (NumSendTrampolines - 1) passes numArgs in SendNumArgsReg."
  numArgs >= (NumSendTrampolines - 1) ifTrue:
  [self MoveCq: numArgs R: SendNumArgsReg].
  (BytecodeSetHasDirectedSuperSend
+ and: [annotation
+ between: IsDirectedSuperSend
+ and: IsDirectedSuperBindingSend]) ifTrue:
- and: [annotation = IsDirectedSuperSend]) ifTrue:
  [self genMoveConstant: tempOop R: TempReg].
  self genLoadInlineCacheWithSelector: selectorIndex.
  (self Call: (sendTable at: (numArgs min: NumSendTrampolines - 1))) annotation: annotation.
  self PushR: ReceiverResultReg.
  ^0!

Item was changed:
  ----- Method: SimpleStackBasedCogit>>genSendDirectedSuper:numArgs: (in category 'bytecode generator support') -----
  genSendDirectedSuper: selectorIndex numArgs: numArgs
  <inline: false>
  "N.B. genPushLiteralVariableGivenDirectedSuper: has already loaded tempOop with the association."
+ | result |
+ result := self
+ genSend: selectorIndex
+ numArgs: numArgs
+ sendTable: (directedSendUsesBinding
+ ifTrue: [directedSuperBindingSendTrampolines]
+ ifFalse: [directedSuperSendTrampolines]).
+ directedSendUsesBinding := false.
+ ^result!
- ^self genSend: selectorIndex numArgs: numArgs sendTable: directedSuperSendTrampolines!

Item was changed:
  ----- Method: StackToRegisterMappingCogit class>>initializeBytecodeTableForSistaV1 (in category 'class initialization') -----
  initializeBytecodeTableForSistaV1
  "StackToRegisterMappingCogit initializeBytecodeTableForSistaV1"
 
  numPushNilsFunction := #sistaV1:Num:Push:Nils:.
  pushNilSizeFunction := #sistaV1PushNilSize:numInitialNils:.
  BytecodeSetHasDirectedSuperSend := true.
  FirstSpecialSelector := 96.
  NumSpecialSelectors := 32.
  self flag:
  'Special selector send class must be inlined to agree with the interpreter, which
   inlines class.  If class is sent to e.g. a general instance of ProtoObject then unless
   class is inlined there will be an MNU.  It must be that the Cointerpreter and Cogit
   have identical semantics.  We get away with not hardwiring the other special
   selectors either because in the Cointerpreter they are not inlined or because they
   are inlined only to instances of classes for which there will always be a method.'.
  self generatorTableFrom: #(
  "1 byte bytecodes"
  "pushes"
  (1    0   15 genPushReceiverVariableBytecode isInstVarRef needsFrameNever: 1)
+ (1  16   31 genPushLiteralVariable16CasesBytecode needsFrameNever: 1)
- (1  16   31 genPushLitVarDirSup16CasesBytecode needsFrameNever: 1)
  (1  32   63 genPushLiteralConstantBytecode needsFrameNever: 1)
  (1  64   75 genPushTemporaryVariableBytecode needsFrameIfMod16GENumArgs: 1)
  (1  76   76 genPushReceiverBytecode needsFrameNever: 1)
  (1  77   77 genPushConstantTrueBytecode needsFrameNever: 1)
  (1  78   78 genPushConstantFalseBytecode needsFrameNever: 1)
  (1  79   79 genPushConstantNilBytecode needsFrameNever: 1)
  (1  80   80 genPushConstantZeroBytecode needsFrameNever: 1)
  (1  81   81 genPushConstantOneBytecode needsFrameNever: 1)
  (1  82   82 genExtPushPseudoVariable)
  (1  83   83 duplicateTopBytecode needsFrameNever: 1)
 
  (1  84   87 unknownBytecode)
 
  "returns"
  (1  88   88 genReturnReceiver return needsFrameIfInBlock: isMappedInBlock 0)
  (1  89   89 genReturnTrue return needsFrameIfInBlock: isMappedInBlock 0)
  (1  90   90 genReturnFalse return needsFrameIfInBlock: isMappedInBlock 0)
  (1  91   91 genReturnNil return needsFrameIfInBlock: isMappedInBlock 0)
  (1  92   92 genReturnTopFromMethod return needsFrameIfInBlock: isMappedInBlock -1)
  (1  93   93 genReturnNilFromBlock return needsFrameNever: -1)
  (1  94   94 genReturnTopFromBlock return needsFrameNever: -1)
  (1  95   95 genExtNopBytecode needsFrameNever: 0)
 
  "sends"
  (1  96   96 genSpecialSelectorArithmetic isMapped AddRR)
  (1  97   97 genSpecialSelectorArithmetic isMapped SubRR)
  (1  98   98 genSpecialSelectorComparison isMapped JumpLess)
  (1  99   99 genSpecialSelectorComparison isMapped JumpGreater)
  (1 100 100 genSpecialSelectorComparison isMapped JumpLessOrEqual)
  (1 101 101 genSpecialSelectorComparison isMapped JumpGreaterOrEqual)
  (1 102 102 genSpecialSelectorComparison isMapped JumpZero)
  (1 103 103 genSpecialSelectorComparison isMapped JumpNonZero)
  (1 104 109 genSpecialSelectorSend isMapped) " #* #/ #\\ #@ #bitShift: //"
  (1 110 110 genSpecialSelectorArithmetic isMapped AndRR)
  (1 111 111 genSpecialSelectorArithmetic isMapped OrRR)
  (1 112 117 genSpecialSelectorSend isMapped) "#at: #at:put: #size #next #nextPut: #atEnd"
  (1 118 118 genSpecialSelectorEqualsEquals needsFrameNever: notMapped -1) "not mapped because it is directly inlined (for now)"
  (1 119 119 genSpecialSelectorClass needsFrameIfStackGreaterThanOne: notMapped 0) "not mapped because it is directly inlined (for now)"
  (1 120 120 genSpecialSelectorNotEqualsEquals needsFrameNever: notMapped -1) "not mapped because it is directly inlined (for now)"
  (1 121 127 genSpecialSelectorSend isMapped) "#value #value: #do: #new #new: #x #y"
 
  (1 128 143 genSendLiteralSelector0ArgsBytecode isMapped)
  (1 144 159 genSendLiteralSelector1ArgBytecode isMapped)
  (1 160 175 genSendLiteralSelector2ArgsBytecode isMapped)
 
  "jumps"
  (1 176 183 genShortUnconditionalJump branch v3:ShortForward:Branch:Distance:)
  (1 184 191 genShortJumpIfTrue branch isBranchTrue isMapped "because of mustBeBoolean"
  v3:ShortForward:Branch:Distance:)
  (1 192 199 genShortJumpIfFalse branch isBranchFalse isMapped "because of mustBeBoolean"
  v3:ShortForward:Branch:Distance:)
  (1 200 207 genStoreAndPopReceiverVariableBytecode isInstVarRef is1ByteInstVarStore isMappedIfImmutability needsFrameIfImmutability: -1)
 
  (1 208 215 genStoreAndPopTemporaryVariableBytecode)
 
  (1 216 216 genPopStackBytecode needsFrameNever: -1)
 
  (1 217 217 genUnconditionalTrapBytecode isMapped)
 
  (1 218 223 unknownBytecode)
 
  "2 byte bytecodes"
  (2 224 224 extABytecode extension)
  (2 225 225 extBBytecode extension)
 
  "pushes"
  (2 226 226 genExtPushReceiverVariableBytecode isInstVarRef) "Needs a frame for context inst var access"
+ (2 227 227 genExtPushLiteralVariableBytecode needsFrameNever: 1)
- (2 227 227 genExtPushLitVarDirSupBytecode needsFrameNever: 1)
  (2 228 228 genExtPushLiteralBytecode needsFrameNever: 1)
  (2 229 229 genLongPushTemporaryVariableBytecode)
  (2 230 230 unknownBytecode)
  (2 231 231 genPushNewArrayBytecode)
  (2 232 232 genExtPushIntegerBytecode needsFrameNever: 1)
  (2 233 233 genExtPushCharacterBytecode needsFrameNever: 1)
 
  "returns"
  "sends"
  (2 234 234 genExtSendBytecode isMapped)
  (2 235 235 genExtSendSuperBytecode isMapped)
 
  "sista bytecodes"
  (2 236 236 genExtEnsureAllocableSlots isMapped)
 
  "jumps"
  (2 237 237 genExtUnconditionalJump branch isMapped "because of interrupt check" v4:Long:Branch:Distance:)
  (2 238 238 genExtJumpIfTrue branch isBranchTrue isMapped "because of mustBeBoolean" v4:Long:Branch:Distance:)
  (2 239 239 genExtJumpIfFalse branch isBranchFalse isMapped "because of mustBeBoolean" v4:Long:Branch:Distance:)
 
  "stores"
  (2 240 240 genSistaExtStoreAndPopReceiverVariableBytecode isInstVarRef isMappedIfImmutability)
  (2 241 241 genSistaExtStoreAndPopLiteralVariableBytecode isMappedIfImmutability)
  (2 242 242 genLongStoreAndPopTemporaryVariableBytecode)
  (2 243 243 genSistaExtStoreReceiverVariableBytecode isInstVarRef isMappedIfImmutability)
  (2 244 244 genSistaExtStoreLiteralVariableBytecode isMappedIfImmutability)
  (2 245 245 genLongStoreTemporaryVariableBytecode)
 
  (2 246 247 unknownBytecode)
 
  "3 byte bytecodes"
  (3 248 248 genCallPrimitiveBytecode)
  (3 249 249 genExtPushFullClosureBytecode)
  (3 250 250 genExtPushClosureBytecode block v4:Block:Code:Size:)
  (3 251 251 genExtPushRemoteTempOrInstVarLongBytecode)
  (3 252 252 genExtStoreRemoteTempOrInstVarLongBytecode isMappedIfImmutability)
  (3 253 253 genExtStoreAndPopRemoteTempOrInstVarLongBytecode isMappedIfImmutability)
 
  (3 254 254 genExtJumpIfNotInstanceOfBehaviorsBytecode branch v4:Long:BranchIfNotInstanceOf:Distance:)
 
  (3 255 255 unknownBytecode))!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genMarshalledSend:numArgs:sendTable: (in category 'bytecode generator support') -----
  genMarshalledSend: selectorIndex numArgs: numArgs sendTable: sendTable
  <inline: false>
  <var: #sendTable type: #'sqInt *'>
  | annotation |
  self assert: needsFrame.
  annotation := self annotationForSendTable: sendTable.
  "Deal with stale super sends; see SpurMemoryManager's class comment."
  (self annotationIsForUncheckedEntryPoint: annotation) ifTrue:
  [objectRepresentation genEnsureOopInRegNotForwarded: ReceiverResultReg scratchReg: TempReg].
  "0 through (NumSendTrampolines - 2) numArgs sends have the arg count implciti in the trampoline.
  The last send trampoline (NumSendTrampolines - 1) passes numArgs in SendNumArgsReg."
  numArgs >= (NumSendTrampolines - 1) ifTrue:
  [self MoveCq: numArgs R: SendNumArgsReg].
  (BytecodeSetHasDirectedSuperSend
+ and: [annotation
+ between: IsDirectedSuperSend
+ and: IsDirectedSuperBindingSend]) ifTrue:
- and: [annotation = IsDirectedSuperSend]) ifTrue:
  [self genMoveConstant: tempOop R: TempReg].
  self genLoadInlineCacheWithSelector: selectorIndex.
  (self Call: (sendTable at: (numArgs min: NumSendTrampolines - 1))) annotation: annotation.
  self voidReceiverOptStatus.
  ^self ssPushRegister: ReceiverResultReg!

Item was added:
+ ----- Method: StackToRegisterMappingCogit>>genPushLiteralIndex: (in category 'bytecode generator support') -----
+ genPushLiteralIndex: literalIndex "<SmallInteger>"
+ "Override to avoid the BytecodeSetHasDirectedSuperSend check, which is unnecessary
+ here given the simulation stack."
+ <inline: false>
+ | literal |
+ literal := self getLiteral: literalIndex.
+ ^self genPushLiteral: literal!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genPushLiteralVariable: (in category 'bytecode generator support') -----
  genPushLiteralVariable: literalIndex
  <inline: false>
  | association freeReg |
- freeReg := self allocateRegNotConflictingWith: 0.
  association := self getLiteral: literalIndex.
+ "If followed by a directed super send bytecode, avoid generating any code yet.
+ The association will be passed to the directed send trampoline in a register
+ and fully dereferenced only when first linked.  It will be ignored in later sends."
+ BytecodeSetHasDirectedSuperSend ifTrue:
+ [self deny: directedSendUsesBinding.
+ self nextDescriptorExtensionsAndNextPCInto:
+ [:descriptor :exta :extb :followingPC|
+ (self isDirectedSuper: descriptor extA: exta extB: extb) ifTrue:
+ [self ssPushConstant: association.
+ directedSendUsesBinding := true.
+ ^0]]].
+ freeReg := self allocateRegNotConflictingWith: 0.
  "N.B. Do _not_ use ReceiverResultReg to avoid overwriting receiver in assignment in frameless methods."
  "So far descriptors are not rich enough to describe the entire dereference so generate the register
  load but don't push the result.  There is an order-of-evaluation issue if we defer the dereference."
  self genMoveConstant: association R: TempReg.
  objectRepresentation
  genEnsureObjInRegNotForwarded: TempReg
  scratchReg: freeReg.
  objectRepresentation
  genLoadSlot: ValueIndex
  sourceReg: TempReg
  destReg: freeReg.
  self ssPushRegister: freeReg.
  ^0!

Item was removed:
- ----- Method: StackToRegisterMappingCogit>>genPushLiteralVariableGivenDirectedSuper: (in category 'bytecode generator support') -----
- genPushLiteralVariableGivenDirectedSuper: literalIndex
- "This is a version of genPushLiteralVariable: that looks ahead for a directed super send bytecode
- and does not generate any code for the dereference yet if followed by a directed super send."
- <inline: false>
- self nextDescriptorExtensionsAndNextPCInto:
- [:descriptor :exta :extb :followingPC|
- (self isDirectedSuper: descriptor extA: exta extB: extb) ifTrue:
- [self ssPushConstant: (self getLiteral: literalIndex).
- ^0]].
- ^self genPushLiteralVariable: literalIndex!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>genSendDirectedSuper:numArgs: (in category 'bytecode generator support') -----
  genSendDirectedSuper: selectorIndex numArgs: numArgs
+ | result |
  self assert: self ssTop type = SSConstant.
  tempOop := self ssTop constant.
  self ssPop: 1.
  self marshallSendArguments: numArgs.
+ result := self
+ genMarshalledSend: selectorIndex
+ numArgs: numArgs
+ sendTable: (directedSendUsesBinding
+ ifTrue: [directedSuperBindingSendTrampolines]
+ ifFalse: [directedSuperSendTrampolines]).
+ directedSendUsesBinding := false.
+ ^result!
- ^self genMarshalledSend: selectorIndex numArgs: numArgs sendTable: directedSuperSendTrampolines!

Item was changed:
  ----- Method: StackToRegisterMappingCogit>>generateSendTrampolines (in category 'initialization') -----
  generateSendTrampolines
  "Override to generate code to push the register arg(s) for <= numRegArg arity sends."
  0 to: NumSendTrampolines - 1 do:
  [:numArgs|
  ordinarySendTrampolines
  at: numArgs
  put: (self genSendTrampolineFor: #ceSend:super:to:numArgs:
   numArgs: numArgs
   called: (self trampolineName: 'ceSend' numArgs: numArgs)
   arg: ClassReg
   arg: (self trampolineArgConstant: false)
   arg: ReceiverResultReg
   arg: (self numArgsOrSendNumArgsReg: numArgs))].
 
  "Generate these in the middle so they are within [firstSend, lastSend]."
  NewspeakVM ifTrue: [self generateNewspeakSendTrampolines].
  BytecodeSetHasDirectedSuperSend ifTrue:
  [0 to: NumSendTrampolines - 1 do:
  [:numArgs|
  directedSuperSendTrampolines
  at: numArgs
  put: (self genSendTrampolineFor: #ceSend:above:to:numArgs:
   numArgs: numArgs
   called: (self trampolineName: 'ceDirectedSuperSend' numArgs: numArgs)
   arg: ClassReg
   arg: TempReg
   arg: ReceiverResultReg
+  arg: (self numArgsOrSendNumArgsReg: numArgs)).
+ directedSuperBindingSendTrampolines
+ at: numArgs
+ put: (self genSendTrampolineFor: #ceSend:aboveClassBinding:to:numArgs:
+  numArgs: numArgs
+  called: (self trampolineName: 'ceDirectedSuperBindingSend' numArgs: numArgs)
+  arg: ClassReg
+  arg: TempReg
+  arg: ReceiverResultReg
   arg: (self numArgsOrSendNumArgsReg: numArgs))]].
 
  0 to: NumSendTrampolines - 1 do:
  [:numArgs|
  superSendTrampolines
  at: numArgs
  put: (self genSendTrampolineFor: #ceSend:super:to:numArgs:
   numArgs: numArgs
   called: (self trampolineName: 'ceSuperSend' numArgs: numArgs)
   arg: ClassReg
   arg: (self trampolineArgConstant: true)
   arg: ReceiverResultReg
   arg: (self numArgsOrSendNumArgsReg: numArgs))].
  firstSend := ordinarySendTrampolines at: 0.
  lastSend := superSendTrampolines at: NumSendTrampolines - 1!