/* Convert from base time to extended time */ static JSInt64 PRMJ_ToExtendedTime(JSInt32 base_time) { JSInt64 exttime; JSInt64 g1970GMTMicroSeconds; JSInt64 low; JSInt32 diff; JSInt64 tmp; JSInt64 tmp1; diff = PRMJ_LocalGMTDifference(); JSLL_UI2L(tmp, PRMJ_USEC_PER_SEC); JSLL_I2L(tmp1,diff); JSLL_MUL(tmp,tmp,tmp1); JSLL_UI2L(g1970GMTMicroSeconds,G1970GMTMICROHI); JSLL_UI2L(low,G1970GMTMICROLOW); #ifndef JS_HAVE_LONG_LONG JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16); JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16); #else JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,32); #endif JSLL_ADD(g1970GMTMicroSeconds,g1970GMTMicroSeconds,low); JSLL_I2L(exttime,base_time); JSLL_ADD(exttime,exttime,g1970GMTMicroSeconds); JSLL_SUB(exttime,exttime,tmp); return exttime; }
JSInt64 PRMJ_Now(void) { JSInt64 s, us, ms2us, s2us; struct timeb b; ftime(&b); JSLL_UI2L(ms2us, PRMJ_USEC_PER_MSEC); JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC); JSLL_UI2L(s, b.time); JSLL_UI2L(us, b.millitm); JSLL_MUL(us, us, ms2us); JSLL_MUL(s, s, s2us); JSLL_ADD(s, s, us); return s; }
static uint32 random_next(JSRuntime *rt, int bits) { int64 nextseed, tmp; uint32 retval; JSLL_MUL(nextseed, rt->rngSeed, rt->rngMultiplier); JSLL_ADD(nextseed, nextseed, rt->rngAddend); JSLL_AND(nextseed, nextseed, rt->rngMask); rt->rngSeed = nextseed; JSLL_USHR(tmp, nextseed, 48 - bits); JSLL_L2I(retval, tmp); return retval; }
static void MacintoshInitializeTime(void) { uint64 upTime; unsigned long currentLocalTimeSeconds, startupTimeSeconds; uint64 startupTimeMicroSeconds; uint32 upTimeSeconds; uint64 oneMillion, upTimeSecondsLong, microSecondsToSeconds; DateTimeRec firstSecondOfUnixTime; /* * Figure out in local time what time the machine started up. This information can be added to * upTime to figure out the current local time as well as GMT. */ Microseconds((UnsignedWide*)&upTime); GetDateTime(¤tLocalTimeSeconds); JSLL_I2L(microSecondsToSeconds, PRMJ_USEC_PER_SEC); JSLL_DIV(upTimeSecondsLong, upTime, microSecondsToSeconds); JSLL_L2I(upTimeSeconds, upTimeSecondsLong); startupTimeSeconds = currentLocalTimeSeconds - upTimeSeconds; /* Make sure that we normalize the macintosh base seconds to the unix base of January 1, 1970. */ firstSecondOfUnixTime.year = 1970; firstSecondOfUnixTime.month = 1; firstSecondOfUnixTime.day = 1; firstSecondOfUnixTime.hour = 0; firstSecondOfUnixTime.minute = 0; firstSecondOfUnixTime.second = 0; firstSecondOfUnixTime.dayOfWeek = 0; DateToSeconds(&firstSecondOfUnixTime, &gJanuaryFirst1970Seconds); startupTimeSeconds -= gJanuaryFirst1970Seconds; /* Now convert the startup time into a wide so that we can figure out GMT and DST. */ JSLL_I2L(startupTimeMicroSeconds, startupTimeSeconds); JSLL_I2L(oneMillion, PRMJ_USEC_PER_SEC); JSLL_MUL(dstLocalBaseMicroseconds, oneMillion, startupTimeMicroSeconds); }
JSInt64 PRMJ_Now(void) { struct timeval tv; JSInt64 s, us, s2us; #ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */ gettimeofday(&tv); #else gettimeofday(&tv, 0); #endif /* _SVID_GETTOD */ JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC); JSLL_UI2L(s, tv.tv_sec); JSLL_UI2L(us, tv.tv_usec); JSLL_MUL(s, s, s2us); JSLL_ADD(s, s, us); return s; }
/* Get the DST timezone offset for the time passed in */ JSInt64 PRMJ_DSTOffset(JSInt64 local_time) { JSInt64 us2s; #ifdef XP_MAC /* * Convert the local time passed in to Macintosh epoch seconds. Use UTC utilities to convert * to UTC time, then compare difference with our GMT offset. If they are the same, then * DST must not be in effect for the input date/time. */ UInt32 macLocalSeconds = (local_time / PRMJ_USEC_PER_SEC) + gJanuaryFirst1970Seconds, utcSeconds; ConvertLocalTimeToUTC(macLocalSeconds, &utcSeconds); if ((utcSeconds - macLocalSeconds) == PRMJ_LocalGMTDifference()) return 0; else { JSInt64 dlsOffset; JSLL_UI2L(us2s, PRMJ_USEC_PER_SEC); JSLL_UI2L(dlsOffset, PRMJ_HOUR_SECONDS); JSLL_MUL(dlsOffset, dlsOffset, us2s); return dlsOffset; } #else time_t local; JSInt32 diff; JSInt64 maxtimet; struct tm tm; PRMJTime prtm; #ifndef HAVE_LOCALTIME_R struct tm *ptm; #endif JSLL_UI2L(us2s, PRMJ_USEC_PER_SEC); JSLL_DIV(local_time, local_time, us2s); /* get the maximum of time_t value */ JSLL_UI2L(maxtimet,PRMJ_MAX_UNIX_TIMET); if(JSLL_CMP(local_time,>,maxtimet)){ JSLL_UI2L(local_time,PRMJ_MAX_UNIX_TIMET); } else if(!JSLL_GE_ZERO(local_time)){
JSInt64 PRMJ_Now(void) { #ifdef XP_OS2 JSInt64 s, us, ms2us, s2us; struct timeb b; #endif #ifdef XP_WIN JSInt64 s, us, win2un = JSLL_INIT(0x19DB1DE, 0xD53E8000), ten = JSLL_INIT(0, 10); FILETIME time, midnight; #endif #if defined(XP_UNIX) || defined(XP_BEOS) struct timeval tv; JSInt64 s, us, s2us; #endif /* XP_UNIX */ #ifdef XP_OS2 ftime(&b); JSLL_UI2L(ms2us, PRMJ_USEC_PER_MSEC); JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC); JSLL_UI2L(s, b.time); JSLL_UI2L(us, b.millitm); JSLL_MUL(us, us, ms2us); JSLL_MUL(s, s, s2us); JSLL_ADD(s, s, us); return s; #endif #ifdef XP_WIN /* The windows epoch is around 1600. The unix epoch is around 1970. win2un is the difference (in windows time units which are 10 times more precise than the JS time unit) */ GetSystemTimeAsFileTime(&time); /* Win9x gets confused at midnight http://support.microsoft.com/default.aspx?scid=KB;en-us;q224423 So if the low part (precision <8mins) is 0 then we get the time again. */ if (!time.dwLowDateTime) { GetSystemTimeAsFileTime(&midnight); time.dwHighDateTime = midnight.dwHighDateTime; } JSLL_UI2L(s, time.dwHighDateTime); JSLL_UI2L(us, time.dwLowDateTime); JSLL_SHL(s, s, 32); JSLL_ADD(s, s, us); JSLL_SUB(s, s, win2un); JSLL_DIV(s, s, ten); return s; #endif #if defined(XP_UNIX) || defined(XP_BEOS) #ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */ gettimeofday(&tv); #else gettimeofday(&tv, 0); #endif /* _SVID_GETTOD */ JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC); JSLL_UI2L(s, tv.tv_sec); JSLL_UI2L(us, tv.tv_usec); JSLL_MUL(s, s, s2us); JSLL_ADD(s, s, us); return s; #endif /* XP_UNIX */ }
JSInt64 PRMJ_Now(void) { #ifdef XP_OS2 JSInt64 s, us, ms2us, s2us; struct timeb b; #endif #ifdef XP_WIN JSInt64 s, us, win2un = JSLL_INIT(0x19DB1DE, 0xD53E8000), ten = JSLL_INIT(0, 10); FILETIME time, midnight; #endif #if defined(XP_UNIX) || defined(XP_BEOS) struct timeval tv; JSInt64 s, us, s2us; #endif /* XP_UNIX */ #ifdef XP_MAC JSUint64 upTime; JSInt64 localTime; JSInt64 gmtOffset; JSInt64 dstOffset; JSInt32 gmtDiff; JSInt64 s2us; #endif /* XP_MAC */ #ifdef XP_OS2 ftime(&b); JSLL_UI2L(ms2us, PRMJ_USEC_PER_MSEC); JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC); JSLL_UI2L(s, b.time); JSLL_UI2L(us, b.millitm); JSLL_MUL(us, us, ms2us); JSLL_MUL(s, s, s2us); JSLL_ADD(s, s, us); return s; #endif #ifdef XP_WIN /* The windows epoch is around 1600. The unix epoch is around 1970. win2un is the difference (in windows time units which are 10 times more precise than the JS time unit) */ GetSystemTimeAsFileTime(&time); /* Win9x gets confused at midnight http://support.microsoft.com/default.aspx?scid=KB;en-us;q224423 So if the low part (precision <8mins) is 0 then we get the time again. */ if (!time.dwLowDateTime) { GetSystemTimeAsFileTime(&midnight); time.dwHighDateTime = midnight.dwHighDateTime; } JSLL_UI2L(s, time.dwHighDateTime); JSLL_UI2L(us, time.dwLowDateTime); JSLL_SHL(s, s, 32); JSLL_ADD(s, s, us); JSLL_SUB(s, s, win2un); JSLL_DIV(s, s, ten); return s; #endif #if defined(XP_UNIX) || defined(XP_BEOS) #ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */ gettimeofday(&tv); #else gettimeofday(&tv, 0); #endif /* _SVID_GETTOD */ JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC); JSLL_UI2L(s, tv.tv_sec); JSLL_UI2L(us, tv.tv_usec); JSLL_MUL(s, s, s2us); JSLL_ADD(s, s, us); return s; #endif /* XP_UNIX */ #ifdef XP_MAC JSLL_UI2L(localTime,0); gmtDiff = PRMJ_LocalGMTDifference(); JSLL_I2L(gmtOffset,gmtDiff); JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC); JSLL_MUL(gmtOffset,gmtOffset,s2us); /* don't adjust for DST since it sets ctime and gmtime off on the MAC */ Microseconds((UnsignedWide*)&upTime); JSLL_ADD(localTime,localTime,gmtOffset); JSLL_ADD(localTime,localTime, dstLocalBaseMicroseconds); JSLL_ADD(localTime,localTime, upTime); dstOffset = PRMJ_DSTOffset(localTime); JSLL_SUB(localTime,localTime,dstOffset); return *((JSUint64 *)&localTime); #endif /* XP_MAC */ }
JSInt64 PRMJ_Now(void) { #ifdef XP_OS2 JSInt64 s, us, ms2us, s2us; struct timeb b; #endif #ifdef XP_WIN static int nCalls = 0; long double lowresTime, highresTimerValue; FILETIME ft; LARGE_INTEGER now; JSBool calibrated = JS_FALSE; JSBool needsCalibration = JS_FALSE; JSInt64 returnedTime; long double cachedOffset = 0.0; #endif #if defined(XP_UNIX) || defined(XP_BEOS) struct timeval tv; JSInt64 s, us, s2us; #endif /* XP_UNIX */ #ifdef XP_OS2 ftime(&b); JSLL_UI2L(ms2us, PRMJ_USEC_PER_MSEC); JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC); JSLL_UI2L(s, b.time); JSLL_UI2L(us, b.millitm); JSLL_MUL(us, us, ms2us); JSLL_MUL(s, s, s2us); JSLL_ADD(s, s, us); return s; #endif #ifdef XP_WIN /* To avoid regressing startup time (where high resolution is likely not needed), give the old behavior for the first few calls. This does not appear to be needed on Vista as the timeBegin/timeEndPeriod calls seem to immediately take effect. */ int thiscall = JS_ATOMIC_INCREMENT(&nCalls); /* 10 seems to be the number of calls to load with a blank homepage */ if (thiscall <= 10) { GetSystemTimeAsFileTime(&ft); return (FILETIME2INT64(ft)-win2un)/10L; } /* For non threadsafe platforms, NowInit is not necessary */ #ifdef JS_THREADSAFE PR_CallOnce(&calibrationOnce, NowInit); #endif do { if (!calibration.calibrated || needsCalibration) { MUTEX_LOCK(&calibration.calibration_lock); MUTEX_LOCK(&calibration.data_lock); /* Recalibrate only if no one else did before us */ if(calibration.offset == cachedOffset) { /* Since calibration can take a while, make any other threads immediately wait */ MUTEX_SETSPINCOUNT(&calibration.data_lock, 0); NowCalibrate(); calibrated = JS_TRUE; /* Restore spin count */ MUTEX_SETSPINCOUNT(&calibration.data_lock, DATALOCK_SPINCOUNT); } MUTEX_UNLOCK(&calibration.data_lock); MUTEX_UNLOCK(&calibration.calibration_lock); } /* Calculate a low resolution time */ GetSystemTimeAsFileTime(&ft); lowresTime = 0.1*(long double)(FILETIME2INT64(ft) - win2un); if (calibration.freq > 0.0) { long double highresTime, diff; DWORD timeAdjustment, timeIncrement; BOOL timeAdjustmentDisabled; /* Default to 15.625 ms if the syscall fails */ long double skewThreshold = 15625.25; /* Grab high resolution time */ QueryPerformanceCounter(&now); highresTimerValue = (long double)now.QuadPart; MUTEX_LOCK(&calibration.data_lock); highresTime = calibration.offset + PRMJ_USEC_PER_SEC* (highresTimerValue-calibration.timer_offset)/calibration.freq; cachedOffset = calibration.offset; /* On some dual processor/core systems, we might get an earlier time so we cache the last time that we returned */ calibration.last = max(calibration.last,(JSInt64)highresTime); returnedTime = calibration.last; MUTEX_UNLOCK(&calibration.data_lock); /* Rather than assume the NT kernel ticks every 15.6ms, ask it */ if (GetSystemTimeAdjustment(&timeAdjustment, &timeIncrement, &timeAdjustmentDisabled)) { if (timeAdjustmentDisabled) { /* timeAdjustment is in units of 100ns */ skewThreshold = timeAdjustment/10.0; } else { /* timeIncrement is in units of 100ns */ skewThreshold = timeIncrement/10.0; } } /* Check for clock skew */ diff = lowresTime - highresTime; /* For some reason that I have not determined, the skew can be up to twice a kernel tick. This does not seem to happen by itself, but I have only seen it triggered by another program doing some kind of file I/O. The symptoms are a negative diff followed by an equally large positive diff. */ if (fabs(diff) > 2*skewThreshold) { /*fprintf(stderr,"Clock skew detected (diff = %f)!\n", diff);*/ if (calibrated) { /* If we already calibrated once this instance, and the clock is still skewed, then either the processor(s) are wildly changing clockspeed or the system is so busy that we get switched out for long periods of time. In either case, it would be infeasible to make use of high resolution results for anything, so let's resort to old behavior for this call. It's possible that in the future, the user will want the high resolution timer, so we don't disable it entirely. */ returnedTime = (JSInt64)lowresTime; needsCalibration = JS_FALSE; } else { /* It is possible that when we recalibrate, we will return a value less than what we have returned before; this is unavoidable. We cannot tell the different between a faulty QueryPerformanceCounter implementation and user changes to the operating system time. Since we must respect user changes to the operating system time, we cannot maintain the invariant that Date.now() never decreases; the old implementation has this behavior as well. */ needsCalibration = JS_TRUE; } } else { /* No detectable clock skew */ returnedTime = (JSInt64)highresTime; needsCalibration = JS_FALSE; } } else { /* No high resolution timer is available, so fall back */ returnedTime = (JSInt64)lowresTime; } } while (needsCalibration); return returnedTime; #endif #if defined(XP_UNIX) || defined(XP_BEOS) #ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */ gettimeofday(&tv); #else gettimeofday(&tv, 0); #endif /* _SVID_GETTOD */ JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC); JSLL_UI2L(s, tv.tv_sec); JSLL_UI2L(us, tv.tv_usec); JSLL_MUL(s, s, s2us); JSLL_ADD(s, s, us); return s; #endif /* XP_UNIX */ }