We should support CreateThis in the FTL
[WebKit-https.git] / Source / JavaScriptCore / runtime / DatePrototype.cpp
index c68b2d2..5ead376 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- *  Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *  Copyright (C) 2004-2008, 2016 Apple Inc. All rights reserved.
  *  Copyright (C) 2008, 2009 Torch Mobile, Inc. All rights reserved.
  *  Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
  *
 #include "DateConversion.h"
 #include "DateInstance.h"
 #include "Error.h"
+#include "JSCBuiltins.h"
+#include "JSDateMath.h"
 #include "JSGlobalObject.h"
+#include "JSObject.h"
 #include "JSString.h"
-#include "JSStringBuilder.h"
 #include "Lookup.h"
 #include "ObjectPrototype.h"
-
-#if !PLATFORM(MAC) && HAVE(LANGINFO_H)
-#include <langinfo.h>
-#endif
-
+#include "JSCInlines.h"
 #include <limits.h>
 #include <locale.h>
 #include <math.h>
 #include <stdlib.h>
 #include <time.h>
 #include <wtf/Assertions.h>
-#include <wtf/DateMath.h>
 #include <wtf/MathExtras.h>
-#include <wtf/StringExtras.h>
-#include <wtf/UnusedParam.h>
+
+#if HAVE(LANGINFO_H)
+#include <langinfo.h>
+#endif
 
 #if HAVE(SYS_PARAM_H)
 #include <sys/param.h>
 #include <sys/timeb.h>
 #endif
 
-#if PLATFORM(MAC)
-#include <CoreFoundation/CoreFoundation.h>
+#if !(OS(DARWIN) && USE(CF))
+#include <unicode/udat.h>
 #endif
 
-#if OS(WINCE) && !PLATFORM(QT)
-extern "C" size_t strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t); //provided by libce
+#if USE(CF)
+#include <CoreFoundation/CoreFoundation.h>
 #endif
 
 using namespace WTF;
 
 namespace JSC {
 
-ASSERT_CLASS_FITS_IN_CELL(DatePrototype);
-
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
-static EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToPrimitiveSymbol(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
 
 }
 
@@ -128,12 +124,12 @@ namespace JSC {
 
 enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
  
-#if PLATFORM(MAC)
+#if OS(DARWIN) && USE(CF)
 
-// FIXME: Since this is superior to the strftime-based version, why limit this to PLATFORM(MAC)?
+// FIXME: Since this is superior to the strftime-based version, why limit this to OS(DARWIN)?
 // Instead we should consider using this whenever USE(CF) is true.
 
-static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle)
+static CFDateFormatterStyle styleFromArgString(const String& string, CFDateFormatterStyle defaultStyle)
 {
     if (string == "short")
         return kCFDateFormatterShortStyle;
@@ -152,69 +148,105 @@ static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMil
     CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
 
     bool useCustomFormat = false;
-    UString customFormatString;
+    String customFormatString;
 
-    UString arg0String = exec->argument(0).toString(exec);
+    String arg0String = exec->argument(0).toWTFString(exec);
     if (arg0String == "custom" && !exec->argument(1).isUndefined()) {
         useCustomFormat = true;
-        customFormatString = exec->argument(1).toString(exec);
+        customFormatString = exec->argument(1).toWTFString(exec);
     } else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) {
         dateStyle = styleFromArgString(arg0String, dateStyle);
-        timeStyle = styleFromArgString(exec->argument(1).toString(exec), timeStyle);
+        timeStyle = styleFromArgString(exec->argument(1).toWTFString(exec), timeStyle);
     } else if (format != LocaleTime && !exec->argument(0).isUndefined())
         dateStyle = styleFromArgString(arg0String, dateStyle);
     else if (format != LocaleDate && !exec->argument(0).isUndefined())
         timeStyle = styleFromArgString(arg0String, timeStyle);
 
-    CFLocaleRef locale = CFLocaleCopyCurrent();
-    CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle);
-    CFRelease(locale);
+    CFAbsoluteTime absoluteTime = floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970;
 
-    if (useCustomFormat) {
-        CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, customFormatString.characters(), customFormatString.length());
-        CFDateFormatterSetFormat(formatter, customFormatCFString);
-        CFRelease(customFormatCFString);
-    }
+    auto formatter = adoptCF(CFDateFormatterCreate(kCFAllocatorDefault, adoptCF(CFLocaleCopyCurrent()).get(), dateStyle, timeStyle));
+    if (useCustomFormat)
+        CFDateFormatterSetFormat(formatter.get(), customFormatString.createCFString().get());
+    return jsNontrivialString(exec, adoptCF(CFDateFormatterCreateStringWithAbsoluteTime(kCFAllocatorDefault, formatter.get(), absoluteTime)).get());
+}
 
-    CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970);
+#elif !UCONFIG_NO_FORMATTING
 
-    CFRelease(formatter);
+static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
+{
+    UDateFormatStyle timeStyle = (format != LocaleDate ? UDAT_LONG : UDAT_NONE);
+    UDateFormatStyle dateStyle = (format != LocaleTime ? UDAT_LONG : UDAT_NONE);
 
-    // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters).
-    // That's not great error handling, but it just won't happen so it doesn't matter.
-    UChar buffer[200];
-    const size_t bufferLength = WTF_ARRAY_LENGTH(buffer);
-    size_t length = CFStringGetLength(string);
-    ASSERT(length <= bufferLength);
-    if (length > bufferLength)
-        length = bufferLength;
-    CFStringGetCharacters(string, CFRangeMake(0, length), buffer);
+    UErrorCode status = U_ZERO_ERROR;
+    UDateFormat* df = udat_open(timeStyle, dateStyle, 0, 0, -1, 0, 0, &status);
+    if (!df)
+        return jsEmptyString(exec);
 
-    CFRelease(string);
+    UChar buffer[128];
+    int32_t length;
+    length = udat_format(df, timeInMilliseconds, buffer, 128, 0, &status);
+    udat_close(df);
+    if (status != U_ZERO_ERROR)
+        return jsEmptyString(exec);
 
-    return jsNontrivialString(exec, UString(buffer, length));
+    return jsNontrivialString(exec, String(buffer, length));
 }
 
-#else // !PLATFORM(MAC)
+#else
 
 static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format)
 {
+#if OS(WINDOWS)
+    SYSTEMTIME systemTime;
+    memset(&systemTime, 0, sizeof(systemTime));
+    systemTime.wYear = gdt.year();
+    systemTime.wMonth = gdt.month() + 1;
+    systemTime.wDay = gdt.monthDay();
+    systemTime.wDayOfWeek = gdt.weekDay();
+    systemTime.wHour = gdt.hour();
+    systemTime.wMinute = gdt.minute();
+    systemTime.wSecond = gdt.second();
+
+    Vector<UChar, 128> buffer;
+    size_t length = 0;
+
+    if (format == LocaleDate) {
+        buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0));
+        length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size());
+    } else if (format == LocaleTime) {
+        buffer.resize(GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0));
+        length = GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data(), buffer.size());
+    } else if (format == LocaleDateAndTime) {
+        buffer.resize(GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, 0, 0) + GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, 0, 0));
+        length = GetDateFormatW(LOCALE_USER_DEFAULT, DATE_LONGDATE, &systemTime, 0, buffer.data(), buffer.size());
+        if (length) {
+            buffer[length - 1] = ' ';
+            length += GetTimeFormatW(LOCALE_USER_DEFAULT, 0, &systemTime, 0, buffer.data() + length, buffer.size() - length);
+        }
+    } else
+        RELEASE_ASSERT_NOT_REACHED();
+
+    //  Remove terminating null character.
+    if (length)
+        length--;
+
+    return jsNontrivialString(exec, String(buffer.data(), length));
+
+#else // OS(WINDOWS)
+
 #if HAVE(LANGINFO_H)
     static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT };
-#elif (OS(WINCE) && !PLATFORM(QT)) || OS(SYMBIAN)
-     // strftime() does not support '#' on WinCE or Symbian
-    static const char* const formatStrings[] = { "%c", "%x", "%X" };
 #else
     static const char* const formatStrings[] = { "%#c", "%#x", "%X" };
 #endif
+
     // Offset year if needed
     struct tm localTM = gdt;
-    int year = gdt.year + 1900;
+    int year = gdt.year();
     bool yearNeedsOffset = year < 1900 || year > 2038;
     if (yearNeedsOffset)
         localTM.tm_year = equivalentYearForDST(year) - 1900;
+
 #if HAVE(LANGINFO_H)
     // We do not allow strftime to generate dates with 2-digits years,
     // both to avoid ambiguity, and a crash in strncpy, for years that
@@ -235,19 +267,19 @@ static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, L
 #else
     size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
 #endif
+
     if (ret == 0)
         return jsEmptyString(exec);
+
     // Copy original into the buffer
     if (yearNeedsOffset && format != LocaleTime) {
         static const int yearLen = 5;   // FIXME will be a problem in the year 10,000
         char yearString[yearLen];
+
         snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
         char* yearLocation = strstr(timebuffer, yearString);
         snprintf(yearString, yearLen, "%d", year);
+
         strncpy(yearLocation, yearString, yearLen - 1);
     }
 
@@ -267,22 +299,41 @@ static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, L
     if (length != static_cast<size_t>(-1)) {
         for (size_t i = 0; i < length; ++i)
             buffer[i] = static_cast<UChar>(tempbuffer[i]);
-        return jsNontrivialString(exec, UString(buffer, length));
+        return jsNontrivialString(exec, String(buffer, length));
     }
 #endif
 
     return jsNontrivialString(exec, timebuffer);
+#endif // OS(WINDOWS)
 }
 
 static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format)
 {
     const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec);
     if (!gregorianDateTime)
-        return jsNontrivialString(exec, "Invalid Date");
+        return jsNontrivialString(exec, "Invalid Date"_s);
     return formatLocaleDate(exec, *gregorianDateTime, format);
 }
 
-#endif // !PLATFORM(MAC)
+#endif // OS(DARWIN) && USE(CF)
+
+static EncodedJSValue formateDateInstance(ExecState* exec, DateTimeFormat format, bool asUTCVariant)
+{
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
+
+    const GregorianDateTime* gregorianDateTime = asUTCVariant
+        ? thisDateObj->gregorianDateTimeUTC(exec)
+        : thisDateObj->gregorianDateTime(exec);
+    if (!gregorianDateTime)
+        return JSValue::encode(jsNontrivialString(exec, String("Invalid Date"_s)));
+
+    return JSValue::encode(jsNontrivialString(exec, formatDateTime(*gregorianDateTime, format, asUTCVariant)));
+}
 
 // Converts a list of arguments sent to a Date member function into milliseconds, updating
 // ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
@@ -290,6 +341,9 @@ static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, doubl
 // Format of member function: f([hour,] [min,] [sec,] [ms])
 static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms, GregorianDateTime* t)
 {
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
     double milliseconds = 0;
     bool ok = true;
     int idx = 0;
@@ -301,25 +355,28 @@ static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms
 
     // hours
     if (maxArgs >= 4 && idx < numArgs) {
-        t->hour = 0;
-        double hours = exec->argument(idx++).toIntegerPreserveNaN(exec);
-        ok = isfinite(hours);
+        t->setHour(0);
+        double hours = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
+        RETURN_IF_EXCEPTION(scope, false);
+        ok = std::isfinite(hours);
         milliseconds += hours * msPerHour;
     }
 
     // minutes
     if (maxArgs >= 3 && idx < numArgs && ok) {
-        t->minute = 0;
-        double minutes = exec->argument(idx++).toIntegerPreserveNaN(exec);
-        ok = isfinite(minutes);
+        t->setMinute(0);
+        double minutes = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
+        RETURN_IF_EXCEPTION(scope, false);
+        ok = std::isfinite(minutes);
         milliseconds += minutes * msPerMinute;
     }
     
     // seconds
     if (maxArgs >= 2 && idx < numArgs && ok) {
-        t->second = 0;
-        double seconds = exec->argument(idx++).toIntegerPreserveNaN(exec);
-        ok = isfinite(seconds);
+        t->setSecond(0);
+        double seconds = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
+        RETURN_IF_EXCEPTION(scope, false);
+        ok = std::isfinite(seconds);
         milliseconds += seconds * msPerSecond;
     }
     
@@ -328,8 +385,9 @@ static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms
         
     // milliseconds
     if (idx < numArgs) {
-        double millis = exec->argument(idx).toIntegerPreserveNaN(exec);
-        ok = isfinite(millis);
+        double millis = exec->uncheckedArgument(idx).toIntegerPreserveNaN(exec);
+        RETURN_IF_EXCEPTION(scope, false);
+        ok = std::isfinite(millis);
         milliseconds += millis;
     } else
         milliseconds += *ms;
@@ -344,6 +402,9 @@ static bool fillStructuresUsingTimeArgs(ExecState* exec, int maxArgs, double* ms
 // Format of member function: f([years,] [months,] [days])
 static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms, GregorianDateTime *t)
 {
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+
     int idx = 0;
     bool ok = true;
     int numArgs = exec->argumentCount();
@@ -354,34 +415,36 @@ static bool fillStructuresUsingDateArgs(ExecState *exec, int maxArgs, double *ms
   
     // years
     if (maxArgs >= 3 && idx < numArgs) {
-        double years = exec->argument(idx++).toIntegerPreserveNaN(exec);
-        ok = isfinite(years);
-        t->year = toInt32(years - 1900);
+        double years = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
+        RETURN_IF_EXCEPTION(scope, false);
+        ok = std::isfinite(years);
+        t->setYear(toInt32(years));
     }
     // months
     if (maxArgs >= 2 && idx < numArgs && ok) {
-        double months = exec->argument(idx++).toIntegerPreserveNaN(exec);
-        ok = isfinite(months);
-        t->month = toInt32(months);
+        double months = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
+        RETURN_IF_EXCEPTION(scope, false);
+        ok = std::isfinite(months);
+        t->setMonth(toInt32(months));
     }
     // days
     if (idx < numArgs && ok) {
-        double days = exec->argument(idx++).toIntegerPreserveNaN(exec);
-        ok = isfinite(days);
-        t->monthDay = 0;
+        double days = exec->uncheckedArgument(idx++).toIntegerPreserveNaN(exec);
+        RETURN_IF_EXCEPTION(scope, false);
+        ok = std::isfinite(days);
+        t->setMonthDay(0);
         *ms += days * msPerDay;
     }
     
     return ok;
 }
 
-const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable, CREATE_METHOD_TABLE(DatePrototype)};
+const ClassInfo DatePrototype::s_info = {"Object", &JSNonFinalObject::s_info, &dateTable, nullptr, CREATE_METHOD_TABLE(DatePrototype)};
 
 /* Source for DatePrototype.lut.h
 @begin dateTable
   toString              dateProtoFuncToString                DontEnum|Function       0
   toISOString           dateProtoFuncToISOString             DontEnum|Function       0
-  toUTCString           dateProtoFuncToUTCString             DontEnum|Function       0
   toDateString          dateProtoFuncToDateString            DontEnum|Function       0
   toTimeString          dateProtoFuncToTimeString            DontEnum|Function       0
   toLocaleString        dateProtoFuncToLocaleString          DontEnum|Function       0
@@ -391,7 +454,6 @@ const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecS
   getTime               dateProtoFuncGetTime                 DontEnum|Function       0
   getFullYear           dateProtoFuncGetFullYear             DontEnum|Function       0
   getUTCFullYear        dateProtoFuncGetUTCFullYear          DontEnum|Function       0
-  toGMTString           dateProtoFuncToGMTString             DontEnum|Function       0
   getMonth              dateProtoFuncGetMonth                DontEnum|Function       0
   getUTCMonth           dateProtoFuncGetUTCMonth             DontEnum|Function       0
   getDate               dateProtoFuncGetDate                 DontEnum|Function       0
@@ -430,389 +492,387 @@ const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecS
 
 // ECMA 15.9.4
 
-DatePrototype::DatePrototype(ExecState* exec, Structure* structure)
-    : DateInstance(exec, structure)
+DatePrototype::DatePrototype(VM& vm, Structure* structure)
+    : Base(vm, structure)
 {
 }
 
-void DatePrototype::finishCreation(ExecState* exec, JSGlobalObject*)
+void DatePrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
 {
-    Base::finishCreation(exec->globalData());
-    ASSERT(inherits(&s_info));
-
-    // The constructor will be added later, after DateConstructor has been built.
-}
-
-bool DatePrototype::getOwnPropertySlotVirtual(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
-{
-    return getOwnPropertySlot(this, exec, propertyName, slot);
-}
+    Base::finishCreation(vm);
+    ASSERT(inherits(vm, info()));
+
+    Identifier toUTCStringName = Identifier::fromString(&vm, "toUTCString"_s);
+    JSFunction* toUTCStringFunction = JSFunction::create(vm, globalObject, 0, toUTCStringName.string(), dateProtoFuncToUTCString);
+    putDirectWithoutTransition(vm, toUTCStringName, toUTCStringFunction, static_cast<unsigned>(PropertyAttribute::DontEnum));
+    putDirectWithoutTransition(vm, Identifier::fromString(&vm, "toGMTString"_s), toUTCStringFunction, static_cast<unsigned>(PropertyAttribute::DontEnum));
+
+#if ENABLE(INTL)
+    JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toLocaleString", datePrototypeToLocaleStringCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
+    JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toLocaleDateString", datePrototypeToLocaleDateStringCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
+    JSC_BUILTIN_FUNCTION_WITHOUT_TRANSITION("toLocaleTimeString", datePrototypeToLocaleTimeStringCodeGenerator, static_cast<unsigned>(PropertyAttribute::DontEnum));
+#endif
 
-bool DatePrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
-{
-    return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec), static_cast<DatePrototype*>(cell), propertyName, slot);
-}
+    JSFunction* toPrimitiveFunction = JSFunction::create(vm, globalObject, 1, "[Symbol.toPrimitive]"_s, dateProtoFuncToPrimitiveSymbol, NoIntrinsic);
+    putDirectWithoutTransition(vm, vm.propertyNames->toPrimitiveSymbol, toPrimitiveFunction, PropertyAttribute::DontEnum | PropertyAttribute::ReadOnly);
 
-bool DatePrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
-{
-    return getStaticFunctionDescriptor<JSObject>(exec, ExecState::dateTable(exec), this, propertyName, descriptor);
+    // The constructor will be added later, after DateConstructor has been built.
 }
 
 // Functions
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
-
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
-    if (!gregorianDateTime)
-        return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
-    DateConversionBuffer date;
-    DateConversionBuffer time;
-    formatDate(*gregorianDateTime, date);
-    formatTime(*gregorianDateTime, time);
-    return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
+    const bool asUTCVariant = false;
+    return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
-
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
-    if (!gregorianDateTime)
-        return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
-    DateConversionBuffer date;
-    DateConversionBuffer time;
-    formatDateUTCVariant(*gregorianDateTime, date);
-    formatTimeUTC(*gregorianDateTime, time);
-    return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
+    const bool asUTCVariant = true;
+    return formateDateInstance(exec, DateTimeFormatDateAndTime, asUTCVariant);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-    
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
     
+    if (!std::isfinite(thisDateObj->internalNumber()))
+        return throwVMError(exec, scope, createRangeError(exec, "Invalid Date"_s));
+
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
     if (!gregorianDateTime)
-        return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
+        return JSValue::encode(jsNontrivialString(exec, String("Invalid Date"_s)));
     // Maximum amount of space we need in buffer: 7 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds)
     // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination.
-    char buffer[29];
+    char buffer[28];
     // If the year is outside the bounds of 0 and 9999 inclusive we want to use the extended year format (ES 15.9.1.15.1).
-    if (gregorianDateTime->year > 8099 || gregorianDateTime->year < -1900)
-        snprintf(buffer, sizeof(buffer) - 1, "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + gregorianDateTime->year, gregorianDateTime->month + 1, gregorianDateTime->monthDay, gregorianDateTime->hour, gregorianDateTime->minute, gregorianDateTime->second, static_cast<int>(fmod(thisDateObj->internalNumber(), 1000)));
+    int ms = static_cast<int>(fmod(thisDateObj->internalNumber(), msPerSecond));
+    if (ms < 0)
+        ms += msPerSecond;
+
+    int charactersWritten;
+    if (gregorianDateTime->year() > 9999 || gregorianDateTime->year() < 0)
+        charactersWritten = snprintf(buffer, sizeof(buffer), "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms);
     else
-        snprintf(buffer, sizeof(buffer) - 1, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + gregorianDateTime->year, gregorianDateTime->month + 1, gregorianDateTime->monthDay, gregorianDateTime->hour, gregorianDateTime->minute, gregorianDateTime->second, static_cast<int>(fmod(thisDateObj->internalNumber(), 1000)));
-    buffer[sizeof(buffer) - 1] = 0;
-    return JSValue::encode(jsNontrivialString(exec, buffer));
+        charactersWritten = snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms);
+
+    ASSERT(charactersWritten > 0 && static_cast<unsigned>(charactersWritten) < sizeof(buffer));
+    if (static_cast<unsigned>(charactersWritten) >= sizeof(buffer))
+        return JSValue::encode(jsEmptyString(exec));
+
+    return JSValue::encode(jsNontrivialString(exec, String(buffer, charactersWritten)));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
-
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
-    if (!gregorianDateTime)
-        return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
-    DateConversionBuffer date;
-    formatDate(*gregorianDateTime, date);
-    return JSValue::encode(jsNontrivialString(exec, date));
+    const bool asUTCVariant = false;
+    return formateDateInstance(exec, DateTimeFormatDate, asUTCVariant);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
-
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
-    if (!gregorianDateTime)
-        return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
-    DateConversionBuffer time;
-    formatTime(*gregorianDateTime, time);
-    return JSValue::encode(jsNontrivialString(exec, time));
+    const bool asUTCVariant = false;
+    return formateDateInstance(exec, DateTimeFormatTime, asUTCVariant);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
     return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
     return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
     return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
 }
 
-EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToPrimitiveSymbol(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    if (!thisValue.isObject())
+        return throwVMTypeError(exec, scope, "Date.prototype[Symbol.toPrimitive] expected |this| to be an object.");
+    JSObject* thisObject = jsCast<JSObject*>(thisValue);
 
-    return JSValue::encode(asDateInstance(thisValue)->internalValue());
-}
+    if (!exec->argumentCount())
+        return throwVMTypeError(exec, scope, "Date.prototype[Symbol.toPrimitive] expected a first argument.");
 
-EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
-{
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
+    JSValue hintValue = exec->uncheckedArgument(0);
+    PreferredPrimitiveType type = toPreferredPrimitiveType(exec, hintValue);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
 
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    if (type == NoPreference)
+        type = PreferString;
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
-    if (!gregorianDateTime)
-        return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
+    scope.release();
+    return JSValue::encode(thisObject->ordinaryToPrimitive(exec, type));
 }
 
-EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
+
+    return JSValue::encode(thisDateObj->internalValue());
+}
 
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
+{
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
-    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
+    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
+    return JSValue::encode(jsNumber(gregorianDateTime->year()));
 }
 
-EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec)
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
     if (!gregorianDateTime)
-        return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
-    DateConversionBuffer date;
-    DateConversionBuffer time;
-    formatDateUTCVariant(*gregorianDateTime, date);
-    formatTimeUTC(*gregorianDateTime, time);
-    return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
+        return JSValue::encode(jsNaN());
+    return JSValue::encode(jsNumber(gregorianDateTime->year()));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(gregorianDateTime->month));
+    return JSValue::encode(jsNumber(gregorianDateTime->month()));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(gregorianDateTime->month));
+    return JSValue::encode(jsNumber(gregorianDateTime->month()));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(gregorianDateTime->monthDay));
+    return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(gregorianDateTime->monthDay));
+    return JSValue::encode(jsNumber(gregorianDateTime->monthDay()));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(gregorianDateTime->weekDay));
+    return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(gregorianDateTime->weekDay));
+    return JSValue::encode(jsNumber(gregorianDateTime->weekDay()));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(gregorianDateTime->hour));
+    return JSValue::encode(jsNumber(gregorianDateTime->hour()));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(gregorianDateTime->hour));
+    return JSValue::encode(jsNumber(gregorianDateTime->hour()));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(gregorianDateTime->minute));
+    return JSValue::encode(jsNumber(gregorianDateTime->minute()));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(gregorianDateTime->minute));
+    return JSValue::encode(jsNumber(gregorianDateTime->minute()));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(gregorianDateTime->second));
+    return JSValue::encode(jsNumber(gregorianDateTime->second()));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(gregorianDateTime->second));
+    return JSValue::encode(jsNumber(gregorianDateTime->second()));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
     double milli = thisDateObj->internalNumber();
-    if (isnan(milli))
+    if (std::isnan(milli))
         return JSValue::encode(jsNaN());
 
     double secs = floor(milli / msPerSecond);
@@ -822,13 +882,15 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
     double milli = thisDateObj->internalNumber();
-    if (isnan(milli))
+    if (std::isnan(milli))
         return JSValue::encode(jsNaN());
 
     double secs = floor(milli / msPerSecond);
@@ -838,51 +900,56 @@ EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
-    return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset / minutesPerHour));
+    return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset() / minutesPerHour));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     double milli = timeClip(exec->argument(0).toNumber(exec));
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
     JSValue result = jsNumber(milli);
-    thisDateObj->setInternalValue(exec->globalData(), result);
+    thisDateObj->setInternalValue(vm, result);
     return JSValue::encode(result);
 }
 
-static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
+static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, WTF::TimeType inputTimeType)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
-    DateInstance* thisDateObj = asDateInstance(thisValue);
     double milli = thisDateObj->internalNumber();
-    
-    if (!exec->argumentCount() || isnan(milli)) {
+
+    if (!exec->argumentCount() || std::isnan(milli)) {
         JSValue result = jsNaN();
-        thisDateObj->setInternalValue(exec->globalData(), result);
+        thisDateObj->setInternalValue(vm, result);
         return JSValue::encode(result);
     }
      
     double secs = floor(milli / msPerSecond);
     double ms = milli - secs * msPerSecond;
 
-    const GregorianDateTime* other = inputIsUTC 
+    const GregorianDateTime* other = inputTimeType == WTF::UTCTime
         ? thisDateObj->gregorianDateTimeUTC(exec)
         : thisDateObj->gregorianDateTime(exec);
     if (!other)
@@ -890,39 +957,44 @@ static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse,
 
     GregorianDateTime gregorianDateTime;
     gregorianDateTime.copyFrom(*other);
-    if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
+    bool success = fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    if (!success) {
         JSValue result = jsNaN();
-        thisDateObj->setInternalValue(exec->globalData(), result);
+        thisDateObj->setInternalValue(vm, result);
         return JSValue::encode(result);
     } 
-    
-    JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
-    thisDateObj->setInternalValue(exec->globalData(), result);
+
+    double newUTCDate = gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputTimeType);
+    JSValue result = jsNumber(timeClip(newUTCDate));
+    thisDateObj->setInternalValue(vm, result);
     return JSValue::encode(result);
 }
 
-static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
+static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, WTF::TimeType inputTimeType)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
-    DateInstance* thisDateObj = asDateInstance(thisValue);
     if (!exec->argumentCount()) {
         JSValue result = jsNaN();
-        thisDateObj->setInternalValue(exec->globalData(), result);
+        thisDateObj->setInternalValue(vm, result);
         return JSValue::encode(result);
-    }      
-    
+    }
+
     double milli = thisDateObj->internalNumber();
     double ms = 0; 
 
     GregorianDateTime gregorianDateTime; 
-    if (numArgsToUse == 3 && isnan(milli)) 
-        msToGregorianDateTime(exec, 0, true, gregorianDateTime); 
+    if (numArgsToUse == 3 && std::isnan(milli)) 
+        msToGregorianDateTime(vm, 0, WTF::UTCTime, gregorianDateTime);
     else { 
         ms = milli - floor(milli / msPerSecond) * msPerSecond; 
-        const GregorianDateTime* other = inputIsUTC 
+        const GregorianDateTime* other = inputTimeType == WTF::UTCTime
             ? thisDateObj->gregorianDateTimeUTC(exec)
             : thisDateObj->gregorianDateTime(exec);
         if (!other)
@@ -930,179 +1002,177 @@ static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse,
         gregorianDateTime.copyFrom(*other);
     }
     
-    if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
+    bool success = fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    if (!success) {
         JSValue result = jsNaN();
-        thisDateObj->setInternalValue(exec->globalData(), result);
+        thisDateObj->setInternalValue(vm, result);
         return JSValue::encode(result);
     } 
-           
-    JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
-    thisDateObj->setInternalValue(exec->globalData(), result);
+
+    double newUTCDate = gregorianDateTimeToMS(vm, gregorianDateTime, ms, inputTimeType);
+    JSValue result = jsNumber(timeClip(newUTCDate));
+    thisDateObj->setInternalValue(vm, result);
     return JSValue::encode(result);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
 {
-    const bool inputIsUTC = false;
-    return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
+    return setNewValueFromTimeArgs(exec, 1, WTF::LocalTime);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
 {
-    const bool inputIsUTC = true;
-    return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
+    return setNewValueFromTimeArgs(exec, 1, WTF::UTCTime);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
 {
-    const bool inputIsUTC = false;
-    return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
+    return setNewValueFromTimeArgs(exec, 2, WTF::LocalTime);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
 {
-    const bool inputIsUTC = true;
-    return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
+    return setNewValueFromTimeArgs(exec, 2, WTF::UTCTime);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
 {
-    const bool inputIsUTC = false;
-    return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
+    return setNewValueFromTimeArgs(exec, 3, WTF::LocalTime);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
 {
-    const bool inputIsUTC = true;
-    return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
+    return setNewValueFromTimeArgs(exec, 3, WTF::UTCTime);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
 {
-    const bool inputIsUTC = false;
-    return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
+    return setNewValueFromTimeArgs(exec, 4, WTF::LocalTime);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
 {
-    const bool inputIsUTC = true;
-    return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
+    return setNewValueFromTimeArgs(exec, 4, WTF::UTCTime);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
 {
-    const bool inputIsUTC = false;
-    return setNewValueFromDateArgs(exec, 1, inputIsUTC);
+    return setNewValueFromDateArgs(exec, 1, WTF::LocalTime);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
 {
-    const bool inputIsUTC = true;
-    return setNewValueFromDateArgs(exec, 1, inputIsUTC);
+    return setNewValueFromDateArgs(exec, 1, WTF::UTCTime);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
 {
-    const bool inputIsUTC = false;
-    return setNewValueFromDateArgs(exec, 2, inputIsUTC);
+    return setNewValueFromDateArgs(exec, 2, WTF::LocalTime);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
 {
-    const bool inputIsUTC = true;
-    return setNewValueFromDateArgs(exec, 2, inputIsUTC);
+    return setNewValueFromDateArgs(exec, 2, WTF::UTCTime);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
 {
-    const bool inputIsUTC = false;
-    return setNewValueFromDateArgs(exec, 3, inputIsUTC);
+    return setNewValueFromDateArgs(exec, 3, WTF::LocalTime);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
 {
-    const bool inputIsUTC = true;
-    return setNewValueFromDateArgs(exec, 3, inputIsUTC);
+    return setNewValueFromDateArgs(exec, 3, WTF::UTCTime);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
-    DateInstance* thisDateObj = asDateInstance(thisValue);     
     if (!exec->argumentCount()) { 
         JSValue result = jsNaN();
-        thisDateObj->setInternalValue(exec->globalData(), result);
+        thisDateObj->setInternalValue(vm, result);
         return JSValue::encode(result);
     }
-    
+
     double milli = thisDateObj->internalNumber();
     double ms = 0;
 
     GregorianDateTime gregorianDateTime;
-    if (isnan(milli))
+    if (std::isnan(milli))
         // Based on ECMA 262 B.2.5 (setYear)
-        // the time must be reset to +0 if it is NaN. 
-        msToGregorianDateTime(exec, 0, true, gregorianDateTime);
-    else {   
+        // the time must be reset to +0 if it is NaN.
+        msToGregorianDateTime(vm, 0, WTF::UTCTime, gregorianDateTime);
+    else {
         double secs = floor(milli / msPerSecond);
         ms = milli - secs * msPerSecond;
         if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec))
             gregorianDateTime.copyFrom(*other);
     }
-    
+
     double year = exec->argument(0).toIntegerPreserveNaN(exec);
-    if (!isfinite(year)) {
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    if (!std::isfinite(year)) {
         JSValue result = jsNaN();
-        thisDateObj->setInternalValue(exec->globalData(), result);
+        thisDateObj->setInternalValue(vm, result);
         return JSValue::encode(result);
     }
-            
-    gregorianDateTime.year = toInt32((year > 99 || year < 0) ? year - 1900 : year);
-    JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, false));
-    thisDateObj->setInternalValue(exec->globalData(), result);
+
+    gregorianDateTime.setYear(toInt32((year >= 0 && year <= 99) ? (year + 1900) : year));
+    double timeInMilliseconds = gregorianDateTimeToMS(vm, gregorianDateTime, ms, WTF::LocalTime);
+    JSValue result = jsNumber(timeClip(timeInMilliseconds));
+    thisDateObj->setInternalValue(vm, result);
     return JSValue::encode(result);
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    if (!thisValue.inherits(&DateInstance::s_info))
-        return throwVMTypeError(exec);
-
-    DateInstance* thisDateObj = asDateInstance(thisValue); 
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    auto* thisDateObj = jsDynamicCast<DateInstance*>(vm, thisValue);
+    if (UNLIKELY(!thisDateObj))
+        return throwVMTypeError(exec, scope);
 
     const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
     if (!gregorianDateTime)
         return JSValue::encode(jsNaN());
 
     // NOTE: IE returns the full year even in getYear.
-    return JSValue::encode(jsNumber(gregorianDateTime->year));
+    return JSValue::encode(jsNumber(gregorianDateTime->year() - 1900));
 }
 
 EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
 {
-    JSValue thisValue = exec->hostThisValue();
-    JSObject* object = thisValue.toThisObject(exec);
-    if (exec->hadException())
-        return JSValue::encode(jsNull());
-    
-    JSValue toISOValue = object->get(exec, exec->globalData().propertyNames->toISOString);
-    if (exec->hadException())
+    VM& vm = exec->vm();
+    auto scope = DECLARE_THROW_SCOPE(vm);
+    JSValue thisValue = exec->thisValue();
+    JSObject* object = jsCast<JSObject*>(thisValue.toThis(exec, NotStrictMode));
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
+    JSValue timeValue = object->toPrimitive(exec, PreferNumber);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+    if (timeValue.isNumber() && !(timeValue.isInt32() || std::isfinite(timeValue.asDouble())))
         return JSValue::encode(jsNull());
 
+    JSValue toISOValue = object->get(exec, vm.propertyNames->toISOString);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
+
     CallData callData;
-    CallType callType = getCallData(toISOValue, callData);
-    if (callType == CallTypeNone)
-        return throwVMError(exec, createTypeError(exec, "toISOString is not a function"));
+    CallType callType = getCallData(vm, toISOValue, callData);
+    if (callType == CallType::None)
+        return throwVMTypeError(exec, scope, "toISOString is not a function"_s);
 
-    JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList());
-    if (exec->hadException())
-        return JSValue::encode(jsNull());
+    JSValue result = call(exec, asObject(toISOValue), callType, callData, object, *vm.emptyList);
+    RETURN_IF_EXCEPTION(scope, encodedJSValue());
     if (result.isObject())
-        return throwVMError(exec, createTypeError(exec, "toISOString did not return a primitive value"));
+        return throwVMTypeError(exec, scope, "toISOString did not return a primitive value"_s);
     return JSValue::encode(result);
 }