<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">2016-03-30 13:46 GMT+02:00 Ben Coman <span dir="ltr">&lt;<a href="mailto:btc@openinworld.com" target="_blank">btc@openinworld.com</a>&gt;</span>:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><br>
On Wed, Mar 30, 2016 at 2:09 PM, Eliot Miranda &lt;<a href="mailto:eliot.miranda@gmail.com">eliot.miranda@gmail.com</a>&gt; wrote:<br>
&gt;<br>
&gt; Hi Nicolas,<br>
<div><div class="h5">&gt;<br>
&gt; On Tue, Mar 29, 2016 at 2:36 PM, Nicolas Cellier &lt;<a href="mailto:nicolas.cellier.aka.nice@gmail.com">nicolas.cellier.aka.nice@gmail.com</a>&gt; wrote:<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; 2016-03-27 15:39 GMT+02:00 Nicolas Cellier &lt;<a href="mailto:nicolas.cellier.aka.nice@gmail.com">nicolas.cellier.aka.nice@gmail.com</a>&gt;:<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; To be more specific,<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; The first thing to do would be to confirm that the KernelNumber tests fail with a squeak.stack.v3 VM compiled with head revision of COG VM branch, whatever OS.<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Then knowing from which SVN version of COG VM branch the KernelNumber the tests start failing would be nice.<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; The bisect job is to:<br>
&gt;&gt;&gt; - iterate on version number (whatever strategy, bsearch or something)<br>
&gt;&gt;&gt; - checkout VM sources<br>
&gt;&gt;&gt; - compile the build.favouriteOS/squeak.stack.v3<br>
&gt;&gt;&gt; - run a v3 image with the generated VM and launch KernelNumber tests<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Really a job for a jenkins bot, travis bot or whatever...<br>
&gt;&gt;&gt; The next good thing would be to give a little love to <a href="http://build.squeak.org" rel="noreferrer" target="_blank">build.squeak.org</a> or anyother similar solution.<br>
&gt;&gt;&gt; I only see red disks on this site...<br>
&gt;&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; Follow up: I did bissect manually:<br>
&gt;&gt; 3648 (VMMaker.oscog-eem.nice.1729) OK<br>
&gt;&gt; 3649 (VMMaker.oscog-eem.1740) Not OK<br>
&gt;&gt;<br>
&gt;&gt; So something went wrong for V3 between these two versions.<br>
&gt;&gt; At the same time, it works for spur.<br>
&gt;&gt;<br>
&gt;&gt; Spur objects are 8 bytes aligned, v3 objects are 4 bytes aligned...<br>
&gt;&gt; So fetching 64 bits from V3 MUST be decomposed into 2 32 bits fetch to avoid a segfault related to misalign fetch.<br>
&gt;&gt;<br>
&gt;&gt; OK, let&#39;s look how it is performed:<br>
&gt;&gt;<br>
&gt;&gt; fetchLong64: longIndex ofObject: oop<br>
&gt;&gt;     &lt;returnTypeC: #sqLong&gt;<br>
&gt;&gt;     ^self cppIf: BytesPerWord = 8<br>
&gt;&gt;         ifTrue: [self long64At: oop + self baseHeaderSize + (longIndex &lt;&lt; 3)]<br>
&gt;&gt;         ifFalse:<br>
&gt;&gt;             [self cppIf: VMBIGENDIAN<br>
&gt;&gt;                 ifTrue: [((self long32At: oop + self baseHeaderSize + (longIndex &lt;&lt; 3)) asUnsignedLongLong &lt;&lt; 32)<br>
&gt;&gt;                     + (self long32At: oop + self baseHeaderSize + (longIndex &lt;&lt; 3 + 4))]<br>
&gt;&gt;                 ifFalse: [(self long32At: oop + self baseHeaderSize + (longIndex &lt;&lt; 3))<br>
&gt;&gt;                     + ((self long32At: oop + self baseHeaderSize + (longIndex &lt;&lt; 3 + 4)) asUnsignedLongLong &lt;&lt; 32)]]<br>
&gt;&gt;<br>
&gt;&gt; AH AH! Operation is:<br>
&gt;&gt;     low + (((unsigned) high) &lt;&lt; 32)<br>
&gt;&gt;<br>
&gt;&gt; With low declared as SIGNED (long32At is signed GRRR).<br>
&gt;&gt; What if bit 32 of low is 1? then the compiler will perform:<br>
&gt;&gt;<br>
&gt;&gt; (unsigned long) low + ...<br>
&gt;&gt;<br>
&gt;&gt; AND THIS WILL DO A SIGN EXTENSION...<br>
&gt;&gt;<br>
&gt;&gt; It&#39;s not that my code was false...<br>
&gt;&gt; It&#39;s just that it uncovered a bug in fetchLong64:ofObject:<br>
&gt;&gt;<br>
&gt;&gt; That cost me many hours, but that enforce my conviction about signedness...<br>
&gt;&gt; I would much much much prefer to call unsignedLong32At because it&#39;s what I mean 9 times out of 10: get the magnitude...<br>
&gt;<br>
&gt;<br>
</div></div>&gt; Let&#39;s add them.  It would be great to have them all consistent too.  But at least let&#39;s add unsignedLong32At:[put:].  Wait.  In the simulator longAt:[put:] et al are unsigned.  So we have three choices:<br>
&gt;<br>
&gt; a) live with it<br>
&gt; b) make longAt:[put:] long32At:put: et al unsigned in C, and add signedLongAt:[put:] et al.<br>
&gt; c) make the simulator&#39;s longAt:[put:] long32At:put: signed and then add unsignedLongAt:[put:] et al<br>
&gt;<br>
&gt; Any others?<br>
&gt;<br>
&gt; I think a) is unwise.  The simulator and C should agree.  Nicolas, I can join your experience in finding that debugging these issues is extremely time consuming.<br>
&gt;<br>
&gt; My preference is for b); some uses where the type should be signed will by located by C compiler warnings; we hope that VM tests will catch the others)<br>
<br>
Wouldn&#39;t (b) risk occasional cognitive dysfunction switching between<br>
the semantic of aa C long being signed and a Slang long being<br>
unsigned?  (c) seems better long term, but switching the signedness of<br>
the an existing simulation method might cause short term instability<br>
and need to be tackled in one sitting?   So a naive question... Why<br>
leave one implicit?  Consider d) introducing both signedLongAt:[put:]<br>
and unsignedLongAt:[put:] and gradual migration.<br>
<br>
cheers -ben<br>
<div class=""><div class="h5"><br></div></div></blockquote><div><br><div>My first thought was as Eliot, use b) because<br>- the simulator is already b)<br></div><div>- wild guess is that there are more unsigned than signed usage<br><br>But I like Ben arguments better.<br>Non uniform naming has great costs<br>- slow learning ramp for noobs<br>- seed for future bug due to misunderstanding.<br><br>For example we already have<br>* long  implicitely meaning 32 bits like in signedIntToLong signedIntFromLong,<br>* long unconditionnally meaning 64 bits like sqLong<br>* long meaning either 32 or 64 bits depending on architecture in generated C (like in StackInterperter&gt;&gt;putLong:toFile:)<br></div><div>* long meaning either 32 or 64 depending on the context<br>  (#longAt: is allways 32 bits when sent to ByteArray Bitmap or CAccessor, but might be 64 bits when sent to simulator argh...)<br></div><div><br>I remember I had similar problems with word the first time I looked at VMMaker.<br>WordArray being allways 32 bits word, but wordSize being 4 or 8 depending on target architecture.<br>Even now, I&#39;m not sure of which word we are talking of...<br><br></div><div>Also b) goes with a blitz strategy:<br></div><div>- do a massive semantic change long32 -&gt; unsigned<br></div><div>- review the send sites and change a few variant to signed<br></div><div>- repair broken C code once image start crashing and tests start failing<br></div><div>- repair the simulator which might show different symptoms (see implementors of #asUnsignedLong)<br></div><div>either it works soon, or never...<br><br>I&#39;ve noted only 47 senders of long32At: . <br><div>Plus the 33 senders of fetchLong32:ofObject:<br>And cannot analyze easily the possible side effects thru Slang type inference...<br><br></div><div>As my recent bug of LargeInteger division showed: abuse of unsigned lead to expensive bug tracking too.<br></div>That does a bit restrain my enthusiasm for solution b) - chat échaudé craint l&#39;eau froide ;)<br><br></div><div>Last, I did not apply b) policy in my VM branch for 32 bits large int.<br></div><div>Instead I introduced the unsigned variant gradually...  (coward !)</div><div><br><div>Before we attempt anything, I&#39;d like to remind the short term goals:<br></div>- avoid uncontrolled sign extension when promoting to larger int in C<br><div>- avoid undefined behavior, most of which being related to signed arithmetic<br></div>- make the simulator better match C (or vice versa in the case)<br><br></div></div><div><div>The last goal is far away, there are subtle &quot;differences&quot;...<br></div><div>Like in the simulator, the difference of two unsigned might be &lt; 0.<br></div><div>In C not, unless we force it (cast, type punning, whatever...).<br></div><br><div>Last point, gradual introduction and non-regression testing pre-suppose a stable VM.<br>I still experiment random crashes I&#39;d like to 
track first.<br> <br></div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div class=""><div class="h5">
&gt;<br>
&gt;&gt;<br>
&gt;&gt;&gt; 2016-03-27 0:40 GMT+01:00 Nicolas Cellier &lt;<a href="mailto:nicolas.cellier.aka.nice@gmail.com">nicolas.cellier.aka.nice@gmail.com</a>&gt;:<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; Hi,<br>
&gt;&gt;&gt;&gt; before I continue, i&#39;ve noticed that the large integer multiply seems broken on v3 object memory (cog &amp; stack)<br>
&gt;&gt;&gt;&gt; Note that this does not happen on Spur.<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; This is independent of my recent changes of LargeIntegers plugin as it happens BEFORE these changes and is related to primitive 29 rather than to the plugin...<br>
&gt;&gt;&gt;&gt; Here are the symptoms:<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; halfPower := 10000.<br>
&gt;&gt;&gt;&gt; s := 111111111111111.<br>
&gt;&gt;&gt;&gt; head := s quo: halfPower.<br>
&gt;&gt;&gt;&gt; tail := s - (head * halfPower).<br>
&gt;&gt;&gt;&gt; {<br>
&gt;&gt;&gt;&gt;    head as: ByteArray.<br>
&gt;&gt;&gt;&gt;    (1 to: halfPower digitLength) collect: [:i | halfPower digitAt: i] as: ByteArray.<br>
&gt;&gt;&gt;&gt;    (head*halfPower) as: ByteArray.<br>
&gt;&gt;&gt;&gt; }.<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; the correct result is:<br>
&gt;&gt;&gt;&gt;  #(#[199 25 70 150 2] #[16 39] #[112 237 78 18 14 101])<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; the wrong result I obtained with SVN revision 3651 compiled by myself is:<br>
&gt;&gt;&gt;&gt;  #(#[199 25 70 150 2] #[16 39] #[112 237 78 18 254 61])<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; The most significant bits (above 32) are wrong...<br>
&gt;&gt;&gt;&gt; The pattern I obtain is (with most significant bit put back left)<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; 2r00111101 &lt;&lt; 8 +  2r11111110   &quot;wrong result&quot;<br>
&gt;&gt;&gt;&gt; 2r01100101 &lt;&lt; 8 + 2r00001110  &quot;Correct result&quot;<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; I completely fail to infer what&#39;s going on from this pattern...<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; This is on MacOSX clang --version<br>
&gt;&gt;&gt;&gt; Apple LLVM version 7.3.0 (clang-703.0.29)<br>
&gt;&gt;&gt;&gt; Target: x86_64-apple-darwin15.4.0<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; This goes thru primitiveMultiplyLargeIntegers (29)<br>
&gt;&gt;&gt;&gt; oopResult := self magnitude64BitIntegerFor: result neg: aIsNegative ~= bIsNegative.<br>
&gt;&gt;&gt;&gt; -&gt; sz &gt; 4<br>
&gt;&gt;&gt;&gt;                 ifTrue: [objectMemory storeLong64: 0 ofObject: newLargeInteger withValue: magnitude]<br>
&gt;&gt;&gt;&gt; (which I changed recently)<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; then:<br>
&gt;&gt;&gt;&gt; storeLong64: longIndex ofObject: oop withValue: value<br>
&gt;&gt;&gt;&gt;     &lt;var: #value type: #sqLong&gt;<br>
&gt;&gt;&gt;&gt;     self flag: #endianness.<br>
&gt;&gt;&gt;&gt;     self long32At: oop + self baseHeaderSize + (longIndex &lt;&lt; 3) put: (self cCode: [value] inSmalltalk: [value bitAnd: 16rFFFFFFFF]);<br>
&gt;&gt;&gt;&gt;         long32At: oop + self baseHeaderSize + (longIndex &lt;&lt; 3) + 4 put: (value &gt;&gt; 32).<br>
&gt;&gt;&gt;&gt;     ^value<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; I don&#39;t see anything wrong with this code...<br>
&gt;&gt;&gt;&gt; Well, using a shift on signed value is not that good, but it works for at least 3 reasons:<br>
&gt;&gt;&gt;&gt; - we throw the signBit extension away<br>
&gt;&gt;&gt;&gt; - slang inlining misses the signedness difference, and the generated C code is correct.<br>
&gt;&gt;&gt;&gt; - Anyway, in our case, the sign bit was 0...<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; Previous implementation in magnitude64BitIntegerFor:neg: was:<br>
&gt;&gt;&gt;&gt; sz &gt; 4 ifTrue:<br>
&gt;&gt;&gt;&gt;                 [objectMemory storeLong32: 1 ofObject: newLargeInteger withValue: magnitude &gt;&gt; 32].<br>
&gt;&gt;&gt;&gt;             objectMemory<br>
&gt;&gt;&gt;&gt;                 storeLong32: 0<br>
&gt;&gt;&gt;&gt;                 ofObject: newLargeInteger<br>
&gt;&gt;&gt;&gt;                 withValue: (self cCode: [magnitude] inSmalltalk: [magnitude bitAnd: 16rFFFFFFFF])<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; Not much different, except that the high 32 bits and low 32 bits are written in a different order...<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; If I had a server I&#39;d like to bisect<br>
&gt;&gt;&gt;&gt; - from which version does this happens<br>
&gt;&gt;&gt;&gt; - for which OS<br>
&gt;&gt;&gt;&gt; - for which compiler<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; Without such information, I think I&#39;ll have to debug it either thru simulator or directly in gdb, but I feel like I&#39;m really losing my time :(<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt; And I&#39;ve got a 2nd problem like this one...<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;<br>
&gt;<br>
&gt;<br>
</div></div><span class=""><font color="#888888">&gt; --<br>
&gt; _,,,^..^,,,_<br>
&gt; best, Eliot<br>
&gt;<br>
</font></span></blockquote></div><br></div></div>