diff --git a/include/ruby/internal/arithmetic/len_t.h b/include/ruby/internal/arithmetic/len_t.h index 7a46289502d..6bd7dd98352 100644 --- a/include/ruby/internal/arithmetic/len_t.h +++ b/include/ruby/internal/arithmetic/len_t.h @@ -22,6 +22,7 @@ */ #include "ruby/internal/config.h" #include "ruby/internal/arithmetic/long.h" +#include "ruby/internal/arithmetic/long_long.h" #include "ruby/internal/assume.h" #include "ruby/internal/cast.h" #include "ruby/internal/value.h" @@ -32,14 +33,20 @@ #define rb_len2int rb_len2int_inline /**< @alias{rb_len2int_inline} */ #define rb_len2long rb_len2long_inline /**< @alias{rb_len2long_inline} */ +#if SIZEOF_RB_LEN_T > SIZEOF_LONG +# define RB_LEN2NUM RB_LL2NUM +# define RB_NUM2LEN RB_NUM2LL +# define RB_ULEN2NUM RB_ULL2NUM +#else /** Converts a ::rb_len_t into an instance of ::rb_cInteger. */ -#define RB_LEN2NUM RB_LONG2NUM +# define RB_LEN2NUM RB_LONG2NUM /** Converts an instance of ::rb_cNumeric into ::rb_len_t. */ -#define RB_NUM2LEN RB_NUM2LONG +# define RB_NUM2LEN RB_NUM2LONG /** Converts a ::rb_ulen_t into an instance of ::rb_cInteger. */ -#define RB_ULEN2NUM RB_ULONG2NUM +# define RB_ULEN2NUM RB_ULONG2NUM +#endif /** * Checks if `int` can hold the given integer. diff --git a/include/ruby/internal/value.h b/include/ruby/internal/value.h index 545bf558fb0..afc089c78ba 100644 --- a/include/ruby/internal/value.h +++ b/include/ruby/internal/value.h @@ -124,34 +124,46 @@ typedef unsigned LONG_LONG ID; # error ---->> ruby requires sizeof(void*) == sizeof(long) or sizeof(LONG_LONG) to be compiled. <<---- #endif +#if defined(SIZEOF_RB_LEN_T) && SIZEOF_RB_LEN_T > SIZEOF_LONG +/* mswin, where long is narrower than a pointer and config.h asks for more. */ +# include +typedef int64_t rb_len_t; +typedef uint64_t rb_ulen_t; +# define PRI_LEN_PREFIX PRI_64_PREFIX +# define RB_LEN_MAX INT64_MAX +# define RB_LEN_MIN INT64_MIN +# define RB_ULEN_MAX UINT64_MAX + +#else /** * A signed integer type for lengths and indices of objects such as String and - * Array. It is `long` for now, on every platform. + * Array. It is `long`, except on mswin, where it is `int64_t`. */ typedef long rb_len_t; /** An unsigned integer type that has the same width with ::rb_len_t. */ typedef unsigned long rb_ulen_t; -/** Indicates that ::rb_len_t and ::rb_ulen_t are available. */ -#define HAVE_RB_LEN_T 1 - -#ifndef SIZEOF_RB_LEN_T +# ifndef SIZEOF_RB_LEN_T /** Size of ::rb_len_t, in bytes. */ -# define SIZEOF_RB_LEN_T SIZEOF_LONG -#endif +# define SIZEOF_RB_LEN_T SIZEOF_LONG +# endif /** Printf prefix for ::rb_len_t. */ -#define PRI_LEN_PREFIX "l" +# define PRI_LEN_PREFIX "l" /** Maximum possible value that a ::rb_len_t can take. */ -#define RB_LEN_MAX LONG_MAX +# define RB_LEN_MAX LONG_MAX /** Minimum possible value that a ::rb_len_t can take. */ -#define RB_LEN_MIN LONG_MIN +# define RB_LEN_MIN LONG_MIN /** Maximum possible value that a ::rb_ulen_t can take. */ -#define RB_ULEN_MAX ULONG_MAX +# define RB_ULEN_MAX ULONG_MAX +#endif + +/** Indicates that ::rb_len_t and ::rb_ulen_t are available. */ +#define HAVE_RB_LEN_T 1 /** @cond INTERNAL_MACRO */ RBIMPL_STATIC_ASSERT(sizeof_int, SIZEOF_INT == sizeof(int)); @@ -159,7 +171,7 @@ RBIMPL_STATIC_ASSERT(sizeof_long, SIZEOF_LONG == sizeof(long)); RBIMPL_STATIC_ASSERT(sizeof_long_long, SIZEOF_LONG_LONG == sizeof(LONG_LONG)); RBIMPL_STATIC_ASSERT(sizeof_voidp, SIZEOF_VOIDP == sizeof(void *)); RBIMPL_STATIC_ASSERT(sizeof_rb_len_t_macro, SIZEOF_RB_LEN_T == sizeof(rb_len_t)); -RBIMPL_STATIC_ASSERT(sizeof_rb_len_t, sizeof(rb_len_t) == sizeof(long)); -RBIMPL_STATIC_ASSERT(sizeof_rb_ulen_t, sizeof(rb_ulen_t) == sizeof(unsigned long)); +RBIMPL_STATIC_ASSERT(sizeof_rb_len_t, sizeof(rb_len_t) <= SIZEOF_VALUE); +RBIMPL_STATIC_ASSERT(sizeof_rb_ulen_t, sizeof(rb_ulen_t) == sizeof(rb_len_t)); /** @endcond */ #endif /* RBIMPL_VALUE_H */ diff --git a/parser_value.h b/parser_value.h index 3108ed9cbe4..ad5da4f4aec 100644 --- a/parser_value.h +++ b/parser_value.h @@ -103,14 +103,24 @@ typedef unsigned LONG_LONG ID; # error ---->> ruby requires sizeof(void*) == sizeof(long) or sizeof(LONG_LONG) to be compiled. <<---- #endif +#if defined(SIZEOF_RB_LEN_T) && SIZEOF_RB_LEN_T > SIZEOF_LONG +# include +typedef int64_t rb_len_t; +typedef uint64_t rb_ulen_t; +# define PRI_LEN_PREFIX PRI_64_PREFIX +# define RB_LEN_MAX INT64_MAX +# define RB_LEN_MIN INT64_MIN +# define RB_ULEN_MAX UINT64_MAX +#else typedef long rb_len_t; typedef unsigned long rb_ulen_t; -#ifndef SIZEOF_RB_LEN_T -# define SIZEOF_RB_LEN_T SIZEOF_LONG +# ifndef SIZEOF_RB_LEN_T +# define SIZEOF_RB_LEN_T SIZEOF_LONG +# endif +# define PRI_LEN_PREFIX "l" +# define RB_LEN_MAX LONG_MAX +# define RB_LEN_MIN LONG_MIN +# define RB_ULEN_MAX ULONG_MAX #endif -#define PRI_LEN_PREFIX "l" -#define RB_LEN_MAX LONG_MAX -#define RB_LEN_MIN LONG_MIN -#define RB_ULEN_MAX ULONG_MAX #endif /* EXTERNAL_VALUE_H */ diff --git a/string.c b/string.c index ae7591e549e..866610f87d7 100644 --- a/string.c +++ b/string.c @@ -6833,7 +6833,7 @@ str_bit_offset_out_of_range(rb_len_t byte_len, uint64_t bit_offset) * Keep both the full bit offset and its rb_len_t representation. Most calls * use a Fixnum-sized offset and can stay on the rb_len_t fast path; only large * Bignum offsets need the uint64_t path below. This matters on platforms where - * rb_len_t is narrower than the address space, such as 32-bit and LLP64. + * rb_len_t is 32 bits. */ struct str_bit_offset { uint64_t value; diff --git a/test/-ext-/string/test_modify_expand.rb b/test/-ext-/string/test_modify_expand.rb index 9aa3b9a6ca2..3c124d81ba5 100644 --- a/test/-ext-/string/test_modify_expand.rb +++ b/test/-ext-/string/test_modify_expand.rb @@ -16,11 +16,11 @@ class Test_StringModifyExpand < Test::Unit::TestCase end def test_integer_overflow - return if RbConfig::SIZEOF['size_t'] > RbConfig::SIZEOF['long'] + return if RbConfig::SIZEOF['size_t'] > RbConfig::SIZEOF['rb_len_t'] bug12390 = '[ruby-core:75592] [Bug #12390]' s = Bug::String.new assert_raise(ArgumentError, bug12390) { - s.modify_expand!(RbConfig::LIMITS["LONG_MAX"]) + s.modify_expand!(2 ** (RbConfig::SIZEOF['rb_len_t'] * 8 - 1) - 1) } end end diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index fdeab39330c..ea3007389c7 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -3778,10 +3778,10 @@ class TestArray < Test::Unit::TestCase assert_include([1, 2], a.bsearch_index {|x| (2**100).coerce((1 - x / 4) * (2**100)).first }) end - sizeof_long = [0].pack("l!").size + sizeof_len = RbConfig::SIZEOF["rb_len_t"] sizeof_voidp = [""].pack("p").size - if sizeof_long < sizeof_voidp - ARY_MAX = (1<<(8*sizeof_long-1)) / sizeof_voidp - 1 + if sizeof_len < sizeof_voidp + ARY_MAX = (1<<(8*sizeof_len-1)) / sizeof_voidp - 1 Bug11235 = '[ruby-dev:49043] [Bug #11235]' def test_push_over_ary_max diff --git a/test/ruby/test_rand.rb b/test/ruby/test_rand.rb index aeb3c35778d..bca570a372f 100644 --- a/test/ruby/test_rand.rb +++ b/test/ruby/test_rand.rb @@ -425,12 +425,12 @@ class TestRand < Test::Unit::TestCase end def test_urandom_size_errors - beyond_long = 2 ** (RbConfig::SIZEOF['long'] * 8 - 1) + beyond_len = 2 ** (RbConfig::SIZEOF['rb_len_t'] * 8 - 1) assert_raise(ArgumentError) { Random.urandom(-1) } - assert_raise(RangeError) { Random.urandom(beyond_long) } + assert_raise(RangeError) { Random.urandom(beyond_len) } # Random#bytes converts its size the same way, so the classes have to agree assert_raise(ArgumentError) { Random.new.bytes(-1) } - assert_raise(RangeError) { Random.new.bytes(beyond_long) } + assert_raise(RangeError) { Random.new.bytes(beyond_len) } end def test_new_seed diff --git a/win32/Makefile.sub b/win32/Makefile.sub index 53275f79077..2d67d661cad 100644 --- a/win32/Makefile.sub +++ b/win32/Makefile.sub @@ -791,6 +791,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub #define SIZEOF_OFF_T 8 !if "$(TARGET_OS)" == "mswin64" #define SIZEOF_VOIDP 8 +#define SIZEOF_RB_LEN_T 8 !else #define SIZEOF_VOIDP 4 !endif diff --git a/yjit.c b/yjit.c index 43dfdd4b07a..5b60e4f8f9a 100644 --- a/yjit.c +++ b/yjit.c @@ -50,9 +50,9 @@ STATIC_ASSERT(size_t_no_padding_bits, sizeof(size_t) == sizeof(uint64_t)); // support one scheme for simplicity. STATIC_ASSERT(pointer_tagging_scheme, USE_FLONUM); -// The bindings declare rb_len_t as c_long, and codegen reads String and Array -// lengths at that width. Widening rb_len_t needs TYPE_REPLACEMENTS updated too. -STATIC_ASSERT(rb_len_t_matches_bindings, sizeof(rb_len_t) == sizeof(long)); +// The bindings declare rb_len_t as i64, and codegen reads String and Array +// lengths at that width. +STATIC_ASSERT(rb_len_t_matches_bindings, sizeof(rb_len_t) == sizeof(int64_t)); enum yjit_bindgen_constants { // ISEQ_TRANSLATED expands to an enum value through a chain of macros, diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs index 44fc5dcda22..0bbe29a2193 100644 --- a/yjit/bindgen/src/main.rs +++ b/yjit/bindgen/src/main.rs @@ -422,6 +422,8 @@ fn main() { // These are unsigned long on LP64 but unsigned long long on LLP64 (Windows) ("pub type ID = ::std::os::raw::c_ulong;", "pub type ID = u64;"), ("pub type st_data_t = ::std::os::raw::c_ulong;", "pub type st_data_t = u64;"), + // long on LP64 but int64_t on mswin + ("pub type rb_len_t = ::std::os::raw::c_long;", "pub type rb_len_t = i64;"), ]; // Each needle is a whole line of the output, so plain replacement is unambiguous. // Yes, this search-and-replace could be faster, but it's a small file. diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index be6cac37f4f..3547abdeec1 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -173,7 +173,7 @@ pub const VM_ENV_DATA_INDEX_SPECVAL: i32 = -1; pub const VM_ENV_DATA_INDEX_FLAGS: u32 = 0; pub const VM_BLOCK_HANDLER_NONE: u32 = 0; pub type ID = u64; -pub type rb_len_t = ::std::os::raw::c_long; +pub type rb_len_t = i64; pub type rb_alloc_func_t = ::std::option::Option VALUE>; pub const RUBY_Qfalse: ruby_special_consts = 0; pub const RUBY_Qnil: ruby_special_consts = 4;