32-битные системы хранят указатели и SMI вот так (речь про v8)
|----- 32 bits -----|
Pointer: |_____address_____w1|
Smi: |___int31_value____0|
64-битные вот так:
|----- 32 bits -----|----- 32 bits -----|
Pointer: |________________address______________w1|
Smi: |____int32_value____|0000000000000000000|
Т.е. в 32-битных системах мы теряем один бит на то, чтобы запомнить (протегировать) — указатель у нас или SMI, в SMI влазит только int31. В 64-битных системах метка (тег) переезжает в «свободные» 32-бита и мы можем хранить int32.
Кстати, с этим связан один неприятный момент. Когда в V8 решили включить Pointer Compression (сжатие указателей), то оказалось, что да, мы можем хранить два 32-битных указателя в одном 64-битном слове (там применяется достаточно сложный алгоритм), но вот снова положить два int31 — это приводит к деградации производительности (1% на Octane). А два int32 не помещаются, негде хранить тег.
UPD
В комментах @cevek подсказал, что всё же включили компрессию для SMI, и в браузере в SMI будет именно int31, а не int32 «как раньше».
%DebugPrint(2147483647)
DebugPrint: 2147483647.0
0x5f700000339: [Map] in ReadOnlySpace
С нодой интереснее, в ноде компрессия указателей изначально не была включена из-за проблем совместимости с нативными аддонами, потому мы продолжаем видеть в SMI int32. Есть такое обсуждение.