<body><div id="__MailbirdStyleContent" style="font-size: 10pt;font-family: Arial;color: #000000">
                                        Hi Levente.<div><br></div><div>> <span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px">And when MC calculates the next update number, it doesn't take into </span><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px">account what's in your package cache. It only looks up the remote </span><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px">repositories and calculates the next number based on those.</span></div><div><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px"><br></span></div><div><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px">No worries. We should also consider the package cache in MCWorkingCopy >> #uniqueVersionName.</span></div><div><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px"><br></span></div><div><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px">Best,</span></div><div><span style="font-family: Arial, Helvetica, sans-serif;font-size: 13px">Marcel</span></div><div class="mb_sig"></div><blockquote class="history_container" type="cite" style="border-left-style:solid;border-width:1px; margin-top:20px; margin-left:0px;padding-left:10px;">
                        <p style="color: #AAAAAA; margin-top: 10px;">Am 16.06.2020 13:25:08 schrieb Levente Uzonyi <leves@caesar.elte.hu>:</p><div style="font-family:Arial,Helvetica,sans-serif">Hi All,<br><br>On Tue, 16 Jun 2020, commits@source.squeak.org wrote:<br><br>> Marcel Taeumel uploaded a new version of Collections to project The Trunk:<br>> http://source.squeak.org/trunk/Collections-mt.898.mcz<br>><br>> ==================== Summary ====================<br>><br>> Name: Collections-mt.898<br>> Author: mt<br>> Time: 16 June 2020, 8:55:38.416917 am<br>> UUID: 89207449-befb-f84f-83a0-ff0d727d40bc<br>> Ancestors: Collections-mt.896, Collections-ul.897<br>><br>> Merges ancestry. <br>><br>> Does somebody know where to find Collections-ul.896?<br><br>Well, that's not the actual Collections-ul.897 I intended to push to <br>the Inbox/Trunk. It contains my experiments with primitive 158, but does <br>not use the primitive yet (the pragmas are commented out).<br>Fortunately, the code is backwards compatible. It introduces minor <br>slowdown because it uses the fallback code (which is the "old" primitive) <br>instead of primitive 158 for string comparison.<br><br>The reason why I mistakenly uploaded it is because MC silently ignores <br>your commit when a file with the same name exists.<br>And when MC calculates the next update number, it doesn't take into <br>account what's in your package cache. It only looks up the remote <br>repositories and calculates the next number based on those.<br>After "saving" it also shows the window with your freshly "saved" <br>version open, so you can easily copy "it" to any repository you want to.<br><br>Since I already had Collections-ul.897 in my package cache, my version <br>with only the WeakIdentityDictionary and the removal of ByteArray >> <br>#atAllPut: got lost.<br><br>Back to primitive 158, there is a bug in either the jitted variant of the <br>primitive or the jit engine I was trying to track down. But I couldn't <br>find out how to set a breakpoint in jitted code with gdb, nor did I want <br>to build the bochs plugin, so I simply gave up.<br>If someone has the time and tools ready to debug it, here's a recipe to <br>trigger the error:<br>1. Make sure your image has been saved as the bug might cause corruption.<br>2. Uncomment the primitive pragmas in String >> #compareWith: and String <br>>> #compareWith:collated:<br>3. Run ClosureCompilerTest >> #testDecompiledDoitMethodTempNames which <br>will fail: the primitive will return a non-zero value even though the two <br>compared strings are equal.<br>4. Don't save your image, it might have been corrupted.<br><br>I couldn't write a script to reproduce the bug, hence the testcase.<br>The bug is so hard to trigger, you won't notice string comparison being <br>broken: your image will keep running.<br>When the testcase fails, the primitive's return value suggests that the <br>jitted code probably sees one of the strings shorter than it actually is.<br>The non-jitted version of the primitive works fine.<br><br><br>Levente<br><br>><br>> =============== Diff against Collections-mt.896 ===============<br>><br>> Item was removed:<br>> - ----- Method: ByteArray>>atAllPut: (in category 'accessing') -----<br>> - atAllPut: value<br>> -    "Fill the receiver with the given value"<br>> - <br>> -     <primitive: 145=""><br>> -     super atAllPut: value!<br>><br>> Item was changed:<br>>  ----- Method: String>>< (in="" category="" 'comparing')=""><br>>  <><br>>         "Answer whether the receiver sorts before aString.<br>>   The collation order is simple ascii (with case differences)."<br>> <br>> +       ^(self compareWith: aString) <><br>> -   ^ (self compare: self with: aString collated: AsciiOrder) = 1!<br>><br>> Item was changed:<br>>  ----- Method: String>><= (in="" category="" 'comparing')=""></=><br>>  <=></=><br>>   "Answer whether the receiver sorts before or equal to aString.<br>>       The collation order is simple ascii (with case differences)."<br>> <br>> +       ^(self compareWith: aString) <=></=><br>> -        ^ (self compare: self with: aString collated: AsciiOrder) <=></=><br>><br>> Item was changed:<br>>  ----- Method: String>>= (in category 'comparing') -----<br>>  = aString<br>>         "Answer whether the receiver sorts equally as aString.<br>>       The collation order is simple ascii (with case differences)."<br>><br>>          self == aString ifTrue: [ ^true ].<br>>        aString isString ifFalse: [ ^false ].<br>>     self size = aString size ifFalse: [ ^false ].<br>> +   ^ (self compareWith: aString) = 0!<br>> -      ^ (self compare: self with: aString collated: AsciiOrder) = 2!<br>><br>> Item was changed:<br>>  ----- Method: String>>> (in category 'comparing') -----<br>>  > aString<br>>          "Answer whether the receiver sorts after aString.<br>>    The collation order is simple ascii (with case differences)."<br>> <br>> +       ^(self compareWith: aString) > 0!<br>> -    ^ (self compare: self with: aString collated: AsciiOrder) = 3!<br>><br>> Item was changed:<br>>  ----- Method: String>>>= (in category 'comparing') -----<br>>  >= aString<br>>        "Answer whether the receiver sorts after or equal to aString.<br>>        The collation order is simple ascii (with case differences)."<br>> <br>> +       ^(self compareWith: aString) >= 0!<br>> -   ^ (self compare: self with: aString collated: AsciiOrder) >= 2!<br>><br>> Item was changed:<br>>  ----- Method: String>>compare:caseSensitive: (in category 'comparing') -----<br>>  compare: aString caseSensitive: aBool<br>>   "Answer a comparison code telling how the receiver sorts relative to aString:<br>>                1 - before<br>>                2 - equal<br>>                 3 - after.<br>>        "<br>>    | map |<br>>   map := aBool ifTrue:[CaseSensitiveOrder] ifFalse:[CaseInsensitiveOrder].<br>> +        ^(self compareWith: aString collated: map) + 2!<br>> -         ^self compare: self with: aString collated: map!<br>><br>> Item was added:<br>> + ----- Method: String>>compareWith: (in category 'comparing') -----<br>> + compareWith: aString<br>> + <br>> +     "<primitive: 158="">"<br>> +         ^(self compare: self with: aString collated: AsciiOrder) - 2!<br>><br>> Item was added:<br>> + ----- Method: String>>compareWith:collated: (in category 'comparing') -----<br>> + compareWith: aString collated: collation<br>> + <br>> +   "<primitive: 158="">"<br>> +         ^(self compare: self with: aString collated: collation) - 2!<br>><br>> Item was removed:<br>> - ----- Method: WeakIdentityDictionary>>cleanupIndex: (in category 'private') -----<br>> - cleanupIndex: anInteger<br>> -      array at: anInteger put: vacuum.<br>> -        tally := tally - 1.<br>> -     self fixCollisionsFrom: anInteger.!<br>><br>> Item was changed:<br>>  ----- Method: WeakIdentityDictionary>>fixCollisionsFrom: (in category 'private') -----<br>>  fixCollisionsFrom: start<br>>     "The element at start has been removed and replaced by vacuum.<br>>       This method moves forward from there, relocating any entries<br>>      that had been placed below due to collisions with this one."<br>><br>>   | element index |<br>>         index := start.<br>>   [ (element := array at: (index := index \\ array size + 1)) == vacuum ] whileFalse: [<br>>             element<br>>                   ifNil:<br>>                            [ "The binding at this slot was reclaimed - finish the cleanup"<br>>                                 array at: index put: vacuum.<br>>                              tally := tally - 1 ]<br>>                      ifNotNil:<br>>                                 [| newIndex |<br>> +                           (newIndex := self scanFor: element key) = index ifFalse: [<br>> -                              (newIndex := self scanWithoutGarbagingFor: element key) = index ifFalse: [<br>>                                        array<br>>                                             at: newIndex put: element;<br>>                                                at: index put: vacuum ] ] ]!<br>><br>> Item was changed:<br>>  ----- Method: WeakIdentityDictionary>>removeKey:ifAbsent: (in category 'removing') -----<br>>  removeKey: key ifAbsent: aBlock<br>>   "Remove key (and its associated value) from the receiver. If key is not in<br>>   the receiver, answer the result of evaluating aBlock. Otherwise, answer<br>>   the value externally named by key."<br>><br>>    | index association |<br>>     index := self scanFor: key.<br>>       (association := (array at: index)) == vacuum ifTrue: [ ^aBlock value ].<br>> +         array at: index put: vacuum.<br>> +    tally := tally - 1.<br>> +     self fixCollisionsFrom: index.<br>> -  self cleanupIndex: index.<br>>         ^association value!<br>><br>> Item was changed:<br>>  ----- Method: WeakIdentityDictionary>>scanFor: (in category 'private') -----<br>>  scanFor: anObject<br>>      "Scan the array for the first slot containing either<br>>         - a vacuum object indicating an empty slot<br>>        - or a binding whose key matches anObject.<br>> +      Answer the index of that slot or raise an error if no slot is found which should never happen."<br>> -    Answer the index of that slot or raise an error if no slot is found.<br>> -    When garbage collected slots are encountered, perform a clean-up."<br>> <br>> +  | index start size |<br>> +    index := start := anObject scaledIdentityHash \\ (size := array size) + 1.<br>> +      [ <br>> +              (array at: index) ifNotNil: [ :element |<br>> +                        (element == vacuum or: [ element key == anObject ])<br>> +                             ifTrue: [ ^index ] ].<br>> +           (index := index \\ size + 1) = start ] whileFalse.<br>> -      | index start rescan | <br>> -         [<br>> -               rescan := false.<br>> -                index := start := anObject scaledIdentityHash \\ array size + 1.<br>> -                [ <br>> -                      (array at: index) <br>> -                              ifNil:<br>> -                                  ["Object at this slot has been garbage collected.<br>> -                                  A rescan is necessary because fixing collisions<br>> -                                         might have moved the target before current index."<br>> -                                         self cleanupIndex: index.<br>> -                                       rescan := true]<br>> -                                 ifNotNil:<br>> -                                       [:element | (element == vacuum or: [ element key == anObject ])<br>> -                                                 ifTrue: [ ^index ].<br>> -                                     (index := index \\ array size + 1) = start ] ] whileFalse.<br>> -              rescan ] whileTrue.<br>>       self errorNoFreeSpace!<br>><br>> Item was changed:<br>>  ----- Method: WeakIdentityDictionary>>scanForEmptySlotFor: (in category 'private') -----<br>>  scanForEmptySlotFor: anObject<br>> +         "Scan the array for the first empty slot marked by vacuum object or nil.<br>> +   Answer the index of that slot or raise an error if no slot is found, which should never happen."<br>> -   "Scan the array for the first empty slot marked by vacuum object.<br>> -  Answer the index of that slot or raise an error if no slot is found.<br>> -    Ignore the slots that have been garbage collected (those containing nil)."<br>><br>>     | index start |<br>>   index := start := anObject scaledIdentityHash \\ array size + 1.<br>>          [ <br>> +              | element |<br>> +             ((element := array at: index) == vacuum or: [ element == nil ]) ifTrue: [ ^index ].<br>> -             (array at: index) <br>> -                      ifNotNil:<br>> -                               [:element | element == vacuum ifTrue: [ ^index ] ].<br>>               (index := index \\ array size + 1) = start ] whileFalse.<br>>          self errorNoFreeSpace!<br>><br>> Item was removed:<br>> - ----- Method: WeakIdentityDictionary>>scanWithoutGarbagingFor: (in category 'private') -----<br>> - scanWithoutGarbagingFor: anObject<br>> -       "Scan the array for the first slot containing either<br>> -       - a vacuum object indicating an empty slot<br>> -      - or a binding whose key matches anObject.<br>> -      Answer the index of that slot or raise an error if no slot is found.<br>> -    Ignore the slots that have been garbage collected (those containing nil)"<br>> - <br>> -         | index start | <br>> -        index := start := anObject scaledIdentityHash \\ array size + 1.<br>> -        [ <br>> -              (array at: index) <br>> -                      ifNotNil:<br>> -                               [:element | (element == vacuum or: [ element key == anObject ])<br>> -                                         ifTrue: [ ^index ] ].<br>> -           (index := index \\ array size + 1) = start ] whileFalse.<br>> -        self errorNoFreeSpace!<br><br></primitive:></primitive:></primitive:></div></blockquote>
                                        </div></body>