1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "src/builtins/builtins-utils.h"
6 #include "src/builtins/builtins.h"
7 #include "src/code-factory.h"
8 #include "src/code-stub-assembler.h"
9 #include "src/conversions.h"
10 #include "src/counters.h"
11 #include "src/dateparser-inl.h"
12 #include "src/objects-inl.h"
13 
14 namespace v8 {
15 namespace internal {
16 
17 // -----------------------------------------------------------------------------
18 // ES6 section 20.3 Date Objects
19 
20 namespace {
21 
22 // ES6 section 20.3.1.1 Time Values and Time Range
23 const double kMinYear = -1000000.0;
24 const double kMaxYear = -kMinYear;
25 const double kMinMonth = -10000000.0;
26 const double kMaxMonth = -kMinMonth;
27 
28 // 20.3.1.2 Day Number and Time within Day
29 const double kMsPerDay = 86400000.0;
30 
31 // ES6 section 20.3.1.11 Hours, Minutes, Second, and Milliseconds
32 const double kMsPerSecond = 1000.0;
33 const double kMsPerMinute = 60000.0;
34 const double kMsPerHour = 3600000.0;
35 
36 // ES6 section 20.3.1.14 MakeDate (day, time)
MakeDate(double day,double time)37 double MakeDate(double day, double time) {
38   if (std::isfinite(day) && std::isfinite(time)) {
39     return time + day * kMsPerDay;
40   }
41   return std::numeric_limits<double>::quiet_NaN();
42 }
43 
44 // ES6 section 20.3.1.13 MakeDay (year, month, date)
MakeDay(double year,double month,double date)45 double MakeDay(double year, double month, double date) {
46   if ((kMinYear <= year && year <= kMaxYear) &&
47       (kMinMonth <= month && month <= kMaxMonth) && std::isfinite(date)) {
48     int y = FastD2I(year);
49     int m = FastD2I(month);
50     y += m / 12;
51     m %= 12;
52     if (m < 0) {
53       m += 12;
54       y -= 1;
55     }
56     DCHECK_LE(0, m);
57     DCHECK_LT(m, 12);
58 
59     // kYearDelta is an arbitrary number such that:
60     // a) kYearDelta = -1 (mod 400)
61     // b) year + kYearDelta > 0 for years in the range defined by
62     //    ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
63     //    Jan 1 1970. This is required so that we don't run into integer
64     //    division of negative numbers.
65     // c) there shouldn't be an overflow for 32-bit integers in the following
66     //    operations.
67     static const int kYearDelta = 399999;
68     static const int kBaseDay =
69         365 * (1970 + kYearDelta) + (1970 + kYearDelta) / 4 -
70         (1970 + kYearDelta) / 100 + (1970 + kYearDelta) / 400;
71     int day_from_year = 365 * (y + kYearDelta) + (y + kYearDelta) / 4 -
72                         (y + kYearDelta) / 100 + (y + kYearDelta) / 400 -
73                         kBaseDay;
74     if ((y % 4 != 0) || (y % 100 == 0 && y % 400 != 0)) {
75       static const int kDayFromMonth[] = {0,   31,  59,  90,  120, 151,
76                                           181, 212, 243, 273, 304, 334};
77       day_from_year += kDayFromMonth[m];
78     } else {
79       static const int kDayFromMonth[] = {0,   31,  60,  91,  121, 152,
80                                           182, 213, 244, 274, 305, 335};
81       day_from_year += kDayFromMonth[m];
82     }
83     return static_cast<double>(day_from_year - 1) + DoubleToInteger(date);
84   }
85   return std::numeric_limits<double>::quiet_NaN();
86 }
87 
88 // ES6 section 20.3.1.12 MakeTime (hour, min, sec, ms)
MakeTime(double hour,double min,double sec,double ms)89 double MakeTime(double hour, double min, double sec, double ms) {
90   if (std::isfinite(hour) && std::isfinite(min) && std::isfinite(sec) &&
91       std::isfinite(ms)) {
92     double const h = DoubleToInteger(hour);
93     double const m = DoubleToInteger(min);
94     double const s = DoubleToInteger(sec);
95     double const milli = DoubleToInteger(ms);
96     return h * kMsPerHour + m * kMsPerMinute + s * kMsPerSecond + milli;
97   }
98   return std::numeric_limits<double>::quiet_NaN();
99 }
100 
101 const char* kShortWeekDays[] = {"Sun", "Mon", "Tue", "Wed",
102                                 "Thu", "Fri", "Sat"};
103 const char* kShortMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
104                               "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
105 
106 // ES6 section 20.3.1.16 Date Time String Format
ParseDateTimeString(Handle<String> str)107 double ParseDateTimeString(Handle<String> str) {
108   Isolate* const isolate = str->GetIsolate();
109   str = String::Flatten(str);
110   // TODO(bmeurer): Change DateParser to not use the FixedArray.
111   Handle<FixedArray> tmp =
112       isolate->factory()->NewFixedArray(DateParser::OUTPUT_SIZE);
113   DisallowHeapAllocation no_gc;
114   String::FlatContent str_content = str->GetFlatContent();
115   bool result;
116   if (str_content.IsOneByte()) {
117     result = DateParser::Parse(isolate, str_content.ToOneByteVector(), *tmp);
118   } else {
119     result = DateParser::Parse(isolate, str_content.ToUC16Vector(), *tmp);
120   }
121   if (!result) return std::numeric_limits<double>::quiet_NaN();
122   double const day = MakeDay(tmp->get(0)->Number(), tmp->get(1)->Number(),
123                              tmp->get(2)->Number());
124   double const time = MakeTime(tmp->get(3)->Number(), tmp->get(4)->Number(),
125                                tmp->get(5)->Number(), tmp->get(6)->Number());
126   double date = MakeDate(day, time);
127   if (tmp->get(7)->IsNull(isolate)) {
128     if (!std::isnan(date)) {
129       date = isolate->date_cache()->ToUTC(static_cast<int64_t>(date));
130     }
131   } else {
132     date -= tmp->get(7)->Number() * 1000.0;
133   }
134   return date;
135 }
136 
137 enum ToDateStringMode { kDateOnly, kTimeOnly, kDateAndTime };
138 
139 // ES6 section 20.3.4.41.1 ToDateString(tv)
ToDateString(double time_val,Vector<char> str,DateCache * date_cache,ToDateStringMode mode=kDateAndTime)140 void ToDateString(double time_val, Vector<char> str, DateCache* date_cache,
141                   ToDateStringMode mode = kDateAndTime) {
142   if (std::isnan(time_val)) {
143     SNPrintF(str, "Invalid Date");
144     return;
145   }
146   int64_t time_ms = static_cast<int64_t>(time_val);
147   int64_t local_time_ms = date_cache->ToLocal(time_ms);
148   int year, month, day, weekday, hour, min, sec, ms;
149   date_cache->BreakDownTime(local_time_ms, &year, &month, &day, &weekday, &hour,
150                             &min, &sec, &ms);
151   int timezone_offset = -date_cache->TimezoneOffset(time_ms);
152   int timezone_hour = std::abs(timezone_offset) / 60;
153   int timezone_min = std::abs(timezone_offset) % 60;
154   const char* local_timezone = date_cache->LocalTimezone(time_ms);
155   switch (mode) {
156     case kDateOnly:
157       SNPrintF(str, "%s %s %02d %04d", kShortWeekDays[weekday],
158                kShortMonths[month], day, year);
159       return;
160     case kTimeOnly:
161       // TODO(842085): str may be silently truncated.
162       SNPrintF(str, "%02d:%02d:%02d GMT%c%02d%02d (%s)", hour, min, sec,
163                (timezone_offset < 0) ? '-' : '+', timezone_hour, timezone_min,
164                local_timezone);
165       return;
166     case kDateAndTime:
167       // TODO(842085): str may be silently truncated.
168       SNPrintF(str, "%s %s %02d %04d %02d:%02d:%02d GMT%c%02d%02d (%s)",
169                kShortWeekDays[weekday], kShortMonths[month], day, year, hour,
170                min, sec, (timezone_offset < 0) ? '-' : '+', timezone_hour,
171                timezone_min, local_timezone);
172       return;
173   }
174   UNREACHABLE();
175 }
176 
SetLocalDateValue(Handle<JSDate> date,double time_val)177 Object* SetLocalDateValue(Handle<JSDate> date, double time_val) {
178   if (time_val >= -DateCache::kMaxTimeBeforeUTCInMs &&
179       time_val <= DateCache::kMaxTimeBeforeUTCInMs) {
180     Isolate* const isolate = date->GetIsolate();
181     time_val = isolate->date_cache()->ToUTC(static_cast<int64_t>(time_val));
182   } else {
183     time_val = std::numeric_limits<double>::quiet_NaN();
184   }
185   return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
186 }
187 
188 }  // namespace
189 
190 // ES #sec-date-constructor
BUILTIN(DateConstructor)191 BUILTIN(DateConstructor) {
192   HandleScope scope(isolate);
193   if (args.new_target()->IsUndefined(isolate)) {
194     double const time_val = JSDate::CurrentTimeValue(isolate);
195     char buffer[128];
196     ToDateString(time_val, ArrayVector(buffer), isolate->date_cache());
197     RETURN_RESULT_OR_FAILURE(
198         isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer)));
199   } else {
200     int const argc = args.length() - 1;
201     Handle<JSFunction> target = args.target();
202     Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target());
203     double time_val;
204     if (argc == 0) {
205       time_val = JSDate::CurrentTimeValue(isolate);
206     } else if (argc == 1) {
207       Handle<Object> value = args.at(1);
208       if (value->IsJSDate()) {
209         time_val = Handle<JSDate>::cast(value)->value()->Number();
210       } else {
211         ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
212                                            Object::ToPrimitive(value));
213         if (value->IsString()) {
214           time_val = ParseDateTimeString(Handle<String>::cast(value));
215         } else {
216           ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
217                                              Object::ToNumber(value));
218           time_val = value->Number();
219         }
220       }
221     } else {
222       Handle<Object> year_object;
223       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year_object,
224                                          Object::ToNumber(args.at(1)));
225       Handle<Object> month_object;
226       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month_object,
227                                          Object::ToNumber(args.at(2)));
228       double year = year_object->Number();
229       double month = month_object->Number();
230       double date = 1.0, hours = 0.0, minutes = 0.0, seconds = 0.0, ms = 0.0;
231       if (argc >= 3) {
232         Handle<Object> date_object;
233         ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date_object,
234                                            Object::ToNumber(args.at(3)));
235         date = date_object->Number();
236         if (argc >= 4) {
237           Handle<Object> hours_object;
238           ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, hours_object,
239                                              Object::ToNumber(args.at(4)));
240           hours = hours_object->Number();
241           if (argc >= 5) {
242             Handle<Object> minutes_object;
243             ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, minutes_object,
244                                                Object::ToNumber(args.at(5)));
245             minutes = minutes_object->Number();
246             if (argc >= 6) {
247               Handle<Object> seconds_object;
248               ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, seconds_object,
249                                                  Object::ToNumber(args.at(6)));
250               seconds = seconds_object->Number();
251               if (argc >= 7) {
252                 Handle<Object> ms_object;
253                 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
254                     isolate, ms_object, Object::ToNumber(args.at(7)));
255                 ms = ms_object->Number();
256               }
257             }
258           }
259         }
260       }
261       if (!std::isnan(year)) {
262         double const y = DoubleToInteger(year);
263         if (0.0 <= y && y <= 99) year = 1900 + y;
264       }
265       double const day = MakeDay(year, month, date);
266       double const time = MakeTime(hours, minutes, seconds, ms);
267       time_val = MakeDate(day, time);
268       if (time_val >= -DateCache::kMaxTimeBeforeUTCInMs &&
269           time_val <= DateCache::kMaxTimeBeforeUTCInMs) {
270         time_val = isolate->date_cache()->ToUTC(static_cast<int64_t>(time_val));
271       } else {
272         time_val = std::numeric_limits<double>::quiet_NaN();
273       }
274     }
275     RETURN_RESULT_OR_FAILURE(isolate,
276                              JSDate::New(target, new_target, time_val));
277   }
278 }
279 
280 // ES6 section 20.3.3.1 Date.now ( )
BUILTIN(DateNow)281 BUILTIN(DateNow) {
282   HandleScope scope(isolate);
283   return *isolate->factory()->NewNumber(JSDate::CurrentTimeValue(isolate));
284 }
285 
286 // ES6 section 20.3.3.2 Date.parse ( string )
BUILTIN(DateParse)287 BUILTIN(DateParse) {
288   HandleScope scope(isolate);
289   Handle<String> string;
290   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
291       isolate, string,
292       Object::ToString(isolate, args.atOrUndefined(isolate, 1)));
293   return *isolate->factory()->NewNumber(ParseDateTimeString(string));
294 }
295 
296 // ES6 section 20.3.3.4 Date.UTC (year,month,date,hours,minutes,seconds,ms)
BUILTIN(DateUTC)297 BUILTIN(DateUTC) {
298   HandleScope scope(isolate);
299   int const argc = args.length() - 1;
300   double year = std::numeric_limits<double>::quiet_NaN();
301   double month = 0.0, date = 1.0, hours = 0.0, minutes = 0.0, seconds = 0.0,
302          ms = 0.0;
303   if (argc >= 1) {
304     Handle<Object> year_object;
305     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year_object,
306                                        Object::ToNumber(args.at(1)));
307     year = year_object->Number();
308     if (argc >= 2) {
309       Handle<Object> month_object;
310       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month_object,
311                                          Object::ToNumber(args.at(2)));
312       month = month_object->Number();
313       if (argc >= 3) {
314         Handle<Object> date_object;
315         ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date_object,
316                                            Object::ToNumber(args.at(3)));
317         date = date_object->Number();
318         if (argc >= 4) {
319           Handle<Object> hours_object;
320           ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, hours_object,
321                                              Object::ToNumber(args.at(4)));
322           hours = hours_object->Number();
323           if (argc >= 5) {
324             Handle<Object> minutes_object;
325             ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, minutes_object,
326                                                Object::ToNumber(args.at(5)));
327             minutes = minutes_object->Number();
328             if (argc >= 6) {
329               Handle<Object> seconds_object;
330               ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, seconds_object,
331                                                  Object::ToNumber(args.at(6)));
332               seconds = seconds_object->Number();
333               if (argc >= 7) {
334                 Handle<Object> ms_object;
335                 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
336                     isolate, ms_object, Object::ToNumber(args.at(7)));
337                 ms = ms_object->Number();
338               }
339             }
340           }
341         }
342       }
343     }
344   }
345   if (!std::isnan(year)) {
346     double const y = DoubleToInteger(year);
347     if (0.0 <= y && y <= 99) year = 1900 + y;
348   }
349   double const day = MakeDay(year, month, date);
350   double const time = MakeTime(hours, minutes, seconds, ms);
351   return *isolate->factory()->NewNumber(
352       DateCache::TimeClip(MakeDate(day, time)));
353 }
354 
355 // ES6 section 20.3.4.20 Date.prototype.setDate ( date )
BUILTIN(DatePrototypeSetDate)356 BUILTIN(DatePrototypeSetDate) {
357   HandleScope scope(isolate);
358   CHECK_RECEIVER(JSDate, date, "Date.prototype.setDate");
359   Handle<Object> value = args.atOrUndefined(isolate, 1);
360   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(value));
361   double time_val = date->value()->Number();
362   if (!std::isnan(time_val)) {
363     int64_t const time_ms = static_cast<int64_t>(time_val);
364     int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
365     int const days = isolate->date_cache()->DaysFromTime(local_time_ms);
366     int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
367     int year, month, day;
368     isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
369     time_val = MakeDate(MakeDay(year, month, value->Number()), time_within_day);
370   }
371   return SetLocalDateValue(date, time_val);
372 }
373 
374 // ES6 section 20.3.4.21 Date.prototype.setFullYear (year, month, date)
BUILTIN(DatePrototypeSetFullYear)375 BUILTIN(DatePrototypeSetFullYear) {
376   HandleScope scope(isolate);
377   CHECK_RECEIVER(JSDate, date, "Date.prototype.setFullYear");
378   int const argc = args.length() - 1;
379   Handle<Object> year = args.atOrUndefined(isolate, 1);
380   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year, Object::ToNumber(year));
381   double y = year->Number(), m = 0.0, dt = 1.0;
382   int time_within_day = 0;
383   if (!std::isnan(date->value()->Number())) {
384     int64_t const time_ms = static_cast<int64_t>(date->value()->Number());
385     int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
386     int const days = isolate->date_cache()->DaysFromTime(local_time_ms);
387     time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
388     int year, month, day;
389     isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
390     m = month;
391     dt = day;
392   }
393   if (argc >= 2) {
394     Handle<Object> month = args.at(2);
395     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month));
396     m = month->Number();
397     if (argc >= 3) {
398       Handle<Object> date = args.at(3);
399       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date));
400       dt = date->Number();
401     }
402   }
403   double time_val = MakeDate(MakeDay(y, m, dt), time_within_day);
404   return SetLocalDateValue(date, time_val);
405 }
406 
407 // ES6 section 20.3.4.22 Date.prototype.setHours(hour, min, sec, ms)
BUILTIN(DatePrototypeSetHours)408 BUILTIN(DatePrototypeSetHours) {
409   HandleScope scope(isolate);
410   CHECK_RECEIVER(JSDate, date, "Date.prototype.setHours");
411   int const argc = args.length() - 1;
412   Handle<Object> hour = args.atOrUndefined(isolate, 1);
413   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, hour, Object::ToNumber(hour));
414   double h = hour->Number();
415   double time_val = date->value()->Number();
416   if (!std::isnan(time_val)) {
417     int64_t const time_ms = static_cast<int64_t>(time_val);
418     int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
419     int day = isolate->date_cache()->DaysFromTime(local_time_ms);
420     int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
421     double m = (time_within_day / (60 * 1000)) % 60;
422     double s = (time_within_day / 1000) % 60;
423     double milli = time_within_day % 1000;
424     if (argc >= 2) {
425       Handle<Object> min = args.at(2);
426       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min));
427       m = min->Number();
428       if (argc >= 3) {
429         Handle<Object> sec = args.at(3);
430         ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec));
431         s = sec->Number();
432         if (argc >= 4) {
433           Handle<Object> ms = args.at(4);
434           ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
435           milli = ms->Number();
436         }
437       }
438     }
439     time_val = MakeDate(day, MakeTime(h, m, s, milli));
440   }
441   return SetLocalDateValue(date, time_val);
442 }
443 
444 // ES6 section 20.3.4.23 Date.prototype.setMilliseconds(ms)
BUILTIN(DatePrototypeSetMilliseconds)445 BUILTIN(DatePrototypeSetMilliseconds) {
446   HandleScope scope(isolate);
447   CHECK_RECEIVER(JSDate, date, "Date.prototype.setMilliseconds");
448   Handle<Object> ms = args.atOrUndefined(isolate, 1);
449   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
450   double time_val = date->value()->Number();
451   if (!std::isnan(time_val)) {
452     int64_t const time_ms = static_cast<int64_t>(time_val);
453     int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
454     int day = isolate->date_cache()->DaysFromTime(local_time_ms);
455     int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
456     int h = time_within_day / (60 * 60 * 1000);
457     int m = (time_within_day / (60 * 1000)) % 60;
458     int s = (time_within_day / 1000) % 60;
459     time_val = MakeDate(day, MakeTime(h, m, s, ms->Number()));
460   }
461   return SetLocalDateValue(date, time_val);
462 }
463 
464 // ES6 section 20.3.4.24 Date.prototype.setMinutes ( min, sec, ms )
BUILTIN(DatePrototypeSetMinutes)465 BUILTIN(DatePrototypeSetMinutes) {
466   HandleScope scope(isolate);
467   CHECK_RECEIVER(JSDate, date, "Date.prototype.setMinutes");
468   int const argc = args.length() - 1;
469   Handle<Object> min = args.atOrUndefined(isolate, 1);
470   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min));
471   double time_val = date->value()->Number();
472   if (!std::isnan(time_val)) {
473     int64_t const time_ms = static_cast<int64_t>(time_val);
474     int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
475     int day = isolate->date_cache()->DaysFromTime(local_time_ms);
476     int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
477     int h = time_within_day / (60 * 60 * 1000);
478     double m = min->Number();
479     double s = (time_within_day / 1000) % 60;
480     double milli = time_within_day % 1000;
481     if (argc >= 2) {
482       Handle<Object> sec = args.at(2);
483       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec));
484       s = sec->Number();
485       if (argc >= 3) {
486         Handle<Object> ms = args.at(3);
487         ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
488         milli = ms->Number();
489       }
490     }
491     time_val = MakeDate(day, MakeTime(h, m, s, milli));
492   }
493   return SetLocalDateValue(date, time_val);
494 }
495 
496 // ES6 section 20.3.4.25 Date.prototype.setMonth ( month, date )
BUILTIN(DatePrototypeSetMonth)497 BUILTIN(DatePrototypeSetMonth) {
498   HandleScope scope(isolate);
499   CHECK_RECEIVER(JSDate, date, "Date.prototype.setMonth");
500   int const argc = args.length() - 1;
501   Handle<Object> month = args.atOrUndefined(isolate, 1);
502   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month));
503   double time_val = date->value()->Number();
504   if (!std::isnan(time_val)) {
505     int64_t const time_ms = static_cast<int64_t>(time_val);
506     int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
507     int days = isolate->date_cache()->DaysFromTime(local_time_ms);
508     int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
509     int year, unused, day;
510     isolate->date_cache()->YearMonthDayFromDays(days, &year, &unused, &day);
511     double m = month->Number();
512     double dt = day;
513     if (argc >= 2) {
514       Handle<Object> date = args.at(2);
515       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date));
516       dt = date->Number();
517     }
518     time_val = MakeDate(MakeDay(year, m, dt), time_within_day);
519   }
520   return SetLocalDateValue(date, time_val);
521 }
522 
523 // ES6 section 20.3.4.26 Date.prototype.setSeconds ( sec, ms )
BUILTIN(DatePrototypeSetSeconds)524 BUILTIN(DatePrototypeSetSeconds) {
525   HandleScope scope(isolate);
526   CHECK_RECEIVER(JSDate, date, "Date.prototype.setSeconds");
527   int const argc = args.length() - 1;
528   Handle<Object> sec = args.atOrUndefined(isolate, 1);
529   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec));
530   double time_val = date->value()->Number();
531   if (!std::isnan(time_val)) {
532     int64_t const time_ms = static_cast<int64_t>(time_val);
533     int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
534     int day = isolate->date_cache()->DaysFromTime(local_time_ms);
535     int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
536     int h = time_within_day / (60 * 60 * 1000);
537     double m = (time_within_day / (60 * 1000)) % 60;
538     double s = sec->Number();
539     double milli = time_within_day % 1000;
540     if (argc >= 2) {
541       Handle<Object> ms = args.at(2);
542       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
543       milli = ms->Number();
544     }
545     time_val = MakeDate(day, MakeTime(h, m, s, milli));
546   }
547   return SetLocalDateValue(date, time_val);
548 }
549 
550 // ES6 section 20.3.4.27 Date.prototype.setTime ( time )
BUILTIN(DatePrototypeSetTime)551 BUILTIN(DatePrototypeSetTime) {
552   HandleScope scope(isolate);
553   CHECK_RECEIVER(JSDate, date, "Date.prototype.setTime");
554   Handle<Object> value = args.atOrUndefined(isolate, 1);
555   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(value));
556   return *JSDate::SetValue(date, DateCache::TimeClip(value->Number()));
557 }
558 
559 // ES6 section 20.3.4.28 Date.prototype.setUTCDate ( date )
BUILTIN(DatePrototypeSetUTCDate)560 BUILTIN(DatePrototypeSetUTCDate) {
561   HandleScope scope(isolate);
562   CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCDate");
563   Handle<Object> value = args.atOrUndefined(isolate, 1);
564   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(value));
565   if (std::isnan(date->value()->Number())) return date->value();
566   int64_t const time_ms = static_cast<int64_t>(date->value()->Number());
567   int const days = isolate->date_cache()->DaysFromTime(time_ms);
568   int const time_within_day = isolate->date_cache()->TimeInDay(time_ms, days);
569   int year, month, day;
570   isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
571   double const time_val =
572       MakeDate(MakeDay(year, month, value->Number()), time_within_day);
573   return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
574 }
575 
576 // ES6 section 20.3.4.29 Date.prototype.setUTCFullYear (year, month, date)
BUILTIN(DatePrototypeSetUTCFullYear)577 BUILTIN(DatePrototypeSetUTCFullYear) {
578   HandleScope scope(isolate);
579   CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCFullYear");
580   int const argc = args.length() - 1;
581   Handle<Object> year = args.atOrUndefined(isolate, 1);
582   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year, Object::ToNumber(year));
583   double y = year->Number(), m = 0.0, dt = 1.0;
584   int time_within_day = 0;
585   if (!std::isnan(date->value()->Number())) {
586     int64_t const time_ms = static_cast<int64_t>(date->value()->Number());
587     int const days = isolate->date_cache()->DaysFromTime(time_ms);
588     time_within_day = isolate->date_cache()->TimeInDay(time_ms, days);
589     int year, month, day;
590     isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
591     m = month;
592     dt = day;
593   }
594   if (argc >= 2) {
595     Handle<Object> month = args.at(2);
596     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month));
597     m = month->Number();
598     if (argc >= 3) {
599       Handle<Object> date = args.at(3);
600       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date));
601       dt = date->Number();
602     }
603   }
604   double const time_val = MakeDate(MakeDay(y, m, dt), time_within_day);
605   return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
606 }
607 
608 // ES6 section 20.3.4.30 Date.prototype.setUTCHours(hour, min, sec, ms)
BUILTIN(DatePrototypeSetUTCHours)609 BUILTIN(DatePrototypeSetUTCHours) {
610   HandleScope scope(isolate);
611   CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCHours");
612   int const argc = args.length() - 1;
613   Handle<Object> hour = args.atOrUndefined(isolate, 1);
614   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, hour, Object::ToNumber(hour));
615   double h = hour->Number();
616   double time_val = date->value()->Number();
617   if (!std::isnan(time_val)) {
618     int64_t const time_ms = static_cast<int64_t>(time_val);
619     int day = isolate->date_cache()->DaysFromTime(time_ms);
620     int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
621     double m = (time_within_day / (60 * 1000)) % 60;
622     double s = (time_within_day / 1000) % 60;
623     double milli = time_within_day % 1000;
624     if (argc >= 2) {
625       Handle<Object> min = args.at(2);
626       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min));
627       m = min->Number();
628       if (argc >= 3) {
629         Handle<Object> sec = args.at(3);
630         ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec));
631         s = sec->Number();
632         if (argc >= 4) {
633           Handle<Object> ms = args.at(4);
634           ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
635           milli = ms->Number();
636         }
637       }
638     }
639     time_val = MakeDate(day, MakeTime(h, m, s, milli));
640   }
641   return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
642 }
643 
644 // ES6 section 20.3.4.31 Date.prototype.setUTCMilliseconds(ms)
BUILTIN(DatePrototypeSetUTCMilliseconds)645 BUILTIN(DatePrototypeSetUTCMilliseconds) {
646   HandleScope scope(isolate);
647   CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMilliseconds");
648   Handle<Object> ms = args.atOrUndefined(isolate, 1);
649   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
650   double time_val = date->value()->Number();
651   if (!std::isnan(time_val)) {
652     int64_t const time_ms = static_cast<int64_t>(time_val);
653     int day = isolate->date_cache()->DaysFromTime(time_ms);
654     int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
655     int h = time_within_day / (60 * 60 * 1000);
656     int m = (time_within_day / (60 * 1000)) % 60;
657     int s = (time_within_day / 1000) % 60;
658     time_val = MakeDate(day, MakeTime(h, m, s, ms->Number()));
659   }
660   return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
661 }
662 
663 // ES6 section 20.3.4.32 Date.prototype.setUTCMinutes ( min, sec, ms )
BUILTIN(DatePrototypeSetUTCMinutes)664 BUILTIN(DatePrototypeSetUTCMinutes) {
665   HandleScope scope(isolate);
666   CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMinutes");
667   int const argc = args.length() - 1;
668   Handle<Object> min = args.atOrUndefined(isolate, 1);
669   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min));
670   double time_val = date->value()->Number();
671   if (!std::isnan(time_val)) {
672     int64_t const time_ms = static_cast<int64_t>(time_val);
673     int day = isolate->date_cache()->DaysFromTime(time_ms);
674     int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
675     int h = time_within_day / (60 * 60 * 1000);
676     double m = min->Number();
677     double s = (time_within_day / 1000) % 60;
678     double milli = time_within_day % 1000;
679     if (argc >= 2) {
680       Handle<Object> sec = args.at(2);
681       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec));
682       s = sec->Number();
683       if (argc >= 3) {
684         Handle<Object> ms = args.at(3);
685         ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
686         milli = ms->Number();
687       }
688     }
689     time_val = MakeDate(day, MakeTime(h, m, s, milli));
690   }
691   return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
692 }
693 
694 // ES6 section 20.3.4.31 Date.prototype.setUTCMonth ( month, date )
BUILTIN(DatePrototypeSetUTCMonth)695 BUILTIN(DatePrototypeSetUTCMonth) {
696   HandleScope scope(isolate);
697   CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMonth");
698   int const argc = args.length() - 1;
699   Handle<Object> month = args.atOrUndefined(isolate, 1);
700   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month));
701   double time_val = date->value()->Number();
702   if (!std::isnan(time_val)) {
703     int64_t const time_ms = static_cast<int64_t>(time_val);
704     int days = isolate->date_cache()->DaysFromTime(time_ms);
705     int time_within_day = isolate->date_cache()->TimeInDay(time_ms, days);
706     int year, unused, day;
707     isolate->date_cache()->YearMonthDayFromDays(days, &year, &unused, &day);
708     double m = month->Number();
709     double dt = day;
710     if (argc >= 2) {
711       Handle<Object> date = args.at(2);
712       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date));
713       dt = date->Number();
714     }
715     time_val = MakeDate(MakeDay(year, m, dt), time_within_day);
716   }
717   return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
718 }
719 
720 // ES6 section 20.3.4.34 Date.prototype.setUTCSeconds ( sec, ms )
BUILTIN(DatePrototypeSetUTCSeconds)721 BUILTIN(DatePrototypeSetUTCSeconds) {
722   HandleScope scope(isolate);
723   CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCSeconds");
724   int const argc = args.length() - 1;
725   Handle<Object> sec = args.atOrUndefined(isolate, 1);
726   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec));
727   double time_val = date->value()->Number();
728   if (!std::isnan(time_val)) {
729     int64_t const time_ms = static_cast<int64_t>(time_val);
730     int day = isolate->date_cache()->DaysFromTime(time_ms);
731     int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
732     int h = time_within_day / (60 * 60 * 1000);
733     double m = (time_within_day / (60 * 1000)) % 60;
734     double s = sec->Number();
735     double milli = time_within_day % 1000;
736     if (argc >= 2) {
737       Handle<Object> ms = args.at(2);
738       ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms));
739       milli = ms->Number();
740     }
741     time_val = MakeDate(day, MakeTime(h, m, s, milli));
742   }
743   return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
744 }
745 
746 // ES6 section 20.3.4.35 Date.prototype.toDateString ( )
BUILTIN(DatePrototypeToDateString)747 BUILTIN(DatePrototypeToDateString) {
748   HandleScope scope(isolate);
749   CHECK_RECEIVER(JSDate, date, "Date.prototype.toDateString");
750   char buffer[128];
751   ToDateString(date->value()->Number(), ArrayVector(buffer),
752                isolate->date_cache(), kDateOnly);
753   RETURN_RESULT_OR_FAILURE(
754       isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer)));
755 }
756 
757 // ES6 section 20.3.4.36 Date.prototype.toISOString ( )
BUILTIN(DatePrototypeToISOString)758 BUILTIN(DatePrototypeToISOString) {
759   HandleScope scope(isolate);
760   CHECK_RECEIVER(JSDate, date, "Date.prototype.toISOString");
761   double const time_val = date->value()->Number();
762   if (std::isnan(time_val)) {
763     THROW_NEW_ERROR_RETURN_FAILURE(
764         isolate, NewRangeError(MessageTemplate::kInvalidTimeValue));
765   }
766   int64_t const time_ms = static_cast<int64_t>(time_val);
767   int year, month, day, weekday, hour, min, sec, ms;
768   isolate->date_cache()->BreakDownTime(time_ms, &year, &month, &day, &weekday,
769                                        &hour, &min, &sec, &ms);
770   char buffer[128];
771   if (year >= 0 && year <= 9999) {
772     SNPrintF(ArrayVector(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", year,
773              month + 1, day, hour, min, sec, ms);
774   } else if (year < 0) {
775     SNPrintF(ArrayVector(buffer), "-%06d-%02d-%02dT%02d:%02d:%02d.%03dZ", -year,
776              month + 1, day, hour, min, sec, ms);
777   } else {
778     SNPrintF(ArrayVector(buffer), "+%06d-%02d-%02dT%02d:%02d:%02d.%03dZ", year,
779              month + 1, day, hour, min, sec, ms);
780   }
781   return *isolate->factory()->NewStringFromAsciiChecked(buffer);
782 }
783 
784 // ES6 section 20.3.4.41 Date.prototype.toString ( )
BUILTIN(DatePrototypeToString)785 BUILTIN(DatePrototypeToString) {
786   HandleScope scope(isolate);
787   CHECK_RECEIVER(JSDate, date, "Date.prototype.toString");
788   char buffer[128];
789   ToDateString(date->value()->Number(), ArrayVector(buffer),
790                isolate->date_cache());
791   RETURN_RESULT_OR_FAILURE(
792       isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer)));
793 }
794 
795 // ES6 section 20.3.4.42 Date.prototype.toTimeString ( )
BUILTIN(DatePrototypeToTimeString)796 BUILTIN(DatePrototypeToTimeString) {
797   HandleScope scope(isolate);
798   CHECK_RECEIVER(JSDate, date, "Date.prototype.toTimeString");
799   char buffer[128];
800   ToDateString(date->value()->Number(), ArrayVector(buffer),
801                isolate->date_cache(), kTimeOnly);
802   RETURN_RESULT_OR_FAILURE(
803       isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer)));
804 }
805 
806 // ES6 section 20.3.4.43 Date.prototype.toUTCString ( )
BUILTIN(DatePrototypeToUTCString)807 BUILTIN(DatePrototypeToUTCString) {
808   HandleScope scope(isolate);
809   CHECK_RECEIVER(JSDate, date, "Date.prototype.toUTCString");
810   double const time_val = date->value()->Number();
811   if (std::isnan(time_val)) {
812     return *isolate->factory()->NewStringFromAsciiChecked("Invalid Date");
813   }
814   char buffer[128];
815   int64_t time_ms = static_cast<int64_t>(time_val);
816   int year, month, day, weekday, hour, min, sec, ms;
817   isolate->date_cache()->BreakDownTime(time_ms, &year, &month, &day, &weekday,
818                                        &hour, &min, &sec, &ms);
819   SNPrintF(ArrayVector(buffer), "%s, %02d %s %04d %02d:%02d:%02d GMT",
820            kShortWeekDays[weekday], day, kShortMonths[month], year, hour, min,
821            sec);
822   return *isolate->factory()->NewStringFromAsciiChecked(buffer);
823 }
824 
825 // ES6 section B.2.4.1 Date.prototype.getYear ( )
BUILTIN(DatePrototypeGetYear)826 BUILTIN(DatePrototypeGetYear) {
827   HandleScope scope(isolate);
828   CHECK_RECEIVER(JSDate, date, "Date.prototype.getYear");
829   double time_val = date->value()->Number();
830   if (std::isnan(time_val)) return date->value();
831   int64_t time_ms = static_cast<int64_t>(time_val);
832   int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
833   int days = isolate->date_cache()->DaysFromTime(local_time_ms);
834   int year, month, day;
835   isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
836   return Smi::FromInt(year - 1900);
837 }
838 
839 // ES6 section B.2.4.2 Date.prototype.setYear ( year )
BUILTIN(DatePrototypeSetYear)840 BUILTIN(DatePrototypeSetYear) {
841   HandleScope scope(isolate);
842   CHECK_RECEIVER(JSDate, date, "Date.prototype.setYear");
843   Handle<Object> year = args.atOrUndefined(isolate, 1);
844   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year, Object::ToNumber(year));
845   double m = 0.0, dt = 1.0, y = year->Number();
846   if (0.0 <= y && y <= 99.0) {
847     y = 1900.0 + DoubleToInteger(y);
848   }
849   int time_within_day = 0;
850   if (!std::isnan(date->value()->Number())) {
851     int64_t const time_ms = static_cast<int64_t>(date->value()->Number());
852     int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
853     int const days = isolate->date_cache()->DaysFromTime(local_time_ms);
854     time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
855     int year, month, day;
856     isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
857     m = month;
858     dt = day;
859   }
860   double time_val = MakeDate(MakeDay(y, m, dt), time_within_day);
861   return SetLocalDateValue(date, time_val);
862 }
863 
864 // ES6 section 20.3.4.37 Date.prototype.toJSON ( key )
BUILTIN(DatePrototypeToJson)865 BUILTIN(DatePrototypeToJson) {
866   HandleScope scope(isolate);
867   Handle<Object> receiver = args.atOrUndefined(isolate, 0);
868   Handle<JSReceiver> receiver_obj;
869   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_obj,
870                                      Object::ToObject(isolate, receiver));
871   Handle<Object> primitive;
872   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
873       isolate, primitive,
874       Object::ToPrimitive(receiver_obj, ToPrimitiveHint::kNumber));
875   if (primitive->IsNumber() && !std::isfinite(primitive->Number())) {
876     return isolate->heap()->null_value();
877   } else {
878     Handle<String> name =
879         isolate->factory()->NewStringFromAsciiChecked("toISOString");
880     Handle<Object> function;
881     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, function,
882                                        Object::GetProperty(receiver_obj, name));
883     if (!function->IsCallable()) {
884       THROW_NEW_ERROR_RETURN_FAILURE(
885           isolate, NewTypeError(MessageTemplate::kCalledNonCallable, name));
886     }
887     RETURN_RESULT_OR_FAILURE(
888         isolate, Execution::Call(isolate, function, receiver_obj, 0, nullptr));
889   }
890 }
891 
892 }  // namespace internal
893 }  // namespace v8
894