Coverage Report

Created: 2025-01-28 06:38

/src/hermes/lib/VM/JSLib/Date.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
8
//===----------------------------------------------------------------------===//
9
/// \file
10
/// ES5.1 15.9 Initialize the Date constructor.
11
//===----------------------------------------------------------------------===//
12
13
#include "JSLibInternal.h"
14
15
#include "hermes/Support/OSCompat.h"
16
#include "hermes/VM/HermesValue.h"
17
#include "hermes/VM/JSLib/DateUtil.h"
18
#include "hermes/VM/JSLib/JSLibStorage.h"
19
#include "hermes/VM/Operations.h"
20
#pragma GCC diagnostic push
21
22
#ifdef HERMES_COMPILER_SUPPORTS_WSHORTEN_64_TO_32
23
#pragma GCC diagnostic ignored "-Wshorten-64-to-32"
24
#endif
25
namespace hermes {
26
namespace vm {
27
28
//===----------------------------------------------------------------------===//
29
/// Date.
30
31
namespace {
32
struct ToStringOptions {
33
  /// Converts a time \p t that has been adjusted by \p tza from UTC,
34
  /// and appends the resultant string into \p buf.
35
  /// \param t the local time since Jan 1 1970 UTC.
36
  /// \param tza the offset from UTC that \p t has been adjusted by.
37
  /// \param buf[out] the buffer into which to output the result string.
38
  void (*toStringFn)(double t, double tza, llvh::SmallVectorImpl<char> &buf);
39
  bool isUTC;
40
  /// Throw if the internal value of this Date is not finite.
41
  bool throwOnError;
42
};
43
44
struct ToLocaleStringOptions {
45
  /// Converts a time \p t that has been adjusted by \p tza from UTC,
46
  /// and appends the resultant string into \p buf.
47
  /// \param t the local time since Jan 1 1970 UTC.
48
  /// \param locale the locale to convert in (the current locale).
49
  /// \param buf[out] the buffer into which to output the result string.
50
  void (*toStringFn)(double t, llvh::SmallVectorImpl<char16_t> &buf);
51
};
52
53
struct GetterOptions {
54
  enum Field {
55
    FULL_YEAR,
56
    YEAR,
57
    MONTH,
58
    DATE,
59
    DAY,
60
    HOURS,
61
    MINUTES,
62
    SECONDS,
63
    MILLISECONDS,
64
    TIMEZONE_OFFSET,
65
  };
66
  Field field;
67
  bool isUTC;
68
};
69
} // namespace
70
71
enum class ToStringKind {
72
  DatetimeToString,
73
  DateToString,
74
  TimeToString,
75
  ISOToString,
76
  UTCToString,
77
  NumKinds
78
};
79
80
enum class ToLocaleStringKind {
81
  DatetimeToLocaleString,
82
  DateToLocaleString,
83
  TimeToLocaleString,
84
  NumKinds
85
};
86
87
enum class GetterKind {
88
  GetFullYear,
89
  GetYear,
90
  GetMonth,
91
  GetDate,
92
  GetDay,
93
  GetHours,
94
  GetMinutes,
95
  GetSeconds,
96
  GetMilliseconds,
97
  GetUTCFullYear,
98
  GetUTCMonth,
99
  GetUTCDate,
100
  GetUTCDay,
101
  GetUTCHours,
102
  GetUTCMinutes,
103
  GetUTCSeconds,
104
  GetUTCMilliseconds,
105
  GetTimezoneOffset,
106
  NumKinds
107
};
108
109
160
Handle<JSObject> createDateConstructor(Runtime &runtime) {
110
160
  auto datePrototype = Handle<JSObject>::vmcast(&runtime.datePrototype);
111
160
  auto cons = defineSystemConstructor<JSDate>(
112
160
      runtime,
113
160
      Predefined::getSymbolID(Predefined::Date),
114
160
      dateConstructor_RJS,
115
160
      datePrototype,
116
160
      7,
117
160
      CellKind::JSDateKind);
118
119
  // Date.prototype.xxx() methods.
120
160
  defineMethod(
121
160
      runtime,
122
160
      datePrototype,
123
160
      Predefined::getSymbolID(Predefined::valueOf),
124
160
      nullptr,
125
160
      datePrototypeGetTime,
126
160
      0);
127
160
  defineMethod(
128
160
      runtime,
129
160
      datePrototype,
130
160
      Predefined::getSymbolID(Predefined::getTime),
131
160
      nullptr,
132
160
      datePrototypeGetTime,
133
160
      0);
134
135
960
  auto defineToStringMethod = [&](SymbolID name, ToStringKind kind) {
136
960
    defineMethod(
137
960
        runtime,
138
960
        datePrototype,
139
960
        name,
140
960
        (void *)kind,
141
960
        datePrototypeToStringHelper,
142
960
        0);
143
960
  };
144
145
160
  defineToStringMethod(
146
160
      Predefined::getSymbolID(Predefined::toString),
147
160
      ToStringKind::DatetimeToString);
148
160
  defineToStringMethod(
149
160
      Predefined::getSymbolID(Predefined::toDateString),
150
160
      ToStringKind::DateToString);
151
160
  defineToStringMethod(
152
160
      Predefined::getSymbolID(Predefined::toTimeString),
153
160
      ToStringKind::TimeToString);
154
160
  defineToStringMethod(
155
160
      Predefined::getSymbolID(Predefined::toISOString),
156
160
      ToStringKind::ISOToString);
157
160
  defineToStringMethod(
158
160
      Predefined::getSymbolID(Predefined::toUTCString),
159
160
      ToStringKind::UTCToString);
160
160
  defineToStringMethod(
161
160
      Predefined::getSymbolID(Predefined::toGMTString),
162
160
      ToStringKind::UTCToString);
163
164
160
  auto defineToLocaleStringMethod = [&](SymbolID name,
165
480
                                        ToLocaleStringKind kind) {
166
480
    defineMethod(
167
480
        runtime,
168
480
        datePrototype,
169
480
        name,
170
480
        (void *)kind,
171
480
        datePrototypeToLocaleStringHelper,
172
480
        0);
173
480
  };
174
175
160
  defineToLocaleStringMethod(
176
160
      Predefined::getSymbolID(Predefined::toLocaleString),
177
160
      ToLocaleStringKind::DatetimeToLocaleString);
178
160
  defineToLocaleStringMethod(
179
160
      Predefined::getSymbolID(Predefined::toLocaleDateString),
180
160
      ToLocaleStringKind::DateToLocaleString);
181
160
  defineToLocaleStringMethod(
182
160
      Predefined::getSymbolID(Predefined::toLocaleTimeString),
183
160
      ToLocaleStringKind::TimeToLocaleString);
184
185
2.88k
  auto defineGetterMethod = [&](SymbolID name, GetterKind kind) {
186
2.88k
    defineMethod(
187
2.88k
        runtime,
188
2.88k
        datePrototype,
189
2.88k
        name,
190
2.88k
        (void *)kind,
191
2.88k
        datePrototypeGetterHelper,
192
2.88k
        0);
193
2.88k
  };
194
195
160
  defineGetterMethod(
196
160
      Predefined::getSymbolID(Predefined::getFullYear),
197
160
      GetterKind::GetFullYear);
198
160
  defineGetterMethod(
199
160
      Predefined::getSymbolID(Predefined::getYear), GetterKind::GetYear);
200
160
  defineGetterMethod(
201
160
      Predefined::getSymbolID(Predefined::getMonth), GetterKind::GetMonth);
202
160
  defineGetterMethod(
203
160
      Predefined::getSymbolID(Predefined::getDate), GetterKind::GetDate);
204
160
  defineGetterMethod(
205
160
      Predefined::getSymbolID(Predefined::getDay), GetterKind::GetDay);
206
160
  defineGetterMethod(
207
160
      Predefined::getSymbolID(Predefined::getHours), GetterKind::GetHours);
208
160
  defineGetterMethod(
209
160
      Predefined::getSymbolID(Predefined::getMinutes), GetterKind::GetMinutes);
210
160
  defineGetterMethod(
211
160
      Predefined::getSymbolID(Predefined::getSeconds), GetterKind::GetSeconds);
212
160
  defineGetterMethod(
213
160
      Predefined::getSymbolID(Predefined::getMilliseconds),
214
160
      GetterKind::GetMilliseconds);
215
160
  defineGetterMethod(
216
160
      Predefined::getSymbolID(Predefined::getUTCFullYear),
217
160
      GetterKind::GetUTCFullYear);
218
160
  defineGetterMethod(
219
160
      Predefined::getSymbolID(Predefined::getUTCMonth),
220
160
      GetterKind::GetUTCMonth);
221
160
  defineGetterMethod(
222
160
      Predefined::getSymbolID(Predefined::getUTCDate), GetterKind::GetUTCDate);
223
160
  defineGetterMethod(
224
160
      Predefined::getSymbolID(Predefined::getUTCDay), GetterKind::GetUTCDay);
225
160
  defineGetterMethod(
226
160
      Predefined::getSymbolID(Predefined::getUTCHours),
227
160
      GetterKind::GetUTCHours);
228
160
  defineGetterMethod(
229
160
      Predefined::getSymbolID(Predefined::getUTCMinutes),
230
160
      GetterKind::GetUTCMinutes);
231
160
  defineGetterMethod(
232
160
      Predefined::getSymbolID(Predefined::getUTCSeconds),
233
160
      GetterKind::GetUTCSeconds);
234
160
  defineGetterMethod(
235
160
      Predefined::getSymbolID(Predefined::getUTCMilliseconds),
236
160
      GetterKind::GetUTCMilliseconds);
237
160
  defineGetterMethod(
238
160
      Predefined::getSymbolID(Predefined::getTimezoneOffset),
239
160
      GetterKind::GetTimezoneOffset);
240
241
160
  defineMethod(
242
160
      runtime,
243
160
      datePrototype,
244
160
      Predefined::getSymbolID(Predefined::setTime),
245
160
      nullptr,
246
160
      datePrototypeSetTime_RJS,
247
160
      1);
248
249
160
  auto defineSetterMethod =
250
2.40k
      [&](SymbolID name, uint32_t length, bool isUTC, NativeFunctionPtr func) {
251
2.40k
        defineMethod(
252
2.40k
            runtime,
253
2.40k
            datePrototype,
254
2.40k
            name,
255
2.40k
            reinterpret_cast<void *>(isUTC),
256
2.40k
            func,
257
2.40k
            length);
258
2.40k
      };
259
260
160
  defineSetterMethod(
261
160
      Predefined::getSymbolID(Predefined::setMilliseconds),
262
160
      1,
263
160
      false,
264
160
      datePrototypeSetMilliseconds_RJS);
265
160
  defineSetterMethod(
266
160
      Predefined::getSymbolID(Predefined::setUTCMilliseconds),
267
160
      1,
268
160
      true,
269
160
      datePrototypeSetMilliseconds_RJS);
270
160
  defineSetterMethod(
271
160
      Predefined::getSymbolID(Predefined::setSeconds),
272
160
      2,
273
160
      false,
274
160
      datePrototypeSetSeconds_RJS);
275
160
  defineSetterMethod(
276
160
      Predefined::getSymbolID(Predefined::setUTCSeconds),
277
160
      2,
278
160
      true,
279
160
      datePrototypeSetSeconds_RJS);
280
160
  defineSetterMethod(
281
160
      Predefined::getSymbolID(Predefined::setMinutes),
282
160
      3,
283
160
      false,
284
160
      datePrototypeSetMinutes_RJS);
285
160
  defineSetterMethod(
286
160
      Predefined::getSymbolID(Predefined::setUTCMinutes),
287
160
      3,
288
160
      true,
289
160
      datePrototypeSetMinutes_RJS);
290
160
  defineSetterMethod(
291
160
      Predefined::getSymbolID(Predefined::setHours),
292
160
      4,
293
160
      false,
294
160
      datePrototypeSetHours_RJS);
295
160
  defineSetterMethod(
296
160
      Predefined::getSymbolID(Predefined::setUTCHours),
297
160
      4,
298
160
      true,
299
160
      datePrototypeSetHours_RJS);
300
160
  defineSetterMethod(
301
160
      Predefined::getSymbolID(Predefined::setDate),
302
160
      1,
303
160
      false,
304
160
      datePrototypeSetDate_RJS);
305
160
  defineSetterMethod(
306
160
      Predefined::getSymbolID(Predefined::setUTCDate),
307
160
      1,
308
160
      true,
309
160
      datePrototypeSetDate_RJS);
310
160
  defineSetterMethod(
311
160
      Predefined::getSymbolID(Predefined::setMonth),
312
160
      2,
313
160
      false,
314
160
      datePrototypeSetMonth_RJS);
315
160
  defineSetterMethod(
316
160
      Predefined::getSymbolID(Predefined::setUTCMonth),
317
160
      2,
318
160
      true,
319
160
      datePrototypeSetMonth_RJS);
320
160
  defineSetterMethod(
321
160
      Predefined::getSymbolID(Predefined::setFullYear),
322
160
      3,
323
160
      false,
324
160
      datePrototypeSetFullYear_RJS);
325
160
  defineSetterMethod(
326
160
      Predefined::getSymbolID(Predefined::setUTCFullYear),
327
160
      3,
328
160
      true,
329
160
      datePrototypeSetFullYear_RJS);
330
160
  defineSetterMethod(
331
160
      Predefined::getSymbolID(Predefined::setYear),
332
160
      1,
333
160
      false,
334
160
      datePrototypeSetYear_RJS);
335
336
160
  defineMethod(
337
160
      runtime,
338
160
      datePrototype,
339
160
      Predefined::getSymbolID(Predefined::toJSON),
340
160
      nullptr,
341
160
      datePrototypeToJSON_RJS,
342
160
      1);
343
344
160
  DefinePropertyFlags dpf = DefinePropertyFlags::getDefaultNewPropertyFlags();
345
160
  dpf.writable = 0;
346
160
  dpf.enumerable = 0;
347
160
  (void)defineMethod(
348
160
      runtime,
349
160
      datePrototype,
350
160
      Predefined::getSymbolID(Predefined::SymbolToPrimitive),
351
160
      Predefined::getSymbolID(Predefined::squareSymbolToPrimitive),
352
160
      nullptr,
353
160
      datePrototypeSymbolToPrimitive,
354
160
      1,
355
160
      dpf);
356
357
  // Date.xxx() methods.
358
160
  defineMethod(
359
160
      runtime,
360
160
      cons,
361
160
      Predefined::getSymbolID(Predefined::parse),
362
160
      nullptr,
363
160
      dateParse_RJS,
364
160
      1);
365
160
  defineMethod(
366
160
      runtime,
367
160
      cons,
368
160
      Predefined::getSymbolID(Predefined::UTC),
369
160
      nullptr,
370
160
      dateUTC_RJS,
371
160
      7);
372
160
  defineMethod(
373
160
      runtime,
374
160
      cons,
375
160
      Predefined::getSymbolID(Predefined::now),
376
160
      nullptr,
377
160
      dateNow,
378
160
      0);
379
380
160
  return cons;
381
160
}
382
383
/// Takes \p args in UTC time of the form:
384
/// (year, month, [, date [, hours [, minutes [, seconds [, ms]]]]])
385
/// and returns the unclipped time in milliseconds since Jan 1 1970 UTC.
386
static CallResult<double> makeTimeFromArgs_RJS(
387
    Runtime &runtime,
388
0
    NativeArgs args) {
389
0
  const double nan = std::numeric_limits<double>::quiet_NaN();
390
0
  auto argCount = args.getArgCount();
391
392
  // General case: read all fields in and compute timestamp.
393
0
  enum fieldname { y, m, dt, h, min, s, milli, yr, FIELD_COUNT };
394
395
  // Initialize to default fields and update them in loop if necessary.
396
0
  double fields[FIELD_COUNT] = {nan, nan, 1, 0, 0, 0, 0};
397
398
0
  for (size_t i = 0; i < std::min(7u, argCount); ++i) {
399
0
    GCScopeMarkerRAII marker{runtime};
400
0
    auto res = toNumber_RJS(runtime, args.getArgHandle(i));
401
0
    if (res == ExecutionStatus::EXCEPTION) {
402
0
      return ExecutionStatus::EXCEPTION;
403
0
    }
404
0
    fields[i] = res->getNumber();
405
0
  }
406
407
  // Years between 0 and 99 are treated as offsets from 1900.
408
0
  double yint = std::trunc(fields[y]);
409
0
  if (!std::isnan(fields[y]) && 0 <= yint && yint <= 99) {
410
0
    fields[yr] = 1900 + yint;
411
0
  } else {
412
0
    fields[yr] = fields[y];
413
0
  }
414
0
  return makeDate(
415
0
      makeDay(fields[yr], fields[m], fields[dt]),
416
0
      makeTime(fields[h], fields[min], fields[s], fields[milli]));
417
0
}
418
419
CallResult<HermesValue>
420
0
dateConstructor_RJS(void *, Runtime &runtime, NativeArgs args) {
421
0
  if (args.isConstructorCall()) {
422
0
    auto self = args.vmcastThis<JSDate>();
423
0
    uint32_t argCount = args.getArgCount();
424
0
    double finalDate;
425
426
0
    if (argCount == 0) {
427
      // No arguments, just set it to the current time.
428
0
      finalDate = curTime();
429
0
    } else if (argCount == 1) {
430
0
      if (auto *dateArg = dyn_vmcast<JSDate>(args.getArg(0))) {
431
        // No handle needed here because we just retrieve a double.
432
0
        NoAllocScope noAlloc(runtime);
433
0
        finalDate = dateArg->getPrimitiveValue();
434
0
      } else {
435
        // Parse the argument if it's a string, else just convert to number.
436
0
        auto res =
437
0
            toPrimitive_RJS(runtime, args.getArgHandle(0), PreferredType::NONE);
438
0
        if (res == ExecutionStatus::EXCEPTION) {
439
0
          return ExecutionStatus::EXCEPTION;
440
0
        }
441
0
        auto v = runtime.makeHandle(res.getValue());
442
443
0
        if (v->isString()) {
444
          // Call the String -> Date parsing function.
445
0
          finalDate = timeClip(parseDate(
446
0
              StringPrimitive::createStringView(
447
0
                  runtime, Handle<StringPrimitive>::vmcast(v)),
448
0
              runtime.getJSLibStorage()->localTimeOffsetCache));
449
0
        } else {
450
0
          auto numRes = toNumber_RJS(runtime, v);
451
0
          if (numRes == ExecutionStatus::EXCEPTION) {
452
0
            return ExecutionStatus::EXCEPTION;
453
0
          }
454
0
          finalDate = timeClip(numRes->getNumber());
455
0
        }
456
0
      }
457
0
    } else {
458
      // General case: read all fields in and compute timestamp.
459
0
      CallResult<double> cr{0};
460
0
      cr = makeTimeFromArgs_RJS(runtime, args);
461
0
      if (cr == ExecutionStatus::EXCEPTION) {
462
0
        return ExecutionStatus::EXCEPTION;
463
0
      }
464
      // makeTimeFromArgs interprets arguments as UTC.
465
      // We want them as local time, so pretend that they are,
466
      // and call utcTime to get the final UTC value we want to store.
467
0
      finalDate = timeClip(
468
0
          utcTime(*cr, runtime.getJSLibStorage()->localTimeOffsetCache));
469
0
    }
470
0
    self->setPrimitiveValue(finalDate);
471
0
    return self.getHermesValue();
472
0
  }
473
474
0
  llvh::SmallString<32> str{};
475
0
  double t = curTime();
476
0
  double local = localTime(t, runtime.getJSLibStorage()->localTimeOffsetCache);
477
0
  dateTimeString(local, local - t, str);
478
0
  return runtime.ignoreAllocationFailure(StringPrimitive::create(runtime, str));
479
0
}
480
481
CallResult<HermesValue>
482
0
dateParse_RJS(void *, Runtime &runtime, NativeArgs args) {
483
0
  auto res = toString_RJS(runtime, args.getArgHandle(0));
484
0
  if (res == ExecutionStatus::EXCEPTION) {
485
0
    return ExecutionStatus::EXCEPTION;
486
0
  }
487
0
  return HermesValue::encodeUntrustedNumberValue(parseDate(
488
0
      StringPrimitive::createStringView(
489
0
          runtime, runtime.makeHandle(std::move(*res))),
490
0
      runtime.getJSLibStorage()->localTimeOffsetCache));
491
0
}
492
493
0
CallResult<HermesValue> dateUTC_RJS(void *, Runtime &runtime, NativeArgs args) {
494
  // With less than 2 arguments, this is implementation-dependent behavior.
495
  // We define the behavior that test262 expects here.
496
0
  if (args.getArgCount() == 0) {
497
0
    return HermesValue::encodeNaNValue();
498
0
  }
499
0
  if (args.getArgCount() == 1) {
500
0
    auto res = toNumber_RJS(runtime, args.getArgHandle(0));
501
0
    if (LLVM_UNLIKELY(res == ExecutionStatus::EXCEPTION)) {
502
0
      return ExecutionStatus::EXCEPTION;
503
0
    }
504
0
    double y = res->getNumber();
505
0
    return HermesValue::encodeUntrustedNumberValue(
506
0
        timeClip(makeDate(makeDay(y, 0, 1), makeTime(0, 0, 0, 0))));
507
0
  }
508
0
  CallResult<double> cr{0};
509
0
  cr = makeTimeFromArgs_RJS(runtime, args);
510
0
  if (cr == ExecutionStatus::EXCEPTION) {
511
0
    return ExecutionStatus::EXCEPTION;
512
0
  }
513
0
  return HermesValue::encodeUntrustedNumberValue(timeClip(*cr));
514
0
}
515
516
0
CallResult<HermesValue> dateNow(void *, Runtime &runtime, NativeArgs args) {
517
0
  return HermesValue::encodeUntrustedNumberValue(curTime());
518
0
}
519
520
CallResult<HermesValue>
521
0
datePrototypeToStringHelper(void *ctx, Runtime &runtime, NativeArgs args) {
522
0
  static ToStringOptions toStringOptions[] = {
523
0
      {dateTimeString, false, false},
524
0
      {dateString, false, false},
525
0
      {timeTZString, false, false},
526
0
      {datetimeToISOString, true, true},
527
0
      {dateTimeUTCString, true, false},
528
0
  };
529
0
  assert(
530
0
      (uint64_t)ctx < (uint64_t)ToStringKind::NumKinds &&
531
0
      "dataPrototypeToString with wrong kind as context");
532
0
  ToStringOptions *opts = &toStringOptions[(uint64_t)ctx];
533
0
  auto *date = dyn_vmcast<JSDate>(args.getThisArg());
534
0
  if (!date) {
535
0
    return runtime.raiseTypeError(
536
0
        "Date.prototype.toString() called on non-Date object");
537
0
  }
538
0
  double t = date->getPrimitiveValue();
539
0
  if (!std::isfinite(t)) {
540
0
    if (opts->throwOnError) {
541
0
      return runtime.raiseRangeError("Date value out of bounds");
542
0
    }
543
    // "Invalid Date" in non-finite or NaN cases.
544
0
    return HermesValue::encodeStringValue(
545
0
        runtime.getPredefinedString(Predefined::InvalidDate));
546
0
  }
547
0
  llvh::SmallString<32> str{};
548
0
  if (!opts->isUTC) {
549
0
    double local =
550
0
        localTime(t, runtime.getJSLibStorage()->localTimeOffsetCache);
551
0
    opts->toStringFn(local, local - t, str);
552
0
  } else {
553
0
    opts->toStringFn(t, 0, str);
554
0
  }
555
0
  return runtime.ignoreAllocationFailure(StringPrimitive::create(runtime, str));
556
0
}
557
558
CallResult<HermesValue> datePrototypeToLocaleStringHelper(
559
    void *ctx,
560
    Runtime &runtime,
561
0
    NativeArgs args) {
562
0
  assert(
563
0
      (uint64_t)ctx < (uint64_t)ToLocaleStringKind::NumKinds &&
564
0
      "dataPrototypeToLocaleString with wrong kind as context");
565
#ifdef HERMES_ENABLE_INTL
566
  static NativeFunctionPtr toLocaleStringFunctions[] = {
567
      intlDatePrototypeToLocaleString,
568
      intlDatePrototypeToLocaleDateString,
569
      intlDatePrototypeToLocaleTimeString,
570
  };
571
  assert(
572
      sizeof(toLocaleStringFunctions) / sizeof(toLocaleStringFunctions[0]) ==
573
          (size_t)ToLocaleStringKind::NumKinds &&
574
      "toLocaleStringFunctions has wrong number of elements");
575
  return toLocaleStringFunctions[(uint64_t)ctx](
576
      /* unused */ ctx, runtime, args);
577
#else
578
0
  static ToLocaleStringOptions toLocaleStringOptions[] = {
579
0
      {datetimeToLocaleString},
580
0
      {dateToLocaleString},
581
0
      {timeToLocaleString},
582
0
  };
583
0
  assert(
584
0
      sizeof(toLocaleStringOptions) / sizeof(toLocaleStringOptions[0]) ==
585
0
          (size_t)ToLocaleStringKind::NumKinds &&
586
0
      "toLocaleStringOptions has wrong number of elements");
587
0
  ToLocaleStringOptions *opts = &toLocaleStringOptions[(uint64_t)ctx];
588
0
  auto *date = dyn_vmcast<JSDate>(args.getThisArg());
589
0
  if (!date) {
590
0
    return runtime.raiseTypeError(
591
0
        "Date.prototype.toString() called on non-Date object");
592
0
  }
593
0
  double t = date->getPrimitiveValue();
594
0
  if (!std::isfinite(t)) {
595
    // "Invalid Date" in non-finite or NaN cases.
596
0
    return HermesValue::encodeStringValue(
597
0
        runtime.getPredefinedString(Predefined::InvalidDate));
598
0
  }
599
0
  SmallU16String<128> str{};
600
601
0
  opts->toStringFn(t, str);
602
0
  return StringPrimitive::create(runtime, str);
603
0
#endif
604
0
}
605
606
CallResult<HermesValue>
607
0
datePrototypeGetTime(void *, Runtime &runtime, NativeArgs args) {
608
0
  auto *date = dyn_vmcast<JSDate>(args.getThisArg());
609
0
  if (!date) {
610
0
    return runtime.raiseTypeError(
611
0
        "Date.prototype.getTime() called on non-Date object");
612
0
  }
613
614
0
  return HermesValue::encodeUntrustedNumberValue(date->getPrimitiveValue());
615
0
}
616
617
CallResult<HermesValue>
618
0
datePrototypeGetterHelper(void *ctx, Runtime &runtime, NativeArgs args) {
619
0
  static GetterOptions getterOptions[] = {
620
0
      {GetterOptions::Field::FULL_YEAR, false},
621
0
      {GetterOptions::Field::YEAR, false},
622
0
      {GetterOptions::Field::MONTH, false},
623
0
      {GetterOptions::Field::DATE, false},
624
0
      {GetterOptions::Field::DAY, false},
625
0
      {GetterOptions::Field::HOURS, false},
626
0
      {GetterOptions::Field::MINUTES, false},
627
0
      {GetterOptions::Field::SECONDS, false},
628
0
      {GetterOptions::Field::MILLISECONDS, false},
629
0
      {GetterOptions::Field::FULL_YEAR, true},
630
0
      {GetterOptions::Field::MONTH, true},
631
0
      {GetterOptions::Field::DATE, true},
632
0
      {GetterOptions::Field::DAY, true},
633
0
      {GetterOptions::Field::HOURS, true},
634
0
      {GetterOptions::Field::MINUTES, true},
635
0
      {GetterOptions::Field::SECONDS, true},
636
0
      {GetterOptions::Field::MILLISECONDS, true},
637
0
      {GetterOptions::Field::TIMEZONE_OFFSET, false},
638
0
  };
639
0
  assert(
640
0
      (uint64_t)ctx < (uint64_t)GetterKind::NumKinds &&
641
0
      "datePropertyGetterHelper with wrong kind as context");
642
0
  GetterOptions *opts = &getterOptions[(uint64_t)ctx];
643
0
  auto *date = dyn_vmcast<JSDate>(args.getThisArg());
644
0
  if (!date) {
645
0
    return runtime.raiseTypeError(
646
0
        "Date.prototype.toString() called on non-Date object");
647
0
  }
648
0
  double t = date->getPrimitiveValue();
649
0
  if (std::isnan(t)) {
650
0
    return HermesValue::encodeNaNValue();
651
0
  }
652
653
  // Store the original value of t to be used in offset calculations.
654
0
  double utc = t;
655
0
  if (!opts->isUTC) {
656
0
    t = localTime(t, runtime.getJSLibStorage()->localTimeOffsetCache);
657
0
  }
658
659
0
  double result{std::numeric_limits<double>::quiet_NaN()};
660
0
  switch (opts->field) {
661
0
    case GetterOptions::Field::FULL_YEAR:
662
0
      result = yearFromTime(t);
663
0
      break;
664
0
    case GetterOptions::Field::YEAR:
665
0
      result = yearFromTime(t) - 1900;
666
0
      break;
667
0
    case GetterOptions::Field::MONTH:
668
0
      result = monthFromTime(t);
669
0
      break;
670
0
    case GetterOptions::Field::DATE:
671
0
      result = dateFromTime(t);
672
0
      break;
673
0
    case GetterOptions::Field::DAY:
674
0
      result = weekDay(t);
675
0
      break;
676
0
    case GetterOptions::Field::HOURS:
677
0
      result = hourFromTime(t);
678
0
      break;
679
0
    case GetterOptions::Field::MINUTES:
680
0
      result = minFromTime(t);
681
0
      break;
682
0
    case GetterOptions::Field::SECONDS:
683
0
      result = secFromTime(t);
684
0
      break;
685
0
    case GetterOptions::Field::MILLISECONDS:
686
0
      result = msFromTime(t);
687
0
      break;
688
0
    case GetterOptions::Field::TIMEZONE_OFFSET:
689
0
      result = (utc - t) / MS_PER_MINUTE;
690
0
      break;
691
0
  }
692
0
  return HermesValue::encodeUntrustedNumberValue(result);
693
0
}
694
695
/// Set the [[PrimitiveValue]] to the given time.
696
CallResult<HermesValue>
697
0
datePrototypeSetTime_RJS(void *ctx, Runtime &runtime, NativeArgs args) {
698
0
  auto self = args.dyncastThis<JSDate>();
699
0
  if (!self) {
700
0
    return runtime.raiseTypeError(
701
0
        "Date.prototype.setTime() called on non-Date object");
702
0
  }
703
0
  auto res = toNumber_RJS(runtime, args.getArgHandle(0));
704
0
  if (res == ExecutionStatus::EXCEPTION) {
705
0
    return ExecutionStatus::EXCEPTION;
706
0
  }
707
0
  double t = timeClip(res->getNumber());
708
0
  self->setPrimitiveValue(t);
709
0
  return HermesValue::encodeUntrustedNumberValue(t);
710
0
}
711
712
/// Set the milliseconds as provided and return the new time value.
713
CallResult<HermesValue>
714
0
datePrototypeSetMilliseconds_RJS(void *ctx, Runtime &runtime, NativeArgs args) {
715
0
  bool isUTC = static_cast<bool>(ctx);
716
0
  auto self = args.dyncastThis<JSDate>();
717
0
  if (!self) {
718
0
    return runtime.raiseTypeError(
719
0
        "Date.prototype.setMilliseconds() called on non-Date object");
720
0
  }
721
0
  double t = self->getPrimitiveValue();
722
0
  auto &localTimeOffsetCache = runtime.getJSLibStorage()->localTimeOffsetCache;
723
0
  if (!isUTC) {
724
0
    t = localTime(t, localTimeOffsetCache);
725
0
  }
726
0
  auto res = toNumber_RJS(runtime, args.getArgHandle(0));
727
0
  if (res == ExecutionStatus::EXCEPTION) {
728
0
    return ExecutionStatus::EXCEPTION;
729
0
  }
730
0
  double ms = res->getNumber();
731
0
  double date = makeDate(
732
0
      day(t), makeTime(hourFromTime(t), minFromTime(t), secFromTime(t), ms));
733
0
  double utcT =
734
0
      !isUTC ? timeClip(utcTime(date, localTimeOffsetCache)) : timeClip(date);
735
0
  self->setPrimitiveValue(utcT);
736
0
  return HermesValue::encodeUntrustedNumberValue(utcT);
737
0
}
738
739
/// Takes 2 arguments: seconds, milliseconds.
740
/// Set the seconds, optionally milliseconds, and return the new time.
741
CallResult<HermesValue>
742
0
datePrototypeSetSeconds_RJS(void *ctx, Runtime &runtime, NativeArgs args) {
743
0
  bool isUTC = static_cast<bool>(ctx);
744
0
  auto self = args.dyncastThis<JSDate>();
745
0
  if (!self) {
746
0
    return runtime.raiseTypeError(
747
0
        "Date.prototype.setSeconds() called on non-Date object");
748
0
  }
749
0
  double t = self->getPrimitiveValue();
750
0
  auto &localTimeOffsetCache = runtime.getJSLibStorage()->localTimeOffsetCache;
751
0
  if (!isUTC) {
752
0
    t = localTime(t, localTimeOffsetCache);
753
0
  }
754
0
  auto res = toNumber_RJS(runtime, args.getArgHandle(0));
755
0
  if (res == ExecutionStatus::EXCEPTION) {
756
0
    return ExecutionStatus::EXCEPTION;
757
0
  }
758
0
  double s = res->getNumber();
759
0
  double milli;
760
0
  if (args.getArgCount() >= 2) {
761
0
    res = toNumber_RJS(runtime, args.getArgHandle(1));
762
0
    if (res == ExecutionStatus::EXCEPTION) {
763
0
      return ExecutionStatus::EXCEPTION;
764
0
    }
765
0
    milli = res->getNumber();
766
0
  } else {
767
0
    milli = msFromTime(t);
768
0
  }
769
770
0
  double date =
771
0
      makeDate(day(t), makeTime(hourFromTime(t), minFromTime(t), s, milli));
772
0
  double utcT =
773
0
      !isUTC ? timeClip(utcTime(date, localTimeOffsetCache)) : timeClip(date);
774
0
  self->setPrimitiveValue(utcT);
775
0
  return HermesValue::encodeUntrustedNumberValue(utcT);
776
0
}
777
778
/// Takes 3 arguments: minutes, seconds, milliseconds.
779
/// Set the minutes, optionally seconds and milliseconds, return time.
780
CallResult<HermesValue>
781
0
datePrototypeSetMinutes_RJS(void *ctx, Runtime &runtime, NativeArgs args) {
782
0
  bool isUTC = static_cast<bool>(ctx);
783
0
  auto self = args.dyncastThis<JSDate>();
784
0
  if (!self) {
785
0
    return runtime.raiseTypeError(
786
0
        "Date.prototype.setMinutes() called on non-Date object");
787
0
  }
788
0
  double t = self->getPrimitiveValue();
789
0
  auto &localTimeOffsetCache = runtime.getJSLibStorage()->localTimeOffsetCache;
790
0
  if (!isUTC) {
791
0
    t = localTime(t, localTimeOffsetCache);
792
0
  }
793
0
  auto res = toNumber_RJS(runtime, args.getArgHandle(0));
794
0
  if (res == ExecutionStatus::EXCEPTION) {
795
0
    return ExecutionStatus::EXCEPTION;
796
0
  }
797
0
  double m = res->getNumber();
798
0
  double s;
799
0
  if (args.getArgCount() >= 2) {
800
0
    res = toNumber_RJS(runtime, args.getArgHandle(1));
801
0
    if (res == ExecutionStatus::EXCEPTION) {
802
0
      return ExecutionStatus::EXCEPTION;
803
0
    }
804
0
    s = res->getNumber();
805
0
  } else {
806
0
    s = secFromTime(t);
807
0
  }
808
0
  double milli;
809
0
  if (args.getArgCount() >= 3) {
810
0
    res = toNumber_RJS(runtime, args.getArgHandle(2));
811
0
    if (res == ExecutionStatus::EXCEPTION) {
812
0
      return ExecutionStatus::EXCEPTION;
813
0
    }
814
0
    milli = res->getNumber();
815
0
  } else {
816
0
    milli = msFromTime(t);
817
0
  }
818
819
0
  double date = makeDate(day(t), makeTime(hourFromTime(t), m, s, milli));
820
0
  double utcT =
821
0
      !isUTC ? timeClip(utcTime(date, localTimeOffsetCache)) : timeClip(date);
822
0
  self->setPrimitiveValue(utcT);
823
0
  return HermesValue::encodeUntrustedNumberValue(utcT);
824
0
}
825
826
/// Takes 4 arguments: hours, minutes, seconds, milliseconds.
827
/// Set the hours, optionally minutes, seconds, and milliseconds, return time.
828
CallResult<HermesValue>
829
0
datePrototypeSetHours_RJS(void *ctx, Runtime &runtime, NativeArgs args) {
830
0
  bool isUTC = static_cast<bool>(ctx);
831
0
  auto self = args.dyncastThis<JSDate>();
832
0
  if (!self) {
833
0
    return runtime.raiseTypeError(
834
0
        "Date.prototype.setHours() called on non-Date object");
835
0
  }
836
0
  double t = self->getPrimitiveValue();
837
0
  auto &localTimeOffsetCache = runtime.getJSLibStorage()->localTimeOffsetCache;
838
0
  if (!isUTC) {
839
0
    t = localTime(t, localTimeOffsetCache);
840
0
  }
841
0
  auto res = toNumber_RJS(runtime, args.getArgHandle(0));
842
0
  if (res == ExecutionStatus::EXCEPTION) {
843
0
    return ExecutionStatus::EXCEPTION;
844
0
  }
845
0
  double h = res->getNumber();
846
0
  double m;
847
0
  if (args.getArgCount() >= 2) {
848
0
    res = toNumber_RJS(runtime, args.getArgHandle(1));
849
0
    if (res == ExecutionStatus::EXCEPTION) {
850
0
      return ExecutionStatus::EXCEPTION;
851
0
    }
852
0
    m = res->getNumber();
853
0
  } else {
854
0
    m = minFromTime(t);
855
0
  }
856
0
  double s;
857
0
  if (args.getArgCount() >= 3) {
858
0
    res = toNumber_RJS(runtime, args.getArgHandle(2));
859
0
    if (res == ExecutionStatus::EXCEPTION) {
860
0
      return ExecutionStatus::EXCEPTION;
861
0
    }
862
0
    s = res->getNumber();
863
0
  } else {
864
0
    s = secFromTime(t);
865
0
  }
866
0
  double milli;
867
0
  if (args.getArgCount() >= 4) {
868
0
    res = toNumber_RJS(runtime, args.getArgHandle(3));
869
0
    if (res == ExecutionStatus::EXCEPTION) {
870
0
      return ExecutionStatus::EXCEPTION;
871
0
    }
872
0
    milli = res->getNumber();
873
0
  } else {
874
0
    milli = msFromTime(t);
875
0
  }
876
877
0
  double date = makeDate(day(t), makeTime(h, m, s, milli));
878
0
  double utcT =
879
0
      !isUTC ? timeClip(utcTime(date, localTimeOffsetCache)) : timeClip(date);
880
0
  self->setPrimitiveValue(utcT);
881
0
  return HermesValue::encodeUntrustedNumberValue(utcT);
882
0
}
883
884
/// Set the date of the month and return the new time.
885
CallResult<HermesValue>
886
0
datePrototypeSetDate_RJS(void *ctx, Runtime &runtime, NativeArgs args) {
887
0
  bool isUTC = static_cast<bool>(ctx);
888
0
  auto self = args.dyncastThis<JSDate>();
889
0
  if (!self) {
890
0
    return runtime.raiseTypeError(
891
0
        "Date.prototype.setDate() called on non-Date object");
892
0
  }
893
0
  double t = self->getPrimitiveValue();
894
0
  auto &localTimeOffsetCache = runtime.getJSLibStorage()->localTimeOffsetCache;
895
0
  if (!isUTC) {
896
0
    t = localTime(t, localTimeOffsetCache);
897
0
  }
898
0
  auto res = toNumber_RJS(runtime, args.getArgHandle(0));
899
0
  if (res == ExecutionStatus::EXCEPTION) {
900
0
    return ExecutionStatus::EXCEPTION;
901
0
  }
902
0
  double dt = res->getNumber();
903
0
  double newDate = makeDate(
904
0
      makeDay(yearFromTime(t), monthFromTime(t), dt), timeWithinDay(t));
905
0
  double utcT = !isUTC ? timeClip(utcTime(newDate, localTimeOffsetCache))
906
0
                       : timeClip(newDate);
907
0
  self->setPrimitiveValue(utcT);
908
0
  return HermesValue::encodeUntrustedNumberValue(utcT);
909
0
}
910
911
/// Takes 2 arguments: month and date.
912
/// Set the month, optionally the date of the month, return the time.
913
CallResult<HermesValue>
914
0
datePrototypeSetMonth_RJS(void *ctx, Runtime &runtime, NativeArgs args) {
915
0
  bool isUTC = static_cast<bool>(ctx);
916
0
  auto self = args.dyncastThis<JSDate>();
917
0
  if (!self) {
918
0
    return runtime.raiseTypeError(
919
0
        "Date.prototype.setMonth() called on non-Date object");
920
0
  }
921
0
  double t = self->getPrimitiveValue();
922
0
  auto &localTimeOffsetCache = runtime.getJSLibStorage()->localTimeOffsetCache;
923
0
  if (!isUTC) {
924
0
    t = localTime(t, localTimeOffsetCache);
925
0
  }
926
0
  auto res = toNumber_RJS(runtime, args.getArgHandle(0));
927
0
  if (res == ExecutionStatus::EXCEPTION) {
928
0
    return ExecutionStatus::EXCEPTION;
929
0
  }
930
0
  double m = res->getNumber();
931
0
  double dt;
932
0
  if (args.getArgCount() >= 2) {
933
0
    res = toNumber_RJS(runtime, args.getArgHandle(1));
934
0
    if (res == ExecutionStatus::EXCEPTION) {
935
0
      return ExecutionStatus::EXCEPTION;
936
0
    }
937
0
    dt = res->getNumber();
938
0
  } else {
939
0
    dt = dateFromTime(t);
940
0
  }
941
0
  double newDate = makeDate(makeDay(yearFromTime(t), m, dt), timeWithinDay(t));
942
0
  double utcT = !isUTC ? timeClip(utcTime(newDate, localTimeOffsetCache))
943
0
                       : timeClip(newDate);
944
0
  self->setPrimitiveValue(utcT);
945
0
  return HermesValue::encodeUntrustedNumberValue(utcT);
946
0
}
947
948
/// Takes 3 arguments: full year, month and date.
949
/// Set the full year, optionally the month and date, return the time.
950
CallResult<HermesValue>
951
0
datePrototypeSetFullYear_RJS(void *ctx, Runtime &runtime, NativeArgs args) {
952
0
  bool isUTC = static_cast<bool>(ctx);
953
0
  auto self = args.dyncastThis<JSDate>();
954
0
  if (!self) {
955
0
    return runtime.raiseTypeError(
956
0
        "Date.prototype.setFullYear() called on non-Date object");
957
0
  }
958
0
  double t = self->getPrimitiveValue();
959
0
  auto &localTimeOffsetCache = runtime.getJSLibStorage()->localTimeOffsetCache;
960
0
  if (!isUTC) {
961
0
    t = localTime(t, localTimeOffsetCache);
962
0
  }
963
0
  if (std::isnan(t)) {
964
0
    t = 0;
965
0
  }
966
0
  auto res = toNumber_RJS(runtime, args.getArgHandle(0));
967
0
  if (res == ExecutionStatus::EXCEPTION) {
968
0
    return ExecutionStatus::EXCEPTION;
969
0
  }
970
0
  double y = res->getNumber();
971
0
  double m;
972
0
  if (args.getArgCount() >= 2) {
973
0
    res = toNumber_RJS(runtime, args.getArgHandle(1));
974
0
    if (res == ExecutionStatus::EXCEPTION) {
975
0
      return ExecutionStatus::EXCEPTION;
976
0
    }
977
0
    m = res->getNumber();
978
0
  } else {
979
0
    m = monthFromTime(t);
980
0
  }
981
0
  double dt;
982
0
  if (args.getArgCount() >= 3) {
983
0
    res = toNumber_RJS(runtime, args.getArgHandle(2));
984
0
    if (res == ExecutionStatus::EXCEPTION) {
985
0
      return ExecutionStatus::EXCEPTION;
986
0
    }
987
0
    dt = res->getNumber();
988
0
  } else {
989
0
    dt = dateFromTime(t);
990
0
  }
991
0
  double newDate = makeDate(makeDay(y, m, dt), timeWithinDay(t));
992
0
  double utcT = !isUTC ? timeClip(utcTime(newDate, localTimeOffsetCache))
993
0
                       : timeClip(newDate);
994
0
  self->setPrimitiveValue(utcT);
995
0
  return HermesValue::encodeUntrustedNumberValue(utcT);
996
0
}
997
998
/// Takes one argument: the partial (or full) year.
999
/// Per spec, adds 1900 if the year is between 0 and 99.
1000
/// Sets the year to the new year and returns the time.
1001
CallResult<HermesValue>
1002
0
datePrototypeSetYear_RJS(void *ctx, Runtime &runtime, NativeArgs args) {
1003
0
  auto self = args.dyncastThis<JSDate>();
1004
0
  if (!self) {
1005
0
    return runtime.raiseTypeError(
1006
0
        "Date.prototype.setYear() called on non-Date object");
1007
0
  }
1008
0
  double t = self->getPrimitiveValue();
1009
0
  auto &localTimeOffsetCache = runtime.getJSLibStorage()->localTimeOffsetCache;
1010
0
  t = localTime(t, localTimeOffsetCache);
1011
0
  if (std::isnan(t)) {
1012
0
    t = 0;
1013
0
  }
1014
0
  auto res = toNumber_RJS(runtime, args.getArgHandle(0));
1015
0
  if (res == ExecutionStatus::EXCEPTION) {
1016
0
    return ExecutionStatus::EXCEPTION;
1017
0
  }
1018
0
  double y = res->getNumber();
1019
0
  if (std::isnan(y)) {
1020
0
    self->setPrimitiveValue(std::numeric_limits<double>::quiet_NaN());
1021
0
    return HermesValue::encodeNaNValue();
1022
0
  }
1023
0
  double yint = std::trunc(y);
1024
0
  double yr = 0 <= yint && yint <= 99 ? yint + 1900 : y;
1025
0
  double date = utcTime(
1026
0
      makeDate(
1027
0
          makeDay(yr, monthFromTime(t), dateFromTime(t)), timeWithinDay(t)),
1028
0
      localTimeOffsetCache);
1029
0
  double d = timeClip(date);
1030
0
  self->setPrimitiveValue(d);
1031
0
  return HermesValue::encodeUntrustedNumberValue(d);
1032
0
}
1033
1034
CallResult<HermesValue>
1035
0
datePrototypeToJSON_RJS(void *ctx, Runtime &runtime, NativeArgs args) {
1036
0
  auto selfHandle = args.getThisHandle();
1037
0
  auto objRes = toObject(runtime, selfHandle);
1038
0
  if (objRes == ExecutionStatus::EXCEPTION) {
1039
0
    return ExecutionStatus::EXCEPTION;
1040
0
  }
1041
0
  auto O = runtime.makeHandle<JSObject>(objRes.getValue());
1042
0
  auto tvRes = toPrimitive_RJS(runtime, O, PreferredType::NUMBER);
1043
0
  if (tvRes == ExecutionStatus::EXCEPTION) {
1044
0
    return ExecutionStatus::EXCEPTION;
1045
0
  }
1046
0
  auto tv = *tvRes;
1047
0
  if (tv.isNumber() && !std::isfinite(tv.getNumber())) {
1048
0
    return HermesValue::encodeNullValue();
1049
0
  }
1050
0
  auto propRes = JSObject::getNamed_RJS(
1051
0
      O, runtime, Predefined::getSymbolID(Predefined::toISOString));
1052
0
  if (LLVM_UNLIKELY(propRes == ExecutionStatus::EXCEPTION)) {
1053
0
    return ExecutionStatus::EXCEPTION;
1054
0
  }
1055
0
  Handle<Callable> toISO =
1056
0
      Handle<Callable>::dyn_vmcast(runtime.makeHandle(std::move(*propRes)));
1057
0
  if (!toISO.get()) {
1058
0
    return runtime.raiseTypeError(
1059
0
        "toISOString is not callable in Date.prototype.toJSON()");
1060
0
  }
1061
0
  return Callable::executeCall0(toISO, runtime, O).toCallResultHermesValue();
1062
0
}
1063
1064
CallResult<HermesValue>
1065
0
datePrototypeSymbolToPrimitive(void *, Runtime &runtime, NativeArgs args) {
1066
0
  auto O = args.dyncastThis<JSObject>();
1067
0
  if (LLVM_UNLIKELY(!O)) {
1068
0
    return runtime.raiseTypeError(
1069
0
        "Date[Symbol.toPrimitive]() must be called on an object");
1070
0
  }
1071
1072
0
  auto hint = args.getArgHandle(0);
1073
0
  if (LLVM_UNLIKELY(!hint->isString())) {
1074
0
    return runtime.raiseTypeError(
1075
0
        "Date[Symbol.toPrimitive]() argument must be a string");
1076
0
  }
1077
1078
0
  PreferredType tryFirst;
1079
1080
0
  if (runtime.symbolEqualsToStringPrim(
1081
0
          Predefined::getSymbolID(Predefined::string), hint->getString()) ||
1082
0
      runtime.symbolEqualsToStringPrim(
1083
0
          Predefined::getSymbolID(Predefined::defaultStr), hint->getString())) {
1084
0
    tryFirst = PreferredType::STRING;
1085
0
  } else if (runtime.symbolEqualsToStringPrim(
1086
0
                 Predefined::getSymbolID(Predefined::number),
1087
0
                 hint->getString())) {
1088
0
    tryFirst = PreferredType::NUMBER;
1089
0
  } else {
1090
0
    return runtime.raiseTypeError(
1091
0
        "Type hint to Date[Symbol.primitive] must be "
1092
0
        "'number', 'string', or 'default'");
1093
0
  }
1094
1095
0
  return ordinaryToPrimitive(O, runtime, tryFirst);
1096
0
}
1097
1098
} // namespace vm
1099
} // namespace hermes