[Vm-dev] VM Maker: VMMaker.oscog-eem.2094.mcz
Ronie Salgado
roniesalg at gmail.com
Tue Jan 17 08:15:14 UTC 2017
Hi Eliot,
With this commit I got the following compilation error on Mac OS X 64. I
made a quick fix by replacing the case into ifTrue:iFalse:
../../spur64src/vm/cogitX64.c:29060:4: error: statement requires expression
of integer type ('sqInt (*)(void)' (aka 'long (*)(void)') invalid)
switch ((descriptor->generator)) {
^ ~~~~~~~~~~~~~~~~~~~~~~~
../../spur64src/vm/cogitX64.c:29061:9: error: expression is not an integer
constant expression
case genPushConstantTrueBytecode:
^~~~~~~~~~~~~~~~~~~~~~~~~~~
../../spur64src/vm/cogitX64.c:29064:9: error: expression is not an integer
constant expression
case genPushConstantFalseBytecode:
(spur64src because I am using the Pharo branch, where I can load the
LowcodeOpalCompiler for testing)
Best regards,
Ronie
2017-01-17 1:21 GMT-03:00 <commits at source.squeak.org>:
>
> Eliot Miranda uploaded a new version of VMMaker to project VM Maker:
> http://source.squeak.org/VMMaker/VMMaker.oscog-eem.2094.mcz
>
> ==================== Summary ====================
>
> Name: VMMaker.oscog-eem.2094
> Author: eem
> Time: 16 January 2017, 8:20:54.697006 pm
> UUID: 69b76ffe-68d9-423c-a3a7-546a6bbb3110
> Ancestors: VMMaker.oscog-rsf.2093
>
> StackToRegisterMappingCogit:
> Follow jumps to jumps and push: aBoolean; jump:if:s, eliminating dead code.
>
> Elimnate jumps to the immediately following instruction in
> StackToRegisterMappingCogit>>generateInstructionsAt:.
>
> Neaten the simulation-only breakpointing for bytecode and machine code
> pcs. Add suport for breakPC during in-image compilation.
>
> =============== Diff against VMMaker.oscog-rsf.2093 ===============
>
> Item was changed:
> ----- Method: Cogit class>>testPCMappingSelect:options: (in category
> 'tests') -----
> testPCMappingSelect: aBlock options: optionsDictionaryOrArray
> "Test pc mapping both ways using a selection of the methods in the
> current image."
> + | n cogit coInterpreter |
> - | cogit coInterpreter |
> cogit := self instanceForTests: optionsDictionaryOrArray.
> coInterpreter := CurrentImageCoInterpreterFacade forCogit: cogit.
> [cogit
> setInterpreter: coInterpreter;
> singleStep: true;
> initializeCodeZoneFrom: 1024 upTo: coInterpreter
> memory size]
> on: Notification
> do: [:ex|
> (ex messageText beginsWith: 'cannot find receiver
> for') ifTrue:
> [ex resume: coInterpreter]].
> + n := -1.
> SystemNavigation new allSelect:
> [:m| | cm |
> (m isQuick not
> and: [aBlock value: m]) ifTrue:
> + [(n := n + 1) \\ 10 = 0 ifTrue: [Transcript
> nextPut: $.; flush].
> - [Transcript nextPut: $.; flush.
> cm := cogit
> cog: (coInterpreter
> oopForObject: m)
> selector: (coInterpreter
> oopForObject: m selector).
> cm ifNil:
> [cogit methodZone clearCogCompiledCode.
> coInterpreter initializeObjectMap.
> cm := cogit
> cog:
> (coInterpreter oopForObject: m)
> selector:
> (coInterpreter oopForObject: m selector).
> cm ifNil: [Transcript show: 'After 1 Cog
> compiled code compaction, still not able to generate the cog method...' ] ].
> cm ifNotNil:
> [cogit testPCMappingForCompiledMethod: m
> cogMethod: cm]].
> false] !
>
> Item was changed:
> ----- Method: Cogit>>compileAbstractInstructionsFrom:through: (in
> category 'compile abstract instructions') -----
> compileAbstractInstructionsFrom: start through: end
> "Loop over bytecodes, dispatching to the generator for each
> bytecode, handling fixups in due course."
> | nextOpcodeIndex descriptor fixup result nExts |
> <var: #descriptor type: #'BytecodeDescriptor *'>
> <var: #fixup type: #'BytecodeFixup *'>
> bytecodePC := start.
> nExts := result := 0.
> descriptor := nil.
> + [self maybeHaltIfDebugPC.
> - [self cCode: '' inSmalltalk: [self isDebugPC ifTrue: [self halt]].
> descriptor := self loadBytesAndGetDescriptor.
> nextOpcodeIndex := opcodeIndex.
> result := self perform: descriptor generator.
> self assertExtsAreConsumed: descriptor.
> fixup := self fixupAt: bytecodePC - initialPC.
> self patchFixupTargetIfNeeded: fixup nextOpcodeIndex:
> nextOpcodeIndex.
> self maybeDumpLiterals: descriptor.
> bytecodePC := self nextBytecodePCFor: descriptor exts: nExts.
> result = 0 and: [bytecodePC <= end]]
> whileTrue:
> [nExts := descriptor isExtension ifTrue: [nExts +
> 1] ifFalse: [0]].
> self checkEnoughOpcodes.
> ^result!
>
> Item was changed:
> ----- Method: Cogit>>generateInstructionsAt: (in category 'generate
> machine code') -----
> generateInstructionsAt: eventualAbsoluteAddress
> "Size pc-dependent instructions and assign eventual addresses to
> all instructions.
> Answer the size of the code.
> Compute forward branches based on virtual address (abstract code
> starts at 0),
> assuming that any branches branched over are long.
> Compute backward branches based on actual address.
> Reuse the fixups array to record the pc-dependent instructions
> that need to have
> their code generation postponed until after the others."
> | absoluteAddress pcDependentIndex abstractInstruction fixup |
> <var: #abstractInstruction type: #'AbstractInstruction *'>
> <var: #fixup type: #'BytecodeFixup *'>
> absoluteAddress := eventualAbsoluteAddress.
> pcDependentIndex := 0.
> 0 to: opcodeIndex - 1 do:
> [:i|
> + self maybeBreakGeneratingAt: absoluteAddress.
> - self cCode: [] inSmalltalk: [self maybeBreakGeneratingAt:
> absoluteAddress].
> abstractInstruction := self abstractInstructionAt: i.
> abstractInstruction isPCDependent
> ifTrue:
> [abstractInstruction
> sizePCDependentInstructionAt: absoluteAddress.
> fixup := self fixupAt: pcDependentIndex.
> pcDependentIndex := pcDependentIndex + 1.
> fixup instructionIndex: i.
> absoluteAddress := absoluteAddress +
> abstractInstruction machineCodeSize]
> ifFalse:
> [absoluteAddress := abstractInstruction
> concretizeAt: absoluteAddress]].
> 0 to: pcDependentIndex - 1 do:
> [:j|
> fixup := self fixupAt: j.
> abstractInstruction := self abstractInstructionAt: fixup
> instructionIndex.
> + self maybeBreakGeneratingAt: abstractInstruction address.
> - self cCode: [] inSmalltalk: [self maybeBreakGeneratingAt:
> abstractInstruction address].
> abstractInstruction concretizeAt: abstractInstruction
> address].
> ^absoluteAddress - eventualAbsoluteAddress!
>
> Item was removed:
> - ----- Method: Cogit>>isDebugPC (in category 'compile abstract
> instructions') -----
> - isDebugPC
> - <doNotGenerate>
> - ^ debugBytecodePointers includes: bytecodePC!
>
> Item was changed:
> ----- Method: Cogit>>maybeBreakGeneratingAt: (in category 'simulation
> only') -----
> maybeBreakGeneratingAt: address
> + "Variation on maybeBreakAt: that only works for integer breakPCs,
> - "Variation on maybeBreakAt: that inly forks for integer breakPCs,
> so we can have break blocks that stop at any pc, except when
> generating."
> + <cmacro: '(address) 0'> "Simulation only; void in C"
> - <doNotGenerate>
> (breakPC = address
> and: [breakBlock shouldStopIfAtPC: address]) ifTrue:
> [coInterpreter changed: #byteCountText.
> self halt: 'machine code generation at ', address hex, '
> in ', thisContext sender selector]!
>
> Item was added:
> + ----- Method: Cogit>>maybeHaltIfDebugPC (in category 'compile abstract
> instructions') -----
> + maybeHaltIfDebugPC
> + <cmacro: '0'> "Simulation only; void in C"
> + (debugBytecodePointers includes: bytecodePC) ifTrue:
> + [self halt]!
>
> 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 := CogMethodZone 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)].
> 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]!
> - debugBytecodePointers := self class initializationOptions at:
> #debugBytecodePointers ifAbsent: [Set new]!
>
> Item was changed:
> ----- Method: RegisterAllocatingCogit>>genJumpIf:to: (in category
> 'bytecode generator support') -----
> genJumpIf: boolean to: targetBytecodePC
> <inline: false>
> + | eventualTarget desc reg fixup ok |
> - | desc reg fixup ok |
> <var: #desc type: #'CogSimStackEntry *'>
> <var: #fixup type: #'BytecodeFixup *'>
> <var: #ok type: #'AbstractInstruction *'>
> + eventualTarget := self eventualTargetOf: targetBytecodePC.
> desc := self ssTop.
> self ssPop: 1.
> (desc type == SSConstant
> and: [desc constant = objectMemory trueObject or: [desc constant
> = objectMemory falseObject]]) ifTrue:
> ["Must arrange there's a fixup at the target whether it is
> jumped to or
> not so that the simStackPtr can be kept correct."
> + fixup := self ensureFixupAt: eventualTarget - initialPC.
> - fixup := self ensureFixupAt: targetBytecodePC - initialPC.
> "Must annotate the bytecode for correct pc mapping."
> self annotateBytecode: (desc constant = boolean
>
> ifTrue: [self Jump: fixup]
>
> ifFalse: [self prevInstIsPCAnnotated
>
> ifTrue: [self Nop]
>
> ifFalse: [self Label]]).
> extA := 0.
> ^0].
> "try and use the top entry's register if anty, but only if it can
> be destroyed."
> reg := (desc type ~= SSRegister
> or: [(self anyReferencesToRegister: desc register
> inAllButTopNItems: 0)
> or: [(desc register = ReceiverResultReg and:
> [optStatus isReceiverResultRegLive])]])
> ifTrue: [TempReg]
> ifFalse: [desc register].
> desc popToReg: reg.
> "Cunning trick by LPD. If true and false are contiguous subtract
> the smaller.
> Correct result is either 0 or the distance between them. If
> result is not 0 or
> their distance send mustBeBoolean."
> self assert: (objectMemory objectAfter: objectMemory falseObject)
> = objectMemory trueObject.
> self genSubConstant: boolean R: reg.
> + self JumpZero: (self ensureFixupAt: eventualTarget - initialPC).
> - self JumpZero: (self ensureFixupAt: targetBytecodePC - initialPC).
>
> self extASpecifiesNoMustBeBoolean ifTrue:
> [extA := 0.
> self annotateBytecode: self lastOpcode.
> ^0].
> extA := 0.
>
> . self CmpCq: (boolean = objectMemory falseObject
> ifTrue: [objectMemory trueObject -
> objectMemory falseObject]
> ifFalse: [objectMemory falseObject
> - objectMemory trueObject])
> R: reg.
> ok := self JumpZero: 0.
> reg ~= TempReg ifTrue:
> [self MoveR: reg R: TempReg].
> self copySimStackToScratch: simSpillBase.
> self ssFlushTo: simStackPtr.
> self genCallMustBeBooleanFor: boolean.
> "NOTREACHED"
> ok jmpTarget: (self annotateBytecode: self Label).
> self restoreSimStackFromScratch.
> ^0!
>
> Item was changed:
> ----- Method: RegisterAllocatingCogit>>genJumpTo: (in category
> 'bytecode generator support') -----
> genJumpTo: targetBytecodePC
> "Overriden to avoid the flush because in this cogit stack state is
> merged at merge point."
> deadCode := true. "can't fall through"
> + self Jump: (self ensureFixupAt: (self eventualTargetOf:
> targetBytecodePC) - initialPC).
> - self Jump: (self ensureFixupAt: targetBytecodePC - initialPC).
> ^ 0!
>
> Item was changed:
> ----- Method: SistaCogit>>genJumpIf:to: (in category 'bytecode generator
> support') -----
> genJumpIf: boolean to: targetBytecodePC
> "The heart of performance counting in Sista. Conditional branches
> are 6 times less
> frequent than sends and can provide basic block frequencies (send
> counters can't).
> Each conditional has a 32-bit counter split into an upper 16 bits
> counting executions
> and a lower half counting untaken executions of the branch.
> Executing the branch
> decrements the upper half, tripping if the count goes negative.
> Not taking the branch
> decrements the lower half. N.B. We *do not* eliminate dead
> branches (true ifTrue:/true ifFalse:)
> so that scanning for send and branch data is simplified and that
> branch data is correct."
> <inline: false>
> + | ok counterAddress countTripped retry nextPC nextDescriptor desc
> eventualTarget |
> - | ok counterAddress countTripped retry nextPC nextDescriptor desc |
> <var: #ok type: #'AbstractInstruction *'>
> <var: #desc type: #'CogSimStackEntry *'>
> <var: #retry type: #'AbstractInstruction *'>
> <var: #countTripped type: #'AbstractInstruction *'>
> <var: #nextDescriptor type: #'BytecodeDescriptor *'>
>
> "In optimized code we don't generate counters to improve
> performance"
> (coInterpreter isOptimizedMethod: methodObj) ifTrue: [ ^ super
> genJumpIf: boolean to: targetBytecodePC ].
>
> "If the branch is reached only for the counter trip trampoline
> (typically, var1 == var2 ifTrue: falls through to the branch only
> for the trampoline)
> we generate a specific path to drastically reduce the number of
> machine instructions"
> branchReachedOnlyForCounterTrip ifTrue:
> [ branchReachedOnlyForCounterTrip := false.
> ^ self genCounterTripOnlyJumpIf: boolean to:
> targetBytecodePC ].
>
> "We detect and: / or:, if found, we don't generate the counters to
> avoid pathological counter slow down"
> boolean = objectMemory falseObject ifTrue:
> [ nextPC := bytecodePC + (self generatorAt: byte0)
> numBytes.
> nextDescriptor := self generatorAt: (objectMemory
> fetchByte: nextPC ofObject: methodObj) + bytecodeSetOffset.
> nextDescriptor generator ==
> #genPushConstantTrueBytecode ifTrue: [ ^ super genJumpIf: boolean to:
> targetBytecodePC ].
> nextDescriptor := self generatorAt: (objectMemory
> fetchByte: targetBytecodePC ofObject: methodObj) + bytecodeSetOffset.
> nextDescriptor generator ==
> #genPushConstantFalseBytecode ifTrue: [ ^ super genJumpIf: boolean to:
> targetBytecodePC ]. ].
>
> extA := 0. "We ignore the noMustBeBoolean flag. It should not be
> present in methods with counters, and if it is we don't care."
>
> "We don't generate counters on branches on true/false, the
> basicblock usage can be inferred"
> desc := self ssTop.
> (desc type == SSConstant
> and: [desc constant = objectMemory trueObject or: [desc constant
> = objectMemory falseObject]]) ifTrue:
> [ ^ super genJumpIf: boolean to: targetBytecodePC ].
> +
> + eventualTarget := self eventualTargetOf: targetBytecodePC.
> +
> -
> self ssFlushTo: simStackPtr - 1.
> desc popToReg: TempReg.
> self ssPop: 1.
>
> "We need SendNumArgsReg because of the mustBeBooleanTrampoline"
> self ssAllocateRequiredReg: SendNumArgsReg.
>
> retry := self Label.
> self
> genExecutionCountLogicInto: [ :cAddress :countTripBranch |
> counterAddress := cAddress.
> countTripped := countTripBranch ]
> counterReg: SendNumArgsReg.
> counterIndex := counterIndex + 1.
>
> "Cunning trick by LPD. If true and false are contiguous subtract
> the smaller.
> Correct result is either 0 or the distance between them. If
> result is not 0 or
> their distance send mustBeBoolean."
> self assert: (objectMemory objectAfter: objectMemory falseObject)
> = objectMemory trueObject.
> self genSubConstant: boolean R: TempReg.
> + self JumpZero: (self ensureFixupAt: eventualTarget - initialPC).
> - self JumpZero: (self ensureFixupAt: targetBytecodePC - initialPC).
>
> self genFallsThroughCountLogicCounterReg: SendNumArgsReg
> counterAddress: counterAddress.
>
> self CmpCq: (boolean = objectMemory falseObject
> ifTrue: [objectMemory trueObject -
> objectMemory falseObject]
> ifFalse: [objectMemory falseObject
> - objectMemory trueObject])
> R: TempReg.
> ok := self JumpZero: 0.
> self MoveCq: 0 R: SendNumArgsReg. "if counterReg is 0 this is a
> mustBeBoolean, not a counter trip."
>
> countTripped jmpTarget: (self genCallMustBeBooleanFor: boolean).
>
> "If we're in an image which hasn't got the Sista code loaded then
> the ceCounterTripped:
> trampoline will return directly to machine code, returning the
> boolean. So the code should
> jump back to the retry point. The trampoline makes sure that
> TempReg has been reloaded."
>
> "Clément: For some reason if I write self annotateBytecode: (self
> Jump: retry) the annotation is not at the correct place."
> "Eliot: Annotations apply the the address following an
> instruction, and the annotation must be for the return address
> of the call (since this is the address the run-time sees), so it
> must be on a label before the jump, not after the jump."
> self annotateBytecode: self Label.
> self Jump: retry.
>
> ok jmpTarget: self Label.
> ^0!
>
> Item was changed:
> ----- Method: SistaRegisterAllocatingCogit>>genJumpIf:to: (in category
> 'bytecode generator support') -----
> genJumpIf: boolean to: targetBytecodePC
> "The heart of performance counting in Sista. Conditional branches
> are 6 times less
> frequent than sends and can provide basic block frequencies (send
> counters can't).
> Each conditional has a 32-bit counter split into an upper 16 bits
> counting executions
> and a lower half counting untaken executions of the branch.
> Executing the branch
> decrements the upper half, tripping if the count goes negative.
> Not taking the branch
> decrements the lower half. N.B. We *do not* eliminate dead
> branches (true ifTrue:/true ifFalse:)
> so that scanning for send and branch data is simplified and that
> branch data is correct."
> <inline: false>
> + | ok counterAddress countTripped retry nextPC nextDescriptor desc
> eventualTarget reg |
> - | ok counterAddress countTripped retry nextPC nextDescriptor desc
> reg |
> <var: #ok type: #'AbstractInstruction *'>
> <var: #desc type: #'CogSimStackEntry *'>
> <var: #retry type: #'AbstractInstruction *'>
> <var: #countTripped type: #'AbstractInstruction *'>
> <var: #nextDescriptor type: #'BytecodeDescriptor *'>
>
> "In optimized code we don't generate counters to improve
> performance"
> (coInterpreter isOptimizedMethod: methodObj) ifTrue:
> [^super genJumpIf: boolean to: targetBytecodePC].
>
> "If the branch is reached only for the counter trip trampoline
> (typically, var1 == var2 ifTrue: falls through to the branch only
> for the trampoline)
> we generate a specific path to drastically reduce the number of
> machine instructions"
> branchReachedOnlyForCounterTrip ifTrue:
> [branchReachedOnlyForCounterTrip := false.
> ^self genCounterTripOnlyJumpIf: boolean to:
> targetBytecodePC].
>
> "We detect and: / or:, if found, we don't generate the counters to
> avoid pathological counter slow down"
> boolean = objectMemory falseObject ifTrue:
> [ nextPC := bytecodePC + (self generatorAt: byte0)
> numBytes.
> nextDescriptor := self generatorAt: (objectMemory
> fetchByte: nextPC ofObject: methodObj) + bytecodeSetOffset.
> nextDescriptor generator ==
> #genPushConstantTrueBytecode ifTrue: [ ^ super genJumpIf: boolean to:
> targetBytecodePC ].
> nextDescriptor := self generatorAt: (objectMemory
> fetchByte: targetBytecodePC ofObject: methodObj) + bytecodeSetOffset.
> nextDescriptor generator ==
> #genPushConstantFalseBytecode ifTrue: [ ^ super genJumpIf: boolean to:
> targetBytecodePC ]. ].
>
> extA := 0. "We ignore the noMustBeBoolean flag. It should not be
> present in methods with counters, and if it is we don't care."
>
> "We don't generate counters on branches on true/false, the
> basicblock usage can be inferred"
> desc := self ssTop.
> (desc type == SSConstant
> and: [desc constant = objectMemory trueObject or: [desc constant
> = objectMemory falseObject]]) ifTrue:
> [ ^ super genJumpIf: boolean to: targetBytecodePC ].
>
> + eventualTarget := self eventualTargetOf: targetBytecodePC.
> +
> self flag: 'Because of the restriction on x64 that absolute loads
> must target %rax, it would perhaps be a better choice to use TempReg (%rax)
> for the counter reg and SendNumArgsReg for the boolean.'.
> "try and use the top entry's register if ant, but only if it can
> be destroyed."
> reg := (desc type ~= SSRegister
> or: [(self anyReferencesToRegister: desc register
> inAllButTopNItems: 0)
> or: [(desc register = ReceiverResultReg and:
> [optStatus isReceiverResultRegLive])]])
> ifTrue: [TempReg]
> ifFalse: [desc register].
> desc popToReg: reg.
> self ssPop: 1.
>
> "We need SendNumArgsReg because of the mustBeBooleanTrampoline"
> self ssAllocateRequiredReg: SendNumArgsReg.
>
> retry := self Label.
> self
> genExecutionCountLogicInto: [ :cAddress :countTripBranch |
> counterAddress := cAddress.
> countTripped := countTripBranch ]
> counterReg: SendNumArgsReg.
> counterIndex := counterIndex + 1.
>
> "Cunning trick by LPD. If true and false are contiguous subtract
> the smaller.
> Correct result is either 0 or the distance between them. If
> result is not 0 or
> their distance send mustBeBoolean."
> self assert: (objectMemory objectAfter: objectMemory falseObject)
> = objectMemory trueObject.
> self genSubConstant: boolean R: reg.
> + self JumpZero: (self ensureFixupAt: eventualTarget - initialPC).
> - self JumpZero: (self ensureFixupAt: targetBytecodePC - initialPC).
>
> self genFallsThroughCountLogicCounterReg: SendNumArgsReg
> counterAddress: counterAddress.
>
> self CmpCq: (boolean = objectMemory falseObject
> ifTrue: [objectMemory trueObject -
> objectMemory falseObject]
> ifFalse: [objectMemory falseObject
> - objectMemory trueObject])
> R: reg.
> ok := self JumpZero: 0.
> self MoveCq: 0 R: SendNumArgsReg. "if counterReg is 0 this is a
> mustBeBoolean, not a counter trip."
> reg ~= TempReg ifTrue:
> [self MoveR: reg R: TempReg].
> countTripped jmpTarget: self Label.
> self copySimStackToScratch: simSpillBase.
> self ssFlushTo: simStackPtr.
> self genCallMustBeBooleanFor: boolean.
>
> "If we're in an image which hasn't got the Sista code loaded then
> the ceCounterTripped: trampoline
> will return directly to machine code, returning the boolean. So
> the code should jump back to the
> retry point. The trampoline preserves register state when taking
> the ceCounterTripped: path."
> "Clément: For some reason if I write self annotateBytecode: (self
> Jump: retry) the annotation is not at the correct place."
> "Eliot: Annotations apply the the address following an
> instruction, and the annotation must be for the return address
> of the call (since this is the address the run-time sees), so it
> must be on a label before the jump, not after the jump."
> self annotateBytecode: self Label.
> simSpillBase ~= scratchSpillBase ifTrue:
> [self assert: simSpillBase > scratchSpillBase.
> self AddCq: simSpillBase - scratchSpillBase *
> objectMemory wordSize R: SPReg].
> self Jump: retry.
>
> ok jmpTarget: self Label.
> self restoreSimStackFromScratch.
> ^0!
>
> Item was changed:
> ----- Method: StackToRegisterMappingCogit>>
> compileAbstractInstructionsFrom:through: (in category 'compile abstract
> instructions') -----
> compileAbstractInstructionsFrom: start through: end
> "Loop over bytecodes, dispatching to the generator for each
> bytecode, handling fixups in due course."
> | nextOpcodeIndex descriptor nExts fixup result |
> <var: #descriptor type: #'BytecodeDescriptor *'>
> <var: #fixup type: #'BytecodeFixup *'>
> self traceSimStack.
> bytecodePC := start.
> nExts := result := 0.
> descriptor := nil.
> deadCode := false.
> + [self maybeHaltIfDebugPC.
> - [self cCode: '' inSmalltalk: [self isDebugPC ifTrue: [self halt]].
> fixup := self fixupAt: bytecodePC - initialPC.
> self mergeWithFixupIfRequired: fixup.
> self assertCorrectSimStackPtr.
> descriptor := self loadBytesAndGetDescriptor.
> nextOpcodeIndex := opcodeIndex.
> result := deadCode
> ifTrue: [self mapDeadDescriptorIfNeeded:
> descriptor]
> ifFalse: [self perform: descriptor
> generator].
> self assertExtsAreConsumed: descriptor.
> self traceDescriptor: descriptor; traceSimStack.
> self patchFixupTargetIfNeeded: fixup nextOpcodeIndex:
> nextOpcodeIndex.
> self maybeDumpLiterals: descriptor.
> bytecodePC := self nextBytecodePCFor: descriptor exts: nExts.
> result = 0 and: [bytecodePC <= end]] whileTrue:
> [nExts := descriptor isExtension ifTrue: [nExts + 1]
> ifFalse: [0]].
> self checkEnoughOpcodes.
> ^result!
>
> Item was changed:
> ----- Method: StackToRegisterMappingCogit>>compileBlockBodies (in
> category 'compile abstract instructions') -----
> compileBlockBodies
> <inline: false>
> | result compiledBlocksCount blockStart savedNeedsFrame
> savedNumArgs savedNumTemps
> initialStackPtr initialOpcodeIndex initialIndexOfIRC
> initialCounterIndex |
> <var: #blockStart type: #'BlockStart *'>
> self assert: blockCount > 0.
> "scanBlock: in compileBlockEntry: sets both of these appropriately
> for each block."
> savedNeedsFrame := needsFrame.
> savedNumArgs := methodOrBlockNumArgs.
> savedNumTemps := methodOrBlockNumTemps.
> inBlock := InVanillaBlock.
> compiledBlocksCount := 0.
> [compiledBlocksCount < blockCount] whileTrue:
> [blockPass := 1.
> blockStart := self blockStartAt: compiledBlocksCount.
> (result := self scanBlock: blockStart) < 0 ifTrue:
> [^result].
> initialOpcodeIndex := opcodeIndex.
> initialCounterIndex := self maybeCounterIndex."for
> SistaCogit"
> literalsManager saveForBlockCompile.
> NewspeakVM ifTrue:
> [initialIndexOfIRC := indexOfIRC].
> [self compileBlockEntry: blockStart.
> initialStackPtr := simStackPtr.
> (result := self compileAbstractInstructionsFrom:
> blockStart startpc + (self pushNilSize: methodObj numInitialNils:
> blockStart numInitialNils)
> through: blockStart
> startpc + blockStart span - 1) < 0 ifTrue:
> [^result].
> "If the final simStackPtr is less than the initial
> simStackPtr then scanBlock: over-
> estimated the number of initial nils (because it
> assumed one or more pushNils to
> produce an operand were pushNils to initialize temps.
> This is very rare, so
> compensate by checking, adjusting numInitialNils and
> recompiling the block body.
> N.B. No need to reinitialize the literalsManager
> because it answers existing literals."
> initialStackPtr = simStackPtr]
> whileFalse:
> + [self assert: (initialStackPtr >
> simStackPtr or: [deadCode]).
> - [self assert: initialStackPtr >
> simStackPtr.
> blockPass := blockPass + 1. "for asserts
> :-("
> blockStart numInitialNils: blockStart
> numInitialNils + simStackPtr - initialStackPtr.
> blockStart fakeHeader dependent: nil.
> self reinitializeFixupsFrom: blockStart
> startpc + blockStart numInitialNils
> through: blockStart startpc +
> blockStart span - 1.
> self cCode: 'bzero(abstractOpcodes +
> initialOpcodeIndex,
>
> (opcodeIndex - initialOpcodeIndex) * sizeof(AbstractInstruction))'
> inSmalltalk: [initialOpcodeIndex
> to: opcodeIndex - 1 do:
>
> [:i| abstractOpcodes at: i put: (CogCompilerClass for: self)]].
> opcodeIndex := initialOpcodeIndex.
> self maybeSetCounterIndex:
> initialCounterIndex. "For SistaCogit"
> literalsManager resetForBlockCompile.
> NewspeakVM ifTrue:
> [indexOfIRC := initialIndexOfIRC]].
> compiledBlocksCount := compiledBlocksCount + 1].
> needsFrame := savedNeedsFrame.
> methodOrBlockNumArgs := savedNumArgs.
> methodOrBlockNumTemps := savedNumTemps.
> ^0!
>
> Item was added:
> + ----- Method: StackToRegisterMappingCogit>>eventualTargetOf: (in
> category 'peephole optimizations') -----
> + eventualTargetOf: targetBytecodePC
> + "Attempt to follow a branch to a pc. Handle branches to
> unconditional jumps
> + and branches to push: aBoolean; conditional branch pairs. If the
> branch cannot
> + be followed answer targetBytecodePC."
> +
> + | currentTarget nextPC nExts descriptor span cond |
> + <var: #descriptor type: #'BytecodeDescriptor *'>
> + nextPC := currentTarget := targetBytecodePC.
> + [[nExts := 0.
> + descriptor := self generatorAt: bytecodeSetOffset
> + +
> (objectMemory fetchByte: nextPC ofObject: methodObj).
> + descriptor isReturn ifTrue: [^currentTarget]. "avoid stepping
> off the end of methods"
> + descriptor isExtension]
> + whileTrue:
> + [nExts := nExts + 1.
> + nextPC := nextPC + descriptor numBytes].
> + descriptor isUnconditionalBranch
> + ifTrue:
> + [span := self spanFor: descriptor at: nextPC exts:
> nExts in: methodObj.
> + span < 0 ifTrue: "Do *not* follow backward
> branches; these are interrupt points and should not be elided."
> + [^currentTarget].
> + nextPC := nextPC + descriptor numBytes + span]
> + ifFalse:
> + [descriptor generator
> + caseOf: {
> + [#genPushConstantTrueBytecode] -> [cond :=
> true].
> + [#genPushConstantFalseBytecode] -> [cond
> := false] }
> + otherwise: [^currentTarget].
> + "Don't step into loops across a pushTrue;
> jump:if: boundary, so as not to confuse stack depth fixup."
> + (fixups at: nextPC - initialPC)
> isBackwardBranchFixup ifTrue:
> + [^currentTarget].
> + nextPC := self eventualTargetOf: nextPC +
> descriptor numBytes.
> + nExts := 0.
> + [descriptor := self generatorAt: bytecodeSetOffset
> + +
> (objectMemory fetchByte: nextPC ofObject: methodObj).
> + descriptor isReturn ifTrue: [^currentTarget].
> "avoid stepping off the end of methods"
> + descriptor isExtension]
> + whileTrue:
> + [nExts := nExts + 1.
> + nextPC := nextPC + descriptor
> numBytes].
> + descriptor isBranch ifFalse:
> + [^currentTarget].
> + descriptor isUnconditionalBranch ifTrue:
> + [^currentTarget].
> + nextPC := cond == descriptor isBranchTrue
> +
> ifTrue: [nextPC
> +
> + descriptor numBytes
> +
> + (self spanFor: descriptor at: nextPC exts: nExts in:
> methodObj)]
> +
> ifFalse: [nextPC + descriptor numBytes]].
> + currentTarget := nextPC]
> + repeat!
>
> Item was changed:
> ----- Method: StackToRegisterMappingCogit>>
> extractMaybeBranchDescriptorInto: (in category 'bytecode generator
> support') -----
> extractMaybeBranchDescriptorInto: fourArgBlock
> "Looks one instruction ahead of the current bytecodePC and answers
> its bytecode descriptor and its pc.
> + If the instruction found is a branch, also answers the pc after
> the branch and the pc targeted by the branch."
> - If the instruction found is a branch, also answers the pc after
> the branch and the pc targetted by the branch"
> | primDescriptor nextPC nExts branchDescriptor targetBytecodePC
> postBranchPC |
> <inline: true>
> <var: #primDescriptor type: #'BytecodeDescriptor *'>
> <var: #branchDescriptor type: #'BytecodeDescriptor *'>
>
> primDescriptor := self generatorAt: byte0.
>
> nextPC := bytecodePC + primDescriptor numBytes.
> nExts := 0.
> + [[branchDescriptor := self generatorAt: (objectMemory fetchByte:
> nextPC ofObject: methodObj) + bytecodeSetOffset.
> + branchDescriptor isExtension] whileTrue:
> - [branchDescriptor := self generatorAt: (objectMemory fetchByte:
> nextPC ofObject: methodObj) + bytecodeSetOffset.
> - branchDescriptor isExtension] whileTrue:
> [nExts := nExts + 1.
> nextPC := nextPC + branchDescriptor numBytes].
> + branchDescriptor isUnconditionalBranch]
> + whileTrue:
> + [nextPC := self eventualTargetOf: nextPC
> +
> + branchDescriptor numBytes
> +
> + (self spanFor: branchDescriptor at: nextPC exts: nExts in:
> methodObj)].
>
> targetBytecodePC := postBranchPC := 0.
>
> + (branchDescriptor isBranchTrue or: [branchDescriptor
> isBranchFalse])
> + ifTrue:
> + [targetBytecodePC := self eventualTargetOf: nextPC
> +
> + branchDescriptor numBytes
> +
> + (self spanFor: branchDescriptor at:
> nextPC exts: nExts in: methodObj).
> + postBranchPC := self eventualTargetOf: nextPC +
> branchDescriptor numBytes]
> + ifFalse:
> + [branchDescriptor isReturn ifFalse:
> + [postBranchPC := self eventualTargetOf:
> nextPC + branchDescriptor numBytes.
> + nextPC := self eventualTargetOf:
> bytecodePC + primDescriptor numBytes]].
> +
> - (branchDescriptor isBranchTrue or: [branchDescriptor
> isBranchFalse]) ifTrue:
> - [ targetBytecodePC := nextPC
> - + branchDescriptor
> numBytes
> - + (self spanFor:
> branchDescriptor at: nextPC exts: nExts in: methodObj).
> - postBranchPC := nextPC + branchDescriptor numBytes ].
> -
> fourArgBlock value: branchDescriptor value: nextPC value:
> postBranchPC value: targetBytecodePC!
>
> Item was changed:
> ----- Method: StackToRegisterMappingCogit>>genJumpIf:to: (in category
> 'bytecode generator support') -----
> genJumpIf: boolean to: targetBytecodePC
> <inline: false>
> + | desc fixup ok eventualTarget |
> - | desc fixup ok |
> <var: #desc type: #'CogSimStackEntry *'>
> <var: #fixup type: #'BytecodeFixup *'>
> <var: #ok type: #'AbstractInstruction *'>
> + eventualTarget := self eventualTargetOf: targetBytecodePC.
> self ssFlushTo: simStackPtr - 1.
> desc := self ssTop.
> self ssPop: 1.
> (desc type == SSConstant
> and: [desc constant = objectMemory trueObject or: [desc constant
> = objectMemory falseObject]]) ifTrue:
> ["Must arrange there's a fixup at the target whether it is
> jumped to or
> not so that the simStackPtr can be kept correct."
> + fixup := self ensureFixupAt: eventualTarget - initialPC.
> - fixup := self ensureFixupAt: targetBytecodePC - initialPC.
> "Must annotate the bytecode for correct pc mapping."
> self annotateBytecode: (desc constant = boolean
>
> ifTrue: [self Jump: fixup]
>
> ifFalse: [self prevInstIsPCAnnotated
>
> ifTrue: [self Nop]
>
> ifFalse: [self Label]]).
> extA := 0.
> ^0].
> desc popToReg: TempReg.
> "Cunning trick by LPD. If true and false are contiguous subtract
> the smaller.
> Correct result is either 0 or the distance between them. If
> result is not 0 or
> their distance send mustBeBoolean."
> self assert: (objectMemory objectAfter: objectMemory falseObject)
> = objectMemory trueObject.
> self genSubConstant: boolean R: TempReg.
> + self JumpZero: (self ensureFixupAt: eventualTarget - initialPC).
> - self JumpZero: (self ensureFixupAt: targetBytecodePC - initialPC).
>
> self extASpecifiesNoMustBeBoolean ifTrue:
> [ extA := 0.
> self annotateBytecode: self lastOpcode.
> ^ 0].
> extA := 0.
>
> + self CmpCq: (boolean = objectMemory falseObject
> - . self CmpCq: (boolean = objectMemory falseObject
> ifTrue: [objectMemory trueObject -
> objectMemory falseObject]
> ifFalse: [objectMemory falseObject
> - objectMemory trueObject])
> R: TempReg.
> ok := self JumpZero: 0.
> self genCallMustBeBooleanFor: boolean.
> ok jmpTarget: (self annotateBytecode: self Label).
> ^0!
>
> Item was changed:
> ----- Method: StackToRegisterMappingCogit>>genJumpTo: (in category
> 'bytecode generator support') -----
> genJumpTo: targetBytecodePC
> self ssFlushTo: simStackPtr.
> deadCode := true. "can't fall through"
> + self Jump: (self ensureFixupAt: (self eventualTargetOf:
> targetBytecodePC) - initialPC).
> + ^0!
> - ^super genJumpTo: targetBytecodePC!
>
> Item was added:
> + ----- Method: StackToRegisterMappingCogit>>generateInstructionsAt: (in
> category 'generate machine code') -----
> + generateInstructionsAt: eventualAbsoluteAddress
> + "Size pc-dependent instructions and assign eventual addresses to
> all instructions.
> + Answer the size of the code.
> + Compute forward branches based on virtual address (abstract code
> starts at 0),
> + assuming that any branches branched over are long.
> + Compute backward branches based on actual address.
> + Reuse the fixups array to record the pc-dependent instructions
> that need to have
> + their code generation postponed until after the others.
> +
> + Override to andd handling for null branches (branches to the
> immediately following
> + instruction) occasioned by StackToRegisterMapping's following of
> jumps."
> + | absoluteAddress pcDependentIndex abstractInstruction fixup |
> + <var: #abstractInstruction type: #'AbstractInstruction *'>
> + <var: #fixup type: #'BytecodeFixup *'>
> + absoluteAddress := eventualAbsoluteAddress.
> + pcDependentIndex := 0.
> + 0 to: opcodeIndex - 1 do:
> + [:i|
> + self maybeBreakGeneratingAt: absoluteAddress.
> + abstractInstruction := self abstractInstructionAt: i.
> + abstractInstruction isPCDependent
> + ifTrue:
> + [abstractInstruction
> sizePCDependentInstructionAt: absoluteAddress.
> + (abstractInstruction isJump
> + and: [i + 1 < opcodeIndex
> + and: [abstractInstruction getJmpTarget
> == (self abstractInstructionAt: i + 1)]])
> + ifTrue:
> + [abstractInstruction
> + opcode: Nop;
> + concretizeAt:
> absoluteAddress]
> + ifFalse:
> + [fixup := self fixupAt:
> pcDependentIndex.
> + pcDependentIndex :=
> pcDependentIndex + 1.
> + fixup instructionIndex:
> i].
> + absoluteAddress := absoluteAddress +
> abstractInstruction machineCodeSize]
> + ifFalse:
> + [absoluteAddress := abstractInstruction
> concretizeAt: absoluteAddress]].
> + 0 to: pcDependentIndex - 1 do:
> + [:j|
> + fixup := self fixupAt: j.
> + abstractInstruction := self abstractInstructionAt: fixup
> instructionIndex.
> + self maybeBreakGeneratingAt: abstractInstruction address.
> + abstractInstruction concretizeAt: abstractInstruction
> address].
> + ^absoluteAddress - eventualAbsoluteAddress!
>
> Item was changed:
> ----- Method: StackToRegisterMappingCogit>>mergeWithFixupIfRequired:
> (in category 'simulation stack') -----
> mergeWithFixupIfRequired: fixup
> "If this bytecode has a fixup, some kind of merge needs to be
> done. There are 4 cases:
> 1) the bytecode has no fixup (fixup isNotAFixup)
> do nothing
> 2) the bytecode has a non merge fixup
> the fixup has needsNonMergeFixup.
> The code generating non merge fixup (currently
> only special selector code) is responsible
> for the merge so no need to do it.
> We set deadCode to false as the instruction can be
> reached from jumps.
> 3) the bytecode has a merge fixup, but execution flow
> *cannot* fall through to the merge point.
> the fixup has needsMergeFixup and deadCode = true.
> ignores the current simStack as it does not mean
> anything
> restores the simStack to the state the jumps to
> the merge point expects it to be.
> 4) the bytecode has a merge fixup and execution flow *can*
> fall through to the merge point.
> the fixup has needsMergeFixup and deadCode = false.
> flushes the stack to the stack pointer so the fall
> through execution path simStack is
> in the state the merge point expects it to
> be.
> restores the simStack to the state the jumps to
> the merge point expects it to be.
>
> In addition, if this is a backjump merge point, we patch the fixup
> to hold the current simStackPtr
> for later assertions."
>
> <var: #fixup type: #'BytecodeFixup *'>
> "case 1"
> + fixup notAFixup ifTrue:
> + [^0].
> - fixup notAFixup ifTrue: [^ 0].
>
> "case 2"
> + fixup isNonMergeFixup ifTrue:
> + [deadCode := false. ^0].
> - fixup isNonMergeFixup ifTrue: [deadCode := false. ^ 0 ].
>
> "cases 3 and 4"
> self assert: fixup isMergeFixup.
> self traceMerge: fixup.
> + deadCode
> + ifTrue: "case 3"
> + ["Would like to assert fixup simStackPtr >=
> (methodOrBlockNumTemps - 1) but can't because
> + a) the initialNils hack, b) deadCode removal
> allows arriving at an isBackwardBranchFixup."
> + self assert: (fixup simStackPtr >=
> (methodOrBlockNumTemps - 1) or: [inBlock = InVanillaBlock or: [fixup
> isBackwardBranchFixup]]).
> + fixup isBackwardBranchFixup ifFalse:
> + [simStackPtr := fixup simStackPtr].
> + LowcodeVM ifTrue:
> + [simNativeStackPtr := fixup
> simNativeStackPtr.
> + simNativeStackSize := fixup
> simNativeStackSize]]
> + ifFalse: "case 4"
> + [self ssFlushTo: simStackPtr].
> - deadCode ifTrue: [
> - "case 3"
> - simStackPtr := fixup simStackPtr.
> - LowcodeVM ifTrue: [
> - simNativeStackPtr := fixup simNativeStackPtr.
> - simNativeStackSize := fixup simNativeStackSize.
> - ]
> - ] ifFalse: [
> - "case 4"
> - self ssFlushTo: simStackPtr
> - ].
>
> "cases 3 and 4"
> deadCode := false.
> + fixup isBackwardBranchFixup ifTrue:
> + [fixup simStackPtr: simStackPtr.
> + LowcodeVM ifTrue:
> + [fixup simNativeStackPtr: simNativeStackPtr.
> + fixup simNativeStackSize: simNativeStackSize]].
> - fixup isBackwardBranchFixup ifTrue: [
> - fixup simStackPtr: simStackPtr.
> - LowcodeVM ifTrue: [
> - fixup simNativeStackPtr: simNativeStackPtr.
> - fixup simNativeStackSize: simNativeStackSize.
> - ]
> - ].
> fixup targetInstruction: self Label.
> self assert: simStackPtr = fixup simStackPtr.
> + LowcodeVM ifTrue:
> + [self assert: simNativeStackPtr = fixup simNativeStackPtr.
> + self assert: simNativeStackSize = fixup
> simNativeStackSize].
> - LowcodeVM ifTrue: [
> - self assert: simNativeStackPtr = fixup simNativeStackPtr.
> - self assert: simNativeStackSize = fixup simNativeStackSize.
> - ].
>
> self cCode: '' inSmalltalk:
> [self assert: fixup simStackPtr = (self
> debugStackPointerFor: bytecodePC)].
> self restoreSimStackAtMergePoint: fixup.
> +
> -
> ^0!
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.squeakfoundation.org/pipermail/vm-dev/attachments/20170117/a585e838/attachment-0001.html>
More information about the Vm-dev
mailing list