/[jscoverage]/trunk/js/prmjtime.cpp
ViewVC logotype

Annotation of /trunk/js/prmjtime.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 332 - (hide annotations)
Thu Oct 23 19:03:33 2008 UTC (11 years ago) by siliconforks
File size: 26939 byte(s)
Add SpiderMonkey from Firefox 3.1b1.

The following directories and files were removed:
correct/, correct.js
liveconnect/
nanojit/
t/
v8/
vprof/
xpconnect/
all JavaScript files (Y.js, call.js, if.js, math-partial-sums.js, md5.js, perfect.js, trace-test.js, trace.js)


1 siliconforks 332 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2     *
3     * ***** BEGIN LICENSE BLOCK *****
4     * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5     *
6     * The contents of this file are subject to the Mozilla Public License Version
7     * 1.1 (the "License"); you may not use this file except in compliance with
8     * the License. You may obtain a copy of the License at
9     * http://www.mozilla.org/MPL/
10     *
11     * Software distributed under the License is distributed on an "AS IS" basis,
12     * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13     * for the specific language governing rights and limitations under the
14     * License.
15     *
16     * The Original Code is Mozilla Communicator client code, released
17     * March 31, 1998.
18     *
19     * The Initial Developer of the Original Code is
20     * Netscape Communications Corporation.
21     * Portions created by the Initial Developer are Copyright (C) 1998
22     * the Initial Developer. All Rights Reserved.
23     *
24     * Contributor(s):
25     *
26     * Alternatively, the contents of this file may be used under the terms of
27     * either of the GNU General Public License Version 2 or later (the "GPL"),
28     * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29     * in which case the provisions of the GPL or the LGPL are applicable instead
30     * of those above. If you wish to allow use of your version of this file only
31     * under the terms of either the GPL or the LGPL, and not to allow others to
32     * use your version of this file under the terms of the MPL, indicate your
33     * decision by deleting the provisions above and replace them with the notice
34     * and other provisions required by the GPL or the LGPL. If you do not delete
35     * the provisions above, a recipient may use your version of this file under
36     * the terms of any one of the MPL, the GPL or the LGPL.
37     *
38     * ***** END LICENSE BLOCK ***** */
39    
40     /*
41     * PR time code.
42     */
43     #include "jsstddef.h"
44     #ifdef SOLARIS
45     #define _REENTRANT 1
46     #endif
47     #include <string.h>
48     #include <time.h>
49     #include "jstypes.h"
50     #include "jsutil.h"
51    
52     #include "jsprf.h"
53     #include "jslock.h"
54     #include "prmjtime.h"
55    
56     #define PRMJ_DO_MILLISECONDS 1
57    
58     #ifdef XP_OS2
59     #include <sys/timeb.h>
60     #endif
61     #ifdef XP_WIN
62     #include <windef.h>
63     #include <winbase.h>
64     #include <math.h> /* for fabs */
65     #include <mmsystem.h> /* for timeBegin/EndPeriod */
66     /* VC++ 8.0 or later, and not WINCE */
67     #if _MSC_VER >= 1400 && !defined(WINCE)
68     #define NS_HAVE_INVALID_PARAMETER_HANDLER 1
69     #endif
70     #ifdef NS_HAVE_INVALID_PARAMETER_HANDLER
71     #include <stdlib.h> /* for _set_invalid_parameter_handler */
72     #include <crtdbg.h> /* for _CrtSetReportMode */
73     #endif
74    
75     #ifdef JS_THREADSAFE
76     #include <prinit.h>
77     #endif
78    
79     #endif
80    
81     #if defined(XP_UNIX) || defined(XP_BEOS)
82    
83     #ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
84     extern int gettimeofday(struct timeval *tv);
85     #endif
86    
87     #include <sys/time.h>
88    
89     #endif /* XP_UNIX */
90    
91     #define PRMJ_YEAR_DAYS 365L
92     #define PRMJ_FOUR_YEARS_DAYS (4 * PRMJ_YEAR_DAYS + 1)
93     #define PRMJ_CENTURY_DAYS (25 * PRMJ_FOUR_YEARS_DAYS - 1)
94     #define PRMJ_FOUR_CENTURIES_DAYS (4 * PRMJ_CENTURY_DAYS + 1)
95     #define PRMJ_HOUR_SECONDS 3600L
96     #define PRMJ_DAY_SECONDS (24L * PRMJ_HOUR_SECONDS)
97     #define PRMJ_YEAR_SECONDS (PRMJ_DAY_SECONDS * PRMJ_YEAR_DAYS)
98     #define PRMJ_MAX_UNIX_TIMET 2145859200L /*time_t value equiv. to 12/31/2037 */
99    
100     /* function prototypes */
101     static void PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm);
102     /*
103     * get the difference in seconds between this time zone and UTC (GMT)
104     */
105     JSInt32
106     PRMJ_LocalGMTDifference()
107     {
108     struct tm ltime;
109    
110     /* get the difference between this time zone and GMT */
111     memset((char *)&ltime,0,sizeof(ltime));
112     ltime.tm_mday = 2;
113     ltime.tm_year = 70;
114     return (JSInt32)mktime(&ltime) - (24L * 3600L);
115     }
116    
117     /* Constants for GMT offset from 1970 */
118     #define G1970GMTMICROHI 0x00dcdcad /* micro secs to 1970 hi */
119     #define G1970GMTMICROLOW 0x8b3fa000 /* micro secs to 1970 low */
120    
121     #define G2037GMTMICROHI 0x00e45fab /* micro secs to 2037 high */
122     #define G2037GMTMICROLOW 0x7a238000 /* micro secs to 2037 low */
123    
124     /* Convert from base time to extended time */
125     static JSInt64
126     PRMJ_ToExtendedTime(JSInt32 base_time)
127     {
128     JSInt64 exttime;
129     JSInt64 g1970GMTMicroSeconds;
130     JSInt64 low;
131     JSInt32 diff;
132     JSInt64 tmp;
133     JSInt64 tmp1;
134    
135     diff = PRMJ_LocalGMTDifference();
136     JSLL_UI2L(tmp, PRMJ_USEC_PER_SEC);
137     JSLL_I2L(tmp1,diff);
138     JSLL_MUL(tmp,tmp,tmp1);
139    
140     JSLL_UI2L(g1970GMTMicroSeconds,G1970GMTMICROHI);
141     JSLL_UI2L(low,G1970GMTMICROLOW);
142     #ifndef JS_HAVE_LONG_LONG
143     JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16);
144     JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,16);
145     #else
146     JSLL_SHL(g1970GMTMicroSeconds,g1970GMTMicroSeconds,32);
147     #endif
148     JSLL_ADD(g1970GMTMicroSeconds,g1970GMTMicroSeconds,low);
149    
150     JSLL_I2L(exttime,base_time);
151     JSLL_ADD(exttime,exttime,g1970GMTMicroSeconds);
152     JSLL_SUB(exttime,exttime,tmp);
153     return exttime;
154     }
155    
156     #ifdef XP_WIN
157     typedef struct CalibrationData
158     {
159     long double freq; /* The performance counter frequency */
160     long double offset; /* The low res 'epoch' */
161     long double timer_offset; /* The high res 'epoch' */
162    
163     /* The last high res time that we returned since recalibrating */
164     JSInt64 last;
165    
166     JSBool calibrated;
167    
168     #ifdef JS_THREADSAFE
169     CRITICAL_SECTION data_lock;
170     CRITICAL_SECTION calibration_lock;
171     #endif
172     } CalibrationData;
173    
174     static const JSInt64 win2un = JSLL_INIT(0x19DB1DE, 0xD53E8000);
175    
176     static CalibrationData calibration = { 0 };
177    
178     #define FILETIME2INT64(ft) (((JSInt64)ft.dwHighDateTime) << 32LL | (JSInt64)ft.dwLowDateTime)
179    
180     static void
181     NowCalibrate()
182     {
183     FILETIME ft, ftStart;
184     LARGE_INTEGER liFreq, now;
185    
186     if (calibration.freq == 0.0) {
187     if(!QueryPerformanceFrequency(&liFreq)) {
188     /* High-performance timer is unavailable */
189     calibration.freq = -1.0;
190     } else {
191     calibration.freq = (long double) liFreq.QuadPart;
192     }
193     }
194     if (calibration.freq > 0.0) {
195     JSInt64 calibrationDelta = 0;
196    
197     /* By wrapping a timeBegin/EndPeriod pair of calls around this loop,
198     the loop seems to take much less time (1 ms vs 15ms) on Vista. */
199     timeBeginPeriod(1);
200     GetSystemTimeAsFileTime(&ftStart);
201     do {
202     GetSystemTimeAsFileTime(&ft);
203     } while (memcmp(&ftStart,&ft, sizeof(ft)) == 0);
204     timeEndPeriod(1);
205    
206     /*
207     calibrationDelta = (FILETIME2INT64(ft) - FILETIME2INT64(ftStart))/10;
208     fprintf(stderr, "Calibration delta was %I64d us\n", calibrationDelta);
209     */
210    
211     QueryPerformanceCounter(&now);
212    
213     calibration.offset = (long double) FILETIME2INT64(ft);
214     calibration.timer_offset = (long double) now.QuadPart;
215    
216     /* The windows epoch is around 1600. The unix epoch is around
217     1970. win2un is the difference (in windows time units which
218     are 10 times more highres than the JS time unit) */
219     calibration.offset -= win2un;
220     calibration.offset *= 0.1;
221     calibration.last = 0;
222    
223     calibration.calibrated = JS_TRUE;
224     }
225     }
226    
227     #define CALIBRATIONLOCK_SPINCOUNT 0
228     #define DATALOCK_SPINCOUNT 4096
229     #define LASTLOCK_SPINCOUNT 4096
230    
231     #ifdef JS_THREADSAFE
232     static PRStatus PR_CALLBACK
233     NowInit(void)
234     {
235     memset(&calibration, 0, sizeof(calibration));
236     NowCalibrate();
237     InitializeCriticalSectionAndSpinCount(&calibration.calibration_lock, CALIBRATIONLOCK_SPINCOUNT);
238     InitializeCriticalSectionAndSpinCount(&calibration.data_lock, DATALOCK_SPINCOUNT);
239     return PR_SUCCESS;
240     }
241    
242     void
243     PRMJ_NowShutdown()
244     {
245     DeleteCriticalSection(&calibration.calibration_lock);
246     DeleteCriticalSection(&calibration.data_lock);
247     }
248    
249     #define MUTEX_LOCK(m) EnterCriticalSection(m)
250     #define MUTEX_TRYLOCK(m) TryEnterCriticalSection(m)
251     #define MUTEX_UNLOCK(m) LeaveCriticalSection(m)
252     #define MUTEX_SETSPINCOUNT(m, c) SetCriticalSectionSpinCount((m),(c))
253    
254     static PRCallOnceType calibrationOnce = { 0 };
255    
256     #else
257    
258     #define MUTEX_LOCK(m)
259     #define MUTEX_TRYLOCK(m) 1
260     #define MUTEX_UNLOCK(m)
261     #define MUTEX_SETSPINCOUNT(m, c)
262    
263     #endif
264    
265    
266     #endif /* XP_WIN */
267    
268     /*
269    
270     Win32 python-esque pseudo code
271     Please see bug 363258 for why the win32 timing code is so complex.
272    
273     calibration mutex : Win32CriticalSection(spincount=0)
274     data mutex : Win32CriticalSection(spincount=4096)
275    
276     def NowInit():
277     init mutexes
278     PRMJ_NowCalibration()
279    
280     def NowCalibration():
281     expensive up-to-15ms call
282    
283     def PRMJ_Now():
284     returnedTime = 0
285     needCalibration = False
286     cachedOffset = 0.0
287     calibrated = False
288     PR_CallOnce(PRMJ_NowInit)
289     do
290     if not global.calibrated or needCalibration:
291     acquire calibration mutex
292     acquire data mutex
293    
294     // Only recalibrate if someone didn't already
295     if cachedOffset == calibration.offset:
296     // Have all waiting threads immediately wait
297     set data mutex spin count = 0
298     PRMJ_NowCalibrate()
299     calibrated = 1
300    
301     set data mutex spin count = default
302     release data mutex
303     release calibration mutex
304    
305     calculate lowres time
306    
307     if highres timer available:
308     acquire data mutex
309     calculate highres time
310     cachedOffset = calibration.offset
311     highres time = calibration.last = max(highres time, calibration.last)
312     release data mutex
313    
314     get kernel tick interval
315    
316     if abs(highres - lowres) < kernel tick:
317     returnedTime = highres time
318     needCalibration = False
319     else:
320     if calibrated:
321     returnedTime = lowres
322     needCalibration = False
323     else:
324     needCalibration = True
325     else:
326     returnedTime = lowres
327     while needCalibration
328    
329     */
330    
331     JSInt64
332     PRMJ_Now(void)
333     {
334     #ifdef XP_OS2
335     JSInt64 s, us, ms2us, s2us;
336     struct timeb b;
337     #endif
338     #ifdef XP_WIN
339     static int nCalls = 0;
340     long double lowresTime, highresTimerValue;
341     FILETIME ft;
342     LARGE_INTEGER now;
343     JSBool calibrated = JS_FALSE;
344     JSBool needsCalibration = JS_FALSE;
345     JSInt64 returnedTime;
346     long double cachedOffset = 0.0;
347     #endif
348     #if defined(XP_UNIX) || defined(XP_BEOS)
349     struct timeval tv;
350     JSInt64 s, us, s2us;
351     #endif /* XP_UNIX */
352    
353     #ifdef XP_OS2
354     ftime(&b);
355     JSLL_UI2L(ms2us, PRMJ_USEC_PER_MSEC);
356     JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC);
357     JSLL_UI2L(s, b.time);
358     JSLL_UI2L(us, b.millitm);
359     JSLL_MUL(us, us, ms2us);
360     JSLL_MUL(s, s, s2us);
361     JSLL_ADD(s, s, us);
362     return s;
363     #endif
364     #ifdef XP_WIN
365    
366     /* To avoid regressing startup time (where high resolution is likely
367     not needed), give the old behavior for the first few calls.
368     This does not appear to be needed on Vista as the timeBegin/timeEndPeriod
369     calls seem to immediately take effect. */
370     int thiscall = JS_ATOMIC_INCREMENT(&nCalls);
371     /* 10 seems to be the number of calls to load with a blank homepage */
372     if (thiscall <= 10) {
373     GetSystemTimeAsFileTime(&ft);
374     return (FILETIME2INT64(ft)-win2un)/10L;
375     }
376    
377     /* For non threadsafe platforms, NowInit is not necessary */
378     #ifdef JS_THREADSAFE
379     PR_CallOnce(&calibrationOnce, NowInit);
380     #endif
381     do {
382     if (!calibration.calibrated || needsCalibration) {
383     MUTEX_LOCK(&calibration.calibration_lock);
384     MUTEX_LOCK(&calibration.data_lock);
385    
386     /* Recalibrate only if no one else did before us */
387     if(calibration.offset == cachedOffset) {
388     /* Since calibration can take a while, make any other
389     threads immediately wait */
390     MUTEX_SETSPINCOUNT(&calibration.data_lock, 0);
391    
392     NowCalibrate();
393    
394     calibrated = JS_TRUE;
395    
396     /* Restore spin count */
397     MUTEX_SETSPINCOUNT(&calibration.data_lock, DATALOCK_SPINCOUNT);
398     }
399     MUTEX_UNLOCK(&calibration.data_lock);
400     MUTEX_UNLOCK(&calibration.calibration_lock);
401     }
402    
403    
404     /* Calculate a low resolution time */
405     GetSystemTimeAsFileTime(&ft);
406     lowresTime = 0.1*(long double)(FILETIME2INT64(ft) - win2un);
407    
408     if (calibration.freq > 0.0) {
409     long double highresTime, diff;
410    
411     DWORD timeAdjustment, timeIncrement;
412     BOOL timeAdjustmentDisabled;
413    
414     /* Default to 15.625 ms if the syscall fails */
415     long double skewThreshold = 15625.25;
416     /* Grab high resolution time */
417     QueryPerformanceCounter(&now);
418     highresTimerValue = (long double)now.QuadPart;
419    
420     MUTEX_LOCK(&calibration.data_lock);
421     highresTime = calibration.offset + PRMJ_USEC_PER_SEC*
422     (highresTimerValue-calibration.timer_offset)/calibration.freq;
423     cachedOffset = calibration.offset;
424    
425     /* On some dual processor/core systems, we might get an earlier time
426     so we cache the last time that we returned */
427     calibration.last = max(calibration.last,(JSInt64)highresTime);
428     returnedTime = calibration.last;
429     MUTEX_UNLOCK(&calibration.data_lock);
430    
431     /* Rather than assume the NT kernel ticks every 15.6ms, ask it */
432     if (GetSystemTimeAdjustment(&timeAdjustment,
433     &timeIncrement,
434     &timeAdjustmentDisabled)) {
435     if (timeAdjustmentDisabled) {
436     /* timeAdjustment is in units of 100ns */
437     skewThreshold = timeAdjustment/10.0;
438     } else {
439     /* timeIncrement is in units of 100ns */
440     skewThreshold = timeIncrement/10.0;
441     }
442     }
443    
444     /* Check for clock skew */
445     diff = lowresTime - highresTime;
446    
447     /* For some reason that I have not determined, the skew can be
448     up to twice a kernel tick. This does not seem to happen by
449     itself, but I have only seen it triggered by another program
450     doing some kind of file I/O. The symptoms are a negative diff
451     followed by an equally large positive diff. */
452     if (fabs(diff) > 2*skewThreshold) {
453     /*fprintf(stderr,"Clock skew detected (diff = %f)!\n", diff);*/
454    
455     if (calibrated) {
456     /* If we already calibrated once this instance, and the
457     clock is still skewed, then either the processor(s) are
458     wildly changing clockspeed or the system is so busy that
459     we get switched out for long periods of time. In either
460     case, it would be infeasible to make use of high
461     resolution results for anything, so let's resort to old
462     behavior for this call. It's possible that in the
463     future, the user will want the high resolution timer, so
464     we don't disable it entirely. */
465     returnedTime = (JSInt64)lowresTime;
466     needsCalibration = JS_FALSE;
467     } else {
468     /* It is possible that when we recalibrate, we will return a
469     value less than what we have returned before; this is
470     unavoidable. We cannot tell the different between a
471     faulty QueryPerformanceCounter implementation and user
472     changes to the operating system time. Since we must
473     respect user changes to the operating system time, we
474     cannot maintain the invariant that Date.now() never
475     decreases; the old implementation has this behavior as
476     well. */
477     needsCalibration = JS_TRUE;
478     }
479     } else {
480     /* No detectable clock skew */
481     returnedTime = (JSInt64)highresTime;
482     needsCalibration = JS_FALSE;
483     }
484     } else {
485     /* No high resolution timer is available, so fall back */
486     returnedTime = (JSInt64)lowresTime;
487     }
488     } while (needsCalibration);
489    
490     return returnedTime;
491     #endif
492    
493     #if defined(XP_UNIX) || defined(XP_BEOS)
494     #ifdef _SVID_GETTOD /* Defined only on Solaris, see Solaris <sys/types.h> */
495     gettimeofday(&tv);
496     #else
497     gettimeofday(&tv, 0);
498     #endif /* _SVID_GETTOD */
499     JSLL_UI2L(s2us, PRMJ_USEC_PER_SEC);
500     JSLL_UI2L(s, tv.tv_sec);
501     JSLL_UI2L(us, tv.tv_usec);
502     JSLL_MUL(s, s, s2us);
503     JSLL_ADD(s, s, us);
504     return s;
505     #endif /* XP_UNIX */
506     }
507    
508     /* Get the DST timezone offset for the time passed in */
509     JSInt64
510     PRMJ_DSTOffset(JSInt64 local_time)
511     {
512     JSInt64 us2s;
513     time_t local;
514     JSInt32 diff;
515     JSInt64 maxtimet;
516     struct tm tm;
517     PRMJTime prtm;
518     #ifndef HAVE_LOCALTIME_R
519     struct tm *ptm;
520     #endif
521    
522    
523     JSLL_UI2L(us2s, PRMJ_USEC_PER_SEC);
524     JSLL_DIV(local_time, local_time, us2s);
525    
526     /* get the maximum of time_t value */
527     JSLL_UI2L(maxtimet,PRMJ_MAX_UNIX_TIMET);
528    
529     if(JSLL_CMP(local_time,>,maxtimet)){
530     JSLL_UI2L(local_time,PRMJ_MAX_UNIX_TIMET);
531     } else if(!JSLL_GE_ZERO(local_time)){
532     /*go ahead a day to make localtime work (does not work with 0) */
533     JSLL_UI2L(local_time,PRMJ_DAY_SECONDS);
534     }
535     JSLL_L2UI(local,local_time);
536     PRMJ_basetime(local_time,&prtm);
537     #ifndef HAVE_LOCALTIME_R
538     ptm = localtime(&local);
539     if(!ptm){
540     return 0;
541     }
542     tm = *ptm;
543     #else
544     localtime_r(&local,&tm); /* get dst information */
545     #endif
546    
547     diff = ((tm.tm_hour - prtm.tm_hour) * PRMJ_HOUR_SECONDS) +
548     ((tm.tm_min - prtm.tm_min) * 60);
549    
550     if(diff < 0){
551     diff += PRMJ_DAY_SECONDS;
552     }
553    
554     JSLL_UI2L(local_time,diff);
555    
556     JSLL_MUL(local_time,local_time,us2s);
557    
558     return(local_time);
559     }
560    
561     #ifdef NS_HAVE_INVALID_PARAMETER_HANDLER
562     static void
563     PRMJ_InvalidParameterHandler(const wchar_t *expression,
564     const wchar_t *function,
565     const wchar_t *file,
566     unsigned int line,
567     uintptr_t pReserved)
568     {
569     /* empty */
570     }
571     #endif
572    
573     /* Format a time value into a buffer. Same semantics as strftime() */
574     size_t
575     PRMJ_FormatTime(char *buf, int buflen, const char *fmt, PRMJTime *prtm)
576     {
577     size_t result = 0;
578     #if defined(XP_UNIX) || defined(XP_WIN) || defined(XP_OS2) || defined(XP_BEOS)
579     struct tm a;
580     int fake_tm_year = 0;
581     #ifdef NS_HAVE_INVALID_PARAMETER_HANDLER
582     _invalid_parameter_handler oldHandler;
583     int oldReportMode;
584     #endif
585    
586     /* Zero out the tm struct. Linux, SunOS 4 struct tm has extra members int
587     * tm_gmtoff, char *tm_zone; when tm_zone is garbage, strftime gets
588     * confused and dumps core. NSPR20 prtime.c attempts to fill these in by
589     * calling mktime on the partially filled struct, but this doesn't seem to
590     * work as well; the result string has "can't get timezone" for ECMA-valid
591     * years. Might still make sense to use this, but find the range of years
592     * for which valid tz information exists, and map (per ECMA hint) from the
593     * given year into that range.
594    
595     * N.B. This hasn't been tested with anything that actually _uses_
596     * tm_gmtoff; zero might be the wrong thing to set it to if you really need
597     * to format a time. This fix is for jsdate.c, which only uses
598     * JS_FormatTime to get a string representing the time zone. */
599     memset(&a, 0, sizeof(struct tm));
600    
601     a.tm_sec = prtm->tm_sec;
602     a.tm_min = prtm->tm_min;
603     a.tm_hour = prtm->tm_hour;
604     a.tm_mday = prtm->tm_mday;
605     a.tm_mon = prtm->tm_mon;
606     a.tm_wday = prtm->tm_wday;
607    
608     /*
609     * Years before 1900 and after 9999 cause strftime() to abort on Windows.
610     * To avoid that we replace it with FAKE_YEAR_BASE + year % 100 and then
611     * replace matching substrings in the strftime() result with the real year.
612     * Note that FAKE_YEAR_BASE should be a multiple of 100 to make 2-digit
613     * year formats (%y) work correctly (since we won't find the fake year
614     * in that case).
615     * e.g. new Date(1873, 0).toLocaleFormat('%Y %y') => "1873 73"
616     * See bug 327869.
617     */
618     #define FAKE_YEAR_BASE 9900
619     if (prtm->tm_year < 1900 || prtm->tm_year > 9999) {
620     fake_tm_year = FAKE_YEAR_BASE + prtm->tm_year % 100;
621     a.tm_year = fake_tm_year - 1900;
622     }
623     else {
624     a.tm_year = prtm->tm_year - 1900;
625     }
626     a.tm_yday = prtm->tm_yday;
627     a.tm_isdst = prtm->tm_isdst;
628    
629     /*
630     * Even with the above, SunOS 4 seems to detonate if tm_zone and tm_gmtoff
631     * are null. This doesn't quite work, though - the timezone is off by
632     * tzoff + dst. (And mktime seems to return -1 for the exact dst
633     * changeover time.)
634     */
635    
636     #ifdef NS_HAVE_INVALID_PARAMETER_HANDLER
637     oldHandler = _set_invalid_parameter_handler(PRMJ_InvalidParameterHandler);
638     oldReportMode = _CrtSetReportMode(_CRT_ASSERT, 0);
639     #endif
640    
641     result = strftime(buf, buflen, fmt, &a);
642    
643     #ifdef NS_HAVE_INVALID_PARAMETER_HANDLER
644     _set_invalid_parameter_handler(oldHandler);
645     _CrtSetReportMode(_CRT_ASSERT, oldReportMode);
646     #endif
647    
648     if (fake_tm_year && result) {
649     char real_year[16];
650     char fake_year[16];
651     size_t real_year_len;
652     size_t fake_year_len;
653     char* p;
654    
655     sprintf(real_year, "%d", prtm->tm_year);
656     real_year_len = strlen(real_year);
657     sprintf(fake_year, "%d", fake_tm_year);
658     fake_year_len = strlen(fake_year);
659    
660     /* Replace the fake year in the result with the real year. */
661     for (p = buf; (p = strstr(p, fake_year)); p += real_year_len) {
662     size_t new_result = result + real_year_len - fake_year_len;
663     if ((int)new_result >= buflen) {
664     return 0;
665     }
666     memmove(p + real_year_len, p + fake_year_len, strlen(p + fake_year_len));
667     memcpy(p, real_year, real_year_len);
668     result = new_result;
669     *(buf + result) = '\0';
670     }
671     }
672     #endif
673     return result;
674     }
675    
676     /* table for number of days in a month */
677     static int mtab[] = {
678     /* jan, feb,mar,apr,may,jun */
679     31,28,31,30,31,30,
680     /* july,aug,sep,oct,nov,dec */
681     31,31,30,31,30,31
682     };
683    
684     /*
685     * basic time calculation functionality for localtime and gmtime
686     * setups up prtm argument with correct values based upon input number
687     * of seconds.
688     */
689     static void
690     PRMJ_basetime(JSInt64 tsecs, PRMJTime *prtm)
691     {
692     /* convert tsecs back to year,month,day,hour,secs */
693     JSInt32 year = 0;
694     JSInt32 month = 0;
695     JSInt32 yday = 0;
696     JSInt32 mday = 0;
697     JSInt32 wday = 6; /* start on a Sunday */
698     JSInt32 days = 0;
699     JSInt32 seconds = 0;
700     JSInt32 minutes = 0;
701     JSInt32 hours = 0;
702     JSInt32 isleap = 0;
703    
704     /* Temporaries used for various computations */
705     JSInt64 result;
706     JSInt64 result1;
707     JSInt64 result2;
708    
709     JSInt64 base;
710    
711     /* Some variables for intermediate result storage to make computing isleap
712     easier/faster */
713     JSInt32 fourCenturyBlocks;
714     JSInt32 centuriesLeft;
715     JSInt32 fourYearBlocksLeft;
716     JSInt32 yearsLeft;
717    
718     /* Since leap years work by 400/100/4 year intervals, precompute the length
719     of those in seconds if they start at the beginning of year 1. */
720     JSInt64 fourYears;
721     JSInt64 century;
722     JSInt64 fourCenturies;
723    
724     JSLL_UI2L(result, PRMJ_DAY_SECONDS);
725    
726     JSLL_I2L(fourYears, PRMJ_FOUR_YEARS_DAYS);
727     JSLL_MUL(fourYears, fourYears, result);
728    
729     JSLL_I2L(century, PRMJ_CENTURY_DAYS);
730     JSLL_MUL(century, century, result);
731    
732     JSLL_I2L(fourCenturies, PRMJ_FOUR_CENTURIES_DAYS);
733     JSLL_MUL(fourCenturies, fourCenturies, result);
734    
735     /* get the base time via UTC */
736     base = PRMJ_ToExtendedTime(0);
737     JSLL_UI2L(result, PRMJ_USEC_PER_SEC);
738     JSLL_DIV(base,base,result);
739     JSLL_ADD(tsecs,tsecs,base);
740    
741     /* Compute our |year|, |isleap|, and part of |days|. When this part is
742     done, |year| should hold the year our date falls in (number of whole
743     years elapsed before our date), isleap should hold 1 if the year the
744     date falls in is a leap year and 0 otherwise. */
745    
746     /* First do year 0; it's special and nonleap. */
747     JSLL_UI2L(result, PRMJ_YEAR_SECONDS);
748     if (!JSLL_CMP(tsecs,<,result)) {
749     days = PRMJ_YEAR_DAYS;
750     year = 1;
751     JSLL_SUB(tsecs, tsecs, result);
752     }
753    
754     /* Now use those constants we computed above */
755     JSLL_UDIVMOD(&result1, &result2, tsecs, fourCenturies);
756     JSLL_L2I(fourCenturyBlocks, result1);
757     year += fourCenturyBlocks * 400;
758     days += fourCenturyBlocks * PRMJ_FOUR_CENTURIES_DAYS;
759     tsecs = result2;
760    
761     JSLL_UDIVMOD(&result1, &result2, tsecs, century);
762     JSLL_L2I(centuriesLeft, result1);
763     year += centuriesLeft * 100;
764     days += centuriesLeft * PRMJ_CENTURY_DAYS;
765     tsecs = result2;
766    
767     JSLL_UDIVMOD(&result1, &result2, tsecs, fourYears);
768     JSLL_L2I(fourYearBlocksLeft, result1);
769     year += fourYearBlocksLeft * 4;
770     days += fourYearBlocksLeft * PRMJ_FOUR_YEARS_DAYS;
771     tsecs = result2;
772    
773     /* Recall that |result| holds PRMJ_YEAR_SECONDS */
774     JSLL_UDIVMOD(&result1, &result2, tsecs, result);
775     JSLL_L2I(yearsLeft, result1);
776     year += yearsLeft;
777     days += yearsLeft * PRMJ_YEAR_DAYS;
778     tsecs = result2;
779    
780     /* now compute isleap. Note that we don't have to use %, since we've
781     already computed those remainders. Also note that they're all offset by
782     1 because of the 1 for year 0. */
783     isleap =
784     (yearsLeft == 3) && (fourYearBlocksLeft != 24 || centuriesLeft == 3);
785     JS_ASSERT(isleap ==
786     ((year % 4 == 0) && (year % 100 != 0 || year % 400 == 0)));
787    
788     JSLL_UI2L(result1,PRMJ_DAY_SECONDS);
789    
790     JSLL_DIV(result,tsecs,result1);
791     JSLL_L2I(mday,result);
792    
793     /* let's find the month */
794     while(((month == 1 && isleap) ?
795     (mday >= mtab[month] + 1) :
796     (mday >= mtab[month]))){
797     yday += mtab[month];
798     days += mtab[month];
799    
800     mday -= mtab[month];
801    
802     /* it's a Feb, check if this is a leap year */
803     if(month == 1 && isleap != 0){
804     yday++;
805     days++;
806     mday--;
807     }
808     month++;
809     }
810    
811     /* now adjust tsecs */
812     JSLL_MUL(result,result,result1);
813     JSLL_SUB(tsecs,tsecs,result);
814    
815     mday++; /* day of month always start with 1 */
816     days += mday;
817     wday = (days + wday) % 7;
818    
819     yday += mday;
820    
821     /* get the hours */
822     JSLL_UI2L(result1,PRMJ_HOUR_SECONDS);
823     JSLL_DIV(result,tsecs,result1);
824     JSLL_L2I(hours,result);
825     JSLL_MUL(result,result,result1);
826     JSLL_SUB(tsecs,tsecs,result);
827    
828     /* get minutes */
829     JSLL_UI2L(result1,60);
830     JSLL_DIV(result,tsecs,result1);
831     JSLL_L2I(minutes,result);
832     JSLL_MUL(result,result,result1);
833     JSLL_SUB(tsecs,tsecs,result);
834    
835     JSLL_L2I(seconds,tsecs);
836    
837     prtm->tm_usec = 0L;
838     prtm->tm_sec = (JSInt8)seconds;
839     prtm->tm_min = (JSInt8)minutes;
840     prtm->tm_hour = (JSInt8)hours;
841     prtm->tm_mday = (JSInt8)mday;
842     prtm->tm_mon = (JSInt8)month;
843     prtm->tm_wday = (JSInt8)wday;
844     prtm->tm_year = (JSInt16)year;
845     prtm->tm_yday = (JSInt16)yday;
846     }

  ViewVC Help
Powered by ViewVC 1.1.24