From e3a783b14191fef175c9a59996afdc744c8edc4c Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Tue, 26 Oct 2021 23:39:43 +0900 Subject: [PATCH] Align `RFloat` at VALUE boundary --- gc.c | 11 +++++------ internal/numeric.h | 27 ++++++++++++++++----------- numeric.c | 8 ++++++-- 3 files changed, 27 insertions(+), 19 deletions(-) diff --git a/gc.c b/gc.c index 0c739ba709..bd3915fb47 100644 --- a/gc.c +++ b/gc.c @@ -565,10 +565,6 @@ struct RMoved { #define RMOVED(obj) ((struct RMoved *)(obj)) -#if (SIZEOF_DOUBLE > SIZEOF_VALUE) && (defined(_MSC_VER) || defined(__CYGWIN__)) -#pragma pack(push, 4) /* == SIZEOF_VALUE: magic for reducing sizeof(RVALUE): 24 -> 20 */ -#endif - typedef struct RVALUE { union { struct { @@ -618,9 +614,12 @@ typedef struct RVALUE { #endif } RVALUE; -#if (SIZEOF_DOUBLE > SIZEOF_VALUE) && (defined(_MSC_VER) || defined(__CYGWIN__)) -#pragma pack(pop) +#if GC_DEBUG +STATIC_ASSERT(sizeof_rvalue, offsetof(RVALUE, file) == SIZEOF_VALUE * 5); +#else +STATIC_ASSERT(sizeof_rvalue, sizeof(RVALUE) == SIZEOF_VALUE * 5); #endif +STATIC_ASSERT(alignof_rvalue, RUBY_ALIGNOF(RVALUE) == SIZEOF_VALUE); typedef uintptr_t bits_t; enum { diff --git a/internal/numeric.h b/internal/numeric.h index 3d88845a16..440bef1671 100644 --- a/internal/numeric.h +++ b/internal/numeric.h @@ -35,9 +35,18 @@ enum ruby_num_rounding_mode { RUBY_NUM_ROUND_DEFAULT = ROUND_DEFAULT, }; +#if SIZEOF_DOUBLE < SIZEOF_VALUE +typedef double rb_float_value_type; +#else +typedef struct { + VALUE values[(SIZEOF_DOUBLE + SIZEOF_VALUE - 1) / SIZEOF_VALUE]; + /* roomof() needs internal.h, and the order of some macros may matter */ +} rb_float_value_type; +#endif + struct RFloat { struct RBasic basic; - double float_value; + rb_float_value_type float_value; }; #define RFLOAT(obj) ((struct RFloat *)(obj)) @@ -206,21 +215,17 @@ rb_float_flonum_value(VALUE v) return 0.0; } -#if SIZEOF_VALUE >= SIZEOF_DOUBLE || defined(UNALIGNED_WORD_ACCESS) -# define UNALIGNED_DOUBLE_ACCESS 1 -#else -# define UNALIGNED_DOUBLE_ACCESS 0 -#endif - static inline double rb_float_noflonum_value(VALUE v) { -#if UNALIGNED_DOUBLE_ACCESS +#if SIZEOF_DOUBLE < SIZEOF_VALUE return RFLOAT(v)->float_value; #else - double d; - memcpy(&d, &RFLOAT(v)->float_value, sizeof(double)); - return d; + union { + rb_float_value_type v; + double d; + } u = {RFLOAT(v)->float_value}; + return u.d; #endif } diff --git a/numeric.c b/numeric.c index e12bcce5b8..3ee98343a7 100644 --- a/numeric.c +++ b/numeric.c @@ -951,10 +951,14 @@ rb_float_new_in_heap(double d) { NEWOBJ_OF(flt, struct RFloat, rb_cFloat, T_FLOAT | (RGENGC_WB_PROTECTED_FLOAT ? FL_WB_PROTECTED : 0)); -#if UNALIGNED_DOUBLE_ACCESS +#if SIZEOF_DOUBLE < SIZEOF_VALUE flt->float_value = d; #else - memcpy(&flt->float_value, &d, sizeof(double)); + union { + double d; + rb_float_value_type v; + } u = {d}; + flt->float_value = u.v; #endif OBJ_FREEZE((VALUE)flt); return (VALUE)flt;