boxing.md: add inline float details and comparison table

Add sections on 64-bit inline float rotation encoding and 32-bit
RFloat heap allocation with char[] buffer for alignment safety.
Add comparison table of all three boxing modes and ABI note.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2026-02-27 17:19:08 +09:00
parent 55348ce0da
commit 5c1aaa0259
+44 -2
View File
@@ -26,8 +26,30 @@ The Word boxing packing bit patterns are like following:
| undef | `00000000 00000000 00000000 00010100` |
| symbol | `xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx10` |
On 64-bit platforms (unless `MRB_WORDBOX_NO_INLINE_FLOAT`), float values are also packed in the `mrb_value` using rotation encoding (lossless for exponents in range).
To disable inline float encoding and heap-allocate all floats, define `MRB_WORDBOX_NO_INLINE_FLOAT`.
### Inline Float (64-bit)
On 64-bit platforms, `double` values are packed into the word using
rotation encoding. The IEEE 754 exponent field is rotated so that
common exponent values (those not colliding with the pointer/tag
patterns above) fit directly in a word. This encoding is lossless
for most float values; only a small set of exotic exponents require
heap allocation as `RFloat`.
To disable inline float and heap-allocate all floats, define
`MRB_WORDBOX_NO_INLINE_FLOAT`.
### 32-bit Considerations
On 32-bit platforms with 64-bit `double` (the common case),
`MRB_WORDBOX_NO_INLINE_FLOAT` is automatically defined because a
64-bit double cannot fit in a 32-bit word. All floats are
heap-allocated as `RFloat` objects.
The `RFloat` struct uses a `char[]` buffer instead of a `double`
field to avoid alignment issues, since GC heap slots (RVALUE) on
32-bit have only 4-byte alignment but `double` requires 8-byte.
Accessor functions `mrb_rfloat_value()` and `mrb_rfloat_set()` use
`memcpy` for safe access.
## NaN Boxing
@@ -52,3 +74,23 @@ The object values appear far more frequently than floating-point numbers, so we
## No Boxing
No boxing represents `mrb_value` by the C struct with `type` and the value union. This is the most portable (but inefficient) representation. No boxing can be specified by `MRB_NO_BOXING`, and it's default for debugging configuration (e.g. `host-debug`).
## Comparison
| Property | Word Boxing | NaN Boxing | No Boxing |
| ---------------------- | ------------------ | ------------------ | -------------------- |
| `mrb_value` size | 1 word (4/8 byte) | 8 bytes | 2 words (8/16 bytes) |
| Default on | most platforms | (manual opt-in) | `host-debug` |
| Macro | `MRB_WORD_BOXING` | `MRB_NAN_BOXING` | `MRB_NO_BOXING` |
| Inline integers | yes (31/63 bit) | yes (32 bit) | yes (full width) |
| Inline floats (64-bit) | yes (rotation) | yes (native) | yes (struct field) |
| Inline floats (32-bit) | no (heap RFloat) | yes (native) | yes (struct field) |
| Pointer size limit | none | 48 bits | none |
| Debugger friendly | no | no | yes |
## ABI Compatibility
The boxing mode changes the layout of `mrb_value`. Code compiled with
one boxing mode **cannot** be linked against a library built with a
different mode. Always use `mruby-config --cflags` to get the correct
compiler flags.