This fixes invalid and inconsistent results for the Fixnum*Fixnum case
where the result of the multiplication does not fit in 64-bit
on OpenBSD/mips64. For example:
$ for x in 1 23; do ruby31 -e 'p(54306000000000*86400)'; done
14409380628474329524
11410664325873689790
Cases where an argument was Bignum, as well as cases where the result
of the multiplication fits in 64-bit are fine:
$ for x in 1 23; do ruby31 -e 'p(54306000*86400)'; done
4692038400000
4692038400000
$ for x in 1 23; do ruby31 -e 'p(5430600000000000000000*86400)'; done
469203840000000000000000000
469203840000000000000000000
This was originally discovered by running the tests for the openssl gem
on OpenBSD/mips64 and having one test fail for a date far in the future.
I eventually traced this to the generic multiplication issue.
The underlying cause is using the int128_t type. This avoids use of the
int128_t type in this case, falling back to the slower conversion code,
which in the overflow case, turns the Fixnums into Bignums, then
performs the multiplication.
According to MSVC manual (*1), cl.exe can skip including a header file
when that:
- contains #pragma once, or
- starts with #ifndef, or
- starts with #if ! defined.
GCC has a similar trick (*2), but it acts more stricter (e. g. there
must be _no tokens_ outside of #ifndef...#endif).
Sun C lacked #pragma once for a looong time. Oracle Developer Studio
12.5 finally implemented it, but we cannot assume such recent version.
This changeset modifies header files so that each of them include
strictly one #ifndef...#endif. I believe this is the most portable way
to trigger compiler optimizations. [Bug #16770]
*1: https://docs.microsoft.com/en-us/cpp/preprocessor/once
*2: https://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html
One day, I could not resist the way it was written. I finally started
to make the code clean. This changeset is the beginning of a series of
housekeeping commits. It is a simple refactoring; split internal.h into
files, so that we can divide and concur in the upcoming commits. No
lines of codes are either added or removed, except the obvious file
headers/footers. The generated binary is identical to the one before.