/* 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; }
static jsdouble random_nextDouble(JSRuntime *rt) { int64 tmp, tmp2; jsdouble d; JSLL_ISHL(tmp, random_next(rt, 26), 27); JSLL_UI2L(tmp2, random_next(rt, 27)); JSLL_ADD(tmp, tmp, tmp2); JSLL_L2D(d, tmp); return d / rt->rngDscale; }
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; }
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; }
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; }
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 */ }
JSBool _callHook(JSDContext *jsdc, JSContext *cx, JSStackFrame *fp, JSBool before, uintN type, JSD_CallHookProc hook, void *hookData) { JSDScript* jsdscript; JSScript* jsscript; JSBool hookresult = JS_TRUE; if (!jsdc || !jsdc->inited) return JS_FALSE; if (!hook && !(jsdc->flags & JSD_COLLECT_PROFILE_DATA) && jsdc->flags & JSD_DISABLE_OBJECT_TRACE) { /* no hook to call, no profile data needs to be collected, and * the client has object tracing disabled, so there is nothing * to do here. */ return hookresult; } if (before && JS_IsConstructorFrame(cx, fp)) jsd_Constructing(jsdc, cx, JS_GetFrameThis(cx, fp), fp); jsscript = JS_GetFrameScript(cx, fp); if (jsscript) { JSD_LOCK_SCRIPTS(jsdc); jsdscript = jsd_FindJSDScript(jsdc, jsscript); JSD_UNLOCK_SCRIPTS(jsdc); if (jsdscript) { if (JSD_IS_PROFILE_ENABLED(jsdc, jsdscript)) { JSDProfileData *pdata; pdata = jsd_GetScriptProfileData (jsdc, jsdscript); if (pdata) { if (before) { if (JSLL_IS_ZERO(pdata->lastCallStart)) { int64 now; JSDProfileData *callerpdata; /* Get the time just the once, for consistency. */ now = JS_Now(); /* This contains a pointer to the profile data for * the caller of this function. */ callerpdata = jsdc->callingFunctionPData; if (callerpdata) { int64 ll_delta; pdata->caller = callerpdata; /* We need to 'stop' the timer for the caller. * Use time since last return if appropriate. */ if (JSLL_IS_ZERO(jsdc->lastReturnTime)) { JSLL_SUB(ll_delta, now, callerpdata->lastCallStart); } else { JSLL_SUB(ll_delta, now, jsdc->lastReturnTime); } JSLL_ADD(callerpdata->runningTime, callerpdata->runningTime, ll_delta); } /* We're the new current function, and no return * has happened yet. */ jsdc->callingFunctionPData = pdata; jsdc->lastReturnTime = JSLL_ZERO; /* This function has no running time (just been * called!), and we'll need the call start time. */ pdata->runningTime = JSLL_ZERO; pdata->lastCallStart = now; } else { if (++pdata->recurseDepth > pdata->maxRecurseDepth) pdata->maxRecurseDepth = pdata->recurseDepth; } /* make sure we're called for the return too. */ hookresult = JS_TRUE; } else if (!pdata->recurseDepth && !JSLL_IS_ZERO(pdata->lastCallStart)) { int64 now, ll_delta; jsdouble delta; now = JS_Now(); JSLL_SUB(ll_delta, now, pdata->lastCallStart); JSLL_L2D(delta, ll_delta); delta /= 1000.0; pdata->totalExecutionTime += delta; /* minExecutionTime starts as 0, so we need to overwrite * it on the first call always. */ if ((0 == pdata->callCount) || delta < pdata->minExecutionTime) { pdata->minExecutionTime = delta; } if (delta > pdata->maxExecutionTime) pdata->maxExecutionTime = delta; /* If we last returned from a function (as opposed to * having last entered this function), we need to inc. * the running total by the time delta since the last * return, and use the running total instead of the * delta calculated above. */ if (!JSLL_IS_ZERO(jsdc->lastReturnTime)) { /* Add last chunk to running time, and use total * running time as 'delta'. */ JSLL_SUB(ll_delta, now, jsdc->lastReturnTime); JSLL_ADD(pdata->runningTime, pdata->runningTime, ll_delta); JSLL_L2D(delta, pdata->runningTime); delta /= 1000.0; } pdata->totalOwnExecutionTime += delta; /* See minExecutionTime comment above. */ if ((0 == pdata->callCount) || delta < pdata->minOwnExecutionTime) { pdata->minOwnExecutionTime = delta; } if (delta > pdata->maxOwnExecutionTime) pdata->maxOwnExecutionTime = delta; /* Current function is now our caller. */ jsdc->callingFunctionPData = pdata->caller; /* No hanging pointers, please. */ pdata->caller = NULL; /* Mark the time we returned, and indicate this * function is no longer running. */ jsdc->lastReturnTime = now; pdata->lastCallStart = JSLL_ZERO; ++pdata->callCount; } else if (pdata->recurseDepth) { --pdata->recurseDepth; ++pdata->callCount; } } if (hook) jsd_CallCallHook (jsdc, cx, type, hook, hookData); } else { if (hook) hookresult = jsd_CallCallHook (jsdc, cx, type, hook, hookData); else hookresult = JS_TRUE; } } } #ifdef JSD_TRACE _interpreterTrace(jsdc, cx, fp, before); return JS_TRUE; #else return hookresult; #endif }
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 */ }