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