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
21 changes: 17 additions & 4 deletions ext/mini_racer_extension/mini_racer_extension.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,19 @@ static void des_bigint(void *arg, const void *p, size_t n, int sign)
if (t >> 63)
*a++ = 0; // suppress sign extension
v = rb_big_unpack(limbs, a-limbs);
if (sign < 0)
v = rb_big_mul(v, LONG2FIX(-1));
if (sign < 0) {
// rb_big_unpack returns T_FIXNUM for smallish bignums
switch (TYPE(v)) {
case T_BIGNUM:
v = rb_big_mul(v, LONG2FIX(-1));
break;
case T_FIXNUM:
v = LONG2FIX(-1 * FIX2LONG(v));
break;
default:
abort();
}
}
put(c, v);
}

Expand Down Expand Up @@ -620,14 +631,16 @@ static int serialize1(Ser *s, VALUE refs, VALUE v)
struct timeval tv = rb_time_timeval(v);
ser_date(s, tv.tv_sec*1e3 + tv.tv_usec/1e3);
} else {
snprintf(s->err, sizeof(s->err), "unsupported type %s", rb_class2name(CLASS_OF(v)));
return -1;
snprintf(s->err, sizeof(s->err), "unsupported type %s", rb_class2name(CLASS_OF(v)));
return -1;
}
break;
default:
snprintf(s->err, sizeof(s->err), "unsupported type %x", TYPE(v));
return -1;
}
if (*s->err)
return -1;
return 0;
}

Expand Down
55 changes: 30 additions & 25 deletions ext/mini_racer_extension/serde.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,15 +239,44 @@ static void ser_num(Ser *s, double v)
}
}

// ser_bigint: |n| is in bytes, not quadwords
static void ser_bigint(Ser *s, const uint64_t *p, size_t n, int sign)
{
if (*s->err)
return;
if (n % 8) {
snprintf(s->err, sizeof(s->err), "bad bigint");
return;
}
w_byte(s, 'Z');
// chop off high all-zero words
n /= 8;
while (n--)
if (p[n])
break;
if (n == (size_t)-1) {
w_byte(s, 0); // normalized zero
} else {
n = 8*n + 8;
w_varint(s, 2*n + (sign < 0));
w(s, p, n);
}
}

static void ser_int(Ser *s, int64_t v)
{
uint64_t t;
int sign;

if (*s->err)
return;
if (v < INT32_MIN || v > INT32_MAX) {
if (v > INT64_MIN/1024)
if (v <= INT64_MAX/1024)
return ser_num(s, v);
snprintf(s->err, sizeof(s->err), "out of range: %lld", (long long)v);
t = v < 0 ? -v : v;
sign = v < 0 ? -1 : 1;
ser_bigint(s, &t, sizeof(t), sign);
} else {
w_byte(s, 'I');
w_zigzag(s, v);
Expand All @@ -265,30 +294,6 @@ static void ser_date(Ser *s, double v)
}
}

// ser_bigint: |n| is in bytes, not quadwords
static void ser_bigint(Ser *s, const uint64_t *p, size_t n, int sign)
{
if (*s->err)
return;
if (n % 8) {
snprintf(s->err, sizeof(s->err), "bad bigint");
return;
}
w_byte(s, 'Z');
// chop off high all-zero words
n /= 8;
while (n--)
if (p[n])
break;
if (n == (size_t)-1) {
w_byte(s, 0); // normalized zero
} else {
n = 8*n + 8;
w_varint(s, 2*n + (sign < 0));
w(s, p, n);
}
}

// string must be utf8
static void ser_string(Ser *s, const char *p, size_t n)
{
Expand Down
14 changes: 14 additions & 0 deletions test/mini_racer_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1153,5 +1153,19 @@ def test_large_integer
assert_equal(result.class, big_int.class)
assert_equal(result, big_int)
}
types = []
[2**63/1024-1, 2**63/1024, -2**63/1024+1, -2**63/1024].each { |big_int|
context = MiniRacer::Context.new
context.attach("test", proc { big_int })
context.attach("type", proc { |arg| types.push(arg) })
result = context.eval("const t = test(); type(typeof t); t")
assert_equal(result.class, big_int.class)
assert_equal(result, big_int)
}
if RUBY_ENGINE == "truffleruby"
assert_equal(types, %w[number number number number])
else
assert_equal(types, %w[number bigint number bigint])
end
end
end
Loading