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

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

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

Name: VMMaker.oscog-eem.957
Author: eem
Time: 27 November 2014, 3:39:41.61 pm
UUID: ac5f8308-02e5-4277-b28c-595b7a4cf34a
Ancestors: VMMaker.oscog-eem.956

Fix regression in magnitude64BitIntegerFor:neg:

Move dispdbg.h above cointerp.h & cogit.h in cogit.c
otherwise NoDbgRegParms gets screwed up.

Use asInteger instead of asUnsignedInteger
in followForwardingPointersInStackZone: so
simulation of Stack VM doesn't trigger the assert in
asUnsignedInteger.

Spur:
Make instantiateClass:indexableSize: check for
Float instantiation, failing for other than 2 words.
Rewrite 32-bit coalesce:and: to use the raw slot
accessors.  Implement 64-bit coalesce:and:.

Simulator:
Make printStackCallStackOf: accept contexts.

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

Item was changed:
  ----- Method: Cogit class>>declareCVarsIn: (in category 'translation') -----
  declareCVarsIn: aCCodeGenerator
  #( 'coInterpreter' 'objectMemory' 'methodZone' 'objectRepresentation'
  'cogBlockMethodSurrogateClass' 'cogMethodSurrogateClass'
  'threadManager' 'processor' 'lastNInstructions' 'simulatedAddresses'
  'simulatedTrampolines' 'simulatedVariableGetters' 'simulatedVariableSetters'
  'printRegisters' 'printInstructions' 'clickConfirm' 'singleStep') do:
  [:simulationVariableNotNeededForRealVM|
  aCCodeGenerator removeVariable: simulationVariableNotNeededForRealVM].
  NewspeakVM ifFalse:
  [#( 'dynSuperEntry' 'dynSuperEntryAlignment' 'dynamicSuperSendTrampolines'
  'ceImplicitReceiverTrampoline' 'ceEnclosingObjectTrampoline' 'cmDynSuperEntryOffset'
  '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 preceed cointerp.h & cogit.h otherwise NoDbgRegParms gets screwed up"
  addHeaderFile:'"cogmethod.h"';
  addHeaderFile:'#if COGMTVM';
  addHeaderFile:'"cointerpmt.h"';
  addHeaderFile:'#else';
  addHeaderFile:'"cointerp.h"';
  addHeaderFile:'#endif';
+ addHeaderFile:'"cogit.h"'.
- addHeaderFile:'"cogit.h"';
- addHeaderFile:'"dispdbg.h"'.
  aCCodeGenerator
  var: #ceGetSP
  declareC: 'unsigned long (*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)(unsigned long from, unsigned long to)';
  var: #ceCheckFeaturesFunction
  declareC: 'static unsigned long (*ceCheckFeaturesFunction)(void)';
  var: #ceTryLockVMOwner
  declareC: 'unsigned long (*ceTryLockVMOwner)(void)';
  var: #ceUnlockVMOwner
  declareC: 'void (*ceUnlockVMOwner)(void)';
  var: #postCompileHook
  declareC: 'void (*postCompileHook)(CogMethod *, void *)';
  var: #openPICList declareC: 'CogMethod *openPICList = 0';
  var: #maxMethodBefore type: #'CogBlockMethod *'.
  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';
  var: #primInvokeLabel type: #'AbstractInstruction *'.
  self declareC: #(abstractOpcodes stackCheckLabel
  blockEntryLabel blockEntryNoContextSwitch
  stackOverflowCall sendMiss sendMissCall entry noCheckEntry dynSuperEntry
  mnuCall interpretCall interpretLabel endCPICCase0 endCPICCase1)
  as: #'AbstractInstruction *'
  in: aCCodeGenerator.
  aCCodeGenerator
  declareVar: #annotations type: #'InstructionAnnotation *';
  declareVar: #blockStarts type: #'BlockStart *';
  declareVar: #fixups type: #'BytecodeFixup *'.
  aCCodeGenerator
  var: #sendTrampolines
  declareC: 'sqInt sendTrampolines[NumSendTrampolines]';
  var: #superSendTrampolines
  declareC: 'sqInt superSendTrampolines[NumSendTrampolines]';
  var: #dynamicSuperSendTrampolines
  declareC: 'sqInt dynamicSuperSendTrampolines[NumSendTrampolines]';
  var: #trampolineAddresses
  declareC: 'static char *trampolineAddresses[NumTrampolines*2]';
  var: #objectReferencesInRuntime
  declareC: 'static sqInt objectReferencesInRuntime[NumObjRefsInRuntime]';
  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: #'unsigned long';
  declareVar: #debugPrimCallStackOffset type: #'unsigned long'.
  aCCodeGenerator vmClass generatorTable ifNotNil:
  [:bytecodeGenTable|
  aCCodeGenerator
  var: #generatorTable
  declareC: 'static BytecodeDescriptor generatorTable[', bytecodeGenTable size, ']',
  (self tableInitializerFor: bytecodeGenTable
  in: aCCodeGenerator);
  var: #primitiveGeneratorTable
  declareC: 'static PrimitiveDescriptor primitiveGeneratorTable[MaxCompiledPrimitiveIndex+1]',
  (self tableInitializerFor: aCCodeGenerator vmClass primitiveTable
  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: InterpreterPrimitives>>magnitude64BitIntegerFor:neg: (in category 'primitive support') -----
  magnitude64BitIntegerFor: magnitude neg: isNegative
  "Return a Large Integer object for the given integer magnitude and sign"
  | newLargeInteger largeClass intValue highWord sz isSmall smallVal |
  <var: 'magnitude' type: #usqLong>
  <var: 'highWord' type: #usqInt>
 
  isSmall := isNegative
+ ifTrue: [magnitude <= (objectMemory maxSmallInteger + 1)]
+ ifFalse: [magnitude <= objectMemory maxSmallInteger].
- ifTrue: [magnitude < objectMemory maxSmallInteger]
- ifFalse: [magnitude < (objectMemory maxSmallInteger + 1)].
  isSmall ifTrue:
  [smallVal := self cCoerceSimple: magnitude to: #sqInt.
  isNegative ifTrue: [smallVal := 0 - smallVal].
  ^objectMemory integerObjectOf: smallVal].
 
  largeClass := isNegative
  ifTrue: [objectMemory classLargeNegativeInteger]
  ifFalse: [objectMemory classLargePositiveInteger].
  objectMemory wordSize = 8
  ifTrue: [sz := 8]
  ifFalse:
  [(highWord := magnitude >> 32) = 0
  ifTrue: [sz := 4]
  ifFalse:
  [sz := 5.
  (highWord := highWord >> 8) = 0 ifFalse:
  [sz := sz + 1.
  (highWord := highWord >> 8) = 0 ifFalse:
  [sz := sz + 1.
  (highWord := highWord >> 8) = 0 ifFalse: [sz := sz + 1]]]]].
  newLargeInteger := objectMemory instantiateClass: largeClass indexableSize:  sz.
  0 to: sz-1 do: [:i |
  intValue := (magnitude >> (i * 8)) bitAnd: 255.
  objectMemory storeByte: i ofObject: newLargeInteger withValue: intValue].
  ^newLargeInteger!

Item was changed:
  ----- Method: Spur32BitMemoryManager>>coalesce:and: (in category 'gc - global') -----
  coalesce: obj1 and: obj2
  | header1NumSlots header2NumSlots obj2slots newNumSlots |
  header1NumSlots := self rawNumSlotsOf: obj1.
  header2NumSlots := self rawNumSlotsOf: obj2.
 
  "compute total number of slots in obj2, including header"
  obj2slots := header2NumSlots = self numSlotsMask
+ ifTrue: [(self rawOverflowSlotsOf: obj2) + (2 * self baseHeaderSize / self wordSize)]
- ifTrue: [(self longAt: obj2 - self baseHeaderSize) + (2 * self baseHeaderSize / self wordSize)]
  ifFalse: [(header2NumSlots = 0 ifTrue: [1] ifFalse: [header2NumSlots]) + (self baseHeaderSize / self wordSize)].
  obj2slots := obj2slots + (obj2slots bitAnd: 1).
  self assert: obj2slots * self wordSize = (self bytesInObject: obj2).
 
  "if obj1 already has a double header things are simple..."
  header1NumSlots = self numSlotsMask ifTrue:
+ [self rawOverflowSlotsOf: obj1 put: obj2slots + (self rawOverflowSlotsOf: obj1).
- [self longAt: obj1  - self baseHeaderSize put: obj2slots + (self longAt: obj1 - self baseHeaderSize).
  ^obj1].
 
  "compute total number of slots in obj1, excluding header"
  header1NumSlots := header1NumSlots = 0
  ifTrue: [2]
  ifFalse: [header1NumSlots + (header1NumSlots bitAnd: 1)].
  self assert: header1NumSlots * self wordSize + self baseHeaderSize = (self bytesInObject: obj1).
  newNumSlots := obj2slots + header1NumSlots.
 
  "if obj1 still only requires a single header things are simple..."
  newNumSlots < self numSlotsMask ifTrue:
+ [self rawNumSlotsOf: obj1 put: newNumSlots.
- [self byteAt: obj1 + (self numSlotsFullShift / BitsPerByte)
- put: newNumSlots.
  ^obj1].
 
  "convert from single to double header..."
  newNumSlots := newNumSlots - (self baseHeaderSize / self wordSize).
  self longAt: obj1 + self baseHeaderSize
  put: (self longAt: obj1);
  longAt: obj1 + 4 + self baseHeaderSize
  put: ((self longAt: obj1 + 4) bitOr: self numSlotsMask << self numSlotsHalfShift).
  self longAt: obj1
  put: newNumSlots.
  self longAt: obj1 + 4
  put: self numSlotsMask << self numSlotsHalfShift.
  ^obj1 + self baseHeaderSize!

Item was changed:
  ----- Method: Spur32BitMemoryManager>>instantiateClass:indexableSize: (in category 'instantiation') -----
  instantiateClass: classObj indexableSize: nElements
  <var: #nElements type: #usqInt>
  "Allocate an instance of a variable class, excepting CompiledMethod."
  | instSpec classFormat numSlots classIndex newObj fillValue |
  classFormat := self formatOfClass: classObj.
  instSpec := self instSpecOfClassFormat: classFormat.
+ classIndex := self rawHashBitsOf: classObj.
  fillValue := 0.
  instSpec caseOf: {
  [self arrayFormat] ->
+ [numSlots := nElements.
- [nElements > self maxSlotsForAlloc ifTrue:
- [^nil].
- numSlots := nElements.
  fillValue := nilObj].
  [self indexablePointersFormat] ->
+ [numSlots := (self fixedFieldsOfClassFormat: classFormat) + nElements.
- [nElements > (self maxSlotsForAlloc - (self fixedFieldsOfClassFormat: classFormat)) ifTrue:
- [^nil].
- numSlots := (self fixedFieldsOfClassFormat: classFormat) + nElements.
  fillValue := nilObj].
  [self weakArrayFormat] ->
+ [numSlots := (self fixedFieldsOfClassFormat: classFormat) + nElements.
- [nElements > (self maxSlotsForAlloc - (self fixedFieldsOfClassFormat: classFormat)) ifTrue:
- [^nil].
- numSlots := (self fixedFieldsOfClassFormat: classFormat) + nElements.
  fillValue := nilObj].
  [self sixtyFourBitIndexableFormat] ->
  [nElements > (self maxSlotsForAlloc / 2) ifTrue:
+ [coInterpreter primitiveFailFor: PrimErrUnsupported.
+ ^nil].
- [^nil].
  numSlots := nElements * 2].
  [self firstLongFormat] ->
+ [(classIndex = ClassFloatCompactIndex and: [nElements ~= 2]) ifTrue:
+ [coInterpreter primitiveFailFor: PrimErrBadReceiver.
+ ^nil].
- [nElements > self maxSlotsForAlloc ifTrue:
- [^nil].
  numSlots := nElements].
  [self firstShortFormat] ->
  [numSlots := nElements + 1 // 2.
- numSlots > self maxSlotsForAlloc ifTrue:
- [^nil].
  instSpec := instSpec + (nElements bitAnd: 1)].
  [self firstByteFormat] ->
  [numSlots := nElements + 3 // 4.
- numSlots > self maxSlotsForAlloc ifTrue:
- [^nil].
  instSpec := instSpec + (4 - nElements bitAnd: 3)] }
  otherwise: ["some Squeak images include funky fixed subclasses of abstract variable
  superclasses. e.g. DirectoryEntry as a subclass of ArrayedCollection.
  Allow fixed classes to be instantiated here iff nElements = 0."
  (nElements ~= 0 or: [instSpec > self lastPointerFormat]) ifTrue:
  [^nil].
  numSlots := self fixedFieldsOfClassFormat: classFormat]. "non-indexable"
+ classIndex = 0 ifTrue:
+ [classIndex := self ensureBehaviorHash: classObj.
+ classIndex < 0 ifTrue:
+ [coInterpreter primitiveFailFor: classIndex negated.
+ ^nil]].
- classIndex := self ensureBehaviorHash: classObj.
- classIndex < 0 ifTrue:
- [coInterpreter primitiveFailFor: classIndex negated.
- ^nil].
  numSlots > self maxSlotsForNewSpaceAlloc
+ ifTrue:
+ [numSlots > self maxSlotsForAlloc ifTrue:
+ [coInterpreter primitiveFailFor: PrimErrUnsupported.
+ ^nil].
+ newObj := self allocateSlotsInOldSpace: numSlots format: instSpec classIndex: classIndex]
+ ifFalse:
+ [newObj := self allocateSlots: numSlots format: instSpec classIndex: classIndex].
- ifTrue: [newObj := self allocateSlotsInOldSpace: numSlots format: instSpec classIndex: classIndex]
- ifFalse: [newObj := self allocateSlots: numSlots format: instSpec classIndex: classIndex].
  newObj ifNotNil:
  [self fillObj: newObj numSlots: numSlots with: fillValue].
  ^newObj!

Item was added:
+ ----- Method: Spur64BitMemoryManager>>coalesce:and: (in category 'gc - global') -----
+ coalesce: obj1 and: obj2
+ | header1NumSlots header2NumSlots obj2slots newNumSlots |
+ header1NumSlots := self rawNumSlotsOf: obj1.
+ header2NumSlots := self rawNumSlotsOf: obj2.
+
+ "compute total number of slots in obj2, including header"
+ obj2slots := header2NumSlots = self numSlotsMask
+ ifTrue: [(self rawOverflowSlotsOf: obj2) + (2 * self baseHeaderSize / self wordSize)]
+ ifFalse: [(header2NumSlots = 0 ifTrue: [1] ifFalse: [header2NumSlots]) + (self baseHeaderSize / self wordSize)].
+ self assert: obj2slots * self wordSize = (self bytesInObject: obj2).
+
+ "if obj1 already has a double header things are simple..."
+ header1NumSlots = self numSlotsMask ifTrue:
+ [self rawOverflowSlotsOf: obj1 put: obj2slots + (self rawOverflowSlotsOf: obj1).
+ ^obj1].
+
+ "compute total number of slots in obj1, excluding header"
+ header1NumSlots := header1NumSlots = 0 ifTrue: [1] ifFalse: [header1NumSlots].
+ self assert: header1NumSlots * self wordSize + self baseHeaderSize = (self bytesInObject: obj1).
+ newNumSlots := obj2slots + header1NumSlots.
+
+ "if obj1 still only requires a single header things are simple..."
+ newNumSlots < self numSlotsMask ifTrue:
+ [self rawNumSlotsOf: obj1 put: newNumSlots.
+ ^obj1].
+
+ "convert from single to double header..."
+ newNumSlots := newNumSlots - (self baseHeaderSize / self wordSize).
+ self
+ setRawNumSlotsOf: obj1 + self baseHeaderSize to: self numSlotsMask;
+ setOverflowNumSlotsOf: obj1 + self baseHeaderSize to: newNumSlots.
+ ^obj1 + self baseHeaderSize!

Item was changed:
  ----- Method: Spur64BitMemoryManager>>instantiateClass:indexableSize: (in category 'instantiation') -----
  instantiateClass: classObj indexableSize: nElements
  <var: #nElements type: #usqInt>
  "Allocate an instance of a variable class, excepting CompiledMethod."
  | instSpec classFormat numSlots classIndex newObj fillValue |
  classFormat := self formatOfClass: classObj.
  instSpec := self instSpecOfClassFormat: classFormat.
+ classIndex := self rawHashBitsOf: classObj.
  fillValue := 0.
  instSpec caseOf: {
  [self arrayFormat] ->
  [numSlots := nElements.
  fillValue := nilObj].
  [self indexablePointersFormat] ->
  [numSlots := (self fixedFieldsOfClassFormat: classFormat) + nElements.
  fillValue := nilObj].
  [self weakArrayFormat] ->
  [numSlots := (self fixedFieldsOfClassFormat: classFormat) + nElements.
  fillValue := nilObj].
  [self sixtyFourBitIndexableFormat] ->
  [numSlots := nElements].
  [self firstLongFormat] ->
+ [(classIndex = ClassFloatCompactIndex and: [nElements ~= 2]) ifTrue:
+ [coInterpreter primitiveFailFor: PrimErrBadReceiver.
+ ^nil].
+ numSlots := nElements + 1 // 2.
- [numSlots := nElements + 1 // 2.
  instSpec := instSpec + (nElements bitAnd: 1)].
  [self firstShortFormat] ->
  [numSlots := nElements + 3 // 4.
  instSpec := instSpec + (4 - nElements bitAnd: 3)].
  [self firstByteFormat] ->
  [numSlots := nElements + 7 // 8.
  instSpec := instSpec + (8 - nElements bitAnd: 7)] }
  otherwise: ["some Squeak images include funky fixed subclasses of abstract variable
  superclasses. e.g. DirectoryEntry as a subclass of ArrayedCollection.
  Allow fixed classes to be instantiated here iff nElements = 0."
  (nElements ~= 0 or: [instSpec > self lastPointerFormat]) ifTrue:
  [^nil].
  numSlots := self fixedFieldsOfClassFormat: classFormat]. "non-indexable"
+ classIndex = 0 ifTrue:
+ [classIndex := self ensureBehaviorHash: classObj.
+ classIndex < 0 ifTrue:
+ [coInterpreter primitiveFailFor: classIndex negated.
+ ^nil]].
- classIndex := self ensureBehaviorHash: classObj.
- classIndex < 0 ifTrue:
- [coInterpreter primitiveFailFor: classIndex negated.
- ^nil].
  numSlots > self maxSlotsForNewSpaceAlloc
  ifTrue:
  [numSlots > self maxSlotsForAlloc ifTrue:
+ [coInterpreter primitiveFailFor: PrimErrUnsupported.
+ ^nil].
- [^nil].
  newObj := self allocateSlotsInOldSpace: numSlots format: instSpec classIndex: classIndex]
  ifFalse:
  [newObj := self allocateSlots: numSlots format: instSpec classIndex: classIndex].
  newObj ifNotNil:
  [self fillObj: newObj numSlots: numSlots with: fillValue].
  ^newObj!

Item was changed:
  ----- Method: Spur64BitMemoryManager>>rawOverflowSlotsOf:put: (in category 'object access') -----
  rawOverflowSlotsOf: objOop put: numSlots
  <returnTypeC: #usqLong>
  <inline: true>
  self flag: #endianness.
+ self longAt: objOop - self baseHeaderSize put: self numSlotsMask << 56 + numSlots.
- self longAt: objOop - self baseHeaderSize
- put: (self byteAt: objOop - 1) << 56 + numSlots.
  ^numSlots!

Item was changed:
  ----- Method: StackInterpreter>>followForwardingPointersInStackZone: (in category 'object memory support') -----
  followForwardingPointersInStackZone: theBecomeEffectsFlags
  "Spur's become: is lazy, turning the becommed object into a forwarding object to the other.
  The read-barrier is minimised by arranging that forwarding pointers will fail a method cache
  probe, since notionally objects' internals are accessed only via sending messages to them,
  the exception is primitives that access the internals of the non-receiver argument(s).
  To avoid a read barrier on bytecode, literal and inst var fetch we scan the receivers and
  methods in the stack zone and follow any forwarded ones.  This is of course way cheaper
  than scanning all of memory as in the old become."
  | theIPPtr |
  <inline: false>
  <var: #thePage type: #'StackPage *'>
  <var: #theSP type: #'char *'>
  <var: #theFP type: #'char *'>
  <var: #callerFP type: #'char *'>
  <var: #theIPPtr type: #usqInt>
 
  (theBecomeEffectsFlags anyMask: BecameCompiledMethodFlag) ifTrue:
  [(objectMemory isForwarded: method) ifTrue:
  [theIPPtr := instructionPointer - method.
  method := objectMemory followForwarded: method.
  instructionPointer := method + theIPPtr].
  (objectMemory isForwarded: newMethod) ifTrue:
  [newMethod := objectMemory followForwarded: newMethod]].
 
  self assert: stackPage ~= 0.
  0 to: numStackPages - 1 do:
  [:i| | thePage theSP theFP callerFP theIP oop |
  thePage := stackPages stackPageAt: i.
  thePage isFree ifFalse:
  [theSP := thePage headSP.
  theFP := thePage  headFP.
  "Skip the instruction pointer on top of stack of inactive pages."
  thePage = stackPage
  ifTrue: [theIPPtr := 0]
  ifFalse:
  [theIPPtr := theSP asUnsignedInteger.
  theSP := theSP + objectMemory wordSize].
  [self assert: (thePage addressIsInPage: theFP).
   self assert: (theIPPtr = 0 or: [thePage addressIsInPage: theIPPtr asVoidPointer]).
   oop := stackPages longAt: theFP + FoxReceiver.
   (objectMemory isOopForwarded: oop) ifTrue:
  [stackPages
  longAt: theFP + FoxReceiver
  put: (objectMemory followForwarded: oop)].
+  theIP := (theFP + (self frameStackedReceiverOffset: theFP)) asInteger. "reuse theIP; its just an offset here"
-  theIP := (theFP + (self frameStackedReceiverOffset: theFP)) asUnsignedInteger. "reuse theIP; its just an offset here"
   oop := stackPages longAt: theIP.
   (objectMemory isOopForwarded: oop) ifTrue:
  [stackPages
  longAt: theIP
  put: (objectMemory followForwarded: oop)].
   ((self frameHasContext: theFP)
    and: [(objectMemory isForwarded: (self frameContext: theFP))]) ifTrue:
  [stackPages
  longAt: theFP + FoxThisContext
  put: (objectMemory followForwarded: (self frameContext: theFP))].
   oop := self frameMethod: theFP.
   (objectMemory isForwarded: oop) ifTrue:
  [| newOop delta |
  newOop := objectMemory followForwarded: oop.
  theIPPtr ~= 0 ifTrue:
  [self assert: (stackPages longAt: theIPPtr) > (self frameMethod: theFP).
  delta := newOop - oop.
  stackPages
  longAt: theIPPtr
  put: (stackPages longAt: theIPPtr) + delta].
  stackPages
  longAt: theFP + FoxMethod
  put: (oop := newOop)].
   (callerFP := self frameCallerFP: theFP) ~= 0] whileTrue:
+ [theIPPtr := (theFP + FoxCallerSavedIP) asInteger.
- [theIPPtr := (theFP + FoxCallerSavedIP) asUnsignedInteger.
  theFP := callerFP]]]!

Item was changed:
  ----- Method: StackInterpreter>>printStackCallStackOf: (in category 'debug printing') -----
+ printStackCallStackOf: frameOrContext
- printStackCallStackOf: aFramePointer
- <var: #aFramePointer type: #'char *'>
  <api>
  | theFP context |
  <var: #theFP type: #'char *'>
+ (objectMemory addressCouldBeObj: frameOrContext) ifTrue:
+ [((objectMemory isContext: frameOrContext)
+  and: [self checkIsStillMarriedContext: frameOrContext currentFP: nil]) ifTrue:
+ [^self printStackCallStackOf: (self frameOfMarriedContext: frameOrContext)].
+ ^nil].
+
+ theFP := frameOrContext asVoidPointer.
- theFP := aFramePointer.
  [context := self shortReversePrintFrameAndCallers: theFP.
  ((self isMarriedOrWidowedContext: context)
   and:
  [theFP := self frameOfMarriedContext: context.
  self checkIsStillMarriedContext: context currentFP: theFP]) ifFalse:
  [^nil]] repeat!

Item was changed:
  ----- Method: ThreadedFFIPlugin>>ffiLoadCalloutAddressFrom: (in category 'symbol loading') -----
  ffiLoadCalloutAddressFrom: oop
  "Load the function address for a call out to an external function"
+ | module moduleHandle functionName address |
- | module moduleHandle functionName functionLength address |
  <inline: false>
  "First find and load the module"
  module := interpreterProxy fetchPointer: externalFunctionInstSize + 1 ofObject: oop.
  moduleHandle := self ffiLoadCalloutModule: module.
  interpreterProxy failed ifTrue:
  [^0]. "failed"
  "fetch the function name"
  functionName := interpreterProxy fetchPointer: externalFunctionInstSize ofObject: oop.
  (interpreterProxy isBytes: functionName) ifFalse:
  [^self ffiFail: FFIErrorBadExternalFunction].
+ address := (interpreterProxy
+ ioLoadSymbol: (interpreterProxy firstIndexableField: functionName) asInteger
+ OfLength: (interpreterProxy byteSizeOf: functionName)
+ FromModule: moduleHandle) asInteger.
- functionLength := interpreterProxy byteSizeOf: functionName.
- address := interpreterProxy
- ioLoadSymbol: (self cCoerce: (interpreterProxy firstIndexableField: functionName) to: #int)
- OfLength: functionLength
- FromModule: moduleHandle.
  (interpreterProxy failed or: [address = 0]) ifTrue:
  [^self ffiFail: FFIErrorAddressNotFound].
  ^address!