Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
14 changes: 13 additions & 1 deletion mrbgems/mruby-compiler/include/mrc_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@
#include <mrubyc.h>
#define mrb_state void
#else
/* May be building standalone mrbc */
/* May be building standalone mrbc. mruby.h would declare a core API this
binary does not link, but mrbconf.h on its own is self-contained, and it
is what settles the target's mrb_int width -- which mrc_int has to match,
because this mrbc dumps irep for that target (see MRC_INT32 below). */
#include <stdint.h>
#include <mrbconf.h>
#define mrb_state void
#endif

Expand Down Expand Up @@ -116,6 +121,13 @@ typedef uint8_t mrc_bool;
# endif
#endif

/* mrc_int must be as wide as the VM's mrb_int and no wider: the pool literals
and the constant folding below are dumped for a target whose loader rejects
an IREP_TT_INT64 entry unless it was built with MRB_INT64 (src/load.c). */
#if defined(MRB_INT32) && !defined(MRC_INT32)
#define MRC_INT32 1
#endif

#if !defined(MRC_INT32)
#define MRC_INT64 1
#endif
Expand Down
32 changes: 17 additions & 15 deletions mrbgems/mruby-compiler/src/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -3987,30 +3987,32 @@ gen_ensure(mrc_codegen_scope *s, mrc_node *tree, uint32_t catch_entry, uint32_t
static void
gen_pm_integer(mrc_codegen_scope *s, const pm_integer_t *iv)
{
mrc_uint value;
mrc_bool fits = FALSE;

if (iv->length == 0) {
if (!iv->negative) {
gen_int(s, cursp(), (mrc_int)iv->value);
}
else {
gen_int(s, cursp(), (mrc_int)iv->value * -1);
}
return;
/* iv->value is a uint32_t, which is wider than mrc_int under MRC_INT32,
so the magnitude still has to be range-checked below. */
value = iv->value;
fits = TRUE;
}
#ifdef MRC_INT64
if (iv->length == 2) {
mrc_uint value = ((mrc_uint)iv->values[0])|((mrc_uint)iv->values[1] << 32);
mrc_bool fits = TRUE;
else if (iv->length == 2) {
value = ((mrc_uint)iv->values[0])|((mrc_uint)iv->values[1] << 32);
fits = TRUE;
}
#endif
if (fits) {
if (!iv->negative && MRC_INT_MAX < value) fits = FALSE;
if (iv->negative) {
if (value > (mrc_uint)MRC_INT_MIN) fits = FALSE;
else value *= -1;
}
if (fits) {
gen_int(s, cursp(), value);
return;
}
}
#endif
if (fits) {
gen_int(s, cursp(), (mrc_int)value);
return;
}
{
pm_buffer_t buf = {0};
pm_integer_string(&buf, iv);
Expand Down
21 changes: 21 additions & 0 deletions test/t/literals.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,27 @@
assert_equal 10.0, 1.0e+1
end

assert('Literals Numerical wider than mrb_int') do
# None of these fit mrb_int on MRB_INT32, so the compiler has to hand them
# to the VM as big integer literals. A shift is written on the other side
# of each because a shift that overflows mrb_int is left to run time, which
# gives the same value by a path the literal does not share. Without
# mruby-bigint the value cannot exist at all, and it is the literal that
# cannot be built where mrb_int is narrow, the shift where it is wide, so
# the guard holds one of each.
begin
n = 2147483648
m = (1 << 63) - 1
rescue RangeError
skip 'a value here is wider than mrb_int and mruby-bigint is absent'
end
assert_equal 1 << 31, n
assert_equal 4294967296, 1 << 32
assert_equal 9223372036854775807, m
assert_equal(-2147483649, -(1 << 31) - 1)
assert_equal 2147483648, 0x80000000
Comment thread
coderabbitai[bot] marked this conversation as resolved.
end

assert('Literals Strings Single Quoted', '8.7.6.3.2') do
assert_equal 'abc', 'abc'
assert_equal '\'', '\''
Expand Down
Loading