[squeak-dev] [BUG] signedLongAt: 1 put:−2,147,483,648

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

[squeak-dev] [BUG] signedLongAt: 1 put:−2,147,483,648

johnmci
I noted the the current VMs don't handle the case of storing  
−2,147,483,648 (primitive failure) via  signed32BitValueOf:  usually  
called via FFI  signedLongAt:put:

For plugin writers who used signed64BitValueOf: (primitive failure)  
and   signed64BitIntegerFor:  returned  zero if passed  
−9,223,372,036,854,775,808.
signed64BitIntegerFor: is the one that is nasty since your value of  
0x8000000000000000  silently turns in 0.

I reopened problem http://bugs.squeak.org/view.php?id=6987 and wrote  
some SUnits.

I also provided a suggested fix, which allows me to run the SUnits.

Lastly for Alien I added long long (signed/unsigned) support which is  
still missing in the FFI plugin so I could do some testing.


--
=
=
=
========================================================================
John M. McIntosh <[hidden email]>
Corporate Smalltalk Consulting Ltd.  http://www.smalltalkconsulting.com
=
=
=
========================================================================




Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] [BUG] signedLongAt: 1 put:−2,147,483,648

Eliot Miranda-2
Hi John,

    here's the fix for signed32BitValueOf:


On Tue, Nov 25, 2008 at 11:15 PM, John M McIntosh <[hidden email]> wrote:
I noted the the current VMs don't handle the case of storing −2,147,483,648 (primitive failure) via  signed32BitValueOf:  usually called via FFI  signedLongAt:put:

For plugin writers who used signed64BitValueOf: (primitive failure) and   signed64BitIntegerFor:  returned  zero if passed −9,223,372,036,854,775,808.
signed64BitIntegerFor: is the one that is nasty since your value of 0x8000000000000000  silently turns in 0.

I reopened problem http://bugs.squeak.org/view.php?id=6987 and wrote some SUnits.

I also provided a suggested fix, which allows me to run the SUnits.

Lastly for Alien I added long long (signed/unsigned) support which is still missing in the FFI plugin so I could do some testing.


--
===========================================================================
John M. McIntosh <[hidden email]>
Corporate Smalltalk Consulting Ltd.  http://www.smalltalkconsulting.com
===========================================================================








Interpreter-signed32BitValueOf.st (2K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] [BUG] signedLongAt: 1 put:−2,147,483,648

johnmci
Eliot thanks for this. I went with

        (negative and: [value = (1<<31)])
                ifTrue: [^value].

versus

(negative and: [value - 1 > 0])
                ifTrue: [^value].

       

I had hardcoded -2147483648 but got some ansi 99 compiler warning so I  
did the shift, I'd *think* the compiler will do the 1<<31 constant  
resolving
and use the final value so we only have the compare, versus a  
subtraction and compare. Not that you could measure any performance  
differences


In the Alien Sunits I cover the cases of 0 4294967295 -2147483648  
2147483647  (for signed/unsigned)

then do random sampling (10,000) elements of

        unsignedIntegerIntervalue := (0 to: 4294967295).
        signedIntegerIntervalue := (-2147483648 to: 2147483647).
        signedIntegerIntervalue := (-4294967295 to: -2147483649).  should  
prim value
        signedIntegerIntervalue := (2147483648 to: 4294967295).  should prim  
fail
       

If someone wants to try they could run *all* the values from  
-0xFFFFFFFF 0xFFFFFFFF   just to confirm *every* value works as  
expected since that would
only take a few hours or less on the fast machines today.

I note I do the 0xFFFFFFFF * (-1)  because it's possible someone might  
pass that in and ask for a signed integer, in that case we of course  
fail until we
reach the lowest 32bit signed integer value of -2147483648   (I so I  
assume) since I've not run the entire range, which is feasible.

Obviously running the 64bit range could take a while. Anyone want to  
estimate?

On 2-Dec-08, at 11:32 AM, Eliot Miranda wrote:

> Hi John,
>
>     here's the fix for signed32BitValueOf:
>
>
> On Tue, Nov 25, 2008 at 11:15 PM, John M McIntosh <[hidden email]
> > wrote:

--
=
=
=
========================================================================
John M. McIntosh <[hidden email]>
Corporate Smalltalk Consulting Ltd.  http://www.smalltalkconsulting.com
=
=
=
========================================================================




Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] [BUG] signedLongAt: 1 put:−2,147,483,648

Eliot Miranda-2


2008/12/2 John M McIntosh <[hidden email]>
Eliot thanks for this. I went with

       (negative and: [value = (1<<31)])
               ifTrue: [^value].

But value doesn't equal 1 << 31.  It equals -(1 << 31).  It only appears to equal 1 << 31 because 1 << 31 overflows.  I think therefore mine is clearer.

Think about it, all less negative values must still be negative when one subtracts one.  Only the most negative value will no longer be negative if one subtracts one.  So I think mine also clearly selects the most negative value and only the most negative value.

I've attached the analogous fix for signed64BitValueOf:



versus

(negative and: [value - 1 > 0])
               ifTrue: [^value].

       

I had hardcoded -2147483648 but got some ansi 99 compiler warning so I did the shift, I'd *think* the compiler will do the 1<<31 constant resolving
and use the final value so we only have the compare, versus a subtraction and compare. Not that you could measure any performance differences

The problem is that 1<<31 is a large constant whereas -1 is small.  So the cost is not really in the arithmetic but in the memory fetch :)  I bet there will be more bytes in the instructions for 1 << 31 than for the - 1 on most architectures.  On the ARM 1<<31 is cheap, but TTBOMK only on ARM :)

 



In the Alien Sunits I cover the cases of 0 4294967295 -2147483648 2147483647  (for signed/unsigned)

then do random sampling (10,000) elements of

       unsignedIntegerIntervalue := (0 to: 4294967295).
       signedIntegerIntervalue := (-2147483648 to: 2147483647).
       signedIntegerIntervalue := (-4294967295 to: -2147483649).  should prim value
       signedIntegerIntervalue := (2147483648 to: 4294967295).  should prim fail
       

If someone wants to try they could run *all* the values from -0xFFFFFFFF 0xFFFFFFFF   just to confirm *every* value works as expected since that would
only take a few hours or less on the fast machines today.

I note I do the 0xFFFFFFFF * (-1)  because it's possible someone might pass that in and ask for a signed integer, in that case we of course fail until we
reach the lowest 32bit signed integer value of -2147483648   (I so I assume) since I've not run the entire range, which is feasible.

Obviously running the 64bit range could take a while. Anyone want to estimate?


On 2-Dec-08, at 11:32 AM, Eliot Miranda wrote:

Hi John,

   here's the fix for signed32BitValueOf:


On Tue, Nov 25, 2008 at 11:15 PM, John M McIntosh <[hidden email]> wrote:

--
===========================================================================
John M. McIntosh <[hidden email]>
Corporate Smalltalk Consulting Ltd.  http://www.smalltalkconsulting.com
===========================================================================







Interpreter-signed64BitValueOf.st (2K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] [BUG] signedLongAt: 1 put:−2,147,483,648

Eliot Miranda-2
Also needed to be fixed are Interpreter>>signed64BitIntegerFor: and Interpreter>>primitiveSubtractLargeIntegers:.  Find attached.

Once one fixes signed64BitValueFor: you'll find that (2 raisedToInteger: 63) negated - ((2 raisedToInteger: 63)-1) is zero :)  i.e. subtract the most +ve integer from the most -ve and you get zero, because primitiveSubtractLargeIntegers: falls into exactly the same trap of assuming

    0 - aValue

is +ve for all -ve values, which isn't the case for the most -ve value.


2008/12/2 Eliot Miranda <[hidden email]>


2008/12/2 John M McIntosh <[hidden email]>

Eliot thanks for this. I went with

       (negative and: [value = (1<<31)])
               ifTrue: [^value].

But value doesn't equal 1 << 31.  It equals -(1 << 31).  It only appears to equal 1 << 31 because 1 << 31 overflows.  I think therefore mine is clearer.

Think about it, all less negative values must still be negative when one subtracts one.  Only the most negative value will no longer be negative if one subtracts one.  So I think mine also clearly selects the most negative value and only the most negative value.

I've attached the analogous fix for signed64BitValueOf:



versus

(negative and: [value - 1 > 0])
               ifTrue: [^value].

       

I had hardcoded -2147483648 but got some ansi 99 compiler warning so I did the shift, I'd *think* the compiler will do the 1<<31 constant resolving
and use the final value so we only have the compare, versus a subtraction and compare. Not that you could measure any performance differences

The problem is that 1<<31 is a large constant whereas -1 is small.  So the cost is not really in the arithmetic but in the memory fetch :)  I bet there will be more bytes in the instructions for 1 << 31 than for the - 1 on most architectures.  On the ARM 1<<31 is cheap, but TTBOMK only on ARM :)

 



In the Alien Sunits I cover the cases of 0 4294967295 -2147483648 2147483647  (for signed/unsigned)

then do random sampling (10,000) elements of

       unsignedIntegerIntervalue := (0 to: 4294967295).
       signedIntegerIntervalue := (-2147483648 to: 2147483647).
       signedIntegerIntervalue := (-4294967295 to: -2147483649).  should prim value
       signedIntegerIntervalue := (2147483648 to: 4294967295).  should prim fail
       

If someone wants to try they could run *all* the values from -0xFFFFFFFF 0xFFFFFFFF   just to confirm *every* value works as expected since that would
only take a few hours or less on the fast machines today.

I note I do the 0xFFFFFFFF * (-1)  because it's possible someone might pass that in and ask for a signed integer, in that case we of course fail until we
reach the lowest 32bit signed integer value of -2147483648   (I so I assume) since I've not run the entire range, which is feasible.

Obviously running the 64bit range could take a while. Anyone want to estimate?


On 2-Dec-08, at 11:32 AM, Eliot Miranda wrote:

Hi John,

   here's the fix for signed32BitValueOf:


On Tue, Nov 25, 2008 at 11:15 PM, John M McIntosh <[hidden email]> wrote:

--
===========================================================================
John M. McIntosh <[hidden email]>
Corporate Smalltalk Consulting Ltd.  http://www.smalltalkconsulting.com
===========================================================================








Interpreter-signed64BitIntegerFor.st (1K) Download Attachment
Interpreter-primitiveSubtractLargeIntegers.st (2K) Download Attachment
MostNegativeVMFixes.cs (8K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] [BUG] signedLongAt: 1 put:−2,147,483,648

johnmci

I'm not sure I've seen a problem logged about that.

On 2-Dec-08, at 1:57 PM, Eliot Miranda wrote:

> Also needed to be fixed are Interpreter>>signed64BitIntegerFor: and  
> Interpreter>>primitiveSubtractLargeIntegers:.  Find attached.
>
> Once one fixes signed64BitValueFor: you'll find that (2  
> raisedToInteger: 63) negated - ((2 raisedToInteger: 63)-1) is  
> zero :)  i.e. subtract the most +ve integer from the most -ve and  
> you get zero, because primitiveSubtractLargeIntegers: falls into  
> exactly the same trap of assuming
>
>     0 - aValue
>
> is +ve for all -ve values, which isn't the case for the most -ve  
> value.
>

--
=
=
=
========================================================================
John M. McIntosh <[hidden email]>
Corporate Smalltalk Consulting Ltd.  http://www.smalltalkconsulting.com
=
=
=
========================================================================