duk_ret_t duk_bi_duktape_object_act(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_activation *act; duk_hobject *h_func; duk_uint_fast32_t pc; duk_uint_fast32_t line; duk_int_t level; /* -1 = top callstack entry, callstack[callstack_top - 1] * -callstack_top = bottom callstack entry, callstack[0] */ level = duk_to_int(ctx, 0); if (level >= 0 || -level > (duk_int_t) thr->callstack_top) { return 0; } DUK_ASSERT(level >= -((duk_int_t) thr->callstack_top) && level <= -1); act = thr->callstack + thr->callstack_top + level; duk_push_object(ctx); h_func = act->func; DUK_ASSERT(h_func != NULL); duk_push_hobject(ctx, h_func); pc = (duk_uint_fast32_t) act->pc; duk_push_int(ctx, (int) pc); /* FIXME: typing */ line = duk_hobject_pc2line_query(ctx, -2, pc); duk_push_int(ctx, (int) line); /* FIXME: typing */ /* Providing access to e.g. act->lex_env would be dangerous: these * internal structures must never be accessible to the application. * Duktape relies on them having consistent data, and this consistency * is only asserted for, not checked for. */ /* [ level obj func pc line ] */ /* FIXME: version specific array format instead? */ duk_def_prop_stridx_wec(ctx, -4, DUK_STRIDX_LINE_NUMBER); duk_def_prop_stridx_wec(ctx, -3, DUK_STRIDX_PC); duk_def_prop_stridx_wec(ctx, -2, DUK_STRIDX_LC_FUNCTION); return 1; }
static void duk__add_traceback(duk_hthread *thr, duk_hthread *thr_callstack, const char *filename, duk_int_t line, duk_bool_t noblame_fileline) { duk_context *ctx = (duk_context *) thr; duk_small_uint_t depth; duk_int_t i, i_min; duk_uarridx_t arr_idx; duk_double_t d; DUK_ASSERT(thr != NULL); DUK_ASSERT(thr_callstack != NULL); DUK_ASSERT(ctx != NULL); /* [ ... error ] */ /* * The traceback format is pretty arcane in an attempt to keep it compact * and cheap to create. It may change arbitrarily from version to version. * It should be decoded/accessed through version specific accessors only. * * See doc/error-objects.txt. */ DUK_DDD(DUK_DDDPRINT("adding traceback to object: %!T", (duk_tval *) duk_get_tval(ctx, -1))); duk_push_array(ctx); /* XXX: specify array size, as we know it */ arr_idx = 0; /* filename/line from C macros (__FILE__, __LINE__) are added as an * entry with a special format: (string, number). The number contains * the line and flags. */ /* XXX: optimize: allocate an array part to the necessary size (upwards * estimate) and fill in the values directly into the array part; finally * update 'length'. */ /* XXX: using duk_put_prop_index() would cause obscure error cases when Array.prototype * has write-protected array index named properties. This was seen as DoubleErrors * in e.g. some test262 test cases. Using duk_def_prop_index() is better but heavier. * The best fix is to fill in the tracedata directly into the array part. */ /* [ ... error arr ] */ if (filename) { duk_push_string(ctx, filename); duk_def_prop_index_wec(ctx, -2, arr_idx); arr_idx++; d = (noblame_fileline ? ((duk_double_t) DUK_TB_FLAG_NOBLAME_FILELINE) * DUK_DOUBLE_2TO32 : 0.0) + (duk_double_t) line; duk_push_number(ctx, d); duk_def_prop_index_wec(ctx, -2, arr_idx); arr_idx++; } /* traceback depth doesn't take into account the filename/line * special handling above (intentional) */ depth = DUK_USE_TRACEBACK_DEPTH; i_min = (thr_callstack->callstack_top > (duk_size_t) depth ? (duk_int_t) (thr_callstack->callstack_top - depth) : 0); DUK_ASSERT(i_min >= 0); /* [ ... error arr ] */ DUK_ASSERT(thr_callstack->callstack_top <= DUK_INT_MAX); /* callstack limits */ for (i = (duk_int_t) (thr_callstack->callstack_top - 1); i >= i_min; i--) { duk_uint32_t pc; /* * Note: each API operation potentially resizes the callstack, * so be careful to re-lookup after every operation. Currently * these is no issue because we don't store a temporary 'act' * pointer at all. (This would be a non-issue if we operated * directly on the array part.) */ /* [... arr] */ DUK_ASSERT(thr_callstack->callstack[i].func != NULL); DUK_ASSERT_DISABLE(thr_callstack->callstack[i].pc >= 0); /* unsigned */ /* add function */ duk_push_hobject(ctx, thr_callstack->callstack[i].func); /* -> [... arr func] */ duk_def_prop_index_wec(ctx, -2, arr_idx); arr_idx++; /* add a number containing: pc, activation flags */ /* Add a number containing: pc, activation flag * * PC points to next instruction, find offending PC. Note that * PC == 0 for native code. */ pc = thr_callstack->callstack[i].pc; if (pc > 0) { pc--; } DUK_ASSERT_DISABLE(pc >= 0); /* unsigned */ DUK_ASSERT((duk_double_t) pc < DUK_DOUBLE_2TO32); /* assume PC is at most 32 bits and non-negative */ d = ((duk_double_t) thr_callstack->callstack[i].flags) * DUK_DOUBLE_2TO32 + (duk_double_t) pc; duk_push_number(ctx, d); /* -> [... arr num] */ duk_def_prop_index_wec(ctx, -2, arr_idx); arr_idx++; } /* XXX: set with duk_hobject_set_length() when tracedata is filled directly */ duk_push_uint(ctx, (duk_uint_t) arr_idx); duk_def_prop_stridx(ctx, -2, DUK_STRIDX_LENGTH, DUK_PROPDESC_FLAGS_WC); /* [ ... error arr ] */ duk_def_prop_stridx_wec(ctx, -2, DUK_STRIDX_TRACEDATA); /* -> [ ... error ] */ }