Reduce allocation size of backtrace arrays.
MODIFY
src/backtrace.c
src/backtrace.c
@@ -93,6 +93,20 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace)
}
}
+static int
+packed_bt_len(struct backtrace_location *bt, int n)
+{
+ int len = 0;
+ int i;
+
+ for (i=0; i<n; i++) {
+ if (!bt[i].filename && !bt[i].lineno && !bt[i].method_id)
+ continue;
+ len++;
+ }
+ return len;
+}
+
static void
print_packed_backtrace(mrb_state *mrb, mrb_value packed)
{
@@ -102,11 +116,10 @@ print_packed_backtrace(mrb_state *mrb, mrb_value packed)
int ai = mrb_gc_arena_save(mrb);
bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, packed, &bt_type);
- if (bt == NULL) {
- mrb_raise(mrb, E_RUNTIME_ERROR, "broken backtrace");
- }
+ if (bt == NULL) return;
n = (mrb_int)RDATA(packed)->flags;
+ if (packed_bt_len(bt, n) == 0) return;
fprintf(stream, "trace:\n");
for (i = 0; i<n; i++) {
struct backtrace_location *entry = &bt[n-i-1];
@@ -155,15 +168,30 @@ mrb_print_backtrace(mrb_state *mrb)
#endif
+static void
+count_backtrace_i(mrb_state *mrb,
+ int i,
+ struct backtrace_location *loc,
+ void *data)
+{
+ int *lenp = (int*)data;
+
+ if (loc->filename == NULL) return;
+ (*lenp)++;
+}
+
static void
pack_backtrace_i(mrb_state *mrb,
int i,
struct backtrace_location *loc,
void *data)
{
- struct backtrace_location *entry = (struct backtrace_location*)data;
+ struct backtrace_location **pptr = (struct backtrace_location**)data;
+ struct backtrace_location *ptr = *pptr;
- entry[i] = *loc;
+ if (loc->filename == NULL) return;
+ *ptr = *loc;
+ *pptr = ptr+1;
}
static mrb_value
@@ -171,14 +199,17 @@ packed_backtrace(mrb_state *mrb)
{
struct RData *backtrace;
ptrdiff_t ciidx = mrb->c->ci - mrb->c->cibase;
- mrb_int len = (ciidx+1)*sizeof(struct backtrace_location);
+ int len = 0;
+ int size;
void *ptr;
- ptr = mrb_malloc(mrb, len);
- memset(ptr, 0, len);
+ each_backtrace(mrb, ciidx, mrb->c->ci->pc, count_backtrace_i, &len);
+ size = len * sizeof(struct backtrace_location);
+ ptr = mrb_malloc(mrb, size);
+ memset(ptr, 0, size);
backtrace = mrb_data_object_alloc(mrb, NULL, ptr, &bt_type);
- backtrace->flags = (unsigned int)ciidx+1;
- each_backtrace(mrb, ciidx, mrb->c->ci->pc, pack_backtrace_i, ptr);
+ backtrace->flags = (unsigned int)len;
+ each_backtrace(mrb, ciidx, mrb->c->ci->pc, pack_backtrace_i, &ptr);
return mrb_obj_value(backtrace);
}
@@ -200,12 +231,13 @@ mrb_unpack_backtrace(mrb_state *mrb, mrb_value backtrace)
mrb_int n, i;
int ai;
- if (mrb_nil_p(backtrace)) return mrb_ary_new_capa(mrb, 0);
+ if (mrb_nil_p(backtrace)) {
+ empty_backtrace:
+ return mrb_ary_new_capa(mrb, 0);
+ }
if (mrb_array_p(backtrace)) return backtrace;
bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, backtrace, &bt_type);
- if (bt == NULL) {
- mrb_raise(mrb, E_RUNTIME_ERROR, "broken backtrace");
- }
+ if (bt == NULL) goto empty_backtrace;
n = (mrb_int)RDATA(backtrace)->flags;
backtrace = mrb_ary_new_capa(mrb, n);
ai = mrb_gc_arena_save(mrb);

Reduce allocation size of backtrace arrays.