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-inl.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(Isolate * isolate,Handle<String> str)107 double ParseDateTimeString(Isolate* isolate, Handle<String> str) {
108 str = String::Flatten(isolate, str);
109 // TODO(bmeurer): Change DateParser to not use the FixedArray.
110 Handle<FixedArray> tmp =
111 isolate->factory()->NewFixedArray(DateParser::OUTPUT_SIZE);
112 DisallowHeapAllocation no_gc;
113 String::FlatContent str_content = str->GetFlatContent();
114 bool result;
115 if (str_content.IsOneByte()) {
116 result = DateParser::Parse(isolate, str_content.ToOneByteVector(), *tmp);
117 } else {
118 result = DateParser::Parse(isolate, str_content.ToUC16Vector(), *tmp);
119 }
120 if (!result) return std::numeric_limits<double>::quiet_NaN();
121 double const day = MakeDay(tmp->get(0)->Number(), tmp->get(1)->Number(),
122 tmp->get(2)->Number());
123 double const time = MakeTime(tmp->get(3)->Number(), tmp->get(4)->Number(),
124 tmp->get(5)->Number(), tmp->get(6)->Number());
125 double date = MakeDate(day, time);
126 if (tmp->get(7)->IsNull(isolate)) {
127 if (!std::isnan(date)) {
128 date = isolate->date_cache()->ToUTC(static_cast<int64_t>(date));
129 }
130 } else {
131 date -= tmp->get(7)->Number() * 1000.0;
132 }
133 return date;
134 }
135
136 enum ToDateStringMode { kDateOnly, kTimeOnly, kDateAndTime };
137
138 // ES6 section 20.3.4.41.1 ToDateString(tv)
ToDateString(double time_val,Vector<char> str,DateCache * date_cache,ToDateStringMode mode=kDateAndTime)139 void ToDateString(double time_val, Vector<char> str, DateCache* date_cache,
140 ToDateStringMode mode = kDateAndTime) {
141 if (std::isnan(time_val)) {
142 SNPrintF(str, "Invalid Date");
143 return;
144 }
145 int64_t time_ms = static_cast<int64_t>(time_val);
146 int64_t local_time_ms = date_cache->ToLocal(time_ms);
147 int year, month, day, weekday, hour, min, sec, ms;
148 date_cache->BreakDownTime(local_time_ms, &year, &month, &day, &weekday, &hour,
149 &min, &sec, &ms);
150 int timezone_offset = -date_cache->TimezoneOffset(time_ms);
151 int timezone_hour = std::abs(timezone_offset) / 60;
152 int timezone_min = std::abs(timezone_offset) % 60;
153 const char* local_timezone = date_cache->LocalTimezone(time_ms);
154 switch (mode) {
155 case kDateOnly:
156 SNPrintF(str, "%s %s %02d %04d", kShortWeekDays[weekday],
157 kShortMonths[month], day, year);
158 return;
159 case kTimeOnly:
160 // TODO(842085): str may be silently truncated.
161 SNPrintF(str, "%02d:%02d:%02d GMT%c%02d%02d (%s)", hour, min, sec,
162 (timezone_offset < 0) ? '-' : '+', timezone_hour, timezone_min,
163 local_timezone);
164 return;
165 case kDateAndTime:
166 // TODO(842085): str may be silently truncated.
167 SNPrintF(str, "%s %s %02d %04d %02d:%02d:%02d GMT%c%02d%02d (%s)",
168 kShortWeekDays[weekday], kShortMonths[month], day, year, hour,
169 min, sec, (timezone_offset < 0) ? '-' : '+', timezone_hour,
170 timezone_min, local_timezone);
171 return;
172 }
173 UNREACHABLE();
174 }
175
SetLocalDateValue(Isolate * isolate,Handle<JSDate> date,double time_val)176 Object* SetLocalDateValue(Isolate* isolate, Handle<JSDate> date,
177 double time_val) {
178 if (time_val >= -DateCache::kMaxTimeBeforeUTCInMs &&
179 time_val <= DateCache::kMaxTimeBeforeUTCInMs) {
180 time_val = isolate->date_cache()->ToUTC(static_cast<int64_t>(time_val));
181 } else {
182 time_val = std::numeric_limits<double>::quiet_NaN();
183 }
184 return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
185 }
186
187 } // namespace
188
189 // ES #sec-date-constructor
BUILTIN(DateConstructor)190 BUILTIN(DateConstructor) {
191 HandleScope scope(isolate);
192 if (args.new_target()->IsUndefined(isolate)) {
193 double const time_val = JSDate::CurrentTimeValue(isolate);
194 char buffer[128];
195 ToDateString(time_val, ArrayVector(buffer), isolate->date_cache());
196 RETURN_RESULT_OR_FAILURE(
197 isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer)));
198 }
199 // [Construct]
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(isolate, Handle<String>::cast(value));
215 } else {
216 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
217 Object::ToNumber(isolate, 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(isolate, args.at(1)));
225 Handle<Object> month_object;
226 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month_object,
227 Object::ToNumber(isolate, 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(isolate, args.at(3)));
235 date = date_object->Number();
236 if (argc >= 4) {
237 Handle<Object> hours_object;
238 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
239 isolate, hours_object, Object::ToNumber(isolate, args.at(4)));
240 hours = hours_object->Number();
241 if (argc >= 5) {
242 Handle<Object> minutes_object;
243 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
244 isolate, minutes_object, Object::ToNumber(isolate, args.at(5)));
245 minutes = minutes_object->Number();
246 if (argc >= 6) {
247 Handle<Object> seconds_object;
248 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
249 isolate, seconds_object, Object::ToNumber(isolate, 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(isolate, 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, JSDate::New(target, new_target, time_val));
276 }
277
278 // ES6 section 20.3.3.1 Date.now ( )
BUILTIN(DateNow)279 BUILTIN(DateNow) {
280 HandleScope scope(isolate);
281 return *isolate->factory()->NewNumber(JSDate::CurrentTimeValue(isolate));
282 }
283
284 // ES6 section 20.3.3.2 Date.parse ( string )
BUILTIN(DateParse)285 BUILTIN(DateParse) {
286 HandleScope scope(isolate);
287 Handle<String> string;
288 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
289 isolate, string,
290 Object::ToString(isolate, args.atOrUndefined(isolate, 1)));
291 return *isolate->factory()->NewNumber(ParseDateTimeString(isolate, string));
292 }
293
294 // ES6 section 20.3.3.4 Date.UTC (year,month,date,hours,minutes,seconds,ms)
BUILTIN(DateUTC)295 BUILTIN(DateUTC) {
296 HandleScope scope(isolate);
297 int const argc = args.length() - 1;
298 double year = std::numeric_limits<double>::quiet_NaN();
299 double month = 0.0, date = 1.0, hours = 0.0, minutes = 0.0, seconds = 0.0,
300 ms = 0.0;
301 if (argc >= 1) {
302 Handle<Object> year_object;
303 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year_object,
304 Object::ToNumber(isolate, args.at(1)));
305 year = year_object->Number();
306 if (argc >= 2) {
307 Handle<Object> month_object;
308 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month_object,
309 Object::ToNumber(isolate, args.at(2)));
310 month = month_object->Number();
311 if (argc >= 3) {
312 Handle<Object> date_object;
313 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
314 isolate, date_object, Object::ToNumber(isolate, args.at(3)));
315 date = date_object->Number();
316 if (argc >= 4) {
317 Handle<Object> hours_object;
318 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
319 isolate, hours_object, Object::ToNumber(isolate, args.at(4)));
320 hours = hours_object->Number();
321 if (argc >= 5) {
322 Handle<Object> minutes_object;
323 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
324 isolate, minutes_object, Object::ToNumber(isolate, args.at(5)));
325 minutes = minutes_object->Number();
326 if (argc >= 6) {
327 Handle<Object> seconds_object;
328 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
329 isolate, seconds_object,
330 Object::ToNumber(isolate, args.at(6)));
331 seconds = seconds_object->Number();
332 if (argc >= 7) {
333 Handle<Object> ms_object;
334 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
335 isolate, ms_object, Object::ToNumber(isolate, args.at(7)));
336 ms = ms_object->Number();
337 }
338 }
339 }
340 }
341 }
342 }
343 }
344 if (!std::isnan(year)) {
345 double const y = DoubleToInteger(year);
346 if (0.0 <= y && y <= 99) year = 1900 + y;
347 }
348 double const day = MakeDay(year, month, date);
349 double const time = MakeTime(hours, minutes, seconds, ms);
350 return *isolate->factory()->NewNumber(
351 DateCache::TimeClip(MakeDate(day, time)));
352 }
353
354 // ES6 section 20.3.4.20 Date.prototype.setDate ( date )
BUILTIN(DatePrototypeSetDate)355 BUILTIN(DatePrototypeSetDate) {
356 HandleScope scope(isolate);
357 CHECK_RECEIVER(JSDate, date, "Date.prototype.setDate");
358 Handle<Object> value = args.atOrUndefined(isolate, 1);
359 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
360 Object::ToNumber(isolate, 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(isolate, 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,
381 Object::ToNumber(isolate, year));
382 double y = year->Number(), m = 0.0, dt = 1.0;
383 int time_within_day = 0;
384 if (!std::isnan(date->value()->Number())) {
385 int64_t const time_ms = static_cast<int64_t>(date->value()->Number());
386 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
387 int const days = isolate->date_cache()->DaysFromTime(local_time_ms);
388 time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
389 int year, month, day;
390 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
391 m = month;
392 dt = day;
393 }
394 if (argc >= 2) {
395 Handle<Object> month = args.at(2);
396 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month,
397 Object::ToNumber(isolate, month));
398 m = month->Number();
399 if (argc >= 3) {
400 Handle<Object> date = args.at(3);
401 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date,
402 Object::ToNumber(isolate, date));
403 dt = date->Number();
404 }
405 }
406 double time_val = MakeDate(MakeDay(y, m, dt), time_within_day);
407 return SetLocalDateValue(isolate, date, time_val);
408 }
409
410 // ES6 section 20.3.4.22 Date.prototype.setHours(hour, min, sec, ms)
BUILTIN(DatePrototypeSetHours)411 BUILTIN(DatePrototypeSetHours) {
412 HandleScope scope(isolate);
413 CHECK_RECEIVER(JSDate, date, "Date.prototype.setHours");
414 int const argc = args.length() - 1;
415 Handle<Object> hour = args.atOrUndefined(isolate, 1);
416 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, hour,
417 Object::ToNumber(isolate, hour));
418 double h = hour->Number();
419 double time_val = date->value()->Number();
420 if (!std::isnan(time_val)) {
421 int64_t const time_ms = static_cast<int64_t>(time_val);
422 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
423 int day = isolate->date_cache()->DaysFromTime(local_time_ms);
424 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
425 double m = (time_within_day / (60 * 1000)) % 60;
426 double s = (time_within_day / 1000) % 60;
427 double milli = time_within_day % 1000;
428 if (argc >= 2) {
429 Handle<Object> min = args.at(2);
430 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min,
431 Object::ToNumber(isolate, min));
432 m = min->Number();
433 if (argc >= 3) {
434 Handle<Object> sec = args.at(3);
435 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec,
436 Object::ToNumber(isolate, sec));
437 s = sec->Number();
438 if (argc >= 4) {
439 Handle<Object> ms = args.at(4);
440 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
441 Object::ToNumber(isolate, ms));
442 milli = ms->Number();
443 }
444 }
445 }
446 time_val = MakeDate(day, MakeTime(h, m, s, milli));
447 }
448 return SetLocalDateValue(isolate, date, time_val);
449 }
450
451 // ES6 section 20.3.4.23 Date.prototype.setMilliseconds(ms)
BUILTIN(DatePrototypeSetMilliseconds)452 BUILTIN(DatePrototypeSetMilliseconds) {
453 HandleScope scope(isolate);
454 CHECK_RECEIVER(JSDate, date, "Date.prototype.setMilliseconds");
455 Handle<Object> ms = args.atOrUndefined(isolate, 1);
456 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
457 Object::ToNumber(isolate, ms));
458 double time_val = date->value()->Number();
459 if (!std::isnan(time_val)) {
460 int64_t const time_ms = static_cast<int64_t>(time_val);
461 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
462 int day = isolate->date_cache()->DaysFromTime(local_time_ms);
463 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
464 int h = time_within_day / (60 * 60 * 1000);
465 int m = (time_within_day / (60 * 1000)) % 60;
466 int s = (time_within_day / 1000) % 60;
467 time_val = MakeDate(day, MakeTime(h, m, s, ms->Number()));
468 }
469 return SetLocalDateValue(isolate, date, time_val);
470 }
471
472 // ES6 section 20.3.4.24 Date.prototype.setMinutes ( min, sec, ms )
BUILTIN(DatePrototypeSetMinutes)473 BUILTIN(DatePrototypeSetMinutes) {
474 HandleScope scope(isolate);
475 CHECK_RECEIVER(JSDate, date, "Date.prototype.setMinutes");
476 int const argc = args.length() - 1;
477 Handle<Object> min = args.atOrUndefined(isolate, 1);
478 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min,
479 Object::ToNumber(isolate, min));
480 double time_val = date->value()->Number();
481 if (!std::isnan(time_val)) {
482 int64_t const time_ms = static_cast<int64_t>(time_val);
483 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
484 int day = isolate->date_cache()->DaysFromTime(local_time_ms);
485 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
486 int h = time_within_day / (60 * 60 * 1000);
487 double m = min->Number();
488 double s = (time_within_day / 1000) % 60;
489 double milli = time_within_day % 1000;
490 if (argc >= 2) {
491 Handle<Object> sec = args.at(2);
492 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec,
493 Object::ToNumber(isolate, sec));
494 s = sec->Number();
495 if (argc >= 3) {
496 Handle<Object> ms = args.at(3);
497 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
498 Object::ToNumber(isolate, ms));
499 milli = ms->Number();
500 }
501 }
502 time_val = MakeDate(day, MakeTime(h, m, s, milli));
503 }
504 return SetLocalDateValue(isolate, date, time_val);
505 }
506
507 // ES6 section 20.3.4.25 Date.prototype.setMonth ( month, date )
BUILTIN(DatePrototypeSetMonth)508 BUILTIN(DatePrototypeSetMonth) {
509 HandleScope scope(isolate);
510 CHECK_RECEIVER(JSDate, date, "Date.prototype.setMonth");
511 int const argc = args.length() - 1;
512 Handle<Object> month = args.atOrUndefined(isolate, 1);
513 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month,
514 Object::ToNumber(isolate, month));
515 double time_val = date->value()->Number();
516 if (!std::isnan(time_val)) {
517 int64_t const time_ms = static_cast<int64_t>(time_val);
518 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
519 int days = isolate->date_cache()->DaysFromTime(local_time_ms);
520 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
521 int year, unused, day;
522 isolate->date_cache()->YearMonthDayFromDays(days, &year, &unused, &day);
523 double m = month->Number();
524 double dt = day;
525 if (argc >= 2) {
526 Handle<Object> date = args.at(2);
527 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date,
528 Object::ToNumber(isolate, date));
529 dt = date->Number();
530 }
531 time_val = MakeDate(MakeDay(year, m, dt), time_within_day);
532 }
533 return SetLocalDateValue(isolate, date, time_val);
534 }
535
536 // ES6 section 20.3.4.26 Date.prototype.setSeconds ( sec, ms )
BUILTIN(DatePrototypeSetSeconds)537 BUILTIN(DatePrototypeSetSeconds) {
538 HandleScope scope(isolate);
539 CHECK_RECEIVER(JSDate, date, "Date.prototype.setSeconds");
540 int const argc = args.length() - 1;
541 Handle<Object> sec = args.atOrUndefined(isolate, 1);
542 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec,
543 Object::ToNumber(isolate, sec));
544 double time_val = date->value()->Number();
545 if (!std::isnan(time_val)) {
546 int64_t const time_ms = static_cast<int64_t>(time_val);
547 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
548 int day = isolate->date_cache()->DaysFromTime(local_time_ms);
549 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day);
550 int h = time_within_day / (60 * 60 * 1000);
551 double m = (time_within_day / (60 * 1000)) % 60;
552 double s = sec->Number();
553 double milli = time_within_day % 1000;
554 if (argc >= 2) {
555 Handle<Object> ms = args.at(2);
556 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
557 Object::ToNumber(isolate, ms));
558 milli = ms->Number();
559 }
560 time_val = MakeDate(day, MakeTime(h, m, s, milli));
561 }
562 return SetLocalDateValue(isolate, date, time_val);
563 }
564
565 // ES6 section 20.3.4.27 Date.prototype.setTime ( time )
BUILTIN(DatePrototypeSetTime)566 BUILTIN(DatePrototypeSetTime) {
567 HandleScope scope(isolate);
568 CHECK_RECEIVER(JSDate, date, "Date.prototype.setTime");
569 Handle<Object> value = args.atOrUndefined(isolate, 1);
570 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
571 Object::ToNumber(isolate, value));
572 return *JSDate::SetValue(date, DateCache::TimeClip(value->Number()));
573 }
574
575 // ES6 section 20.3.4.28 Date.prototype.setUTCDate ( date )
BUILTIN(DatePrototypeSetUTCDate)576 BUILTIN(DatePrototypeSetUTCDate) {
577 HandleScope scope(isolate);
578 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCDate");
579 Handle<Object> value = args.atOrUndefined(isolate, 1);
580 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value,
581 Object::ToNumber(isolate, value));
582 if (std::isnan(date->value()->Number())) return date->value();
583 int64_t const time_ms = static_cast<int64_t>(date->value()->Number());
584 int const days = isolate->date_cache()->DaysFromTime(time_ms);
585 int const time_within_day = isolate->date_cache()->TimeInDay(time_ms, days);
586 int year, month, day;
587 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
588 double const time_val =
589 MakeDate(MakeDay(year, month, value->Number()), time_within_day);
590 return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
591 }
592
593 // ES6 section 20.3.4.29 Date.prototype.setUTCFullYear (year, month, date)
BUILTIN(DatePrototypeSetUTCFullYear)594 BUILTIN(DatePrototypeSetUTCFullYear) {
595 HandleScope scope(isolate);
596 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCFullYear");
597 int const argc = args.length() - 1;
598 Handle<Object> year = args.atOrUndefined(isolate, 1);
599 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year,
600 Object::ToNumber(isolate, year));
601 double y = year->Number(), m = 0.0, dt = 1.0;
602 int time_within_day = 0;
603 if (!std::isnan(date->value()->Number())) {
604 int64_t const time_ms = static_cast<int64_t>(date->value()->Number());
605 int const days = isolate->date_cache()->DaysFromTime(time_ms);
606 time_within_day = isolate->date_cache()->TimeInDay(time_ms, days);
607 int year, month, day;
608 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
609 m = month;
610 dt = day;
611 }
612 if (argc >= 2) {
613 Handle<Object> month = args.at(2);
614 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month,
615 Object::ToNumber(isolate, month));
616 m = month->Number();
617 if (argc >= 3) {
618 Handle<Object> date = args.at(3);
619 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date,
620 Object::ToNumber(isolate, date));
621 dt = date->Number();
622 }
623 }
624 double const time_val = MakeDate(MakeDay(y, m, dt), time_within_day);
625 return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
626 }
627
628 // ES6 section 20.3.4.30 Date.prototype.setUTCHours(hour, min, sec, ms)
BUILTIN(DatePrototypeSetUTCHours)629 BUILTIN(DatePrototypeSetUTCHours) {
630 HandleScope scope(isolate);
631 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCHours");
632 int const argc = args.length() - 1;
633 Handle<Object> hour = args.atOrUndefined(isolate, 1);
634 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, hour,
635 Object::ToNumber(isolate, hour));
636 double h = hour->Number();
637 double time_val = date->value()->Number();
638 if (!std::isnan(time_val)) {
639 int64_t const time_ms = static_cast<int64_t>(time_val);
640 int day = isolate->date_cache()->DaysFromTime(time_ms);
641 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
642 double m = (time_within_day / (60 * 1000)) % 60;
643 double s = (time_within_day / 1000) % 60;
644 double milli = time_within_day % 1000;
645 if (argc >= 2) {
646 Handle<Object> min = args.at(2);
647 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min,
648 Object::ToNumber(isolate, min));
649 m = min->Number();
650 if (argc >= 3) {
651 Handle<Object> sec = args.at(3);
652 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec,
653 Object::ToNumber(isolate, sec));
654 s = sec->Number();
655 if (argc >= 4) {
656 Handle<Object> ms = args.at(4);
657 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
658 Object::ToNumber(isolate, ms));
659 milli = ms->Number();
660 }
661 }
662 }
663 time_val = MakeDate(day, MakeTime(h, m, s, milli));
664 }
665 return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
666 }
667
668 // ES6 section 20.3.4.31 Date.prototype.setUTCMilliseconds(ms)
BUILTIN(DatePrototypeSetUTCMilliseconds)669 BUILTIN(DatePrototypeSetUTCMilliseconds) {
670 HandleScope scope(isolate);
671 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMilliseconds");
672 Handle<Object> ms = args.atOrUndefined(isolate, 1);
673 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
674 Object::ToNumber(isolate, ms));
675 double time_val = date->value()->Number();
676 if (!std::isnan(time_val)) {
677 int64_t const time_ms = static_cast<int64_t>(time_val);
678 int day = isolate->date_cache()->DaysFromTime(time_ms);
679 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
680 int h = time_within_day / (60 * 60 * 1000);
681 int m = (time_within_day / (60 * 1000)) % 60;
682 int s = (time_within_day / 1000) % 60;
683 time_val = MakeDate(day, MakeTime(h, m, s, ms->Number()));
684 }
685 return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
686 }
687
688 // ES6 section 20.3.4.32 Date.prototype.setUTCMinutes ( min, sec, ms )
BUILTIN(DatePrototypeSetUTCMinutes)689 BUILTIN(DatePrototypeSetUTCMinutes) {
690 HandleScope scope(isolate);
691 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMinutes");
692 int const argc = args.length() - 1;
693 Handle<Object> min = args.atOrUndefined(isolate, 1);
694 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min,
695 Object::ToNumber(isolate, min));
696 double time_val = date->value()->Number();
697 if (!std::isnan(time_val)) {
698 int64_t const time_ms = static_cast<int64_t>(time_val);
699 int day = isolate->date_cache()->DaysFromTime(time_ms);
700 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
701 int h = time_within_day / (60 * 60 * 1000);
702 double m = min->Number();
703 double s = (time_within_day / 1000) % 60;
704 double milli = time_within_day % 1000;
705 if (argc >= 2) {
706 Handle<Object> sec = args.at(2);
707 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec,
708 Object::ToNumber(isolate, sec));
709 s = sec->Number();
710 if (argc >= 3) {
711 Handle<Object> ms = args.at(3);
712 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
713 Object::ToNumber(isolate, ms));
714 milli = ms->Number();
715 }
716 }
717 time_val = MakeDate(day, MakeTime(h, m, s, milli));
718 }
719 return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
720 }
721
722 // ES6 section 20.3.4.31 Date.prototype.setUTCMonth ( month, date )
BUILTIN(DatePrototypeSetUTCMonth)723 BUILTIN(DatePrototypeSetUTCMonth) {
724 HandleScope scope(isolate);
725 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMonth");
726 int const argc = args.length() - 1;
727 Handle<Object> month = args.atOrUndefined(isolate, 1);
728 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month,
729 Object::ToNumber(isolate, month));
730 double time_val = date->value()->Number();
731 if (!std::isnan(time_val)) {
732 int64_t const time_ms = static_cast<int64_t>(time_val);
733 int days = isolate->date_cache()->DaysFromTime(time_ms);
734 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, days);
735 int year, unused, day;
736 isolate->date_cache()->YearMonthDayFromDays(days, &year, &unused, &day);
737 double m = month->Number();
738 double dt = day;
739 if (argc >= 2) {
740 Handle<Object> date = args.at(2);
741 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date,
742 Object::ToNumber(isolate, date));
743 dt = date->Number();
744 }
745 time_val = MakeDate(MakeDay(year, m, dt), time_within_day);
746 }
747 return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
748 }
749
750 // ES6 section 20.3.4.34 Date.prototype.setUTCSeconds ( sec, ms )
BUILTIN(DatePrototypeSetUTCSeconds)751 BUILTIN(DatePrototypeSetUTCSeconds) {
752 HandleScope scope(isolate);
753 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCSeconds");
754 int const argc = args.length() - 1;
755 Handle<Object> sec = args.atOrUndefined(isolate, 1);
756 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec,
757 Object::ToNumber(isolate, sec));
758 double time_val = date->value()->Number();
759 if (!std::isnan(time_val)) {
760 int64_t const time_ms = static_cast<int64_t>(time_val);
761 int day = isolate->date_cache()->DaysFromTime(time_ms);
762 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day);
763 int h = time_within_day / (60 * 60 * 1000);
764 double m = (time_within_day / (60 * 1000)) % 60;
765 double s = sec->Number();
766 double milli = time_within_day % 1000;
767 if (argc >= 2) {
768 Handle<Object> ms = args.at(2);
769 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms,
770 Object::ToNumber(isolate, ms));
771 milli = ms->Number();
772 }
773 time_val = MakeDate(day, MakeTime(h, m, s, milli));
774 }
775 return *JSDate::SetValue(date, DateCache::TimeClip(time_val));
776 }
777
778 // ES6 section 20.3.4.35 Date.prototype.toDateString ( )
BUILTIN(DatePrototypeToDateString)779 BUILTIN(DatePrototypeToDateString) {
780 HandleScope scope(isolate);
781 CHECK_RECEIVER(JSDate, date, "Date.prototype.toDateString");
782 char buffer[128];
783 ToDateString(date->value()->Number(), ArrayVector(buffer),
784 isolate->date_cache(), kDateOnly);
785 RETURN_RESULT_OR_FAILURE(
786 isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer)));
787 }
788
789 // ES6 section 20.3.4.36 Date.prototype.toISOString ( )
BUILTIN(DatePrototypeToISOString)790 BUILTIN(DatePrototypeToISOString) {
791 HandleScope scope(isolate);
792 CHECK_RECEIVER(JSDate, date, "Date.prototype.toISOString");
793 double const time_val = date->value()->Number();
794 if (std::isnan(time_val)) {
795 THROW_NEW_ERROR_RETURN_FAILURE(
796 isolate, NewRangeError(MessageTemplate::kInvalidTimeValue));
797 }
798 int64_t const time_ms = static_cast<int64_t>(time_val);
799 int year, month, day, weekday, hour, min, sec, ms;
800 isolate->date_cache()->BreakDownTime(time_ms, &year, &month, &day, &weekday,
801 &hour, &min, &sec, &ms);
802 char buffer[128];
803 if (year >= 0 && year <= 9999) {
804 SNPrintF(ArrayVector(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", year,
805 month + 1, day, hour, min, sec, ms);
806 } else if (year < 0) {
807 SNPrintF(ArrayVector(buffer), "-%06d-%02d-%02dT%02d:%02d:%02d.%03dZ", -year,
808 month + 1, day, hour, min, sec, ms);
809 } else {
810 SNPrintF(ArrayVector(buffer), "+%06d-%02d-%02dT%02d:%02d:%02d.%03dZ", year,
811 month + 1, day, hour, min, sec, ms);
812 }
813 return *isolate->factory()->NewStringFromAsciiChecked(buffer);
814 }
815
816 // ES6 section 20.3.4.41 Date.prototype.toString ( )
BUILTIN(DatePrototypeToString)817 BUILTIN(DatePrototypeToString) {
818 HandleScope scope(isolate);
819 CHECK_RECEIVER(JSDate, date, "Date.prototype.toString");
820 char buffer[128];
821 ToDateString(date->value()->Number(), ArrayVector(buffer),
822 isolate->date_cache());
823 RETURN_RESULT_OR_FAILURE(
824 isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer)));
825 }
826
827 // ES6 section 20.3.4.42 Date.prototype.toTimeString ( )
BUILTIN(DatePrototypeToTimeString)828 BUILTIN(DatePrototypeToTimeString) {
829 HandleScope scope(isolate);
830 CHECK_RECEIVER(JSDate, date, "Date.prototype.toTimeString");
831 char buffer[128];
832 ToDateString(date->value()->Number(), ArrayVector(buffer),
833 isolate->date_cache(), kTimeOnly);
834 RETURN_RESULT_OR_FAILURE(
835 isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer)));
836 }
837
838 // ES6 section 20.3.4.43 Date.prototype.toUTCString ( )
BUILTIN(DatePrototypeToUTCString)839 BUILTIN(DatePrototypeToUTCString) {
840 HandleScope scope(isolate);
841 CHECK_RECEIVER(JSDate, date, "Date.prototype.toUTCString");
842 double const time_val = date->value()->Number();
843 if (std::isnan(time_val)) {
844 return *isolate->factory()->NewStringFromAsciiChecked("Invalid Date");
845 }
846 char buffer[128];
847 int64_t time_ms = static_cast<int64_t>(time_val);
848 int year, month, day, weekday, hour, min, sec, ms;
849 isolate->date_cache()->BreakDownTime(time_ms, &year, &month, &day, &weekday,
850 &hour, &min, &sec, &ms);
851 SNPrintF(ArrayVector(buffer), "%s, %02d %s %04d %02d:%02d:%02d GMT",
852 kShortWeekDays[weekday], day, kShortMonths[month], year, hour, min,
853 sec);
854 return *isolate->factory()->NewStringFromAsciiChecked(buffer);
855 }
856
857 // ES6 section B.2.4.1 Date.prototype.getYear ( )
BUILTIN(DatePrototypeGetYear)858 BUILTIN(DatePrototypeGetYear) {
859 HandleScope scope(isolate);
860 CHECK_RECEIVER(JSDate, date, "Date.prototype.getYear");
861 double time_val = date->value()->Number();
862 if (std::isnan(time_val)) return date->value();
863 int64_t time_ms = static_cast<int64_t>(time_val);
864 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
865 int days = isolate->date_cache()->DaysFromTime(local_time_ms);
866 int year, month, day;
867 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
868 return Smi::FromInt(year - 1900);
869 }
870
871 // ES6 section B.2.4.2 Date.prototype.setYear ( year )
BUILTIN(DatePrototypeSetYear)872 BUILTIN(DatePrototypeSetYear) {
873 HandleScope scope(isolate);
874 CHECK_RECEIVER(JSDate, date, "Date.prototype.setYear");
875 Handle<Object> year = args.atOrUndefined(isolate, 1);
876 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year,
877 Object::ToNumber(isolate, year));
878 double m = 0.0, dt = 1.0, y = year->Number();
879 if (0.0 <= y && y <= 99.0) {
880 y = 1900.0 + DoubleToInteger(y);
881 }
882 int time_within_day = 0;
883 if (!std::isnan(date->value()->Number())) {
884 int64_t const time_ms = static_cast<int64_t>(date->value()->Number());
885 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms);
886 int const days = isolate->date_cache()->DaysFromTime(local_time_ms);
887 time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days);
888 int year, month, day;
889 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day);
890 m = month;
891 dt = day;
892 }
893 double time_val = MakeDate(MakeDay(y, m, dt), time_within_day);
894 return SetLocalDateValue(isolate, date, time_val);
895 }
896
897 // ES6 section 20.3.4.37 Date.prototype.toJSON ( key )
BUILTIN(DatePrototypeToJson)898 BUILTIN(DatePrototypeToJson) {
899 HandleScope scope(isolate);
900 Handle<Object> receiver = args.atOrUndefined(isolate, 0);
901 Handle<JSReceiver> receiver_obj;
902 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_obj,
903 Object::ToObject(isolate, receiver));
904 Handle<Object> primitive;
905 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
906 isolate, primitive,
907 Object::ToPrimitive(receiver_obj, ToPrimitiveHint::kNumber));
908 if (primitive->IsNumber() && !std::isfinite(primitive->Number())) {
909 return ReadOnlyRoots(isolate).null_value();
910 } else {
911 Handle<String> name =
912 isolate->factory()->NewStringFromAsciiChecked("toISOString");
913 Handle<Object> function;
914 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
915 isolate, function, Object::GetProperty(isolate, receiver_obj, name));
916 if (!function->IsCallable()) {
917 THROW_NEW_ERROR_RETURN_FAILURE(
918 isolate, NewTypeError(MessageTemplate::kCalledNonCallable, name));
919 }
920 RETURN_RESULT_OR_FAILURE(
921 isolate, Execution::Call(isolate, function, receiver_obj, 0, nullptr));
922 }
923 }
924
925 } // namespace internal
926 } // namespace v8
927