Back out changeset 6e21339a66ed (bug 1208808) for bustage in the mislabelled and deceptive arm64 simulator

CLOSED TREE
This commit is contained in:
Phil Ringnalda
2015-10-31 01:44:22 -07:00
parent d0e626ac5e
commit bbe02a1792
20 changed files with 341 additions and 481 deletions

View File

@@ -6,7 +6,7 @@
#include "DateCacheCleaner.h" #include "DateCacheCleaner.h"
#include "js/Date.h" #include "jsapi.h"
#include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/ScriptSettings.h"
#include "mozilla/ClearOnShutdown.h" #include "mozilla/ClearOnShutdown.h"
#include "mozilla/Hal.h" #include "mozilla/Hal.h"
@@ -33,7 +33,7 @@ public:
void Notify(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo) void Notify(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo)
{ {
mozilla::AutoSafeJSContext cx; mozilla::AutoSafeJSContext cx;
JS::ResetTimeZone(); JS_ClearDateCaches(cx);
} }
}; };

View File

@@ -7,7 +7,7 @@
/* /*
* InitializeDateCacheCleaner registers DateCacheCleaner to * InitializeDateCacheCleaner registers DateCacheCleaner to
* SystemTimeChangeObserver. When time zone is changed, DateCacheCleaner calls * SystemTimeChangeObserver. When time zone is changed, DateCacheCleaner calls
* JS::ResetTimeZone to update the time zone information. * JS_ClearDateCaches to update the time zone information.
*/ */
namespace mozilla { namespace mozilla {

View File

@@ -39,22 +39,6 @@ struct JSContext;
namespace JS { namespace JS {
/**
* Re-query the system to determine the current time zone adjustment from UTC,
* including any component due to DST. If the time zone has changed, this will
* cause all Date object non-UTC methods and formatting functions to produce
* appropriately adjusted results.
*
* Left to its own devices, SpiderMonkey itself may occasionally call this
* method to attempt to keep up with system time changes. However, no
* particular frequency of checking is guaranteed. Embedders unable to accept
* occasional inaccuracies should call this method in response to system time
* changes, or immediately before operations requiring instantaneous
* correctness, to guarantee correct behavior.
*/
extern JS_PUBLIC_API(void)
ResetTimeZone();
class ClippedTime; class ClippedTime;
inline ClippedTime TimeClip(double time); inline ClippedTime TimeClip(double time);

View File

@@ -1,84 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* SpiderMonkey initialization and shutdown APIs. */
#ifndef js_Initialization_h
#define js_Initialization_h
#include "jstypes.h"
namespace JS {
namespace detail {
enum class InitState { Uninitialized = 0, Running, ShutDown };
/**
* SpiderMonkey's initialization status is tracked here, and it controls things
* that should happen only once across all runtimes. It's an API requirement
* that JS_Init (and JS_ShutDown, if called) be called in a thread-aware
* manner, so this (internal -- embedders, don't use!) variable doesn't need to
* be atomic.
*/
extern JS_PUBLIC_DATA(InitState)
libraryInitState;
} // namespace detail
} // namespace JS
// These are equivalent to ICU's |UMemAllocFn|, |UMemReallocFn|, and
// |UMemFreeFn| types. The first argument (called |context| in the ICU docs)
// will always be nullptr and should be ignored.
typedef void* (*JS_ICUAllocFn)(const void*, size_t size);
typedef void* (*JS_ICUReallocFn)(const void*, void* p, size_t size);
typedef void (*JS_ICUFreeFn)(const void*, void* p);
/**
* This function can be used to track memory used by ICU. If it is called, it
* *must* be called before JS_Init. Don't use it unless you know what you're
* doing!
*/
extern JS_PUBLIC_API(bool)
JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn,
JS_ICUReallocFn reallocFn,
JS_ICUFreeFn freeFn);
/**
* Initialize SpiderMonkey, returning true only if initialization succeeded.
* Once this method has succeeded, it is safe to call JS_NewRuntime and other
* JSAPI methods.
*
* This method must be called before any other JSAPI method is used on any
* thread. Once it has been used, it is safe to call any JSAPI method, and it
* remains safe to do so until JS_ShutDown is correctly called.
*
* It is currently not possible to initialize SpiderMonkey multiple times (that
* is, calling JS_Init/JSAPI methods/JS_ShutDown in that order, then doing so
* again). This restriction may eventually be lifted.
*/
extern JS_PUBLIC_API(bool)
JS_Init(void);
/**
* Destroy free-standing resources allocated by SpiderMonkey, not associated
* with any runtime, context, or other structure.
*
* This method should be called after all other JSAPI data has been properly
* cleaned up: every new runtime must have been destroyed, every new context
* must have been destroyed, and so on. Calling this method before all other
* resources have been destroyed has undefined behavior.
*
* Failure to call this method, at present, has no adverse effects other than
* leaking memory. This may not always be the case; it's recommended that all
* embedders call this method when all other JSAPI operations have completed.
*
* It is currently not possible to initialize SpiderMonkey multiple times (that
* is, calling JS_Init/JSAPI methods/JS_ShutDown in that order, then doing so
* again). This restriction may eventually be lifted.
*/
extern JS_PUBLIC_API(void)
JS_ShutDown(void);
#endif /* js_Initialization_h */

View File

@@ -9,7 +9,6 @@
#include "gdb-tests.h" #include "gdb-tests.h"
#include "jsapi.h" #include "jsapi.h"
#include "jsfriendapi.h" #include "jsfriendapi.h"
#include "js/Initialization.h"
using namespace JS; using namespace JS;

View File

@@ -8,7 +8,6 @@
#include <stdio.h> #include <stdio.h>
#include "js/Initialization.h"
#include "js/RootingAPI.h" #include "js/RootingAPI.h"
JSAPITest* JSAPITest::list; JSAPITest* JSAPITest::list;

View File

@@ -62,10 +62,14 @@
#include "js/CharacterEncoding.h" #include "js/CharacterEncoding.h"
#include "js/Conversions.h" #include "js/Conversions.h"
#include "js/Date.h" #include "js/Date.h"
#include "js/Initialization.h"
#include "js/Proxy.h" #include "js/Proxy.h"
#include "js/SliceBudget.h" #include "js/SliceBudget.h"
#include "js/StructuredClone.h" #include "js/StructuredClone.h"
#if ENABLE_INTL_API
#include "unicode/timezone.h"
#include "unicode/uclean.h"
#include "unicode/utypes.h"
#endif // ENABLE_INTL_API
#include "vm/DateObject.h" #include "vm/DateObject.h"
#include "vm/Debugger.h" #include "vm/Debugger.h"
#include "vm/ErrorObject.h" #include "vm/ErrorObject.h"
@@ -441,6 +445,129 @@ JS_IsBuiltinFunctionConstructor(JSFunction* fun)
/************************************************************************/ /************************************************************************/
/*
* SpiderMonkey's initialization status is tracked here, and it controls things
* that should happen only once across all runtimes. It's an API requirement
* that JS_Init (and JS_ShutDown, if called) be called in a thread-aware
* manner, so this variable doesn't need to be atomic.
*
* The only reason at present for the restriction that you can't call
* JS_Init/stuff/JS_ShutDown multiple times is the Windows PRMJ NowInit
* initialization code, which uses PR_CallOnce to initialize the PRMJ_Now
* subsystem. (For reinitialization to be permitted, we'd need to "reset" the
* called-once status -- doable, but more trouble than it's worth now.)
* Initializing that subsystem from JS_Init eliminates the problem, but
* initialization can take a comparatively long time (15ms or so), so we
* really don't want to do it in JS_Init, and we really do want to do it only
* when PRMJ_Now is eventually called.
*/
enum InitState { Uninitialized, Running, ShutDown };
static InitState jsInitState = Uninitialized;
#ifdef DEBUG
static unsigned
MessageParameterCount(const char* format)
{
unsigned numfmtspecs = 0;
for (const char* fmt = format; *fmt != '\0'; fmt++) {
if (*fmt == '{' && isdigit(fmt[1]))
++numfmtspecs;
}
return numfmtspecs;
}
static void
CheckMessageParameterCounts()
{
// Assert that each message format has the correct number of braced
// parameters.
# define MSG_DEF(name, count, exception, format) \
MOZ_ASSERT(MessageParameterCount(format) == count);
# include "js.msg"
# undef MSG_DEF
}
#endif /* DEBUG */
JS_PUBLIC_API(bool)
JS_Init(void)
{
MOZ_ASSERT(jsInitState == Uninitialized,
"must call JS_Init once before any JSAPI operation except "
"JS_SetICUMemoryFunctions");
MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(),
"how do we have live runtimes before JS_Init?");
PRMJ_NowInit();
#ifdef DEBUG
CheckMessageParameterCounts();
#endif
using js::TlsPerThreadData;
if (!TlsPerThreadData.initialized() && !TlsPerThreadData.init())
return false;
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
if (!js::oom::InitThreadType())
return false;
js::oom::SetThreadType(js::oom::THREAD_TYPE_MAIN);
#endif
jit::ExecutableAllocator::initStatic();
if (!jit::InitializeIon())
return false;
#if EXPOSE_INTL_API
UErrorCode err = U_ZERO_ERROR;
u_init(&err);
if (U_FAILURE(err))
return false;
#endif // EXPOSE_INTL_API
if (!CreateHelperThreadsState())
return false;
if (!FutexRuntime::initialize())
return false;
jsInitState = Running;
return true;
}
JS_PUBLIC_API(void)
JS_ShutDown(void)
{
MOZ_ASSERT(jsInitState == Running,
"JS_ShutDown must only be called after JS_Init and can't race with it");
#ifdef DEBUG
if (JSRuntime::hasLiveRuntimes()) {
// Gecko is too buggy to assert this just yet.
fprintf(stderr,
"WARNING: YOU ARE LEAKING THE WORLD (at least one JSRuntime "
"and everything alive inside it, that is) AT JS_ShutDown "
"TIME. FIX THIS!\n");
}
#endif
FutexRuntime::destroy();
DestroyHelperThreadsState();
#ifdef JS_TRACE_LOGGING
DestroyTraceLoggerThreadState();
DestroyTraceLoggerGraphState();
#endif
PRMJ_NowShutdown();
#if EXPOSE_INTL_API
u_cleanup();
#endif // EXPOSE_INTL_API
jsInitState = ShutDown;
}
#ifdef DEBUG #ifdef DEBUG
JS_FRIEND_API(bool) JS_FRIEND_API(bool)
JS::isGCEnabled() JS::isGCEnabled()
@@ -454,7 +581,7 @@ JS_FRIEND_API(bool) JS::isGCEnabled() { return true; }
JS_PUBLIC_API(JSRuntime*) JS_PUBLIC_API(JSRuntime*)
JS_NewRuntime(uint32_t maxbytes, uint32_t maxNurseryBytes, JSRuntime* parentRuntime) JS_NewRuntime(uint32_t maxbytes, uint32_t maxNurseryBytes, JSRuntime* parentRuntime)
{ {
MOZ_ASSERT(JS::detail::libraryInitState == JS::detail::InitState::Running, MOZ_ASSERT(jsInitState == Running,
"must call JS_Init prior to creating any JSRuntimes"); "must call JS_Init prior to creating any JSRuntimes");
// Make sure that all parent runtimes are the topmost parent. // Make sure that all parent runtimes are the topmost parent.
@@ -479,6 +606,22 @@ JS_DestroyRuntime(JSRuntime* rt)
js_delete(rt); js_delete(rt);
} }
JS_PUBLIC_API(bool)
JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, JS_ICUReallocFn reallocFn, JS_ICUFreeFn freeFn)
{
MOZ_ASSERT(jsInitState == Uninitialized,
"must call JS_SetICUMemoryFunctions before any other JSAPI "
"operation (including JS_Init)");
#if EXPOSE_INTL_API
UErrorCode status = U_ZERO_ERROR;
u_setMemoryFunctions(/* context = */ nullptr, allocFn, reallocFn, freeFn, &status);
return U_SUCCESS(status);
#else
return true;
#endif
}
static JS_CurrentEmbedderTimeFunction currentEmbedderTimeFunction; static JS_CurrentEmbedderTimeFunction currentEmbedderTimeFunction;
JS_PUBLIC_API(void) JS_PUBLIC_API(void)
@@ -5430,6 +5573,14 @@ JS_ObjectIsDate(JSContext* cx, HandleObject obj, bool* isDate)
return true; return true;
} }
JS_PUBLIC_API(void)
JS_ClearDateCaches(JSContext* cx)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
cx->runtime()->dateTimeInfo.updateTimeZoneAdjustment();
}
/************************************************************************/ /************************************************************************/
/* /*
@@ -6202,3 +6353,11 @@ JS::GetObjectZone(JSObject* obj)
{ {
return obj->zone(); return obj->zone();
} }
JS_PUBLIC_API(void)
JS::ResetTimeZone()
{
#if ENABLE_INTL_API && defined(ICU_TZ_HAS_RECREATE_DEFAULT)
icu::TimeZone::recreateDefault();
#endif
}

View File

@@ -40,6 +40,9 @@
namespace JS { namespace JS {
extern JS_PUBLIC_API(void)
ResetTimeZone();
class TwoByteChars; class TwoByteChars;
#ifdef JS_DEBUG #ifdef JS_DEBUG
@@ -950,14 +953,49 @@ JS_IsBuiltinFunctionConstructor(JSFunction* fun);
/************************************************************************/ /************************************************************************/
/* /*
* Locking, contexts, and memory allocation. * Initialization, locking, contexts, and memory allocation.
* *
* It is important that SpiderMonkey be initialized, and the first runtime and * It is important that the first runtime and first context be created in a
* first context be created, in a single-threaded fashion. Otherwise the * single-threaded fashion, otherwise the behavior of the library is undefined.
* behavior of the library is undefined.
* See: http://developer.mozilla.org/en/docs/Category:JSAPI_Reference * See: http://developer.mozilla.org/en/docs/Category:JSAPI_Reference
*/ */
/**
* Initialize SpiderMonkey, returning true only if initialization succeeded.
* Once this method has succeeded, it is safe to call JS_NewRuntime and other
* JSAPI methods.
*
* This method must be called before any other JSAPI method is used on any
* thread. Once it has been used, it is safe to call any JSAPI method, and it
* remains safe to do so until JS_ShutDown is correctly called.
*
* It is currently not possible to initialize SpiderMonkey multiple times (that
* is, calling JS_Init/JSAPI methods/JS_ShutDown in that order, then doing so
* again). This restriction may eventually be lifted.
*/
extern JS_PUBLIC_API(bool)
JS_Init(void);
/**
* Destroy free-standing resources allocated by SpiderMonkey, not associated
* with any runtime, context, or other structure.
*
* This method should be called after all other JSAPI data has been properly
* cleaned up: every new runtime must have been destroyed, every new context
* must have been destroyed, and so on. Calling this method before all other
* resources have been destroyed has undefined behavior.
*
* Failure to call this method, at present, has no adverse effects other than
* leaking memory. This may not always be the case; it's recommended that all
* embedders call this method when all other JSAPI operations have completed.
*
* It is currently not possible to initialize SpiderMonkey multiple times (that
* is, calling JS_Init/JSAPI methods/JS_ShutDown in that order, then doing so
* again). This restriction may eventually be lifted.
*/
extern JS_PUBLIC_API(void)
JS_ShutDown(void);
extern JS_PUBLIC_API(JSRuntime*) extern JS_PUBLIC_API(JSRuntime*)
JS_NewRuntime(uint32_t maxbytes, JS_NewRuntime(uint32_t maxbytes,
uint32_t maxNurseryBytes = JS::DefaultNurseryBytes, uint32_t maxNurseryBytes = JS::DefaultNurseryBytes,
@@ -966,6 +1004,20 @@ JS_NewRuntime(uint32_t maxbytes,
extern JS_PUBLIC_API(void) extern JS_PUBLIC_API(void)
JS_DestroyRuntime(JSRuntime* rt); JS_DestroyRuntime(JSRuntime* rt);
// These are equivalent to ICU's |UMemAllocFn|, |UMemReallocFn|, and
// |UMemFreeFn| types. The first argument (called |context| in the ICU docs)
// will always be nullptr, and should be ignored.
typedef void* (*JS_ICUAllocFn)(const void*, size_t size);
typedef void* (*JS_ICUReallocFn)(const void*, void* p, size_t size);
typedef void (*JS_ICUFreeFn)(const void*, void* p);
/**
* This function can be used to track memory used by ICU.
* Do not use it unless you know what you are doing!
*/
extern JS_PUBLIC_API(bool)
JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, JS_ICUReallocFn reallocFn, JS_ICUFreeFn freeFn);
typedef double (*JS_CurrentEmbedderTimeFunction)(); typedef double (*JS_CurrentEmbedderTimeFunction)();
/** /**
@@ -4940,6 +4992,13 @@ JS_NewDateObject(JSContext* cx, int year, int mon, int mday, int hour, int min,
extern JS_PUBLIC_API(bool) extern JS_PUBLIC_API(bool)
JS_ObjectIsDate(JSContext* cx, JS::HandleObject obj, bool* isDate); JS_ObjectIsDate(JSContext* cx, JS::HandleObject obj, bool* isDate);
/**
* Clears the cache of calculated local time from each Date object.
* Call to propagate a system timezone change.
*/
extern JS_PUBLIC_API(void)
JS_ClearDateCaches(JSContext* cx);
/************************************************************************/ /************************************************************************/
/* /*

View File

@@ -18,7 +18,6 @@
#include "gc/Marking.h" #include "gc/Marking.h"
#include "jit/JitCompartment.h" #include "jit/JitCompartment.h"
#include "js/Date.h"
#include "js/Proxy.h" #include "js/Proxy.h"
#include "js/RootingAPI.h" #include "js/RootingAPI.h"
#include "proxy/DeadObjectProxy.h" #include "proxy/DeadObjectProxy.h"
@@ -121,10 +120,11 @@ JSCompartment::init(JSContext* maybecx)
* *
* As a hack, we clear our timezone cache every time we create a new * As a hack, we clear our timezone cache every time we create a new
* compartment. This ensures that the cache is always relatively fresh, but * compartment. This ensures that the cache is always relatively fresh, but
* shouldn't interfere with benchmarks that create tons of date objects * shouldn't interfere with benchmarks which create tons of date objects
* (unless they also create tons of iframes, which seems unlikely). * (unless they also create tons of iframes, which seems unlikely).
*/ */
JS::ResetTimeZone(); if (maybecx)
maybecx->runtime()->dateTimeInfo.updateTimeZoneAdjustment();
if (!crossCompartmentWrappers.init(0)) { if (!crossCompartmentWrappers.init(0)) {
if (maybecx) if (maybecx)

View File

@@ -407,7 +407,7 @@ EquivalentYearForDST(int year)
/* ES5 15.9.1.8. */ /* ES5 15.9.1.8. */
static double static double
DaylightSavingTA(double t) DaylightSavingTA(double t, DateTimeInfo* dtInfo)
{ {
if (!IsFinite(t)) if (!IsFinite(t))
return GenericNaN(); return GenericNaN();
@@ -423,30 +423,29 @@ DaylightSavingTA(double t)
} }
int64_t utcMilliseconds = static_cast<int64_t>(t); int64_t utcMilliseconds = static_cast<int64_t>(t);
int64_t offsetMilliseconds = DateTimeInfo::getDSTOffsetMilliseconds(utcMilliseconds); int64_t offsetMilliseconds = dtInfo->getDSTOffsetMilliseconds(utcMilliseconds);
return static_cast<double>(offsetMilliseconds); return static_cast<double>(offsetMilliseconds);
} }
static double static double
AdjustTime(double date) AdjustTime(double date, DateTimeInfo* dtInfo)
{ {
double localTZA = DateTimeInfo::localTZA(); double t = DaylightSavingTA(date, dtInfo) + dtInfo->localTZA();
double t = DaylightSavingTA(date) + localTZA; t = (dtInfo->localTZA() >= 0) ? fmod(t, msPerDay) : -fmod(msPerDay - t, msPerDay);
t = (localTZA >= 0) ? fmod(t, msPerDay) : -fmod(msPerDay - t, msPerDay);
return t; return t;
} }
/* ES5 15.9.1.9. */ /* ES5 15.9.1.9. */
static double static double
LocalTime(double t) LocalTime(double t, DateTimeInfo* dtInfo)
{ {
return t + AdjustTime(t); return t + AdjustTime(t, dtInfo);
} }
static double static double
UTC(double t) UTC(double t, DateTimeInfo* dtInfo)
{ {
return t - AdjustTime(t - DateTimeInfo::localTZA()); return t - AdjustTime(t - dtInfo->localTZA(), dtInfo);
} }
/* ES5 15.9.1.10. */ /* ES5 15.9.1.10. */
@@ -765,7 +764,7 @@ DaysInMonth(int year, int month)
*/ */
template <typename CharT> template <typename CharT>
static bool static bool
ParseISODate(const CharT* s, size_t length, ClippedTime* result) ParseISODate(const CharT* s, size_t length, ClippedTime* result, DateTimeInfo* dtInfo)
{ {
size_t i = 0; size_t i = 0;
int tzMul = 1; int tzMul = 1;
@@ -865,7 +864,7 @@ ParseISODate(const CharT* s, size_t length, ClippedTime* result)
MakeTime(hour, min, sec, frac * 1000.0)); MakeTime(hour, min, sec, frac * 1000.0));
if (isLocalTime) if (isLocalTime)
msec = UTC(msec); msec = UTC(msec, dtInfo);
else else
msec -= tzMul * (tzHour * msPerHour + tzMin * msPerMinute); msec -= tzMul * (tzHour * msPerHour + tzMin * msPerMinute);
@@ -880,9 +879,9 @@ ParseISODate(const CharT* s, size_t length, ClippedTime* result)
template <typename CharT> template <typename CharT>
static bool static bool
ParseDate(const CharT* s, size_t length, ClippedTime* result) ParseDate(const CharT* s, size_t length, ClippedTime* result, DateTimeInfo* dtInfo)
{ {
if (ParseISODate(s, length, result)) if (ParseISODate(s, length, result, dtInfo))
return true; return true;
if (length == 0) if (length == 0)
@@ -1145,7 +1144,7 @@ ParseDate(const CharT* s, size_t length, ClippedTime* result)
double msec = MakeDate(MakeDay(year, mon, mday), MakeTime(hour, min, sec, 0)); double msec = MakeDate(MakeDay(year, mon, mday), MakeTime(hour, min, sec, 0));
if (tzOffset == -1) /* no time zone specified, have to use local */ if (tzOffset == -1) /* no time zone specified, have to use local */
msec = UTC(msec); msec = UTC(msec, dtInfo);
else else
msec += tzOffset * msPerMinute; msec += tzOffset * msPerMinute;
@@ -1154,12 +1153,12 @@ ParseDate(const CharT* s, size_t length, ClippedTime* result)
} }
static bool static bool
ParseDate(JSLinearString* s, ClippedTime* result) ParseDate(JSLinearString* s, ClippedTime* result, DateTimeInfo* dtInfo)
{ {
AutoCheckCannotGC nogc; AutoCheckCannotGC nogc;
return s->hasLatin1Chars() return s->hasLatin1Chars()
? ParseDate(s->latin1Chars(nogc), s->length(), result) ? ParseDate(s->latin1Chars(nogc), s->length(), result, dtInfo)
: ParseDate(s->twoByteChars(nogc), s->length(), result); : ParseDate(s->twoByteChars(nogc), s->length(), result, dtInfo);
} }
static bool static bool
@@ -1180,7 +1179,7 @@ date_parse(JSContext* cx, unsigned argc, Value* vp)
return false; return false;
ClippedTime result; ClippedTime result;
if (!ParseDate(linearStr, &result)) { if (!ParseDate(linearStr, &result, &cx->runtime()->dateTimeInfo)) {
args.rval().setNaN(); args.rval().setNaN();
return true; return true;
} }
@@ -1220,17 +1219,17 @@ DateObject::setUTCTime(ClippedTime t, MutableHandleValue vp)
} }
void void
DateObject::fillLocalTimeSlots() DateObject::fillLocalTimeSlots(DateTimeInfo* dtInfo)
{ {
/* Check if the cache is already populated. */ /* Check if the cache is already populated. */
if (!getReservedSlot(LOCAL_TIME_SLOT).isUndefined() && if (!getReservedSlot(LOCAL_TIME_SLOT).isUndefined() &&
getReservedSlot(TZA_SLOT).toDouble() == DateTimeInfo::localTZA()) getReservedSlot(TZA_SLOT).toDouble() == dtInfo->localTZA())
{ {
return; return;
} }
/* Remember timezone used to generate the local cache. */ /* Remember timezone used to generate the local cache. */
setReservedSlot(TZA_SLOT, DoubleValue(DateTimeInfo::localTZA())); setReservedSlot(TZA_SLOT, DoubleValue(dtInfo->localTZA()));
double utcTime = UTCTime().toNumber(); double utcTime = UTCTime().toNumber();
@@ -1240,7 +1239,7 @@ DateObject::fillLocalTimeSlots()
return; return;
} }
double localTime = LocalTime(utcTime); double localTime = LocalTime(utcTime, dtInfo);
setReservedSlot(LOCAL_TIME_SLOT, DoubleValue(localTime)); setReservedSlot(LOCAL_TIME_SLOT, DoubleValue(localTime));
@@ -1350,9 +1349,9 @@ DateObject::fillLocalTimeSlots()
} }
inline double inline double
DateObject::cachedLocalTime() DateObject::cachedLocalTime(DateTimeInfo* dtInfo)
{ {
fillLocalTimeSlots(); fillLocalTimeSlots(dtInfo);
return getReservedSlot(LOCAL_TIME_SLOT).toDouble(); return getReservedSlot(LOCAL_TIME_SLOT).toDouble();
} }
@@ -1383,7 +1382,7 @@ date_getTime(JSContext* cx, unsigned argc, Value* vp)
DateObject::getYear_impl(JSContext* cx, const CallArgs& args) DateObject::getYear_impl(JSContext* cx, const CallArgs& args)
{ {
DateObject* dateObj = &args.thisv().toObject().as<DateObject>(); DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
dateObj->fillLocalTimeSlots(); dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
Value yearVal = dateObj->getReservedSlot(LOCAL_YEAR_SLOT); Value yearVal = dateObj->getReservedSlot(LOCAL_YEAR_SLOT);
if (yearVal.isInt32()) { if (yearVal.isInt32()) {
@@ -1408,7 +1407,7 @@ date_getYear(JSContext* cx, unsigned argc, Value* vp)
DateObject::getFullYear_impl(JSContext* cx, const CallArgs& args) DateObject::getFullYear_impl(JSContext* cx, const CallArgs& args)
{ {
DateObject* dateObj = &args.thisv().toObject().as<DateObject>(); DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
dateObj->fillLocalTimeSlots(); dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
args.rval().set(dateObj->getReservedSlot(LOCAL_YEAR_SLOT)); args.rval().set(dateObj->getReservedSlot(LOCAL_YEAR_SLOT));
return true; return true;
@@ -1443,7 +1442,7 @@ date_getUTCFullYear(JSContext* cx, unsigned argc, Value* vp)
DateObject::getMonth_impl(JSContext* cx, const CallArgs& args) DateObject::getMonth_impl(JSContext* cx, const CallArgs& args)
{ {
DateObject* dateObj = &args.thisv().toObject().as<DateObject>(); DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
dateObj->fillLocalTimeSlots(); dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
args.rval().set(dateObj->getReservedSlot(LOCAL_MONTH_SLOT)); args.rval().set(dateObj->getReservedSlot(LOCAL_MONTH_SLOT));
return true; return true;
@@ -1475,7 +1474,7 @@ date_getUTCMonth(JSContext* cx, unsigned argc, Value* vp)
DateObject::getDate_impl(JSContext* cx, const CallArgs& args) DateObject::getDate_impl(JSContext* cx, const CallArgs& args)
{ {
DateObject* dateObj = &args.thisv().toObject().as<DateObject>(); DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
dateObj->fillLocalTimeSlots(); dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
args.rval().set(dateObj->getReservedSlot(LOCAL_DATE_SLOT)); args.rval().set(dateObj->getReservedSlot(LOCAL_DATE_SLOT));
return true; return true;
@@ -1510,7 +1509,7 @@ date_getUTCDate(JSContext* cx, unsigned argc, Value* vp)
DateObject::getDay_impl(JSContext* cx, const CallArgs& args) DateObject::getDay_impl(JSContext* cx, const CallArgs& args)
{ {
DateObject* dateObj = &args.thisv().toObject().as<DateObject>(); DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
dateObj->fillLocalTimeSlots(); dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
args.rval().set(dateObj->getReservedSlot(LOCAL_DAY_SLOT)); args.rval().set(dateObj->getReservedSlot(LOCAL_DAY_SLOT));
return true; return true;
@@ -1545,7 +1544,7 @@ date_getUTCDay(JSContext* cx, unsigned argc, Value* vp)
DateObject::getHours_impl(JSContext* cx, const CallArgs& args) DateObject::getHours_impl(JSContext* cx, const CallArgs& args)
{ {
DateObject* dateObj = &args.thisv().toObject().as<DateObject>(); DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
dateObj->fillLocalTimeSlots(); dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
args.rval().set(dateObj->getReservedSlot(LOCAL_HOURS_SLOT)); args.rval().set(dateObj->getReservedSlot(LOCAL_HOURS_SLOT));
return true; return true;
@@ -1580,7 +1579,7 @@ date_getUTCHours(JSContext* cx, unsigned argc, Value* vp)
DateObject::getMinutes_impl(JSContext* cx, const CallArgs& args) DateObject::getMinutes_impl(JSContext* cx, const CallArgs& args)
{ {
DateObject* dateObj = &args.thisv().toObject().as<DateObject>(); DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
dateObj->fillLocalTimeSlots(); dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
args.rval().set(dateObj->getReservedSlot(LOCAL_MINUTES_SLOT)); args.rval().set(dateObj->getReservedSlot(LOCAL_MINUTES_SLOT));
return true; return true;
@@ -1617,7 +1616,7 @@ date_getUTCMinutes(JSContext* cx, unsigned argc, Value* vp)
DateObject::getUTCSeconds_impl(JSContext* cx, const CallArgs& args) DateObject::getUTCSeconds_impl(JSContext* cx, const CallArgs& args)
{ {
DateObject* dateObj = &args.thisv().toObject().as<DateObject>(); DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
dateObj->fillLocalTimeSlots(); dateObj->fillLocalTimeSlots(&cx->runtime()->dateTimeInfo);
args.rval().set(dateObj->getReservedSlot(LOCAL_SECONDS_SLOT)); args.rval().set(dateObj->getReservedSlot(LOCAL_SECONDS_SLOT));
return true; return true;
@@ -1655,7 +1654,7 @@ DateObject::getTimezoneOffset_impl(JSContext* cx, const CallArgs& args)
{ {
DateObject* dateObj = &args.thisv().toObject().as<DateObject>(); DateObject* dateObj = &args.thisv().toObject().as<DateObject>();
double utctime = dateObj->UTCTime().toNumber(); double utctime = dateObj->UTCTime().toNumber();
double localtime = dateObj->cachedLocalTime(); double localtime = dateObj->cachedLocalTime(&cx->runtime()->dateTimeInfo);
/* /*
* Return the time zone offset in minutes for the current locale that is * Return the time zone offset in minutes for the current locale that is
@@ -1728,27 +1727,25 @@ GetMinsOrDefault(JSContext* cx, const CallArgs& args, unsigned i, double t, doub
return ToNumber(cx, args[i], mins); return ToNumber(cx, args[i], mins);
} }
/* ES6 20.3.4.23. */ /* ES5 15.9.5.28. */
MOZ_ALWAYS_INLINE bool MOZ_ALWAYS_INLINE bool
date_setMilliseconds_impl(JSContext* cx, const CallArgs& args) date_setMilliseconds_impl(JSContext* cx, const CallArgs& args)
{ {
Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
// Steps 1-2. /* Step 1. */
double t = LocalTime(dateObj->UTCTime().toNumber()); double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo);
// Steps 3-4. /* Step 2. */
double ms; double milli;
if (!ToNumber(cx, args.get(0), &ms)) if (!ToNumber(cx, args.get(0), &milli))
return false; return false;
double time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), milli);
// Step 5. /* Step 3. */
double time = MakeTime(HourFromTime(t), MinFromTime(t), SecFromTime(t), ms); ClippedTime u = TimeClip(UTC(MakeDate(Day(t), time), &cx->runtime()->dateTimeInfo));
// Step 6. /* Steps 4-5. */
ClippedTime u = TimeClip(UTC(MakeDate(Day(t), time)));
// Steps 7-8.
dateObj->setUTCTime(u, args.rval()); dateObj->setUTCTime(u, args.rval());
return true; return true;
} }
@@ -1796,31 +1793,31 @@ date_setSeconds_impl(JSContext* cx, const CallArgs& args)
{ {
Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
// Steps 1-2. /* Step 1. */
double t = LocalTime(dateObj->UTCTime().toNumber()); double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo);
// Steps 3-4. /* Step 2. */
double s; double s;
if (!ToNumber(cx, args.get(0), &s)) if (!ToNumber(cx, args.get(0), &s))
return false; return false;
// Steps 5-6. /* Step 3. */
double milli; double milli;
if (!GetMsecsOrDefault(cx, args, 1, t, &milli)) if (!GetMsecsOrDefault(cx, args, 1, t, &milli))
return false; return false;
// Step 7. /* Step 4. */
double date = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), s, milli)); double date = MakeDate(Day(t), MakeTime(HourFromTime(t), MinFromTime(t), s, milli));
// Step 8. /* Step 5. */
ClippedTime u = TimeClip(UTC(date)); ClippedTime u = TimeClip(UTC(date, &cx->runtime()->dateTimeInfo));
// Step 9. /* Steps 6-7. */
dateObj->setUTCTime(u, args.rval()); dateObj->setUTCTime(u, args.rval());
return true; return true;
} }
/* ES6 20.3.4.26. */ /* ES5 15.9.5.31. */
static bool static bool
date_setSeconds(JSContext* cx, unsigned argc, Value* vp) date_setSeconds(JSContext* cx, unsigned argc, Value* vp)
{ {
@@ -1870,40 +1867,39 @@ date_setMinutes_impl(JSContext* cx, const CallArgs& args)
{ {
Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
// Steps 1-2. /* Step 1. */
double t = LocalTime(dateObj->UTCTime().toNumber()); double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo);
// Steps 3-4. /* Step 2. */
double m; double m;
if (!ToNumber(cx, args.get(0), &m)) if (!ToNumber(cx, args.get(0), &m))
return false; return false;
// Steps 5-6. /* Step 3. */
double s; double s;
if (!GetSecsOrDefault(cx, args, 1, t, &s)) if (!GetSecsOrDefault(cx, args, 1, t, &s))
return false; return false;
// Steps 7-8. /* Step 4. */
double milli; double milli;
if (!GetMsecsOrDefault(cx, args, 2, t, &milli)) if (!GetMsecsOrDefault(cx, args, 2, t, &milli))
return false; return false;
// Step 9. /* Step 5. */
double date = MakeDate(Day(t), MakeTime(HourFromTime(t), m, s, milli)); double date = MakeDate(Day(t), MakeTime(HourFromTime(t), m, s, milli));
// Step 10. /* Step 6. */
ClippedTime u = TimeClip(UTC(date)); ClippedTime u = TimeClip(UTC(date, &cx->runtime()->dateTimeInfo));
// Steps 11-12. /* Steps 7-8. */
dateObj->setUTCTime(u, args.rval()); dateObj->setUTCTime(u, args.rval());
return true; return true;
} }
/* ES6 20.3.4.24. */ /* ES5 15.9.5.33. */
static bool static bool
date_setMinutes(JSContext* cx, unsigned argc, Value* vp) date_setMinutes(JSContext* cx, unsigned argc, Value* vp)
{ {
// Steps 1-2 (the effectful parts).
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<IsDate, date_setMinutes_impl>(cx, args); return CallNonGenericMethod<IsDate, date_setMinutes_impl>(cx, args);
} }
@@ -1955,36 +1951,36 @@ date_setHours_impl(JSContext* cx, const CallArgs& args)
{ {
Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
// Steps 1-2. /* Step 1. */
double t = LocalTime(dateObj->UTCTime().toNumber()); double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo);
// Steps 3-4. /* Step 2. */
double h; double h;
if (!ToNumber(cx, args.get(0), &h)) if (!ToNumber(cx, args.get(0), &h))
return false; return false;
// Steps 5-6. /* Step 3. */
double m; double m;
if (!GetMinsOrDefault(cx, args, 1, t, &m)) if (!GetMinsOrDefault(cx, args, 1, t, &m))
return false; return false;
// Steps 7-8. /* Step 4. */
double s; double s;
if (!GetSecsOrDefault(cx, args, 2, t, &s)) if (!GetSecsOrDefault(cx, args, 2, t, &s))
return false; return false;
// Steps 9-10. /* Step 5. */
double milli; double milli;
if (!GetMsecsOrDefault(cx, args, 3, t, &milli)) if (!GetMsecsOrDefault(cx, args, 3, t, &milli))
return false; return false;
// Step 11. /* Step 6. */
double date = MakeDate(Day(t), MakeTime(h, m, s, milli)); double date = MakeDate(Day(t), MakeTime(h, m, s, milli));
// Step 12. /* Step 6. */
ClippedTime u = TimeClip(UTC(date)); ClippedTime u = TimeClip(UTC(date, &cx->runtime()->dateTimeInfo));
// Steps 13-14. /* Steps 7-8. */
dateObj->setUTCTime(u, args.rval()); dateObj->setUTCTime(u, args.rval());
return true; return true;
} }
@@ -2050,7 +2046,7 @@ date_setDate_impl(JSContext* cx, const CallArgs& args)
Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
/* Step 1. */ /* Step 1. */
double t = LocalTime(dateObj->UTCTime().toNumber()); double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo);
/* Step 2. */ /* Step 2. */
double date; double date;
@@ -2061,7 +2057,7 @@ date_setDate_impl(JSContext* cx, const CallArgs& args)
double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t)); double newDate = MakeDate(MakeDay(YearFromTime(t), MonthFromTime(t), date), TimeWithinDay(t));
/* Step 4. */ /* Step 4. */
ClippedTime u = TimeClip(UTC(newDate)); ClippedTime u = TimeClip(UTC(newDate, &cx->runtime()->dateTimeInfo));
/* Steps 5-6. */ /* Steps 5-6. */
dateObj->setUTCTime(u, args.rval()); dateObj->setUTCTime(u, args.rval());
@@ -2134,7 +2130,7 @@ date_setMonth_impl(JSContext* cx, const CallArgs& args)
Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
/* Step 1. */ /* Step 1. */
double t = LocalTime(dateObj->UTCTime().toNumber()); double t = LocalTime(dateObj->UTCTime().toNumber(), &cx->runtime()->dateTimeInfo);
/* Step 2. */ /* Step 2. */
double m; double m;
@@ -2150,7 +2146,7 @@ date_setMonth_impl(JSContext* cx, const CallArgs& args)
double newDate = MakeDate(MakeDay(YearFromTime(t), m, date), TimeWithinDay(t)); double newDate = MakeDate(MakeDay(YearFromTime(t), m, date), TimeWithinDay(t));
/* Step 5. */ /* Step 5. */
ClippedTime u = TimeClip(UTC(newDate)); ClippedTime u = TimeClip(UTC(newDate, &cx->runtime()->dateTimeInfo));
/* Steps 6-7. */ /* Steps 6-7. */
dateObj->setUTCTime(u, args.rval()); dateObj->setUTCTime(u, args.rval());
@@ -2202,12 +2198,12 @@ date_setUTCMonth(JSContext* cx, unsigned argc, Value* vp)
} }
static double static double
ThisLocalTimeOrZero(Handle<DateObject*> dateObj) ThisLocalTimeOrZero(Handle<DateObject*> dateObj, DateTimeInfo* dtInfo)
{ {
double t = dateObj->UTCTime().toNumber(); double t = dateObj->UTCTime().toNumber();
if (IsNaN(t)) if (IsNaN(t))
return +0; return +0;
return LocalTime(t); return LocalTime(t, dtInfo);
} }
static double static double
@@ -2224,7 +2220,7 @@ date_setFullYear_impl(JSContext* cx, const CallArgs& args)
Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
/* Step 1. */ /* Step 1. */
double t = ThisLocalTimeOrZero(dateObj); double t = ThisLocalTimeOrZero(dateObj, &cx->runtime()->dateTimeInfo);
/* Step 2. */ /* Step 2. */
double y; double y;
@@ -2245,7 +2241,7 @@ date_setFullYear_impl(JSContext* cx, const CallArgs& args)
double newDate = MakeDate(MakeDay(y, m, date), TimeWithinDay(t)); double newDate = MakeDate(MakeDay(y, m, date), TimeWithinDay(t));
/* Step 6. */ /* Step 6. */
ClippedTime u = TimeClip(UTC(newDate)); ClippedTime u = TimeClip(UTC(newDate, &cx->runtime()->dateTimeInfo));
/* Steps 7-8. */ /* Steps 7-8. */
dateObj->setUTCTime(u, args.rval()); dateObj->setUTCTime(u, args.rval());
@@ -2308,7 +2304,7 @@ date_setYear_impl(JSContext* cx, const CallArgs& args)
Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>()); Rooted<DateObject*> dateObj(cx, &args.thisv().toObject().as<DateObject>());
/* Step 1. */ /* Step 1. */
double t = ThisLocalTimeOrZero(dateObj); double t = ThisLocalTimeOrZero(dateObj, &cx->runtime()->dateTimeInfo);
/* Step 2. */ /* Step 2. */
double y; double y;
@@ -2330,7 +2326,7 @@ date_setYear_impl(JSContext* cx, const CallArgs& args)
double day = MakeDay(yint, MonthFromTime(t), DateFromTime(t)); double day = MakeDay(yint, MonthFromTime(t), DateFromTime(t));
/* Step 6. */ /* Step 6. */
double u = UTC(MakeDate(day, TimeWithinDay(t))); double u = UTC(MakeDate(day, TimeWithinDay(t)), &cx->runtime()->dateTimeInfo);
/* Steps 7-8. */ /* Steps 7-8. */
dateObj->setUTCTime(TimeClip(u), args.rval()); dateObj->setUTCTime(TimeClip(u), args.rval());
@@ -2509,7 +2505,7 @@ date_toJSON(JSContext* cx, unsigned argc, Value* vp)
/* for Date.toLocaleFormat; interface to PRMJTime date struct. /* for Date.toLocaleFormat; interface to PRMJTime date struct.
*/ */
static void static void
new_explode(double timeval, PRMJTime* split) new_explode(double timeval, PRMJTime* split, DateTimeInfo* dtInfo)
{ {
double year = YearFromTime(timeval); double year = YearFromTime(timeval);
@@ -2525,7 +2521,7 @@ new_explode(double timeval, PRMJTime* split)
/* not sure how this affects things, but it doesn't seem /* not sure how this affects things, but it doesn't seem
to matter. */ to matter. */
split->tm_isdst = (DaylightSavingTA(timeval) != 0); split->tm_isdst = (DaylightSavingTA(timeval, dtInfo) != 0);
} }
typedef enum formatspec { typedef enum formatspec {
@@ -2547,11 +2543,11 @@ date_format(JSContext* cx, double date, formatspec format, MutableHandleValue rv
} else { } else {
MOZ_ASSERT(NumbersAreIdentical(TimeClip(date).toDouble(), date)); MOZ_ASSERT(NumbersAreIdentical(TimeClip(date).toDouble(), date));
double local = LocalTime(date); double local = LocalTime(date, &cx->runtime()->dateTimeInfo);
/* offset from GMT in minutes. The offset includes daylight savings, /* offset from GMT in minutes. The offset includes daylight savings,
if it applies. */ if it applies. */
int minutes = (int) floor(AdjustTime(date) / msPerMinute); int minutes = (int) floor(AdjustTime(date, &cx->runtime()->dateTimeInfo) / msPerMinute);
/* map 510 minutes to 0830 hours */ /* map 510 minutes to 0830 hours */
int offset = (minutes / 60) * 100 + minutes % 60; int offset = (minutes / 60) * 100 + minutes % 60;
@@ -2567,7 +2563,7 @@ date_format(JSContext* cx, double date, formatspec format, MutableHandleValue rv
/* get a timezone string from the OS to include as a /* get a timezone string from the OS to include as a
comment. */ comment. */
new_explode(date, &split); new_explode(date, &split, &cx->runtime()->dateTimeInfo);
if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) { if (PRMJ_FormatTime(tzbuf, sizeof tzbuf, "(%Z)", &split) != 0) {
/* Decide whether to use the resulting timezone string. /* Decide whether to use the resulting timezone string.
@@ -2657,9 +2653,9 @@ ToLocaleFormatHelper(JSContext* cx, HandleObject obj, const char* format, Mutabl
JS_snprintf(buf, sizeof buf, js_NaN_date_str); JS_snprintf(buf, sizeof buf, js_NaN_date_str);
} else { } else {
int result_len; int result_len;
double local = LocalTime(utctime); double local = LocalTime(utctime, &cx->runtime()->dateTimeInfo);
PRMJTime split; PRMJTime split;
new_explode(local, &split); new_explode(local, &split, &cx->runtime()->dateTimeInfo);
/* Let PRMJTime format it. */ /* Let PRMJTime format it. */
result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split); result_len = PRMJ_FormatTime(buf, sizeof buf, format, &split);
@@ -2677,7 +2673,7 @@ ToLocaleFormatHelper(JSContext* cx, HandleObject obj, const char* format, Mutabl
/* ...but not if starts with 4-digit year, like 2022/3/11. */ /* ...but not if starts with 4-digit year, like 2022/3/11. */
!(isdigit(buf[0]) && isdigit(buf[1]) && !(isdigit(buf[0]) && isdigit(buf[1]) &&
isdigit(buf[2]) && isdigit(buf[3]))) { isdigit(buf[2]) && isdigit(buf[3]))) {
double localtime = obj->as<DateObject>().cachedLocalTime(); double localtime = obj->as<DateObject>().cachedLocalTime(&cx->runtime()->dateTimeInfo);
int year = IsNaN(localtime) ? 0 : (int) YearFromTime(localtime); int year = IsNaN(localtime) ? 0 : (int) YearFromTime(localtime);
JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2), JS_snprintf(buf + (result_len - 2), (sizeof buf) - (result_len - 2),
"%d", year); "%d", year);
@@ -3074,7 +3070,7 @@ DateOneArgument(JSContext* cx, const CallArgs& args)
if (!linearStr) if (!linearStr)
return false; return false;
if (!ParseDate(linearStr, &t)) if (!ParseDate(linearStr, &t, &cx->runtime()->dateTimeInfo))
t = ClippedTime::invalid(); t = ClippedTime::invalid();
} else { } else {
double d; double d;
@@ -3163,7 +3159,7 @@ DateMultipleArguments(JSContext* cx, const CallArgs& args)
double finalDate = MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli)); double finalDate = MakeDate(MakeDay(yr, m, dt), MakeTime(h, min, s, milli));
// Steps 3q-t. // Steps 3q-t.
return NewDateObject(cx, args, TimeClip(UTC(finalDate))); return NewDateObject(cx, args, TimeClip(UTC(finalDate, &cx->runtime()->dateTimeInfo)));
} }
return ToDateString(cx, args, NowAsMillis()); return ToDateString(cx, args, NowAsMillis());
@@ -3275,7 +3271,7 @@ js::NewDateObject(JSContext* cx, int year, int mon, int mday,
{ {
MOZ_ASSERT(mon < 12); MOZ_ASSERT(mon < 12);
double msec_time = MakeDate(MakeDay(year, mon, mday), MakeTime(hour, min, sec, 0.0)); double msec_time = MakeDate(MakeDay(year, mon, mday), MakeTime(hour, min, sec, 0.0));
return NewDateObjectMsec(cx, TimeClip(UTC(msec_time))); return NewDateObjectMsec(cx, TimeClip(UTC(msec_time, &cx->runtime()->dateTimeInfo)));
} }
JS_FRIEND_API(bool) JS_FRIEND_API(bool)

View File

@@ -114,7 +114,6 @@ EXPORTS.js += [
'../public/HashTable.h', '../public/HashTable.h',
'../public/HeapAPI.h', '../public/HeapAPI.h',
'../public/Id.h', '../public/Id.h',
'../public/Initialization.h',
'../public/LegacyIntTypes.h', '../public/LegacyIntTypes.h',
'../public/MemoryMetrics.h', '../public/MemoryMetrics.h',
'../public/Principals.h', '../public/Principals.h',
@@ -363,7 +362,6 @@ SOURCES += [
'jsatom.cpp', 'jsatom.cpp',
'jsmath.cpp', 'jsmath.cpp',
'jsutil.cpp', 'jsutil.cpp',
'vm/Initialization.cpp',
] ]
if CONFIG['JS_POSIX_NSPR']: if CONFIG['JS_POSIX_NSPR']:

View File

@@ -67,7 +67,6 @@
#include "jit/OptimizationTracking.h" #include "jit/OptimizationTracking.h"
#include "js/Debug.h" #include "js/Debug.h"
#include "js/GCAPI.h" #include "js/GCAPI.h"
#include "js/Initialization.h"
#include "js/StructuredClone.h" #include "js/StructuredClone.h"
#include "js/TrackedOptimizationInfo.h" #include "js/TrackedOptimizationInfo.h"
#include "perf/jsperf.h" #include "perf/jsperf.h"

View File

@@ -14,6 +14,8 @@
namespace js { namespace js {
class DateTimeInfo;
class DateObject : public NativeObject class DateObject : public NativeObject
{ {
static const uint32_t UTC_TIME_SLOT = 0; static const uint32_t UTC_TIME_SLOT = 0;
@@ -56,12 +58,12 @@ class DateObject : public NativeObject
void setUTCTime(JS::ClippedTime t); void setUTCTime(JS::ClippedTime t);
void setUTCTime(JS::ClippedTime t, MutableHandleValue vp); void setUTCTime(JS::ClippedTime t, MutableHandleValue vp);
inline double cachedLocalTime(); inline double cachedLocalTime(DateTimeInfo* dtInfo);
// Cache the local time, year, month, and so forth of the object. // Cache the local time, year, month, and so forth of the object.
// If UTC time is not finite (e.g., NaN), the local time // If UTC time is not finite (e.g., NaN), the local time
// slots will be set to the UTC time without conversion. // slots will be set to the UTC time without conversion.
void fillLocalTimeSlots(); void fillLocalTimeSlots(DateTimeInfo* dtInfo);
static MOZ_ALWAYS_INLINE bool getTime_impl(JSContext* cx, const CallArgs& args); static MOZ_ALWAYS_INLINE bool getTime_impl(JSContext* cx, const CallArgs& args);
static MOZ_ALWAYS_INLINE bool getYear_impl(JSContext* cx, const CallArgs& args); static MOZ_ALWAYS_INLINE bool getYear_impl(JSContext* cx, const CallArgs& args);

View File

@@ -10,19 +10,8 @@
#include "jsutil.h" #include "jsutil.h"
#include "js/Date.h"
#if ENABLE_INTL_API
#include "unicode/timezone.h"
#endif
using mozilla::UnspecifiedNaN; using mozilla::UnspecifiedNaN;
/* static */ js::DateTimeInfo
js::DateTimeInfo::instance;
/* static */ mozilla::Atomic<bool, mozilla::ReleaseAcquire>
js::DateTimeInfo::AcquireLock::spinLock;
static bool static bool
ComputeLocalTime(time_t local, struct tm* ptm) ComputeLocalTime(time_t local, struct tm* ptm)
{ {
@@ -142,7 +131,7 @@ UTCToLocalStandardOffsetSeconds()
} }
void void
js::DateTimeInfo::internalUpdateTimeZoneAdjustment() js::DateTimeInfo::updateTimeZoneAdjustment()
{ {
/* /*
* The difference between local standard time and UTC will never change for * The difference between local standard time and UTC will never change for
@@ -175,19 +164,12 @@ js::DateTimeInfo::internalUpdateTimeZoneAdjustment()
* negative numbers to ensure the first computation is always a cache miss and * negative numbers to ensure the first computation is always a cache miss and
* doesn't return a bogus offset. * doesn't return a bogus offset.
*/ */
/* static */ void js::DateTimeInfo::DateTimeInfo()
js::DateTimeInfo::init()
{ {
DateTimeInfo* dtInfo = &DateTimeInfo::instance;
MOZ_ASSERT(dtInfo->localTZA_ == 0,
"we should be initializing only once, and the static instance "
"should have started out zeroed");
// Set to a totally impossible TZA so that the comparison above will fail // Set to a totally impossible TZA so that the comparison above will fail
// and all fields will be properly initialized. // and all fields will be properly initialized.
dtInfo->localTZA_ = UnspecifiedNaN<double>(); localTZA_ = UnspecifiedNaN<double>();
dtInfo->internalUpdateTimeZoneAdjustment(); updateTimeZoneAdjustment();
} }
int64_t int64_t
@@ -219,7 +201,7 @@ js::DateTimeInfo::computeDSTOffsetMilliseconds(int64_t utcSeconds)
} }
int64_t int64_t
js::DateTimeInfo::internalGetDSTOffsetMilliseconds(int64_t utcMilliseconds) js::DateTimeInfo::getDSTOffsetMilliseconds(int64_t utcMilliseconds)
{ {
sanityCheck(); sanityCheck();
@@ -306,13 +288,3 @@ js::DateTimeInfo::sanityCheck()
MOZ_ASSERT_IF(rangeStartSeconds != INT64_MIN, MOZ_ASSERT_IF(rangeStartSeconds != INT64_MIN,
rangeStartSeconds <= MaxUnixTimeT && rangeEndSeconds <= MaxUnixTimeT); rangeStartSeconds <= MaxUnixTimeT && rangeEndSeconds <= MaxUnixTimeT);
} }
JS_PUBLIC_API(void)
JS::ResetTimeZone()
{
DateTimeInfo::updateTimeZoneAdjustment();
#if ENABLE_INTL_API && defined(ICU_TZ_HAS_RECREATE_DEFAULT)
icu::TimeZone::recreateDefault();
#endif
}

View File

@@ -7,17 +7,12 @@
#ifndef vm_DateTime_h #ifndef vm_DateTime_h
#define vm_DateTime_h #define vm_DateTime_h
#include "mozilla/Assertions.h"
#include "mozilla/Atomics.h"
#include "mozilla/Attributes.h"
#include "mozilla/FloatingPoint.h" #include "mozilla/FloatingPoint.h"
#include "mozilla/MathAlgorithms.h" #include "mozilla/MathAlgorithms.h"
#include <stdint.h> #include <stdint.h>
#include "js/Conversions.h" #include "js/Conversions.h"
#include "js/Date.h"
#include "js/Initialization.h"
#include "js/Value.h" #include "js/Value.h"
namespace js { namespace js {
@@ -93,71 +88,23 @@ const double EndOfTime = 8.64e15;
*/ */
class DateTimeInfo class DateTimeInfo
{ {
static DateTimeInfo instance;
// Date/time info is shared across all threads in DateTimeInfo::instance,
// for consistency with ICU's handling of its default time zone. Thus we
// need something to protect concurrent accesses.
//
// The spec implicitly assumes DST and time zone adjustment information
// never change in the course of a function -- sometimes even across
// reentrancy. So make critical sections as narrow as possible, and use a
// bog-standard spinlock with busy-waiting in case of contention for
// simplicity.
class MOZ_RAII AcquireLock
{
static mozilla::Atomic<bool, mozilla::ReleaseAcquire> spinLock;
public: public:
AcquireLock() { DateTimeInfo();
while (!spinLock.compareExchange(false, true))
continue;
}
~AcquireLock() {
MOZ_ASSERT(spinLock, "spinlock should have been acquired");
spinLock = false;
}
};
friend bool ::JS_Init();
// Initialize global date/time tracking state. This operation occurs
// during, and is restricted to, SpiderMonkey initialization.
static void init();
public:
/* /*
* Get the DST offset in milliseconds at a UTC time. This is usually * Get the DST offset in milliseconds at a UTC time. This is usually
* either 0 or |msPerSecond * SecondsPerHour|, but at least one exotic time * either 0 or |msPerSecond * SecondsPerHour|, but at least one exotic time
* zone (Lord Howe Island, Australia) has a fractional-hour offset, just to * zone (Lord Howe Island, Australia) has a fractional-hour offset, just to
* keep things interesting. * keep things interesting.
*/ */
static int64_t getDSTOffsetMilliseconds(int64_t utcMilliseconds) { int64_t getDSTOffsetMilliseconds(int64_t utcMilliseconds);
AcquireLock lock;
return DateTimeInfo::instance.internalGetDSTOffsetMilliseconds(utcMilliseconds); void updateTimeZoneAdjustment();
}
/* ES5 15.9.1.7. */ /* ES5 15.9.1.7. */
static double localTZA() { double localTZA() { return localTZA_; }
AcquireLock lock;
return DateTimeInfo::instance.localTZA_;
}
private: private:
// We don't want anyone accidentally calling *only*
// DateTimeInfo::updateTimeZoneAdjustment() to respond to a system time
// zone change (missing the necessary poking of ICU as well), so ensure
// only JS::ResetTimeZone() can call this via access restrictions.
friend void JS::ResetTimeZone();
static void updateTimeZoneAdjustment() {
AcquireLock lock;
DateTimeInfo::instance.internalUpdateTimeZoneAdjustment();
}
/* /*
* The current local time zone adjustment, cached because retrieving this * The current local time zone adjustment, cached because retrieving this
* dynamically is Slow, and a certain venerable benchmark which shall not * dynamically is Slow, and a certain venerable benchmark which shall not
@@ -166,7 +113,7 @@ class DateTimeInfo
* SpiderMonkey occasionally and arbitrarily updates this value from the * SpiderMonkey occasionally and arbitrarily updates this value from the
* system time zone to attempt to keep this reasonably up-to-date. If * system time zone to attempt to keep this reasonably up-to-date. If
* temporary inaccuracy can't be tolerated, JSAPI clients may call * temporary inaccuracy can't be tolerated, JSAPI clients may call
* JS::ResetTimeZone to forcibly sync this with the system time zone. * JS_ClearDateCaches to forcibly sync this with the system time zone.
*/ */
double localTZA_; double localTZA_;
@@ -194,9 +141,6 @@ class DateTimeInfo
static const int64_t RangeExpansionAmount = 30 * SecondsPerDay; static const int64_t RangeExpansionAmount = 30 * SecondsPerDay;
int64_t internalGetDSTOffsetMilliseconds(int64_t utcMilliseconds);
void internalUpdateTimeZoneAdjustment();
void sanityCheck(); void sanityCheck();
}; };

View File

@@ -1,166 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 tw=99:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* SpiderMonkey initialization and shutdown code. */
#include "js/Initialization.h"
#include "mozilla/Assertions.h"
#include <ctype.h>
#include "jstypes.h"
#include "builtin/AtomicsObject.h"
#include "jit/ExecutableAllocator.h"
#include "jit/Ion.h"
#include "js/Utility.h"
#if ENABLE_INTL_API
#include "unicode/uclean.h"
#include "unicode/utypes.h"
#endif // ENABLE_INTL_API
#include "vm/DateTime.h"
#include "vm/HelperThreads.h"
#include "vm/Runtime.h"
#include "vm/Time.h"
#include "vm/TraceLogging.h"
using JS::detail::InitState;
using JS::detail::libraryInitState;
using js::FutexRuntime;
InitState JS::detail::libraryInitState;
#ifdef DEBUG
static unsigned
MessageParameterCount(const char* format)
{
unsigned numfmtspecs = 0;
for (const char* fmt = format; *fmt != '\0'; fmt++) {
if (*fmt == '{' && isdigit(fmt[1]))
++numfmtspecs;
}
return numfmtspecs;
}
static void
CheckMessageParameterCounts()
{
// Assert that each message format has the correct number of braced
// parameters.
# define MSG_DEF(name, count, exception, format) \
MOZ_ASSERT(MessageParameterCount(format) == count);
# include "js.msg"
# undef MSG_DEF
}
#endif /* DEBUG */
JS_PUBLIC_API(bool)
JS_Init(void)
{
MOZ_ASSERT(libraryInitState == InitState::Uninitialized,
"must call JS_Init once before any JSAPI operation except "
"JS_SetICUMemoryFunctions");
MOZ_ASSERT(!JSRuntime::hasLiveRuntimes(),
"how do we have live runtimes before JS_Init?");
PRMJ_NowInit();
#ifdef DEBUG
CheckMessageParameterCounts();
#endif
using js::TlsPerThreadData;
if (!TlsPerThreadData.initialized() && !TlsPerThreadData.init())
return false;
#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
if (!js::oom::InitThreadType())
return false;
js::oom::SetThreadType(js::oom::THREAD_TYPE_MAIN);
#endif
js::jit::ExecutableAllocator::initStatic();
if (!js::jit::InitializeIon())
return false;
js::DateTimeInfo::init();
#if EXPOSE_INTL_API
UErrorCode err = U_ZERO_ERROR;
u_init(&err);
if (U_FAILURE(err))
return false;
#endif // EXPOSE_INTL_API
if (!js::CreateHelperThreadsState())
return false;
if (!FutexRuntime::initialize())
return false;
libraryInitState = InitState::Running;
return true;
}
JS_PUBLIC_API(void)
JS_ShutDown(void)
{
MOZ_ASSERT(libraryInitState == InitState::Running,
"JS_ShutDown must only be called after JS_Init and can't race with it");
#ifdef DEBUG
if (JSRuntime::hasLiveRuntimes()) {
// Gecko is too buggy to assert this just yet.
fprintf(stderr,
"WARNING: YOU ARE LEAKING THE WORLD (at least one JSRuntime "
"and everything alive inside it, that is) AT JS_ShutDown "
"TIME. FIX THIS!\n");
}
#endif
FutexRuntime::destroy();
js::DestroyHelperThreadsState();
#ifdef JS_TRACE_LOGGING
js::DestroyTraceLoggerThreadState();
js::DestroyTraceLoggerGraphState();
#endif
// The only difficult-to-address reason for the restriction that you can't
// call JS_Init/stuff/JS_ShutDown multiple times is the Windows PRMJ
// NowInit initialization code, which uses PR_CallOnce to initialize the
// PRMJ_Now subsystem. (For reinitialization to be permitted, we'd need to
// "reset" the called-once status -- doable, but more trouble than it's
// worth now.) Initializing that subsystem from JS_Init eliminates the
// problem, but initialization can take a comparatively long time (15ms or
// so), so we really don't want to do it in JS_Init, and we really do want
// to do it only when PRMJ_Now is eventually called.
PRMJ_NowShutdown();
#if EXPOSE_INTL_API
u_cleanup();
#endif // EXPOSE_INTL_API
libraryInitState = InitState::ShutDown;
}
JS_PUBLIC_API(bool)
JS_SetICUMemoryFunctions(JS_ICUAllocFn allocFn, JS_ICUReallocFn reallocFn, JS_ICUFreeFn freeFn)
{
MOZ_ASSERT(libraryInitState == InitState::Uninitialized,
"must call JS_SetICUMemoryFunctions before any other JSAPI "
"operation (including JS_Init)");
#if EXPOSE_INTL_API
UErrorCode status = U_ZERO_ERROR;
u_setMemoryFunctions(/* context = */ nullptr, allocFn, reallocFn, freeFn, &status);
return U_SUCCESS(status);
#else
return true;
#endif
}

View File

@@ -45,7 +45,6 @@
#include "jit/JitCompartment.h" #include "jit/JitCompartment.h"
#include "jit/mips32/Simulator-mips32.h" #include "jit/mips32/Simulator-mips32.h"
#include "jit/PcScriptCache.h" #include "jit/PcScriptCache.h"
#include "js/Date.h"
#include "js/MemoryMetrics.h" #include "js/MemoryMetrics.h"
#include "js/SliceBudget.h" #include "js/SliceBudget.h"
#include "vm/Debugger.h" #include "vm/Debugger.h"
@@ -334,7 +333,7 @@ JSRuntime::init(uint32_t maxbytes, uint32_t maxNurseryBytes)
if (!InitRuntimeNumberState(this)) if (!InitRuntimeNumberState(this))
return false; return false;
JS::ResetTimeZone(); dateTimeInfo.updateTimeZoneAdjustment();
#ifdef JS_SIMULATOR #ifdef JS_SIMULATOR
simulator_ = js::jit::Simulator::Create(); simulator_ = js::jit::Simulator::Create();

View File

@@ -1205,6 +1205,7 @@ struct JSRuntime : public JS::shadow::Runtime,
js::LazyScriptCache lazyScriptCache; js::LazyScriptCache lazyScriptCache;
js::CompressedSourceSet compressedSourceSet; js::CompressedSourceSet compressedSourceSet;
js::DateTimeInfo dateTimeInfo;
// Pool of maps used during parse/emit. This may be modified by threads // Pool of maps used during parse/emit. This may be modified by threads
// with an ExclusiveContext and requires a lock. Active compilations // with an ExclusiveContext and requires a lock. Active compilations

View File

@@ -1263,7 +1263,7 @@ intrinsic_LocalTZA(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0, "the LocalTZA intrinsic takes no arguments"); MOZ_ASSERT(args.length() == 0, "the LocalTZA intrinsic takes no arguments");
args.rval().setDouble(DateTimeInfo::localTZA()); args.rval().setDouble(cx->runtime()->dateTimeInfo.localTZA());
return true; return true;
} }

View File

@@ -155,7 +155,6 @@ extern nsresult nsStringInputStreamConstructor(nsISupports*, REFNSIID, void**);
#include "GeckoProfiler.h" #include "GeckoProfiler.h"
#include "jsapi.h" #include "jsapi.h"
#include "js/Initialization.h"
#include "gfxPlatform.h" #include "gfxPlatform.h"