Exception: MiniRacer::EvalError

Inherits:
Error
  • Object
show all
Defined in:
lib/mini_racer.rb,
ext/mini_racer_extension/mini_racer_extension.c

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Object



1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 1922

static VALUE context_initialize(int argc, VALUE *argv, VALUE self)
{
    VALUE kwargs, a, k, v;
    pthread_attr_t attr;
    const char *cause;
    pthread_t thr;
    Snapshot *ss;
    Context *c;
    char *s;
    int r;

    TypedData_Get_Struct(self, Context, &context_type, c);
    rb_scan_args(argc, argv, ":", &kwargs);
    if (NIL_P(kwargs))
        goto init;
    a = rb_ary_new();
    rb_hash_foreach(kwargs, collect, a);
    while (RARRAY_LENINT(a)) {
        v = rb_ary_pop(a);
        k = rb_ary_pop(a);
        k = rb_sym2str(k);
        s = RSTRING_PTR(k);
        if (!strcmp(s, "ensure_gc_after_idle")) {
            Check_Type(v, T_FIXNUM);
            c->idle_gc = FIX2LONG(v);
            if (c->idle_gc < 0 || c->idle_gc > INT32_MAX)
                rb_raise(rb_eArgError, "bad ensure_gc_after_idle");
        } else if (!strcmp(s, "max_memory")) {
            Check_Type(v, T_FIXNUM);
            c->max_memory = FIX2LONG(v);
            if (c->max_memory < 0 || c->max_memory >= UINT32_MAX)
                rb_raise(rb_eArgError, "bad max_memory");
        } else if (!strcmp(s, "marshal_stack_depth")) { // backcompat, ignored
            Check_Type(v, T_FIXNUM);
        } else if (!strcmp(s, "timeout")) {
            Check_Type(v, T_FIXNUM);
            c->timeout = FIX2LONG(v);
            if (c->timeout < 0 || c->timeout > INT32_MAX)
                rb_raise(rb_eArgError, "bad timeout");
        } else if (!strcmp(s, "snapshot")) {
            if (NIL_P(v))
                continue;
            TypedData_Get_Struct(v, Snapshot, &snapshot_type, ss);
            if (buf_put(&c->snapshot, RSTRING_PTR(ss->blob), RSTRING_LENINT(ss->blob)))
                rb_raise(runtime_error, "out of memory");
        } else if (!strcmp(s, "verbose_exceptions")) {
            c->verbose_exceptions = !(v == Qfalse || v == Qnil);
        } else {
            rb_raise(runtime_error, "bad keyword: %s", s);
        }
    }
init:
    if (single_threaded) {
        v8_once_init();
        c->pst = v8_thread_init(c, c->snapshot.buf, c->snapshot.len, c->max_memory, c->verbose_exceptions);
    } else {
        cause = "pthread_attr_init";
        if ((r = pthread_attr_init(&attr)))
            goto fail;
        pthread_attr_setstacksize(&attr, 2<<20); // 2 MiB
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        // v8 thread takes ownership of |c|
        cause = "pthread_create";
        r = pthread_create(&thr, &attr, v8_thread_start, c);
        pthread_attr_destroy(&attr);
        if (r)
            goto fail;
        barrier_wait(&c->early_init);
        barrier_wait(&c->late_init);
    }
    return Qnil;
fail:
    rb_raise(runtime_error, "Context.initialize: %s: %s", cause, strerror(r));
    return Qnil; // pacify compiler
}

Class Method Details

.load(blob) ⇒ Object



2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 2096

static VALUE snapshot_load(VALUE klass, VALUE blob)
{
    Snapshot *ss;
    VALUE self;

    Check_Type(blob, T_STRING);
    self = snapshot_alloc(klass);
    TypedData_Get_Struct(self, Snapshot, &snapshot_type, ss);
    ss->blob = rb_str_dup(blob);
    rb_enc_associate(ss->blob, rb_ascii8bit_encoding());
    ENC_CODERANGE_SET(ss->blob, ENC_CODERANGE_VALID);
    return self;
}

Instance Method Details

#attach(name, proc) ⇒ Object



1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 1563

static VALUE context_attach(VALUE self, VALUE name, VALUE proc)
{
    Context *c;
    VALUE e;
    Ser s;
    long id;

    TypedData_Get_Struct(self, Context, &context_type, c);
    id = RARRAY_LEN(c->procs);
    if (id > INT32_MAX)
        rb_raise(runtime_error, "too many callbacks");
    // request is (A)ttach, [name, id] array
    ser_init1(&s, 'A');
    ser_array_begin(&s, 2);
    add_string(&s, name);
    ser_int(&s, id);
    ser_array_end(&s, 2);
    rb_ary_push(c->procs, proc);
    // response is an exception or undefined
    e = rendezvous(c, &s.b);
    handle_exception(e);
    return Qnil;
}

#call(*args) ⇒ Object



1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 1658

static VALUE context_call(int argc, VALUE *argv, VALUE self)
{
    VALUE name, args;
    VALUE a, e;
    Context *c;
    Ser s;

    TypedData_Get_Struct(self, Context, &context_type, c);
    rb_scan_args(argc, argv, "1*", &name, &args);
    Check_Type(name, T_STRING);
    rb_ary_unshift(args, name);
    // request is (C)all, [name, args...] array
    ser_init1(&s, 'C');
    if (serialize(&s, args)) {
        ser_reset(&s);
        rb_raise(runtime_error, "Context.call: %s", s.err);
    }
    // response is [result, err] array
    a = rendezvous(c, &s.b); // takes ownership of |s.b|
    e = rb_ary_pop(a);
    handle_exception(e);
    return rb_ary_pop(a);
}

#disposeObject



1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 1633

static VALUE context_dispose(VALUE self)
{
    Context *c;
    void *r;

    TypedData_Get_Struct(self, Context, &context_type, c);
    r = rb_thread_call_without_gvl(context_dispose_do, c, terminate_ubf, c);
    if (r)
        rb_raise(runtime_error, "context dispose: %s", strerror((int)(intptr_t)r));
    return Qnil;
}

#dumpObject



2088
2089
2090
2091
2092
2093
2094
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 2088

static VALUE snapshot_dump(VALUE self)
{
    Snapshot *ss;

    TypedData_Get_Struct(self, Snapshot, &snapshot_type, ss);
    return ss->blob;
}

#eval(*args) ⇒ Object



1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 1682

static VALUE context_eval(int argc, VALUE *argv, VALUE self)
{
    VALUE a, e, source, filename, kwargs;
    Context *c;
    Ser s;

    TypedData_Get_Struct(self, Context, &context_type, c);
    filename = Qnil;
    rb_scan_args(argc, argv, "1:", &source, &kwargs);
    Check_Type(source, T_STRING);
    if (!NIL_P(kwargs))
        filename = rb_hash_aref(kwargs, rb_id2sym(rb_intern("filename")));
    if (NIL_P(filename))
        filename = rb_str_new_cstr("<eval>");
    Check_Type(filename, T_STRING);
    // request is (E)val, [filename, source] array
    ser_init1(&s, 'E');
    ser_array_begin(&s, 2);
    add_string(&s, filename);
    add_string(&s, source);
    ser_array_end(&s, 2);
    // response is [result, errname] array
    a = rendezvous(c, &s.b); // takes ownership of |s.b|
    e = rb_ary_pop(a);
    handle_exception(e);
    return rb_ary_pop(a);
}

#heap_snapshotObject



1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 1746

static VALUE context_heap_snapshot(VALUE self)
{
    Buf req, res;
    Context *c;

    TypedData_Get_Struct(self, Context, &context_type, c);
    buf_init(&req);
    buf_putc(&req, 'H');              // (H)eap snapshot, returns plain bytes
    rendezvous_no_des(c, &req, &res); // takes ownership of |req|
    return rb_ensure(heap_snapshot_to_str, (VALUE)&res,
                     buf_reset_ensure, (VALUE)&res);
}

#heap_statsObject



1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 1710

static VALUE context_heap_stats(VALUE self)
{
    VALUE a, h, k, v;
    Context *c;
    int i, n;
    Buf b;

    TypedData_Get_Struct(self, Context, &context_type, c);
    buf_init(&b);
    buf_putc(&b, 'S');     // (S)tats, returns object
    h = rendezvous(c, &b); // takes ownership of |b|
    a = rb_ary_new();
    rb_hash_foreach(h, collect, a);
    for (i = 0, n = RARRAY_LENINT(a); i < n; i += 2) {
        k = rb_ary_entry(a, i+0);
        v = rb_ary_entry(a, i+1);
        rb_hash_delete(h, k);
        rb_hash_aset(h, rb_str_intern(k), v); // turn "key" into :key
    }
    return h;
}

#low_memory_notificationObject

takes ownership of |b|



1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 1781

static VALUE context_low_memory_notification(VALUE self)
{
    Buf req, res;
    Context *c;

    TypedData_Get_Struct(self, Context, &context_type, c);
    buf_init(&req);
    buf_putc(&req, 'L');              // (L)ow memory notification, returns nothing
    rendezvous_no_des(c, &req, &res); // takes ownership of |req|
    buf_reset(&res);
    return Qnil;
}

#perform_microtask_checkpointObject



1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 1759

static VALUE context_perform_microtask_checkpoint(VALUE self)
{
    Context *c;
    Buf b;

    TypedData_Get_Struct(self, Context, &context_type, c);
    buf_init(&b);
    buf_putc(&b, 'M');        // (M)icrotask checkpoint, returns nil
    return rendezvous(c, &b); // takes ownership of |b|
}

#pump_message_loopObject

takes ownership of |b|



1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 1770

static VALUE context_pump_message_loop(VALUE self)
{
    Context *c;
    Buf b;

    TypedData_Get_Struct(self, Context, &context_type, c);
    buf_init(&b);
    buf_putc(&b, 'P');        // (P)ump, returns bool
    return rendezvous(c, &b); // takes ownership of |b|
}

#sizeObject



2110
2111
2112
2113
2114
2115
2116
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 2110

static VALUE snapshot_size0(VALUE self)
{
    Snapshot *ss;

    TypedData_Get_Struct(self, Snapshot, &snapshot_type, ss);
    return LONG2FIX(RSTRING_LENINT(ss->blob));
}

#stopObject



1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 1645

static VALUE context_stop(VALUE self)
{
    Context *c;

    // does not grab |mtx| because Context.stop can be called from another
    // thread and then we deadlock if e.g. the V8 thread busy-loops in JS
    TypedData_Get_Struct(self, Context, &context_type, c);
    if (atomic_load(&c->quit))
        rb_raise(context_disposed_error, "disposed context");
    v8_terminate_execution(c->pst);
    return Qnil;
}

#warmup!(arg) ⇒ Object



2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
# File 'ext/mini_racer_extension/mini_racer_extension.c', line 2058

static VALUE snapshot_warmup(VALUE self, VALUE arg)
{
    VALUE a, e, cv;
    Snapshot *ss;
    Context *c;
    DesCtx d;
    Ser s;

    TypedData_Get_Struct(self, Snapshot, &snapshot_type, ss);
    Check_Type(arg, T_STRING);
    cv = context_alloc(context_class);
    context_initialize(0, NULL, cv);
    TypedData_Get_Struct(cv, Context, &context_type, c);
    // request is (W)armup, [snapshot, "warmup code"]
    ser_init1(&s, 'W');
    ser_array_begin(&s, 2);
    ser_string8(&s, (const uint8_t *)RSTRING_PTR(ss->blob), RSTRING_LENINT(ss->blob));
    add_string(&s, arg);
    ser_array_end(&s, 2);
    // response is [arraybuffer, error]
    DesCtx_init(&d);
    d.transcode_latin1 = 0; // don't mangle snapshot binary data
    a = rendezvous1(c, &s.b, &d);
    e = rb_ary_pop(a);
    context_dispose(cv);
    raise_exception_with_message(snapshot_error, e);
    ss->blob = rb_ary_pop(a);
    return self;
}