JavaScript-Embedded

 view release on metacpan or  search on metacpan

lib/JavaScript/Embedded/C/lib/duktape.c  view on Meta::CPAN

	 * 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(thr, buf);
	return 1;
}
#endif /* DUK_USE_DATE_FMT_STRFTIME */

#if defined(DUK_USE_GET_MONOTONIC_TIME_CLOCK_GETTIME)
DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_clock_gettime(void) {
	struct timespec ts;

	if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
		return (duk_double_t) ts.tv_sec * 1000.0 + (duk_double_t) ts.tv_nsec / 1000000.0;
	} else {
		DUK_D(DUK_DPRINT("clock_gettime(CLOCK_MONOTONIC) failed"));
		return 0.0;
	}
}
#endif

/* automatic undefs */
#undef DUK__STRFTIME_BUF_SIZE
#undef DUK__STRPTIME_BUF_SIZE
#line 1 "duk_bi_date_windows.c"
/*
 *  Windows Date providers
 *
 *  Platform specific links:
 *
 *    - http://msdn.microsoft.com/en-us/library/windows/desktop/ms725473(v=vs.85).aspx
 */

/* #include duk_internal.h -> already included */

/* The necessary #includes are in place in duk_config.h. */

#if defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS)
/* Shared Windows helpers. */
DUK_LOCAL void duk__convert_systime_to_ularge(const SYSTEMTIME *st, ULARGE_INTEGER *res) {
	FILETIME ft;
	if (SystemTimeToFileTime(st, &ft) == 0) {
		DUK_D(DUK_DPRINT("SystemTimeToFileTime() failed, returning 0"));
		res->QuadPart = 0;
	} else {
		res->LowPart = ft.dwLowDateTime;
		res->HighPart = ft.dwHighDateTime;
	}
}

#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
DUK_LOCAL void duk__convert_filetime_to_ularge(const FILETIME *ft, ULARGE_INTEGER *res) {
	res->LowPart = ft->dwLowDateTime;
	res->HighPart = ft->dwHighDateTime;
}
#endif /* DUK_USE_DATE_NOW_WINDOWS_SUBMS */

DUK_LOCAL void duk__set_systime_jan1970(SYSTEMTIME *st) {
	duk_memzero((void *) st, sizeof(*st));
	st->wYear = 1970;
	st->wMonth = 1;
	st->wDayOfWeek = 4; /* not sure whether or not needed; Thursday */
	st->wDay = 1;
	DUK_ASSERT(st->wHour == 0);
	DUK_ASSERT(st->wMinute == 0);
	DUK_ASSERT(st->wSecond == 0);
	DUK_ASSERT(st->wMilliseconds == 0);
}
#endif /* defined(DUK_USE_DATE_NOW_WINDOWS) || defined(DUK_USE_DATE_TZO_WINDOWS) */

#if defined(DUK_USE_DATE_NOW_WINDOWS)
DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows(void) {
	/* Suggested step-by-step method from documentation of RtlTimeToSecondsSince1970:
	 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724928(v=vs.85).aspx
	 */
	SYSTEMTIME st1, st2;
	ULARGE_INTEGER tmp1, tmp2;

	GetSystemTime(&st1);
	duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);

	duk__set_systime_jan1970(&st2);
	duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);

	/* Difference is in 100ns units, convert to milliseconds, keeping
	 * fractions since Duktape 2.2.0.  This is only theoretical because
	 * SYSTEMTIME is limited to milliseconds.
	 */
	return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0;
}
#endif /* DUK_USE_DATE_NOW_WINDOWS */

#if defined(DUK_USE_DATE_NOW_WINDOWS_SUBMS)
DUK_INTERNAL duk_double_t duk_bi_date_get_now_windows_subms(void) {
	/* Variant of the basic algorithm using GetSystemTimePreciseAsFileTime()
	 * for more accuracy.
	 */
	FILETIME ft1;
	SYSTEMTIME st2;
	ULARGE_INTEGER tmp1, tmp2;

	GetSystemTimePreciseAsFileTime(&ft1);
	duk__convert_filetime_to_ularge((const FILETIME *) &ft1, &tmp1);

	duk__set_systime_jan1970(&st2);
	duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);

	/* Difference is in 100ns units, convert to milliseconds, keeping
	 * fractions since Duktape 2.2.0.
	 */
	return (duk_double_t) ((LONGLONG) tmp1.QuadPart - (LONGLONG) tmp2.QuadPart) / 10000.0;
}
#endif /* DUK_USE_DATE_NOW_WINDOWS */

#if defined(DUK_USE_DATE_TZO_WINDOWS)
DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows(duk_double_t d) {
	SYSTEMTIME st1;
	SYSTEMTIME st2;
	SYSTEMTIME st3;
	ULARGE_INTEGER tmp1;
	ULARGE_INTEGER tmp2;
	ULARGE_INTEGER tmp3;
	FILETIME ft1;

	/* XXX: handling of timestamps outside Windows supported range.
	 * How does Windows deal with dates before 1600?  Does windows
	 * support all ECMAScript years (like -200000 and +200000)?
	 * Should equivalent year mapping be used here too?  If so, use
	 * a shared helper (currently integrated into timeval-to-parts).
	 */

	/* Use the approach described in "Remarks" of FileTimeToLocalFileTime:
	 * http://msdn.microsoft.com/en-us/library/windows/desktop/ms724277(v=vs.85).aspx
	 */

	duk__set_systime_jan1970(&st1);
	duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);
	tmp2.QuadPart = (ULONGLONG) (d * 10000.0); /* millisec -> 100ns units since jan 1, 1970 */
	tmp2.QuadPart += tmp1.QuadPart; /* input 'd' in Windows UTC, 100ns units */

	ft1.dwLowDateTime = tmp2.LowPart;
	ft1.dwHighDateTime = tmp2.HighPart;
	if (FileTimeToSystemTime((const FILETIME *) &ft1, &st2) == 0) {
		DUK_D(DUK_DPRINT("FileTimeToSystemTime() failed, return tzoffset 0"));
		return 0;
	}
	if (SystemTimeToTzSpecificLocalTime((LPTIME_ZONE_INFORMATION) NULL, &st2, &st3) == 0) {
		DUK_D(DUK_DPRINT("SystemTimeToTzSpecificLocalTime() failed, return tzoffset 0"));
		return 0;
	}
	duk__convert_systime_to_ularge((const SYSTEMTIME *) &st3, &tmp3);

	/* Positive if local time ahead of UTC. */
	return (duk_int_t) (((LONGLONG) tmp3.QuadPart - (LONGLONG) tmp2.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */
}
#endif /* DUK_USE_DATE_TZO_WINDOWS */

#if defined(DUK_USE_DATE_TZO_WINDOWS_NO_DST)
DUK_INTERNAL duk_int_t duk_bi_date_get_local_tzoffset_windows_no_dst(duk_double_t d) {
	SYSTEMTIME st1;
	SYSTEMTIME st2;
	FILETIME ft1;
	FILETIME ft2;
	ULARGE_INTEGER tmp1;
	ULARGE_INTEGER tmp2;

	/* Do a similar computation to duk_bi_date_get_local_tzoffset_windows
	 * but without accounting for daylight savings time.  Use this on
	 * Windows platforms (like Durango) that don't support the
	 * SystemTimeToTzSpecificLocalTime() call.
	 */

	/* current time not needed for this computation */
	DUK_UNREF(d);

	duk__set_systime_jan1970(&st1);
	duk__convert_systime_to_ularge((const SYSTEMTIME *) &st1, &tmp1);

	ft1.dwLowDateTime = tmp1.LowPart;
	ft1.dwHighDateTime = tmp1.HighPart;
	if (FileTimeToLocalFileTime((const FILETIME *) &ft1, &ft2) == 0) {
		DUK_D(DUK_DPRINT("FileTimeToLocalFileTime() failed, return tzoffset 0"));
		return 0;
	}
	if (FileTimeToSystemTime((const FILETIME *) &ft2, &st2) == 0) {
		DUK_D(DUK_DPRINT("FileTimeToSystemTime() failed, return tzoffset 0"));
		return 0;
	}
	duk__convert_systime_to_ularge((const SYSTEMTIME *) &st2, &tmp2);

	return (duk_int_t) (((LONGLONG) tmp2.QuadPart - (LONGLONG) tmp1.QuadPart) / DUK_I64_CONSTANT(10000000)); /* seconds */
}
#endif /* DUK_USE_DATE_TZO_WINDOWS_NO_DST */

#if defined(DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC)
DUK_INTERNAL duk_double_t duk_bi_date_get_monotonic_time_windows_qpc(void) {
	LARGE_INTEGER count, freq;

	/* There are legacy issues with QueryPerformanceCounter():
	 * - Potential jumps:
	 * https://support.microsoft.com/en-us/help/274323/performance-counter-value-may-unexpectedly-leap-forward
	 * - Differences between cores (XP):
	 * https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx#qpc_support_in_windows_versions
	 *
	 * We avoid these by enabling QPC by default only for Vista or later.
	 */

	if (QueryPerformanceCounter(&count) && QueryPerformanceFrequency(&freq)) {
		/* XXX: QueryPerformanceFrequency() can be cached */
		return (duk_double_t) count.QuadPart / (duk_double_t) freq.QuadPart * 1000.0;
	} else {
		/* MSDN: "On systems that run Windows XP or later, the function
		 * will always succeed and will thus never return zero."
		 * Provide minimal error path just in case user enables this
		 * feature in pre-XP Windows.
		 */
		return 0.0;
	}
}
#endif /* DUK_USE_GET_MONOTONIC_TIME_WINDOWS_QPC */
#line 1 "duk_bi_duktape.c"
/*
 *  Duktape built-ins
 *
 *  Size optimization note: it might seem that vararg multipurpose functions
 *  like fin(), enc(), and dec() are not very size optimal, but using a single
 *  user-visible ECMAScript function saves a lot of run-time footprint; each
 *  Function instance takes >100 bytes.  Using a shared native helper and a
 *  'magic' value won't save much if there are multiple Function instances
 *  anyway.
 */

/* #include duk_internal.h -> already included */

#if defined(DUK_USE_DUKTAPE_BUILTIN)

DUK_INTERNAL duk_ret_t duk_bi_duktape_object_info(duk_hthread *thr) {
	duk_inspect_value(thr, -1);
	return 1;
}

DUK_INTERNAL duk_ret_t duk_bi_duktape_object_act(duk_hthread *thr) {
	duk_int_t level;

	level = duk_to_int(thr, 0);
	duk_inspect_callstack_entry(thr, level);
	return 1;
}

DUK_INTERNAL duk_ret_t duk_bi_duktape_object_gc(duk_hthread *thr) {
	duk_small_uint_t flags;

	flags = (duk_small_uint_t) duk_get_uint(thr, 0);
	duk_heap_mark_and_sweep(thr->heap, flags);

	/* XXX: Not sure what the best return value would be in the API.
	 * Return true for now.
	 */
	duk_push_true(thr);
	return 1;
}

#if defined(DUK_USE_FINALIZER_SUPPORT)



( run in 2.598 seconds using v1.01-cache-2.11-cpan-4991d5b9bd9 )