Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ruby/spec changes to future proof for 64-bit fixnums on 64-bit Windows #11130

Merged
merged 4 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add "c_long_size" guard, supplanting "wordsize" and stop using Intege…
…r#size

What a "word" is when talking about sizes is confusing because it's a
highly overloaded term. Intel, Microsoft, and GDB are just a few vendors
that have their own definition of what a "word" is. Specs that used the
"wordsize" guard actually were mostly testing for the size of the C
`long` fundamental type, so rename the guard for clarity.

Also, get the size of `long` directly from RbConfig instead of guessing
using Integer#size. Integer#size is not guaranteed to have anything to
do with the `long` type.
  • Loading branch information
XrXr committed Jul 24, 2024
commit 34f6246d69e5cf6f0dad63e60036e60fb3b9e751
18 changes: 11 additions & 7 deletions spec/mspec/lib/mspec/guards/platform.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,23 53,27 @@ def self.wsl?
end
end

WORD_SIZE = 1.size * 8

POINTER_SIZE = begin
require 'rbconfig/sizeof'
RbConfig::SIZEOF["void*"] * 8
rescue LoadError
WORD_SIZE
[0].pack('j').size
end

def self.wordsize?(size)
size == WORD_SIZE
C_LONG_SIZE = if defined?(RbConfig::SIZEOF[])
Copy link
Member

@eregon eregon Jul 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder what WORD_SIZE actually means given there is already POINTER_SIZE.
Maybe WORD_SIZE is meant to be sizeof(long) already but with a bad name?
Do you think it would make sense to basically rename :wordsize to :c_long_size (or make it an alias of it and still update all usages)?

Copy link
Member Author

@XrXr XrXr Jul 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch! In fact, it looks like the only usage of wordsize? left is platform_spec. I've pushed code to rename it.

RbConfig::SIZEOF["long"] * 8
else
[0].pack('l!').size
end

def self.pointer_size?(size)
size == POINTER_SIZE
end

def self.c_long_size?(size)
size == C_LONG_SIZE
end

def initialize(*args)
if args.last.is_a?(Hash)
@options, @platforms = args.last, args[0..-2]
Expand All @@ -85,10 89,10 @@ def match?
case key
when :os
match &&= PlatformGuard.os?(*value)
when :wordsize
match &&= PlatformGuard.wordsize? value
when :pointer_size
match &&= PlatformGuard.pointer_size? value
when :c_long_size
match &&= PlatformGuard::c_long_size? value
end
end
match
Expand Down
4 changes: 2 additions & 2 deletions spec/mspec/lib/mspec/helpers/numeric.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 28,15 @@ def min_long
# specs based on the relationship between values rather than specific
# values.
if PlatformGuard.standard? or PlatformGuard.implementation? :topaz
if PlatformGuard.wordsize? 32
if PlatformGuard.c_long_size? 32
def fixnum_max
(2**30) - 1
end

def fixnum_min
-(2**30)
end
elsif PlatformGuard.wordsize? 64
elsif PlatformGuard.c_long_size? 64
def fixnum_max
(2**62) - 1
end
Expand Down
38 changes: 19 additions & 19 deletions spec/mspec/spec/guards/platform_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,44 81,44 @@
end
end

RSpec.describe Object, "#platform_is :wordsize => SIZE_SPEC" do
RSpec.describe Object, "#platform_is :c_long_size => SIZE_SPEC" do
before :each do
@guard = PlatformGuard.new :darwin, :wordsize => 32
@guard = PlatformGuard.new :darwin, :c_long_size => 32
allow(PlatformGuard).to receive(:os?).and_return(true)
allow(PlatformGuard).to receive(:new).and_return(@guard)
ScratchPad.clear
end

it "yields when #wordsize? returns true" do
allow(PlatformGuard).to receive(:wordsize?).and_return(true)
platform_is(:wordsize => 32) { ScratchPad.record :yield }
it "yields when #c_long_size? returns true" do
allow(PlatformGuard).to receive(:c_long_size?).and_return(true)
platform_is(:c_long_size => 32) { ScratchPad.record :yield }
expect(ScratchPad.recorded).to eq(:yield)
end

it "doesn not yield when #wordsize? returns false" do
allow(PlatformGuard).to receive(:wordsize?).and_return(false)
platform_is(:wordsize => 32) { ScratchPad.record :yield }
it "doesn not yield when #c_long_size? returns false" do
allow(PlatformGuard).to receive(:c_long_size?).and_return(false)
platform_is(:c_long_size => 32) { ScratchPad.record :yield }
expect(ScratchPad.recorded).not_to eq(:yield)
end
end

RSpec.describe Object, "#platform_is_not :wordsize => SIZE_SPEC" do
RSpec.describe Object, "#platform_is_not :c_long_size => SIZE_SPEC" do
before :each do
@guard = PlatformGuard.new :darwin, :wordsize => 32
@guard = PlatformGuard.new :darwin, :c_long_size => 32
allow(PlatformGuard).to receive(:os?).and_return(true)
allow(PlatformGuard).to receive(:new).and_return(@guard)
ScratchPad.clear
end

it "yields when #wordsize? returns false" do
allow(PlatformGuard).to receive(:wordsize?).and_return(false)
platform_is_not(:wordsize => 32) { ScratchPad.record :yield }
it "yields when #c_long_size? returns false" do
allow(PlatformGuard).to receive(:c_long_size?).and_return(false)
platform_is_not(:c_long_size => 32) { ScratchPad.record :yield }
expect(ScratchPad.recorded).to eq(:yield)
end

it "doesn not yield when #wordsize? returns true" do
allow(PlatformGuard).to receive(:wordsize?).and_return(true)
platform_is_not(:wordsize => 32) { ScratchPad.record :yield }
it "doesn not yield when #c_long_size? returns true" do
allow(PlatformGuard).to receive(:c_long_size?).and_return(true)
platform_is_not(:c_long_size => 32) { ScratchPad.record :yield }
expect(ScratchPad.recorded).not_to eq(:yield)
end
end
Expand Down Expand Up @@ -184,13 184,13 @@
end
end

RSpec.describe PlatformGuard, ".wordsize?" do
RSpec.describe PlatformGuard, ".c_long_size?" do
it "returns true when arg is 32 and 1.size is 4" do
expect(PlatformGuard.wordsize?(32)).to eq(1.size == 4)
expect(PlatformGuard.c_long_size?(32)).to eq(1.size == 4)
end

it "returns true when arg is 64 and 1.size is 8" do
expect(PlatformGuard.wordsize?(64)).to eq(1.size == 8)
expect(PlatformGuard.c_long_size?(64)).to eq(1.size == 8)
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/ruby/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 164,7 @@ end
platform_is_not :linux, :darwin do # Not Linux and not Darwin
end

platform_is wordsize: 64 do
platform_is pointer_size: 64 do
# 64-bit platform
end

Expand Down
16 changes: 8 additions & 8 deletions spec/ruby/core/array/pack/l_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 29,7 @@
it_behaves_like :array_pack_32bit_be, 'L>'
end

platform_is wordsize: 32 do
platform_is c_long_size: 32 do
describe "with modifier '<' and '_'" do
it_behaves_like :array_pack_32bit_le, 'L<_'
it_behaves_like :array_pack_32bit_le, 'L_<'
Expand All @@ -51,7 51,7 @@
end
end

platform_is wordsize: 64 do
platform_is c_long_size: 64 do
describe "with modifier '<' and '_'" do
it_behaves_like :array_pack_64bit_le, 'L<_'
it_behaves_like :array_pack_64bit_le, 'L_<'
Expand Down Expand Up @@ -83,7 83,7 @@
it_behaves_like :array_pack_32bit_be, 'l>'
end

platform_is wordsize: 32 do
platform_is c_long_size: 32 do
describe "with modifier '<' and '_'" do
it_behaves_like :array_pack_32bit_le, 'l<_'
it_behaves_like :array_pack_32bit_le, 'l_<'
Expand All @@ -105,7 105,7 @@
end
end

platform_is wordsize: 64 do
platform_is c_long_size: 64 do
describe "with modifier '<' and '_'" do
it_behaves_like :array_pack_64bit_le, 'l<_'
it_behaves_like :array_pack_64bit_le, 'l_<'
Expand Down Expand Up @@ -137,7 137,7 @@
it_behaves_like :array_pack_32bit_le, 'l'
end

platform_is wordsize: 32 do
platform_is c_long_size: 32 do
describe "Array#pack with format 'L' with modifier '_'" do
it_behaves_like :array_pack_32bit_le, 'L_'
end
Expand All @@ -155,7 155,7 @@
end
end

platform_is wordsize: 64 do
platform_is c_long_size: 64 do
describe "Array#pack with format 'L' with modifier '_'" do
it_behaves_like :array_pack_64bit_le, 'L_'
end
Expand Down Expand Up @@ -183,7 183,7 @@
it_behaves_like :array_pack_32bit_be, 'l'
end

platform_is wordsize: 32 do
platform_is c_long_size: 32 do
describe "Array#pack with format 'L' with modifier '_'" do
it_behaves_like :array_pack_32bit_be, 'L_'
end
Expand All @@ -201,7 201,7 @@
end
end

platform_is wordsize: 64 do
platform_is c_long_size: 64 do
describe "Array#pack with format 'L' with modifier '_'" do
it_behaves_like :array_pack_64bit_be, 'L_'
end
Expand Down
4 changes: 2 additions & 2 deletions spec/ruby/core/array/pack/shared/integer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 273,7 @@
str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde\x21\x43\x65\x78"
end

platform_is wordsize: 64 do
platform_is c_long_size: 64 do
it "encodes the least significant 32 bits of a number that is greater than 32 bits" do
[ [[0xff_7865_4321], "\x21\x43\x65\x78"],
[[-0xff_7865_4321], "\xdf\xbc\x9a\x87"]
Expand All @@ -299,7 299,7 @@
str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd\x78\x65\x43\x21"
end

platform_is wordsize: 64 do
platform_is c_long_size: 64 do
it "encodes the least significant 32 bits of a number that is greater than 32 bits" do
[ [[0xff_7865_4321], "\x78\x65\x43\x21"],
[[-0xff_7865_4321], "\x87\x9a\xbc\xdf"]
Expand Down
2 changes: 1 addition & 1 deletion spec/ruby/core/file/shared/update_time.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 84,7 @@
end

platform_is :linux do
platform_is wordsize: 64 do
platform_is pointer_size: 64 do
it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19 or 2486-07-02)" do
# https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Timestamps
# "Therefore, timestamps should not overflow until May 2446."
Expand Down
4 changes: 2 additions & 2 deletions spec/ruby/core/integer/size_spec.rb
Original file line number Diff line number Diff line change
@@ -1,15 1,15 @@
require_relative '../../spec_helper'

describe "Integer#size" do
platform_is wordsize: 32 do
platform_is c_long_size: 32 do
it "returns the number of bytes in the machine representation of self" do
-1.size.should == 4
0.size.should == 4
4091.size.should == 4
end
end

platform_is wordsize: 64 do
platform_is c_long_size: 64 do
it "returns the number of bytes in the machine representation of self" do
-1.size.should == 8
0.size.should == 8
Expand Down
2 changes: 1 addition & 1 deletion spec/ruby/core/marshal/dump_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 38,7 @@
].should be_computed_by(:dump)
end

platform_is wordsize: 64 do
platform_is c_long_size: 64 do
it "dumps a positive Fixnum > 31 bits as a Bignum" do
Marshal.dump(2**31 1).should == "\x04\bl \a\x01\x00\x00\x80"
end
Expand Down
2 changes: 1 addition & 1 deletion spec/ruby/core/marshal/shared/load.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1049,7 1049,7 @@ def io.binmode; raise "binmode"; end
end

describe "for a Bignum" do
platform_is wordsize: 64 do
platform_is c_long_size: 64 do
context "that is Bignum on 32-bit platforms but Fixnum on 64-bit" do
it "dumps a Fixnum" do
val = Marshal.send(@method, "\004\bl \ab:wU")
Expand Down
16 changes: 8 additions & 8 deletions spec/ruby/core/string/unpack/l_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 14,7 @@
it_behaves_like :string_unpack_32bit_be_unsigned, 'L>'
end

platform_is wordsize: 32 do
platform_is c_long_size: 32 do
describe "with modifier '<' and '_'" do
it_behaves_like :string_unpack_32bit_le, 'L<_'
it_behaves_like :string_unpack_32bit_le, 'L_<'
Expand Down Expand Up @@ -44,7 44,7 @@
end
end

platform_is wordsize: 64 do
platform_is c_long_size: 64 do
describe "with modifier '<' and '_'" do
it_behaves_like :string_unpack_64bit_le, 'L<_'
it_behaves_like :string_unpack_64bit_le, 'L_<'
Expand Down Expand Up @@ -86,7 86,7 @@
it_behaves_like :string_unpack_32bit_be_signed, 'l>'
end

platform_is wordsize: 32 do
platform_is c_long_size: 32 do
describe "with modifier '<' and '_'" do
it_behaves_like :string_unpack_32bit_le, 'l<_'
it_behaves_like :string_unpack_32bit_le, 'l_<'
Expand Down Expand Up @@ -116,7 116,7 @@
end
end

platform_is wordsize: 64 do
platform_is c_long_size: 64 do
describe "with modifier '<' and '_'" do
it_behaves_like :string_unpack_64bit_le, 'l<_'
it_behaves_like :string_unpack_64bit_le, 'l_<'
Expand Down Expand Up @@ -160,7 160,7 @@
it_behaves_like :string_unpack_32bit_le_signed, 'l'
end

platform_is wordsize: 32 do
platform_is c_long_size: 32 do
describe "String#unpack with format 'L' with modifier '_'" do
it_behaves_like :string_unpack_32bit_le, 'L_'
it_behaves_like :string_unpack_32bit_le_unsigned, 'L_'
Expand All @@ -182,7 182,7 @@
end
end

platform_is wordsize: 64 do
platform_is c_long_size: 64 do
describe "String#unpack with format 'L' with modifier '_'" do
it_behaves_like :string_unpack_64bit_le, 'L_'
it_behaves_like :string_unpack_64bit_le_unsigned, 'L_'
Expand Down Expand Up @@ -218,7 218,7 @@
it_behaves_like :string_unpack_32bit_be_signed, 'l'
end

platform_is wordsize: 32 do
platform_is c_long_size: 32 do
describe "String#unpack with format 'L' with modifier '_'" do
it_behaves_like :string_unpack_32bit_be, 'L_'
it_behaves_like :string_unpack_32bit_be_unsigned, 'L_'
Expand All @@ -240,7 240,7 @@
end
end

platform_is wordsize: 64 do
platform_is c_long_size: 64 do
describe "String#unpack with format 'L' with modifier '_'" do
it_behaves_like :string_unpack_64bit_be, 'L_'
it_behaves_like :string_unpack_64bit_be_unsigned, 'L_'
Expand Down
2 changes: 1 addition & 1 deletion spec/ruby/library/bigdecimal/sqrt_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 36,7 @@
BigDecimal('121').sqrt(5).should be_close(11, 0.00001)
end

platform_is_not wordsize: 32 do # fails on i686
platform_is_not c_long_size: 32 do # fails on i686
it "returns square root of 0.9E-99999 with desired precision" do
@frac_2.sqrt(1).to_s.should =~ /\A0\.3E-49999\z/i
end
Expand Down
2 changes: 1 addition & 1 deletion spec/ruby/optional/capi/bignum_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 123,7 @@ def ensure_bignum(n)
val.should == @max_ulong
end

platform_is wordsize: 64 do
platform_is c_long_size: 64 do
it "packs max_ulong into 2 ulongs to allow sign bit" do
val = @s.rb_big_pack_length(@max_ulong)
val.should == 2
Expand Down
4 changes: 2 additions & 2 deletions spec/ruby/optional/capi/fixnum_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 25,7 @@
end
end

platform_is wordsize: 64 do # sizeof(long) > sizeof(int)
platform_is c_long_size: 64 do # sizeof(long) > sizeof(int)
it "raises a TypeError if passed nil" do
-> { @s.FIX2INT(nil) }.should raise_error(TypeError)
end
Expand Down Expand Up @@ -74,7 74,7 @@
end
end

platform_is wordsize: 64 do # sizeof(long) > sizeof(int)
platform_is c_long_size: 64 do # sizeof(long) > sizeof(int)
it "raises a TypeError if passed nil" do
-> { @s.FIX2UINT(nil) }.should raise_error(TypeError)
end
Expand Down
Loading