DUK_INTERNAL void duk_default_panic_handler(duk_errcode_t code, const char *msg) { #ifdef DUK_USE_FILE_IO DUK_FPRINTF(DUK_STDERR, "PANIC %ld: %s (" #if defined(DUK_USE_PANIC_ABORT) "calling abort" #elif defined(DUK_USE_PANIC_EXIT) "calling exit" #elif defined(DUK_USE_PANIC_SEGFAULT) "segfaulting on purpose" #else #error no DUK_USE_PANIC_xxx macro defined #endif ")\n", (long) code, (const char *) (msg ? msg : "null")); DUK_FFLUSH(DUK_STDERR); #else /* omit print */ DUK_UNREF(code); DUK_UNREF(msg); #endif #if defined(DUK_USE_PANIC_ABORT) DUK_ABORT(); #elif defined(DUK_USE_PANIC_EXIT) DUK_EXIT(-1); #elif defined(DUK_USE_PANIC_SEGFAULT) /* exit() afterwards to satisfy "noreturn" */ DUK_CAUSE_SEGFAULT(); /* SCANBUILD: "Dereference of null pointer", normal */ DUK_EXIT(-1); #else #error no DUK_USE_PANIC_xxx macro defined #endif DUK_UNREACHABLE(); }
static void duk__free_hobject_inner(duk_heap *heap, duk_hobject *h) { DUK_ASSERT(heap != NULL); DUK_ASSERT(h != NULL); DUK_FREE(heap, h->p); if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) { duk_hcompiledfunction *f = (duk_hcompiledfunction *) h; DUK_UNREF(f); /* Currently nothing to free; 'data' is a heap object */ } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) { duk_hnativefunction *f = (duk_hnativefunction *) h; DUK_UNREF(f); /* Currently nothing to free */ } else if (DUK_HOBJECT_IS_THREAD(h)) { duk_hthread *t = (duk_hthread *) h; DUK_FREE(heap, t->valstack); DUK_FREE(heap, t->callstack); DUK_FREE(heap, t->catchstack); /* Don't free h->resumer because it exists in the heap. * Callstack entries also contain function pointers which * are not freed for the same reason. */ /* XXX: with 'caller' property the callstack would need * to be unwound to update the 'caller' properties of * functions in the callstack. */ } }
DUK_LOCAL void duk__mark_hstring(duk_heap *heap, duk_hstring *h) { DUK_UNREF(heap); DUK_UNREF(h); DUK_DDD(DUK_DDDPRINT("duk__mark_hstring: %p", (void *) h)); DUK_ASSERT(h); /* nothing to process */ }
DUK_INTERNAL void duk_free_hstring_inner(duk_heap *heap, duk_hstring *h) { DUK_ASSERT(heap != NULL); DUK_ASSERT(h != NULL); DUK_UNREF(heap); DUK_UNREF(h); #if defined(DUK_USE_HSTRING_EXTDATA) && defined(DUK_USE_EXTSTR_FREE) if (DUK_HSTRING_HAS_EXTDATA(h)) { DUK_DDD(DUK_DDDPRINT("free extstr: hstring %!O, extdata: %p", h, DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h))); DUK_USE_EXTSTR_FREE((const void *) DUK_HSTRING_GET_EXTDATA((duk_hstring_external *) h)); } #endif }
/* Shared helper to implement Object.getPrototypeOf and the ES6 * Object.prototype.__proto__ getter. * * http://www.ecma-international.org/ecma-262/6.0/index.html#sec-get-object.prototype.__proto__ */ DUK_INTERNAL duk_ret_t duk_bi_object_getprototype_shared(duk_context *ctx) { duk_hthread *thr = (duk_hthread *) ctx; duk_hobject *h; duk_hobject *proto; DUK_UNREF(thr); /* magic: 0=getter call, 1=Object.getPrototypeOf */ if (duk_get_current_magic(ctx) == 0) { duk_push_this_coercible_to_object(ctx); duk_insert(ctx, 0); } h = duk_require_hobject_or_lfunc(ctx, 0); /* h is NULL for lightfunc */ /* XXX: should the API call handle this directly, i.e. attempt * to duk_push_hobject(ctx, null) would push a null instead? * (On the other hand 'undefined' would be just as logical, but * not wanted here.) */ if (h == NULL) { duk_push_hobject_bidx(ctx, DUK_BIDX_FUNCTION_PROTOTYPE); } else { proto = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); if (proto) { duk_push_hobject(ctx, proto); } else { duk_push_null(ctx); } } return 1; }
DUK_EXTERNAL duk_double_t duk_components_to_time(duk_context *ctx, duk_time_components *comp) { duk_double_t d; duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; duk_uint_t flags; DUK_ASSERT(ctx != NULL); DUK_ASSERT(comp != NULL); /* XXX: or check? */ DUK_UNREF(ctx); /* Match Date constructor behavior (with UTC time). Month is given * as zero-based. Day-of-month is given as one-based so normalize * it to zero-based as the internal conversion helpers expects all * components to be zero-based. */ flags = 0; /* XXX: expensive conversion; use array format in API instead, or unify * time provider and time API to use same struct? */ dparts[DUK_DATE_IDX_YEAR] = comp->year; dparts[DUK_DATE_IDX_MONTH] = comp->month; dparts[DUK_DATE_IDX_DAY] = comp->day - 1.0; dparts[DUK_DATE_IDX_HOUR] = comp->hours; dparts[DUK_DATE_IDX_MINUTE] = comp->minutes; dparts[DUK_DATE_IDX_SECOND] = comp->seconds; dparts[DUK_DATE_IDX_MILLISECOND] = comp->milliseconds; dparts[DUK_DATE_IDX_WEEKDAY] = 0; /* ignored */ d = duk_bi_date_get_timeval_from_dparts(dparts, flags); return d; }
DUK_EXTERNAL void duk_time_to_components(duk_context *ctx, duk_double_t timeval, duk_time_components *comp) { duk_int_t parts[DUK_DATE_IDX_NUM_PARTS]; duk_double_t dparts[DUK_DATE_IDX_NUM_PARTS]; duk_uint_t flags; DUK_ASSERT(ctx != NULL); DUK_ASSERT(comp != NULL); /* XXX: or check? */ DUK_UNREF(ctx); /* Convert as one-based, but change month to zero-based to match the * Ecmascript Date built-in behavior 1:1. */ flags = DUK_DATE_FLAG_ONEBASED | DUK_DATE_FLAG_NAN_TO_ZERO; duk_bi_date_timeval_to_parts(timeval, parts, dparts, flags); DUK_ASSERT(dparts[DUK_DATE_IDX_MONTH] >= 1.0 && dparts[DUK_DATE_IDX_MONTH] <= 12.0); comp->year = dparts[DUK_DATE_IDX_YEAR]; comp->month = dparts[DUK_DATE_IDX_MONTH] - 1.0; comp->day = dparts[DUK_DATE_IDX_DAY]; comp->hours = dparts[DUK_DATE_IDX_HOUR]; comp->minutes = dparts[DUK_DATE_IDX_MINUTE]; comp->seconds = dparts[DUK_DATE_IDX_SECOND]; comp->milliseconds = dparts[DUK_DATE_IDX_MILLISECOND]; comp->weekday = dparts[DUK_DATE_IDX_WEEKDAY]; }
DUK_EXTERNAL void duk_debugger_cooperate(duk_context *ctx) { duk_hthread *thr; duk_bool_t processed_messages; thr = (duk_hthread *) ctx; DUK_ASSERT(ctx != NULL); DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); if (!DUK_HEAP_IS_DEBUGGER_ATTACHED(thr->heap)) { return; } if (thr->callstack_top > 0 || thr->heap->dbg_processing) { /* Calling duk_debugger_cooperate() while Duktape is being * called into is not supported. This is not a 100% check * but prevents any damage in most cases. */ return; } thr->heap->dbg_processing = 1; processed_messages = duk_debug_process_messages(thr, 1 /*no_block*/); thr->heap->dbg_processing = 0; DUK_UNREF(processed_messages); }
DUK_LOCAL duk_ret_t duk__finalize_helper(duk_context *ctx, void *udata) { duk_hthread *thr; DUK_ASSERT(ctx != NULL); thr = (duk_hthread *) ctx; DUK_UNREF(udata); DUK_DDD(DUK_DDDPRINT("protected finalization helper running")); /* [... obj] */ /* XXX: Finalizer lookup should traverse the prototype chain (to allow * inherited finalizers) but should not invoke accessors or proxy object * behavior. At the moment this lookup will invoke proxy behavior, so * caller must ensure that this function is not called if the target is * a Proxy. */ duk_get_prop_stridx_short(ctx, -1, DUK_STRIDX_INT_FINALIZER); /* -> [... obj finalizer] */ if (!duk_is_callable(ctx, -1)) { DUK_DDD(DUK_DDDPRINT("-> no finalizer or finalizer not callable")); return 0; } duk_dup_m2(ctx); duk_push_boolean(ctx, DUK_HEAP_HAS_FINALIZER_NORESCUE(thr->heap)); DUK_DDD(DUK_DDDPRINT("-> finalizer found, calling finalizer")); duk_call(ctx, 2); /* [ ... obj finalizer obj heapDestruct ] -> [ ... obj retval ] */ DUK_DDD(DUK_DDDPRINT("finalizer finished successfully")); return 0; /* Note: we rely on duk_safe_call() to fix up the stack for the caller, * so we don't need to pop stuff here. There is no return value; * caller determines rescued status based on object refcount. */ }
int duk_bi_error_prototype_nop_setter(duk_context *ctx) { /* Attempt to write 'stack', 'fileName', 'lineNumber' is a silent no-op. * User can use Object.defineProperty() to override this behavior. */ DUK_ASSERT_TOP(ctx, 1); /* fixed arg count */ DUK_UNREF(ctx); return 0; }
DUK_LOCAL int duk__protected_compact_object(duk_context *ctx, void *udata) { duk_hobject *obj; /* XXX: for threads, compact value stack, call stack, catch stack? */ DUK_UNREF(udata); obj = duk_known_hobject(ctx, -1); duk_hobject_compact_props((duk_hthread *) ctx, obj); return 0; }
DUK_LOCAL void duk__get_this_regexp(duk_hthread *thr) { duk_hobject *h; duk_push_this(thr); h = duk_require_hobject_with_class(thr, -1, DUK_HOBJECT_CLASS_REGEXP); DUK_ASSERT(h != NULL); DUK_UNREF(h); duk_insert(thr, 0); /* prepend regexp to valstack 0 index */ }
/* Default function to write a formatted log line. Writes to stderr, * appending a newline to the log line. * * The argument is a buffer whose visible size contains the log message. * This function should avoid coercing the buffer to a string to avoid * string table traffic. */ DUK_INTERNAL duk_ret_t duk_bi_logger_prototype_raw(duk_context *ctx) { const char *data; duk_size_t data_len; DUK_UNREF(ctx); DUK_UNREF(data); DUK_UNREF(data_len); #ifdef DUK_USE_FILE_IO data = (const char *) duk_require_buffer(ctx, 0, &data_len); DUK_FWRITE((const void *) data, 1, data_len, DUK_STDERR); DUK_FPUTC((int) '\n', DUK_STDERR); DUK_FFLUSH(DUK_STDERR); #else /* nop */ #endif return 0; }
/* * String comparison (E5 Section 11.8.5, step 4), which * needs to compare codepoint by codepoint. * * However, UTF-8 allows us to use strcmp directly: the shared * prefix will be encoded identically (UTF-8 has unique encoding) * and the first differing character can be compared with a simple * unsigned byte comparison (which strcmp does). * * This will not work properly for non-xutf-8 strings, but this * is not an issue for compliance. */ DUK_ASSERT(h1 != NULL); DUK_ASSERT(h2 != NULL); return duk_js_data_compare((const duk_uint8_t *) DUK_HSTRING_GET_DATA(h1), (const duk_uint8_t *) DUK_HSTRING_GET_DATA(h2), (duk_size_t) DUK_HSTRING_GET_BYTELEN(h1), (duk_size_t) DUK_HSTRING_GET_BYTELEN(h2)); } #if 0 /* unused */ DUK_INTERNAL duk_small_int_t duk_js_buffer_compare(duk_heap *heap, duk_hbuffer *h1, duk_hbuffer *h2) { /* Similar to String comparison. */ DUK_ASSERT(h1 != NULL); DUK_ASSERT(h2 != NULL); DUK_UNREF(heap); return duk_js_data_compare((const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h1), (const duk_uint8_t *) DUK_HBUFFER_GET_DATA_PTR(heap, h2), (duk_size_t) DUK_HBUFFER_GET_SIZE(h1), (duk_size_t) DUK_HBUFFER_GET_SIZE(h2)); }
DUK_INTERNAL void duk_default_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg) { DUK_UNREF(ctx); #ifdef DUK_USE_FILE_IO DUK_FPRINTF(DUK_STDERR, "FATAL %ld: %s\n", (long) code, (const char *) (msg ? msg : "null")); DUK_FFLUSH(DUK_STDERR); #else /* omit print */ #endif DUK_D(DUK_DPRINT("default fatal handler called, code %ld -> calling DUK_PANIC()", (long) code)); DUK_PANIC(code, msg); DUK_UNREACHABLE(); }
DUK_INTERNAL void duk_heap_force_strtab_resize(duk_heap *heap) { /* Force a resize so that DELETED entries are eliminated. * Another option would be duk__recheck_strtab_size_probe(); * but since that happens on every intern anyway, this whole * check can now be disabled. */ #if defined(DUK_USE_STRTAB_CHAIN) DUK_UNREF(heap); #elif defined(DUK_USE_STRTAB_PROBE) duk__resize_strtab_probe(heap); #endif }
DUK_LOCAL void duk__run_voluntary_gc(duk_heap *heap) { if (DUK_HEAP_HAS_MARKANDSWEEP_RUNNING(heap)) { DUK_DD(DUK_DDPRINT("mark-and-sweep in progress -> skip voluntary mark-and-sweep now")); } else { duk_small_uint_t flags; duk_bool_t rc; DUK_D(DUK_DPRINT("triggering voluntary mark-and-sweep")); flags = 0; rc = duk_heap_mark_and_sweep(heap, flags); DUK_UNREF(rc); } }
static void free_hobject_inner(duk_heap *heap, duk_hobject *h) { DUK_ASSERT(heap != NULL); DUK_ASSERT(h != NULL); DUK_FREE(heap, h->p); if (DUK_HOBJECT_IS_COMPILEDFUNCTION(h)) { duk_hcompiledfunction *f = (duk_hcompiledfunction *) h; DUK_UNREF(f); /* Currently nothing to free; 'data' is a heap object */ } else if (DUK_HOBJECT_IS_NATIVEFUNCTION(h)) { duk_hnativefunction *f = (duk_hnativefunction *) h; DUK_UNREF(f); /* Currently nothing to free */ } else if (DUK_HOBJECT_IS_THREAD(h)) { duk_hthread *t = (duk_hthread *) h; DUK_FREE(heap, t->valstack); DUK_FREE(heap, t->callstack); DUK_FREE(heap, t->catchstack); /* don't free h->resumer, because it exists in the heap */ } }
DUK_LOCAL void duk__dump_indented(duk_heaphdr *obj, int index) { DUK_UNREF(obj); DUK_UNREF(index); DUK_UNREF(duk__get_heap_type_string); #ifdef DUK_USE_REFERENCE_COUNTING DUK_D(DUK_DPRINT(" [%ld]: %p %s (flags: 0x%08lx, ref: %ld) -> %!O", (long) index, (void *) obj, (const char *) duk__get_heap_type_string(obj), (unsigned long) DUK_HEAPHDR_GET_FLAGS(obj), (long) DUK_HEAPHDR_GET_REFCOUNT(obj), (duk_heaphdr *) obj)); #else DUK_D(DUK_DPRINT(" [%ld]: %p %s (flags: 0x%08lx) -> %!O", (long) index, (void *) obj, (const char *) duk__get_heap_type_string(obj), (unsigned long) DUK_HEAPHDR_GET_FLAGS(obj), (duk_heaphdr *) obj)); #endif }
DUK_LOCAL duk_ret_t duk__refcount_fake_finalizer(duk_context *ctx) { DUK_UNREF(ctx); DUK_D(DUK_DPRINT("fake refcount torture finalizer executed")); #if 0 DUK_DD(DUK_DDPRINT("fake torture finalizer for: %!T", duk_get_tval(ctx, 0))); #endif /* Require a lot of stack to force a value stack grow/shrink. */ duk_require_stack(ctx, 100000); /* XXX: do something to force a callstack grow/shrink, perhaps * just a manual forced resize? */ return 0; }
DUK_EXTERNAL void duk_gc(duk_context *ctx, duk_uint_t flags) { #ifdef DUK_USE_MARK_AND_SWEEP duk_hthread *thr = (duk_hthread *) ctx; duk_heap *heap; DUK_UNREF(flags); /* NULL accepted */ if (!ctx) { return; } DUK_ASSERT_CTX_VALID(ctx); heap = thr->heap; DUK_ASSERT(heap != NULL); DUK_D(DUK_DPRINT("mark-and-sweep requested by application")); duk_heap_mark_and_sweep(heap, 0); #else DUK_D(DUK_DPRINT("mark-and-sweep requested by application but mark-and-sweep not enabled, ignoring")); DUK_UNREF(ctx); DUK_UNREF(flags); #endif }
DUK_INTERNAL duk_uint_fast32_t duk_hthread_get_act_curr_pc(duk_hthread *thr, duk_activation *act) { duk_instr_t *bcode; DUK_ASSERT(thr != NULL); DUK_ASSERT(act != NULL); DUK_UNREF(thr); /* XXX: store 'bcode' pointer to activation for faster lookup? */ if (act->func && DUK_HOBJECT_IS_COMPFUNC(act->func)) { bcode = DUK_HCOMPFUNC_GET_CODE_BASE(thr->heap, (duk_hcompfunc *) (act->func)); return (duk_uint_fast32_t) (act->curr_pc - bcode); } return 0; }
DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start, duk_size_t *p_count_check, duk_size_t *p_count_compact, duk_size_t *p_count_bytes_saved) { #else DUK_LOCAL void duk__compact_object_list(duk_heap *heap, duk_hthread *thr, duk_heaphdr *start) { #endif duk_heaphdr *curr; #if defined(DUK_USE_DEBUG) duk_size_t old_size, new_size; #endif duk_hobject *obj; DUK_UNREF(heap); curr = start; while (curr) { DUK_DDD(DUK_DDDPRINT("mark-and-sweep compact: %p", (void *) curr)); if (DUK_HEAPHDR_GET_TYPE(curr) != DUK_HTYPE_OBJECT) { goto next; } obj = (duk_hobject *) curr; #if defined(DUK_USE_DEBUG) old_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj), DUK_HOBJECT_GET_ASIZE(obj), DUK_HOBJECT_GET_HSIZE(obj)); #endif DUK_DD(DUK_DDPRINT("compact object: %p", (void *) obj)); duk_push_hobject((duk_context *) thr, obj); /* XXX: disable error handlers for duration of compaction? */ duk_safe_call((duk_context *) thr, duk__protected_compact_object, NULL, 1, 0); #if defined(DUK_USE_DEBUG) new_size = DUK_HOBJECT_P_COMPUTE_SIZE(DUK_HOBJECT_GET_ESIZE(obj), DUK_HOBJECT_GET_ASIZE(obj), DUK_HOBJECT_GET_HSIZE(obj)); #endif #if defined(DUK_USE_DEBUG) (*p_count_compact)++; (*p_count_bytes_saved) += (duk_size_t) (old_size - new_size); #endif next: curr = DUK_HEAPHDR_GET_NEXT(heap, curr); #if defined(DUK_USE_DEBUG) (*p_count_check)++; #endif } }
DUK_LOCAL void duk__err_augment_builtin_create(duk_hthread *thr, duk_hthread *thr_callstack, const char *c_filename, duk_int_t c_line, duk_small_int_t noblame_fileline, duk_hobject *obj) { duk_context *ctx = (duk_context *) thr; #if defined(DUK_USE_ASSERTIONS) duk_int_t entry_top; #endif #if defined(DUK_USE_ASSERTIONS) entry_top = duk_get_top(ctx); #endif DUK_ASSERT(obj != NULL); DUK_UNREF(obj); /* unreferenced w/o tracebacks */ DUK_UNREF(ctx); /* unreferenced w/o asserts */ duk__add_compiler_error_line(thr); #if defined(DUK_USE_TRACEBACKS) /* If tracebacks are enabled, the '_Tracedata' property is the only * thing we need: 'fileName' and 'lineNumber' are virtual properties * which use '_Tracedata'. */ if (duk_hobject_hasprop_raw(thr, obj, DUK_HTHREAD_STRING_INT_TRACEDATA(thr))) { DUK_DDD(DUK_DDDPRINT("error value already has a '_Tracedata' property, not modifying it")); } else { duk__add_traceback(thr, thr_callstack, c_filename, c_line, noblame_fileline); } #else /* Without tracebacks the concrete .fileName and .lineNumber need * to be added directly. */ duk__add_fileline(thr, thr_callstack, c_filename, c_line, noblame_fileline); #endif #if defined(DUK_USE_ASSERTIONS) DUK_ASSERT(duk_get_top(ctx) == entry_top); #endif }
static void duk__call_errhandler(duk_hthread *thr) { int call_flags; int rc; DUK_ASSERT(thr != NULL); DUK_ASSERT(thr->heap != NULL); if (!thr->heap->lj.errhandler) { DUK_DDDPRINT("no errhandler, return"); return; } /* FIXME: assert/require for valstack space */ /* [ ... errval ] */ DUK_DDDPRINT("errhandler is %p", (void *) thr->heap->lj.errhandler); DUK_DDDPRINT("errhandler dump: %!O", (duk_heaphdr *) thr->heap->lj.errhandler); duk_push_hobject((duk_context *) thr, thr->heap->lj.errhandler); duk_insert((duk_context *) thr, -2); /* -> [ ... errhandler errval ] */ duk_push_undefined((duk_context *) thr); duk_insert((duk_context *) thr, -2); /* -> [ ... errhandler undefined(= this) errval ] */ /* [ ... errhandler undefined errval ] */ /* * DUK_CALL_FLAG_IGNORE_RECLIMIT causes duk_handle_call() to ignore C * recursion depth limit (and won't increase it either). This is * dangerous, but useful because it allows an errhandler to run even * if the original error is caused by C recursion depth limit. Because * errhandler is NULL in the errhandler call, the errhandler call * can't cause the same situation to occur again. * * We ignore errors now: a success return and an error value both * replace the original error value. (This would be easy to change.) */ call_flags = DUK_CALL_FLAG_PROTECTED | DUK_CALL_FLAG_IGNORE_RECLIMIT; /* protected, ignore reclimit, not constructor */ rc = duk_handle_call(thr, 1, /* num args */ call_flags, /* call_flags */ NULL); /* errhandler */ DUK_UNREF(rc); /* no need to check now: both success and error are OK */ /* [ ... errval ] */ }
DUK_INTERNAL duk_bool_t duk_bi_date_format_parts_strftime(duk_context *ctx, duk_int_t *parts, duk_int_t tzoffset, duk_small_uint_t flags) { char buf[DUK__STRFTIME_BUF_SIZE]; struct tm tm; const char *fmt; DUK_UNREF(tzoffset); /* If the platform doesn't support the entire Ecmascript range, we need * to return 0 so that the caller can fall back to the default formatter. * * For now, assume that if time_t is 8 bytes or more, the whole Ecmascript * range is supported. For smaller time_t values (4 bytes in practice), * assumes that the signed 32-bit range is supported. * * XXX: detect this more correctly per platform. The size of time_t is * probably not an accurate guarantee of strftime() supporting or not * supporting a large time range (the full Ecmascript range). */ if (sizeof(time_t) < 8 && (parts[DUK_DATE_IDX_YEAR] < 1970 || parts[DUK_DATE_IDX_YEAR] > 2037)) { /* be paranoid for 32-bit time values (even avoiding negative ones) */ return 0; } DUK_MEMZERO(&tm, sizeof(tm)); tm.tm_sec = parts[DUK_DATE_IDX_SECOND]; tm.tm_min = parts[DUK_DATE_IDX_MINUTE]; tm.tm_hour = parts[DUK_DATE_IDX_HOUR]; tm.tm_mday = parts[DUK_DATE_IDX_DAY]; /* already one-based */ tm.tm_mon = parts[DUK_DATE_IDX_MONTH] - 1; /* one-based -> zero-based */ tm.tm_year = parts[DUK_DATE_IDX_YEAR] - 1900; tm.tm_wday = parts[DUK_DATE_IDX_WEEKDAY]; tm.tm_isdst = 0; DUK_MEMZERO(buf, sizeof(buf)); if ((flags & DUK_DATE_FLAG_TOSTRING_DATE) && (flags & DUK_DATE_FLAG_TOSTRING_TIME)) { fmt = "%c"; } else if (flags & DUK_DATE_FLAG_TOSTRING_DATE) { fmt = "%x"; } else { DUK_ASSERT(flags & DUK_DATE_FLAG_TOSTRING_TIME); fmt = "%X"; } (void) strftime(buf, sizeof(buf) - 1, fmt, &tm); DUK_ASSERT(buf[sizeof(buf) - 1] == 0); duk_push_string(ctx, buf); return 1; }
/* Called by duk_hstring.h macros */ DUK_INTERNAL duk_uarridx_t duk_js_to_arrayindex_string_helper(duk_hstring *h) { duk_uarridx_t res; duk_small_int_t rc; if (!DUK_HSTRING_HAS_ARRIDX(h)) { return DUK_HSTRING_NO_ARRAY_INDEX; } rc = duk_js_to_arrayindex_raw_string(DUK_HSTRING_GET_DATA(h), DUK_HSTRING_GET_BYTELEN(h), &res); DUK_UNREF(rc); DUK_ASSERT(rc != 0); return res; }
/* * Debug dumping of duk_heap. */ #include "duk_internal.h" #ifdef DUK_USE_DEBUG #if 0 /*unused*/ DUK_LOCAL void duk__sanitize_snippet(char *buf, duk_size_t buf_size, duk_hstring *str) { duk_size_t i; duk_size_t nchars; duk_size_t maxchars; duk_uint8_t *data; DUK_MEMZERO(buf, buf_size); maxchars = (duk_size_t) (buf_size - 1); data = DUK_HSTRING_GET_DATA(str); nchars = ((duk_size_t) str->blen < maxchars ? (duk_size_t) str->blen : maxchars); for (i = 0; i < nchars; i++) { duk_small_int_t c = (duk_small_int_t) data[i]; if (c < 0x20 || c > 0x7e) { c = '.'; } buf[i] = (char) c; } } #endif #if 0 DUK_LOCAL const char *duk__get_heap_type_string(duk_heaphdr *hdr) { switch (DUK_HEAPHDR_GET_TYPE(hdr)) { case DUK_HTYPE_STRING: return "string"; case DUK_HTYPE_OBJECT: return "object"; case DUK_HTYPE_BUFFER: return "buffer"; default: return "???"; } } #endif #if 0 DUK_LOCAL void duk__dump_indented(duk_heaphdr *obj, int index) { DUK_UNREF(obj); DUK_UNREF(index); DUK_UNREF(duk__get_heap_type_string); #ifdef DUK_USE_REFERENCE_COUNTING DUK_D(DUK_DPRINT(" [%ld]: %p %s (flags: 0x%08lx, ref: %ld) -> %!O", (long) index, (void *) obj, (const char *) duk__get_heap_type_string(obj), (unsigned long) DUK_HEAPHDR_GET_FLAGS(obj), (long) DUK_HEAPHDR_GET_REFCOUNT(obj), (duk_heaphdr *) obj)); #else DUK_D(DUK_DPRINT(" [%ld]: %p %s (flags: 0x%08lx) -> %!O", (long) index, (void *) obj, (const char *) duk__get_heap_type_string(obj), (unsigned long) DUK_HEAPHDR_GET_FLAGS(obj), (duk_heaphdr *) obj)); #endif } #endif #if 0 /*unused*/ DUK_LOCAL void duk__dump_heaphdr_list(duk_heap *heap, duk_heaphdr *root, const char *name) { duk_int_t count; duk_heaphdr *curr; DUK_UNREF(heap); DUK_UNREF(name); count = 0; curr = root; while (curr) { count++; curr = DUK_HEAPHDR_GET_NEXT(curr); } DUK_D(DUK_DPRINT("%s, %ld objects", (const char *) name, (long) count)); count = 0; curr = root; while (curr) { count++; duk__dump_indented(curr, count); curr = DUK_HEAPHDR_GET_NEXT(curr); } }
duk_ret_t duk_bi_duktape_object_gc(duk_context *ctx) { #ifdef DUK_USE_MARK_AND_SWEEP duk_hthread *thr = (duk_hthread *) ctx; int flags; int rc; flags = duk_get_int(ctx, 0); rc = duk_heap_mark_and_sweep(thr->heap, flags); duk_push_int(ctx, rc); return 1; #else DUK_UNREF(ctx); return 0; #endif }
DUK_INTERNAL void duk_hobject_set_prototype_updref(duk_hthread *thr, duk_hobject *h, duk_hobject *p) { #ifdef DUK_USE_REFERENCE_COUNTING duk_hobject *tmp; DUK_ASSERT(h); tmp = DUK_HOBJECT_GET_PROTOTYPE(thr->heap, h); DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p); DUK_HOBJECT_INCREF_ALLOWNULL(thr, p); /* avoid problems if p == h->prototype */ DUK_HOBJECT_DECREF_ALLOWNULL(thr, tmp); #else DUK_ASSERT(h); DUK_UNREF(thr); DUK_HOBJECT_SET_PROTOTYPE(thr->heap, h, p); #endif }