Observed while simulating newspeak with this stack:
``` 16r107230 M BitBlt>copy:from:in:fillColor:rule: 16r320338: a(n) BitBlt 16r10725C M Form>copy:from:in:rule: 16r31F618: a(n) Form 16r1072A0 M StrikeFont>characterFormAt:put: 16r318E60: a(n) StrikeFont 16r1072D4 I StrikeFont>ensureCleanBold 16r318E60: a(n) StrikeFont 16r1072FC M StrikeFont>emphasized: 16r8EAFE8: a(n) StrikeFont 16r10731C M BrazilStringMorph(StringMorph)>fontToUse 16r314AF8: a(n) BrazilStringMorph 16r107338 M BrazilStringMorph(StringMorph)>measureContents 16r314AF8: a(n) BrazilStringMorph 16r107358 M BrazilStringMorph(StringMorph)>fitContents 16r314AF8: a(n) BrazilStringMorph 16r107370 M BrazilStringMorph(StringMorph)>font:emphasis: 16r314AF8: a(n) BrazilStringMorph 16r107398 I BrazilStringMorph(StringMorph)>font: 16r314AF8: a(n) BrazilStringMorph 16r1073B4 M LabelMorphicAgent>setMorphFont: 16r1183A0: a(n) LabelMorphicAgent 16r1073D4 M [] in LabelMorphicAgent(Object)>~ 16r1183A0: a(n) LabelMorphicAgent 16r1073F0 M AttributeMapping>update 16r316A60: a(n) AttributeMapping ```
The BitBlt spec is:
``` interpreterProxy: a Spur32BitMMLECoSimulator moduleName: nil translatedMethodCache: nil simulator: a SmartSyntaxPluginSimulator destForm: 3274264 sourceForm: 3268464 halftoneForm: 5419272 combinationRule: 3 destX: 20 destY: 0 width: 1581 height: 15 sourceX: 19 sourceY: 0 clipX: 0 clipY: 0 clipWidth: 1601 clipHeight: 15 sourceWidth: 1600 sourceHeight: 15 sourceDepth: 1 sourcePitch: 200 sourceBits: 3268512 sourcePPW: 32 sourceMSB: true destWidth: 1601 destHeight: 15 destDepth: 1 destPitch: 204 destBits: 3274312 destPPW: 32 destMSB: true bitCount: 0 skew: -1 mask1: 4095 mask2: 2147483648 preload: false nWords: 51 destMask: 2147483648 hDir: 1 vDir: 1 sourceIndex: 3271512 sourceDelta: -4 destIndex: 3277368 destDelta: 0 sx: 19 sy: 0 dx: 20 dy: 0 bbW: 1581 bbH: 15 halftoneHeight: 0 noSource: false noHalftone: true halftoneBase: nil sourceAlpha: nil srcBitShift: 0 dstBitShift: 0 bitBltOop: 3277624 affectedL: 0 affectedR: 15 affectedT: 0 affectedB: 15 opTable: #(#clearWord:with: #bitAnd:with: #bitAndInvert:with: #sourceWord:with: #bitInvertAnd:with: #destinationWord:with: #bitXor:with: #bitOr:with: #bitInvertAndInvert:with: #bitInvertXor:with: #bitInvertDestination:with: #bitOrInvert:with: #bitInvertSource:with: #bitInvertOr:with: #bitInvertOrInvert:with: #destinationWord:with: #destinationWord:with: #destinationWord:with: #addWord:with: #subWord:with: #rgbAdd:with: #rgbSub:with: #OLDrgbDiff:with: #OLDtallyIntoMap:with: #alphaBlend:with: #pixPaint:with: #pixMask:with: #rgbMax:with: #rgbMin:with: #rgbMinInvert:with: #alphaBlendConst:with: #alphaPaintConst:with: #rgbDiff:with: #tallyIntoMap:with: #alphaBlendScaled:with: #alphaBlendScaled:with: #alphaBlendScaled:with: #rgbMul:with: #pixSwap:with: #pixClear:with: #fixAlpha:with: #rgbComponentAlpha:with:) maskTable: #(1 3 nil 15 31 nil nil 255 nil nil nil nil nil nil nil 65535 nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil 4294967295) ditherMatrix4x4: a CArrayAccessor on: #(0 8 2 10 12 4 14 6 3 11 1 9 15 7 13 5) ditherThresholds16: a CArrayAccessor on: #(0 2 4 6 8 10 12 14 16) ditherValues16: a CArrayAccessor on: #(0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30) hasSurfaceLock: false warpSrcShift: 5 warpSrcMask: 4294967295 warpAlignShift: 0 warpAlignMask: 0 warpBitShiftTable: a CArrayAccessor on: #(0 nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil) querySurfaceFn: nil lockSurfaceFn: nil unlockSurfaceFn: nil isWarping: false cmFlags: 0 cmMask: 0 cmShiftTable: nil cmMaskTable: nil cmLookupTable: nil cmBitsPerColor: 0 dither8Lookup: a CArrayAccessor on: #( ...snip byte array of size 4096 ...) componentAlphaModeColor: nil componentAlphaModeAlpha: nil ungammaLookupTable: nil gammaLookupTable: nil numGCsOnInvocation: 14 bitBltIsReceiver: true endOfDestination: 3277372 endOfSource: 3271512 destinationHashes: nil copyBitsCount: nil copyBitsBreakCount: nil ```
So, we need exactly 50 words to represent a row of source (width = 1600 pixels / 32 pixelPerWord). Trying to read `nWords = 51` is asking for trouble... We are translating 1 bit to the right, so the destination requires 51 words (1601 pixels).
What we ought to do in the `BitBlt>>copyLoop` is: Copy 12bits from 1st src word (`mask1 - 16rFFF "4095"`) onto 1st dst word Then 49 times copy the rotate thing (last bit from prev src word+31 bits from next src word) onto next dest word ``` skewWord := ((prevWord bitAnd: notSkewMask) bitShift: unskew) bitOr: "32-bit rotate" ((thisWord bitAnd: skewMask) bitShift: skew). ``` Then last bit of prev src word to next dest word (with `mask2 = 16r80000000`).
The incorrect code is in the last section, trying to read next sourceWord for nothing since it will be fully masked by `mask2` after rotation (skew). So this last code requires a protection. We could for example try `((skewMask bitShift: skew) bitAnd: mask2)`, and if null don't fetch next sourceWord (just use 0 instead).
Thanks for looking into this!
http://source.squeak.org/VMMaker/VMMaker.oscog-nice.2575.diff is integrated
Closed #441.
vm-dev@lists.squeakfoundation.org